aboutsummaryrefslogtreecommitdiff
path: root/apps/web/app
diff options
context:
space:
mode:
authorDhravya <[email protected]>2024-07-01 20:32:50 -0500
committerDhravya <[email protected]>2024-07-01 20:32:50 -0500
commit46dfc3b4e7ac5958251401a670c1f4cff49706bb (patch)
treef9baefd7dfd4cac46ef09cfc8349131e6235dfe1 /apps/web/app
parentspaces function (diff)
downloadsupermemory-46dfc3b4e7ac5958251401a670c1f4cff49706bb.tar.xz
supermemory-46dfc3b4e7ac5958251401a670c1f4cff49706bb.zip
shareable spaces
Diffstat (limited to 'apps/web/app')
-rw-r--r--apps/web/app/(dash)/(memories)/content.tsx60
-rw-r--r--apps/web/app/(dash)/(memories)/space/[spaceid]/page.tsx9
-rw-r--r--apps/web/app/actions/doers.ts44
-rw-r--r--apps/web/app/actions/fetchers.ts27
4 files changed, 123 insertions, 17 deletions
diff --git a/apps/web/app/(dash)/(memories)/content.tsx b/apps/web/app/(dash)/(memories)/content.tsx
index 26aed6a5..23bff46b 100644
--- a/apps/web/app/(dash)/(memories)/content.tsx
+++ b/apps/web/app/(dash)/(memories)/content.tsx
@@ -30,17 +30,20 @@ import {
DropdownMenuTrigger,
} from "@repo/ui/shadcn/dropdown-menu";
import { Button } from "@repo/ui/shadcn/button";
-import { deleteItem, moveItem } from "@/app/actions/doers";
+import { addUserToSpace, deleteItem, moveItem } from "@/app/actions/doers";
import { toast } from "sonner";
+import { Input } from "@repo/ui/shadcn/input";
export function MemoriesPage({
memoriesAndSpaces,
title = "Your Memories",
currentSpace,
+ usersWithAccess,
}: {
memoriesAndSpaces: { memories: Content[]; spaces: StoredSpace[] };
title?: string;
currentSpace?: StoredSpace;
+ usersWithAccess?: string[];
}) {
const [filter, setFilter] = useState("All");
@@ -70,7 +73,6 @@ export function MemoriesPage({
.filter((item) => {
if (filter === "All") return true;
if (filter === "Spaces" && item.item === "space") {
- console.log(item);
return true;
}
if (filter === "Pages")
@@ -105,12 +107,55 @@ export function MemoriesPage({
{title}
</h2>
{currentSpace && (
- <div className="flex gap-4 items-center">
- Space
- <div className="flex items-center gap-2 bg-secondary p-2 rounded-xl">
- <Image src={MemoriesIcon} alt="Spaces icon" className="w-3 h-3" />
- <span className="text-[#fff]">{currentSpace.name}</span>
+ <div className="flex flex-col gap-2">
+ <div className="flex gap-4 items-center">
+ Space
+ <div className="flex items-center gap-2 bg-secondary p-2 rounded-xl">
+ <Image src={MemoriesIcon} alt="Spaces icon" className="w-3 h-3" />
+ <span className="text-[#fff]">{currentSpace.name}</span>
+ </div>
</div>
+
+ {usersWithAccess && usersWithAccess.length > 0 && (
+ <div className="flex gap-4 items-center">
+ Users with access
+ <div className="flex gap-2">
+ {usersWithAccess.map((user) => (
+ <div className="flex items-center gap-2 bg-secondary p-2 rounded-xl">
+ <Image
+ src={UrlIcon}
+ alt="Spaces icon"
+ className="w-3 h-3"
+ />
+ <span className="text-[#fff]">{user}</span>
+ </div>
+ ))}
+ </div>
+ </div>
+ )}
+
+ <form
+ action={async (e: FormData) => {
+ const email = e.get("email")?.toString();
+
+ if (!email) {
+ toast.error("Please enter an email");
+ return;
+ }
+
+ const resp = await addUserToSpace(email, currentSpace.id);
+
+ if (resp.success) {
+ toast.success("User added to space");
+ } else {
+ toast.error("Failed to add user to space");
+ }
+ }}
+ className="flex gap-2 max-w-xl mt-2"
+ >
+ <Input name="email" placeholder="Add user by email" />
+ <Button variant="secondary">Add</Button>
+ </form>
</div>
)}
@@ -268,7 +313,6 @@ function LinkComponent({
onClick={async () => {
toast.info("Adding to space...");
- console.log(id, space.id);
const response = await moveItem(id, [space.id]);
if (response.success) {
diff --git a/apps/web/app/(dash)/(memories)/space/[spaceid]/page.tsx b/apps/web/app/(dash)/(memories)/space/[spaceid]/page.tsx
index 723fb29e..759519cb 100644
--- a/apps/web/app/(dash)/(memories)/space/[spaceid]/page.tsx
+++ b/apps/web/app/(dash)/(memories)/space/[spaceid]/page.tsx
@@ -1,15 +1,24 @@
import { getMemoriesInsideSpace } from "@/app/actions/fetchers";
import { redirect } from "next/navigation";
import MemoriesPage from "../../content";
+import { db } from "@/server/db";
+import { and, eq } from "drizzle-orm";
+import { spacesAccess } from "@/server/db/schema";
async function Page({ params: { spaceid } }: { params: { spaceid: number } }) {
const { success, data } = await getMemoriesInsideSpace(spaceid);
if (!success ?? !data) return redirect("/home");
+
+ const hasAccess = await db.query.spacesAccess.findMany({
+ where: and(eq(spacesAccess.spaceId, spaceid)),
+ });
+
return (
<MemoriesPage
memoriesAndSpaces={{ memories: data.memories, spaces: [] }}
title={data.spaces[0]?.name}
currentSpace={data.spaces[0]}
+ usersWithAccess={hasAccess.map((x) => x.userEmail) ?? []}
/>
);
}
diff --git a/apps/web/app/actions/doers.ts b/apps/web/app/actions/doers.ts
index 90103092..82263f6e 100644
--- a/apps/web/app/actions/doers.ts
+++ b/apps/web/app/actions/doers.ts
@@ -9,6 +9,7 @@ import {
contentToSpace,
sessions,
space,
+ spacesAccess,
storedContent,
users,
} from "../../server/db/schema";
@@ -95,6 +96,47 @@ export const limit = async (
return items <= remainingLimit;
};
+export const addUserToSpace = async (userEmail: string, spaceId: number) => {
+ const data = await auth();
+
+ if (!data || !data.user || !data.user.id) {
+ redirect("/signin");
+ return { error: "Not authenticated", success: false };
+ }
+
+ // We need to make sure that the user owns the space
+ const spaceData = await db
+ .select()
+ .from(space)
+ .where(and(eq(space.id, spaceId), eq(space.user, data.user.id)))
+ .all();
+
+ if (spaceData.length === 0) {
+ return {
+ success: false,
+ error: "You do not own this space",
+ };
+ }
+
+ try {
+ await db.insert(spacesAccess).values({
+ spaceId: spaceId,
+ userEmail: userEmail,
+ });
+
+ revalidatePath("/space/" + spaceId);
+
+ return {
+ success: true,
+ };
+ } catch (e) {
+ return {
+ success: false,
+ error: (e as Error).message,
+ };
+ }
+};
+
const getTweetData = async (tweetID: string) => {
const url = `https://cdn.syndication.twimg.com/tweet-result?id=${tweetID}&lang=en&features=tfw_timeline_list%3A%3Btfw_follower_count_sunset%3Atrue%3Btfw_tweet_edit_backend%3Aon%3Btfw_refsrc_session%3Aon%3Btfw_fosnr_soft_interventions_enabled%3Aon%3Btfw_show_birdwatch_pivots_enabled%3Aon%3Btfw_show_business_verified_badge%3Aon%3Btfw_duplicate_scribes_to_settings%3Aon%3Btfw_use_profile_image_shape_enabled%3Aon%3Btfw_show_blue_verified_badge%3Aon%3Btfw_legacy_timeline_sunset%3Atrue%3Btfw_show_gov_verified_badge%3Aon%3Btfw_show_business_affiliate_badge%3Aon%3Btfw_tweet_edit_frontend%3Aon&token=4c2mmul6mnh`;
@@ -191,8 +233,6 @@ export const createMemory = async (input: {
storeToSpaces = [];
}
- console.log("SAVING URL: ", metadata.baseUrl);
-
const vectorSaveResponse = await fetch(
`${process.env.BACKEND_BASE_URL}/api/add`,
{
diff --git a/apps/web/app/actions/fetchers.ts b/apps/web/app/actions/fetchers.ts
index c33f90d1..1541e4ee 100644
--- a/apps/web/app/actions/fetchers.ts
+++ b/apps/web/app/actions/fetchers.ts
@@ -1,6 +1,6 @@
"use server";
-import { and, asc, eq, inArray, not, sql } from "drizzle-orm";
+import { and, asc, eq, inArray, not, or, sql } from "drizzle-orm";
import { db } from "../../server/db";
import {
canvas,
@@ -10,6 +10,7 @@ import {
Content,
contentToSpace,
space,
+ spacesAccess,
storedContent,
StoredSpace,
users,
@@ -90,12 +91,24 @@ export const getMemoriesInsideSpace = async (
.select()
.from(storedContent)
.where(
- inArray(
- storedContent.id,
- db
- .select({ contentId: contentToSpace.contentId })
- .from(contentToSpace)
- .where(eq(contentToSpace.spaceId, spaceId)),
+ and(
+ inArray(
+ storedContent.id,
+ db
+ .select({ contentId: contentToSpace.contentId })
+ .from(contentToSpace)
+ .where(eq(contentToSpace.spaceId, spaceId)),
+ ),
+ or(
+ eq(storedContent.userId, data.user.id!),
+ eq(
+ db
+ .select({ userId: spacesAccess.userEmail })
+ .from(spacesAccess)
+ .where(eq(spacesAccess.spaceId, spaceId)),
+ data.user.email,
+ ),
+ ),
),
)
.execute();