mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 13:20:31 +00:00
feat: hook up the request to the send mail form
This commit is contained in:
@@ -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 (
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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')),
|
||||
});
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface InvoiceSendMailFormValues {
|
||||
subject: string;
|
||||
message: string;
|
||||
to: string[];
|
||||
cc?: string[];
|
||||
bcc?: string[];
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user