useStripeSyncStatus.ts99 lines · main
| 1 | import { useEffect } from 'react' |
| 2 | import { getCurrentVersion, parseSchemaComment } from 'stripe-experiment-sync/supabase' |
| 3 | |
| 4 | import { |
| 5 | findStripeSchema, |
| 6 | isInProgress, |
| 7 | isInstalled, |
| 8 | type StripeSyncStatusResult, |
| 9 | } from '@/components/interfaces/Integrations/templates/StripeSyncEngine/stripe-sync-status' |
| 10 | import { useStripeSyncingState } from '@/data/database-integrations/stripe/sync-state-query' |
| 11 | import { Schema, useSchemasQuery } from '@/data/database/schemas-query' |
| 12 | import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' |
| 13 | |
| 14 | // Maximum time allowed for installation or uninstallation operations before the UI times out |
| 15 | const OPERATION_TIME_OUT_MS: number = 5 * 60 * 1000 // 5 minutes |
| 16 | |
| 17 | export const getStripeSyncSchemaComment = (schemas: Schema[]) => { |
| 18 | // Find and parse stripe schema status |
| 19 | const stripeSchema = findStripeSchema(schemas) |
| 20 | const rawSchemaComment = parseSchemaComment(stripeSchema?.comment) |
| 21 | |
| 22 | const now = Date.now() |
| 23 | const timedOut = rawSchemaComment.startTime |
| 24 | ? now - rawSchemaComment.startTime > OPERATION_TIME_OUT_MS |
| 25 | : false |
| 26 | |
| 27 | const status = timedOut |
| 28 | ? rawSchemaComment.status === 'installing' |
| 29 | ? 'install error' |
| 30 | : rawSchemaComment.status === 'uninstalling' |
| 31 | ? 'uninstall error' |
| 32 | : rawSchemaComment.status |
| 33 | : rawSchemaComment.status |
| 34 | |
| 35 | const errorMessage = timedOut |
| 36 | ? rawSchemaComment.status === 'installing' |
| 37 | ? 'Installation timed out' |
| 38 | : rawSchemaComment.status === 'uninstalling' |
| 39 | ? 'Uninstallation timed out' |
| 40 | : rawSchemaComment.errorMessage |
| 41 | : rawSchemaComment.errorMessage |
| 42 | |
| 43 | return { ...rawSchemaComment, status, errorMessage, timedOut } |
| 44 | } |
| 45 | |
| 46 | /** |
| 47 | * Unified hook for Stripe Sync installation status. |
| 48 | * |
| 49 | * This hook consolidates all schema querying, status parsing, and polling logic |
| 50 | * into a single source of truth. It returns a discriminated union status that |
| 51 | * makes impossible states unrepresentable. |
| 52 | */ |
| 53 | export function useStripeSyncStatus(): StripeSyncStatusResult { |
| 54 | const latestAvailableVersion = getCurrentVersion() |
| 55 | const { data: project } = useSelectedProjectQuery() |
| 56 | const { ref: projectRef, connectionString } = project || {} |
| 57 | |
| 58 | // Query schemas once |
| 59 | const { |
| 60 | data: schemas, |
| 61 | isLoading: isSchemasLoading, |
| 62 | refetch, |
| 63 | } = useSchemasQuery({ projectRef, connectionString }, { enabled: !!projectRef }) |
| 64 | |
| 65 | const schemaComment = getStripeSyncSchemaComment(schemas ?? []) |
| 66 | const timedOut = schemaComment.timedOut |
| 67 | const installed = isInstalled(schemaComment.status) |
| 68 | const inProgress = isInProgress(schemaComment.status) |
| 69 | |
| 70 | // Query sync state only when installed |
| 71 | const { data: syncState, isPending: isLoadingStripeSyncState } = useStripeSyncingState( |
| 72 | { projectRef: projectRef!, connectionString }, |
| 73 | { |
| 74 | refetchInterval: 4000, |
| 75 | enabled: !!projectRef && installed, |
| 76 | } |
| 77 | ) |
| 78 | |
| 79 | // Poll schemas during install/uninstall operations |
| 80 | useEffect(() => { |
| 81 | // Return if installation/uninstallation is not in progress |
| 82 | // inProgres is likely to be false during initial render |
| 83 | if (!inProgress) return |
| 84 | |
| 85 | const interval = setInterval(() => { |
| 86 | refetch() |
| 87 | }, 5000) |
| 88 | |
| 89 | return () => clearInterval(interval) |
| 90 | }, [inProgress, refetch]) |
| 91 | |
| 92 | return { |
| 93 | schemaComment, |
| 94 | syncState: installed ? syncState : undefined, |
| 95 | isLoading: isSchemasLoading || isLoadingStripeSyncState, |
| 96 | latestAvailableVersion, |
| 97 | timedOut, |
| 98 | } |
| 99 | } |