@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.
Files changed (206) hide show
  1. package/dist/_internal/server/features/auctions/actions.js +2 -2
  2. package/dist/_internal/server/features/cart/service.d.ts +3 -3
  3. package/dist/_internal/server/features/checkout/actions.js +19 -0
  4. package/dist/_internal/server/features/checkout/source-context.d.ts +5 -0
  5. package/dist/_internal/server/features/checkout/source-context.js +157 -0
  6. package/dist/_internal/server/features/offers/adapters.d.ts +103 -0
  7. package/dist/_internal/server/features/offers/adapters.js +88 -0
  8. package/dist/_internal/server/features/offers/index.d.ts +2 -0
  9. package/dist/_internal/server/features/offers/index.js +1 -0
  10. package/dist/_internal/server/features/orders/adapters.js +24 -0
  11. package/dist/_internal/server/jobs/core/offerExpiry.js +10 -10
  12. package/dist/_internal/shared/actions/action-registry.d.ts +9 -2
  13. package/dist/_internal/shared/actions/action-registry.js +458 -7
  14. package/dist/_internal/shared/features/auctions/schema.d.ts +14 -2
  15. package/dist/_internal/shared/features/auctions/schema.js +13 -1
  16. package/dist/_internal/shared/features/blog/schema.d.ts +4 -4
  17. package/dist/_internal/shared/features/cart/schema.d.ts +25 -20
  18. package/dist/_internal/shared/features/cart/schema.js +15 -0
  19. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +22 -22
  20. package/dist/_internal/shared/features/orders/schema.d.ts +4 -4
  21. package/dist/_internal/shared/features/products/schema.d.ts +27 -27
  22. package/dist/_internal/shared/features/promotions/schema.d.ts +4 -4
  23. package/dist/_internal/shared/features/reviews/schema.d.ts +2 -2
  24. package/dist/_internal/shared/history/history.d.ts +22 -0
  25. package/dist/_internal/shared/history/history.js +41 -1
  26. package/dist/client.d.ts +13 -2
  27. package/dist/client.js +20 -2
  28. package/dist/constants/field-names.d.ts +8 -6
  29. package/dist/constants/field-names.js +48 -6
  30. package/dist/contracts/extend.d.ts +29 -0
  31. package/dist/contracts/extend.js +20 -0
  32. package/dist/contracts/index.d.ts +2 -1
  33. package/dist/contracts/index.js +2 -0
  34. package/dist/features/account/components/UserBidsView.js +12 -4
  35. package/dist/features/account/components/UserReturnsView.d.ts +3 -0
  36. package/dist/features/account/components/UserReturnsView.js +17 -1
  37. package/dist/features/admin/components/AdminAuditLogView.js +1 -0
  38. package/dist/features/admin/components/AdminBidsView.js +15 -2
  39. package/dist/features/admin/components/AdminBlogEditorView.js +65 -33
  40. package/dist/features/admin/components/AdminFeatureEditorView.js +35 -6
  41. package/dist/features/admin/components/AdminNavEditorView.js +15 -5
  42. package/dist/features/admin/components/AdminNewsletterView.js +18 -2
  43. package/dist/features/admin/components/AdminOffersView.js +62 -18
  44. package/dist/features/admin/components/AdminPaymentMethodsView.js +24 -4
  45. package/dist/features/admin/components/AdminScammerEditorView.d.ts +2 -1
  46. package/dist/features/admin/components/AdminScammerEditorView.js +3 -13
  47. package/dist/features/admin/components/AdminScammersView.js +3 -8
  48. package/dist/features/admin/components/AdminSectionsView.js +32 -23
  49. package/dist/features/admin/components/AdminSessionsView.js +17 -2
  50. package/dist/features/admin/components/AdminViewCards.js +24 -17
  51. package/dist/features/admin/components/DataListingView.js +15 -1
  52. package/dist/features/admin/components/DataTable.js +7 -17
  53. package/dist/features/admin/components/ViewAuditLogEntryModal.js +1 -0
  54. package/dist/features/admin/components/sections/adminSectionsTypes.d.ts +4 -2
  55. package/dist/features/admin/components/sections/adminSectionsTypes.js +45 -27
  56. package/dist/features/admin/constants/filter-tabs.d.ts +3 -0
  57. package/dist/features/admin/constants/filter-tabs.js +1 -0
  58. package/dist/features/admin/schemas/homepage-section-form.d.ts +22 -0
  59. package/dist/features/admin/schemas/homepage-section-form.js +68 -0
  60. package/dist/features/admin/schemas/nav-item-form.d.ts +74 -0
  61. package/dist/features/admin/schemas/nav-item-form.js +72 -0
  62. package/dist/features/auctions/components/AuctionBidsTable.d.ts +10 -1
  63. package/dist/features/auctions/components/AuctionBidsTable.js +22 -4
  64. package/dist/features/auctions/components/bid-detail-fields.d.ts +29 -0
  65. package/dist/features/auctions/components/bid-detail-fields.js +103 -0
  66. package/dist/features/auctions/schemas/index.d.ts +14 -14
  67. package/dist/features/audit-log/schemas/firestore.d.ts +14 -0
  68. package/dist/features/audit-log/schemas/firestore.js +7 -0
  69. package/dist/features/auth/schemas/index.d.ts +2 -2
  70. package/dist/features/blog/actions/blog-actions.d.ts +7 -7
  71. package/dist/features/blog/schemas/blog-form.d.ts +80 -0
  72. package/dist/features/blog/schemas/blog-form.js +100 -0
  73. package/dist/features/blog/schemas/index.d.ts +10 -10
  74. package/dist/features/cart/schemas/index.d.ts +3 -3
  75. package/dist/features/catalogue/schemas/validation.d.ts +12 -12
  76. package/dist/features/categories/schemas/index.d.ts +16 -16
  77. package/dist/features/collections/schemas/index.d.ts +8 -8
  78. package/dist/features/events/components/AdminEventEditorView.js +32 -54
  79. package/dist/features/events/components/AdminEventEntriesView.js +22 -3
  80. package/dist/features/events/schemas/event-form.d.ts +113 -0
  81. package/dist/features/events/schemas/event-form.js +82 -0
  82. package/dist/features/events/schemas/index.d.ts +2 -2
  83. package/dist/features/faq/actions/faq-actions.d.ts +6 -6
  84. package/dist/features/faq/schemas/index.d.ts +6 -6
  85. package/dist/features/grouped/schemas/grouped-listing-form.d.ts +101 -0
  86. package/dist/features/grouped/schemas/grouped-listing-form.js +89 -0
  87. package/dist/features/grouped/schemas/index.d.ts +4 -4
  88. package/dist/features/homepage/actions/homepage-section-actions.d.ts +11 -3
  89. package/dist/features/homepage/actions/homepage-section-actions.js +33 -1
  90. package/dist/features/homepage/schemas/index.d.ts +71 -40
  91. package/dist/features/homepage/schemas/index.js +24 -0
  92. package/dist/features/messages/schemas/index.d.ts +2 -2
  93. package/dist/features/orders/components/OrderStatusTimeline.d.ts +5 -1
  94. package/dist/features/orders/components/OrderStatusTimeline.js +39 -20
  95. package/dist/features/orders/repository/orders.repository.js +5 -0
  96. package/dist/features/orders/schemas/firestore.d.ts +36 -1
  97. package/dist/features/orders/schemas/index.d.ts +24 -24
  98. package/dist/features/orders/types/index.d.ts +35 -7
  99. package/dist/features/pre-orders/schemas/index.d.ts +4 -4
  100. package/dist/features/products/components/GroupSettingsPanel.js +5 -1
  101. package/dist/features/products/schemas/index.d.ts +38 -38
  102. package/dist/features/products/schemas/product-features.validators.d.ts +75 -2
  103. package/dist/features/products/schemas/product-features.validators.js +63 -0
  104. package/dist/features/promotions/schemas/index.d.ts +14 -14
  105. package/dist/features/reviews/schemas/index.d.ts +14 -14
  106. package/dist/features/scams/constants/scammer-status-display.d.ts +28 -0
  107. package/dist/features/scams/constants/scammer-status-display.js +79 -0
  108. package/dist/features/scams/schemas/index.d.ts +2 -2
  109. package/dist/features/search/schemas/index.d.ts +2 -2
  110. package/dist/features/seller/actions/offer-actions.js +32 -2
  111. package/dist/features/seller/components/OfferPhaseTimeline.d.ts +59 -0
  112. package/dist/features/seller/components/OfferPhaseTimeline.js +107 -0
  113. package/dist/features/seller/components/SellerBidsView.js +11 -4
  114. package/dist/features/seller/components/SellerCouponEditorView.js +17 -17
  115. package/dist/features/seller/components/SellerOffersView.js +2 -1
  116. package/dist/features/seller/components/SellerPayoutSettingsView.js +38 -14
  117. package/dist/features/seller/repository/offer.repository.d.ts +69 -8
  118. package/dist/features/seller/repository/offer.repository.js +127 -23
  119. package/dist/features/seller/schemas/coupon-form.d.ts +72 -0
  120. package/dist/features/seller/schemas/coupon-form.js +116 -0
  121. package/dist/features/seller/schemas/firestore.d.ts +56 -2
  122. package/dist/features/seller/schemas/firestore.js +27 -0
  123. package/dist/features/seller/schemas/index.d.ts +2 -2
  124. package/dist/features/seller/schemas/offer-forms.d.ts +21 -0
  125. package/dist/features/seller/schemas/offer-forms.js +21 -0
  126. package/dist/features/shell/build-sections.d.ts +63 -0
  127. package/dist/features/shell/build-sections.js +207 -0
  128. package/dist/features/shell/field-ui-meta.d.ts +115 -0
  129. package/dist/features/shell/field-ui-meta.js +324 -0
  130. package/dist/features/shell/index.d.ts +4 -0
  131. package/dist/features/shell/index.js +2 -0
  132. package/dist/features/shipments/schemas/validation.d.ts +22 -22
  133. package/dist/features/status-history/components/StatusTimeline.d.ts +74 -0
  134. package/dist/features/status-history/components/StatusTimeline.js +46 -0
  135. package/dist/features/status-history/index.d.ts +11 -0
  136. package/dist/features/status-history/index.js +10 -0
  137. package/dist/features/store-extensions/components/ReviewDecisionModal.d.ts +27 -0
  138. package/dist/features/store-extensions/components/ReviewDecisionModal.js +82 -0
  139. package/dist/features/store-extensions/index.d.ts +12 -0
  140. package/dist/features/store-extensions/index.js +12 -0
  141. package/dist/features/store-extensions/schemas/admin-notification-form.d.ts +36 -0
  142. package/dist/features/store-extensions/schemas/admin-notification-form.js +114 -0
  143. package/dist/features/store-extensions/schemas/analytics-forms.d.ts +57 -0
  144. package/dist/features/store-extensions/schemas/analytics-forms.js +158 -0
  145. package/dist/features/store-extensions/schemas/custom-role-form.d.ts +85 -0
  146. package/dist/features/store-extensions/schemas/custom-role-form.js +118 -0
  147. package/dist/features/store-extensions/schemas/firestore.d.ts +21 -1
  148. package/dist/features/store-extensions/schemas/firestore.js +60 -0
  149. package/dist/features/store-extensions/schemas/google-config-form.d.ts +53 -0
  150. package/dist/features/store-extensions/schemas/google-config-form.js +105 -0
  151. package/dist/features/store-extensions/schemas/item-request-create-form.d.ts +28 -0
  152. package/dist/features/store-extensions/schemas/item-request-create-form.js +80 -0
  153. package/dist/features/store-extensions/schemas/listing-template-form.d.ts +78 -0
  154. package/dist/features/store-extensions/schemas/listing-template-form.js +87 -0
  155. package/dist/features/store-extensions/schemas/moderation-review-form.d.ts +49 -0
  156. package/dist/features/store-extensions/schemas/moderation-review-form.js +101 -0
  157. package/dist/features/store-extensions/schemas/payout-method-form.d.ts +153 -0
  158. package/dist/features/store-extensions/schemas/payout-method-form.js +155 -0
  159. package/dist/features/store-extensions/schemas/report-create-form.d.ts +25 -0
  160. package/dist/features/store-extensions/schemas/report-create-form.js +79 -0
  161. package/dist/features/store-extensions/schemas/report-review-form.d.ts +47 -0
  162. package/dist/features/store-extensions/schemas/report-review-form.js +111 -0
  163. package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +148 -0
  164. package/dist/features/store-extensions/schemas/shipping-config-form.js +104 -0
  165. package/dist/features/store-extensions/schemas/store-category-form.d.ts +54 -0
  166. package/dist/features/store-extensions/schemas/store-category-form.js +73 -0
  167. package/dist/features/stores/schemas/index.d.ts +4 -4
  168. package/dist/features/support/schemas/index.d.ts +4 -4
  169. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +350 -0
  170. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
  171. package/dist/index.d.ts +12 -2
  172. package/dist/index.js +12 -2
  173. package/dist/next/routing/route-map.d.ts +16 -2
  174. package/dist/next/routing/route-map.js +9 -2
  175. package/dist/schemas/firestore-value.d.ts +8 -0
  176. package/dist/schemas/firestore-value.js +44 -0
  177. package/dist/schemas/index.d.ts +1 -1
  178. package/dist/schemas/index.js +1 -1
  179. package/dist/schemas/registry.d.ts +734 -101
  180. package/dist/schemas/registry.js +64 -1
  181. package/dist/seed/bids-seed-data.js +30 -0
  182. package/dist/seed/offers-seed-data.js +212 -7
  183. package/dist/seed/orders-seed-data.js +336 -1
  184. package/dist/seed/products-auctions-seed-data.js +41 -0
  185. package/dist/server.d.ts +2 -0
  186. package/dist/server.js +5 -0
  187. package/dist/styles.css +1 -1
  188. package/dist/tailwind-utilities.css +1 -1
  189. package/dist/ui/DataTable.js +4 -2
  190. package/dist/ui/columns/build-columns.d.ts +6 -1
  191. package/dist/ui/columns/build-columns.js +53 -0
  192. package/dist/ui/columns/cell-renderers.d.ts +68 -0
  193. package/dist/ui/columns/cell-renderers.js +111 -0
  194. package/dist/ui/columns/column-renderers.d.ts +6 -1
  195. package/dist/ui/columns/column-renderers.js +6 -1
  196. package/dist/ui/columns/index.d.ts +2 -1
  197. package/dist/ui/columns/index.js +5 -1
  198. package/dist/ui/components/Button.js +27 -2
  199. package/dist/ui/components/RecordDetailModal.d.ts +10 -1
  200. package/dist/ui/components/RecordDetailModal.js +2 -2
  201. package/dist/ui/icons/icon-registry.d.ts +65 -0
  202. package/dist/ui/icons/icon-registry.js +115 -0
  203. package/package.json +2 -1
  204. package/scripts/node-esm-loader.mjs +65 -0
  205. package/scripts/seed-cli-loader.mjs +6 -49
  206. 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
- function AuctionRow({ auction, portal, }) {
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", className: `border-b border-[var(--appkit-color-border-subtle)] last:border-0 hover:bg-[var(--appkit-color-border-subtle)] transition-colors ${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
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" | "seller" | "moderator" | "employee" | "admin" | undefined;
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" | "seller" | "moderator" | "employee" | "admin" | undefined;
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 | {