add private functionality

This commit is contained in:
Ishaan Dey 2024-05-26 19:02:47 -07:00
parent 34afefcc4a
commit 089ab2b1df
3 changed files with 84 additions and 75 deletions

View File

@ -82,6 +82,10 @@ export default async function CodePage({ params }: { params: { id: string } }) {
return notFound() return notFound()
} }
if (isSharedUser && sandboxData.visibility === "private") {
return notFound()
}
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">
<Room id={sandboxId}> <Room id={sandboxId}>

View File

@ -1,7 +1,7 @@
"use client"; "use client"
import CustomButton from "@/components/ui/customButton"; import CustomButton from "@/components/ui/customButton"
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button"
import { import {
Code2, Code2,
FolderDot, FolderDot,
@ -9,51 +9,51 @@ import {
Plus, Plus,
Settings, Settings,
Users, Users,
} from "lucide-react"; } from "lucide-react"
import { useEffect, useState } from "react"; import { useEffect, useState } from "react"
import { Sandbox } from "@/lib/types"; import { Sandbox } from "@/lib/types"
import DashboardProjects from "./projects"; import DashboardProjects from "./projects"
import DashboardSharedWithMe from "./shared"; import DashboardSharedWithMe from "./shared"
import NewProjectModal from "./newProject"; import NewProjectModal from "./newProject"
import Link from "next/link"; import Link from "next/link"
import { useRouter, useSearchParams } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation"
import AboutModal from "./about"; import AboutModal from "./about"
import { toast } from "sonner"; import { toast } from "sonner"
type TScreen = "projects" | "shared" | "settings" | "search"; type TScreen = "projects" | "shared" | "settings" | "search"
export default function Dashboard({ export default function Dashboard({
sandboxes, sandboxes,
shared, shared,
}: { }: {
sandboxes: Sandbox[]; sandboxes: Sandbox[]
shared: { shared: {
id: string; id: string
name: string; name: string
type: "react" | "node"; type: "react" | "node"
author: string; author: string
sharedOn: Date; sharedOn: Date
}[]; }[]
}) { }) {
const [screen, setScreen] = useState<TScreen>("projects"); const [screen, setScreen] = useState<TScreen>("projects")
const [newProjectModalOpen, setNewProjectModalOpen] = useState(false); const [newProjectModalOpen, setNewProjectModalOpen] = useState(false)
const [aboutModalOpen, setAboutModalOpen] = useState(false); const [aboutModalOpen, setAboutModalOpen] = useState(false)
const activeScreen = (s: TScreen) => { const activeScreen = (s: TScreen) => {
if (screen === s) return "justify-start"; if (screen === s) return "justify-start"
else return "justify-start font-normal text-muted-foreground"; else return "justify-start font-normal text-muted-foreground"
}; }
const searchParams = useSearchParams(); const searchParams = useSearchParams()
const q = searchParams.get("q"); const q = searchParams.get("q")
const router = useRouter(); const router = useRouter()
useEffect(() => { useEffect(() => {
if (!sandboxes) { if (!sandboxes) {
router.refresh(); router.refresh()
} }
}, [sandboxes]); }, [sandboxes])
return ( return (
<> <>
@ -68,10 +68,10 @@ export default function Dashboard({
<CustomButton <CustomButton
onClick={() => { onClick={() => {
if (sandboxes.length >= 8) { if (sandboxes.length >= 8) {
toast.error("You reached the maximum # of sandboxes."); toast.error("You reached the maximum # of sandboxes.")
return; return
} }
setNewProjectModalOpen(true); setNewProjectModalOpen(true)
}} }}
className="mb-4" className="mb-4"
> >
@ -107,7 +107,7 @@ export default function Dashboard({
<a target="_blank" href="https://github.com/ishaan1013/sandbox"> <a target="_blank" href="https://github.com/ishaan1013/sandbox">
<Button <Button
variant="ghost" variant="ghost"
className="justify-start font-normal text-muted-foreground" className="justify-start w-full font-normal text-muted-foreground"
> >
<Code2 className="w-4 h-4 mr-2" /> <Code2 className="w-4 h-4 mr-2" />
GitHub Repository GitHub Repository
@ -134,5 +134,5 @@ export default function Dashboard({
) : screen === "settings" ? null : null} ) : screen === "settings" ? null : null}
</div> </div>
</> </>
); )
} }

View File

@ -1,4 +1,4 @@
"use client"; "use client"
import { import {
Dialog, Dialog,
@ -7,12 +7,12 @@ import {
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
DialogTrigger, DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog"
import Image from "next/image"; import Image from "next/image"
import { useState } from "react"; import { useState } from "react"
import { set, z } from "zod"; import { set, z } from "zod"
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form"
import { import {
Form, Form,
@ -22,29 +22,29 @@ import {
FormItem, FormItem,
FormLabel, FormLabel,
FormMessage, FormMessage,
} from "@/components/ui/form"; } from "@/components/ui/form"
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input"
import { import {
Select, Select,
SelectContent, SelectContent,
SelectItem, SelectItem,
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select"
import { useUser } from "@clerk/nextjs"; import { useUser } from "@clerk/nextjs"
import { createSandbox } from "@/lib/actions"; import { createSandbox } from "@/lib/actions"
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation"
import { Loader2 } from "lucide-react"; import { Loader2 } from "lucide-react"
import { Button } from "../ui/button"; import { Button } from "../ui/button"
type TOptions = "react" | "node" | "python" | "more"; type TOptions = "react" | "node" | "python" | "more"
const data: { const data: {
id: TOptions; id: TOptions
name: string; name: string
icon: string; icon: string
description: string; description: string
disabled: boolean; disabled: boolean
}[] = [ }[] = [
{ {
id: "react", id: "react",
@ -74,7 +74,7 @@ const data: {
description: "More coming soon, feel free to contribute on GitHub", description: "More coming soon, feel free to contribute on GitHub",
disabled: true, disabled: true,
}, },
]; ]
const formSchema = z.object({ const formSchema = z.object({
name: z name: z
@ -86,20 +86,20 @@ const formSchema = z.object({
"Name must be alphanumeric and can contain underscores" "Name must be alphanumeric and can contain underscores"
), ),
visibility: z.enum(["public", "private"]), visibility: z.enum(["public", "private"]),
}); })
export default function NewProjectModal({ export default function NewProjectModal({
open, open,
setOpen, setOpen,
}: { }: {
open: boolean; open: boolean
setOpen: (open: boolean) => void; setOpen: (open: boolean) => void
}) { }) {
const [selected, setSelected] = useState<TOptions>("react"); const [selected, setSelected] = useState<TOptions>("react")
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false)
const router = useRouter(); const router = useRouter()
const user = useUser(); const user = useUser()
const form = useForm<z.infer<typeof formSchema>>({ const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema), resolver: zodResolver(formSchema),
@ -107,23 +107,23 @@ export default function NewProjectModal({
name: "", name: "",
visibility: "public", visibility: "public",
}, },
}); })
async function onSubmit(values: z.infer<typeof formSchema>) { async function onSubmit(values: z.infer<typeof formSchema>) {
if (!user.isSignedIn) return; if (!user.isSignedIn) return
const sandboxData = { type: selected, userId: user.user.id, ...values }; const sandboxData = { type: selected, userId: user.user.id, ...values }
setLoading(true); setLoading(true)
const id = await createSandbox(sandboxData); const id = await createSandbox(sandboxData)
router.push(`/code/${id}`); router.push(`/code/${id}`)
} }
return ( return (
<Dialog <Dialog
open={open} open={open}
onOpenChange={(open: boolean) => { onOpenChange={(open: boolean) => {
if (!loading) setOpen(open); if (!loading) setOpen(open)
}} }}
> >
<DialogContent> <DialogContent>
@ -152,7 +152,7 @@ export default function NewProjectModal({
</div> </div>
<Form {...form}> <Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}> <form autoComplete="off" onSubmit={form.handleSubmit(onSubmit)}>
<FormField <FormField
control={form.control} control={form.control}
name="name" name="name"
@ -191,6 +191,11 @@ export default function NewProjectModal({
<SelectItem value="private">Private</SelectItem> <SelectItem value="private">Private</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
<FormDescription>
Note: All sandboxes cannot be seen by the public. Private
sandboxes cannot be accessed by shared users that you add,
while public sandboxes can.
</FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
)} )}
@ -208,5 +213,5 @@ export default function NewProjectModal({
</Form> </Form>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
); )
} }