Skip to content

Commit ad3e615

Browse files
authored
Merge pull request #210 from authorizerdev/fix/dashboard-ui
Fix/dashboard UI
2 parents bbd4d43 + e9a2301 commit ad3e615

File tree

14 files changed

+252
-489
lines changed

14 files changed

+252
-489
lines changed

dashboard/package-lock.json

Lines changed: 29 additions & 374 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dashboard/package.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
"@types/react-dom": "^17.0.11",
2020
"@types/react-router-dom": "^5.3.2",
2121
"dayjs": "^1.10.7",
22-
"draft-js": "^0.11.7",
23-
"draft-js-import-html": "^1.4.1",
24-
"draftjs-to-html": "^0.9.1",
2522
"esbuild": "^0.14.9",
2623
"focus-visible": "^5.2.0",
2724
"framer-motion": "^5.5.5",
@@ -31,13 +28,13 @@
3128
"react-dom": "^17.0.2",
3229
"react-draft-wysiwyg": "^1.15.0",
3330
"react-dropzone": "^12.0.4",
31+
"react-email-editor": "^1.6.1",
3432
"react-icons": "^4.3.1",
3533
"react-router-dom": "^6.2.1",
3634
"typescript": "^4.5.4",
3735
"urql": "^2.0.6"
3836
},
3937
"devDependencies": {
40-
"@types/draftjs-to-html": "^0.8.1",
41-
"@types/react-draft-wysiwyg": "^1.13.4"
38+
"@types/react-email-editor": "^1.1.7"
4239
}
4340
}

dashboard/src/components/EnvComponents/Features.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,35 @@ const Features = ({ variables, setVariables }: any) => {
8383
/>
8484
</Flex>
8585
</Flex>
86+
<Flex>
87+
<Flex w="100%" justifyContent="start" alignItems="center">
88+
<Text fontSize="sm">Disable Multi Factor Authentication:</Text>
89+
</Flex>
90+
<Flex justifyContent="start" mb={3}>
91+
<InputField
92+
variables={variables}
93+
setVariables={setVariables}
94+
inputType={SwitchInputType.DISABLE_MULTI_FACTOR_AUTHENTICATION}
95+
/>
96+
</Flex>
97+
</Flex>
98+
</Stack>
99+
<Text fontSize="md" paddingTop="2%" fontWeight="bold" mb={5}>
100+
Enable Features
101+
</Text>
102+
<Stack spacing={6} padding="2% 0%">
103+
<Flex>
104+
<Flex w="100%" justifyContent="start" alignItems="center">
105+
<Text fontSize="sm">Enforce Multi Factor Authentication:</Text>
106+
</Flex>
107+
<Flex justifyContent="start" mb={3}>
108+
<InputField
109+
variables={variables}
110+
setVariables={setVariables}
111+
inputType={SwitchInputType.ENFORCE_MULTI_FACTOR_AUTHENTICATION}
112+
/>
113+
</Flex>
114+
</Flex>
86115
</Stack>
87116
</div>
88117
);

dashboard/src/components/UpdateEmailTemplateModal.tsx

