@mohasinac/appkit 4.14.0 → 4.16.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.d.ts +9 -2
- package/dist/_internal/shared/actions/action-registry.js +458 -7
- 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/blog/schema.d.ts +4 -4
- package/dist/_internal/shared/features/cart/schema.d.ts +25 -20
- package/dist/_internal/shared/features/cart/schema.js +15 -0
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +22 -22
- package/dist/_internal/shared/features/orders/schema.d.ts +4 -4
- package/dist/_internal/shared/features/products/schema.d.ts +27 -27
- package/dist/_internal/shared/features/promotions/schema.d.ts +4 -4
- package/dist/_internal/shared/features/reviews/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/contracts/extend.d.ts +29 -0
- package/dist/contracts/extend.js +20 -0
- package/dist/contracts/index.d.ts +2 -1
- package/dist/contracts/index.js +2 -0
- 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/AdminViewCards.js +24 -17
- package/dist/features/admin/components/DataListingView.js +15 -1
- package/dist/features/admin/components/DataTable.js +7 -17
- 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/auctions/schemas/index.d.ts +14 -14
- package/dist/features/audit-log/schemas/firestore.d.ts +14 -0
- package/dist/features/audit-log/schemas/firestore.js +7 -0
- package/dist/features/auth/schemas/index.d.ts +2 -2
- package/dist/features/blog/actions/blog-actions.d.ts +7 -7
- package/dist/features/blog/schemas/blog-form.d.ts +80 -0
- package/dist/features/blog/schemas/blog-form.js +100 -0
- package/dist/features/blog/schemas/index.d.ts +10 -10
- package/dist/features/cart/schemas/index.d.ts +3 -3
- package/dist/features/catalogue/schemas/validation.d.ts +12 -12
- package/dist/features/categories/schemas/index.d.ts +16 -16
- package/dist/features/collections/schemas/index.d.ts +8 -8
- 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/events/schemas/index.d.ts +2 -2
- package/dist/features/faq/actions/faq-actions.d.ts +6 -6
- package/dist/features/faq/schemas/index.d.ts +6 -6
- 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/grouped/schemas/index.d.ts +4 -4
- 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 +71 -40
- package/dist/features/homepage/schemas/index.js +24 -0
- package/dist/features/messages/schemas/index.d.ts +2 -2
- 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/schemas/index.d.ts +24 -24
- package/dist/features/orders/types/index.d.ts +35 -7
- package/dist/features/pre-orders/schemas/index.d.ts +4 -4
- package/dist/features/products/components/GroupSettingsPanel.js +5 -1
- package/dist/features/products/schemas/index.d.ts +38 -38
- package/dist/features/products/schemas/product-features.validators.d.ts +75 -2
- package/dist/features/products/schemas/product-features.validators.js +63 -0
- package/dist/features/promotions/schemas/index.d.ts +14 -14
- package/dist/features/reviews/schemas/index.d.ts +14 -14
- 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/scams/schemas/index.d.ts +2 -2
- package/dist/features/search/schemas/index.d.ts +2 -2
- 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/index.d.ts +2 -2
- 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/shipments/schemas/validation.d.ts +22 -22
- 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/stores/schemas/index.d.ts +4 -4
- package/dist/features/support/schemas/index.d.ts +4 -4
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +350 -0
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- 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 +734 -101
- 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/DataTable.js +4 -2
- package/dist/ui/columns/build-columns.d.ts +6 -1
- package/dist/ui/columns/build-columns.js +53 -0
- package/dist/ui/columns/cell-renderers.d.ts +68 -0
- package/dist/ui/columns/cell-renderers.js +111 -0
- package/dist/ui/columns/column-renderers.d.ts +6 -1
- package/dist/ui/columns/column-renderers.js +6 -1
- package/dist/ui/columns/index.d.ts +2 -1
- package/dist/ui/columns/index.js +5 -1
- package/dist/ui/components/Button.js +27 -2
- package/dist/ui/components/RecordDetailModal.d.ts +10 -1
- package/dist/ui/components/RecordDetailModal.js +2 -2
- package/dist/ui/icons/icon-registry.d.ts +65 -0
- package/dist/ui/icons/icon-registry.js +115 -0
- 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
package/dist/schemas/registry.js
CHANGED
|
@@ -96,8 +96,56 @@ const api = {
|
|
|
96
96
|
// `audit-form-schema` already enforces presence at FormShell sites; this
|
|
97
97
|
// registry centralizes the schemas for cross-route reuse.
|
|
98
98
|
// ---------------------------------------------------------------------------
|
|
99
|
+
/**
|
|
100
|
+
* Entity id -> the form schema that validates it.
|
|
101
|
+
*
|
|
102
|
+
* Populated one entity per slice from W4 on. Deliberately NOT pre-declared
|
|
103
|
+
* with placeholder keys: an empty bucket is honest, and a bucket full of
|
|
104
|
+
* `undefined` reads as "migrated" to everyone who comes after — this codebase
|
|
105
|
+
* already documents eight abandoned migrations that started exactly that way.
|
|
106
|
+
*
|
|
107
|
+
* `roundtrip-diff` reads this. An entity registered here is checked, on every
|
|
108
|
+
* run, against real documents for silent field loss; an entity absent from it
|
|
109
|
+
* has no such protection, which is the whole reason to register early.
|
|
110
|
+
*/
|
|
111
|
+
import { blogDraftSchema } from "../features/blog/schemas/blog-form";
|
|
112
|
+
import { eventDraftSchema } from "../features/events/schemas/event-form";
|
|
113
|
+
import { productFeatureFormSchema } from "../features/products/schemas/product-features.validators";
|
|
114
|
+
import { storeCategoryFormSchema } from "../features/store-extensions/schemas/store-category-form";
|
|
115
|
+
import { listingTemplateFormSchema } from "../features/store-extensions/schemas/listing-template-form";
|
|
116
|
+
import { payoutMethodFormSchema } from "../features/store-extensions/schemas/payout-method-form";
|
|
117
|
+
import { shippingConfigFormSchema } from "../features/store-extensions/schemas/shipping-config-form";
|
|
118
|
+
import { groupedListingFormSchema } from "../features/grouped/schemas/grouped-listing-form";
|
|
119
|
+
import { sellerCouponFormSchema } from "../features/seller/schemas/coupon-form";
|
|
120
|
+
import { customRoleFormSchema } from "../features/store-extensions/schemas/custom-role-form";
|
|
121
|
+
import { moderationReviewFormSchema } from "../features/store-extensions/schemas/moderation-review-form";
|
|
122
|
+
import { reportReviewFormSchema } from "../features/store-extensions/schemas/report-review-form";
|
|
123
|
+
import { reportCreateSchema } from "../features/store-extensions/schemas/report-create-form";
|
|
124
|
+
import { itemRequestCreateSchema } from "../features/store-extensions/schemas/item-request-create-form";
|
|
125
|
+
import { analyticsAlertCreateSchema, analyticsCardCreateSchema, } from "../features/store-extensions/schemas/analytics-forms";
|
|
126
|
+
import { storeGoogleConfigUpdateSchema } from "../features/store-extensions/schemas/google-config-form";
|
|
127
|
+
import { adminNotificationCreateSchema } from "../features/store-extensions/schemas/admin-notification-form";
|
|
128
|
+
import { homepageSectionCreateSchema } from "../features/homepage/schemas/index";
|
|
99
129
|
const forms = {
|
|
100
|
-
|
|
130
|
+
blog: blogDraftSchema,
|
|
131
|
+
event: eventDraftSchema,
|
|
132
|
+
productFeature: productFeatureFormSchema,
|
|
133
|
+
storeCategory: storeCategoryFormSchema,
|
|
134
|
+
listingTemplate: listingTemplateFormSchema,
|
|
135
|
+
payoutMethod: payoutMethodFormSchema,
|
|
136
|
+
shippingConfig: shippingConfigFormSchema,
|
|
137
|
+
groupedListing: groupedListingFormSchema,
|
|
138
|
+
sellerCoupon: sellerCouponFormSchema,
|
|
139
|
+
customRole: customRoleFormSchema,
|
|
140
|
+
moderationReview: moderationReviewFormSchema,
|
|
141
|
+
reportReview: reportReviewFormSchema,
|
|
142
|
+
reportCreate: reportCreateSchema,
|
|
143
|
+
itemRequest: itemRequestCreateSchema,
|
|
144
|
+
analyticsAlert: analyticsAlertCreateSchema,
|
|
145
|
+
analyticsCard: analyticsCardCreateSchema,
|
|
146
|
+
storeGoogleConfig: storeGoogleConfigUpdateSchema,
|
|
147
|
+
adminNotification: adminNotificationCreateSchema,
|
|
148
|
+
homepageSection: homepageSectionCreateSchema,
|
|
101
149
|
};
|
|
102
150
|
// ---------------------------------------------------------------------------
|
|
103
151
|
// Sieve filter-grammar schemas — populated by W6. Each collection registers
|
|
@@ -161,6 +209,21 @@ export function lookupApiSchema(key) {
|
|
|
161
209
|
}
|
|
162
210
|
return entry;
|
|
163
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* The form schema for an entity.
|
|
214
|
+
*
|
|
215
|
+
* Throws rather than returning undefined: a caller asking for a schema it
|
|
216
|
+
* expects to exist should fail loudly at the call site, not silently skip
|
|
217
|
+
* validation and strip every field on the next save.
|
|
218
|
+
*/
|
|
219
|
+
export function lookupFormSchema(entity) {
|
|
220
|
+
const entry = SCHEMAS.forms[entity];
|
|
221
|
+
if (!entry) {
|
|
222
|
+
throw new Error(`[schemas] No form schema registered for "${String(entity)}". ` +
|
|
223
|
+
`Register it in SCHEMAS.forms as part of that entity's slice.`);
|
|
224
|
+
}
|
|
225
|
+
return entry;
|
|
226
|
+
}
|
|
164
227
|
export function lookupFirestoreSchema(collection) {
|
|
165
228
|
const entry = SCHEMAS.firestore[collection];
|
|
166
229
|
if (!entry) {
|
|
@@ -143,5 +143,35 @@ const _rawBidsSeedData = [
|
|
|
143
143
|
currentBid: 1450,
|
|
144
144
|
bidderIds: ["user-ananya-collector", "user-rohit-collector", "user-meera-bey"],
|
|
145
145
|
}),
|
|
146
|
+
// auction-beyblade-burst-spriggan-requiem-bought-out — a BUYOUT ended it.
|
|
147
|
+
//
|
|
148
|
+
// Three competitive bids that lost, then the buyout that won. A buyout is a
|
|
149
|
+
// real BidDocument (`isBuyout: true`) — it is not a bid-free purchase, which
|
|
150
|
+
// is why the order's `sourceContext.bidCount` is 3 rather than 0: the buyout
|
|
151
|
+
// itself is excluded from the "against N bidders" figure, the three it beat
|
|
152
|
+
// are not. `standingBidAtBuyout` is read from these bids and NOT from
|
|
153
|
+
// `product.currentBid`, because a pending buyout never writes that mirror.
|
|
154
|
+
...buildLadder({
|
|
155
|
+
productId: "auction-beyblade-burst-spriggan-requiem-bought-out",
|
|
156
|
+
productTitle: "Beyblade Burst B-128 Spriggan Requiem (Ended — Bought Out)",
|
|
157
|
+
startingBid: 2499,
|
|
158
|
+
currentBid: 3100,
|
|
159
|
+
bidderIds: ["user-meera-bey", "user-ananya-collector", "user-rohit-collector"],
|
|
160
|
+
closed: true,
|
|
161
|
+
}).map((b) => ({ ...b, status: "lost", isWinning: false })),
|
|
162
|
+
{
|
|
163
|
+
id: "bid-beyblade-burst-spriggan-requiem-seto-kaiba-20260820-buyout",
|
|
164
|
+
productId: "auction-beyblade-burst-spriggan-requiem-bought-out",
|
|
165
|
+
productTitle: "Beyblade Burst B-128 Spriggan Requiem (Ended — Bought Out)",
|
|
166
|
+
userId: "user-seto-kaiba",
|
|
167
|
+
userName: "Mock User 2",
|
|
168
|
+
bidAmount: 4999,
|
|
169
|
+
status: "won",
|
|
170
|
+
isWinning: true,
|
|
171
|
+
isBuyout: true,
|
|
172
|
+
bidDate: daysAgo(4),
|
|
173
|
+
createdAt: daysAgo(4),
|
|
174
|
+
orderId: "order-1-20260820-buyout",
|
|
175
|
+
},
|
|
146
176
|
];
|
|
147
177
|
export const bidsSeedData = _rawBidsSeedData.map(withBidDefaults);
|
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* WHY: Seeds offers for the Beyblade marketplace —
|
|
3
|
-
*
|
|
2
|
+
* WHY: Seeds offers for the Beyblade marketplace — every status, plus a real
|
|
3
|
+
* multi-round negotiation. Before W2 a counter-offer created an unlinked
|
|
4
|
+
* document, so no fixture could demonstrate a chain and the timeline had
|
|
5
|
+
* nothing to render.
|
|
6
|
+
* WHAT: 10 offers. pending (2), accepted (1), declined (1), countered (1),
|
|
7
|
+
* expired (1), withdrawn (3 — one a genuine walk-away, two superseded
|
|
8
|
+
* rounds of the Metal Storm Pegasus chain), paid (1).
|
|
9
|
+
*
|
|
10
|
+
* ## The Metal Storm Pegasus chain
|
|
11
|
+
*
|
|
12
|
+
* Three linked documents ending at the pre-existing `…-countered` id, so the
|
|
13
|
+
* final round keeps the id every other fixture and checklist case already
|
|
14
|
+
* refers to and `appkit-seed delete` still cleans the whole chain up:
|
|
15
|
+
*
|
|
16
|
+
* …-r1 (withdrawn, superseded by r2) → …-r2 (withdrawn, superseded by the
|
|
17
|
+
* countered offer) → …-countered (round 3, live)
|
|
18
|
+
*
|
|
19
|
+
* Two withdrawn plus one live keeps `hasActiveOffer` consistent, and three
|
|
20
|
+
* rounds makes the 3-offer chain cap demonstrable.
|
|
21
|
+
*
|
|
22
|
+
* ## One fixture deliberately has NO statusHistory
|
|
23
|
+
*
|
|
24
|
+
* `offer-kaiba-x-wizard-arrow-expired` is left history-less on purpose — see
|
|
25
|
+
* the comment at that fixture. It is the only way the timeline's legacy branch
|
|
26
|
+
* is testable, and it is the exact shape of every offer written before W2.
|
|
4
27
|
*
|
|
5
28
|
* EXPORTS:
|
|
6
29
|
* offersSeedData — Array of Partial<OfferDocument> for seed runner
|
|
@@ -16,6 +39,23 @@ import { OfferStatusValues } from "../features/seller/schemas/firestore";
|
|
|
16
39
|
const NOW = new Date();
|
|
17
40
|
const daysAgo = (n) => new Date(NOW.getTime() - n * 86400000);
|
|
18
41
|
const daysFromNow = (n) => new Date(NOW.getTime() + n * 86400000);
|
|
42
|
+
/**
|
|
43
|
+
* One history entry, in the same delta shape `withHistory()` produces at
|
|
44
|
+
* runtime — so a seeded timeline and a real one render identically.
|
|
45
|
+
*
|
|
46
|
+
* `actorUid` is the only identity a history entry may ever carry. Never a name
|
|
47
|
+
* or an email: `encryptPiiFields` is a flat top-level loop that does not
|
|
48
|
+
* descend into arrays, so a PII value placed inside `statusHistory` would be
|
|
49
|
+
* written to Firestore in plaintext and never decrypted on the way back out.
|
|
50
|
+
*/
|
|
51
|
+
function entry(at, actorRole, trigger, changes, extra = {}) {
|
|
52
|
+
return { at, actorRole, trigger, changes, ...extra };
|
|
53
|
+
}
|
|
54
|
+
const BUYER_YUGI = "user-yugi-muto";
|
|
55
|
+
const BUYER_KAIBA = "user-seto-kaiba";
|
|
56
|
+
const BUYER_ADMIN = "user-admin-letitrip";
|
|
57
|
+
const STORE = "store-beyblade-arena";
|
|
58
|
+
const PEGASUS_CHAIN_ROOT = "offer-yugi-metal-storm-pegasus-r1";
|
|
19
59
|
export const offersSeedData = [
|
|
20
60
|
// ── 1. PENDING — Rehan → Beyblade Arena — Burst Valkyrie ────────────────
|
|
21
61
|
{
|
|
@@ -35,6 +75,12 @@ export const offersSeedData = [
|
|
|
35
75
|
expiresAt: daysFromNow(3),
|
|
36
76
|
createdAt: daysAgo(0),
|
|
37
77
|
updatedAt: daysAgo(0),
|
|
78
|
+
statusHistory: [
|
|
79
|
+
entry(daysAgo(0), "buyer", "makeOffer", {
|
|
80
|
+
status: { from: null, to: "pending" },
|
|
81
|
+
offerAmount: { from: null, to: 780 },
|
|
82
|
+
}, { actorUid: BUYER_YUGI, note: "Would you accept ₹780 for the Burst Valkyrie?" }),
|
|
83
|
+
],
|
|
38
84
|
},
|
|
39
85
|
// ── 2. COUNTERED — Rehan → Beyblade Arena — Metal Storm Pegasus ─────────
|
|
40
86
|
{
|
|
@@ -57,6 +103,107 @@ export const offersSeedData = [
|
|
|
57
103
|
respondedAt: daysAgo(1),
|
|
58
104
|
createdAt: daysAgo(3),
|
|
59
105
|
updatedAt: daysAgo(1),
|
|
106
|
+
// Round 3 — the live end of the chain. Keeping the original id here (rather
|
|
107
|
+
// than appending an `…-r3`) means every existing reference and checklist
|
|
108
|
+
// href still resolves, and `appkit-seed delete` still removes the lot.
|
|
109
|
+
previousOfferId: "offer-yugi-metal-storm-pegasus-r2",
|
|
110
|
+
chainRootOfferId: PEGASUS_CHAIN_ROOT,
|
|
111
|
+
counterRound: 3,
|
|
112
|
+
statusHistory: [
|
|
113
|
+
entry(daysAgo(3), "buyer", "counterOfferByBuyer", {
|
|
114
|
+
status: { from: null, to: "pending" },
|
|
115
|
+
offerAmount: { from: 900, to: 1000 },
|
|
116
|
+
previousOfferId: { from: null, to: "offer-yugi-metal-storm-pegasus-r2" },
|
|
117
|
+
}, { actorUid: BUYER_YUGI, note: "₹1,000 — will you take it?" }),
|
|
118
|
+
entry(daysAgo(1), "seller", "respondToOffer:counter", {
|
|
119
|
+
status: { from: "pending", to: "countered" },
|
|
120
|
+
counterAmount: { from: null, to: 1150 },
|
|
121
|
+
}, { actorUid: STORE, note: "Best I can do is ₹1,150." }),
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
// ── 2a. Metal Storm Pegasus — ROUND 1 (superseded, not a walk-away) ─────
|
|
125
|
+
{
|
|
126
|
+
id: PEGASUS_CHAIN_ROOT,
|
|
127
|
+
productId: "product-beyblade-metal-storm-pegasus",
|
|
128
|
+
productTitle: "Beyblade Metal Storm Pegasus",
|
|
129
|
+
storeId: STORE,
|
|
130
|
+
storeName: "Beyblade Arena",
|
|
131
|
+
buyerUid: BUYER_YUGI,
|
|
132
|
+
buyerName: "Mock User 3",
|
|
133
|
+
buyerEmail: "rehan.sheikh@gmail.com",
|
|
134
|
+
listedPrice: 1299,
|
|
135
|
+
offerAmount: 800,
|
|
136
|
+
counterAmount: 1200,
|
|
137
|
+
currency: "INR",
|
|
138
|
+
// `withdrawn` PLUS `supersededByOfferId` is what makes the timeline render
|
|
139
|
+
// this round neutral ("Superseded") instead of negative ("Withdrawn").
|
|
140
|
+
// `superseded` is a render key, deliberately never an eighth OfferStatus —
|
|
141
|
+
// an eighth value would add a filter chip matching zero stored rows.
|
|
142
|
+
status: OfferStatusValues.WITHDRAWN,
|
|
143
|
+
buyerNote: "Starting at ₹800 for the Storm Pegasus.",
|
|
144
|
+
sellerNote: "₹1,200 and it's yours.",
|
|
145
|
+
expiresAt: daysAgo(6),
|
|
146
|
+
respondedAt: daysAgo(7),
|
|
147
|
+
createdAt: daysAgo(9),
|
|
148
|
+
updatedAt: daysAgo(7),
|
|
149
|
+
supersededByOfferId: "offer-yugi-metal-storm-pegasus-r2",
|
|
150
|
+
chainRootOfferId: PEGASUS_CHAIN_ROOT,
|
|
151
|
+
counterRound: 1,
|
|
152
|
+
statusHistory: [
|
|
153
|
+
entry(daysAgo(9), "buyer", "makeOffer", {
|
|
154
|
+
status: { from: null, to: "pending" },
|
|
155
|
+
offerAmount: { from: null, to: 800 },
|
|
156
|
+
}, { actorUid: BUYER_YUGI, note: "Starting at ₹800 for the Storm Pegasus." }),
|
|
157
|
+
entry(daysAgo(8), "seller", "respondToOffer:counter", {
|
|
158
|
+
status: { from: "pending", to: "countered" },
|
|
159
|
+
counterAmount: { from: null, to: 1200 },
|
|
160
|
+
}, { actorUid: STORE, note: "₹1,200 and it's yours." }),
|
|
161
|
+
entry(daysAgo(7), "buyer", "counterOfferByBuyer:supersede", {
|
|
162
|
+
status: { from: "countered", to: "withdrawn" },
|
|
163
|
+
supersededByOfferId: { from: null, to: "offer-yugi-metal-storm-pegasus-r2" },
|
|
164
|
+
}, { actorUid: BUYER_YUGI, reason: "Superseded by the buyer's counter" }),
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
// ── 2b. Metal Storm Pegasus — ROUND 2 (superseded) ──────────────────
|
|
168
|
+
{
|
|
169
|
+
id: "offer-yugi-metal-storm-pegasus-r2",
|
|
170
|
+
productId: "product-beyblade-metal-storm-pegasus",
|
|
171
|
+
productTitle: "Beyblade Metal Storm Pegasus",
|
|
172
|
+
storeId: STORE,
|
|
173
|
+
storeName: "Beyblade Arena",
|
|
174
|
+
buyerUid: BUYER_YUGI,
|
|
175
|
+
buyerName: "Mock User 3",
|
|
176
|
+
buyerEmail: "rehan.sheikh@gmail.com",
|
|
177
|
+
listedPrice: 1299,
|
|
178
|
+
offerAmount: 900,
|
|
179
|
+
counterAmount: 1175,
|
|
180
|
+
currency: "INR",
|
|
181
|
+
status: OfferStatusValues.WITHDRAWN,
|
|
182
|
+
buyerNote: "Can you meet me at ₹900?",
|
|
183
|
+
sellerNote: "₹1,175 is as low as I can go.",
|
|
184
|
+
expiresAt: daysAgo(3),
|
|
185
|
+
respondedAt: daysAgo(3),
|
|
186
|
+
createdAt: daysAgo(7),
|
|
187
|
+
updatedAt: daysAgo(3),
|
|
188
|
+
previousOfferId: PEGASUS_CHAIN_ROOT,
|
|
189
|
+
supersededByOfferId: "offer-yugi-metal-storm-pegasus-countered",
|
|
190
|
+
chainRootOfferId: PEGASUS_CHAIN_ROOT,
|
|
191
|
+
counterRound: 2,
|
|
192
|
+
statusHistory: [
|
|
193
|
+
entry(daysAgo(7), "buyer", "counterOfferByBuyer", {
|
|
194
|
+
status: { from: null, to: "pending" },
|
|
195
|
+
offerAmount: { from: 800, to: 900 },
|
|
196
|
+
previousOfferId: { from: null, to: PEGASUS_CHAIN_ROOT },
|
|
197
|
+
}, { actorUid: BUYER_YUGI, note: "Can you meet me at ₹900?" }),
|
|
198
|
+
entry(daysAgo(4), "seller", "respondToOffer:counter", {
|
|
199
|
+
status: { from: "pending", to: "countered" },
|
|
200
|
+
counterAmount: { from: null, to: 1175 },
|
|
201
|
+
}, { actorUid: STORE, note: "₹1,175 is as low as I can go." }),
|
|
202
|
+
entry(daysAgo(3), "buyer", "counterOfferByBuyer:supersede", {
|
|
203
|
+
status: { from: "countered", to: "withdrawn" },
|
|
204
|
+
supersededByOfferId: { from: null, to: "offer-yugi-metal-storm-pegasus-countered" },
|
|
205
|
+
}, { actorUid: BUYER_YUGI, reason: "Superseded by the buyer's counter" }),
|
|
206
|
+
],
|
|
60
207
|
},
|
|
61
208
|
// ── 3. PAID — Admin → Beyblade Arena — X Knife Shinobi (order placed) ───
|
|
62
209
|
{
|
|
@@ -81,6 +228,19 @@ export const offersSeedData = [
|
|
|
81
228
|
respondedAt: daysAgo(12),
|
|
82
229
|
createdAt: daysAgo(14),
|
|
83
230
|
updatedAt: daysAgo(11),
|
|
231
|
+
statusHistory: [
|
|
232
|
+
entry(daysAgo(14), "buyer", "makeOffer", {
|
|
233
|
+
status: { from: null, to: "pending" },
|
|
234
|
+
offerAmount: { from: null, to: 800 },
|
|
235
|
+
}, { actorUid: BUYER_ADMIN, note: "Would you accept ₹800 for the X Knife Shinobi?" }),
|
|
236
|
+
entry(daysAgo(12), "seller", "respondToOffer:accept", {
|
|
237
|
+
status: { from: "pending", to: "accepted" },
|
|
238
|
+
lockedPrice: { from: null, to: 800 },
|
|
239
|
+
}, { actorUid: STORE, note: "Accepted. Thank you!" }),
|
|
240
|
+
entry(daysAgo(11), "system", "finalizeLockedLines", {
|
|
241
|
+
status: { from: "accepted", to: "paid" },
|
|
242
|
+
}),
|
|
243
|
+
],
|
|
84
244
|
},
|
|
85
245
|
// ── 4. DECLINED — Rehan → Beyblade Arena — Burst Regalia Genesis ────────
|
|
86
246
|
{
|
|
@@ -96,12 +256,23 @@ export const offersSeedData = [
|
|
|
96
256
|
offerAmount: 1050,
|
|
97
257
|
currency: "INR",
|
|
98
258
|
status: OfferStatusValues.DECLINED,
|
|
99
|
-
|
|
100
|
-
|
|
259
|
+
// Both notes quoted prices from the pre-Beyblade catalogue this seed was
|
|
260
|
+
// narrowed away from, so a ₹1,050 offer read as "offering ₹2,500".
|
|
261
|
+
buyerNote: "Offering ₹1,050 — slightly above my budget.",
|
|
262
|
+
sellerNote: "Sorry, we cannot go below ₹1,300 for this piece.",
|
|
101
263
|
expiresAt: daysAgo(5),
|
|
102
264
|
respondedAt: daysAgo(8),
|
|
103
265
|
createdAt: daysAgo(10),
|
|
104
266
|
updatedAt: daysAgo(8),
|
|
267
|
+
statusHistory: [
|
|
268
|
+
entry(daysAgo(10), "buyer", "makeOffer", {
|
|
269
|
+
status: { from: null, to: "pending" },
|
|
270
|
+
offerAmount: { from: null, to: 1050 },
|
|
271
|
+
}, { actorUid: BUYER_YUGI, note: "Offering ₹1,050 — slightly above my budget." }),
|
|
272
|
+
entry(daysAgo(8), "seller", "respondToOffer:decline", {
|
|
273
|
+
status: { from: "pending", to: "declined" },
|
|
274
|
+
}, { actorUid: STORE, note: "Sorry, we cannot go below ₹1,300 for this piece." }),
|
|
275
|
+
],
|
|
105
276
|
},
|
|
106
277
|
// ── 5. EXPIRED — Vivaan → Beyblade Arena — X Wizard Arrow ───────────────
|
|
107
278
|
{
|
|
@@ -117,10 +288,16 @@ export const offersSeedData = [
|
|
|
117
288
|
offerAmount: 700,
|
|
118
289
|
currency: "INR",
|
|
119
290
|
status: OfferStatusValues.EXPIRED,
|
|
120
|
-
buyerNote: "₹
|
|
291
|
+
buyerNote: "₹700 — let me know.",
|
|
121
292
|
expiresAt: daysAgo(2),
|
|
122
293
|
createdAt: daysAgo(9),
|
|
123
294
|
updatedAt: daysAgo(2),
|
|
295
|
+
// NO `statusHistory`, deliberately. This is the ONLY fixture exercising the
|
|
296
|
+
// timeline's legacy branch, and it is exactly the shape of every offer
|
|
297
|
+
// written before W2. Its "Expired" step renders with an em-dash and no
|
|
298
|
+
// date — `expireMany` never wrote a timestamp, `updatedAt` means "last
|
|
299
|
+
// write of any kind", and `expiresAt` is a deadline rather than an event,
|
|
300
|
+
// so any date shown here would be fabricated. Do not "complete" this one.
|
|
124
301
|
},
|
|
125
302
|
// ── 6. WITHDRAWN — Admin → Beyblade Arena — Original Driger V ───────────
|
|
126
303
|
{
|
|
@@ -136,10 +313,21 @@ export const offersSeedData = [
|
|
|
136
313
|
offerAmount: 1450,
|
|
137
314
|
currency: "INR",
|
|
138
315
|
status: OfferStatusValues.WITHDRAWN,
|
|
139
|
-
buyerNote: "Offering ₹1,
|
|
316
|
+
buyerNote: "Offering ₹1,450 for the Driger V.",
|
|
140
317
|
expiresAt: daysAgo(3),
|
|
141
318
|
createdAt: daysAgo(7),
|
|
142
319
|
updatedAt: daysAgo(5),
|
|
320
|
+
// No `supersededByOfferId` — a genuine walk-away, so this renders as
|
|
321
|
+
// "Withdrawn" (negative). Contrast with the two Pegasus rounds above.
|
|
322
|
+
statusHistory: [
|
|
323
|
+
entry(daysAgo(7), "buyer", "makeOffer", {
|
|
324
|
+
status: { from: null, to: "pending" },
|
|
325
|
+
offerAmount: { from: null, to: 1450 },
|
|
326
|
+
}, { actorUid: BUYER_ADMIN, note: "Offering ₹1,450 for the Driger V." }),
|
|
327
|
+
entry(daysAgo(5), "buyer", "withdrawOffer", {
|
|
328
|
+
status: { from: "pending", to: "withdrawn" },
|
|
329
|
+
}, { actorUid: BUYER_ADMIN }),
|
|
330
|
+
],
|
|
143
331
|
},
|
|
144
332
|
// ── 7. ACCEPTED — Vivaan → Beyblade Arena — Original Dranzer S (pending payment) ──
|
|
145
333
|
{
|
|
@@ -167,6 +355,17 @@ export const offersSeedData = [
|
|
|
167
355
|
respondedAt: daysAgo(0),
|
|
168
356
|
createdAt: daysAgo(1),
|
|
169
357
|
updatedAt: daysAgo(0),
|
|
358
|
+
statusHistory: [
|
|
359
|
+
entry(daysAgo(1), "buyer", "makeOffer", {
|
|
360
|
+
status: { from: null, to: "pending" },
|
|
361
|
+
offerAmount: { from: null, to: 1250 },
|
|
362
|
+
}, { actorUid: BUYER_KAIBA, note: "₹1,250 final offer on the sealed Dranzer S." }),
|
|
363
|
+
entry(daysAgo(0), "seller", "respondToOffer:accept", {
|
|
364
|
+
status: { from: "pending", to: "accepted" },
|
|
365
|
+
lockedPrice: { from: null, to: 1250 },
|
|
366
|
+
checkoutDeadline: { from: null, to: daysFromNow(2) },
|
|
367
|
+
}, { actorUid: STORE, note: "Accepted! Please complete payment within 24 hours." }),
|
|
368
|
+
],
|
|
170
369
|
},
|
|
171
370
|
// ── 8. PENDING — Admin → Beyblade Arena — Metal Lightning L-Drago ───────
|
|
172
371
|
{
|
|
@@ -182,9 +381,15 @@ export const offersSeedData = [
|
|
|
182
381
|
offerAmount: 950,
|
|
183
382
|
currency: "INR",
|
|
184
383
|
status: OfferStatusValues.PENDING,
|
|
185
|
-
buyerNote: "Interested in this piece. Would you accept ₹
|
|
384
|
+
buyerNote: "Interested in this piece. Would you accept ₹950?",
|
|
186
385
|
expiresAt: daysFromNow(3),
|
|
187
386
|
createdAt: daysAgo(1),
|
|
188
387
|
updatedAt: daysAgo(1),
|
|
388
|
+
statusHistory: [
|
|
389
|
+
entry(daysAgo(1), "buyer", "makeOffer", {
|
|
390
|
+
status: { from: null, to: "pending" },
|
|
391
|
+
offerAmount: { from: null, to: 950 },
|
|
392
|
+
}, { actorUid: BUYER_ADMIN, note: "Interested in this piece. Would you accept ₹950?" }),
|
|
393
|
+
],
|
|
189
394
|
},
|
|
190
395
|
];
|