import * as store from '../store/store'; import * as React from 'react'; import { createContext, useEffect } from 'react'; import { useClientContext } from '../hooks/useClientContext'; import { Record } from '../interfaces/Record'; import { recordsAction } from '../store/actions'; import { subscriptionsAction } from '../store/actions'; type SubscribeType = (collectionName: string) => Promise; type UnsubscribeType = (collectionName?: string) => Promise; type FetchType = (collectionName: string, queryParams?: any) => Promise; type CreateType = (collectionName: string, record: {}) => Promise; type UpdateType = ( collectionName: string, recordId: string, record: {} ) => Promise; type DeleteType = (collectionName: string, recordId: string) => Promise; interface ContentActions { subscribe: SubscribeType; unsubscribe: UnsubscribeType; fetch: FetchType; create: CreateType; update: UpdateType; delete: DeleteType; } export const ContentContext = createContext({} as ContentActions); export type ContentProviderProps = { children: React.ReactNode; collections?: string[]; }; interface MessageData { action: string; record: Record; } export const ContentProvider = (props: ContentProviderProps) => { const client = useClientContext(); const dispatch = store.useAppDispatch; function tempErrorHandler(error: any) { // TODO: Handle error // IDEA: Create new ErrorContext and Update it with error if (error?.originalError?.name !== 'AbortError') { console.log('Error in content provider', JSON.stringify(error)); } return error; } const actions: ContentActions = { subscribe: async (collectionName: string) => { try { await client?.realtime .subscribe(collectionName, (event: MessageData) => { switch (event.action) { case 'create': dispatch(recordsAction.addRecord(collectionName, event.record)); break; case 'update': dispatch(recordsAction.updateRecord(collectionName, event.record)); break; case 'delete': dispatch(recordsAction.deleteRecord(collectionName, event.record)); break; default: break; } }) .then(() => { dispatch(subscriptionsAction.addSubscription(collectionName)); }); } catch (error: any) { const errors = JSON.parse(JSON.stringify(error)); throw errors; } }, unsubscribe: async (collectionName?: string) => { try { if (collectionName) { await client?.realtime.unsubscribe(collectionName).then(() => { dispatch(subscriptionsAction.deleteSubscription(collectionName)); }); } else { await client?.realtime.unsubscribe().then(() => { dispatch(subscriptionsAction.setSubscriptions([])); }); } } catch (error: any) { const errors = JSON.parse(JSON.stringify(error)); throw errors; } }, fetch: async (collectionName: string, queryParams?: any) => { try { await client ?.collection(collectionName) .getFullList(200, queryParams) .then((records) => { dispatch(recordsAction.setRecords(collectionName, records as Record[])); }); } catch (error: any) { const errors = JSON.parse(JSON.stringify(error)); throw errors; } }, create: async (collectionName: string, record: {}) => { try { return await client?.collection(collectionName).create(record); } catch (error: any) { const errors = JSON.parse(JSON.stringify(error)); throw errors; } }, update: async (collectionName: string, recordId: string, record: {}) => { try { return await client?.collection(collectionName).update(recordId, record); } catch (error: any) { const errors = JSON.parse(JSON.stringify(error)); throw errors; } // .catch(tempErrorHandler); }, delete: async (collectionName: string, recordId: string) => { try { return await client?.collection(collectionName).delete(recordId); } catch (error: any) { const errors = JSON.parse(JSON.stringify(error)); throw errors; } }, }; useEffect(() => { if (props.collections) { props.collections.forEach(async (collectionName) => { await actions.fetch(collectionName); await actions.subscribe(collectionName); }); } return () => { (async () => { await actions.unsubscribe(); })(); }; }, [props.collections]); return {props.children}; };