unsharing logic

This commit is contained in:
Ishaan Dey 2024-05-01 02:22:02 -04:00
parent 5ba1c03030
commit e23b38875e
4 changed files with 118 additions and 55 deletions

View File

@ -5,7 +5,7 @@ import { ZodError, z } from "zod";
import { user, sandbox, usersToSandboxes } from "./schema";
import * as schema from "./schema";
import { eq } from "drizzle-orm";
import { and, eq } from "drizzle-orm";
export interface Env {
DB: D1Database;
@ -91,33 +91,48 @@ export default {
console.log(method);
return methodNotAllowed;
}
} else if (path === "/api/sandbox/share" && method === "POST") {
const shareSchema = z.object({
sandboxId: z.string(),
email: z.string(),
});
} else if (path === "/api/sandbox/share") {
if (method === "POST") {
const shareSchema = z.object({
sandboxId: z.string(),
email: z.string(),
});
const body = await request.json();
const { sandboxId, email } = shareSchema.parse(body);
const body = await request.json();
const { sandboxId, email } = shareSchema.parse(body);
const user = await db.query.user.findFirst({
where: (user, { eq }) => eq(user.email, email),
with: {
usersToSandboxes: true,
},
});
const user = await db.query.user.findFirst({
where: (user, { eq }) => eq(user.email, email),
with: {
usersToSandboxes: true,
},
});
if (!user) {
return new Response("No user associated with email.", { status: 400 });
}
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 });
}
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();
return success;
return success;
} else if (method === "DELETE") {
const deleteShareSchema = z.object({
sandboxId: z.string(),
userId: z.string(),
});
const body = await request.json();
const { sandboxId, userId } = deleteShareSchema.parse(body);
console.log("DELETE", sandboxId, userId);
await db.delete(usersToSandboxes).where(and(eq(usersToSandboxes.userId, userId), eq(usersToSandboxes.sandboxId, sandboxId)));
return success;
} else return methodNotAllowed;
} else if (path === "/api/user") {
if (method === "GET") {
const params = url.searchParams;

View File

@ -3,10 +3,8 @@
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { z } from "zod"
import { zodResolver } from "@hookform/resolvers/zod"
@ -15,27 +13,19 @@ import { useForm } from "react-hook-form"
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { Loader2, UserPlus, X } from "lucide-react"
import { useEffect, useState, useTransition } from "react"
import { Sandbox, User } from "@/lib/types"
import { useState } from "react"
import { Sandbox } from "@/lib/types"
import { Button } from "@/components/ui/button"
import Avatar from "@/components/ui/avatar"
import { shareSandbox } from "@/lib/actions"
import { toast } from "sonner"
import SharedUser from "./sharedUser"
import { DialogDescription } from "@radix-ui/react-dialog"
const formSchema = z.object({
email: z.string().email(),
@ -79,9 +69,15 @@ export default function ShareSandboxModal({
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="p-0">
<div className="p-6 pb-3 space-y-6">
<div className={`p-6 ${shared.length > 0 ? "pb-3" : null} space-y-6`}>
<DialogHeader>
<DialogTitle>Share Sandbox</DialogTitle>
{data.visibility === "private" ? (
<DialogDescription className="text-sm text-muted-foreground">
This sandbox is private. Making it public will allow shared
users to view and collaborate.
</DialogDescription>
) : null}
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="flex">
@ -115,25 +111,21 @@ export default function ShareSandboxModal({
</form>
</Form>
</div>
<div className="w-full h-[1px] bg-border" />
<div className="p-6 pt-3">
<DialogHeader className="mb-6">
<DialogTitle>Manage Access</DialogTitle>
</DialogHeader>
<div className="space-y-2">
{shared.map((user) => (
<div key={user.id} className="flex items-center justify-between">
<div className="flex items-center">
<Avatar name={user.name} className="mr-2" />
{user.name}
</div>
<Button variant="ghost" size="smIcon">
<X className="w-4 h-4" />
</Button>
{shared.length > 0 ? (
<>
<div className="w-full h-[1px] mb- bg-border" />
<div className="p-6 pt-3">
<DialogHeader className="mb-6">
<DialogTitle>Manage Access</DialogTitle>
</DialogHeader>
<div className="space-y-2">
{shared.map((user) => (
<SharedUser key={user.id} user={user} sandboxId={data.id} />
))}
</div>
))}
</div>
</div>
</div>
</>
) : null}
</DialogContent>
</Dialog>
)

View File

@ -0,0 +1,44 @@
"use client"
import Avatar from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import { unshareSandbox } from "@/lib/actions"
import { Loader2, X } from "lucide-react"
import { useState } from "react"
export default function SharedUser({
user,
sandboxId,
}: {
user: { id: string; name: string }
sandboxId: string
}) {
const [loading, setLoading] = useState(false)
async function handleUnshare(id: string) {
setLoading(true)
await unshareSandbox(sandboxId, user.id)
}
return (
<div className="flex items-center justify-between">
<div className="flex items-center">
<Avatar name={user.name} className="mr-2" />
{user.name}
</div>
<Button
disabled={loading}
onClick={() => handleUnshare(user.id)}
variant="ghost"
size="smIcon"
>
{loading ? (
<Loader2 className="animate-spin w-4 h-4" />
) : (
<X className="w-4 h-4" />
)}
</Button>
</div>
)
}

View File

@ -60,3 +60,15 @@ export async function shareSandbox(sandboxId: string, email: string) {
revalidatePath(`/code/${sandboxId}`)
return { success: true, message: "Shared successfully." }
}
export async function unshareSandbox(sandboxId: string, userId: string) {
const res = await fetch("http://localhost:8787/api/sandbox/share", {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ sandboxId, userId }),
})
revalidatePath(`/code/${sandboxId}`)
}