Skip to content

Commit

Permalink
feat: payment received mail receipt preview
Browse files Browse the repository at this point in the history
  • Loading branch information
abouolia committed Nov 20, 2024
1 parent 6103f1e commit 63a95df
Show file tree
Hide file tree
Showing 18 changed files with 622 additions and 9 deletions.
15 changes: 9 additions & 6 deletions packages/server/src/api/controllers/Sales/PaymentReceives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,9 @@ export default class PaymentReceivesController extends BaseController {
const { tenantId } = req;

try {
const data =
await this.paymentReceiveApplication.getPaymentReceivedState(tenantId);
const data = await this.paymentReceiveApplication.getPaymentReceivedState(
tenantId
);
return res.status(200).send({ data });
} catch (error) {
next(error);
Expand Down Expand Up @@ -469,6 +470,7 @@ export default class PaymentReceivesController extends BaseController {
const acceptType = accept.types([
ACCEPT_TYPE.APPLICATION_JSON,
ACCEPT_TYPE.APPLICATION_PDF,
ACCEPT_TYPE.APPLICATION_TEXT_HTML,
]);
// Responses pdf format.
if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) {
Expand All @@ -485,10 +487,11 @@ export default class PaymentReceivesController extends BaseController {
res.send(pdfContent);
// Responses html format.
} else if (ACCEPT_TYPE.APPLICATION_TEXT_HTML === acceptType) {
const htmlContent = this.paymentReceiveApplication.getPaymentReceivedHtml(
tenantId,
paymentReceiveId
);
const htmlContent =
await this.paymentReceiveApplication.getPaymentReceivedHtml(
tenantId,
paymentReceiveId
);
return res.status(200).send({ htmlContent });
// Responses json format.
} else {
Expand Down
2 changes: 0 additions & 2 deletions packages/webapp/src/components/DialogsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import ProjectBillableEntriesFormDialog from '@/containers/Projects/containers/P
import TaxRateFormDialog from '@/containers/TaxRates/dialogs/TaxRateFormDialog/TaxRateFormDialog';
import { DialogsName } from '@/constants/dialogs';
import InvoiceExchangeRateChangeDialog from '@/containers/Sales/Invoices/InvoiceForm/Dialogs/InvoiceExchangeRateChangeDialog';
import PaymentMailDialog from '@/containers/Sales/PaymentsReceived/PaymentMailDialog/PaymentMailDialog';
import { ExportDialog } from '@/containers/Dialogs/ExportDialog';
import { RuleFormDialog } from '@/containers/Banking/Rules/RuleFormDialog/RuleFormDialog';
import { DisconnectBankAccountDialog } from '@/containers/CashFlow/AccountTransactions/dialogs/DisconnectBankAccountDialog/DisconnectBankAccountDialog';
Expand Down Expand Up @@ -139,7 +138,6 @@ export default function DialogsContainer() {
<InvoiceExchangeRateChangeDialog
dialogName={DialogsName.InvoiceExchangeRateChangeNotice}
/>
<PaymentMailDialog dialogName={DialogsName.PaymentMail} />
<ExportDialog dialogName={DialogsName.Export} />
<RuleFormDialog dialogName={DialogsName.BankRuleForm} />
<DisconnectBankAccountDialog
Expand Down
2 changes: 2 additions & 0 deletions packages/webapp/src/components/DrawersContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { DRAWERS } from '@/constants/drawers';
import { InvoiceSendMailDrawer } from '@/containers/Sales/Invoices/InvoiceSendMailDrawer/InvoiceSendMailDrawer';
import { EstimateSendMailDrawer } from '@/containers/Sales/Estimates/EstimateSendMailDrawer';
import { ReceiptSendMailDrawer } from '@/containers/Sales/Receipts/ReceiptSendMailDrawer';
import { PaymentReceivedSendMailDrawer } from '@/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer';

/**
* Drawers container of the dashboard.
Expand Down Expand Up @@ -85,6 +86,7 @@ export default function DrawersContainer() {
<InvoiceSendMailDrawer name={DRAWERS.INVOICE_SEND_MAIL} />
<EstimateSendMailDrawer name={DRAWERS.ESTIMATE_SEND_MAIL} />
<ReceiptSendMailDrawer name={DRAWERS.RECEIPT_SEND_MAIL} />
<PaymentReceivedSendMailDrawer name={DRAWERS.PAYMENT_RECEIVED_SEND_MAIL} />
</div>
);
}
1 change: 1 addition & 0 deletions packages/webapp/src/constants/drawers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ export enum DRAWERS {
INVOICE_SEND_MAIL = 'INVOICE_SEND_MAIL',
ESTIMATE_SEND_MAIL = 'ESTIMATE_SEND_MAIL',
RECEIPT_SEND_MAIL = 'RECEIPT_SEND_MAIL',
PAYMENT_RECEIVED_SEND_MAIL = 'PAYMENT_RECEIVED_SEND_MAIL',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { createContext, useContext } from 'react';
import { Spinner } from '@blueprintjs/core';
import {
PaymentReceivedStateResponse,
usePaymentReceivedState,
} from '@/hooks/query';
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';

interface PaymentReceivedSendMailBootValues {
paymentReceivedId: number;

paymentReceivedMailState: PaymentReceivedStateResponse | undefined;
isPaymentReceivedStateLoading: boolean;
}
interface InvoiceSendMailBootProps {
children: React.ReactNode;
}

const PaymentReceivedSendMailBootContext =
createContext<PaymentReceivedSendMailBootValues>(
{} as PaymentReceivedSendMailBootValues,
);

export const PaymentReceivedSendMailBoot = ({
children,
}: InvoiceSendMailBootProps) => {
const {
payload: { paymentReceivedId },
} = useDrawerContext();

const {
data: paymentReceivedMailState,
isLoading: isPaymentReceivedStateLoading,
} = usePaymentReceivedState(paymentReceivedId);

const isLoading = isPaymentReceivedStateLoading;

if (isLoading) {
return <Spinner size={20} />;
}
const value = {
paymentReceivedId,

// # mail options
isPaymentReceivedStateLoading,
paymentReceivedMailState,
};

return (
<PaymentReceivedSendMailBootContext.Provider value={value}>
{children}
</PaymentReceivedSendMailBootContext.Provider>
);
};
PaymentReceivedSendMailBoot.displayName = 'PaymentReceivedSendMailBoot';

export const usePaymentReceivedSendMailBoot = () => {
return useContext<PaymentReceivedSendMailBootValues>(
PaymentReceivedSendMailBootContext,
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Stack } from '@/components';
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';

export function PaymentReceivedSendMailContent() {
return (
<Stack className={Classes.DRAWER_BODY}>
<PaymentReceivedSendMailBoot>
<PaymentReceivedSendMailForm>
<SendMailViewLayout
header={<SendMailViewHeader label={'Send Payment Mail'} />}
fields={<PaymentReceivedSendMailFields />}
preview={<PaymentReceivedSendMailPreview />}
/>
</PaymentReceivedSendMailForm>
</PaymentReceivedSendMailBoot>
</Stack>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// @ts-nocheck
import React from 'react';
import * as R from 'ramda';
import { Drawer, DrawerSuspense } from '@/components';
import withDrawers from '@/containers/Drawer/withDrawers';

const PaymentReceivedMailContent = React.lazy(() =>
import('./PaymentReceivedMailContent').then((module) => ({
default: module.PaymentReceivedSendMailContent,
})),
);

interface PaymentReceivedSendMailDrawerProps {
name: string;
isOpen?: boolean;
payload?: any;
}

function PaymentReceivedSendMailDrawerRoot({
name,

// #withDrawer
isOpen,
payload,
}: PaymentReceivedSendMailDrawerProps) {
return (
<Drawer
isOpen={isOpen}
name={name}
payload={payload}
size={'calc(100% - 10px)'}
>
<DrawerSuspense>
<PaymentReceivedMailContent />
</DrawerSuspense>
</Drawer>
);
}

export const PaymentReceivedSendMailDrawer = R.compose(withDrawers())(
PaymentReceivedSendMailDrawerRoot,
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// @ts-nocheck
import { Button, Intent } from '@blueprintjs/core';
import { useFormikContext } from 'formik';
import { FCheckbox, FFormGroup, FInputGroup, Group, Stack } from '@/components';
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 = [];

export function PaymentReceivedSendMailFields() {
// const items = useInvoiceMailItems();
// const argsOptions = useSendInvoiceFormatArgsOptions();

return (
<Stack>
<Stack spacing={0} overflow="auto" flex="1" p={'30px'}>
<SendMailViewToAddressField
toMultiSelectProps={{ items }}
ccMultiSelectProps={{ items }}
bccMultiSelectProps={{ items }}
/>
<FFormGroup label={'Submit'} name={'subject'}>
<FInputGroup name={'subject'} large fastField />
</FFormGroup>

<SendMailViewMessageField argsOptions={argsOptions} />

<Group>
<FCheckbox name={'attachPdf'} label={'Attach PDF'} />
</Group>
</Stack>

<PaymentReceivedSendMailFooter />
</Stack>
);
}

function PaymentReceivedSendMailFooter() {
const { isSubmitting } = useFormikContext();
const { name } = useDrawerContext();
const { closeDrawer } = useDrawerActions();

const handleClose = () => {
closeDrawer(name);
};

return (
<Group
py={'12px'}
px={'16px'}
borderTop="1px solid #d8d8d9"
position={'apart'}
>
<Group spacing={10} ml={'auto'}>
<Button
disabled={isSubmitting}
onClick={handleClose}
style={{ minWidth: '65px' }}
>
Close
</Button>

<Button
intent={Intent.PRIMARY}
loading={isSubmitting}
style={{ minWidth: '85px' }}
type="submit"
>
Send Mail
</Button>
</Group>
</Group>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { Form, Formik, FormikHelpers } from 'formik';
import { css } from '@emotion/css';
import { Intent } from '@blueprintjs/core';
import { PaymentReceivedSendMailFormSchema } from './_types';
import { AppToaster } from '@/components';
import { useSendSaleInvoiceMail } from '@/hooks/query';
import { usePaymentReceivedSendMailBoot } from './PaymentReceivedMailBoot';
import { useDrawerActions } from '@/hooks/state';
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
import { transformToForm } from '@/utils';
import { PaymentReceivedSendMailFormValues } from './_types';

const initialValues: PaymentReceivedSendMailFormValues = {
subject: '',
message: '',
to: [],
cc: [],
bcc: [],
attachPdf: true,
};

interface PaymentReceivedSendMailFormProps {
children: React.ReactNode;
}

export function PaymentReceivedSendMailForm({
children,
}: PaymentReceivedSendMailFormProps) {
const { mutateAsync: sendInvoiceMail } = useSendSaleInvoiceMail();
const { paymentReceivedId, paymentReceivedMailState } =
usePaymentReceivedSendMailBoot();

const { name } = useDrawerContext();
const { closeDrawer } = useDrawerActions();

const _initialValues: PaymentReceivedSendMailFormValues = {
...initialValues,
...transformToForm(paymentReceivedMailState, initialValues),
};
const handleSubmit = (
values: PaymentReceivedSendMailFormValues,
{ setSubmitting }: FormikHelpers<PaymentReceivedSendMailFormValues>,
) => {
setSubmitting(true);
sendInvoiceMail({ id: paymentReceivedId, values: { ...values } })
.then(() => {
AppToaster.show({
message: 'The invoice mail has been sent to the customer.',
intent: Intent.SUCCESS,
});
setSubmitting(false);
closeDrawer(name);
})
.catch(() => {
setSubmitting(false);
AppToaster.show({
message: 'Something went wrong!',
intent: Intent.SUCCESS,
});
});
};

return (
<Formik
initialValues={_initialValues}
validationSchema={PaymentReceivedSendMailFormSchema}
onSubmit={handleSubmit}
>
<Form
className={css`
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
`}
>
{children}
</Form>
</Formik>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { SendViewPreviewHeader } from "../../Estimates/SendMailViewDrawer/SendMailViewPreviewHeader";

export function PaymentReceivedMailPreviewHeader() {
return (
<SendViewPreviewHeader
companyName="A"
customerName="A"
subject={'adsfsdf'}
from={['[email protected]']}
to={['[email protected]']}
/>
);
}
Loading

0 comments on commit 63a95df

Please sign in to comment.