Compare commits

...

18 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
3cd54653a8 Merge pull request #694 from bigcapitalhq/lerna-shared
feat: Add shared packages to Docker container
2024-10-06 17:26:39 +02:00
Ahmed Bouhuolia
6cad929738 feat: Lerna shared 2024-10-06 17:20:28 +02:00
Ahmed Bouhuolia
184648040c Merge pull request #693 from bigcapitalhq/fix-display-country-name
fix: Display country name
2024-10-06 13:19:17 +02:00
Ahmed Bouhuolia
df9d277e66 fix: Display country name 2024-10-06 13:18:31 +02:00
Ahmed Bouhuolia
75ec315de2 Merge pull request #689 from bigcapitalhq/download-payment-link-invoice-pdf
feat: Download invoice pdf of the payment link
2024-10-05 21:48:07 +02:00
Ahmed Bouhuolia
c89b2367e6 fix: Download invoice pdf of the payment link page 2024-10-05 21:46:48 +02:00
Ahmed Bouhuolia
bca5b3481c Merge pull request #691 from bigcapitalhq/pdf-templates-layout
fix: Pdf templates layout
2024-10-05 21:26:37 +02:00
Ahmed Bouhuolia
59996e7a40 feat: re-layout server-side pdf template 2024-10-05 21:24:07 +02:00
Ahmed Bouhuolia
af5726c48c fix: Pdf templates layout 2024-10-05 19:01:34 +02:00
Ahmed Bouhuolia
90f08c5d51 Merge pull request #690 from bigcapitalhq/fix-remove-empty-lines-from-address
fix: Remove empty lines from address formats
2024-10-05 16:09:03 +02:00
Ahmed Bouhuolia
a0a9f4a768 fix: Remove empty lines from address formats 2024-10-05 16:08:09 +02:00
Ahmed Bouhuolia
2649f1c326 feat: Download invoice pdf of the payment link 2024-10-05 13:56:25 +02:00
Ahmed Bouhuolia
c5ff1e4d4a Merge pull request #688 from bigcapitalhq/fix-pdf-template-addresses-controlling
fix: pdf template addresses controlling
2024-10-03 17:13:07 +02:00
Ahmed Bouhuolia
c74c8e896a fix: pdf template addresses controlling 2024-10-03 17:12:12 +02:00
Ahmed Bouhuolia
55fdc47ff0 Merge pull request #687 from bigcapitalhq/assign-default-pdf-template
feat: Assign default PDF template automatically
2024-10-03 17:02:17 +02:00
Ahmed Bouhuolia
126eb221d0 feat: invalidate invoice state once change default template 2024-10-03 17:01:35 +02:00
Ahmed Bouhuolia
3c7e22be43 feat: Assign default pdf template automatically 2024-10-03 16:36:44 +02:00
Ahmed Bouhuolia
b23112bc92 feat: Assign default PDF template automatically 2024-10-02 18:18:57 +02:00
85 changed files with 1951 additions and 457 deletions

View File

@@ -3,6 +3,7 @@
"version": "independent", "version": "independent",
"npmClient": "pnpm", "npmClient": "pnpm",
"packages": [ "packages": [
"packages/*" "packages/*",
"shared/*"
] ]
} }

View File

@@ -4,11 +4,11 @@
"scripts": { "scripts": {
"dev": "lerna run dev", "dev": "lerna run dev",
"build": "lerna run build", "build": "lerna run build",
"dev:webapp": "lerna run dev --scope \"@bigcapital/webapp\"", "dev:webapp": "lerna run dev --scope \"@bigcapital/webapp\" --scope \"@bigcapital/utils\"",
"build:webapp": "lerna run build --scope \"@bigcapital/webapp\"", "build:webapp": "lerna run build --scope \"@bigcapital/webapp\" --scope \"@bigcapital/utils\"",
"dev:server": "lerna run dev --scope \"@bigcapital/server\"", "dev:server": "lerna run dev --scope \"@bigcapital/server\" --scope \"@bigcapital/utils\"",
"build:server": "lerna run build --scope \"@bigcapital/server\"", "build:server": "lerna run build --scope \"@bigcapital/server\" --scope \"@bigcapital/utils\"",
"serve:server": "lerna run serve --scope \"@bigcapital/server\"", "serve:server": "lerna run serve --scope \"@bigcapital/server\" --scope \"@bigcapital/utils\"",
"test:e2e": "playwright test", "test:e2e": "playwright test",
"prepare": "husky install" "prepare": "husky install"
}, },
@@ -29,5 +29,8 @@
"hooks": { "hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS" "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
} }
},
"dependencies": {
"tsup": "^8.3.0"
} }
} }

View File

@@ -90,11 +90,7 @@ RUN chown node:node /
RUN npm install -g pnpm RUN npm install -g pnpm
# Copy application dependency manifests to the container image. # Copy application dependency manifests to the container image.
COPY ./package*.json ./ COPY --chown=node:node ./ ./
COPY ./pnpm-lock.yaml ./pnpm-lock.yaml
COPY ./lerna.json ./lerna.json
COPY ./pnpm-workspace.yaml ./pnpm-workspace.yaml
COPY ./packages/server/package*.json ./packages/server/
# Install application dependencies # Install application dependencies
RUN apk update RUN apk update
@@ -109,6 +105,6 @@ RUN pnpm install
COPY --chown=node:node ./packages/server ./packages/server COPY --chown=node:node ./packages/server ./packages/server
# # Creates a "dist" folder with the production build # # Creates a "dist" folder with the production build
RUN npm run build:server --skip-nx-cache RUN pnpm run build:server --skip-nx-cache
CMD [ "node", "./packages/server/build/index.js" ] CMD [ "node", "./packages/server/build/index.js" ]

View File

@@ -22,6 +22,7 @@
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.576.0", "@aws-sdk/client-s3": "^3.576.0",
"@aws-sdk/s3-request-presigner": "^3.583.0", "@aws-sdk/s3-request-presigner": "^3.583.0",
"@bigcapital/utils": "*",
"@casl/ability": "^5.4.3", "@casl/ability": "^5.4.3",
"@hapi/boom": "^7.4.3", "@hapi/boom": "^7.4.3",
"@lemonsqueezy/lemonsqueezy.js": "^2.2.0", "@lemonsqueezy/lemonsqueezy.js": "^2.2.0",

View File

@@ -10,21 +10,37 @@ block head
position: relative; position: relative;
box-shadow: inset 0 4px 0px 0 var(--invoice-primary-color); box-shadow: inset 0 4px 0px 0 var(--invoice-primary-color);
} }
.#{prefix}-header{
box-sizing: border-box;
display: flex;
flex-flow: wrap;
flex: 0 0 auto;
-webkit-box-align: start;
align-items: start;
-webkit-box-pack: start;
justify-content: flex-start;
gap: 10px;
}
.#{prefix}-header-details{
flex: 1;
display: flex;
flex-direction: column;
align-items: stretch;
gap: 20px;
flex: 1 1 0%;
}
.#{prefix}-big-title { .#{prefix}-big-title {
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;
} }
.#{prefix}-logo-wrap { .#{prefix}-logo-wrap img {
height: 120px; height: auto;
width: 120px; width: auto;
position: absolute; max-width: 400px;
right: 26px; max-height: 160px;
top: 26px;
overflow: hidden;
} }
.#{prefix}-terms-list { .#{prefix}-terms-list {
display: flex; display: flex;
@@ -132,22 +148,27 @@ block head
block content block content
div(class=`${prefix}-root`) div(class=`${prefix}-root`)
div(class=`${prefix}-big-title`) Credit Note
if showCompanyLogo && companyLogoUri
div(class=`${prefix}-logo-wrap`)
img(src=companyLogoUri alt=`Company Logo`)
div(class=`${prefix}-terms-list`) //- Header (includes big title, details and logo)
if showCreditNoteNumber div(class=`${prefix}-header`)
div(class=`${prefix}-terms-item`) //- Header details (includes big title and details)
div(class=`${prefix}-terms-item__label`) #{creditNoteNumberLabel}: div(class=`${prefix}-header-details`)
div(class=`${prefix}-terms-item__value`) #{creditNoteNumebr} div(class=`${prefix}-big-title`) Credit Note
if showCreditNoteDate div(class=`${prefix}-terms-list`)
div(class=`${prefix}-terms-item`) if showCreditNoteNumber
div(class=`${prefix}-terms-item__label`) #{creditNoteDateLabel}: div(class=`${prefix}-terms-item`)
div(class=`${prefix}-terms-item__value`) #{creditNoteDate} div(class=`${prefix}-terms-item__label`) #{creditNoteNumberLabel}:
div(class=`${prefix}-terms-item__value`) #{creditNoteNumebr}
if showCreditNoteDate
div(class=`${prefix}-terms-item`)
div(class=`${prefix}-terms-item__label`) #{creditNoteDateLabel}:
div(class=`${prefix}-terms-item__value`) #{creditNoteDate}
if showCompanyLogo && companyLogoUri
div(class=`${prefix}-logo-wrap`)
img(src=companyLogoUri alt=`Company Logo`)
div(class=`${prefix}-address-section`) div(class=`${prefix}-address-section`)
if showCompanyAddress if showCompanyAddress

View File

@@ -10,21 +10,37 @@ block head
position: relative; position: relative;
box-shadow: inset 0 4px 0px 0 var(--invoice-primary-color); box-shadow: inset 0 4px 0px 0 var(--invoice-primary-color);
} }
.#{prefix}-header {
box-sizing: border-box;
display: flex;
flex-flow: wrap;
flex: 0 0 auto;
-webkit-box-align: start;
align-items: start;
-webkit-box-pack: start;
justify-content: flex-start;
gap: 10px;
}
.#{prefix}-header-details {
flex: 1;
display: flex;
flex-direction: column;
align-items: stretch;
gap: 20px;
flex: 1 1 0%;
}
.#{prefix}-big-title { .#{prefix}-big-title {
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;
} }
.#{prefix}-logo-wrap { .#{prefix}-logo-wrap img {
height: 120px; height: auto;
width: 120px; width: auto;
position: absolute; max-width: 400px;
right: 26px; max-height: 160px;
top: 26px;
overflow: hidden;
} }
.#{prefix}-terms { .#{prefix}-terms {
display: flex; display: flex;
@@ -131,26 +147,35 @@ block head
block content block content
div(class=`${prefix}-root`, style=`--invoice-primary-color: ${primaryColor}; --invoice-secondary-color: ${secondaryColor};`) div(class=`${prefix}-root`, style=`--invoice-primary-color: ${primaryColor}; --invoice-secondary-color: ${secondaryColor};`)
h1(class=`${prefix}-big-title`) Estimate
if showCompanyLogo && companyLogoUri //- Header (invluces big title, details and logo)
div(class=`${prefix}-logo-wrap`) div(class=`${prefix}-header`)
img(alt="Company logo", src=companyLogoUri)
//- Terms List //- Header details (includes big title and details )
div(class=`${prefix}-terms`) div(class=`${prefix}-header-details`)
if showEstimateNumber h1(class=`${prefix}-big-title`) Estimate
div(class=`${prefix}-terms-item`)
div(class=`${prefix}-terms-item__label`) #{estimateNumberLabel} //- Terms List
div(class=`${prefix}-terms-item__value`) #{estimateNumebr} div(class=`${prefix}-terms`)
if showEstimateDate if showEstimateNumber
div(class=`${prefix}-terms-item`) div(class=`${prefix}-terms-item`)
div(class=`${prefix}-terms-item__label`) #{estimateDateLabel} div(class=`${prefix}-terms-item__label`) #{estimateNumberLabel}
div(class=`${prefix}-terms-item__value`) #{estimateDate} div(class=`${prefix}-terms-item__value`) #{estimateNumebr}
if showExpirationDate
div(class=`${prefix}-terms-item`) if showEstimateDate
div(class=`${prefix}-terms-item__label`) #{expirationDateLabel} div(class=`${prefix}-terms-item`)
div(class=`${prefix}-terms-item__value`) #{expirationDate} div(class=`${prefix}-terms-item__label`) #{estimateDateLabel}
div(class=`${prefix}-terms-item__value`) #{estimateDate}
if showExpirationDate
div(class=`${prefix}-terms-item`)
div(class=`${prefix}-terms-item__label`) #{expirationDateLabel}
div(class=`${prefix}-terms-item__value`) #{expirationDate}
//- Company logo
if showCompanyLogo && companyLogoUri
div(class=`${prefix}-logo-wrap`)
img(alt="Company logo", src=companyLogoUri)
//- Addresses (Group section) //- Addresses (Group section)
div(class=`${prefix}-addresses`) div(class=`${prefix}-addresses`)

View File

@@ -10,21 +10,37 @@ block head
position: relative; position: relative;
box-shadow: inset 0 4px 0px 0 var(--invoice-primary-color); box-shadow: inset 0 4px 0px 0 var(--invoice-primary-color);
} }
.#{prefix}-header{
box-sizing: border-box;
display: flex;
flex-flow: wrap;
flex: 0 0 auto;
-webkit-box-align: start;
align-items: start;
-webkit-box-pack: start;
justify-content: flex-start;
gap: 10px;
}
.#{prefix}-header-details{
flex: 1;
display: flex;
flex-direction: column;
align-items: stretch;
gap: 20px;
flex: 1 1 0%;
}
.#{prefix}-big-title { .#{prefix}-big-title {
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;
} }
.#{prefix}-logo-wrap { .#{prefix}-logo-wrap img {
height: 120px; height: auto;
width: 120px; width: auto;
position: absolute; max-width: 400px;
right: 26px; max-height: 160px;
top: 26px;
overflow: hidden;
} }
.#{prefix}-details { .#{prefix}-details {
display: flex; display: flex;
@@ -138,30 +154,35 @@ block head
block content block content
//- block head //- block head
div(class=`${prefix}-root`, style=`--invoice-primary-color: ${primaryColor}; --invoice-secondary-color: ${secondaryColor};`) div(class=`${prefix}-root`, style=`--invoice-primary-color: ${primaryColor}; --invoice-secondary-color: ${secondaryColor};`)
//- Title and company logo
h1(class=`${prefix}-big-title`) Invoice
if showCompanyLogo && companyLogoUri //- Header (includes big title, details and logo )
div(class=`${prefix}-logo-wrap`) div(class=`${prefix}-header`)
img(alt="Company logo", src=companyLogoUri) //- Header details (includes big title and details )
div(class=`${prefix}-header-details`)
//- Title and company logo
h1(class=`${prefix}-big-title`) Invoice
//- Invoice details //- Invoice details
div(class=`${prefix}-details`) div(class=`${prefix}-details`)
if showInvoiceNumber if showInvoiceNumber
div(class=`${prefix}-detail`) div(class=`${prefix}-detail`)
div(class=`${prefix}-detail__label`) #{invoiceNumberLabel} div(class=`${prefix}-detail__label`) #{invoiceNumberLabel}
div(class=`${prefix}-detail__value`) #{invoiceNumber} div(class=`${prefix}-detail__value`) #{invoiceNumber}
if showDateIssue if showDateIssue
div(class=`${prefix}-detail`) div(class=`${prefix}-detail`)
div(class=`${prefix}-detail__label`) #{dateIssueLabel} div(class=`${prefix}-detail__label`) #{dateIssueLabel}
div(class=`${prefix}-detail__value`) #{dateIssue} div(class=`${prefix}-detail__value`) #{dateIssue}
if showDueDate if showDueDate
div(class=`${prefix}-detail`) div(class=`${prefix}-detail`)
div(class=`${prefix}-detail__label`) #{dueDateLabel} div(class=`${prefix}-detail__label`) #{dueDateLabel}
div(class=`${prefix}-detail__value`) #{dueDate} div(class=`${prefix}-detail__value`) #{dueDate}
//- Company logo
if showCompanyLogo && companyLogoUri
div(class=`${prefix}-logo-wrap`)
img(alt="Company logo", src=companyLogoUri)
//- Address section //- Address section
div(class=`${prefix}-address-root`) div(class=`${prefix}-address-root`)

View File

