feat: hook up the request to the send mail form

This commit is contained in:
Ahmed Bouhuolia
2024-10-28 12:00:17 +02:00
parent 0930b0428d
commit 0111b0e6ff
7 changed files with 162 additions and 80 deletions

View File

@@ -6,6 +6,7 @@ import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
interface InvoiceSendMailBootValues {
invoice: any;
invoiceId: number;
isInvoiceLoading: boolean;
}
interface InvoiceSendMailBootProps {
@@ -31,6 +32,7 @@ export const InvoiceSendMailBoot = ({ children }: InvoiceSendMailBootProps) => {
const value = {
invoice,
isInvoiceLoading,
invoiceId,
};
return (

View File

@@ -16,6 +16,7 @@ import {
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
import { useDrawerActions } from '@/hooks/state';
import { SelectOptionProps } from '@blueprintjs-formik/select';
import { useInvoiceMailItems } from './_hooks';
// Create new account renderer.
const createNewItemRenderer = (query, active, handleClick) => {
@@ -44,20 +45,24 @@ const styleEmailButton = css`
}
`;
const fieldsWrapStyle = css`
> :not(:first-of-type) .bp4-input {
border-top-color: transparent;
border-top-right-radius: 0;
border-top-left-radius: 0;
}
> :not(:last-of-type) .bp4-input {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
`;
export function InvoiceSendMailFields() {
const [showCCField, setShowCCField] = useState<boolean>(false);
const [showBccField, setShowBccField] = useState<boolean>(false);
const { values, setFieldValue } = useFormikContext();
const items = chain([...values?.to, ...values?.cc, ...values?.bcc])
.filter((email) => !!email?.trim())
.uniq()
.map((email) => ({
value: email,
text: email,
}))
.value();
const items = useInvoiceMailItems();
const handleClickCcBtn = (event) => {
event.preventDefault();
@@ -74,19 +79,44 @@ export function InvoiceSendMailFields() {
};
const handleCreateToItemSelect = (value: SelectOptionProps) => {
const _value = [...values?.to, value?.name];
setFieldValue('to', _value);
setFieldValue('to', [...values?.to, value?.name]);
};
const handleCreateCcItemSelect = (value: SelectOptionProps) => {
const _value = [...values?.cc, value?.name];
setFieldValue('cc', _value);
setFieldValue('cc', [...values?.cc, value?.name]);
};
const handleCreateBccItemSelect = (value: SelectOptionProps) => {
const _value = [...values?.bcc, value?.name];
setFieldValue('bcc', _value);
setFieldValue('bcc', [...values?.bcc, value?.name]);
};
const rightElementsToField = (
<Group
spacing={0}
paddingRight={'7px'}
paddingTop={'7px'}
fontWeight={500}
color={'#000'}
>
<Button
onClick={handleClickCcBtn}
minimal
small
className={styleEmailButton}
>
CC
</Button>
<Button
onClick={handleClickBccBtn}
minimal
small
className={styleEmailButton}
>
BCC
</Button>
</Group>
);
return (
<Stack
bg="white"
@@ -95,22 +125,9 @@ export function InvoiceSendMailFields() {
spacing={0}
borderRight="1px solid #dcdcdd"
>
<Stack spacing={0} overflow="auto" flex="1" p={'30px'} className={css``}>
<Stack spacing={0} overflow="auto" flex="1" p={'30px'}>
<FFormGroup label={'To'} name={'to'}>
<Stack
spacing={0}
className={css`
> :not(:first-of-type) .bp4-input {
border-top-color: transparent;
border-top-right-radius: 0;
border-top-left-radius: 0;
}
> :not(:last-of-type) .bp4-input {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
`}
>
<Stack spacing={0} className={fieldsWrapStyle}>
<FMultiSelect
items={items}
name={'to'}
@@ -118,34 +135,8 @@ export function InvoiceSendMailFields() {
popoverProps={{ minimal: true, fill: true }}
tagInputProps={{
tagProps: { round: true, minimal: true, large: true },
rightElement: rightElementsToField,
large: true,
rightElement: (
<Group
spacing={0}
paddingRight={'7px'}
paddingTop={'7px'}
fontWeight={500}
color={'#000'}
>
<Button
onClick={handleClickCcBtn}
minimal
small
className={styleEmailButton}
>
CC
</Button>
<Button
onClick={handleClickBccBtn}
minimal
small
className={styleEmailButton}
>
BCC
</Button>
</Group>
),
}}
createNewItemRenderer={createNewItemRenderer}
createNewItemFromQuery={createNewItemFromQuery}
@@ -252,3 +243,4 @@ function InvoiceSendMailFooter() {
</Group>
);
}

View File

@@ -0,0 +1,11 @@
import * as Yup from 'yup';
export const InvoiceSendMailFormSchema = Yup.object().shape({
subject: Yup.string().required('Subject is required'),
message: Yup.string().required('Message is required'),
to: Yup.array()
.of(Yup.string().email('Invalid email'))
.required('To address is required'),
cc: Yup.array().of(Yup.string().email('Invalid email')),
bcc: Yup.array().of(Yup.string().email('Invalid email')),
});

View File

@@ -1,6 +1,14 @@
import * as Yup from 'yup';
import { Form, Formik, FormikHelpers } from 'formik';
import { css } from '@emotion/css';
import { Intent } from '@blueprintjs/core';
import { InvoiceSendMailFormValues } from './_types';
import { InvoiceSendMailFormSchema } from './InvoiceSendMailForm.schema';
import { useSendSaleInvoiceMail } from '@/hooks/query';
import { AppToaster } from '@/components';
import { useInvoiceSendMailBoot } from './InvoiceSendMailContentBoot';
import { useDrawerActions } from '@/hooks/state';
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
const initialValues = {
subject: 'invoice INV-0002 for AED 0.00',
@@ -17,33 +25,40 @@ If you have any questions, please let us know,
Thanks,
Mohamed`,
to: ['a.bouhuolia@gmail.com'],
cc: [],
bcc: [],
};
interface InvoiceSendMailFormValues {
subject: string;
message: string;
to: string;
cc: string;
}
const InvoiceSendMailFormSchema = Yup.object().shape({
subject: Yup.string().required('Subject is required'),
message: Yup.string().required('Message is required'),
to: Yup.string().email('Invalid email').required('To address is required'),
cc: Yup.string().email('Invalid email'),
});
interface InvoiceSendMailFormProps {
children: React.ReactNode;
}
export function InvoiceSendMailForm({ children }: InvoiceSendMailFormProps) {
//
const { mutateAsync: sendInvoiceMail } = useSendSaleInvoiceMail();
const { invoiceId } = useInvoiceSendMailBoot();
const { name } = useDrawerContext();
const { closeDrawer } = useDrawerActions();
const handleSubmit = (
values: InvoiceSendMailFormValues,
{ setSubmitting }: FormikHelpers<InvoiceSendMailFormValues>,
) => {};
) => {
setSubmitting(true);
sendInvoiceMail({ id: invoiceId, values: { ...values } })
.then(() => {
AppToaster.show({
message: 'The invoice mail has been sent to the customer.',
intent: Intent.SUCCESS,
});
setSubmitting(false);
closeDrawer(name);
})
.catch((error) => {
setSubmitting(false);
AppToaster.show({
message: 'Something went wrong!',
intent: Intent.SUCCESS,
});
});
};
return (
<Formik

View File

@@ -0,0 +1,18 @@
import { useFormikContext } from 'formik';
import { chain } from 'lodash';
import { InvoiceSendMailFormValues } from './_types';
export const useInvoiceMailItems = () => {
const { values } = useFormikContext<InvoiceSendMailFormValues>();
const cc = values?.cc || [];
const bcc = values?.bcc || [];
return chain([...values?.to, ...cc, ...bcc])
.filter((email) => !!email?.trim())
.uniq()
.map((email) => ({
value: email,
text: email,
}))
.value();
};

View File

@@ -0,0 +1,7 @@
export interface InvoiceSendMailFormValues {
subject: string;
message: string;
to: string[];
cc?: string[];
bcc?: string[];
}

View File

@@ -1,5 +1,11 @@
// @ts-nocheck
import { useQueryClient, useMutation, useQuery } from 'react-query';
import {
useQueryClient,
useMutation,
useQuery,
UseMutationOptions,
UseMutationResult,
} from 'react-query';
import { useRequestQuery } from '../useQueryRequest';
import { transformPagination, transformToCamelCase } from '@/utils';
import useApiRequest from '../useRequest';
@@ -312,18 +318,49 @@ export function useInvoicePaymentTransactions(invoiceId, props) {
);
}
export function useSendSaleInvoiceMail(props) {
interface SendSaleInvoiceMailValues {
id: number;
values: {
subject: string;
message: string;
to: Array<string>;
cc?: Array<string>;
bcc?: Array<string>;
attachInvoice?: boolean;
};
}
interface SendSaleInvoiceMailResponse {}
/**
* Sends the sale invoice mail.
* @param {UseMutationOptions<SendSaleInvoiceMailValues, Error, SendSaleInvoiceMailResponse>}
* @returns {UseMutationResult<SendSaleInvoiceMailResponse, Error, SendSaleInvoiceMailValues>}
*/
export function useSendSaleInvoiceMail(
options?: UseMutationOptions<
SendSaleInvoiceMailResponse,
Error,
SendSaleInvoiceMailValues
>,
): UseMutationResult<
SendSaleInvoiceMailResponse,
Error,
SendSaleInvoiceMailValues
> {
const queryClient = useQueryClient();
const apiRequest = useApiRequest();
return useMutation(
([id, values]) => apiRequest.post(`sales/invoices/${id}/mail`, values),
return useMutation<
SendSaleInvoiceMailResponse,
Error,
SendSaleInvoiceMailValues
>(
(value) => apiRequest.post(`sales/invoices/${value.id}/mail`, value.values),
{
onSuccess: (res, [id, values]) => {
onSuccess: (res) => {
// Common invalidate queries.
commonInvalidateQueries(queryClient);
},
...props,
...options,
},
);
}