@mohasinac/appkit 4.41.0 → 4.41.2
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/seller/schemas/coupon-form.d.ts +37 -37
- package/dist/features/seller/schemas/coupon-form.js +36 -8
- package/dist/features/shell/SectionForm.js +44 -5
- package/dist/schemas/registry.d.ts +10 -10
- 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,160 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback, useEffect, useState, useTransition } from "react";
|
|
4
|
-
import { Alert, Badge, Button, Div, Heading, Input, LoginRequiredModal, Row, Spinner, Stack, Text } from "../../../ui";
|
|
5
|
-
import { isAuthError } from "../../../utils/auth-error";
|
|
6
|
-
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
7
|
-
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
8
|
-
import { normalizeError } from "../../../errors/normalize";
|
|
9
|
-
function formatRupees(amount) {
|
|
10
|
-
if (amount === undefined || amount === null)
|
|
11
|
-
return "—";
|
|
12
|
-
return `₹${amount.toLocaleString("en-IN")}`;
|
|
13
|
-
}
|
|
14
|
-
function relativeTime(date) {
|
|
15
|
-
if (!date)
|
|
16
|
-
return "";
|
|
17
|
-
const d = date instanceof Date ? date : new Date(date);
|
|
18
|
-
const diff = Date.now() - d.getTime();
|
|
19
|
-
const mins = Math.floor(diff / 60000);
|
|
20
|
-
if (mins < 60)
|
|
21
|
-
return `${mins}m ago`;
|
|
22
|
-
const hrs = Math.floor(diff / 3600000);
|
|
23
|
-
if (hrs < 24)
|
|
24
|
-
return `${hrs}h ago`;
|
|
25
|
-
return `${Math.floor(diff / 86400000)}d ago`;
|
|
26
|
-
}
|
|
27
|
-
function expiresIn(expiresAt) {
|
|
28
|
-
if (!expiresAt)
|
|
29
|
-
return "";
|
|
30
|
-
const exp = expiresAt instanceof Date ? expiresAt : new Date(expiresAt);
|
|
31
|
-
const diff = exp.getTime() - Date.now();
|
|
32
|
-
if (diff <= 0)
|
|
33
|
-
return "Expired";
|
|
34
|
-
const hrs = Math.floor(diff / 3600000);
|
|
35
|
-
if (hrs < 1)
|
|
36
|
-
return "< 1h left";
|
|
37
|
-
if (hrs < 24)
|
|
38
|
-
return `${hrs}h left`;
|
|
39
|
-
return `${Math.floor(diff / 86400000)}d left`;
|
|
40
|
-
}
|
|
41
|
-
function statusVariant(status) {
|
|
42
|
-
switch (status) {
|
|
43
|
-
case "pending": return "warning";
|
|
44
|
-
case "accepted": return "success";
|
|
45
|
-
case "declined": return "danger";
|
|
46
|
-
case "countered": return "info";
|
|
47
|
-
case "expired": return "default";
|
|
48
|
-
case "withdrawn": return "default";
|
|
49
|
-
case "paid": return "success";
|
|
50
|
-
default: return "default";
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
const PLACEHOLDER_SELLER_NOTE = "Optional note to buyer";
|
|
54
|
-
function OfferCard({ offer, onRespond, onUpdate, onNeedsLogin }) {
|
|
55
|
-
const [uiState, setUiState] = useState("idle");
|
|
56
|
-
const [counterInput, setCounterInput] = useState("");
|
|
57
|
-
const [sellerNote, setSellerNote] = useState("");
|
|
58
|
-
const [error, setError] = useState("");
|
|
59
|
-
const [isPending, startTransition] = useTransition();
|
|
60
|
-
const toAccepting = useCallback(() => setUiState("accepting"), []);
|
|
61
|
-
const toCountering = useCallback(() => setUiState("countering"), []);
|
|
62
|
-
const toDeclining = useCallback(() => setUiState("declining"), []);
|
|
63
|
-
const toIdle = useCallback(() => setUiState("idle"), []);
|
|
64
|
-
const isPendingOffer = offer.status === "pending";
|
|
65
|
-
function submit(action) {
|
|
66
|
-
setError("");
|
|
67
|
-
startTransition(async () => {
|
|
68
|
-
try {
|
|
69
|
-
await onRespond(action);
|
|
70
|
-
onUpdate(offer.id, {
|
|
71
|
-
status: action.action === "accept"
|
|
72
|
-
? "accepted"
|
|
73
|
-
: action.action === "decline"
|
|
74
|
-
? "declined"
|
|
75
|
-
: "countered",
|
|
76
|
-
});
|
|
77
|
-
setUiState("idle");
|
|
78
|
-
}
|
|
79
|
-
catch (err) {
|
|
80
|
-
void normalizeError(err);
|
|
81
|
-
if (isAuthError(err)) {
|
|
82
|
-
onNeedsLogin();
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
setError(err instanceof Error ? err.message : "Something went wrong.");
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
function handleAccept() {
|
|
91
|
-
submit({ action: "accept", offerId: offer.id, sellerNote: sellerNote || undefined });
|
|
92
|
-
}
|
|
93
|
-
function handleDecline() {
|
|
94
|
-
submit({ action: "decline", offerId: offer.id, sellerNote: sellerNote || undefined });
|
|
95
|
-
}
|
|
96
|
-
function handleCounter() {
|
|
97
|
-
const amount = parseInt(counterInput, 10);
|
|
98
|
-
if (!amount || amount <= 0) {
|
|
99
|
-
setError("Enter a valid counter amount.");
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
if (amount >= offer.listedPrice) {
|
|
103
|
-
setError("Counter must be below the listed price.");
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (amount === offer.offerAmount) {
|
|
107
|
-
setError("Counter must differ from the buyer's offer.");
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
submit({ action: "counter", offerId: offer.id, counterAmount: amount, sellerNote: sellerNote || undefined });
|
|
111
|
-
}
|
|
112
|
-
return (_jsxs(Stack, { surface: "card", padding: "sm", gap: "3", children: [_jsxs(Row, { align: "start", justify: "between", gap: "sm", wrap: true, children: [_jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: "truncate", color: "primary", size: "sm", weight: "semibold", children: offer.productTitle ?? "Unknown Product" }), _jsxs(Text, { className: "mt-0.5", color: "muted", size: "xs", children: [relativeTime(offer.createdAt), " \u00B7 ", isPendingOffer ? expiresIn(offer.expiresAt) : ""] })] }), _jsx(Badge, { variant: statusVariant(offer.status), size: "xs", className: "shrink-0 capitalize", children: offer.status })] }), _jsxs(Row, { wrap: true, gap: "md", children: [_jsxs(Div, { children: [_jsx(Text, { className: "tracking-wide", color: "faint", size: "xs", transform: "uppercase", children: "Listed" }), _jsx(Text, { size: "sm", weight: "medium", color: "muted", children: formatRupees(offer.listedPrice) })] }), _jsxs(Div, { children: [_jsx(Text, { className: "tracking-wide", color: "faint", size: "xs", transform: "uppercase", children: "Offered" }), _jsx(Text, { size: "sm", weight: "semibold", color: "primary", children: formatRupees(offer.offerAmount) })] }), offer.counterAmount != null && (_jsxs(Div, { children: [_jsx(Text, { className: "tracking-wide", color: "faint", size: "xs", transform: "uppercase", children: "Your Counter" }), _jsx(Text, { className: "text-info", size: "sm", weight: "medium", children: formatRupees(offer.counterAmount) })] }))] }), offer.buyerNote && (_jsxs(Text, { className: "italic", color: "muted", size: "xs", children: ["\"", offer.buyerNote, "\""] })), isPendingOffer && uiState === "idle" && (_jsxs(Row, { wrap: true, gap: "sm", children: [_jsx(Button, { size: "sm", variant: "primary", onClick: toAccepting, disabled: isPending, children: "Accept" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toCountering, disabled: isPending, border: "strong", children: "Counter" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toDeclining, disabled: isPending, className: "text-error border border-error/20", children: "Decline" })] })), uiState === "accepting" && (_jsxs(Stack, { gap: "sm", children: [_jsx(Input, { placeholder: PLACEHOLDER_SELLER_NOTE, value: sellerNote, onChange: (e) => setSellerNote(e.target.value), disabled: isPending }), _jsxs(Row, { gap: "sm", children: [_jsx(Button, { size: "sm", variant: "primary", onClick: handleAccept, disabled: isPending, children: isPending ? "Accepting…" : "Confirm Accept" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toIdle, disabled: isPending, children: ACTIONS.STORE["cancel-form"].label })] })] })), uiState === "declining" && (_jsxs(Stack, { gap: "sm", children: [_jsx(Input, { placeholder: PLACEHOLDER_SELLER_NOTE, value: sellerNote, onChange: (e) => setSellerNote(e.target.value), disabled: isPending }), _jsxs(Row, { gap: "sm", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: handleDecline, disabled: isPending, className: "text-error border border-error/20", children: isPending ? "Declining…" : "Confirm Decline" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toIdle, disabled: isPending, children: ACTIONS.STORE["cancel-form"].label })] })] })), uiState === "countering" && (_jsxs(Stack, { gap: "sm", children: [_jsxs(Text, { size: "xs", color: "muted", children: ["Suggest a price between the buyer's offer (", formatRupees(offer.offerAmount), ") and your listed price (", formatRupees(offer.listedPrice), ")."] }), _jsx(Input, { type: "number", placeholder: "Your counter amount (\u20B9)", value: counterInput, onChange: (e) => setCounterInput(e.target.value), disabled: isPending }), _jsx(Input, { placeholder: PLACEHOLDER_SELLER_NOTE, value: sellerNote, onChange: (e) => setSellerNote(e.target.value), disabled: isPending }), _jsxs(Row, { gap: "sm", children: [_jsx(Button, { size: "sm", variant: "secondary", onClick: handleCounter, disabled: isPending, children: isPending ? "Sending…" : "Send Counter" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: toIdle, disabled: isPending, children: ACTIONS.STORE["cancel-form"].label })] })] })), error && _jsx(Alert, { variant: "error", children: _jsx(Text, { size: "xs", children: error }) })] }));
|
|
113
|
-
}
|
|
114
|
-
export function SellerOffersPanel({ fetchEndpoint = SELLER_ENDPOINTS.OFFERS, onRespond, className = "", }) {
|
|
115
|
-
const [offers, setOffers] = useState([]);
|
|
116
|
-
const [loading, setLoading] = useState(true);
|
|
117
|
-
const [fetchError, setFetchError] = useState("");
|
|
118
|
-
const [showLoginModal, setShowLoginModal] = useState(false);
|
|
119
|
-
const [statusFilter, setStatusFilter] = useState("all");
|
|
120
|
-
const loadOffers = useCallback(async () => {
|
|
121
|
-
setLoading(true);
|
|
122
|
-
setFetchError("");
|
|
123
|
-
try {
|
|
124
|
-
const url = statusFilter === "all"
|
|
125
|
-
? fetchEndpoint
|
|
126
|
-
: `${fetchEndpoint}?status=${statusFilter}`;
|
|
127
|
-
const res = await fetch(url);
|
|
128
|
-
if (!res.ok) {
|
|
129
|
-
if (res.status === 401 || res.status === 403) {
|
|
130
|
-
setShowLoginModal(true);
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
throw new Error(`Error ${res.status}`);
|
|
134
|
-
}
|
|
135
|
-
const json = (await res.json());
|
|
136
|
-
setOffers(json.items ?? json.offers ?? []);
|
|
137
|
-
}
|
|
138
|
-
catch (err) {
|
|
139
|
-
void normalizeError(err);
|
|
140
|
-
setFetchError(err instanceof Error ? err.message : "Failed to load offers.");
|
|
141
|
-
}
|
|
142
|
-
finally {
|
|
143
|
-
setLoading(false);
|
|
144
|
-
}
|
|
145
|
-
}, [fetchEndpoint, statusFilter]);
|
|
146
|
-
useEffect(() => { void loadOffers(); }, [loadOffers]);
|
|
147
|
-
function handleUpdate(id, patch) {
|
|
148
|
-
setOffers((prev) => prev.map((o) => (o.id === id ? { ...o, ...patch } : o)));
|
|
149
|
-
}
|
|
150
|
-
const STATUS_FILTERS = [
|
|
151
|
-
{ value: "all", label: "All" },
|
|
152
|
-
{ value: "pending", label: "Pending" },
|
|
153
|
-
{ value: "countered", label: "Countered" },
|
|
154
|
-
{ value: "accepted", label: "Accepted" },
|
|
155
|
-
{ value: "declined", label: "Declined" },
|
|
156
|
-
{ value: "expired", label: "Expired" },
|
|
157
|
-
];
|
|
158
|
-
const pending = offers.filter((o) => o.status === "pending").length;
|
|
159
|
-
return (_jsxs(Stack, { className: `${className}`, gap: "md", children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to manage offers. Please log in or create an account to continue." }), _jsxs(Row, { align: "center", justify: "between", gap: "sm", wrap: true, children: [_jsxs(Div, { children: [_jsx(Heading, { level: 2, size: "lg", weight: "semibold", color: "primary", children: "Offers Received" }), pending > 0 && (_jsxs(Text, { className: "text-warning mt-0.5", size: "xs", children: [pending, " pending offer", pending > 1 ? "s" : "", " awaiting your response"] }))] }), _jsx(Button, { size: "sm", variant: "ghost", onClick: loadOffers, disabled: loading, border: "strong", textSize: "xs", children: loading ? "Refreshing…" : ACTIONS.STORE["refresh-offers"].label })] }), _jsx(Row, { wrap: true, gap: "xs", children: STATUS_FILTERS.map((f) => (_jsx(Button, { size: "sm", variant: statusFilter === f.value ? "primary" : "ghost", onClick: () => setStatusFilter(f.value), className: "text-[length:var(--appkit-text-xs)] px-[var(--appkit-space-2)] py-[var(--appkit-space-1)]", children: f.label }, f.value))) }), fetchError && _jsx(Alert, { variant: "error", children: _jsx(Text, { size: "sm", children: fetchError }) }), loading && (_jsx(Row, { justify: "center", padding: "y-3xl", children: _jsx(Spinner, { size: "lg" }) })), !loading && offers.length === 0 && (_jsx(Div, { className: "text-center", padding: "y-3xl", children: _jsx(Text, { size: "sm", color: "faint", children: "No offers found" }) })), !loading && offers.length > 0 && (_jsx(Stack, { gap: "3", children: offers.map((offer) => (_jsx(OfferCard, { offer: offer, onRespond: onRespond, onUpdate: handleUpdate, onNeedsLogin: () => setShowLoginModal(true) }, offer.id))) }))] }));
|
|
160
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { ListingLayoutProps } from "../../../ui";
|
|
3
|
-
export interface SellerPreOrdersViewProps extends ListingLayoutProps {
|
|
4
|
-
onDelete?: (id: string) => Promise<void>;
|
|
5
|
-
}
|
|
6
|
-
export declare function SellerPreOrdersView({ children, onDelete, ...props }: SellerPreOrdersViewProps): React.JSX.Element;
|
|
@@ -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;
|