From b51c8c1fa4cdec758a2ed2b27c2393685a9328ed Mon Sep 17 00:00:00 2001 From: joseph izang Date: Tue, 24 Aug 2021 12:04:35 +0100 Subject: [PATCH] replace custom hook implementation for permissions --- .../lib/components/permissionsSettings.tsx | 85 ++++++------ .../src/lib/custom-hooks/useLocalStorage.ts | 123 ++++++++++++++---- libs/remix-ui/plugin-manager/tsconfig.json | 3 - .../remix-ui/plugin-manager/tsconfig.lib.json | 4 +- .../plugin-manager/tsconfig.spec.json | 15 --- 5 files changed, 146 insertions(+), 84 deletions(-) delete mode 100644 libs/remix-ui/plugin-manager/tsconfig.spec.json diff --git a/libs/remix-ui/plugin-manager/src/lib/components/permissionsSettings.tsx b/libs/remix-ui/plugin-manager/src/lib/components/permissionsSettings.tsx index 877c087846..52cd3b1d22 100644 --- a/libs/remix-ui/plugin-manager/src/lib/components/permissionsSettings.tsx +++ b/libs/remix-ui/plugin-manager/src/lib/components/permissionsSettings.tsx @@ -2,7 +2,8 @@ import React, { Fragment, useEffect, useState } from 'react' /* eslint-disable-line */ import { ModalDialog } from '@remix-ui/modal-dialog' -import { useLocalStorage } from '../custom-hooks/useLocalStorage' +import useLocalStorage from '../custom-hooks/useLocalStorage' +import { PluginPermissions } from '../../types' // import { PluginManagerSettings, PluginPermissions } from '../../types' interface PermissionSettingsProps { @@ -14,7 +15,7 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) { * Declare component local state */ const [modalVisibility, setModalVisibility] = useState(true) - const [permissions, setPermissions] = useLocalStorage('plugins/permissions', '{}') + const [permissions, setPermissions] = useLocalStorage('plugins/permissions', {} as PluginPermissions) const closeModal = () => setModalVisibility(true) function ShowPluginHeading ({ headingName }) { @@ -23,7 +24,6 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) {

{headingName} permissions:

{ - console.log(`${headingName}`) clearPersmission(headingName) }} className="far fa-trash-alt" @@ -41,45 +41,48 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) { topLevelPluginName: string }) { const [checkBoxState, setCheckBoxState] = useState(allow) + const [showPermissions, setShowPermissions] = useLocalStorage('plugins/permissions', {} as PluginPermissions) useEffect(() => { - + window.addEventListener('storage', () => setPermissions(showPermissions)) + return () => window.removeEventListener('storage', () => setPermissions(showPermissions)) }, [checkBoxState]) const handleCheckboxClick = () => { - const copyPermissions = permissions + const copyPermissions = showPermissions copyPermissions[pluginName][functionName][topLevelPluginName].allow = !checkBoxState setCheckBoxState(!checkBoxState) - setPermissions(copyPermissions) + setShowPermissions(copyPermissions) } + console.log('showPermissions', showPermissions) return (
-
- - - - -
- { - console.log(`${pluginName}'s trash icon was clicked!`) - clearAllPersmissions(pluginName, topLevelPluginName, functionName) - }} - className="fa fa-trash-alt" - data-id={`pluginManagerSettingsRemovePermission-${topLevelPluginName}-${functionName}-${topLevelPluginName}`} - /> + { showPermissions && Object.keys(showPermissions).length > 0 + ? ( + <>
+ + + + +
{ + clearAllPersmissions(pluginName, topLevelPluginName, functionName) + } } + className="fa fa-trash-alt" + data-id={`pluginManagerSettingsRemovePermission-${topLevelPluginName}-${functionName}-${topLevelPluginName}`} /> + ) : null + }
) } @@ -95,9 +98,7 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) { delete permissionsCopy[topLevelPluginName] } } - // eslint-disable-next-line no-debugger - debugger - setPermissions({ ...permissionsCopy }) + setPermissions(permissionsCopy) } function clearPersmission (topLevelPluginName: string) { @@ -105,7 +106,7 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) { if (permissionsCopy[topLevelPluginName]) { delete permissionsCopy[topLevelPluginName] } - setPermissions({}) + setPermissions({} as PluginPermissions) } return ( @@ -117,23 +118,23 @@ function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) { okLabel="OK" cancelLabel="Cancel" > - {JSON.parse(localStorage.getItem('plugins/permissions')) && Object.keys(JSON.parse(localStorage.getItem('plugins/permissions'))).length > 0 + {permissions && Object.keys(permissions).length > 0 ? (

