feat: add plain html email template editor

This commit is contained in:
anik-ghosh-au7 2022-11-09 22:17:41 +05:30
parent 4afd544c41
commit b467e7002d
3 changed files with 778 additions and 1730 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,457 +1,565 @@
import React, { useEffect, useRef, useState } from 'react';
import {
Button,
Center,
Flex,
Input,
InputGroup,
MenuItem,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Select,
Text,
useDisclosure,
useToast,
Alert,
AlertIcon,
Collapse,
Box,
TableContainer,
Table,
Thead,
Tr,
Th,
Tbody,
Td,
Code,
Button,
Center,
Flex,
Input,
InputGroup,
MenuItem,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Select,
Text,
useDisclosure,
useToast,
Alert,
AlertIcon,
Collapse,
Box,
TableContainer,
Table,
Thead,
Tr,
Th,
Tbody,
Td,
Code,
Radio,
RadioGroup,
Stack,
Textarea,
} from '@chakra-ui/react';
import { FaPlus, FaAngleDown, FaAngleUp } from 'react-icons/fa';
import { useClient } from 'urql';
import EmailEditor from 'react-email-editor';
import {
UpdateModalViews,
EmailTemplateInputDataFields,
emailTemplateEventNames,
emailTemplateVariables,
UpdateModalViews,
EmailTemplateInputDataFields,
emailTemplateEventNames,
emailTemplateVariables,
EmailTemplateEditors,
} 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;
[EmailTemplateInputDataFields.DESIGN]: string;
[EmailTemplateInputDataFields.ID]: string;
[EmailTemplateInputDataFields.EVENT_NAME]: string;
[EmailTemplateInputDataFields.SUBJECT]: string;
[EmailTemplateInputDataFields.CREATED_AT]: number;
[EmailTemplateInputDataFields.TEMPLATE]: string;
[EmailTemplateInputDataFields.DESIGN]: string;
}
interface UpdateEmailTemplateInputPropTypes {
view: UpdateModalViews;
selectedTemplate?: selectedEmailTemplateDataTypes;
fetchEmailTemplatesData: Function;
view: UpdateModalViews;
selectedTemplate?: selectedEmailTemplateDataTypes;
fetchEmailTemplatesData: Function;
}
interface templateVariableDataTypes {
text: string;
value: string;
description: string;
text: string;
value: string;
description: string;
}
interface emailTemplateDataType {
[EmailTemplateInputDataFields.EVENT_NAME]: string;
[EmailTemplateInputDataFields.SUBJECT]: string;
[EmailTemplateInputDataFields.EVENT_NAME]: string;
[EmailTemplateInputDataFields.SUBJECT]: string;
[EmailTemplateInputDataFields.TEMPLATE]: string;
[EmailTemplateInputDataFields.DESIGN]: string;
}
interface validatorDataType {
[EmailTemplateInputDataFields.SUBJECT]: boolean;
[EmailTemplateInputDataFields.SUBJECT]: boolean;
}
const initTemplateData: emailTemplateDataType = {
[EmailTemplateInputDataFields.EVENT_NAME]: emailTemplateEventNames.Signup,
[EmailTemplateInputDataFields.SUBJECT]: '',
[EmailTemplateInputDataFields.EVENT_NAME]: emailTemplateEventNames.Signup,
[EmailTemplateInputDataFields.SUBJECT]: '',
[EmailTemplateInputDataFields.TEMPLATE]: '',
[EmailTemplateInputDataFields.DESIGN]: '',
};
const initTemplateValidatorData: validatorDataType = {
[EmailTemplateInputDataFields.SUBJECT]: true,
[EmailTemplateInputDataFields.SUBJECT]: true,
};
const UpdateEmailTemplate = ({
view,
selectedTemplate,
fetchEmailTemplatesData,
view,
selectedTemplate,
fetchEmailTemplatesData,
}: UpdateEmailTemplateInputPropTypes) => {
const client = useClient();
const toast = useToast();
const emailEditorRef = useRef(null);
const { isOpen, onOpen, onClose } = useDisclosure();
const [loading, setLoading] = useState<boolean>(false);
const [templateVariables, setTemplateVariables] = useState<
templateVariableDataTypes[]
>([]);
const [templateData, setTemplateData] = useState<emailTemplateDataType>({
...initTemplateData,
});
const [validator, setValidator] = useState<validatorDataType>({
...initTemplateValidatorData,
});
const [isDynamicVariableInfoOpen, setIsDynamicVariableInfoOpen] =
useState<boolean>(false);
const client = useClient();
const toast = useToast();
const emailEditorRef = useRef(null);
const { isOpen, onOpen, onClose } = useDisclosure();
const [loading, setLoading] = useState<boolean>(false);
const [editor, setEditor] = useState<string>(
EmailTemplateEditors.PLAIN_HTML_EDITOR,
);
const [templateVariables, setTemplateVariables] = useState<
templateVariableDataTypes[]
>([]);
const [templateData, setTemplateData] = useState<emailTemplateDataType>({
...initTemplateData,
});
const [validator, setValidator] = useState<validatorDataType>({
...initTemplateValidatorData,
});
const [isDynamicVariableInfoOpen, setIsDynamicVariableInfoOpen] =
useState<boolean>(false);
const onReady = () => {
if (selectedTemplate) {
const { design } = selectedTemplate;
try {
const designData = JSON.parse(design);
// @ts-ignore
emailEditorRef.current.editor.loadDesign(designData);
} catch (error) {
console.error(error);
onClose();
}
}
};
const onReady = () => {
if (selectedTemplate) {
const { design } = selectedTemplate;
try {
if (design) {
const designData = JSON.parse(design);
// @ts-ignore
emailEditorRef.current.editor.loadDesign(designData);
}
} catch (error) {
console.error(error);
onClose();
}
}
};
const inputChangehandler = (inputType: string, value: any) => {
if (inputType !== EmailTemplateInputDataFields.EVENT_NAME) {
setValidator({
...validator,
[inputType]: value?.trim().length,
});
}
setTemplateData({ ...templateData, [inputType]: value });
};
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.SUBJECT].length > 0 &&
validator[EmailTemplateInputDataFields.SUBJECT]
);
};
const validateData = () => {
return (
!loading &&
templateData[EmailTemplateInputDataFields.EVENT_NAME].length > 0 &&
templateData[EmailTemplateInputDataFields.SUBJECT].length > 0 &&
validator[EmailTemplateInputDataFields.SUBJECT]
);
};
const saveData = async () => {
if (!validateData()) return;
setLoading(true);
// @ts-ignore
return await emailEditorRef.current.editor.exportHtml(async (data) => {
const { design, html } = data;
if (!html || !design) {
setLoading(false);
return;
}
const params = {
[EmailTemplateInputDataFields.EVENT_NAME]:
templateData[EmailTemplateInputDataFields.EVENT_NAME],
[EmailTemplateInputDataFields.SUBJECT]:
templateData[EmailTemplateInputDataFields.SUBJECT],
[EmailTemplateInputDataFields.TEMPLATE]: html.trim(),
[EmailTemplateInputDataFields.DESIGN]: JSON.stringify(design),
};
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, template, design, ...rest } = selectedTemplate;
setTemplateData(rest);
}
}, [isOpen]);
useEffect(() => {
const updatedTemplateVariables = Object.entries(
emailTemplateVariables,
).reduce((acc, [key, val]): any => {
if (
(templateData[EmailTemplateInputDataFields.EVENT_NAME] !==
emailTemplateEventNames['Verify Otp'] &&
val === emailTemplateVariables.otp) ||
(templateData[EmailTemplateInputDataFields.EVENT_NAME] ===
emailTemplateEventNames['Verify Otp'] &&
val === emailTemplateVariables.verification_url)
) {
return acc;
}
return [
...acc,
{
text: key,
value: val.value,
description: val.description,
},
];
}, []);
setTemplateVariables(updatedTemplateVariables);
}, [templateData[EmailTemplateInputDataFields.EVENT_NAME]]);
const updateTemplate = async (params: emailTemplateDataType) => {
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();
}
};
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={() => {
resetData();
onClose();
}}
size="6xl"
>
<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"
>
<Alert
status="info"
onClick={() =>
setIsDynamicVariableInfoOpen(!isDynamicVariableInfoOpen)
}
borderRadius="5"
marginBottom={5}
cursor="pointer"
fontSize="sm"
>
<AlertIcon />
<Flex
width="100%"
justifyContent="space-between"
alignItems="center"
>
<Box width="85%">
<b>Note:</b> You can add set of dynamic variables to subject
and email body. Click here to see the set of dynamic
variables.
</Box>
{isDynamicVariableInfoOpen ? <FaAngleUp /> : <FaAngleDown />}
</Flex>
</Alert>
<Collapse
style={{
width: '100%',
}}
in={isDynamicVariableInfoOpen}
>
<TableContainer
background="gray.100"
borderRadius={5}
height={200}
width="100%"
overflowY="auto"
overflowWrap="break-word"
>
<Table variant="simple">
<Thead>
<Tr>
<Th>Variable</Th>
<Th>Description</Th>
</Tr>
</Thead>
<Tbody>
{templateVariables.map((i) => (
<Tr key={i.text}>
<Td>
<Code fontSize="sm">{`{{.${i.text}}}`}</Code>
</Td>
<Td>
<Text
size="sm"
fontSize="sm"
overflowWrap="break-word"
width="100%"
>
{i.description}
</Text>
</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
</Collapse>
<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="2%"
>
<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%"
>
Template Body
</Flex>
<Flex
width="100%"
justifyContent="flex-start"
alignItems="center"
border="1px solid"
borderColor="gray.200"
>
<EmailEditor ref={emailEditorRef} onReady={onReady} />
</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>
</>
);
const saveData = async () => {
if (!validateData()) return;
setLoading(true);
let params: emailTemplateDataType = {
[EmailTemplateInputDataFields.EVENT_NAME]:
templateData[EmailTemplateInputDataFields.EVENT_NAME],
[EmailTemplateInputDataFields.SUBJECT]:
templateData[EmailTemplateInputDataFields.SUBJECT],
[EmailTemplateInputDataFields.TEMPLATE]:
templateData[EmailTemplateInputDataFields.TEMPLATE],
[EmailTemplateInputDataFields.DESIGN]: '',
};
if (editor === EmailTemplateEditors.UNLAYER_EDITOR) {
// @ts-ignore
await emailEditorRef.current.editor.exportHtml(async (data) => {
const { design, html } = data;
if (!html || !design) {
setLoading(false);
return;
}
params = {
...params,
[EmailTemplateInputDataFields.TEMPLATE]: html.trim(),
[EmailTemplateInputDataFields.DESIGN]: JSON.stringify(design),
};
await updateTemplate(params);
});
} else {
await updateTemplate(params);
}
view === UpdateModalViews.ADD && onClose();
};
const resetData = () => {
if (selectedTemplate) {
setTemplateData(selectedTemplate);
} else {
setTemplateData({ ...initTemplateData });
}
};
// set template data if edit modal is open
useEffect(() => {
if (
isOpen &&
view === UpdateModalViews.Edit &&
selectedTemplate &&
Object.keys(selectedTemplate || {}).length
) {
const { id, created_at, ...rest } = selectedTemplate;
setTemplateData(rest);
}
}, [isOpen]);
// set template variables
useEffect(() => {
const updatedTemplateVariables = Object.entries(
emailTemplateVariables,
).reduce((acc, [key, val]): any => {
if (
(templateData[EmailTemplateInputDataFields.EVENT_NAME] !==
emailTemplateEventNames['Verify Otp'] &&
val === emailTemplateVariables.otp) ||
(templateData[EmailTemplateInputDataFields.EVENT_NAME] ===
emailTemplateEventNames['Verify Otp'] &&
val === emailTemplateVariables.verification_url)
) {
return acc;
}
return [
...acc,
{
text: key,
value: val.value,
description: val.description,
},
];
}, []);
setTemplateVariables(updatedTemplateVariables);
}, [templateData[EmailTemplateInputDataFields.EVENT_NAME]]);
// change editor
useEffect(() => {
if (isOpen && selectedTemplate) {
const { design } = selectedTemplate;
if (design) {
setEditor(EmailTemplateEditors.UNLAYER_EDITOR);
} else {
setEditor(EmailTemplateEditors.PLAIN_HTML_EDITOR);
}
}
}, [isOpen, selectedTemplate]);
// reset fields when editor is changed
useEffect(() => {
if (selectedTemplate?.design) {
if (editor === EmailTemplateEditors.UNLAYER_EDITOR) {
setTemplateData({
...templateData,
[EmailTemplateInputDataFields.TEMPLATE]: selectedTemplate.template,
[EmailTemplateInputDataFields.DESIGN]: selectedTemplate.design,
});
} else {
setTemplateData({
...templateData,
[EmailTemplateInputDataFields.TEMPLATE]: '',
[EmailTemplateInputDataFields.DESIGN]: '',
});
}
} else if (selectedTemplate?.template) {
if (editor === EmailTemplateEditors.UNLAYER_EDITOR) {
setTemplateData({
...templateData,
[EmailTemplateInputDataFields.TEMPLATE]: '',
[EmailTemplateInputDataFields.DESIGN]: '',
});
} else {
setTemplateData({
...templateData,
[EmailTemplateInputDataFields.TEMPLATE]: selectedTemplate?.template,
[EmailTemplateInputDataFields.DESIGN]: '',
});
}
}
}, [editor]);
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={() => {
resetData();
onClose();
}}
size="6xl"
>
<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"
>
<Alert
status="info"
onClick={() =>
setIsDynamicVariableInfoOpen(!isDynamicVariableInfoOpen)
}
borderRadius="5"
marginBottom={5}
cursor="pointer"
fontSize="sm"
>
<AlertIcon />
<Flex
width="100%"
justifyContent="space-between"
alignItems="center"
>
<Box width="85%">
<b>Note:</b> You can add set of dynamic variables to subject
and email body. Click here to see the set of dynamic
variables.
</Box>
{isDynamicVariableInfoOpen ? <FaAngleUp /> : <FaAngleDown />}
</Flex>
</Alert>
<Collapse
style={{
width: '100%',
}}
in={isDynamicVariableInfoOpen}
>
<TableContainer
background="gray.100"
borderRadius={5}
height={200}
width="100%"
overflowY="auto"
overflowWrap="break-word"
>
<Table variant="simple">
<Thead>
<Tr>
<Th>Variable</Th>
<Th>Description</Th>
</Tr>
</Thead>
<Tbody>
{templateVariables.map((i) => (
<Tr key={i.text}>
<Td>
<Code fontSize="sm">{`{{.${i.text}}}`}</Code>
</Td>
<Td>
<Text
size="sm"
fontSize="sm"
overflowWrap="break-word"
width="100%"
>
{i.description}
</Text>
</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
</Collapse>
<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="2%"
>
<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 flex="1">Template Body</Flex>
<Flex flex="3">
<RadioGroup
onChange={(value) => setEditor(value)}
value={editor}
>
<Stack direction="row" spacing="50px">
<Radio value={EmailTemplateEditors.PLAIN_HTML_EDITOR}>
Plain HTML
</Radio>
<Radio value={EmailTemplateEditors.UNLAYER_EDITOR}>
Unlayer Editor
</Radio>
</Stack>
</RadioGroup>
</Flex>
</Flex>
<Flex
width="100%"
justifyContent="flex-start"
alignItems="center"
border="1px solid"
borderColor="gray.200"
>
{editor === EmailTemplateEditors.UNLAYER_EDITOR ? (
<EmailEditor ref={emailEditorRef} onReady={onReady} />
) : (
<Textarea
value={templateData.template}
onChange={(e) => {
setTemplateData({
...templateData,
[EmailTemplateInputDataFields.TEMPLATE]: e.target.value,
});
}}
placeholder="Template HTML"
border="0"
height="500px"
/>
)}
</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;

View File

@ -1,314 +1,314 @@
export const LOGO_URL =
'https://user-images.githubusercontent.com/6964334/147834043-fc384cab-e7ca-40f8-9663-38fc25fd5f3a.png';
'https://user-images.githubusercontent.com/6964334/147834043-fc384cab-e7ca-40f8-9663-38fc25fd5f3a.png';
export const TextInputType = {
ACCESS_TOKEN_EXPIRY_TIME: 'ACCESS_TOKEN_EXPIRY_TIME',
CLIENT_ID: 'CLIENT_ID',
GOOGLE_CLIENT_ID: 'GOOGLE_CLIENT_ID',
GITHUB_CLIENT_ID: 'GITHUB_CLIENT_ID',
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
REDIS_URL: 'REDIS_URL',
SMTP_HOST: 'SMTP_HOST',
SMTP_PORT: 'SMTP_PORT',
SMTP_USERNAME: 'SMTP_USERNAME',
SMTP_LOCAL_NAME: 'SMTP_LOCAL_NAME',
SENDER_EMAIL: 'SENDER_EMAIL',
ORGANIZATION_NAME: 'ORGANIZATION_NAME',
ORGANIZATION_LOGO: 'ORGANIZATION_LOGO',
DATABASE_NAME: 'DATABASE_NAME',
DATABASE_TYPE: 'DATABASE_TYPE',
DATABASE_URL: 'DATABASE_URL',
GIVEN_NAME: 'given_name',
MIDDLE_NAME: 'middle_name',
FAMILY_NAME: 'family_name',
NICKNAME: 'nickname',
PHONE_NUMBER: 'phone_number',
PICTURE: 'picture',
ACCESS_TOKEN_EXPIRY_TIME: 'ACCESS_TOKEN_EXPIRY_TIME',
CLIENT_ID: 'CLIENT_ID',
GOOGLE_CLIENT_ID: 'GOOGLE_CLIENT_ID',
GITHUB_CLIENT_ID: 'GITHUB_CLIENT_ID',
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
REDIS_URL: 'REDIS_URL',
SMTP_HOST: 'SMTP_HOST',
SMTP_PORT: 'SMTP_PORT',
SMTP_USERNAME: 'SMTP_USERNAME',
SMTP_LOCAL_NAME: 'SMTP_LOCAL_NAME',
SENDER_EMAIL: 'SENDER_EMAIL',
ORGANIZATION_NAME: 'ORGANIZATION_NAME',
ORGANIZATION_LOGO: 'ORGANIZATION_LOGO',
DATABASE_NAME: 'DATABASE_NAME',
DATABASE_TYPE: 'DATABASE_TYPE',
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 = {
CLIENT_SECRET: 'CLIENT_SECRET',
GOOGLE_CLIENT_SECRET: 'GOOGLE_CLIENT_SECRET',
GITHUB_CLIENT_SECRET: 'GITHUB_CLIENT_SECRET',
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
JWT_SECRET: 'JWT_SECRET',
SMTP_PASSWORD: 'SMTP_PASSWORD',
ADMIN_SECRET: 'ADMIN_SECRET',
OLD_ADMIN_SECRET: 'OLD_ADMIN_SECRET',
CLIENT_SECRET: 'CLIENT_SECRET',
GOOGLE_CLIENT_SECRET: 'GOOGLE_CLIENT_SECRET',
GITHUB_CLIENT_SECRET: 'GITHUB_CLIENT_SECRET',
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
JWT_SECRET: 'JWT_SECRET',
SMTP_PASSWORD: 'SMTP_PASSWORD',
ADMIN_SECRET: 'ADMIN_SECRET',
OLD_ADMIN_SECRET: 'OLD_ADMIN_SECRET',
};
export const ArrayInputType = {
ROLES: 'ROLES',
DEFAULT_ROLES: 'DEFAULT_ROLES',
PROTECTED_ROLES: 'PROTECTED_ROLES',
ALLOWED_ORIGINS: 'ALLOWED_ORIGINS',
ROLES: 'ROLES',
DEFAULT_ROLES: 'DEFAULT_ROLES',
PROTECTED_ROLES: 'PROTECTED_ROLES',
ALLOWED_ORIGINS: 'ALLOWED_ORIGINS',
};
export const SelectInputType = {
JWT_TYPE: 'JWT_TYPE',
GENDER: 'gender',
JWT_TYPE: 'JWT_TYPE',
GENDER: 'gender',
};
export const MultiSelectInputType = {
USER_ROLES: 'roles',
USER_ROLES: 'roles',
};
export const TextAreaInputType = {
CUSTOM_ACCESS_TOKEN_SCRIPT: 'CUSTOM_ACCESS_TOKEN_SCRIPT',
JWT_PRIVATE_KEY: 'JWT_PRIVATE_KEY',
JWT_PUBLIC_KEY: 'JWT_PUBLIC_KEY',
CUSTOM_ACCESS_TOKEN_SCRIPT: 'CUSTOM_ACCESS_TOKEN_SCRIPT',
JWT_PRIVATE_KEY: 'JWT_PRIVATE_KEY',
JWT_PUBLIC_KEY: 'JWT_PUBLIC_KEY',
};
export const SwitchInputType = {
APP_COOKIE_SECURE: 'APP_COOKIE_SECURE',
ADMIN_COOKIE_SECURE: 'ADMIN_COOKIE_SECURE',
DISABLE_LOGIN_PAGE: 'DISABLE_LOGIN_PAGE',
DISABLE_MAGIC_LINK_LOGIN: 'DISABLE_MAGIC_LINK_LOGIN',
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
DISABLE_MULTI_FACTOR_AUTHENTICATION: 'DISABLE_MULTI_FACTOR_AUTHENTICATION',
ENFORCE_MULTI_FACTOR_AUTHENTICATION: 'ENFORCE_MULTI_FACTOR_AUTHENTICATION',
APP_COOKIE_SECURE: 'APP_COOKIE_SECURE',
ADMIN_COOKIE_SECURE: 'ADMIN_COOKIE_SECURE',
DISABLE_LOGIN_PAGE: 'DISABLE_LOGIN_PAGE',
DISABLE_MAGIC_LINK_LOGIN: 'DISABLE_MAGIC_LINK_LOGIN',
DISABLE_EMAIL_VERIFICATION: 'DISABLE_EMAIL_VERIFICATION',
DISABLE_BASIC_AUTHENTICATION: 'DISABLE_BASIC_AUTHENTICATION',
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
DISABLE_MULTI_FACTOR_AUTHENTICATION: 'DISABLE_MULTI_FACTOR_AUTHENTICATION',
ENFORCE_MULTI_FACTOR_AUTHENTICATION: 'ENFORCE_MULTI_FACTOR_AUTHENTICATION',
};
export const DateInputType = {
BIRTHDATE: 'birthdate',
BIRTHDATE: 'birthdate',
};
export const ArrayInputOperations = {
APPEND: 'APPEND',
REMOVE: 'REMOVE',
APPEND: 'APPEND',
REMOVE: 'REMOVE',
};
export const HMACEncryptionType = {
HS256: 'HS256',
HS384: 'HS384',
HS512: 'HS512',
HS256: 'HS256',
HS384: 'HS384',
HS512: 'HS512',
};
export const RSAEncryptionType = {
RS256: 'RS256',
RS384: 'RS384',
RS512: 'RS512',
RS256: 'RS256',
RS384: 'RS384',
RS512: 'RS512',
};
export const ECDSAEncryptionType = {
ES256: 'ES256',
ES384: 'ES384',
ES512: 'ES512',
ES256: 'ES256',
ES384: 'ES384',
ES512: 'ES512',
};
export interface envVarTypes {
GOOGLE_CLIENT_ID: string;
GOOGLE_CLIENT_SECRET: string;
GITHUB_CLIENT_ID: string;
GITHUB_CLIENT_SECRET: string;
FACEBOOK_CLIENT_ID: string;
FACEBOOK_CLIENT_SECRET: string;
LINKEDIN_CLIENT_ID: string;
LINKEDIN_CLIENT_SECRET: string;
APPLE_CLIENT_ID: string;
APPLE_CLIENT_SECRET: string;
TWITTER_CLIENT_ID: string;
TWITTER_CLIENT_SECRET: string;
ROLES: [string] | [];
DEFAULT_ROLES: [string] | [];
PROTECTED_ROLES: [string] | [];
JWT_TYPE: string;
JWT_SECRET: string;
JWT_ROLE_CLAIM: string;
JWT_PRIVATE_KEY: string;
JWT_PUBLIC_KEY: string;
REDIS_URL: string;
SMTP_HOST: string;
SMTP_PORT: string;
SMTP_USERNAME: string;
SMTP_PASSWORD: string;
SMTP_LOCAL_NAME: string;
SENDER_EMAIL: string;
ALLOWED_ORIGINS: [string] | [];
ORGANIZATION_NAME: string;
ORGANIZATION_LOGO: string;
CUSTOM_ACCESS_TOKEN_SCRIPT: string;
ADMIN_SECRET: string;
APP_COOKIE_SECURE: boolean;
ADMIN_COOKIE_SECURE: boolean;
DISABLE_LOGIN_PAGE: boolean;
DISABLE_MAGIC_LINK_LOGIN: boolean;
DISABLE_EMAIL_VERIFICATION: boolean;
DISABLE_BASIC_AUTHENTICATION: boolean;
DISABLE_SIGN_UP: boolean;
DISABLE_STRONG_PASSWORD: boolean;
OLD_ADMIN_SECRET: string;
DATABASE_NAME: string;
DATABASE_TYPE: string;
DATABASE_URL: string;
ACCESS_TOKEN_EXPIRY_TIME: string;
DISABLE_MULTI_FACTOR_AUTHENTICATION: boolean;
ENFORCE_MULTI_FACTOR_AUTHENTICATION: boolean;
GOOGLE_CLIENT_ID: string;
GOOGLE_CLIENT_SECRET: string;
GITHUB_CLIENT_ID: string;
GITHUB_CLIENT_SECRET: string;
FACEBOOK_CLIENT_ID: string;
FACEBOOK_CLIENT_SECRET: string;
LINKEDIN_CLIENT_ID: string;
LINKEDIN_CLIENT_SECRET: string;
APPLE_CLIENT_ID: string;
APPLE_CLIENT_SECRET: string;
TWITTER_CLIENT_ID: string;
TWITTER_CLIENT_SECRET: string;
ROLES: [string] | [];
DEFAULT_ROLES: [string] | [];
PROTECTED_ROLES: [string] | [];
JWT_TYPE: string;
JWT_SECRET: string;
JWT_ROLE_CLAIM: string;
JWT_PRIVATE_KEY: string;
JWT_PUBLIC_KEY: string;
REDIS_URL: string;
SMTP_HOST: string;
SMTP_PORT: string;
SMTP_USERNAME: string;
SMTP_PASSWORD: string;
SMTP_LOCAL_NAME: string;
SENDER_EMAIL: string;
ALLOWED_ORIGINS: [string] | [];
ORGANIZATION_NAME: string;
ORGANIZATION_LOGO: string;
CUSTOM_ACCESS_TOKEN_SCRIPT: string;
ADMIN_SECRET: string;
APP_COOKIE_SECURE: boolean;
ADMIN_COOKIE_SECURE: boolean;
DISABLE_LOGIN_PAGE: boolean;
DISABLE_MAGIC_LINK_LOGIN: boolean;
DISABLE_EMAIL_VERIFICATION: boolean;
DISABLE_BASIC_AUTHENTICATION: boolean;
DISABLE_SIGN_UP: boolean;
DISABLE_STRONG_PASSWORD: boolean;
OLD_ADMIN_SECRET: string;
DATABASE_NAME: string;
DATABASE_TYPE: string;
DATABASE_URL: string;
ACCESS_TOKEN_EXPIRY_TIME: string;
DISABLE_MULTI_FACTOR_AUTHENTICATION: boolean;
ENFORCE_MULTI_FACTOR_AUTHENTICATION: boolean;
}
export const envSubViews = {
INSTANCE_INFO: 'instance-info',
ROLES: 'roles',
JWT_CONFIG: 'jwt-config',
SESSION_STORAGE: 'session-storage',
EMAIL_CONFIG: 'email-config',
WHITELIST_VARIABLES: 'whitelist-variables',
ORGANIZATION_INFO: 'organization-info',
ACCESS_TOKEN: 'access-token',
FEATURES: 'features',
ADMIN_SECRET: 'admin-secret',
DB_CRED: 'db-cred',
INSTANCE_INFO: 'instance-info',
ROLES: 'roles',
JWT_CONFIG: 'jwt-config',
SESSION_STORAGE: 'session-storage',
EMAIL_CONFIG: 'email-config',
WHITELIST_VARIABLES: 'whitelist-variables',
ORGANIZATION_INFO: 'organization-info',
ACCESS_TOKEN: 'access-token',
FEATURES: 'features',
ADMIN_SECRET: 'admin-secret',
DB_CRED: 'db-cred',
};
export enum WebhookInputDataFields {
ID = 'id',
EVENT_NAME = 'event_name',
ENDPOINT = 'endpoint',
ENABLED = 'enabled',
HEADERS = 'headers',
ID = 'id',
EVENT_NAME = 'event_name',
ENDPOINT = 'endpoint',
ENABLED = 'enabled',
HEADERS = 'headers',
}
export enum EmailTemplateInputDataFields {
ID = 'id',
EVENT_NAME = 'event_name',
SUBJECT = 'subject',
CREATED_AT = 'created_at',
TEMPLATE = 'template',
DESIGN = 'design',
ID = 'id',
EVENT_NAME = 'event_name',
SUBJECT = 'subject',
CREATED_AT = 'created_at',
TEMPLATE = 'template',
DESIGN = 'design',
}
export enum WebhookInputHeaderFields {
KEY = 'key',
VALUE = 'value',
KEY = 'key',
VALUE = 'value',
}
export enum UpdateModalViews {
ADD = 'add',
Edit = 'edit',
ADD = 'add',
Edit = 'edit',
}
export const pageLimits: number[] = [5, 10, 15];
export const webhookEventNames = {
'User signup': 'user.signup',
'User created': 'user.created',
'User login': 'user.login',
'User deleted': 'user.deleted',
'User access enabled': 'user.access_enabled',
'User access revoked': 'user.access_revoked',
'User signup': 'user.signup',
'User created': 'user.created',
'User login': 'user.login',
'User deleted': 'user.deleted',
'User access enabled': 'user.access_enabled',
'User access revoked': 'user.access_revoked',
};
export const emailTemplateEventNames = {
Signup: 'basic_auth_signup',
'Magic Link Login': 'magic_link_login',
'Update Email': 'update_email',
'Forgot Password': 'forgot_password',
'Verify Otp': 'verify_otp',
'Invite member': 'invite_member',
Signup: 'basic_auth_signup',
'Magic Link Login': 'magic_link_login',
'Update Email': 'update_email',
'Forgot Password': 'forgot_password',
'Verify Otp': 'verify_otp',
'Invite member': 'invite_member',
};
export enum webhookVerifiedStatus {
VERIFIED = 'verified',
NOT_VERIFIED = 'not_verified',
PENDING = 'verification_pending',
VERIFIED = 'verified',
NOT_VERIFIED = 'not_verified',
PENDING = 'verification_pending',
}
export const emailTemplateVariables = {
'user.id': {
description: `User identifier`,
value: '{.user.id}}',
},
'user.email': {
description: 'User email address',
value: '{.user.email}}',
},
'user.given_name': {
description: `User first name`,
value: '{.user.given_name}}',
},
'user.family_name': {
description: `User last name`,
value: '{.user.family_name}}',
},
'user.middle_name': {
description: `Middle name of user`,
value: '{.user.middle_name}}',
},
'user.nickname': {
description: `Nick name of user`,
value: '{.user.nickname}}',
},
'user.preferred_username': {
description: `Username, by default it is email`,
value: '{.user.preferred_username}}',
},
'user.signup_methods': {
description: `Comma separated list of methods using which user has signed up`,
value: '{.user.signup_methods}}',
},
'user.email_verified': {
description: `Whether email is verified or not`,
value: '{.user.email_verified}}',
},
'user.picture': {
description: `URL of the user profile picture`,
value: '{.user.picture}}',
},
'user.roles': {
description: `Comma separated list of roles assigned to user`,
value: '{.user.roles}}',
},
'user.gender': {
description: `Gender of user`,
value: '{.user.gender}}',
},
'user.birthdate': {
description: `BirthDate of user`,
value: '{.user.birthdate}}',
},
'user.phone_number': {
description: `Phone number of user`,
value: '{.user.phone_number}}',
},
'user.phone_number_verified': {
description: `Whether phone number is verified or not`,
value: '{.user.phone_number_verified}}',
},
'user.created_at': {
description: `User created at time`,
value: '{.user.created_at}}',
},
'user.updated_at': {
description: `Last updated time at user`,
value: '{.user.updated_at}}',
},
'organization.name': {
description: `Organization name`,
value: '{.organization.name}}',
},
'organization.logo': {
description: `Organization logo`,
value: '{.organization.logo}}',
},
verification_url: {
description: `Verification URL in case of events other than verify otp`,
value: '{.verification_url}}',
},
otp: {
description: `OTP sent during login with Multi factor authentication`,
value: '{.otp}}',
},
'user.id': {
description: `User identifier`,
value: '{.user.id}}',
},
'user.email': {
description: 'User email address',
value: '{.user.email}}',
},
'user.given_name': {
description: `User first name`,
value: '{.user.given_name}}',
},
'user.family_name': {
description: `User last name`,
value: '{.user.family_name}}',
},
'user.middle_name': {
description: `Middle name of user`,
value: '{.user.middle_name}}',
},
'user.nickname': {
description: `Nick name of user`,
value: '{.user.nickname}}',
},
'user.preferred_username': {
description: `Username, by default it is email`,
value: '{.user.preferred_username}}',
},
'user.signup_methods': {
description: `Comma separated list of methods using which user has signed up`,
value: '{.user.signup_methods}}',
},
'user.email_verified': {
description: `Whether email is verified or not`,
value: '{.user.email_verified}}',
},
'user.picture': {
description: `URL of the user profile picture`,
value: '{.user.picture}}',
},
'user.roles': {
description: `Comma separated list of roles assigned to user`,
value: '{.user.roles}}',
},
'user.gender': {
description: `Gender of user`,
value: '{.user.gender}}',
},
'user.birthdate': {
description: `BirthDate of user`,
value: '{.user.birthdate}}',
},
'user.phone_number': {
description: `Phone number of user`,
value: '{.user.phone_number}}',
},
'user.phone_number_verified': {
description: `Whether phone number is verified or not`,
value: '{.user.phone_number_verified}}',
},
'user.created_at': {
description: `User created at time`,
value: '{.user.created_at}}',
},
'user.updated_at': {
description: `Last updated time at user`,
value: '{.user.updated_at}}',
},
'organization.name': {
description: `Organization name`,
value: '{.organization.name}}',
},
'organization.logo': {
description: `Organization logo`,
value: '{.organization.logo}}',
},
verification_url: {
description: `Verification URL in case of events other than verify otp`,
value: '{.verification_url}}',
},
otp: {
description: `OTP sent during login with Multi factor authentication`,
value: '{.otp}}',
},
};
export const webhookPayloadExample: string = `{
@ -337,3 +337,8 @@ export const webhookPayloadExample: string = `{
},
"auth_recipe":"google"
}`;
export enum EmailTemplateEditors {
UNLAYER_EDITOR = 'unlayer_editor',
PLAIN_HTML_EDITOR = 'plain_html_editor',
}