@mohasinac/appkit 4.41.0 → 4.41.1

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 (166) hide show
  1. package/dist/features/shell/SectionForm.js +44 -5
  2. package/package.json +2 -2
  3. package/dist/_internal/server/features/classified/actions.d.ts +0 -12
  4. package/dist/_internal/server/features/classified/actions.js +0 -33
  5. package/dist/_internal/server/features/digital-code/actions.d.ts +0 -12
  6. package/dist/_internal/server/features/digital-code/actions.js +0 -33
  7. package/dist/_internal/server/features/homepage/data.d.ts +0 -18
  8. package/dist/_internal/server/features/homepage/data.js +0 -70
  9. package/dist/_internal/server/features/live/actions.d.ts +0 -6
  10. package/dist/_internal/server/features/live/actions.js +0 -27
  11. package/dist/_internal/server/features/messages/actions.d.ts +0 -6
  12. package/dist/_internal/server/features/messages/actions.js +0 -6
  13. package/dist/_internal/server/features/messages/data.d.ts +0 -10
  14. package/dist/_internal/server/features/messages/data.js +0 -24
  15. package/dist/_internal/server/features/messages/index.d.ts +0 -2
  16. package/dist/_internal/server/features/messages/index.js +0 -2
  17. package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +0 -12
  18. package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +0 -112
  19. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +0 -2
  20. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +0 -2
  21. package/dist/_internal/shared/features/homepage/section-gate.d.ts +0 -14
  22. package/dist/_internal/shared/features/homepage/section-gate.js +0 -51
  23. package/dist/_internal/shared/features/lottery/config-form.d.ts +0 -58
  24. package/dist/_internal/shared/features/lottery/config-form.js +0 -71
  25. package/dist/client/api/useFeatureFlags.d.ts +0 -22
  26. package/dist/client/api/useFeatureFlags.js +0 -27
  27. package/dist/features/account/address-validation.d.ts +0 -20
  28. package/dist/features/account/address-validation.js +0 -35
  29. package/dist/features/account/components/ChatList.d.ts +0 -14
  30. package/dist/features/account/components/ChatList.js +0 -9
  31. package/dist/features/account/components/ChatWindow.d.ts +0 -17
  32. package/dist/features/account/components/ChatWindow.js +0 -6
  33. package/dist/features/account/components/MessagesView.d.ts +0 -16
  34. package/dist/features/account/components/MessagesView.js +0 -5
  35. package/dist/features/account/components/UserOffersView.d.ts +0 -10
  36. package/dist/features/account/components/UserOffersView.js +0 -5
  37. package/dist/features/account/constants/addresses.d.ts +0 -13
  38. package/dist/features/account/constants/addresses.js +0 -43
  39. package/dist/features/account/hooks/useAddressForm.d.ts +0 -24
  40. package/dist/features/account/hooks/useAddressForm.js +0 -58
  41. package/dist/features/admin/actions/chat-actions.d.ts +0 -29
  42. package/dist/features/admin/actions/chat-actions.js +0 -101
  43. package/dist/features/admin/components/AdminFeatureFlagsView.d.ts +0 -9
  44. package/dist/features/admin/components/AdminFeatureFlagsView.js +0 -109
  45. package/dist/features/admin/components/AdminSiteView.d.ts +0 -10
  46. package/dist/features/admin/components/AdminSiteView.js +0 -52
  47. package/dist/features/admin/hooks/useChat.d.ts +0 -24
  48. package/dist/features/admin/hooks/useChat.js +0 -100
  49. package/dist/features/admin/permission-map.d.ts +0 -3
  50. package/dist/features/admin/permission-map.js +0 -26
  51. package/dist/features/admin/repository/chat.repository.d.ts +0 -50
  52. package/dist/features/admin/repository/chat.repository.js +0 -223
  53. package/dist/features/auth/actions/password-change-otp-actions.d.ts +0 -18
  54. package/dist/features/auth/actions/password-change-otp-actions.js +0 -88
  55. package/dist/features/auth/actions/realtime-token-actions.d.ts +0 -11
  56. package/dist/features/auth/actions/realtime-token-actions.js +0 -38
  57. package/dist/features/auth/password-change-otp.d.ts +0 -34
  58. package/dist/features/auth/password-change-otp.js +0 -56
  59. package/dist/features/classified/components/ClassifiedContactSellerPanel.d.ts +0 -12
  60. package/dist/features/classified/components/ClassifiedContactSellerPanel.js +0 -49
  61. package/dist/features/events/api/route.d.ts +0 -12
  62. package/dist/features/events/api/route.js +0 -90
  63. package/dist/features/faq/api/route.d.ts +0 -11
  64. package/dist/features/faq/api/route.js +0 -52
  65. package/dist/features/faq/hooks/useFAQs.d.ts +0 -22
  66. package/dist/features/faq/hooks/useFAQs.js +0 -41
  67. package/dist/features/media/upload/video-poster.test.d.ts +0 -1
  68. package/dist/features/media/upload/video-poster.test.js +0 -42
  69. package/dist/features/messages/actions/index.d.ts +0 -2
  70. package/dist/features/messages/actions/index.js +0 -2
  71. package/dist/features/messages/actions/messages-actions.d.ts +0 -15
  72. package/dist/features/messages/actions/messages-actions.js +0 -33
  73. package/dist/features/messages/actions/ping-rtdb.d.ts +0 -2
  74. package/dist/features/messages/actions/ping-rtdb.js +0 -26
  75. package/dist/features/messages/hooks/useConversation.d.ts +0 -22
  76. package/dist/features/messages/hooks/useConversation.js +0 -155
  77. package/dist/features/messages/hooks/useConversations.d.ts +0 -15
  78. package/dist/features/messages/hooks/useConversations.js +0 -104
  79. package/dist/features/messages/index.d.ts +0 -6
  80. package/dist/features/messages/index.js +0 -4
  81. package/dist/features/messages/realtime.d.ts +0 -32
  82. package/dist/features/messages/realtime.js +0 -39
  83. package/dist/features/messages/repository/conversations.repository.d.ts +0 -71
  84. package/dist/features/messages/repository/conversations.repository.js +0 -284
  85. package/dist/features/messages/schemas/firestore.d.ts +0 -34
  86. package/dist/features/messages/schemas/firestore.js +0 -16
  87. package/dist/features/messages/schemas/index.d.ts +0 -177
  88. package/dist/features/messages/schemas/index.js +0 -35
  89. package/dist/features/messages/server.d.ts +0 -6
  90. package/dist/features/messages/server.js +0 -6
  91. package/dist/features/products/components/MakeOfferForm.d.ts +0 -20
  92. package/dist/features/products/components/MakeOfferForm.js +0 -9
  93. package/dist/features/reviews/api/route.d.ts +0 -21
  94. package/dist/features/reviews/api/route.js +0 -174
  95. package/dist/features/seller/api/offers/route.d.ts +0 -17
  96. package/dist/features/seller/api/offers/route.js +0 -63
  97. package/dist/features/seller/components/SellerAuctionsView.d.ts +0 -9
  98. package/dist/features/seller/components/SellerAuctionsView.js +0 -113
  99. package/dist/features/seller/components/SellerOffersPanel.d.ts +0 -21
  100. package/dist/features/seller/components/SellerOffersPanel.js +0 -160
  101. package/dist/features/seller/components/SellerPreOrdersView.d.ts +0 -6
  102. package/dist/features/seller/components/SellerPreOrdersView.js +0 -148
  103. package/dist/features/seller/components/SellerPrizeDrawsView.d.ts +0 -6
  104. package/dist/features/seller/components/SellerPrizeDrawsView.js +0 -152
  105. package/dist/features/seller/permission-map.d.ts +0 -5
  106. package/dist/features/seller/permission-map.js +0 -17
  107. package/dist/features/shell/StepForm.d.ts +0 -80
  108. package/dist/features/shell/StepForm.js +0 -136
  109. package/dist/features/stores/api/route.d.ts +0 -12
  110. package/dist/features/stores/api/route.js +0 -110
  111. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.d.ts +0 -2
  112. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.js +0 -33
  113. package/dist/features/tester/seed-data/authored/account-auth__testing-program.d.ts +0 -2
  114. package/dist/features/tester/seed-data/authored/account-auth__testing-program.js +0 -138
  115. package/dist/features/tester/seed-data/bids-tester-seed-data.d.ts +0 -2
  116. package/dist/features/tester/seed-data/bids-tester-seed-data.js +0 -37
  117. package/dist/features/tester/seed-data/blog-tester-seed-data.d.ts +0 -2
  118. package/dist/features/tester/seed-data/blog-tester-seed-data.js +0 -40
  119. package/dist/features/tester/seed-data/carts-tester-seed-data.d.ts +0 -3
  120. package/dist/features/tester/seed-data/carts-tester-seed-data.js +0 -70
  121. package/dist/features/tester/seed-data/categories-tester-seed-data.d.ts +0 -2
  122. package/dist/features/tester/seed-data/categories-tester-seed-data.js +0 -218
  123. package/dist/features/tester/seed-data/coupons-tester-seed-data.d.ts +0 -2
  124. package/dist/features/tester/seed-data/coupons-tester-seed-data.js +0 -76
  125. package/dist/features/tester/seed-data/events-tester-seed-data.d.ts +0 -2
  126. package/dist/features/tester/seed-data/events-tester-seed-data.js +0 -193
  127. package/dist/features/tester/seed-data/offers-tester-seed-data.d.ts +0 -2
  128. package/dist/features/tester/seed-data/offers-tester-seed-data.js +0 -191
  129. package/dist/features/tester/seed-data/orders-tester-seed-data.d.ts +0 -2
  130. package/dist/features/tester/seed-data/orders-tester-seed-data.js +0 -329
  131. package/dist/features/tester/seed-data/products-tester-seed-data.d.ts +0 -2
  132. package/dist/features/tester/seed-data/products-tester-seed-data.js +0 -815
  133. package/dist/features/tester/seed-data/stores-tester-seed-data.d.ts +0 -2
  134. package/dist/features/tester/seed-data/stores-tester-seed-data.js +0 -79
  135. package/dist/features/wishlist/components/WishlistToggleButton.d.ts +0 -12
  136. package/dist/features/wishlist/components/WishlistToggleButton.js +0 -36
  137. package/dist/monitoring/analytics.d.ts +0 -80
  138. package/dist/monitoring/analytics.js +0 -176
  139. package/dist/next/middleware/pii-redactor.d.ts +0 -32
  140. package/dist/next/middleware/pii-redactor.js +0 -84
  141. package/dist/providers/db-firebase/realtime.d.ts +0 -42
  142. package/dist/providers/db-firebase/realtime.js +0 -138
  143. package/dist/security/rbac/Can.d.ts +0 -31
  144. package/dist/security/rbac/Can.js +0 -22
  145. package/dist/security/rbac/default-roles.d.ts +0 -2
  146. package/dist/security/rbac/default-roles.js +0 -83
  147. package/dist/security/rbac/hook.d.ts +0 -20
  148. package/dist/security/rbac/hook.js +0 -30
  149. package/dist/security/rbac/index.d.ts +0 -8
  150. package/dist/security/rbac/index.js +0 -6
  151. package/dist/security/rbac/middleware.d.ts +0 -51
  152. package/dist/security/rbac/middleware.js +0 -51
  153. package/dist/security/rbac/resolver.d.ts +0 -5
  154. package/dist/security/rbac/resolver.js +0 -38
  155. package/dist/security/rbac/server.d.ts +0 -24
  156. package/dist/security/rbac/server.js +0 -42
  157. package/dist/security/rbac/types.d.ts +0 -22
  158. package/dist/security/rbac/types.js +0 -2
  159. package/dist/seed/conversations-seed-data.d.ts +0 -2
  160. package/dist/seed/conversations-seed-data.js +0 -292
  161. package/dist/utils/filter.helper.d.ts +0 -18
  162. package/dist/utils/filter.helper.js +0 -21
  163. package/dist/utils/pagination.helper.d.ts +0 -23
  164. package/dist/utils/pagination.helper.js +0 -24
  165. package/dist/utils/search-tokens.d.ts +0 -2
  166. package/dist/utils/search-tokens.js +0 -21