Lines changed: 93 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect, useState } from 'react';
1+
import React, { useEffect, useRef, useState } from 'react';
22
import {
33
Button,
44
Center,
@@ -32,10 +32,7 @@ import {
3232
} from '@chakra-ui/react';
3333
import { FaPlus, FaAngleDown, FaAngleUp } from 'react-icons/fa';
3434
import { useClient } from 'urql';
35-
import { Editor } from 'react-draft-wysiwyg';
36-
import { EditorState, convertToRaw, Modifier } from 'draft-js';
37-
import draftToHtml from 'draftjs-to-html';
38-
import { stateFromHTML } from 'draft-js-import-html';
35+
import EmailEditor from 'react-email-editor';
3936
import {
4037
UpdateModalViews,
4138
EmailTemplateInputDataFields,
@@ -51,6 +48,7 @@ interface selectedEmailTemplateDataTypes {
5148
[EmailTemplateInputDataFields.SUBJECT]: string;
5249
[EmailTemplateInputDataFields.CREATED_AT]: number;
5350
[EmailTemplateInputDataFields.TEMPLATE]: string;
51+
[EmailTemplateInputDataFields.DESIGN]: string;
5452
}
5553

5654
interface UpdateEmailTemplateInputPropTypes {
@@ -90,11 +88,9 @@ const UpdateEmailTemplate = ({
9088
}: UpdateEmailTemplateInputPropTypes) => {
9189
const client = useClient();
9290
const toast = useToast();
91+
const emailEditorRef = useRef(null);
9392
const { isOpen, onOpen, onClose } = useDisclosure();
9493
const [loading, setLoading] = useState<boolean>(false);
95-
const [editorState, setEditorState] = React.useState<EditorState>(
96-
EditorState.createEmpty()
97-
);
9894
const [templateVariables, setTemplateVariables] = useState<
9995
templateVariableDataTypes[]
10096
>([]);
@@ -104,12 +100,23 @@ const UpdateEmailTemplate = ({
104100
const [validator, setValidator] = useState<validatorDataType>({
105101
...initTemplateValidatorData,
106102
});
107-
const onEditorStateChange = (editorState: EditorState) => {
108-
setEditorState(editorState);
109-
};
110103
const [isDynamicVariableInfoOpen, setIsDynamicVariableInfoOpen] =
111104
useState<boolean>(false);
112105

106+
const onReady = () => {
107+
if (selectedTemplate) {
108+
const { design } = selectedTemplate;
109+
try {
110+
const designData = JSON.parse(design);
111+
// @ts-ignore
112+
emailEditorRef.current.editor.loadDesign(designData);
113+
} catch (error) {
114+
console.error(error);
115+
onClose();
116+
}
117+
}
118+
};
119+
113120
const inputChangehandler = (inputType: string, value: any) => {
114121
if (inputType !== EmailTemplateInputDataFields.EVENT_NAME) {
115122
setValidator({
@@ -121,14 +128,8 @@ const UpdateEmailTemplate = ({
121128
};
122129

123130
const validateData = () => {
124-
const rawData: string = draftToHtml(
125-
convertToRaw(editorState.getCurrentContent())
126-
).trim();
127131
return (
128132
!loading &&
129-
rawData &&
130-
rawData !== '<p></p>' &&
131-
rawData !== '<h1></h1>' &&
132133
templateData[EmailTemplateInputDataFields.EVENT_NAME].length > 0 &&
133134
templateData[EmailTemplateInputDataFields.SUBJECT].length > 0 &&
134135
validator[EmailTemplateInputDataFields.SUBJECT]
@@ -138,69 +139,72 @@ const UpdateEmailTemplate = ({
138139
const saveData = async () => {
139140
if (!validateData()) return;
140141
setLoading(true);
141-
const params = {
142-
[EmailTemplateInputDataFields.EVENT_NAME]:
143-
templateData[EmailTemplateInputDataFields.EVENT_NAME],
144-
[EmailTemplateInputDataFields.SUBJECT]:
145-
templateData[EmailTemplateInputDataFields.SUBJECT],
146-
[EmailTemplateInputDataFields.TEMPLATE]: draftToHtml(
147-
convertToRaw(editorState.getCurrentContent())
148-
).trim(),
149-
};
150-
let res: any = {};
151-
if (
152-
view === UpdateModalViews.Edit &&
153-
selectedTemplate?.[EmailTemplateInputDataFields.ID]
154-
) {
155-
res = await client
156-
.mutation(EditEmailTemplate, {
157-
params: {
158-
...params,
159-
id: selectedTemplate[EmailTemplateInputDataFields.ID],
160-
},
161-
})
162-
.toPromise();
163-
} else {
164-
res = await client.mutation(AddEmailTemplate, { params }).toPromise();
165-
}
166-
setLoading(false);
167-
if (res.error) {
168-
toast({
169-
title: capitalizeFirstLetter(res.error.message),
170-
isClosable: true,
171-
status: 'error',
172-
position: 'bottom-right',
173-
});
174-
} else if (
175-
res.data?._add_email_template ||
176-
res.data?._update_email_template
177-
) {
178-
toast({
179-
title: capitalizeFirstLetter(
180-
res.data?._add_email_template?.message ||
181-
res.data?._update_email_template?.message
182-
),
183-
isClosable: true,
184-
status: 'success',
185-
position: 'bottom-right',
186-
});
187-
setTemplateData({
188-
...initTemplateData,
189-
});
190-
setValidator({ ...initTemplateValidatorData });
191-
fetchEmailTemplatesData();
192-
}
193-
view === UpdateModalViews.ADD && onClose();
142+
// @ts-ignore
143+
return await emailEditorRef.current.editor.exportHtml(async (data) => {
144+
const { design, html } = data;
145+
if (!html || !design) {
146+
setLoading(false);
147+
return;
148+
}
149+
const params = {
150+
[EmailTemplateInputDataFields.EVENT_NAME]:
151+
templateData[EmailTemplateInputDataFields.EVENT_NAME],
152+
[EmailTemplateInputDataFields.SUBJECT]:
153+
templateData[EmailTemplateInputDataFields.SUBJECT],
154+
[EmailTemplateInputDataFields.TEMPLATE]: html.trim(),
155+
[EmailTemplateInputDataFields.DESIGN]: JSON.stringify(design),
156+
};
157+
let res: any = {};
158+
if (
159+
view === UpdateModalViews.Edit &&
160+
selectedTemplate?.[EmailTemplateInputDataFields.ID]
161+
) {
162+
res = await client
163+
.mutation(EditEmailTemplate, {
164+
params: {
165+
...params,
166+
id: selectedTemplate[EmailTemplateInputDataFields.ID],
167+
},
168+
})
169+
.toPromise();
170+
} else {
171+
res = await client.mutation(AddEmailTemplate, { params }).toPromise();
172+
}
173+
setLoading(false);
174+
if (res.error) {
175+
toast({
176+
title: capitalizeFirstLetter(res.error.message),
177+
isClosable: true,
178+
status: 'error',
179+
position: 'bottom-right',
180+
});
181+
} else if (
182+
res.data?._add_email_template ||
183+
res.data?._update_email_template
184+
) {
185+
toast({
186+
title: capitalizeFirstLetter(
187+
res.data?._add_email_template?.message ||
188+
res.data?._update_email_template?.message
189+
),
190+
isClosable: true,
191+
status: 'success',
192+
position: 'bottom-right',
193+
});
194+
setTemplateData({
195+
...initTemplateData,
196+
});
197+
setValidator({ ...initTemplateValidatorData });
198+
fetchEmailTemplatesData();
199+
}
200+
view === UpdateModalViews.ADD && onClose();
201+
});
194202
};
195203
const resetData = () => {
196204
if (selectedTemplate) {
197205
setTemplateData(selectedTemplate);
198-
setEditorState(
199-
EditorState.createWithContent(stateFromHTML(selectedTemplate.template))
200-
);
201206
} else {
202207
setTemplateData({ ...initTemplateData });
203-
setEditorState(EditorState.createEmpty());
204208
}
205209
};
206210
useEffect(() => {
@@ -210,9 +214,8 @@ const UpdateEmailTemplate = ({
210214
selectedTemplate &&
211215
Object.keys(selectedTemplate || {}).length
212216
) {
213-
const { id, created_at, template, ...rest } = selectedTemplate;
217+
const { id, created_at, template, design, ...rest } = selectedTemplate;
214218
setTemplateData(rest);
215-
setEditorState(EditorState.createWithContent(stateFromHTML(template)));
216219
}
217220
}, [isOpen]);
218221
useEffect(() => {
@@ -263,7 +266,7 @@ const UpdateEmailTemplate = ({
263266
resetData();
264267
onClose();
265268
}}
266-
size="3xl"
269+
size="6xl"
267270
>
268271
<ModalOverlay />
269272
<ModalContent>
@@ -287,7 +290,7 @@ const UpdateEmailTemplate = ({
287290
setIsDynamicVariableInfoOpen(!isDynamicVariableInfoOpen)
288291
}
289292
borderRadius="5"
290-
marginY={5}
293+
marginBottom={5}
291294
cursor="pointer"
292295
fontSize="sm"
293296
>
@@ -382,7 +385,7 @@ const UpdateEmailTemplate = ({
382385
width="100%"
383386
justifyContent="start"
384387
alignItems="center"
385-
marginBottom="5%"
388+
marginBottom="2%"
386389
>
387390
<Flex flex="1">Subject</Flex>
388391
<Flex flex="3">
@@ -407,41 +410,21 @@ const UpdateEmailTemplate = ({
407410
</Flex>
408411
<Flex
409412
width="100%"
410-
justifyContent="space-between"
413+
justifyContent="flex-start"
411414
alignItems="center"
412415
marginBottom="2%"
413416
>
414-
<Flex>Template Body</Flex>
415-
<Text
416-
style={{
417-
fontSize: 14,
418-
}}
419-
color="gray.400"
420-
>{`To select dynamic variables open curly braces "{"`}</Text>
417+
Template Body
418+
</Flex>
419+
<Flex
420+
width="100%"
421+
justifyContent="flex-start"
422+
alignItems="center"
423+
border="1px solid"
424+
borderColor="gray.200"
425+
>
426+
<EmailEditor ref={emailEditorRef} onReady={onReady} />
421427
</Flex>
422-
<Editor
423-
editorState={editorState}
424-
onEditorStateChange={onEditorStateChange}
425-
editorStyle={{
426-
border: '1px solid #d9d9d9',
427-
borderRadius: '5px',
428-
marginTop: '2%',
429-
height: '30vh',
430-
padding: 10,
431-
}}
432-
mention={{
433-
separator: ' ',
434-
trigger: '{',
435-
suggestions: templateVariables,
436-
}}
437-
/>
438-
<Alert status="info" marginY={5} borderRadius={5}>
439-
<AlertIcon />
440-
<Box fontSize="sm">
441-
<b>Note:</b> In order to use dynamic variables with link and
442-
images you can put them as part of URL in editor section.
443-
</Box>
444-
</Alert>
445428
</Flex>
446429
</ModalBody>
447430
<ModalFooter>

dashboard/src/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ export const SwitchInputType = {
6868
DISABLE_SIGN_UP: 'DISABLE_SIGN_UP',
6969
DISABLE_REDIS_FOR_ENV: 'DISABLE_REDIS_FOR_ENV',
7070
DISABLE_STRONG_PASSWORD: 'DISABLE_STRONG_PASSWORD',
71+
DISABLE_MULTI_FACTOR_AUTHENTICATION: 'DISABLE_MULTI_FACTOR_AUTHENTICATION',
72+
ENFORCE_MULTI_FACTOR_AUTHENTICATION: 'ENFORCE_MULTI_FACTOR_AUTHENTICATION',
7173
};
7274

7375
export const DateInputType = {
@@ -138,6 +140,8 @@ export interface envVarTypes {
138140
DATABASE_TYPE: string;
139141
DATABASE_URL: string;
140142
ACCESS_TOKEN_EXPIRY_TIME: string;
143+
DISABLE_MULTI_FACTOR_AUTHENTICATION: boolean;
144+
ENFORCE_MULTI_FACTOR_AUTHENTICATION: boolean;
141145
}
142146

143147
export const envSubViews = {
@@ -168,6 +172,7 @@ export enum EmailTemplateInputDataFields {
168172
SUBJECT = 'subject',
169173
CREATED_AT = 'created_at',
170174
TEMPLATE = 'template',
175+
DESIGN = 'design',
171176
}
172177

173178
export enum WebhookInputHeaderFields {

0 commit comments

Comments
 (0)