import { createContext, useCallback, useContext, useState, useMemo, ReactNode, } from 'react' import { postJSON } from '../../../infrastructure/fetch-json' import useIsMounted from '../../../shared/hooks/use-is-mounted' import { set, cloneDeep } from 'lodash' type SSOSubscription = { name: string descriptionKey: string linked?: boolean linkPath: string } type SSOContextValue = { subscriptions: Record unlink: (id: string, signal?: AbortSignal) => Promise } export const SSOContext = createContext(undefined) type SSOProviderProps = { children: ReactNode } export function SSOProvider({ children }: SSOProviderProps) { const isMountedRef = useIsMounted() const [subscriptions, setSubscriptions] = useState(() => { const initialSubscriptions: Record = {} for (const [id, provider] of Object.entries(window.oauthProviders)) { initialSubscriptions[id] = { descriptionKey: provider.descriptionKey, name: provider.name, linkPath: provider.linkPath, linked: !!window.thirdPartyIds[id], } } return initialSubscriptions }) const unlink = useCallback( (providerId: string, signal?: AbortSignal) => { if (!subscriptions[providerId].linked) { return Promise.resolve() } const body = { link: false, providerId, } return postJSON('/user/oauth-unlink', { body, signal }).then(() => { if (isMountedRef.current) { setSubscriptions(subs => set(cloneDeep(subs), `${providerId}.linked`, false) ) } }) }, [isMountedRef, subscriptions] ) const value = useMemo( () => ({ subscriptions, unlink, }), [subscriptions, unlink] ) return {children} } export function useSSOContext() { const context = useContext(SSOContext) if (!context) { throw new Error('SSOContext is only available inside SSOProvider') } return context }