import {createContext, FC, useCallback, useContext, useMemo} from "react"; import {Group} from "../../src/types"; import {useLocalStorage} from "../../src/hooks/useLocalStorage"; import {ReactNodeLike} from "prop-types"; import pako from "pako"; interface Props { children: ReactNodeLike } interface GroupContextType { doNotSuggest: Set exportedFactories: Set ignoredFactories: string[] setIgnoredFactories(factories: string[]): void baseFactories: string[] setBaseFactories(factories: string[]): void groups: Record addGroup(name: string, exported?: string[], malls?: string[]): void removeGroup(name: string): void renameGroup(name: string, newName: string): void setFactories(name: string, factories: string[], type: 'exports'|'malls'): void getInputType(uid: string): 'base'|'produced'|'unknown' store(): Uint8Array load(str: Uint8Array): void } const defaultValues: GroupContextType = { doNotSuggest: new Set(), exportedFactories: new Set(), ignoredFactories: [], setIgnoredFactories() {}, baseFactories: [], setBaseFactories() {}, groups: {}, addGroup() {}, removeGroup() {}, renameGroup() {}, setFactories() {}, getInputType() {return 'unknown'}, store() {return new Uint8Array(0)}, load() {} } const GroupContext = createContext(defaultValues); export const useGroups = () => useContext(GroupContext) interface StoredFile { groups: Record, basicValues: string[], excludedSuggestions: string[] } export const GroupProvider: FC = ({children}) => { const [excludedSuggestions, setExcludedSuggestions] = useLocalStorage('excludedSuggestions', []) const [basicValues, setBasicValues] = useLocalStorage('basicValues', []) const [groups, setGroups] = useLocalStorage>('serviceGroups', {}) const doNotSuggest = useMemo>(() => { return new Set([...Object.values(groups).flatMap(group => [...group.exports, ...group.malls]), ...excludedSuggestions, ...basicValues]) }, [basicValues, groups, excludedSuggestions]) const exportedFactories = useMemo>(() => { return new Set([...Object.values(groups).flatMap(group => [...group.exports])]) }, [groups]) const addGroup = useCallback((name: string, exports: string[] = [], malls: string[] = []) => { if (name in groups) return false setGroups(groups => { groups[name] = { name, exports, malls } return groups }) return true }, [groups, setGroups]) const removeGroup = useCallback((name: string) => { setGroups(groups => { delete groups[name] return groups }) }, [setGroups]) const renameGroup = useCallback((name: string, newName: string) => { if (name === newName) return setGroups(groups => { groups[newName] = {...groups[name], name: newName} delete groups[name] return groups }) }, [setGroups]) const setFactories = useCallback((name: string, factories: string[], type: 'inputs'|'intermediates'|'exports'|'malls') => { setGroups(groups => { groups[name] = {...groups[name], [type]: factories} return groups }) }, [setGroups]) const getInputType = useCallback((uid: string) => { if (basicValues.includes(uid)) return 'base' else if (exportedFactories.has(uid)) return 'produced' else return 'unknown' }, [basicValues, exportedFactories]) const store = useCallback(() => { const btoa = (bin: Uint8Array) => Buffer.from(bin).toString('base64') const value: StoredFile = { groups, basicValues, excludedSuggestions } const uncompressed = JSON.stringify(value) return pako.deflate(uncompressed) }, [basicValues, excludedSuggestions, groups]) const load = useCallback((compressed: Uint8Array) => { const atob = (str: string) => Buffer.from(str, 'base64') const uncompressed = pako.inflate(compressed, {to: "string"}) const value: StoredFile = JSON.parse(uncompressed) if (!value.groups || !value.basicValues || !value.excludedSuggestions) return setGroups(value.groups) setBasicValues(value.basicValues) setExcludedSuggestions(value.excludedSuggestions) }, [setBasicValues, setExcludedSuggestions, setGroups]) const value: GroupContextType = useMemo(() => ({ doNotSuggest, exportedFactories, ignoredFactories: excludedSuggestions, setIgnoredFactories: setExcludedSuggestions, baseFactories: basicValues, setBaseFactories: setBasicValues, groups, addGroup, removeGroup, renameGroup, setFactories, getInputType, store, load }), [addGroup, basicValues, doNotSuggest, excludedSuggestions, exportedFactories, getInputType, groups, load, removeGroup, renameGroup, setBasicValues, setExcludedSuggestions, setFactories, store]) return {children} }