useStripeSyncStatus.ts99 lines · main
1import { useEffect } from 'react'
2import { getCurrentVersion, parseSchemaComment } from 'stripe-experiment-sync/supabase'
3
4import {
5 findStripeSchema,
6 isInProgress,
7 isInstalled,
8 type StripeSyncStatusResult,
9} from '@/components/interfaces/Integrations/templates/StripeSyncEngine/stripe-sync-status'
10import { useStripeSyncingState } from '@/data/database-integrations/stripe/sync-state-query'
11import { Schema, useSchemasQuery } from '@/data/database/schemas-query'
12import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
13
14// Maximum time allowed for installation or uninstallation operations before the UI times out
15const OPERATION_TIME_OUT_MS: number = 5 * 60 * 1000 // 5 minutes
16
17export 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 */
53export 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}