Current Permission Settings

) : (

No Permission requested yet.

) }
{ - Object.keys(JSON.parse(localStorage.getItem('plugins/permissions'))).map(toplevelName => ( + Object.keys(permissions).map(toplevelName => ( )) } { - Object.keys(JSON.parse(localStorage.getItem('plugins/permissions'))).map(topName => { - return Object.keys(JSON.parse(localStorage.getItem('plugins/permissions'))[topName]).map(funcName => { - return Object.keys(JSON.parse(localStorage.getItem('plugins/permissions'))[topName][funcName]).map(pluginName => ( + Object.keys(permissions).map(topName => { + return Object.keys(permissions[topName]).map(funcName => { + return Object.keys(permissions[topName][funcName]).map(pluginName => ( { +// // State to store our value +// // Pass initial state function to useState so logic is only executed once +// const [storedValue, setStoredValue] = useState(() => { +// try { +// // Get from local storage by key +// const item = window.localStorage.getItem(key) +// // Parse stored json or if none return initialValue +// return item ? JSON.parse(item) : initialValue +// } catch (error) { +// // If error also return initialValue +// console.log(error) +// return initialValue +// } +// }) +// // Return a wrapped version of useState's setter function that ... +// // ... persists the new value to localStorage. +// const setValue = (value: any | ((val: any) => any)) => { +// try { +// // Allow value to be a function so we have same API as useState +// const valueToStore = +// value instanceof Function ? value(storedValue) : value +// // Save state +// setStoredValue(valueToStore) +// // Save to local storage +// window.localStorage.setItem(key, JSON.stringify(valueToStore)) +// } catch (error) { +// // A more advanced implementation would handle the error case +// console.log(error) +// } +// } +// return [storedValue, setValue] as const +// } + +import { Dispatch, SetStateAction, useEffect, useState } from 'react' + +type SetValue = Dispatch> + +function useLocalStorage (key: string, initialValue: T): [T, SetValue] { + // Get from local storage then + // parse stored json or return initialValue + const readValue = (): T => { + // Prevent build error "window is undefined" but keep keep working + if (typeof window === 'undefined') { + return initialValue + } -// Hook -export const useLocalStorage = (key: string, initialValue: any) => { - // State to store our value - // Pass initial state function to useState so logic is only executed once - const [storedValue, setStoredValue] = useState(() => { try { - // Get from local storage by key const item = window.localStorage.getItem(key) - // Parse stored json or if none return initialValue - return item ? JSON.parse(item) : initialValue + return item ? (JSON.parse(item) as T) : initialValue } catch (error) { - // If error also return initialValue - console.log(error) + console.warn(`Error reading localStorage key “${key}”:`, error) return initialValue } - }) + } + + // State to store our value + // Pass initial state function to useState so logic is only executed once + const [storedValue, setStoredValue] = useState(readValue) + // Return a wrapped version of useState's setter function that ... // ... persists the new value to localStorage. - const setValue = (value: any | ((val: any) => any)) => { + const setValue: SetValue = value => { + // Prevent build error "window is undefined" but keeps working + if (typeof window === 'undefined') { + console.warn( + `Tried setting localStorage key “${key}” even though environment is not a client` + ) + } + try { - // Allow value to be a function so we have same API as useState - const valueToStore = - value instanceof Function ? value(storedValue) : value - // Save state - setStoredValue(valueToStore) + // Allow value to be a function so we have the same API as useState + const newValue = value instanceof Function ? value(storedValue) : value + // Save to local storage - window.localStorage.setItem(key, JSON.stringify(valueToStore)) + window.localStorage.setItem(key, JSON.stringify(newValue)) + + // Save state + setStoredValue(newValue) + + // We dispatch a custom event so every useLocalStorage hook are notified + window.dispatchEvent(new Event('local-storage')) } catch (error) { - // A more advanced implementation would handle the error case - console.log(error) + console.warn(`Error setting localStorage key “${key}”:`, error) } } - return [storedValue, setValue] as const + + useEffect(() => { + setStoredValue(readValue()) + }, []) + + useEffect(() => { + const handleStorageChange = () => { + setStoredValue(readValue()) + } + + // this only works for other documents, not the current one + window.addEventListener('storage', handleStorageChange) + + // this is a custom event, triggered in writeValueToLocalStorage + window.addEventListener('local-storage', handleStorageChange) + + return () => { + window.removeEventListener('storage', handleStorageChange) + window.removeEventListener('local-storage', handleStorageChange) + } + }, []) + + return [storedValue, setValue] } + +export default useLocalStorage diff --git a/libs/remix-ui/plugin-manager/tsconfig.json b/libs/remix-ui/plugin-manager/tsconfig.json index e0fb09a18c..efb99f9af9 100644 --- a/libs/remix-ui/plugin-manager/tsconfig.json +++ b/libs/remix-ui/plugin-manager/tsconfig.json @@ -12,9 +12,6 @@ "references": [ { "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.spec.json" } ] } diff --git a/libs/remix-ui/plugin-manager/tsconfig.lib.json b/libs/remix-ui/plugin-manager/tsconfig.lib.json index 4362d2c0cb..b560bc4dec 100644 --- a/libs/remix-ui/plugin-manager/tsconfig.lib.json +++ b/libs/remix-ui/plugin-manager/tsconfig.lib.json @@ -5,8 +5,8 @@ "types": ["node"] }, "files": [ - "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", - "../../node_modules/@nrwl/react/typings/image.d.ts" + "../../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../../node_modules/@nrwl/react/typings/image.d.ts" ], "exclude": ["**/*.spec.ts", "**/*.spec.tsx"], "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] diff --git a/libs/remix-ui/plugin-manager/tsconfig.spec.json b/libs/remix-ui/plugin-manager/tsconfig.spec.json deleted file mode 100644 index 1798b378a9..0000000000 --- a/libs/remix-ui/plugin-manager/tsconfig.spec.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "include": [ - "**/*.spec.ts", - "**/*.spec.tsx", - "**/*.spec.js", - "**/*.spec.jsx", - "**/*.d.ts" - ] -}