Skip to content

Commit

Permalink
feat: add mails can be sent to anothe users with gmail account
Browse files Browse the repository at this point in the history
  • Loading branch information
Molaryy committed Oct 1, 2023
1 parent 632b642 commit 3bb32eb
Show file tree
Hide file tree
Showing 10 changed files with 6,463 additions and 5,613 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"@chakra-ui/styled-system": "^2.9.1",
"@chakra-ui/system": "^2.5.8",
"@chakra-ui/theme-tools": "^2.0.18",
"@elasticemail/elasticemail-client": "^4.0.23",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"aleph-sdk-ts": "^3.2.0",
Expand All @@ -22,9 +23,11 @@
"js-file-download": "^0.4.12",
"next": "^12.3.4",
"next-auth": "4.10.3",
"nodemailer": "^6.9.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.10.1",
"smtpjs": "^0.0.1",
"typescript": "^5.1.3",
"zod": "^3.21.4"
},
Expand Down Expand Up @@ -54,6 +57,7 @@
"@types/crypto-js": "^4.1.1",
"@types/git-clone": "^0.2.0",
"@types/node": "^16.18.31",
"@types/nodemailer": "^6.4.11",
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"@typescript-eslint/eslint-plugin": "^5.60.0",
Expand Down
57 changes: 57 additions & 0 deletions pages/api/email.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { NextApiRequest, NextApiResponse } from 'next';
import { mailOptions, transporter } from '../../src/config/nodemailer';

type BodyEmail = {
email: string,
subject: string,
message: string,
}

const CONTACT_MESSAGE_FIELDS: BodyEmail = {
email: 'Email',
subject: 'Subject',
message: 'Message',
};

const generateEmailContent = (data: BodyEmail): { text: string, html: string } => {
const stringData = Object.entries(data).reduce((str: string, [key, val]) => {
if (CONTACT_MESSAGE_FIELDS[key as keyof BodyEmail]) {
return `${str}${CONTACT_MESSAGE_FIELDS[key as keyof BodyEmail]}: \n${val} \n \n`;
}
return str;
}, '');
const htmlData = Object.entries(data).reduce((str, [key, val]) => (`${str}<h3 class='form-heading' align='left'>${CONTACT_MESSAGE_FIELDS[key as keyof BodyEmail]}</h3><p class='form-answer' align='left'>${val}</p>`), '');

return {
text: stringData,
html: `<!DOCTYPE html><html lang='en'> <head> <title></title> <meta charset='utf-8'/> <meta name='viewport' content='width=device-width, initial-scale=1'/> <meta http-equiv='X-UA-Compatible' content='IE=edge'/> <style type='text/css'> body, table, td, a{-webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%;}table{border-collapse: collapse !important;}body{height: 100% !important; margin: 0 !important; padding: 0 !important; width: 100% !important;}@media screen and (max-width: 525px){.wrapper{width: 100% !important; max-width: 100% !important;}.responsive-table{width: 100% !important;}.padding{padding: 10px 5% 15px 5% !important;}.section-padding{padding: 0 15px 50px 15px !important;}}.form-container{margin-bottom: 24px; padding: 20px; border: 1px dashed #ccc;}.form-heading{color: #2a2a2a; font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif; font-weight: 400; text-align: left; line-height: 20px; font-size: 18px; margin: 0 0 8px; padding: 0;}.form-answer{color: #2a2a2a; font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif; font-weight: 300; text-align: left; line-height: 20px; font-size: 16px; margin: 0 0 24px; padding: 0;}div[style*="margin: 16px 0;"]{margin: 0 !important;}</style> </head> <body style='margin: 0 !important; padding: 0 !important; background: #fff'> <div style=' display: none; font-size: 1px; color: #fefefe; line-height: 1px; max-height: 0px; max-width: 0px; opacity: 0; overflow: hidden; ' ></div><table border='0' cellpadding='0' cellspacing='0' width='100%'> <tr> <td bgcolor='#ffffff' align='center' style='padding: 10px 15px 30px 15px' class='section-padding' > <table border='0' cellpadding='0' cellspacing='0' width='100%' style='max-width: 500px' class='responsive-table' > <tr> <td> <table width='100%' border='0' cellspacing='0' cellpadding='0'> <tr> <td> <table width='100%' border='0' cellspacing='0' cellpadding='0' > <tr> <td style=' padding: 0 0 0 0; font-size: 16px; line-height: 25px; color: #232323; ' class='padding message-content' > <h2>New Contact Message</h2> <div class='form-container'>${htmlData}</div></td></tr></table> </td></tr></table> </td></tr></table> </td></tr></table> </body></html>`,
};
};

