@mohasinac/appkit 2.7.8 → 2.7.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/shared/config/index.d.ts +1 -1
- package/dist/_internal/shared/config/schema.d.ts +95 -1
- package/dist/client-entry.d.ts +1 -1
- package/dist/client.d.ts +3 -0
- package/dist/client.js +5 -0
- package/dist/configs/next.js +28 -76
- package/dist/features/account/components/UserOffersPanel.js +17 -5
- package/dist/features/auctions/components/AuctionDetailPageView.js +17 -1
- package/dist/features/auctions/components/PlaceBidFormClient.js +10 -5
- package/dist/features/categories/components/BundleBuyNowCta.js +13 -6
- package/dist/features/events/components/EventPollWidget.js +7 -1
- package/dist/features/events/components/SpinWheelView.js +12 -5
- package/dist/features/pre-orders/components/PreOrderActionsClient.js +10 -3
- package/dist/features/products/components/MakeOfferButton.js +16 -8
- package/dist/features/products/components/PrizeRevealModal.js +18 -5
- package/dist/features/products/components/ProductDetailPageView.js +23 -1
- package/dist/features/seller/components/SellerOffersPanel.js +17 -5
- package/dist/features/wishlist/components/WishlistToggleButton.js +26 -12
- package/dist/http/api-handler.js +7 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +2 -0
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/BaseListingCard.js +8 -6
- package/dist/ui/components/Button.style.css +8 -5
- package/dist/ui/components/ListingLayout.style.css +19 -9
- package/dist/ui/components/LoginRequiredModal.d.ts +9 -0
- package/dist/ui/components/LoginRequiredModal.js +11 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/dist/utils/auth-error.d.ts +8 -0
- package/dist/utils/auth-error.js +20 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +1 -1
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useTransition } from "react";
|
|
4
|
-
import { Button, Div, Input, Span, Text } from "../../../ui";
|
|
4
|
+
import { Button, Div, Input, LoginRequiredModal, Span, Text } from "../../../ui";
|
|
5
|
+
import { isAuthError } from "../../../utils/auth-error";
|
|
5
6
|
import { formatCurrency } from "../../../utils/number.formatter";
|
|
6
7
|
export function MakeOfferButton({ productId, listedPrice, currency, minOfferPercent = 70, onMakeOffer, className = "", }) {
|
|
7
8
|
const [state, setState] = useState("idle");
|
|
8
9
|
const [errorMsg, setErrorMsg] = useState("");
|
|
10
|
+
const [showLoginModal, setShowLoginModal] = useState(false);
|
|
9
11
|
const [isPending, startTransition] = useTransition();
|
|
10
12
|
const minOffer = Math.round(listedPrice * (minOfferPercent / 100));
|
|
11
13
|
const defaultOffer = Math.round(listedPrice * 0.9);
|
|
@@ -41,13 +43,19 @@ export function MakeOfferButton({ productId, listedPrice, currency, minOfferPerc
|
|
|
41
43
|
setState("success");
|
|
42
44
|
}
|
|
43
45
|
catch (err) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
if (isAuthError(err)) {
|
|
47
|
+
setState("idle");
|
|
48
|
+
setShowLoginModal(true);
|
|
47
49
|
}
|
|
48
50
|
else {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
52
|
+
if (msg.includes("active offer") || msg.includes("ACTIVE_OFFER")) {
|
|
53
|
+
setState("pending");
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
setErrorMsg(msg || "Could not send offer. Please try again.");
|
|
57
|
+
setState("error");
|
|
58
|
+
}
|
|
51
59
|
}
|
|
52
60
|
}
|
|
53
61
|
});
|
|
@@ -64,5 +72,5 @@ export function MakeOfferButton({ productId, listedPrice, currency, minOfferPerc
|
|
|
64
72
|
if (state === "error") {
|
|
65
73
|
return (_jsxs(Div, { className: `rounded-xl border border-red-200 dark:border-red-800 bg-red-50 dark:bg-red-900/20 p-4 space-y-2 ${className}`, children: [_jsx(Text, { className: "text-xs text-red-600 dark:text-red-400 text-center", children: errorMsg }), _jsxs(Div, { className: "flex gap-2", children: [_jsx(Button, { variant: "ghost", size: "sm", className: "flex-1", onClick: handleCancel, children: "Cancel" }), _jsx(Button, { variant: "secondary", size: "sm", className: "flex-1", onClick: () => setState("confirm"), children: "Try Again" })] })] }));
|
|
66
74
|
}
|
|
67
|
-
return (_jsx(Button, { variant: "ghost", size: "md", className: `w-full border border-zinc-300 dark:border-zinc-600 ${className}`, onClick: handleOpenConfirm, children: "Make Offer" }));
|
|
75
|
+
return (_jsxs(_Fragment, { children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to make an offer. Please log in or create an account to continue." }), _jsx(Button, { variant: "ghost", size: "md", className: `w-full border border-zinc-300 dark:border-zinc-600 ${className}`, onClick: handleOpenConfirm, children: "Make Offer" })] }));
|
|
68
76
|
}
|
|
@@ -15,7 +15,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
15
15
|
* nor LetItRip admins can influence the outcome.
|
|
16
16
|
*/
|
|
17
17
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
18
|
-
import { Button, Div, Heading, Modal, Stack, Text } from "../../../ui";
|
|
18
|
+
import { Button, Div, Heading, LoginRequiredModal, Modal, Stack, Text } from "../../../ui";
|
|
19
|
+
import { isAuthError } from "../../../utils/auth-error";
|
|
19
20
|
import { PrizeDrawCollage } from "./PrizeDrawCollage";
|
|
20
21
|
const REVEAL_DURATION_MS = 3200; // total animation length
|
|
21
22
|
const CYCLE_INTERVAL_FAST = 80;
|
|
@@ -26,6 +27,7 @@ export function PrizeRevealModal({ open, onClose, items, orderId, productId, onR
|
|
|
26
27
|
const [winner, setWinner] = useState(initialPrizeWon);
|
|
27
28
|
const [errorMessage, setErrorMessage] = useState("");
|
|
28
29
|
const [effectiveRngUrl, setEffectiveRngUrl] = useState(rngSourceUrl);
|
|
30
|
+
const [showLoginModal, setShowLoginModal] = useState(false);
|
|
29
31
|
const cycleTimerRef = useRef(null);
|
|
30
32
|
const endTimerRef = useRef(null);
|
|
31
33
|
// Clean up timers on close/unmount so we don't leak between sessions.
|
|
@@ -83,12 +85,23 @@ export function PrizeRevealModal({ open, onClose, items, orderId, productId, onR
|
|
|
83
85
|
body: JSON.stringify({ orderId }),
|
|
84
86
|
});
|
|
85
87
|
const json = (await res.json());
|
|
86
|
-
if (!res.ok)
|
|
88
|
+
if (!res.ok) {
|
|
89
|
+
if (res.status === 401 || res.status === 403) {
|
|
90
|
+
setPhase("idle");
|
|
91
|
+
setShowLoginModal(true);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
87
94
|
throw new Error("Reveal request failed");
|
|
95
|
+
}
|
|
88
96
|
response = json.data ?? {};
|
|
89
97
|
}
|
|
90
98
|
}
|
|
91
99
|
catch (err) {
|
|
100
|
+
if (isAuthError(err)) {
|
|
101
|
+
setPhase("idle");
|
|
102
|
+
setShowLoginModal(true);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
92
105
|
setPhase("error");
|
|
93
106
|
setErrorMessage(err instanceof Error ? err.message : "Reveal request failed");
|
|
94
107
|
return;
|
|
@@ -117,8 +130,8 @@ export function PrizeRevealModal({ open, onClose, items, orderId, productId, onR
|
|
|
117
130
|
}, REVEAL_DURATION_MS);
|
|
118
131
|
}, [onReveal, orderId, phase, productId, startAnimation]);
|
|
119
132
|
const winnerImg = winner?.images?.[0];
|
|
120
|
-
return (
|
|
121
|
-
|
|
122
|
-
|
|
133
|
+
return (_jsxs(Modal, { isOpen: open, onClose: onClose, title: "Prize Reveal", size: "lg", children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to reveal your prize. Please log in or create an account to continue." }), _jsxs(Stack, { gap: "md", children: [phase === "refunded" ? (_jsxs(Div, { className: "rounded border border-yellow-400/40 bg-yellow-50 px-4 py-3 text-yellow-900 dark:bg-yellow-900/30 dark:text-yellow-100", children: [_jsx(Heading, { level: 3, className: "mb-1", children: "Pool exhausted \u2014 you've been refunded" }), _jsx(Text, { className: "text-sm", children: "Every prize in this draw was already claimed by the time your entry rolled. Your order has been marked refunded automatically." })] })) : null, phase === "error" ? (_jsxs(Div, { className: "rounded border border-red-400/40 bg-red-50 px-4 py-3 text-red-900 dark:bg-red-900/30 dark:text-red-100", children: [_jsx(Text, { className: "text-sm font-semibold", children: "Something went wrong" }), _jsx(Text, { className: "text-sm", children: errorMessage })] })) : null, _jsx(PrizeDrawCollage, { items: items, hideWonState: true, highlightItemNumber: highlight }), phase === "idle" ? (_jsx(Button, { type: "button", variant: "primary", size: "lg", onClick: handleRevealClick, children: "\u2728 Reveal my prize" })) : null, phase === "revealing" ? (_jsxs(Div, { className: "rounded bg-[var(--appkit-color-surface-muted)] p-4 text-center", children: [_jsx(Text, { className: "text-lg font-semibold", children: "Rolling\u2026" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "The winner was locked by the server before this animation started. Hang tight \u2014 we're just making it look pretty." })] })) : null, phase === "won" && winner ? (_jsxs(Div, { className: "rounded-lg border-2 border-[var(--appkit-color-primary)] bg-[var(--appkit-color-surface)] p-4 text-center", children: [_jsx(Text, { className: "text-xs uppercase tracking-wider text-[var(--appkit-color-text-muted)]", children: "You won" }), _jsxs(Heading, { level: 2, className: "my-2", children: ["#", winner.itemNumber, " \u2014 ", winner.title] }), winnerImg ? (
|
|
134
|
+
/* eslint-disable-next-line @next/next/no-img-element */
|
|
135
|
+
_jsx("img", { src: winnerImg, alt: winner.title, className: "mx-auto max-h-64 rounded" })) : null, winner.estimatedValue != null ? (_jsxs(Text, { className: "mt-2 text-sm text-[var(--appkit-color-text-muted)]", children: ["Estimated value: \u20B9", (winner.estimatedValue / 100).toLocaleString("en-IN")] })) : null] })) : null, _jsxs(Div, { className: "rounded border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-muted)] px-3 py-2 text-xs text-[var(--appkit-color-text-muted)]", children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Fairness guarantee:" }), " ", "Winners are picked by ", _jsx("code", { children: "crypto.randomInt" }), " running on LetItRip's server before the animation starts. The animation is theatrical \u2014 neither the store nor LetItRip staff can influence the outcome.", " ", effectiveRngUrl ? (_jsx("a", { href: effectiveRngUrl, target: "_blank", rel: "noreferrer noopener", className: "underline", children: "View RNG source code \u2192" })) : null] })] })] }));
|
|
123
136
|
}
|
|
124
137
|
export default PrizeRevealModal;
|
|
@@ -182,8 +182,30 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
|
|
|
182
182
|
: Promise.resolve([]),
|
|
183
183
|
]);
|
|
184
184
|
const reviews = reviewDocs.map(toReview);
|
|
185
|
+
const _now = new Date();
|
|
185
186
|
const relatedItems = relatedDocs
|
|
186
|
-
.filter((r) =>
|
|
187
|
+
.filter((r) => {
|
|
188
|
+
if (r.id === product.id)
|
|
189
|
+
return false;
|
|
190
|
+
const s = r.status;
|
|
191
|
+
if (s && ["sold", "out_of_stock", "archived", "discontinued", "draft"].includes(s))
|
|
192
|
+
return false;
|
|
193
|
+
if (r.isSold === true)
|
|
194
|
+
return false;
|
|
195
|
+
if (r.availableQuantity === 0)
|
|
196
|
+
return false;
|
|
197
|
+
if (r.listingType === "auction" && r.auctionEndDate) {
|
|
198
|
+
const end = r.auctionEndDate;
|
|
199
|
+
const endDate = typeof end.toDate === "function"
|
|
200
|
+
? end.toDate()
|
|
201
|
+
: end instanceof Date ? end : new Date(String(end));
|
|
202
|
+
if (endDate <= _now)
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
if (r.listingType === "prize-draw" && r.prizeRevealStatus === "closed")
|
|
206
|
+
return false;
|
|
207
|
+
return true;
|
|
208
|
+
})
|
|
187
209
|
.slice(0, 8)
|
|
188
210
|
.map(toProductItem);
|
|
189
211
|
const formattedPrice = price !== null ? formatCurrency(price, currency) : null;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useState, useTransition } from "react";
|
|
4
|
-
import { Alert, Badge, Button, Div, Heading, Input, Spinner, Text } from "../../../ui";
|
|
4
|
+
import { Alert, Badge, Button, Div, Heading, Input, LoginRequiredModal, Spinner, Text } from "../../../ui";
|
|
5
|
+
import { isAuthError } from "../../../utils/auth-error";
|
|
5
6
|
function formatRupees(amount) {
|
|
6
7
|
if (amount === undefined || amount === null)
|
|
7
8
|
return "—";
|
|
@@ -46,7 +47,7 @@ function statusVariant(status) {
|
|
|
46
47
|
default: return "default";
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
|
-
function OfferCard({ offer, onRespond, onUpdate }) {
|
|
50
|
+
function OfferCard({ offer, onRespond, onUpdate, onNeedsLogin }) {
|
|
50
51
|
const [uiState, setUiState] = useState("idle");
|
|
51
52
|
const [counterInput, setCounterInput] = useState("");
|
|
52
53
|
const [sellerNote, setSellerNote] = useState("");
|
|
@@ -68,7 +69,12 @@ function OfferCard({ offer, onRespond, onUpdate }) {
|
|
|
68
69
|
setUiState("idle");
|
|
69
70
|
}
|
|
70
71
|
catch (err) {
|
|
71
|
-
|
|
72
|
+
if (isAuthError(err)) {
|
|
73
|
+
onNeedsLogin();
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
setError(err instanceof Error ? err.message : "Something went wrong.");
|
|
77
|
+
}
|
|
72
78
|
}
|
|
73
79
|
});
|
|
74
80
|
}
|
|
@@ -100,6 +106,7 @@ export function SellerOffersPanel({ fetchEndpoint = "/api/store/offers", onRespo
|
|
|
100
106
|
const [offers, setOffers] = useState([]);
|
|
101
107
|
const [loading, setLoading] = useState(true);
|
|
102
108
|
const [fetchError, setFetchError] = useState("");
|
|
109
|
+
const [showLoginModal, setShowLoginModal] = useState(false);
|
|
103
110
|
const [statusFilter, setStatusFilter] = useState("all");
|
|
104
111
|
const loadOffers = useCallback(async () => {
|
|
105
112
|
setLoading(true);
|
|
@@ -109,8 +116,13 @@ export function SellerOffersPanel({ fetchEndpoint = "/api/store/offers", onRespo
|
|
|
109
116
|
? fetchEndpoint
|
|
110
117
|
: `${fetchEndpoint}?status=${statusFilter}`;
|
|
111
118
|
const res = await fetch(url);
|
|
112
|
-
if (!res.ok)
|
|
119
|
+
if (!res.ok) {
|
|
120
|
+
if (res.status === 401 || res.status === 403) {
|
|
121
|
+
setShowLoginModal(true);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
113
124
|
throw new Error(`Error ${res.status}`);
|
|
125
|
+
}
|
|
114
126
|
const json = (await res.json());
|
|
115
127
|
setOffers(json.items ?? json.offers ?? []);
|
|
116
128
|
}
|
|
@@ -134,5 +146,5 @@ export function SellerOffersPanel({ fetchEndpoint = "/api/store/offers", onRespo
|
|
|
134
146
|
{ value: "expired", label: "Expired" },
|
|
135
147
|
];
|
|
136
148
|
const pending = offers.filter((o) => o.status === "pending").length;
|
|
137
|
-
return (_jsxs(Div, { className: `space-y-4 ${className}`, children: [_jsxs(Div, { className: "flex items-center justify-between flex-wrap gap-2", children: [_jsxs(Div, { children: [_jsx(Heading, { level: 2, className: "text-lg font-semibold text-zinc-900 dark:text-zinc-100", children: "Offers Received" }), pending > 0 && (_jsxs(Text, { className: "text-xs text-amber-600 dark:text-amber-400 mt-0.5", children: [pending, " pending offer", pending > 1 ? "s" : "", " awaiting your response"] }))] }), _jsx(Button, { size: "sm", variant: "ghost", onClick: loadOffers, disabled: loading, className: "border border-zinc-300 dark:border-zinc-600 text-xs", children: loading ? "Refreshing…" : "Refresh" })] }), _jsx(Div, { className: "flex gap-1 flex-wrap", children: STATUS_FILTERS.map((f) => (_jsx(Button, { size: "sm", variant: statusFilter === f.value ? "primary" : "ghost", onClick: () => setStatusFilter(f.value), className: "text-xs px-2 py-1", children: f.label }, f.value))) }), fetchError && _jsx(Alert, { variant: "error", children: _jsx(Text, { className: "text-sm", children: fetchError }) }), loading && (_jsx(Div, { className: "flex justify-center py-12", children: _jsx(Spinner, { size: "lg" }) })), !loading && offers.length === 0 && (_jsx(Div, { className: "text-center py-12", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-500 text-sm", children: "No offers found" }) })), !loading && offers.length > 0 && (_jsx(Div, { className: "space-y-3", children: offers.map((offer) => (_jsx(OfferCard, { offer: offer, onRespond: onRespond, onUpdate: handleUpdate }, offer.id))) }))] }));
|
|
149
|
+
return (_jsxs(Div, { className: `space-y-4 ${className}`, 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(Div, { className: "flex items-center justify-between flex-wrap gap-2", children: [_jsxs(Div, { children: [_jsx(Heading, { level: 2, className: "text-lg font-semibold text-zinc-900 dark:text-zinc-100", children: "Offers Received" }), pending > 0 && (_jsxs(Text, { className: "text-xs text-amber-600 dark:text-amber-400 mt-0.5", children: [pending, " pending offer", pending > 1 ? "s" : "", " awaiting your response"] }))] }), _jsx(Button, { size: "sm", variant: "ghost", onClick: loadOffers, disabled: loading, className: "border border-zinc-300 dark:border-zinc-600 text-xs", children: loading ? "Refreshing…" : "Refresh" })] }), _jsx(Div, { className: "flex gap-1 flex-wrap", children: STATUS_FILTERS.map((f) => (_jsx(Button, { size: "sm", variant: statusFilter === f.value ? "primary" : "ghost", onClick: () => setStatusFilter(f.value), className: "text-xs px-2 py-1", children: f.label }, f.value))) }), fetchError && _jsx(Alert, { variant: "error", children: _jsx(Text, { className: "text-sm", children: fetchError }) }), loading && (_jsx(Div, { className: "flex justify-center py-12", children: _jsx(Spinner, { size: "lg" }) })), !loading && offers.length === 0 && (_jsx(Div, { className: "text-center py-12", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-500 text-sm", children: "No offers found" }) })), !loading && offers.length > 0 && (_jsx(Div, { className: "space-y-3", children: offers.map((offer) => (_jsx(OfferCard, { offer: offer, onRespond: onRespond, onUpdate: handleUpdate, onNeedsLogin: () => setShowLoginModal(true) }, offer.id))) }))] }));
|
|
138
150
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Button, LoginRequiredModal } from "../../../ui";
|
|
5
|
+
import { isAuthError } from "../../../utils/auth-error";
|
|
3
6
|
const sizeClasses = {
|
|
4
7
|
sm: "w-7 h-7",
|
|
5
8
|
md: "w-9 h-9",
|
|
@@ -7,14 +10,25 @@ const sizeClasses = {
|
|
|
7
10
|
};
|
|
8
11
|
export function WishlistToggleButton({ inWishlist, isLoading = false, onToggle, addLabel, removeLabel, className = "", size = "md", }) {
|
|
9
12
|
const label = inWishlist ? removeLabel : addLabel;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
const [showLoginModal, setShowLoginModal] = useState(false);
|
|
14
|
+
async function handleClick(e) {
|
|
15
|
+
try {
|
|
16
|
+
await onToggle(e);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
if (isAuthError(err)) {
|
|
20
|
+
setShowLoginModal(true);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return (_jsxs(_Fragment, { children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to save items to your wishlist. Please log in or create an account." }), _jsx(Button, { type: "button", onClick: handleClick, disabled: isLoading, "aria-label": label, title: label, className: `
|
|
25
|
+
flex items-center justify-center rounded-full
|
|
26
|
+
transition-all duration-150
|
|
27
|
+
${inWishlist
|
|
28
|
+
? "bg-rose-50 text-rose-500 hover:bg-rose-100"
|
|
29
|
+
: "bg-white/80 text-zinc-400 hover:text-rose-400"}
|
|
30
|
+
${sizeClasses[size]}
|
|
31
|
+
${isLoading ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}
|
|
32
|
+
${className}
|
|
33
|
+
`, children: _jsx("svg", { className: "w-4/6 h-4/6", viewBox: "0 0 24 24", fill: inWishlist ? "currentColor" : "none", stroke: "currentColor", strokeWidth: 2, children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" }) }) })] }));
|
|
20
34
|
}
|
package/dist/http/api-handler.js
CHANGED
|
@@ -34,7 +34,13 @@ async function getUserFromRequest(request) {
|
|
|
34
34
|
if (!sessionCookie)
|
|
35
35
|
return null;
|
|
36
36
|
const providers = getProviders();
|
|
37
|
-
|
|
37
|
+
let decoded;
|
|
38
|
+
try {
|
|
39
|
+
decoded = await providers.session.verifySession(sessionCookie);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
throw new AuthenticationError(ERROR_MESSAGES.USER.NOT_AUTHENTICATED);
|
|
43
|
+
}
|
|
38
44
|
const db = providers.db;
|
|
39
45
|
if (!db) {
|
|
40
46
|
throw new Error("Database provider is not registered");
|
package/dist/index.d.ts
CHANGED
|
@@ -2931,6 +2931,9 @@ export { SlottedListingView, DetailViewShell, StackedViewShell } from "./ui/inde
|
|
|
2931
2931
|
export { buildColumns, createColumnBuilder } from "./ui/index";
|
|
2932
2932
|
export { renderBoolean, renderCurrency, renderCurrencyCompact, renderCount, renderNullable } from "./ui/index";
|
|
2933
2933
|
export { Ol } from "./ui/index";
|
|
2934
|
+
export { LoginRequiredModal } from "./ui/components/LoginRequiredModal";
|
|
2935
|
+
export type { LoginRequiredModalProps } from "./ui/components/LoginRequiredModal";
|
|
2936
|
+
export { isAuthError } from "./utils/auth-error";
|
|
2934
2937
|
export { API_ENDPOINTS, API_ROUTES, LOGS_ENDPOINTS, AUTH_ENDPOINTS, ACCOUNT_ENDPOINTS, NOTIFICATIONS_ENDPOINTS, ADMIN_ENDPOINTS, CHAT_ENDPOINTS, AUCTION_ENDPOINTS, BID_ENDPOINTS, CART_ENDPOINTS, CATEGORY_ENDPOINTS, CHECKOUT_ENDPOINTS, PAYMENT_ENDPOINTS, COPILOT_ENDPOINTS, CORPORATE_ENDPOINTS, EVENT_ENDPOINTS, FAQ_ENDPOINTS, HOMEPAGE_ENDPOINTS, LOYALTY_ENDPOINTS, MEDIA_ENDPOINTS, ORDER_ENDPOINTS, PREORDER_ENDPOINTS, PRODUCT_ENDPOINTS, REVIEW_ENDPOINTS, SEARCH_ENDPOINTS, SELLER_ENDPOINTS, BLOG_ENDPOINTS, WISHLIST_ENDPOINTS, DEMO_ENDPOINTS, COLLECTION_CACHE_PATHS, resolveEndpoint, resolveEndpointFn, ROUTES, PUBLIC_ROUTES, PROTECTED_ROUTES, AUTH_ROUTES, WISHLIST_MAX, HISTORY_MAX, CART_MAX_ITEMS, WISHLIST_DOC_ID, HISTORY_DOC_ID, WISHLIST_COLLECTION, HISTORY_COLLECTION, } from "./constants/index";
|
|
2935
2938
|
export { WishlistFullError } from "./features/wishlist/server";
|
|
2936
2939
|
export { useHistory, useHistoryMergeOnLogin, getGuestHistory, trackGuestHistory, removeGuestHistoryItem, clearGuestHistory, getGuestHistoryCount, type GuestHistoryItem, type GuestHistoryType, type UserHistoryItem, type HistoryProductType, type HistoryItemSnapshot, type TrackArgs as TrackHistoryArgs, } from "./features/history";
|
package/dist/index.js
CHANGED
|
@@ -5362,6 +5362,8 @@ export { SlottedListingView, DetailViewShell, StackedViewShell } from "./ui/inde
|
|
|
5362
5362
|
export { buildColumns, createColumnBuilder } from "./ui/index";
|
|
5363
5363
|
export { renderBoolean, renderCurrency, renderCurrencyCompact, renderCount, renderNullable } from "./ui/index";
|
|
5364
5364
|
export { Ol } from "./ui/index";
|
|
5365
|
+
export { LoginRequiredModal } from "./ui/components/LoginRequiredModal";
|
|
5366
|
+
export { isAuthError } from "./utils/auth-error";
|
|
5365
5367
|
// -- Missing constants ----------------------------------------------------------
|
|
5366
5368
|
export { API_ENDPOINTS, API_ROUTES, LOGS_ENDPOINTS, AUTH_ENDPOINTS, ACCOUNT_ENDPOINTS, NOTIFICATIONS_ENDPOINTS, ADMIN_ENDPOINTS, CHAT_ENDPOINTS, AUCTION_ENDPOINTS, BID_ENDPOINTS, CART_ENDPOINTS, CATEGORY_ENDPOINTS, CHECKOUT_ENDPOINTS, PAYMENT_ENDPOINTS, COPILOT_ENDPOINTS, CORPORATE_ENDPOINTS, EVENT_ENDPOINTS, FAQ_ENDPOINTS, HOMEPAGE_ENDPOINTS, LOYALTY_ENDPOINTS, MEDIA_ENDPOINTS, ORDER_ENDPOINTS, PREORDER_ENDPOINTS, PRODUCT_ENDPOINTS, REVIEW_ENDPOINTS, SEARCH_ENDPOINTS, SELLER_ENDPOINTS, BLOG_ENDPOINTS, WISHLIST_ENDPOINTS, DEMO_ENDPOINTS, COLLECTION_CACHE_PATHS, resolveEndpoint, resolveEndpointFn, ROUTES, PUBLIC_ROUTES, PROTECTED_ROUTES, AUTH_ROUTES, WISHLIST_MAX, HISTORY_MAX, CART_MAX_ITEMS, WISHLIST_DOC_ID, HISTORY_DOC_ID, WISHLIST_COLLECTION, HISTORY_COLLECTION, } from "./constants/index";
|
|
5367
5369
|
// Wishlist server errors (server-only via tree-shake — class only, no firebase-admin at module scope)
|
package/dist/server.d.ts
CHANGED
package/dist/server.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// Server-only public exports
|
|
2
|
+
// isAuthError - Pure util — detects auth errors from caught exceptions (usable in server actions).
|
|
3
|
+
export { isAuthError } from "./utils/auth-error";
|
|
2
4
|
// [SERVER-ONLY]-Server-only — uses Node.js, Next.js server internals, or third-party server SDKs (auth, email, payment, shipping).
|
|
3
5
|
// ADDRESS_FIXTURES - Constant used across modules.
|
|
4
6
|
export { ADDRESS_FIXTURES } from "./seed/index";
|