From 0f67d746571098735e3f84e1a35bf099245774a9 Mon Sep 17 00:00:00 2001 From: anik-ghosh-au7 Date: Sun, 23 Oct 2022 22:59:17 +0530 Subject: [PATCH 01/24] feat: add user roles multi select input --- dashboard/src/components/EditUserModal.tsx | 467 ++++++------- dashboard/src/components/InputField.tsx | 746 ++++++++++++--------- dashboard/src/constants.ts | 485 +++++++------- dashboard/src/graphql/queries/index.ts | 9 + 4 files changed, 912 insertions(+), 795 deletions(-) diff --git a/dashboard/src/components/EditUserModal.tsx b/dashboard/src/components/EditUserModal.tsx index 265a10c..e1a3e0f 100644 --- a/dashboard/src/components/EditUserModal.tsx +++ b/dashboard/src/components/EditUserModal.tsx @@ -1,250 +1,263 @@ -import React from 'react'; +import React, { useState } from 'react'; import { - Button, - Center, - Flex, - MenuItem, - Modal, - ModalBody, - ModalCloseButton, - ModalContent, - ModalFooter, - ModalHeader, - ModalOverlay, - Stack, - useDisclosure, - Text, - useToast, + Button, + Center, + Flex, + MenuItem, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, + Stack, + useDisclosure, + Text, + useToast, } from '@chakra-ui/react'; import { useClient } from 'urql'; import { FaSave } from 'react-icons/fa'; import InputField from './InputField'; import { - ArrayInputType, - DateInputType, - SelectInputType, - TextInputType, + DateInputType, + MultiSelectInputType, + SelectInputType, + TextInputType, } from '../constants'; import { getObjectDiff } from '../utils'; import { UpdateUser } from '../graphql/mutation'; +import { GetAvailableRolesQuery } from '../graphql/queries'; const GenderTypes = { - Undisclosed: null, - Male: 'Male', - Female: 'Female', + Undisclosed: null, + Male: 'Male', + Female: 'Female', }; interface userDataTypes { - id: string; - email: string; - given_name: string; - family_name: string; - middle_name: string; - nickname: string; - gender: string; - birthdate: string; - phone_number: string; - picture: string; - roles: [string] | []; + id: string; + email: string; + given_name: string; + family_name: string; + middle_name: string; + nickname: string; + gender: string; + birthdate: string; + phone_number: string; + picture: string; + roles: [string] | []; } const EditUserModal = ({ - user, - updateUserList, + user, + updateUserList, }: { - user: userDataTypes; - updateUserList: Function; + user: userDataTypes; + updateUserList: Function; }) => { - const client = useClient(); - const toast = useToast(); - const { isOpen, onOpen, onClose } = useDisclosure(); - const [userData, setUserData] = React.useState({ - id: '', - email: '', - given_name: '', - family_name: '', - middle_name: '', - nickname: '', - gender: '', - birthdate: '', - phone_number: '', - picture: '', - roles: [], - }); - React.useEffect(() => { - setUserData(user); - }, []); - const saveHandler = async () => { - const diff = getObjectDiff(user, userData); - const updatedUserData = diff.reduce( - (acc: any, property: string) => ({ - ...acc, - // @ts-ignore - [property]: userData[property], - }), - {}, - ); - const res = await client - .mutation(UpdateUser, { params: { ...updatedUserData, id: userData.id } }) - .toPromise(); - if (res.error) { - toast({ - title: 'User data update failed', - isClosable: true, - status: 'error', - position: 'bottom-right', - }); - } else if (res.data?._update_user?.id) { - toast({ - title: 'User data update successful', - isClosable: true, - status: 'success', - position: 'bottom-right', - }); - } - onClose(); - updateUserList(); - }; - return ( - <> - Edit User Details - - - - Edit User Details - - - - - - Given Name: - -
- -
-
- - - Middle Name: - -
- -
-
- - - Family Name: - -
- -
-
- - - Birth Date: - -
- -
-
- - - Nickname: - -
- -
-
- - - Gender: - -
- -
-
- - - Phone Number: - -
- -
-
- - - Picture: - -
- -
-
- - - Roles: - -
- -
-
-
-
+ const client = useClient(); + const toast = useToast(); + const [availableRoles, setAvailableRoles] = useState([]); + const { isOpen, onOpen, onClose } = useDisclosure(); + const [userData, setUserData] = useState({ + id: '', + email: '', + given_name: '', + family_name: '', + middle_name: '', + nickname: '', + gender: '', + birthdate: '', + phone_number: '', + picture: '', + roles: [], + }); + React.useEffect(() => { + setUserData(user); + fetchAvailableRoles(); + }, []); + const fetchAvailableRoles = async () => { + const res = await client.query(GetAvailableRolesQuery).toPromise(); + if (res.data?._env?.ROLES && res.data?._env?.PROTECTED_ROLES) { + setAvailableRoles([ + ...res.data._env.ROLES, + ...res.data._env.PROTECTED_ROLES, + ]); + } + }; + const saveHandler = async () => { + const diff = getObjectDiff(user, userData); + const updatedUserData = diff.reduce( + (acc: any, property: string) => ({ + ...acc, + // @ts-ignore + [property]: userData[property], + }), + {}, + ); + const res = await client + .mutation(UpdateUser, { params: { ...updatedUserData, id: userData.id } }) + .toPromise(); + if (res.error) { + toast({ + title: 'User data update failed', + isClosable: true, + status: 'error', + position: 'bottom-right', + }); + } else if (res.data?._update_user?.id) { + toast({ + title: 'User data update successful', + isClosable: true, + status: 'success', + position: 'bottom-right', + }); + } + onClose(); + updateUserList(); + }; + return ( + <> + Edit User Details + + + + Edit User Details + + + + + + Given Name: + +
+ +
+
+ + + Middle Name: + +
+ +
+
+ + + Family Name: + +
+ +
+
+ + + Birth Date: + +
+ +
+
+ + + Nickname: + +
+ +
+
+ + + Gender: + +
+ +
+
+ + + Phone Number: + +
+ +
+
+ + + Picture: + +
+ +
+
+ + + Roles: + +
+ +
+
+
+
- - - -
-
- - ); + + + +
+
+ + ); }; export default EditUserModal; diff --git a/dashboard/src/components/InputField.tsx b/dashboard/src/components/InputField.tsx index 651f54b..fe1d3d6 100644 --- a/dashboard/src/components/InputField.tsx +++ b/dashboard/src/components/InputField.tsx @@ -1,340 +1,432 @@ -import React from 'react'; +import React, { useState } from 'react'; import { - Box, - Flex, - Input, - Center, - InputGroup, - InputRightElement, - Tag, - TagLabel, - TagRightIcon, - Select, - Textarea, - Switch, - Text, + Box, + Flex, + Input, + Center, + InputGroup, + InputRightElement, + Tag, + TagLabel, + TagRightIcon, + Select, + Textarea, + Switch, + Text, + MenuButton, + MenuList, + MenuItemOption, + MenuOptionGroup, + Button, + Menu, } from '@chakra-ui/react'; import { - FaRegClone, - FaRegEye, - FaRegEyeSlash, - FaPlus, - FaTimes, + FaRegClone, + FaRegEye, + FaRegEyeSlash, + FaPlus, + FaTimes, + FaAngleDown, } from 'react-icons/fa'; import { - ArrayInputOperations, - ArrayInputType, - SelectInputType, - HiddenInputType, - TextInputType, - TextAreaInputType, - SwitchInputType, - DateInputType, + ArrayInputOperations, + ArrayInputType, + SelectInputType, + HiddenInputType, + TextInputType, + TextAreaInputType, + SwitchInputType, + DateInputType, + MultiSelectInputType, } from '../constants'; import { copyTextToClipboard } from '../utils'; const InputField = ({ - inputType, - variables, - setVariables, - fieldVisibility, - setFieldVisibility, - ...downshiftProps + inputType, + variables, + setVariables, + fieldVisibility, + setFieldVisibility, + availableRoles, + ...downshiftProps }: any) => { - const props = { - size: 'sm', - ...downshiftProps, - }; - const [inputFieldVisibility, setInputFieldVisibility] = React.useState< - Record - >({ - ROLES: false, - DEFAULT_ROLES: false, - PROTECTED_ROLES: false, - ALLOWED_ORIGINS: false, - roles: false, - }); - const [inputData, setInputData] = React.useState>({ - ROLES: '', - DEFAULT_ROLES: '', - PROTECTED_ROLES: '', - ALLOWED_ORIGINS: '', - roles: '', - }); - const updateInputHandler = ( - type: string, - operation: any, - role: string = '', - ) => { - if (operation === ArrayInputOperations.APPEND) { - if (inputData[type] !== '') { - setVariables({ - ...variables, - [type]: [...variables[type], inputData[type]], - }); - setInputData({ ...inputData, [type]: '' }); - } - setInputFieldVisibility({ ...inputFieldVisibility, [type]: false }); - } - if (operation === ArrayInputOperations.REMOVE) { - let updatedEnvVars = variables[type].filter( - (item: string) => item !== role, - ); - setVariables({ - ...variables, - [type]: updatedEnvVars, - }); - } - }; - if (Object.values(TextInputType).includes(inputType)) { - return ( - - - setVariables({ - ...variables, - [inputType]: event.target.value, - }) - } - /> - } - cursor="pointer" - onClick={() => copyTextToClipboard(variables[inputType])} - /> - - ); - } - if (Object.values(HiddenInputType).includes(inputType)) { - return ( - - - setVariables({ - ...variables, - [inputType]: event.target.value, - }) - } - type={!fieldVisibility[inputType] ? 'password' : 'text'} - /> - - {fieldVisibility[inputType] ? ( -
- setFieldVisibility({ - ...fieldVisibility, - [inputType]: false, - }) - } - > - -
- ) : ( -
- setFieldVisibility({ - ...fieldVisibility, - [inputType]: true, - }) - } - > - -
- )} -
copyTextToClipboard(variables[inputType])} - > - -
- - } - /> -
- ); - } - if (Object.values(ArrayInputType).includes(inputType)) { - return ( - 3 ? 'scroll' : 'hidden'} - overflowY="hidden" - justifyContent="start" - alignItems="center" - > - {variables[inputType].map((role: string, index: number) => ( - - - {role} - - updateInputHandler( - inputType, - ArrayInputOperations.REMOVE, - role, - ) - } - /> - - - ))} - {inputFieldVisibility[inputType] ? ( - - { - setInputData({ ...inputData, [inputType]: e.target.value }); - }} - onBlur={() => - updateInputHandler(inputType, ArrayInputOperations.APPEND) - } - onKeyPress={(event) => { - if (event.key === 'Enter') { - updateInputHandler(inputType, ArrayInputOperations.APPEND); - } - }} - /> - - ) : ( - - setInputFieldVisibility({ - ...inputFieldVisibility, - [inputType]: true, - }) - } - > - - - - - )} - - ); - } - if (Object.values(SelectInputType).includes(inputType)) { - const { options, ...rest } = props; - return ( - - ); - } - if (Object.values(TextAreaInputType).includes(inputType)) { - return ( -