From 9c4a36463239a355cdbfdd3fbb82ac8be4504ec6 Mon Sep 17 00:00:00 2001 From: codetorso Date: Fri, 19 Jul 2024 01:33:25 +0530 Subject: [PATCH] recent searches feature and some other cool stuff --- apps/web/app/(dash)/home/filterSpaces.tsx | 37 +- apps/web/app/(dash)/home/heading.tsx | 28 +- apps/web/app/(dash)/home/page.tsx | 56 +- apps/web/app/(dash)/home/queryinput.tsx | 4 +- apps/web/app/actions/fetchers.ts | 30 +- apps/web/migrations/0001_nervous_longshot.sql | 2 + apps/web/migrations/meta/0001_snapshot.json | 905 ++++++++++++++++++ apps/web/migrations/meta/_journal.json | 31 +- apps/web/package.json | 1 + apps/web/server/db/schema.ts | 3 +- bun.lockb | Bin 1158164 -> 1158660 bytes 11 files changed, 1045 insertions(+), 52 deletions(-) create mode 100644 apps/web/migrations/0001_nervous_longshot.sql create mode 100644 apps/web/migrations/meta/0001_snapshot.json diff --git a/apps/web/app/(dash)/home/filterSpaces.tsx b/apps/web/app/(dash)/home/filterSpaces.tsx index d0e4fa1e..061923d8 100644 --- a/apps/web/app/(dash)/home/filterSpaces.tsx +++ b/apps/web/app/(dash)/home/filterSpaces.tsx @@ -76,30 +76,31 @@ export function FilterSpaces({ - {initialSpaces.map((space) => ( - handleSelect(space)} - > - v.id === space.id) ? "opacity-100" : "opacity-0"}`} - /> - {space.name} - - ))} + {initialSpaces.map((space) => { + if (!selectedSpaces.some((v) => v.id === space.id)) { + return ( + handleSelect(space)} + > + v.id === space.id) ? "opacity-100" : "opacity-0"}`} + /> + {space.name} + + ); + } + })} - {/* */} - diff --git a/apps/web/app/(dash)/home/heading.tsx b/apps/web/app/(dash)/home/heading.tsx index 75a83dae..e50f509b 100644 --- a/apps/web/app/(dash)/home/heading.tsx +++ b/apps/web/app/(dash)/home/heading.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { motion } from "framer-motion"; +import { AnimatePresence, motion } from "framer-motion"; const headings = [ "Unlock your digital brain", @@ -13,17 +13,23 @@ export function Heading({ queryPresent }: { queryPresent: boolean }) { const [showHeading, setShowHeading] = useState(0); useEffect(() => { setShowHeading(Math.floor(Math.random() * headings.length)); - }, []); + }, [queryPresent]); return ( -
- - {headings[showHeading]} - +
+ + {!queryPresent && ( + + {headings[showHeading]} + + )} +
); } diff --git a/apps/web/app/(dash)/home/page.tsx b/apps/web/app/(dash)/home/page.tsx index 84ecf242..7572056a 100644 --- a/apps/web/app/(dash)/home/page.tsx +++ b/apps/web/app/(dash)/home/page.tsx @@ -1,12 +1,18 @@ "use client"; -import React, { useEffect, useState } from "react"; +import React, { Suspense, memo, use, useEffect, useState } from "react"; import QueryInput from "./queryinput"; -import { getSessionAuthToken, getSpaces } from "@/app/actions/fetchers"; +import { + getRecentChats, + getSessionAuthToken, + getSpaces, +} from "@/app/actions/fetchers"; import { useRouter } from "next/navigation"; import { createChatThread, linkTelegramToUser } from "@/app/actions/doers"; import { toast } from "sonner"; import { Heading } from "./heading"; +import { ArrowLongRightIcon } from "@heroicons/react/24/outline"; +import Link from "next/link"; const linkTelegram = async (telegramUser: string) => { const response = await linkTelegramToUser(telegramUser); @@ -23,7 +29,6 @@ function Page({ }: { searchParams: Record; }) { - const { push } = useRouter(); const [spaces, setSpaces] = useState<{ id: number; name: string }[]>([]); @@ -32,7 +37,7 @@ function Page({ useEffect(() => { // telegram bot - const telegramUser = searchParams.extension as string + const telegramUser = searchParams.extension as string; if (telegramUser) { linkTelegram(telegramUser); } @@ -57,11 +62,11 @@ function Page({ }, []); return ( -
+
-
+
setQueryPresent(t)} + setQueryPresent={(t: boolean) => setQueryPresent(t)} handleSubmit={async (q, spaces) => { if (q.length === 0) { toast.error("Query is required"); @@ -82,8 +87,45 @@ function Page({ initialSpaces={spaces} />
+
); } +const History = memo(() => { + const [chatThreads, setChatThreads] = useState(null); + + useEffect(() => { + (async () => { + const chatThreads = await getRecentChats(); + + setChatThreads(chatThreads); + })(); + }, []); + + if (!chatThreads){ + return
Loading
; + } + + if (!chatThreads.success || !chatThreads.data) { + return
Error fetching chat threads
; + } + + return ( +
+

Recent Searches

+
    + {chatThreads.data.map((thread) => ( +
  • + {" "} + + {thread.firstMessage} + +
  • + ))} +
+
+ ); +}); + export default Page; diff --git a/apps/web/app/(dash)/home/queryinput.tsx b/apps/web/app/(dash)/home/queryinput.tsx index 6767d5ea..930f34db 100644 --- a/apps/web/app/(dash)/home/queryinput.tsx +++ b/apps/web/app/(dash)/home/queryinput.tsx @@ -25,9 +25,9 @@ function QueryInput({ >([]); return ( -
+
{/* input and action button */}
=> { + const data = await auth(); + + if (!data || !data.user || !data.user.id) { + redirect("/signin"); + return { error: "Not authenticated", success: false }; + } + + try { + const chatHistorys = await db.query.chatThreads.findMany({ + where: eq(chatThreads.userId, data.user.id), + orderBy: desc(chatThreads.createdAt), + limit: 4, + }); + + return { + success: true, + data: chatHistorys, + }; + } catch (e) { + return { + success: false, + error: (e as Error).message, + }; + } +}; + + export const getChatHistory = async (): ServerActionReturnType< ChatThread[] > => { diff --git a/apps/web/migrations/0001_nervous_longshot.sql b/apps/web/migrations/0001_nervous_longshot.sql new file mode 100644 index 00000000..a15917c6 --- /dev/null +++ b/apps/web/migrations/0001_nervous_longshot.sql @@ -0,0 +1,2 @@ +ALTER TABLE `chatThread` ADD `createdAt` integer; +UPDATE `chatThread` SET `createdAt` = strftime('%s', 'now') WHERE `createdAt` IS NULL; diff --git a/apps/web/migrations/meta/0001_snapshot.json b/apps/web/migrations/meta/0001_snapshot.json new file mode 100644 index 00000000..91c50c13 --- /dev/null +++ b/apps/web/migrations/meta/0001_snapshot.json @@ -0,0 +1,905 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "39768c98-95d2-4d42-bae0-43e3e511be7e", + "prevId": "ab91d972-05ff-4916-84b7-1cfaab4c3879", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "columns": [ + "provider", + "providerAccountId" + ], + "name": "account_provider_providerAccountId_pk" + } + }, + "uniqueConstraints": {} + }, + "authenticator": { + "name": "authenticator", + "columns": { + "credentialID": { + "name": "credentialID", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credentialPublicKey": { + "name": "credentialPublicKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "counter": { + "name": "counter", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credentialDeviceType": { + "name": "credentialDeviceType", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credentialBackedUp": { + "name": "credentialBackedUp", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "transports": { + "name": "transports", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "authenticator_credentialID_unique": { + "name": "authenticator_credentialID_unique", + "columns": [ + "credentialID" + ], + "isUnique": true + } + }, + "foreignKeys": { + "authenticator_userId_user_id_fk": { + "name": "authenticator_userId_user_id_fk", + "tableFrom": "authenticator", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "authenticator_userId_credentialID_pk": { + "columns": [ + "credentialID", + "userId" + ], + "name": "authenticator_userId_credentialID_pk" + } + }, + "uniqueConstraints": {} + }, + "canvas": { + "name": "canvas", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Untitled'" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Untitled'" + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "canvas_user_userId": { + "name": "canvas_user_userId", + "columns": [ + "userId" + ], + "isUnique": false + } + }, + "foreignKeys": { + "canvas_userId_user_id_fk": { + "name": "canvas_userId_user_id_fk", + "tableFrom": "canvas", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "chatHistory": { + "name": "chatHistory", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "threadId": { + "name": "threadId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "question": { + "name": "question", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "answerParts": { + "name": "answerParts", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "answerSources": { + "name": "answerSources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "answerJustification": { + "name": "answerJustification", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "chatHistory_thread_idx": { + "name": "chatHistory_thread_idx", + "columns": [ + "threadId" + ], + "isUnique": false + } + }, + "foreignKeys": { + "chatHistory_threadId_chatThread_id_fk": { + "name": "chatHistory_threadId_chatThread_id_fk", + "tableFrom": "chatHistory", + "tableTo": "chatThread", + "columnsFrom": [ + "threadId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "chatThread": { + "name": "chatThread", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "firstMessage": { + "name": "firstMessage", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "chatThread_user_idx": { + "name": "chatThread_user_idx", + "columns": [ + "userId" + ], + "isUnique": false + } + }, + "foreignKeys": { + "chatThread_userId_user_id_fk": { + "name": "chatThread_userId_user_id_fk", + "tableFrom": "chatThread", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "contentToSpace": { + "name": "contentToSpace", + "columns": { + "contentId": { + "name": "contentId", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "spaceId": { + "name": "spaceId", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "contentToSpace_contentId_storedContent_id_fk": { + "name": "contentToSpace_contentId_storedContent_id_fk", + "tableFrom": "contentToSpace", + "tableTo": "storedContent", + "columnsFrom": [ + "contentId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "contentToSpace_spaceId_space_id_fk": { + "name": "contentToSpace_spaceId_space_id_fk", + "tableFrom": "contentToSpace", + "tableTo": "space", + "columnsFrom": [ + "spaceId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "contentToSpace_contentId_spaceId_pk": { + "columns": [ + "contentId", + "spaceId" + ], + "name": "contentToSpace_contentId_spaceId_pk" + } + }, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "space": { + "name": "space", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'none'" + }, + "user": { + "name": "user", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "numItems": { + "name": "numItems", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + } + }, + "indexes": { + "space_name_unique": { + "name": "space_name_unique", + "columns": [ + "name" + ], + "isUnique": true + }, + "spaces_name_idx": { + "name": "spaces_name_idx", + "columns": [ + "name" + ], + "isUnique": false + }, + "spaces_user_idx": { + "name": "spaces_user_idx", + "columns": [ + "user" + ], + "isUnique": false + } + }, + "foreignKeys": { + "space_user_user_id_fk": { + "name": "space_user_user_id_fk", + "tableFrom": "space", + "tableTo": "user", + "columnsFrom": [ + "user" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "spacesAccess": { + "name": "spacesAccess", + "columns": { + "spaceId": { + "name": "spaceId", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userEmail": { + "name": "userEmail", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "spacesAccess_spaceId_space_id_fk": { + "name": "spacesAccess_spaceId_space_id_fk", + "tableFrom": "spacesAccess", + "tableTo": "space", + "columnsFrom": [ + "spaceId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "spacesAccess_spaceId_userEmail_pk": { + "columns": [ + "spaceId", + "userEmail" + ], + "name": "spacesAccess_spaceId_userEmail_pk" + } + }, + "uniqueConstraints": {} + }, + "storedContent": { + "name": "storedContent", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "savedAt": { + "name": "savedAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "baseUrl": { + "name": "baseUrl", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ogImage": { + "name": "ogImage", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'page'" + }, + "image": { + "name": "image", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user": { + "name": "user", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "noteId": { + "name": "noteId", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "storedContent_baseUrl_unique": { + "name": "storedContent_baseUrl_unique", + "columns": [ + "baseUrl" + ], + "isUnique": true + }, + "storedContent_url_idx": { + "name": "storedContent_url_idx", + "columns": [ + "url" + ], + "isUnique": false + }, + "storedContent_savedAt_idx": { + "name": "storedContent_savedAt_idx", + "columns": [ + "savedAt" + ], + "isUnique": false + }, + "storedContent_title_idx": { + "name": "storedContent_title_idx", + "columns": [ + "title" + ], + "isUnique": false + }, + "storedContent_user_idx": { + "name": "storedContent_user_idx", + "columns": [ + "user" + ], + "isUnique": false + } + }, + "foreignKeys": { + "storedContent_user_user_id_fk": { + "name": "storedContent_user_user_id_fk", + "tableFrom": "storedContent", + "tableTo": "user", + "columnsFrom": [ + "user" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "users_email_idx": { + "name": "users_email_idx", + "columns": [ + "email" + ], + "isUnique": false + }, + "users_telegram_idx": { + "name": "users_telegram_idx", + "columns": [ + "telegramId" + ], + "isUnique": false + }, + "users_id_idx": { + "name": "users_id_idx", + "columns": [ + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "columns": [ + "identifier", + "token" + ], + "name": "verificationToken_identifier_token_pk" + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/apps/web/migrations/meta/_journal.json b/apps/web/migrations/meta/_journal.json index c7ab51e1..7af2b032 100644 --- a/apps/web/migrations/meta/_journal.json +++ b/apps/web/migrations/meta/_journal.json @@ -1,13 +1,20 @@ { - "version": "6", - "dialect": "sqlite", - "entries": [ - { - "idx": 0, - "version": "6", - "when": 1720360287793, - "tag": "0000_exotic_sway", - "breakpoints": true - } - ] -} + "version": "6", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1720360287793, + "tag": "0000_exotic_sway", + "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1721329604476, + "tag": "0001_nervous_longshot", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/apps/web/package.json b/apps/web/package.json index ed3eec11..3699d02d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -23,6 +23,7 @@ "@radix-ui/react-slot": "^1.1.0", "@sentry/nextjs": "^8", "cmdk": "^1.0.0", + "drizzle-kit": "^0.23.0", "lowlight": "^3.1.0", "million": "^3.1.6", "next": "^14.1.1", diff --git a/apps/web/server/db/schema.ts b/apps/web/server/db/schema.ts index ae293a91..8d6157e9 100644 --- a/apps/web/server/db/schema.ts +++ b/apps/web/server/db/schema.ts @@ -193,7 +193,8 @@ export const chatThreads = createTable( userId: text("userId") .notNull() .references(() => users.id, { onDelete: "cascade" }), - }, + createdAt: integer("createdAt").notNull().$defaultFn(() => Math.floor(Date.now() / 1000)), // Use Unix timestamp + }, (thread) => ({ userIdx: index("chatThread_user_idx").on(thread.userId), }), diff --git a/bun.lockb b/bun.lockb index ee0e6c3544d4005383371d67ae0454e87a5f1b04..c388a6af17d5cecad5e87bd80b7274b9553136a5 100755 GIT binary patch delta 27643 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 KUG6LR;{O1xGnWJa delta 28520 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