mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-24 16:49:48 +00:00
Merge branch 'develop' into add-mail-invoice-receipt-schema
This commit is contained in:
@@ -4,10 +4,10 @@
|
||||
"scripts": {
|
||||
"dev": "lerna run dev",
|
||||
"build": "lerna run build",
|
||||
"dev:webapp": "lerna run dev --scope \"@bigcapital/webapp\" --scope \"@bigcapital/utils\"",
|
||||
"build:webapp": "lerna run build --scope \"@bigcapital/webapp\" --scope \"@bigcapital/utils\"",
|
||||
"dev:server": "lerna run dev --scope \"@bigcapital/server\" --scope \"@bigcapital/utils\"",
|
||||
"build:server": "lerna run build --scope \"@bigcapital/server\" --scope \"@bigcapital/utils\"",
|
||||
"dev:webapp": "lerna run dev --scope \"@bigcapital/webapp\" --scope \"@bigcapital/utils\" --scope \"@bigcapital/pdf-templates\"",
|
||||
"build:webapp": "lerna run build --scope \"@bigcapital/webapp\" --scope \"@bigcapital/utils\" --scope \"@bigcapital/pdf-templates\"",
|
||||
"dev:server": "lerna run dev --scope \"@bigcapital/server\" --scope \"@bigcapital/utils\" --scope \"@bigcapital/pdf-templates\" --scope \"@bigcapital/email-components\"",
|
||||
"build:server": "lerna run build --scope \"@bigcapital/server\" --scope \"@bigcapital/utils\" --scope \"@bigcapital/pdf-templates\" --scope \"@bigcapital/email-components\"",
|
||||
"serve:server": "lerna run serve --scope \"@bigcapital/server\" --scope \"@bigcapital/utils\"",
|
||||
"test:e2e": "playwright test",
|
||||
"prepare": "husky install"
|
||||
|
||||
@@ -37,7 +37,8 @@ export interface CommonMailOptions {
|
||||
cc?: Array<string>;
|
||||
bcc?: Array<string>;
|
||||
formatArgs?: Record<string, any>;
|
||||
toOptions: Array<AddressItem>;
|
||||
fromOptions: Array<AddressItem>;
|
||||
}
|
||||
|
||||
export interface CommonMailOptionsDTO extends Partial<CommonMailOptions> {
|
||||
}
|
||||
export interface CommonMailOptionsDTO extends Partial<CommonMailOptions> {}
|
||||
|
||||
@@ -338,21 +338,22 @@ export interface InvoicePdfTemplateAttributes {
|
||||
subtotalLabel: string;
|
||||
discountLabel: string;
|
||||
paymentMadeLabel: string;
|
||||
balanceDueLabel: string;
|
||||
|
||||
showTotal: boolean;
|
||||
showSubtotal: boolean;
|
||||
showDiscount: boolean;
|
||||
showTaxes: boolean;
|
||||
showPaymentMade: boolean;
|
||||
showDueAmount: boolean;
|
||||
showBalanceDue: boolean;
|
||||
|
||||
total: string;
|
||||
subtotal: string;
|
||||
discount: string;
|
||||
paymentMade: string;
|
||||
balanceDue: string;
|
||||
|
||||
// Due Amount
|
||||
dueAmount: string;
|
||||
showDueAmount: boolean;
|
||||
dueAmountLabel: string;
|
||||
|
||||
termsConditionsLabel: string;
|
||||
showTermsConditions: boolean;
|
||||
|
||||
@@ -58,7 +58,7 @@ export class PdfTemplate extends TenantModel {
|
||||
* @returns {string}
|
||||
*/
|
||||
get companyLogoUri() {
|
||||
return this.attributes.companyLogoKey
|
||||
return this.attributes?.companyLogoKey
|
||||
? getUploadedObjectUri(this.attributes.companyLogoKey)
|
||||
: '';
|
||||
}
|
||||
|
||||
@@ -23,22 +23,24 @@ export class ContactMailNotification {
|
||||
public async getDefaultMailOptions(
|
||||
tenantId: number,
|
||||
customerId: number
|
||||
): Promise<Pick<CommonMailOptions, 'to' | 'from'>> {
|
||||
): Promise<
|
||||
Pick<CommonMailOptions, 'to' | 'from' | 'toOptions' | 'fromOptions'>
|
||||
> {
|
||||
const { Customer } = this.tenancy.models(tenantId);
|
||||
const customer = await Customer.query()
|
||||
.findById(customerId)
|
||||
.throwIfNotFound();
|
||||
|
||||
const toAddresses = customer.contactAddresses;
|
||||
const fromAddresses = await this.mailTenancy.senders(tenantId);
|
||||
const toOptions = customer.contactAddresses;
|
||||
const fromOptions = await this.mailTenancy.senders(tenantId);
|
||||
|
||||
const toAddress = toAddresses.find((a) => a.primary);
|
||||
const fromAddress = fromAddresses.find((a) => a.primary);
|
||||
const toAddress = toOptions.find((a) => a.primary);
|
||||
const fromAddress = fromOptions.find((a) => a.primary);
|
||||
|
||||
const to = toAddress?.mail ? castArray(toAddress?.mail) : [];
|
||||
const from = fromAddress?.mail ? castArray(fromAddress?.mail) : [];
|
||||
|
||||
return { to, from };
|
||||
return { to, from, toOptions, fromOptions };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,9 +19,6 @@ export class SaleInvoicePdf {
|
||||
@Inject()
|
||||
private chromiumlyTenancy: ChromiumlyTenancy;
|
||||
|
||||
@Inject()
|
||||
private templateInjectable: TemplateInjectable;
|
||||
|
||||
@Inject()
|
||||
private getInvoiceService: GetSaleInvoice;
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import Mail from '@/lib/Mail';
|
||||
import { ISaleInvoiceMailSend, SendInvoiceMailDTO } from '@/interfaces';
|
||||
import {
|
||||
ISaleInvoiceMailSend,
|
||||
SaleInvoiceMailOptions,
|
||||
SendInvoiceMailDTO,
|
||||
} from '@/interfaces';
|
||||
import { SaleInvoicePdf } from './SaleInvoicePdf';
|
||||
import { SendSaleInvoiceMailCommon } from './SendInvoiceInvoiceMailCommon';
|
||||
import { mergeAndValidateMailOptions } from '@/services/MailNotification/utils';
|
||||
@@ -47,6 +51,34 @@ export class SendSaleInvoiceMail {
|
||||
} as ISaleInvoiceMailSend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the formatted mail options.
|
||||
* @param {number} tenantId
|
||||
* @param {number} saleInvoiceId
|
||||
* @param {SendInvoiceMailDTO} messageOptions
|
||||
* @returns {Promise<SaleInvoiceMailOptions>}
|
||||
*/
|
||||
async getFormattedMailOptions(
|
||||
tenantId: number,
|
||||
saleInvoiceId: number,
|
||||
messageOptions: SendInvoiceMailDTO
|
||||
): Promise<SaleInvoiceMailOptions> {
|
||||
const defaultMessageOptions = await this.invoiceMail.getInvoiceMailOptions(
|
||||
tenantId,
|
||||
saleInvoiceId
|
||||
);
|
||||
// Merges message options with default options and parses the options values.
|
||||
const parsedMessageOptions = mergeAndValidateMailOptions(
|
||||
defaultMessageOptions,
|
||||
messageOptions
|
||||
);
|
||||
return this.invoiceMail.formatInvoiceMailOptions(
|
||||
tenantId,
|
||||
saleInvoiceId,
|
||||
parsedMessageOptions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the mail invoice.
|
||||
* @param {number} tenantId
|
||||
@@ -59,20 +91,10 @@ export class SendSaleInvoiceMail {
|
||||
saleInvoiceId: number,
|
||||
messageOptions: SendInvoiceMailDTO
|
||||
) {
|
||||
const defaultMessageOptions = await this.invoiceMail.getInvoiceMailOptions(
|
||||
tenantId,
|
||||
saleInvoiceId
|
||||
);
|
||||
// Merges message options with default options and parses the options values.
|
||||
const parsedMessageOptions = mergeAndValidateMailOptions(
|
||||
defaultMessageOptions,
|
||||
messageOptions
|
||||
);
|
||||
const formattedMessageOptions =
|
||||
await this.invoiceMail.formatInvoiceMailOptions(
|
||||
const formattedMessageOptions = await this.getFormattedMailOptions(
|
||||
tenantId,
|
||||
saleInvoiceId,
|
||||
parsedMessageOptions
|
||||
messageOptions
|
||||
);
|
||||
const mail = new Mail()
|
||||
.setSubject(formattedMessageOptions.subject)
|
||||
|
||||
@@ -27,7 +27,7 @@ export const transformInvoiceToPdfTemplate = (
|
||||
total: invoice.totalFormatted,
|
||||
subtotal: invoice.subtotalFormatted,
|
||||
paymentMade: invoice.paymentAmountFormatted,
|
||||
balanceDue: invoice.balanceAmountFormatted,
|
||||
dueAmount: invoice.dueAmountFormatted,
|
||||
|
||||
termsConditions: invoice.termsConditions,
|
||||
statement: invoice.invoiceMessage,
|
||||
|
||||
@@ -112,17 +112,20 @@ export class SendPaymentReceiveMailNotification {
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggers the mail invoice.
|
||||
* Retrieves the formatted mail options of the given payment receive.
|
||||
* @param {number} tenantId
|
||||
* @param {number} saleInvoiceId
|
||||
* @param {number} paymentReceiveId
|
||||
* @param {SendInvoiceMailDTO} messageDTO
|
||||
* @returns {Promise<void>}
|
||||
* @returns {Promise<PaymentReceiveMailOpts>}
|
||||
*/
|
||||
public async sendMail(
|
||||
public getFormattedMailOptions = async (
|
||||
tenantId: number,
|
||||
paymentReceiveId: number,
|
||||
messageDTO: SendInvoiceMailDTO
|
||||
): Promise<void> {
|
||||
) => {
|
||||
const formatterArgs = await this.textFormatter(tenantId, paymentReceiveId);
|
||||
|
||||
// Default message options.
|
||||
const defaultMessageOpts = await this.getMailOptions(
|
||||
tenantId,
|
||||
paymentReceiveId
|
||||
@@ -132,17 +135,43 @@ export class SendPaymentReceiveMailNotification {
|
||||
defaultMessageOpts,
|
||||
messageDTO
|
||||
);
|
||||
// Formats the message options.
|
||||
return this.contactMailNotification.formatMailOptions(
|
||||
tenantId,
|
||||
parsedMessageOpts,
|
||||
formatterArgs
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggers the mail invoice.
|
||||
* @param {number} tenantId
|
||||
* @param {number} saleInvoiceId - Invoice id.
|
||||
* @param {SendInvoiceMailDTO} messageDTO - Message options.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async sendMail(
|
||||
tenantId: number,
|
||||
paymentReceiveId: number,
|
||||
messageDTO: SendInvoiceMailDTO
|
||||
): Promise<void> {
|
||||
// Retrieves the formatted mail options.
|
||||
const formattedMessageOptions = await this.getFormattedMailOptions(
|
||||
tenantId,
|
||||
paymentReceiveId,
|
||||
messageDTO
|
||||
);
|
||||
const mail = new Mail()
|
||||
.setSubject(parsedMessageOpts.subject)
|
||||
.setTo(parsedMessageOpts.to)
|
||||
.setCC(parsedMessageOpts.cc)
|
||||
.setBCC(parsedMessageOpts.bcc)
|
||||
.setContent(parsedMessageOpts.message);
|
||||
.setSubject(formattedMessageOptions.subject)
|
||||
.setTo(formattedMessageOptions.to)
|
||||
.setCC(formattedMessageOptions.cc)
|
||||
.setBCC(formattedMessageOptions.bcc)
|
||||
.setContent(formattedMessageOptions.message);
|
||||
|
||||
const eventPayload = {
|
||||
tenantId,
|
||||
paymentReceiveId,
|
||||
messageOptions: parsedMessageOpts,
|
||||
messageOptions: formattedMessageOptions,
|
||||
};
|
||||
// Triggers `onPaymentReceiveMailSend` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const DEFAULT_PAYMENT_MAIL_SUBJECT = 'Payment Received by {CompanyName}';
|
||||
export const DEFAULT_PAYMENT_MAIL_SUBJECT =
|
||||
'Payment Received for {Customer Name} from {Company Name}';
|
||||
export const DEFAULT_PAYMENT_MAIL_CONTENT = `
|
||||
<p>Dear {Customer Name}</p>
|
||||
<p>Thank you for your payment. It was a pleasure doing business with you. We look forward to work together again!</p>
|
||||
|
||||
@@ -114,6 +114,58 @@ export class SaleReceiptMailNotification {
|
||||
return transformReceiptToMailDataArgs(receipt);
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats the mail options of the given sale receipt.
|
||||
* @param {number} tenantId
|
||||
* @param {number} receiptId
|
||||
* @param {SaleReceiptMailOpts} mailOptions
|
||||
* @returns {Promise<SaleReceiptMailOpts>}
|
||||
*/
|
||||
public async formatEstimateMailOptions(
|
||||
tenantId: number,
|
||||
receiptId: number,
|
||||
mailOptions: SaleReceiptMailOpts
|
||||
): Promise<SaleReceiptMailOpts> {
|
||||
const formatterArgs = await this.textFormatterArgs(tenantId, receiptId);
|
||||
const formattedOptions =
|
||||
(await this.contactMailNotification.formatMailOptions(
|
||||
tenantId,
|
||||
mailOptions,
|
||||
formatterArgs
|
||||
)) as SaleReceiptMailOpts;
|
||||
return formattedOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the formatted mail options of the given sale receipt.
|
||||
* @param {number} tenantId
|
||||
* @param {number} saleReceiptId
|
||||
* @param {SaleReceiptMailOptsDTO} messageOpts
|
||||
* @returns {Promise<SaleReceiptMailOpts>}
|
||||
*/
|
||||
public getFormatMailOptions = async (
|
||||
tenantId: number,
|
||||
saleReceiptId: number,
|
||||
messageOpts: SaleReceiptMailOptsDTO
|
||||
): Promise<SaleReceiptMailOpts> => {
|
||||
const defaultMessageOptions = await this.getMailOptions(
|
||||
tenantId,
|
||||
saleReceiptId
|
||||
);
|
||||
// Merges message opts with default options.
|
||||
const parsedMessageOpts = mergeAndValidateMailOptions(
|
||||
defaultMessageOptions,
|
||||
messageOpts
|
||||
) as SaleReceiptMailOpts;
|
||||
|
||||
// Formats the message options.
|
||||
return this.formatEstimateMailOptions(
|
||||
tenantId,
|
||||
saleReceiptId,
|
||||
parsedMessageOpts
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggers the mail notification of the given sale receipt.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
@@ -126,25 +178,21 @@ export class SaleReceiptMailNotification {
|
||||
saleReceiptId: number,
|
||||
messageOpts: SaleReceiptMailOptsDTO
|
||||
) {
|
||||
const defaultMessageOptions = await this.getMailOptions(
|
||||
// Formats the message options.
|
||||
const formattedMessageOptions = await this.getFormatMailOptions(
|
||||
tenantId,
|
||||
saleReceiptId
|
||||
);
|
||||
// Merges message opts with default options.
|
||||
const parsedMessageOpts = mergeAndValidateMailOptions(
|
||||
defaultMessageOptions,
|
||||
saleReceiptId,
|
||||
messageOpts
|
||||
) as SaleReceiptMailOpts;
|
||||
|
||||
);
|
||||
const mail = new Mail()
|
||||
.setSubject(parsedMessageOpts.subject)
|
||||
.setTo(parsedMessageOpts.to)
|
||||
.setCC(parsedMessageOpts.cc)
|
||||
.setBCC(parsedMessageOpts.bcc)
|
||||
.setContent(parsedMessageOpts.message);
|
||||
.setSubject(formattedMessageOptions.subject)
|
||||
.setTo(formattedMessageOptions.to)
|
||||
.setCC(formattedMessageOptions.cc)
|
||||
.setBCC(formattedMessageOptions.bcc)
|
||||
.setContent(formattedMessageOptions.message);
|
||||
|
||||
// Attaches the receipt pdf document.
|
||||
if (parsedMessageOpts.attachReceipt) {
|
||||
if (formattedMessageOptions.attachReceipt) {
|
||||
// Retrieves document buffer of the receipt pdf document.
|
||||
const [receiptPdfBuffer, filename] =
|
||||
await this.receiptPdfService.saleReceiptPdf(tenantId, saleReceiptId);
|
||||
|
||||
@@ -75,7 +75,7 @@ function LoginFooterLinks() {
|
||||
)}
|
||||
<AuthFooterLink>
|
||||
<Link to={'/auth/send_reset_password'}>
|
||||
<T id={'forget_my_password'} />
|
||||
<T id={'forgot_my_password'} />
|
||||
</Link>
|
||||
</AuthFooterLink>
|
||||
</AuthFooterLinks>
|
||||
|
||||
@@ -99,7 +99,7 @@ function RegisterFooterLinks() {
|
||||
|
||||
<AuthFooterLink>
|
||||
<Link to={'/auth/send_reset_password'}>
|
||||
<T id={'forget_my_password'} />
|
||||
<T id={'forgot_my_password'} />
|
||||
</Link>
|
||||
</AuthFooterLink>
|
||||
</AuthFooterLinks>
|
||||
|
||||
@@ -48,6 +48,7 @@ export const useBrandingTemplateFormInitialValues = <
|
||||
|
||||
const brandingAttributes = {
|
||||
templateName: pdfTemplate?.templateName,
|
||||
companyLogoUri: pdfTemplate?.companyLogoUri,
|
||||
...pdfTemplate?.attributes,
|
||||
};
|
||||
return {
|
||||
@@ -56,14 +57,16 @@ export const useBrandingTemplateFormInitialValues = <
|
||||
};
|
||||
};
|
||||
|
||||
export const useBrandingState = (state?: Partial<BrandingState>): BrandingState => {
|
||||
export const useBrandingState = (
|
||||
state?: Partial<BrandingState>,
|
||||
): BrandingState => {
|
||||
const { brandingTemplateState } = useBrandingTemplateBoot();
|
||||
|
||||
return {
|
||||
...brandingTemplateState,
|
||||
...state
|
||||
}
|
||||
}
|
||||
...state,
|
||||
};
|
||||
};
|
||||
|
||||
export const getCustomizeDrawerNameFromResource = (resource: string) => {
|
||||
const pairs = {
|
||||
|
||||
@@ -32,7 +32,7 @@ function EstimateMailDialogFormRoot({
|
||||
closeDialog,
|
||||
}) {
|
||||
const { mutateAsync: sendEstimateMail } = useSendSaleEstimateMail();
|
||||
const { mailOptions, saleEstimateId, redirectToEstimatesList } =
|
||||
const { mailOptions, saleEstimateId, } =
|
||||
useEstimateMailDialogBoot();
|
||||
|
||||
const initialValues = transformMailFormToInitialValues(
|
||||
|
||||
@@ -25,8 +25,8 @@ export function EstimateMailDialogFormContent({
|
||||
<Form>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<MailNotificationForm
|
||||
fromAddresses={mailOptions.from_addresses}
|
||||
toAddresses={mailOptions.to_addresses}
|
||||
fromAddresses={mailOptions.from_options}
|
||||
toAddresses={mailOptions.to_options}
|
||||
/>
|
||||
<AttachFormGroup name={'attachEstimate'} inline>
|
||||
<FSwitch name={'attachEstimate'} label={'Attach Estimate'} />
|
||||
|
||||
@@ -22,6 +22,7 @@ interface PaymentMailDialogBootProps {
|
||||
*/
|
||||
function PaymentMailDialogBoot({
|
||||
paymentReceiveId,
|
||||
redirectToPaymentsList,
|
||||
...props
|
||||
}: PaymentMailDialogBootProps) {
|
||||
const { data: mailOptions, isLoading: isMailOptionsLoading } =
|
||||
|
||||
@@ -25,8 +25,8 @@ export function PaymentMailDialogFormContent({
|
||||
<Form>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<MailNotificationForm
|
||||
fromAddresses={mailOptions.from_addresses}
|
||||
toAddresses={mailOptions.to_addresses}
|
||||
fromAddresses={mailOptions.from_options}
|
||||
toAddresses={mailOptions.to_options}
|
||||
/>
|
||||
<AttachFormGroup name={'attachPayment'} inline>
|
||||
<FSwitch name={'attachPayment'} label={'Attach Payment'} />
|
||||
|
||||
@@ -25,8 +25,8 @@ export function ReceiptMailDialogFormContent({
|
||||
<Form>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<MailNotificationForm
|
||||
fromAddresses={mailOptions.from_addresses}
|
||||
toAddresses={mailOptions.to_addresses}
|
||||
fromAddresses={mailOptions.from_options}
|
||||
toAddresses={mailOptions.to_options}
|
||||
/>
|
||||
<AttachFormGroup name={'attachReceipt:'} inline>
|
||||
<FSwitch name={'attachReceipt:'} label={'Attach Receipt'} />
|
||||
|
||||
@@ -66,7 +66,7 @@ export function MailNotificationForm({
|
||||
</FFormGroup>
|
||||
</HeaderBox>
|
||||
|
||||
<MailMessageEditor name={'body'} />
|
||||
<MailMessageEditor name={'message'} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ export const initialMailNotificationValues = {
|
||||
from: [],
|
||||
to: [],
|
||||
subject: '',
|
||||
body: '',
|
||||
message: '',
|
||||
};
|
||||
|
||||
export interface MailNotificationFormValues {
|
||||
@@ -26,7 +26,7 @@ export const transformMailFormToRequest = (
|
||||
};
|
||||
|
||||
/**
|
||||
* Transformes the mail options response values to form initial values.
|
||||
* Transforms the mail options response values to form initial values.
|
||||
* @param {any} mailOptions
|
||||
* @param {MailNotificationFormValues} initialValues
|
||||
* @returns {MailNotificationFormValues}
|
||||
|
||||
@@ -38,6 +38,7 @@ export interface GetPdfTemplateValues {}
|
||||
|
||||
export interface GetPdfTemplateResponse {
|
||||
templateName: string;
|
||||
companyLogoUri?: string | null;
|
||||
attributes: Record<string, any>;
|
||||
predefined: boolean;
|
||||
default: boolean;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"to_date": "الى تاريخ",
|
||||
"report_date_range": "تقرير نطاق التاريخ",
|
||||
"log_in": "تسجيل الدخول",
|
||||
"forget_my_password": "نسيت كلمة المرور الخاصة بي",
|
||||
"forgot_my_password": "نسيت كلمة المرور الخاصة بي",
|
||||
"keep_me_logged_in": "تذكرني",
|
||||
"dont_have_an_account": "ليس لديك حساب؟",
|
||||
"sign_up": "تسجيل",
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"to_date": "To date",
|
||||
"report_date_range": "Report date range",
|
||||
"log_in": "Log in",
|
||||
"forget_my_password": "Forget my password",
|
||||
"forgot_my_password": "Forgot my password",
|
||||
"keep_me_logged_in": "Keep me logged in",
|
||||
"dont_have_an_account": "Don't have an account?",
|
||||
"sign_up": "Sign up",
|
||||
|
||||
6
packages/webapp/src/lang/es/authentication.tsx
Normal file
6
packages/webapp/src/lang/es/authentication.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
// @ts-nocheck
|
||||
|
||||
export default {
|
||||
"login": "Ingresar",
|
||||
"reset_password": "Resetear contraseña",
|
||||
};
|
||||
2275
packages/webapp/src/lang/es/index.json
Normal file
2275
packages/webapp/src/lang/es/index.json
Normal file
File diff suppressed because it is too large
Load Diff
61
packages/webapp/src/lang/es/locale.tsx
Normal file
61
packages/webapp/src/lang/es/locale.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
// @ts-nocheck
|
||||
import printValue from '../printValue';
|
||||
|
||||
export const locale = {
|
||||
mixed: {
|
||||
default: '${path} es inválido',
|
||||
required: '${path} es un campo requerido',
|
||||
oneOf: '${path} debe ser uno de los siguientes valores: ${values}',
|
||||
notOneOf: '${path} no debe ser uno de los siguientes valores: ${values}',
|
||||
notType: ({ path, type, value, originalValue }) => {
|
||||
let isCast = originalValue != null && originalValue !== value;
|
||||
let msg =
|
||||
`${path} debe ser de tipo \`${type}\`, ` +
|
||||
`pero el valor final fue: \`${printValue(value, true)}\`` +
|
||||
(isCast
|
||||
? ` (convertido del valor \`${printValue(originalValue, true)}\`).`
|
||||
: '.');
|
||||
|
||||
if (value === null) {
|
||||
msg += `\n Si "null" se pretende como un valor vacío, asegúrate de marcar el esquema como \`.nullable()\``;
|
||||
}
|
||||
|
||||
return msg;
|
||||
},
|
||||
defined: '${path} debe estar definido',
|
||||
},
|
||||
string: {
|
||||
length: '${path} debe tener exactamente ${length} caracteres',
|
||||
min: '${path} debe tener al menos ${min} caracteres',
|
||||
max: '${path} debe tener como máximo ${max} caracteres',
|
||||
matches: '${path} debe coincidir con lo siguiente: "${regex}"',
|
||||
email: '${path} debe ser un correo electrónico válido',
|
||||
url: '${path} debe ser una URL válida',
|
||||
trim: '${path} debe ser una cadena recortada',
|
||||
lowercase: '${path} debe ser una cadena en minúsculas',
|
||||
uppercase: '${path} debe ser una cadena en mayúsculas',
|
||||
},
|
||||
number: {
|
||||
min: '${path} debe ser mayor o igual a ${min}',
|
||||
max: '${path} debe ser menor o igual a ${max}',
|
||||
lessThan: '${path} debe ser menor que ${less}',
|
||||
moreThan: '${path} debe ser mayor que ${more}',
|
||||
notEqual: '${path} no debe ser igual a ${notEqual}',
|
||||
positive: '${path} debe ser un número positivo',
|
||||
negative: '${path} debe ser un número negativo',
|
||||
integer: '${path} debe ser un número entero',
|
||||
},
|
||||
date: {
|
||||
min: '${path} debe ser posterior a ${min}',
|
||||
max: '${path} debe ser anterior a ${max}',
|
||||
},
|
||||
boolean: {},
|
||||
object: {
|
||||
noUnknown:
|
||||
'${path} no puede tener claves no especificadas en la forma del objeto',
|
||||
},
|
||||
array: {
|
||||
min: '${path} debe tener al menos ${min} elementos',
|
||||
max: '${path} debe tener como máximo ${max} elementos',
|
||||
},
|
||||
};
|
||||
7
packages/webapp/src/lang/sv/authentication.tsx
Normal file
7
packages/webapp/src/lang/sv/authentication.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
// @ts-nocheck
|
||||
|
||||
|
||||
export default {
|
||||
"login": "Logga in",
|
||||
"reset_password": "Återställ lösenord",
|
||||
};
|
||||
2247
packages/webapp/src/lang/sv/index.json
Normal file
2247
packages/webapp/src/lang/sv/index.json
Normal file
File diff suppressed because it is too large
Load Diff
61
packages/webapp/src/lang/sv/locale.tsx
Normal file
61
packages/webapp/src/lang/sv/locale.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
// @ts-nocheck
|
||||
import printValue from '../printValue';
|
||||
|
||||
export const locale = {
|
||||
mixed: {
|
||||
default: '${path} är inkorrekt',
|
||||
required: '${path} är ett obligatoriskt fält ',
|
||||
oneOf: '${path} måste vara en av följande värden: ${values}',
|
||||
notOneOf: '${path} kan inte vara en av följande värden: ${values}',
|
||||
notType: ({ path, type, value, originalValue }) => {
|
||||
let isCast = originalValue != null && originalValue !== value;
|
||||
let msg =
|
||||
`${path} måste ha typen \`${type}\`, ` +
|
||||
`men det slutliga värdet var: \`${printValue(value, true)}\`` +
|
||||
(isCast
|
||||
? ` (gjord av värdet \`${printValue(originalValue, true)}\`).`
|
||||
: '.');
|
||||
|
||||
if (value === null) {
|
||||
msg += `\n Om ”null” är avsett som ett tomt värde ska du se till att markera schemat som \`.nullable()\``;
|
||||
}
|
||||
|
||||
return msg;
|
||||
},
|
||||
defined: '${path} måste vara definierad',
|
||||
},
|
||||
string: {
|
||||
length: '${path} måste vara exakt ${length} tecken',
|
||||
min: '${path} måste vara som minst ${min} tecken',
|
||||
max: '${path} måste vara som mest ${max} tecken',
|
||||
matches: '${path} måste matcha det följande: "${regex}"',
|
||||
email: '${path} måste vara en giltig e-post',
|
||||
url: '${path} måste vara en giltig URL',
|
||||
trim: '${path} måste vara en trimmad sträng',
|
||||
lowercase: '${path} måste vara en sträng med små bokstäver',
|
||||
uppercase: '${path} måste vara en sträng med stora bokstäver',
|
||||
},
|
||||
number: {
|
||||
min: '${path} måste vara större eller lika med ${min}',
|
||||
max: '${path} måste vara mindre eller lika med ${max}',
|
||||
lessThan: '${path} måste vara mindre än ${less}',
|
||||
moreThan: '${path} måste vara större än ${more}',
|
||||
notEqual: '${path} får inte vara lika med ${notEqual}',
|
||||
positive: '${path} får inte vara ett positivt nummer',
|
||||
negative: '${path} får inte vara ett negativt nummer',
|
||||
integer: '${path} måste vara ett nummer',
|
||||
},
|
||||
date: {
|
||||
min: '${path} fältet måste vara senare än ${min}',
|
||||
max: '${path} fältet måste vara tidigare än ${max}',
|
||||
},
|
||||
boolean: {},
|
||||
object: {
|
||||
noUnknown:
|
||||
'${path}-fältet kan inte ha nycklar som inte anges i objektform',
|
||||
},
|
||||
array: {
|
||||
min: '${path}-fältet måste ha minst ${min} objekt',
|
||||
max: '${path} fältet måste ha mindre än eller lika med ${max} objekt',
|
||||
},
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import { Meta } from '@storybook/react';
|
||||
import { StoryFn } from '@storybook/react';
|
||||
import {
|
||||
@@ -15,22 +16,3 @@ export default meta;
|
||||
const Template: StoryFn<typeof InvoicePaymentEmail> = (
|
||||
args: InvoicePaymentEmailProps
|
||||
) => <InvoicePaymentEmail {...args} />;
|
||||
|
||||
export const PreviewInvoicePaymentMail = Template.bind({});
|
||||
|
||||
PreviewInvoicePaymentMail.args = {
|
||||
preview: 'Preview text',
|
||||
companyName: 'ABC Company',
|
||||
companyLogoUri: 'https://example.com/logo.png',
|
||||
invoiceAmount: '100.00',
|
||||
dueDate: '2022-12-31',
|
||||
invoiceMessage: 'Thank you for your purchase!',
|
||||
invoiceNumber: 'INV-001',
|
||||
dueAmount: '100.00',
|
||||
total: '100.00',
|
||||
viewInvoiceButtonUrl: 'https://example.com/invoice',
|
||||
items: [
|
||||
{ label: 'Item 1', quantity: '1', rate: '50.00' },
|
||||
{ label: 'Item 2', quantity: '2', rate: '25.00' },
|
||||
],
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
"scripts": {
|
||||
"build": "webpack --config webpack.config.js",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview",
|
||||
"storybook:dev": "storybook dev -p 6006",
|
||||
"storybook:build": "storybook build"
|
||||
},
|
||||
|
||||
@@ -71,10 +71,12 @@ export interface InvoicePaperTemplateProps extends PaperTemplateProps {
|
||||
totalLabel?: string;
|
||||
total?: string;
|
||||
|
||||
// Discount
|
||||
showDiscount?: boolean;
|
||||
discountLabel?: string;
|
||||
discount?: string;
|
||||
|
||||
// Subtotal
|
||||
showSubtotal?: boolean;
|
||||
subtotalLabel?: string;
|
||||
subtotal?: string;
|
||||
@@ -85,10 +87,10 @@ export interface InvoicePaperTemplateProps extends PaperTemplateProps {
|
||||
|
||||
showTaxes?: boolean;
|
||||
|
||||
// Due Amount
|
||||
showDueAmount?: boolean;
|
||||
showBalanceDue?: boolean;
|
||||
balanceDueLabel?: string;
|
||||
balanceDue?: string;
|
||||
dueAmountLabel?: string;
|
||||
dueAmount?: string;
|
||||
|
||||
// Footer
|
||||
termsConditionsLabel?: string;
|
||||
@@ -144,7 +146,7 @@ export function InvoicePaperTemplate({
|
||||
subtotalLabel = 'Subtotal',
|
||||
discountLabel = 'Discount',
|
||||
paymentMadeLabel = 'Payment Made',
|
||||
balanceDueLabel = 'Balance Due',
|
||||
dueAmountLabel = 'Balance Due',
|
||||
|
||||
// Totals
|
||||
showTotal = true,
|
||||
@@ -153,13 +155,12 @@ export function InvoicePaperTemplate({
|
||||
showTaxes = true,
|
||||
showPaymentMade = true,
|
||||
showDueAmount = true,
|
||||
showBalanceDue = true,
|
||||
|
||||
total = '$662.75',
|
||||
subtotal = '630.00',
|
||||
discount = '0.00',
|
||||
paymentMade = '100.00',
|
||||
balanceDue = '$562.75',
|
||||
dueAmount = '$562.75',
|
||||
|
||||
// Footer paragraphs.
|
||||
termsConditionsLabel = 'Terms & Conditions',
|
||||
@@ -297,10 +298,10 @@ export function InvoicePaperTemplate({
|
||||
amount={paymentMade}
|
||||
/>
|
||||
)}
|
||||
{showBalanceDue && (
|
||||
{showDueAmount && (
|
||||
<PaperTemplate.TotalLine
|
||||
label={balanceDueLabel}
|
||||
amount={balanceDue}
|
||||
label={dueAmountLabel}
|
||||
amount={dueAmount}
|
||||
border={PaperTemplateTotalBorder.Dark}
|
||||
style={{ fontWeight: 500 }}
|
||||
/>
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"target": "ESNext",
|
||||
"types": ["vitest/globals"],
|
||||
"resolveJsonModule": true,
|
||||
"outDir": "dist",
|
||||
},
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import react from '@vitejs/plugin-react';
|
||||
import path from 'node:path';
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import dts from 'vite-plugin-dts';
|
||||
import tailwindcss from 'tailwindcss';
|
||||
import { UserConfigExport } from 'vite';
|
||||
import { name } from './package.json';
|
||||
|
||||
const app = async (): Promise<UserConfigExport> => {
|
||||
/**
|
||||
* Removes everything before the last
|
||||
* @octocat/library-repo -> library-repo
|
||||
* vite-component-library-template -> vite-component-library-template
|
||||
*/
|
||||
const formattedName = name.match(/[^/]+$/)?.[0] ?? name;
|
||||
|
||||
return defineConfig({
|
||||
define: {
|
||||
isBrowser: 'false', // This will replace isBrowser with false in the bundled code
|
||||
},
|
||||
ssr: {
|
||||
noExternal: true,
|
||||
},
|
||||
plugins: [
|
||||
react(),
|
||||
dts({
|
||||
insertTypesEntry: true,
|
||||
}),
|
||||
],
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [tailwindcss],
|
||||
},
|
||||
},
|
||||
build: {
|
||||
lib: {
|
||||
entry: path.resolve(__dirname, 'src/lib/main.ts'),
|
||||
name: formattedName,
|
||||
formats: ['es', 'umd'],
|
||||
fileName: (format: string) => `${formattedName}.${format}.js`,
|
||||
},
|
||||
rollupOptions: {
|
||||
// external: ['react', 'react/jsx-runtime', 'react-dom', 'tailwindcss'],
|
||||
// output: {
|
||||
// globals: {
|
||||
// react: 'React',
|
||||
// 'react/jsx-runtime': 'react/jsx-runtime',
|
||||
// 'react-dom': 'ReactDOM',
|
||||
// tailwindcss: 'tailwindcss',
|
||||
// },
|
||||
// },
|
||||
},
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
},
|
||||
});
|
||||
};
|
||||
// https://vitejs.dev/config/
|
||||
export default app;
|
||||
Reference in New Issue
Block a user