mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 07:10:33 +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 {
|
interface InvoiceSendMailBootValues {
|
||||||
invoice: any;
|
invoice: any;
|
||||||
|
invoiceId: number;
|
||||||
isInvoiceLoading: boolean;
|
isInvoiceLoading: boolean;
|
||||||
}
|
}
|
||||||
interface InvoiceSendMailBootProps {
|
interface InvoiceSendMailBootProps {
|
||||||
@@ -31,6 +32,7 @@ export const InvoiceSendMailBoot = ({ children }: InvoiceSendMailBootProps) => {
|
|||||||
const value = {
|
const value = {
|
||||||
invoice,
|
invoice,
|
||||||
isInvoiceLoading,
|
isInvoiceLoading,
|
||||||
|
invoiceId,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
||||||
import { useDrawerActions } from '@/hooks/state';
|
import { useDrawerActions } from '@/hooks/state';
|
||||||
import { SelectOptionProps } from '@blueprintjs-formik/select';
|
import { SelectOptionProps } from '@blueprintjs-formik/select';
|
||||||
|
import { useInvoiceMailItems } from './_hooks';
|
||||||
|
|
||||||
// Create new account renderer.
|
// Create new account renderer.
|
||||||
const createNewItemRenderer = (query, active, handleClick) => {
|
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() {
|
export function InvoiceSendMailFields() {
|
||||||
const [showCCField, setShowCCField] = useState<boolean>(false);
|
const [showCCField, setShowCCField] = useState<boolean>(false);
|
||||||
const [showBccField, setShowBccField] = useState<boolean>(false);
|
const [showBccField, setShowBccField] = useState<boolean>(false);
|
||||||
|
|
||||||
const { values, setFieldValue } = useFormikContext();
|
const { values, setFieldValue } = useFormikContext();
|
||||||
|
const items = useInvoiceMailItems();
|
||||||
const items = chain([...values?.to, ...values?.cc, ...values?.bcc])
|
|
||||||
.filter((email) => !!email?.trim())
|
|
||||||
.uniq()
|
|
||||||
.map((email) => ({
|
|
||||||
value: email,
|
|
||||||
text: email,
|
|
||||||
}))
|
|
||||||
.value();
|
|
||||||
|
|
||||||
const handleClickCcBtn = (event) => {
|
const handleClickCcBtn = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -74,19 +79,44 @@ export function InvoiceSendMailFields() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateToItemSelect = (value: SelectOptionProps) => {
|
const handleCreateToItemSelect = (value: SelectOptionProps) => {
|
||||||
const _value = [...values?.to, value?.name];
|
setFieldValue('to', [...values?.to, value?.name]);
|
||||||
setFieldValue('to', _value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateCcItemSelect = (value: SelectOptionProps) => {
|
const handleCreateCcItemSelect = (value: SelectOptionProps) => {
|
||||||
const _value = [...values?.cc, value?.name];
|
setFieldValue('cc', [...values?.cc, value?.name]);
|
||||||
setFieldValue('cc', _value);
|
|
||||||
};
|
};
|
||||||
const handleCreateBccItemSelect = (value: SelectOptionProps) => {
|
const handleCreateBccItemSelect = (value: SelectOptionProps) => {
|
||||||
const _value = [...values?.bcc, value?.name];
|
setFieldValue('bcc', [...values?.bcc, value?.name]);
|
||||||
setFieldValue('bcc', _value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
bg="white"
|
bg="white"
|
||||||
@@ -95,22 +125,9 @@ export function InvoiceSendMailFields() {
|
|||||||
spacing={0}
|
spacing={0}
|
||||||
borderRight="1px solid #dcdcdd"
|
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'}>
|
<FFormGroup label={'To'} name={'to'}>
|
||||||
<Stack
|
<Stack spacing={0} className={fieldsWrapStyle}>
|
||||||
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;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<FMultiSelect
|
<FMultiSelect
|
||||||
items={items}
|
items={items}
|
||||||
name={'to'}
|
name={'to'}
|
||||||
@@ -118,34 +135,8 @@ export function InvoiceSendMailFields() {
|
|||||||
popoverProps={{ minimal: true, fill: true }}
|
popoverProps={{ minimal: true, fill: true }}
|
||||||
tagInputProps={{
|
tagInputProps={{
|
||||||
tagProps: { round: true, minimal: true, large: true },
|
tagProps: { round: true, minimal: true, large: true },
|
||||||
|
rightElement: rightElementsToField,
|
||||||
large: true,
|
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}
|
createNewItemRenderer={createNewItemRenderer}
|
||||||
createNewItemFromQuery={createNewItemFromQuery}
|
createNewItemFromQuery={createNewItemFromQuery}
|
||||||
@@ -252,3 +243,4 @@ function InvoiceSendMailFooter() {
|
|||||||
</Group>
|
</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 * as Yup from 'yup';
|
||||||
import { Form, Formik, FormikHelpers } from 'formik';
|
import { Form, Formik, FormikHelpers } from 'formik';
|
||||||
import { css } from '@emotion/css';
|
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 = {
|
const initialValues = {
|
||||||
subject: 'invoice INV-0002 for AED 0.00',
|
subject: 'invoice INV-0002 for AED 0.00',
|
||||||
@@ -17,33 +25,40 @@ If you have any questions, please let us know,
|
|||||||
Thanks,
|
Thanks,
|
||||||
Mohamed`,
|
Mohamed`,
|
||||||
to: ['a.bouhuolia@gmail.com'],
|
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 {
|
interface InvoiceSendMailFormProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InvoiceSendMailForm({ children }: InvoiceSendMailFormProps) {
|
export function InvoiceSendMailForm({ children }: InvoiceSendMailFormProps) {
|
||||||
//
|
const { mutateAsync: sendInvoiceMail } = useSendSaleInvoiceMail();
|
||||||
|
const { invoiceId } = useInvoiceSendMailBoot();
|
||||||
|
const { name } = useDrawerContext();
|
||||||
|
const { closeDrawer } = useDrawerActions();
|
||||||
|
|
||||||
const handleSubmit = (
|
const handleSubmit = (
|
||||||
values: InvoiceSendMailFormValues,
|
values: InvoiceSendMailFormValues,
|
||||||
{ setSubmitting }: FormikHelpers<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 (
|
return (
|
||||||
<Formik
|
<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
|
// @ts-nocheck
|
||||||
import { useQueryClient, useMutation, useQuery } from 'react-query';
|
import {
|
||||||
|
useQueryClient,
|
||||||
|
useMutation,
|
||||||
|
useQuery,
|
||||||
|
UseMutationOptions,
|
||||||
|
UseMutationResult,
|
||||||
|
} from 'react-query';
|
||||||
import { useRequestQuery } from '../useQueryRequest';
|
import { useRequestQuery } from '../useQueryRequest';
|
||||||
import { transformPagination, transformToCamelCase } from '@/utils';
|
import { transformPagination, transformToCamelCase } from '@/utils';
|
||||||
import useApiRequest from '../useRequest';
|
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 queryClient = useQueryClient();
|
||||||
const apiRequest = useApiRequest();
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
return useMutation(
|
return useMutation<
|
||||||
([id, values]) => apiRequest.post(`sales/invoices/${id}/mail`, values),
|
SendSaleInvoiceMailResponse,
|
||||||
|
Error,
|
||||||
|
SendSaleInvoiceMailValues
|
||||||
|
>(
|
||||||
|
(value) => apiRequest.post(`sales/invoices/${value.id}/mail`, value.values),
|
||||||
{
|
{
|
||||||
onSuccess: (res, [id, values]) => {
|
onSuccess: (res) => {
|
||||||
// Common invalidate queries.
|
// Common invalidate queries.
|
||||||
commonInvalidateQueries(queryClient);
|
commonInvalidateQueries(queryClient);
|
||||||
},
|
},
|
||||||
...props,
|
...options,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user