From 5cb4fec6e52d740ad2eba1a6fbb7af1e216ff457 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 01:59:33 +0000 Subject: [PATCH 01/14] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/integrations/supabase/types.ts | 6 ++++++ .../20260418015930_9b4dd1a4-bbde-4d53-8a24-d6bd69675211.sql | 4 ++++ 2 files changed, 10 insertions(+) create mode 100644 supabase/migrations/20260418015930_9b4dd1a4-bbde-4d53-8a24-d6bd69675211.sql diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts index 83e55c5..78fdb4c 100644 --- a/src/integrations/supabase/types.ts +++ b/src/integrations/supabase/types.ts @@ -2162,6 +2162,8 @@ export type Database = { hourly_rate: number | null id: string phone: string | null + signature_block: string | null + signature_image_path: string | null timezone: string | null title: string | null updated_at: string @@ -2175,6 +2177,8 @@ export type Database = { hourly_rate?: number | null id: string phone?: string | null + signature_block?: string | null + signature_image_path?: string | null timezone?: string | null title?: string | null updated_at?: string @@ -2188,6 +2192,8 @@ export type Database = { hourly_rate?: number | null id?: string phone?: string | null + signature_block?: string | null + signature_image_path?: string | null timezone?: string | null title?: string | null updated_at?: string diff --git a/supabase/migrations/20260418015930_9b4dd1a4-bbde-4d53-8a24-d6bd69675211.sql b/supabase/migrations/20260418015930_9b4dd1a4-bbde-4d53-8a24-d6bd69675211.sql new file mode 100644 index 0000000..4199b71 --- /dev/null +++ b/supabase/migrations/20260418015930_9b4dd1a4-bbde-4d53-8a24-d6bd69675211.sql @@ -0,0 +1,4 @@ +-- Attorney signatures stored on profile +ALTER TABLE public.profiles + ADD COLUMN IF NOT EXISTS signature_block text, + ADD COLUMN IF NOT EXISTS signature_image_path text; \ No newline at end of file From 00b867fabf1a8ff8e1e12590f42bb0424fe29da9 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 01:59:45 +0000 Subject: [PATCH 02/14] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/settings.profile.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/settings.profile.tsx b/src/routes/settings.profile.tsx index d7a5db9..b6a2618 100644 --- a/src/routes/settings.profile.tsx +++ b/src/routes/settings.profile.tsx @@ -8,7 +8,7 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; -import { Loader2, Upload, Trash2, User as UserIcon } from "lucide-react"; +import { Loader2, Upload, Trash2, User as UserIcon, PenLine } from "lucide-react"; import { toast } from "sonner"; export const Route = createFileRoute("/settings/profile")({ From 50a33f1bdf24549db615d5975b061f4e4b50154b Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 01:59:51 +0000 Subject: [PATCH 03/14] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/settings.profile.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/routes/settings.profile.tsx b/src/routes/settings.profile.tsx index b6a2618..b6c27cc 100644 --- a/src/routes/settings.profile.tsx +++ b/src/routes/settings.profile.tsx @@ -22,6 +22,8 @@ const EMPTY = { bio: "", timezone: "", avatar_url: "" as string | null | "", + signature_block: "", + signature_image_path: "" as string | null | "", }; function initials(name: string, email: string) { From 4ecd92b1e890ba95395a6f3045cf786790a28418 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:00:18 +0000 Subject: [PATCH 04/14] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/settings.profile.tsx | 67 ++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/src/routes/settings.profile.tsx b/src/routes/settings.profile.tsx index b6c27cc..f14fe30 100644 --- a/src/routes/settings.profile.tsx +++ b/src/routes/settings.profile.tsx @@ -36,9 +36,16 @@ function ProfilePage() { const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [uploading, setUploading] = useState(false); + const [uploadingSig, setUploadingSig] = useState(false); const [form, setForm] = useState({ ...EMPTY }); const [email, setEmail] = useState(""); const fileInput = useRef(null); + const sigInput = useRef(null); + + // Derive a public preview URL for the saved signature image + const signatureUrl = form.signature_image_path + ? supabase.storage.from("avatars").getPublicUrl(form.signature_image_path).data.publicUrl + : ""; const load = async () => { if (!user) return; @@ -50,13 +57,16 @@ function ProfilePage() { .maybeSingle(); if (data) { setEmail(data.email || user.email || ""); + const d = data as any; setForm({ full_name: data.full_name ?? "", - title: (data as any).title ?? "", - phone: (data as any).phone ?? "", - bio: (data as any).bio ?? "", - timezone: (data as any).timezone ?? "", - avatar_url: (data as any).avatar_url ?? "", + title: d.title ?? "", + phone: d.phone ?? "", + bio: d.bio ?? "", + timezone: d.timezone ?? "", + avatar_url: d.avatar_url ?? "", + signature_block: d.signature_block ?? "", + signature_image_path: d.signature_image_path ?? "", }); } setLoading(false); @@ -118,6 +128,50 @@ function ProfilePage() { toast.success("Photo removed"); }; + const onSignatureFile = async (file: File) => { + if (!user) return; + if (file.size > 2 * 1024 * 1024) { + toast.error("Signature image must be under 2 MB"); + return; + } + setUploadingSig(true); + const ext = (file.name.split(".").pop() || "png").toLowerCase(); + const path = `${user.id}/signature-${Date.now()}.${ext}`; + const { error } = await supabase.storage + .from("avatars") + .upload(path, file, { upsert: true, contentType: file.type, cacheControl: "3600" }); + if (error) { + setUploadingSig(false); + toast.error("Upload failed", { description: error.message }); + return; + } + const { error: upErr } = await supabase + .from("profiles") + .update({ signature_image_path: path } as any) + .eq("id", user.id); + setUploadingSig(false); + if (upErr) { + toast.error("Could not save signature", { description: upErr.message }); + return; + } + setForm((f) => ({ ...f, signature_image_path: path })); + toast.success("Signature image saved"); + }; + + const removeSignatureImage = async () => { + if (!user) return; + const { error } = await supabase + .from("profiles") + .update({ signature_image_path: null } as any) + .eq("id", user.id); + if (error) { + toast.error("Could not remove", { description: error.message }); + return; + } + setForm((f) => ({ ...f, signature_image_path: "" })); + toast.success("Signature image removed"); + }; + const save = async () => { if (!user) return; setSaving(true); @@ -129,7 +183,8 @@ function ProfilePage() { phone: form.phone || null, bio: form.bio || null, timezone: form.timezone || null, - }) + signature_block: form.signature_block || null, + } as any) .eq("id", user.id); setSaving(false); if (error) { From 19f190215313c4992623fde4e1b8d743809686b9 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:00:40 +0000 Subject: [PATCH 05/14] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/settings.profile.tsx | 80 +++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/routes/settings.profile.tsx b/src/routes/settings.profile.tsx index f14fe30..1bc3fb0 100644 --- a/src/routes/settings.profile.tsx +++ b/src/routes/settings.profile.tsx @@ -300,6 +300,86 @@ function ProfilePage() { + + + + Attorney signature + + + +

+ Used in pleadings. The signature line is drawn automatically; the block + below appears under it. Optionally upload a scanned signature image to + place above the line. +

+ + +