export default async function handler(req: NextApiRequest, res: NextApiResponse): Promise<void> {
if (req.method === 'POST') {
const data = req.body;
if (!data || !data.email) {
return res.status(400).send({ message: 'Bad request' });
}

try {
mailOptions.to = data.email;
await transporter.sendMail({
...mailOptions,
...generateEmailContent(data),
subject: data.subject,
});

return res.status(200).json({ success: true });
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
} catch (err: Error) {
return res.status(400).json({ message: err.message });
}
}
if (req.method === 'GET') {
return res.status(200).json({ success: 'Bien vu' });
}
return res.status(200).json({ success: 'Bien return' });
};
30 changes: 15 additions & 15 deletions pages/api/program/create.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import z from 'zod';

import deploy from 'lib/services/deploy';
import { clone, getProgramName } from 'lib/services/git';
import { NextApiRequest, NextApiResponse } from 'next';
import {clone, getProgramName} from 'lib/services/git';
import {NextApiRequest, NextApiResponse} from 'next';

const postSchema = z.object({
// eslint-disable-next-line no-useless-escape
repository: z.string().regex(/((git|http(s)?)|(git@[\w\.]+))(:(\/\/)?)([\w\.@\:\/\-~]+)(\.git)(\/)?/),
entrypoint: z.string(),
// eslint-disable-next-line no-useless-escape
repository: z.string().regex(/((git|http(s)?)|(git@[\w\.]+))(:(\/\/)?)([\w\.@\:\/\-~]+)(\.git)(\/)?/),
entrypoint: z.string(),
});

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
if (req.method !== 'POST') throw new Error('Method not allowed');
const body = postSchema.parse(req.body);
const { repository, entrypoint } = body;
const path = await clone(repository);
const itemHash = await deploy(path, entrypoint);
return res.status(200).json({ name: getProgramName(repository), item_hash: itemHash, entrypoint });
} catch (error) {
return res.status(400).end('Bad request');
}
try {
if (req.method !== 'POST') throw new Error('Method not allowed');
const body = postSchema.parse(req.body);
const {repository, entrypoint} = body;
const path = await clone(repository);
const itemHash = await deploy(path, entrypoint);
return res.status(200).json({name: getProgramName(repository), item_hash: itemHash, entrypoint});
} catch (error) {
return res.status(400).end('Bad request');
}
}
202 changes: 102 additions & 100 deletions src/components/dashboardPage/FileOptions.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import {
Box,
Drawer,
DrawerBody,
DrawerContent,
DrawerOverlay,
Popover,
PopoverBody,
PopoverContent,
PopoverTrigger,
Portal,
useDisclosure,
VStack,
Box,
Drawer,
DrawerBody,
DrawerContent,
DrawerOverlay,
Popover,
PopoverBody,
PopoverContent,
PopoverTrigger,
Portal,
useDisclosure,
VStack,
} from '@chakra-ui/react';
import { useEffect } from 'react';
import {useEffect} from 'react';

import DeleteFile from 'components/file/DeleteFile';
import DetailsFile from 'components/file/detailsFile/DetailsFile';
Expand All @@ -23,106 +23,108 @@ import RestoreFile from 'components/file/RestoreFile';
import ShareFile from 'components/file/ShareFile';
import UpdateContentFile from 'components/file/UpdateContentFile';

import { IPCFile } from 'types/types';
import {IPCFile} from 'types/types';

import { useConfigContext } from 'contexts/config';
import {useConfigContext} from 'contexts/config';
import SendEmailFile from "../file/SendEmailFile";

const FileOptionsContent = ({
file,
files,
onClose,
}: {
file: IPCFile;
files: IPCFile[];
onClose: () => void;
file,
files,
onClose,
}: {
file: IPCFile;
files: IPCFile[];
onClose: () => void;
}): JSX.Element => (
<>
{file.deletedAt ? (
<RestoreFile file={file} concernedFiles={files} onClose={onClose} />
) : (
<>
<DownloadFile file={file} onClose={onClose} />
<ShareFile file={file} onClosePopover={onClose} />
<MoveFile file={file} onClosePopover={onClose} />
<RenameFile file={file} concernedFiles={files} onClosePopover={onClose} />
<UpdateContentFile file={file} onClosePopover={onClose} />
</>
)}
<DetailsFile file={file} onClosePopover={onClose} />
<DeleteFile file={file} concernedFiles={files} onClosePopover={onClose} />
</>
<>
{file.deletedAt ? (
<RestoreFile file={file} concernedFiles={files} onClose={onClose}/>
) : (
<>
<DownloadFile file={file} onClose={onClose}/>
<ShareFile file={file} onClosePopover={onClose}/>
<MoveFile file={file} onClosePopover={onClose}/>
<RenameFile file={file} concernedFiles={files} onClosePopover={onClose}/>
<UpdateContentFile file={file} onClosePopover={onClose}/>
<SendEmailFile file={file} onClosePopover={onClose}/>
</>
)}
<DetailsFile file={file} onClosePopover={onClose}/>
<DeleteFile file={file} concernedFiles={files} onClosePopover={onClose}/>
</>
);

