PoliciesDataContext.tsx82 lines · main
1import type { PropsWithChildren } from 'react'
2import { createContext, useCallback, useContext, useMemo } from 'react'
3
4import type { Policy } from '@/components/interfaces/Auth/Policies/PolicyTableRow/PolicyTableRow.utils'
5import type { ResponseError } from '@/types'
6
7type TableKey = `${string}.${string}`
8
9type PoliciesDataContextValue = {
10 getPoliciesForTable: (schema: string, table: string) => Array<Policy>
11 isPoliciesLoading: boolean
12 isPoliciesError: boolean
13 policiesError?: ResponseError | Error
14 exposedSchemas: Set<string>
15}
16
17const PoliciesDataContext = createContext<PoliciesDataContextValue | null>(null)
18
19export const usePoliciesData = () => {
20 const context = useContext(PoliciesDataContext)
21 if (!context) throw new Error('usePoliciesData must be used within PoliciesDataProvider')
22 return context
23}
24
25type PoliciesDataProviderProps = {
26 policies: Array<Policy>
27 isPoliciesLoading: boolean
28 isPoliciesError: boolean
29 policiesError?: ResponseError | Error
30 exposedSchemas: string[]
31}
32
33export const PoliciesDataProvider = ({
34 children,
35 policies,
36 isPoliciesLoading,
37 isPoliciesError,
38 policiesError,
39 exposedSchemas,
40}: PropsWithChildren<PoliciesDataProviderProps>) => {
41 const policiesByTable = useMemo(() => {
42 const map = new Map<TableKey, Array<Policy>>()
43
44 for (const policy of policies) {
45 const key = `${policy.schema}.${policy.table}` satisfies TableKey
46 const existing = map.get(key)
47 if (existing) {
48 existing.push(policy)
49 } else {
50 map.set(key, [policy])
51 }
52 }
53
54 for (const list of map.values()) {
55 list.sort((a, b) => a.name.localeCompare(b.name))
56 }
57
58 return map
59 }, [policies])
60
61 const getPoliciesForTable = useCallback(
62 (schema: string, table: string) => policiesByTable.get(`${schema}.${table}`) ?? [],
63 [policiesByTable]
64 )
65
66 const exposedSchemasSet = useMemo(() => new Set(exposedSchemas), [exposedSchemas])
67
68 const contextValue = useMemo(
69 () => ({
70 getPoliciesForTable,
71 isPoliciesLoading,
72 isPoliciesError,
73 policiesError,
74 exposedSchemas: exposedSchemasSet,
75 }),
76 [getPoliciesForTable, isPoliciesLoading, isPoliciesError, policiesError, exposedSchemasSet]
77 )
78
79 return (
80 <PoliciesDataContext.Provider value={contextValue}>{children}</PoliciesDataContext.Provider>
81 )
82}