feat: estimate, receipt, credit note mail preview

This commit is contained in:
Ahmed Bouhuolia
2024-11-17 15:45:55 +02:00
parent d115ebde12
commit 53ab40a075
37 changed files with 1531 additions and 396 deletions

View File

@@ -0,0 +1,3 @@
import * as Yup from 'yup';
export const EstimateSendMailSchema = Yup.object().shape({});

View File

@@ -0,0 +1,52 @@
import React, { createContext, useContext } from 'react';
import { Spinner } from '@blueprintjs/core';
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
interface EstimateSendMailBootValues {
estimateId: number;
estimateMailState: GetSaleEstimateDefaultOptionsResponse | undefined;
isEstimateMailState: boolean;
}
interface EstimateSendMailBootProps {
children: React.ReactNode;
}
const EstimateSendMailContentBootContext =
createContext<EstimateSendMailBootValues>({} as EstimateSendMailBootValues);
export const EstimateSendMailBoot = ({ children }: EstimateSendMailBootProps) => {
const {
payload: { estimateId },
} = useDrawerContext();
// Estimate mail options.
const { data: estimateMailState, isLoading: isEstimateMailState } =
useSaleEstimateMailState(estimateId);
const isLoading = isEstimateMailState;
if (isLoading) {
return <Spinner size={20} />;
}
const value = {
estimateId,
// # Estimate mail options
isEstimateMailState,
estimateMailState,
};
return (
<EstimateSendMailContentBootContext.Provider value={value}>
{children}
</EstimateSendMailContentBootContext.Provider>
);
};
EstimateSendMailBoot.displayName = 'EstimateSendMailBoot';
export const useEstimateSendMailBoot = () => {
return useContext<EstimateSendMailBootValues>(
EstimateSendMailContentBootContext,
);
};

View File

@@ -0,0 +1,9 @@
export function EstimateSendMailContent() {
return (
);
}

View File

@@ -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 EstimateSendMailDrawerProps = React.lazy(() =>
import('./EstimateSendMailContent').then((module) => ({
default: module.InvoiceSendMailContent,
})),
);
interface EstimateSendMailDrawerProps {
name: string;
isOpen?: boolean;
payload?: any;
}
function EstimateSendMailDrawerRoot({
name,
// #withDrawer
isOpen,
payload,
}: EstimateSendMailDrawerProps) {
return (
<Drawer
isOpen={isOpen}
name={name}
payload={payload}
size={'calc(100% - 10px)'}
>
<DrawerSuspense>
<EstimateSendMailDrawerProps />
</DrawerSuspense>
</Drawer>
);
}
export const EstimateSendMailDrawer = R.compose(withDrawers())(
EstimateSendMailDrawerRoot,
);

View File

@@ -0,0 +1,79 @@
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';
import { transformToForm } from '@/utils';
import { useEstimateSendMailBoot } from './EstimateSendMailBoot';
const initialValues: InvoiceSendMailFormValues = {
subject: '',
message: '',
to: [],
cc: [],
bcc: [],
attachPdf: true,
};
interface InvoiceSendMailFormProps {
children: React.ReactNode;
}
export function EstimateSendMailForm({ children }: InvoiceSendMailFormProps) {
const { mutateAsync: sendInvoiceMail } = useSendSaleInvoiceMail();
const { estimateId, estimateMailState } = useEstimateSendMailBoot();
const { name } = useDrawerContext();
const { closeDrawer } = useDrawerActions();
const _initialValues: InvoiceSendMailFormValues = {
...initialValues,
...transformToForm(invoiceMailState, initialValues),
};
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
initialValues={_initialValues}
validationSchema={InvoiceSendMailFormSchema}
onSubmit={handleSubmit}
>
<Form
className={css`
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
`}
>
{children}
</Form>
</Formik>
);
}

View File

@@ -0,0 +1 @@
export interface EstimateSendMailFormValues {}

View File

