@carlonicora/nextjs-jsonapi 5.6.0 → 5.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BlockNoteEditor-NEYG5L6W.mjs → BlockNoteEditor-R3WXUFHX.mjs} +4 -4
- package/dist/{BlockNoteEditor-AE3ZTEEH.js → BlockNoteEditor-ZHXXFWUJ.js} +19 -19
- package/dist/{BlockNoteEditor-AE3ZTEEH.js.map → BlockNoteEditor-ZHXXFWUJ.js.map} +1 -1
- package/dist/{BlockNoteViewer-3OUT5UFY.mjs → BlockNoteViewer-BVVN6D3T.mjs} +2 -2
- package/dist/{BlockNoteViewer-4CFKQM7U.js → BlockNoteViewer-SD3ZFIXD.js} +3 -3
- package/dist/{BlockNoteViewer-4CFKQM7U.js.map → BlockNoteViewer-SD3ZFIXD.js.map} +1 -1
- package/dist/billing/index.d.mts +33 -43
- package/dist/billing/index.d.ts +33 -43
- package/dist/billing/index.js +590 -574
- package/dist/billing/index.js.map +1 -1
- package/dist/billing/index.mjs +28 -12
- package/dist/billing/index.mjs.map +1 -1
- package/dist/{chunk-3I5AAJXV.js → chunk-2TXE57LE.js} +3 -3
- package/dist/{chunk-3I5AAJXV.js.map → chunk-2TXE57LE.js.map} +1 -1
- package/dist/{chunk-HKZAESS6.js → chunk-5TH2DSAH.js} +17 -12
- package/dist/chunk-5TH2DSAH.js.map +1 -0
- package/dist/{chunk-SFYPXCK4.mjs → chunk-CFB6FHIY.mjs} +638 -536
- package/dist/{chunk-SFYPXCK4.mjs.map → chunk-CFB6FHIY.mjs.map} +1 -1
- package/dist/{chunk-EYA2F6AN.mjs → chunk-FK26NX3S.mjs} +16 -11
- package/dist/chunk-FK26NX3S.mjs.map +1 -0
- package/dist/{chunk-53BAULDP.js → chunk-IJME5SAM.js} +4 -4
- package/dist/{chunk-53BAULDP.js.map → chunk-IJME5SAM.js.map} +1 -1
- package/dist/{chunk-KQHBONL4.mjs → chunk-OKCV4GPJ.mjs} +2 -2
- package/dist/{chunk-BTPUYUQ3.mjs → chunk-RGQYFSJF.mjs} +2 -2
- package/dist/{chunk-Y7RR57EW.mjs → chunk-WCHLCOZG.mjs} +2 -2
- package/dist/{chunk-RL3PL3KV.js → chunk-XOSC3FFP.js} +8 -8
- package/dist/{chunk-RL3PL3KV.js.map → chunk-XOSC3FFP.js.map} +1 -1
- package/dist/{chunk-LQ4DK4JF.js → chunk-ZCOPOO7T.js} +1314 -1212
- package/dist/chunk-ZCOPOO7T.js.map +1 -0
- package/dist/client/index.js +4 -4
- package/dist/client/index.mjs +3 -3
- package/dist/components/index.js +4 -4
- package/dist/components/index.mjs +3 -3
- package/dist/contexts/index.js +4 -4
- package/dist/contexts/index.mjs +3 -3
- package/dist/core/index.d.mts +9 -3
- package/dist/core/index.d.ts +9 -3
- package/dist/core/index.js +10 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +9 -1
- package/dist/{format-options-D6c7FNDi.d.mts → currency-DT_dveBx.d.mts} +41 -8
- package/dist/{format-options-BtX3o0Yu.d.ts → currency-pK9eRYRC.d.ts} +41 -8
- package/dist/email-automations/index.js +92 -92
- package/dist/email-automations/index.mjs +3 -3
- package/dist/features/analytics/index.js +121 -121
- package/dist/features/analytics/index.mjs +4 -4
- package/dist/features/analytics/server.js +4 -4
- package/dist/features/analytics/server.mjs +2 -2
- package/dist/features/blog/index.js +150 -150
- package/dist/features/blog/index.mjs +3 -3
- package/dist/features/blog/server.js +16 -16
- package/dist/features/blog/server.mjs +1 -1
- package/dist/features/help/index.js +37 -37
- package/dist/features/help/index.mjs +3 -3
- package/dist/features/tokenusage/index.js +124 -124
- package/dist/features/tokenusage/index.mjs +4 -4
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10 -2
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +2 -2
- package/package.json +1 -1
- package/src/core/index.ts +3 -0
- package/src/features/billing/contexts/CouponContext.tsx +0 -2
- package/src/features/billing/stripe-coupon/components/details/CouponDetails.tsx +5 -2
- package/src/features/billing/stripe-coupon/components/forms/CouponCodeEditor.tsx +6 -5
- package/src/features/billing/stripe-coupon/components/forms/CouponCodeFields.tsx +67 -45
- package/src/features/billing/stripe-coupon/components/forms/CouponEditor.tsx +304 -212
- package/src/features/billing/stripe-coupon/components/widgets/CouponCodeActions.tsx +4 -3
- package/src/features/billing/stripe-coupon/data/stripe-coupon.interface.ts +11 -7
- package/src/features/billing/stripe-coupon/data/stripe-coupon.ts +6 -4
- package/src/features/billing/stripe-coupon/hooks/useStripeCouponCodeTableStructure.tsx +14 -7
- package/src/features/billing/stripe-coupon/hooks/useStripeCouponTableStructure.tsx +2 -2
- package/src/features/billing/stripe-coupon/stripe-coupon-code.module.ts +3 -2
- package/src/features/billing/stripe-coupon/stripe-coupon.module.ts +11 -4
- package/src/features/billing/stripe-promotion-code/components/PromoCodeInput.tsx +1 -1
- package/src/features/billing/stripe-subscription/hooks/wizard-promotion.ts +15 -8
- package/dist/chunk-EYA2F6AN.mjs.map +0 -1
- package/dist/chunk-HKZAESS6.js.map +0 -1
- package/dist/chunk-LQ4DK4JF.js.map +0 -1
- /package/dist/{BlockNoteEditor-NEYG5L6W.mjs.map → BlockNoteEditor-R3WXUFHX.mjs.map} +0 -0
- /package/dist/{BlockNoteViewer-3OUT5UFY.mjs.map → BlockNoteViewer-BVVN6D3T.mjs.map} +0 -0
- /package/dist/{chunk-KQHBONL4.mjs.map → chunk-OKCV4GPJ.mjs.map} +0 -0
- /package/dist/{chunk-BTPUYUQ3.mjs.map → chunk-RGQYFSJF.mjs.map} +0 -0
- /package/dist/{chunk-Y7RR57EW.mjs.map → chunk-WCHLCOZG.mjs.map} +0 -0
|
@@ -124,10 +124,12 @@ export class StripeCoupon extends AbstractApiData implements StripeCouponInterfa
|
|
|
124
124
|
|
|
125
125
|
const attributes = response.data.attributes;
|
|
126
126
|
if (data.stripeCouponId) attributes.stripeCouponId = data.stripeCouponId;
|
|
127
|
-
if (data.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
if (data.discountType === "percent_off") attributes.percentOff = data.percentOff;
|
|
128
|
+
else {
|
|
129
|
+
attributes.amountOff = data.amountOff;
|
|
130
|
+
attributes.currency = data.currency;
|
|
131
|
+
}
|
|
132
|
+
if (data.duration === "repeating") attributes.durationInMonths = data.durationInMonths;
|
|
131
133
|
if (data.productIds && data.productIds.length > 0) attributes.productIds = data.productIds;
|
|
132
134
|
if (data.redeemBy !== undefined) attributes.redeemBy = data.redeemBy.toISOString();
|
|
133
135
|
if (data.maxRedemptions !== undefined) attributes.maxRedemptions = data.maxRedemptions;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { ColumnDef } from "@tanstack/react-table";
|
|
4
4
|
import { useTranslations } from "next-intl";
|
|
5
|
-
import { useMemo } from "react";
|
|
5
|
+
import { useMemo, useState } from "react";
|
|
6
6
|
import { Badge } from "../../../../shadcnui";
|
|
7
7
|
import { registerTableGenerator, TableContent, UseTableStructureHook } from "../../../../hooks";
|
|
8
8
|
import { formatDate, useBillingFormatOptions } from "../../components/utils";
|
|
@@ -20,8 +20,12 @@ export type CouponCodeStatus = "active" | "inactive" | "expired" | "used_up";
|
|
|
20
20
|
* they win over a plain inactive flag. Places follow the same rule as the
|
|
21
21
|
* backend: the smaller of the code's and the coupon's remaining limits.
|
|
22
22
|
*/
|
|
23
|
-
export function couponCodeStatus(
|
|
24
|
-
|
|
23
|
+
export function couponCodeStatus(
|
|
24
|
+
code: StripeCouponCodeInterface,
|
|
25
|
+
coupon: StripeCouponInterface | undefined,
|
|
26
|
+
now: Date,
|
|
27
|
+
): CouponCodeStatus {
|
|
28
|
+
if (code.expiresAt && code.expiresAt.getTime() <= now.getTime()) return "expired";
|
|
25
29
|
const left = couponPlacesLeft(code, coupon ?? { maxRedemptions: undefined, timesRedeemed: 0 });
|
|
26
30
|
if (left === 0) return "used_up";
|
|
27
31
|
return code.active ? "active" : "inactive";
|
|
@@ -43,6 +47,9 @@ export const useStripeCouponCodeTableStructure: UseTableStructureHook<
|
|
|
43
47
|
// The codes list is mounted on the coupon's own page, so the coupon whose
|
|
44
48
|
// limits share the places is the context's, not whatever the code includes.
|
|
45
49
|
const { coupon } = useCouponContext();
|
|
50
|
+
// Read once on mount: render stays pure, and "expired" is judged against the
|
|
51
|
+
// moment the list was opened.
|
|
52
|
+
const [now] = useState(() => new Date());
|
|
46
53
|
|
|
47
54
|
const tableData = useMemo(() => {
|
|
48
55
|
return params.data.map((code: StripeCouponCodeInterface) => {
|
|
@@ -61,7 +68,7 @@ export const useStripeCouponCodeTableStructure: UseTableStructureHook<
|
|
|
61
68
|
header: t("billing.admin.coupons.fields.code"),
|
|
62
69
|
cell: ({ row }: { row: TableContent<StripeCouponCodeInterface> }) => {
|
|
63
70
|
const code: StripeCouponCodeInterface = row.original.jsonApiData;
|
|
64
|
-
return <span className="text-xs
|
|
71
|
+
return <span className="text-xs">{code.code}</span>;
|
|
65
72
|
},
|
|
66
73
|
enableSorting: false,
|
|
67
74
|
enableHiding: false,
|
|
@@ -123,7 +130,7 @@ export const useStripeCouponCodeTableStructure: UseTableStructureHook<
|
|
|
123
130
|
header: t("billing.admin.coupons.fields.status"),
|
|
124
131
|
cell: ({ row }: { row: TableContent<StripeCouponCodeInterface> }) => {
|
|
125
132
|
const code: StripeCouponCodeInterface = row.original.jsonApiData;
|
|
126
|
-
const status = couponCodeStatus(code, code.coupon ?? coupon);
|
|
133
|
+
const status = couponCodeStatus(code, code.coupon ?? coupon, now);
|
|
127
134
|
return <Badge variant={STATUS_VARIANT[status]}>{t(`billing.admin.coupons.codes.status.${status}`)}</Badge>;
|
|
128
135
|
},
|
|
129
136
|
enableSorting: false,
|
|
@@ -135,7 +142,7 @@ export const useStripeCouponCodeTableStructure: UseTableStructureHook<
|
|
|
135
142
|
header: "",
|
|
136
143
|
cell: ({ row }: { row: TableContent<StripeCouponCodeInterface> }) => {
|
|
137
144
|
const code: StripeCouponCodeInterface = row.original.jsonApiData;
|
|
138
|
-
return <CouponCodeActions code={code} status={couponCodeStatus(code, code.coupon ?? coupon)} />;
|
|
145
|
+
return <CouponCodeActions code={code} status={couponCodeStatus(code, code.coupon ?? coupon, now)} />;
|
|
139
146
|
},
|
|
140
147
|
enableSorting: false,
|
|
141
148
|
enableHiding: false,
|
|
@@ -146,7 +153,7 @@ export const useStripeCouponCodeTableStructure: UseTableStructureHook<
|
|
|
146
153
|
return params.fields.map((field) => fieldColumnMap[field]?.()).filter((col) => col !== undefined) as ColumnDef<
|
|
147
154
|
TableContent<StripeCouponCodeInterface>
|
|
148
155
|
>[];
|
|
149
|
-
}, [params.fields, fieldColumnMap, t, coupon]);
|
|
156
|
+
}, [params.fields, fieldColumnMap, t, coupon, now]);
|
|
150
157
|
|
|
151
158
|
return useMemo(() => ({ data: tableData, columns: columns }), [tableData, columns]);
|
|
152
159
|
};
|
|
@@ -4,10 +4,10 @@ import { ColumnDef } from "@tanstack/react-table";
|
|
|
4
4
|
import { useTranslations } from "next-intl";
|
|
5
5
|
import { useMemo } from "react";
|
|
6
6
|
import { Badge, Link } from "../../../../shadcnui";
|
|
7
|
-
import { Modules } from "../../../../core";
|
|
8
7
|
import { registerTableGenerator, TableContent, usePageUrlGenerator, UseTableStructureHook } from "../../../../hooks";
|
|
9
8
|
import { useBillingFormatOptions } from "../../components/utils";
|
|
10
9
|
import { StripeCouponFields } from "../data/stripe-coupon.fields";
|
|
10
|
+
import { STRIPE_COUPON_DETAIL_PAGE_URL } from "../stripe-coupon.module";
|
|
11
11
|
import { StripeCouponInterface } from "../data/stripe-coupon.interface";
|
|
12
12
|
import { formatCouponDiscount } from "../utils/format-coupon-discount";
|
|
13
13
|
|
|
@@ -35,7 +35,7 @@ export const useStripeCouponTableStructure: UseTableStructureHook<StripeCouponIn
|
|
|
35
35
|
header: t("billing.admin.coupons.fields.name"),
|
|
36
36
|
cell: ({ row }: { row: TableContent<StripeCouponInterface> }) => {
|
|
37
37
|
const coupon: StripeCouponInterface = row.original.jsonApiData;
|
|
38
|
-
return <Link href={generateUrl({ page:
|
|
38
|
+
return <Link href={generateUrl({ page: STRIPE_COUPON_DETAIL_PAGE_URL, id: coupon.id })}>{coupon.name}</Link>;
|
|
39
39
|
},
|
|
40
40
|
enableSorting: false,
|
|
41
41
|
enableHiding: false,
|
|
@@ -7,8 +7,9 @@ export const STRIPE_COUPON_CODE_AUTOMATIC_SEGMENT = "automatic";
|
|
|
7
7
|
export const StripeCouponCodeModule = (factory: ModuleFactory) =>
|
|
8
8
|
factory({
|
|
9
9
|
name: "stripe-coupon-codes",
|
|
10
|
-
// Codes are
|
|
11
|
-
|
|
10
|
+
// Codes are listed on the products page (Codes tab), same value as
|
|
11
|
+
// StripeProductModule. A code has no page of its own.
|
|
12
|
+
pageUrl: "/administration/products",
|
|
12
13
|
model: StripeCouponCode,
|
|
13
14
|
moduleId: "85feb4c7-ff22-416a-b856-8dafcf28ff26",
|
|
14
15
|
});
|
|
@@ -5,13 +5,20 @@ import { StripeCoupon } from "./data/stripe-coupon";
|
|
|
5
5
|
/** The coupon endpoint's non-resource segment that re-reads its counts from Stripe. */
|
|
6
6
|
export const STRIPE_COUPON_REFRESH_SEGMENT = "refresh";
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Route of a coupon's own page (`/administration/coupons/<id>`). It is not the
|
|
10
|
+
* module's pageUrl: there is no coupons list route, the list is the Codes tab of
|
|
11
|
+
* the products page. Links to one coupon build on this instead.
|
|
12
|
+
*/
|
|
13
|
+
export const STRIPE_COUPON_DETAIL_PAGE_URL = "/administration/coupons";
|
|
14
|
+
|
|
8
15
|
export const StripeCouponModule = (factory: ModuleFactory) =>
|
|
9
16
|
factory({
|
|
10
17
|
name: "stripe-coupons",
|
|
11
|
-
// The
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
pageUrl: "/administration/
|
|
18
|
+
// The coupons list lives on the products page (Codes tab), so the module
|
|
19
|
+
// points there, same value as StripeProductModule. Links to a single coupon
|
|
20
|
+
// use STRIPE_COUPON_DETAIL_PAGE_URL.
|
|
21
|
+
pageUrl: "/administration/products",
|
|
15
22
|
model: StripeCoupon,
|
|
16
23
|
moduleId: "50bdb0d2-539c-4358-b609-d6beab248bdb",
|
|
17
24
|
icon: TicketPercentIcon,
|
|
@@ -118,7 +118,7 @@ export function PromoCodeInput({
|
|
|
118
118
|
<p className="text-success text-sm">{formatDuration(appliedCode)}</p>
|
|
119
119
|
</div>
|
|
120
120
|
<div className="space-y-2">
|
|
121
|
-
<p className="text-muted-foreground text-
|
|
121
|
+
<p className="text-muted-foreground text-xs/relaxed">{t("billing.ui.promo_code.use_different")}</p>
|
|
122
122
|
{codeInput}
|
|
123
123
|
</div>
|
|
124
124
|
</div>
|
|
@@ -19,8 +19,14 @@ export function shouldLookUpAutomatic(code: PromotionCodeValidationResult | null
|
|
|
19
19
|
return !code || code.automatic === true;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
/** `value[key]` when `value` is an object, else undefined. */
|
|
23
|
+
function read(value: unknown, key: string): unknown {
|
|
24
|
+
return typeof value === "object" && value !== null ? Reflect.get(value, key) : undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function errorStatus(error: unknown): number | undefined {
|
|
28
|
+
const status = read(error, "status") ?? read(read(error, "response"), "status");
|
|
29
|
+
return typeof status === "number" ? status : undefined;
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
/**
|
|
@@ -29,10 +35,11 @@ function errorStatus(error: any): number | undefined {
|
|
|
29
35
|
* attaches to the thrown error as `body`:
|
|
30
36
|
* `{ message, errors: [{ status, code, title, detail, meta: { context: { code } } }] }`.
|
|
31
37
|
*/
|
|
32
|
-
function errorCode(error:
|
|
33
|
-
const body = error
|
|
34
|
-
const
|
|
35
|
-
const
|
|
38
|
+
function errorCode(error: unknown): string | undefined {
|
|
39
|
+
const body = read(error, "body");
|
|
40
|
+
const errors = read(body, "errors");
|
|
41
|
+
const first = Array.isArray(errors) ? errors[0] : undefined;
|
|
42
|
+
const code = read(first, "code") ?? read(read(read(first, "meta"), "context"), "code") ?? read(body, "code");
|
|
36
43
|
return typeof code === "string" ? code : undefined;
|
|
37
44
|
}
|
|
38
45
|
|
|
@@ -40,7 +47,7 @@ function errorCode(error: any): string | undefined {
|
|
|
40
47
|
* True when the API refused the payment because the automatic discount has no
|
|
41
48
|
* places left (HTTP 410, code `discount_sold_out`). Nothing was charged.
|
|
42
49
|
*/
|
|
43
|
-
export function isDiscountSoldOut(error:
|
|
50
|
+
export function isDiscountSoldOut(error: unknown): boolean {
|
|
44
51
|
return errorStatus(error) === 410 && errorCode(error) === "discount_sold_out";
|
|
45
52
|
}
|
|
46
53
|
|
|
@@ -49,6 +56,6 @@ export function isDiscountSoldOut(error: any): boolean {
|
|
|
49
56
|
* showed is no longer valid (HTTP 422, code `discount_unavailable`). Nothing was
|
|
50
57
|
* charged.
|
|
51
58
|
*/
|
|
52
|
-
export function isDiscountUnavailable(error:
|
|
59
|
+
export function isDiscountUnavailable(error: unknown): boolean {
|
|
53
60
|
return errorStatus(error) === 422 && errorCode(error) === "discount_unavailable";
|
|
54
61
|
}
|