aboutsummaryrefslogtreecommitdiff
path: root/apps/web/src
diff options
context:
space:
mode:
authorDhravya <[email protected]>2024-05-21 22:47:33 -0500
committerDhravya <[email protected]>2024-05-21 22:47:33 -0500
commita4f566aaa085ce2a871f12070f932fa7da557316 (patch)
treee8ff7e3eb0a27ef47300f261975afdefae093b32 /apps/web/src
parentfooter fix: Arrow color should be consistent, no need for stroke (diff)
downloadsupermemory-a4f566aaa085ce2a871f12070f932fa7da557316.tar.xz
supermemory-a4f566aaa085ce2a871f12070f932fa7da557316.zip
format documents
Diffstat (limited to 'apps/web/src')
-rw-r--r--apps/web/src/actions/db.ts530
-rw-r--r--apps/web/src/app/api/chat/route.ts74
-rw-r--r--apps/web/src/app/globals.css32
-rw-r--r--apps/web/src/components/ChatMessage.tsx40
-rw-r--r--apps/web/src/components/MemoryDrawer.tsx24
-rw-r--r--apps/web/src/components/Sidebar/DeleteConfirmation.tsx48
-rw-r--r--apps/web/src/components/Sidebar/ExpandedSpace.tsx325
-rw-r--r--apps/web/src/contexts/MemoryContext.tsx157
-rw-r--r--apps/web/src/lib/utils.ts26
9 files changed, 681 insertions, 575 deletions
diff --git a/apps/web/src/actions/db.ts b/apps/web/src/actions/db.ts
index 59899639..59eb8976 100644
--- a/apps/web/src/actions/db.ts
+++ b/apps/web/src/actions/db.ts
@@ -10,7 +10,17 @@ import {
StoredContent,
} from "@/server/db/schema";
import { SearchResult } from "@/contexts/MemoryContext";
-import { like, eq, and, sql, exists, asc, notExists, inArray, notInArray } from "drizzle-orm";
+import {
+ like,
+ eq,
+ and,
+ sql,
+ exists,
+ asc,
+ notExists,
+ inArray,
+ notInArray,
+} from "drizzle-orm";
import { union } from "drizzle-orm/sqlite-core";
import { env } from "@/env";
@@ -20,10 +30,10 @@ export async function searchMemoriesAndSpaces(
opts?: {
filter?: { memories?: boolean; spaces?: boolean };
range?: { offset: number; limit: number };
- memoriesRelativeToSpace?: {
- fromSpaces?: number[];
- notInSpaces?: number[];
- }
+ memoriesRelativeToSpace?: {
+ fromSpaces?: number[];
+ notInSpaces?: number[];
+ };
},
): Promise<SearchResult[]> {
const user = await getUser();
@@ -32,26 +42,50 @@ export async function searchMemoriesAndSpaces(
return [];
}
- const defaultWhere = and(
- eq(storedContent.user, user.id),
- like(storedContent.title, `%${query}%`),
- )
- const extraWheres = []
-
- if (opts?.memoriesRelativeToSpace) {
- if (opts.memoriesRelativeToSpace.fromSpaces) {
- extraWheres.push(exists(db.select().from(contentToSpace).where(and(
- eq(contentToSpace.contentId, storedContent.id),
- inArray(contentToSpace.spaceId, opts.memoriesRelativeToSpace.fromSpaces)
- ))))
- }
- if (opts.memoriesRelativeToSpace.notInSpaces) {
- extraWheres.push(notExists(db.select().from(contentToSpace).where(and(
- eq(contentToSpace.contentId, storedContent.id),
- inArray(contentToSpace.spaceId, opts.memoriesRelativeToSpace.notInSpaces)
- ))))
- }
- }
+ const defaultWhere = and(
+ eq(storedContent.user, user.id),
+ like(storedContent.title, `%${query}%`),
+ );
+ const extraWheres = [];
+
+ if (opts?.memoriesRelativeToSpace) {
+ if (opts.memoriesRelativeToSpace.fromSpaces) {
+ extraWheres.push(
+ exists(
+ db
+ .select()
+ .from(contentToSpace)
+ .where(
+ and(
+ eq(contentToSpace.contentId, storedContent.id),
+ inArray(
+ contentToSpace.spaceId,
+ opts.memoriesRelativeToSpace.fromSpaces,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+ if (opts.memoriesRelativeToSpace.notInSpaces) {
+ extraWheres.push(
+ notExists(
+ db
+ .select()
+ .from(contentToSpace)
+ .where(
+ and(
+ eq(contentToSpace.contentId, storedContent.id),
+ inArray(
+ contentToSpace.spaceId,
+ opts.memoriesRelativeToSpace.notInSpaces,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+ }
try {
let searchMemoriesQuery = db
@@ -62,8 +96,11 @@ export async function searchMemoriesAndSpaces(
})
.from(storedContent)
.where(
- extraWheres.length == 2 ? and(and(...extraWheres), defaultWhere) :
- extraWheres.length == 1 ? and(...extraWheres, defaultWhere) : defaultWhere
+ extraWheres.length == 2
+ ? and(and(...extraWheres), defaultWhere)
+ : extraWheres.length == 1
+ ? and(...extraWheres, defaultWhere)
+ : defaultWhere,
)
.orderBy(asc(storedContent.savedAt));
@@ -105,19 +142,24 @@ export async function searchMemoriesAndSpaces(
}
export async function getMemoriesFromUrl(urls: string[]) {
-
const user = await getUser();
if (!user) {
return [];
}
- return urls.length > 0 ? await db.select()
- .from(storedContent)
- .where(and(
- inArray(storedContent.url, urls),
- eq(storedContent.user, user.id)
- )).all() : []
+ return urls.length > 0
+ ? await db
+ .select()
+ .from(storedContent)
+ .where(
+ and(
+ inArray(storedContent.url, urls),
+ eq(storedContent.user, user.id),
+ ),
+ )
+ .all()
+ : [];
}
async function getUser() {
@@ -154,20 +196,18 @@ async function getUser() {
}
export async function getSpace(id: number) {
-
const user = await getUser();
if (!user) {
return null;
}
-
- return (await db.select()
- .from(space)
- .where(and(
- eq(space.id, id),
- eq(space.user, user.id)
- )))[0]
+ return (
+ await db
+ .select()
+ .from(space)
+ .where(and(eq(space.id, id), eq(space.user, user.id)))
+ )[0];
}
export async function addSpace(name: string, memories: number[]) {
@@ -205,35 +245,30 @@ export async function addSpace(name: string, memories: number[]) {
}
export async function fetchContent(id: number) {
-
-
const user = await getUser();
if (!user) {
return null;
}
- const fetchedMemory = await db.select()
- .from(storedContent)
- .where(and(
- eq(storedContent.id, id),
- eq(storedContent.user, user.id)
- ));
-
- const memory = fetchedMemory.length > 0 ? fetchedMemory[0] : null
-
- const spaces = memory ? await db.select()
- .from(contentToSpace)
- .where(
- eq(contentToSpace.contentId, memory.id)
- ) : []
-
-
- return {
- memory,
- spaces: spaces.map(s => s.spaceId)
- }
+ const fetchedMemory = await db
+ .select()
+ .from(storedContent)
+ .where(and(eq(storedContent.id, id), eq(storedContent.user, user.id)));
+ const memory = fetchedMemory.length > 0 ? fetchedMemory[0] : null;
+
+ const spaces = memory
+ ? await db
+ .select()
+ .from(contentToSpace)
+ .where(eq(contentToSpace.contentId, memory.id))
+ : [];
+
+ return {
+ memory,
+ spaces: spaces.map((s) => s.spaceId),
+ };
}
export async function fetchContentForSpace(
@@ -243,7 +278,6 @@ export async function fetchContentForSpace(
limit: number;
},
) {
-
const user = await getUser();
if (!user) {
@@ -260,19 +294,22 @@ export async function fetchContentForSpace(
.from(contentToSpace)
.where(
and(
- and(
- eq(contentToSpace.spaceId, spaceId),
- eq(contentToSpace.contentId, storedContent.id),
- ),
- exists(
- db.select()
- .from(space)
- .where(and(
- eq(space.user, user.id),
- eq(space.id, contentToSpace.spaceId)
- ))
- )
- )
+ and(
+ eq(contentToSpace.spaceId, spaceId),
+ eq(contentToSpace.contentId, storedContent.id),
+ ),
+ exists(
+ db
+ .select()
+ .from(space)
+ .where(
+ and(
+ eq(space.user, user.id),
+ eq(space.id, contentToSpace.spaceId),
+ ),
+ ),
+ ),
+ ),
),
),
)
@@ -293,46 +330,45 @@ export async function fetchFreeMemories(range?: {
return [];
}
- try {
- const query = db
- .select()
- .from(storedContent)
- .where(
- and(
- notExists(
- db
- .select()
- .from(contentToSpace)
- .where(eq(contentToSpace.contentId, storedContent.id)),
- ),
- eq(storedContent.user, user.id),
- ),
- )
- .orderBy(asc(storedContent.savedAt));
-
- return range
- ? await query.limit(range.limit).offset(range.offset)
- : await query.all();
- } catch {
- return []
- }
+ try {
+ const query = db
+ .select()
+ .from(storedContent)
+ .where(
+ and(
+ notExists(
+ db
+ .select()
+ .from(contentToSpace)
+ .where(eq(contentToSpace.contentId, storedContent.id)),
+ ),
+ eq(storedContent.user, user.id),
+ ),
+ )
+ .orderBy(asc(storedContent.savedAt));
+ return range
+ ? await query.limit(range.limit).offset(range.offset)
+ : await query.all();
+ } catch {
+ return [];
+ }
}
export async function updateSpaceTitle(id: number, title: string) {
-
const user = await getUser();
if (!user) {
return null;
}
- return (await db.update(space).set({ name: title }).where(
- and(
- eq(space.id, id),
- eq(space.user, user.id)
- )
- ).returning())[0];
+ return (
+ await db
+ .update(space)
+ .set({ name: title })
+ .where(and(eq(space.id, id), eq(space.user, user.id)))
+ .returning()
+ )[0];
}
export async function addMemory(
@@ -387,16 +423,19 @@ export async function addMemory(
.returning()
: [];
- if (content.type === 'note') {
- addedMemory = (await db.update(storedContent)
- .set({
- url: addedMemory.url + addedMemory.id
- })
- .where(eq(storedContent.id, addedMemory.id))
- .returning())[0]
- }
+ if (content.type === "note") {
+ addedMemory = (
+ await db
+ .update(storedContent)
+ .set({
+ url: addedMemory.url + addedMemory.id,
+ })
+ .where(eq(storedContent.id, addedMemory.id))
+ .returning()
+ )[0];
+ }
- console.log("adding with:", `${addedMemory.url}-${user.email}`)
+ console.log("adding with:", `${addedMemory.url}-${user.email}`);
// Add to vectorDB
const res = (await Promise.race([
fetch("https://cf-ai-backend.dhravya.workers.dev/add", {
@@ -423,30 +462,41 @@ export async function addMemory(
}
export async function addContentInSpaces(id: number, contents: number[]) {
-
const user = await getUser();
if (!user) {
return null;
}
-
- const data = contents.length > 0 ? await db.insert(contentToSpace).values(contents.map(i => ({
- spaceId: id,
- contentId: i
- }))).returning() : []
- return data
+ const data =
+ contents.length > 0
+ ? await db
+ .insert(contentToSpace)
+ .values(
+ contents.map((i) => ({
+ spaceId: id,
+ contentId: i,
+ })),
+ )
+ .returning()
+ : [];
+ return data;
}
export async function updateMemory(
- id: number,
- { title, content, spaces, removedFromSpaces: removeSpaces }: {
- title?: string;
- content?: string;
- spaces?: number[];
- removedFromSpaces?: number[];
- }
+ id: number,
+ {
+ title,
+ content,
+ spaces,
+ removedFromSpaces: removeSpaces,
+ }: {
+ title?: string;
+ content?: string;
+ spaces?: number[];
+ removedFromSpaces?: number[];
+ },
) {
const user = await getUser();
@@ -454,96 +504,95 @@ export async function updateMemory(
return null;
}
- let updatedMemory: StoredContent | null = null;
+ let updatedMemory: StoredContent | null = null;
- if (title && content) {
+ if (title && content) {
+ const [prev] = await db
+ .select()
+ .from(storedContent)
+ .where(and(eq(storedContent.user, user.id), eq(storedContent.id, id)));
- const [prev] = await db.select()
- .from(storedContent)
- .where(and(
- eq(storedContent.user, user.id),
- eq(storedContent.id, id)
- ));
-
- if (!prev) {
- return null
- }
+ if (!prev) {
+ return null;
+ }
- const newContent = {
- ...(title ? { title }: {}),
- ...(content ? { content }: {}),
- }
+ const newContent = {
+ ...(title ? { title } : {}),
+ ...(content ? { content } : {}),
+ };
+
+ const updated = {
+ ...newContent,
+ ...prev,
+ };
+
+ console.log("adding with:", `${updated.url}-${user.email}`);
+ // Add to vectorDB
+ const res = (await Promise.race([
+ fetch("https://cf-ai-backend.dhravya.workers.dev/edit", {
+ method: "POST",
+ headers: {
+ "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
+ },
+ body: JSON.stringify({
+ pageContent: updated.content,
+ title: updated.title,
+ url: updated.url,
+ user: user.email,
+ uniqueUrl: updated.url,
+ }),
+ }),
+ new Promise((_, reject) =>
+ setTimeout(() => reject(new Error("Request timed out")), 40000),
+ ),
+ ])) as Response;
- const updated = {
- ...newContent,
- ...prev
- }
+ [updatedMemory] = await db
+ .update(storedContent)
+ .set(newContent)
+ .where(and(eq(storedContent.id, id), eq(storedContent.user, user.id)))
+ .returning();
- console.log("adding with:", `${updated.url}-${user.email}`)
- // Add to vectorDB
- const res = (await Promise.race([
- fetch("https://cf-ai-backend.dhravya.workers.dev/edit", {
- method: "POST",
- headers: {
- "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
- },
- body: JSON.stringify({
- pageContent: updated.content,
- title: updated.title,
- url: updated.url,
- user: user.email,
- uniqueUrl: updated.url,
- }),
- }),
- new Promise((_, reject) =>
- setTimeout(() => reject(new Error("Request timed out")), 40000),
- ),
- ])) as Response;
+ console.log(updatedMemory, newContent);
+ }
- [updatedMemory] = await db
- .update(storedContent)
- .set(newContent)
- .where(and(
- eq(storedContent.id, id),
- eq(storedContent.user, user.id)
- ))
- .returning();
-
- console.log(updatedMemory, newContent)
- }
-
- if (!updatedMemory) {
- [updatedMemory] = await db
- .select()
- .from(storedContent)
- .where(and(
- eq(storedContent.id, id),
- eq(storedContent.user, user.id)
- ))
- }
-
- const removedFromSpaces = removeSpaces ?
- removeSpaces.length > 0 ?
- await db.delete(contentToSpace)
- .where(and(
- inArray(contentToSpace.spaceId, removeSpaces),
- eq(contentToSpace.contentId, id)
- )).returning() : []
- : spaces ?
- spaces.length > 0 ?
- await db.delete(contentToSpace)
- .where(and(
- notInArray(contentToSpace.spaceId, spaces),
- eq(contentToSpace.contentId, id)
- )).returning()
- : await db.delete(contentToSpace)
- .where(
- eq(contentToSpace.contentId, id)
- )
- : [];
+ if (!updatedMemory) {
+ [updatedMemory] = await db
+ .select()
+ .from(storedContent)
+ .where(and(eq(storedContent.id, id), eq(storedContent.user, user.id)));
+ }
+
+ const removedFromSpaces = removeSpaces
+ ? removeSpaces.length > 0
+ ? await db
+ .delete(contentToSpace)
+ .where(
+ and(
+ inArray(contentToSpace.spaceId, removeSpaces),
+ eq(contentToSpace.contentId, id),
+ ),
+ )
+ .returning()
+ : []
+ : spaces
+ ? spaces.length > 0
+ ? await db
+ .delete(contentToSpace)
+ .where(
+ and(
+ notInArray(contentToSpace.spaceId, spaces),
+ eq(contentToSpace.contentId, id),
+ ),
+ )
+ .returning()
+ : await db
+ .delete(contentToSpace)
+ .where(eq(contentToSpace.contentId, id))
+ : [];
const addedToSpaces =
- (spaces && spaces.length > 0)
+ spaces && spaces.length > 0
? await db
.insert(contentToSpace)
.values(
@@ -552,20 +601,24 @@ export async function updateMemory(
spaceId: s,
})),
)
- .onConflictDoNothing()
+ .onConflictDoNothing()
.returning()
: [];
- const resultedSpaces = (await db.select()
- .from(contentToSpace)
- .where(eq(contentToSpace.contentId, id))
- .all()).map(i => i.spaceId) ?? [];
+ const resultedSpaces =
+ (
+ await db
+ .select()
+ .from(contentToSpace)
+ .where(eq(contentToSpace.contentId, id))
+ .all()
+ ).map((i) => i.spaceId) ?? [];
return {
memory: updatedMemory,
addedToSpaces,
- removedFromSpaces,
- resultedSpaces
+ removedFromSpaces,
+ resultedSpaces,
};
}
@@ -600,25 +653,24 @@ export async function deleteMemory(id: number) {
.where(and(eq(storedContent.user, user.id), eq(storedContent.id, id)))
.returning();
- if (deleted) {
-
- console.log("adding with:", `${deleted.url}-${user.email}`)
- const res = (await Promise.race([
- fetch(`https://cf-ai-backend.dhravya.workers.dev/delete` , {
- method: "DELETE",
- headers: {
- "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
- },
- body: JSON.stringify({
- websiteUrl: deleted.url,
- user: user.email
- })
- }),
- new Promise((_, reject) =>
- setTimeout(() => reject(new Error("Request timed out")), 40000),
- ),
- ])) as Response;
- }
+ if (deleted) {
+ console.log("adding with:", `${deleted.url}-${user.email}`);
+ const res = (await Promise.race([
+ fetch(`https://cf-ai-backend.dhravya.workers.dev/delete`, {
+ method: "DELETE",
+ headers: {
+ "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
+ },
+ body: JSON.stringify({
+ websiteUrl: deleted.url,
+ user: user.email,
+ }),
+ }),
+ new Promise((_, reject) =>
+ setTimeout(() => reject(new Error("Request timed out")), 40000),
+ ),
+ ])) as Response;
+ }
return deleted;
}
diff --git a/apps/web/src/app/api/chat/route.ts b/apps/web/src/app/api/chat/route.ts
index 374f39cd..c815070b 100644
--- a/apps/web/src/app/api/chat/route.ts
+++ b/apps/web/src/app/api/chat/route.ts
@@ -69,43 +69,41 @@ export async function POST(req: NextRequest) {
});
}
- try {
- const resp = await fetch(
- `https://cf-ai-backend.dhravya.workers.dev/chat?q=${query}&user=${session.user.email ?? session.user.name}&sourcesOnly=${sourcesOnly}&spaces=${spaces}`,
- {
- headers: {
- "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
- },
- method: "POST",
- body: JSON.stringify({
- chatHistory: chatHistory.chatHistory ?? [],
- }),
- },
- );
-
- console.log("sourcesOnly", sourcesOnly);
-
- if (sourcesOnly == "true") {
- const data = await resp.json();
- console.log("data", data);
- return new Response(JSON.stringify(data), { status: 200 });
- }
-
- if (resp.status !== 200 || !resp.ok) {
- const errorData = await resp.json();
- console.log(errorData);
- return new Response(
- JSON.stringify({ message: "Error in CF function", error: errorData }),
- { status: resp.status },
- );
- }
-
- // Stream the response back to the client
- const { readable, writable } = new TransformStream();
- resp && resp.body!.pipeTo(writable);
-
- return new Response(readable, { status: 200 });
- } catch {
- }
+ try {
+ const resp = await fetch(
+ `https://cf-ai-backend.dhravya.workers.dev/chat?q=${query}&user=${session.user.email ?? session.user.name}&sourcesOnly=${sourcesOnly}&spaces=${spaces}`,
+ {
+ headers: {
+ "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
+ },
+ method: "POST",
+ body: JSON.stringify({
+ chatHistory: chatHistory.chatHistory ?? [],
+ }),
+ },
+ );
+
+ console.log("sourcesOnly", sourcesOnly);
+
+ if (sourcesOnly == "true") {
+ const data = await resp.json();
+ console.log("data", data);
+ return new Response(JSON.stringify(data), { status: 200 });
+ }
+
+ if (resp.status !== 200 || !resp.ok) {
+ const errorData = await resp.json();
+ console.log(errorData);
+ return new Response(
+ JSON.stringify({ message: "Error in CF function", error: errorData }),
+ { status: resp.status },
+ );
+ }
+
+ // Stream the response back to the client
+ const { readable, writable } = new TransformStream();
+ resp && resp.body!.pipeTo(writable);
+ return new Response(readable, { status: 200 });
+ } catch {}
}
diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css
index 9a543be6..bed9278b 100644
--- a/apps/web/src/app/globals.css
+++ b/apps/web/src/app/globals.css
@@ -58,22 +58,22 @@ body {
}
.bottom-padding {
- bottom: 20vh;
- bottom: 20dvh;
+ bottom: 20vh;
+ bottom: 20dvh;
}
@media (min-width: 768px) {
- .bottom-padding {
- bottom: 0;
- }
+ .bottom-padding {
+ bottom: 0;
+ }
}
-.chat-answer code {
- @apply bg-rgray-3 text-wrap rounded-md border border-rgray-5 p-1 text-sm text-rgray-11;
+.chat-answer code {
+ @apply bg-rgray-3 border-rgray-5 text-rgray-11 text-wrap rounded-md border p-1 text-sm;
}
.novel-editor pre {
- @apply bg-rgray-3 rounded-md border border-rgray-5 p-4 my-5 text-sm text-rgray-11;
+ @apply bg-rgray-3 border-rgray-5 text-rgray-11 my-5 rounded-md border p-4 text-sm;
}
.chat-answer h1 {
@@ -81,19 +81,19 @@ body {
}
.chat-answer a {
- @apply underline underline-offset-1 opacity-90 hover:opacity-100;
+ @apply underline underline-offset-1 opacity-90 hover:opacity-100;
}
.chat-answer img {
- @apply rounded-md font-medium my-5;
+ @apply my-5 rounded-md font-medium;
}
.tippy-box {
- @apply bg-rgray-3 text-rgray-11 border border-rgray-5 rounded-md py-0;
+ @apply bg-rgray-3 text-rgray-11 border-rgray-5 rounded-md border py-0;
}
.tippy-content #slash-command {
- @apply text-rgray-11 bg-transparent border-none;
+ @apply text-rgray-11 border-none bg-transparent;
}
#slash-command button {
@@ -101,18 +101,18 @@ body {
}
#slash-command button div:first-child {
- @apply text-rgray-11 bg-rgray-4 border-rgray-5 ;
+ @apply text-rgray-11 bg-rgray-4 border-rgray-5;
}
#slash-command button.novel-bg-stone-100 {
@apply bg-rgray-1;
}
-.novel-editor [data-type=taskList] > li {
+.novel-editor [data-type="taskList"] > li {
@apply my-0;
}
-.novel-editor input[type=checkbox] {
+.novel-editor input[type="checkbox"] {
@apply accent-rgray-4 rounded-md;
background: var(--gray-4) !important;
@@ -120,7 +120,7 @@ body {
}
.novel-editor .is-empty::before {
- content: 'Press \'/\' for commands' !important;
+ content: "Press '/' for commands" !important;
}
.novel-editor h1 {
diff --git a/apps/web/src/components/ChatMessage.tsx b/apps/web/src/components/ChatMessage.tsx
index 0ab22271..58ef9870 100644
--- a/apps/web/src/components/ChatMessage.tsx
+++ b/apps/web/src/components/ChatMessage.tsx
@@ -12,7 +12,7 @@ export function ChatAnswer({
loading = false,
}: {
children: string;
- sources?: ChatHistory['answer']['sources'];
+ sources?: ChatHistory["answer"]["sources"];
loading?: boolean;
}) {
return (
@@ -30,25 +30,25 @@ export function ChatAnswer({
<SpaceIcon className="h-6 w-6 -translate-y-[2px]" />
Related Memories
</h1>
- <div className="animate-fade-in gap-1 -mt-3 flex items-center justify-start opacity-0 [animation-duration:1s]">
- {sources?.map((source) => source.isNote ? (
- <button
- className="bg-rgray-3 flex items-center justify-center gap-2 rounded-full py-1 pl-2 pr-3 text-sm"
- >
- <Text className="w-4 h-4" />
- {source.source}
- </button>
- ) : (
- <a
- className="bg-rgray-3 flex items-center justify-center gap-2 rounded-full py-1 pl-2 pr-3 text-sm"
- key={source.source}
- href={source.source}
- target="_blank"
- >
- <Globe className="h-4 w-4" />
- {cleanUrl(source.source)}
- </a>
- ))}
+ <div className="animate-fade-in -mt-3 flex items-center justify-start gap-1 opacity-0 [animation-duration:1s]">
+ {sources?.map((source) =>
+ source.isNote ? (
+ <button className="bg-rgray-3 flex items-center justify-center gap-2 rounded-full py-1 pl-2 pr-3 text-sm">
+ <Text className="h-4 w-4" />
+ {source.source}
+ </button>
+ ) : (
+ <a
+ className="bg-rgray-3 flex items-center justify-center gap-2 rounded-full py-1 pl-2 pr-3 text-sm"
+ key={source.source}
+ href={source.source}
+ target="_blank"
+ >
+ <Globe className="h-4 w-4" />
+ {cleanUrl(source.source)}
+ </a>
+ ),
+ )}
</div>
</>
)}
diff --git a/apps/web/src/components/MemoryDrawer.tsx b/apps/web/src/components/MemoryDrawer.tsx
index a71d3d19..14283281 100644
--- a/apps/web/src/components/MemoryDrawer.tsx
+++ b/apps/web/src/components/MemoryDrawer.tsx
@@ -32,18 +32,18 @@ export function MemoryDrawer({ className, hide = false, ...props }: Props) {
)}
handle={false}
>
- <button
- onClick={() =>
- setActiveSnapPoint((prev) => (prev === 0.9 ? 0.1 : 0.9))
- }
- className="bg-rgray-4 border-rgray-6 text-rgray-11 absolute left-1/2 top-0 flex w-fit -translate-x-1/2 -translate-y-1/2 items-center justify-center gap-2 rounded-md border px-3 py-2"
- >
- <MemoryIcon className="h-7 w-7" />
- Memories
- </button>
- <div className="w-full h-full overflow-y-auto">
- <MemoriesBar isOpen={true} />
- </div>
+ <button
+ onClick={() =>
+ setActiveSnapPoint((prev) => (prev === 0.9 ? 0.1 : 0.9))
+ }
+ className="bg-rgray-4 border-rgray-6 text-rgray-11 absolute left-1/2 top-0 flex w-fit -translate-x-1/2 -translate-y-1/2 items-center justify-center gap-2 rounded-md border px-3 py-2"
+ >
+ <MemoryIcon className="h-7 w-7" />
+ Memories
+ </button>
+ <div className="h-full w-full overflow-y-auto">
+ <MemoriesBar isOpen={true} />
+ </div>
</DrawerContent>
<DrawerOverlay className="relative bg-transparent" />
</Drawer>
diff --git a/apps/web/src/components/Sidebar/DeleteConfirmation.tsx b/apps/web/src/components/Sidebar/DeleteConfirmation.tsx
index 9324b147..7955df0d 100644
--- a/apps/web/src/components/Sidebar/DeleteConfirmation.tsx
+++ b/apps/web/src/components/Sidebar/DeleteConfirmation.tsx
@@ -1,18 +1,30 @@
-import { Dialog, DialogContent, DialogTrigger, DialogTitle, DialogDescription, DialogClose, DialogFooter } from "../ui/dialog";
+import {
+ Dialog,
+ DialogContent,
+ DialogTrigger,
+ DialogTitle,
+ DialogDescription,
+ DialogClose,
+ DialogFooter,
+} from "../ui/dialog";
-export default function DeleteConfirmation({ onDelete, trigger = true, children }: { trigger?: boolean, onDelete?: () => void; children: React.ReactNode }) {
- return (
- <Dialog>
- {trigger ? (
- <DialogTrigger asChild>
- {children}
- </DialogTrigger>
- ) : (
- <>
- {children}
- </>
- )}
- <DialogContent>
+export default function DeleteConfirmation({
+ onDelete,
+ trigger = true,
+ children,
+}: {
+ trigger?: boolean;
+ onDelete?: () => void;
+ children: React.ReactNode;
+}) {
+ return (
+ <Dialog>
+ {trigger ? (
+ <DialogTrigger asChild>{children}</DialogTrigger>
+ ) : (
+ <>{children}</>
+ )}
+ <DialogContent>
<DialogTitle className="text-xl">Are you sure?</DialogTitle>
<DialogDescription className="text-md">
You will not be able to recover this it.
@@ -21,7 +33,7 @@ export default function DeleteConfirmation({ onDelete, trigger = true, children
<DialogClose
type={undefined}
onClick={onDelete}
- className="ml-auto flex items-center justify-center rounded-md text-red-400 bg-red-100/10 px-3 py-2 transition hover:bg-red-100/5 focus-visible:bg-red-100/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-100/30"
+ className="ml-auto flex items-center justify-center rounded-md bg-red-100/10 px-3 py-2 text-red-400 transition hover:bg-red-100/5 focus-visible:bg-red-100/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-100/30"
>
Delete
</DialogClose>
@@ -29,7 +41,7 @@ export default function DeleteConfirmation({ onDelete, trigger = true, children
Cancel
</DialogClose>
</DialogFooter>
- </DialogContent>
- </Dialog>
- )
+ </DialogContent>
+ </Dialog>
+ );
}
diff --git a/apps/web/src/components/Sidebar/ExpandedSpace.tsx b/apps/web/src/components/Sidebar/ExpandedSpace.tsx
index 9e46f3fb..55d3f3f8 100644
--- a/apps/web/src/components/Sidebar/ExpandedSpace.tsx
+++ b/apps/web/src/components/Sidebar/ExpandedSpace.tsx
@@ -1,33 +1,52 @@
-import { fetchContentForSpace, getSpace } from "@/actions/db"
-import { useMemory } from "@/contexts/MemoryContext"
-import { StoredContent, StoredSpace } from '@/server/db/schema'
-import { Edit3, Loader, Plus, Search, Sparkles, StickyNote, Text, Undo2 } from "lucide-react"
-import { useEffect, useRef, useState } from "react"
-import { Input, InputWithIcon } from "../ui/input"
-import { useDebounce } from "@/hooks/useDebounce"
-import { useAutoAnimate } from "@formkit/auto-animate/react"
-import { AddMemoryModal, MemoryItem } from "./MemoriesBar"
-import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu"
-import { DialogTrigger } from "../ui/dialog"
-
-export function ExpandedSpace({ spaceId, back }: { spaceId: number, back: () => void; }) {
-
- const { updateMemory, updateSpace, search } = useMemory()
+import { fetchContentForSpace, getSpace } from "@/actions/db";
+import { useMemory } from "@/contexts/MemoryContext";
+import { StoredContent, StoredSpace } from "@/server/db/schema";
+import {
+ Edit3,
+ Loader,
+ Plus,
+ Search,
+ Sparkles,
+ StickyNote,
+ Text,
+ Undo2,
+} from "lucide-react";
+import { useEffect, useRef, useState } from "react";
+import { Input, InputWithIcon } from "../ui/input";
+import { useDebounce } from "@/hooks/useDebounce";
+import { useAutoAnimate } from "@formkit/auto-animate/react";
+import { AddMemoryModal, MemoryItem } from "./MemoriesBar";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "../ui/dropdown-menu";
+import { DialogTrigger } from "../ui/dialog";
+
+export function ExpandedSpace({
+ spaceId,
+ back,
+}: {
+ spaceId: number;
+ back: () => void;
+}) {
+ const { updateMemory, updateSpace, search } = useMemory();
const [parent, enableAnimations] = useAutoAnimate();
- const inputRef = useRef<HTMLInputElement>(null);
+ const inputRef = useRef<HTMLInputElement>(null);
- const [contentForSpace, setContentForSpace] = useState<StoredContent[]>([])
+ const [contentForSpace, setContentForSpace] = useState<StoredContent[]>([]);
- const [lastUpdatedTitle, setLastUpdatedTitle] = useState<string | null>(null);
+ const [lastUpdatedTitle, setLastUpdatedTitle] = useState<string | null>(null);
- const [title, setTitle] = useState<string>('');
- const debouncedTitle = useDebounce(title, 500)
+ const [title, setTitle] = useState<string>("");
+ const debouncedTitle = useDebounce(title, 500);
- const [loading, setLoading] = useState(true)
+ const [loading, setLoading] = useState(true);
- const [saveLoading, setSaveLoading] = useState(false);
+ const [saveLoading, setSaveLoading] = useState(false);
const [searchQuery, setSearcyQuery] = useState("");
const [searchLoading, setSearchLoading] = useState(false);
@@ -35,33 +54,34 @@ export function ExpandedSpace({ spaceId, back }: { spaceId: number, back: () =>
const [searchResults, setSearchResults] = useState<StoredContent[]>([]);
-
const [addMemoryState, setAddMemoryState] = useState<
"page" | "note" | "existing-memory" | "space" | null
>(null);
- const [isDropdownOpen, setIsDropdownOpen] = useState(false);
-
-
- useEffect(() => {
- (async () => {
- const title = (await getSpace(spaceId))?.name ?? "";
- setTitle(title)
- setLastUpdatedTitle(title)
- setContentForSpace((await fetchContentForSpace(spaceId)) ?? [])
- setLoading(false)
- })();
- }, [])
-
- useEffect(() => {
- if (debouncedTitle.trim().length < 1 || debouncedTitle.trim() === lastUpdatedTitle?.trim()) return
- (async () => {
- setSaveLoading(true)
- await updateSpace(spaceId, debouncedTitle.trim())
- setLastUpdatedTitle(debouncedTitle)
- setSaveLoading(false)
- })()
- }, [debouncedTitle])
+ const [isDropdownOpen, setIsDropdownOpen] = useState(false);
+
+ useEffect(() => {
+ (async () => {
+ const title = (await getSpace(spaceId))?.name ?? "";
+ setTitle(title);
+ setLastUpdatedTitle(title);
+ setContentForSpace((await fetchContentForSpace(spaceId)) ?? []);
+ setLoading(false);
+ })();
+ }, []);
+ useEffect(() => {
+ if (
+ debouncedTitle.trim().length < 1 ||
+ debouncedTitle.trim() === lastUpdatedTitle?.trim()
+ )
+ return;
+ (async () => {
+ setSaveLoading(true);
+ await updateSpace(spaceId, debouncedTitle.trim());
+ setLastUpdatedTitle(debouncedTitle);
+ setSaveLoading(false);
+ })();
+ }, [debouncedTitle]);
useEffect(() => {
const q = query.trim();
@@ -73,56 +93,68 @@ export function ExpandedSpace({ spaceId, back }: { spaceId: number, back: () =>
setSearchLoading(true);
(async () => {
- setSearchResults((await search(q, {
- filter: { spaces: false },
- memoriesRelativeToSpace: {
- fromSpaces: [spaceId]
- }
- })).map(i => i.memory!));
+ setSearchResults(
+ (
+ await search(q, {
+ filter: { spaces: false },
+ memoriesRelativeToSpace: {
+ fromSpaces: [spaceId],
+ },
+ })
+ ).map((i) => i.memory!),
+ );
setSearchLoading(false);
})();
}, [query]);
-
- if (loading) {
- return (
- <div className="h-full w-full flex justify-center items-center">
- <Loader className="w-5 h-5 animate-spin" />
- </div>
- )
- }
+ if (loading) {
+ return (
+ <div className="flex h-full w-full items-center justify-center">
+ <Loader className="h-5 w-5 animate-spin" />
+ </div>
+ );
+ }
return (
<div className="text-rgray-11 flex w-full flex-col items-start py-8 text-left">
- <div className="px-8 flex justify-start items-center w-full gap-2">
- <button onClick={back} className="transition rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-rgray-3 focus-visible:ring-rgray-7">
- <Undo2 className="w-5 h-5" />
- </button>
- <Input
- ref={inputRef}
- data-error="false"
- className="w-full border-none p-0 text-xl ring-0 placeholder:text-white/30 placeholder:transition placeholder:duration-500 focus-visible:ring-0 data-[error=true]:placeholder:text-red-400"
- placeholder="Title of the space"
- data-modal-autofocus
- value={title}
- onChange={(e) => setTitle(e.target.value)}
- />
- <button onClick={() => {
- inputRef.current?.focus()
- inputRef.current?.animate({
- opacity: [1, 0.2, 1]
- }, {
- duration: 100
- })
- }} className="transition rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-rgray-3 focus-visible:ring-rgray-7">
- {saveLoading ? (
- <Loader className="w-5 h-5 opacity-70 animate-spin" />
- ) : (
- <Edit3 className="w-5 h-5 opacity-70" />
- )}
- </button>
- </div>
- <div className="px-8 w-full">
+ <div className="flex w-full items-center justify-start gap-2 px-8">
+ <button
+ onClick={back}
+ className="focus-visible:ring-offset-rgray-3 focus-visible:ring-rgray-7 rounded-sm transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2"
+ >
+ <Undo2 className="h-5 w-5" />
+ </button>
+ <Input
+ ref={inputRef}
+ data-error="false"
+ className="w-full border-none p-0 text-xl ring-0 placeholder:text-white/30 placeholder:transition placeholder:duration-500 focus-visible:ring-0 data-[error=true]:placeholder:text-red-400"
+ placeholder="Title of the space"
+ data-modal-autofocus
+ value={title}
+ onChange={(e) => setTitle(e.target.value)}
+ />
+ <button
+ onClick={() => {
+ inputRef.current?.focus();
+ inputRef.current?.animate(
+ {
+ opacity: [1, 0.2, 1],
+ },
+ {
+ duration: 100,
+ },
+ );
+ }}
+ className="focus-visible:ring-offset-rgray-3 focus-visible:ring-rgray-7 rounded-sm transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2"
+ >
+ {saveLoading ? (
+ <Loader className="h-5 w-5 animate-spin opacity-70" />
+ ) : (
+ <Edit3 className="h-5 w-5 opacity-70" />
+ )}
+ </button>
+ </div>
+ <div className="w-full px-8">
<InputWithIcon
placeholder="Search"
icon={
@@ -136,23 +168,28 @@ export function ExpandedSpace({ spaceId, back }: { spaceId: number, back: () =>
value={searchQuery}
onChange={(e) => setSearcyQuery(e.target.value)}
/>
- </div>
- <div className="w-full px-8 mt-2">
- <AddMemoryModal onAdd={(data) => {
- if (!data) {
- setLoading(true);
- (async () => {
- const title = (await getSpace(spaceId))?.name ?? "";
- setTitle(title)
- setLastUpdatedTitle(title)
- setContentForSpace((await fetchContentForSpace(spaceId)) ?? [])
- setLoading(false)
- })();
- } else if (Object.hasOwn(data, "url")) {
- const _data = data as StoredContent;
- setContentForSpace(prev => [...prev, _data])
- }
- }} data={{ space: { title, id: spaceId }, notInSpaces: [spaceId] }} defaultSpaces={[spaceId]} type={addMemoryState}>
+ </div>
+ <div className="mt-2 w-full px-8">
+ <AddMemoryModal
+ onAdd={(data) => {
+ if (!data) {
+ setLoading(true);
+ (async () => {
+ const title = (await getSpace(spaceId))?.name ?? "";
+ setTitle(title);
+ setLastUpdatedTitle(title);
+ setContentForSpace((await fetchContentForSpace(spaceId)) ?? []);
+ setLoading(false);
+ })();
+ } else if (Object.hasOwn(data, "url")) {
+ const _data = data as StoredContent;
+ setContentForSpace((prev) => [...prev, _data]);
+ }
+ }}
+ data={{ space: { title, id: spaceId }, notInSpaces: [spaceId] }}
+ defaultSpaces={[spaceId]}
+ type={addMemoryState}
+ >
<DropdownMenu open={isDropdownOpen} onOpenChange={setIsDropdownOpen}>
<DropdownMenuTrigger asChild>
<button className="focus-visible:bg-rgray-4 focus-visible:ring-rgray-7 hover:bg-rgray-4 ml-auto flex items-center justify-center rounded-md px-3 py-2 transition focus-visible:outline-none focus-visible:ring-2">
@@ -194,47 +231,57 @@ export function ExpandedSpace({ spaceId, back }: { spaceId: number, back: () =>
</DropdownMenuContent>
</DropdownMenu>
</AddMemoryModal>
- </div>
+ </div>
<div
ref={parent}
className="grid w-full grid-flow-row grid-cols-3 gap-1 px-2 py-5"
>
- {query.trim().length > 0 ? (
+ {query.trim().length > 0 ? (
<>
{searchResults.map((memory, i) => (
- <MemoryItem
- removeFromSpace={async () => {
- await updateMemory(memory.id, {
- removedFromSpaces: [spaceId]
- })
- setContentForSpace(prev => prev.filter(s => s.id !== memory.id))
- setSearchResults(prev => prev.filter(i => i.id !== memory.id))
- }}
- {...memory!}
- key={i}
- onDelete={() => {
- setContentForSpace(prev => prev.filter(s => s.id !== memory.id))
- setSearchResults(prev => prev.filter(i => i.id !== memory.id))
- }}
- />
+ <MemoryItem
+ removeFromSpace={async () => {
+ await updateMemory(memory.id, {
+ removedFromSpaces: [spaceId],
+ });
+ setContentForSpace((prev) =>
+ prev.filter((s) => s.id !== memory.id),
+ );
+ setSearchResults((prev) =>
+ prev.filter((i) => i.id !== memory.id),
+ );
+ }}
+ {...memory!}
+ key={i}
+ onDelete={() => {
+ setContentForSpace((prev) =>
+ prev.filter((s) => s.id !== memory.id),
+ );
+ setSearchResults((prev) =>
+ prev.filter((i) => i.id !== memory.id),
+ );
+ }}
+ />
))}
</>
- ) :
- contentForSpace.map(m => (
- <MemoryItem
- key={m.id}
- {...m}
- onDelete={() => setContentForSpace(prev => prev.filter(s => s.id !== m.id))}
- removeFromSpace={async () => {
- await updateMemory(m.id, {
- removedFromSpaces: [spaceId]
- })
- setContentForSpace(prev => prev.filter(s => s.id !== m.id))
- }}
- />
- ))
- }
- </div>
+ ) : (
+ contentForSpace.map((m) => (
+ <MemoryItem
+ key={m.id}
+ {...m}
+ onDelete={() =>
+ setContentForSpace((prev) => prev.filter((s) => s.id !== m.id))
+ }
+ removeFromSpace={async () => {
+ await updateMemory(m.id, {
+ removedFromSpaces: [spaceId],
+ });
+ setContentForSpace((prev) => prev.filter((s) => s.id !== m.id));
+ }}
+ />
+ ))
+ )}
+ </div>
</div>
- )
+ );
}
diff --git a/apps/web/src/contexts/MemoryContext.tsx b/apps/web/src/contexts/MemoryContext.tsx
index 5e58b6a6..09412465 100644
--- a/apps/web/src/contexts/MemoryContext.tsx
+++ b/apps/web/src/contexts/MemoryContext.tsx
@@ -36,9 +36,9 @@ export const MemoryContext = React.createContext<{
search: typeof searchMemoriesAndSpaces;
deleteSpace: typeof deleteSpace;
deleteMemory: typeof deleteMemory;
- updateMemory: typeof updateMemory;
- updateSpace: typeof updateSpaceTitle;
- addMemoriesToSpace: typeof addContentInSpaces;
+ updateMemory: typeof updateMemory;
+ updateSpace: typeof updateSpaceTitle;
+ addMemoriesToSpace: typeof addContentInSpaces;
}>({
spaces: [],
freeMemories: [],
@@ -50,7 +50,7 @@ export const MemoryContext = React.createContext<{
deleteSpace: (() => {}) as unknown as typeof deleteSpace,
updateMemory: (() => {}) as unknown as typeof updateMemory,
updateSpace: (() => {}) as unknown as typeof updateSpaceTitle,
- addMemoriesToSpace: (() => {}) as unknown as typeof addContentInSpaces,
+ addMemoriesToSpace: (() => {}) as unknown as typeof addContentInSpaces,
});
export const MemoryProvider: React.FC<
@@ -104,10 +104,10 @@ export const MemoryProvider: React.FC<
setSpaces((prev) => [...prev, addedSpace]);
const cachedMemories = (
- await fetchContentForSpace(addedSpace.id, {
+ (await fetchContentForSpace(addedSpace.id, {
offset: 0,
limit: 3,
- }) ?? []
+ })) ?? []
).map((m) => ({ ...m, space: addedSpace.id }));
setCachedMemories((prev) => [...prev, ...cachedMemories]);
@@ -141,81 +141,80 @@ export const MemoryProvider: React.FC<
};
};
- const _updateMemory: typeof updateMemory = async (id, _data) => {
- const data = await updateMemory(id, _data);
-
- let contents: ChachedSpaceContent[] = [];
-
- await Promise.all([
- spaces.forEach(async (space) => {
- console.log("fetching ");
- const data = (
- await fetchContentForSpace(space.id, {
- offset: 0,
- limit: 3,
- }) ?? []
- ).map((data) => ({
- ...data,
- space: space.id,
- }));
- contents = [...contents, ...data];
- }),
- ]);
-
- const freeMemories = await fetchFreeMemories();
-
- setCachedMemories(contents)
- setFreeMemories(freeMemories)
-
-
- return data
- }
-
- const _updateSpace: typeof updateSpaceTitle = async (...params) => {
- const updatedSpace = await updateSpaceTitle(...params);
-
- if (updatedSpace) {
- setSpaces(prev => prev.map(
- i => i.id === updatedSpace.id ? updatedSpace : i
- ))
- }
-
- return updatedSpace
- }
-
- const addMemoriesToSpace: typeof addContentInSpaces = async (...params) => {
- const data = await addContentInSpaces(...params);
-
- let contents: ChachedSpaceContent[] = [];
-
- await Promise.all([
- spaces.forEach(async (space) => {
- console.log("fetching ");
- const data = (
- await fetchContentForSpace(space.id, {
- offset: 0,
- limit: 3,
- }) ?? []
- ).map((data) => ({
- ...data,
- space: space.id,
- }));
- contents = [...contents, ...data];
- }),
- ]);
-
- const freeMemories = await fetchFreeMemories();
-
- setCachedMemories(contents)
- setFreeMemories(freeMemories)
-
- return data
- }
+ const _updateMemory: typeof updateMemory = async (id, _data) => {
+ const data = await updateMemory(id, _data);
+
+ let contents: ChachedSpaceContent[] = [];
+
+ await Promise.all([
+ spaces.forEach(async (space) => {
+ console.log("fetching ");
+ const data = (
+ (await fetchContentForSpace(space.id, {
+ offset: 0,
+ limit: 3,
+ })) ?? []
+ ).map((data) => ({
+ ...data,
+ space: space.id,
+ }));
+ contents = [...contents, ...data];
+ }),
+ ]);
+
+ const freeMemories = await fetchFreeMemories();
+
+ setCachedMemories(contents);
+ setFreeMemories(freeMemories);
+
+ return data;
+ };
+
+ const _updateSpace: typeof updateSpaceTitle = async (...params) => {
+ const updatedSpace = await updateSpaceTitle(...params);
+
+ if (updatedSpace) {
+ setSpaces((prev) =>
+ prev.map((i) => (i.id === updatedSpace.id ? updatedSpace : i)),
+ );
+ }
+
+ return updatedSpace;
+ };
+
+ const addMemoriesToSpace: typeof addContentInSpaces = async (...params) => {
+ const data = await addContentInSpaces(...params);
+
+ let contents: ChachedSpaceContent[] = [];
+
+ await Promise.all([
+ spaces.forEach(async (space) => {
+ console.log("fetching ");
+ const data = (
+ (await fetchContentForSpace(space.id, {
+ offset: 0,
+ limit: 3,
+ })) ?? []
+ ).map((data) => ({
+ ...data,
+ space: space.id,
+ }));
+ contents = [...contents, ...data];
+ }),
+ ]);
+
+ const freeMemories = await fetchFreeMemories();
+
+ setCachedMemories(contents);
+ setFreeMemories(freeMemories);
+
+ return data;
+ };
return (
<MemoryContext.Provider
value={{
- updateSpace: _updateSpace,
+ updateSpace: _updateSpace,
search: searchMemoriesAndSpaces,
spaces,
addSpace: _addSpace,
@@ -224,8 +223,8 @@ export const MemoryProvider: React.FC<
cachedMemories,
deleteMemory: _deleteMemory,
addMemory: _addMemory,
- updateMemory: _updateMemory,
- addMemoriesToSpace,
+ updateMemory: _updateMemory,
+ addMemoriesToSpace,
}}
>
{children}
diff --git a/apps/web/src/lib/utils.ts b/apps/web/src/lib/utils.ts
index 0fe5bdfd..81fa8549 100644
--- a/apps/web/src/lib/utils.ts
+++ b/apps/web/src/lib/utils.ts
@@ -89,25 +89,23 @@ export function convertRemToPixels(rem: number) {
}
export function isArraysEqual(a: any[], b: any[]) {
- if (a === b) return true;
+ if (a === b) return true;
if (a == null || b == null) return false;
if (a.length !== b.length) return false;
- let isEqual = true;
-
- a.forEach(i => {
- if (!isEqual) return
- isEqual = b.includes(i)
- })
+ let isEqual = true;
- if (!isEqual)
- return isEqual
+ a.forEach((i) => {
+ if (!isEqual) return;
+ isEqual = b.includes(i);
+ });
- b.forEach(i => {
- if (!isEqual) return
- isEqual = a.includes(i)
- })
+ if (!isEqual) return isEqual;
- return isEqual
+ b.forEach((i) => {
+ if (!isEqual) return;
+ isEqual = a.includes(i);
+ });
+ return isEqual;
}