const FileOptionsPopover = ({
file,
files,
clickPosition,
popoverOpeningToggle,
popoverOpeningHandler,
}: {
file: IPCFile;
files: IPCFile[];
clickPosition: { x: number; y: number };
popoverOpeningToggle: boolean;
popoverOpeningHandler: () => void;
file,
files,
clickPosition,
popoverOpeningToggle,
popoverOpeningHandler,
}: {
file: IPCFile;
files: IPCFile[];
clickPosition: { x: number; y: number };
popoverOpeningToggle: boolean;
popoverOpeningHandler: () => void;
}): JSX.Element => {
const { config } = useConfigContext();
const { isOpen, onOpen, onClose } = useDisclosure();
const {config} = useConfigContext();
const {isOpen, onOpen, onClose} = useDisclosure();

useEffect(() => {
if (popoverOpeningToggle) {
popoverOpeningHandler();
onOpen();
}
}, [popoverOpeningToggle]);
useEffect(() => {
if (popoverOpeningToggle) {
popoverOpeningHandler();
onOpen();
}
}, [popoverOpeningToggle]);

return (
<Popover placement="right-start" isOpen={isOpen} onClose={() => onClose()}>
<PopoverTrigger>
<Box position="fixed" w="1px" h="1px" bg="transparent" top={clickPosition.y} left={clickPosition.x} />
</PopoverTrigger>
<Portal>
<PopoverContent
w="250px"
backgroundColor={config?.theme.value ?? 'white'}
borderRadius="8px"
border="2px solid #E8EBFF"
_focus={{
boxShadow: 'none',
}}
>
<PopoverBody p="8px">
<VStack w="100%" spacing="4px">
<FileOptionsContent file={file} files={files} onClose={onClose} />
</VStack>
</PopoverBody>
</PopoverContent>
</Portal>
</Popover>
);
return (
<Popover placement="right-start" isOpen={isOpen} onClose={() => onClose()}>
<PopoverTrigger>
<Box position="fixed" w="1px" h="1px" bg="transparent" top={clickPosition.y} left={clickPosition.x}/>
</PopoverTrigger>
<Portal>
<PopoverContent
w="250px"
backgroundColor={config?.theme.value ?? 'white'}
borderRadius="8px"
border="2px solid #E8EBFF"
_focus={{
boxShadow: 'none',
}}
>
<PopoverBody p="8px">
<VStack w="100%" spacing="4px">
<FileOptionsContent file={file} files={files} onClose={onClose}/>
</VStack>
</PopoverBody>
</PopoverContent>
</Portal>
</Popover>
);
};

const FileOptionsDrawer = ({
file,
files,
isOpen,
onClose,
}: {
file: IPCFile;
files: IPCFile[];
isOpen: boolean;
onClose: () => void;
file,
files,
isOpen,
onClose,
}: {
file: IPCFile;
files: IPCFile[];
isOpen: boolean;
onClose: () => void;
}): JSX.Element => (
<Drawer isOpen={isOpen} onClose={onClose} placement="bottom">
<DrawerOverlay />
<DrawerContent borderRadius="16px 16px 0px 0px">
<DrawerBody px="16px" py="32px">
<VStack w="100%" spacing="12px">
<FileOptionsContent file={file} files={files} onClose={onClose} />
</VStack>
</DrawerBody>
</DrawerContent>
</Drawer>
<Drawer isOpen={isOpen} onClose={onClose} placement="bottom">
<DrawerOverlay/>
<DrawerContent borderRadius="16px 16px 0px 0px">
<DrawerBody px="16px" py="32px">
<VStack w="100%" spacing="12px">
<FileOptionsContent file={file} files={files} onClose={onClose}/>
</VStack>
</DrawerBody>
</DrawerContent>
</Drawer>
);

export { FileOptionsPopover, FileOptionsDrawer };
export {FileOptionsPopover, FileOptionsDrawer};
Loading

0 comments on commit 3bb32eb

Please sign in to comment.