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

201 lines
6.3 KiB
TypeScript
Raw Normal View History

2023-08-01 20:14:03 +03:00
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
import { ErrorInfo } from '../components/BackendError';
2023-09-11 20:31:54 +03:00
import { ILibraryItem } from '../models/library';
import { matchLibraryItem } from '../models/libraryAPI';
2023-11-01 13:41:32 +03:00
import { ILibraryFilter } from '../models/miscelanious';
import { IRSForm, IRSFormCreateData, IRSFormData } from '../models/rsform';
import { loadRSFormData } from '../models/rsformAPI';
2023-11-04 01:29:21 +03:00
import { DataCallback, deleteLibraryItem, getLibrary, getRSFormDetails, getTemplates, postCloneLibraryItem, postNewRSForm } from '../utils/backendAPI';
import { useAuth } from './AuthContext';
2023-08-01 20:14:03 +03:00
interface ILibraryContext {
2023-08-25 22:51:20 +03:00
items: ILibraryItem[]
2023-11-01 13:41:32 +03:00
templates: ILibraryItem[]
2023-08-01 20:14:03 +03:00
loading: boolean
2023-08-09 17:19:12 +03:00
processing: boolean
2023-08-01 20:14:03 +03:00
error: ErrorInfo
setError: (error: ErrorInfo) => void
2023-11-04 01:29:21 +03:00
2023-11-01 13:41:32 +03:00
applyFilter: (params: ILibraryFilter) => ILibraryItem[]
2023-11-04 01:29:21 +03:00
retrieveTemplate: (templateID: number, callback: (schema: IRSForm) => void) => void
2023-11-01 13:41:32 +03:00
createItem: (data: IRSFormCreateData, callback?: DataCallback<ILibraryItem>) => void
cloneItem: (target: number, data: IRSFormCreateData, callback: DataCallback<IRSFormData>) => void
destroyItem: (target: number, callback?: () => void) => void
localUpdateItem: (data: ILibraryItem) => void
localUpdateTimestamp: (target: number) => void
2023-08-01 20:14:03 +03:00
}
const LibraryContext = createContext<ILibraryContext | null>(null)
export const useLibrary = (): ILibraryContext => {
const context = useContext(LibraryContext);
if (context === null) {
2023-08-01 20:14:03 +03:00
throw new Error(
'useLibrary has to be used within <LibraryState.Provider>'
);
}
return context;
}
interface LibraryStateProps {
children: React.ReactNode
}
export const LibraryState = ({ children }: LibraryStateProps) => {
2023-11-04 01:29:21 +03:00
const [ items, setItems ] = useState<ILibraryItem[]>([]);
const [ templates, setTemplates ] = useState<ILibraryItem[]>([]);
2023-08-09 17:19:12 +03:00
const [ loading, setLoading ] = useState(false);
const [ processing, setProcessing ] = useState(false);
const [ error, setError ] = useState<ErrorInfo>(undefined);
const { user } = useAuth();
2023-08-01 20:14:03 +03:00
2023-11-04 01:29:21 +03:00
const [ cachedTemplates, setCachedTemplates ] = useState<IRSForm[]>([]);
2023-11-01 13:41:32 +03:00
const applyFilter = useCallback(
2023-08-01 20:14:03 +03:00
(params: ILibraryFilter) => {
let result = items;
2023-08-27 00:19:19 +03:00
if (params.is_owned) {
result = result.filter(item => item.owner === user?.id);
2023-08-01 20:14:03 +03:00
}
if (params.is_common !== undefined) {
2023-08-25 22:51:20 +03:00
result = result.filter(item => item.is_common === params.is_common);
2023-08-01 20:14:03 +03:00
}
2023-08-27 00:19:19 +03:00
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!));
2023-08-01 20:14:03 +03:00
}
return result;
2023-08-26 17:26:49 +03:00
}, [items, user]);
2023-08-01 20:14:03 +03:00
2023-11-04 01:29:21 +03:00
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]);
2023-08-01 20:14:03 +03:00
const reload = useCallback(
(callback?: () => void) => {
2023-08-01 20:14:03 +03:00
setItems([]);
setError(undefined);
getLibrary({
setLoading: setLoading,
showError: true,
onError: error => setError(error),
onSuccess: newData => {
setItems(newData);
if (callback) callback();
}
2023-08-01 20:14:03 +03:00
});
2023-11-01 13:41:32 +03:00
setTemplates([]);
getTemplates({
showError: true,
onSuccess: newData => setTemplates(newData)
});
2023-08-01 20:14:03 +03:00
}, []);
useEffect(() => {
reload();
}, [reload, user]);
2023-08-09 17:19:12 +03:00
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]);
2023-11-01 13:41:32 +03:00
const createItem = useCallback(
2023-08-25 22:51:20 +03:00
(data: IRSFormCreateData, callback?: DataCallback<ILibraryItem>) => {
2023-08-09 17:19:12 +03:00
setError(undefined);
postNewRSForm({
data: data,
showError: true,
setLoading: setProcessing,
2023-08-25 22:51:20 +03:00
onError: error => setError(error),
2023-08-27 15:39:49 +03:00
onSuccess: newSchema => reload(() => {
if (user && !user.subscriptions.includes(newSchema.id)) {
user.subscriptions.push(newSchema.id);
}
2023-08-09 17:19:12 +03:00
if (callback) callback(newSchema);
2023-08-27 15:39:49 +03:00
})
2023-08-09 17:19:12 +03:00
});
2023-08-27 15:39:49 +03:00
}, [reload, user]);
2023-08-01 20:14:03 +03:00
2023-11-01 13:41:32 +03:00
const destroyItem = useCallback(
(target: number, callback?: () => void) => {
setError(undefined)
2023-08-25 22:51:20 +03:00
deleteLibraryItem(String(target), {
showError: true,
setLoading: setProcessing,
onError: error => setError(error),
onSuccess: () => reload(() => {
2023-08-27 15:39:49 +03:00
if (user && user.subscriptions.includes(target)) {
user.subscriptions.splice(user.subscriptions.findIndex(item => item === target), 1);
}
if (callback) callback();
})
});
2023-08-27 15:39:49 +03:00
}, [setError, reload, user]);
2023-11-01 13:41:32 +03:00
const cloneItem = useCallback(
(target: number, data: IRSFormCreateData, callback: DataCallback<IRSFormData>) => {
if (!user) {
return;
}
setError(undefined)
2023-08-25 22:51:20 +03:00
postCloneLibraryItem(String(target), {
data: data,
showError: true,
setLoading: setProcessing,
onError: error => setError(error),
onSuccess: newSchema => reload(() => {
2023-08-27 15:39:49 +03:00
if (user && !user.subscriptions.includes(newSchema.id)) {
user.subscriptions.push(newSchema.id);
}
if (callback) callback(newSchema);
})
});
}, [reload, setError, user]);
2023-08-01 20:14:03 +03:00
return (
<LibraryContext.Provider value={{
2023-11-01 13:41:32 +03:00
items, templates, loading, processing, error, setError,
applyFilter, createItem, cloneItem, destroyItem, retrieveTemplate,
localUpdateItem, localUpdateTimestamp
2023-08-01 20:14:03 +03:00
}}>
{ children }
</LibraryContext.Provider>
);
}