From bba10d31ac49e37c8916e7d7fbebe0b52f4ba651 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:16:25 +0000 Subject: [PATCH 1/5] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/integrations/supabase/types.ts | 99 +++++++++++++++++++ ...2_8f2085e8-1834-4de6-bab8-e87c8d7a0a41.sql | 60 +++++++++++ 2 files changed, 159 insertions(+) create mode 100644 supabase/migrations/20260418011622_8f2085e8-1834-4de6-bab8-e87c8d7a0a41.sql diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts index c990442..100e462 100644 --- a/src/integrations/supabase/types.ts +++ b/src/integrations/supabase/types.ts @@ -26,6 +26,7 @@ export type Database = { created_by: string | null direction: string duration_minutes: number | null + external_id: string | null follow_up_date: string | null follow_up_required: boolean homeowner_id: string | null @@ -45,6 +46,7 @@ export type Database = { created_by?: string | null direction?: string duration_minutes?: number | null + external_id?: string | null follow_up_date?: string | null follow_up_required?: boolean homeowner_id?: string | null @@ -64,6 +66,7 @@ export type Database = { created_by?: string | null direction?: string duration_minutes?: number | null + external_id?: string | null follow_up_date?: string | null follow_up_required?: boolean homeowner_id?: string | null @@ -153,6 +156,7 @@ export type Database = { created_by: string | null default_hourly_rate: number | null description: string | null + external_id: string | null filing_date: string | null id: string judge: string | null @@ -188,6 +192,7 @@ export type Database = { created_by?: string | null default_hourly_rate?: number | null description?: string | null + external_id?: string | null filing_date?: string | null id?: string judge?: string | null @@ -223,6 +228,7 @@ export type Database = { created_by?: string | null default_hourly_rate?: number | null description?: string | null + external_id?: string | null filing_date?: string | null id?: string judge?: string | null @@ -313,6 +319,7 @@ export type Database = { client_type: Database["public"]["Enums"]["client_type"] created_at: string created_by: string | null + external_id: string | null id: string management_company: string | null name: string @@ -334,6 +341,7 @@ export type Database = { client_type?: Database["public"]["Enums"]["client_type"] created_at?: string created_by?: string | null + external_id?: string | null id?: string management_company?: string | null name: string @@ -355,6 +363,7 @@ export type Database = { client_type?: Database["public"]["Enums"]["client_type"] created_at?: string created_by?: string | null + external_id?: string | null id?: string management_company?: string | null name?: string @@ -741,6 +750,7 @@ export type Database = { created_at: string created_by: string | null email: string | null + external_id: string | null id: string name: string notes: string | null @@ -759,6 +769,7 @@ export type Database = { created_at?: string created_by?: string | null email?: string | null + external_id?: string | null id?: string name: string notes?: string | null @@ -777,6 +788,7 @@ export type Database = { created_at?: string created_by?: string | null email?: string | null + external_id?: string | null id?: string name?: string notes?: string | null @@ -926,6 +938,7 @@ export type Database = { case_id: string created_at: string description: string | null + external_id: string | null folder: string id: string mime_type: string | null @@ -938,6 +951,7 @@ export type Database = { case_id: string created_at?: string description?: string | null + external_id?: string | null folder?: string id?: string mime_type?: string | null @@ -950,6 +964,7 @@ export type Database = { case_id?: string created_at?: string description?: string | null + external_id?: string | null folder?: string id?: string mime_type?: string | null @@ -1025,6 +1040,72 @@ export type Database = { } Relationships: [] } + events: { + Row: { + all_day: boolean + case_id: string | null + client_id: string | null + created_at: string + created_by: string | null + description: string | null + end_at: string | null + event_type: string + external_id: string | null + id: string + location: string | null + start_at: string + title: string + updated_at: string + } + Insert: { + all_day?: boolean + case_id?: string | null + client_id?: string | null + created_at?: string + created_by?: string | null + description?: string | null + end_at?: string | null + event_type?: string + external_id?: string | null + id?: string + location?: string | null + start_at: string + title: string + updated_at?: string + } + Update: { + all_day?: boolean + case_id?: string | null + client_id?: string | null + created_at?: string + created_by?: string | null + description?: string | null + end_at?: string | null + event_type?: string + external_id?: string | null + id?: string + location?: string | null + start_at?: string + title?: string + updated_at?: string + } + Relationships: [ + { + foreignKeyName: "events_case_id_fkey" + columns: ["case_id"] + isOneToOne: false + referencedRelation: "cases" + referencedColumns: ["id"] + }, + { + foreignKeyName: "events_client_id_fkey" + columns: ["client_id"] + isOneToOne: false + referencedRelation: "clients" + referencedColumns: ["id"] + }, + ] + } expenses: { Row: { amount: number @@ -1033,6 +1114,7 @@ export type Database = { created_at: string description: string expense_date: string + external_id: string | null id: string invoice_id: string | null receipt_storage_path: string | null @@ -1046,6 +1128,7 @@ export type Database = { created_at?: string description: string expense_date?: string + external_id?: string | null id?: string invoice_id?: string | null receipt_storage_path?: string | null @@ -1059,6 +1142,7 @@ export type Database = { created_at?: string description?: string expense_date?: string + external_id?: string | null id?: string invoice_id?: string | null receipt_storage_path?: string | null @@ -1241,6 +1325,7 @@ export type Database = { created_at: string created_by: string | null email: string | null + external_id: string | null first_name: string id: string last_name: string @@ -1256,6 +1341,7 @@ export type Database = { created_at?: string created_by?: string | null email?: string | null + external_id?: string | null first_name: string id?: string last_name: string @@ -1271,6 +1357,7 @@ export type Database = { created_at?: string created_by?: string | null email?: string | null + external_id?: string | null first_name?: string id?: string last_name?: string @@ -1559,6 +1646,7 @@ export type Database = { created_at: string created_by: string | null due_date: string | null + external_id: string | null id: string invoice_number: string is_retainer: boolean @@ -1578,6 +1666,7 @@ export type Database = { created_at?: string created_by?: string | null due_date?: string | null + external_id?: string | null id?: string invoice_number: string is_retainer?: boolean @@ -1597,6 +1686,7 @@ export type Database = { created_at?: string created_by?: string | null due_date?: string | null + external_id?: string | null id?: string invoice_number?: string is_retainer?: boolean @@ -2023,6 +2113,7 @@ export type Database = { case_id: string created_at: string created_by: string | null + external_id: string | null id: string report_storage_path: string | null title: string @@ -2032,6 +2123,7 @@ export type Database = { case_id: string created_at?: string created_by?: string | null + external_id?: string | null id?: string report_storage_path?: string | null title: string @@ -2041,6 +2133,7 @@ export type Database = { case_id?: string created_at?: string created_by?: string | null + external_id?: string | null id?: string report_storage_path?: string | null title?: string @@ -2166,6 +2259,7 @@ export type Database = { created_by: string | null description: string | null due_date: string | null + external_id: string | null id: string parent_task_id: string | null priority: Database["public"]["Enums"]["task_priority"] @@ -2183,6 +2277,7 @@ export type Database = { created_by?: string | null description?: string | null due_date?: string | null + external_id?: string | null id?: string parent_task_id?: string | null priority?: Database["public"]["Enums"]["task_priority"] @@ -2200,6 +2295,7 @@ export type Database = { created_by?: string | null description?: string | null due_date?: string | null + external_id?: string | null id?: string parent_task_id?: string | null priority?: Database["public"]["Enums"]["task_priority"] @@ -2239,6 +2335,7 @@ export type Database = { case_id: string created_at: string description: string + external_id: string | null hourly_rate: number hours: number id: string @@ -2252,6 +2349,7 @@ export type Database = { case_id: string created_at?: string description: string + external_id?: string | null hourly_rate?: number hours: number id?: string @@ -2265,6 +2363,7 @@ export type Database = { case_id?: string created_at?: string description?: string + external_id?: string | null hourly_rate?: number hours?: number id?: string diff --git a/supabase/migrations/20260418011622_8f2085e8-1834-4de6-bab8-e87c8d7a0a41.sql b/supabase/migrations/20260418011622_8f2085e8-1834-4de6-bab8-e87c8d7a0a41.sql new file mode 100644 index 0000000..e576c8a --- /dev/null +++ b/supabase/migrations/20260418011622_8f2085e8-1834-4de6-bab8-e87c8d7a0a41.sql @@ -0,0 +1,60 @@ +-- Calendar events table +CREATE TABLE IF NOT EXISTS public.events ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + case_id uuid REFERENCES public.cases(id) ON DELETE CASCADE, + client_id uuid REFERENCES public.clients(id) ON DELETE SET NULL, + title text NOT NULL, + description text, + location text, + start_at timestamptz NOT NULL, + end_at timestamptz, + all_day boolean NOT NULL DEFAULT false, + event_type text NOT NULL DEFAULT 'general', + external_id text, + created_by uuid, + created_at timestamptz NOT NULL DEFAULT now(), + updated_at timestamptz NOT NULL DEFAULT now() +); + +CREATE UNIQUE INDEX IF NOT EXISTS events_external_id_uidx ON public.events(external_id) WHERE external_id IS NOT NULL; +CREATE INDEX IF NOT EXISTS events_case_id_idx ON public.events(case_id); +CREATE INDEX IF NOT EXISTS events_start_at_idx ON public.events(start_at); + +ALTER TABLE public.events ENABLE ROW LEVEL SECURITY; + +CREATE POLICY "events_select" ON public.events FOR SELECT TO authenticated + USING (case_id IS NULL OR public.can_access_case(case_id, auth.uid()) OR public.is_admin(auth.uid())); +CREATE POLICY "events_insert" ON public.events FOR INSERT TO authenticated + WITH CHECK (auth.uid() IS NOT NULL); +CREATE POLICY "events_update" ON public.events FOR UPDATE TO authenticated + USING (public.is_admin(auth.uid()) OR created_by = auth.uid() OR (case_id IS NOT NULL AND public.can_access_case(case_id, auth.uid()))); +CREATE POLICY "events_delete" ON public.events FOR DELETE TO authenticated + USING (public.is_admin(auth.uid()) OR created_by = auth.uid()); + +CREATE TRIGGER events_set_updated_at BEFORE UPDATE ON public.events + FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at(); + +-- Add external_id to common imported tables for idempotent re-imports +ALTER TABLE public.cases ADD COLUMN IF NOT EXISTS external_id text; +ALTER TABLE public.clients ADD COLUMN IF NOT EXISTS external_id text; +ALTER TABLE public.contacts ADD COLUMN IF NOT EXISTS external_id text; +ALTER TABLE public.homeowners ADD COLUMN IF NOT EXISTS external_id text; +ALTER TABLE public.tasks ADD COLUMN IF NOT EXISTS external_id text; +ALTER TABLE public.invoices ADD COLUMN IF NOT EXISTS external_id text; +ALTER TABLE public.expenses ADD COLUMN IF NOT EXISTS external_id text; +ALTER TABLE public.time_entries ADD COLUMN IF NOT EXISTS external_id text; +ALTER TABLE public.call_logs ADD COLUMN IF NOT EXISTS external_id text; +ALTER TABLE public.documents ADD COLUMN IF NOT EXISTS external_id text; +ALTER TABLE public.status_updates ADD COLUMN IF NOT EXISTS external_id text; + +CREATE UNIQUE INDEX IF NOT EXISTS cases_external_id_uidx ON public.cases(external_id) WHERE external_id IS NOT NULL; +CREATE UNIQUE INDEX IF NOT EXISTS clients_external_id_uidx ON public.clients(external_id) WHERE external_id IS NOT NULL; +CREATE UNIQUE INDEX IF NOT EXISTS contacts_external_id_uidx ON public.contacts(external_id) WHERE external_id IS NOT NULL; +CREATE UNIQUE INDEX IF NOT EXISTS homeowners_external_id_uidx ON public.homeowners(external_id) WHERE external_id IS NOT NULL; +CREATE UNIQUE INDEX IF NOT EXISTS tasks_external_id_uidx ON public.tasks(external_id) WHERE external_id IS NOT NULL; +CREATE UNIQUE INDEX IF NOT EXISTS invoices_external_id_uidx ON public.invoices(external_id) WHERE external_id IS NOT NULL; +CREATE UNIQUE INDEX IF NOT EXISTS expenses_external_id_uidx ON public.expenses(external_id) WHERE external_id IS NOT NULL; +CREATE UNIQUE INDEX IF NOT EXISTS time_entries_external_id_uidx ON public.time_entries(external_id) WHERE external_id IS NOT NULL; +CREATE UNIQUE INDEX IF NOT EXISTS call_logs_external_id_uidx ON public.call_logs(external_id) WHERE external_id IS NOT NULL; +CREATE UNIQUE INDEX IF NOT EXISTS documents_external_id_uidx ON public.documents(external_id) WHERE external_id IS NOT NULL; +CREATE UNIQUE INDEX IF NOT EXISTS status_updates_external_id_uidx ON public.status_updates(external_id) WHERE external_id IS NOT NULL; \ No newline at end of file From f1fe7f61498b4114189c4d119eb08e0c4d3ab093 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:16:39 +0000 Subject: [PATCH 2/5] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- bun.lockb | Bin 359432 -> 360336 bytes package.json | 2 ++ 2 files changed, 2 insertions(+) diff --git a/bun.lockb b/bun.lockb index 2045680b0a7ab39e9a1f38cf62a9221feb9504e1..a940daa634c28ab718242f0ce0fd4f6179ff239a 100755 GIT binary patch delta 59709 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 >N9* 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

O?kFDZ|wQcHi*`UrZr;@P);euQJQmrl3tf+ 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 Date: Sat, 18 Apr 2026 01:16:45 +0000 Subject: [PATCH 3/5] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/settings.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/settings.tsx b/src/routes/settings.tsx index 71a08f7..911bbfc 100644 --- a/src/routes/settings.tsx +++ b/src/routes/settings.tsx @@ -17,6 +17,7 @@ const TABS = [ { to: "/settings/workflows", label: "Task workflows" }, { to: "/settings/smtp", label: "Email (SMTP)" }, { to: "/settings/imap", label: "Email (IMAP)" }, + { to: "/settings/import", label: "CSV import" }, ]; function SettingsLayout() { From 33cb737483a5784ddaa7304124a80ba2e1a5a6c9 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:18:35 +0000 Subject: [PATCH 4/5] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/settings.import.tsx | 717 +++++++++++++++++++++++++++++++++ 1 file changed, 717 insertions(+) create mode 100644 src/routes/settings.import.tsx diff --git a/src/routes/settings.import.tsx b/src/routes/settings.import.tsx new file mode 100644 index 0000000..666a49b --- /dev/null +++ b/src/routes/settings.import.tsx @@ -0,0 +1,717 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { useMemo, useState } from "react"; +import Papa from "papaparse"; +import { supabase } from "@/integrations/supabase/client"; +import { useAuth } from "@/lib/auth"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { Alert, AlertDescription } from "@/components/ui/alert"; +import { Upload, CheckCircle2, AlertCircle, Loader2, FileSpreadsheet } from "lucide-react"; +import { toast } from "sonner"; + +export const Route = createFileRoute("/settings/import")({ + component: ImportPage, +}); + +type Row = Record; + +interface ImporterConfig { + key: string; + label: string; + description: string; + table: string; + conflict: string; // column for upsert + // Maps normalized csv header → db column + aliases: Record; + // Numeric columns (parsed from string) + numeric?: string[]; + // Date-only columns (YYYY-MM-DD) + dateCols?: string[]; + // Datetime columns + datetimeCols?: string[]; + // Boolean columns + boolCols?: string[]; + // Required output columns; if missing in row, row is skipped + required: string[]; + // Per-row transform after mapping (e.g. split full name, set defaults) + transform?: (row: Row, ctx: ImportCtx) => Row | null; + // After successful insert, hook for caching ids by external_id (e.g. clients) + postInsert?: (rows: Row[], ctx: ImportCtx) => void; +} + +interface ImportCtx { + userId: string; + // Cached lookup tables: external_id → uuid + clientByExt: Map; + caseByExt: Map; + contactByExt: Map; + homeownerByExt: Map; + invoiceByExt: Map; + // Name → uuid lookups (for files that reference by name only) + clientByName: Map; + caseByNumber: Map; +} + +const norm = (s: string) => + s.toLowerCase().replace(/[^a-z0-9]/g, ""); + +const splitName = (full: string): { first_name: string; last_name: string } => { + const parts = (full ?? "").trim().split(/\s+/); + if (parts.length === 0) return { first_name: "", last_name: "" }; + if (parts.length === 1) return { first_name: parts[0], last_name: "" }; + return { first_name: parts[0], last_name: parts.slice(1).join(" ") }; +}; + +const toBool = (v: any) => { + if (typeof v === "boolean") return v; + const s = String(v ?? "").trim().toLowerCase(); + return s === "true" || s === "yes" || s === "1" || s === "y"; +}; + +const toNum = (v: any) => { + if (v === "" || v == null) return null; + const n = Number(String(v).replace(/[$,]/g, "")); + return isNaN(n) ? null : n; +}; + +const toDate = (v: any): string | null => { + if (!v) return null; + const d = new Date(v); + if (isNaN(d.getTime())) return null; + return d.toISOString().slice(0, 10); +}; + +const toDateTime = (v: any): string | null => { + if (!v) return null; + const d = new Date(v); + return isNaN(d.getTime()) ? null : d.toISOString(); +}; + +const IMPORTERS: ImporterConfig[] = [ + // Companies → clients + { + key: "companies", + label: "Companies → Clients", + description: "HOAs and corporate clients.", + table: "clients", + conflict: "external_id", + required: ["name"], + aliases: { + id: "external_id", companyid: "external_id", externalid: "external_id", + name: "name", companyname: "name", company: "name", + type: "client_type", clienttype: "client_type", + addressline1: "address_line1", address1: "address_line1", address: "address_line1", + addressline2: "address_line2", address2: "address_line2", + city: "city", state: "state", + zip: "postal_code", zipcode: "postal_code", postalcode: "postal_code", + phone: "primary_contact_phone", primaryphone: "primary_contact_phone", + email: "primary_contact_email", primaryemail: "primary_contact_email", + contactname: "primary_contact_name", primarycontact: "primary_contact_name", + management: "management_company", managementcompany: "management_company", + units: "num_units", numunits: "num_units", + notes: "notes", + }, + numeric: ["num_units", "annual_interest_rate"], + transform: (r) => { + const t = String(r.client_type ?? "").toLowerCase(); + r.client_type = t.includes("condo") ? "condo" : t.includes("hoa") ? "hoa" : "hoa"; + return r; + }, + postInsert: (rows, ctx) => { + for (const r of rows) { + if (r.external_id && r.id) ctx.clientByExt.set(r.external_id, r.id); + if (r.name && r.id) ctx.clientByName.set(r.name.toLowerCase(), r.id); + } + }, + }, + // People → contacts + { + key: "people", + label: "People → Contacts", + description: "Individual contacts (board members, vendors, etc.).", + table: "contacts", + conflict: "external_id", + required: ["name"], + aliases: { + id: "external_id", personid: "external_id", externalid: "external_id", + name: "name", fullname: "name", + firstname: "_first", lastname: "_last", + email: "email", phone: "phone", + company: "company", title: "title", + addressline1: "address_line1", address1: "address_line1", address: "address_line1", + addressline2: "address_line2", address2: "address_line2", + city: "city", state: "state", + zip: "postal_code", zipcode: "postal_code", postalcode: "postal_code", + type: "contact_type", contacttype: "contact_type", + notes: "notes", + }, + transform: (r) => { + if (!r.name && (r._first || r._last)) { + r.name = [r._first, r._last].filter(Boolean).join(" ").trim(); + } + delete r._first; delete r._last; + if (!r.contact_type) r.contact_type = "other"; + return r; + }, + }, + // Lawyers → contacts (type=attorney) + { + key: "lawyers", + label: "Lawyers → Contacts", + description: "Opposing counsel & external attorneys (added as contacts).", + table: "contacts", + conflict: "external_id", + required: ["name"], + aliases: { + id: "external_id", lawyerid: "external_id", externalid: "external_id", + name: "name", fullname: "name", + firstname: "_first", lastname: "_last", + email: "email", phone: "phone", + firm: "company", company: "company", + addressline1: "address_line1", address: "address_line1", + city: "city", state: "state", zip: "postal_code", postalcode: "postal_code", + notes: "notes", + }, + transform: (r) => { + if (!r.name && (r._first || r._last)) r.name = [r._first, r._last].filter(Boolean).join(" ").trim(); + delete r._first; delete r._last; + r.contact_type = "attorney"; + return r; + }, + }, + // Locations → homeowners (units) + { + key: "locations", + label: "Locations → Homeowner addresses", + description: "Property addresses tied to a client (HOA unit list).", + table: "homeowners", + conflict: "external_id", + required: ["client_id", "first_name"], + aliases: { + id: "external_id", locationid: "external_id", externalid: "external_id", + companyid: "_clientext", clientid: "_clientext", company: "_clientname", + address: "address", street: "address", addressline1: "address", + unit: "unit_number", unitnumber: "unit_number", + ownername: "_ownername", owner: "_ownername", + firstname: "first_name", lastname: "last_name", + email: "email", phone: "phone", + notes: "notes", + }, + transform: (r, ctx) => { + const cid = r._clientext ? ctx.clientByExt.get(String(r._clientext)) : null; + const cidByName = r._clientname ? ctx.clientByName.get(String(r._clientname).toLowerCase()) : null; + r.client_id = cid ?? cidByName ?? null; + delete r._clientext; delete r._clientname; + if (!r.client_id) return null; + if (!r.first_name && r._ownername) { + const { first_name, last_name } = splitName(r._ownername); + r.first_name = first_name; r.last_name = last_name; + } + delete r._ownername; + if (!r.last_name) r.last_name = ""; + return r; + }, + }, + // Cases → cases + { + key: "cases", + label: "Cases → Cases", + description: "Matters / cases linked to a client.", + table: "cases", + conflict: "external_id", + required: ["case_number", "title", "client_id"], + aliases: { + id: "external_id", caseid: "external_id", externalid: "external_id", + casenumber: "case_number", number: "case_number", mattercode: "case_number", + name: "title", title: "title", mattername: "title", + companyid: "_clientext", clientid: "_clientext", company: "_clientname", client: "_clientname", + description: "description", summary: "case_summary", casesummary: "case_summary", + practicearea: "practice_area", area: "practice_area", + status: "status", + opened: "opened_at", openedat: "opened_at", dateopened: "opened_at", + closed: "closed_at", closedat: "closed_at", dateclosed: "closed_at", + court: "court", judge: "judge", jurisdiction: "jurisdiction", + caseCaption: "case_caption", caption: "case_caption", + courtcasenumber: "court_case_number", + filingdate: "filing_date", + nexthearing: "next_hearing_date", nexthearingdate: "next_hearing_date", + opposingparty: "opposing_party", + opposingcounsel: "opposing_counsel", + opposingcounselfirm: "opposing_counsel_firm", + opposingcounselemail: "opposing_counsel_email", + opposingcounselphone: "opposing_counsel_phone", + claimamount: "claim_amount", settlementamount: "settlement_amount", + hourlyrate: "default_hourly_rate", rate: "default_hourly_rate", + }, + numeric: ["claim_amount", "settlement_amount", "default_hourly_rate"], + dateCols: ["opened_at", "closed_at", "filing_date", "next_hearing_date", "statute_of_limitations"], + transform: (r, ctx) => { + const cid = r._clientext ? ctx.clientByExt.get(String(r._clientext)) : null; + const cidByName = r._clientname ? ctx.clientByName.get(String(r._clientname).toLowerCase()) : null; + r.client_id = cid ?? cidByName ?? null; + delete r._clientext; delete r._clientname; + if (!r.client_id) return null; + const s = String(r.status ?? "").toLowerCase(); + r.status = s.includes("close") ? "closed" : s.includes("hold") ? "on_hold" : s.includes("intake") ? "intake" : "active"; + if (!r.case_number) r.case_number = `CASE-${Date.now()}-${Math.floor(Math.random() * 1000)}`; + if (!r.title) r.title = r.case_number; + return r; + }, + postInsert: (rows, ctx) => { + for (const r of rows) { + if (r.external_id && r.id) ctx.caseByExt.set(r.external_id, r.id); + if (r.case_number && r.id) ctx.caseByNumber.set(r.case_number, r.id); + } + }, + }, + // Case stages → not stored (informational only). Skipped. + // Tasks + { + key: "tasks", + label: "Tasks → Tasks", + description: "Task list with case linkage.", + table: "tasks", + conflict: "external_id", + required: ["title"], + aliases: { + id: "external_id", taskid: "external_id", externalid: "external_id", + title: "title", name: "title", subject: "title", + description: "description", notes: "description", + duedate: "due_date", due: "due_date", + priority: "priority", status: "status", + caseid: "_caseext", matterid: "_caseext", casenumber: "_casenum", + }, + dateCols: ["due_date"], + transform: (r, ctx) => { + const cid = r._caseext ? ctx.caseByExt.get(String(r._caseext)) : null; + const cidByNum = r._casenum ? ctx.caseByNumber.get(String(r._casenum)) : null; + r.case_id = cid ?? cidByNum ?? null; + delete r._caseext; delete r._casenum; + const s = String(r.status ?? "").toLowerCase(); + r.status = s.includes("complete") || s.includes("done") ? "complete" : "incomplete"; + const p = String(r.priority ?? "").toLowerCase(); + r.priority = ["low", "normal", "high", "urgent"].includes(p) ? p : "normal"; + return r; + }, + }, + // Events + { + key: "events", + label: "Events → Calendar", + description: "Calendar events (hearings, meetings, deadlines).", + table: "events", + conflict: "external_id", + required: ["title", "start_at"], + aliases: { + id: "external_id", eventid: "external_id", externalid: "external_id", + title: "title", name: "title", subject: "title", + description: "description", notes: "description", + location: "location", + start: "start_at", startat: "start_at", startdate: "start_at", startdatetime: "start_at", date: "start_at", + end: "end_at", endat: "end_at", enddate: "end_at", enddatetime: "end_at", + allday: "all_day", + type: "event_type", eventtype: "event_type", + caseid: "_caseext", matterid: "_caseext", casenumber: "_casenum", + companyid: "_clientext", clientid: "_clientext", + }, + boolCols: ["all_day"], + datetimeCols: ["start_at", "end_at"], + transform: (r, ctx) => { + r.case_id = (r._caseext && ctx.caseByExt.get(String(r._caseext))) || (r._casenum && ctx.caseByNumber.get(String(r._casenum))) || null; + r.client_id = (r._clientext && ctx.clientByExt.get(String(r._clientext))) || null; + delete r._caseext; delete r._casenum; delete r._clientext; + if (!r.event_type) r.event_type = "general"; + return r; + }, + }, + // Call logs + { + key: "call_logs", + label: "Calls → Call logs", + description: "Phone call records.", + table: "call_logs", + conflict: "external_id", + required: ["case_id"], + aliases: { + id: "external_id", callid: "external_id", externalid: "external_id", + caseid: "_caseext", matterid: "_caseext", casenumber: "_casenum", + direction: "direction", subject: "subject", topic: "subject", + notes: "notes", description: "notes", + callername: "caller_name", from: "caller_name", + callerphone: "caller_phone", phone: "caller_phone", + duration: "duration_minutes", durationminutes: "duration_minutes", minutes: "duration_minutes", + billable: "billable", + date: "call_date", calldate: "call_date", datetime: "call_date", + }, + numeric: ["duration_minutes"], + boolCols: ["billable"], + datetimeCols: ["call_date"], + transform: (r, ctx) => { + r.case_id = (r._caseext && ctx.caseByExt.get(String(r._caseext))) || (r._casenum && ctx.caseByNumber.get(String(r._casenum))) || null; + delete r._caseext; delete r._casenum; + if (!r.case_id) return null; + const d = String(r.direction ?? "").toLowerCase(); + r.direction = d.includes("in") ? "inbound" : "outbound"; + return r; + }, + }, + // Time entries + { + key: "time_entries", + label: "Time entries → Time", + description: "Billable time records.", + table: "time_entries", + conflict: "external_id", + required: ["case_id", "description", "hours"], + aliases: { + id: "external_id", timeid: "external_id", externalid: "external_id", + caseid: "_caseext", matterid: "_caseext", casenumber: "_casenum", + description: "description", notes: "description", + hours: "hours", duration: "hours", + rate: "hourly_rate", hourlyrate: "hourly_rate", + billable: "billable", + date: "work_date", workdate: "work_date", + }, + numeric: ["hours", "hourly_rate"], + boolCols: ["billable"], + dateCols: ["work_date"], + transform: (r, ctx) => { + r.case_id = (r._caseext && ctx.caseByExt.get(String(r._caseext))) || (r._casenum && ctx.caseByNumber.get(String(r._casenum))) || null; + delete r._caseext; delete r._casenum; + if (!r.case_id) return null; + r.user_id = ctx.userId; + if (r.hours == null) return null; + return r; + }, + }, + // Expenses + { + key: "expenses", + label: "Expenses → Expenses", + description: "Case-related expenses.", + table: "expenses", + conflict: "external_id", + required: ["case_id", "description", "amount"], + aliases: { + id: "external_id", expenseid: "external_id", externalid: "external_id", + caseid: "_caseext", matterid: "_caseext", casenumber: "_casenum", + description: "description", notes: "description", + amount: "amount", cost: "amount", + billable: "billable", + date: "expense_date", expensedate: "expense_date", + }, + numeric: ["amount"], + boolCols: ["billable"], + dateCols: ["expense_date"], + transform: (r, ctx) => { + r.case_id = (r._caseext && ctx.caseByExt.get(String(r._caseext))) || (r._casenum && ctx.caseByNumber.get(String(r._casenum))) || null; + delete r._caseext; delete r._casenum; + if (!r.case_id || r.amount == null) return null; + r.user_id = ctx.userId; + return r; + }, + }, + // Invoices + { + key: "invoices", + label: "Invoices → Invoices", + description: "Invoice headers (line items not imported).", + table: "invoices", + conflict: "external_id", + required: ["invoice_number", "client_id"], + aliases: { + id: "external_id", invoiceid: "external_id", externalid: "external_id", + number: "invoice_number", invoicenumber: "invoice_number", + companyid: "_clientext", clientid: "_clientext", company: "_clientname", + caseid: "_caseext", casenumber: "_casenum", + issuedate: "issue_date", date: "issue_date", + duedate: "due_date", + status: "status", + subtotal: "subtotal", tax: "tax", total: "total", amount: "total", + amountpaid: "amount_paid", paid: "amount_paid", + notes: "notes", memo: "notes", + }, + numeric: ["subtotal", "tax", "total", "amount_paid"], + dateCols: ["issue_date", "due_date"], + transform: (r, ctx) => { + r.client_id = (r._clientext && ctx.clientByExt.get(String(r._clientext))) || (r._clientname && ctx.clientByName.get(String(r._clientname).toLowerCase())) || null; + r.case_id = (r._caseext && ctx.caseByExt.get(String(r._caseext))) || (r._casenum && ctx.caseByNumber.get(String(r._casenum))) || null; + delete r._clientext; delete r._clientname; delete r._caseext; delete r._casenum; + if (!r.client_id) return null; + const s = String(r.status ?? "").toLowerCase(); + r.status = ["draft", "sent", "paid", "overdue", "void"].includes(s) ? s : "draft"; + return r; + }, + }, + // Notes → comments (general entity) + { + key: "notes", + label: "Notes → Comments", + description: "Free-form notes attached to cases.", + table: "comments", + conflict: "external_id", + required: ["body", "case_id"], + aliases: { + id: "external_id", noteid: "external_id", externalid: "external_id", + body: "body", content: "body", text: "body", notes: "body", + caseid: "_caseext", matterid: "_caseext", casenumber: "_casenum", + }, + transform: (r, ctx) => { + r.case_id = (r._caseext && ctx.caseByExt.get(String(r._caseext))) || (r._casenum && ctx.caseByNumber.get(String(r._casenum))) || null; + delete r._caseext; delete r._casenum; + if (!r.case_id || !r.body) return null; + r.author_id = ctx.userId; + r.entity_type = "case"; + r.entity_id = r.case_id; + return r; + }, + }, + // Status updates + { + key: "status_updates", + label: "Status updates → Status", + description: "Case status reports.", + table: "status_updates", + conflict: "external_id", + required: ["title", "body", "case_id"], + aliases: { + id: "external_id", statusid: "external_id", externalid: "external_id", + title: "title", subject: "title", + body: "body", content: "body", notes: "body", description: "body", + caseid: "_caseext", matterid: "_caseext", casenumber: "_casenum", + }, + transform: (r, ctx) => { + r.case_id = (r._caseext && ctx.caseByExt.get(String(r._caseext))) || (r._casenum && ctx.caseByNumber.get(String(r._casenum))) || null; + delete r._caseext; delete r._casenum; + if (!r.case_id || !r.body) return null; + return r; + }, + }, +]; + +interface ImportResult { + total: number; + inserted: number; + skipped: number; + errors: string[]; +} + +function ImportPage() { + const { user } = useAuth(); + const [results, setResults] = useState>({}); + const ctx = useMemo(() => ({ + userId: user?.id ?? "", + clientByExt: new Map(), + caseByExt: new Map(), + contactByExt: new Map(), + homeownerByExt: new Map(), + invoiceByExt: new Map(), + clientByName: new Map(), + caseByNumber: new Map(), + }), [user?.id]); + + // Pre-load lookup caches from existing rows so subsequent imports can join + const ensureLookupsLoaded = async () => { + if (ctx.clientByExt.size === 0) { + const { data } = await supabase.from("clients").select("id, name, external_id"); + for (const r of data ?? []) { + if (r.external_id) ctx.clientByExt.set(r.external_id, r.id); + if (r.name) ctx.clientByName.set(r.name.toLowerCase(), r.id); + } + } + if (ctx.caseByExt.size === 0) { + const { data } = await supabase.from("cases").select("id, case_number, external_id"); + for (const r of data ?? []) { + if (r.external_id) ctx.caseByExt.set(r.external_id, r.id); + if (r.case_number) ctx.caseByNumber.set(r.case_number, r.id); + } + } + }; + + const handleFile = async (cfg: ImporterConfig, file: File) => { + if (!user?.id) return; + setResults((r) => ({ ...r, [cfg.key]: "running" })); + await ensureLookupsLoaded(); + + const parsed = await new Promise>>((resolve, reject) => { + Papa.parse>(file, { + header: true, + skipEmptyLines: true, + complete: resolve, + error: reject, + }); + }); + + const rawRows = parsed.data; + const headers = parsed.meta.fields ?? []; + // Build header → db column map + const headerMap: Record = {}; + for (const h of headers) { + const n = norm(h); + const target = cfg.aliases[n] ?? n; + headerMap[h] = target; + } + + const mapped: Row[] = []; + let skipped = 0; + const errors: string[] = []; + + for (const raw of rawRows) { + const row: Row = {}; + for (const [h, target] of Object.entries(headerMap)) { + const v = raw[h]; + if (v === undefined || v === "") continue; + row[target] = v; + } + // type coercions + for (const c of cfg.numeric ?? []) if (c in row) row[c] = toNum(row[c]); + for (const c of cfg.boolCols ?? []) if (c in row) row[c] = toBool(row[c]); + for (const c of cfg.dateCols ?? []) if (c in row) row[c] = toDate(row[c]); + for (const c of cfg.datetimeCols ?? []) if (c in row) row[c] = toDateTime(row[c]); + + // transform + const transformed = cfg.transform ? cfg.transform(row, ctx) : row; + if (!transformed) { skipped++; continue; } + + // required check + const missing = cfg.required.find((k) => !transformed[k] && transformed[k] !== 0); + if (missing) { skipped++; continue; } + + // attach created_by where not present + if (!transformed.created_by && !["time_entries", "expenses", "comments"].includes(cfg.table)) { + transformed.created_by = user.id; + } + mapped.push(transformed); + } + + if (mapped.length === 0) { + setResults((r) => ({ ...r, [cfg.key]: { total: rawRows.length, inserted: 0, skipped, errors: ["No valid rows after mapping. Check headers/required fields."] } })); + return; + } + + // Batch upsert in chunks of 200 + const chunkSize = 200; + let inserted = 0; + const inserted_rows: Row[] = []; + for (let i = 0; i < mapped.length; i += chunkSize) { + const chunk = mapped.slice(i, i + chunkSize); + // Filter out rows missing the conflict column for upsert; insert plain + const withConflict = chunk.filter((r) => r[cfg.conflict]); + const withoutConflict = chunk.filter((r) => !r[cfg.conflict]); + + if (withConflict.length > 0) { + const { data, error } = await supabase + .from(cfg.table as any) + .upsert(withConflict as any, { onConflict: cfg.conflict, ignoreDuplicates: false }) + .select("*"); + if (error) { + errors.push(`Batch ${i / chunkSize + 1} (upsert): ${error.message}`); + } else if (data) { + inserted += data.length; + inserted_rows.push(...data); + } + } + if (withoutConflict.length > 0) { + const { data, error } = await supabase + .from(cfg.table as any) + .insert(withoutConflict as any) + .select("*"); + if (error) { + errors.push(`Batch ${i / chunkSize + 1} (insert): ${error.message}`); + } else if (data) { + inserted += data.length; + inserted_rows.push(...data); + } + } + } + + if (cfg.postInsert) cfg.postInsert(inserted_rows, ctx); + + const summary = { total: rawRows.length, inserted, skipped, errors }; + setResults((r) => ({ ...r, [cfg.key]: summary })); + if (errors.length === 0) toast.success(`${cfg.label}: ${inserted} imported`); + else toast.error(`${cfg.label}: ${errors.length} batch error(s)`); + }; + + return ( +

+ + + + Headers are auto-mapped (snake_case + common aliases). Existing rows with a matching{" "} + external_id are updated. Import in order: + companies → people/lawyers → locations → cases → tasks/events/calls/time/expenses/invoices/notes/status. + + + +
+ {IMPORTERS.map((cfg) => { + const result = results[cfg.key]; + const running = result === "running"; + const r = typeof result === "object" ? result : null; + return ( + + +
+
+ + + {cfg.label} + +

{cfg.description}

+
+
+ { + const f = e.target.files?.[0]; + if (f) handleFile(cfg, f); + e.target.value = ""; + }} + disabled={running} + /> + +
+
+
+ {r && ( + +
+ {r.errors.length === 0 ? ( + + + {r.inserted} of {r.total} imported + + ) : ( + + + {r.inserted} imported, {r.errors.length} error(s) + + )} + {r.skipped > 0 && ( + {r.skipped} skipped (missing required fields) + )} +
+ {r.errors.length > 0 && ( +
+ {r.errors.slice(0, 3).map((e, i) =>
• {e}
)} +
+ )} +
+ )} +
+ ); + })} +
+
+ ); +} From 8e9d5acfa02cc35d95a5c62be5516ea1b46277c1 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:18:45 +0000 Subject: [PATCH 5/5] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routeTree.gen.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 026bfc4..f509e07 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -31,6 +31,7 @@ import { Route as SettingsWorkflowsRouteImport } from './routes/settings.workflo import { Route as SettingsWorkflowRouteImport } from './routes/settings.workflow' import { Route as SettingsSmtpRouteImport } from './routes/settings.smtp' import { Route as SettingsProfileRouteImport } from './routes/settings.profile' +import { Route as SettingsImportRouteImport } from './routes/settings.import' import { Route as SettingsImapRouteImport } from './routes/settings.imap' import { Route as SettingsFeesRouteImport } from './routes/settings.fees' import { Route as InvoicesInvoiceIdRouteImport } from './routes/invoices.$invoiceId' @@ -156,6 +157,11 @@ const SettingsProfileRoute = SettingsProfileRouteImport.update({ path: '/profile', getParentRoute: () => SettingsRoute, } as any) +const SettingsImportRoute = SettingsImportRouteImport.update({ + id: '/import', + path: '/import', + getParentRoute: () => SettingsRoute, +} as any) const SettingsImapRoute = SettingsImapRouteImport.update({ id: '/imap', path: '/imap', @@ -243,6 +249,7 @@ export interface FileRoutesByFullPath { '/invoices/$invoiceId': typeof InvoicesInvoiceIdRoute '/settings/fees': typeof SettingsFeesRoute '/settings/imap': typeof SettingsImapRoute + '/settings/import': typeof SettingsImportRoute '/settings/profile': typeof SettingsProfileRoute '/settings/smtp': typeof SettingsSmtpRoute '/settings/workflow': typeof SettingsWorkflowRoute @@ -280,6 +287,7 @@ export interface FileRoutesByTo { '/invoices/$invoiceId': typeof InvoicesInvoiceIdRoute '/settings/fees': typeof SettingsFeesRoute '/settings/imap': typeof SettingsImapRoute + '/settings/import': typeof SettingsImportRoute '/settings/profile': typeof SettingsProfileRoute '/settings/smtp': typeof SettingsSmtpRoute '/settings/workflow': typeof SettingsWorkflowRoute @@ -319,6 +327,7 @@ export interface FileRoutesById { '/invoices/$invoiceId': typeof InvoicesInvoiceIdRoute '/settings/fees': typeof SettingsFeesRoute '/settings/imap': typeof SettingsImapRoute + '/settings/import': typeof SettingsImportRoute '/settings/profile': typeof SettingsProfileRoute '/settings/smtp': typeof SettingsSmtpRoute '/settings/workflow': typeof SettingsWorkflowRoute @@ -359,6 +368,7 @@ export interface FileRouteTypes { | '/invoices/$invoiceId' | '/settings/fees' | '/settings/imap' + | '/settings/import' | '/settings/profile' | '/settings/smtp' | '/settings/workflow' @@ -396,6 +406,7 @@ export interface FileRouteTypes { | '/invoices/$invoiceId' | '/settings/fees' | '/settings/imap' + | '/settings/import' | '/settings/profile' | '/settings/smtp' | '/settings/workflow' @@ -434,6 +445,7 @@ export interface FileRouteTypes { | '/invoices/$invoiceId' | '/settings/fees' | '/settings/imap' + | '/settings/import' | '/settings/profile' | '/settings/smtp' | '/settings/workflow' @@ -646,6 +658,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof SettingsProfileRouteImport parentRoute: typeof SettingsRoute } + '/settings/import': { + id: '/settings/import' + path: '/import' + fullPath: '/settings/import' + preLoaderRoute: typeof SettingsImportRouteImport + parentRoute: typeof SettingsRoute + } '/settings/imap': { id: '/settings/imap' path: '/imap' @@ -750,6 +769,7 @@ declare module '@tanstack/react-router' { interface SettingsRouteChildren { SettingsFeesRoute: typeof SettingsFeesRoute SettingsImapRoute: typeof SettingsImapRoute + SettingsImportRoute: typeof SettingsImportRoute SettingsProfileRoute: typeof SettingsProfileRoute SettingsSmtpRoute: typeof SettingsSmtpRoute SettingsWorkflowRoute: typeof SettingsWorkflowRoute @@ -760,6 +780,7 @@ interface SettingsRouteChildren { const SettingsRouteChildren: SettingsRouteChildren = { SettingsFeesRoute: SettingsFeesRoute, SettingsImapRoute: SettingsImapRoute, + SettingsImportRoute: SettingsImportRoute, SettingsProfileRoute: SettingsProfileRoute, SettingsSmtpRoute: SettingsSmtpRoute, SettingsWorkflowRoute: SettingsWorkflowRoute,