diff --git a/packages/webapp/src/containers/Sales/Estimates/EstimateSendMailDrawer/EstimateSnedMailFields.tsx b/packages/webapp/src/containers/Sales/Estimates/EstimateSendMailDrawer/EstimateSnedMailFields.tsx index 74b4227c3..9922574f5 100644 --- a/packages/webapp/src/containers/Sales/Estimates/EstimateSendMailDrawer/EstimateSnedMailFields.tsx +++ b/packages/webapp/src/containers/Sales/Estimates/EstimateSendMailDrawer/EstimateSnedMailFields.tsx @@ -1,10 +1,10 @@ -import { FCheckbox, FFormGroup, FInputGroup, Group, Stack } from "@/components"; -import { SendMailViewToAddressField } from "../SendMailViewDrawer/SendMailViewToAddressField"; -import { SendMailViewMessageField } from "../SendMailViewDrawer/SendMailViewMessageField"; -import { Button, Intent } from "@blueprintjs/core"; -import { useFormikContext } from "formik"; -import { useDrawerContext } from "@/components/Drawer/DrawerProvider"; -import { useDrawerActions } from "@/hooks/state"; +import { useFormikContext } from 'formik'; +import { FCheckbox, FFormGroup, FInputGroup, Group, Stack } from '@/components'; +import { SendMailViewToAddressField } from '../SendMailViewDrawer/SendMailViewToAddressField'; +import { SendMailViewMessageField } from '../SendMailViewDrawer/SendMailViewMessageField'; +import { Button, Intent } from '@blueprintjs/core'; +import { useDrawerContext } from '@/components/Drawer/DrawerProvider'; +import { useDrawerActions } from '@/hooks/state'; const items: Array = []; const argsOptions: Array = []; @@ -34,7 +34,6 @@ export function EstimateSendMailFields() { ); } - function EstimateSendMailFooter() { const { isSubmitting } = useFormikContext(); const { name } = useDrawerContext(); diff --git a/shared/email-components/src/lib/CreditNoteEmailTemplate.stories.tsx b/shared/email-components/src/lib/CreditNoteEmailTemplate.stories.tsx new file mode 100644 index 000000000..9ee681c5c --- /dev/null +++ b/shared/email-components/src/lib/CreditNoteEmailTemplate.stories.tsx @@ -0,0 +1,21 @@ +import { Meta, StoryFn } from '@storybook/react'; +import { + CreditNoteEmailProps, + CreditNoteEmailTemplate, +} from './CreditNoteEmailTemplate'; + +export default { + title: 'Email/CreditNoteEmailTemplate', + component: CreditNoteEmailTemplate, +} as Meta; + +const Template: StoryFn = (args) => ( + +); + +export const Default: StoryFn = Template.bind({}); + +Default.args = { + total: '$1,000.00', + items: [{ label: 'Swaniawski Muller', quantity: '1', rate: '$1,000.00' }], +}; diff --git a/shared/email-components/src/lib/CreditNoteEmailTemplate.tsx b/shared/email-components/src/lib/CreditNoteEmailTemplate.tsx new file mode 100644 index 000000000..52024b21c --- /dev/null +++ b/shared/email-components/src/lib/CreditNoteEmailTemplate.tsx @@ -0,0 +1,40 @@ +export interface CreditNoteEmailProps { + preview?: string; + + companyName?: string; + companyLogoUri: string; + + primaryColor?: string; + + total: string; + totalLabel?: string; + + // # Items + items: Array<{ label: string; quantity: string; rate: string }>; + + viewEstimateButtonLabel?: string; + viewEstimateButtonUrl?: string; +} + +export const CreditNoteEmailTemplate: React.FC< + Readonly +> = ({ + preview, + + // # Company + companyName, + companyLogoUri, + + // # Colors + primaryColor = 'rgb(0, 82, 204)', + + // # invoice total + total, + totalLabel = 'Total', + + // # View invoice button + viewEstimateButtonLabel = 'View Estimate', + viewEstimateButtonUrl, +}) => { + return

asdasd

; + }; diff --git a/shared/email-components/src/lib/EmailTemplateLayout.tsx b/shared/email-components/src/lib/EmailTemplateLayout.tsx new file mode 100644 index 000000000..0c0d21e0d --- /dev/null +++ b/shared/email-components/src/lib/EmailTemplateLayout.tsx @@ -0,0 +1,29 @@ +import { Html, Head, Body, Preview, Tailwind } from '@react-email/components'; +import { CSSProperties } from 'react'; + +interface EmailTemplateLayoutProps { + children?: React.ReactNode; + preview: string; +} +export const EmailTemplateLayout = ({ + children, + preview, +}: EmailTemplateLayoutProps) => { + return ( + + + {preview} + + + {children} + + + ); +}; + +const bodyStyle: CSSProperties = { + backgroundColor: '#F5F5F5', + fontFamily: + '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', + padding: '40px 0', +}; diff --git a/shared/email-components/src/lib/EstimatePaymentEmail.stories.tsx b/shared/email-components/src/lib/EstimatePaymentEmail.stories.tsx new file mode 100644 index 000000000..634783ae8 --- /dev/null +++ b/shared/email-components/src/lib/EstimatePaymentEmail.stories.tsx @@ -0,0 +1,33 @@ +import { Meta, StoryFn } from '@storybook/react'; +import { + EstimatePaymentEmailProps, + EstimatePaymentEmail, +} from './EstimatePaymentEmail'; + +export default { + title: 'Email/EstimatePaymentEmail', + component: EstimatePaymentEmail, +} as Meta; + +const Template: StoryFn = (args) => ( + +); + +export const Default: StoryFn = Template.bind({}); + +Default.args = { + total: '$1,000.00', + items: [{ label: 'Swaniawski Muller', quantity: '1', rate: '$1,000.00' }], + message: `Hi Ahmed Bouhuolia, + +Here's invoice # INV-00005 for $1,000.00 + +The amount outstanding of $1,000.00 is due on 10 Oct 2024. + +From your online payment page you can print a PDF or view your outstanding bills. + +If you have any questions, please let us know. + +Thanks, +Bigcapital`, +}; diff --git a/shared/email-components/src/lib/EstimatePaymentEmail.tsx b/shared/email-components/src/lib/EstimatePaymentEmail.tsx new file mode 100644 index 000000000..50572bf3e --- /dev/null +++ b/shared/email-components/src/lib/EstimatePaymentEmail.tsx @@ -0,0 +1,259 @@ +import { CSSProperties } from 'react'; +import { + Button, + Column, + Container, + Heading, + Row, + Section, + Text, +} from '@react-email/components'; +import { EmailTemplateLayout } from './EmailTemplateLayout'; + +export interface EstimatePaymentEmailProps { + preview: string; + + // # Company + companyName?: string; + companyLogoUri: string; + + // # Colors + primaryColor?: string; + + // # Total + total: string; + totalLabel?: string; + + // # Estimate No# + estimateNumber?: string; + estimateNumberLabel?: string; + + // # Expiration date. + expirationDateLabel?: string; + expirationDate?: string; + + // # Items + items: Array<{ label: string; quantity: string; rate: string }>; + + // # View estimate button. + viewEstimateButtonLabel?: string; + viewEstimateButtonUrl?: string; + + // # Estimate message + message?: string; +} + +export const EstimatePaymentEmail: React.FC< + Readonly +> = ({ + preview, + + // # Company + companyName, + companyLogoUri, + + // # Colors + primaryColor = 'rgb(0, 82, 204)', + + // # invoice total + total, + totalLabel = 'Total', + + // # Estimate No# + estimateNumberLabel = 'Estimate No: {estimateNumber}', + estimateNumber = 'EST-00001', + + // # Expiration date + expirationDateLabel = 'Expiration Date: {expirationDate}', + expirationDate = '12/12/2021', + + // # View invoice button + viewEstimateButtonLabel = 'View Estimate', + viewEstimateButtonUrl, + + // # Message + message = '', + + // # Items + items = [], +}) => { + return ( + + + {companyLogoUri && ( +
+
+
+ )} + +
+ + {companyName} + + + {total} + + + + {estimateNumberLabel?.replace('{estimateNumber}', estimateNumber)} + + + + + {expirationDateLabel.replace('{expirationDate}', expirationDate)} + + +
+ + {message} + + +
+ {items.map((item, index) => ( + + + {item.label} + + + + + {item.quantity} x {item.rate} + + + + ))} + + + + {totalLabel} + + + + {total} + + +
+ +
+
+ ); + }; + +const containerStyle: CSSProperties = { + backgroundColor: '#fff', + width: '100%', + maxWidth: '500px', + padding: '35px 25px', + color: '#000', + borderRadius: '5px', +}; + +const headerInfoStyle: CSSProperties = { + textAlign: 'center', + marginBottom: 20, +}; + +const estimateAmountStyle: CSSProperties = { + margin: 0, + color: '#383E47', + fontWeight: 500, +}; +const estimateNumberStyle: CSSProperties = { + margin: 0, + fontSize: '13px', + color: '#404854', +}; +const estimateExpirationStyle: CSSProperties = { + margin: 0, + fontSize: '13px', + color: '#404854', +}; + +const invoiceCompanyNameStyle: CSSProperties = { + margin: 0, + fontSize: '18px', + fontWeight: 500, + color: '#404854', +}; + +const viewEstimateButtonStyle: CSSProperties = { + display: 'block', + cursor: 'pointer', + textAlign: 'center', + fontSize: 16, + padding: '10px 15px', + lineHeight: '1', + backgroundColor: 'rgb(0, 82, 204)', + color: '#fff', + borderRadius: '5px', +}; + +const listItemLabelStyle: CSSProperties = { + margin: 0, +}; + +const listItemAmountStyle: CSSProperties = { + margin: 0, + textAlign: 'right', +}; + +const estimateMessageStyle: CSSProperties = { + whiteSpace: 'pre-line', + color: '#252A31', + margin: '0 0 20px 0', + lineHeight: '20px', +}; +const totalLineRowStyle: CSSProperties = { + borderBottom: '1px solid #000', + height: 40, +}; + +const totalLineItemLabelStyle: CSSProperties = { + ...listItemLabelStyle, + fontWeight: 500, +}; + +const totalLineItemAmountStyle: CSSProperties = { + ...listItemAmountStyle, + fontWeight: 600, +}; + +const itemLineRowStyle: CSSProperties = { + borderBottom: '1px solid #D9D9D9', + height: 40, +}; + +const totalsSectionStyle = { + marginTop: '20px', + borderTop: '1px solid #D9D9D9', +}; + +const logoSectionStyle = { + marginBottom: '15px', +}; + +const companyLogoStyle = { + height: 90, + width: 90, + borderRadius: '3px', + marginLeft: 'auto', + marginRight: 'auto', + textIndent: '-999999px', + overflow: 'hidden', + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center center', + backgroundSize: 'contain', +}; diff --git a/shared/email-components/src/lib/InvoicePaymentEmail.stories.tsx b/shared/email-components/src/lib/InvoicePaymentEmail.stories.tsx index f8daf0481..280e3b452 100644 --- a/shared/email-components/src/lib/InvoicePaymentEmail.stories.tsx +++ b/shared/email-components/src/lib/InvoicePaymentEmail.stories.tsx @@ -1,18 +1,38 @@ - -import { Meta } from '@storybook/react'; -import { StoryFn } from '@storybook/react'; +import { Meta, StoryFn } from '@storybook/react'; import { InvoicePaymentEmail, InvoicePaymentEmailProps, } from './InvoicePaymentEmail'; -const meta: Meta = { - title: 'Invoice Payment Email', +export default { + title: 'Email/InvoicePaymentEmail', component: InvoicePaymentEmail, +} as Meta; + +const Template: StoryFn = (args) => ( + +); + +export const Default: StoryFn = Template.bind({}); + +Default.args = { + // Add default props here + invoiceNumber: 'INV-12345', + companyName: 'Bigcapital, Inc.', + invoiceMessage: `Hi Ahmed Bouhuolia, + +Here's invoice # INV-00005 for $1,000.00 + +The amount outstanding of $1,000.00 is due on 10 Oct 2024. + +From your online payment page you can print a PDF or view your outstanding bills. + +If you have any questions, please let us know. + +Thanks, +Bigcapital`, + dueDate: ' 10 Oct 2024', + total: '$1,000.00', + dueAmount: '$1,000.00', + items: [{ label: 'Swaniawski Muller', quantity: '1', rate: '$1,000.00' }], }; - -export default meta; - -const Template: StoryFn = ( - args: InvoicePaymentEmailProps -) => ; diff --git a/shared/email-components/src/lib/InvoicePaymentEmail.tsx b/shared/email-components/src/lib/InvoicePaymentEmail.tsx index bbd062b85..e46e57949 100644 --- a/shared/email-components/src/lib/InvoicePaymentEmail.tsx +++ b/shared/email-components/src/lib/InvoicePaymentEmail.tsx @@ -14,6 +14,7 @@ import { render, } from '@react-email/components'; import { CSSProperties } from 'react'; +import { EmailTemplateLayout } from './EmailTemplateLayout'; export interface InvoicePaymentEmailProps { preview: string; @@ -96,106 +97,90 @@ export const InvoicePaymentEmail: React.FC< items, }) => { return ( - - - {preview} - - - - -
- {companyLogoUri && ( -
-
- Image -
-
- )} - -
- - - {companyName} - - - - {invoiceAmount} - - - - {invoiceNumberLabel?.replace( - '{invoiceNumber}', - invoiceNumber - )} - - - - - {dueDateLabel.replace('{dueDate}', dueDate)} - - -
- - {invoiceMessage} - - -
- {items.map((item, index) => ( - - - {item.label} - - - - - {item.quantity} x {item.rate} - - - - ))} - - - - - {dueAmountLabel} - - - - - - {dueAmount} - - - - - - - {totalLabel} - - - - {total} - - -
+ >
-
- -
- + )} + +
+ + {companyName} + + + {invoiceAmount} + + + + {invoiceNumberLabel?.replace('{invoiceNumber}', invoiceNumber)} + + + + + {dueDateLabel.replace('{dueDate}', dueDate)} + + +
+ + {invoiceMessage} + + +
+ {items.map((item, index) => ( + + + {item.label} + + + + + {item.quantity} x {item.rate} + + + + ))} + + + + + {dueAmountLabel} + + + + + {dueAmount} + + + + + + {totalLabel} + + + + {total} + + +
+ + + ); }; @@ -203,14 +188,6 @@ export const renderInvoicePaymentEmail = (props: InvoicePaymentEmailProps) => { return render(); }; -const bodyStyle: CSSProperties = { - backgroundColor: '#F5F5F5', - fontFamily: - '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif', - - padding: '40px 0', -}; - const containerStyle: CSSProperties = { backgroundColor: '#fff', width: '100%', diff --git a/shared/email-components/src/lib/PaymentReceivedEmailTemplate.stories.tsx b/shared/email-components/src/lib/PaymentReceivedEmailTemplate.stories.tsx new file mode 100644 index 000000000..3b2cddc7b --- /dev/null +++ b/shared/email-components/src/lib/PaymentReceivedEmailTemplate.stories.tsx @@ -0,0 +1,19 @@ +import { Meta, StoryFn } from '@storybook/react'; +import { + PaymentReceivedEmailTemplateProps, + PaymentReceivedEmailTemplate, +} from './PaymentReceivedEmailTemplate'; + +export default { + title: 'Email/PaymentReceivedEmailTemplate', + component: PaymentReceivedEmailTemplate, +} as Meta; + +const Template: StoryFn = (args) => ( + +); + +export const Default: StoryFn = + Template.bind({}); + +Default.args = {}; diff --git a/shared/email-components/src/lib/PaymentReceivedEmailTemplate.tsx b/shared/email-components/src/lib/PaymentReceivedEmailTemplate.tsx new file mode 100644 index 000000000..d2c6c7daf --- /dev/null +++ b/shared/email-components/src/lib/PaymentReceivedEmailTemplate.tsx @@ -0,0 +1,40 @@ +export interface PaymentReceivedEmailTemplateProps { + preview?: string; + + companyName?: string; + companyLogoUri: string; + + primaryColor?: string; + + total: string; + totalLabel?: string; + + // # Items + items: Array<{ label: string; quantity: string; rate: string }>; + + viewEstimateButtonLabel?: string; + viewEstimateButtonUrl?: string; +} + +export const PaymentReceivedEmailTemplate: React.FC< + Readonly +> = ({ + preview, + + // # Company + companyName, + companyLogoUri, + + // # Colors + primaryColor = 'rgb(0, 82, 204)', + + // # invoice total + total, + totalLabel = 'Total', + + // # View invoice button + viewEstimateButtonLabel = 'View Estimate', + viewEstimateButtonUrl, +}) => { + return

asdasd

; + }; diff --git a/shared/email-components/src/lib/ReceiptPaymentEmail.stories.tsx b/shared/email-components/src/lib/ReceiptPaymentEmail.stories.tsx new file mode 100644 index 000000000..d1ae99df5 --- /dev/null +++ b/shared/email-components/src/lib/ReceiptPaymentEmail.stories.tsx @@ -0,0 +1,20 @@ +import { Meta, StoryFn } from '@storybook/react'; +import { + ReceiptEmailTemplate, + ReceiptEmailTemplateProps, +} from './ReceiptPaymentEmail'; + +export default { + title: 'Email/ReceiptPaymentEmail', + component: ReceiptEmailTemplate, +} as Meta; + +const Template: StoryFn = (args) => ( + +); + +export const Default: StoryFn = Template.bind({}); + +Default.args = { + // Add default props here +}; diff --git a/shared/email-components/src/lib/ReceiptPaymentEmail.tsx b/shared/email-components/src/lib/ReceiptPaymentEmail.tsx new file mode 100644 index 000000000..0b633af9f --- /dev/null +++ b/shared/email-components/src/lib/ReceiptPaymentEmail.tsx @@ -0,0 +1,45 @@ +export interface ReceiptEmailTemplateProps { + preview?: string; + + // # Company + companyName?: string; + companyLogoUri: string; + + // # Colors + primaryColor?: string; + + // # Invoice total + total: string; + totalLabel?: string; + + // # Items + items: Array<{ label: string; quantity: string; rate: string }>; + + viewReceiptButtonLabel?: string; + viewReceiptButtonUrl?: string; +} + +export const ReceiptEmailTemplate: React.FC< + Readonly +> = ({ + preview, + + // # Company + companyName, + companyLogoUri, + + // # Colors + primaryColor = 'rgb(0, 82, 204)', + + // # Invoice total + total, + totalLabel = 'Total', + + // # View invoice button + viewReceiptButtonLabel = 'View Estimate', + viewReceiptButtonUrl, +}) => { + return ( +

asdasd

+ ) + };