Skip to content

Commit

Permalink
add file uploading + send attachments
Browse files Browse the repository at this point in the history
  • Loading branch information
huang0h committed Jul 18, 2024
1 parent fdad50d commit eb3ce58
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 1 deletion.
3 changes: 3 additions & 0 deletions src/api/test/protectedApiClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2105,6 +2105,7 @@ describe('Admin Protected Client Routes', () => {
emails: ['[email protected]'],
emailSubject: 'Some subject',
emailBody: 'Some body',
attachments: [],
});

expect(result).toEqual(response);
Expand All @@ -2119,6 +2120,7 @@ describe('Admin Protected Client Routes', () => {
emails: ['notAnEmail'],
emailSubject: 'Some subject',
emailBody: 'Some body',
attachments: [],
}).catch((err) => err.response.data);

expect(result).toEqual(response);
Expand All @@ -2133,6 +2135,7 @@ describe('Admin Protected Client Routes', () => {
emails: [],
emailSubject: 'Subject',
emailBody: 'Body',
attachments: [],
}).catch((err) => err.response.data);

expect(result).toEqual(response);
Expand Down
6 changes: 6 additions & 0 deletions src/components/forms/ducks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ export interface SendEmailFormValues {

export interface SendEmailRequest extends SendEmailFormValues {
readonly emails: string[];
readonly attachments: EmailAttachment[];
}

interface EmailAttachment {
readonly name: string;
readonly data: string;
}

export interface AddTemplateRequest {
Expand Down
63 changes: 62 additions & 1 deletion src/components/forms/sendEmailForm/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import styled from 'styled-components';
import { Form, Input, Switch, message } from 'antd';
import { Collapse, Form, Input, Switch, UploadProps, message } from 'antd';
import {
Flex,
SubmitButton,
Expand All @@ -19,6 +19,10 @@ import { n } from '../../../utils/stringFormat';
import DOMPurify from 'isomorphic-dompurify';
import SaveMenu from '../../saveMenu';
import templateContent from './content';
import Dragger from 'antd/lib/upload/Dragger';
import { InboxOutlined } from '@ant-design/icons';
import { LIGHT_GREEN } from '../../../utils/colors';
import { RcFile } from 'antd/lib/upload';

const PreviewSwitch = styled(Switch)`
display: flex;
Expand Down Expand Up @@ -46,6 +50,20 @@ const EmailFlex = styled(Flex)`
gap: 4px;
`;

function readAndPreview(f: RcFile): Promise<[string, string]> {
return new Promise((resolve) => {
const reader = new FileReader();
reader.addEventListener(
'loadend',
() => {
resolve([f.name, reader.result as string]);
},
false,
);
reader.readAsDataURL(f);
});
}

interface SendEmailFormProps {
readonly emails: string[];
readonly sendEmailForm: FormInstance<SendEmailRequest>;
Expand All @@ -63,6 +81,7 @@ const SendEmailForm: React.FC<SendEmailFormProps> = ({
const [showPreview, setShowPreview] = useState<boolean>(false);
const [showSave, setShowSave] = useState(false);
const [sanitizedBodyContent, setSanitizedBodyContent] = useState<string>('');
const [attachments, setAttachments] = useState<Record<string, string>>({});

const togglePreview = (isShowPreview: boolean) => {
setShowPreview(isShowPreview);
Expand All @@ -78,10 +97,15 @@ const SendEmailForm: React.FC<SendEmailFormProps> = ({
return;
}

const attachmentData = Object.entries(attachments).map(([name, data]) => {
return { name, data };
});

const sendEmailRequest: SendEmailRequest = {
emailSubject: values.emailSubject,
emailBody: DOMPurify.sanitize(values.emailBody),
emails,
attachments: attachmentData,
};
ProtectedApiClient.sendEmail(sendEmailRequest)
.then(() => {
Expand All @@ -92,6 +116,32 @@ const SendEmailForm: React.FC<SendEmailFormProps> = ({
);
};

const attachmentFormProps: UploadProps = {
name: 'file',
multiple: true,
beforeUpload: (_, fileList) => {
if (fileList.length === 0) {
return false;
}

const uploadPromises = fileList.map((f) => readAndPreview(f));
Promise.all(uploadPromises).then((uploadedAttachments) => {
setAttachments({
...attachments,
...Object.fromEntries(uploadedAttachments),
});
});

return false;
},
onRemove(file) {
const attachmentsCopy = attachments;
delete attachmentsCopy[file.name];

setAttachments(attachmentsCopy);
},
};

return (
<Form name="sendEmail" form={sendEmailForm} onFinish={onFinishSendEmail}>
<Form.Item
Expand Down Expand Up @@ -123,6 +173,17 @@ const SendEmailForm: React.FC<SendEmailFormProps> = ({
}}
/>
)}
<Collapse ghost style={{ maxWidth: '600px' }}>
<Collapse.Panel header={t('upload_collapse_title')} key="attachments">
<Dragger {...attachmentFormProps}>
<p className="ant-upload-drag-icon">
<InboxOutlined style={{ color: LIGHT_GREEN }} />
</p>
<p className="ant-upload-text">{t('upload_header')}</p>
<p className="ant-upload-hint">{t('upload_description')}</p>
</Dragger>
</Collapse.Panel>
</Collapse>
<EmailFlex>
<SubmitButton type="primary" htmlType="submit">
{t('send')}
Expand Down
3 changes: 3 additions & 0 deletions src/i18n/en/forms.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@
},
"body_required": "The email body is required",
"body_placeholder": "Email Body",
"upload_collapse_title": "Upload Attachments",
"upload_header": "Click or drag a file to this area to upload",
"upload_description": "Add attachments to send to users!",
"send": "Send Email",
"save": "Save as Template",
"name_template": "Name your template",
Expand Down

0 comments on commit eb3ce58

Please sign in to comment.