@@ -1,148 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { Row, SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit/client";
4
- import { sortBy } from "@mohasinac/appkit/client";
5
- import React, { useState, useCallback } from "react";
6
- import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
7
- import { Badge, ConfirmDeleteModal, Div, FilterChipGroup, ListingLayout, RowActionMenu, Span, Text } from "../../../ui";
8
- import { MediaImage } from "../../media/MediaImage";
9
- import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
10
- import { SELLER_PRE_ORDER_STATUS_TABS } from "../../admin/constants/filter-tabs";
11
- import { ROUTES } from "../../../constants";
12
- import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
13
- import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../../admin/hooks/useAdminListingData";
14
- import { DataListingView } from "../../admin/components/DataListingView";
15
- import { useActionDispatch } from "../../../react/hooks/use-action-dispatch";
16
- import { useAvailabilityScope } from "../../products/hooks/useAvailabilityScope";
17
- const PRE_ORDER_TYPES = ["pre-order"];
18
- const PRE_ORDER_COLUMNS = [
19
- {
20
- key: "thumbnail",
21
- header: "",
22
- className: "w-12",
23
- render: (row) => row.imageUrl ? (_jsx(Div, { className: "relative w-10 h-10 flex-shrink-0 border border-[var(--appkit-color-border)]", rounded: "lg", overflow: "hidden", children: _jsx(MediaImage, { src: row.imageUrl, alt: "", size: "thumbnail" }) })) : (_jsx(Row, { className: "w-10 h-10 bg-[var(--appkit-color-surface-raised)] border border-[var(--appkit-color-border)]", align: "center", justify: "center", rounded: "lg", children: _jsx(Span, { size: "xs", color: "faint", children: "\u2013" }) })),
24
- },
25
- {
26
- key: "primary",
27
- header: "Pre-order",
28
- render: (row) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { className: "text-[var(--appkit-color-text)] line-clamp-1", weight: "medium", children: row.primary }), _jsx(Span, { size: "xs", color: "muted", children: row.secondary })] })),
29
- },
30
- {
31
- key: "price",
32
- header: "Price",
33
- className: "w-28 text-right",
34
- render: (row) => (_jsx(Span, { size: "sm", weight: "medium", className: "text-[var(--appkit-color-text)]", children: row.price })),
35
- },
36
- {
37
- key: "status",
38
- header: "Status",
39
- className: "w-28",
40
- render: (row) => {
41
- // Real ProductStatus is draft|published|in_review|archived — "active"
42
- // fixed to "published"; "cancelled" is not a stored status value.
43
- const variant = row.status === "published"
44
- ? "success"
45
- : row.status === "draft"
46
- ? "default"
47
- : "warning";
48
- return _jsx(Badge, { variant: variant, children: row.status });
49
- },
50
- },
51
- {
52
- key: "deliveryDate",
53
- header: "Est. Delivery",
54
- className: "w-36",
55
- render: (row) => (_jsx(Span, { size: "xs", color: "muted", children: row.deliveryDate })),
56
- },
57
- {
58
- key: "updatedAt",
59
- header: "Updated",
60
- className: "w-28",
61
- render: (row) => (_jsx(Span, { size: "xs", color: "muted", children: row.updatedAt })),
62
- },
63
- ];
64
- export function SellerPreOrdersView({ children, onDelete, ...props }) {
65
- const dispatch = useActionDispatch();
66
- const [deleteTargetId, setDeleteTargetId] = useState(null);
67
- const { deletingId, handleDelete: performDelete } = useEntityDelete({
68
- endpoint: SELLER_ENDPOINTS.PRODUCT_BY_ID,
69
- deleteFn: onDelete,
70
- successMessage: "Pre-order deleted.",
71
- fetchOptions: { credentials: "include" },
72
- });
73
- const handleDelete = useCallback(async (id) => {
74
- await performDelete(id);
75
- setDeleteTargetId(null);
76
- }, [performDelete]);
77
- if (React.Children.count(children) > 0) {
78
- return (_jsx(ListingLayout, { portal: "seller", ...props, children: children }));
79
- }
80
- const scope = useAvailabilityScope(PRE_ORDER_TYPES);
81
- const config = {
82
- portal: "seller",
83
- title: "Pre-Orders",
84
- searchPlaceholder: "Search pre-orders by name…",
85
- emptyLabel: "No pre-orders listed yet",
86
- filterKeys: ["status"],
87
- defaultSort: sortBy("createdAt", "DESC"),
88
- queryKey: ["seller", "pre-orders", "listing"],
89
- endpoint: SELLER_ENDPOINTS.PRODUCTS,
90
- sortOptions: [
91
- { value: sortBy("createdAt", "DESC"), label: "Newest" },
92
- { value: sortBy("createdAt", "ASC"), label: "Oldest" },
93
- { value: "title", label: "Title A–Z" },
94
- { value: "preOrderDeliveryDate", label: "Delivery Soon" },
95
- ],
96
- columns: PRE_ORDER_COLUMNS,
97
- mapRows: (response) => toRecordArray(response.products).map((item, index) => {
98
- const priceRaw = typeof item.price === "number" ? item.price : 0;
99
- return {
100
- id: toStringValue(item.id, `preorder-${index}`),
101
- primary: toStringValue(item.title ?? item.name, "Untitled pre-order"),
102
- secondary: toStringValue(item.condition, ""),
103
- status: toStringValue(item.status, "draft"),
104
- price: priceRaw ? toCurrency(priceRaw) : "—",
105
- deliveryDate: item.preOrderDeliveryDate
106
- ? toRelativeDate(item.preOrderDeliveryDate)
107
- : "TBA",
108
- updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
109
- imageUrl: toStringValue(item.mainImage ?? item.images?.[0], undefined),
110
- image: toStringValue(item.mainImage ?? item.images?.[0], undefined),
111
- };
112
- }),
113
- getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
114
- // No "Show closed" toggle here (unlike Auctions/Prize Draws): the public
115
- // PreOrdersIndexListing equivalent filters on stockQuantity>0, a range
116
- // filter, which cannot be combined with this view's title/
117
- // preOrderDeliveryDate/createdAt sort options without violating
118
- // Firestore's orderBy-must-match-the-range-field rule (confirmed by
119
- // appkit/scripts/audit-listing-indices.mjs QUERY_UNSATISFIABLE). Fixing
120
- // this properly would mean constraining sort choices per toggle state,
121
- // out of scope for this pass — left as a real gap, not silently broken.
122
- buildFilters: (state) => {
123
- const status = state.status && state.status !== "All" ? sieveFilter("status", SIEVE_OP.EQ, state.status) : null;
124
- return ["listingType==pre-order", status].filter(Boolean).join(",");
125
- },
126
- buildExtraParams: () => scope.extraParams,
127
- renderAboveContent: scope.renderAboveContent,
128
- rowHrefTemplate: String(ROUTES.STORE.PRE_ORDERS_EDIT("{id}")),
129
- renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
130
- {
131
- label: ACTIONS.STORE["edit-listing"].label,
132
- onClick: () => void dispatch({ type: "NAVIGATE", href: String(ROUTES.STORE.PRE_ORDERS_EDIT(row.id)) }),
133
- },
134
- ...(onDelete
135
- ? [
136
- {
137
- label: ACTIONS.STORE["delete-listing"].label,
138
- destructive: true,
139
- onClick: () => setDeleteTargetId(row.id),
140
- disabled: deletingId === row.id,
141
- },
142
- ]
143
- : []),
144
- ] })),
145
- renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: SELLER_PRE_ORDER_STATUS_TABS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) })),
146
- };
147
- return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Pre-Order", message: "Are you sure you want to delete this pre-order listing? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
148
- }
@@ -1,6 +0,0 @@
1
- import React from "react";
2
- import type { ListingLayoutProps } from "../../../ui";
3
- export interface SellerPrizeDrawsViewProps extends ListingLayoutProps {
4
- onDelete?: (id: string) => Promise<void>;
5
- }
6
- export declare function SellerPrizeDrawsView({ children, onDelete, ...props }: SellerPrizeDrawsViewProps): React.JSX.Element;
@@ -1,152 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { Row, SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit/client";
4
- import { sortBy } from "@mohasinac/appkit/client";
5
- import React, { useState, useCallback } from "react";
6
- import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
7
- import { Badge, ConfirmDeleteModal, Div, FilterChipGroup, ListingLayout, RowActionMenu, Span, Text } from "../../../ui";
8
- import { MediaImage } from "../../media/MediaImage";
9
- import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
10
- import { SELLER_PRIZE_DRAW_STATUS_TABS } from "../../admin/constants/filter-tabs";
11
- import { ROUTES } from "../../../constants";
12
- import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
13
- import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../../admin/hooks/useAdminListingData";
14
- import { DataListingView } from "../../admin/components/DataListingView";
15
- import { useAvailabilityScope } from "../../products/hooks/useAvailabilityScope";
16
- const PRIZE_DRAW_TYPES = ["prize-draw"];
17
- import { useActionDispatch } from "../../../react/hooks/use-action-dispatch";
18
- // Real ProductStatus is draft|published|in_review|archived — "active"
19
- // fixed to "published"; "ended"/"cancelled" removed since status never
20
- // holds those values (ended is derived from prizeRevealWindowEnd, shown
21
- // via the "Show closed" toolbar toggle below).
22
- const STATUS_VARIANT = {
23
- published: "success",
24
- draft: "default",
25
- };
26
- const PRIZE_DRAW_COLUMNS = [
27
- {
28
- key: "thumbnail",
29
- header: "",
30
- className: "w-12",
31
- render: (row) => row.imageUrl ? (_jsx(Div, { className: "relative w-10 h-10 flex-shrink-0 border border-[var(--appkit-color-border)]", rounded: "lg", overflow: "hidden", children: _jsx(MediaImage, { src: row.imageUrl, alt: "", size: "thumbnail" }) })) : (_jsx(Row, { className: "w-10 h-10 bg-[var(--appkit-color-surface-raised)] border border-[var(--appkit-color-border)]", align: "center", justify: "center", rounded: "lg", children: _jsx(Span, { size: "xs", color: "faint", children: "\u2013" }) })),
32
- },
33
- {
34
- key: "primary",
35
- header: "Prize Draw",
36
- render: (row) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Text, { className: "text-[var(--appkit-color-text)] line-clamp-1", weight: "medium", children: row.primary }), _jsx(Span, { size: "xs", color: "muted", children: row.secondary })] })),
37
- },
38
- {
39
- key: "entryFee",
40
- header: "Entry Fee",
41
- className: "w-28 text-right",
42
- render: (row) => (_jsx(Span, { size: "sm", weight: "medium", className: "text-[var(--appkit-color-text)]", children: row.entryFee })),
43
- },
44
- {
45
- key: "status",
46
- header: "Status",
47
- className: "w-28",
48
- render: (row) => (_jsx(Badge, { variant: STATUS_VARIANT[row.status] ?? "default", children: row.status })),
49
- },
50
- {
51
- key: "drawDate",
52
- header: "Draw Date",
53
- className: "w-32",
54
- render: (row) => (_jsx(Span, { size: "xs", color: "muted", children: row.drawDate })),
55
- },
56
- {
57
- key: "updatedAt",
58
- header: "Updated",
59
- className: "w-28",
60
- render: (row) => (_jsx(Span, { size: "xs", color: "muted", children: row.updatedAt })),
61
- },
62
- ];
63
- export function SellerPrizeDrawsView({ children, onDelete, ...props }) {
64
- const dispatch = useActionDispatch();
65
- // Independent of DataListingView's own internal useUrlTable() — see the
66
- // same pattern in SellerAuctionsView.tsx.
67
- const scope = useAvailabilityScope(PRIZE_DRAW_TYPES);
68
- const [deleteTargetId, setDeleteTargetId] = useState(null);
69
- const { deletingId, handleDelete: performDelete } = useEntityDelete({
70
- endpoint: SELLER_ENDPOINTS.PRODUCT_BY_ID,
71
- deleteFn: onDelete,
72
- successMessage: "Prize draw deleted.",
73
- fetchOptions: { credentials: "include" },
74
- });
75
- const handleDelete = useCallback(async (id) => {
76
- await performDelete(id);
77
- setDeleteTargetId(null);
78
- }, [performDelete]);
79
- if (React.Children.count(children) > 0) {
80
- return (_jsx(ListingLayout, { portal: "seller", ...props, children: children }));
81
- }
82
- const config = {
83
- portal: "seller",
84
- title: "Prize Draws",
85
- searchPlaceholder: "Search prize draws by name…",
86
- emptyLabel: "No prize draws listed yet",
87
- filterKeys: ["status"],
88
- defaultSort: sortBy("createdAt", "DESC"),
89
- queryKey: ["seller", "prize-draws", "listing"],
90
- endpoint: SELLER_ENDPOINTS.PRODUCTS,
91
- sortOptions: [
92
- { value: sortBy("createdAt", "DESC"), label: "Newest" },
93
- { value: sortBy("createdAt", "ASC"), label: "Oldest" },
94
- { value: "title", label: "Title A–Z" },
95
- { value: "prizeRevealWindowEnd", label: "Draw Date Soon" },
96
- ],
97
- columns: PRIZE_DRAW_COLUMNS,
98
- mapRows: (response) => toRecordArray(response.products).map((item, index) => {
99
- const priceRaw = typeof item.price === "number" ? item.price : 0;
100
- return {
101
- id: toStringValue(item.id, `prize-draw-${index}`),
102
- primary: toStringValue(item.title ?? item.name, "Untitled prize draw"),
103
- secondary: toStringValue(item.condition, ""),
104
- status: toStringValue(item.status, "draft"),
105
- entryFee: priceRaw ? toCurrency(priceRaw) : "Free",
106
- drawDate: item.prizeRevealWindowEnd
107
- ? toRelativeDate(item.prizeRevealWindowEnd)
108
- : "TBA",
109
- updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
110
- imageUrl: toStringValue(item.mainImage ?? item.images?.[0], undefined),
111
- image: toStringValue(item.mainImage ?? item.images?.[0], undefined),
112
- };
113
- }),
114
- getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
115
- buildFilters: (state) => {
116
- const status = state.status && state.status !== "All" ? sieveFilter("status", SIEVE_OP.EQ, state.status) : null;
117
- // The hide-closed clause that used to live here tested the reveal
118
- // WINDOW END date, a different field from the reveal STATUS every other
119
- // surface reads — so a draw the seller had closed early still showed as
120
- // open here. It also pushed an inequality alongside an arbitrary sort
121
- // (Root Cause #59), which `audit-listing-indices` had been reporting as
122
- // QUERY_UNSATISFIABLE. The scope param now carries it, resolved from the
123
- // listing-type registry.
124
- return ["listingType==prize-draw", status].filter(Boolean).join(",");
125
- },
126
- buildExtraParams: () => scope.extraParams,
127
- renderAboveContent: scope.renderAboveContent,
128
- rowHrefTemplate: String(ROUTES.STORE.PRIZE_DRAWS_EDIT("{id}")),
129
- renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
130
- {
131
- label: ACTIONS.STORE["edit-listing"].label,
132
- onClick: () => void dispatch({ type: "NAVIGATE", href: String(ROUTES.STORE.PRIZE_DRAWS_EDIT(row.id)) }),
133
- },
134
- {
135
- label: "View Entries",
136
- onClick: () => void dispatch({ type: "NAVIGATE", href: String(ROUTES.STORE.PRIZE_DRAW_ENTRIES(row.id)) }),
137
- },
138
- ...(onDelete
139
- ? [
140
- {
141
- label: ACTIONS.STORE["delete-listing"].label,
142
- destructive: true,
143
- onClick: () => setDeleteTargetId(row.id),
144
- disabled: deletingId === row.id,
145
- },
146
- ]
147
- : []),
148
- ] })),
149
- renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: SELLER_PRIZE_DRAW_STATUS_TABS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) })),
150
- };
151
- return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Prize Draw", message: "Are you sure you want to delete this prize draw listing? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
152
- }
@@ -1,5 +0,0 @@
1
- import type { Permission } from "../../security";
2
- /** Required permission for each store management route path */
3
- export declare const STORE_PAGE_PERMISSIONS: Record<string, Permission>;
4
- /** @deprecated Use STORE_PAGE_PERMISSIONS */
5
- export declare const SELLER_PAGE_PERMISSIONS: Record<string, string>;
@@ -1,17 +0,0 @@
1
- /** Required permission for each store management route path */
2
- export const STORE_PAGE_PERMISSIONS = {
3
- "/store": "seller:access",
4
- "/store/dashboard": "seller:analytics",
5
- "/store/products": "seller:products:read",
6
- "/store/products/new": "seller:products:write",
7
- "/store/products/[id]": "seller:products:write",
8
- "/store/orders": "seller:orders:read",
9
- "/store/orders/[id]": "seller:orders:read",
10
- "/store/analytics": "seller:analytics",
11
- "/store/coupons": "seller:coupons",
12
- "/store/storefront": "seller:store",
13
- "/store/payouts": "seller:payouts:read",
14
- "/store/shipping": "seller:shipping",
15
- };
16
- /** @deprecated Use STORE_PAGE_PERMISSIONS */
17
- export const SELLER_PAGE_PERMISSIONS = STORE_PAGE_PERMISSIONS;
@@ -1,80 +0,0 @@
1
- import { type ReactNode } from "react";
2
- import type { JsonValue } from "@mohasinac/appkit/client";
3
- import type { ZodTypeAny } from "zod";
4
- export interface StepDef<T extends object = Record<string, JsonValue>> {
5
- label: string;
6
- render: (props: {
7
- values: T;
8
- onChange: (partial: Partial<T>) => void;
9
- errors: Record<string, string>;
10
- }) => ReactNode;
11
- /** Returns an error message string if invalid, or null/undefined if valid. */
12
- validate?: (values: T) => string | null | undefined;
13
- /**
14
- * Schema field names this step owns — drives error→step attribution
15
- * (surfaced to the caller via `onValidationChange`'s `fieldToStepIndex`,
16
- * consumed by `<FormErrorSummary>`).
17
- */
18
- fields?: string[];
19
- /**
20
- * Per-step Zod schema. Runs live (on every value change, not just on
21
- * Next/Publish) via `onValidationChange`. Falls back to the whole-form
22
- * `schema` prop, then to a schema inherited from an ancestor `FormShell`
23
- * via `FormSchemaContext`, when omitted.
24
- */
25
- schema?: ZodTypeAny;
26
- }
27
- export interface StepFormProps<T extends object = Record<string, JsonValue>> {
28
- steps: StepDef<T>[];
29
- values: T;
30
- onChange: (partial: Partial<T>) => void;
31
- onComplete: () => void | Promise<void>;
32
- completeLabel?: string;
33
- isLoading?: boolean;
34
- /** localStorage key to persist current step (optional). */
35
- formId?: string;
36
- /** Current step index (0-based). Controlled from outside. */
37
- currentStep: number;
38
- onStepChange: (step: number) => void;
39
- /** Suppress the built-in action bar. Use FormShell's renderBottomBar instead. */
40
- hideActions?: boolean;
41
- /** Per-step error flags — when true, step button shows a red error badge */
42
- stepErrors?: boolean[];
43
- /**
44
- * Whole-form Zod schema, used by any step that doesn't declare its own
45
- * `StepDef.schema`. Falls back to an ancestor `FormShell`'s schema (via
46
- * `FormSchemaContext`) when omitted here too.
47
- */
48
- schema?: ZodTypeAny;
49
- /**
50
- * Fired whenever live validation recomputes — the current field-name→
51
- * message map plus a field-name→step-index map derived from `steps[].fields`.
52
- * The caller (which owns the single `FormShellContext.Provider` for the
53
- * surrounding form) composes these into its own context value so
54
- * `<FormErrorSummary>` and per-field inline errors both work, instead of
55
- * `StepForm` mounting a second, potentially-shadowing provider itself.
56
- */
57
- onValidationChange?: (fieldErrors: Record<string, string>, fieldToStepIndex: Record<string, number>) => void;
58
- }
59
- export interface StepFormActionsProps {
60
- currentStep: number;
61
- totalSteps: number;
62
- onNext: () => void;
63
- onPrev?: () => void;
64
- completeLabel?: string;
65
- isLoading?: boolean;
66
- disabled?: boolean;
67
- }
68
- /** Standalone step nav bar — use as `renderBottomBar` in FormShell. */
69
- export declare function StepFormActions({ currentStep, totalSteps, onNext, onPrev, completeLabel, isLoading, disabled, }: StepFormActionsProps): import("react").JSX.Element;
70
- /** Step indicator bar shown above step content. */
71
- export declare function StepIndicator({ steps, currentStep, onStepClick, stepErrors, }: {
72
- steps: {
73
- label: string;
74
- }[];
75
- currentStep: number;
76
- onStepClick?: (index: number) => void;
77
- /** True for each step that has a validation error — renders a red dot badge */
78
- stepErrors?: boolean[];
79
- }): import("react").JSX.Element;
80
- export declare function StepForm<T extends object = Record<string, JsonValue>>({ steps, values, onChange, onComplete, completeLabel, isLoading, formId, currentStep, onStepChange, hideActions, stepErrors, schema, onValidationChange, }: StepFormProps<T>): import("react").JSX.Element;
@@ -1,136 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useCallback, useContext, useEffect, useMemo, useState } from "react";
4
- import { Check } from "lucide-react";
5
- import { Button } from "../../ui/components/Button";
6
- import { classNames } from "../../ui/style.helper";
7
- import { Div, Nav, Row, Span, Stack, Text, useToast } from "../../ui";
8
- import { normalizeError } from "../../errors/normalize";
9
- import { FormSchemaContext } from "./FormShell";
10
- /** Standalone step nav bar — use as `renderBottomBar` in FormShell. */
11
- export function StepFormActions({ currentStep, totalSteps, onNext, onPrev, completeLabel = "Publish Now", isLoading = false, disabled = false, }) {
12
- const isFirst = currentStep === 0;
13
- const isLast = currentStep === totalSteps - 1;
14
- const nextStepLabel = `Next →`;
15
- return (_jsxs(Row, { paddingX: "x-5", className: "border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", padding: "y-sm", align: "center", justify: "between", gap: "sm", children: [_jsx(_Fragment, { children: !isFirst && onPrev && (_jsx(Button, { variant: "outline", size: "sm", onClick: onPrev, disabled: disabled || isLoading, children: "\u2190 Back" })) }), _jsxs(Row, { align: "center", gap: "3", children: [_jsxs(Span, { size: "xs", color: "muted", children: [currentStep + 1, " / ", totalSteps] }), _jsx(Button, { variant: "primary", size: "sm", onClick: onNext, disabled: disabled || isLoading, isLoading: isLoading && isLast, children: isLast ? completeLabel : nextStepLabel })] })] }));
16
- }
17
- /** Step indicator bar shown above step content. */
18
- export function StepIndicator({ steps, currentStep, onStepClick, stepErrors, }) {
19
- return (_jsx(Nav, { "aria-label": "Form steps", layout: "flex", gap: "none", className: "mb-6 overflow-x-auto", children: steps.map((step, i) => {
20
- const isDone = i < currentStep;
21
- const isActive = i === currentStep;
22
- const hasError = stepErrors?.[i] === true;
23
- return (_jsxs(Row, { className: "flex-shrink-0", align: "center", gap: "none", children: [_jsxs(Button, { variant: "ghost", type: "button", onClick: () => onStepClick?.(i), gap: "sm", rounded: "lg", paddingX: "sm", paddingY: "xs", textSize: "sm", className: classNames("cursor-pointer", isActive
24
- ? "font-semibold text-[var(--appkit-color-primary)]"
25
- : isDone
26
- ? "text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-text)]"
27
- : "text-[var(--appkit-color-text-faint)] hover:text-[var(--appkit-color-text-muted)]"), children: [_jsxs(Span, { className: "relative flex-shrink-0", children: [hasError && (_jsx(Span, { className: "absolute -top-0.5 -right-0.5 w-2 h-2 bg-[var(--appkit-color-error)] z-10", rounded: "full", "aria-label": "This step has errors" })), _jsx(Span, { className: classNames("flex-shrink-0 w-6 h-6 rounded-full flex items-center justify-center text-[length:var(--appkit-text-xs)] font-bold border-2", hasError
28
- ? "border-[var(--appkit-color-error)] bg-[var(--appkit-color-error)] text-white"
29
- : isActive
30
- ? "border-[var(--appkit-color-primary)] bg-[var(--appkit-color-primary)] text-white"
31
- : isDone
32
- ? "border-[var(--appkit-color-primary)] bg-[var(--appkit-color-primary)] text-white"
33
- : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-faint)]"), children: isDone && !hasError ? _jsx(Check, { className: "w-3 h-3" }) : hasError ? "!" : i + 1 })] }), _jsx(Span, { className: "hidden sm:inline", children: step.label })] }), i < steps.length - 1 && (_jsx(Div, { className: classNames("w-6 h-px flex-shrink-0 mx-1", i < currentStep
34
- ? "bg-[var(--appkit-color-primary)]"
35
- : "bg-[var(--appkit-color-border)]") }))] }, i));
36
- }) }));
37
- }
38
- export function StepForm({ steps, values, onChange, onComplete, completeLabel = "Publish Now", isLoading = false, formId, currentStep, onStepChange, hideActions = false, stepErrors, schema, onValidationChange, }) {
39
- const { showToast } = useToast();
40
- const inheritedSchema = useContext(FormSchemaContext);
41
- const [fieldErrors, setFieldErrors] = useState({});
42
- const [stepError, setStepError] = useState(null);
43
- const fieldToStepIndex = useMemo(() => {
44
- const map = {};
45
- steps.forEach((step, i) => {
46
- step.fields?.forEach((field) => { map[field] = i; });
47
- });
48
- return map;
49
- }, [steps]);
50
- const runValidation = useCallback((nextValues) => {
51
- const activeSchema = steps[currentStep]?.schema ?? schema ?? inheritedSchema;
52
- if (!activeSchema)
53
- return;
54
- // audit-unvalidated-safeparse-ok: bulk-replaces fieldErrors from the full
55
- // parse result (clears fields that just became valid); applyZodIssues'
56
- // incremental setFieldError-per-issue can't do that.
57
- const parsed = activeSchema.safeParse(nextValues);
58
- if (parsed.success) {
59
- setFieldErrors({});
60
- onValidationChange?.({}, fieldToStepIndex);
61
- return;
62
- }
63
- const next = {};
64
- for (const issue of parsed.error.issues) {
65
- if (!issue.path || issue.path.length === 0)
66
- continue;
67
- next[issue.path.map(String).join(".")] = issue.message;
68
- }
69
- setFieldErrors(next);
70
- onValidationChange?.(next, fieldToStepIndex);
71
- }, [steps, currentStep, schema, inheritedSchema, fieldToStepIndex, onValidationChange]);
72
- // Re-run validation whenever the active step or schema changes, so
73
- // switching steps (or arriving with pre-filled values) shows accurate
74
- // live errors immediately rather than only after the next keystroke.
75
- useEffect(() => {
76
- runValidation(values);
77
- // eslint-disable-next-line react-hooks/exhaustive-deps
78
- }, [currentStep, steps[currentStep]?.schema, schema, inheritedSchema]);
79
- const handleFieldChange = useCallback((partial) => {
80
- const merged = { ...values, ...partial };
81
- onChange(partial);
82
- runValidation(merged);
83
- }, [values, onChange, runValidation]);
84
- // Persist step to localStorage if formId provided
85
- useEffect(() => {
86
- if (formId)
87
- localStorage.setItem(`stepform:${formId}`, String(currentStep));
88
- }, [formId, currentStep]);
89
- // Restore step from localStorage on mount
90
- useEffect(() => {
91
- if (!formId)
92
- return;
93
- const saved = localStorage.getItem(`stepform:${formId}`);
94
- if (saved !== null) {
95
- const n = Number(saved);
96
- if (!isNaN(n) && n >= 0 && n < steps.length)
97
- onStepChange(n);
98
- }
99
- // eslint-disable-next-line react-hooks/exhaustive-deps
100
- }, [formId]);
101
- const goNext = useCallback(async () => {
102
- const step = steps[currentStep];
103
- if (step?.validate) {
104
- const err = step.validate(values);
105
- if (err) {
106
- setStepError(err);
107
- return;
108
- }
109
- }
110
- setStepError(null);
111
- if (currentStep < steps.length - 1) {
112
- onStepChange(currentStep + 1);
113
- }
114
- else {
115
- try {
116
- await onComplete();
117
- }
118
- catch (err) {
119
- void normalizeError(err);
120
- showToast(err instanceof Error ? err.message : "Something went wrong.", "error");
121
- }
122
- }
123
- }, [currentStep, steps, values, onComplete, onStepChange, showToast]);
124
- const goPrev = useCallback(() => {
125
- if (currentStep > 0) {
126
- setStepError(null);
127
- onStepChange(currentStep - 1);
128
- }
129
- }, [currentStep, onStepChange]);
130
- const currentStepDef = steps[currentStep];
131
- const isLast = currentStep === steps.length - 1;
132
- return (_jsxs(Stack, { children: [_jsx(StepIndicator, { steps: steps, currentStep: currentStep, stepErrors: stepErrors, onStepClick: (i) => { if (i !== currentStep) {
133
- setStepError(null);
134
- onStepChange(i);
135
- } } }), _jsx(Div, { className: "flex-1", children: currentStepDef?.render({ values, onChange: handleFieldChange, errors: fieldErrors }) }), !hideActions && stepError && (_jsx(Text, { className: "mt-3 text-[var(--appkit-color-error)]", size: "sm", children: stepError })), !hideActions && (_jsx(StepFormActions, { currentStep: currentStep, totalSteps: steps.length, onNext: () => void goNext(), onPrev: currentStep > 0 ? goPrev : undefined, completeLabel: completeLabel, isLoading: isLoading && isLast, disabled: isLoading }))] }));
136
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * feat-stores — Next.js App Router API handlers (GET /api/stores)
3
- *
4
- * Consuming projects can create a 2-line stub:
5
- *
6
- * ```ts
7
- * // app/api/stores/route.ts
8
- * export { GET } from "@mohasinac/feat-stores";
9
- * ```
10
- */
11
- import { NextResponse } from "next/server.js";
12
- export declare function GET(request: Request): Promise<NextResponse>;