diff --git a/backend/database/src/index.ts b/backend/database/src/index.ts
index 4cf8d51..4e1610f 100644
--- a/backend/database/src/index.ts
+++ b/backend/database/src/index.ts
@@ -36,6 +36,9 @@ export default {
const id = params.get("id") as string;
const res = await db.query.sandbox.findFirst({
where: (sandbox, { eq }) => eq(sandbox.id, id),
+ with: {
+ usersToSandboxes: true,
+ },
});
return json(res ?? {});
} else {
@@ -99,9 +102,18 @@ export default {
const user = await db.query.user.findFirst({
where: (user, { eq }) => eq(user.email, email),
+ with: {
+ usersToSandboxes: true,
+ },
});
- if (!user) return invalidRequest;
+ if (!user) {
+ return new Response("No user associated with email.", { status: 400 });
+ }
+
+ if (user.usersToSandboxes.find((uts) => uts.sandboxId === sandboxId)) {
+ return new Response("User already has access.", { status: 400 });
+ }
await db.insert(usersToSandboxes).values({ userId: user.id, sandboxId }).get();
diff --git a/backend/server/src/types.ts b/backend/server/src/types.ts
index be0d21f..650f529 100644
--- a/backend/server/src/types.ts
+++ b/backend/server/src/types.ts
@@ -5,6 +5,10 @@ export type User = {
name: string
email: string
sandbox: Sandbox[]
+ usersToSandboxes: {
+ userId: string
+ sandboxId: string
+ }[]
}
export type Sandbox = {
@@ -13,6 +17,10 @@ export type Sandbox = {
type: "react" | "node"
visibility: "public" | "private"
userId: string
+ usersToSandboxes: {
+ userId: string
+ sandboxId: string
+ }[]
}
export type TFolder = {
diff --git a/frontend/app/(app)/code/[id]/page.tsx b/frontend/app/(app)/code/[id]/page.tsx
index b0d646d..765c4b8 100644
--- a/frontend/app/(app)/code/[id]/page.tsx
+++ b/frontend/app/(app)/code/[id]/page.tsx
@@ -1,5 +1,5 @@
import Navbar from "@/components/editor/navbar"
-import { Sandbox, User } from "@/lib/types"
+import { Sandbox, User, UsersToSandboxes } from "@/lib/types"
import { currentUser } from "@clerk/nextjs"
import dynamic from "next/dynamic"
import { redirect } from "next/navigation"
@@ -20,6 +20,20 @@ const getSandboxData = async (id: string) => {
return sandboxData
}
+const getSharedUsers = async (usersToSandboxes: UsersToSandboxes[]) => {
+ const shared = await Promise.all(
+ usersToSandboxes.map(async (user) => {
+ const userRes = await fetch(
+ `http://localhost:8787/api/user?id=${user.userId}`
+ )
+ const userData: User = await userRes.json()
+ return { id: userData.id, name: userData.name }
+ })
+ )
+
+ return shared
+}
+
export default async function CodePage({ params }: { params: { id: string } }) {
const user = await currentUser()
const sandboxId = params.id
@@ -30,12 +44,13 @@ export default async function CodePage({ params }: { params: { id: string } }) {
const userData = await getUserData(user.id)
const sandboxData = await getSandboxData(sandboxId)
+ const shared = await getSharedUsers(sandboxData.usersToSandboxes)
return (
)
diff --git a/frontend/components/editor/index.tsx b/frontend/components/editor/index.tsx
index 2365b84..089488a 100644
--- a/frontend/components/editor/index.tsx
+++ b/frontend/components/editor/index.tsx
@@ -30,12 +30,13 @@ import { processFileType, validateName } from "@/lib/utils"
import { toast } from "sonner"
import EditorTerminal from "./terminal"
import { Button } from "../ui/button"
+import { User } from "@/lib/types"
export default function CodeEditor({
- userId,
+ userData,
sandboxId,
}: {
- userId: string
+ userData: User
sandboxId: string
}) {
const clerk = useClerk()
@@ -54,7 +55,7 @@ export default function CodeEditor({
const [terminals, setTerminals] = useState([])
const socket = io(
- `http://localhost:4000?userId=${userId}&sandboxId=${sandboxId}`
+ `http://localhost:4000?userId=${userData.id}&sandboxId=${sandboxId}`
)
useEffect(() => {
diff --git a/frontend/components/editor/navbar/index.tsx b/frontend/components/editor/navbar/index.tsx
index 7dff4f2..ae45487 100644
--- a/frontend/components/editor/navbar/index.tsx
+++ b/frontend/components/editor/navbar/index.tsx
@@ -14,9 +14,14 @@ import ShareSandboxModal from "./share"
export default function Navbar({
userData,
sandboxData,
+ shared,
}: {
userData: User
sandboxData: Sandbox
+ shared: {
+ id: string
+ name: string
+ }[]
}) {
const [isEditOpen, setIsEditOpen] = useState(false)
const [isShareOpen, setIsShareOpen] = useState(false)
@@ -32,6 +37,7 @@ export default function Navbar({
open={isShareOpen}
setOpen={setIsShareOpen}
data={sandboxData}
+ shared={shared}
/>
diff --git a/frontend/components/editor/navbar/share.tsx b/frontend/components/editor/navbar/share.tsx
index f941c3e..67ebf3d 100644
--- a/frontend/components/editor/navbar/share.tsx
+++ b/frontend/components/editor/navbar/share.tsx
@@ -30,8 +30,8 @@ import {
SelectValue,
} from "@/components/ui/select"
import { Loader2, UserPlus, X } from "lucide-react"
-import { useState, useTransition } from "react"
-import { Sandbox } from "@/lib/types"
+import { useEffect, useState, useTransition } from "react"
+import { Sandbox, User } from "@/lib/types"
import { Button } from "@/components/ui/button"
import Avatar from "@/components/ui/avatar"
import { shareSandbox } from "@/lib/actions"
@@ -45,10 +45,15 @@ export default function ShareSandboxModal({
open,
setOpen,
data,
+ shared,
}: {
open: boolean
setOpen: (open: boolean) => void
data: Sandbox
+ shared: {
+ id: string
+ name: string
+ }[]
}) {
const [loading, setLoading] = useState(false)
@@ -60,17 +65,12 @@ export default function ShareSandboxModal({
})
async function onSubmit(values: z.infer
) {
- // if (!user.isSignedIn) return
- // const sandboxData = { type: selected, userId: user.user.id, ...values }
- // setLoading(true)
- // const id = await createSandbox(sandboxData)
-
- console.log(values)
-
setLoading(true)
const res = await shareSandbox(data.id, values.email)
- if (!res) {
- toast.error("Failed to share.")
+ if (!res.success) {
+ toast.error(res.message)
+ } else {
+ toast.success("Shared successfully.")
}
setLoading(false)
@@ -121,15 +121,17 @@ export default function ShareSandboxModal({
Manage Access
-
-
-
- Ishaan Dey
+ {shared.map((user) => (
+
-
-
+ ))}
diff --git a/frontend/lib/actions.ts b/frontend/lib/actions.ts
index 0e59d5f..c87fd8a 100644
--- a/frontend/lib/actions.ts
+++ b/frontend/lib/actions.ts
@@ -44,18 +44,19 @@ export async function deleteSandbox(id: string) {
}
export async function shareSandbox(sandboxId: string, email: string) {
- try {
- const res = await fetch("http://localhost:8787/api/sandbox/share", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ sandboxId, email }),
- })
+ const res = await fetch("http://localhost:8787/api/sandbox/share", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ sandboxId, email }),
+ })
+ const text = await res.text()
- revalidatePath(`/code/${sandboxId}`)
- return true
- } catch (err) {
- return false
+ if (res.status !== 200) {
+ return { success: false, message: text }
}
+
+ revalidatePath(`/code/${sandboxId}`)
+ return { success: true, message: "Shared successfully." }
}
diff --git a/frontend/lib/types.ts b/frontend/lib/types.ts
index 7b729ee..01739ca 100644
--- a/frontend/lib/types.ts
+++ b/frontend/lib/types.ts
@@ -5,6 +5,7 @@ export type User = {
name: string
email: string
sandbox: Sandbox[]
+ usersToSandboxes: UsersToSandboxes[]
}
export type Sandbox = {
@@ -13,6 +14,12 @@ export type Sandbox = {
type: "react" | "node"
visibility: "public" | "private"
userId: string
+ usersToSandboxes: UsersToSandboxes[]
+}
+
+export type UsersToSandboxes = {
+ userId: string
+ sandboxId: string
}
export type R2Files = {