@mohasinac/appkit 4.14.0 → 4.15.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/_internal/server/features/auctions/actions.js +2 -2
- package/dist/_internal/server/features/cart/service.d.ts +3 -3
- package/dist/_internal/server/features/checkout/actions.js +19 -0
- package/dist/_internal/server/features/checkout/source-context.d.ts +5 -0
- package/dist/_internal/server/features/checkout/source-context.js +157 -0
- package/dist/_internal/server/features/offers/adapters.d.ts +103 -0
- package/dist/_internal/server/features/offers/adapters.js +88 -0
- package/dist/_internal/server/features/offers/index.d.ts +2 -0
- package/dist/_internal/server/features/offers/index.js +1 -0
- package/dist/_internal/server/features/orders/adapters.js +24 -0
- package/dist/_internal/server/jobs/core/offerExpiry.js +10 -10
- package/dist/_internal/shared/actions/action-registry.js +3 -1
- package/dist/_internal/shared/features/auctions/schema.d.ts +14 -2
- package/dist/_internal/shared/features/auctions/schema.js +13 -1
- package/dist/_internal/shared/features/cart/schema.d.ts +14 -9
- package/dist/_internal/shared/features/cart/schema.js +15 -0
- package/dist/_internal/shared/features/products/schema.d.ts +2 -2
- package/dist/_internal/shared/history/history.d.ts +22 -0
- package/dist/_internal/shared/history/history.js +41 -1
- package/dist/client.d.ts +13 -2
- package/dist/client.js +20 -2
- package/dist/constants/field-names.d.ts +8 -6
- package/dist/constants/field-names.js +48 -6
- package/dist/features/account/components/UserBidsView.js +12 -4
- package/dist/features/account/components/UserReturnsView.d.ts +3 -0
- package/dist/features/account/components/UserReturnsView.js +17 -1
- package/dist/features/admin/components/AdminAuditLogView.js +1 -0
- package/dist/features/admin/components/AdminBidsView.js +15 -2
- package/dist/features/admin/components/AdminBlogEditorView.js +65 -33
- package/dist/features/admin/components/AdminFeatureEditorView.js +35 -6
- package/dist/features/admin/components/AdminNavEditorView.js +15 -5
- package/dist/features/admin/components/AdminNewsletterView.js +18 -2
- package/dist/features/admin/components/AdminOffersView.js +62 -18
- package/dist/features/admin/components/AdminPaymentMethodsView.js +24 -4
- package/dist/features/admin/components/AdminScammerEditorView.d.ts +2 -1
- package/dist/features/admin/components/AdminScammerEditorView.js +3 -13
- package/dist/features/admin/components/AdminScammersView.js +3 -8
- package/dist/features/admin/components/AdminSectionsView.js +32 -23
- package/dist/features/admin/components/AdminSessionsView.js +17 -2
- package/dist/features/admin/components/ViewAuditLogEntryModal.js +1 -0
- package/dist/features/admin/components/sections/adminSectionsTypes.d.ts +4 -2
- package/dist/features/admin/components/sections/adminSectionsTypes.js +45 -27
- package/dist/features/admin/constants/filter-tabs.d.ts +3 -0
- package/dist/features/admin/constants/filter-tabs.js +1 -0
- package/dist/features/admin/schemas/homepage-section-form.d.ts +22 -0
- package/dist/features/admin/schemas/homepage-section-form.js +68 -0
- package/dist/features/admin/schemas/nav-item-form.d.ts +74 -0
- package/dist/features/admin/schemas/nav-item-form.js +72 -0
- package/dist/features/auctions/components/AuctionBidsTable.d.ts +10 -1
- package/dist/features/auctions/components/AuctionBidsTable.js +22 -4
- package/dist/features/auctions/components/bid-detail-fields.d.ts +29 -0
- package/dist/features/auctions/components/bid-detail-fields.js +103 -0
- package/dist/features/audit-log/schemas/firestore.d.ts +14 -0
- package/dist/features/audit-log/schemas/firestore.js +7 -0
- package/dist/features/blog/schemas/blog-form.d.ts +80 -0
- package/dist/features/blog/schemas/blog-form.js +100 -0
- package/dist/features/events/components/AdminEventEditorView.js +32 -54
- package/dist/features/events/components/AdminEventEntriesView.js +22 -3
- package/dist/features/events/schemas/event-form.d.ts +113 -0
- package/dist/features/events/schemas/event-form.js +82 -0
- package/dist/features/grouped/schemas/grouped-listing-form.d.ts +101 -0
- package/dist/features/grouped/schemas/grouped-listing-form.js +89 -0
- package/dist/features/homepage/actions/homepage-section-actions.d.ts +11 -3
- package/dist/features/homepage/actions/homepage-section-actions.js +33 -1
- package/dist/features/homepage/schemas/index.d.ts +31 -0
- package/dist/features/homepage/schemas/index.js +24 -0
- package/dist/features/orders/components/OrderStatusTimeline.d.ts +5 -1
- package/dist/features/orders/components/OrderStatusTimeline.js +39 -20
- package/dist/features/orders/repository/orders.repository.js +5 -0
- package/dist/features/orders/schemas/firestore.d.ts +36 -1
- package/dist/features/orders/types/index.d.ts +35 -7
- package/dist/features/products/components/GroupSettingsPanel.js +5 -1
- package/dist/features/products/schemas/index.d.ts +2 -2
- package/dist/features/products/schemas/product-features.validators.d.ts +73 -0
- package/dist/features/products/schemas/product-features.validators.js +63 -0
- package/dist/features/scams/constants/scammer-status-display.d.ts +28 -0
- package/dist/features/scams/constants/scammer-status-display.js +79 -0
- package/dist/features/seller/actions/offer-actions.js +32 -2
- package/dist/features/seller/components/OfferPhaseTimeline.d.ts +59 -0
- package/dist/features/seller/components/OfferPhaseTimeline.js +107 -0
- package/dist/features/seller/components/SellerBidsView.js +11 -4
- package/dist/features/seller/components/SellerCouponEditorView.js +17 -17
- package/dist/features/seller/components/SellerOffersView.js +2 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +38 -14
- package/dist/features/seller/repository/offer.repository.d.ts +69 -8
- package/dist/features/seller/repository/offer.repository.js +127 -23
- package/dist/features/seller/schemas/coupon-form.d.ts +72 -0
- package/dist/features/seller/schemas/coupon-form.js +116 -0
- package/dist/features/seller/schemas/firestore.d.ts +56 -2
- package/dist/features/seller/schemas/firestore.js +27 -0
- package/dist/features/seller/schemas/offer-forms.d.ts +21 -0
- package/dist/features/seller/schemas/offer-forms.js +21 -0
- package/dist/features/shell/build-sections.d.ts +63 -0
- package/dist/features/shell/build-sections.js +207 -0
- package/dist/features/shell/field-ui-meta.d.ts +115 -0
- package/dist/features/shell/field-ui-meta.js +324 -0
- package/dist/features/shell/index.d.ts +4 -0
- package/dist/features/shell/index.js +2 -0
- package/dist/features/status-history/components/StatusTimeline.d.ts +74 -0
- package/dist/features/status-history/components/StatusTimeline.js +46 -0
- package/dist/features/status-history/index.d.ts +11 -0
- package/dist/features/status-history/index.js +10 -0
- package/dist/features/store-extensions/components/ReviewDecisionModal.d.ts +27 -0
- package/dist/features/store-extensions/components/ReviewDecisionModal.js +82 -0
- package/dist/features/store-extensions/index.d.ts +12 -0
- package/dist/features/store-extensions/index.js +12 -0
- package/dist/features/store-extensions/schemas/admin-notification-form.d.ts +36 -0
- package/dist/features/store-extensions/schemas/admin-notification-form.js +114 -0
- package/dist/features/store-extensions/schemas/analytics-forms.d.ts +57 -0
- package/dist/features/store-extensions/schemas/analytics-forms.js +158 -0
- package/dist/features/store-extensions/schemas/custom-role-form.d.ts +85 -0
- package/dist/features/store-extensions/schemas/custom-role-form.js +118 -0
- package/dist/features/store-extensions/schemas/firestore.d.ts +21 -1
- package/dist/features/store-extensions/schemas/firestore.js +60 -0
- package/dist/features/store-extensions/schemas/google-config-form.d.ts +53 -0
- package/dist/features/store-extensions/schemas/google-config-form.js +105 -0
- package/dist/features/store-extensions/schemas/item-request-create-form.d.ts +28 -0
- package/dist/features/store-extensions/schemas/item-request-create-form.js +80 -0
- package/dist/features/store-extensions/schemas/listing-template-form.d.ts +78 -0
- package/dist/features/store-extensions/schemas/listing-template-form.js +87 -0
- package/dist/features/store-extensions/schemas/moderation-review-form.d.ts +49 -0
- package/dist/features/store-extensions/schemas/moderation-review-form.js +101 -0
- package/dist/features/store-extensions/schemas/payout-method-form.d.ts +153 -0
- package/dist/features/store-extensions/schemas/payout-method-form.js +155 -0
- package/dist/features/store-extensions/schemas/report-create-form.d.ts +25 -0
- package/dist/features/store-extensions/schemas/report-create-form.js +79 -0
- package/dist/features/store-extensions/schemas/report-review-form.d.ts +47 -0
- package/dist/features/store-extensions/schemas/report-review-form.js +111 -0
- package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +148 -0
- package/dist/features/store-extensions/schemas/shipping-config-form.js +104 -0
- package/dist/features/store-extensions/schemas/store-category-form.d.ts +54 -0
- package/dist/features/store-extensions/schemas/store-category-form.js +73 -0
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +326 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.js +12 -2
- package/dist/next/routing/route-map.d.ts +16 -2
- package/dist/next/routing/route-map.js +9 -2
- package/dist/schemas/firestore-value.d.ts +8 -0
- package/dist/schemas/firestore-value.js +44 -0
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/index.js +1 -1
- package/dist/schemas/registry.d.ts +634 -1
- package/dist/schemas/registry.js +64 -1
- package/dist/seed/bids-seed-data.js +30 -0
- package/dist/seed/offers-seed-data.js +212 -7
- package/dist/seed/orders-seed-data.js +336 -1
- package/dist/seed/products-auctions-seed-data.js +41 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +5 -0
- package/dist/styles.css +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/RecordDetailModal.d.ts +10 -1
- package/dist/ui/components/RecordDetailModal.js +2 -2
- package/package.json +2 -1
- package/scripts/node-esm-loader.mjs +65 -0
- package/scripts/seed-cli-loader.mjs +6 -49
- package/scripts/seed-cli.mjs +1 -1
|
@@ -8,7 +8,7 @@ export declare const addToCartSchema: z.ZodObject<{
|
|
|
8
8
|
storeId: z.ZodString;
|
|
9
9
|
storeName: z.ZodDefault<z.ZodString>;
|
|
10
10
|
quantity: z.ZodDefault<z.ZodNumber>;
|
|
11
|
-
listingType: z.ZodEnum<["standard", "auction", "pre-order", "prize-draw", "classified", "digital-code", "live"]>;
|
|
11
|
+
listingType: z.ZodEnum<["standard", "auction", "pre-order", "prize-draw", "classified", "digital-code", "live", "art", "stickers"]>;
|
|
12
12
|
isOffer: z.ZodOptional<z.ZodBoolean>;
|
|
13
13
|
offerId: z.ZodOptional<z.ZodString>;
|
|
14
14
|
lockedPrice: z.ZodOptional<z.ZodNumber>;
|
|
@@ -16,7 +16,7 @@ export declare const addToCartSchema: z.ZodObject<{
|
|
|
16
16
|
currency: string;
|
|
17
17
|
storeId: string;
|
|
18
18
|
price: number;
|
|
19
|
-
listingType: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
|
|
19
|
+
listingType: "art" | "stickers" | "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
|
|
20
20
|
productId: string;
|
|
21
21
|
productTitle: string;
|
|
22
22
|
quantity: number;
|
|
@@ -28,7 +28,7 @@ export declare const addToCartSchema: z.ZodObject<{
|
|
|
28
28
|
}, {
|
|
29
29
|
storeId: string;
|
|
30
30
|
price: number;
|
|
31
|
-
listingType: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
|
|
31
|
+
listingType: "art" | "stickers" | "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
|
|
32
32
|
productId: string;
|
|
33
33
|
productTitle: string;
|
|
34
34
|
currency?: string | undefined;
|
|
@@ -66,7 +66,7 @@ export declare const mergeGuestCartSchema: z.ZodObject<{
|
|
|
66
66
|
storeId: z.ZodString;
|
|
67
67
|
storeName: z.ZodDefault<z.ZodString>;
|
|
68
68
|
quantity: z.ZodDefault<z.ZodNumber>;
|
|
69
|
-
listingType: z.ZodEnum<["standard", "auction", "pre-order", "prize-draw", "classified", "digital-code", "live"]>;
|
|
69
|
+
listingType: z.ZodEnum<["standard", "auction", "pre-order", "prize-draw", "classified", "digital-code", "live", "art", "stickers"]>;
|
|
70
70
|
isOffer: z.ZodOptional<z.ZodBoolean>;
|
|
71
71
|
offerId: z.ZodOptional<z.ZodString>;
|
|
72
72
|
lockedPrice: z.ZodOptional<z.ZodNumber>;
|
|
@@ -74,7 +74,7 @@ export declare const mergeGuestCartSchema: z.ZodObject<{
|
|
|
74
74
|
currency: string;
|
|
75
75
|
storeId: string;
|
|
76
76
|
price: number;
|
|
77
|
-
listingType: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
|
|
77
|
+
listingType: "art" | "stickers" | "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
|
|
78
78
|
productId: string;
|
|
79
79
|
productTitle: string;
|
|
80
80
|
quantity: number;
|
|
@@ -86,7 +86,7 @@ export declare const mergeGuestCartSchema: z.ZodObject<{
|
|
|
86
86
|
}, {
|
|
87
87
|
storeId: string;
|
|
88
88
|
price: number;
|
|
89
|
-
listingType: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
|
|
89
|
+
listingType: "art" | "stickers" | "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
|
|
90
90
|
productId: string;
|
|
91
91
|
productTitle: string;
|
|
92
92
|
currency?: string | undefined;
|
|
@@ -102,7 +102,7 @@ export declare const mergeGuestCartSchema: z.ZodObject<{
|
|
|
102
102
|
currency: string;
|
|
103
103
|
storeId: string;
|
|
104
104
|
price: number;
|
|
105
|
-
listingType: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
|
|
105
|
+
listingType: "art" | "stickers" | "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
|
|
106
106
|
productId: string;
|
|
107
107
|
productTitle: string;
|
|
108
108
|
quantity: number;
|
|
@@ -116,7 +116,7 @@ export declare const mergeGuestCartSchema: z.ZodObject<{
|
|
|
116
116
|
guestItems: {
|
|
117
117
|
storeId: string;
|
|
118
118
|
price: number;
|
|
119
|
-
listingType: "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
|
|
119
|
+
listingType: "art" | "stickers" | "classified" | "standard" | "auction" | "pre-order" | "prize-draw" | "digital-code" | "live";
|
|
120
120
|
productId: string;
|
|
121
121
|
productTitle: string;
|
|
122
122
|
currency?: string | undefined;
|
|
@@ -128,5 +128,10 @@ export declare const mergeGuestCartSchema: z.ZodObject<{
|
|
|
128
128
|
isOffer?: boolean | undefined;
|
|
129
129
|
}[];
|
|
130
130
|
}>;
|
|
131
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Renamed from `AddToCartInput` 2026-08-24 (W3) — `features/cart/schemas/
|
|
133
|
+
* firestore.ts` declares its own hand-written `AddToCartInput`, and a consumer
|
|
134
|
+
* importing the name had no way to tell which one it got.
|
|
135
|
+
*/
|
|
136
|
+
export type AddToCartActionInput = z.infer<typeof addToCartSchema>;
|
|
132
137
|
export type MergeGuestCartInput = z.infer<typeof mergeGuestCartSchema>;
|
|
@@ -10,6 +10,19 @@ const cartItemBaseSchema = z.object({
|
|
|
10
10
|
quantity: z.number().int().min(1).max(99).default(1),
|
|
11
11
|
// SB1-G Phase 4 — canonical listing-kind snapshot.
|
|
12
12
|
// SB-UNI-D — "bundle" removed from the listing-kind enum.
|
|
13
|
+
/*
|
|
14
|
+
* All NINE listing types. `art` and `stickers` were missing until
|
|
15
|
+
* 2026-08-24 (W3) — added to the union, the plugin registry, the capability
|
|
16
|
+
* map and the Sieve alias map, but not here.
|
|
17
|
+
*
|
|
18
|
+
* Not a live bug today, and verified rather than assumed (Rule #4): the real
|
|
19
|
+
* add-to-cart path is `POST /api/cart`, which takes only {productId,
|
|
20
|
+
* quantity} and derives the type server-side via `normalizeListingType`,
|
|
21
|
+
* never validating it against an enum. This enum sits on paths an art or
|
|
22
|
+
* sticker listing cannot currently reach. It was a trap waiting for the
|
|
23
|
+
* first caller that did — the third instalment of Root Cause #58, where a
|
|
24
|
+
* union member is added everywhere except the one allowlist that gates it.
|
|
25
|
+
*/
|
|
13
26
|
listingType: z.enum([
|
|
14
27
|
"standard",
|
|
15
28
|
"auction",
|
|
@@ -18,6 +31,8 @@ const cartItemBaseSchema = z.object({
|
|
|
18
31
|
"classified",
|
|
19
32
|
"digital-code",
|
|
20
33
|
"live",
|
|
34
|
+
"art",
|
|
35
|
+
"stickers",
|
|
21
36
|
]),
|
|
22
37
|
isOffer: z.boolean().optional(),
|
|
23
38
|
offerId: z.string().optional(),
|
|
@@ -289,7 +289,7 @@ export declare const preOrderInputSchema: z.ZodObject<{
|
|
|
289
289
|
tags: string[];
|
|
290
290
|
listingType: "pre-order";
|
|
291
291
|
preOrderDeliveryDate: string;
|
|
292
|
-
preOrderProductionStatus: "
|
|
292
|
+
preOrderProductionStatus: "upcoming" | "in_production" | "ready_to_ship";
|
|
293
293
|
preOrderCancellable: boolean;
|
|
294
294
|
features?: string[] | undefined;
|
|
295
295
|
description?: string | undefined;
|
|
@@ -330,7 +330,7 @@ export declare const preOrderInputSchema: z.ZodObject<{
|
|
|
330
330
|
shippingPaidBy?: "seller" | "buyer" | undefined;
|
|
331
331
|
preOrderDepositPercent?: number | undefined;
|
|
332
332
|
preOrderMaxQuantity?: number | undefined;
|
|
333
|
-
preOrderProductionStatus?: "
|
|
333
|
+
preOrderProductionStatus?: "upcoming" | "in_production" | "ready_to_ship" | undefined;
|
|
334
334
|
preOrderCancellable?: boolean | undefined;
|
|
335
335
|
seoTitle?: string | undefined;
|
|
336
336
|
seoDescription?: string | undefined;
|
|
@@ -59,6 +59,28 @@ export declare function withHistory<TPatch extends FirestoreDocument>(current: F
|
|
|
59
59
|
* a reader actually wants on the timeline.
|
|
60
60
|
*/
|
|
61
61
|
extraChanges?: Record<string, FieldChange>;
|
|
62
|
+
/**
|
|
63
|
+
* This entity's PII field names — pass the same list the repository hands
|
|
64
|
+
* to `encryptPiiFields` (`ORDER_PII_FIELDS`, `OFFER_PII_FIELDS`, …).
|
|
65
|
+
*
|
|
66
|
+
* 🛑 Not optional in spirit. `encryptPiiFields` is a FLAT top-level loop:
|
|
67
|
+
* it reads `doc[field]`, skips anything that is not a string, and never
|
|
68
|
+
* descends into arrays or nested objects. `statusHistory` is an array of
|
|
69
|
+
* objects, so a PII value that reaches `changes` is written to Firestore
|
|
70
|
+
* **in plaintext** and `mapDoc`'s decrypt never touches it on the way
|
|
71
|
+
* back out — a leak with no error and no visible symptom.
|
|
72
|
+
*
|
|
73
|
+
* Scrubbing here rather than at each call site is deliberate: a
|
|
74
|
+
* convention that says "don't put PII in history" is one forgetful
|
|
75
|
+
* adopter away from that leak, and 9 more entities adopt this primitive.
|
|
76
|
+
*
|
|
77
|
+
* SCOPE: this scrubs `changes` structurally, at any depth — a key whose
|
|
78
|
+
* NAME is PII is dropped. It cannot scrub `note`, which is free text the
|
|
79
|
+
* user themselves authored (a seller's counter-offer note). The rule
|
|
80
|
+
* there is a call-site one: pass the author's own text, never an identity
|
|
81
|
+
* field lifted off the document.
|
|
82
|
+
*/
|
|
83
|
+
piiFields?: readonly string[];
|
|
62
84
|
historyField?: string;
|
|
63
85
|
truncatedField?: string;
|
|
64
86
|
now?: Date;
|
|
@@ -99,6 +99,46 @@ export function diffTrackedFields(current, patch, tracked) {
|
|
|
99
99
|
}
|
|
100
100
|
return changes;
|
|
101
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Remove PII-named keys from a `changes` map, at any depth.
|
|
104
|
+
*
|
|
105
|
+
* Two passes are needed because PII can arrive two ways: as a tracked field
|
|
106
|
+
* that happens to be PII (`buyerEmail` in `changes`), or nested inside a
|
|
107
|
+
* value a caller contributed via `extraChanges` (a refund's `reason`, an
|
|
108
|
+
* offer note object). `encryptPiiFields` catches neither — it only ever
|
|
109
|
+
* looks at top-level string properties of the document itself.
|
|
110
|
+
*
|
|
111
|
+
* Scrubbed rather than redacted-in-place: an entry that silently omits a
|
|
112
|
+
* field is honest, whereas one containing `"[redacted]"` invites a reader to
|
|
113
|
+
* assume the real value is recoverable somewhere.
|
|
114
|
+
*/
|
|
115
|
+
function scrubPii(changes, piiFields) {
|
|
116
|
+
if (!piiFields?.length)
|
|
117
|
+
return changes;
|
|
118
|
+
const pii = new Set(piiFields);
|
|
119
|
+
const stripNested = (v) => {
|
|
120
|
+
if (v == null || typeof v !== "object")
|
|
121
|
+
return v;
|
|
122
|
+
if (v instanceof Date)
|
|
123
|
+
return v;
|
|
124
|
+
if (Array.isArray(v))
|
|
125
|
+
return v.map(stripNested);
|
|
126
|
+
const out = {};
|
|
127
|
+
for (const [k, val] of Object.entries(v)) {
|
|
128
|
+
if (pii.has(k))
|
|
129
|
+
continue;
|
|
130
|
+
out[k] = stripNested(val);
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
};
|
|
134
|
+
const result = {};
|
|
135
|
+
for (const [field, change] of Object.entries(changes)) {
|
|
136
|
+
if (pii.has(field))
|
|
137
|
+
continue; // the tracked field itself is PII
|
|
138
|
+
result[field] = { from: stripNested(change.from), to: stripNested(change.to) };
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
102
142
|
export function buildHistoryEntry(input) {
|
|
103
143
|
const entry = {
|
|
104
144
|
at: input.now ?? new Date(),
|
|
@@ -136,7 +176,7 @@ export function appendHistoryEntry(existing, entry, previousTruncatedCount = 0,
|
|
|
136
176
|
* writes its patch unchanged, so an untracked update never grows the array.
|
|
137
177
|
*/
|
|
138
178
|
export function withHistory(current, patch, opts) {
|
|
139
|
-
const changes = { ...diffTrackedFields(current, patch, opts.tracked), ...opts.extraChanges };
|
|
179
|
+
const changes = scrubPii({ ...diffTrackedFields(current, patch, opts.tracked), ...opts.extraChanges }, opts.piiFields);
|
|
140
180
|
if (Object.keys(changes).length === 0)
|
|
141
181
|
return null;
|
|
142
182
|
const historyField = opts.historyField ?? "statusHistory";
|
package/dist/client.d.ts
CHANGED
|
@@ -112,6 +112,17 @@ export { useBulkSelection } from "./react/hooks/useBulkSelection";
|
|
|
112
112
|
export type { UseBulkSelectionOptions, UseBulkSelectionReturn } from "./react/hooks/useBulkSelection";
|
|
113
113
|
export { useEntityDelete } from "./react/hooks/useEntityDelete";
|
|
114
114
|
export type { UseEntityDeleteOptions, UseEntityDeleteReturn } from "./react/hooks/useEntityDelete";
|
|
115
|
+
export { storeCategoryFormSchema, storeCategoryCreateSchema, type StoreCategoryFormValues, } from "./features/store-extensions/schemas/store-category-form";
|
|
116
|
+
export { payoutMethodFormSchema, payoutMethodCreateSchema, payoutMethodUpdateSchema, type PayoutMethodFormValues, } from "./features/store-extensions/schemas/payout-method-form";
|
|
117
|
+
export { groupedListingFormSchema, groupedListingCreateSchema, groupedListingUpdateSchema, type GroupedListingFormValues, } from "./features/grouped/schemas/grouped-listing-form";
|
|
118
|
+
export { navItemFormSchema, navItemCreateSchema, navItemUpdateSchema, type NavItemFormValues, } from "./features/admin/schemas/nav-item-form";
|
|
119
|
+
export { customRoleFormSchema, customRoleCreateSchema, customRoleUpdateSchema, isKnownPermission, type CustomRoleFormValues, } from "./features/store-extensions/schemas/custom-role-form";
|
|
120
|
+
export { SCAMMER_STATUS_LABEL, SCAMMER_STATUS_BADGE, SCAMMER_STATUS_OPTIONS, toScammerStatus, } from "./features/scams/constants/scammer-status-display";
|
|
121
|
+
export { ReviewDecisionModal, type ReviewDecisionModalProps, } from "./features/store-extensions/components/ReviewDecisionModal";
|
|
122
|
+
export { moderationReviewFormSchema, moderationReviewUpdateSchema, MODERATION_REVIEWER_STATUSES, type ModerationReviewFormValues, } from "./features/store-extensions/schemas/moderation-review-form";
|
|
123
|
+
export { reportReviewFormSchema, reportReviewUpdateSchema, REPORT_REVIEWER_STATUSES, REPORT_TERMINAL_STATUSES, type ReportReviewFormValues, } from "./features/store-extensions/schemas/report-review-form";
|
|
124
|
+
export { shippingConfigFormSchema, shippingConfigCreateSchema, shippingConfigUpdateSchema, type ShippingConfigFormValues, } from "./features/store-extensions/schemas/shipping-config-form";
|
|
125
|
+
export { listingTemplateFormSchema, listingTemplateCreateSchema, listingTemplateUpdateSchema, type ListingTemplateFormValues, } from "./features/store-extensions/schemas/listing-template-form";
|
|
115
126
|
export { ROUTES, PUBLIC_ROUTES, PROTECTED_ROUTES, AUTH_ROUTES } from "./constants/index";
|
|
116
127
|
export { SORT_DIR, sortBy } from "./constants/sort";
|
|
117
128
|
export { SIEVE_OP, sieveFilter, sieveAnd, sieveMultiEq } from "./utils/sieve-builder";
|
|
@@ -381,7 +392,7 @@ export { SellerDigitalCodesView } from "./features/seller/components/SellerDigit
|
|
|
381
392
|
export type { SellerDigitalCodesViewProps } from "./features/seller/components/SellerDigitalCodesView";
|
|
382
393
|
export { SellerLiveView } from "./features/seller/components/SellerLiveView";
|
|
383
394
|
export type { SellerLiveViewProps } from "./features/seller/components/SellerLiveView";
|
|
384
|
-
export { SCHEMAS, lookupApiSchema, lookupFirestoreSchema, } from "./schemas/index";
|
|
395
|
+
export { SCHEMAS, lookupApiSchema, lookupFormSchema, lookupFirestoreSchema, } from "./schemas/index";
|
|
385
396
|
export type { ApiRouteKey, ApiRouteSchema, FirestoreDocument, FirestoreValue, FormFieldValue, FormValues, HttpVerb, JsonArray, JsonObject, JsonObjectWithUndefined, JsonPrimitive, JsonValue, JsonValueWithUndefined, RegisteredApiRouteKey, RegisteredFirestoreCollection, RegisteredFormId, RegisteredRtdbChannel, RegisteredSieveCollection, RegisteredStorageOp, RegisteredWebhookProvider, RegistryEntry, SchemaRegistry, SchemasShape, WebhookSchemaBucket, } from "./schemas/index";
|
|
386
397
|
export { normalizeError, getErrorMessage, isApiNormalized, isAppNormalized, isFirebaseAuthNormalized, isFirebaseFirestoreNormalized, isFirebaseStorageNormalized, isNativeNormalized, isNetworkNormalized, isUnknownNormalized, isZodNormalized, } from "./errors/normalize";
|
|
387
398
|
export type { NormalizedError, NormalizedApiError, NormalizedAppError, NormalizedFirebaseAuthError, NormalizedFirebaseFirestoreError, NormalizedFirebaseStorageError, NormalizedNativeError, NormalizedNetworkError, NormalizedUnknownThrownValue, NormalizedZodError, } from "./errors/normalize";
|
|
@@ -390,7 +401,7 @@ export type { PaymentProofReviewMessageInput } from "./features/whatsapp-bot/typ
|
|
|
390
401
|
export type { AdminNotificationDocument, ItemRequestDocument, ModerationQueueDocument, ReportDocument, CustomRoleDocument, AnalyticsCardDocument, ListingTemplateDocument, } from "./features/store-extensions/index";
|
|
391
402
|
export { CommandPalette, useCommandPaletteHotkey } from "./features/shell/index";
|
|
392
403
|
export type { CommandPaletteGroup } from "./features/shell/index";
|
|
393
|
-
export { AdminBlogEditorView, AdminBundleEditorView, AdminCarouselEditorView, AdminCategoryEditorView, AdminCouponEditorView, AdminFaqEditorView, AdminOrderEditorView, AdminPayoutMarkPaidModal, AdminAuditLogView, ViewAuditLogEntryModal, AdminProductEditorView, AdminScammerEditorView, AdminStoreEditorView, AdminSublistingCategoryEditorView, AdminSupportTicketDetailView, } from "./features/admin/index";
|
|
404
|
+
export { AdminBlogEditorView, AdminBundleEditorView, AdminCarouselEditorView, AdminCategoryEditorView, AdminCouponEditorView, AdminFaqEditorView, AdminFeatureEditorView, AdminOrderEditorView, AdminPayoutMarkPaidModal, AdminAuditLogView, ViewAuditLogEntryModal, AdminProductEditorView, AdminScammerEditorView, AdminStoreEditorView, AdminSublistingCategoryEditorView, AdminSupportTicketDetailView, } from "./features/admin/index";
|
|
394
405
|
export type { AdminStoreEditorViewProps, AdminPayoutMarkPaidModalProps, AdminAuditLogViewProps, AuditLogEntryDetail, ViewAuditLogEntryModalProps } from "./features/admin/index";
|
|
395
406
|
export { ADMIN_CHECKOUT_BYPASS_FLAG_KEY } from "./features/admin/schemas/firestore";
|
|
396
407
|
export { SpinWheelView, EventRaffleEntryForm } from "./features/events/index";
|
package/dist/client.js
CHANGED
|
@@ -178,6 +178,24 @@ export { useUrlTable } from "./react/hooks/useUrlTable";
|
|
|
178
178
|
export { useBulkSelection } from "./react/hooks/useBulkSelection";
|
|
179
179
|
export { useEntityDelete } from "./react/hooks/useEntityDelete";
|
|
180
180
|
// Client-safe constants, UI primitives, and views
|
|
181
|
+
// Storefront-category form schema — isomorphic (the page parses it client-side,
|
|
182
|
+
// the route parses the same one server-side).
|
|
183
|
+
export { storeCategoryFormSchema, storeCategoryCreateSchema, } from "./features/store-extensions/schemas/store-category-form";
|
|
184
|
+
// Payout-method + listing-template form schemas — isomorphic: the pages parse
|
|
185
|
+
// them client-side and the routes parse the SAME ones server-side.
|
|
186
|
+
export { payoutMethodFormSchema, payoutMethodCreateSchema, payoutMethodUpdateSchema, } from "./features/store-extensions/schemas/payout-method-form";
|
|
187
|
+
export { groupedListingFormSchema, groupedListingCreateSchema, groupedListingUpdateSchema, } from "./features/grouped/schemas/grouped-listing-form";
|
|
188
|
+
export { navItemFormSchema, navItemCreateSchema, navItemUpdateSchema, } from "./features/admin/schemas/nav-item-form";
|
|
189
|
+
export { customRoleFormSchema, customRoleCreateSchema, customRoleUpdateSchema, isKnownPermission, } from "./features/store-extensions/schemas/custom-role-form";
|
|
190
|
+
// Client-only: deliberately NOT added to `features/store-extensions/index.ts`,
|
|
191
|
+
// which the schema registry's import chain reaches — a "use client" React tree
|
|
192
|
+
// re-exported from there would be pulled into every API route (the W4 trap).
|
|
193
|
+
export { SCAMMER_STATUS_LABEL, SCAMMER_STATUS_BADGE, SCAMMER_STATUS_OPTIONS, toScammerStatus, } from "./features/scams/constants/scammer-status-display";
|
|
194
|
+
export { ReviewDecisionModal, } from "./features/store-extensions/components/ReviewDecisionModal";
|
|
195
|
+
export { moderationReviewFormSchema, moderationReviewUpdateSchema, MODERATION_REVIEWER_STATUSES, } from "./features/store-extensions/schemas/moderation-review-form";
|
|
196
|
+
export { reportReviewFormSchema, reportReviewUpdateSchema, REPORT_REVIEWER_STATUSES, REPORT_TERMINAL_STATUSES, } from "./features/store-extensions/schemas/report-review-form";
|
|
197
|
+
export { shippingConfigFormSchema, shippingConfigCreateSchema, shippingConfigUpdateSchema, } from "./features/store-extensions/schemas/shipping-config-form";
|
|
198
|
+
export { listingTemplateFormSchema, listingTemplateCreateSchema, listingTemplateUpdateSchema, } from "./features/store-extensions/schemas/listing-template-form";
|
|
181
199
|
export { ROUTES, PUBLIC_ROUTES, PROTECTED_ROUTES, AUTH_ROUTES } from "./constants/index";
|
|
182
200
|
export { SORT_DIR, sortBy } from "./constants/sort";
|
|
183
201
|
export { SIEVE_OP, sieveFilter, sieveAnd, sieveMultiEq } from "./utils/sieve-builder";
|
|
@@ -368,7 +386,7 @@ export { SellerLiveView } from "./features/seller/components/SellerLiveView";
|
|
|
368
386
|
// ── Central schema registry (W1) ──────────────────────────────────────────────
|
|
369
387
|
// Pure Zod, isomorphic — re-exported here so client code can resolve schemas
|
|
370
388
|
// without pulling in the full server barrel.
|
|
371
|
-
export { SCHEMAS, lookupApiSchema, lookupFirestoreSchema, } from "./schemas/index";
|
|
389
|
+
export { SCHEMAS, lookupApiSchema, lookupFormSchema, lookupFirestoreSchema, } from "./schemas/index";
|
|
372
390
|
// ── W3 catch-clause normalizer ──────────────────────────────────────────────
|
|
373
391
|
export { normalizeError, getErrorMessage, isApiNormalized, isAppNormalized, isFirebaseAuthNormalized, isFirebaseFirestoreNormalized, isFirebaseStorageNormalized, isNativeNormalized, isNetworkNormalized, isUnknownNormalized, isZodNormalized, } from "./errors/normalize";
|
|
374
392
|
// [CLIENT-SAFE] Pure wa.me share-link message builder — imported directly
|
|
@@ -376,7 +394,7 @@ export { normalizeError, getErrorMessage, isApiNormalized, isAppNormalized, isFi
|
|
|
376
394
|
// never touches the sibling crypto-importing helpers.
|
|
377
395
|
export { buildPaymentProofReviewMessage } from "./features/whatsapp-bot/helpers/payment-proof-message";
|
|
378
396
|
export { CommandPalette, useCommandPaletteHotkey } from "./features/shell/index";
|
|
379
|
-
export { AdminBlogEditorView, AdminBundleEditorView, AdminCarouselEditorView, AdminCategoryEditorView, AdminCouponEditorView, AdminFaqEditorView, AdminOrderEditorView, AdminPayoutMarkPaidModal, AdminAuditLogView, ViewAuditLogEntryModal, AdminProductEditorView, AdminScammerEditorView, AdminStoreEditorView, AdminSublistingCategoryEditorView, AdminSupportTicketDetailView, } from "./features/admin/index";
|
|
397
|
+
export { AdminBlogEditorView, AdminBundleEditorView, AdminCarouselEditorView, AdminCategoryEditorView, AdminCouponEditorView, AdminFaqEditorView, AdminFeatureEditorView, AdminOrderEditorView, AdminPayoutMarkPaidModal, AdminAuditLogView, ViewAuditLogEntryModal, AdminProductEditorView, AdminScammerEditorView, AdminStoreEditorView, AdminSublistingCategoryEditorView, AdminSupportTicketDetailView, } from "./features/admin/index";
|
|
380
398
|
export { ADMIN_CHECKOUT_BYPASS_FLAG_KEY } from "./features/admin/schemas/firestore";
|
|
381
399
|
export { SpinWheelView, EventRaffleEntryForm } from "./features/events/index";
|
|
382
400
|
export { Card, CardBody } from "./ui/index";
|
|
@@ -151,10 +151,9 @@ export declare const PRODUCT_FIELDS: {
|
|
|
151
151
|
readonly WINNER: "winner";
|
|
152
152
|
};
|
|
153
153
|
readonly PRE_ORDER_PRODUCTION_STATUS_VALUES: {
|
|
154
|
+
readonly UPCOMING: "upcoming";
|
|
154
155
|
readonly IN_PRODUCTION: "in_production";
|
|
155
|
-
readonly
|
|
156
|
-
readonly DELAYED: "delayed";
|
|
157
|
-
readonly CANCELLED: "cancelled";
|
|
156
|
+
readonly READY_TO_SHIP: "ready_to_ship";
|
|
158
157
|
};
|
|
159
158
|
readonly PRIZE_REVEAL_STATUS_VALUES: {
|
|
160
159
|
readonly PENDING: "pending";
|
|
@@ -246,9 +245,11 @@ export declare const ORDER_FIELDS: {
|
|
|
246
245
|
};
|
|
247
246
|
readonly PAYMENT_STATUS_VALUES: {
|
|
248
247
|
readonly PENDING: "pending";
|
|
248
|
+
readonly PROCESSING: "processing";
|
|
249
249
|
readonly PAID: "paid";
|
|
250
250
|
readonly FAILED: "failed";
|
|
251
251
|
readonly REFUNDED: "refunded";
|
|
252
|
+
readonly PARTIAL_REFUND: "partial_refund";
|
|
252
253
|
};
|
|
253
254
|
readonly PAYOUT_STATUS_VALUES: {
|
|
254
255
|
readonly ELIGIBLE: "eligible";
|
|
@@ -322,6 +323,8 @@ export declare const BID_FIELDS: {
|
|
|
322
323
|
readonly WON: "won";
|
|
323
324
|
readonly LOST: "lost";
|
|
324
325
|
readonly CANCELLED: "cancelled";
|
|
326
|
+
/** Won, then the buyer let the payment window lapse. Was missing here. */
|
|
327
|
+
readonly FORFEITED: "forfeited";
|
|
325
328
|
};
|
|
326
329
|
};
|
|
327
330
|
export declare const AD_FIELDS: {
|
|
@@ -443,7 +446,6 @@ export declare const PAYOUT_FIELDS: {
|
|
|
443
446
|
readonly PROCESSING: "processing";
|
|
444
447
|
readonly PAID: "paid";
|
|
445
448
|
readonly FAILED: "failed";
|
|
446
|
-
readonly CANCELLED: "cancelled";
|
|
447
449
|
};
|
|
448
450
|
};
|
|
449
451
|
export declare const STORE_FIELDS: {
|
|
@@ -687,9 +689,10 @@ export declare const SCAMMER_FIELDS: {
|
|
|
687
689
|
readonly VERIFIED_BY: "verifiedBy";
|
|
688
690
|
readonly CREATED_AT: "createdAt";
|
|
689
691
|
readonly STATUS_VALUES: {
|
|
690
|
-
readonly
|
|
692
|
+
readonly PENDING_REVIEW: "pending_review";
|
|
691
693
|
readonly VERIFIED: "verified";
|
|
692
694
|
readonly REJECTED: "rejected";
|
|
695
|
+
readonly REMOVED: "removed";
|
|
693
696
|
};
|
|
694
697
|
};
|
|
695
698
|
export declare const SUPPORT_TICKET_FIELDS: {
|
|
@@ -712,7 +715,6 @@ export declare const SUPPORT_TICKET_FIELDS: {
|
|
|
712
715
|
readonly PRIORITY_VALUES: {
|
|
713
716
|
readonly LOW: "low";
|
|
714
717
|
readonly NORMAL: "normal";
|
|
715
|
-
readonly MEDIUM: "medium";
|
|
716
718
|
readonly HIGH: "high";
|
|
717
719
|
readonly URGENT: "urgent";
|
|
718
720
|
};
|
|
@@ -159,11 +159,19 @@ export const PRODUCT_FIELDS = {
|
|
|
159
159
|
SELLER: "seller",
|
|
160
160
|
WINNER: "winner",
|
|
161
161
|
},
|
|
162
|
+
/*
|
|
163
|
+
* Corrected 2026-08-24 (W3). This block used to read
|
|
164
|
+
* {in_production, ready, delayed, cancelled} — and `ready`, `delayed` and
|
|
165
|
+
* `cancelled` were values no product has ever held. `ProductDocument`
|
|
166
|
+
* declares "upcoming" | "in_production" | "ready_to_ship", the write schema
|
|
167
|
+
* agrees, and all 9 seeded pre-orders store one of those three. It had zero
|
|
168
|
+
* consumers, which is the only reason it never produced a visibly broken
|
|
169
|
+
* filter chip (Recurrent Root Cause #33).
|
|
170
|
+
*/
|
|
162
171
|
PRE_ORDER_PRODUCTION_STATUS_VALUES: {
|
|
172
|
+
UPCOMING: "upcoming",
|
|
163
173
|
IN_PRODUCTION: "in_production",
|
|
164
|
-
|
|
165
|
-
DELAYED: "delayed",
|
|
166
|
-
CANCELLED: "cancelled",
|
|
174
|
+
READY_TO_SHIP: "ready_to_ship",
|
|
167
175
|
},
|
|
168
176
|
PRIZE_REVEAL_STATUS_VALUES: {
|
|
169
177
|
PENDING: "pending",
|
|
@@ -261,11 +269,19 @@ export const ORDER_FIELDS = {
|
|
|
261
269
|
RETURN_REQUESTED: "return_requested",
|
|
262
270
|
REFUNDED: "refunded",
|
|
263
271
|
},
|
|
272
|
+
/*
|
|
273
|
+
* Corrected 2026-08-24 (W3) — `processing` and `partial_refund` were
|
|
274
|
+
* missing, so this listed 4 of the real 6. `PaymentStatus`
|
|
275
|
+
* (features/orders/types/index.ts) is the source; a partial refund is a
|
|
276
|
+
* state real orders reach, and W2 put it on the order timeline.
|
|
277
|
+
*/
|
|
264
278
|
PAYMENT_STATUS_VALUES: {
|
|
265
279
|
PENDING: "pending",
|
|
280
|
+
PROCESSING: "processing",
|
|
266
281
|
PAID: "paid",
|
|
267
282
|
FAILED: "failed",
|
|
268
283
|
REFUNDED: "refunded",
|
|
284
|
+
PARTIAL_REFUND: "partial_refund",
|
|
269
285
|
},
|
|
270
286
|
PAYOUT_STATUS_VALUES: {
|
|
271
287
|
ELIGIBLE: "eligible",
|
|
@@ -339,12 +355,22 @@ export const BID_FIELDS = {
|
|
|
339
355
|
AUTO_MAX_BID: "autoMaxBid",
|
|
340
356
|
CREATED_AT: "createdAt",
|
|
341
357
|
UPDATED_AT: "updatedAt",
|
|
358
|
+
/*
|
|
359
|
+
* Corrected 2026-08-24 (W3). Verified against the feature's own union AND
|
|
360
|
+
* against what is actually stored. This file is a deliberate LEAF — it
|
|
361
|
+
* imports nothing, and `features/products/types/index.ts` imports IT — so it
|
|
362
|
+
* cannot re-export the feature unions without a cycle. The values are
|
|
363
|
+
* therefore duplicated on purpose, and `audit-field-names-union-parity`
|
|
364
|
+
* blocks them drifting again.
|
|
365
|
+
*/
|
|
342
366
|
STATUS_VALUES: {
|
|
343
367
|
ACTIVE: "active",
|
|
344
368
|
OUTBID: "outbid",
|
|
345
369
|
WON: "won",
|
|
346
370
|
LOST: "lost",
|
|
347
371
|
CANCELLED: "cancelled",
|
|
372
|
+
/** Won, then the buyer let the payment window lapse. Was missing here. */
|
|
373
|
+
FORFEITED: "forfeited",
|
|
348
374
|
},
|
|
349
375
|
};
|
|
350
376
|
// ============================================================================
|
|
@@ -476,12 +502,17 @@ export const PAYOUT_FIELDS = {
|
|
|
476
502
|
STATUS: "status",
|
|
477
503
|
CREATED_AT: "createdAt",
|
|
478
504
|
UPDATED_AT: "updatedAt",
|
|
505
|
+
/*
|
|
506
|
+
* Corrected 2026-08-24 (W3) — `cancelled` was listed here and is NOT a
|
|
507
|
+
* member of `PayoutStatus` (features/payments/schemas/firestore.ts:18,
|
|
508
|
+
* pending|processing|paid|failed). A chip or badge keyed on it could only
|
|
509
|
+
* ever match zero rows (Recurrent Root Cause #33).
|
|
510
|
+
*/
|
|
479
511
|
STATUS_VALUES: {
|
|
480
512
|
PENDING: "pending",
|
|
481
513
|
PROCESSING: "processing",
|
|
482
514
|
PAID: "paid",
|
|
483
515
|
FAILED: "failed",
|
|
484
|
-
CANCELLED: "cancelled",
|
|
485
516
|
},
|
|
486
517
|
};
|
|
487
518
|
// ============================================================================
|
|
@@ -771,10 +802,17 @@ export const SCAMMER_FIELDS = {
|
|
|
771
802
|
REPORTED_BY: "reportedBy",
|
|
772
803
|
VERIFIED_BY: "verifiedBy",
|
|
773
804
|
CREATED_AT: "createdAt",
|
|
805
|
+
/*
|
|
806
|
+
* Corrected 2026-08-24 (W3). Two defects: the real stored value is
|
|
807
|
+
* `pending_review`, not `pending` (the seeded scammer profile stores
|
|
808
|
+
* `pending_review`), and `removed` was missing entirely. Already flagged in
|
|
809
|
+
* CLAUDE.md's Root Cause #34 and never actioned.
|
|
810
|
+
*/
|
|
774
811
|
STATUS_VALUES: {
|
|
775
|
-
|
|
812
|
+
PENDING_REVIEW: "pending_review",
|
|
776
813
|
VERIFIED: "verified",
|
|
777
814
|
REJECTED: "rejected",
|
|
815
|
+
REMOVED: "removed",
|
|
778
816
|
},
|
|
779
817
|
};
|
|
780
818
|
// ============================================================================
|
|
@@ -797,10 +835,14 @@ export const SUPPORT_TICKET_FIELDS = {
|
|
|
797
835
|
RESOLVED: "resolved",
|
|
798
836
|
CLOSED: "closed",
|
|
799
837
|
},
|
|
838
|
+
/*
|
|
839
|
+
* Corrected 2026-08-24 (W3) — `medium` is not a member of
|
|
840
|
+
* `TicketPriorityValues` (low|normal|high|urgent). `normal` is the
|
|
841
|
+
* middle value.
|
|
842
|
+
*/
|
|
800
843
|
PRIORITY_VALUES: {
|
|
801
844
|
LOW: "low",
|
|
802
845
|
NORMAL: "normal",
|
|
803
|
-
MEDIUM: "medium",
|
|
804
846
|
HIGH: "high",
|
|
805
847
|
URGENT: "urgent",
|
|
806
848
|
},
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { sortBy, sieveFilter, SIEVE_OP } from "../../../utils/sieve-builder";
|
|
4
4
|
import { ACCOUNT_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
5
5
|
import { ROUTES } from "../../../constants/index";
|
|
6
|
-
import {
|
|
6
|
+
import { useState } from "react";
|
|
7
|
+
import { Div, Span, Stack, TextLink, RecordDetailModal } from "../../../ui";
|
|
8
|
+
import { buildBidDetailFields, bidStatusBadge } from "../../auctions/components/bid-detail-fields";
|
|
7
9
|
import { FieldSelect } from "../../../ui/forms";
|
|
8
10
|
import { AuctionBidsTable } from "../../auctions/components/AuctionBidsTable";
|
|
9
11
|
import { DataListingView } from "../../admin/components/DataListingView";
|
|
@@ -21,6 +23,11 @@ const STATUS_OPTIONS = [
|
|
|
21
23
|
{ value: "cancelled", label: "Cancelled" },
|
|
22
24
|
];
|
|
23
25
|
export function UserBidsView() {
|
|
26
|
+
// A bid could be seen in this list and never opened — no row click, no row
|
|
27
|
+
// action, no detail page. The "Browse auctions" link in the empty state is
|
|
28
|
+
// not an affordance: it is not row-scoped, and it only shows when there are
|
|
29
|
+
// no bids at all.
|
|
30
|
+
const [detail, setDetail] = useState(null);
|
|
24
31
|
const config = {
|
|
25
32
|
portal: "user",
|
|
26
33
|
title: "My Bids",
|
|
@@ -40,8 +47,9 @@ export function UserBidsView() {
|
|
|
40
47
|
if (isLoading) {
|
|
41
48
|
return (_jsx(Stack, { gap: "md", children: Array.from({ length: 3 }).map((_, i) => (_jsx(Div, { className: "h-16 animate-pulse border border-[var(--appkit-color-border)]", rounded: "xl" }, i))) }));
|
|
42
49
|
}
|
|
43
|
-
return (_jsx(AuctionBidsTable, { bids: rows, portal: "buyer", totalPages: 1, currentPage: 1, onPageChange: () => { }, emptyLabel: _jsxs(Span, { children: ["You haven't placed any bids yet.", " ", _jsx(TextLink, { href: String(ROUTES.PUBLIC.AUCTIONS), children: "Browse auctions" })] }) }));
|
|
50
|
+
return (_jsx(AuctionBidsTable, { bids: rows, portal: "buyer", onRowClick: (bid) => setDetail(bid), totalPages: 1, currentPage: 1, onPageChange: () => { }, emptyLabel: _jsxs(Span, { children: ["You haven't placed any bids yet.", " ", _jsx(TextLink, { href: String(ROUTES.PUBLIC.AUCTIONS), children: "Browse auctions" })] }) }));
|
|
44
51
|
},
|
|
45
52
|
};
|
|
46
|
-
|
|
53
|
+
const badge = detail ? bidStatusBadge(detail.status) : null;
|
|
54
|
+
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(RecordDetailModal, { isOpen: detail !== null, onClose: () => setDetail(null), title: detail?.productTitle || "Bid", badges: badge ? [{ label: badge.label }] : undefined, fields: detail ? buildBidDetailFields(detail, "buyer") : undefined, footer: detail ? (_jsx(TextLink, { href: String(ROUTES.PUBLIC.AUCTION_DETAIL(detail.productId)), children: "View auction \u2192" })) : undefined })] }));
|
|
47
55
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { Order } from "../../orders/types";
|
|
2
2
|
export interface UserReturnsViewProps {
|
|
3
|
+
/**
|
|
4
|
+
* Optional override. When omitted the card still opens — see below.
|
|
5
|
+
*/
|
|
3
6
|
onOrderClick?: (order: Order) => void;
|
|
4
7
|
}
|
|
5
8
|
export declare function UserReturnsView({ onOrderClick }: UserReturnsViewProps): import("react").JSX.Element;
|
|
@@ -3,6 +3,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { sortBy } from "../../../constants/sort";
|
|
4
4
|
import { ACCOUNT_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
5
5
|
import { Div, Grid, Stack, Text } from "../../../ui";
|
|
6
|
+
import { useRouter } from "next/navigation";
|
|
7
|
+
import { ROUTES } from "../../../next/routing/route-map";
|
|
6
8
|
import { DataListingView } from "../../admin/components/DataListingView";
|
|
7
9
|
import { OrderCard } from "../../orders/components/OrdersList";
|
|
8
10
|
const SORT_OPTIONS = [
|
|
@@ -11,6 +13,11 @@ const SORT_OPTIONS = [
|
|
|
11
13
|
{ value: sortBy("createdAt", "ASC"), label: "Oldest" },
|
|
12
14
|
];
|
|
13
15
|
export function UserReturnsView({ onOrderClick }) {
|
|
16
|
+
const router = useRouter();
|
|
17
|
+
// Client-side navigation, not a full reload — the row is a link in behaviour
|
|
18
|
+
// even though the card itself contains its own controls, so wrapping it in
|
|
19
|
+
// an <a> would nest interactive content inside a link.
|
|
20
|
+
const openOrder = (order) => router.push(String(ROUTES.USER.ORDER_DETAIL(order.id)));
|
|
14
21
|
const config = {
|
|
15
22
|
portal: "user",
|
|
16
23
|
title: "Returns & Refunds",
|
|
@@ -32,7 +39,16 @@ export function UserReturnsView({ onOrderClick }) {
|
|
|
32
39
|
if (rows.length === 0) {
|
|
33
40
|
return _jsx(Text, { color: "muted", children: "You have no return or refund requests." });
|
|
34
41
|
}
|
|
35
|
-
return (_jsx(Grid, { gap: "md", className: "grid-cols-1", children: rows.map((order) => (_jsx(OrderCard, { order: order,
|
|
42
|
+
return (_jsx(Grid, { gap: "md", className: "grid-cols-1", children: rows.map((order) => (_jsx(OrderCard, { order: order,
|
|
43
|
+
// A return IS an order, and its detail page already exists — so
|
|
44
|
+
// the row opens whether or not a consumer supplies a handler.
|
|
45
|
+
//
|
|
46
|
+
// It was previously openable ONLY because the single consumer
|
|
47
|
+
// happened to pass `onOrderClick`; a second one that forgot
|
|
48
|
+
// would have produced a listing whose rows do nothing, and no
|
|
49
|
+
// audit could have seen it because the affordance lived in the
|
|
50
|
+
// caller. Defaulting here makes it structural.
|
|
51
|
+
onClick: onOrderClick ?? openOrder }, order.id))) }));
|
|
36
52
|
},
|
|
37
53
|
};
|
|
38
54
|
return _jsx(DataListingView, { config: config });
|
|
@@ -23,6 +23,7 @@ const ACTION_LABELS = {
|
|
|
23
23
|
checkout_bypass: "Admin checkout bypass",
|
|
24
24
|
coupon_update: "Coupon updated",
|
|
25
25
|
payout_mark_paid: "Payout marked paid",
|
|
26
|
+
offer_cancel: "Offer cancelled",
|
|
26
27
|
store_status_change: "Store status changed",
|
|
27
28
|
user_role_change: "User role changed",
|
|
28
29
|
};
|
|
@@ -5,11 +5,12 @@ import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit/client";
|
|
|
5
5
|
import { sortBy } from "@mohasinac/appkit/client";
|
|
6
6
|
import React, { useState } from "react";
|
|
7
7
|
import { useQueryClient } from "@tanstack/react-query";
|
|
8
|
-
import { ConfirmDeleteModal, FilterChipGroup, ListingLayout, RowActionMenu, useToast } from "../../../ui";
|
|
8
|
+
import { ConfirmDeleteModal, FilterChipGroup, ListingLayout, RecordDetailModal, RowActionMenu, useToast, } from "../../../ui";
|
|
9
9
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
10
|
import { ADMIN_BID_STATUS_TABS } from "../constants/filter-tabs";
|
|
11
11
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
12
12
|
import { ROW_ACTION_META, ROW_ACTION_ID } from "../../products/constants/action-defs";
|
|
13
|
+
import { buildBidDetailFields, bidStatusBadge } from "../../auctions/components/bid-detail-fields";
|
|
13
14
|
import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../hooks/useAdminListingData";
|
|
14
15
|
import { DataListingView } from "./DataListingView";
|
|
15
16
|
import { apiClient } from "../../../http";
|
|
@@ -18,6 +19,7 @@ export function AdminBidsView({ children, ...props }) {
|
|
|
18
19
|
const { showToast } = useToast();
|
|
19
20
|
const [cancelOpen, setCancelOpen] = useState(false);
|
|
20
21
|
const [selectedRow, setSelectedRow] = useState(null);
|
|
22
|
+
const [detail, setDetail] = useState(null);
|
|
21
23
|
const cancelMutation = useApiMutation({
|
|
22
24
|
mutationFn: async (bidId) => {
|
|
23
25
|
await apiClient.patch(ADMIN_ENDPOINTS.BID_BY_ID(bidId), { status: "cancelled" });
|
|
@@ -58,6 +60,7 @@ export function AdminBidsView({ children, ...props }) {
|
|
|
58
60
|
secondary: toStringValue(item.bidderId ?? item.bidderName ?? item.userId, "Unknown bidder"),
|
|
59
61
|
status: toStringValue(item.status, "active"),
|
|
60
62
|
updatedAt: toRelativeDate(item.bidDate ?? item.updatedAt ?? item.createdAt),
|
|
63
|
+
detail: item,
|
|
61
64
|
})),
|
|
62
65
|
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
63
66
|
buildFilters: (state) => state.status && state.status !== "All" ? sieveFilter("status", SIEVE_OP.EQ, state.status) : undefined,
|
|
@@ -72,6 +75,13 @@ export function AdminBidsView({ children, ...props }) {
|
|
|
72
75
|
renderRowActions: (row) => {
|
|
73
76
|
const isCancelled = row.status === "cancelled" || row.status === "voided";
|
|
74
77
|
return (_jsx(RowActionMenu, { actions: [
|
|
78
|
+
// A menu of pure MUTATIONS is not a detail affordance (Root Cause
|
|
79
|
+
// #56): it let an admin cancel a bid they had never been able to
|
|
80
|
+
// read. View comes first for that reason.
|
|
81
|
+
{
|
|
82
|
+
label: ROW_ACTION_META[ROW_ACTION_ID.VIEW].label,
|
|
83
|
+
onClick: () => setDetail(row),
|
|
84
|
+
},
|
|
75
85
|
{
|
|
76
86
|
label: ROW_ACTION_META[ROW_ACTION_ID.CANCEL].label,
|
|
77
87
|
destructive: ROW_ACTION_META[ROW_ACTION_ID.CANCEL].destructive,
|
|
@@ -85,7 +95,10 @@ export function AdminBidsView({ children, ...props }) {
|
|
|
85
95
|
},
|
|
86
96
|
renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: ADMIN_BID_STATUS_TABS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) })),
|
|
87
97
|
};
|
|
88
|
-
|
|
98
|
+
const detailBadge = detail ? bidStatusBadge(detail.status) : null;
|
|
99
|
+
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(RecordDetailModal, { isOpen: detail !== null, onClose: () => setDetail(null), title: toStringValue(detail?.detail?.productTitle, "Bid"), badges: detailBadge ? [{ label: detailBadge.label }] : undefined, fields: detail
|
|
100
|
+
? buildBidDetailFields(detail.detail, "admin")
|
|
101
|
+
: undefined }), _jsx(ConfirmDeleteModal, { isOpen: cancelOpen, onClose: () => {
|
|
89
102
|
setCancelOpen(false);
|
|
90
103
|
setSelectedRow(null);
|
|
91
104
|
}, onConfirm: () => {
|