@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
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: `AdminSectionsView` rendered a `<Form>` with no `schema` prop. The route
|
|
3
|
+
* validated `order` / `enabled` / `config`, so nothing invalid was ever
|
|
4
|
+
* stored — but a bad value came back as a 400 banner after a round-trip
|
|
5
|
+
* rather than as an error on the field that caused it.
|
|
6
|
+
* WHAT: The homepage-section form schema.
|
|
7
|
+
*
|
|
8
|
+
* ## `config` stays open, deliberately
|
|
9
|
+
*
|
|
10
|
+
* Its shape differs per section type across 21 types, and the route models it
|
|
11
|
+
* the same way (`z.object({}).passthrough()`). Naming a fixed shape here would
|
|
12
|
+
* strip whatever the current type actually needs — the exact defect that made
|
|
13
|
+
* `productBaseSchema` eat every per-type listing field. The form parses it as
|
|
14
|
+
* JSON and reports malformed input; the per-type meaning stays with the
|
|
15
|
+
* section renderer that owns it.
|
|
16
|
+
*
|
|
17
|
+
* EXPORTS:
|
|
18
|
+
* homepageSectionFormSchema, type HomepageSectionFormValues
|
|
19
|
+
*
|
|
20
|
+
* @tag domain:admin,homepage
|
|
21
|
+
* @tag layer:schema
|
|
22
|
+
* @tag pattern:none
|
|
23
|
+
* @tag access:isomorphic
|
|
24
|
+
* @tag consumers:AdminSectionsView
|
|
25
|
+
* @tag sideEffects:none
|
|
26
|
+
*/
|
|
27
|
+
import { z } from "zod";
|
|
28
|
+
import { annotate } from "../../shell/field-ui-meta";
|
|
29
|
+
import { normalizeError } from "../../../errors/normalize";
|
|
30
|
+
/**
|
|
31
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
32
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
33
|
+
*/
|
|
34
|
+
export const homepageSectionFormSchema = z.object({
|
|
35
|
+
sectionType: annotate(z.string().min(1, "Choose a section type."), {
|
|
36
|
+
section: "basics", sectionLabel: "Section", sectionRequired: true,
|
|
37
|
+
quick: true, order: 1, row: "pair",
|
|
38
|
+
}),
|
|
39
|
+
order: annotate(z.coerce
|
|
40
|
+
.number({ invalid_type_error: "Order must be a number." })
|
|
41
|
+
.int("Order must be a whole number.")
|
|
42
|
+
.min(0, "Order cannot be negative.")
|
|
43
|
+
.optional(), { section: "basics", order: 2, row: "pair" }),
|
|
44
|
+
enabled: annotate(z.boolean(), {
|
|
45
|
+
section: "basics", order: 3, row: "quarter",
|
|
46
|
+
}),
|
|
47
|
+
configJson: annotate(z.string().refine(isParsableJson, { message: "Config must be valid JSON." }), {
|
|
48
|
+
section: "config", sectionLabel: "Configuration",
|
|
49
|
+
order: 1, row: "full", kind: "list",
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
/** Hoisted so the `annotate()` call above stays a simple two-argument call. */
|
|
53
|
+
function isParsableJson(value) {
|
|
54
|
+
if (!value.trim())
|
|
55
|
+
return true;
|
|
56
|
+
try {
|
|
57
|
+
JSON.parse(value);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch (_err) {
|
|
61
|
+
// Normalized rather than suppressed. The parse failure IS the return value
|
|
62
|
+
// here — `false` answers the only question this asks — but the project
|
|
63
|
+
// forbids adding new suppression markers, and this is the same shape
|
|
64
|
+
// AdminSectionsView already uses for the very same JSON parse.
|
|
65
|
+
void normalizeError(_err);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
4
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
5
|
+
*/
|
|
6
|
+
export declare const navItemFormSchema: z.ZodObject<{
|
|
7
|
+
label: z.ZodString;
|
|
8
|
+
href: z.ZodEffects<z.ZodString, string, string>;
|
|
9
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
10
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
parentId: z.ZodOptional<z.ZodString>;
|
|
12
|
+
isVisible: z.ZodOptional<z.ZodBoolean>;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
label: string;
|
|
15
|
+
href: string;
|
|
16
|
+
icon?: string | undefined;
|
|
17
|
+
order?: number | undefined;
|
|
18
|
+
parentId?: string | undefined;
|
|
19
|
+
isVisible?: boolean | undefined;
|
|
20
|
+
}, {
|
|
21
|
+
label: string;
|
|
22
|
+
href: string;
|
|
23
|
+
icon?: string | undefined;
|
|
24
|
+
order?: number | undefined;
|
|
25
|
+
parentId?: string | undefined;
|
|
26
|
+
isVisible?: boolean | undefined;
|
|
27
|
+
}>;
|
|
28
|
+
export type NavItemFormValues = z.infer<typeof navItemFormSchema>;
|
|
29
|
+
/** Create contract — `label` and `href` are what make an item usable at all. */
|
|
30
|
+
export declare const navItemCreateSchema: z.ZodObject<{
|
|
31
|
+
label: z.ZodString;
|
|
32
|
+
href: z.ZodEffects<z.ZodString, string, string>;
|
|
33
|
+
icon: z.ZodOptional<z.ZodString>;
|
|
34
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
35
|
+
parentId: z.ZodOptional<z.ZodString>;
|
|
36
|
+
isVisible: z.ZodOptional<z.ZodBoolean>;
|
|
37
|
+
}, "strip", z.ZodTypeAny, {
|
|
38
|
+
label: string;
|
|
39
|
+
href: string;
|
|
40
|
+
icon?: string | undefined;
|
|
41
|
+
order?: number | undefined;
|
|
42
|
+
parentId?: string | undefined;
|
|
43
|
+
isVisible?: boolean | undefined;
|
|
44
|
+
}, {
|
|
45
|
+
label: string;
|
|
46
|
+
href: string;
|
|
47
|
+
icon?: string | undefined;
|
|
48
|
+
order?: number | undefined;
|
|
49
|
+
parentId?: string | undefined;
|
|
50
|
+
isVisible?: boolean | undefined;
|
|
51
|
+
}>;
|
|
52
|
+
/** Update contract — every field optional. */
|
|
53
|
+
export declare const navItemUpdateSchema: z.ZodObject<{
|
|
54
|
+
label: z.ZodOptional<z.ZodString>;
|
|
55
|
+
href: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
56
|
+
icon: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
57
|
+
order: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
|
|
58
|
+
parentId: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
59
|
+
isVisible: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
60
|
+
}, "strip", z.ZodTypeAny, {
|
|
61
|
+
label?: string | undefined;
|
|
62
|
+
icon?: string | undefined;
|
|
63
|
+
href?: string | undefined;
|
|
64
|
+
order?: number | undefined;
|
|
65
|
+
parentId?: string | undefined;
|
|
66
|
+
isVisible?: boolean | undefined;
|
|
67
|
+
}, {
|
|
68
|
+
label?: string | undefined;
|
|
69
|
+
icon?: string | undefined;
|
|
70
|
+
href?: string | undefined;
|
|
71
|
+
order?: number | undefined;
|
|
72
|
+
parentId?: string | undefined;
|
|
73
|
+
isVisible?: boolean | undefined;
|
|
74
|
+
}>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: `AdminNavEditorView` rendered a `<Form>` with no `schema` prop, so the
|
|
3
|
+
* only validation on a navigation item was whatever the server said after
|
|
4
|
+
* the round-trip — a 400 banner rather than an error on the field that
|
|
5
|
+
* caused it. The route DID validate (`navItemSchema` /
|
|
6
|
+
* `updateNavItemSchema` in `api/admin/navigation`), so nothing invalid
|
|
7
|
+
* was ever stored; the gap was purely that the admin was told badly.
|
|
8
|
+
* WHAT: The nav-item form schema, shared by the editor and the routes so the
|
|
9
|
+
* two cannot disagree about what a valid nav item is.
|
|
10
|
+
*
|
|
11
|
+
* ## `href` is checked against real routes only loosely
|
|
12
|
+
*
|
|
13
|
+
* A nav item pointing at a page that does not exist is a real defect —
|
|
14
|
+
* `audit-nav-page-wiring` blocks it — but that check needs the filesystem and
|
|
15
|
+
* therefore cannot run in a browser. Here the rule is only "shaped like a
|
|
16
|
+
* path"; the audit remains the authority on whether the path resolves.
|
|
17
|
+
*
|
|
18
|
+
* EXPORTS:
|
|
19
|
+
* navItemFormSchema, navItemCreateSchema, navItemUpdateSchema,
|
|
20
|
+
* type NavItemFormValues
|
|
21
|
+
*
|
|
22
|
+
* @tag domain:admin,navigation
|
|
23
|
+
* @tag layer:schema
|
|
24
|
+
* @tag pattern:none
|
|
25
|
+
* @tag access:isomorphic
|
|
26
|
+
* @tag consumers:AdminNavEditorView,/api/admin/navigation
|
|
27
|
+
* @tag sideEffects:none
|
|
28
|
+
*/
|
|
29
|
+
import { z } from "zod";
|
|
30
|
+
import { annotate } from "../../shell/field-ui-meta";
|
|
31
|
+
/**
|
|
32
|
+
* A path or an absolute URL.
|
|
33
|
+
*
|
|
34
|
+
* Hoisted for readability only. It was originally inlined, and that surfaced a
|
|
35
|
+
* real bug in `audit-field-ui-meta`: its comment-stripper did not understand
|
|
36
|
+
* regex literals, so the trailing `\/\/` of this pattern read as the start of
|
|
37
|
+
* a line comment and blanked the rest of the line — unbalancing the brace walk
|
|
38
|
+
* and reporting a false NO_SECTION. The audit now handles regex literals; this
|
|
39
|
+
* stays hoisted because it reads better, not because it has to.
|
|
40
|
+
*/
|
|
41
|
+
const hrefSchema = z
|
|
42
|
+
.string()
|
|
43
|
+
.min(1, "A destination is required.")
|
|
44
|
+
.refine((v) => v.startsWith("/") || /^https?:\/\//.test(v), {
|
|
45
|
+
message: "Use a path starting with / or a full http(s) URL.",
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
49
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
50
|
+
*/
|
|
51
|
+
export const navItemFormSchema = z.object({
|
|
52
|
+
label: annotate(z.string().min(1, "A label is required.").max(60, "Keep the label under 60 characters."), {
|
|
53
|
+
section: "basics", sectionLabel: "Nav item", sectionRequired: true,
|
|
54
|
+
quick: true, order: 1, row: "pair",
|
|
55
|
+
}),
|
|
56
|
+
href: annotate(hrefSchema, { section: "basics", quick: true, order: 2, row: "pair" }),
|
|
57
|
+
icon: annotate(z.string().max(60).optional(), {
|
|
58
|
+
section: "basics", order: 3, row: "pair",
|
|
59
|
+
}),
|
|
60
|
+
order: annotate(z.coerce.number().int("Order must be a whole number.").min(0, "Order cannot be negative.").optional(), { section: "placement", sectionLabel: "Placement", order: 1, row: "pair" }),
|
|
61
|
+
parentId: annotate(z.string().max(80).optional(), {
|
|
62
|
+
section: "placement", order: 2, row: "pair",
|
|
63
|
+
help: "Leave blank for a top-level item.",
|
|
64
|
+
}),
|
|
65
|
+
isVisible: annotate(z.boolean().optional(), {
|
|
66
|
+
section: "placement", order: 3, row: "quarter",
|
|
67
|
+
}),
|
|
68
|
+
});
|
|
69
|
+
/** Create contract — `label` and `href` are what make an item usable at all. */
|
|
70
|
+
export const navItemCreateSchema = navItemFormSchema;
|
|
71
|
+
/** Update contract — every field optional. */
|
|
72
|
+
export const navItemUpdateSchema = navItemFormSchema.partial();
|
|
@@ -14,5 +14,14 @@ export interface AuctionBidsTableProps {
|
|
|
14
14
|
totalPages?: number;
|
|
15
15
|
currentPage?: number;
|
|
16
16
|
onPageChange?: (page: number) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Open a bid. Supplied by the three dashboard bid listings, which were dead
|
|
19
|
+
* ends until W8 — a bid could be seen here and never opened, so its amount,
|
|
20
|
+
* auction, timing and outcome existed only as a table row.
|
|
21
|
+
*
|
|
22
|
+
* Optional because the PUBLIC bid history on an auction page also renders
|
|
23
|
+
* this table, and there a row is not something a visitor may open.
|
|
24
|
+
*/
|
|
25
|
+
onRowClick?: (bid: BidDocument) => void;
|
|
17
26
|
}
|
|
18
|
-
export declare function AuctionBidsTable({ bids, portal, emptyLabel, totalPages, currentPage, onPageChange, }: AuctionBidsTableProps): React.JSX.Element;
|
|
27
|
+
export declare function AuctionBidsTable({ bids, portal, emptyLabel, totalPages, currentPage, onPageChange, onRowClick, }: AuctionBidsTableProps): React.JSX.Element;
|
|
@@ -52,7 +52,22 @@ function groupByAuction(bids) {
|
|
|
52
52
|
}
|
|
53
53
|
return Array.from(map.values());
|
|
54
54
|
}
|
|
55
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Enter/Space activate a non-button element that behaves as one.
|
|
57
|
+
*
|
|
58
|
+
* A named helper rather than an inline closure: the inline form nested six
|
|
59
|
+
* braces deep inside the row's JSX, which is both unreadable and what
|
|
60
|
+
* `audit-code-quality`'s DEEP_NESTING rule exists to prevent.
|
|
61
|
+
*/
|
|
62
|
+
function activateOnKey(run) {
|
|
63
|
+
return (e) => {
|
|
64
|
+
if (e.key !== "Enter" && e.key !== " ")
|
|
65
|
+
return;
|
|
66
|
+
e.preventDefault();
|
|
67
|
+
run();
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function AuctionRow({ auction, portal, onRowClick, }) {
|
|
56
71
|
const [expanded, setExpanded] = useState(false);
|
|
57
72
|
// Most-recent bid first — matches the caller's own newest-first ordering
|
|
58
73
|
// (see UserBidsPage) instead of re-sorting by amount, which silently threw
|
|
@@ -60,14 +75,17 @@ function AuctionRow({ auction, portal, }) {
|
|
|
60
75
|
const sorted = useMemo(() => [...auction.bids].sort((a, b) => +new Date(b.bidDate) - +new Date(a.bidDate)), [auction.bids]);
|
|
61
76
|
const highest = auction.bids.reduce((max, b) => Math.max(max, b.bidAmount), 0);
|
|
62
77
|
const isWinning = auction.bids.some((b) => b.isWinning);
|
|
63
|
-
return (_jsxs(Div, { className: `border border-[var(--appkit-color-border)] ${__O.hidden} bg-[var(--appkit-color-surface)]`, rounded: "xl", shadow: "sm", children: [_jsxs(Button, { type: "button", variant: "ghost", onClick: () => setExpanded((v) => !v), gap: "lg", paddingX: "md", paddingY: "md", className: "w-full text-left", "aria-expanded": expanded, children: [_jsx(ChevronRight, { className: `shrink-0 text-[var(--appkit-color-text-muted)] transition-transform ${expanded ? "rotate-90" : ""}`, size: 16 }), _jsx(Div, { className: "flex-1 min-w-0", children: _jsx(Text, { className: "text-[var(--appkit-color-text)] line-clamp-1", size: "sm", weight: "semibold", children: auction.productTitle }) }), _jsxs(Row, { gap: "sm", className: "shrink-0", children: [isWinning && (_jsx(Badge, { variant: "active", children: "Winning" })), _jsxs(Text, { variant: "secondary", size: "xs", children: [auction.bids.length, " bid", auction.bids.length !== 1 ? "s" : ""] }), _jsx(Text, { className: "text-[var(--appkit-color-text)]", size: "sm", weight: "semibold", children: formatBidAmount(highest) })] })] }), expanded && (_jsxs(Div, { className: "border-t border-[var(--appkit-color-border)]", children: [_jsxs(Div, { textSize: "xs", textWeight: "medium", paddingX: "x-md", paddingY: "y-xs", className: `grid text-[var(--appkit-color-text-muted)] uppercase tracking-wide border-b border-[var(--appkit-color-border-subtle)] ${portal === "buyer" ? "[grid-template-columns:1fr_auto_auto]" : "[grid-template-columns:1fr_1fr_auto_auto]"}`, children: [_jsx(Span, { children: portal === "buyer" ? "Amount" : "Bidder" }), portal !== "buyer" && _jsx(Span, { children: "Amount" }), _jsx(Span, { children: "Status" }), _jsx(Span, { className: "text-right", children: "Time" })] }), sorted.map((bid) => (_jsxs(Div, { layout: "grid", align: "center", paddingX: "x-md", paddingY: "y-xs-tall",
|
|
78
|
+
return (_jsxs(Div, { className: `border border-[var(--appkit-color-border)] ${__O.hidden} bg-[var(--appkit-color-surface)]`, rounded: "xl", shadow: "sm", children: [_jsxs(Button, { type: "button", variant: "ghost", onClick: () => setExpanded((v) => !v), gap: "lg", paddingX: "md", paddingY: "md", className: "w-full text-left", "aria-expanded": expanded, children: [_jsx(ChevronRight, { className: `shrink-0 text-[var(--appkit-color-text-muted)] transition-transform ${expanded ? "rotate-90" : ""}`, size: 16 }), _jsx(Div, { className: "flex-1 min-w-0", children: _jsx(Text, { className: "text-[var(--appkit-color-text)] line-clamp-1", size: "sm", weight: "semibold", children: auction.productTitle }) }), _jsxs(Row, { gap: "sm", className: "shrink-0", children: [isWinning && (_jsx(Badge, { variant: "active", children: "Winning" })), _jsxs(Text, { variant: "secondary", size: "xs", children: [auction.bids.length, " bid", auction.bids.length !== 1 ? "s" : ""] }), _jsx(Text, { className: "text-[var(--appkit-color-text)]", size: "sm", weight: "semibold", children: formatBidAmount(highest) })] })] }), expanded && (_jsxs(Div, { className: "border-t border-[var(--appkit-color-border)]", children: [_jsxs(Div, { textSize: "xs", textWeight: "medium", paddingX: "x-md", paddingY: "y-xs", className: `grid text-[var(--appkit-color-text-muted)] uppercase tracking-wide border-b border-[var(--appkit-color-border-subtle)] ${portal === "buyer" ? "[grid-template-columns:1fr_auto_auto]" : "[grid-template-columns:1fr_1fr_auto_auto]"}`, children: [_jsx(Span, { children: portal === "buyer" ? "Amount" : "Bidder" }), portal !== "buyer" && _jsx(Span, { children: "Amount" }), _jsx(Span, { children: "Status" }), _jsx(Span, { className: "text-right", children: "Time" })] }), sorted.map((bid) => (_jsxs(Div, { layout: "grid", align: "center", paddingX: "x-md", paddingY: "y-xs-tall",
|
|
79
|
+
// Keyboard-reachable only when it is actually interactive —
|
|
80
|
+
// a row with no handler must not be a tab stop.
|
|
81
|
+
role: onRowClick ? "button" : undefined, tabIndex: onRowClick ? 0 : undefined, onClick: onRowClick ? () => onRowClick(bid) : undefined, onKeyDown: onRowClick ? activateOnKey(() => onRowClick(bid)) : undefined, className: `border-b border-[var(--appkit-color-border-subtle)] last:border-0 hover:bg-[var(--appkit-color-border-subtle)] transition-colors ${onRowClick ? "cursor-pointer" : ""} ${portal === "buyer" ? "[grid-template-columns:1fr_auto_auto]" : "[grid-template-columns:1fr_1fr_auto_auto]"}`, children: [portal !== "buyer" && (_jsx(Text, { className: "text-[var(--appkit-color-text)] truncate pr-[0.75rem]", size: "sm", children: bid.userName || bid.userId })), _jsx(Text, { className: "text-[var(--appkit-color-text)]", size: "sm", weight: "medium", children: formatBidAmount(bid.bidAmount) }), _jsx(Badge, { variant: STATUS_VARIANT[bid.status] ?? "pending", className: "capitalize", children: bid.status }), _jsxs(Stack, { gap: "xs", align: "end", children: [_jsx(Text, { variant: "secondary", size: "xs", align: "end", children: relDate(bid.bidDate) }), portal === "buyer" && bid.status === "won" && (_jsx(TextLink, { href: bid.orderId
|
|
64
82
|
? String(ROUTES.USER.ORDER_DETAIL(bid.orderId))
|
|
65
83
|
: `${String(ROUTES.USER.CHECKOUT)}?lane=${CART_LANE.AUCTION}`, size: "xs", weight: "semibold", children: bid.orderId ? "View order" : "Pay now →" }))] })] }, bid.id)))] }))] }));
|
|
66
84
|
}
|
|
67
|
-
export function AuctionBidsTable({ bids, portal = "buyer", emptyLabel = "No bids found.", totalPages, currentPage, onPageChange, }) {
|
|
85
|
+
export function AuctionBidsTable({ bids, portal = "buyer", emptyLabel = "No bids found.", totalPages, currentPage, onPageChange, onRowClick, }) {
|
|
68
86
|
const auctions = useMemo(() => groupByAuction(bids), [bids]);
|
|
69
87
|
if (auctions.length === 0) {
|
|
70
88
|
return (_jsx(Div, { padding: "y-6xl", className: "text-left", children: _jsx(Text, { variant: "secondary", children: emptyLabel }) }));
|
|
71
89
|
}
|
|
72
|
-
return (_jsxs(Stack, { gap: "3", children: [auctions.map((auction) => (_jsx(AuctionRow, { auction: auction, portal: portal }, auction.productId))), totalPages !== undefined && totalPages > 1 && currentPage !== undefined && onPageChange && (_jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange }) }))] }));
|
|
90
|
+
return (_jsxs(Stack, { gap: "3", children: [auctions.map((auction) => (_jsx(AuctionRow, { auction: auction, portal: portal, onRowClick: onRowClick }, auction.productId))), totalPages !== undefined && totalPages > 1 && currentPage !== undefined && onPageChange && (_jsx(Row, { justify: "center", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange }) }))] }));
|
|
73
91
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { BidDocument } from "../schemas/firestore";
|
|
2
|
+
/** Which portal is looking. Decides whether bidder identity is shown. */
|
|
3
|
+
export type BidDetailViewer = "buyer" | "seller" | "admin";
|
|
4
|
+
type FieldRow = {
|
|
5
|
+
label: string;
|
|
6
|
+
value: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* A bid's status as a badge.
|
|
10
|
+
*
|
|
11
|
+
* `forfeited` is deliberately distinguished from `cancelled`: a forfeited bid
|
|
12
|
+
* WON and then let the payment window lapse, which is the seller's problem and
|
|
13
|
+
* the buyer's fault; a cancelled one never won anything. Collapsing them would
|
|
14
|
+
* hide exactly the distinction a support query is about.
|
|
15
|
+
*/
|
|
16
|
+
export declare function bidStatusBadge(status: string | undefined): {
|
|
17
|
+
label: string;
|
|
18
|
+
tone: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* The scalar rows for a bid's detail modal.
|
|
22
|
+
*
|
|
23
|
+
* `bidderName` appears only for seller and admin. A buyer opening their OWN
|
|
24
|
+
* bid does not need to be told their own name, and the same component is used
|
|
25
|
+
* by all three, so gating here rather than at each call site is what stops a
|
|
26
|
+
* future copy-paste showing one buyer another's identity.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildBidDetailFields(bid: BidDocument, viewer: BidDetailViewer): FieldRow[];
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: All three bid listings — buyer, seller and admin — were dead ends. A
|
|
3
|
+
* bid could be SEEN in a list and never opened, so the amount, the
|
|
4
|
+
* auction it belongs to, when it was placed and whether it was outbid,
|
|
5
|
+
* won or forfeited were only ever visible as a table row. `bid` is also
|
|
6
|
+
* one of the three `relatedType` values with no per-record page in ANY
|
|
7
|
+
* role, so a bid notification had nowhere to link.
|
|
8
|
+
* WHAT: The `<RecordDetailModal>` field list for a bid, built once.
|
|
9
|
+
*
|
|
10
|
+
* ## One builder, three portals
|
|
11
|
+
*
|
|
12
|
+
* The three views differ only in whether they may show the bidder's identity:
|
|
13
|
+
* a buyer sees their own bid, a seller sees who bid on their auction, and an
|
|
14
|
+
* admin sees everything. Writing the field list three times would be three
|
|
15
|
+
* chances to leak a bidder's name into the buyer view or to forget a field in
|
|
16
|
+
* one portal — the shape of Root Cause #38, one layer up.
|
|
17
|
+
*
|
|
18
|
+
* `maskPublicBid` already exists for the PUBLIC bid history and is unchanged;
|
|
19
|
+
* this is the dashboard equivalent, where the viewer is authenticated and the
|
|
20
|
+
* question is which role they hold.
|
|
21
|
+
*
|
|
22
|
+
* EXPORTS:
|
|
23
|
+
* buildBidDetailFields, bidStatusBadge, type BidDetailViewer
|
|
24
|
+
*
|
|
25
|
+
* @tag domain:auctions
|
|
26
|
+
* @tag layer:feature-util
|
|
27
|
+
* @tag pattern:none
|
|
28
|
+
* @tag access:isomorphic
|
|
29
|
+
* @tag consumers:UserBidsView,SellerBidsView,AdminBidsView
|
|
30
|
+
* @tag sideEffects:none
|
|
31
|
+
*/
|
|
32
|
+
const money = (amount, currency = "INR") => amount == null
|
|
33
|
+
? "—"
|
|
34
|
+
: new Intl.NumberFormat("en-IN", { style: "currency", currency, maximumFractionDigits: 2 }).format(amount);
|
|
35
|
+
const when = (value) => {
|
|
36
|
+
if (!value)
|
|
37
|
+
return "—";
|
|
38
|
+
const d = value instanceof Date ? value : new Date(String(value));
|
|
39
|
+
return Number.isNaN(d.getTime()) ? "—" : d.toLocaleString();
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* A bid's status as a badge.
|
|
43
|
+
*
|
|
44
|
+
* `forfeited` is deliberately distinguished from `cancelled`: a forfeited bid
|
|
45
|
+
* WON and then let the payment window lapse, which is the seller's problem and
|
|
46
|
+
* the buyer's fault; a cancelled one never won anything. Collapsing them would
|
|
47
|
+
* hide exactly the distinction a support query is about.
|
|
48
|
+
*/
|
|
49
|
+
export function bidStatusBadge(status) {
|
|
50
|
+
switch (status) {
|
|
51
|
+
case "won":
|
|
52
|
+
return { label: "Won", tone: "success" };
|
|
53
|
+
case "active":
|
|
54
|
+
return { label: "Leading", tone: "info" };
|
|
55
|
+
case "outbid":
|
|
56
|
+
return { label: "Outbid", tone: "warning" };
|
|
57
|
+
case "forfeited":
|
|
58
|
+
return { label: "Forfeited — payment window lapsed", tone: "danger" };
|
|
59
|
+
case "cancelled":
|
|
60
|
+
return { label: "Cancelled", tone: "default" };
|
|
61
|
+
case "lost":
|
|
62
|
+
return { label: "Lost", tone: "default" };
|
|
63
|
+
default:
|
|
64
|
+
return { label: status ?? "Unknown", tone: "default" };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The scalar rows for a bid's detail modal.
|
|
69
|
+
*
|
|
70
|
+
* `bidderName` appears only for seller and admin. A buyer opening their OWN
|
|
71
|
+
* bid does not need to be told their own name, and the same component is used
|
|
72
|
+
* by all three, so gating here rather than at each call site is what stops a
|
|
73
|
+
* future copy-paste showing one buyer another's identity.
|
|
74
|
+
*/
|
|
75
|
+
export function buildBidDetailFields(bid, viewer) {
|
|
76
|
+
const rows = [
|
|
77
|
+
{ label: "Auction", value: bid.productTitle || bid.productId },
|
|
78
|
+
{ label: "Bid amount", value: money(bid.bidAmount, bid.currency) },
|
|
79
|
+
];
|
|
80
|
+
// Only meaningful when the bid raised a previous one.
|
|
81
|
+
if (bid.previousBidAmount != null) {
|
|
82
|
+
rows.push({ label: "Previous high bid", value: money(bid.previousBidAmount, bid.currency) });
|
|
83
|
+
}
|
|
84
|
+
if (bid.autoMaxBid != null) {
|
|
85
|
+
rows.push({ label: "Auto-bid limit", value: money(bid.autoMaxBid, bid.currency) });
|
|
86
|
+
}
|
|
87
|
+
rows.push({ label: "Placed", value: when(bid.bidDate ?? bid.createdAt) });
|
|
88
|
+
if (viewer !== "buyer") {
|
|
89
|
+
rows.push({ label: "Bidder", value: bid.userName || bid.userId });
|
|
90
|
+
}
|
|
91
|
+
// A buyout is a real bid, not a bid-free purchase — surfacing it here is
|
|
92
|
+
// what makes "why is there no ladder on this auction" answerable.
|
|
93
|
+
if (bid.isBuyout) {
|
|
94
|
+
rows.push({ label: "Placed via", value: "Buy Now" });
|
|
95
|
+
}
|
|
96
|
+
// The order this bid became. Present only once the win was actually paid,
|
|
97
|
+
// which is exactly the question "did they ever pay?" asks.
|
|
98
|
+
if (bid.orderId) {
|
|
99
|
+
rows.push({ label: "Order", value: bid.orderId });
|
|
100
|
+
}
|
|
101
|
+
rows.push({ label: "Bid ID", value: bid.id });
|
|
102
|
+
return rows;
|
|
103
|
+
}
|
|
@@ -67,20 +67,15 @@ export declare const auctionItemSchema: z.ZodObject<{
|
|
|
67
67
|
title: string;
|
|
68
68
|
createdAt: string;
|
|
69
69
|
updatedAt: string;
|
|
70
|
-
slug: string;
|
|
71
70
|
price: number;
|
|
71
|
+
listingType: "auction";
|
|
72
|
+
slug: string;
|
|
72
73
|
sellerId: string;
|
|
73
74
|
featured: boolean;
|
|
74
|
-
listingType: "auction";
|
|
75
75
|
auctionEndDate: string;
|
|
76
76
|
startingBid: number;
|
|
77
77
|
bidCount: number;
|
|
78
78
|
storeId?: string | undefined;
|
|
79
|
-
description?: string | undefined;
|
|
80
|
-
mainImage?: string | undefined;
|
|
81
|
-
images?: string[] | undefined;
|
|
82
|
-
currentBid?: number | undefined;
|
|
83
|
-
storeSlug?: string | undefined;
|
|
84
79
|
media?: {
|
|
85
80
|
type: "video" | "image" | "file";
|
|
86
81
|
url: string;
|
|
@@ -90,6 +85,11 @@ export declare const auctionItemSchema: z.ZodObject<{
|
|
|
90
85
|
youtubeId?: string | undefined;
|
|
91
86
|
duration?: number | undefined;
|
|
92
87
|
}[] | undefined;
|
|
88
|
+
description?: string | undefined;
|
|
89
|
+
mainImage?: string | undefined;
|
|
90
|
+
images?: string[] | undefined;
|
|
91
|
+
currentBid?: number | undefined;
|
|
92
|
+
storeSlug?: string | undefined;
|
|
93
93
|
}, {
|
|
94
94
|
currency: string;
|
|
95
95
|
status: "draft" | "published" | "archived" | "sold";
|
|
@@ -97,20 +97,15 @@ export declare const auctionItemSchema: z.ZodObject<{
|
|
|
97
97
|
title: string;
|
|
98
98
|
createdAt: string;
|
|
99
99
|
updatedAt: string;
|
|
100
|
-
slug: string;
|
|
101
100
|
price: number;
|
|
101
|
+
listingType: "auction";
|
|
102
|
+
slug: string;
|
|
102
103
|
sellerId: string;
|
|
103
104
|
featured: boolean;
|
|
104
|
-
listingType: "auction";
|
|
105
105
|
auctionEndDate: string;
|
|
106
106
|
startingBid: number;
|
|
107
107
|
bidCount: number;
|
|
108
108
|
storeId?: string | undefined;
|
|
109
|
-
description?: string | undefined;
|
|
110
|
-
mainImage?: string | undefined;
|
|
111
|
-
images?: string[] | undefined;
|
|
112
|
-
currentBid?: number | undefined;
|
|
113
|
-
storeSlug?: string | undefined;
|
|
114
109
|
media?: {
|
|
115
110
|
type: "video" | "image" | "file";
|
|
116
111
|
url: string;
|
|
@@ -120,6 +115,11 @@ export declare const auctionItemSchema: z.ZodObject<{
|
|
|
120
115
|
youtubeId?: string | undefined;
|
|
121
116
|
duration?: number | undefined;
|
|
122
117
|
}[] | undefined;
|
|
118
|
+
description?: string | undefined;
|
|
119
|
+
mainImage?: string | undefined;
|
|
120
|
+
images?: string[] | undefined;
|
|
121
|
+
currentBid?: number | undefined;
|
|
122
|
+
storeSlug?: string | undefined;
|
|
123
123
|
}>;
|
|
124
124
|
export declare const bidRecordSchema: z.ZodObject<{
|
|
125
125
|
id: z.ZodString;
|
|
@@ -23,6 +23,13 @@ export declare const AdminAuditActionValues: {
|
|
|
23
23
|
readonly PAYOUT_MARK_PAID: "payout_mark_paid";
|
|
24
24
|
readonly STORE_STATUS_CHANGE: "store_status_change";
|
|
25
25
|
readonly USER_ROLE_CHANGE: "user_role_change";
|
|
26
|
+
/**
|
|
27
|
+
* Admin cancelled an offer. The store keeps sole authority to accept,
|
|
28
|
+
* counter and decline; cancelling is the ONE write an admin may make, and
|
|
29
|
+
* it is an escalation — reason required, and recorded both here and in the
|
|
30
|
+
* offer's own `statusHistory`.
|
|
31
|
+
*/
|
|
32
|
+
readonly OFFER_CANCEL: "offer_cancel";
|
|
26
33
|
};
|
|
27
34
|
export type AdminAuditAction = (typeof AdminAuditActionValues)[keyof typeof AdminAuditActionValues];
|
|
28
35
|
export interface AdminAuditLogDocument extends BaseDocument {
|
|
@@ -55,5 +62,12 @@ export declare const ADMIN_AUDIT_LOG_FIELDS: {
|
|
|
55
62
|
readonly PAYOUT_MARK_PAID: "payout_mark_paid";
|
|
56
63
|
readonly STORE_STATUS_CHANGE: "store_status_change";
|
|
57
64
|
readonly USER_ROLE_CHANGE: "user_role_change";
|
|
65
|
+
/**
|
|
66
|
+
* Admin cancelled an offer. The store keeps sole authority to accept,
|
|
67
|
+
* counter and decline; cancelling is the ONE write an admin may make, and
|
|
68
|
+
* it is an escalation — reason required, and recorded both here and in the
|
|
69
|
+
* offer's own `statusHistory`.
|
|
70
|
+
*/
|
|
71
|
+
readonly OFFER_CANCEL: "offer_cancel";
|
|
58
72
|
};
|
|
59
73
|
};
|
|
@@ -21,6 +21,13 @@ export const AdminAuditActionValues = {
|
|
|
21
21
|
PAYOUT_MARK_PAID: "payout_mark_paid",
|
|
22
22
|
STORE_STATUS_CHANGE: "store_status_change",
|
|
23
23
|
USER_ROLE_CHANGE: "user_role_change",
|
|
24
|
+
/**
|
|
25
|
+
* Admin cancelled an offer. The store keeps sole authority to accept,
|
|
26
|
+
* counter and decline; cancelling is the ONE write an admin may make, and
|
|
27
|
+
* it is an escalation — reason required, and recorded both here and in the
|
|
28
|
+
* offer's own `statusHistory`.
|
|
29
|
+
*/
|
|
30
|
+
OFFER_CANCEL: "offer_cancel",
|
|
24
31
|
};
|
|
25
32
|
export const ADMIN_AUDIT_LOG_FIELDS = {
|
|
26
33
|
ACTOR_UID: "actorUid",
|
|
@@ -65,14 +65,14 @@ export declare const authUserSchema: z.ZodObject<{
|
|
|
65
65
|
isEmailVerified: z.ZodOptional<z.ZodBoolean>;
|
|
66
66
|
}, "strip", z.ZodTypeAny, {
|
|
67
67
|
id: string;
|
|
68
|
-
role?: "user" | "
|
|
68
|
+
role?: "user" | "admin" | "moderator" | "seller" | "employee" | undefined;
|
|
69
69
|
email?: string | undefined;
|
|
70
70
|
displayName?: string | undefined;
|
|
71
71
|
photoURL?: string | undefined;
|
|
72
72
|
isEmailVerified?: boolean | undefined;
|
|
73
73
|
}, {
|
|
74
74
|
id: string;
|
|
75
|
-
role?: "user" | "
|
|
75
|
+
role?: "user" | "admin" | "moderator" | "seller" | "employee" | undefined;
|
|
76
76
|
email?: string | undefined;
|
|
77
77
|
displayName?: string | undefined;
|
|
78
78
|
photoURL?: string | undefined;
|
|
@@ -72,8 +72,8 @@ export declare const createBlogPostSchema: z.ZodObject<{
|
|
|
72
72
|
status: "draft" | "published" | "archived";
|
|
73
73
|
title: string;
|
|
74
74
|
content: string;
|
|
75
|
-
slug: string;
|
|
76
75
|
category: "news" | "tips" | "guides" | "updates" | "community";
|
|
76
|
+
slug: string;
|
|
77
77
|
tags: string[];
|
|
78
78
|
isFeatured: boolean;
|
|
79
79
|
excerpt: string;
|
|
@@ -108,12 +108,12 @@ export declare const createBlogPostSchema: z.ZodObject<{
|
|
|
108
108
|
}, {
|
|
109
109
|
title: string;
|
|
110
110
|
content: string;
|
|
111
|
-
slug: string;
|
|
112
111
|
category: "news" | "tips" | "guides" | "updates" | "community";
|
|
112
|
+
slug: string;
|
|
113
113
|
excerpt: string;
|
|
114
114
|
status?: "draft" | "published" | "archived" | undefined;
|
|
115
|
-
tags?: string[] | undefined;
|
|
116
115
|
publishedAt?: string | undefined;
|
|
116
|
+
tags?: string[] | undefined;
|
|
117
117
|
isFeatured?: boolean | undefined;
|
|
118
118
|
coverImage?: string | {
|
|
119
119
|
type: "video" | "image" | "file";
|
|
@@ -211,10 +211,10 @@ export declare const updateBlogPostSchema: z.ZodObject<{
|
|
|
211
211
|
status?: "draft" | "published" | "archived" | undefined;
|
|
212
212
|
title?: string | undefined;
|
|
213
213
|
content?: string | undefined;
|
|
214
|
-
slug?: string | undefined;
|
|
215
214
|
category?: "news" | "tips" | "guides" | "updates" | "community" | undefined;
|
|
216
|
-
tags?: string[] | undefined;
|
|
217
215
|
publishedAt?: string | undefined;
|
|
216
|
+
slug?: string | undefined;
|
|
217
|
+
tags?: string[] | undefined;
|
|
218
218
|
isFeatured?: boolean | undefined;
|
|
219
219
|
excerpt?: string | undefined;
|
|
220
220
|
coverImage?: {
|
|
@@ -248,10 +248,10 @@ export declare const updateBlogPostSchema: z.ZodObject<{
|
|
|
248
248
|
status?: "draft" | "published" | "archived" | undefined;
|
|
249
249
|
title?: string | undefined;
|
|
250
250
|
content?: string | undefined;
|
|
251
|
-
slug?: string | undefined;
|
|
252
251
|
category?: "news" | "tips" | "guides" | "updates" | "community" | undefined;
|
|
253
|
-
tags?: string[] | undefined;
|
|
254
252
|
publishedAt?: string | undefined;
|
|
253
|
+
slug?: string | undefined;
|
|
254
|
+
tags?: string[] | undefined;
|
|
255
255
|
isFeatured?: boolean | undefined;
|
|
256
256
|
excerpt?: string | undefined;
|
|
257
257
|
coverImage?: string | {
|