sharing logic

This commit is contained in:
Ishaan Dey 2024-05-01 01:53:49 -04:00
parent 66a76eb0f9
commit 5ba1c03030
8 changed files with 90 additions and 38 deletions

View File

@ -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();

View File

@ -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 = {

View File

@ -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 (
<div className="overflow-hidden overscroll-none w-screen flex flex-col h-screen bg-background">
<Navbar userData={userData} sandboxData={sandboxData} />
<Navbar userData={userData} sandboxData={sandboxData} shared={shared} />
<div className="w-screen flex grow">
<CodeEditor userId={user.id} sandboxId={sandboxId} />
<CodeEditor userData={userData} sandboxId={sandboxId} />
</div>
</div>
)

View File

@ -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<string[]>([])
const socket = io(
`http://localhost:4000?userId=${userId}&sandboxId=${sandboxId}`
`http://localhost:4000?userId=${userData.id}&sandboxId=${sandboxId}`
)
useEffect(() => {

View File

@ -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}
/>
<div className="h-14 px-2 w-full flex items-center justify-between border-b border-border">
<div className="flex items-center space-x-4">

View File

@ -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<typeof formSchema>) {
// 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({
<DialogTitle>Manage Access</DialogTitle>
</DialogHeader>
<div className="space-y-2">
<div className="flex items-center justify-between">
{shared.map((user) => (
<div key={user.id} className="flex items-center justify-between">
<div className="flex items-center">
<Avatar name="Ishaan Dey" className="mr-2" />
Ishaan Dey
<Avatar name={user.name} className="mr-2" />
{user.name}
</div>
<Button variant="ghost" size="smIcon">
<X className="w-4 h-4" />
</Button>
</div>
))}
</div>
</div>
</DialogContent>

View File

@ -44,7 +44,6 @@ 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: {
@ -52,10 +51,12 @@ export async function shareSandbox(sandboxId: string, email: string) {
},
body: JSON.stringify({ sandboxId, email }),
})
const text = await res.text()
if (res.status !== 200) {
return { success: false, message: text }
}
revalidatePath(`/code/${sandboxId}`)
return true
} catch (err) {
return false
}
return { success: true, message: "Shared successfully." }
}

View File

@ -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 = {