feat: dashboard add email-template page
This commit is contained in:
@@ -31,6 +31,7 @@ import {
|
||||
FiUsers,
|
||||
FiChevronDown,
|
||||
FiLink,
|
||||
FiFileText,
|
||||
} from 'react-icons/fi';
|
||||
import { BiCustomize } from 'react-icons/bi';
|
||||
import { AiOutlineKey } from 'react-icons/ai';
|
||||
@@ -113,6 +114,7 @@ const LinkItems: Array<LinkItemProps> = [
|
||||
},
|
||||
{ name: 'Users', icon: FiUsers, route: '/users' },
|
||||
{ name: 'Webhooks', icon: FiLink, route: '/webhooks' },
|
||||
{ name: 'Email Templates', icon: FiFileText, route: '/email-templates' },
|
||||
];
|
||||
|
||||
interface SidebarProps extends BoxProps {
|
||||
|
327
dashboard/src/components/UpdateEmailTemplateModal.tsx
Normal file
327
dashboard/src/components/UpdateEmailTemplateModal.tsx
Normal file
@@ -0,0 +1,327 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Center,
|
||||
Flex,
|
||||
Input,
|
||||
InputGroup,
|
||||
MenuItem,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Select,
|
||||
useDisclosure,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaPlus } from 'react-icons/fa';
|
||||
import { useClient } from 'urql';
|
||||
import {
|
||||
UpdateModalViews,
|
||||
EmailTemplateInputDataFields,
|
||||
emailTemplateEventNames,
|
||||
} from '../constants';
|
||||
import { capitalizeFirstLetter } from '../utils';
|
||||
import { AddEmailTemplate, EditEmailTemplate } from '../graphql/mutation';
|
||||
|
||||
interface selectedEmailTemplateDataTypes {
|
||||
[EmailTemplateInputDataFields.ID]: string;
|
||||
[EmailTemplateInputDataFields.EVENT_NAME]: string;
|
||||
[EmailTemplateInputDataFields.SUBJECT]: string;
|
||||
[EmailTemplateInputDataFields.CREATED_AT]: number;
|
||||
[EmailTemplateInputDataFields.TEMPLATE]: string;
|
||||
}
|
||||
|
||||
interface UpdateEmailTemplateInputPropTypes {
|
||||
view: UpdateModalViews;
|
||||
selectedTemplate?: selectedEmailTemplateDataTypes;
|
||||
fetchEmailTemplatesData: Function;
|
||||
}
|
||||
|
||||
interface emailTemplateDataType {
|
||||
[EmailTemplateInputDataFields.EVENT_NAME]: string;
|
||||
[EmailTemplateInputDataFields.SUBJECT]: string;
|
||||
[EmailTemplateInputDataFields.TEMPLATE]: string;
|
||||
}
|
||||
|
||||
interface validatorDataType {
|
||||
[EmailTemplateInputDataFields.SUBJECT]: boolean;
|
||||
[EmailTemplateInputDataFields.TEMPLATE]: boolean;
|
||||
}
|
||||
|
||||
const initTemplateData: emailTemplateDataType = {
|
||||
[EmailTemplateInputDataFields.EVENT_NAME]:
|
||||
emailTemplateEventNames.BASIC_AUTH_SIGNUP,
|
||||
[EmailTemplateInputDataFields.SUBJECT]: '',
|
||||
[EmailTemplateInputDataFields.TEMPLATE]: '',
|
||||
};
|
||||
|
||||
const initTemplateValidatorData: validatorDataType = {
|
||||
[EmailTemplateInputDataFields.SUBJECT]: true,
|
||||
[EmailTemplateInputDataFields.TEMPLATE]: true,
|
||||
};
|
||||
|
||||
const UpdateEmailTemplate = ({
|
||||
view,
|
||||
selectedTemplate,
|
||||
fetchEmailTemplatesData,
|
||||
}: UpdateEmailTemplateInputPropTypes) => {
|
||||
const client = useClient();
|
||||
const toast = useToast();
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [templateData, setTemplateData] = useState<emailTemplateDataType>({
|
||||
...initTemplateData,
|
||||
});
|
||||
const [validator, setValidator] = useState<validatorDataType>({
|
||||
...initTemplateValidatorData,
|
||||
});
|
||||
const inputChangehandler = (inputType: string, value: any) => {
|
||||
if (inputType !== EmailTemplateInputDataFields.EVENT_NAME) {
|
||||
setValidator({
|
||||
...validator,
|
||||
[inputType]: value?.trim().length,
|
||||
});
|
||||
}
|
||||
setTemplateData({ ...templateData, [inputType]: value });
|
||||
};
|
||||
|
||||
const validateData = () => {
|
||||
return (
|
||||
!loading &&
|
||||
templateData[EmailTemplateInputDataFields.EVENT_NAME].length > 0 &&
|
||||
templateData[EmailTemplateInputDataFields.TEMPLATE].length > 0 &&
|
||||
templateData[EmailTemplateInputDataFields.SUBJECT].length > 0 &&
|
||||
validator[EmailTemplateInputDataFields.TEMPLATE] &&
|
||||
validator[EmailTemplateInputDataFields.SUBJECT]
|
||||
);
|
||||
};
|
||||
|
||||
const saveData = async () => {
|
||||
if (!validateData()) return;
|
||||
setLoading(true);
|
||||
const params = {
|
||||
[EmailTemplateInputDataFields.EVENT_NAME]:
|
||||
templateData[EmailTemplateInputDataFields.EVENT_NAME],
|
||||
[EmailTemplateInputDataFields.SUBJECT]:
|
||||
templateData[EmailTemplateInputDataFields.SUBJECT],
|
||||
[EmailTemplateInputDataFields.TEMPLATE]:
|
||||
templateData[EmailTemplateInputDataFields.TEMPLATE],
|
||||
};
|
||||
let res: any = {};
|
||||
if (
|
||||
view === UpdateModalViews.Edit &&
|
||||
selectedTemplate?.[EmailTemplateInputDataFields.ID]
|
||||
) {
|
||||
res = await client
|
||||
.mutation(EditEmailTemplate, {
|
||||
params: {
|
||||
...params,
|
||||
id: selectedTemplate[EmailTemplateInputDataFields.ID],
|
||||
},
|
||||
})
|
||||
.toPromise();
|
||||
} else {
|
||||
res = await client.mutation(AddEmailTemplate, { params }).toPromise();
|
||||
}
|
||||
setLoading(false);
|
||||
if (res.error) {
|
||||
toast({
|
||||
title: capitalizeFirstLetter(res.error.message),
|
||||
isClosable: true,
|
||||
status: 'error',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
} else if (
|
||||
res.data?._add_email_template ||
|
||||
res.data?._update_email_template
|
||||
) {
|
||||
toast({
|
||||
title: capitalizeFirstLetter(
|
||||
res.data?._add_email_template?.message ||
|
||||
res.data?._update_email_template?.message
|
||||
),
|
||||
isClosable: true,
|
||||
status: 'success',
|
||||
position: 'bottom-right',
|
||||
});
|
||||
setTemplateData({
|
||||
...initTemplateData,
|
||||
});
|
||||
setValidator({ ...initTemplateValidatorData });
|
||||
fetchEmailTemplatesData();
|
||||
}
|
||||
view === UpdateModalViews.ADD && onClose();
|
||||
};
|
||||
const resetData = () => {
|
||||
if (selectedTemplate) {
|
||||
setTemplateData(selectedTemplate);
|
||||
} else {
|
||||
setTemplateData({ ...initTemplateData });
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (
|
||||
isOpen &&
|
||||
view === UpdateModalViews.Edit &&
|
||||
selectedTemplate &&
|
||||
Object.keys(selectedTemplate || {}).length
|
||||
) {
|
||||
const { id, created_at, ...rest } = selectedTemplate;
|
||||
setTemplateData(rest);
|
||||
}
|
||||
}, [isOpen]);
|
||||
return (
|
||||
<>
|
||||
{view === UpdateModalViews.ADD ? (
|
||||
<Button
|
||||
leftIcon={<FaPlus />}
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
onClick={onOpen}
|
||||
isDisabled={false}
|
||||
size="sm"
|
||||
>
|
||||
<Center h="100%">Add Template</Center>{' '}
|
||||
</Button>
|
||||
) : (
|
||||
<MenuItem onClick={onOpen}>Edit</MenuItem>
|
||||
)}
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="3xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
{view === UpdateModalViews.ADD
|
||||
? 'Add New Email Template'
|
||||
: 'Edit Email Template'}
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
border="1px"
|
||||
borderRadius="md"
|
||||
borderColor="gray.200"
|
||||
p="5"
|
||||
>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
marginBottom="2%"
|
||||
>
|
||||
<Flex flex="1">Event Name</Flex>
|
||||
<Flex flex="3">
|
||||
<Select
|
||||
size="md"
|
||||
value={
|
||||
templateData[EmailTemplateInputDataFields.EVENT_NAME]
|
||||
}
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
EmailTemplateInputDataFields.EVENT_NAME,
|
||||
e.currentTarget.value
|
||||
)
|
||||
}
|
||||
>
|
||||
{Object.entries(emailTemplateEventNames).map(
|
||||
([key, value]: any) => (
|
||||
<option value={value} key={key}>
|
||||
{key}
|
||||
</option>
|
||||
)
|
||||
)}
|
||||
</Select>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
marginBottom="5%"
|
||||
>
|
||||
<Flex flex="1">Subject</Flex>
|
||||
<Flex flex="3">
|
||||
<InputGroup size="md">
|
||||
<Input
|
||||
pr="4.5rem"
|
||||
type="text"
|
||||
placeholder="Subject Line"
|
||||
value={templateData[EmailTemplateInputDataFields.SUBJECT]}
|
||||
isInvalid={
|
||||
!validator[EmailTemplateInputDataFields.SUBJECT]
|
||||
}
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
EmailTemplateInputDataFields.SUBJECT,
|
||||
e.currentTarget.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex
|
||||
width="100%"
|
||||
justifyContent="flex-start"
|
||||
alignItems="center"
|
||||
marginBottom="2%"
|
||||
>
|
||||
<Flex>Template Body</Flex>
|
||||
</Flex>
|
||||
<Flex flexDirection="column" maxH={220} overflowY="scroll">
|
||||
<Flex>
|
||||
<InputGroup size="md">
|
||||
<Input
|
||||
pr="4.5rem"
|
||||
type="text"
|
||||
placeholder="Subject Line"
|
||||
value={
|
||||
templateData[EmailTemplateInputDataFields.TEMPLATE]
|
||||
}
|
||||
isInvalid={
|
||||
!validator[EmailTemplateInputDataFields.TEMPLATE]
|
||||
}
|
||||
onChange={(e) =>
|
||||
inputChangehandler(
|
||||
EmailTemplateInputDataFields.TEMPLATE,
|
||||
e.currentTarget.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={resetData}
|
||||
isDisabled={loading}
|
||||
marginRight="5"
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
variant="solid"
|
||||
isLoading={loading}
|
||||
onClick={saveData}
|
||||
isDisabled={!validateData()}
|
||||
>
|
||||
<Center h="100%" pt="5%">
|
||||
Save
|
||||
</Center>
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateEmailTemplate;
|
@@ -27,12 +27,11 @@ import {
|
||||
ArrayInputOperations,
|
||||
WebhookInputDataFields,
|
||||
WebhookInputHeaderFields,
|
||||
UpdateWebhookModalViews,
|
||||
UpdateModalViews,
|
||||
webhookVerifiedStatus,
|
||||
} from '../constants';
|
||||
import { capitalizeFirstLetter, validateURI } from '../utils';
|
||||
import { AddWebhook, EditWebhook, TestEndpoint } from '../graphql/mutation';
|
||||
import { rest } from 'lodash';
|
||||
import { BiCheckCircle, BiError, BiErrorCircle } from 'react-icons/bi';
|
||||
|
||||
interface headersDataType {
|
||||
@@ -54,7 +53,7 @@ interface selecetdWebhookDataTypes {
|
||||
}
|
||||
|
||||
interface UpdateWebhookModalInputPropTypes {
|
||||
view: UpdateWebhookModalViews;
|
||||
view: UpdateModalViews;
|
||||
selectedWebhook?: selecetdWebhookDataTypes;
|
||||
fetchWebookData: Function;
|
||||
}
|
||||
@@ -254,7 +253,7 @@ const UpdateWebhookModal = ({
|
||||
const params = getParams();
|
||||
let res: any = {};
|
||||
if (
|
||||
view === UpdateWebhookModalViews.Edit &&
|
||||
view === UpdateModalViews.Edit &&
|
||||
selectedWebhook?.[WebhookInputDataFields.ID]
|
||||
) {
|
||||
res = await client
|
||||
@@ -292,12 +291,12 @@ const UpdateWebhookModal = ({
|
||||
setValidator({ ...initWebhookValidatorData });
|
||||
fetchWebookData();
|
||||
}
|
||||
view === UpdateWebhookModalViews.ADD && onClose();
|
||||
view === UpdateModalViews.ADD && onClose();
|
||||
};
|
||||
useEffect(() => {
|
||||
if (
|
||||
isOpen &&
|
||||
view === UpdateWebhookModalViews.Edit &&
|
||||
view === UpdateModalViews.Edit &&
|
||||
selectedWebhook &&
|
||||
Object.keys(selectedWebhook || {}).length
|
||||
) {
|
||||
@@ -347,7 +346,7 @@ const UpdateWebhookModal = ({
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{view === UpdateWebhookModalViews.ADD ? (
|
||||
{view === UpdateModalViews.ADD ? (
|
||||
<Button
|
||||
leftIcon={<FaPlus />}
|
||||
colorScheme="blue"
|
||||
@@ -365,9 +364,7 @@ const UpdateWebhookModal = ({
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
{view === UpdateWebhookModalViews.ADD
|
||||
? 'Add New Webhook'
|
||||
: 'Edit Webhook'}
|
||||
{view === UpdateModalViews.ADD ? 'Add New Webhook' : 'Edit Webhook'}
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
|
Reference in New Issue
Block a user