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

479 lines
13 KiB
TypeScript
Raw Normal View History

'use client';
import { createContext, useCallback, useContext, useMemo, useState } from 'react';
2023-07-25 20:27:29 +03:00
import { type ErrorData } from '@/components/InfoError';
import useRSFormDetails from '@/hooks/useRSFormDetails';
2024-03-04 19:22:22 +03:00
import { ILibraryItem, IVersionData } from '@/models/library';
import { ILibraryUpdateData } from '@/models/library';
2023-09-11 20:31:54 +03:00
import {
2023-12-28 14:04:44 +03:00
IConstituentaList,
IConstituentaMeta,
ICstCreateData,
ICstMovetoData,
ICstRenameData,
ICstSubstituteData,
2023-12-28 14:04:44 +03:00
ICstUpdateData,
IRSForm,
IRSFormUploadData
} from '@/models/rsform';
2023-07-25 20:27:29 +03:00
import {
2023-12-28 14:04:44 +03:00
type DataCallback,
deleteUnsubscribe,
2024-03-04 19:22:22 +03:00
deleteVersion,
getTRSFile,
2023-12-28 14:04:44 +03:00
patchConstituenta,
patchDeleteConstituenta,
patchLibraryItem,
2023-12-28 14:04:44 +03:00
patchMoveConstituenta,
patchRenameConstituenta,
patchResetAliases,
patchSubstituteConstituenta,
2023-12-28 14:04:44 +03:00
patchUploadTRS,
2024-03-04 19:22:22 +03:00
patchVersion,
2023-12-28 14:04:44 +03:00
postClaimLibraryItem,
2024-03-04 19:22:22 +03:00
postCreateVersion,
2023-12-28 14:04:44 +03:00
postNewConstituenta,
postSubscribe
} from '@/utils/backendAPI';
import { useAuth } from './AuthContext';
import { useLibrary } from './LibraryContext';
2023-07-15 17:46:19 +03:00
interface IRSFormContext {
2023-12-28 14:04:44 +03:00
schema?: IRSForm;
2024-03-04 19:22:22 +03:00
schemaID: string;
2023-12-28 14:04:44 +03:00
error: ErrorData;
loading: boolean;
processing: boolean;
2024-03-04 19:22:22 +03:00
isArchive: boolean;
2023-12-28 14:04:44 +03:00
isOwned: boolean;
isClaimable: boolean;
isSubscribed: boolean;
2023-12-28 14:04:44 +03:00
update: (data: ILibraryUpdateData, callback?: DataCallback<ILibraryItem>) => void;
claim: (callback?: DataCallback<ILibraryItem>) => void;
subscribe: (callback?: () => void) => void;
unsubscribe: (callback?: () => void) => void;
download: (callback: DataCallback<Blob>) => void;
upload: (data: IRSFormUploadData, callback: () => void) => void;
2023-12-28 14:04:44 +03:00
resetAliases: (callback: () => void) => void;
cstCreate: (data: ICstCreateData, callback?: DataCallback<IConstituentaMeta>) => void;
cstRename: (data: ICstRenameData, callback?: DataCallback<IConstituentaMeta>) => void;
cstSubstitute: (data: ICstSubstituteData, callback?: () => void) => void;
2023-12-28 14:04:44 +03:00
cstUpdate: (data: ICstUpdateData, callback?: DataCallback<IConstituentaMeta>) => void;
cstDelete: (data: IConstituentaList, callback?: () => void) => void;
cstMoveTo: (data: ICstMovetoData, callback?: () => void) => void;
2024-03-04 19:22:22 +03:00
versionCreate: (data: IVersionData, callback?: (version: number) => void) => void;
2024-03-04 19:22:22 +03:00
versionUpdate: (target: number, data: IVersionData, callback?: () => void) => void;
versionDelete: (target: number, callback?: () => void) => void;
2023-07-15 17:46:19 +03:00
}
2023-12-28 14:04:44 +03:00
const RSFormContext = createContext<IRSFormContext | null>(null);
export const useRSForm = () => {
2023-12-28 14:04:44 +03:00
const context = useContext(RSFormContext);
if (context === null) {
throw new Error('useRSForm has to be used within <RSFormState.Provider>');
}
return context;
2023-12-28 14:04:44 +03:00
};
2023-07-15 17:46:19 +03:00
interface RSFormStateProps {
2023-12-28 14:04:44 +03:00
schemaID: string;
2024-03-04 19:22:22 +03:00
versionID?: string;
2023-12-28 14:04:44 +03:00
children: React.ReactNode;
2023-07-15 17:46:19 +03:00
}
2024-03-04 19:22:22 +03:00
export const RSFormState = ({ schemaID, versionID, children }: RSFormStateProps) => {
2023-08-27 15:39:49 +03:00
const library = useLibrary();
2023-08-09 17:19:12 +03:00
const { user } = useAuth();
2024-03-04 19:22:22 +03:00
const {
schema, // prettier: split lines
reload,
error,
setError,
setSchema,
loading
} = useRSFormDetails({
target: schemaID,
version: versionID
});
const [processing, setProcessing] = useState(false);
2023-07-15 17:46:19 +03:00
const [toggleTracking, setToggleTracking] = useState(false);
2023-07-20 17:11:03 +03:00
2023-12-28 14:04:44 +03:00
const isOwned = useMemo(() => {
2023-08-25 22:51:20 +03:00
return user?.id === schema?.owner || false;
}, [user, schema?.owner]);
2024-03-04 19:22:22 +03:00
const isArchive = useMemo(() => !!versionID, [versionID]);
2023-12-28 14:04:44 +03:00
const isClaimable = useMemo(() => {
return isArchive && ((user?.id !== schema?.owner && schema?.is_common && !schema?.is_canonical) ?? false);
}, [user, schema?.owner, schema?.is_common, schema?.is_canonical, isArchive]);
2023-08-25 22:51:20 +03:00
2023-12-28 14:04:44 +03:00
const isSubscribed = useMemo(() => {
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);
2023-12-28 14:04:44 +03:00
// eslint-disable-next-line react-hooks/exhaustive-deps
2023-08-26 17:26:49 +03:00
}, [user, schema, toggleTracking]);
2023-07-20 17:11:03 +03:00
const update = useCallback(
2023-12-28 14:04:44 +03:00
(data: ILibraryUpdateData, callback?: DataCallback<ILibraryItem>) => {
if (!schema) {
return;
}
2023-12-28 14:04:44 +03:00
setError(undefined);
patchLibraryItem(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
2024-01-04 22:10:57 +03:00
onError: setError,
2023-12-28 14:04:44 +03:00
onSuccess: newData => {
setSchema(Object.assign(schema, newData));
library.localUpdateItem(newData);
if (callback) callback(newData);
}
});
},
[schemaID, setError, setSchema, schema, library]
);
2023-07-27 22:04:25 +03:00
const upload = useCallback(
2023-12-28 14:04:44 +03:00
(data: IRSFormUploadData, callback?: () => void) => {
if (!schema) {
return;
2023-07-27 22:04:25 +03:00
}
2023-12-28 14:04:44 +03:00
setError(undefined);
patchUploadTRS(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
2024-01-04 22:10:57 +03:00
onError: setError,
2023-12-28 14:04:44 +03:00
onSuccess: newData => {
setSchema(newData);
library.localUpdateItem(newData);
if (callback) callback();
}
});
},
[schemaID, setError, setSchema, schema, library]
);
2023-07-15 17:46:19 +03:00
const claim = useCallback(
2023-12-28 14:04:44 +03:00
(callback?: DataCallback<ILibraryItem>) => {
if (!schema || !user) {
return;
}
2023-12-28 14:04:44 +03:00
setError(undefined);
postClaimLibraryItem(schemaID, {
showError: true,
setLoading: setProcessing,
2024-01-04 22:10:57 +03:00
onError: setError,
2023-12-28 14:04:44 +03:00
onSuccess: newData => {
setSchema(Object.assign(schema, newData));
library.localUpdateItem(newData);
if (!user.subscriptions.includes(newData.id)) {
user.subscriptions.push(newData.id);
}
if (callback) callback(newData);
2023-08-26 17:26:49 +03:00
}
2023-12-28 14:04:44 +03:00
});
},
[schemaID, setError, schema, user, setSchema, library]
);
const subscribe = useCallback(
(callback?: () => void) => {
if (!schema || !user) {
return;
2023-08-26 17:26:49 +03:00
}
2023-12-28 14:04:44 +03:00
setError(undefined);
postSubscribe(schemaID, {
showError: true,
setLoading: setProcessing,
2024-01-04 22:10:57 +03:00
onError: setError,
2023-12-28 14:04:44 +03:00
onSuccess: () => {
if (user.id && !schema.subscribers.includes(user.id)) {
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]
);
2023-08-26 17:26:49 +03:00
const unsubscribe = useCallback(
2023-12-28 14:04:44 +03:00
(callback?: () => void) => {
if (!schema || !user) {
return;
2023-08-26 17:26:49 +03:00
}
2023-12-28 14:04:44 +03:00
setError(undefined);
deleteUnsubscribe(schemaID, {
showError: true,
setLoading: setProcessing,
2024-01-04 22:10:57 +03:00
onError: setError,
2023-12-28 14:04:44 +03:00
onSuccess: () => {
if (user.id && schema.subscribers.includes(user.id)) {
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-12-28 14:04:44 +03:00
(callback?: () => void) => {
if (!schema || !user) {
return;
2023-07-27 22:04:25 +03:00
}
2023-12-28 14:04:44 +03:00
setError(undefined);
patchResetAliases(schemaID, {
showError: true,
setLoading: setProcessing,
2024-01-04 22:10:57 +03:00
onError: setError,
2023-12-28 14:04:44 +03:00
onSuccess: newData => {
setSchema(Object.assign(schema, newData));
library.localUpdateTimestamp(newData.id);
if (callback) callback();
}
});
},
[schemaID, setError, schema, library, user, setSchema]
);
2023-07-27 22:04:25 +03:00
const download = useCallback(
2023-12-28 14:04:44 +03:00
(callback: DataCallback<Blob>) => {
setError(undefined);
getTRSFile(schemaID, String(schema?.version) ?? '', {
2023-12-28 14:04:44 +03:00
showError: true,
setLoading: setProcessing,
2024-01-04 22:10:57 +03:00
onError: setError,
2023-12-28 14:04:44 +03:00
onSuccess: callback
});
},
[schemaID, setError, schema]
2023-12-28 14:04:44 +03:00
);
2023-07-16 22:25:23 +03:00
const cstCreate = useCallback(
2023-12-28 14:04:44 +03:00
(data: ICstCreateData, callback?: DataCallback<IConstituentaMeta>) => {
setError(undefined);
postNewConstituenta(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
2024-01-04 22:10:57 +03:00
onError: setError,
2023-12-28 14:04:44 +03:00
onSuccess: newData => {
setSchema(newData.schema);
library.localUpdateTimestamp(newData.schema.id);
if (callback) callback(newData.new_cst);
}
});
},
[schemaID, setError, library, setSchema]
);
2023-07-18 14:55:40 +03:00
const cstDelete = useCallback(
2023-12-28 14:04:44 +03:00
(data: IConstituentaList, callback?: () => void) => {
setError(undefined);
patchDeleteConstituenta(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
2024-01-04 22:10:57 +03:00
onError: setError,
2023-12-28 14:04:44 +03:00
onSuccess: newData => {
setSchema(newData);
library.localUpdateTimestamp(newData.id);
if (callback) callback();
}
});
},
[schemaID, setError, library, setSchema]
);
const cstUpdate = useCallback(
2023-12-28 14:04:44 +03:00
(data: ICstUpdateData, callback?: DataCallback<IConstituentaMeta>) => {
setError(undefined);
patchConstituenta(String(data.id), {
data: data,
showError: true,
setLoading: setProcessing,
2024-01-04 22:10:57 +03:00
onError: setError,
2023-12-28 14:04:44 +03:00
onSuccess: newData =>
reload(setProcessing, () => {
library.localUpdateTimestamp(Number(schemaID));
if (callback) callback(newData);
})
});
},
[setError, schemaID, library, reload]
);
2023-07-25 20:27:29 +03:00
2023-08-23 01:36:17 +03:00
const cstRename = useCallback(
2023-12-28 14:04:44 +03:00
(data: ICstRenameData, callback?: DataCallback<IConstituentaMeta>) => {
setError(undefined);
patchRenameConstituenta(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
2024-01-04 22:10:57 +03:00
onError: setError,
2023-12-28 14:04:44 +03:00
onSuccess: newData => {
setSchema(newData.schema);
library.localUpdateTimestamp(newData.schema.id);
if (callback) callback(newData.new_cst);
}
});
},
[setError, setSchema, library, schemaID]
);
2023-08-23 01:36:17 +03:00
const cstSubstitute = useCallback(
(data: ICstSubstituteData, callback?: () => void) => {
setError(undefined);
patchSubstituteConstituenta(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
onError: setError,
onSuccess: newData => {
setSchema(newData);
library.localUpdateTimestamp(newData.id);
if (callback) callback();
}
});
},
[setError, setSchema, library, schemaID]
);
2023-07-25 20:27:29 +03:00
const cstMoveTo = useCallback(
2023-12-28 14:04:44 +03:00
(data: ICstMovetoData, callback?: () => void) => {
setError(undefined);
patchMoveConstituenta(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
2024-01-04 22:10:57 +03:00
onError: setError,
2023-12-28 14:04:44 +03:00
onSuccess: newData => {
setSchema(newData);
library.localUpdateTimestamp(Number(schemaID));
if (callback) callback();
}
});
},
[schemaID, setError, library, setSchema]
);
2024-03-04 19:22:22 +03:00
const versionCreate = useCallback(
(data: IVersionData, callback?: (version: number) => void) => {
2024-03-04 19:22:22 +03:00
setError(undefined);
postCreateVersion(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
onError: setError,
onSuccess: newData => {
setSchema(newData.schema);
library.localUpdateTimestamp(Number(schemaID));
if (callback) callback(newData.version);
2024-03-04 19:22:22 +03:00
}
});
},
[schemaID, setError, library, setSchema]
);
const versionUpdate = useCallback(
(target: number, data: IVersionData, callback?: () => void) => {
setError(undefined);
patchVersion(String(target), {
data: data,
showError: true,
setLoading: setProcessing,
onError: setError,
onSuccess: () => {
schema!.versions = schema!.versions.map(prev => {
if (prev.id === target) {
prev.description = data.description;
prev.version = data.version;
return prev;
} else {
return prev;
}
});
setSchema(schema);
if (callback) callback();
}
});
},
[setError, schema, setSchema]
);
const versionDelete = useCallback(
(target: number, callback?: () => void) => {
setError(undefined);
deleteVersion(String(target), {
showError: true,
setLoading: setProcessing,
onError: setError,
onSuccess: () => {
schema!.versions = schema!.versions.filter(prev => prev.id !== target);
setSchema(schema);
if (callback) callback();
}
});
},
[setError, schema, setSchema]
);
2023-07-15 17:46:19 +03:00
return (
2023-12-28 14:04:44 +03:00
<RSFormContext.Provider
value={{
schema,
2024-03-04 19:22:22 +03:00
schemaID,
2023-12-28 14:04:44 +03:00
error,
loading,
processing,
isOwned,
isClaimable,
isSubscribed,
2024-03-04 19:22:22 +03:00
isArchive,
2023-12-28 14:04:44 +03:00
update,
download,
upload,
claim,
resetAliases,
subscribe,
unsubscribe,
cstUpdate,
cstCreate,
cstRename,
cstSubstitute,
2023-12-28 14:04:44 +03:00
cstDelete,
2024-03-04 19:22:22 +03:00
cstMoveTo,
versionCreate,
versionUpdate,
versionDelete
2023-12-28 14:04:44 +03:00
}}
>
{children}
</RSFormContext.Provider>
);
};