From fbd1c2cc4a1f7c99a993c6e0175cd0ae5c6c756f Mon Sep 17 00:00:00 2001 From: MOHAN Date: Fri, 17 Jul 2026 23:43:11 +0530 Subject: [PATCH] Add Sheets-first mirror control --- app/api/google/data-system-mode/route.ts | 6 ++ app/app/connect/page.tsx | 72 +++++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 app/api/google/data-system-mode/route.ts diff --git a/app/api/google/data-system-mode/route.ts b/app/api/google/data-system-mode/route.ts new file mode 100644 index 0000000..2cc3d81 --- /dev/null +++ b/app/api/google/data-system-mode/route.ts @@ -0,0 +1,6 @@ +import { NextRequest } from "next/server"; +import { proxyRequest } from "@/lib/backend"; + +export async function POST(req: NextRequest) { + return proxyRequest(req, "google/data-system-mode"); +} diff --git a/app/app/connect/page.tsx b/app/app/connect/page.tsx index 4dd43f6..d916046 100644 --- a/app/app/connect/page.tsx +++ b/app/app/connect/page.tsx @@ -24,6 +24,23 @@ type TellerEnrollment = { }; }; +type GoogleStatus = { + connected: boolean; + googleEmail?: string; + driveMirror?: { + enabled: boolean; + status: string; + url?: string | null; + lastSyncedAt?: string | null; + }; + dataSystem?: { + mode: string; + operationalSystemOfRecord: string; + userOwnedMirror: boolean; + note: string; + }; +}; + declare global { interface Window { TellerConnect?: { @@ -53,6 +70,7 @@ export default function ConnectPage() { const [manualType, setManualType] = useState("checking"); const [accounts, setAccounts] = useState([]); const [tellerReady, setTellerReady] = useState(false); + const [googleStatus, setGoogleStatus] = useState(null); const createLinkToken = useCallback(async () => { setStatus("Requesting Plaid link token..."); @@ -84,6 +102,13 @@ export default function ConnectPage() { setAccounts(payload.data?.accounts ?? payload.data ?? []); }, []); + const loadGoogleStatus = useCallback(async () => { + const res = await fetch("/api/google/status"); + if (!res.ok) return; + const payload = await res.json(); + setGoogleStatus(payload.data ?? payload); + }, []); + const loadTellerScript = useCallback(() => { if (typeof window === "undefined") return Promise.resolve(false); if (window.TellerConnect) { @@ -115,8 +140,9 @@ export default function ConnectPage() { useEffect(() => { createLinkToken(); loadAccounts(); + loadGoogleStatus(); loadTellerScript(); - }, [createLinkToken, loadAccounts, loadTellerScript]); + }, [createLinkToken, loadAccounts, loadGoogleStatus, loadTellerScript]); const onSuccess = useCallback( async (publicToken: string | null) => { @@ -301,6 +327,22 @@ export default function ConnectPage() { await loadAccounts(); }; + const enableSheetsMirror = async () => { + setStatus("Enabling Sheets-first mirror mode..."); + const res = await fetch("/api/google/data-system-mode", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ mode: "google_sheets_mirror" }) + }); + const payload = await res.json(); + if (!res.ok || payload.error) { + setStatus(payload.error?.message ?? "Unable to enable Sheets-first mirror mode."); + return; + } + setStatus("Sheets-first mirror mode enabled."); + await loadGoogleStatus(); + }; + return ( + +
+

Google Sheets ownership

+

+ Keep a user-owned Google Sheets mirror synced from LedgerOne transaction changes. +

+
+

+ {googleStatus?.connected ? `Connected: ${googleStatus.googleEmail}` : "Google is not connected"} +

+

+ Mode: {googleStatus?.dataSystem?.mode ?? "backend_db"} ยท Mirror: {googleStatus?.driveMirror?.status ?? "not_started"} +

+ {googleStatus?.driveMirror?.url ? ( + + Open Google Sheet + + ) : null} +
+ +
); }