fix: Pdf templates layout

This commit is contained in:
Ahmed Bouhuolia
2024-10-05 19:01:34 +02:00
parent 90f08c5d51
commit af5726c48c
9 changed files with 184 additions and 145 deletions

View File

@@ -27,11 +27,14 @@ export interface GroupProps extends React.ComponentPropsWithoutRef<'div'> {
/** Defines align-items css property */ /** Defines align-items css property */
align?: React.CSSProperties['alignItems']; align?: React.CSSProperties['alignItems'];
flex?: React.CSSProperties['flex'];
} }
const defaultProps: Partial<GroupProps> = { const defaultProps: Partial<GroupProps> = {
position: 'left', position: 'left',
spacing: 20, spacing: 20,
flex: 'none'
}; };
export function Group({ children, ...props }: GroupProps) { export function Group({ children, ...props }: GroupProps) {
@@ -48,6 +51,7 @@ const GroupStyled = styled(Box)`
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex: ${(props: GroupProps) => (props.flex)};
align-items: ${(props: GroupProps) => (props.align || 'center')}; align-items: ${(props: GroupProps) => (props.align || 'center')};
flex-wrap: ${(props: GroupProps) => (props.noWrap ? 'nowrap' : 'wrap')}; flex-wrap: ${(props: GroupProps) => (props.noWrap ? 'nowrap' : 'wrap')};
justify-content: ${(props: GroupProps) => justify-content: ${(props: GroupProps) =>

View File

@@ -11,12 +11,15 @@ export interface StackProps extends React.ComponentPropsWithoutRef<'div'> {
/** justify-content CSS property */ /** justify-content CSS property */
justify?: React.CSSProperties['justifyContent']; justify?: React.CSSProperties['justifyContent'];
flex?: React.CSSProperties['flex'];
} }
const defaultProps: Partial<StackProps> = { const defaultProps: Partial<StackProps> = {
spacing: 20, spacing: 20,
align: 'stretch', align: 'stretch',
justify: 'top', justify: 'top',
flex: 'none',
}; };
export function Stack(props: StackProps) { export function Stack(props: StackProps) {
@@ -33,4 +36,5 @@ const StackStyled = styled(Box)`
align-items: ${(props: StackProps) => props.align}; align-items: ${(props: StackProps) => props.align};
justify-content: justify; justify-content: justify;
gap: ${(props: StackProps) => props.spacing}px; gap: ${(props: StackProps) => props.spacing}px;
flex: ${(props: StackProps) => props.flex};
`; `;

View File

@@ -1,4 +1,4 @@
import { Box, Stack } from '@/components'; import { Box, Group, Stack } from '@/components';
import { import {
PaperTemplate, PaperTemplate,
PaperTemplateProps, PaperTemplateProps,
@@ -13,6 +13,13 @@ import {
} from '@/constants/PdfTemplates'; } from '@/constants/PdfTemplates';
export interface CreditNotePaperTemplateProps extends PaperTemplateProps { export interface CreditNotePaperTemplateProps extends PaperTemplateProps {
// # Company logo
showCompanyLogo?: boolean;
companyLogoUri?: string;
// # Company name
companyName?: string;
// Address // Address
showCustomerAddress?: boolean; showCustomerAddress?: boolean;
customerAddress?: string; customerAddress?: string;
@@ -122,26 +129,30 @@ export function CreditNotePaperTemplate({
creditNoteDateLabel = 'Credit Note Date', creditNoteDateLabel = 'Credit Note Date',
}: CreditNotePaperTemplateProps) { }: CreditNotePaperTemplateProps) {
return ( return (
<PaperTemplate <PaperTemplate primaryColor={primaryColor} secondaryColor={secondaryColor}>
primaryColor={primaryColor}
secondaryColor={secondaryColor}
showCompanyLogo={showCompanyLogo}
companyLogoUri={companyLogoUri}
bigtitle={'Credit Note'}
>
<Stack spacing={24}> <Stack spacing={24}>
<PaperTemplate.TermsList> <Group align={'start'} spacing={10}>
{showCreditNoteNumber && ( <Stack flex={1}>
<PaperTemplate.TermsItem label={creditNoteNumberLabel}> <PaperTemplate.BigTitle title={'Credit Note'} />
{creditNoteNumebr}
</PaperTemplate.TermsItem> <PaperTemplate.TermsList>
{showCreditNoteNumber && (
<PaperTemplate.TermsItem label={creditNoteNumberLabel}>
{creditNoteNumebr}
</PaperTemplate.TermsItem>
)}
{showCreditNoteDate && (
<PaperTemplate.TermsItem label={creditNoteDateLabel}>
{creditNoteDate}
</PaperTemplate.TermsItem>
)}
</PaperTemplate.TermsList>
</Stack>
{companyLogoUri && showCompanyLogo && (
<PaperTemplate.Logo logoUri={companyLogoUri} />
)} )}
{showCreditNoteDate && ( </Group>
<PaperTemplate.TermsItem label={creditNoteDateLabel}>
{creditNoteDate}
</PaperTemplate.TermsItem>
)}
</PaperTemplate.TermsList>
<PaperTemplate.AddressesGroup> <PaperTemplate.AddressesGroup>
{showCompanyAddress && ( {showCompanyAddress && (

View File

@@ -1,4 +1,4 @@
import { Box, Stack } from '@/components'; import { Box, Group, Stack } from '@/components';
import { import {
PaperTemplate, PaperTemplate,
PaperTemplateProps, PaperTemplateProps,
@@ -13,6 +13,10 @@ import {
} from '@/constants/PdfTemplates'; } from '@/constants/PdfTemplates';
export interface EstimatePaperTemplateProps extends PaperTemplateProps { export interface EstimatePaperTemplateProps extends PaperTemplateProps {
// # Company
showCompanyLogo?: boolean;
companyLogoUri?: string;
// # Estimate number // # Estimate number
estimateNumebr?: string; estimateNumebr?: string;
estimateNumberLabel?: string; estimateNumberLabel?: string;
@@ -132,31 +136,35 @@ export function EstimatePaperTemplate({
expirationDate = 'September 3, 2024', expirationDate = 'September 3, 2024',
}: EstimatePaperTemplateProps) { }: EstimatePaperTemplateProps) {
return ( return (
<PaperTemplate <PaperTemplate primaryColor={primaryColor} secondaryColor={secondaryColor}>
primaryColor={primaryColor}
secondaryColor={secondaryColor}
showCompanyLogo={showCompanyLogo}
companyLogoUri={companyLogoUri}
bigtitle={'Estimate'}
>
<Stack spacing={24}> <Stack spacing={24}>
<PaperTemplate.TermsList> <Group align={'start'} spacing={10}>
{showEstimateNumber && ( <Stack flex={1}>
<PaperTemplate.TermsItem label={estimateNumberLabel}> <PaperTemplate.BigTitle title={'Estimate'} />
{estimateNumebr}
</PaperTemplate.TermsItem> <PaperTemplate.TermsList>
{showEstimateNumber && (
<PaperTemplate.TermsItem label={estimateNumberLabel}>
{estimateNumebr}
</PaperTemplate.TermsItem>
)}
{showEstimateDate && (
<PaperTemplate.TermsItem label={estimateDateLabel}>
{estimateDate}
</PaperTemplate.TermsItem>
)}
{showExpirationDate && (
<PaperTemplate.TermsItem label={expirationDateLabel}>
{expirationDate}
</PaperTemplate.TermsItem>
)}
</PaperTemplate.TermsList>
</Stack>
{companyLogoUri && showCompanyLogo && (
<PaperTemplate.Logo logoUri={companyLogoUri} />
)} )}
{showEstimateDate && ( </Group>
<PaperTemplate.TermsItem label={estimateDateLabel}>
{estimateDate}
</PaperTemplate.TermsItem>
)}
{showExpirationDate && (
<PaperTemplate.TermsItem label={expirationDateLabel}>
{expirationDate}
</PaperTemplate.TermsItem>
)}
</PaperTemplate.TermsList>
<PaperTemplate.AddressesGroup> <PaperTemplate.AddressesGroup>
{showCompanyAddress && ( {showCompanyAddress && (

View File

@@ -11,16 +11,13 @@
width: 794px; width: 794px;
height: 1123px; height: 1123px;
} }
.bigTitle{ .bigTitle{
font-size: 60px; font-size: 60px;
margin: 0; margin: 0;
line-height: 1; line-height: 1;
margin-bottom: 25px;
font-weight: 500; font-weight: 500;
color: #333; color: #333;
} }
.details { .details {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -35,13 +32,11 @@
min-width: 120px; min-width: 120px;
color: #333; color: #333;
} }
.addressRoot{ .addressRoot{
> div{ > div{
flex: 1; flex: 1;
} }
} }
.table { .table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
@@ -66,10 +61,6 @@
} }
tbody{ tbody{
tr {
}
td{ td{
border-bottom: 1px solid #F6F6F6; border-bottom: 1px solid #F6F6F6;
padding: 12px 10px; padding: 12px 10px;
@@ -80,7 +71,6 @@
&:last-of-type{ &:last-of-type{
padding-right: 0; padding-right: 0;
} }
&.rate, &.rate,
&.total{ &.total{
text-align: right; text-align: right;
@@ -88,7 +78,6 @@
} }
} }
} }
.totals{ .totals{
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -112,25 +101,22 @@
.totalBottomGrayBordered { .totalBottomGrayBordered {
border-bottom: 1px solid #DADADA; border-bottom: 1px solid #DADADA;
} }
.logoWrap{ .logoWrap{
height: 120px;
width: 120px;
position: absolute;
right: 26px;
top: 26px;
border-radius: 5px;
overflow: hidden; overflow: hidden;
img{ img{
max-width: 100%; max-width: 100%;
} }
} }
.logoImg {
height: auto;
width: auto;
max-width: 400px;
max-height: 160px;
}
.footer{ .footer{
} }
.paragraph{ .paragraph{
margin-bottom: 20px; margin-bottom: 20px;
} }

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { PaperTemplate, PaperTemplateTotalBorder } from './PaperTemplate'; import { PaperTemplate, PaperTemplateTotalBorder } from './PaperTemplate';
import { Box, Stack } from '@/components'; import { Box, Group, Stack } from '@/components';
import { import {
DefaultPdfTemplateTerms, DefaultPdfTemplateTerms,
DefaultPdfTemplateItemDescription, DefaultPdfTemplateItemDescription,
@@ -178,31 +178,35 @@ export function InvoicePaperTemplate({
statement = DefaultPdfTemplateStatement, statement = DefaultPdfTemplateStatement,
}: InvoicePaperTemplateProps) { }: InvoicePaperTemplateProps) {
return ( return (
<PaperTemplate <PaperTemplate primaryColor={primaryColor} secondaryColor={secondaryColor}>
primaryColor={primaryColor}
secondaryColor={secondaryColor}
showCompanyLogo={showCompanyLogo}
companyLogoUri={companyLogoUri}
bigtitle={'Invoice'}
>
<Stack spacing={24}> <Stack spacing={24}>
<PaperTemplate.TermsList> <Group align="start" spacing={10}>
{showInvoiceNumber && ( <Stack flex={1}>
<PaperTemplate.TermsItem label={invoiceNumberLabel}> <PaperTemplate.BigTitle title={'Invoice'} />
{invoiceNumber}
</PaperTemplate.TermsItem> <PaperTemplate.TermsList>
{showInvoiceNumber && (
<PaperTemplate.TermsItem label={invoiceNumberLabel}>
{invoiceNumber}
</PaperTemplate.TermsItem>
)}
{showDateIssue && (
<PaperTemplate.TermsItem label={dateIssueLabel}>
{dateIssue}
</PaperTemplate.TermsItem>
)}
{showDueDate && (
<PaperTemplate.TermsItem label={dueDateLabel}>
{dueDate}
</PaperTemplate.TermsItem>
)}
</PaperTemplate.TermsList>
</Stack>
{companyLogoUri && showCompanyLogo && (
<PaperTemplate.Logo logoUri={companyLogoUri} />
)} )}
{showDateIssue && ( </Group>
<PaperTemplate.TermsItem label={dateIssueLabel}>
{dateIssue}
</PaperTemplate.TermsItem>
)}
{showDueDate && (
<PaperTemplate.TermsItem label={dueDateLabel}>
{dueDate}
</PaperTemplate.TermsItem>
)}
</PaperTemplate.TermsList>
<PaperTemplate.AddressesGroup> <PaperTemplate.AddressesGroup>
{showCompanyAddress && ( {showCompanyAddress && (

View File

@@ -7,38 +7,18 @@ import styles from './InvoicePaperTemplate.module.scss';
export interface PaperTemplateProps { export interface PaperTemplateProps {
primaryColor?: string; primaryColor?: string;
secondaryColor?: string; secondaryColor?: string;
showCompanyLogo?: boolean;
companyLogoUri?: string;
companyName?: string;
bigtitle?: string;
children?: React.ReactNode; children?: React.ReactNode;
} }
export function PaperTemplate({ export function PaperTemplate({
primaryColor, primaryColor,
secondaryColor, secondaryColor,
showCompanyLogo,
companyLogoUri,
bigtitle = 'Invoice',
children, children,
}: PaperTemplateProps) { }: PaperTemplateProps) {
return ( return (
<div className={styles.root}> <div className={styles.root}>
<style>{`:root { --invoice-primary-color: ${primaryColor}; --invoice-secondary-color: ${secondaryColor}; }`}</style> <style>{`:root { --invoice-primary-color: ${primaryColor}; --invoice-secondary-color: ${secondaryColor}; }`}</style>
<div>
<h1 className={styles.bigTitle}>{bigtitle}</h1>
{showCompanyLogo && companyLogoUri && (
<div className={styles.logoWrap}>
<img alt="" src={companyLogoUri} />
</div>
)}
</div>
{children} {children}
</div> </div>
); );
@@ -53,6 +33,26 @@ interface PaperTemplateTableProps {
data: Array<Record<string, any>>; data: Array<Record<string, any>>;
} }
interface PaperTemplateBigTitleProps {
title: string;
}
PaperTemplate.BigTitle = ({ title }: PaperTemplateBigTitleProps) => {
return <h1 className={styles.bigTitle}>{title}</h1>;
};
interface PaperTemplateLogoProps {
logoUri: string;
}
PaperTemplate.Logo = ({ logoUri }: PaperTemplateLogoProps) => {
return (
<div className={styles.logoWrap}>
<img className={styles.logoImg} alt="" src={logoUri} />
</div>
);
};
PaperTemplate.Table = ({ columns, data }: PaperTemplateTableProps) => { PaperTemplate.Table = ({ columns, data }: PaperTemplateTableProps) => {
return ( return (
<table className={styles.table}> <table className={styles.table}>

View File

@@ -1,4 +1,4 @@
import { Box, Stack } from '@/components'; import { Box, Group, Stack } from '@/components';
import { import {
PaperTemplate, PaperTemplate,
PaperTemplateProps, PaperTemplateProps,
@@ -10,6 +10,13 @@ import {
} from '@/constants/PdfTemplates'; } from '@/constants/PdfTemplates';
export interface PaymentReceivedPaperTemplateProps extends PaperTemplateProps { export interface PaymentReceivedPaperTemplateProps extends PaperTemplateProps {
// # Company logo
showCompanyLogo?: boolean;
companyLogoUri?: string;
// # Company name
companyName?: string;
// Customer address // Customer address
showCustomerAddress?: boolean; showCustomerAddress?: boolean;
customerAddress?: string; customerAddress?: string;
@@ -93,27 +100,31 @@ export function PaymentReceivedPaperTemplate({
paymentReceivedDateLabel = 'Payment Date', paymentReceivedDateLabel = 'Payment Date',
}: PaymentReceivedPaperTemplateProps) { }: PaymentReceivedPaperTemplateProps) {
return ( return (
<PaperTemplate <PaperTemplate primaryColor={primaryColor} secondaryColor={secondaryColor}>
primaryColor={primaryColor}
secondaryColor={secondaryColor}
showCompanyLogo={showCompanyLogo}
companyLogoUri={companyLogoUri}
bigtitle={'Payment'}
>
<Stack spacing={24}> <Stack spacing={24}>
<PaperTemplate.TermsList> <Group align={'start'} spacing={10}>
{showPaymentReceivedNumber && ( <Stack flex={1}>
<PaperTemplate.TermsItem label={paymentReceivedNumberLabel}> <PaperTemplate.BigTitle title={'Payment'} />
{paymentReceivedNumebr}
</PaperTemplate.TermsItem>
)}
{showPaymentReceivedDate && ( <PaperTemplate.TermsList>
<PaperTemplate.TermsItem label={paymentReceivedDateLabel}> {showPaymentReceivedNumber && (
{paymentReceivedDate} <PaperTemplate.TermsItem label={paymentReceivedNumberLabel}>
</PaperTemplate.TermsItem> {paymentReceivedNumebr}
</PaperTemplate.TermsItem>
)}
{showPaymentReceivedDate && (
<PaperTemplate.TermsItem label={paymentReceivedDateLabel}>
{paymentReceivedDate}
</PaperTemplate.TermsItem>
)}
</PaperTemplate.TermsList>
</Stack>
{companyLogoUri && showCompanyLogo && (
<PaperTemplate.Logo logoUri={companyLogoUri} />
)} )}
</PaperTemplate.TermsList> </Group>
<PaperTemplate.AddressesGroup> <PaperTemplate.AddressesGroup>
{showCompanyAddress && ( {showCompanyAddress && (

View File

@@ -1,4 +1,4 @@
import { Box, Stack } from '@/components'; import { Box, Group, Stack } from '@/components';
import { import {
PaperTemplate, PaperTemplate,
PaperTemplateProps, PaperTemplateProps,
@@ -13,6 +13,13 @@ import {
} from '@/constants/PdfTemplates'; } from '@/constants/PdfTemplates';
export interface ReceiptPaperTemplateProps extends PaperTemplateProps { export interface ReceiptPaperTemplateProps extends PaperTemplateProps {
// # Company logo
showCompanyLogo?: boolean;
companyLogoUri?: string;
// # Company name
companyName?: string;
// Addresses // Addresses
showCustomerAddress?: boolean; showCustomerAddress?: boolean;
customerAddress?: string; customerAddress?: string;
@@ -117,26 +124,30 @@ export function ReceiptPaperTemplate({
receiptDateLabel = 'Receipt Date', receiptDateLabel = 'Receipt Date',
}: ReceiptPaperTemplateProps) { }: ReceiptPaperTemplateProps) {
return ( return (
<PaperTemplate <PaperTemplate primaryColor={primaryColor} secondaryColor={secondaryColor}>
primaryColor={primaryColor}
secondaryColor={secondaryColor}
showCompanyLogo={showCompanyLogo}
companyLogoUri={companyLogoUri}
bigtitle={'Receipt'}
>
<Stack spacing={24}> <Stack spacing={24}>
<PaperTemplate.TermsList> <Group align={'start'} spacing={10}>
{showReceiptNumber && ( <Stack flex={1}>
<PaperTemplate.TermsItem label={receiptNumberLabel}> <PaperTemplate.BigTitle title={'Receipt'} />
{receiptNumebr}
</PaperTemplate.TermsItem> <PaperTemplate.TermsList>
{showReceiptNumber && (
<PaperTemplate.TermsItem label={receiptNumberLabel}>
{receiptNumebr}
</PaperTemplate.TermsItem>
)}
{showReceiptDate && (
<PaperTemplate.TermsItem label={receiptDateLabel}>
{receiptDate}
</PaperTemplate.TermsItem>
)}
</PaperTemplate.TermsList>
</Stack>
{companyLogoUri && showCompanyLogo && (
<PaperTemplate.Logo logoUri={companyLogoUri} />
)} )}
{showReceiptDate && ( </Group>
<PaperTemplate.TermsItem label={receiptDateLabel}>
{receiptDate}
</PaperTemplate.TermsItem>
)}
</PaperTemplate.TermsList>
<PaperTemplate.AddressesGroup> <PaperTemplate.AddressesGroup>
{showCompanyAddress && ( {showCompanyAddress && (