'use client'; import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { DataCallback } from '@/backend/apiTransport'; import { patchLibraryItem, patchSetAccessPolicy, patchSetEditors, patchSetLocation, patchSetOwner } from '@/backend/library'; import { patchCreateInput, patchDeleteOperation, patchSetInput, patchUpdateOperation, patchUpdatePositions, postCreateOperation, postExecuteOperation } from '@/backend/oss'; import { type ErrorData } from '@/components/info/InfoError'; import { AccessPolicy, ILibraryItem } from '@/models/library'; import { ILibraryUpdateData } from '@/models/library'; import { IOperationCreateData, IOperationData, IOperationDeleteData, IOperationSchema, IOperationSchemaData, IOperationSetInputData, IOperationUpdateData, IPositionsData, ITargetOperation } from '@/models/oss'; import { UserID } from '@/models/user'; import { contextOutsideScope } from '@/utils/labels'; import { useAuth } from './AuthContext'; import { useGlobalOss } from './GlobalOssContext'; import { useLibrary } from './LibraryContext'; interface IOssContext { schema?: IOperationSchema; itemID: string; loading: boolean; loadingError: ErrorData; processing: boolean; processingError: ErrorData; isOwned: boolean; update: (data: ILibraryUpdateData, callback?: DataCallback) => void; setOwner: (newOwner: UserID, callback?: () => void) => void; setAccessPolicy: (newPolicy: AccessPolicy, callback?: () => void) => void; setLocation: (newLocation: string, callback?: () => void) => void; setEditors: (newEditors: UserID[], callback?: () => void) => void; savePositions: (data: IPositionsData, callback?: () => void) => void; createOperation: (data: IOperationCreateData, callback?: DataCallback) => void; deleteOperation: (data: IOperationDeleteData, callback?: () => void) => void; createInput: (data: ITargetOperation, callback?: DataCallback) => void; setInput: (data: IOperationSetInputData, callback?: () => void) => void; updateOperation: (data: IOperationUpdateData, callback?: () => void) => void; executeOperation: (data: ITargetOperation, callback?: () => void) => void; } const OssContext = createContext(null); export const useOSS = () => { const context = useContext(OssContext); if (context === null) { throw new Error(contextOutsideScope('useOSS', 'OssState')); } return context; }; interface OssStateProps { itemID: string; } export const OssState = ({ itemID, children }: React.PropsWithChildren) => { const library = useLibrary(); const oss = useGlobalOss(); const model = oss.schema; const { user } = useAuth(); const [processing, setProcessing] = useState(false); const [processingError, setProcessingError] = useState(undefined); const isOwned = useMemo(() => { return user?.id === model?.owner || false; }, [user, model?.owner]); useEffect(() => { oss.setID(itemID); }, [itemID, oss.setID]); const update = useCallback( (data: ILibraryUpdateData, callback?: DataCallback) => { if (!model) { return; } setProcessingError(undefined); patchLibraryItem(itemID, { data: data, showError: true, setLoading: setProcessing, onError: setProcessingError, onSuccess: newData => { const fullData: IOperationSchemaData = Object.assign(model, newData); oss.setData(fullData); library.localUpdateItem(newData); if (callback) callback(newData); } }); }, [itemID, model, library.localUpdateItem, oss.setData] ); const setOwner = useCallback( (newOwner: UserID, callback?: () => void) => { if (!model) { return; } setProcessingError(undefined); patchSetOwner(itemID, { data: { user: newOwner }, showError: true, setLoading: setProcessing, onError: setProcessingError, onSuccess: () => { model.owner = newOwner; library.reloadItems(() => { if (callback) callback(); }); } }); }, [itemID, model, library.reloadItems] ); const setAccessPolicy = useCallback( (newPolicy: AccessPolicy, callback?: () => void) => { if (!model) { return; } setProcessingError(undefined); patchSetAccessPolicy(itemID, { data: { access_policy: newPolicy }, showError: true, setLoading: setProcessing, onError: setProcessingError, onSuccess: () => { model.access_policy = newPolicy; library.reloadItems(() => { if (callback) callback(); }); } }); }, [itemID, model, library.reloadItems] ); const setLocation = useCallback( (newLocation: string, callback?: () => void) => { if (!model) { return; } setProcessingError(undefined); patchSetLocation(itemID, { data: { location: newLocation }, showError: true, setLoading: setProcessing, onError: setProcessingError, onSuccess: () => { model.location = newLocation; library.reloadItems(() => { if (callback) callback(); }); } }); }, [itemID, model, library.reloadItems] ); const setEditors = useCallback( (newEditors: UserID[], callback?: () => void) => { if (!model) { return; } setProcessingError(undefined); patchSetEditors(itemID, { data: { users: newEditors }, showError: true, setLoading: setProcessing, onError: setProcessingError, onSuccess: () => { model.editors = newEditors; library.reloadItems(() => { if (callback) callback(); }); } }); }, [itemID, model, library.reloadItems] ); const savePositions = useCallback( (data: IPositionsData, callback?: () => void) => { setProcessingError(undefined); patchUpdatePositions(itemID, { data: data, showError: true, setLoading: setProcessing, onError: setProcessingError, onSuccess: () => { library.localUpdateTimestamp(Number(itemID)); if (callback) callback(); } }); }, [itemID, library.localUpdateTimestamp] ); const createOperation = useCallback( (data: IOperationCreateData, callback?: DataCallback) => { setProcessingError(undefined); postCreateOperation(itemID, { data: data, showError: true, setLoading: setProcessing, onError: setProcessingError, onSuccess: newData => { oss.setData(newData.oss); library.localUpdateTimestamp(newData.oss.id); if (callback) callback(newData.new_operation); } }); }, [itemID, library.localUpdateTimestamp, oss.setData] ); const deleteOperation = useCallback( (data: IOperationDeleteData, callback?: () => void) => { setProcessingError(undefined); patchDeleteOperation(itemID, { data: data, showError: true, setLoading: setProcessing, onError: setProcessingError, onSuccess: newData => { oss.setData(newData); library.reloadItems(() => { if (callback) callback(); }); } }); }, [itemID, library.reloadItems, oss.setData] ); const createInput = useCallback( (data: ITargetOperation, callback?: DataCallback) => { setProcessingError(undefined); patchCreateInput(itemID, { data: data, showError: true, setLoading: setProcessing, onError: setProcessingError, onSuccess: newData => { oss.setData(newData.oss); library.reloadItems(() => { if (callback) callback(newData.new_schema); }); } }); }, [itemID, library.reloadItems, oss.setData] ); const setInput = useCallback( (data: IOperationSetInputData, callback?: () => void) => { if (!model) { return; } setProcessingError(undefined); patchSetInput(itemID, { data: data, showError: true, setLoading: setProcessing, onError: setProcessingError, onSuccess: newData => { oss.setData(newData); library.reloadItems(() => { if (callback) callback(); }); } }); }, [itemID, model, library.reloadItems, oss.setData] ); const updateOperation = useCallback( (data: IOperationUpdateData, callback?: () => void) => { if (!model) { return; } setProcessingError(undefined); patchUpdateOperation(itemID, { data: data, showError: true, setLoading: setProcessing, onError: setProcessingError, onSuccess: newData => { oss.setData(newData); library.reloadItems(() => { if (callback) callback(); }); } }); }, [itemID, model, library.reloadItems, oss.setData] ); const executeOperation = useCallback( (data: ITargetOperation, callback?: () => void) => { if (!model) { return; } setProcessingError(undefined); postExecuteOperation(itemID, { data: data, showError: true, setLoading: setProcessing, onError: setProcessingError, onSuccess: newData => { oss.setData(newData); library.reloadItems(() => { if (callback) callback(); }); } }); }, [itemID, model, library.reloadItems, oss.setData] ); return ( {children} ); };