edit user details modal added

This commit is contained in:
Anik Ghosh 2022-01-30 10:39:35 +05:30
parent 681ffc65f1
commit 388530a69c
6 changed files with 456 additions and 131 deletions

View File

@ -0,0 +1,250 @@
import React from 'react';
import {
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,
} from '../constants';
import { getObjectDiff } from '../utils';
import { UpdateUser } from '../graphql/mutation';
const GenderTypes = {
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] | [];
}
const EditUserModal = ({
user,
updateUserList,
}: {
user: userDataTypes;
updateUserList: Function;
}) => {
const client = useClient();
const toast = useToast();
const { isOpen, onOpen, onClose } = useDisclosure();
const [userData, setUserData] = React.useState<userDataTypes>({
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 })
.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 (
<>
<MenuItem onClick={onOpen}>Edit User Details</MenuItem>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Edit User Details</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Stack>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Given Name:</Text>
</Flex>
<Center w="70%">
<InputField
variables={userData}
setVariables={setUserData}
inputType={TextInputType.GIVEN_NAME}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Middle Name:</Text>
</Flex>
<Center w="70%">
<InputField
variables={userData}
setVariables={setUserData}
inputType={TextInputType.MIDDLE_NAME}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Family Name:</Text>
</Flex>
<Center w="70%">
<InputField
variables={userData}
setVariables={setUserData}
inputType={TextInputType.FAMILY_NAME}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Birth Date:</Text>
</Flex>
<Center w="70%">
<InputField
variables={userData}
setVariables={setUserData}
inputType={DateInputType.BIRTHDATE}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Nickname:</Text>
</Flex>
<Center w="70%">
<InputField
variables={userData}
setVariables={setUserData}
inputType={TextInputType.NICKNAME}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Gender:</Text>
</Flex>
<Center w="70%">
<InputField
variables={userData}
setVariables={setUserData}
inputType={SelectInputType.GENDER}
value={userData.gender}
options={GenderTypes}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Phone Number:</Text>
</Flex>
<Center w="70%">
<InputField
variables={userData}
setVariables={setUserData}
inputType={TextInputType.PHONE_NUMBER}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Picture:</Text>
</Flex>
<Center w="70%">
<InputField
variables={userData}
setVariables={setUserData}
inputType={TextInputType.PICTURE}
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Roles:</Text>
</Flex>
<Center w="70%">
<InputField
variables={userData}
setVariables={setUserData}
inputType={ArrayInputType.USER_ROLES}
/>
</Center>
</Flex>
</Stack>
</ModalBody>
<ModalFooter>
<Button
leftIcon={<FaSave />}
colorScheme="blue"
variant="solid"
onClick={saveHandler}
isDisabled={false}
>
<Center h="100%" pt="5%">
Save
</Center>
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
);
};
export default EditUserModal;

View File

