import { createContext, useCallback, useContext, useMemo, useState } from 'react' import { toast } from 'react-toastify' import { type ErrorInfo } from '../components/BackendError' import { useRSFormDetails } from '../hooks/useRSFormDetails' import { type DataCallback, getTRSFile, patchConstituenta, patchDeleteConstituenta, patchLibraryItem, patchMoveConstituenta, patchRenameConstituenta, patchResetAliases, patchUploadTRS, postClaimLibraryItem, postNewConstituenta } from '../utils/backendAPI' import { IConstituentaList, IConstituentaMeta, ICstCreateData, ICstMovetoData, ICstRenameData, ICstUpdateData, ILibraryItem, ILibraryUpdateData, IRSForm, IRSFormUploadData } from '../utils/models' import { useAuth } from './AuthContext' interface IRSFormContext { schema?: IRSForm error: ErrorInfo loading: boolean processing: boolean isOwned: boolean isEditable: boolean isClaimable: boolean isReadonly: boolean isTracking: boolean isForceAdmin: boolean toggleForceAdmin: () => void toggleReadonly: () => void toggleTracking: () => void update: (data: ILibraryUpdateData, callback?: DataCallback) => void claim: (callback?: DataCallback) => void download: (callback: DataCallback) => void upload: (data: IRSFormUploadData, callback: () => void) => void resetAliases: (callback: () => void) => void cstCreate: (data: ICstCreateData, callback?: DataCallback) => void cstRename: (data: ICstRenameData, callback?: DataCallback) => void cstUpdate: (data: ICstUpdateData, callback?: DataCallback) => void cstDelete: (data: IConstituentaList, callback?: () => void) => void cstMoveTo: (data: ICstMovetoData, callback?: () => void) => void } const RSFormContext = createContext(null) export const useRSForm = () => { const context = useContext(RSFormContext) if (context === null) { throw new Error( 'useRSForm has to be used within ' ) } return context } interface RSFormStateProps { schemaID: string children: React.ReactNode } export const RSFormState = ({ schemaID, children }: RSFormStateProps) => { const { user } = useAuth(); const { schema, reload, error, setError, setSchema, loading } = useRSFormDetails({ target: schemaID }); const [ processing, setProcessing ] = useState(false); const [ isForceAdmin, setIsForceAdmin ] = useState(false); const [ isReadonly, setIsReadonly ] = useState(false); const isOwned = useMemo( () => { return user?.id === schema?.owner || false; }, [user, schema?.owner]); const isClaimable = useMemo( () => { return (user?.id !== schema?.owner && schema?.is_common && !schema?.is_canonical) ?? false; }, [user, schema?.owner, schema?.is_common, schema?.is_canonical]); const isEditable = useMemo( () => { return ( !loading && !processing && !isReadonly && ((isOwned || (isForceAdmin && user?.is_staff)) ?? false) ); }, [user?.is_staff, isReadonly, isForceAdmin, isOwned, loading, processing]); const isTracking = useMemo( () => { return true; }, []); const toggleTracking = useCallback( () => { toast.info('Отслеживание в разработке...') }, []); const update = useCallback( (data: ILibraryUpdateData, callback?: DataCallback) => { if (!schema) { return; } setError(undefined) patchLibraryItem(schemaID, { data: data, showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: newData => { setSchema(Object.assign(schema, newData)); if (callback) callback(newData); } }); }, [schemaID, setError, setSchema, schema]); const upload = useCallback( (data: IRSFormUploadData, callback?: () => void) => { if (!schema) { return; } setError(undefined) patchUploadTRS(schemaID, { data: data, showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: newData => { setSchema(newData); if (callback) callback(); } }); }, [schemaID, setError, setSchema, schema]); const claim = useCallback( (callback?: DataCallback) => { if (!schema || !user) { return; } setError(undefined) postClaimLibraryItem(schemaID, { showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: newData => { setSchema(Object.assign(schema, newData)); if (callback) callback(newData); } }); }, [schemaID, setError, schema, user, setSchema]); const resetAliases = useCallback( (callback?: () => void) => { if (!schema || !user) { return; } setError(undefined) patchResetAliases(schemaID, { showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: newData => { setSchema(Object.assign(schema, newData)); if (callback) callback(); } }); }, [schemaID, setError, schema, user, setSchema]); const download = useCallback( (callback: DataCallback) => { setError(undefined) getTRSFile(schemaID, { showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: callback }); }, [schemaID, setError]); const cstCreate = useCallback( (data: ICstCreateData, callback?: DataCallback) => { setError(undefined) postNewConstituenta(schemaID, { data: data, showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: newData => { setSchema(newData.schema); if (callback) callback(newData.new_cst); } }); }, [schemaID, setError, setSchema]); const cstDelete = useCallback( (data: IConstituentaList, callback?: () => void) => { setError(undefined) patchDeleteConstituenta(schemaID, { data: data, showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: newData => { setSchema(newData); if (callback) callback(); } }); }, [schemaID, setError, setSchema]); const cstUpdate = useCallback( (data: ICstUpdateData, callback?: DataCallback) => { setError(undefined) patchConstituenta(String(data.id), { data: data, showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: newData => { reload(setProcessing, () => { if (callback) callback(newData); }) } }); }, [setError, reload]); const cstRename = useCallback( (data: ICstRenameData, callback?: DataCallback) => { setError(undefined) patchRenameConstituenta(schemaID, { data: data, showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: newData => { setSchema(newData.schema); if (callback) callback(newData.new_cst); } }); }, [setError, setSchema, schemaID]); const cstMoveTo = useCallback( (data: ICstMovetoData, callback?: () => void) => { setError(undefined) patchMoveConstituenta(schemaID, { data: data, showError: true, setLoading: setProcessing, onError: error => setError(error), onSuccess: newData => { setSchema(newData); if (callback) callback(); } }); }, [schemaID, setError, setSchema]); return ( setIsForceAdmin(prev => !prev), toggleReadonly: () => setIsReadonly(prev => !prev), toggleTracking, update, download, upload, claim, resetAliases, cstUpdate, cstCreate, cstRename, cstDelete, cstMoveTo }}> { children } ); }