ConceptPortal-public/rsconcept/frontend/src/context/RSFormContext.tsx

333 lines
10 KiB
TypeScript
Raw Normal View History

import { createContext, useCallback, useContext, useMemo, useState } from 'react';
2023-07-25 20:27:29 +03:00
import { type ErrorInfo } from '../components/BackendError';
import { useRSFormDetails } from '../hooks/useRSFormDetails';
import { ILibraryItem } from '../models/library';
import { ILibraryUpdateData } from '../models/library';
2023-09-11 20:31:54 +03:00
import {
IConstituentaList, IConstituentaMeta, ICstCreateData,
ICstMovetoData, ICstRenameData, ICstUpdateData,
IRSForm, IRSFormUploadData
} from '../models/rsform';
2023-07-25 20:27:29 +03:00
import {
2023-08-26 17:26:49 +03:00
type DataCallback, deleteUnsubscribe,
getTRSFile,
2023-08-23 01:36:17 +03:00
patchConstituenta, patchDeleteConstituenta,
2023-08-25 22:51:20 +03:00
patchLibraryItem,
2023-08-23 01:36:17 +03:00
patchMoveConstituenta, patchRenameConstituenta,
patchResetAliases, patchUploadTRS, postClaimLibraryItem, postNewConstituenta, postSubscribe} from '../utils/backendAPI';
import { useAuth } from './AuthContext';
import { useLibrary } from './LibraryContext';
2023-07-15 17:46:19 +03:00
interface IRSFormContext {
schema?: IRSForm
2023-07-15 17:46:19 +03:00
error: ErrorInfo
loading: boolean
processing: boolean
2023-12-04 14:19:54 +03:00
isMutable: boolean
2023-07-21 00:09:05 +03:00
isOwned: boolean
2023-07-15 17:46:19 +03:00
isClaimable: boolean
2023-07-20 17:11:03 +03:00
isTracking: boolean
adminMode: boolean
toggleAdminMode: () => void
readerMode: boolean
toggleReaderMode: () => void
2023-07-28 01:37:26 +03:00
2023-08-25 22:51:20 +03:00
update: (data: ILibraryUpdateData, callback?: DataCallback<ILibraryItem>) => void
claim: (callback?: DataCallback<ILibraryItem>) => void
2023-08-26 17:26:49 +03:00
subscribe: (callback?: () => void) => void
unsubscribe: (callback?: () => void) => void
download: (callback: DataCallback<Blob>) => void
2023-07-27 22:04:25 +03:00
upload: (data: IRSFormUploadData, callback: () => void) => void
2023-07-27 22:04:25 +03:00
resetAliases: (callback: () => void) => void
cstCreate: (data: ICstCreateData, callback?: DataCallback<IConstituentaMeta>) => void
2023-08-23 01:36:17 +03:00
cstRename: (data: ICstRenameData, callback?: DataCallback<IConstituentaMeta>) => void
cstUpdate: (data: ICstUpdateData, callback?: DataCallback<IConstituentaMeta>) => void
cstDelete: (data: IConstituentaList, callback?: () => void) => void
cstMoveTo: (data: ICstMovetoData, callback?: () => void) => void
2023-07-15 17:46:19 +03:00
}
2023-07-25 20:27:29 +03:00
const RSFormContext = createContext<IRSFormContext | null>(null)
export const useRSForm = () => {
2023-07-25 20:27:29 +03:00
const context = useContext(RSFormContext)
if (context === null) {
throw new Error('useRSForm has to be used within <RSFormState.Provider>');
}
return context;
}
2023-07-15 17:46:19 +03:00
interface RSFormStateProps {
schemaID: string
2023-07-15 17:46:19 +03:00
children: React.ReactNode
}
export const RSFormState = ({ schemaID, children }: RSFormStateProps) => {
2023-08-27 15:39:49 +03:00
const library = useLibrary();
2023-08-09 17:19:12 +03:00
const { user } = useAuth();
const { schema, reload, error, setError, setSchema, loading } = useRSFormDetails({ target: schemaID });
const [processing, setProcessing] = useState(false);
2023-07-15 17:46:19 +03:00
const [adminMode, setAdminMode] = useState(false);
const [readerMode, setReaderMode] = useState(false);
const [toggleTracking, setToggleTracking] = useState(false);
2023-07-20 17:11:03 +03:00
2023-08-25 22:51:20 +03:00
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]);
2023-12-04 14:19:54 +03:00
const isMutable = useMemo(
2023-08-25 22:51:20 +03:00
() => {
return (
!loading && !processing && !readerMode &&
2023-11-30 02:14:24 +03:00
((isOwned || (adminMode && user?.is_staff)) ?? false)
2023-08-25 22:51:20 +03:00
);
}, [user?.is_staff, readerMode, adminMode, isOwned, loading, processing]);
const isTracking = useMemo(
2023-08-25 22:51:20 +03:00
() => {
2023-08-26 19:39:49 +03:00
if (!user || !schema || !user.id) {
2023-08-26 17:26:49 +03:00
return false;
}
return schema.subscribers.includes(user.id);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user, schema, toggleTracking]);
2023-07-20 17:11:03 +03:00
const update = useCallback(
2023-08-25 22:51:20 +03:00
(data: ILibraryUpdateData, callback?: DataCallback<ILibraryItem>) => {
2023-08-09 17:19:12 +03:00
if (!schema) {
return;
}
setError(undefined)
2023-08-25 22:51:20 +03:00
patchLibraryItem(schemaID, {
2023-08-09 17:19:12 +03:00
data: data,
showError: true,
setLoading: setProcessing,
onError: error => setError(error),
onSuccess: newData => {
setSchema(Object.assign(schema, newData));
library.localUpdateItem(newData);
2023-08-09 17:19:12 +03:00
if (callback) callback(newData);
}
2023-08-09 17:19:12 +03:00
});
2023-08-27 15:39:49 +03:00
}, [schemaID, setError, setSchema, schema, library]);
2023-07-27 22:04:25 +03:00
const upload = useCallback(
2023-08-09 17:19:12 +03:00
(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);
library.localUpdateItem(newData);
2023-08-09 17:19:12 +03:00
if (callback) callback();
2023-07-27 22:04:25 +03:00
}
2023-08-09 17:19:12 +03:00
});
2023-08-27 15:39:49 +03:00
}, [schemaID, setError, setSchema, schema, library]);
2023-07-15 17:46:19 +03:00
const claim = useCallback(
2023-08-25 22:51:20 +03:00
(callback?: DataCallback<ILibraryItem>) => {
2023-08-09 17:19:12 +03:00
if (!schema || !user) {
return;
}
setError(undefined)
2023-08-25 22:51:20 +03:00
postClaimLibraryItem(schemaID, {
2023-08-09 17:19:12 +03:00
showError: true,
setLoading: setProcessing,
onError: error => setError(error),
onSuccess: newData => {
setSchema(Object.assign(schema, newData));
library.localUpdateItem(newData);
if (!user.subscriptions.includes(newData.id)) {
user.subscriptions.push(newData.id);
2023-08-27 15:39:49 +03:00
}
2023-08-09 17:19:12 +03:00
if (callback) callback(newData);
}
2023-08-09 17:19:12 +03:00
});
2023-08-27 15:39:49 +03:00
}, [schemaID, setError, schema, user, setSchema, library]);
2023-08-26 17:26:49 +03:00
const subscribe = useCallback(
(callback?: () => void) => {
if (!schema || !user) {
return;
}
setError(undefined)
postSubscribe(schemaID, {
showError: true,
setLoading: setProcessing,
onError: error => setError(error),
onSuccess: () => {
2023-08-26 19:39:49 +03:00
if (user.id && !schema.subscribers.includes(user.id)) {
2023-08-26 17:26:49 +03:00
schema.subscribers.push(user.id);
}
if (!user.subscriptions.includes(schema.id)) {
user.subscriptions.push(schema.id);
}
setToggleTracking(prev => !prev);
if (callback) callback();
}
});
}, [schemaID, setError, schema, user]);
const unsubscribe = useCallback(
(callback?: () => void) => {
if (!schema || !user) {
return;
}
setError(undefined)
deleteUnsubscribe(schemaID, {
showError: true,
setLoading: setProcessing,
onError: error => setError(error),
onSuccess: () => {
2023-08-26 19:39:49 +03:00
if (user.id && schema.subscribers.includes(user.id)) {
2023-08-26 17:26:49 +03:00
schema.subscribers.splice(schema.subscribers.indexOf(user.id), 1);
}
if (user.subscriptions.includes(schema.id)) {
user.subscriptions.splice(user.subscriptions.indexOf(schema.id), 1);
}
setToggleTracking(prev => !prev);
if (callback) callback();
}
});
}, [schemaID, setError, schema, user]);
2023-07-15 17:46:19 +03:00
2023-07-27 22:04:25 +03:00
const resetAliases = useCallback(
2023-08-09 17:19:12 +03:00
(callback?: () => void) => {
if (!schema || !user) {
return;
}
setError(undefined)
patchResetAliases(schemaID, {
showError: true,
setLoading: setProcessing,
2023-08-23 01:36:17 +03:00
onError: error => setError(error),
2023-08-09 17:19:12 +03:00
onSuccess: newData => {
setSchema(Object.assign(schema, newData));
library.localUpdateTimestamp(newData.id);
2023-08-09 17:19:12 +03:00
if (callback) callback();
2023-07-27 22:04:25 +03:00
}
2023-08-09 17:19:12 +03:00
});
}, [schemaID, setError, schema, library, user, setSchema]);
2023-07-27 22:04:25 +03:00
const download = useCallback(
2023-08-09 17:19:12 +03:00
(callback: DataCallback<Blob>) => {
setError(undefined)
getTRSFile(schemaID, {
showError: true,
setLoading: setProcessing,
2023-08-23 01:36:17 +03:00
onError: error => setError(error),
2023-08-09 17:19:12 +03:00
onSuccess: callback
});
}, [schemaID, setError]);
2023-07-16 22:25:23 +03:00
const cstCreate = useCallback(
2023-08-09 17:19:12 +03:00
(data: ICstCreateData, callback?: DataCallback<IConstituentaMeta>) => {
setError(undefined)
postNewConstituenta(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
2023-08-23 01:36:17 +03:00
onError: error => setError(error),
2023-08-09 17:19:12 +03:00
onSuccess: newData => {
setSchema(newData.schema);
library.localUpdateTimestamp(newData.schema.id);
2023-08-09 17:19:12 +03:00
if (callback) callback(newData.new_cst);
}
});
}, [schemaID, setError, library, setSchema]);
2023-07-18 14:55:40 +03:00
const cstDelete = useCallback(
2023-08-09 17:19:12 +03:00
(data: IConstituentaList, callback?: () => void) => {
setError(undefined)
patchDeleteConstituenta(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
2023-08-23 01:36:17 +03:00
onError: error => setError(error),
2023-08-09 17:19:12 +03:00
onSuccess: newData => {
setSchema(newData);
library.localUpdateTimestamp(newData.id);
2023-08-09 17:19:12 +03:00
if (callback) callback();
}
});
}, [schemaID, setError, library, setSchema]);
const cstUpdate = useCallback(
2023-08-09 17:19:12 +03:00
(data: ICstUpdateData, callback?: DataCallback<IConstituentaMeta>) => {
setError(undefined)
patchConstituenta(String(data.id), {
2023-08-09 17:19:12 +03:00
data: data,
showError: true,
setLoading: setProcessing,
2023-08-23 01:36:17 +03:00
onError: error => setError(error),
2023-08-27 16:35:17 +03:00
onSuccess: newData => reload(setProcessing, () => {
library.localUpdateTimestamp(Number(schemaID));
2023-08-27 16:35:17 +03:00
if (callback) callback(newData);
})
2023-08-09 17:19:12 +03:00
});
}, [setError, schemaID, library, reload]);
2023-07-25 20:27:29 +03:00
2023-08-23 01:36:17 +03:00
const cstRename = useCallback(
(data: ICstRenameData, callback?: DataCallback<IConstituentaMeta>) => {
setError(undefined)
patchRenameConstituenta(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
onError: error => setError(error),
onSuccess: newData => {
2023-08-23 12:15:16 +03:00
setSchema(newData.schema);
library.localUpdateTimestamp(newData.schema.id);
2023-08-23 12:15:16 +03:00
if (callback) callback(newData.new_cst);
2023-08-23 01:36:17 +03:00
}
});
}, [setError, setSchema, library, schemaID]);
2023-08-23 01:36:17 +03:00
2023-07-25 20:27:29 +03:00
const cstMoveTo = useCallback(
2023-08-09 17:19:12 +03:00
(data: ICstMovetoData, callback?: () => void) => {
setError(undefined)
patchMoveConstituenta(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
2023-08-23 01:36:17 +03:00
onError: error => setError(error),
2023-08-09 17:19:12 +03:00
onSuccess: newData => {
setSchema(newData);
library.localUpdateTimestamp(Number(schemaID));
2023-08-09 17:19:12 +03:00
if (callback) callback();
}
});
}, [schemaID, setError, library, setSchema]);
2023-07-15 17:46:19 +03:00
return (
<RSFormContext.Provider value={{
schema,
error, loading, processing,
adminMode, readerMode, isOwned, isMutable,
isClaimable, isTracking,
update, download, upload, claim, resetAliases, subscribe, unsubscribe,
cstUpdate, cstCreate, cstRename, cstDelete, cstMoveTo,
toggleAdminMode: () => setAdminMode(prev => !prev),
toggleReaderMode: () => setReaderMode(prev => !prev)
}}>
{ children }
</RSFormContext.Provider>);
2023-07-25 20:27:29 +03:00
}