sharing logic
This commit is contained in:
parent
66a76eb0f9
commit
5ba1c03030
@ -36,6 +36,9 @@ export default {
|
|||||||
const id = params.get("id") as string;
|
const id = params.get("id") as string;
|
||||||
const res = await db.query.sandbox.findFirst({
|
const res = await db.query.sandbox.findFirst({
|
||||||
where: (sandbox, { eq }) => eq(sandbox.id, id),
|
where: (sandbox, { eq }) => eq(sandbox.id, id),
|
||||||
|
with: {
|
||||||
|
usersToSandboxes: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
return json(res ?? {});
|
return json(res ?? {});
|
||||||
} else {
|
} else {
|
||||||
@ -99,9 +102,18 @@ export default {
|
|||||||
|
|
||||||
const user = await db.query.user.findFirst({
|
const user = await db.query.user.findFirst({
|
||||||
where: (user, { eq }) => eq(user.email, email),
|
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();
|
await db.insert(usersToSandboxes).values({ userId: user.id, sandboxId }).get();
|
||||||
|
|
||||||
|
@ -5,6 +5,10 @@ export type User = {
|
|||||||
name: string
|
name: string
|
||||||
email: string
|
email: string
|
||||||
sandbox: Sandbox[]
|
sandbox: Sandbox[]
|
||||||
|
usersToSandboxes: {
|
||||||
|
userId: string
|
||||||
|
sandboxId: string
|
||||||
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Sandbox = {
|
export type Sandbox = {
|
||||||
@ -13,6 +17,10 @@ export type Sandbox = {
|
|||||||
type: "react" | "node"
|
type: "react" | "node"
|
||||||
visibility: "public" | "private"
|
visibility: "public" | "private"
|
||||||
userId: string
|
userId: string
|
||||||
|
usersToSandboxes: {
|
||||||
|
userId: string
|
||||||
|
sandboxId: string
|
||||||
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TFolder = {
|
export type TFolder = {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Navbar from "@/components/editor/navbar"
|
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 { currentUser } from "@clerk/nextjs"
|
||||||
import dynamic from "next/dynamic"
|
import dynamic from "next/dynamic"
|
||||||
import { redirect } from "next/navigation"
|
import { redirect } from "next/navigation"
|
||||||
@ -20,6 +20,20 @@ const getSandboxData = async (id: string) => {
|
|||||||
return sandboxData
|
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 } }) {
|
export default async function CodePage({ params }: { params: { id: string } }) {
|
||||||
const user = await currentUser()
|
const user = await currentUser()
|
||||||
const sandboxId = params.id
|
const sandboxId = params.id
|
||||||
@ -30,12 +44,13 @@ export default async function CodePage({ params }: { params: { id: string } }) {
|
|||||||
|
|
||||||
const userData = await getUserData(user.id)
|
const userData = await getUserData(user.id)
|
||||||
const sandboxData = await getSandboxData(sandboxId)
|
const sandboxData = await getSandboxData(sandboxId)
|
||||||
|
const shared = await getSharedUsers(sandboxData.usersToSandboxes)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="overflow-hidden overscroll-none w-screen flex flex-col h-screen bg-background">
|
<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">
|
<div className="w-screen flex grow">
|
||||||
<CodeEditor userId={user.id} sandboxId={sandboxId} />
|
<CodeEditor userData={userData} sandboxId={sandboxId} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -30,12 +30,13 @@ import { processFileType, validateName } from "@/lib/utils"
|
|||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
import EditorTerminal from "./terminal"
|
import EditorTerminal from "./terminal"
|
||||||
import { Button } from "../ui/button"
|
import { Button } from "../ui/button"
|
||||||
|
import { User } from "@/lib/types"
|
||||||
|
|
||||||
export default function CodeEditor({
|
export default function CodeEditor({
|
||||||
userId,
|
userData,
|
||||||
sandboxId,
|
sandboxId,
|
||||||
}: {
|
}: {
|
||||||
userId: string
|
userData: User
|
||||||
sandboxId: string
|
sandboxId: string
|
||||||
}) {
|
}) {
|
||||||
const clerk = useClerk()
|
const clerk = useClerk()
|
||||||
@ -54,7 +55,7 @@ export default function CodeEditor({
|
|||||||
const [terminals, setTerminals] = useState<string[]>([])
|
const [terminals, setTerminals] = useState<string[]>([])
|
||||||
|
|
||||||
const socket = io(
|
const socket = io(
|
||||||
`http://localhost:4000?userId=${userId}&sandboxId=${sandboxId}`
|
`http://localhost:4000?userId=${userData.id}&sandboxId=${sandboxId}`
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -14,9 +14,14 @@ import ShareSandboxModal from "./share"
|
|||||||
export default function Navbar({
|
export default function Navbar({
|
||||||
userData,
|
userData,
|
||||||
sandboxData,
|
sandboxData,
|
||||||
|
shared,
|
||||||
}: {
|
}: {
|
||||||
userData: User
|
userData: User
|
||||||
sandboxData: Sandbox
|
sandboxData: Sandbox
|
||||||
|
shared: {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
}[]
|
||||||
}) {
|
}) {
|
||||||
const [isEditOpen, setIsEditOpen] = useState(false)
|
const [isEditOpen, setIsEditOpen] = useState(false)
|
||||||
const [isShareOpen, setIsShareOpen] = useState(false)
|
const [isShareOpen, setIsShareOpen] = useState(false)
|
||||||
@ -32,6 +37,7 @@ export default function Navbar({
|
|||||||
open={isShareOpen}
|
open={isShareOpen}
|
||||||
setOpen={setIsShareOpen}
|
setOpen={setIsShareOpen}
|
||||||
data={sandboxData}
|
data={sandboxData}
|
||||||
|
shared={shared}
|
||||||
/>
|
/>
|
||||||
<div className="h-14 px-2 w-full flex items-center justify-between border-b border-border">
|
<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">
|
<div className="flex items-center space-x-4">
|
||||||
|
@ -30,8 +30,8 @@ import {
|
|||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select"
|
} from "@/components/ui/select"
|
||||||
import { Loader2, UserPlus, X } from "lucide-react"
|
import { Loader2, UserPlus, X } from "lucide-react"
|
||||||
import { useState, useTransition } from "react"
|
import { useEffect, useState, useTransition } from "react"
|
||||||
import { Sandbox } from "@/lib/types"
|
import { Sandbox, User } from "@/lib/types"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import Avatar from "@/components/ui/avatar"
|
import Avatar from "@/components/ui/avatar"
|
||||||
import { shareSandbox } from "@/lib/actions"
|
import { shareSandbox } from "@/lib/actions"
|
||||||
@ -45,10 +45,15 @@ export default function ShareSandboxModal({
|
|||||||
open,
|
open,
|
||||||
setOpen,
|
setOpen,
|
||||||
data,
|
data,
|
||||||
|
shared,
|
||||||
}: {
|
}: {
|
||||||
open: boolean
|
open: boolean
|
||||||
setOpen: (open: boolean) => void
|
setOpen: (open: boolean) => void
|
||||||
data: Sandbox
|
data: Sandbox
|
||||||
|
shared: {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
}[]
|
||||||
}) {
|
}) {
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
@ -60,17 +65,12 @@ export default function ShareSandboxModal({
|
|||||||
})
|
})
|
||||||
|
|
||||||
async function onSubmit(values: z.infer<typeof formSchema>) {
|
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)
|
setLoading(true)
|
||||||
const res = await shareSandbox(data.id, values.email)
|
const res = await shareSandbox(data.id, values.email)
|
||||||
if (!res) {
|
if (!res.success) {
|
||||||
toast.error("Failed to share.")
|
toast.error(res.message)
|
||||||
|
} else {
|
||||||
|
toast.success("Shared successfully.")
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
@ -121,15 +121,17 @@ export default function ShareSandboxModal({
|
|||||||
<DialogTitle>Manage Access</DialogTitle>
|
<DialogTitle>Manage Access</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex items-center justify-between">
|
{shared.map((user) => (
|
||||||
<div className="flex items-center">
|
<div key={user.id} className="flex items-center justify-between">
|
||||||
<Avatar name="Ishaan Dey" className="mr-2" />
|
<div className="flex items-center">
|
||||||
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>
|
||||||
<Button variant="ghost" size="smIcon">
|
))}
|
||||||
<X className="w-4 h-4" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
@ -44,18 +44,19 @@ export async function deleteSandbox(id: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function shareSandbox(sandboxId: string, email: string) {
|
export async function shareSandbox(sandboxId: string, email: string) {
|
||||||
try {
|
const res = await fetch("http://localhost:8787/api/sandbox/share", {
|
||||||
const res = await fetch("http://localhost:8787/api/sandbox/share", {
|
method: "POST",
|
||||||
method: "POST",
|
headers: {
|
||||||
headers: {
|
"Content-Type": "application/json",
|
||||||
"Content-Type": "application/json",
|
},
|
||||||
},
|
body: JSON.stringify({ sandboxId, email }),
|
||||||
body: JSON.stringify({ sandboxId, email }),
|
})
|
||||||
})
|
const text = await res.text()
|
||||||
|
|
||||||
revalidatePath(`/code/${sandboxId}`)
|
if (res.status !== 200) {
|
||||||
return true
|
return { success: false, message: text }
|
||||||
} catch (err) {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
revalidatePath(`/code/${sandboxId}`)
|
||||||
|
return { success: true, message: "Shared successfully." }
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ export type User = {
|
|||||||
name: string
|
name: string
|
||||||
email: string
|
email: string
|
||||||
sandbox: Sandbox[]
|
sandbox: Sandbox[]
|
||||||
|
usersToSandboxes: UsersToSandboxes[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Sandbox = {
|
export type Sandbox = {
|
||||||
@ -13,6 +14,12 @@ export type Sandbox = {
|
|||||||
type: "react" | "node"
|
type: "react" | "node"
|
||||||
visibility: "public" | "private"
|
visibility: "public" | "private"
|
||||||
userId: string
|
userId: string
|
||||||
|
usersToSandboxes: UsersToSandboxes[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UsersToSandboxes = {
|
||||||
|
userId: string
|
||||||
|
sandboxId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type R2Files = {
|
export type R2Files = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user