From 8c36dada4c0b5d45f606696a91d9135043258345 Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:17:17 +0330 Subject: [PATCH] Import source: vault/app/snippets/[id]/edit/page Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- vault/app/snippets/[id]/edit/page.tsx | 196 ++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 vault/app/snippets/[id]/edit/page.tsx diff --git a/vault/app/snippets/[id]/edit/page.tsx b/vault/app/snippets/[id]/edit/page.tsx new file mode 100644 index 0000000..17e44bb --- /dev/null +++ b/vault/app/snippets/[id]/edit/page.tsx @@ -0,0 +1,196 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { useParams, useRouter } from "next/navigation"; +import { motion } from "framer-motion"; +import { Save, ArrowLeft } from "lucide-react"; +import Link from "next/link"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { CodeEditor } from "@/components/code-editor"; +import { PrivacyToggle } from "@/components/privacy-toggle"; +import { LanguageSelector } from "@/components/language-selector"; +import { ExpirationSelector } from "@/components/expiration-selector"; +import { TagInput } from "@/components/tag-input"; +import { api } from "@/lib/api-client"; +import { PrivacyType, Expiration } from "@/lib/types"; +import { toast } from "sonner"; + +export default function EditSnippetPage() { + const params = useParams(); + const router = useRouter(); + const id = params.id as string; + + const [title, setTitle] = useState(""); + const [code, setCode] = useState(""); + const [language, setLanguage] = useState("javascript"); + const [privacy, setPrivacy] = useState("secret"); + const [password, setPassword] = useState(""); + const [expiration, setExpiration] = useState("never"); + const [tags, setTags] = useState([]); + const [loaded, setLoaded] = useState(false); + const [isText, setIsText] = useState(false); + const [originalPrivacy, setOriginalPrivacy] = useState("secret"); + const [saving, setSaving] = useState(false); + + useEffect(() => { + api.getSnippet(id) + .then(({ snippet: s }) => { + setTitle(s.title); + setCode(s.code); + setLanguage(s.language); + setPrivacy(s.privacy); + setOriginalPrivacy(s.privacy); + setPassword(""); + setExpiration(s.expiration); + setTags(s.tags); + setIsText(s.language === "plaintext"); + }) + .catch((error) => { + toast.error(error instanceof Error ? error.message : "Snippet not found"); + if (error instanceof Error && error.message === "Authentication required") router.push("/login"); + }) + .finally(() => setLoaded(true)); + }, [id, router]); + + const handleSave = async () => { + if (!title.trim()) { + toast.error("Please add a title"); + return; + } + if (!code.trim()) { + toast.error("Please add some content"); + return; + } + + if (saving) return; + + if (privacy === "password" && originalPrivacy !== "password" && !password.trim()) { + toast.error("Set a password for password-protected snippets"); + return; + } + + try { + setSaving(true); + await api.updateSnippet(id, { + title: title.trim(), + code, + language: isText ? "plaintext" : language, + privacy, + password: privacy === "password" && password.trim() ? password : undefined, + expiration, + tags, + }); + + toast.success("Snippet updated!"); + router.push(`/snippets/${id}`); + } catch (error) { + toast.error(error instanceof Error ? error.message : "Failed to update snippet"); + } finally { + setSaving(false); + } + }; + + if (!loaded) { + return ( +
+
+
+
+
+
+
+ ); + } + + return ( +
+ + + + + +
+

Edit snippet

+ +
+ +
+
+ + setTitle(e.target.value)} + className="h-11 bg-muted/50 border-border/50" + /> +
+ + {!isText && ( +
+
+ + +
+
+ + +
+
+ )} + + {isText && ( +
+ + +
+ )} + +
+ + +
+ +
+ + +
+ + {isText ? ( +
+ +