'use client'; import { createContext, useCallback, useContext, useEffect, useState } from 'react'; import { ErrorData } from '@/components/InfoError'; import { ILibraryItem } from '@/models/library'; import { matchLibraryItem } from '@/models/libraryAPI'; import { ILibraryFilter } from '@/models/miscellaneous'; import { IRSForm, IRSFormCreateData, IRSFormData } from '@/models/rsform'; import { loadRSFormData } from '@/models/rsformAPI'; import { DataCallback, deleteLibraryItem, getLibrary, getRSFormDetails, getTemplates, postCloneLibraryItem, postNewRSForm } from '@/utils/backendAPI'; import { useAuth } from './AuthContext'; interface ILibraryContext { items: ILibraryItem[] templates: ILibraryItem[] loading: boolean processing: boolean error: ErrorData setError: (error: ErrorData) => void applyFilter: (params: ILibraryFilter) => ILibraryItem[] retrieveTemplate: (templateID: number, callback: (schema: IRSForm) => void) => void createItem: (data: IRSFormCreateData, callback?: DataCallback) => void cloneItem: (target: number, data: IRSFormCreateData, callback: DataCallback) => void destroyItem: (target: number, callback?: () => void) => void localUpdateItem: (data: ILibraryItem) => void localUpdateTimestamp: (target: number) => void } const LibraryContext = createContext(null) export const useLibrary = (): ILibraryContext => { const context = useContext(LibraryContext); if (context === null) { throw new Error( 'useLibrary has to be used within ' ); } return context; } interface LibraryStateProps { children: React.ReactNode } export const LibraryState = ({ children }: LibraryStateProps) => { const { user } = useAuth(); const [items, setItems] = useState([]); const [templates, setTemplates] = useState([]); const [loading, setLoading] = useState(false); const [processing, setProcessing] = useState(false); const [error, setError] = useState(undefined); const [cachedTemplates, setCachedTemplates] = useState([]); const applyFilter = useCallback( (params: ILibraryFilter) => { let result = items; if (params.is_owned) { result = result.filter(item => item.owner === user?.id); } if (params.is_common !== undefined) { result = result.filter(item => item.is_common === params.is_common); } if (params.is_canonical !== undefined) { result = result.filter(item => item.is_canonical === params.is_canonical); } if (params.is_subscribed !== undefined) { result = result.filter(item => user?.subscriptions.includes(item.id)); } if (params.is_personal !== undefined) { result = result.filter(item => user?.subscriptions.includes(item.id) || item.owner === user?.id); } if (params.query) { result = result.filter(item => matchLibraryItem(item, params.query!)); } return result; }, [items, user]); const retrieveTemplate = useCallback( (templateID: number, callback: (schema: IRSForm) => void) => { const cached = cachedTemplates.find(schema => schema.id == templateID); if (cached) { callback(cached); return; } setError(undefined); getRSFormDetails(String(templateID), { showError: true, setLoading: setLoading, onError: error => setError(error), onSuccess: data => { const schema = loadRSFormData(data); setCachedTemplates(prev => ([...prev, schema])); callback(schema); } }); }, [cachedTemplates]); const reload = useCallback( (callback?: () => void) => { setItems([]); setError(undefined); getLibrary({ setLoading: setLoading, showError: true, onError: error => setError(error), onSuccess: newData => { setItems(newData); if (callback) callback(); } }); setTemplates([]); getTemplates({ showError: true, onSuccess: newData => setTemplates(newData) }); }, []); useEffect(() => { reload(); }, [reload, user]); const localUpdateItem = useCallback( (data: ILibraryItem) => { const libraryItem = items.find(item => item.id === data.id); if (libraryItem) Object.assign(libraryItem, data); }, [items]); const localUpdateTimestamp = useCallback( (target: number) => { const libraryItem = items.find(item => item.id === target); if (libraryItem) { libraryItem.time_update = Date(); } }, [items]); const createItem = useCallback( (data: IRSFormCreateData, callback?: DataCallback) => { setError(undefined); postNewRSForm({ data: data, showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: newSchema => reload(() => { if (user && !user.subscriptions.includes(newSchema.id)) { user.subscriptions.push(newSchema.id); } if (callback) callback(newSchema); }) }); }, [reload, user]); const destroyItem = useCallback( (target: number, callback?: () => void) => { setError(undefined) deleteLibraryItem(String(target), { showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: () => reload(() => { if (user && user.subscriptions.includes(target)) { user.subscriptions.splice(user.subscriptions.findIndex(item => item === target), 1); } if (callback) callback(); }) }); }, [setError, reload, user]); const cloneItem = useCallback( (target: number, data: IRSFormCreateData, callback: DataCallback) => { if (!user) { return; } setError(undefined) postCloneLibraryItem(String(target), { data: data, showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: newSchema => reload(() => { if (user && !user.subscriptions.includes(newSchema.id)) { user.subscriptions.push(newSchema.id); } if (callback) callback(newSchema); }) }); }, [reload, setError, user]); return ( {children} ); }