@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.
- package/dist/features/shell/SectionForm.js +44 -5
- package/package.json +2 -2
- package/dist/_internal/server/features/classified/actions.d.ts +0 -12
- package/dist/_internal/server/features/classified/actions.js +0 -33
- package/dist/_internal/server/features/digital-code/actions.d.ts +0 -12
- package/dist/_internal/server/features/digital-code/actions.js +0 -33
- package/dist/_internal/server/features/homepage/data.d.ts +0 -18
- package/dist/_internal/server/features/homepage/data.js +0 -70
- package/dist/_internal/server/features/live/actions.d.ts +0 -6
- package/dist/_internal/server/features/live/actions.js +0 -27
- package/dist/_internal/server/features/messages/actions.d.ts +0 -6
- package/dist/_internal/server/features/messages/actions.js +0 -6
- package/dist/_internal/server/features/messages/data.d.ts +0 -10
- package/dist/_internal/server/features/messages/data.js +0 -24
- package/dist/_internal/server/features/messages/index.d.ts +0 -2
- package/dist/_internal/server/features/messages/index.js +0 -2
- package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +0 -12
- package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +0 -112
- package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +0 -2
- package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +0 -2
- package/dist/_internal/shared/features/homepage/section-gate.d.ts +0 -14
- package/dist/_internal/shared/features/homepage/section-gate.js +0 -51
- package/dist/_internal/shared/features/lottery/config-form.d.ts +0 -58
- package/dist/_internal/shared/features/lottery/config-form.js +0 -71
- package/dist/client/api/useFeatureFlags.d.ts +0 -22
- package/dist/client/api/useFeatureFlags.js +0 -27
- package/dist/features/account/address-validation.d.ts +0 -20
- package/dist/features/account/address-validation.js +0 -35
- package/dist/features/account/components/ChatList.d.ts +0 -14
- package/dist/features/account/components/ChatList.js +0 -9
- package/dist/features/account/components/ChatWindow.d.ts +0 -17
- package/dist/features/account/components/ChatWindow.js +0 -6
- package/dist/features/account/components/MessagesView.d.ts +0 -16
- package/dist/features/account/components/MessagesView.js +0 -5
- package/dist/features/account/components/UserOffersView.d.ts +0 -10
- package/dist/features/account/components/UserOffersView.js +0 -5
- package/dist/features/account/constants/addresses.d.ts +0 -13
- package/dist/features/account/constants/addresses.js +0 -43
- package/dist/features/account/hooks/useAddressForm.d.ts +0 -24
- package/dist/features/account/hooks/useAddressForm.js +0 -58
- package/dist/features/admin/actions/chat-actions.d.ts +0 -29
- package/dist/features/admin/actions/chat-actions.js +0 -101
- package/dist/features/admin/components/AdminFeatureFlagsView.d.ts +0 -9
- package/dist/features/admin/components/AdminFeatureFlagsView.js +0 -109
- package/dist/features/admin/components/AdminSiteView.d.ts +0 -10
- package/dist/features/admin/components/AdminSiteView.js +0 -52
- package/dist/features/admin/hooks/useChat.d.ts +0 -24
- package/dist/features/admin/hooks/useChat.js +0 -100
- package/dist/features/admin/permission-map.d.ts +0 -3
- package/dist/features/admin/permission-map.js +0 -26
- package/dist/features/admin/repository/chat.repository.d.ts +0 -50
- package/dist/features/admin/repository/chat.repository.js +0 -223
- package/dist/features/auth/actions/password-change-otp-actions.d.ts +0 -18
- package/dist/features/auth/actions/password-change-otp-actions.js +0 -88
- package/dist/features/auth/actions/realtime-token-actions.d.ts +0 -11
- package/dist/features/auth/actions/realtime-token-actions.js +0 -38
- package/dist/features/auth/password-change-otp.d.ts +0 -34
- package/dist/features/auth/password-change-otp.js +0 -56
- package/dist/features/classified/components/ClassifiedContactSellerPanel.d.ts +0 -12
- package/dist/features/classified/components/ClassifiedContactSellerPanel.js +0 -49
- package/dist/features/events/api/route.d.ts +0 -12
- package/dist/features/events/api/route.js +0 -90
- package/dist/features/faq/api/route.d.ts +0 -11
- package/dist/features/faq/api/route.js +0 -52
- package/dist/features/faq/hooks/useFAQs.d.ts +0 -22
- package/dist/features/faq/hooks/useFAQs.js +0 -41
- package/dist/features/media/upload/video-poster.test.d.ts +0 -1
- package/dist/features/media/upload/video-poster.test.js +0 -42
- package/dist/features/messages/actions/index.d.ts +0 -2
- package/dist/features/messages/actions/index.js +0 -2
- package/dist/features/messages/actions/messages-actions.d.ts +0 -15
- package/dist/features/messages/actions/messages-actions.js +0 -33
- package/dist/features/messages/actions/ping-rtdb.d.ts +0 -2
- package/dist/features/messages/actions/ping-rtdb.js +0 -26
- package/dist/features/messages/hooks/useConversation.d.ts +0 -22
- package/dist/features/messages/hooks/useConversation.js +0 -155
- package/dist/features/messages/hooks/useConversations.d.ts +0 -15
- package/dist/features/messages/hooks/useConversations.js +0 -104
- package/dist/features/messages/index.d.ts +0 -6
- package/dist/features/messages/index.js +0 -4
- package/dist/features/messages/realtime.d.ts +0 -32
- package/dist/features/messages/realtime.js +0 -39
- package/dist/features/messages/repository/conversations.repository.d.ts +0 -71
- package/dist/features/messages/repository/conversations.repository.js +0 -284
- package/dist/features/messages/schemas/firestore.d.ts +0 -34
- package/dist/features/messages/schemas/firestore.js +0 -16
- package/dist/features/messages/schemas/index.d.ts +0 -177
- package/dist/features/messages/schemas/index.js +0 -35
- package/dist/features/messages/server.d.ts +0 -6
- package/dist/features/messages/server.js +0 -6
- package/dist/features/products/components/MakeOfferForm.d.ts +0 -20
- package/dist/features/products/components/MakeOfferForm.js +0 -9
- package/dist/features/reviews/api/route.d.ts +0 -21
- package/dist/features/reviews/api/route.js +0 -174
- package/dist/features/seller/api/offers/route.d.ts +0 -17
- package/dist/features/seller/api/offers/route.js +0 -63
- package/dist/features/seller/components/SellerAuctionsView.d.ts +0 -9
- package/dist/features/seller/components/SellerAuctionsView.js +0 -113
- package/dist/features/seller/components/SellerOffersPanel.d.ts +0 -21
- package/dist/features/seller/components/SellerOffersPanel.js +0 -160
- package/dist/features/seller/components/SellerPreOrdersView.d.ts +0 -6
- package/dist/features/seller/components/SellerPreOrdersView.js +0 -148
- package/dist/features/seller/components/SellerPrizeDrawsView.d.ts +0 -6
- package/dist/features/seller/components/SellerPrizeDrawsView.js +0 -152
- package/dist/features/seller/permission-map.d.ts +0 -5
- package/dist/features/seller/permission-map.js +0 -17
- package/dist/features/shell/StepForm.d.ts +0 -80
- package/dist/features/shell/StepForm.js +0 -136
- package/dist/features/stores/api/route.d.ts +0 -12
- package/dist/features/stores/api/route.js +0 -110
- package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.d.ts +0 -2
- package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.js +0 -33
- package/dist/features/tester/seed-data/authored/account-auth__testing-program.d.ts +0 -2
- package/dist/features/tester/seed-data/authored/account-auth__testing-program.js +0 -138
- package/dist/features/tester/seed-data/bids-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/bids-tester-seed-data.js +0 -37
- package/dist/features/tester/seed-data/blog-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/blog-tester-seed-data.js +0 -40
- package/dist/features/tester/seed-data/carts-tester-seed-data.d.ts +0 -3
- package/dist/features/tester/seed-data/carts-tester-seed-data.js +0 -70
- package/dist/features/tester/seed-data/categories-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/categories-tester-seed-data.js +0 -218
- package/dist/features/tester/seed-data/coupons-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/coupons-tester-seed-data.js +0 -76
- package/dist/features/tester/seed-data/events-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/events-tester-seed-data.js +0 -193
- package/dist/features/tester/seed-data/offers-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/offers-tester-seed-data.js +0 -191
- package/dist/features/tester/seed-data/orders-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/orders-tester-seed-data.js +0 -329
- package/dist/features/tester/seed-data/products-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/products-tester-seed-data.js +0 -815
- package/dist/features/tester/seed-data/stores-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/stores-tester-seed-data.js +0 -79
- package/dist/features/wishlist/components/WishlistToggleButton.d.ts +0 -12
- package/dist/features/wishlist/components/WishlistToggleButton.js +0 -36
- package/dist/monitoring/analytics.d.ts +0 -80
- package/dist/monitoring/analytics.js +0 -176
- package/dist/next/middleware/pii-redactor.d.ts +0 -32
- package/dist/next/middleware/pii-redactor.js +0 -84
- package/dist/providers/db-firebase/realtime.d.ts +0 -42
- package/dist/providers/db-firebase/realtime.js +0 -138
- package/dist/security/rbac/Can.d.ts +0 -31
- package/dist/security/rbac/Can.js +0 -22
- package/dist/security/rbac/default-roles.d.ts +0 -2
- package/dist/security/rbac/default-roles.js +0 -83
- package/dist/security/rbac/hook.d.ts +0 -20
- package/dist/security/rbac/hook.js +0 -30
- package/dist/security/rbac/index.d.ts +0 -8
- package/dist/security/rbac/index.js +0 -6
- package/dist/security/rbac/middleware.d.ts +0 -51
- package/dist/security/rbac/middleware.js +0 -51
- package/dist/security/rbac/resolver.d.ts +0 -5
- package/dist/security/rbac/resolver.js +0 -38
- package/dist/security/rbac/server.d.ts +0 -24
- package/dist/security/rbac/server.js +0 -42
- package/dist/security/rbac/types.d.ts +0 -22
- package/dist/security/rbac/types.js +0 -2
- package/dist/seed/conversations-seed-data.d.ts +0 -2
- package/dist/seed/conversations-seed-data.js +0 -292
- package/dist/utils/filter.helper.d.ts +0 -18
- package/dist/utils/filter.helper.js +0 -21
- package/dist/utils/pagination.helper.d.ts +0 -23
- package/dist/utils/pagination.helper.js +0 -24
- package/dist/utils/search-tokens.d.ts +0 -2
- 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>;
|