From 2a85fe2f3ca203f18719065360cf1dbadac7579e Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Fri, 29 Dec 2023 17:31:51 +0200 Subject: [PATCH] feat(webapp): the mail notifications dialogs --- .../EstimateMailDialogForm.tsx | 45 +++++++------ .../EstimateMailDialogFormContent.tsx | 8 ++- .../InvoiceMailDialogForm.tsx | 46 ++++++++------ .../InvoiceMailDialogFormContent.tsx | 8 ++- .../PaymentMailDialogForm.tsx | 47 ++++++++------ .../PaymentMailDialogFormContent.tsx | 8 ++- .../ReceiptMailDialogForm.tsx | 50 +++++++++------ .../ReceiptMailDialogFormContent.tsx | 8 ++- .../MailNotificationForm.tsx | 11 +++- .../SendMailNotification/RichEditor.tsx | 63 ------------------- .../containers/SendMailNotification/index.ts | 2 +- .../containers/SendMailNotification/utils.ts | 44 +++++++++++++ packages/webapp/src/hooks/query/receipts.tsx | 2 +- 13 files changed, 192 insertions(+), 150 deletions(-) delete mode 100644 packages/webapp/src/containers/SendMailNotification/RichEditor.tsx create mode 100644 packages/webapp/src/containers/SendMailNotification/utils.ts diff --git a/packages/webapp/src/containers/Sales/Estimates/EstimateMailDialog/EstimateMailDialogForm.tsx b/packages/webapp/src/containers/Sales/Estimates/EstimateMailDialog/EstimateMailDialogForm.tsx index 5f00c996e..f8811cdbb 100644 --- a/packages/webapp/src/containers/Sales/Estimates/EstimateMailDialog/EstimateMailDialogForm.tsx +++ b/packages/webapp/src/containers/Sales/Estimates/EstimateMailDialog/EstimateMailDialogForm.tsx @@ -1,27 +1,26 @@ // @ts-nocheck import { Formik } from 'formik'; import * as R from 'ramda'; -import { castArray } from 'lodash'; import { useEstimateMailDialogBoot } from './EstimateMailDialogBoot'; -import { transformToForm } from '@/utils'; import { DialogsName } from '@/constants/dialogs'; import withDialogActions from '@/containers/Dialog/withDialogActions'; import { useSendSaleEstimateMail } from '@/hooks/query'; import { EstimateMailDialogFormContent } from './EstimateMailDialogFormContent'; +import { + initialMailNotificationValues, + MailNotificationFormValues, + transformMailFormToInitialValues, + transformMailFormToRequest, +} from '@/containers/SendMailNotification/utils'; +import { Intent } from '@blueprintjs/core'; +import { AppToaster } from '@/components'; const initialFormValues = { - from: [], - to: [], - subject: '', - body: '', + ...initialMailNotificationValues, attachEstimate: true, }; -interface EstimateMailFormValues { - from: string[]; - to: string[]; - subject: string; - body: string; +interface EstimateMailFormValues extends MailNotificationFormValues { attachEstimate: boolean; } @@ -32,21 +31,31 @@ function EstimateMailDialogFormRoot({ const { mutateAsync: sendEstimateMail } = useSendSaleEstimateMail(); const { mailOptions, saleEstimateId } = useEstimateMailDialogBoot(); - const initialValues = { - ...initialFormValues, - ...transformToForm(mailOptions, initialFormValues), - from: mailOptions.from ? castArray(mailOptions.from) : [], - to: mailOptions.to ? castArray(mailOptions.to) : [], - }; + const initialValues = transformMailFormToInitialValues( + mailOptions, + initialFormValues, + ); // Handle the form submitting. const handleSubmit = (values: EstimateMailFormValues, { setSubmitting }) => { + const reqValues = transformMailFormToRequest(values); + setSubmitting(true); - sendEstimateMail([saleEstimateId, values]) + sendEstimateMail([saleEstimateId, reqValues]) .then(() => { + AppToaster.show({ + message: 'The mail notification has been sent successfully.', + intent: Intent.SUCCESS, + }); + closeDialog(DialogsName.EstimateMail); setSubmitting(false); }) .catch((error) => { setSubmitting(false); + closeDialog(DialogsName.EstimateMail); + AppToaster.show({ + message: 'Something went wrong.', + intent: Intent.DANGER, + }); }); }; diff --git a/packages/webapp/src/containers/Sales/Estimates/EstimateMailDialog/EstimateMailDialogFormContent.tsx b/packages/webapp/src/containers/Sales/Estimates/EstimateMailDialog/EstimateMailDialogFormContent.tsx index d299d5b16..668c7a4c9 100644 --- a/packages/webapp/src/containers/Sales/Estimates/EstimateMailDialog/EstimateMailDialogFormContent.tsx +++ b/packages/webapp/src/containers/Sales/Estimates/EstimateMailDialog/EstimateMailDialogFormContent.tsx @@ -5,6 +5,7 @@ import styled from 'styled-components'; import { FFormGroup, FSwitch } from '@/components'; import { MailNotificationForm } from '@/containers/SendMailNotification'; import { saveInvoke } from '@/utils'; +import { useEstimateMailDialogBoot } from './EstimateMailDialogBoot'; interface EstimateMailDialogFormContentProps { onClose?: () => void; @@ -14,6 +15,7 @@ export function EstimateMailDialogFormContent({ onClose, }: EstimateMailDialogFormContentProps) { const { isSubmitting } = useFormikContext(); + const { mailOptions } = useEstimateMailDialogBoot(); const handleClose = () => { saveInvoke(onClose); @@ -22,8 +24,10 @@ export function EstimateMailDialogFormContent({ return (
- - + diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceMailDialog/InvoiceMailDialogForm.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceMailDialog/InvoiceMailDialogForm.tsx index 6aa62cfba..794ed890d 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceMailDialog/InvoiceMailDialogForm.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceMailDialog/InvoiceMailDialogForm.tsx @@ -1,28 +1,27 @@ // @ts-nocheck import { Formik } from 'formik'; -import { castArray } from 'lodash'; import * as R from 'ramda'; +import { Intent } from '@blueprintjs/core'; import { useInvoiceMailDialogBoot } from './InvoiceMailDialogBoot'; -import { transformToForm } from '@/utils'; import { DialogsName } from '@/constants/dialogs'; +import { AppToaster } from '@/components'; import { useSendSaleInvoiceMail } from '@/hooks/query'; -import { InvoiceMailDialogFormContent } from './InvoiceMailDialogFormContent'; import withDialogActions from '@/containers/Dialog/withDialogActions'; +import { InvoiceMailDialogFormContent } from './InvoiceMailDialogFormContent'; import { InvoiceMailFormSchema } from './InvoiceMailDialogForm.schema'; +import { + MailNotificationFormValues, + initialMailNotificationValues, + transformMailFormToRequest, + transformMailFormToInitialValues, +} from '@/containers/SendMailNotification/utils'; const initialFormValues = { - from: [], - to: [], - subject: '', - body: '', + ...initialMailNotificationValues, attachInvoice: true, }; -interface InvoiceMailFormValues { - from: string[]; - to: string[]; - subject: string; - body: string; +interface InvoiceMailFormValues extends MailNotificationFormValues { attachInvoice: boolean; } @@ -33,20 +32,29 @@ function InvoiceMailDialogFormRoot({ const { mailOptions, saleInvoiceId } = useInvoiceMailDialogBoot(); const { mutateAsync: sendInvoiceMail } = useSendSaleInvoiceMail(); - const initialValues = { - ...initialFormValues, - ...transformToForm(mailOptions, initialFormValues), - from: mailOptions.from ? castArray(mailOptions.from) : [], - to: mailOptions.to ? castArray(mailOptions.to) : [], - }; + const initialValues = transformMailFormToInitialValues( + mailOptions, + initialFormValues, + ); // Handle the form submitting. const handleSubmit = (values: InvoiceMailFormValues, { setSubmitting }) => { + const reqValues = transformMailFormToRequest(values); + setSubmitting(true); - sendInvoiceMail([saleInvoiceId, values]) + sendInvoiceMail([saleInvoiceId, reqValues]) .then(() => { + AppToaster.show({ + message: 'The mail notification has been sent successfully.', + intent: Intent.SUCCESS, + }); + closeDialog(DialogsName.InvoiceMail); setSubmitting(false); }) .catch(() => { + AppToaster.show({ + message: 'Something went wrong.', + intent: Intent.DANGER, + }); setSubmitting(false); }); }; diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceMailDialog/InvoiceMailDialogFormContent.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceMailDialog/InvoiceMailDialogFormContent.tsx index 2038d5379..07e104027 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceMailDialog/InvoiceMailDialogFormContent.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceMailDialog/InvoiceMailDialogFormContent.tsx @@ -5,6 +5,7 @@ import styled from 'styled-components'; import { FFormGroup, FSwitch } from '@/components'; import { MailNotificationForm } from '@/containers/SendMailNotification'; import { saveInvoke } from '@/utils'; +import { useInvoiceMailDialogBoot } from './InvoiceMailDialogBoot'; interface SendMailNotificationFormProps { onClose?: () => void; @@ -14,6 +15,7 @@ export function InvoiceMailDialogFormContent({ onClose, }: SendMailNotificationFormProps) { const { isSubmitting } = useFormikContext(); + const { mailOptions } = useInvoiceMailDialogBoot(); const handleClose = () => { saveInvoke(onClose); @@ -22,8 +24,10 @@ export function InvoiceMailDialogFormContent({ return (
- - + diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentMailDialog/PaymentMailDialogForm.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentMailDialog/PaymentMailDialogForm.tsx index 04906185d..075c2ee8b 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentMailDialog/PaymentMailDialogForm.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentMailDialog/PaymentMailDialogForm.tsx @@ -1,27 +1,26 @@ // @ts-nocheck import { Formik, FormikBag } from 'formik'; -import { castArray } from 'lodash'; import * as R from 'ramda'; +import { Intent } from '@blueprintjs/core'; import { usePaymentMailDialogBoot } from './PaymentMailDialogBoot'; import withDialogActions from '@/containers/Dialog/withDialogActions'; import { DialogsName } from '@/constants/dialogs'; import { useSendPaymentReceiveMail } from '@/hooks/query'; import { PaymentMailDialogFormContent } from './PaymentMailDialogFormContent'; -import { transformToForm } from '@/utils'; +import { + MailNotificationFormValues, + initialMailNotificationValues, + transformMailFormToRequest, + transformMailFormToInitialValues, +} from '@/containers/SendMailNotification/utils'; +import { AppToaster } from '@/components'; const initialFormValues = { - from: [], - to: [], - subject: '', - body: '', + ...initialMailNotificationValues, attachPayment: true, }; -interface PaymentMailFormValue { - from: string[]; - to: string[]; - subject: string; - body: string; +interface PaymentMailFormValue extends MailNotificationFormValues { attachPayment: boolean; } @@ -32,24 +31,34 @@ export function PaymentMailDialogFormRoot({ const { mailOptions, paymentId } = usePaymentMailDialogBoot(); const { mutateAsync: sendPaymentMail } = useSendPaymentReceiveMail(); - const initialValues = { - ...initialFormValues, - ...transformToForm(mailOptions, initialFormValues), - from: mailOptions.from ? castArray(mailOptions.from) : [], - to: mailOptions.to ? castArray(mailOptions.to) : [], - }; + const initialValues = transformMailFormToInitialValues( + mailOptions, + initialFormValues, + ); // Handles the form submitting. const handleSubmit = ( values: PaymentMailFormValue, { setSubmitting }: FormikBag, ) => { + const reqValues = transformMailFormToRequest(values); + setSubmitting(true); - sendPaymentMail([paymentId, values]) + sendPaymentMail([paymentId, reqValues]) .then(() => { + AppToaster.show({ + message: 'The mail notification has been sent successfully.', + intent: Intent.SUCCESS, + }); setSubmitting(false); + closeDialog(DialogsName.PaymentMail); }) - .catch((error) => { + .catch(() => { + AppToaster.show({ + message: 'Something went wrong.', + intent: Intent.DANGER, + }); setSubmitting(false); + closeDialog(DialogsName.PaymentMail); }); }; diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentMailDialog/PaymentMailDialogFormContent.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentMailDialog/PaymentMailDialogFormContent.tsx index 172494c40..5a04f0f28 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentMailDialog/PaymentMailDialogFormContent.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentMailDialog/PaymentMailDialogFormContent.tsx @@ -5,6 +5,7 @@ import styled from 'styled-components'; import { FFormGroup, FSwitch } from '@/components'; import { MailNotificationForm } from '@/containers/SendMailNotification'; import { saveInvoke } from '@/utils'; +import { usePaymentMailDialogBoot } from './PaymentMailDialogBoot'; interface PaymentMailDialogFormContentProps { onClose?: () => void; @@ -13,6 +14,7 @@ interface PaymentMailDialogFormContentProps { export function PaymentMailDialogFormContent({ onClose, }: PaymentMailDialogFormContentProps) { + const { mailOptions } = usePaymentMailDialogBoot(); const { isSubmitting } = useFormikContext(); const handleClose = () => { @@ -22,8 +24,10 @@ export function PaymentMailDialogFormContent({ return (
- - + diff --git a/packages/webapp/src/containers/Sales/Receipts/ReceiptMailDialog/ReceiptMailDialogForm.tsx b/packages/webapp/src/containers/Sales/Receipts/ReceiptMailDialog/ReceiptMailDialogForm.tsx index 2d5a3bcf1..fb9b845af 100644 --- a/packages/webapp/src/containers/Sales/Receipts/ReceiptMailDialog/ReceiptMailDialogForm.tsx +++ b/packages/webapp/src/containers/Sales/Receipts/ReceiptMailDialog/ReceiptMailDialogForm.tsx @@ -1,26 +1,25 @@ // @ts-nocheck import { Formik, FormikBag } from 'formik'; -import { castArray } from 'lodash'; import * as R from 'ramda'; +import { Intent } from '@blueprintjs/core'; import { useReceiptMailDialogBoot } from './ReceiptMailDialogBoot'; -import { transformToForm } from '@/utils'; import withDialogActions from '@/containers/Dialog/withDialogActions'; import { DialogsName } from '@/constants/dialogs'; import { useSendSaleReceiptMail } from '@/hooks/query'; import { ReceiptMailDialogFormContent } from './ReceiptMailDialogFormContent'; +import { + initialMailNotificationValues, + MailNotificationFormValues, + transformMailFormToInitialValues, + transformMailFormToRequest, +} from '@/containers/SendMailNotification/utils'; +import { AppToaster } from '@/components'; const initialFormValues = { - from: [], - to: [], - subject: '', - body: '', + ...initialMailNotificationValues, attachReceipt: true, }; -interface ReceiptMailFormValues { - from: string[]; - to: string[]; - subject: string; - body: string; +interface ReceiptMailFormValues extends MailNotificationFormValues { attachReceipt: boolean; } @@ -28,26 +27,37 @@ function ReceiptMailDialogFormRoot({ closeDialog }) { const { mailOptions, saleReceiptId } = useReceiptMailDialogBoot(); const { mutateAsync: sendReceiptMail } = useSendSaleReceiptMail(); - const initialValues = { - ...initialFormValues, - ...transformToForm(mailOptions, initialFormValues), - from: mailOptions.from ? castArray(mailOptions.from) : [], - to: mailOptions.to ? castArray(mailOptions.to) : [], - }; + // Transformes mail options to initial form values. + const initialValues = transformMailFormToInitialValues( + mailOptions, + initialFormValues, + ); + // Handle the form submitting. const handleSubmit = ( values: ReceiptMailFormValues, { setSubmitting }: FormikBag, ) => { + const reqValues = transformMailFormToRequest(values); + setSubmitting(true); - sendReceiptMail([saleReceiptId, values]) + sendReceiptMail([saleReceiptId, reqValues]) .then(() => { + AppToaster.show({ + message: 'The mail notification has been sent successfully.', + intent: Intent.SUCCESS, + }); + closeDialog(DialogsName.ReceiptMail); setSubmitting(false); }) - .catch((error) => { + .catch(() => { + AppToaster.show({ + message: 'Something went wrong.', + intent: Intent.DANGER, + }); setSubmitting(false); }); }; - + // Handle the close button click. const handleClose = () => { closeDialog(DialogsName.ReceiptMail); }; diff --git a/packages/webapp/src/containers/Sales/Receipts/ReceiptMailDialog/ReceiptMailDialogFormContent.tsx b/packages/webapp/src/containers/Sales/Receipts/ReceiptMailDialog/ReceiptMailDialogFormContent.tsx index 381160f09..d824d35af 100644 --- a/packages/webapp/src/containers/Sales/Receipts/ReceiptMailDialog/ReceiptMailDialogFormContent.tsx +++ b/packages/webapp/src/containers/Sales/Receipts/ReceiptMailDialog/ReceiptMailDialogFormContent.tsx @@ -4,6 +4,7 @@ import { Button, Classes, Intent } from '@blueprintjs/core'; import styled from 'styled-components'; import { FFormGroup, FSwitch } from '@/components'; import { MailNotificationForm } from '@/containers/SendMailNotification'; +import { useReceiptMailDialogBoot } from './ReceiptMailDialogBoot'; import { saveInvoke } from '@/utils'; interface SendMailNotificationFormProps { @@ -13,6 +14,7 @@ interface SendMailNotificationFormProps { export function ReceiptMailDialogFormContent({ onClose, }: SendMailNotificationFormProps) { + const { mailOptions } = useReceiptMailDialogBoot(); const { isSubmitting } = useFormikContext(); const handleClose = () => { @@ -22,8 +24,10 @@ export function ReceiptMailDialogFormContent({ return (
- - + diff --git a/packages/webapp/src/containers/SendMailNotification/MailNotificationForm.tsx b/packages/webapp/src/containers/SendMailNotification/MailNotificationForm.tsx index 6b5053dd5..b7e578b91 100644 --- a/packages/webapp/src/containers/SendMailNotification/MailNotificationForm.tsx +++ b/packages/webapp/src/containers/SendMailNotification/MailNotificationForm.tsx @@ -16,6 +16,14 @@ interface MailNotificationFormProps { toAddresses: SelectOptionProps[]; } +const commonAddressSelect = { + placeholder: '', + labelAccessor: '', + valueAccessor: 'mail', + tagAccessor: (item) => `<${item.label}> (${item.mail})`, + textAccessor: (item) => `<${item.label}> (${item.mail})`, +}; + export function MailNotificationForm({ fromAddresses, toAddresses, @@ -38,12 +46,12 @@ export function MailNotificationForm({ @@ -57,6 +65,7 @@ export function MailNotificationForm({ tagProps: { round: true, minimal: true, large: true }, }} fill={true} + {...commonAddressSelect} /> diff --git a/packages/webapp/src/containers/SendMailNotification/RichEditor.tsx b/packages/webapp/src/containers/SendMailNotification/RichEditor.tsx deleted file mode 100644 index e540fd6da..000000000 --- a/packages/webapp/src/containers/SendMailNotification/RichEditor.tsx +++ /dev/null @@ -1,63 +0,0 @@ -// @ts-nocheck -import './styles.scss'; -import { Color } from '@tiptap/extension-color'; -import ListItem from '@tiptap/extension-list-item'; -import TextStyle from '@tiptap/extension-text-style'; -import { EditorProvider } from '@tiptap/react'; -import StarterKit from '@tiptap/starter-kit'; -import { Box } from '@/components'; -import styled from 'styled-components'; -import { useUncontrolled } from '@/hooks/useUncontrolled'; - -const extensions = [ - Color.configure({ types: [TextStyle.name, ListItem.name] }), - TextStyle.configure({ types: [ListItem.name] }), - StarterKit.configure({ - bulletList: { - keepMarks: true, - keepAttributes: false, - }, - orderedList: { - keepMarks: true, - keepAttributes: false, - }, - }), -]; - -export interface RichEditorProps { - value?: string; - initialValue?: string; - onChange?: (value: string) => void; - className?: string; -} -export const RichEditor = ({ - value, - initialValue, - onChange, - className, -}: RichEditorProps) => { - const [content, handleChange] = useUncontrolled({ - value, - initialValue, - finalValue: '', - onChange, - }); - - return ( - - - - ); -}; - -const Root = styled(Box)` - padding: 15px; - border: 1px solid #dedfe9; - border-top: 0; - border-bottom-left-radius: 5px; - border-bottom-right-radius: 5px; -`; diff --git a/packages/webapp/src/containers/SendMailNotification/index.ts b/packages/webapp/src/containers/SendMailNotification/index.ts index 6e5788dcc..5662fe7c9 100644 --- a/packages/webapp/src/containers/SendMailNotification/index.ts +++ b/packages/webapp/src/containers/SendMailNotification/index.ts @@ -1 +1 @@ -export * from './SendMailNotificationForm'; \ No newline at end of file +export * from './MailNotificationForm'; \ No newline at end of file diff --git a/packages/webapp/src/containers/SendMailNotification/utils.ts b/packages/webapp/src/containers/SendMailNotification/utils.ts new file mode 100644 index 000000000..59d0f6420 --- /dev/null +++ b/packages/webapp/src/containers/SendMailNotification/utils.ts @@ -0,0 +1,44 @@ +import { castArray, first } from 'lodash'; +import { transformToForm } from '@/utils'; + +export const initialMailNotificationValues = { + from: [], + to: [], + subject: '', + body: '', +}; + +export interface MailNotificationFormValues { + from: string[]; + to: string[]; + subject: string; + body: string; +} + +export const transformMailFormToRequest = ( + values: MailNotificationFormValues, +) => { + return { + ...values, + from: first(values.from), + to: values.to?.join(', '), + }; +}; + +/** + * Transformes the mail options response values to form initial values. + * @param {any} mailOptions + * @param {MailNotificationFormValues} initialValues + * @returns {MailNotificationFormValues} + */ +export const transformMailFormToInitialValues = ( + mailOptions: any, + initialValues: MailNotificationFormValues, +): MailNotificationFormValues => { + return { + ...initialValues, + ...transformToForm(mailOptions, initialValues), + from: mailOptions.from ? castArray(mailOptions.from) : [], + to: mailOptions.to ? castArray(mailOptions.to) : [], + }; +}; diff --git a/packages/webapp/src/hooks/query/receipts.tsx b/packages/webapp/src/hooks/query/receipts.tsx index 60b309589..7a6ae2ce9 100644 --- a/packages/webapp/src/hooks/query/receipts.tsx +++ b/packages/webapp/src/hooks/query/receipts.tsx @@ -216,7 +216,7 @@ export function useSendSaleReceiptMail(props) { const apiRequest = useApiRequest(); return useMutation( - (id, values) => apiRequest.post(`sales/receipts/${id}/mail`, values), + ([id, values]) => apiRequest.post(`sales/receipts/${id}/mail`, values), { onSuccess: () => { // Invalidate queries.