UNPKG

livesheets-sdk

Version:

LiveSheets SDK for Google Sheets integration with Lovable apps. OAuth onboarding URL: https://livesheets-backend-624058308714.europe-north1.run.app/onboarding

244 lines (243 loc) 8.13 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.useLiveSheets = useLiveSheets; exports.useSheetData = useSheetData; const react_1 = require("react"); const index_1 = require("./index"); /** * React Hook for LiveSheets integration * * @example * ```tsx * import { useLiveSheets } from 'livesheets-sdk/react'; * * function MyComponent() { * const { * isAuthenticated, * data, * connect, * selectSheet * } = useLiveSheets(); * * if (!isAuthenticated) { * return <button onClick={connect}>Connect Google Sheets</button>; * } * * return <div>{data.length} rows loaded</div>; * } * ``` */ function useLiveSheets(options = {}) { const { autoConnect = false, autoLoadData = true, onAuthSuccess, onAuthError, onDataLoaded, backendUrl } = options; // State const [isConnecting, setIsConnecting] = (0, react_1.useState)(false); const [isSelectingSheet, setIsSelectingSheet] = (0, react_1.useState)(false); const [isLoading, setIsLoading] = (0, react_1.useState)(false); const [error, setError] = (0, react_1.useState)(null); const [jwt, setJwt] = (0, react_1.useState)(null); const [client, setClient] = (0, react_1.useState)(null); const [data, setData] = (0, react_1.useState)([]); const [sheetMetadata, setSheetMetadata] = (0, react_1.useState)(null); // Refs to prevent stale closures const authRef = (0, react_1.useRef)(); const clientRef = (0, react_1.useRef)(null); // Initialize auth helper (0, react_1.useEffect)(() => { authRef.current = index_1.LiveSheetsClient.getAuth({ backendUrl }); }, [backendUrl]); // Check for existing auth on mount (0, react_1.useEffect)(() => { const auth = authRef.current; if (!auth) return; const token = auth.getJWT(); if (token) { setJwt(token); const newClient = new index_1.LiveSheetsClient(token); setClient(newClient); clientRef.current = newClient; // Load saved metadata const savedMetadata = localStorage.getItem('livesheets_metadata'); if (savedMetadata) { try { setSheetMetadata(JSON.parse(savedMetadata)); if (autoLoadData) { loadData(newClient); } } catch (e) { console.error('Failed to parse saved metadata:', e); } } onAuthSuccess?.(); } else if (autoConnect) { connect(); } }, [autoConnect, autoLoadData]); // eslint-disable-line react-hooks/exhaustive-deps // Load data helper const loadData = (0, react_1.useCallback)(async (clientInstance) => { const activeClient = clientInstance || clientRef.current; if (!activeClient) return; setIsLoading(true); setError(null); try { const [rows, metadata] = await Promise.all([ activeClient.listRows(), activeClient.getMetadata() ]); setData(rows); setSheetMetadata(metadata); // Save metadata for next session localStorage.setItem('livesheets_metadata', JSON.stringify(metadata)); onDataLoaded?.(rows); } catch (err) { const error = err instanceof Error ? err : new Error('Failed to load data'); setError(error); console.error('Failed to load sheet data:', error); } finally { setIsLoading(false); } }, [onDataLoaded]); // Connect action const connect = (0, react_1.useCallback)(() => { const auth = authRef.current; if (!auth) return; try { setIsConnecting(true); auth.startOAuth(); } catch (err) { const error = err instanceof Error ? err : new Error('Failed to start OAuth'); setError(error); setIsConnecting(false); onAuthError?.(error); } }, [onAuthError]); // Disconnect action const disconnect = (0, react_1.useCallback)(() => { const auth = authRef.current; if (!auth) return; auth.logout(); setJwt(null); setClient(null); clientRef.current = null; setData([]); setSheetMetadata(null); setError(null); localStorage.removeItem('livesheets_metadata'); }, []); // Select sheet action const selectSheet = (0, react_1.useCallback)(async () => { if (!jwt) { setError(new Error('Not authenticated')); return; } setIsSelectingSheet(true); setError(null); try { await index_1.LiveSheetsClient.openSheetPicker({ jwt, onSuccess: async (result) => { setIsSelectingSheet(false); // Reload data after sheet selection await loadData(); }, onCancel: () => { setIsSelectingSheet(false); } }); } catch (err) { const error = err instanceof Error ? err : new Error('Failed to open sheet picker'); setError(error); setIsSelectingSheet(false); } }, [jwt, loadData]); // Refresh action const refresh = (0, react_1.useCallback)(async () => { if (!clientRef.current) { setError(new Error('Not authenticated')); return; } await loadData(); }, [loadData]); return { // Auth state isAuthenticated: !!jwt, isConnecting, // Sheet state hasSheet: !!sheetMetadata, isSelectingSheet, sheetMetadata, // Data state data, isLoading, error, // Actions connect, disconnect, selectSheet, refresh, // Direct client access client }; } /** * Simple hook for just reading sheet data * * @example * ```tsx * const { data, loading, error } = useSheetData(); * ``` */ function useSheetData(jwt) { const [data, setData] = (0, react_1.useState)([]); const [loading, setLoading] = (0, react_1.useState)(true); const [error, setError] = (0, react_1.useState)(null); (0, react_1.useEffect)(() => { const loadData = async () => { try { setLoading(true); setError(null); // Try to get JWT from auth if not provided const token = jwt || index_1.LiveSheetsClient.getAuth().getJWT(); if (!token) { throw new Error('No JWT token available'); } const client = new index_1.LiveSheetsClient(token); const rows = await client.listRows(); setData(rows); } catch (err) { setError(err instanceof Error ? err : new Error('Failed to load data')); } finally { setLoading(false); } }; loadData(); }, [jwt]); return { data, loading, error }; } // Export everything from main module __exportStar(require("./index"), exports);