@@ -10,22 +10,38 @@ block head
font-size: 12px; font-size: 12px;
position: relative; position: relative;
box-shadow: inset 0 4px 0px 0 var(--invoice-primary-color); box-shadow: inset 0 4px 0px 0 var(--invoice-primary-color);
}
.#{prefix}-header{
box-sizing: border-box;
display: flex;
flex-flow: wrap;
flex: 0 0 auto;
-webkit-box-align: start;
align-items: start;
-webkit-box-pack: start;
justify-content: flex-start;
gap: 10px;
}
.#{prefix}-header-details{
flex: 1;
display: flex;
flex-direction: column;
align-items: stretch;
gap: 20px;
flex: 1 1 0%;
} }
.#{prefix}-big-title{ .#{prefix}-big-title{
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;
} }
.#{prefix}-logo-wrap{ .#{prefix}-logo-wrap img {
height: 120px; height: auto;
width: 120px; width: auto;
position: absolute; max-width: 400px;
right: 26px; max-height: 160px;
top: 26px;
overflow: hidden;
} }
.#{prefix}-terms-list{ .#{prefix}-terms-list{
display: flex; display: flex;
@@ -120,23 +136,26 @@ block head
} }
block content block content
div(class=`${prefix}-root`) div(class=`${prefix}-root`)
div(class=`${prefix}-big-title`) Payment //- Header (includes big title, details and logo )
div(class=`${prefix}-header`)
//- Header details (includes big title and details )
div(class=`${prefix}-header-details`)
div(class=`${prefix}-big-title`) Payment
div(class=`${prefix}-terms-list`)
if showPaymentReceivedNumber
div(class=`${prefix}-terms-item`)
div(class=`${prefix}-terms-item__label`) #{paymentReceivedNumberLabel}
div(class=`${prefix}-terms-item__value`) #{paymentReceivedNumebr}
if showCompanyLogo && companyLogoUri if showPaymentReceivedDate
div(class=`${prefix}-logo-wrap`) div(class=`${prefix}-terms-item`)
img(src=companyLogoUri alt="Company Logo") div(class=`${prefix}-terms-item__label`) #{paymentReceivedDateLabel}
div(class=`${prefix}-terms-item__value`) #{paymentReceivedDate}
div(class=`${prefix}-terms-list`)
if showPaymentReceivedNumber
div(class=`${prefix}-terms-item`)
div(class=`${prefix}-terms-item__label`) #{paymentReceivedNumberLabel}
div(class=`${prefix}-terms-item__value`) #{paymentReceivedNumebr}
if showPaymentReceivedDate if showCompanyLogo && companyLogoUri
div(class=`${prefix}-terms-item`) div(class=`${prefix}-logo-wrap`)
div(class=`${prefix}-terms-item__label`) #{paymentReceivedDateLabel} img(src=companyLogoUri alt="Company Logo")
div(class=`${prefix}-terms-item__value`) #{paymentReceivedDate}
div(class=`${prefix}-addresses`) div(class=`${prefix}-addresses`)
if showCompanyAddress if showCompanyAddress
div(class=`${prefix}-address-from`) div(class=`${prefix}-address-from`)

View File

@@ -10,19 +10,33 @@ block head
position: relative; position: relative;
box-shadow: inset 0 4px 0px 0 var(--invoice-primary-color); box-shadow: inset 0 4px 0px 0 var(--invoice-primary-color);
} }
.#{prefix}-logo-wrap { .#{prefix}-header{
height: 120px; box-sizing: border-box;
width: 120px; display: flex;
position: absolute; flex-flow: wrap;
right: 26px; flex: 0 0 auto;
top: 26px; align-items: start;
overflow: hidden; justify-content: flex-start;
gap: 10px;
}
.#{prefix}-header-details{
flex: 1;
display: flex;
flex-direction: column;
align-items: stretch;
gap: 20px;
flex: 1 1 0%;
}
.#{prefix}-logo-wrap img {
height: auto;
width: auto;
max-width: 400px;
max-height: 160px;
} }
.#{prefix}-big-title { .#{prefix}-big-title {
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;
} }
@@ -124,25 +138,30 @@ block head
block content block content
//- block head //- block head
div(class=`${prefix}-root`, style=`--invoice-primary-color: ${primaryColor}; --invoice-secondary-color: ${secondaryColor};`) div(class=`${prefix}-root`, style=`--invoice-primary-color: ${primaryColor}; --invoice-secondary-color: ${secondaryColor};`)
//- Title and company logo
h1(class=`${prefix}-big-title`) Receipt
//- Company Logo //- Header (includes big title, details and logo )
if showCompanyLogo && companyLogoUri div(class=`${prefix}-header`)
div(class=`${prefix}-logo-wrap`) //- Header details (includes big title and details )
img(src=companyLogoUri alt=`Company Logo`) div(class=`${prefix}-header-details`)
//- Title and company logo
h1(class=`${prefix}-big-title`) Receipt
//- Terms List //- Terms List
div(class=`${prefix}-terms-list`) div(class=`${prefix}-terms-list`)
if showReceiptNumber if showReceiptNumber
div(class=`${prefix}-terms-item`) div(class=`${prefix}-terms-item`)
span(class=`${prefix}-terms-item__label`)= receiptNumberLabel span(class=`${prefix}-terms-item__label`)= receiptNumberLabel
span(class=`${prefix}-terms-item__value`)= receiptNumber span(class=`${prefix}-terms-item__value`)= receiptNumber
if showReceiptDate
div(class=`${prefix}-terms-item`) if showReceiptDate
span(class=`${prefix}-terms-item__label`)= receiptDateLabel div(class=`${prefix}-terms-item`)
span(class=`${prefix}-terms-item__value`)= receiptDate span(class=`${prefix}-terms-item__label`)= receiptDateLabel
span(class=`${prefix}-terms-item__value`)= receiptDate
//- Company logo
if showCompanyLogo && companyLogoUri
div(class=`${prefix}-logo-wrap`)
img(src=companyLogoUri alt=`Company Logo`)
//- Address Section //- Address Section
div(class=`${prefix}-address-section`) div(class=`${prefix}-address-section`)

View File

@@ -27,6 +27,7 @@ import GetCreditNoteAssociatedAppliedInvoices from '@/services/CreditNotes/GetCr
import GetRefundCreditTransaction from '@/services/CreditNotes/GetRefundCreditNoteTransaction'; import GetRefundCreditTransaction from '@/services/CreditNotes/GetRefundCreditNoteTransaction';
import GetCreditNotePdf from '../../../services/CreditNotes/GetCreditNotePdf'; import GetCreditNotePdf from '../../../services/CreditNotes/GetCreditNotePdf';
import { ACCEPT_TYPE } from '@/interfaces/Http'; import { ACCEPT_TYPE } from '@/interfaces/Http';
import { GetCreditNoteState } from '@/services/CreditNotes/GetCreditNoteState';
/** /**
* Credit notes controller. * Credit notes controller.
* @service * @service
@@ -81,6 +82,9 @@ export default class PaymentReceivesController extends BaseController {
@Inject() @Inject()
creditNotePdf: GetCreditNotePdf; creditNotePdf: GetCreditNotePdf;
@Inject()
getCreditNoteStateService: GetCreditNoteState;
/** /**
* Router constructor. * Router constructor.
*/ */
@@ -105,6 +109,12 @@ export default class PaymentReceivesController extends BaseController {
this.asyncMiddleware(this.newCreditNote), this.asyncMiddleware(this.newCreditNote),
this.handleServiceErrors this.handleServiceErrors
); );
router.get(
'/state',
CheckPolicies(CreditNoteAction.View, AbilitySubject.CreditNote),
this.asyncMiddleware(this.getCreditNoteState.bind(this)),
this.handleServiceErrors
);
// Get specific credit note. // Get specific credit note.
router.get( router.get(
'/:id', '/:id',
@@ -736,6 +746,23 @@ export default class PaymentReceivesController extends BaseController {
} }
}; };
private getCreditNoteState = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { tenantId } = req;
try {
const data = await this.getCreditNoteStateService.getCreditNoteState(
tenantId
);
return res.status(200).send({ data });
} catch (error) {
next(error);
}
};
/** /**
* Handles service errors. * Handles service errors.
* @param {Error} error * @param {Error} error

View File

@@ -95,6 +95,12 @@ export default class PaymentReceivesController extends BaseController {
asyncMiddleware(this.getPaymentReceiveInvoices.bind(this)), asyncMiddleware(this.getPaymentReceiveInvoices.bind(this)),
this.handleServiceErrors this.handleServiceErrors
); );
router.get(
'/state',
CheckPolicies(PaymentReceiveAction.View, AbilitySubject.PaymentReceive),
this.getPaymentReceivedState.bind(this),
this.handleServiceErrors
);
router.get( router.get(
'/:id', '/:id',
CheckPolicies(PaymentReceiveAction.View, AbilitySubject.PaymentReceive), CheckPolicies(PaymentReceiveAction.View, AbilitySubject.PaymentReceive),
@@ -391,6 +397,29 @@ export default class PaymentReceivesController extends BaseController {
} }
} }
/**
*
* @async
* @param {Request} req -
* @param {Response} res -
*/
private async getPaymentReceivedState(
req: Request,
res: Response,
next: NextFunction
) {
const { tenantId } = req;
try {
const data = await this.paymentReceiveApplication.getPaymentReceivedState(
tenantId
);
return res.status(200).send({ data });
} catch (error) {
next(error);
}
}
/** /**
* Retrieve the given payment receive details. * Retrieve the given payment receive details.
* @async * @async

View File

@@ -51,7 +51,7 @@ export default class SalesEstimatesController extends BaseController {
router.post( router.post(
'/:id/approve', '/:id/approve',
CheckPolicies(SaleEstimateAction.Edit, AbilitySubject.SaleEstimate), CheckPolicies(SaleEstimateAction.Edit, AbilitySubject.SaleEstimate),
[this.validateSpecificEstimateSchema], [...this.validateSpecificEstimateSchema],
this.validationResult, this.validationResult,
asyncMiddleware(this.approveSaleEstimate.bind(this)), asyncMiddleware(this.approveSaleEstimate.bind(this)),
this.handleServiceErrors this.handleServiceErrors
@@ -59,7 +59,7 @@ export default class SalesEstimatesController extends BaseController {
router.post( router.post(
'/:id/reject', '/:id/reject',
CheckPolicies(SaleEstimateAction.Edit, AbilitySubject.SaleEstimate), CheckPolicies(SaleEstimateAction.Edit, AbilitySubject.SaleEstimate),
[this.validateSpecificEstimateSchema], [...this.validateSpecificEstimateSchema],
this.validationResult, this.validationResult,
asyncMiddleware(this.rejectSaleEstimate.bind(this)), asyncMiddleware(this.rejectSaleEstimate.bind(this)),
this.handleServiceErrors this.handleServiceErrors
@@ -105,6 +105,12 @@ export default class SalesEstimatesController extends BaseController {
asyncMiddleware(this.deleteEstimate.bind(this)), asyncMiddleware(this.deleteEstimate.bind(this)),
this.handleServiceErrors this.handleServiceErrors
); );
router.get(
'/state',
CheckPolicies(SaleEstimateAction.View, AbilitySubject.SaleEstimate),
this.getSaleEstimateState.bind(this),
this.handleServiceErrors
);
router.get( router.get(
'/:id', '/:id',
CheckPolicies(SaleEstimateAction.View, AbilitySubject.SaleEstimate), CheckPolicies(SaleEstimateAction.View, AbilitySubject.SaleEstimate),
@@ -546,6 +552,23 @@ export default class SalesEstimatesController extends BaseController {
} }
}; };
private getSaleEstimateState = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { tenantId } = req;
try {
const data = await this.saleEstimatesApplication.getSaleEstimateState(
tenantId
);
return res.status(200).send({ data });
} catch (error) {
next(error);
}
};
/** /**
* Handles service errors. * Handles service errors.
* @param {Error} error * @param {Error} error

View File

@@ -130,6 +130,12 @@ export default class SaleInvoicesController extends BaseController {
this.asyncMiddleware(this.getInvoicePaymentTransactions), this.asyncMiddleware(this.getInvoicePaymentTransactions),
this.handleServiceErrors this.handleServiceErrors
); );
router.get(
'/state',
CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice),
asyncMiddleware(this.getSaleInvoiceState.bind(this)),
this.handleServiceErrors
);
router.get( router.get(
'/:id', '/:id',
CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice), CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice),
@@ -138,6 +144,7 @@ export default class SaleInvoicesController extends BaseController {
asyncMiddleware(this.getSaleInvoice.bind(this)), asyncMiddleware(this.getSaleInvoice.bind(this)),
this.handleServiceErrors this.handleServiceErrors
); );
router.get( router.get(
'/', '/',
CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice), CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice),
@@ -453,6 +460,24 @@ export default class SaleInvoicesController extends BaseController {
return res.status(200).send({ saleInvoice }); return res.status(200).send({ saleInvoice });
} }
} }
private async getSaleInvoiceState(
req: Request,
res: Response,
next: NextFunction
) {
const { tenantId } = req;
try {
const data = await this.saleInvoiceApplication.getSaleInvoiceState(
tenantId
);
return res.status(200).send({ data });
} catch (error) {
next(error);
}
}
/** /**
* Retrieve paginated sales invoices with custom view metadata. * Retrieve paginated sales invoices with custom view metadata.
* @param {Request} req * @param {Request} req

View File

@@ -108,6 +108,12 @@ export default class SalesReceiptsController extends BaseController {
this.handleServiceErrors, this.handleServiceErrors,
this.dynamicListService.handlerErrorsToResponse this.dynamicListService.handlerErrorsToResponse
); );
router.get(
'/state',
CheckPolicies(SaleReceiptAction.View, AbilitySubject.SaleReceipt),
asyncMiddleware(this.getSaleReceiptState.bind(this)),
this.handleServiceErrors
);
router.get( router.get(
'/:id', '/:id',
CheckPolicies(SaleReceiptAction.View, AbilitySubject.SaleReceipt), CheckPolicies(SaleReceiptAction.View, AbilitySubject.SaleReceipt),
@@ -369,6 +375,30 @@ export default class SalesReceiptsController extends BaseController {
} }
} }
/**
*
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
public async getSaleReceiptState(
req: Request,
res: Response,
next: NextFunction
) {
const { tenantId } = req;
// Retrieves receipt in pdf format.
try {
const data = await this.saleReceiptsApplication.getSaleReceiptState(
tenantId
);
return res.status(200).send({ data });
} catch (error) {
next(error);
}
}
/** /**
* Sale receipt notification via SMS. * Sale receipt notification via SMS.
* @param {Request} req * @param {Request} req

View File

@@ -22,6 +22,13 @@ export class PublicSharableLinkController extends BaseController {
this.getPaymentLinkPublicMeta.bind(this), this.getPaymentLinkPublicMeta.bind(this),
this.validationResult this.validationResult
); );
router.get(
'/:paymentLinkId/invoice/pdf',
[param('paymentLinkId').exists()],
this.validationResult,
this.getPaymentLinkInvoicePdf.bind(this),
this.validationResult
);
router.post( router.post(
'/:paymentLinkId/stripe_checkout_session', '/:paymentLinkId/stripe_checkout_session',
[param('paymentLinkId').exists()], [param('paymentLinkId').exists()],
@@ -80,4 +87,31 @@ export class PublicSharableLinkController extends BaseController {
next(error); next(error);
} }
} }
/**
* Retrieves the sale invoice pdf of the given payment link.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
public async getPaymentLinkInvoicePdf(
req: Request<{ paymentLinkId: string }>,
res: Response,
next: NextFunction
) {
const { paymentLinkId } = req.params;
try {
const pdfContent = await this.paymentLinkApp.getPaymentLinkInvoicePdf(
paymentLinkId
);
res.set({
'Content-Type': 'application/pdf',
'Content-Length': pdfContent.length,
});
res.send(pdfContent);
} catch (error) {
next(error);
}
}
} }

View File

@@ -314,3 +314,7 @@ export interface CreditNotePdfTemplateAttributes {
showCreditNoteDate: boolean; showCreditNoteDate: boolean;
creditNoteDateLabel: string; creditNoteDateLabel: string;
} }
export interface ICreditNoteState {
defaultTemplateId: number;
}

View File

@@ -238,3 +238,8 @@ export interface PaymentReceivedPdfTemplateAttributes {
showPaymentReceivedDate: boolean; showPaymentReceivedDate: boolean;
paymentReceivedDateLabel: string; paymentReceivedDateLabel: string;
} }
export interface IPaymentReceivedState {
defaultTemplateId: number;
}

View File

@@ -144,3 +144,6 @@ export interface ISaleEstimateMailPresendEvent {
messageOptions: SaleEstimateMailOptionsDTO; messageOptions: SaleEstimateMailOptionsDTO;
} }
export interface ISaleEstimateState {
defaultTemplateId: number;
}

View File

@@ -20,7 +20,7 @@ export interface PaymentIntegrationTransactionLinkEventPayload {
referenceType: string; referenceType: string;
referenceId: number; referenceId: number;
saleInvoiceId: number; saleInvoiceId: number;
trx?: Knex.Transaction trx?: Knex.Transaction;
} }
export interface PaymentIntegrationTransactionLinkDeleteEventPayload { export interface PaymentIntegrationTransactionLinkDeleteEventPayload {
@@ -30,7 +30,7 @@ export interface PaymentIntegrationTransactionLinkDeleteEventPayload {
referenceType: string; referenceType: string;
referenceId: number; referenceId: number;
oldSaleInvoiceId: number; oldSaleInvoiceId: number;
trx?: Knex.Transaction trx?: Knex.Transaction;
} }
export interface ISaleInvoice { export interface ISaleInvoice {
@@ -174,7 +174,7 @@ export interface ISaleInvoiceDeletingPayload {
tenantId: number; tenantId: number;
oldSaleInvoice: ISaleInvoice; oldSaleInvoice: ISaleInvoice;
saleInvoiceId: number; saleInvoiceId: number;
trx: Knex.Transaction; trx: Knex.Transaction;
} }
export interface ISaleInvoiceDeletedPayload { export interface ISaleInvoiceDeletedPayload {
@@ -339,3 +339,7 @@ export interface InvoicePdfTemplateAttributes {
showStatement: boolean; showStatement: boolean;
statement: string; statement: string;
} }
export interface ISaleInvocieState {
defaultTemplateId: number;
}

View File

@@ -211,3 +211,8 @@ export interface ISaleReceiptBrandingTemplateAttributes {
showReceiptDate: boolean; showReceiptDate: boolean;
receiptDateLabel: string; receiptDateLabel: string;
} }
export interface ISaleReceiptState {
defaultTemplateId: number;
}

View File

@@ -29,6 +29,20 @@ export class PdfTemplate extends TenantModel {
}; };
} }
/**
* Model modifiers.
*/
static get modifiers() {
return {
/**
* Filters the due invoices.
*/
default(query) {
query.where('default', true);
},
};
}
/** /**
* Virtual attributes. * Virtual attributes.
*/ */

