diff --git a/packages/server/src/models/PaymentReceive.ts b/packages/server/src/models/PaymentReceive.ts index 0fc013962..daab81d2a 100644 --- a/packages/server/src/models/PaymentReceive.ts +++ b/packages/server/src/models/PaymentReceive.ts @@ -29,7 +29,7 @@ export default class PaymentReceive extends mixin(TenantModel, [ * Virtual attributes. */ static get virtualAttributes() { - return ['localAmount']; + return ['localAmount', 'total']; } /** @@ -40,6 +40,10 @@ export default class PaymentReceive extends mixin(TenantModel, [ return this.amount * this.exchangeRate; } + get total() { + return this.paymentAmount; + } + /** * Resourcable model. */ diff --git a/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailState.tsx b/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailState.tsx new file mode 100644 index 000000000..c6411c881 --- /dev/null +++ b/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailState.tsx @@ -0,0 +1,53 @@ +import { PaymentReceiveMailOpts } from '@/interfaces'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { GetPaymentReceivedMailStateTransformer } from './GetPaymentReceivedMailStateTransformer'; +import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; +import { Inject, Service } from 'typedi'; +import { ContactMailNotification } from '@/services/MailNotification/ContactMailNotification'; + +@Service() +export class GetPaymentReceivedMailState { + @Inject() + private tenancy: HasTenancyService; + + @Inject() + private contactMailNotification: ContactMailNotification; + + @Inject() + private transformer: TransformerInjectable; + + /** + * Retrieves the default payment mail options. + * @param {number} tenantId - Tenant id. + * @param {number} paymentReceiveId - Payment receive id. + * @returns {Promise} + */ + public getMailOptions = async ( + tenantId: number, + paymentId: number + ): Promise => { + const { PaymentReceive } = this.tenancy.models(tenantId); + + const paymentReceive = await PaymentReceive.query() + .findById(paymentId) + .withGraphFetched('customer') + .withGraphFetched('entries.invoice') + .throwIfNotFound(); + + const mailOptions = + await this.contactMailNotification.getDefaultMailOptions( + tenantId, + paymentReceive.customerId + ); + + const transformed = await this.transformer.transform( + tenantId, + paymentReceive, + new GetPaymentReceivedMailStateTransformer(), + { + mailOptions, + } + ); + return transformed; + }; +} diff --git a/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailStateTransformer.ts b/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailStateTransformer.ts new file mode 100644 index 000000000..d52ec279e --- /dev/null +++ b/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailStateTransformer.ts @@ -0,0 +1,134 @@ +import { PaymentReceiveEntry } from '@/models'; +import { PaymentReceiveTransfromer } from './PaymentReceivedTransformer'; +import { PaymentReceivedEntryTransfromer } from './PaymentReceivedEntryTransformer'; + +export class GetPaymentReceivedMailStateTransformer extends PaymentReceiveTransfromer { + /** + * Exclude these attributes from user object. + * @returns {Array} + */ + public excludeAttributes = (): string[] => { + return ['*']; + }; + + /** + * Included attributes. + * @returns {Array} + */ + public includeAttributes = (): string[] => { + return [ + 'paymentDate', + 'paymentDateFormatted', + + 'paymentAmount', + 'paymentAmountFormatted', + + 'total', + 'totalFormatted', + + 'paymentNo', + + 'entries', + + 'companyName', + 'companyLogoUri', + + 'primaryColor', + + 'customerName', + ]; + }; + + /** + * Retrieves the customer name of the payment. + * @returns {string} + */ + protected customerName = (payment) => { + return payment.customer.displayName; + }; + + /** + * Retrieves the company name. + * @returns {string} + */ + protected companyName = () => { + return this.context.organization.name; + }; + + /** + * Retrieves the company logo uri. + * @returns {string | null} + */ + protected companyLogoUri = (payment) => { + return payment.pdfTemplate?.companyLogoUri; + }; + + /** + * Retrieves the primary color. + * @returns {string} + */ + protected primaryColor = (payment) => { + return payment.pdfTemplate?.attributes?.primaryColor; + }; + + /** + * Retrieves the formatted payment date. + * @returns {string} + */ + protected paymentDateFormatted = (payment) => { + return this.formatDate(payment.paymentDate); + }; + + /** + * Retrieves the formatted payment amount. + * @returns {string} + */ + protected paymentAmountFormatted = (payment) => { + return this.formatMoney(payment.paymentAmount); + }; + + /** + * Retrieves the formatted payment amount. + * @returns {string} + */ + protected totalFormatted = (payment) => { + return this.formatMoney(payment.total); + }; + + /** + * Retrieves the payment entries. + * @param {IPaymentReceived} payment + * @returns {IPaymentReceivedEntry[]} + */ + protected entries = (payment) => { + return this.item(payment.entries, new GetPaymentReceivedEntryMailState()); + }; + + /** + * Merges the mail options with the invoice object. + */ + public transform = (object: any) => { + return { + ...this.options.mailOptions, + ...object, + }; + }; +} + +export class GetPaymentReceivedEntryMailState extends PaymentReceivedEntryTransfromer { + /** + * Include these attributes to payment receive entry object. + * @returns {Array} + */ + public includeAttributes = (): string[] => { + return ['paymentAmountFormatted']; + }; + + /** + * Exclude these attributes from user object. + * @returns {Array} + */ + public excludeAttributes = (): string[] => { + return ['*']; + }; +} diff --git a/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedApplication.ts b/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedApplication.ts index 95edd334b..a2bac86fa 100644 --- a/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedApplication.ts +++ b/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedApplication.ts @@ -20,6 +20,7 @@ import { PaymentReceiveNotifyBySms } from './PaymentReceivedSmsNotify'; import GetPaymentReceivedPdf from './GetPaymentReceivedPdf'; import { SendPaymentReceiveMailNotification } from './PaymentReceivedMailNotification'; import { GetPaymentReceivedState } from './GetPaymentReceivedState'; +import { GetPaymentReceivedMailState } from './GetPaymentReceivedMailState'; @Service() export class PaymentReceivesApplication { @@ -53,6 +54,9 @@ export class PaymentReceivesApplication { @Inject() private getPaymentReceivedStateService: GetPaymentReceivedState; + @Inject() + private getPaymentReceivedMailStateService: GetPaymentReceivedMailState; + /** * Creates a new payment receive. * @param {number} tenantId @@ -204,12 +208,15 @@ export class PaymentReceivesApplication { /** * Retrieves the default mail options of the given payment transaction. - * @param {number} tenantId - * @param {number} paymentReceiveId + * @param {number} tenantId - Tenant id. + * @param {number} paymentReceiveId - Payment received id. * @returns {Promise} */ public getPaymentMailOptions(tenantId: number, paymentReceiveId: number) { - return this.paymentMailNotify.getMailOptions(tenantId, paymentReceiveId); + return this.getPaymentReceivedMailStateService.getMailOptions( + tenantId, + paymentReceiveId + ); } /** diff --git a/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedMailNotification.ts b/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedMailNotification.ts index a02db9143..fbd2d236c 100644 --- a/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedMailNotification.ts +++ b/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedMailNotification.ts @@ -62,37 +62,6 @@ export class SendPaymentReceiveMailNotification { } as PaymentReceiveMailPresendEvent); } - /** - * Retrieves the default payment mail options. - * @param {number} tenantId - Tenant id. - * @param {number} paymentReceiveId - Payment receive id. - * @returns {Promise} - */ - public getMailOptions = async ( - tenantId: number, - paymentId: number - ): Promise => { - const { PaymentReceive } = this.tenancy.models(tenantId); - - const paymentReceive = await PaymentReceive.query() - .findById(paymentId) - .throwIfNotFound(); - - const formatArgs = await this.textFormatter(tenantId, paymentId); - - const mailOptions = - await this.contactMailNotification.getDefaultMailOptions( - tenantId, - paymentReceive.customerId - ); - return { - ...mailOptions, - subject: DEFAULT_PAYMENT_MAIL_SUBJECT, - message: DEFAULT_PAYMENT_MAIL_CONTENT, - ...formatArgs, - }; - }; - /** * Retrieves the formatted text of the given sale invoice. * @param {number} tenantId - Tenant id. diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialog.tsx b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialog.tsx deleted file mode 100644 index 32c175ed9..000000000 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialog.tsx +++ /dev/null @@ -1,43 +0,0 @@ -// @ts-nocheck -import React from 'react'; -import { Dialog, DialogSuspense } from '@/components'; -import withDialogRedux from '@/components/DialogReduxConnect'; -import { compose } from '@/utils'; - -const PaymentMailDialogContent = React.lazy( - () => import('./PaymentMailDialogContent'), -); - -/** - * Payment mail dialog. - */ -function PaymentMailDialog({ - dialogName, - payload: { - paymentReceiveId = null, - - // Redirects to the payments list on mail submitting. - redirectToPaymentsList = false, - }, - isOpen, -}) { - return ( - - - - - - ); -} -export default compose(withDialogRedux())(PaymentMailDialog); diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialogBoot.tsx b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialogBoot.tsx deleted file mode 100644 index 61171b41f..000000000 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialogBoot.tsx +++ /dev/null @@ -1,48 +0,0 @@ -// @ts-nocheck -import React, { createContext } from 'react'; -import { usePaymentReceiveDefaultOptions } from '@/hooks/query'; -import { DialogContent } from '@/components'; - -interface PaymentMailDialogBootValues { - paymentReceiveId: number; - mailOptions: any; -} - -const PaymentMailDialogBootContext = - createContext(); - -interface PaymentMailDialogBootProps { - paymentReceiveId: number; - redirectToPaymentsList: boolean; - children: React.ReactNode; -} - -/** - * Payment mail dialog boot provider. - */ -function PaymentMailDialogBoot({ - paymentReceiveId, - redirectToPaymentsList, - ...props -}: PaymentMailDialogBootProps) { - const { data: mailOptions, isLoading: isMailOptionsLoading } = - usePaymentReceiveDefaultOptions(paymentReceiveId); - - const provider = { - mailOptions, - isMailOptionsLoading, - paymentReceiveId, - redirectToPaymentsList - }; - - return ( - - - - ); -} - -const usePaymentMailDialogBoot = () => - React.useContext(PaymentMailDialogBootContext); - -export { PaymentMailDialogBoot, usePaymentMailDialogBoot }; diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialogContent.tsx b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialogContent.tsx deleted file mode 100644 index 33597cfa9..000000000 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialogContent.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { PaymentMailDialogBoot } from './PaymentMailDialogBoot'; -import { PaymentMailDialogForm } from './PaymentMailDialogForm'; - -interface PaymentMailDialogContentProps { - dialogName: string; - paymentReceiveId: number; - redirectToPaymentsList: boolean; -} -export default function PaymentMailDialogContent({ - dialogName, - paymentReceiveId, - redirectToPaymentsList, -}: PaymentMailDialogContentProps) { - return ( - - - - ); -} diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialogForm.tsx b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialogForm.tsx deleted file mode 100644 index 65a6c4ff6..000000000 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialogForm.tsx +++ /dev/null @@ -1,87 +0,0 @@ -// @ts-nocheck -import { Formik, FormikBag } from 'formik'; -import * as R from 'ramda'; -import { Intent } from '@blueprintjs/core'; -import { usePaymentMailDialogBoot } from './PaymentMailDialogBoot'; -import { DialogsName } from '@/constants/dialogs'; -import { useSendPaymentReceiveMail } from '@/hooks/query'; -import { PaymentMailDialogFormContent } from './PaymentMailDialogFormContent'; -import { - MailNotificationFormValues, - initialMailNotificationValues, - transformMailFormToRequest, - transformMailFormToInitialValues, -} from '@/containers/SendMailNotification/utils'; -import { AppToaster } from '@/components'; -import { useHistory } from 'react-router-dom'; -import withDialogActions from '@/containers/Dialog/withDialogActions'; - -const initialFormValues = { - ...initialMailNotificationValues, - attachPayment: true, -}; - -interface PaymentMailFormValue extends MailNotificationFormValues { - attachPayment: boolean; -} - -export function PaymentMailDialogFormRoot({ - // #withDialogActions - closeDialog, -}) { - const { mailOptions, paymentReceiveId, redirectToPaymentsList } = - usePaymentMailDialogBoot(); - const { mutateAsync: sendPaymentMail } = useSendPaymentReceiveMail(); - - const history = useHistory(); - - const initialValues = transformMailFormToInitialValues( - mailOptions, - initialFormValues, - ); - // Handles the form submitting. - const handleSubmit = ( - values: PaymentMailFormValue, - { setSubmitting }: FormikBag, - ) => { - const reqValues = transformMailFormToRequest(values); - - setSubmitting(true); - sendPaymentMail([paymentReceiveId, reqValues]) - .then(() => { - AppToaster.show({ - message: 'The mail notification has been sent successfully.', - intent: Intent.SUCCESS, - }); - setSubmitting(false); - closeDialog(DialogsName.PaymentMail); - - // Redirects to payments list if the option is enabled. - if (redirectToPaymentsList) { - history.push('/payments-received'); - } - }) - .catch(() => { - AppToaster.show({ - message: 'Something went wrong.', - intent: Intent.DANGER, - }); - setSubmitting(false); - closeDialog(DialogsName.PaymentMail); - }); - }; - - const handleClose = () => { - closeDialog(DialogsName.PaymentMail); - }; - - return ( - - - - ); -} - -export const PaymentMailDialogForm = R.compose(withDialogActions)( - PaymentMailDialogFormRoot, -); diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialogFormContent.tsx b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialogFormContent.tsx deleted file mode 100644 index 5e84bf99c..000000000 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialogFormContent.tsx +++ /dev/null @@ -1,66 +0,0 @@ -// @ts-nocheck -import { Form, useFormikContext } from 'formik'; -import { Button, Classes, Intent } from '@blueprintjs/core'; -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; -} - -export function PaymentMailDialogFormContent({ - onClose, -}: PaymentMailDialogFormContentProps) { - const { mailOptions } = usePaymentMailDialogBoot(); - const { isSubmitting } = useFormikContext(); - - const handleClose = () => { - saveInvoke(onClose); - }; - - return ( -
-
- - - - -
- -
-
- - - -
-
-
- ); -} - -const AttachFormGroup = styled(FFormGroup)` - background: #f8f9fb; - margin-top: 0.6rem; - padding: 4px 14px; - border-radius: 5px; - border: 1px solid #dcdcdd; -`; diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/index.ts b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/index.ts deleted file mode 100644 index 5a2fbde70..000000000 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentMailDialog/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './PaymentMailDialog'; \ No newline at end of file diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailBoot.tsx b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailBoot.tsx index c7323b8f4..639717b82 100644 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailBoot.tsx +++ b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailBoot.tsx @@ -1,15 +1,15 @@ import React, { createContext, useContext } from 'react'; import { Spinner } from '@blueprintjs/core'; import { - PaymentReceivedStateResponse, - usePaymentReceivedState, + GetPaymentReceivedMailStateResponse, + usePaymentReceivedMailState, } from '@/hooks/query'; import { useDrawerContext } from '@/components/Drawer/DrawerProvider'; interface PaymentReceivedSendMailBootValues { paymentReceivedId: number; - paymentReceivedMailState: PaymentReceivedStateResponse | undefined; + paymentReceivedMailState: GetPaymentReceivedMailStateResponse | undefined; isPaymentReceivedStateLoading: boolean; } interface InvoiceSendMailBootProps { @@ -31,7 +31,7 @@ export const PaymentReceivedSendMailBoot = ({ const { data: paymentReceivedMailState, isLoading: isPaymentReceivedStateLoading, - } = usePaymentReceivedState(paymentReceivedId); + } = usePaymentReceivedMailState(paymentReceivedId); const isLoading = isPaymentReceivedStateLoading; diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailContent.tsx b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailContent.tsx index bfc536f2a..5115f2ace 100644 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailContent.tsx +++ b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailContent.tsx @@ -3,7 +3,6 @@ import { Classes } from '@blueprintjs/core'; import { PaymentReceivedSendMailBoot } from './PaymentReceivedMailBoot'; import { PaymentReceivedSendMailForm } from './PaymentReceivedMailForm'; import { PaymentReceivedSendMailPreview } from './PaymentReceivedMailPreviewTabs'; -// import { InvoiceSendMailFields } from './InvoiceSendMailFields'; import { SendMailViewHeader } from '../../Estimates/SendMailViewDrawer/SendMailViewHeader'; import { SendMailViewLayout } from '../../Estimates/SendMailViewDrawer/SendMailViewLayout'; import { PaymentReceivedSendMailFields } from './PaymentReceivedMailFields'; diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailFields.tsx b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailFields.tsx index 5dde36570..8c442e556 100644 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailFields.tsx +++ b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailFields.tsx @@ -6,16 +6,15 @@ import { useDrawerContext } from '@/components/Drawer/DrawerProvider'; import { useDrawerActions } from '@/hooks/state'; import { SendMailViewToAddressField } from '../../Estimates/SendMailViewDrawer/SendMailViewToAddressField'; import { SendMailViewMessageField } from '../../Estimates/SendMailViewDrawer/SendMailViewMessageField'; - -const items = []; -const argsOptions = []; +import { usePaymentReceivedFormatArgsOptions, } from './_hooks'; +import { useSendMailItems } from '../../Estimates/SendMailViewDrawer/hooks'; export function PaymentReceivedSendMailFields() { - // const items = useInvoiceMailItems(); - // const argsOptions = useSendInvoiceFormatArgsOptions(); + const argsOptions = usePaymentReceivedFormatArgsOptions(); + const items = useSendMailItems(); return ( - + (); + return ( ); } diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailPreviewPdf.tsx b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailPreviewPdf.tsx index 0dd19ecae..18eb69fec 100644 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailPreviewPdf.tsx +++ b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailPreviewPdf.tsx @@ -7,7 +7,7 @@ import { PaymentReceivedMailPreviewHeader } from './PaymentReceivedMailPreviewHe export function PaymentReceivedSendMailPreviewPdf() { return ( - + diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailPreviewReceipt.tsx b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailPreviewReceipt.tsx index 45b23db46..f04dbfe6c 100644 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailPreviewReceipt.tsx +++ b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailPreviewReceipt.tsx @@ -21,7 +21,7 @@ const defaultPaymentReceiptMailProps = { export function PaymentReceivedMailPreviewReceipt() { return ( - + diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/_hooks.ts b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/_hooks.ts new file mode 100644 index 000000000..ae93af986 --- /dev/null +++ b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/_hooks.ts @@ -0,0 +1,55 @@ +import { useMemo } from 'react'; +import { useFormikContext } from 'formik'; +import { SelectOptionProps } from '@blueprintjs-formik/select'; +import { usePaymentReceivedSendMailBoot } from './PaymentReceivedMailBoot'; +import { PaymentReceivedSendMailFormValues } from './_types'; +import { + formatMailMessage, + transformEmailArgs, + transformFormatArgsToOptions, +} from '../../Estimates/SendMailViewDrawer/hooks'; + +/** + * Retrieves the mail format arguments of payment received mail. + * @returns {Record} + */ +export const usePaymentReceivedMailFormatArgs = (): Record => { + const { paymentReceivedMailState } = usePaymentReceivedSendMailBoot(); + + return useMemo(() => { + return transformEmailArgs(paymentReceivedMailState?.formatArgs || {}); + }, [paymentReceivedMailState]); +}; + +/** + * Retrieves the formatted receipt subject. + * @returns {string} + */ +export const usePaymentReceivedMailSubject = (): string => { + const { values } = useFormikContext(); + const formatArgs = usePaymentReceivedMailFormatArgs(); + + return formatMailMessage(values?.subject, formatArgs); +}; + +/** + * Retrieves the payment received format options. + * @returns {Array} + */ +export const usePaymentReceivedFormatArgsOptions = + (): Array => { + const formatArgs = usePaymentReceivedMailFormatArgs(); + + return transformFormatArgsToOptions(formatArgs); + }; + +/** + * Retrieves the formatted estimate message. + * @returns {string} + */ +export const useSendPaymentReceivedtMailMessage = (): string => { + const { values } = useFormikContext(); + const formatArgs = usePaymentReceivedMailFormatArgs(); + + return formatMailMessage(values?.message, formatArgs); +}; diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/_types.ts b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/_types.ts index 0813c4888..148a3e5b5 100644 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/_types.ts +++ b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/_types.ts @@ -1,4 +1,5 @@ import * as Yup from 'yup'; +import { SendMailViewFormValues } from '../../Estimates/SendMailViewDrawer/_types'; export const PaymentReceivedSendMailFormSchema = Yup.object().shape({ subject: Yup.string().required('Subject is required'), @@ -10,11 +11,7 @@ export const PaymentReceivedSendMailFormSchema = Yup.object().shape({ bcc: Yup.array().of(Yup.string().email('Invalid email address')), }); -export interface PaymentReceivedSendMailFormValues { - subject: string; - message: string; - to: string[]; - cc: string[]; - bcc: string[]; +export interface PaymentReceivedSendMailFormValues + extends SendMailViewFormValues { attachPdf: boolean; } diff --git a/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/ReceiptSendMailBoot.tsx b/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/ReceiptSendMailBoot.tsx index cc53f8682..330235378 100644 --- a/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/ReceiptSendMailBoot.tsx +++ b/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/ReceiptSendMailBoot.tsx @@ -2,12 +2,12 @@ import React, { createContext, useContext } from 'react'; import { Spinner } from '@blueprintjs/core'; import { useDrawerContext } from '@/components/Drawer/DrawerProvider'; -import { useSaleInvoiceMailState } from '@/hooks/query'; +import { GetSaleReceiptMailStateResponse, useSaleInvoiceMailState, useSaleReceiptMailState } from '@/hooks/query'; interface ReceiptSendMailBootValues { receiptId: number; - receiptMailState: any; + receiptMailState: GetSaleReceiptMailStateResponse | null; isReceiptMailState: boolean; } interface ReceiptSendMailBootProps { @@ -24,13 +24,13 @@ export const ReceiptSendMailBoot = ({ children }: ReceiptSendMailBootProps) => { // Receipt mail options. const { data: receiptMailState, isLoading: isReceiptMailState } = - useSaleInvoiceMailState(receiptId); + useSaleReceiptMailState(receiptId); const isLoading = isReceiptMailState; - // if (isLoading) { - // return ; - // } + if (isLoading) { + return ; + } const value = { receiptId, diff --git a/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/ReceiptSendMailFormFields.tsx b/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/ReceiptSendMailFormFields.tsx index 95f1ac2af..b91ae9c30 100644 --- a/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/ReceiptSendMailFormFields.tsx +++ b/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/ReceiptSendMailFormFields.tsx @@ -1,17 +1,19 @@ +import { Button, Intent } from "@blueprintjs/core"; +import { useFormikContext } from "formik"; import { FCheckbox, FFormGroup, FInputGroup, Group, Stack } from "@/components"; import { SendMailViewToAddressField } from "../../Estimates/SendMailViewDrawer/SendMailViewToAddressField"; import { SendMailViewMessageField } from "../../Estimates/SendMailViewDrawer/SendMailViewMessageField"; -import { Button, Intent } from "@blueprintjs/core"; import { useDrawerActions } from "@/hooks/state"; import { useDrawerContext } from "@/components/Drawer/DrawerProvider"; -import { useFormikContext } from "formik"; - -const items: Array = []; -const argsOptions: Array = []; +import { useSendReceiptFormatArgsOptions } from "./_hooks"; +import { useSendMailItems } from "../../Estimates/SendMailViewDrawer/hooks"; export function ReceiptSendMailFormFields() { + const argsOptions = useSendReceiptFormatArgsOptions(); + const items = useSendMailItems(); + return ( - + (); + return ( ); } diff --git a/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/_hooks.ts b/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/_hooks.ts new file mode 100644 index 000000000..b82af3c76 --- /dev/null +++ b/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/_hooks.ts @@ -0,0 +1,54 @@ +import { useMemo } from 'react'; +import { useFormikContext } from 'formik'; +import { SelectOptionProps } from '@blueprintjs-formik/select'; +import { useReceiptSendMailBoot } from './ReceiptSendMailBoot'; +import { ReceiptSendMailFormValues } from './_types'; +import { + formatMailMessage, + transformEmailArgs, + transformFormatArgsToOptions, +} from '../../Estimates/SendMailViewDrawer/hooks'; + +/** + * Retrieves the mail format arguments of receipt mail. + * @returns {Record} + */ +export const useSendReceiptMailFormatArgs = (): Record => { + const { receiptMailState } = useReceiptSendMailBoot(); + + return useMemo(() => { + return transformEmailArgs(receiptMailState?.formatArgs || {}); + }, [receiptMailState]); +}; + +/** + * Retrieves the formatted receipt subject. + * @returns {string} + */ +export const useSendReceiptMailSubject = (): string => { + const { values } = useFormikContext(); + const formatArgs = useSendReceiptMailFormatArgs(); + + return formatMailMessage(values?.subject, formatArgs); +}; + +/** + * Retrieves the estimate format options. + * @returns {Array} + */ +export const useSendReceiptFormatArgsOptions = (): Array => { + const formatArgs = useSendReceiptMailFormatArgs(); + + return transformFormatArgsToOptions(formatArgs); +}; + +/** + * Retrieves the formatted estimate message. + * @returns {string} + */ +export const useSendReceiptMailMessage = (): string => { + const { values } = useFormikContext(); + const formatArgs = useSendReceiptMailFormatArgs(); + + return formatMailMessage(values?.message, formatArgs); +}; diff --git a/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/_types.ts b/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/_types.ts index 839328a34..77c731f81 100644 --- a/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/_types.ts +++ b/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/_types.ts @@ -1 +1,3 @@ -export interface ReceiptSendMailFormValues {} +import { SendMailViewFormValues } from "../../Estimates/SendMailViewDrawer/_types"; + +export interface ReceiptSendMailFormValues extends SendMailViewFormValues {} diff --git a/packages/webapp/src/hooks/query/paymentReceives.tsx b/packages/webapp/src/hooks/query/paymentReceives.tsx index 1d6270a71..3b3112d6e 100644 --- a/packages/webapp/src/hooks/query/paymentReceives.tsx +++ b/packages/webapp/src/hooks/query/paymentReceives.tsx @@ -261,17 +261,32 @@ export function useSendPaymentReceiveMail(props) { ); } -export function usePaymentReceiveDefaultOptions(paymentReceiveId, props) { - return useRequestQuery( +export interface GetPaymentReceivedMailStateResponse { + companyName: string; + customerName: string; + entries: Array<{ paymentAmountFormatted: string }>; + from: Array; + fromOptions: Array<{ mail: string; label: string; primary: boolean }>; + paymentAmountFormatted: string; + paymentDate: string; + paymentDateFormatted: string; + to: Array; + toOptions: Array<{ mail: string; label: string; primary: boolean }>; + totalFormatted: string; +} + +export function usePaymentReceivedMailState( + paymentReceiveId: number, + props?: UseQueryOptions, +): UseQueryResult { + const apiRequest = useApiRequest(); + + return useQuery( [t.PAYMENT_RECEIVE_MAIL_OPTIONS, paymentReceiveId], - { - method: 'get', - url: `sales/payment_receives/${paymentReceiveId}/mail`, - }, - { - select: (res) => res.data.data, - ...props, - }, + () => + apiRequest + .get(`sales/payment_receives/${paymentReceiveId}/mail`) + .then((res) => transformToCamelCase(res.data?.data)), ); } diff --git a/packages/webapp/src/hooks/query/receipts.tsx b/packages/webapp/src/hooks/query/receipts.tsx index dc2f027fd..e37fb4962 100644 --- a/packages/webapp/src/hooks/query/receipts.tsx +++ b/packages/webapp/src/hooks/query/receipts.tsx @@ -237,17 +237,29 @@ export function useSendSaleReceiptMail(props) { ); } -export function useSaleReceiptDefaultOptions(invoiceId, props) { - return useRequestQuery( - [t.SALE_RECEIPT_MAIL_OPTIONS, invoiceId], - { - method: 'get', - url: `sales/receipts/${invoiceId}/mail`, - }, - { - select: (res) => res.data.data, - ...props, - }, +export interface GetSaleReceiptMailStateResponse { + attachReceipt: boolean; + formatArgs: Record; + from: string[]; + fromOptions: Array<{ mail: string; label: string; primary: boolean; }> + message: string; + subject: string; + to: string[]; + toOptions: Array<{ mail: string; label: string; primary: boolean; }>; +} + +export function useSaleReceiptMailState( + receiptId: number, + props?: UseQueryOptions, +): UseQueryResult { + const apiRequest = useApiRequest(); + + return useQuery( + [t.SALE_RECEIPT_MAIL_OPTIONS, receiptId], + () => + apiRequest + .get(`sales/receipts/${receiptId}/mail`) + .then((res) => transformToCamelCase(res.data.data)), ); }