@@ -18,20 +18,8 @@ const EstimateRejectAlert = React.lazy(
* Estimates alert.
*/
export default [
{
name: 'estimate-delete',
component: EstimateDeleteAlert,
},
{
name: 'estimate-deliver',
component: EstimateDeliveredAlert,
},
{
name: 'estimate-Approve',
component: EstimateApproveAlert,
},
{
name: 'estimate-reject',
component: EstimateRejectAlert,
},
{ name: 'estimate-delete', component: EstimateDeleteAlert },
{ name: 'estimate-deliver', component: EstimateDeliveredAlert },
{ name: 'estimate-Approve', component: EstimateApproveAlert },
{ name: 'estimate-reject', component: EstimateRejectAlert },
];

View File

@@ -4,16 +4,16 @@ import { Group, Icon } from '@/components';
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
import { useDrawerActions } from '@/hooks/state';
interface ElementCustomizeHeaderProps {
interface SendMailViewHeaderProps {
label?: string;
children?: React.ReactNode;
closeButton?: boolean;
}
export function InvoiceSendMailHeader({
export function SendMailViewHeader({
label,
closeButton = true,
}: ElementCustomizeHeaderProps) {
}: SendMailViewHeaderProps) {
const { name } = useDrawerContext();
const { closeDrawer } = useDrawerActions();

View File

@@ -0,0 +1,109 @@
// @ts-nocheck
import { useFormikContext } from 'formik';
import { Button, Icon, Position } from '@blueprintjs/core';
import { SelectOptionProps } from '@blueprintjs-formik/select';
import { FormGroupProps, TextAreaProps } from '@blueprintjs-formik/core';
import { css } from '@emotion/css';
import { FFormGroup, FSelect, FTextArea, Group, Stack } from '@/components';
import { useCallback, useRef } from 'react';
import { InvoiceSendMailFormValues } from '../../Invoices/InvoiceSendMailDrawer/_types';
interface SendMailViewMessageFieldProps {
argsOptions?: Array<SelectOptionProps>;
formGroupProps?: Partial<FormGroupProps>;
selectProps?: Partial<any>;
textareaProps?: Partial<TextAreaProps>;
}
export function SendMailViewMessageField({
argsOptions,
formGroupProps,
textareaProps,
}: SendMailViewMessageFieldProps) {
const textareaRef = useRef<HTMLTextAreaElement>(null);
const { setFieldValue } = useFormikContext<InvoiceSendMailFormValues>();
const handleTextareaChange = useCallback(
(item: SelectOptionProps) => {
const textarea = textareaRef.current;
if (!textarea) return;
const { selectionStart, selectionEnd, value: text } = textarea;
const insertText = `{${item.value}}`;
const message =
text.substring(0, selectionStart) +
insertText +
text.substring(selectionEnd);
setFieldValue('message', message);
// Move the cursor to the end of the inserted text
setTimeout(() => {
textarea.selectionStart = textarea.selectionEnd =
selectionStart + insertText.length;
textarea.focus();
}, 0);
},
[setFieldValue],
);
const handleTagInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
// Prevent the form from submitting when the user presses the Enter key
if (e.key === 'Enter') {
e.preventDefault();
}
};
return (
<FFormGroup label={'Message'} name={'message'} {...formGroupProps}>
<Stack spacing={0}>
<Group
border={'1px solid #ced4da'}
borderBottom={0}
borderRadius={'3px 3px 0 0'}
>
<FSelect
selectedItem={'customerName'}
name={'item'}
items={argsOptions}
onItemChange={handleTextareaChange}
popoverProps={{
fill: false,
position: Position.BOTTOM_LEFT,
minimal: true,
inputProps: {
onKeyDown: handleTagInputKeyDown,
},
}}
input={() => (
<Button
minimal
rightIcon={<Icon icon={'caret-down-16'} color={'#8F99A8'} />}
>
Insert Variable
</Button>
)}
fill={false}
fastField
/>
</Group>
<FTextArea
inputRef={textareaRef}
name={'message'}
large
fill
fastField
className={css`
resize: vertical;
min-height: 300px;
border-top-right-radius: 0px;
border-top-left-radius: 0px;
`}
{...textareaProps}
/>
</Stack>
</FFormGroup>
);
}

View File

@@ -0,0 +1,76 @@
import { useMemo } from 'react';
import { x } from '@xstyled/emotion';
import { Box, Group, Stack } from '@/components';
interface SendViewPreviewHeaderProps {
companyName?: string;
customerName?: string;
subject: string;
from?: Array<string>;
to?: Array<string>;
}
export function SendViewPreviewHeader({
companyName,
subject,
customerName,
from,
to,
}: SendViewPreviewHeaderProps) {
const formatedFromAddresses = useMemo(
() => formatAddresses(from || []),
[from],
);
const formattedToAddresses = useMemo(() => formatAddresses(to || []), [to]);
return (
<Stack
bg={'white'}
borderBottom={'1px solid #dcdcdd'}
padding={'22px 30px'}
spacing={8}
position={'sticky'}
top={0}
zIndex={1}
>
<Box>
<x.h2 fontWeight={600} fontSize={16}>
{subject}
</x.h2>
</Box>
<Group display="flex" gap={2}>
<Group display="flex" alignItems="center" gap={15}>
<x.abbr
role="presentation"
w={'40px'}
h={'40px'}
bg={'#daa3e4'}
fill={'#daa3e4'}
color={'#3f1946'}
lineHeight={'40px'}
textAlign={'center'}
borderRadius={'40px'}
fontSize={'14px'}
>
A
</x.abbr>
<Stack spacing={2}>
<Group spacing={2}>
<Box fontWeight={600}>{companyName} </Box>
<Box color={'#738091'}>{formatedFromAddresses}</Box>
</Group>
<Box fontSize={'sm'} color={'#738091'}>
Send to: {customerName} {formattedToAddresses};
</Box>
</Stack>
</Group>
</Group>
</Stack>
);
}
const formatAddresses = (addresses: Array<string>) =>
addresses?.map((email) => '<' + email + '>').join(' ');

View File

@@ -0,0 +1,27 @@
import { css } from '@emotion/css';
import clsx from 'classnames';
interface SendMailViewPreviewPdfIframeProps
extends React.IframeHTMLAttributes<HTMLIFrameElement> {}
export const SendMailViewPreviewPdfIframe = ({
...props
}: SendMailViewPreviewPdfIframeProps) => {
return (
<iframe
title={'invoice-pdf-preview'}
{...props}
className={clsx(
css`
height: 1123px;
width: 794px;
border: 0;
border-radius: 5px;
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.05);
margin: 0 auto;
`,
props.className,
)}
/>
);
};

View File

@@ -0,0 +1,47 @@
import { css } from '@emotion/css';
import { Tabs } from '@blueprintjs/core';
import { Stack } from '@/components';
interface SendMailViewPreviewTabsProps {
children: React.ReactNode;
}
export function SendMailViewPreviewTabs({
children,
}: SendMailViewPreviewTabsProps) {
return (
<Stack bg="#F5F5F5" flex={'1'} maxHeight={'100%'} minWidth="850px">
<Tabs
id={'preview'}
defaultSelectedTabId={'payment-page'}
className={css`
overflow: hidden;
flex: 1 1;
display: flex;
flex-direction: column;
.bp4-tab-list {
padding: 0 20px;
background: #fff;
border-bottom: 1px solid #dcdcdd;
}
.bp4-tab {
line-height: 40px;
}
.bp4-tab:not([aria-selected='true']) {
color: #5f6b7c;
}
.bp4-tab-indicator-wrapper .bp4-tab-indicator {
height: 2px;
}
.bp4-tab-panel {
margin: 0;
overflow: auto;
}
`}
>
{children}
</Tabs>
</Stack>
);
}

View File

@@ -0,0 +1,209 @@
import { useMemo, useState } from 'react';
import { Button, MenuItem } from '@blueprintjs/core';
import { SelectOptionProps } from '@blueprintjs-formik/select';
import { useFormikContext } from 'formik';
import { css } from '@emotion/css';
import { FormGroupProps } from '@blueprintjs-formik/core';
import { FFormGroup, FMultiSelect, Group, Stack } from '@/components';
import { SendMailViewFormValues } from './_types';
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;
}
`;
const styleEmailButton = css`
&.bp4-button.bp4-small {
width: auto;
margin: 0;
min-height: 26px;
line-height: 26px;
padding-top: 0;
padding-bottom: 0;
font-size: 12px;
}
`;
// Create new account renderer.
const createNewItemRenderer = (
query: string,
active: boolean,
handleClick: React.MouseEventHandler<HTMLElement>,
) => {
return (
<MenuItem
icon="add"
text={'Now contact address'}
active={active}
onClick={handleClick}
/>
);
};
// Create new item from the given query string.
const createNewItemFromQuery = (text: string): SelectOptionProps => ({ text });
interface SendMailViewToAddressFieldProps {
formGroupProps?: Partial<FormGroupProps>;
toMultiSelectProps?: Partial<any>;
fromMultiSelectProps?: Partial<any>;
ccMultiSelectProps?: Partial<any>;
bccMultiSelectProps?: Partial<any>;
}
export function SendMailViewToAddressField({
formGroupProps,
toMultiSelectProps,
ccMultiSelectProps,
bccMultiSelectProps,
}: SendMailViewToAddressFieldProps) {
const { values, setFieldValue } = useFormikContext<SendMailViewFormValues>();
const [showCCField, setShowCCField] = useState<boolean>(false);
const [showBccField, setShowBccField] = useState<boolean>(false);
const handleClickCcBtn = (event: React.MouseEvent<HTMLElement>) => {
event.preventDefault();
event.stopPropagation();
setShowCCField(true);
};
const handleClickBccBtn = (event: React.MouseEvent<HTMLElement>) => {
event.preventDefault();
event.stopPropagation();
setShowBccField(true);
};
const handleCreateToItemSelect = (value: SelectOptionProps) => {
setFieldValue('to', [...values?.to, value?.text]);
};
const handleCreateCcItemSelect = (value: SelectOptionProps) => {
setFieldValue('cc', [...values?.cc, value?.text]);
};
const handleCreateBccItemSelect = (value: SelectOptionProps) => {
setFieldValue('bcc', [...values?.bcc, value?.text]);
};
const handleTagInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
// Prevent the form from submitting when the user presses the Enter key
if (e.key === 'Enter') {
e.preventDefault();
}
};
const rightElementsToField = useMemo(
() => (
<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 (
<FFormGroup label={'To'} name={'to'} {...formGroupProps}>
<Stack spacing={0} className={fieldsWrapStyle}>
<FMultiSelect
items={[]}
name={'to'}
placeholder={'To'}
popoverProps={{ minimal: true, fill: true }}
tagInputProps={{
tagProps: { round: true, minimal: true, large: true },
rightElement: rightElementsToField,
large: true,
inputProps: {
onKeyDown: handleTagInputKeyDown,
},
}}
createNewItemRenderer={createNewItemRenderer}
createNewItemFromQuery={createNewItemFromQuery}
onCreateItemSelect={handleCreateToItemSelect}
resetOnQuery
resetOnSelect
fill
fastField
{...toMultiSelectProps}
/>
{showCCField && (
<FMultiSelect
items={[]}
name={'cc'}
placeholder={'Cc'}
popoverProps={{ minimal: true, fill: true }}
tagInputProps={{
tagProps: { round: true, minimal: true, large: true },
large: true,
inputProps: {
onKeyDown: handleTagInputKeyDown,
},
}}
createNewItemRenderer={createNewItemRenderer}
createNewItemFromQuery={createNewItemFromQuery}
onCreateItemSelect={handleCreateCcItemSelect}
resetOnQuery
resetOnSelect
fill
fastField
{...ccMultiSelectProps}
/>
)}
{showBccField && (
<FMultiSelect
items={[]}
name={'bcc'}
placeholder={'Bcc'}
popoverProps={{ minimal: true, fill: true }}
tagInputProps={{
tagProps: { round: true, minimal: true, large: true },
large: true,
inputProps: {
onKeyDown: handleTagInputKeyDown,
},
}}
createNewItemRenderer={createNewItemRenderer}
createNewItemFromQuery={createNewItemFromQuery}
onCreateItemSelect={handleCreateBccItemSelect}
resetOnQuery
resetOnSelect
fill
fastField
{...bccMultiSelectProps}
/>
)}
</Stack>
</FFormGroup>
);
}

View File

@@ -0,0 +1 @@
export interface SendMailViewFormValues {}

View File

@@ -2,9 +2,9 @@ import { Group, Stack } from '@/components';
import { Classes } from '@blueprintjs/core';
import { InvoiceSendMailBoot } from './InvoiceSendMailContentBoot';
import { InvoiceSendMailForm } from './InvoiceSendMailForm';
import { InvoiceSendMailHeader } from './InvoiceSendMailHeader';
import { InvoiceSendMailPreview } from './InvoiceSendMailPreview';
import { InvoiceSendMailFields } from './InvoiceSendMailFields';
import { SendMailViewHeader } from '../../Estimates/SendMailViewDrawer/SendMailViewHeader';
export function InvoiceSendMailContent() {
return (
@@ -12,7 +12,7 @@ export function InvoiceSendMailContent() {
<InvoiceSendMailBoot>
<InvoiceSendMailForm>
<Stack spacing={0} flex={1} overflow="hidden">
<InvoiceSendMailHeader label={'Send Invoice Mail'} />
<SendMailViewHeader label={'Send Invoice Mail'} />
<Group flex={1} overflow="auto" spacing={0} alignItems={'stretch'}>
<InvoiceSendMailFields />

View File

@@ -8,157 +8,17 @@ import {
FCheckbox,
FFormGroup,
FInputGroup,
FMultiSelect,
FSelect,
FTextArea,
Group,
Icon,
Stack,
} from '@/components';
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
import { useDrawerActions } from '@/hooks/state';
import { useInvoiceMailItems, useSendInvoiceFormatArgsOptions } from './_hooks';
import { InvoiceSendMailFormValues } from './_types';
// Create new account renderer.
const createNewItemRenderer = (
query: string,
active: boolean,
handleClick: React.MouseEventHandler<HTMLElement>,
) => {
return (
<MenuItem
icon="add"
text={'Now contact address'}
active={active}
onClick={handleClick}
/>
);
};
// Create new item from the given query string.
const createNewItemFromQuery = (text: string): SelectOptionProps => ({ text });
const styleEmailButton = css`
&.bp4-button.bp4-small {
width: auto;
margin: 0;
min-height: 26px;
line-height: 26px;
padding-top: 0;
padding-bottom: 0;
font-size: 12px;
}
`;
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;
}
`;
import { useInvoiceMailItems, } from './_hooks';
import { SendMailViewToAddressField } from '../../Estimates/SendMailViewDrawer/SendMailViewToAddressField';
import { SendMailViewMessageField } from '../../Estimates/SendMailViewDrawer/SendMailViewMessageField';
export function InvoiceSendMailFields() {
const [showCCField, setShowCCField] = useState<boolean>(false);
const [showBccField, setShowBccField] = useState<boolean>(false);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const { values, setFieldValue } =
useFormikContext<InvoiceSendMailFormValues>();
const items = useInvoiceMailItems();
const argsOptions = useSendInvoiceFormatArgsOptions();
const handleClickCcBtn = (event: React.MouseEvent<HTMLElement>) => {
event.preventDefault();
event.stopPropagation();
setShowCCField(true);
};
const handleClickBccBtn = (event: React.MouseEvent<HTMLElement>) => {
event.preventDefault();
event.stopPropagation();
setShowBccField(true);
};
const handleCreateToItemSelect = (value: SelectOptionProps) => {
setFieldValue('to', [...values?.to, value?.text]);
};
const handleCreateCcItemSelect = (value: SelectOptionProps) => {
setFieldValue('cc', [...values?.cc, value?.text]);
};
const handleCreateBccItemSelect = (value: SelectOptionProps) => {
setFieldValue('bcc', [...values?.bcc, value?.text]);
};
const rightElementsToField = useMemo(
() => (
<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>
),
[],
);
const handleTextareaChange = useCallback(
(item: SelectOptionProps) => {
const textarea = textareaRef.current;
if (!textarea) return;
const { selectionStart, selectionEnd, value: text } = textarea;
const insertText = `{${item.value}}`;
const message =
text.substring(0, selectionStart) +
insertText +
text.substring(selectionEnd);
setFieldValue('message', message);
// Move the cursor to the end of the inserted text
setTimeout(() => {
textarea.selectionStart = textarea.selectionEnd =
selectionStart + insertText.length;
textarea.focus();
}, 0);
},
[setFieldValue],
);
const handleTagInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
// Prevent the form from submitting when the user presses the Enter key
if (e.key === 'Enter') {
e.preventDefault();
}
};
return (
<Stack
@@ -170,130 +30,16 @@ export function InvoiceSendMailFields() {
borderRight="1px solid #dcdcdd"
>
<Stack spacing={0} overflow="auto" flex="1" p={'30px'}>
<FFormGroup label={'To'} name={'to'}>
<Stack spacing={0} className={fieldsWrapStyle}>
<FMultiSelect
items={items}
name={'to'}
placeholder={'To'}
popoverProps={{ minimal: true, fill: true }}
tagInputProps={{
tagProps: { round: true, minimal: true, large: true },
rightElement: rightElementsToField,
large: true,
inputProps: {
onKeyDown: handleTagInputKeyDown,
},
}}
createNewItemRenderer={createNewItemRenderer}
createNewItemFromQuery={createNewItemFromQuery}
onCreateItemSelect={handleCreateToItemSelect}
resetOnQuery
resetOnSelect
fill
fastField
/>
{showCCField && (
<FMultiSelect
items={items}
name={'cc'}
placeholder={'Cc'}
popoverProps={{ minimal: true, fill: true }}
tagInputProps={{
tagProps: { round: true, minimal: true, large: true },
large: true,
inputProps: {
onKeyDown: handleTagInputKeyDown,
},
}}
createNewItemRenderer={createNewItemRenderer}
createNewItemFromQuery={createNewItemFromQuery}
onCreateItemSelect={handleCreateCcItemSelect}
resetOnQuery
resetOnSelect
fill
fastField
/>
)}
{showBccField && (
<FMultiSelect
items={items}
name={'bcc'}
placeholder={'Bcc'}
popoverProps={{ minimal: true, fill: true }}
tagInputProps={{
tagProps: { round: true, minimal: true, large: true },
large: true,
inputProps: {
onKeyDown: handleTagInputKeyDown,
},
}}
createNewItemRenderer={createNewItemRenderer}
createNewItemFromQuery={createNewItemFromQuery}
onCreateItemSelect={handleCreateBccItemSelect}
resetOnQuery
resetOnSelect
fill
fastField
/>
)}
</Stack>
</FFormGroup>
<SendMailViewToAddressField
toMultiSelectProps={{ items }}
ccMultiSelectProps={{ items }}
bccMultiSelectProps={{ items }}
/>
<FFormGroup label={'Submit'} name={'subject'}>
<FInputGroup name={'subject'} large fastField />
</FFormGroup>
<FFormGroup label={'Message'} name={'message'}>
<Stack spacing={0}>
<Group
border={'1px solid #ced4da'}
borderBottom={0}
borderRadius={'3px 3px 0 0'}
>
<FSelect
selectedItem={'customerName'}
name={'item'}
items={argsOptions}
onItemChange={handleTextareaChange}
popoverProps={{
fill: false,
position: Position.BOTTOM_LEFT,
minimal: true,
inputProps: {
onKeyDown: handleTagInputKeyDown,
},
}}
input={() => (
<Button
minimal
rightIcon={
<Icon icon={'caret-down-16'} color={'#8F99A8'} />
}
>
Insert Variable
</Button>
)}
fill={false}
fastField
/>
</Group>
<FTextArea
inputRef={textareaRef}
name={'message'}
large
fill
fastField
className={css`
resize: vertical;
min-height: 300px;
border-top-right-radius: 0px;
border-top-left-radius: 0px;
`}
/>
</Stack>
</FFormGroup>
<SendMailViewMessageField />
<Group>
<FCheckbox name={'attachPdf'} label={'Attach PDF'} />

View File

@@ -1,7 +1,6 @@
import { lazy, Suspense } from 'react';
import { css } from '@emotion/css';
import { Tab, Tabs } from '@blueprintjs/core';
import { Stack } from '@/components';
import { Tab, } from '@blueprintjs/core';
import { SendMailViewPreviewTabs } from '../../Estimates/SendMailViewDrawer/SendMailViewPreviewTabs';
const InvoiceMailReceiptPreviewConnected = lazy(() =>
import('./InvoiceMailReceiptPreviewConnected').then((module) => ({
@@ -16,55 +15,25 @@ const InvoiceSendPdfPreviewConnected = lazy(() =>
export function InvoiceSendMailPreview() {
return (
<Stack bg="#F5F5F5" flex={'1'} maxHeight={'100%'} minWidth="850px">
<Tabs
id={'preview'}
defaultSelectedTabId={'payment-page'}
className={css`
overflow: hidden;
flex: 1 1;
display: flex;
flex-direction: column;
.bp4-tab-list {
padding: 0 20px;
background: #fff;
border-bottom: 1px solid #dcdcdd;
}
.bp4-tab {
line-height: 40px;
}
.bp4-tab:not([aria-selected='true']) {
color: #5f6b7c;
}
.bp4-tab-indicator-wrapper .bp4-tab-indicator {
height: 2px;
}
.bp4-tab-panel {
margin: 0;
overflow: auto;
}
`}
>
<Tab
id={'payment-page'}
title={'Payment page'}
panel={
<Suspense>
<InvoiceMailReceiptPreviewConnected />
</Suspense>
}
/>
<Tab
id="pdf-document"
title={'PDF document'}
panel={
<Suspense>
<InvoiceSendPdfPreviewConnected />
</Suspense>
}
/>
</Tabs>
</Stack>
<SendMailViewPreviewTabs>
<Tab
id={'payment-page'}
title={'Payment page'}
panel={
<Suspense>
<InvoiceMailReceiptPreviewConnected />
</Suspense>
}
/>
<Tab
id="pdf-document"
title={'PDF document'}
panel={
<Suspense>
<InvoiceSendPdfPreviewConnected />
</Suspense>
}
/>
</SendMailViewPreviewTabs>
);
}

View File

@@ -4,6 +4,7 @@ import { Stack } from '@/components';
import { InvoiceSendMailPreviewWithHeader } from './InvoiceSendMailHeaderPreview';
import { useInvoiceHtml } from '@/hooks/query';
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
import { SendMailViewPreviewPdfIframe } from '../../Estimates/SendMailViewDrawer/SendMailViewPreviewPdfIframe';
export function InvoiceSendPdfPreviewConnected() {
return (
@@ -24,18 +25,5 @@ function InvoiceSendPdfPreviewIframe() {
}
const iframeSrcDoc = data?.htmlContent;
return (
<iframe
title={'invoice-pdf-preview'}
srcDoc={iframeSrcDoc}
className={css`
height: 1123px;
width: 794px;
border: 0;
border-radius: 5px;
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.05);
margin: 0 auto;
`}
/>
);
return <SendMailViewPreviewPdfIframe srcDoc={iframeSrcDoc} />;
}