View File

@@ -0,0 +1,26 @@
import { Inject, Service } from 'typedi';
import { ICreditNoteState } from '@/interfaces';
import HasTenancyService from '../Tenancy/TenancyService';
@Service()
export class GetCreditNoteState {
@Inject()
private tenancy: HasTenancyService;
/**
* Retrieves the create/edit initial state of the payment received.
* @param {Number} saleInvoiceId -
* @return {Promise<ISaleInvoice>}
*/
public async getCreditNoteState(tenantId: number): Promise<ICreditNoteState> {
const { PdfTemplate } = this.tenancy.models(tenantId);
const defaultPdfTemplate = await PdfTemplate.query()
.findOne({ resource: 'CreditNote' })
.modify('default');
return {
defaultTemplateId: defaultPdfTemplate?.id,
};
}
}

View File

@@ -0,0 +1,33 @@
import { Inject, Service } from 'typedi';
import { initalizeTenantServices } from '@/api/middleware/TenantDependencyInjection';
import { SaleInvoicePdf } from '../Sales/Invoices/SaleInvoicePdf';
import { PaymentLink } from '@/system/models';
@Service()
export class GetPaymentLinkInvoicePdf {
@Inject()
private getSaleInvoicePdfService: SaleInvoicePdf;
/**
* Retrieves the sale invoice PDF of the given payment link id.
* @param {number} tenantId
* @param {number} paymentLinkId
* @returns {Promise<Buffer>}
*/
async getPaymentLinkInvoicePdf(paymentLinkId: string): Promise<Buffer> {
const paymentLink = await PaymentLink.query()
.findOne('linkId', paymentLinkId)
.where('resourceType', 'SaleInvoice')
.throwIfNotFound();
const tenantId = paymentLink.tenantId;
await initalizeTenantServices(tenantId);
const saleInvoiceId = paymentLink.resourceId;
return this.getSaleInvoicePdfService.saleInvoicePdf(
tenantId,
saleInvoiceId
);
}
}

View File

@@ -2,6 +2,7 @@ import { Inject, Service } from 'typedi';
import { GetInvoicePaymentLinkMetadata } from './GetInvoicePaymentLinkMetadata'; import { GetInvoicePaymentLinkMetadata } from './GetInvoicePaymentLinkMetadata';
import { CreateInvoiceCheckoutSession } from './CreateInvoiceCheckoutSession'; import { CreateInvoiceCheckoutSession } from './CreateInvoiceCheckoutSession';
import { StripeInvoiceCheckoutSessionPOJO } from '@/interfaces/StripePayment'; import { StripeInvoiceCheckoutSessionPOJO } from '@/interfaces/StripePayment';
import { GetPaymentLinkInvoicePdf } from './GetPaymentLinkInvoicePdf';
@Service() @Service()
export class PaymentLinksApplication { export class PaymentLinksApplication {
@@ -10,6 +11,9 @@ export class PaymentLinksApplication {
@Inject() @Inject()
private createInvoiceCheckoutSessionService: CreateInvoiceCheckoutSession; private createInvoiceCheckoutSessionService: CreateInvoiceCheckoutSession;
@Inject()
private getPaymentLinkInvoicePdfService: GetPaymentLinkInvoicePdf;
/** /**
* Retrieves the invoice payment link. * Retrieves the invoice payment link.
@@ -34,4 +38,16 @@ export class PaymentLinksApplication {
paymentLinkId paymentLinkId
); );
} }
/**
* Retrieves the sale invoice pdf of the given payment link id.
* @param {number} tenantId
* @param {number} paymentLinkId
* @returns {Promise<Buffer> }
*/
public getPaymentLinkInvoicePdf(paymentLinkId: string): Promise<Buffer> {
return this.getPaymentLinkInvoicePdfService.getPaymentLinkInvoicePdf(
paymentLinkId
);
}
} }

View File

@@ -0,0 +1,28 @@
import { Inject, Service } from 'typedi';
import { ISaleEstimateState } from '@/interfaces';
import HasTenancyService from '@/services/Tenancy/TenancyService';
@Service()
export class GetSaleEstimateState {
@Inject()
private tenancy: HasTenancyService;
/**
* Retrieves the create/edit sale estimate state.
* @param {Number} saleEstimateId -
* @return {Promise<ISaleEstimateState>}
*/
public async getSaleEstimateState(
tenantId: number
): Promise<ISaleEstimateState> {
const { PdfTemplate } = this.tenancy.models(tenantId);
const defaultPdfTemplate = await PdfTemplate.query()
.findOne({ resource: 'SaleEstimate' })
.modify('default');
return {
defaultTemplateId: defaultPdfTemplate?.id,
};
}
}

View File

@@ -20,6 +20,7 @@ import { RejectSaleEstimate } from './RejectSaleEstimate';
import { SaleEstimateNotifyBySms } from './SaleEstimateSmsNotify'; import { SaleEstimateNotifyBySms } from './SaleEstimateSmsNotify';
import { SaleEstimatesPdf } from './SaleEstimatesPdf'; import { SaleEstimatesPdf } from './SaleEstimatesPdf';
import { SendSaleEstimateMail } from './SendSaleEstimateMail'; import { SendSaleEstimateMail } from './SendSaleEstimateMail';
import { GetSaleEstimateState } from './GetSaleEstimateState';
@Service() @Service()
export class SaleEstimatesApplication { export class SaleEstimatesApplication {
@@ -56,6 +57,9 @@ export class SaleEstimatesApplication {
@Inject() @Inject()
private sendEstimateMailService: SendSaleEstimateMail; private sendEstimateMailService: SendSaleEstimateMail;
@Inject()
private getSaleEstimateStateService: GetSaleEstimateState;
/** /**
* Create a sale estimate. * Create a sale estimate.
* @param {number} tenantId - The tenant id. * @param {number} tenantId - The tenant id.
@@ -249,4 +253,13 @@ export class SaleEstimatesApplication {
saleEstimateId saleEstimateId
); );
} }
/**
* Retrieves the current state of the sale estimate.
* @param {number} tenantId - The ID of the tenant.
* @returns {Promise<ISaleEstimateState>} - A promise resolving to the sale estimate state.
*/
public getSaleEstimateState(tenantId: number) {
return this.getSaleEstimateStateService.getSaleEstimateState(tenantId);
}
} }

View File

@@ -104,12 +104,24 @@ export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer
); );
} }
protected formattedCustomerAddress(invoice) { get customerAddressFormat() {
return contactAddressTextFormat(invoice.customer, `{ADDRESS_1} return `{ADDRESS_1}
{ADDRESS_2} {ADDRESS_2}
{CITY}, {STATE} {POSTAL_CODE} {CITY} {STATE} {POSTAL_CODE}
{COUNTRY} {COUNTRY}
{PHONE}`); {PHONE}`;
}
/**
* Retrieves the formatted customer address.
* @param invoice
* @returns {string}
*/
protected formattedCustomerAddress(invoice) {
return contactAddressTextFormat(
invoice.customer,
this.customerAddressFormat
);
} }
} }

View File

@@ -0,0 +1,28 @@
import { Inject, Service } from 'typedi';
import { ISaleInvocieState } from '@/interfaces';
import HasTenancyService from '@/services/Tenancy/TenancyService';
@Service()
export class GetSaleInvoiceState {
@Inject()
private tenancy: HasTenancyService;
/**
* Retrieves the create/edit invoice state.
* @param {Number} saleInvoiceId -
* @return {Promise<ISaleInvoice>}
*/
public async getSaleInvoiceState(
tenantId: number
): Promise<ISaleInvocieState> {
const { PdfTemplate } = this.tenancy.models(tenantId);
const defaultPdfTemplate = await PdfTemplate.query()
.findOne({ resource: 'SaleInvoice' })
.modify('default');
return {
defaultTemplateId: defaultPdfTemplate?.id,
};
}
}

View File