@ -29,13 +29,14 @@ import {
TextInputType, TextInputType,
TextAreaInputType, TextAreaInputType,
SwitchInputType, SwitchInputType,
DateInputType,
} from '../constants'; } from '../constants';
import { copyTextToClipboard } from '../utils'; import { copyTextToClipboard } from '../utils';
const InputField = ({ const InputField = ({
inputType, inputType,
envVariables, variables,
setEnvVariables, setVariables,
fieldVisibility, fieldVisibility,
setFieldVisibility, setFieldVisibility,
...downshiftProps ...downshiftProps
@ -51,12 +52,14 @@ const InputField = ({
DEFAULT_ROLES: false, DEFAULT_ROLES: false,
PROTECTED_ROLES: false, PROTECTED_ROLES: false,
ALLOWED_ORIGINS: false, ALLOWED_ORIGINS: false,
roles: false,
}); });
const [inputData, setInputData] = React.useState<Record<string, string>>({ const [inputData, setInputData] = React.useState<Record<string, string>>({
ROLES: '', ROLES: '',
DEFAULT_ROLES: '', DEFAULT_ROLES: '',
PROTECTED_ROLES: '', PROTECTED_ROLES: '',
ALLOWED_ORIGINS: '', ALLOWED_ORIGINS: '',
roles: '',
}); });
const updateInputHandler = ( const updateInputHandler = (
type: string, type: string,
@ -65,20 +68,20 @@ const InputField = ({
) => { ) => {
if (operation === ArrayInputOperations.APPEND) { if (operation === ArrayInputOperations.APPEND) {
if (inputData[type] !== '') { if (inputData[type] !== '') {
setEnvVariables({ setVariables({
...envVariables, ...variables,
[type]: [...envVariables[type], inputData[type]], [type]: [...variables[type], inputData[type]],
}); });
setInputData({ ...inputData, [type]: '' }); setInputData({ ...inputData, [type]: '' });
} }
setInputFieldVisibility({ ...inputFieldVisibility, [type]: false }); setInputFieldVisibility({ ...inputFieldVisibility, [type]: false });
} }
if (operation === ArrayInputOperations.REMOVE) { if (operation === ArrayInputOperations.REMOVE) {
let updatedEnvVars = envVariables[type].filter( let updatedEnvVars = variables[type].filter(
(item: string) => item !== role (item: string) => item !== role
); );
setEnvVariables({ setVariables({
...envVariables, ...variables,
[type]: updatedEnvVars, [type]: updatedEnvVars,
}); });
} }
@ -88,14 +91,14 @@ const InputField = ({
<InputGroup size="sm"> <InputGroup size="sm">
<Input <Input
{...props} {...props}
value={envVariables[inputType]} value={variables[inputType] ? variables[inputType] : ''}
onChange={( onChange={(
event: Event & { event: Event & {
target: HTMLInputElement; target: HTMLInputElement;
} }
) => ) =>
setEnvVariables({ setVariables({
...envVariables, ...variables,
[inputType]: event.target.value, [inputType]: event.target.value,
}) })
} }
@ -103,7 +106,7 @@ const InputField = ({
<InputRightElement <InputRightElement
children={<FaRegClone color="#bfbfbf" />} children={<FaRegClone color="#bfbfbf" />}
cursor="pointer" cursor="pointer"
onClick={() => copyTextToClipboard(envVariables[inputType])} onClick={() => copyTextToClipboard(variables[inputType])}
/> />
</InputGroup> </InputGroup>
); );
@ -113,14 +116,14 @@ const InputField = ({
<InputGroup size="sm"> <InputGroup size="sm">
<Input <Input
{...props} {...props}
value={envVariables[inputType]} value={variables[inputType]}
onChange={( onChange={(
event: Event & { event: Event & {
target: HTMLInputElement; target: HTMLInputElement;
} }
) => ) =>
setEnvVariables({ setVariables({
...envVariables, ...variables,
[inputType]: event.target.value, [inputType]: event.target.value,
}) })
} }
@ -163,7 +166,7 @@ const InputField = ({
w="25px" w="25px"
margin="0 1.5%" margin="0 1.5%"
cursor="pointer" cursor="pointer"
onClick={() => copyTextToClipboard(envVariables[inputType])} onClick={() => copyTextToClipboard(variables[inputType])}
> >
<FaRegClone color="#bfbfbf" /> <FaRegClone color="#bfbfbf" />
</Center> </Center>
@ -183,7 +186,7 @@ const InputField = ({
overflow="scroll" overflow="scroll"
padding="1%" padding="1%"
> >
{envVariables[inputType].map((role: string, index: number) => ( {variables[inputType].map((role: string, index: number) => (
<Box key={index} margin="1" role="group"> <Box key={index} margin="1" role="group">
<Tag <Tag
size="sm" size="sm"
@ -254,11 +257,30 @@ const InputField = ({
); );
} }
if (Object.values(SelectInputType).includes(inputType)) { if (Object.values(SelectInputType).includes(inputType)) {
if (inputType === SelectInputType.JWT_TYPE) {
return (
<Select size="sm" {...props}>
{[variables[inputType]].map((value: string) => (
<option value="value" key={value}>
{value}
</option>
))}
</Select>
);
}
const { options, ...rest } = props;
return ( return (
<Select size="sm" {...props}> <Select
{[envVariables[inputType]].map((value: string) => ( size="sm"
<option value="value" key={value}> {...rest}
{value} value={variables[inputType] ? variables[inputType] : ''}
onChange={(e) =>
setVariables({ ...variables, [inputType]: e.target.value })
}
>
{Object.entries(options).map(([key, value]: any) => (
<option value={value} key={key}>
{key}
</option> </option>
))} ))}
</Select> </Select>
@ -282,11 +304,11 @@ const InputField = ({
<Code h="75%">Off</Code> <Code h="75%">Off</Code>
<Switch <Switch
size="md" size="md"
isChecked={envVariables[inputType]} isChecked={variables[inputType]}
onChange={() => { onChange={() => {
setEnvVariables({ setVariables({
...envVariables, ...variables,
[inputType]: !envVariables[inputType], [inputType]: !variables[inputType],
}); });
}} }}
/> />
@ -294,6 +316,20 @@ const InputField = ({
</Flex> </Flex>
); );
} }
if (Object.values(DateInputType).includes(inputType)) {
return (
<Flex border="1px solid #e2e8f0" w="100%" h="33px" padding="1%">
<input
type="date"
style={{ width: '100%', paddingLeft: '2.5%' }}
value={variables[inputType] ? variables[inputType] : ''}
onChange={(e) =>
setVariables({ ...variables, [inputType]: e.target.value })
}
/>
</Flex>
);
}
return null; return null;
}; };

View File

@ -16,6 +16,12 @@ export const TextInputType = {
DATABASE_NAME: 'DATABASE_NAME', DATABASE_NAME: 'DATABASE_NAME',
DATABASE_TYPE: 'DATABASE_TYPE', DATABASE_TYPE: 'DATABASE_TYPE',
DATABASE_URL: 'DATABASE_URL', DATABASE_URL: 'DATABASE_URL',
GIVEN_NAME: 'given_name',
MIDDLE_NAME: 'middle_name',
FAMILY_NAME: 'family_name',
NICKNAME: 'nickname',
PHONE_NUMBER: 'phone_number',
PICTURE: 'picture',
}; };
export const HiddenInputType = { export const HiddenInputType = {
@ -33,10 +39,12 @@ export const ArrayInputType = {
DEFAULT_ROLES: 'DEFAULT_ROLES', DEFAULT_ROLES: 'DEFAULT_ROLES',
PROTECTED_ROLES: 'PROTECTED_ROLES', PROTECTED_ROLES: 'PROTECTED_ROLES',
ALLOWED_ORIGINS: 'ALLOWED_ORIGINS', ALLOWED_ORIGINS: 'ALLOWED_ORIGINS',
USER_ROLES: 'roles',
}; };
export const SelectInputType = { export const SelectInputType = {
JWT_TYPE: 'JWT_TYPE', JWT_TYPE: 'JWT_TYPE',
GENDER: 'gender',
}; };
export const TextAreaInputType = { export const TextAreaInputType = {
@ -50,6 +58,10 @@ export const SwitchInputType = {
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION', DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
}; };
export const DateInputType = {
BIRTHDATE: 'birthdate',
};
export const ArrayInputOperations = { export const ArrayInputOperations = {
APPEND: 'APPEND', APPEND: 'APPEND',
REMOVE: 'REMOVE', REMOVE: 'REMOVE',

View File

@ -249,16 +249,16 @@ export default function Environment() {
</Center> </Center>
<Center w="45%" marginRight="1.5%"> <Center w="45%" marginRight="1.5%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.GOOGLE_CLIENT_ID} inputType={TextInputType.GOOGLE_CLIENT_ID}
placeholder="Google Client ID" placeholder="Google Client ID"
/> />
</Center> </Center>
<Center w="45%"> <Center w="45%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
fieldVisibility={fieldVisibility} fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility} setFieldVisibility={setFieldVisibility}
inputType={HiddenInputType.GOOGLE_CLIENT_SECRET} inputType={HiddenInputType.GOOGLE_CLIENT_SECRET}
@ -277,16 +277,16 @@ export default function Environment() {
</Center> </Center>
<Center w="45%" marginRight="1.5%"> <Center w="45%" marginRight="1.5%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.GITHUB_CLIENT_ID} inputType={TextInputType.GITHUB_CLIENT_ID}
placeholder="Github Client ID" placeholder="Github Client ID"
/> />
</Center> </Center>
<Center w="45%"> <Center w="45%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
fieldVisibility={fieldVisibility} fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility} setFieldVisibility={setFieldVisibility}
inputType={HiddenInputType.GITHUB_CLIENT_SECRET} inputType={HiddenInputType.GITHUB_CLIENT_SECRET}
@ -305,16 +305,16 @@ export default function Environment() {
</Center> </Center>
<Center w="45%" marginRight="1.5%"> <Center w="45%" marginRight="1.5%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.FACEBOOK_CLIENT_ID} inputType={TextInputType.FACEBOOK_CLIENT_ID}
placeholder="Facebook Client ID" placeholder="Facebook Client ID"
/> />
</Center> </Center>
<Center w="45%"> <Center w="45%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
fieldVisibility={fieldVisibility} fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility} setFieldVisibility={setFieldVisibility}
inputType={HiddenInputType.FACEBOOK_CLIENT_SECRET} inputType={HiddenInputType.FACEBOOK_CLIENT_SECRET}
@ -334,8 +334,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={ArrayInputType.ROLES} inputType={ArrayInputType.ROLES}
/> />
</Center> </Center>
@ -346,8 +346,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={ArrayInputType.DEFAULT_ROLES} inputType={ArrayInputType.DEFAULT_ROLES}
/> />
</Center> </Center>
@ -358,8 +358,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={ArrayInputType.PROTECTED_ROLES} inputType={ArrayInputType.PROTECTED_ROLES}
/> />
</Center> </Center>
@ -378,8 +378,8 @@ export default function Environment() {
<Flex w="100%" justifyContent="space-between"> <Flex w="100%" justifyContent="space-between">
<Flex flex="2"> <Flex flex="2">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={SelectInputType.JWT_TYPE} inputType={SelectInputType.JWT_TYPE}
isDisabled={true} isDisabled={true}
defaultValue={SelectInputType.JWT_TYPE} defaultValue={SelectInputType.JWT_TYPE}
@ -399,8 +399,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
fieldVisibility={fieldVisibility} fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility} setFieldVisibility={setFieldVisibility}
inputType={HiddenInputType.JWT_SECRET} inputType={HiddenInputType.JWT_SECRET}
@ -413,8 +413,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.JWT_ROLE_CLAIM} inputType={TextInputType.JWT_ROLE_CLAIM}
/> />
</Center> </Center>
@ -431,8 +431,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.REDIS_URL} inputType={TextInputType.REDIS_URL}
/> />
</Center> </Center>
@ -449,8 +449,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.SMTP_HOST} inputType={TextInputType.SMTP_HOST}
/> />
</Center> </Center>
@ -461,8 +461,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.SMTP_PORT} inputType={TextInputType.SMTP_PORT}
/> />
</Center> </Center>
@ -473,8 +473,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.SMTP_USERNAME} inputType={TextInputType.SMTP_USERNAME}
/> />
</Center> </Center>
@ -485,8 +485,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
fieldVisibility={fieldVisibility} fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility} setFieldVisibility={setFieldVisibility}
inputType={HiddenInputType.SMTP_PASSWORD} inputType={HiddenInputType.SMTP_PASSWORD}
@ -499,8 +499,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.SENDER_EMAIL} inputType={TextInputType.SENDER_EMAIL}
/> />
</Center> </Center>
@ -517,8 +517,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={ArrayInputType.ALLOWED_ORIGINS} inputType={ArrayInputType.ALLOWED_ORIGINS}
/> />
</Center> </Center>
@ -535,8 +535,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.ORGANIZATION_NAME} inputType={TextInputType.ORGANIZATION_NAME}
/> />
</Center> </Center>
@ -547,8 +547,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.ORGANIZATION_LOGO} inputType={TextInputType.ORGANIZATION_LOGO}
/> />
</Center> </Center>
@ -562,8 +562,8 @@ export default function Environment() {
<Flex> <Flex>
<Center w="100%"> <Center w="100%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextAreaInputType.CUSTOM_ACCESS_TOKEN_SCRIPT} inputType={TextAreaInputType.CUSTOM_ACCESS_TOKEN_SCRIPT}
placeholder="Add script here" placeholder="Add script here"
minH="25vh" minH="25vh"
@ -582,8 +582,8 @@ export default function Environment() {
</Flex> </Flex>
<Flex justifyContent="start" w="70%"> <Flex justifyContent="start" w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={SwitchInputType.DISABLE_LOGIN_PAGE} inputType={SwitchInputType.DISABLE_LOGIN_PAGE}
/> />
</Flex> </Flex>
@ -594,8 +594,8 @@ export default function Environment() {
</Flex> </Flex>
<Flex justifyContent="start" w="70%"> <Flex justifyContent="start" w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={SwitchInputType.DISABLE_EMAIL_VERIFICATION} inputType={SwitchInputType.DISABLE_EMAIL_VERIFICATION}
/> />
</Flex> </Flex>
@ -606,8 +606,8 @@ export default function Environment() {
</Flex> </Flex>
<Flex justifyContent="start" w="70%"> <Flex justifyContent="start" w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={SwitchInputType.DISABLE_MAGIC_LINK_LOGIN} inputType={SwitchInputType.DISABLE_MAGIC_LINK_LOGIN}
/> />
</Flex> </Flex>
@ -618,8 +618,8 @@ export default function Environment() {
</Flex> </Flex>
<Flex justifyContent="start" w="70%"> <Flex justifyContent="start" w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={SwitchInputType.DISABLE_BASIC_AUTHENTICATION} inputType={SwitchInputType.DISABLE_BASIC_AUTHENTICATION}
/> />
</Flex> </Flex>
@ -647,8 +647,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.DATABASE_NAME} inputType={TextInputType.DATABASE_NAME}
isDisabled={true} isDisabled={true}
/> />
@ -660,8 +660,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.DATABASE_TYPE} inputType={TextInputType.DATABASE_TYPE}
isDisabled={true} isDisabled={true}
/> />
@ -673,8 +673,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={TextInputType.DATABASE_URL} inputType={TextInputType.DATABASE_URL}
isDisabled={true} isDisabled={true}
/> />
@ -743,8 +743,8 @@ export default function Environment() {
</Flex> </Flex>
<Center w="70%"> <Center w="70%">
<InputField <InputField
envVariables={envVariables} variables={envVariables}
setEnvVariables={setEnvVariables} setVariables={setEnvVariables}
inputType={HiddenInputType.ADMIN_SECRET} inputType={HiddenInputType.ADMIN_SECRET}
fieldVisibility={fieldVisibility} fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility} setFieldVisibility={setFieldVisibility}

View File

@ -27,6 +27,7 @@ import {
MenuButton, MenuButton,
MenuList, MenuList,
MenuItem, MenuItem,
useToast,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { import {
FaAngleLeft, FaAngleLeft,
@ -38,6 +39,7 @@ import {
} from 'react-icons/fa'; } from 'react-icons/fa';
import { UserDetailsQuery } from '../graphql/queries'; import { UserDetailsQuery } from '../graphql/queries';
import { UpdateUser } from '../graphql/mutation'; import { UpdateUser } from '../graphql/mutation';
import EditUserModal from '../components/EditUserModal';
interface paginationPropTypes { interface paginationPropTypes {
limit: number; limit: number;
@ -85,6 +87,7 @@ const getLimits = (pagination: paginationPropTypes) => {
export default function Users() { export default function Users() {
const client = useClient(); const client = useClient();
const toast = useToast();
const [paginationProps, setPaginationProps] = const [paginationProps, setPaginationProps] =
React.useState<paginationPropTypes>({ React.useState<paginationPropTypes>({
limit: 5, limit: 5,
@ -94,7 +97,7 @@ export default function Users() {
maxPages: 1, maxPages: 1,
}); });
const [userList, setUserList] = React.useState<userDataTypes[]>([]); const [userList, setUserList] = React.useState<userDataTypes[]>([]);
const updateData = async () => { const updateUserList = async () => {
const { data } = await client const { data } = await client
.query(UserDetailsQuery, { .query(UserDetailsQuery, {
params: { params: {
@ -110,15 +113,13 @@ export default function Users() {
const maxPages = getMaxPages(pagination); const maxPages = getMaxPages(pagination);
setPaginationProps({ ...paginationProps, ...pagination, maxPages }); setPaginationProps({ ...paginationProps, ...pagination, maxPages });
setUserList(users); setUserList(users);
console.log('users ==>> ', users);
console.log('pagination ==>> ', { ...pagination, maxPages });
} }
}; };
React.useEffect(() => { React.useEffect(() => {
updateData(); updateUserList();
}, []); }, []);
React.useEffect(() => { React.useEffect(() => {
updateData(); updateUserList();
}, [paginationProps.page, paginationProps.limit]); }, [paginationProps.page, paginationProps.limit]);
const paginationHandler = (value: Record<string, number>) => { const paginationHandler = (value: Record<string, number>) => {
@ -127,7 +128,7 @@ export default function Users() {
const userVerificationHandler = async (user: userDataTypes) => { const userVerificationHandler = async (user: userDataTypes) => {
const { id, email } = user; const { id, email } = user;
await client const res = await client
.mutation(UpdateUser, { .mutation(UpdateUser, {
params: { params: {
id, id,
@ -136,9 +137,23 @@ export default function Users() {
}, },
}) })
.toPromise(); .toPromise();
updateData(); if (res.error) {
toast({
title: 'User verification failed',
isClosable: true,
status: 'error',
position: 'bottom-right',
});
} else if (res.data?._update_user?.id) {
toast({
title: 'User verification successful',
isClosable: true,
status: 'success',
position: 'bottom-right',
});
}
updateUserList();
}; };
return ( return (
<Box m="5" py="5" px="10" bg="white" rounded="md"> <Box m="5" py="5" px="10" bg="white" rounded="md">
<Flex margin="2% 0" justifyContent="space-between" alignItems="center"> <Flex margin="2% 0" justifyContent="space-between" alignItems="center">
@ -157,44 +172,52 @@ export default function Users() {
</Tr> </Tr>
</Thead> </Thead>
<Tbody> <Tbody>
{userList.map((user: userDataTypes) => ( {userList.map((user: userDataTypes) => {
<Tr key={user.id} style={{ fontSize: 14 }}> const { email_verified, created_at, ...rest }: any = user;
<Td>{user.email}</Td> return (
<Td>{dayjs(user.created_at).format('MMM DD, YYYY')}</Td> <Tr key={user.id} style={{ fontSize: 14 }}>
<Td> <Td>{user.email}</Td>
<Tag <Td>{dayjs(user.created_at).format('MMM DD, YYYY')}</Td>
size="sm" <Td>
variant="outline" <Tag
colorScheme={user.email_verified ? 'green' : 'yellow'} size="sm"
> variant="outline"
{user.email_verified.toString()} colorScheme={user.email_verified ? 'green' : 'yellow'}
</Tag> >
</Td> {user.email_verified.toString()}
<Td> </Tag>
<Menu> </Td>
<MenuButton as={Button} variant="unstyled" size="sm"> <Td>
<Flex justifyContent="space-between" alignItems="center"> <Menu>
<Text fontSize="sm" fontWeight="light"> <MenuButton as={Button} variant="unstyled" size="sm">
Menu <Flex
</Text> justifyContent="space-between"
<FaAngleDown style={{ marginLeft: 10 }} /> alignItems="center"
</Flex>
</MenuButton>
<MenuList>
<MenuItem value="update">Update User Details</MenuItem>
{!user.email_verified && (
<MenuItem
value="verify"
onClick={() => userVerificationHandler(user)}
> >
Verify User <Text fontSize="sm" fontWeight="light">
</MenuItem> Menu
)} </Text>
</MenuList> <FaAngleDown style={{ marginLeft: 10 }} />
</Menu> </Flex>
</Td> </MenuButton>
</Tr> <MenuList>
))} <EditUserModal
user={rest}
updateUserList={updateUserList}
/>
{!user.email_verified && (
<MenuItem
onClick={() => userVerificationHandler(user)}
>
Verify User
</MenuItem>
)}
</MenuList>
</Menu>
</Td>
</Tr>
);
})}
</Tbody> </Tbody>
{paginationProps.maxPages > 1 && ( {paginationProps.maxPages > 1 && (
<TableCaption> <TableCaption>

View File

@ -48,7 +48,11 @@ export const getObjectDiff = (obj1: any, obj2: any) => {
const diff = Object.keys(obj1).reduce((result, key) => { const diff = Object.keys(obj1).reduce((result, key) => {
if (!obj2.hasOwnProperty(key)) { if (!obj2.hasOwnProperty(key)) {
result.push(key); result.push(key);
} else if (_.isEqual(obj1[key], obj2[key])) { } else if (
_.isEqual(obj1[key], obj2[key]) ||
(obj1[key] === null && obj2[key] === '') ||
(obj1[key] === [] && obj2[key] === null)
) {
const resultKeyIndex = result.indexOf(key); const resultKeyIndex = result.indexOf(key);
result.splice(resultKeyIndex, 1); result.splice(resultKeyIndex, 1);
} }