@@ -28,6 +28,7 @@ import { SaleInvoiceNotifyBySms } from './SaleInvoiceNotifyBySms';
import { SendInvoiceMailReminder } from './SendSaleInvoiceMailReminder'; import { SendInvoiceMailReminder } from './SendSaleInvoiceMailReminder';
import { SendSaleInvoiceMail } from './SendSaleInvoiceMail'; import { SendSaleInvoiceMail } from './SendSaleInvoiceMail';
import { GetSaleInvoiceMailReminder } from './GetSaleInvoiceMailReminder'; import { GetSaleInvoiceMailReminder } from './GetSaleInvoiceMailReminder';
import { GetSaleInvoiceState } from './GetSaleInvoiceState';
@Service() @Service()
export class SaleInvoiceApplication { export class SaleInvoiceApplication {
@@ -73,6 +74,9 @@ export class SaleInvoiceApplication {
@Inject() @Inject()
private getSaleInvoiceReminderService: GetSaleInvoiceMailReminder; private getSaleInvoiceReminderService: GetSaleInvoiceMailReminder;
@Inject()
private getSaleInvoiceStateService: GetSaleInvoiceState;
/** /**
* Creates a new sale invoice with associated GL entries. * Creates a new sale invoice with associated GL entries.
* @param {number} tenantId * @param {number} tenantId
@@ -169,6 +173,16 @@ export class SaleInvoiceApplication {
); );
} }
/**
* Retrieves the sale invoice state.
* @param {number} tenantId
* @param {number} saleInvoiceId
* @returns
*/
public getSaleInvoiceState(tenantId: number) {
return this.getSaleInvoiceStateService.getSaleInvoiceState(tenantId);
}
/** /**
* Mark the given sale invoice as delivered. * Mark the given sale invoice as delivered.
* @param {number} tenantId * @param {number} tenantId

View File

@@ -0,0 +1,28 @@
import { Inject, Service } from 'typedi';
import { IPaymentReceivedState } from '@/interfaces';
import HasTenancyService from '@/services/Tenancy/TenancyService';
@Service()
export class GetPaymentReceivedState {
@Inject()
private tenancy: HasTenancyService;
/**
* Retrieves the create/edit initial state of the payment received.
* @param {number} tenantId - The ID of the tenant.
* @returns {Promise<IPaymentReceivedState>} - A promise resolving to the payment received state.
*/
public async getPaymentReceivedState(
tenantId: number
): Promise<IPaymentReceivedState> {
const { PdfTemplate } = this.tenancy.models(tenantId);
const defaultPdfTemplate = await PdfTemplate.query()
.findOne({ resource: 'PaymentReceive' })
.modify('default');
return {
defaultTemplateId: defaultPdfTemplate?.id,
};
}
}

View File

@@ -19,6 +19,7 @@ import { GetPaymentReceivedInvoices } from './GetPaymentReceivedInvoices';
import { PaymentReceiveNotifyBySms } from './PaymentReceivedSmsNotify'; import { PaymentReceiveNotifyBySms } from './PaymentReceivedSmsNotify';
import GetPaymentReceivedPdf from './GetPaymentReceivedPdf'; import GetPaymentReceivedPdf from './GetPaymentReceivedPdf';
import { SendPaymentReceiveMailNotification } from './PaymentReceivedMailNotification'; import { SendPaymentReceiveMailNotification } from './PaymentReceivedMailNotification';
import { GetPaymentReceivedState } from './GetPaymentReceivedState';
@Service() @Service()
export class PaymentReceivesApplication { export class PaymentReceivesApplication {
@@ -49,6 +50,9 @@ export class PaymentReceivesApplication {
@Inject() @Inject()
private getPaymentReceivePdfService: GetPaymentReceivedPdf; private getPaymentReceivePdfService: GetPaymentReceivedPdf;
@Inject()
private getPaymentReceivedStateService: GetPaymentReceivedState;
/** /**
* Creates a new payment receive. * Creates a new payment receive.
* @param {number} tenantId * @param {number} tenantId
@@ -223,4 +227,15 @@ export class PaymentReceivesApplication {
paymentReceiveId paymentReceiveId
); );
}; };
/**
* Retrieves the create/edit initial state of the payment received.
* @param {number} tenantId - The ID of the tenant.
* @returns {Promise<IPaymentReceivedState>}
*/
public getPaymentReceivedState = (tenantId: number) => {
return this.getPaymentReceivedStateService.getPaymentReceivedState(
tenantId
);
};
} }

View File

@@ -0,0 +1,28 @@
import { Inject, Service } from 'typedi';
import { ISaleReceiptState } from '@/interfaces';
import HasTenancyService from '@/services/Tenancy/TenancyService';
@Service()
export class GetSaleReceiptState {
@Inject()
private tenancy: HasTenancyService;
/**
* Retireves the sale receipt state.
* @param {Number} tenantId -
* @return {Promise<ISaleReceiptState>}
*/
public async getSaleReceiptState(
tenantId: number
): Promise<ISaleReceiptState> {
const { PdfTemplate } = this.tenancy.models(tenantId);
const defaultPdfTemplate = await PdfTemplate.query()
.findOne({ resource: 'SaleReceipt' })
.modify('default');
return {
defaultTemplateId: defaultPdfTemplate?.id,
};
}
}

View File

@@ -4,6 +4,7 @@ import {
IFilterMeta, IFilterMeta,
IPaginationMeta, IPaginationMeta,
ISaleReceipt, ISaleReceipt,
ISaleReceiptState,
ISalesReceiptsFilter, ISalesReceiptsFilter,
SaleReceiptMailOpts, SaleReceiptMailOpts,
SaleReceiptMailOptsDTO, SaleReceiptMailOptsDTO,
@@ -16,6 +17,7 @@ import { CloseSaleReceipt } from './CloseSaleReceipt';
import { SaleReceiptsPdf } from './SaleReceiptsPdfService'; import { SaleReceiptsPdf } from './SaleReceiptsPdfService';
import { SaleReceiptNotifyBySms } from './SaleReceiptNotifyBySms'; import { SaleReceiptNotifyBySms } from './SaleReceiptNotifyBySms';
import { SaleReceiptMailNotification } from './SaleReceiptMailNotification'; import { SaleReceiptMailNotification } from './SaleReceiptMailNotification';
import { GetSaleReceiptState } from './GetSaleReceiptState';
@Service() @Service()
export class SaleReceiptApplication { export class SaleReceiptApplication {
@@ -46,6 +48,9 @@ export class SaleReceiptApplication {
@Inject() @Inject()
private saleReceiptNotifyByMailService: SaleReceiptMailNotification; private saleReceiptNotifyByMailService: SaleReceiptMailNotification;
@Inject()
private getSaleReceiptStateService: GetSaleReceiptState;
/** /**
* Creates a new sale receipt with associated entries. * Creates a new sale receipt with associated entries.
* @param {number} tenantId * @param {number} tenantId
@@ -207,4 +212,13 @@ export class SaleReceiptApplication {
saleReceiptId saleReceiptId
); );
} }
/**
* Retrieves the current state of the sale receipt.
* @param {number} tenantId - The ID of the tenant.
* @returns {Promise<ISaleReceiptState>} - A promise resolving to the sale receipt state.
*/
public getSaleReceiptState(tenantId: number): Promise<ISaleReceiptState> {
return this.getSaleReceiptStateService.getSaleReceiptState(tenantId);
}
} }

View File

@@ -1,5 +1,9 @@
import { organizationAddressTextFormat } from '@/utils/address-text-format'; import {
defaultOrganizationAddressFormat,
organizationAddressTextFormat,
} from '@/utils/address-text-format';
import BaseModel from 'models/Model'; import BaseModel from 'models/Model';
import { findByIsoCountryCode } from '@bigcapital/utils';
import { getUploadedObjectUri } from '../../services/Attachments/utils'; import { getUploadedObjectUri } from '../../services/Attachments/utils';
export default class TenantMetadata extends BaseModel { export default class TenantMetadata extends BaseModel {
@@ -67,14 +71,9 @@ export default class TenantMetadata extends BaseModel {
* @returns {string} * @returns {string}
*/ */
public get addressTextFormatted() { public get addressTextFormatted() {
const defaultMessage = `<strong>{ORGANIZATION_NAME}</strong> const addressCountry = findByIsoCountryCode(this.location);
{ADDRESS_1}
{ADDRESS_2} return organizationAddressTextFormat(defaultOrganizationAddressFormat, {
{CITY}, {STATE} {POSTAL_CODE}
{COUNTRY}
{PHONE}
`;
return organizationAddressTextFormat(defaultMessage, {
organizationName: this.name, organizationName: this.name,
address1: this.address?.address1, address1: this.address?.address1,
address2: this.address?.address2, address2: this.address?.address2,
@@ -82,7 +81,7 @@ export default class TenantMetadata extends BaseModel {
city: this.address?.city, city: this.address?.city,
postalCode: this.address?.postalCode, postalCode: this.address?.postalCode,
phone: this.address?.phone, phone: this.address?.phone,
country: 'United State', country: addressCountry?.name ?? '',
}); });
} }
} }

View File

@@ -11,13 +11,13 @@ interface OrganizationAddressFormatArgs {
phone?: string; phone?: string;
} }
const defaultMessage = ` export const defaultOrganizationAddressFormat = `
<strong>{ORGANIZATION_NAME}</strong> <strong>{ORGANIZATION_NAME}</strong>
{ADDRESS_1} {ADDRESS_1}
{ADDRESS_2} {ADDRESS_2}
{CITY}, {STATE} {POSTAL_CODE} {CITY} {STATE} {POSTAL_CODE}
{COUNTRY} {COUNTRY}
{PHONE} {PHONE}
`; `;
/** /**
* Formats the address text based on the provided message and arguments. * Formats the address text based on the provided message and arguments.
@@ -36,7 +36,9 @@ const formatText = (message: string, replacements: Record<string, string>) => {
}, },
message message
); );
formattedMessage = formattedMessage.replace(/\n{2,}/g, '\n').trim(); // Removes any empty lines.
formattedMessage = formattedMessage.replace(/^\s*[\r\n]/gm, '');
formattedMessage = formattedMessage.replace(/\n{2,}/g, '\n');
formattedMessage = formattedMessage.replace(/\n/g, '<br />'); formattedMessage = formattedMessage.replace(/\n/g, '<br />');
formattedMessage = formattedMessage.trim(); formattedMessage = formattedMessage.trim();
@@ -72,17 +74,17 @@ interface ContactAddressTextFormatArgs {
phone?: string; phone?: string;
} }
const contactFormatMessage = `{CONTACT_NAME} export const defaultContactAddressFormat = `{CONTACT_NAME}
{ADDRESS_1} {ADDRESS_1}
{ADDRESS_2} {ADDRESS_2}
{CITY}, {STATE} {POSTAL_CODE} {CITY} {STATE} {POSTAL_CODE}
{COUNTRY} {COUNTRY}
{PHONE} {PHONE}
`; `;
export const contactAddressTextFormat = ( export const contactAddressTextFormat = (
contact: IContact, contact: IContact,
message: string = contactFormatMessage message: string = defaultContactAddressFormat
) => { ) => {
const args = { const args = {
displayName: contact.displayName, displayName: contact.displayName,

View File

@@ -5,11 +5,7 @@ USER root
WORKDIR /app WORKDIR /app
# Copy application dependency manifests to the container image. # Copy application dependency manifests to the container image.
COPY ./package*.json ./ COPY . .
COPY ./pnpm-lock.yaml ./pnpm-lock.yaml
COPY ./lerna.json ./lerna.json
COPY ./pnpm-workspace.yaml ./pnpm-workspace.yaml
COPY ./packages/webapp/package*.json ./packages/webapp/
# Install application dependencies # Install application dependencies
RUN apk update RUN apk update
@@ -23,7 +19,6 @@ RUN npm install -g pnpm
RUN pnpm install RUN pnpm install
# Build webapp package # Build webapp package
COPY ./packages/webapp /app/packages/webapp
RUN pnpm run build:webapp RUN pnpm run build:webapp
FROM nginx FROM nginx

View File

@@ -3,6 +3,7 @@
"version": "0.10.2", "version": "0.10.2",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@bigcapital/utils": "*",
"@blueprintjs-formik/core": "^0.3.6", "@blueprintjs-formik/core": "^0.3.6",
"@blueprintjs-formik/datetime": "^0.3.7", "@blueprintjs-formik/datetime": "^0.3.7",
"@blueprintjs-formik/select": "^0.3.5", "@blueprintjs-formik/select": "^0.3.5",

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,10 +1,14 @@
import { Text, Classes, Button, Intent, Tag } from '@blueprintjs/core'; import { Text, Classes, Button, Intent } from '@blueprintjs/core';
import clsx from 'classnames'; import clsx from 'classnames';
import { AppToaster, Box, Group, Stack } from '@/components'; import { AppToaster, Box, Group, Stack } from '@/components';
import { usePaymentPortalBoot } from './PaymentPortalBoot'; import { usePaymentPortalBoot } from './PaymentPortalBoot';
import { useDrawerActions } from '@/hooks/state'; import { useDrawerActions } from '@/hooks/state';
import { useCreateStripeCheckoutSession } from '@/hooks/query/payment-link'; import {
useCreateStripeCheckoutSession,
useGeneratePaymentLinkInvoicePdf,
} from '@/hooks/query/payment-link';
import { DRAWERS } from '@/constants/drawers'; import { DRAWERS } from '@/constants/drawers';
import { downloadFile } from '@/hooks/useDownloadFile';
import styles from './PaymentPortal.module.scss'; import styles from './PaymentPortal.module.scss';
export function PaymentPortal() { export function PaymentPortal() {
@@ -15,10 +19,34 @@ export function PaymentPortal() {
isLoading: isStripeCheckoutLoading, isLoading: isStripeCheckoutLoading,
} = useCreateStripeCheckoutSession(); } = useCreateStripeCheckoutSession();
const {
mutateAsync: generatePaymentLinkInvoice,
isLoading: isInvoiceGenerating,
} = useGeneratePaymentLinkInvoicePdf();
// Handles invoice preview button click. // Handles invoice preview button click.
const handleInvoicePreviewBtnClick = () => { const handleInvoicePreviewBtnClick = () => {
openDrawer(DRAWERS.PAYMENT_INVOICE_PREVIEW); openDrawer(DRAWERS.PAYMENT_INVOICE_PREVIEW);
}; };
// Handles invoice download button click.
const handleInvoiceDownloadBtnClick = () => {
generatePaymentLinkInvoice({ paymentLinkId: linkId })
.then((data) => {
downloadFile(
data,
`Invoice ${sharableLinkMeta?.invoiceNo}`,
'application/pdf',
);
})
.catch(() => {
AppToaster.show({
intent: Intent.DANGER,
message: 'Something went wrong.',
});
});
};
// handles the pay button click. // handles the pay button click.
const handlePayButtonClick = () => { const handlePayButtonClick = () => {
createStripeCheckoutSession({ linkId }) createStripeCheckoutSession({ linkId })
@@ -125,6 +153,8 @@ export function PaymentPortal() {
<Button <Button
minimal minimal
className={clsx(styles.footerButton, styles.downloadInvoiceButton)} className={clsx(styles.footerButton, styles.downloadInvoiceButton)}
onClick={handleInvoiceDownloadBtnClick}
loading={isInvoiceGenerating}
> >
Download Invoice Download Invoice
</Button> </Button>

View File

@@ -7,6 +7,7 @@ import { Button, FormGroup, Intent } from '@blueprintjs/core';
import { TimezonePicker } from '@blueprintjs/timezone'; import { TimezonePicker } from '@blueprintjs/timezone';
import { ErrorMessage, FastField } from 'formik'; import { ErrorMessage, FastField } from 'formik';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { getAllCountries } from '@bigcapital/utils';
import { import {
FieldRequiredHint, FieldRequiredHint,
@@ -23,7 +24,6 @@ import { getAllCurrenciesOptions } from '@/constants/currencies';
import { getFiscalYear } from '@/constants/fiscalYearOptions'; import { getFiscalYear } from '@/constants/fiscalYearOptions';
import { getLanguages } from '@/constants/languagesOptions'; import { getLanguages } from '@/constants/languagesOptions';
import { useGeneralFormContext } from './GeneralFormProvider'; import { useGeneralFormContext } from './GeneralFormProvider';
import { getAllCountries } from '@/utils/countries';
import { shouldBaseCurrencyUpdate } from './utils'; import { shouldBaseCurrencyUpdate } from './utils';

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

@@ -62,12 +62,12 @@ export const fieldsGroups = [
label: 'Credit Note #', label: 'Credit Note #',
}, },
{ {
enableKey: 'showBilledToAddress', enableKey: 'showCustomerAddress',
labelKey: 'billedToLabel', labelKey: 'billedToLabel',
label: 'Bill To', label: 'Bill To',
}, },
{ {
enableKey: 'showBilledFromAddress', enableKey: 'showCompanyAddress',
label: 'Billed From', label: 'Billed From',
}, },
], ],

View File

@@ -67,6 +67,7 @@ function CreditNoteForm({
newCreditNote, newCreditNote,
createCreditNoteMutate, createCreditNoteMutate,
editCreditNoteMutate, editCreditNoteMutate,
creditNoteState,
} = useCreditNoteFormContext(); } = useCreditNoteFormContext();
// Credit number. // Credit number.
@@ -85,6 +86,7 @@ function CreditNoteForm({
currency_code: base_currency, currency_code: base_currency,
terms_conditions: defaultTo(creditTermsConditions, ''), terms_conditions: defaultTo(creditTermsConditions, ''),
note: defaultTo(creditCustomerNotes, ''), note: defaultTo(creditCustomerNotes, ''),
pdf_template_id: creditNoteState?.defaultTemplateId,
...newCreditNote, ...newCreditNote,
}), }),
}; };

View File

@@ -17,10 +17,19 @@ import {
useBranches, useBranches,
useSettingsCreditNotes, useSettingsCreditNotes,
useInvoice, useInvoice,
useGetCreditNoteState,
CreditNoteStateResponse,
} from '@/hooks/query'; } from '@/hooks/query';
import { useGetPdfTemplates } from '@/hooks/query/pdf-templates'; import { useGetPdfTemplates } from '@/hooks/query/pdf-templates';
const CreditNoteFormContext = React.createContext(); interface CreditNoteFormProviderValue {
creditNoteState: CreditNoteStateResponse;
isCreditNoteStateLoading: boolean;
}
const CreditNoteFormContext = React.createContext<CreditNoteFormProviderValue>(
{} as CreditNoteFormProviderValue,
);
/** /**
* Credit note data provider. * Credit note data provider.
@@ -76,7 +85,11 @@ function CreditNoteFormProvider({ creditNoteId, ...props }) {
// Fetches branding templates of invoice. // Fetches branding templates of invoice.
const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } = const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } =
useGetPdfTemplates({ resource: 'PaymentReceive' }); useGetPdfTemplates({ resource: 'CreditNote' });
// Fetches the credit note state.
const { data: creditNoteState, isLoading: isCreditNoteStateLoading } =
useGetCreditNoteState();
// Handle fetching settings. // Handle fetching settings.
useSettingsCreditNotes(); useSettingsCreditNotes();
@@ -124,6 +137,10 @@ function CreditNoteFormProvider({ creditNoteId, ...props }) {
// Branding templates. // Branding templates.
brandingTemplates, brandingTemplates,
isBrandingTemplatesLoading, isBrandingTemplatesLoading,
// Credit note state
creditNoteState,
isCreditNoteStateLoading,
}; };
const isLoading = const isLoading =
@@ -140,6 +157,7 @@ function CreditNoteFormProvider({ creditNoteId, ...props }) {
); );
} }
const useCreditNoteFormContext = () => React.useContext(CreditNoteFormContext); const useCreditNoteFormContext = () =>
React.useContext<CreditNoteFormProviderValue>(CreditNoteFormContext);
export { CreditNoteFormProvider, useCreditNoteFormContext }; export { CreditNoteFormProvider, useCreditNoteFormContext };

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

@@ -25,7 +25,7 @@ export const initialValues = {
// Customer address // Customer address
showCustomerAddress: true, showCustomerAddress: true,
// Company address // Company address
showCompanyAddress: true, showCompanyAddress: true,
companyAddress: '', companyAddress: '',
@@ -73,12 +73,12 @@ export const fieldsGroups = [
label: 'Expiration Date', label: 'Expiration Date',
}, },
{ {
enableKey: 'showBilledToAddress', enableKey: 'showCustomerAddress',
labelKey: 'billedToLabel', labelKey: 'billedToLabel',
label: 'Bill To', label: 'Bill To',
}, },
{ {
enableKey: 'showBilledFromAddress', enableKey: 'showCompanyAddress',
label: 'Billed From', label: 'Billed From',
}, },
], ],

View File

@@ -58,6 +58,7 @@ function EstimateForm({
submitPayload, submitPayload,
createEstimateMutate, createEstimateMutate,
editEstimateMutate, editEstimateMutate,
saleEstimateState,
} = useEstimateFormContext(); } = useEstimateFormContext();
const estimateNumber = transactionNumber( const estimateNumber = transactionNumber(
@@ -79,6 +80,7 @@ function EstimateForm({
currency_code: base_currency, currency_code: base_currency,
terms_conditions: defaultTo(estimateTermsConditions, ''), terms_conditions: defaultTo(estimateTermsConditions, ''),
note: defaultTo(estimateCustomerNotes, ''), note: defaultTo(estimateCustomerNotes, ''),
pdf_template_id: saleEstimateState?.defaultTemplateId,
}), }),
}; };

View File

@@ -11,6 +11,8 @@ import {
useSettingsEstimates, useSettingsEstimates,
useCreateEstimate, useCreateEstimate,
useEditEstimate, useEditEstimate,
useGetSaleEstimatesState,
ISaleEstimatesStateResponse,
} from '@/hooks/query'; } from '@/hooks/query';
import { useProjects } from '@/containers/Projects/hooks'; import { useProjects } from '@/containers/Projects/hooks';
import { useGetPdfTemplates } from '@/hooks/query/pdf-templates'; import { useGetPdfTemplates } from '@/hooks/query/pdf-templates';
@@ -18,7 +20,12 @@ import { Features } from '@/constants';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
import { ITEMS_FILTER_ROLES } from './utils'; import { ITEMS_FILTER_ROLES } from './utils';
const EstimateFormContext = createContext(); interface EstimateFormProviderValues {
saleEstimateState: ISaleEstimatesStateResponse;
isSaleEstimateStateLoading: boolean;
}
const EstimateFormContext = createContext({} as EstimateFormProviderValues);
/** /**
* Estimate form provider. * Estimate form provider.
@@ -76,6 +83,10 @@ function EstimateFormProvider({ query, estimateId, ...props }) {
const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } = const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } =
useGetPdfTemplates({ resource: 'SaleEstimate' }); useGetPdfTemplates({ resource: 'SaleEstimate' });
// Fetches the sale estimate state.
const { data: saleEstimateState, isLoading: isSaleEstimateStateLoading } =
useGetSaleEstimatesState();
// Handle fetch settings. // Handle fetch settings.
useSettingsEstimates(); useSettingsEstimates();
@@ -118,15 +129,21 @@ function EstimateFormProvider({ query, estimateId, ...props }) {
createEstimateMutate, createEstimateMutate,
editEstimateMutate, editEstimateMutate,
// Branding templates
brandingTemplates, brandingTemplates,
isBrandingTemplatesLoading, isBrandingTemplatesLoading,
// Estimate state
saleEstimateState,
isSaleEstimateStateLoading,
}; };
const isLoading = const isLoading =
isCustomersLoading || isCustomersLoading ||
isItemsLoading || isItemsLoading ||
isEstimateLoading || isEstimateLoading ||
isBrandingTemplatesLoading; isBrandingTemplatesLoading ||
isSaleEstimateStateLoading;
return ( return (
<DashboardInsider loading={isLoading} name={'estimate-form'}> <DashboardInsider loading={isLoading} name={'estimate-form'}>
@@ -135,6 +152,7 @@ function EstimateFormProvider({ query, estimateId, ...props }) {
); );
} }
const useEstimateFormContext = () => useContext(EstimateFormContext); const useEstimateFormContext = () =>
useContext<EstimateFormProviderValues>(EstimateFormContext);
export { EstimateFormProvider, useEstimateFormContext }; export { EstimateFormProvider, useEstimateFormContext };

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

@@ -83,12 +83,12 @@ export const fieldsGroups = [
label: 'Due Date', label: 'Due Date',
}, },
{ {
enableKey: 'showBillingToAddress', enableKey: 'showCustomerAddress',
labelKey: 'billedToLabel', labelKey: 'billedToLabel',
label: 'Bill To', label: 'Bill To',
}, },
{ {
enableKey: 'showBilledFromAddress', enableKey: 'showCompanyAddress',
label: 'Billed From', label: 'Billed From',
}, },
], ],

View File

@@ -61,6 +61,7 @@ function InvoiceForm({
createInvoiceMutate, createInvoiceMutate,
editInvoiceMutate, editInvoiceMutate,
submitPayload, submitPayload,
saleInvoiceState
} = useInvoiceFormContext(); } = useInvoiceFormContext();
// Invoice number. // Invoice number.
@@ -83,6 +84,7 @@ function InvoiceForm({
currency_code: base_currency, currency_code: base_currency,
invoice_message: defaultTo(invoiceCustomerNotes, ''), invoice_message: defaultTo(invoiceCustomerNotes, ''),
terms_conditions: defaultTo(invoiceTermsConditions, ''), terms_conditions: defaultTo(invoiceTermsConditions, ''),
pdf_template_id: saleInvoiceState?.defaultTemplateId,
...newInvoice, ...newInvoice,
}), }),
}; };

View File

@@ -16,13 +16,22 @@ import {
useEditInvoice, useEditInvoice,
useSettingsInvoices, useSettingsInvoices,
useEstimate, useEstimate,
useGetSaleInvoiceState,
GetSaleInvoiceStateResponse,
} from '@/hooks/query'; } from '@/hooks/query';
import { useProjects } from '@/containers/Projects/hooks'; import { useProjects } from '@/containers/Projects/hooks';
import { useTaxRates } from '@/hooks/query/taxRates'; import { useTaxRates } from '@/hooks/query/taxRates';
import { useGetPdfTemplates } from '@/hooks/query/pdf-templates'; import { useGetPdfTemplates } from '@/hooks/query/pdf-templates';
import { useGetPaymentServices } from '@/hooks/query/payment-services'; import { useGetPaymentServices } from '@/hooks/query/payment-services';
const InvoiceFormContext = createContext(); interface InvoiceFormContextValue {
saleInvoiceState: GetSaleInvoiceStateResponse | null;
isInvoiceStateLoading: boolean;
}
const InvoiceFormContext = createContext<InvoiceFormContextValue>(
{} as InvoiceFormContextValue,
);
/** /**
* Accounts chart data provider. * Accounts chart data provider.
@@ -100,6 +109,9 @@ function InvoiceFormProvider({ invoiceId, baseCurrency, ...props }) {
isSuccess: isBranchesSuccess, isSuccess: isBranchesSuccess,
} = useBranches({}, { enabled: isBranchFeatureCan }); } = useBranches({}, { enabled: isBranchFeatureCan });
const { data: saleInvoiceState, isLoading: isInvoiceStateLoading } =
useGetSaleInvoiceState();
// Handle fetching settings. // Handle fetching settings.
const { isLoading: isSettingsLoading } = useSettingsInvoices(); const { isLoading: isSettingsLoading } = useSettingsInvoices();
@@ -154,24 +166,28 @@ function InvoiceFormProvider({ invoiceId, baseCurrency, ...props }) {
// Payment Services // Payment Services
paymentServices, paymentServices,
isPaymentServicesLoading, isPaymentServicesLoading,
// Invoice state
saleInvoiceState,
isInvoiceStateLoading,
}; };
const isLoading =
isInvoiceLoading ||
isItemsLoading ||
isCustomersLoading ||
isEstimateLoading ||
isSettingsLoading ||
isInvoiceStateLoading;
return ( return (
<DashboardInsider <DashboardInsider loading={isLoading} name={'invoice-form'}>
loading={
isInvoiceLoading ||
isItemsLoading ||
isCustomersLoading ||
isEstimateLoading ||
isSettingsLoading
}
name={'invoice-form'}
>
<InvoiceFormContext.Provider value={provider} {...props} /> <InvoiceFormContext.Provider value={provider} {...props} />
</DashboardInsider> </DashboardInsider>
); );
} }
const useInvoiceFormContext = () => React.useContext(InvoiceFormContext); const useInvoiceFormContext = () =>
React.useContext<InvoiceFormContextValue>(InvoiceFormContext);
export { InvoiceFormProvider, useInvoiceFormContext }; export { InvoiceFormProvider, useInvoiceFormContext };

View File

@@ -69,6 +69,7 @@ function PaymentReceiveForm({
editPaymentReceiveMutate, editPaymentReceiveMutate,
createPaymentReceiveMutate, createPaymentReceiveMutate,
isExcessConfirmed, isExcessConfirmed,
paymentReceivedState,
} = usePaymentReceiveFormContext(); } = usePaymentReceiveFormContext();
// Payment receive number. // Payment receive number.
@@ -77,29 +78,21 @@ function PaymentReceiveForm({
paymentReceiveNextNumber, paymentReceiveNextNumber,
); );
// Form initial values. // Form initial values.
const initialValues = useMemo( const initialValues = {
() => ({ ...(!isEmpty(paymentReceiveEditPage)
...(!isEmpty(paymentReceiveEditPage) ? transformToEditForm(paymentReceiveEditPage, paymentEntriesEditPage)
? transformToEditForm(paymentReceiveEditPage, paymentEntriesEditPage) : {
: { ...defaultPaymentReceive,
...defaultPaymentReceive, // If the auto-increment mode is enabled, take the next payment
// If the auto-increment mode is enabled, take the next payment // number from the settings.
// number from the settings. ...(paymentReceiveAutoIncrement && {
...(paymentReceiveAutoIncrement && { payment_receive_no: nextPaymentNumber,
payment_receive_no: nextPaymentNumber,
}),
deposit_account_id: defaultTo(preferredDepositAccount, ''),
currency_code: base_currency,
}), }),
}), deposit_account_id: defaultTo(preferredDepositAccount, ''),
[ currency_code: base_currency,
paymentReceiveEditPage, pdf_template_id: paymentReceivedState?.defaultTemplateId,
nextPaymentNumber, }),
paymentEntriesEditPage, };
paymentReceiveAutoIncrement,
preferredDepositAccount,
],
);
// Handle form submit. // Handle form submit.
const handleSubmitForm = ( const handleSubmitForm = (
values, values,

View File

@@ -12,11 +12,21 @@ import {
useBranches, useBranches,
useCreatePaymentReceive, useCreatePaymentReceive,
useEditPaymentReceive, useEditPaymentReceive,
usePaymentReceivedState,
PaymentReceivedStateResponse,
} from '@/hooks/query'; } from '@/hooks/query';
import { useGetPdfTemplates } from '@/hooks/query/pdf-templates'; import { useGetPdfTemplates } from '@/hooks/query/pdf-templates';
interface PaymentReceivedFormContextValue {
isPaymentReceivedStateLoading: boolean;
paymentReceivedState: PaymentReceivedStateResponse;
}
// Payment receive form context. // Payment receive form context.
const PaymentReceiveFormContext = createContext(); const PaymentReceiveFormContext =
createContext<PaymentReceivedFormContextValue>(
{} as PaymentReceivedFormContextValue,
);
/** /**
* Payment receive form provider. * Payment receive form provider.
@@ -70,6 +80,12 @@ function PaymentReceiveFormProvider({ query, paymentReceiveId, ...props }) {
const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } = const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } =
useGetPdfTemplates({ resource: 'PaymentReceive' }); useGetPdfTemplates({ resource: 'PaymentReceive' });
// Fetches the payment received initial state.
const {
data: paymentReceivedState,
isLoading: isPaymentReceivedStateLoading,
} = usePaymentReceivedState();
// Detarmines whether the new mode. // Detarmines whether the new mode.
const isNewMode = !paymentReceiveId; const isNewMode = !paymentReceiveId;
@@ -111,13 +127,18 @@ function PaymentReceiveFormProvider({ query, paymentReceiveId, ...props }) {
// Branding templates // Branding templates
brandingTemplates, brandingTemplates,
isBrandingTemplatesLoading, isBrandingTemplatesLoading,
// Payment received state
isPaymentReceivedStateLoading,
paymentReceivedState,
}; };
const isLoading = const isLoading =
isPaymentLoading || isPaymentLoading ||
isAccountsLoading || isAccountsLoading ||
isCustomersLoading || isCustomersLoading ||
isBrandingTemplatesLoading; isBrandingTemplatesLoading ||
isPaymentReceivedStateLoading;
return ( return (
<DashboardInsider loading={isLoading} name={'payment-receive-form'}> <DashboardInsider loading={isLoading} name={'payment-receive-form'}>
@@ -127,6 +148,6 @@ function PaymentReceiveFormProvider({ query, paymentReceiveId, ...props }) {
} }
const usePaymentReceiveFormContext = () => const usePaymentReceiveFormContext = () =>
useContext(PaymentReceiveFormContext); useContext<PaymentReceivedFormContextValue>(PaymentReceiveFormContext);
export { PaymentReceiveFormProvider, usePaymentReceiveFormContext }; export { PaymentReceiveFormProvider, usePaymentReceiveFormContext };

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

@@ -59,12 +59,12 @@ export const fieldsGroups = [
label: 'Payment Date', label: 'Payment Date',
}, },
{ {
enableKey: 'showBillingToAddress', enableKey: 'showCustomerAddress',
labelKey: 'billedToLabel', labelKey: 'billedToLabel',
label: 'Bill To', label: 'Bill To',
}, },
{ {
enableKey: 'showBilledFromAddress', enableKey: 'showCompanyAddress',
label: 'Billed From', label: 'Billed From',
}, },
], ],

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 && (

View File

@@ -21,7 +21,7 @@ export const initialValues = {
// Company name // Company name
companyName: 'Bigcapital Technology, Inc.', companyName: 'Bigcapital Technology, Inc.',
// Customer address // Customer address
showCustomerAddress: true, showCustomerAddress: true,
// Company address // Company address
@@ -67,12 +67,12 @@ export const fieldsGroups = [
label: 'Receipt Date', label: 'Receipt Date',
}, },
{ {
enableKey: 'showBilledToAddress', enableKey: 'showCustomerAddress',
labelKey: 'billedToLabel', labelKey: 'billedToLabel',
label: 'Bill To', label: 'Bill To',
}, },
{ {
enableKey: 'showBilledFromAddress', enableKey: 'showCompanyAddress',
label: 'Billed From', label: 'Billed From',
}, },
], ],

View File

@@ -63,6 +63,7 @@ function ReceiptForm({
createReceiptMutate, createReceiptMutate,
submitPayload, submitPayload,
isNewMode, isNewMode,
saleReceiptState,
} = useReceiptFormContext(); } = useReceiptFormContext();
// The next receipt number. // The next receipt number.
@@ -84,6 +85,7 @@ function ReceiptForm({
currency_code: base_currency, currency_code: base_currency,
receipt_message: receiptMessage, receipt_message: receiptMessage,
terms_conditions: receiptTermsConditions, terms_conditions: receiptTermsConditions,
pdf_template_id: saleReceiptState?.defaultTemplateId,
}), }),
}; };
// Handle the form submit. // Handle the form submit.
@@ -171,7 +173,7 @@ function ReceiptForm({
{/*---------- Dialogs ---------*/} {/*---------- Dialogs ---------*/}
<ReceiptFormDialogs /> <ReceiptFormDialogs />
css
{/*---------- Effects ---------*/} {/*---------- Effects ---------*/}
<ReceiptSyncIncrementSettingsToForm /> <ReceiptSyncIncrementSettingsToForm />
<ReceiptSyncAutoExRateToForm /> <ReceiptSyncAutoExRateToForm />

View File

@@ -13,11 +13,20 @@ import {
useItems, useItems,
useCreateReceipt, useCreateReceipt,
useEditReceipt, useEditReceipt,
useGetReceiptState,
IGetReceiptStateResponse,
} from '@/hooks/query'; } from '@/hooks/query';
import { useProjects } from '@/containers/Projects/hooks'; import { useProjects } from '@/containers/Projects/hooks';
import { useGetPdfTemplates } from '@/hooks/query/pdf-templates'; import { useGetPdfTemplates } from '@/hooks/query/pdf-templates';
const ReceiptFormContext = createContext(); const ReceiptFormContext = createContext<ReceiptFormProviderValue>(
{} as ReceiptFormProviderValue,
);
interface ReceiptFormProviderValue {
isSaleReceiptStateLoading: boolean;
saleReceiptState: IGetReceiptStateResponse;
}
/** /**
* Receipt form provider. * Receipt form provider.
@@ -96,6 +105,10 @@ function ReceiptFormProvider({ receiptId, ...props }) {
const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } = const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } =
useGetPdfTemplates({ resource: 'SaleReceipt' }); useGetPdfTemplates({ resource: 'SaleReceipt' });
// Fetches the sale receipt state.
const { data: saleReceiptState, isLoading: isSaleReceiptStateLoading } =
useGetReceiptState();
// Fetch receipt settings. // Fetch receipt settings.
const { isLoading: isSettingLoading } = useSettingsReceipts(); const { isLoading: isSettingLoading } = useSettingsReceipts();
@@ -137,6 +150,10 @@ function ReceiptFormProvider({ receiptId, ...props }) {
// Branding templates // Branding templates
brandingTemplates, brandingTemplates,
isBrandingTemplatesLoading, isBrandingTemplatesLoading,
// State
isSaleReceiptStateLoading,
saleReceiptState,
}; };
const isLoading = const isLoading =
isReceiptLoading || isReceiptLoading ||
@@ -144,7 +161,8 @@ function ReceiptFormProvider({ receiptId, ...props }) {
isCustomersLoading || isCustomersLoading ||
isItemsLoading || isItemsLoading ||
isSettingLoading || isSettingLoading ||
isBrandingTemplatesLoading; isBrandingTemplatesLoading ||
isSaleReceiptStateLoading;
return ( return (
<DashboardInsider loading={isLoading} name={'receipt-form'}> <DashboardInsider loading={isLoading} name={'receipt-form'}>
@@ -153,6 +171,7 @@ function ReceiptFormProvider({ receiptId, ...props }) {
); );
} }
const useReceiptFormContext = () => React.useContext(ReceiptFormContext); const useReceiptFormContext = () =>
React.useContext<ReceiptFormProviderValue>(ReceiptFormContext);
export { ReceiptFormProvider, useReceiptFormContext }; export { ReceiptFormProvider, useReceiptFormContext };

View File

@@ -4,6 +4,7 @@ import { FastField, Form, ErrorMessage } from 'formik';
import { Button, Intent, FormGroup, Classes } from '@blueprintjs/core'; import { Button, Intent, FormGroup, Classes } from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { TimezonePicker } from '@blueprintjs/timezone'; import { TimezonePicker } from '@blueprintjs/timezone';
import { getAllCountries } from '@bigcapital/utils';
import { import {
FFormGroup, FFormGroup,
FInputGroup, FInputGroup,
@@ -17,7 +18,6 @@ import { inputIntent } from '@/utils';
import { getFiscalYear } from '@/constants/fiscalYearOptions'; import { getFiscalYear } from '@/constants/fiscalYearOptions';
import { getLanguages } from '@/constants/languagesOptions'; import { getLanguages } from '@/constants/languagesOptions';
import { getAllCurrenciesOptions } from '@/constants/currencies'; import { getAllCurrenciesOptions } from '@/constants/currencies';
import { getAllCountries } from '@/utils/countries';
const countries = getAllCountries(); const countries = getAllCountries();

View File

@@ -1,7 +1,7 @@
// @ts-nocheck // @ts-nocheck
import { useQueryClient, useMutation } from 'react-query'; import { useQueryClient, useMutation, useQuery } from 'react-query';
import { useRequestQuery } from '../useQueryRequest'; import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from '@/utils'; import { transformPagination, transformToCamelCase } from '@/utils';
import useApiRequest from '../useRequest'; import useApiRequest from '../useRequest';
import { useRequestPdf } from '../useRequestPdf'; import { useRequestPdf } from '../useRequestPdf';
import t from './types'; import t from './types';
@@ -356,3 +356,21 @@ export function useRefundCreditTransaction(id, props, requestProps) {
export function usePdfCreditNote(creditNoteId) { export function usePdfCreditNote(creditNoteId) {
return useRequestPdf({ url: `sales/credit_notes/${creditNoteId}` }); return useRequestPdf({ url: `sales/credit_notes/${creditNoteId}` });
} }
export interface CreditNoteStateResponse {
defaultTemplateId: number;
}
export function useGetCreditNoteState(
options?: UseQueryOptions<CreditNoteStateResponse, Error>,
): UseQueryResult<CreditNoteStateResponse, Error> {
const apiRequest = useApiRequest();
return useQuery<CreditNoteStateResponse, Error>(
['CREDIT_NOTE_STATE'],
() =>
apiRequest
.get('/sales/credit_notes/state')
.then((res) => transformToCamelCase(res.data?.data)),
{ ...options },
);
}

View File

@@ -1,8 +1,8 @@
// @ts-nocheck // @ts-nocheck
import { useQueryClient, useMutation } from 'react-query'; import { useQueryClient, useMutation, useQuery } from 'react-query';
import { useRequestQuery } from '../useQueryRequest'; import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest'; import useApiRequest from '../useRequest';
import { transformPagination } from '@/utils'; import { transformPagination, transformToCamelCase } from '@/utils';
import t from './types'; import t from './types';
import { useRequestPdf } from '../useRequestPdf'; import { useRequestPdf } from '../useRequestPdf';
@@ -270,3 +270,22 @@ export function useSaleEstimateDefaultOptions(estimateId, props) {
}, },
); );
} }
export interface ISaleEstimatesStateResponse {
defaultTemplateId: number;
}
export function useGetSaleEstimatesState(
options?: UseQueryOptions<ISaleEstimatesStateResponse, Error>,
): UseQueryResult<ISaleEstimatesStateResponse, Error> {
const apiRequest = useApiRequest();
return useQuery<ISaleEstimatesStateResponse, Error>(
['SALE_ESTIMATE_STATE'],
() =>
apiRequest
.get('/sales/estimates/state')
.then((res) => transformToCamelCase(res.data?.data)),
{ ...options },
);
}

View File

@@ -1,7 +1,7 @@
// @ts-nocheck // @ts-nocheck
import { useQueryClient, useMutation } from 'react-query'; import { useQueryClient, useMutation, useQuery } from 'react-query';
import { useRequestQuery } from '../useQueryRequest'; import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from '@/utils'; import { transformPagination, transformToCamelCase } from '@/utils';
import useApiRequest from '../useRequest'; import useApiRequest from '../useRequest';
import { useRequestPdf } from '../useRequestPdf'; import { useRequestPdf } from '../useRequestPdf';
import t from './types'; import t from './types';
@@ -341,3 +341,22 @@ export function useSaleInvoiceDefaultOptions(invoiceId, props) {
}, },
); );
} }
export interface GetSaleInvoiceStateResponse {
defaultTemplateId: number;
}
export function useGetSaleInvoiceState(
options?: UseQueryOptions<GetSaleInvoiceStateResponse, Error>,
): UseQueryResult<GetSaleInvoiceStateResponse, Error> {
const apiRequest = useApiRequest();
return useQuery<GetSaleInvoiceStateResponse, Error>(
['SALE_INVOICE_STATE'],
() =>
apiRequest
.get(`/sales/invoices/state`)
.then((res) => transformToCamelCase(res.data?.data)),
{ ...options },
);
}

View File

@@ -11,6 +11,7 @@ import useApiRequest from '../useRequest';
import { transformToCamelCase, transfromToSnakeCase } from '@/utils'; import { transformToCamelCase, transfromToSnakeCase } from '@/utils';
const GetPaymentLinkInvoice = 'GetPaymentLinkInvoice'; const GetPaymentLinkInvoice = 'GetPaymentLinkInvoice';
const GetPaymentLinkInvoicePdf = 'GetPaymentLinkInvoicePdf';
// Create Payment Link // Create Payment Link
// ------------------------------------ // ------------------------------------
@@ -170,3 +171,62 @@ export const useCreateStripeCheckoutSession = (
{ ...options }, { ...options },
); );
}; };
// Get Payment Link Invoice PDF
// ------------------------------------
interface GetPaymentLinkInvoicePdfResponse {}
interface GeneratePaymentLinkInvoicePdfValues {
paymentLinkId: string;
}
export const useGeneratePaymentLinkInvoicePdf = (
options?: UseMutationOptions<
GetPaymentLinkInvoicePdfResponse,
Error,
GeneratePaymentLinkInvoicePdfValues
>,
): UseMutationResult<
GetPaymentLinkInvoicePdfResponse,
Error,
GeneratePaymentLinkInvoicePdfValues
> => {
const apiRequest = useApiRequest();
return useMutation<
GetPaymentLinkInvoicePdfResponse,
Error,
GeneratePaymentLinkInvoicePdfValues
>(
(values: GeneratePaymentLinkInvoicePdfValues) => {
return apiRequest
.get(`/payment-links/${values.paymentLinkId}/invoice/pdf`, {
responseType: 'blob',
headers: { accept: 'application/pdf' },
})
.then((res) => res?.data);
},
{ ...options },
);
};
export const useGetPaymentLinkInvoicePdf = (
invoiceId: string,
options?: UseQueryOptions<GetPaymentLinkInvoicePdfResponse, Error>,
): UseQueryResult<GetPaymentLinkInvoicePdfResponse, Error> => {
const apiRequest = useApiRequest();
return useQuery<GetPaymentLinkInvoicePdfResponse, Error>(
[GetPaymentLinkInvoicePdf, invoiceId],
() =>
apiRequest
.get(`/payment-links/${invoiceId}/invoice/pdf`, {
responseType: 'blob',
headers: { accept: 'application/pdf' },
})
.then((res) => res.data),
{
...options,
},
);
};

View File

@@ -1,11 +1,16 @@
// @ts-nocheck // @ts-nocheck
import { useMutation, useQueryClient } from 'react-query'; import {
import { useRequestQuery } from '../useQueryRequest'; useMutation,
useQueryClient,
UseQueryOptions,
UseQueryResult,
useQuery,
} from 'react-query';
import useApiRequest from '../useRequest'; import useApiRequest from '../useRequest';
import { transformPagination, saveInvoke } from '@/utils'; import { useRequestQuery } from '../useQueryRequest';
import { transformPagination, saveInvoke, transformToCamelCase } from '@/utils';
import t from './types';
import { useRequestPdf } from '../useRequestPdf'; import { useRequestPdf } from '../useRequestPdf';
import t from './types';
// Common invalidate queries. // Common invalidate queries.
const commonInvalidateQueries = (client) => { const commonInvalidateQueries = (client) => {
@@ -269,3 +274,30 @@ export function usePaymentReceiveDefaultOptions(paymentReceiveId, props) {
}, },
); );
} }
export interface PaymentReceivedStateResponse {
defaultTemplateId: number;
}
/**
* Retrieves the payment receive state.
* @param {Record<string, any>} query - Query parameters for the request.
* @param {UseQueryOptions<PaymentReceivedStateResponse, Error>} options - Optional query options.
* @returns {UseQueryResult<PaymentReceivedStateResponse, Error>} The query result.
*/
export function usePaymentReceivedState(
options?: UseQueryOptions<PaymentReceivedStateResponse, Error>,
): UseQueryResult<PaymentReceivedStateResponse, Error> {
const apiRequest = useApiRequest();
return useQuery<PaymentReceivedStateResponse, Error>(
['PAYMENT_RECEIVED_STATE'],
() =>
apiRequest
.get('/sales/payment_receives/state')
.then((res) => transformToCamelCase(res.data?.data)),
{
...options,
},
);
}

View File

@@ -198,6 +198,11 @@ export const useAssignPdfTemplateAsDefault = (
{ {
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries([PdfTemplatesQueryKey]); queryClient.invalidateQueries([PdfTemplatesQueryKey]);
queryClient.invalidateQueries(['SALE_INVOICE_STATE']);
queryClient.invalidateQueries(['SALE_ESTIMATE_STATE']);
queryClient.invalidateQueries(['SALE_RECEIPT_STATE']);
queryClient.invalidateQueries(['CREDIT_NOTE_STATE']);
queryClient.invalidateQueries(['PAYMENT_RECEIVED_STATE']);
}, },
...options, ...options,
}, },

View File

@@ -1,8 +1,14 @@
// @ts-nocheck // @ts-nocheck
import { useQueryClient, useMutation } from 'react-query'; import {
useQueryClient,
useMutation,
UseQueryResult,
UseQueryOptions,
useQuery,
} from 'react-query';
import { useRequestQuery } from '../useQueryRequest'; import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest'; import useApiRequest from '../useRequest';
import { transformPagination } from '@/utils'; import { transformPagination, transformToCamelCase } from '@/utils';
import { useRequestPdf } from '../useRequestPdf'; import { useRequestPdf } from '../useRequestPdf';
import t from './types'; import t from './types';
@@ -244,3 +250,22 @@ export function useSaleReceiptDefaultOptions(invoiceId, props) {
}, },
); );
} }
export interface IGetReceiptStateResponse {
defaultTemplateId: number;
}
export function useGetReceiptState(
options?: UseQueryOptions<IGetReceiptStateResponse, Error>,
): UseQueryResult<IGetReceiptStateResponse, Error> {
const apiRequest = useApiRequest();
return useQuery<IGetReceiptStateResponse, Error>(
['SALE_RECEIPT_STATE'],
() =>
apiRequest
.get(`/sales/receipts/state`)
.then((res) => transformToCamelCase(res.data?.data)),
{ ...options },
);
}

View File

@@ -33,9 +33,15 @@ export const useDownloadFile = (args: IArgs) => {
return { ...mutation }; return { ...mutation };
}; };
export function downloadFile(data, filename, mime, bom) { export function downloadFile(
data,
filename,
mime = 'application/octet-stream',
bom?: any,
) {
var blobData = typeof bom !== 'undefined' ? [bom, data] : [data]; var blobData = typeof bom !== 'undefined' ? [bom, data] : [data];
var blob = new Blob(blobData, { type: mime || 'application/octet-stream' }); var blob = new Blob(blobData, { type: mime });
if (typeof window.navigator.msSaveBlob !== 'undefined') { if (typeof window.navigator.msSaveBlob !== 'undefined') {
// IE workaround for "HTML7007: One or more blob URLs were // IE workaround for "HTML7007: One or more blob URLs were
// revoked by closing the blob for which they were created. // revoked by closing the blob for which they were created.

View File

@@ -1,10 +0,0 @@
import { Countries } from '@/constants/countries';
export const getAllCountries = () => {
return Object.keys(Countries).map((countryCode) => {
return {
...Countries[countryCode],
countryCode,
}
});
};

614
pnpm-lock.yaml generated
View File

@@ -7,6 +7,10 @@ settings:
importers: importers:
.: .:
dependencies:
tsup:
specifier: ^8.3.0
version: 8.3.0(typescript@4.9.5)
devDependencies: devDependencies:
'@commitlint/cli': '@commitlint/cli':
specifier: ^17.4.2 specifier: ^17.4.2
@@ -41,6 +45,9 @@ importers:
'@aws-sdk/s3-request-presigner': '@aws-sdk/s3-request-presigner':
specifier: ^3.583.0 specifier: ^3.583.0
version: 3.583.0 version: 3.583.0
'@bigcapital/utils':
specifier: '*'
version: link:../../shared/bigcapital-utils
'@casl/ability': '@casl/ability':
specifier: ^5.4.3 specifier: ^5.4.3
version: 5.4.4 version: 5.4.4
@@ -455,7 +462,7 @@ importers:
version: 3.9.10 version: 3.9.10
webpack: webpack:
specifier: ^5.75.0 specifier: ^5.75.0
version: 5.91.0(webpack-cli@4.10.0) version: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
webpack-cli: webpack-cli:
specifier: ^4.10.0 specifier: ^4.10.0
version: 4.10.0(webpack@5.91.0) version: 4.10.0(webpack@5.91.0)
@@ -471,6 +478,9 @@ importers:
packages/webapp: packages/webapp:
dependencies: dependencies:
'@bigcapital/utils':
specifier: '*'
version: link:../../shared/bigcapital-utils
'@blueprintjs-formik/core': '@blueprintjs-formik/core':
specifier: ^0.3.6 specifier: ^0.3.6
version: 0.3.6(@babel/core@7.24.5)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1) version: 0.3.6(@babel/core@7.24.5)(@blueprintjs/core@4.20.2)(@blueprintjs/select@4.9.24)(formik@2.4.6)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1)
@@ -755,7 +765,7 @@ importers:
version: 5.3.4(react@18.3.1) version: 5.3.4(react@18.3.1)
react-scripts: react-scripts:
specifier: 5.0.1 specifier: 5.0.1
version: 5.0.1(@babel/plugin-syntax-flow@7.24.1)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.57.0)(react@18.3.1)(sass@1.77.2)(ts-node@10.9.2)(typescript@4.9.5) version: 5.0.1(@babel/plugin-syntax-flow@7.24.1)(@babel/plugin-transform-react-jsx@7.23.4)(esbuild@0.23.1)(eslint@8.57.0)(react@18.3.1)(sass@1.77.2)(ts-node@10.9.2)(typescript@4.9.5)
react-scroll-sync: react-scroll-sync:
specifier: ^0.7.1 specifier: ^0.7.1
version: 0.7.1(prop-types@15.8.1)(react-dom@18.3.1)(react@18.3.1) version: 0.7.1(prop-types@15.8.1)(react-dom@18.3.1)(react@18.3.1)
@@ -829,6 +839,8 @@ importers:
specifier: ^0.28.1 specifier: ^0.28.1
version: 0.28.5 version: 0.28.5
shared/bigcapital-utils: {}
packages: packages:
/@alloc/quick-lru@5.2.0: /@alloc/quick-lru@5.2.0:
@@ -3531,7 +3543,7 @@ packages:
dependencies: dependencies:
cross-spawn: 7.0.3 cross-spawn: 7.0.3
lodash: 4.17.21 lodash: 4.17.21
react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.24.1)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.57.0)(react@18.3.1)(sass@1.77.2)(ts-node@10.9.2)(typescript@4.9.5) react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.24.1)(@babel/plugin-transform-react-jsx@7.23.4)(esbuild@0.23.1)(eslint@8.57.0)(react@18.3.1)(sass@1.77.2)(ts-node@10.9.2)(typescript@4.9.5)
webpack-merge: 4.2.2 webpack-merge: 4.2.2
dev: false dev: false
@@ -3789,6 +3801,198 @@ packages:
resolution: {integrity: sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==} resolution: {integrity: sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==}
dev: false dev: false
/@esbuild/aix-ppc64@0.23.1:
resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
requiresBuild: true
optional: true
/@esbuild/android-arm64@0.23.1:
resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
requiresBuild: true
optional: true
/@esbuild/android-arm@0.23.1:
resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
requiresBuild: true
optional: true
/@esbuild/android-x64@0.23.1:
resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
requiresBuild: true
optional: true
/@esbuild/darwin-arm64@0.23.1:
resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
optional: true
/@esbuild/darwin-x64@0.23.1:
resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
requiresBuild: true
optional: true
/@esbuild/freebsd-arm64@0.23.1:
resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
optional: true
/@esbuild/freebsd-x64@0.23.1:
resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
optional: true
/@esbuild/linux-arm64@0.23.1:
resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-arm@0.23.1:
resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-ia32@0.23.1:
resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-loong64@0.23.1:
resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-mips64el@0.23.1:
resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-ppc64@0.23.1:
resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-riscv64@0.23.1:
resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-s390x@0.23.1:
resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/linux-x64@0.23.1:
resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
requiresBuild: true
optional: true
/@esbuild/netbsd-x64@0.23.1:
resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
optional: true
/@esbuild/openbsd-arm64@0.23.1:
resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
requiresBuild: true
optional: true
/@esbuild/openbsd-x64@0.23.1:
resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
optional: true
/@esbuild/sunos-x64@0.23.1:
resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
requiresBuild: true
optional: true
/@esbuild/win32-arm64@0.23.1:
resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
requiresBuild: true
optional: true
/@esbuild/win32-ia32@0.23.1:
resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
requiresBuild: true
optional: true
/@esbuild/win32-x64@0.23.1:
resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
requiresBuild: true
optional: true
/@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0):
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -5003,7 +5207,7 @@ packages:
react-refresh: 0.11.0 react-refresh: 0.11.0
schema-utils: 3.3.0 schema-utils: 3.3.0
source-map: 0.7.4 source-map: 0.7.4
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
webpack-dev-server: 4.15.2(webpack@5.91.0) webpack-dev-server: 4.15.2(webpack@5.91.0)
dev: false dev: false
@@ -5137,6 +5341,134 @@ packages:
rollup: 2.79.1 rollup: 2.79.1
dev: false dev: false
/@rollup/rollup-android-arm-eabi@4.24.0:
resolution: {integrity: sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==}
cpu: [arm]
os: [android]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-android-arm64@4.24.0:
resolution: {integrity: sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-darwin-arm64@4.24.0:
resolution: {integrity: sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-darwin-x64@4.24.0:
resolution: {integrity: sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-linux-arm-gnueabihf@4.24.0:
resolution: {integrity: sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-linux-arm-musleabihf@4.24.0:
resolution: {integrity: sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-linux-arm64-gnu@4.24.0:
resolution: {integrity: sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-linux-arm64-musl@4.24.0:
resolution: {integrity: sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-linux-powerpc64le-gnu@4.24.0:
resolution: {integrity: sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-linux-riscv64-gnu@4.24.0:
resolution: {integrity: sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-linux-s390x-gnu@4.24.0:
resolution: {integrity: sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-linux-x64-gnu@4.24.0:
resolution: {integrity: sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-linux-x64-musl@4.24.0:
resolution: {integrity: sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-win32-arm64-msvc@4.24.0:
resolution: {integrity: sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-win32-ia32-msvc@4.24.0:
resolution: {integrity: sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@rollup/rollup-win32-x64-msvc@4.24.0:
resolution: {integrity: sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@rushstack/eslint-patch@1.10.3: /@rushstack/eslint-patch@1.10.3:
resolution: {integrity: sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==} resolution: {integrity: sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==}
dev: false dev: false
@@ -6362,6 +6694,10 @@ packages:
/@types/estree@1.0.5: /@types/estree@1.0.5:
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
/@types/estree@1.0.6:
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
dev: false
/@types/express-serve-static-core@4.19.1: /@types/express-serve-static-core@4.19.1:
resolution: {integrity: sha512-ej0phymbFLoCB26dbbq5PGScsf2JAJ4IJHjG10LalgUV36XKTmA4GdA+PVllKvRk0sEKt64X8975qFnkSi0hqA==} resolution: {integrity: sha512-ej0phymbFLoCB26dbbq5PGScsf2JAJ4IJHjG10LalgUV36XKTmA4GdA+PVllKvRk0sEKt64X8975qFnkSi0hqA==}
dependencies: dependencies:
@@ -7266,7 +7602,7 @@ packages:
webpack: 4.x.x || 5.x.x webpack: 4.x.x || 5.x.x
webpack-cli: 4.x.x webpack-cli: 4.x.x
dependencies: dependencies:
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
webpack-cli: 4.10.0(webpack@5.91.0) webpack-cli: 4.10.0(webpack@5.91.0)
/@webpack-cli/info@1.5.0(webpack-cli@4.10.0): /@webpack-cli/info@1.5.0(webpack-cli@4.10.0):
@@ -8198,7 +8534,7 @@ packages:
loader-utils: 2.0.4 loader-utils: 2.0.4
make-dir: 3.1.0 make-dir: 3.1.0
schema-utils: 2.7.1 schema-utils: 2.7.1
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/babel-loader@9.1.3(@babel/core@7.24.5)(webpack@5.91.0): /babel-loader@9.1.3(@babel/core@7.24.5)(webpack@5.91.0):
@@ -8211,7 +8547,7 @@ packages:
'@babel/core': 7.24.5 '@babel/core': 7.24.5
find-cache-dir: 4.0.0 find-cache-dir: 4.0.0
schema-utils: 4.2.0 schema-utils: 4.2.0
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/babel-plugin-emotion@10.2.2: /babel-plugin-emotion@10.2.2:
@@ -8932,6 +9268,16 @@ packages:
semver: 7.6.2 semver: 7.6.2
dev: true dev: true
/bundle-require@5.0.0(esbuild@0.23.1):
resolution: {integrity: sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
peerDependencies:
esbuild: '>=0.18'
dependencies:
esbuild: 0.23.1
load-tsconfig: 0.2.5
dev: false
/busboy@1.6.0: /busboy@1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'} engines: {node: '>=10.16.0'}
@@ -8954,6 +9300,11 @@ packages:
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
dev: false dev: false
/cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
dev: false
/cacache@17.1.4: /cacache@17.1.4:
resolution: {integrity: sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==} resolution: {integrity: sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -9716,6 +10067,11 @@ packages:
engines: {node: '>=0.8'} engines: {node: '>=0.8'}
dev: false dev: false
/consola@3.2.3:
resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==}
engines: {node: ^14.18.0 || >=16.10.0}
dev: false
/console-browserify@1.2.0: /console-browserify@1.2.0:
resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==}
dev: true dev: true
@@ -10261,10 +10617,10 @@ packages:
postcss-modules-values: 4.0.0(postcss@8.4.38) postcss-modules-values: 4.0.0(postcss@8.4.38)
postcss-value-parser: 4.2.0 postcss-value-parser: 4.2.0
semver: 7.6.2 semver: 7.6.2
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/css-minimizer-webpack-plugin@3.4.1(webpack@5.91.0): /css-minimizer-webpack-plugin@3.4.1(esbuild@0.23.1)(webpack@5.91.0):
resolution: {integrity: sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==} resolution: {integrity: sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==}
engines: {node: '>= 12.13.0'} engines: {node: '>= 12.13.0'}
peerDependencies: peerDependencies:
@@ -10284,12 +10640,13 @@ packages:
optional: true optional: true
dependencies: dependencies:
cssnano: 5.1.15(postcss@8.4.38) cssnano: 5.1.15(postcss@8.4.38)
esbuild: 0.23.1
jest-worker: 27.5.1 jest-worker: 27.5.1
postcss: 8.4.38 postcss: 8.4.38
schema-utils: 4.2.0 schema-utils: 4.2.0
serialize-javascript: 6.0.2 serialize-javascript: 6.0.2
source-map: 0.6.1 source-map: 0.6.1
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/css-prefers-color-scheme@6.0.3(postcss@8.4.38): /css-prefers-color-scheme@6.0.3(postcss@8.4.38):
@@ -10646,6 +11003,18 @@ packages:
ms: 2.1.2 ms: 2.1.2
supports-color: 5.5.0 supports-color: 5.5.0
/debug@4.3.7:
resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.1.3
dev: false
/decamelize-keys@1.1.1: /decamelize-keys@1.1.1:
resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -11125,7 +11494,7 @@ packages:
webpack: ^4 || ^5 webpack: ^4 || ^5
dependencies: dependencies:
dotenv-defaults: 2.0.2 dotenv-defaults: 2.0.2
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/dotenv@10.0.0: /dotenv@10.0.0:
@@ -11515,6 +11884,37 @@ packages:
es6-symbol: 3.1.4 es6-symbol: 3.1.4
dev: false dev: false
/esbuild@0.23.1:
resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==}
engines: {node: '>=18'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/aix-ppc64': 0.23.1
'@esbuild/android-arm': 0.23.1
'@esbuild/android-arm64': 0.23.1
'@esbuild/android-x64': 0.23.1
'@esbuild/darwin-arm64': 0.23.1
'@esbuild/darwin-x64': 0.23.1
'@esbuild/freebsd-arm64': 0.23.1
'@esbuild/freebsd-x64': 0.23.1
'@esbuild/linux-arm': 0.23.1
'@esbuild/linux-arm64': 0.23.1
'@esbuild/linux-ia32': 0.23.1
'@esbuild/linux-loong64': 0.23.1
'@esbuild/linux-mips64el': 0.23.1
'@esbuild/linux-ppc64': 0.23.1
'@esbuild/linux-riscv64': 0.23.1
'@esbuild/linux-s390x': 0.23.1
'@esbuild/linux-x64': 0.23.1
'@esbuild/netbsd-x64': 0.23.1
'@esbuild/openbsd-arm64': 0.23.1
'@esbuild/openbsd-x64': 0.23.1
'@esbuild/sunos-x64': 0.23.1
'@esbuild/win32-arm64': 0.23.1
'@esbuild/win32-ia32': 0.23.1
'@esbuild/win32-x64': 0.23.1
/escalade@3.1.2: /escalade@3.1.2:
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
engines: {node: '>=6'} engines: {node: '>=6'}
@@ -11691,7 +12091,7 @@ packages:
node-libs-browser: 2.2.1 node-libs-browser: 2.2.1
resolve: 1.22.8 resolve: 1.22.8
semver: 5.7.2 semver: 5.7.2
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@@ -11709,7 +12109,7 @@ packages:
object-assign: 4.1.1 object-assign: 4.1.1
object-hash: 1.3.1 object-hash: 1.3.1
rimraf: 2.7.1 rimraf: 2.7.1
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: true dev: true
/eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint-import-resolver-webpack@0.11.1)(eslint@8.57.0): /eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint-import-resolver-webpack@0.11.1)(eslint@8.57.0):
@@ -12001,7 +12401,7 @@ packages:
micromatch: 4.0.7 micromatch: 4.0.7
normalize-path: 3.0.0 normalize-path: 3.0.0
schema-utils: 4.2.0 schema-utils: 4.2.0
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/eslint@8.57.0: /eslint@8.57.0:
@@ -12512,6 +12912,17 @@ packages:
pend: 1.2.0 pend: 1.2.0
dev: false dev: false
/fdir@6.4.0(picomatch@4.0.2):
resolution: {integrity: sha512-3oB133prH1o4j/L5lLW7uOCF1PlD+/It2L0eL/iAqWMB91RBbqTewABqxhj0ibBd90EEmWZq7ntIWzVaWcXTGQ==}
peerDependencies:
picomatch: ^3 || ^4
peerDependenciesMeta:
picomatch:
optional: true
dependencies:
picomatch: 4.0.2
dev: false
/feature-policy@0.3.0: /feature-policy@0.3.0:
resolution: {integrity: sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==} resolution: {integrity: sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==}
engines: {node: '>=4.0.0'} engines: {node: '>=4.0.0'}
@@ -12542,7 +12953,7 @@ packages:
dependencies: dependencies:
loader-utils: 2.0.4 loader-utils: 2.0.4
schema-utils: 3.3.0 schema-utils: 3.3.0
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/file-selector@0.4.0: /file-selector@0.4.0:
@@ -12835,7 +13246,7 @@ packages:
semver: 5.7.2 semver: 5.7.2
tapable: 1.1.3 tapable: 1.1.3
typescript: 4.9.5 typescript: 4.9.5
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
worker-rpc: 0.1.1 worker-rpc: 0.1.1
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -12870,7 +13281,7 @@ packages:
semver: 7.6.2 semver: 7.6.2
tapable: 1.1.3 tapable: 1.1.3
typescript: 4.9.5 typescript: 4.9.5
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/form-data@2.3.3: /form-data@2.3.3:
@@ -13034,7 +13445,7 @@ packages:
resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==}
engines: {node: '>= 4.0'} engines: {node: '>= 4.0'}
os: [darwin] os: [darwin]
deprecated: The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2 deprecated: Upgrade to fsevents v2 to mitigate potential security issues
requiresBuild: true requiresBuild: true
dependencies: dependencies:
bindings: 1.5.0 bindings: 1.5.0
@@ -13995,7 +14406,7 @@ packages:
lodash: 4.17.21 lodash: 4.17.21
pretty-error: 4.0.0 pretty-error: 4.0.0
tapable: 2.2.1 tapable: 2.2.1
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/htmlparser2@6.1.0: /htmlparser2@6.1.0:
@@ -16167,6 +16578,11 @@ packages:
hasBin: true hasBin: true
dev: false dev: false
/joycon@3.1.1:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'}
dev: false
/js-cookie@2.2.1: /js-cookie@2.2.1:
resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==}
dev: false dev: false
@@ -16903,6 +17319,11 @@ packages:
type-fest: 0.6.0 type-fest: 0.6.0
dev: true dev: true
/load-tsconfig@0.2.5:
resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: false
/loader-fs-cache@1.0.3: /loader-fs-cache@1.0.3:
resolution: {integrity: sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA==} resolution: {integrity: sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA==}
dependencies: dependencies:
@@ -17592,7 +18013,7 @@ packages:
dependencies: dependencies:
schema-utils: 4.2.0 schema-utils: 4.2.0
tapable: 2.2.1 tapable: 2.2.1
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/minimalistic-assert@1.0.1: /minimalistic-assert@1.0.1:
@@ -19546,6 +19967,11 @@ packages:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'} engines: {node: '>=8.6'}
/picomatch@4.0.2:
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
engines: {node: '>=12'}
dev: false
/pidtree@0.3.1: /pidtree@0.3.1:
resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==} resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==}
engines: {node: '>=0.10'} engines: {node: '>=0.10'}
@@ -20041,6 +20467,27 @@ packages:
yaml: 2.4.2 yaml: 2.4.2
dev: true dev: true
/postcss-load-config@6.0.1:
resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
engines: {node: '>= 18'}
peerDependencies:
jiti: '>=1.21.0'
postcss: '>=8.0.9'
tsx: ^4.8.1
yaml: ^2.4.2
peerDependenciesMeta:
jiti:
optional: true
postcss:
optional: true
tsx:
optional: true
yaml:
optional: true
dependencies:
lilconfig: 3.1.1
dev: false
/postcss-loader@6.2.1(postcss@8.4.38)(webpack@5.91.0): /postcss-loader@6.2.1(postcss@8.4.38)(webpack@5.91.0):
resolution: {integrity: sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==} resolution: {integrity: sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==}
engines: {node: '>= 12.13.0'} engines: {node: '>= 12.13.0'}
@@ -20052,7 +20499,7 @@ packages:
klona: 2.0.6 klona: 2.0.6
postcss: 8.4.38 postcss: 8.4.38
semver: 7.6.2 semver: 7.6.2
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/postcss-logical@5.0.4(postcss@8.4.38): /postcss-logical@5.0.4(postcss@8.4.38):
@@ -20665,7 +21112,7 @@ packages:
dependencies: dependencies:
chalk: 3.0.0 chalk: 3.0.0
progress: 2.0.3 progress: 2.0.3
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: true dev: true
/progress@2.0.1: /progress@2.0.1:
@@ -21371,7 +21818,7 @@ packages:
strip-ansi: 6.0.0 strip-ansi: 6.0.0
text-table: 0.2.0 text-table: 0.2.0
typescript: 4.9.5 typescript: 4.9.5
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
transitivePeerDependencies: transitivePeerDependencies:
- eslint - eslint
- supports-color - supports-color
@@ -21413,7 +21860,7 @@ packages:
strip-ansi: 6.0.1 strip-ansi: 6.0.1
text-table: 0.2.0 text-table: 0.2.0
typescript: 4.9.5 typescript: 4.9.5
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
transitivePeerDependencies: transitivePeerDependencies:
- eslint - eslint
- supports-color - supports-color
@@ -21720,7 +22167,7 @@ packages:
react-dom: 18.3.1(react@18.3.1) react-dom: 18.3.1(react@18.3.1)
dev: false dev: false
/react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.1)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.57.0)(react@18.3.1)(sass@1.77.2)(ts-node@10.9.2)(typescript@4.9.5): /react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.1)(@babel/plugin-transform-react-jsx@7.23.4)(esbuild@0.23.1)(eslint@8.57.0)(react@18.3.1)(sass@1.77.2)(ts-node@10.9.2)(typescript@4.9.5):
resolution: {integrity: sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==} resolution: {integrity: sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
hasBin: true hasBin: true
@@ -21744,7 +22191,7 @@ packages:
camelcase: 6.3.0 camelcase: 6.3.0
case-sensitive-paths-webpack-plugin: 2.4.0 case-sensitive-paths-webpack-plugin: 2.4.0
css-loader: 6.11.0(webpack@5.91.0) css-loader: 6.11.0(webpack@5.91.0)
css-minimizer-webpack-plugin: 3.4.1(webpack@5.91.0) css-minimizer-webpack-plugin: 3.4.1(esbuild@0.23.1)(webpack@5.91.0)
dotenv: 10.0.0 dotenv: 10.0.0
dotenv-expand: 5.1.0 dotenv-expand: 5.1.0
eslint: 8.57.0 eslint: 8.57.0
@@ -21775,9 +22222,9 @@ packages:
source-map-loader: 3.0.2(webpack@5.91.0) source-map-loader: 3.0.2(webpack@5.91.0)
style-loader: 3.3.4(webpack@5.91.0) style-loader: 3.3.4(webpack@5.91.0)
tailwindcss: 3.4.3(ts-node@10.9.2) tailwindcss: 3.4.3(ts-node@10.9.2)
terser-webpack-plugin: 5.3.10(webpack@5.91.0) terser-webpack-plugin: 5.3.10(esbuild@0.23.1)(webpack@5.91.0)
typescript: 4.9.5 typescript: 4.9.5
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
webpack-dev-server: 4.15.2(webpack@5.91.0) webpack-dev-server: 4.15.2(webpack@5.91.0)
webpack-manifest-plugin: 4.1.1(webpack@5.91.0) webpack-manifest-plugin: 4.1.1(webpack@5.91.0)
workbox-webpack-plugin: 6.6.0(webpack@5.91.0) workbox-webpack-plugin: 6.6.0(webpack@5.91.0)
@@ -22740,6 +23187,32 @@ packages:
fsevents: 2.3.3 fsevents: 2.3.3
dev: false dev: false
/rollup@4.24.0:
resolution: {integrity: sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
dependencies:
'@types/estree': 1.0.6
optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.24.0
'@rollup/rollup-android-arm64': 4.24.0
'@rollup/rollup-darwin-arm64': 4.24.0
'@rollup/rollup-darwin-x64': 4.24.0
'@rollup/rollup-linux-arm-gnueabihf': 4.24.0
'@rollup/rollup-linux-arm-musleabihf': 4.24.0
'@rollup/rollup-linux-arm64-gnu': 4.24.0
'@rollup/rollup-linux-arm64-musl': 4.24.0
'@rollup/rollup-linux-powerpc64le-gnu': 4.24.0
'@rollup/rollup-linux-riscv64-gnu': 4.24.0
'@rollup/rollup-linux-s390x-gnu': 4.24.0
'@rollup/rollup-linux-x64-gnu': 4.24.0
'@rollup/rollup-linux-x64-musl': 4.24.0
'@rollup/rollup-win32-arm64-msvc': 4.24.0
'@rollup/rollup-win32-ia32-msvc': 4.24.0
'@rollup/rollup-win32-x64-msvc': 4.24.0
fsevents: 2.3.3
dev: false
/rope-sequence@1.3.4: /rope-sequence@1.3.4:
resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
dev: false dev: false
@@ -22896,7 +23369,7 @@ packages:
klona: 2.0.6 klona: 2.0.6
neo-async: 2.6.2 neo-async: 2.6.2
sass: 1.77.2 sass: 1.77.2
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/sass@1.77.2: /sass@1.77.2:
@@ -23470,7 +23943,7 @@ packages:
abab: 2.0.6 abab: 2.0.6
iconv-lite: 0.6.3 iconv-lite: 0.6.3
source-map-js: 1.2.0 source-map-js: 1.2.0
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/source-map-loader@4.0.2(webpack@5.91.0): /source-map-loader@4.0.2(webpack@5.91.0):
@@ -23481,7 +23954,7 @@ packages:
dependencies: dependencies:
iconv-lite: 0.6.3 iconv-lite: 0.6.3
source-map-js: 1.2.0 source-map-js: 1.2.0
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/source-map-resolve@0.5.3: /source-map-resolve@0.5.3:
@@ -24087,7 +24560,7 @@ packages:
peerDependencies: peerDependencies:
webpack: ^5.0.0 webpack: ^5.0.0
dependencies: dependencies:
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/styled-components@5.3.11(@babel/core@7.24.5)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1): /styled-components@5.3.11(@babel/core@7.24.5)(react-dom@18.3.1)(react-is@18.3.1)(react@18.3.1):
@@ -24411,7 +24884,7 @@ packages:
supports-hyperlinks: 2.3.0 supports-hyperlinks: 2.3.0
dev: false dev: false
/terser-webpack-plugin@5.3.10(webpack@5.91.0): /terser-webpack-plugin@5.3.10(esbuild@0.23.1)(webpack@5.91.0):
resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==}
engines: {node: '>= 10.13.0'} engines: {node: '>= 10.13.0'}
peerDependencies: peerDependencies:
@@ -24428,11 +24901,12 @@ packages:
optional: true optional: true
dependencies: dependencies:
'@jridgewell/trace-mapping': 0.3.25 '@jridgewell/trace-mapping': 0.3.25
esbuild: 0.23.1
jest-worker: 27.5.1 jest-worker: 27.5.1
schema-utils: 3.3.0 schema-utils: 3.3.0
serialize-javascript: 6.0.2 serialize-javascript: 6.0.2
terser: 5.31.0 terser: 5.31.0
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
/terser@5.31.0: /terser@5.31.0:
resolution: {integrity: sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==} resolution: {integrity: sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==}
@@ -24577,6 +25051,14 @@ packages:
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
dev: false dev: false
/tinyglobby@0.2.9:
resolution: {integrity: sha512-8or1+BGEdk1Zkkw2ii16qSS7uVrQJPre5A9o/XkWPATkk23FZh/15BKFxPnlTy6vkljZxLqYCzzBMj30ZrSvjw==}
engines: {node: '>=12.0.0'}
dependencies:
fdir: 6.4.0(picomatch@4.0.2)
picomatch: 4.0.2
dev: false
/tippy.js@6.3.7: /tippy.js@6.3.7:
resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==}
dependencies: dependencies:
@@ -24734,6 +25216,11 @@ packages:
punycode: 2.3.1 punycode: 2.3.1
dev: false dev: false
/tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
dev: false
/trim-newlines@3.0.1: /trim-newlines@3.0.1:
resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -24768,7 +25255,7 @@ packages:
semver: 7.6.2 semver: 7.6.2
source-map: 0.7.4 source-map: 0.7.4
typescript: 3.9.10 typescript: 3.9.10
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: true dev: true
/ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.5): /ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.5):
@@ -24869,6 +25356,49 @@ packages:
engines: {node: '>=0.6.x'} engines: {node: '>=0.6.x'}
dev: false dev: false
/tsup@8.3.0(typescript@4.9.5):
resolution: {integrity: sha512-ALscEeyS03IomcuNdFdc0YWGVIkwH1Ws7nfTbAPuoILvEV2hpGQAY72LIOjglGo4ShWpZfpBqP/jpQVCzqYQag==}
engines: {node: '>=18'}
hasBin: true
peerDependencies:
'@microsoft/api-extractor': ^7.36.0
'@swc/core': ^1
postcss: ^8.4.12
typescript: '>=4.5.0'
peerDependenciesMeta:
'@microsoft/api-extractor':
optional: true
'@swc/core':
optional: true
postcss:
optional: true
typescript:
optional: true
dependencies:
bundle-require: 5.0.0(esbuild@0.23.1)
cac: 6.7.14
chokidar: 3.6.0
consola: 3.2.3
debug: 4.3.7
esbuild: 0.23.1
execa: 5.1.1
joycon: 3.1.1
picocolors: 1.0.1
postcss-load-config: 6.0.1
resolve-from: 5.0.0
rollup: 4.24.0
source-map: 0.8.0-beta.0
sucrase: 3.35.0
tinyglobby: 0.2.9
tree-kill: 1.2.2
typescript: 4.9.5
transitivePeerDependencies:
- jiti
- supports-color
- tsx
- yaml
dev: false
/tsutils@3.21.0(typescript@3.9.10): /tsutils@3.21.0(typescript@3.9.10):
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@@ -25669,7 +26199,7 @@ packages:
import-local: 3.1.0 import-local: 3.1.0
interpret: 2.2.0 interpret: 2.2.0
rechoir: 0.7.1 rechoir: 0.7.1
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
webpack-merge: 5.10.0 webpack-merge: 5.10.0
/webpack-dev-middleware@5.3.4(webpack@5.91.0): /webpack-dev-middleware@5.3.4(webpack@5.91.0):
@@ -25683,7 +26213,7 @@ packages:
mime-types: 2.1.35 mime-types: 2.1.35
range-parser: 1.2.1 range-parser: 1.2.1
schema-utils: 4.2.0 schema-utils: 4.2.0
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
dev: false dev: false
/webpack-dev-server@4.15.2(webpack@5.91.0): /webpack-dev-server@4.15.2(webpack@5.91.0):
@@ -25727,7 +26257,7 @@ packages:
serve-index: 1.9.1 serve-index: 1.9.1
sockjs: 0.3.24 sockjs: 0.3.24
spdy: 4.0.2 spdy: 4.0.2
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
webpack-dev-middleware: 5.3.4(webpack@5.91.0) webpack-dev-middleware: 5.3.4(webpack@5.91.0)
ws: 8.17.0 ws: 8.17.0
transitivePeerDependencies: transitivePeerDependencies:
@@ -25744,7 +26274,7 @@ packages:
webpack: ^4.44.2 || ^5.47.0 webpack: ^4.44.2 || ^5.47.0
dependencies: dependencies:
tapable: 2.2.1 tapable: 2.2.1
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
webpack-sources: 2.3.1 webpack-sources: 2.3.1
dev: false dev: false
@@ -25792,7 +26322,7 @@ packages:
chalk: 2.4.2 chalk: 2.4.2
dev: true dev: true
/webpack@5.91.0(webpack-cli@4.10.0): /webpack@5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0):
resolution: {integrity: sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==} resolution: {integrity: sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
hasBin: true hasBin: true
@@ -25823,7 +26353,7 @@ packages:
neo-async: 2.6.2 neo-async: 2.6.2
schema-utils: 3.3.0 schema-utils: 3.3.0
tapable: 2.2.1 tapable: 2.2.1
terser-webpack-plugin: 5.3.10(webpack@5.91.0) terser-webpack-plugin: 5.3.10(esbuild@0.23.1)(webpack@5.91.0)
watchpack: 2.4.1 watchpack: 2.4.1
webpack-cli: 4.10.0(webpack@5.91.0) webpack-cli: 4.10.0(webpack@5.91.0)
webpack-sources: 3.2.3 webpack-sources: 3.2.3
@@ -26202,7 +26732,7 @@ packages:
fast-json-stable-stringify: 2.1.0 fast-json-stable-stringify: 2.1.0
pretty-bytes: 5.6.0 pretty-bytes: 5.6.0
upath: 1.2.0 upath: 1.2.0
webpack: 5.91.0(webpack-cli@4.10.0) webpack: 5.91.0(esbuild@0.23.1)(webpack-cli@4.10.0)
webpack-sources: 1.4.3 webpack-sources: 1.4.3
workbox-build: 6.6.0 workbox-build: 6.6.0
transitivePeerDependencies: transitivePeerDependencies:

View File

@@ -1,3 +1,4 @@
packages: packages:
# all packages in direct subdirs of packages/ # all packages in direct subdirs of packages/
- 'packages/*' - 'packages/*'
- 'shared/*'

1
shared/bigcapital-utils/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/dist

View File

@@ -0,0 +1,22 @@
{
"name": "@bigcapital/utils",
"version": "1.0.0",
"description": "",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"require": "./dist/index.js",
"import": "./dist/index.mjs"
}
},
"scripts": {
"build:cjs": "tsup src/index.ts --format cjs --dts --sourcemap",
"build:esm": "tsup src/index.ts --format esm --dts --sourcemap",
"build": "npm run build:cjs && npm run build:esm",
"dev": "npm run build -- --watch"
},
"author": "",
"license": "ISC"
}

View File

@@ -1,13 +1,4 @@
interface Country { import { Country } from './types';
name: string;
native: string;
phone: number[];
continent: string;
continents?: string[];
capital: string;
currency: string[];
languages: string[];
}
export const Countries: Record<string, Country> = { export const Countries: Record<string, Country> = {
AD: { AD: {

View File

@@ -0,0 +1,20 @@
import { Countries } from './constant';
import { Country, Maybe } from './types';
export const getAllCountries = () => {
return Object.keys(Countries).map((countryCode) => {
return {
...Countries[countryCode],
countryCode,
};
});
};
export const findByIsoCountryCode = (
isoCode: string
): Maybe<Country & { countryCode: string }> => {
const _isoCode = isoCode?.toUpperCase();
const country = Countries[_isoCode];
return country ? { ...country, countryCode: isoCode } : null;
};

View File

@@ -0,0 +1,12 @@
export interface Country {
name: string;
native: string;
phone: number[];
continent: string;
continents?: string[];
capital: string;
currency: string[];
languages: string[];
}
export type Maybe<T> = T | null;

View File

@@ -0,0 +1,3 @@
export * from './countries';
export const test = () => {};

View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES6", // Equivalent to ES6 output
"module": "ESNext", // CommonJS for Node.js compatibility
"outDir": "dist", // Output directory for compiled files
"declaration": true, // Generates .d.ts files (same as dts: true)
"declarationDir": "dist", // Specifies where to output declaration files
"sourceMap": true, // Generate sourcemaps
"esModuleInterop": true, // Enables interop between CommonJS and ESModules
"strict": true, // Enables strict type-checking options
"moduleResolution": "node", // Resolve modules using Node.js-style resolution
"skipLibCheck": true, // Skip type checking of declaration files
"forceConsistentCasingInFileNames": true // Enforces consistent casing in import paths
},
"include": ["src/**/*"], // Includes all TypeScript files in the src directory
"exclude": ["node_modules"] // Excludes node_modules from being compiled
}