@mohasinac/appkit 2.7.31 → 2.7.33
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/client/features/layout/DashboardLayoutClient.js +1 -1
- package/dist/_internal/server/features/faqs/index.d.ts +1 -0
- package/dist/_internal/server/features/faqs/index.js +1 -0
- package/dist/_internal/server/features/faqs/og.d.ts +9 -0
- package/dist/_internal/server/features/faqs/og.js +50 -0
- package/dist/_internal/server/features/reviews/index.d.ts +2 -0
- package/dist/_internal/server/features/reviews/index.js +2 -0
- package/dist/_internal/server/features/reviews/og-data.d.ts +1 -0
- package/dist/_internal/server/features/reviews/og-data.js +7 -0
- package/dist/_internal/server/features/reviews/og.d.ts +19 -0
- package/dist/_internal/server/features/reviews/og.js +70 -0
- package/dist/_internal/server/features/scams/index.d.ts +1 -0
- package/dist/_internal/server/features/scams/index.js +1 -0
- package/dist/_internal/server/features/scams/og.d.ts +18 -0
- package/dist/_internal/server/features/scams/og.js +59 -0
- package/dist/features/about/components/FAQPageView.js +1 -1
- package/dist/features/account/components/UserSidebar.js +1 -1
- package/dist/features/admin/components/AdminSidebar.js +1 -1
- package/dist/features/blog/components/BlogPostView.js +1 -1
- package/dist/features/homepage/components/FAQSection.js +1 -1
- package/dist/features/homepage/components/FeaturedProductsSection.js +6 -1
- package/dist/features/homepage/components/HeroCarousel.js +21 -5
- package/dist/features/homepage/components/SectionCarousel.js +3 -1
- package/dist/features/homepage/components/ShopByCategorySection.js +2 -2
- package/dist/features/reviews/repository/reviews.repository.d.ts +1 -0
- package/dist/features/reviews/repository/reviews.repository.js +14 -3
- package/dist/features/seller/components/SellerSidebar.js +1 -1
- package/dist/features/stores/components/StoreAboutView.js +1 -1
- package/dist/features/stores/components/StoreHeader.js +1 -1
- package/dist/seed/bids-seed-data.js +7 -4
- package/dist/seed/conversations-seed-data.js +52 -0
- package/dist/seed/events-seed-data.js +23 -0
- package/dist/seed/history-seed-data.js +13 -0
- package/dist/seed/notifications-seed-data.js +10 -0
- package/dist/seed/orders-seed-data.js +108 -1
- package/dist/seed/sessions-seed-data.js +35 -1
- package/dist/seed/users-seed-data.js +1 -1
- package/dist/seed/wishlists-seed-data.js +5 -1
- package/dist/server-entry.d.ts +3 -1
- package/dist/server-entry.js +3 -1
- package/dist/server.d.ts +4 -0
- package/dist/server.js +4 -0
- package/dist/tailwind-utilities.css +1 -1
- package/package.json +1 -1
|
@@ -91,5 +91,5 @@ export function DashboardLayoutClient({ variant, groups, permissions, activeHref
|
|
|
91
91
|
const adminGroups = variant === "admin"
|
|
92
92
|
? filteredGroups
|
|
93
93
|
: groups;
|
|
94
|
-
return (_jsxs(_Fragment, { children: [variant === "admin" && (_jsx(AdminSidebar, { variant: "sidebar", desktopOpen: desktopOpen, mobileOpen: mobileOpen, activePath: activeHref, groups: adminGroups, onCloseMobile: close, onToggle: toggle, className: className })), variant === "store" && (_jsx(StoreSidebar, { variant: "sidebar", desktopOpen: desktopOpen, mobileOpen: mobileOpen, activeHref: activeHref, items: [], groups: filteredGroups, onCloseMobile: close, onToggle: toggle, className: className })), variant === "user" && (_jsx(UserSidebar, { variant: "sidebar", desktopOpen: desktopOpen, mobileOpen: mobileOpen, items: filteredGroups.flatMap((g) => g.items), groups: filteredGroups, onCloseMobile: close, onToggle: toggle, className: className })), _jsx("div", { className: "w-full px-4 py-
|
|
94
|
+
return (_jsxs(_Fragment, { children: [variant === "admin" && (_jsx(AdminSidebar, { variant: "sidebar", desktopOpen: desktopOpen, mobileOpen: mobileOpen, activePath: activeHref, groups: adminGroups, onCloseMobile: close, onToggle: toggle, className: className })), variant === "store" && (_jsx(StoreSidebar, { variant: "sidebar", desktopOpen: desktopOpen, mobileOpen: mobileOpen, activeHref: activeHref, items: [], groups: filteredGroups, onCloseMobile: close, onToggle: toggle, className: className })), variant === "user" && (_jsx(UserSidebar, { variant: "sidebar", desktopOpen: desktopOpen, mobileOpen: mobileOpen, items: filteredGroups.flatMap((g) => g.items), groups: filteredGroups, onCloseMobile: close, onToggle: toggle, className: className })), _jsx("div", { className: "w-full px-4 py-8 md:pl-7 md:pr-6 lg:pl-8 lg:pr-8 min-h-[calc(100dvh-var(--header-height,3.5rem))]", children: children })] }));
|
|
95
95
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { renderFaqOg, renderFaqOgImage, type FaqOgData } from "./og";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { renderFaqOg, renderFaqOgImage } from "./og";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
export interface FaqOgData {
|
|
3
|
+
categoryLabel: string;
|
|
4
|
+
siteName: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function renderFaqOg(category: string, opts: {
|
|
7
|
+
siteName: string;
|
|
8
|
+
}): ReactElement;
|
|
9
|
+
export declare function renderFaqOgImage(data: FaqOgData): ReactElement;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export function renderFaqOg(category, opts) {
|
|
3
|
+
const label = category
|
|
4
|
+
.replace(/-/g, " ")
|
|
5
|
+
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
6
|
+
return renderFaqOgImage({ categoryLabel: label, siteName: opts.siteName });
|
|
7
|
+
}
|
|
8
|
+
export function renderFaqOgImage(data) {
|
|
9
|
+
const { categoryLabel, siteName } = data;
|
|
10
|
+
return (_jsxs("div", { style: {
|
|
11
|
+
display: "flex",
|
|
12
|
+
width: "100%",
|
|
13
|
+
height: "100%",
|
|
14
|
+
background: "linear-gradient(135deg, #3570fc 0%, #1343de 100%)",
|
|
15
|
+
fontFamily: "sans-serif",
|
|
16
|
+
alignItems: "center",
|
|
17
|
+
justifyContent: "center",
|
|
18
|
+
padding: "80px",
|
|
19
|
+
position: "relative",
|
|
20
|
+
overflow: "hidden",
|
|
21
|
+
}, children: [_jsx("div", { style: {
|
|
22
|
+
position: "absolute",
|
|
23
|
+
inset: 0,
|
|
24
|
+
opacity: 0.06,
|
|
25
|
+
backgroundImage: "radial-gradient(circle at 25% 25%, white 1px, transparent 0), radial-gradient(circle at 75% 75%, white 1px, transparent 0)",
|
|
26
|
+
backgroundSize: "64px 64px",
|
|
27
|
+
} }), _jsxs("div", { style: {
|
|
28
|
+
position: "relative",
|
|
29
|
+
display: "flex",
|
|
30
|
+
flexDirection: "column",
|
|
31
|
+
alignItems: "center",
|
|
32
|
+
gap: 24,
|
|
33
|
+
textAlign: "center",
|
|
34
|
+
}, children: [_jsxs("div", { style: {
|
|
35
|
+
fontSize: 20,
|
|
36
|
+
color: "rgba(255,255,255,0.7)",
|
|
37
|
+
letterSpacing: 3,
|
|
38
|
+
textTransform: "uppercase",
|
|
39
|
+
}, children: [siteName, " \u00B7 Help Centre"] }), _jsx("div", { style: {
|
|
40
|
+
fontSize: 72,
|
|
41
|
+
fontWeight: 800,
|
|
42
|
+
color: "white",
|
|
43
|
+
lineHeight: 1.1,
|
|
44
|
+
letterSpacing: "-1px",
|
|
45
|
+
}, children: categoryLabel }), _jsx("div", { style: {
|
|
46
|
+
fontSize: 32,
|
|
47
|
+
color: "rgba(255,255,255,0.8)",
|
|
48
|
+
fontWeight: 400,
|
|
49
|
+
}, children: "Frequently Asked Questions" })] })] }));
|
|
50
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { getReviewsForProduct, getReviewsForStore, hasUserPurchasedProduct } from "./data";
|
|
2
|
+
export { getReviewById } from "./og-data";
|
|
3
|
+
export { renderReviewOg, renderReviewOgImage, type ReviewOgData } from "./og";
|
|
2
4
|
export { createReviewAction, replyToReviewAction, deleteReviewAction, markReviewHelpfulAction, } from "./actions";
|
|
3
5
|
export { REVIEWS_PAGE_SIZE, REVIEW_MAX_RATING, REVIEW_MIN_RATING, REVIEW_IMAGES_MAX } from "../../../shared/features/reviews/config";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { getReviewsForProduct, getReviewsForStore, hasUserPurchasedProduct } from "./data";
|
|
2
|
+
export { getReviewById } from "./og-data";
|
|
3
|
+
export { renderReviewOg, renderReviewOgImage } from "./og";
|
|
2
4
|
export { createReviewAction, replyToReviewAction, deleteReviewAction, markReviewHelpfulAction, } from "./actions";
|
|
3
5
|
export { REVIEWS_PAGE_SIZE, REVIEW_MAX_RATING, REVIEW_MIN_RATING, REVIEW_IMAGES_MAX } from "../../../shared/features/reviews/config";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getReviewById: (id: string) => Promise<import("../../../..").ReviewDocument | null>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
export interface ReviewOgData {
|
|
3
|
+
productTitle: string;
|
|
4
|
+
rating: number;
|
|
5
|
+
reviewerInitial: string;
|
|
6
|
+
reviewExcerpt?: string | null;
|
|
7
|
+
}
|
|
8
|
+
interface ReviewDocLike {
|
|
9
|
+
title?: string | null;
|
|
10
|
+
productName?: string | null;
|
|
11
|
+
rating?: number | null;
|
|
12
|
+
userName?: string | null;
|
|
13
|
+
body?: string | null;
|
|
14
|
+
}
|
|
15
|
+
export declare function renderReviewOg(doc: ReviewDocLike | null | undefined, opts: {
|
|
16
|
+
siteName: string;
|
|
17
|
+
}): ReactElement;
|
|
18
|
+
export declare function renderReviewOgImage(data: ReviewOgData, siteName: string): ReactElement;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
function stars(n) {
|
|
3
|
+
return "★".repeat(Math.min(5, Math.max(1, Math.round(n))));
|
|
4
|
+
}
|
|
5
|
+
export function renderReviewOg(doc, opts) {
|
|
6
|
+
return renderReviewOgImage({
|
|
7
|
+
productTitle: doc?.productName ?? doc?.title ?? "Collectible",
|
|
8
|
+
rating: doc?.rating ?? 5,
|
|
9
|
+
reviewerInitial: (doc?.userName?.[0] ?? "?").toUpperCase(),
|
|
10
|
+
reviewExcerpt: doc?.body ? doc.body.slice(0, 120) : null,
|
|
11
|
+
}, opts.siteName);
|
|
12
|
+
}
|
|
13
|
+
export function renderReviewOgImage(data, siteName) {
|
|
14
|
+
const { productTitle, rating, reviewerInitial, reviewExcerpt } = data;
|
|
15
|
+
return (_jsxs("div", { style: {
|
|
16
|
+
display: "flex",
|
|
17
|
+
width: "100%",
|
|
18
|
+
height: "100%",
|
|
19
|
+
background: "#0f172a",
|
|
20
|
+
fontFamily: "sans-serif",
|
|
21
|
+
alignItems: "center",
|
|
22
|
+
justifyContent: "center",
|
|
23
|
+
padding: "60px",
|
|
24
|
+
position: "relative",
|
|
25
|
+
}, children: [_jsx("div", { style: {
|
|
26
|
+
position: "absolute",
|
|
27
|
+
inset: 0,
|
|
28
|
+
background: "linear-gradient(135deg, #0f172a 0%, #1e293b 100%)",
|
|
29
|
+
} }), _jsxs("div", { style: {
|
|
30
|
+
position: "relative",
|
|
31
|
+
display: "flex",
|
|
32
|
+
flexDirection: "column",
|
|
33
|
+
width: "100%",
|
|
34
|
+
maxWidth: 1080,
|
|
35
|
+
gap: 32,
|
|
36
|
+
}, children: [_jsxs("div", { style: { fontSize: 18, color: "#94a3b8", letterSpacing: 2, textTransform: "uppercase" }, children: [siteName, " \u00B7 Customer Review"] }), _jsxs("div", { style: {
|
|
37
|
+
display: "flex",
|
|
38
|
+
alignItems: "center",
|
|
39
|
+
gap: 24,
|
|
40
|
+
}, children: [_jsx("div", { style: {
|
|
41
|
+
width: 80,
|
|
42
|
+
height: 80,
|
|
43
|
+
borderRadius: 40,
|
|
44
|
+
background: "linear-gradient(135deg, #3570fc, #e91e8c)",
|
|
45
|
+
display: "flex",
|
|
46
|
+
alignItems: "center",
|
|
47
|
+
justifyContent: "center",
|
|
48
|
+
fontSize: 36,
|
|
49
|
+
fontWeight: 700,
|
|
50
|
+
color: "white",
|
|
51
|
+
flexShrink: 0,
|
|
52
|
+
}, children: reviewerInitial }), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: [_jsx("div", { style: { fontSize: 32, color: "#f59e0b", letterSpacing: 2 }, children: stars(rating) }), _jsxs("div", { style: { fontSize: 20, color: "#64748b" }, children: [rating, "/5"] })] })] }), _jsx("div", { style: {
|
|
53
|
+
fontSize: 48,
|
|
54
|
+
fontWeight: 700,
|
|
55
|
+
color: "#f1f5f9",
|
|
56
|
+
lineHeight: 1.2,
|
|
57
|
+
display: "-webkit-box",
|
|
58
|
+
WebkitLineClamp: 2,
|
|
59
|
+
WebkitBoxOrient: "vertical",
|
|
60
|
+
overflow: "hidden",
|
|
61
|
+
}, children: productTitle }), reviewExcerpt && (_jsxs("div", { style: {
|
|
62
|
+
fontSize: 24,
|
|
63
|
+
color: "#94a3b8",
|
|
64
|
+
lineHeight: 1.5,
|
|
65
|
+
display: "-webkit-box",
|
|
66
|
+
WebkitLineClamp: 2,
|
|
67
|
+
WebkitBoxOrient: "vertical",
|
|
68
|
+
overflow: "hidden",
|
|
69
|
+
}, children: ["\u201C", reviewExcerpt, "\u201D"] }))] })] }));
|
|
70
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
export interface ScamOgData {
|
|
3
|
+
displayName: string;
|
|
4
|
+
scamTypeLabel: string;
|
|
5
|
+
reportCount: number;
|
|
6
|
+
}
|
|
7
|
+
interface ScammerDocLike {
|
|
8
|
+
displayNames?: string[];
|
|
9
|
+
scamType?: string;
|
|
10
|
+
incidents?: unknown[];
|
|
11
|
+
totalReports?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function renderScamOg(doc: ScammerDocLike | null | undefined, opts: {
|
|
14
|
+
siteName: string;
|
|
15
|
+
scamTypeLabel?: string;
|
|
16
|
+
}): ReactElement;
|
|
17
|
+
export declare function renderScamOgImage(data: ScamOgData, siteName: string): ReactElement;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export function renderScamOg(doc, opts) {
|
|
3
|
+
return renderScamOgImage({
|
|
4
|
+
displayName: doc?.displayNames?.[0] ?? "Unknown",
|
|
5
|
+
scamTypeLabel: opts.scamTypeLabel ?? doc?.scamType ?? "Scammer",
|
|
6
|
+
reportCount: doc?.totalReports ?? 0,
|
|
7
|
+
}, opts.siteName);
|
|
8
|
+
}
|
|
9
|
+
export function renderScamOgImage(data, siteName) {
|
|
10
|
+
const { displayName, scamTypeLabel, reportCount } = data;
|
|
11
|
+
return (_jsxs("div", { style: {
|
|
12
|
+
display: "flex",
|
|
13
|
+
width: "100%",
|
|
14
|
+
height: "100%",
|
|
15
|
+
background: "#0f172a",
|
|
16
|
+
fontFamily: "sans-serif",
|
|
17
|
+
alignItems: "center",
|
|
18
|
+
padding: "60px 80px",
|
|
19
|
+
position: "relative",
|
|
20
|
+
overflow: "hidden",
|
|
21
|
+
}, children: [_jsx("div", { style: {
|
|
22
|
+
position: "absolute",
|
|
23
|
+
inset: 0,
|
|
24
|
+
background: "linear-gradient(135deg, #1e0505 0%, #0f172a 60%)",
|
|
25
|
+
} }), _jsxs("div", { style: {
|
|
26
|
+
position: "relative",
|
|
27
|
+
display: "flex",
|
|
28
|
+
flexDirection: "column",
|
|
29
|
+
gap: 28,
|
|
30
|
+
width: "100%",
|
|
31
|
+
}, children: [_jsxs("div", { style: {
|
|
32
|
+
display: "flex",
|
|
33
|
+
alignItems: "center",
|
|
34
|
+
gap: 12,
|
|
35
|
+
}, children: [_jsx("div", { style: {
|
|
36
|
+
background: "#dc2626",
|
|
37
|
+
color: "white",
|
|
38
|
+
padding: "6px 18px",
|
|
39
|
+
borderRadius: 6,
|
|
40
|
+
fontSize: 16,
|
|
41
|
+
fontWeight: 700,
|
|
42
|
+
letterSpacing: 2,
|
|
43
|
+
textTransform: "uppercase",
|
|
44
|
+
}, children: "\u26A0 Verified Scammer" }), _jsxs("div", { style: { fontSize: 18, color: "#94a3b8", letterSpacing: 1 }, children: [siteName, " \u00B7 Scam Registry"] })] }), _jsx("div", { style: {
|
|
45
|
+
fontSize: 72,
|
|
46
|
+
fontWeight: 800,
|
|
47
|
+
color: "#f1f5f9",
|
|
48
|
+
lineHeight: 1.1,
|
|
49
|
+
letterSpacing: "-1px",
|
|
50
|
+
}, children: displayName }), _jsxs("div", { style: { display: "flex", gap: 24, alignItems: "center" }, children: [_jsx("div", { style: {
|
|
51
|
+
background: "#1e293b",
|
|
52
|
+
border: "1px solid #334155",
|
|
53
|
+
borderRadius: 8,
|
|
54
|
+
padding: "10px 20px",
|
|
55
|
+
fontSize: 22,
|
|
56
|
+
color: "#f87171",
|
|
57
|
+
fontWeight: 600,
|
|
58
|
+
}, children: scamTypeLabel }), reportCount > 0 && (_jsxs("div", { style: { fontSize: 22, color: "#64748b" }, children: [reportCount, " ", reportCount === 1 ? "report" : "reports"] }))] }), _jsx("div", { style: { fontSize: 20, color: "#64748b", marginTop: 8 }, children: "Do not transact with this individual. Verified by the LetItRip community." })] })] }));
|
|
59
|
+
}
|
|
@@ -23,5 +23,5 @@ export async function FAQPageView({ category, heroBannerClass = DEFAULT_HERO_CLA
|
|
|
23
23
|
? "bg-primary/10 text-primary font-semibold"
|
|
24
24
|
: "hover:bg-neutral-100 dark:hover:bg-neutral-800"}`, children: [_jsxs("span", { className: `${flex.row} gap-2`, children: [_jsx(HelpCircle, { className: "w-4 h-4" }), t("allCategories")] }), _jsx(ChevronRight, { className: "w-3.5 h-3.5 opacity-50" })] }), categories.map((cat) => (_jsxs(TextLink, { href: String(ROUTES.PUBLIC.FAQ_CATEGORY(cat.slug)), className: `flex items-center justify-between px-3 py-2 rounded-lg text-sm transition-colors ${category === cat.slug
|
|
25
25
|
? "bg-primary/10 text-primary font-semibold"
|
|
26
|
-
: "hover:bg-neutral-100 dark:hover:bg-neutral-800"}`, children: [_jsxs("span", { className: `${flex.row} gap-2`, children: [_jsx("span", { children: cat.icon }), cat.label] }), _jsx(ChevronRight, { className: "w-3.5 h-3.5 opacity-50" })] }, cat.slug)))] })] })), _jsxs("div", { className: "flex-1 min-w-0", "data-section": "faqpageview-div-97", children: [visibleItems.length === 0 ? (_jsxs(Section, { className: `text-center py-16 rounded-2xl border ${themed.border} ${themed.bgSecondary}`, children: [_jsx(HelpCircle, { className: "w-10 h-10 mx-auto mb-3 text-neutral-300 dark:text-neutral-600" }), _jsx(Heading, { level: 3, className: "mb-2 text-base", children: t("emptyTitle") }), _jsx(Text, { variant: "secondary", className: "text-sm", children: t("emptyText") })] })) : (_jsx(Stack, { gap: "sm", className: "space-y-3", children: visibleItems.map((item, i) => (_jsxs("details", { className: `group rounded-xl border ${themed.border} ${themed.bgPrimary} overflow-hidden`, children: [_jsxs("summary", { className: `flex items-center justify-between px-5 py-4 cursor-pointer list-none select-none font-medium text-sm hover:bg-neutral-50 dark:hover:bg-neutral-800/50 transition-colors`, children: [_jsx("span", { children: item.question }), _jsx(ChevronRight, { className: "w-4 h-4 flex-shrink-0 ml-3 transition-transform group-open:rotate-90" })] }), _jsx("div", { className: "px-5 pb-5 pt-1", "data-section": "faqpageview-div-98", children: _jsx(RichTextRenderer, { html: item.answer, proseClass: "prose prose-sm max-w-none dark:prose-invert"
|
|
26
|
+
: "hover:bg-neutral-100 dark:hover:bg-neutral-800"}`, children: [_jsxs("span", { className: `${flex.row} gap-2`, children: [_jsx("span", { children: cat.icon }), cat.label] }), _jsx(ChevronRight, { className: "w-3.5 h-3.5 opacity-50" })] }, cat.slug)))] })] })), _jsxs("div", { className: "flex-1 min-w-0", "data-section": "faqpageview-div-97", children: [visibleItems.length === 0 ? (_jsxs(Section, { className: `text-center py-16 rounded-2xl border ${themed.border} ${themed.bgSecondary}`, children: [_jsx(HelpCircle, { className: "w-10 h-10 mx-auto mb-3 text-neutral-300 dark:text-neutral-600" }), _jsx(Heading, { level: 3, className: "mb-2 text-base", children: t("emptyTitle") }), _jsx(Text, { variant: "secondary", className: "text-sm", children: t("emptyText") })] })) : (_jsx(Stack, { gap: "sm", className: "space-y-3", children: visibleItems.map((item, i) => (_jsxs("details", { className: `group rounded-xl border ${themed.border} ${themed.bgPrimary} overflow-hidden`, children: [_jsxs("summary", { className: `flex items-center justify-between px-5 py-4 cursor-pointer list-none select-none font-medium text-sm hover:bg-neutral-50 dark:hover:bg-neutral-800/50 transition-colors`, children: [_jsx("span", { children: item.question }), _jsx(ChevronRight, { className: "w-4 h-4 flex-shrink-0 ml-3 transition-transform group-open:rotate-90" })] }), _jsx("div", { className: "px-5 pb-5 pt-1", "data-section": "faqpageview-div-98", children: _jsx(RichTextRenderer, { html: item.answer, proseClass: "prose prose-sm max-w-none dark:prose-invert" }) })] }, i))) })), _jsxs(Section, { className: `mt-10 rounded-2xl p-6 text-center border ${themed.border} ${themed.bgSecondary}`, children: [_jsx(Heading, { level: 3, className: "mb-2 text-base", children: t("stillNeedHelpTitle") }), _jsx(Text, { variant: "secondary", className: "text-sm mb-4", children: t("stillNeedHelpText") }), _jsxs("div", { className: `${flex.center} gap-4 flex-wrap`, "data-section": "faqpageview-div-99", children: [_jsx(TextLink, { href: String(ROUTES.PUBLIC.HELP), children: t("helpCenter") }), _jsx(TextLink, { href: String(ROUTES.PUBLIC.CONTACT), variant: "muted", children: t("contactUs") })] })] })] })] }) })] }));
|
|
27
27
|
}
|
|
@@ -63,7 +63,7 @@ export function UserSidebar({ items, groups, mobileOpen = false, onCloseMobile,
|
|
|
63
63
|
height: "calc(100vh - var(--header-height, 3.5rem))",
|
|
64
64
|
width: "13rem",
|
|
65
65
|
transform: desktopOpen ? "translateX(0)" : "translateX(calc(-100% + 1.25rem))",
|
|
66
|
-
}, children: [_jsxs("div", { className: "flex-1 bg-white dark:bg-slate-900 border-r border-zinc-200 dark:border-slate-800 flex flex-col overflow-hidden shadow-xl", children: [_jsx("div", { className: "px-4 py-3.5 border-b border-zinc-100 dark:border-slate-800 shrink-0", children: _jsx("span", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-400 dark:text-zinc-500", children: "My Account" }) }), _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx(DrawerContent, { groups: groups, items: items, activeHref: pathname }) })] }), _jsx("button", { type: "button", onClick: handleToggle, "aria-label": desktopOpen ? "Collapse sidebar" : "Expand sidebar", className: "w-5 shrink-0
|
|
66
|
+
}, children: [_jsxs("div", { className: "flex-1 bg-white dark:bg-slate-900 border-r border-zinc-200 dark:border-slate-800 flex flex-col overflow-hidden shadow-xl", children: [_jsx("div", { className: "px-4 py-3.5 border-b border-zinc-100 dark:border-slate-800 shrink-0", children: _jsx("span", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-400 dark:text-zinc-500", children: "My Account" }) }), _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx(DrawerContent, { groups: groups, items: items, activeHref: pathname }) })] }), _jsx("button", { type: "button", onClick: handleToggle, "aria-label": desktopOpen ? "Collapse sidebar" : "Expand sidebar", className: "w-5 shrink-0 flex items-center justify-center transition-opacity rounded-r-md shadow-md hover:opacity-85", style: { background: "linear-gradient(to bottom, var(--appkit-color-cobalt-700), var(--appkit-color-cobalt))" }, children: _jsx("svg", { className: "w-3 h-3 text-white", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: desktopOpen ? (_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M11 19l-7-7 7-7m8 14l-7-7 7-7" })) : (_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M13 5l7 7-7 7M5 5l7 7-7 7" })) }) })] }), _jsx("div", { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: "My Account", children: _jsx(DrawerContent, { groups: groups, items: items, activeHref: pathname, onItemClick: close }) }) })] }));
|
|
67
67
|
}
|
|
68
68
|
// ── Overlay variant (default) — portal on desktop, bottom-sheet on mobile ─
|
|
69
69
|
const content = (_jsx(DrawerContent, { groups: groups, items: items, activeHref: pathname, onItemClick: close }));
|
|
@@ -47,7 +47,7 @@ export function AdminSidebar({ renderNavItems, renderHeader, renderFooter, activ
|
|
|
47
47
|
height: "calc(100vh - var(--header-height, 3.5rem))",
|
|
48
48
|
width: "18rem",
|
|
49
49
|
transform: desktopOpen ? "translateX(0)" : "translateX(calc(-100% + 1.25rem))",
|
|
50
|
-
}, children: [_jsxs("div", { className: "flex-1 bg-white dark:bg-slate-950 border-r border-zinc-200 dark:border-slate-800 flex flex-col overflow-hidden shadow-xl", children: [_jsx("div", { className: "px-4 py-3.5 border-b border-zinc-100 dark:border-slate-800 shrink-0", children: renderHeader ? renderHeader() : _jsx("span", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-400 dark:text-zinc-500", children: "Admin Panel" }) }), _jsx("div", { className: "flex-1 overflow-y-auto", children: navContent }), renderFooter && _jsx("div", { className: "px-4 py-3 border-t border-zinc-200 dark:border-slate-800", children: renderFooter() })] }), _jsx("button", { type: "button", onClick: handleToggle, "aria-label": desktopOpen ? "Collapse sidebar" : "Expand sidebar", className: "w-5 shrink-0
|
|
50
|
+
}, children: [_jsxs("div", { className: "flex-1 bg-white dark:bg-slate-950 border-r border-zinc-200 dark:border-slate-800 flex flex-col overflow-hidden shadow-xl", children: [_jsx("div", { className: "px-4 py-3.5 border-b border-zinc-100 dark:border-slate-800 shrink-0", children: renderHeader ? renderHeader() : _jsx("span", { className: "text-xs font-semibold uppercase tracking-widest text-zinc-400 dark:text-zinc-500", children: "Admin Panel" }) }), _jsx("div", { className: "flex-1 overflow-y-auto", children: navContent }), renderFooter && _jsx("div", { className: "px-4 py-3 border-t border-zinc-200 dark:border-slate-800", children: renderFooter() })] }), _jsx("button", { type: "button", onClick: handleToggle, "aria-label": desktopOpen ? "Collapse sidebar" : "Expand sidebar", className: "w-5 shrink-0 flex items-center justify-center transition-opacity rounded-r-md shadow-md hover:opacity-85", style: { background: "linear-gradient(to bottom, var(--appkit-color-cobalt-700), var(--appkit-color-cobalt))" }, children: _jsx("svg", { className: "w-3 h-3 text-white", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: desktopOpen ? (_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M11 19l-7-7 7-7m8 14l-7-7 7-7" })) : (_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M13 5l7 7-7 7M5 5l7 7-7 7" })) }) })] }), _jsx("div", { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: "Admin Panel", children: mobileNavContent }) })] }));
|
|
51
51
|
}
|
|
52
52
|
return (_jsxs(_Fragment, { children: [mounted && mobileOpen &&
|
|
53
53
|
createPortal(_jsx(DrawerPanel, { title: "Admin Panel", onClose: close, children: navContent }), document.body), _jsx("div", { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: "Admin Panel", children: mobileNavContent }) })] }));
|
|
@@ -45,5 +45,5 @@ export function BlogPostView({ slug, initialData, labels = {}, renderImage, rend
|
|
|
45
45
|
})
|
|
46
46
|
: "";
|
|
47
47
|
const coverImageUrl = getMediaUrl(post.coverImage);
|
|
48
|
-
return (_jsxs(Div, { className: `min-h-screen ${className}`, children: [coverImageUrl && (_jsxs(Div, { className: "relative h-72 md:h-96 overflow-hidden", children: [renderImage ? (renderImage(post)) : (_jsx(Div, { role: "img", "aria-label": post.title, className: "h-full w-full bg-cover bg-center", style: { backgroundImage: `url(${coverImageUrl})` } })), _jsx(Div, { className: "absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" })] })), _jsxs(Div, { className: "max-w-3xl mx-auto px-4 py-12", children: [renderBlogPostHeader(post, date, labels), post.tags && post.tags.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mb-8", children: post.tags.map((tag) => (_jsxs(Span, { className: "inline-block px-3 py-1 rounded-full bg-neutral-100 text-neutral-600 text-xs font-medium", children: ["#", tag] }, tag))) })), renderAuthorBio && _jsx(Div, { className: "mb-6", children: renderAuthorBio(post) }), _jsx(Div, { className: "bg-white dark:bg-slate-900 rounded-xl border border-neutral-200 dark:border-slate-700 p-8 mb-12", children: renderContent ? renderContent(post) : (_jsx(RichText, { html: normalizeRichTextHtml(post.content ?? ""), proseClass: "prose max-w-none dark:prose-invert"
|
|
48
|
+
return (_jsxs(Div, { className: `min-h-screen ${className}`, children: [coverImageUrl && (_jsxs(Div, { className: "relative h-72 md:h-96 overflow-hidden", children: [renderImage ? (renderImage(post)) : (_jsx(Div, { role: "img", "aria-label": post.title, className: "h-full w-full bg-cover bg-center", style: { backgroundImage: `url(${coverImageUrl})` } })), _jsx(Div, { className: "absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" })] })), _jsxs(Div, { className: "max-w-3xl mx-auto px-4 py-12", children: [renderBlogPostHeader(post, date, labels), post.tags && post.tags.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mb-8", children: post.tags.map((tag) => (_jsxs(Span, { className: "inline-block px-3 py-1 rounded-full bg-neutral-100 text-neutral-600 text-xs font-medium", children: ["#", tag] }, tag))) })), renderAuthorBio && _jsx(Div, { className: "mb-6", children: renderAuthorBio(post) }), _jsx(Div, { className: "bg-white dark:bg-slate-900 rounded-xl border border-neutral-200 dark:border-slate-700 p-8 mb-12", children: renderContent ? renderContent(post) : (_jsx(RichText, { html: normalizeRichTextHtml(post.content ?? ""), proseClass: "prose max-w-none dark:prose-invert" })) }), renderBlogPostRelated(related, labels, renderRelatedCard), renderBackButton && _jsx(Div, { className: "mt-10 pt-8 border-t border-neutral-200", children: renderBackButton() })] })] }));
|
|
49
49
|
}
|
|
@@ -65,6 +65,6 @@ export function FAQSection({ title, subtitle, items, tabs: tabsProp, showCategor
|
|
|
65
65
|
}, [items, showTabs, activeTab]);
|
|
66
66
|
return (_jsx(Section, { className: `py-16 px-4 sm:px-8 ${themed.bgSecondary} ${className}`, children: _jsxs("div", { className: "w-full max-w-4xl mx-auto", "data-section": "faqsection-div-320", children: [_jsxs("div", { className: "text-center mb-10", "data-section": "faqsection-div-321", children: [_jsx(Heading, { level: 2, variant: "none", className: "bg-gradient-to-r from-primary to-cobalt bg-clip-text text-transparent text-3xl md:text-4xl font-bold mb-3", children: title }), subtitle && (_jsx(Text, { className: `text-base max-w-xl mx-auto ${themed.textSecondary}`, children: subtitle }))] }), showTabs && (_jsxs("div", { className: `${flex.center} flex-wrap gap-2 mb-8`, "data-section": "faqsection-div-322", children: [_jsx(Button, { variant: activeTab === "all" ? "primary" : "ghost", size: "sm", onClick: () => setActiveTab("all"), className: "rounded-full", children: "All" }), derivedTabs.map((tab) => (_jsx(Button, { variant: activeTab === tab.value ? "primary" : "ghost", size: "sm", onClick: () => setActiveTab(tab.value), className: "rounded-full", children: tab.label }, tab.value)))] })), _jsxs("div", { className: "space-y-2", "data-section": "faqsection-div-323", children: [visibleItems.length === 0 && (_jsx(Text, { className: `text-center py-12 ${themed.textSecondary}`, children: "No FAQs in this category yet." })), visibleItems.map((faq) => {
|
|
67
67
|
const isOpen = openIds.has(faq.id);
|
|
68
|
-
return (_jsxs("div", { className: `${themed.bgPrimary} rounded-xl overflow-hidden border transition-all duration-200 ${isOpen ? "border-primary/40 shadow-sm" : `${themed.border}`}`, "data-section": "faqsection-div-324", children: [_jsxs(Button, { variant: "ghost", className: `w-full text-left px-5 py-4 ${flex.between} gap-4 hover:${themed.bgTertiary} transition-colors rounded-none`, onClick: () => toggle(faq.id), "aria-expanded": isOpen, children: [_jsx(Span, { className: `text-sm font-medium flex-1 leading-snug ${isOpen ? "text-primary" : themed.textPrimary}`, children: faq.question }), _jsx(ChevronDown, { className: `w-4 h-4 flex-shrink-0 transition-transform duration-250 ${isOpen ? "rotate-180 text-primary" : themed.textSecondary}` })] }), _jsx("div", { className: `grid transition-all duration-300 ease-out ${isOpen ? "grid-rows-[1fr] opacity-100" : "grid-rows-[0fr] opacity-0"}`, "data-section": "faqsection-div-325", children: _jsx("div", { className: "overflow-hidden", "data-section": "faqsection-div-326", children: _jsx("div", { className: "px-5 pb-5 pt-0", children: isHtml(faq.answer) ? (_jsx(RichText, { html: faq.answer, proseClass: "prose prose-sm max-w-none dark:prose-invert"
|
|
68
|
+
return (_jsxs("div", { className: `${themed.bgPrimary} rounded-xl overflow-hidden border transition-all duration-200 ${isOpen ? "border-primary/40 shadow-sm" : `${themed.border}`}`, "data-section": "faqsection-div-324", children: [_jsxs(Button, { variant: "ghost", className: `w-full text-left px-5 py-4 ${flex.between} gap-4 hover:${themed.bgTertiary} transition-colors rounded-none`, onClick: () => toggle(faq.id), "aria-expanded": isOpen, children: [_jsx(Span, { className: `text-sm font-medium flex-1 leading-snug ${isOpen ? "text-primary" : themed.textPrimary}`, children: faq.question }), _jsx(ChevronDown, { className: `w-4 h-4 flex-shrink-0 transition-transform duration-250 ${isOpen ? "rotate-180 text-primary" : themed.textSecondary}` })] }), _jsx("div", { className: `grid transition-all duration-300 ease-out ${isOpen ? "grid-rows-[1fr] opacity-100" : "grid-rows-[0fr] opacity-0"}`, "data-section": "faqsection-div-325", children: _jsx("div", { className: "overflow-hidden", "data-section": "faqsection-div-326", children: _jsx("div", { className: "px-5 pb-5 pt-0", children: isHtml(faq.answer) ? (_jsx(RichText, { html: faq.answer, proseClass: "prose prose-sm max-w-none dark:prose-invert" })) : (_jsx(Text, { className: `text-sm leading-relaxed ${themed.textSecondary}`, children: faq.answer })) }) }) })] }, faq.id));
|
|
69
69
|
})] }), viewMoreHref && (_jsx("div", { className: "text-center mt-10", "data-section": "faqsection-div-327", children: _jsxs(TextLink, { href: viewMoreHref, className: "inline-flex items-center gap-2 px-6 py-2.5 rounded-full text-sm font-medium bg-primary/10 text-primary hover:bg-primary/20 dark:bg-primary/15 transition-colors", children: [viewMoreLabel, hasMore && moreCount > 0 && (_jsxs(Span, { className: "bg-primary text-white text-xs px-2 py-0.5 rounded-full", children: ["+", moreCount] }))] }) }))] }) }));
|
|
70
70
|
}
|
|
@@ -4,6 +4,7 @@ import { useState, useEffect, useRef } from "react";
|
|
|
4
4
|
import Link from "next/link";
|
|
5
5
|
import { SectionCarousel } from "./SectionCarousel";
|
|
6
6
|
import { useFeaturedProducts } from "../hooks/useFeaturedProducts";
|
|
7
|
+
import { useMediaQuery } from "../../../react";
|
|
7
8
|
import { InteractiveProductCard } from "../../products/components/InteractiveProductCard";
|
|
8
9
|
import { ROUTES } from "../../../next";
|
|
9
10
|
import { Section, Heading, Text } from "../../../ui";
|
|
@@ -11,7 +12,11 @@ import { THEME_CONSTANTS } from "../../../tokens";
|
|
|
11
12
|
// --- Multi-row grid + pagination -----------------------------------------------
|
|
12
13
|
function ProductGrid({ items, rows, maxItems, pagination, viewMoreHref, viewMoreLabel, title, description, }) {
|
|
13
14
|
const { themed } = THEME_CONSTANTS;
|
|
14
|
-
|
|
15
|
+
// On mobile (<sm, 2-col grid) a second row doubles the section height to ~2 screens.
|
|
16
|
+
// Collapse to 1 row automatically so the section fits within one viewport.
|
|
17
|
+
const isMobile = useMediaQuery("(max-width: 639px)");
|
|
18
|
+
const effectiveRows = isMobile ? 1 : rows;
|
|
19
|
+
const pageSize = Math.min(effectiveRows * 5, maxItems);
|
|
15
20
|
const [offset, setOffset] = useState(0);
|
|
16
21
|
const timerRef = useRef(null);
|
|
17
22
|
const totalItems = Math.min(items.length, maxItems);
|
|
@@ -43,11 +43,27 @@ function getHoverClass(effect) {
|
|
|
43
43
|
return "";
|
|
44
44
|
}
|
|
45
45
|
function getSlideHeightClass(height) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (height === "
|
|
49
|
-
return
|
|
50
|
-
|
|
46
|
+
// BN-1 (fixed bottom nav) = h-16 = 4rem, shown only below lg — must be subtracted on mobile.
|
|
47
|
+
// --header-height is the measured sticky header height set by AppLayoutShell.
|
|
48
|
+
if (height === "viewport") {
|
|
49
|
+
return [
|
|
50
|
+
// mobile: full dvh minus header minus BN-1
|
|
51
|
+
"min-h-[calc(100dvh-var(--header-height,3.5rem)-4rem)]",
|
|
52
|
+
// desktop: full dvh minus header only (no BN-1)
|
|
53
|
+
"lg:min-h-[calc(100dvh-var(--header-height,3.5rem))]",
|
|
54
|
+
].join(" ");
|
|
55
|
+
}
|
|
56
|
+
if (height === "tall") {
|
|
57
|
+
return [
|
|
58
|
+
"min-h-[calc(72dvh-var(--header-height,3.5rem)-4rem)]",
|
|
59
|
+
"lg:min-h-[clamp(480px,76dvh,840px)]",
|
|
60
|
+
].join(" ");
|
|
61
|
+
}
|
|
62
|
+
// medium (default) — comfortable hero without forcing full-screen
|
|
63
|
+
return [
|
|
64
|
+
"min-h-[calc(52dvh-var(--header-height,3.5rem)-4rem)]",
|
|
65
|
+
"lg:min-h-[clamp(420px,65dvh,680px)]",
|
|
66
|
+
].join(" ");
|
|
51
67
|
}
|
|
52
68
|
/** Renders the slide background — image, video, solid colour, or gradient. */
|
|
53
69
|
function SlideBackground({ bg, legacy, mobileLegacy, isMobile, priority, }) {
|
|
@@ -24,7 +24,9 @@ export function SectionCarousel({ title, description, headingVariant = "editoria
|
|
|
24
24
|
return (_jsxs(Section, { className: [
|
|
25
25
|
"relative overflow-hidden w-full",
|
|
26
26
|
hasBg ? "" : themed.bgSecondary,
|
|
27
|
-
|
|
27
|
+
// Vertical padding: 5rem on desktop, 3rem on mobile to leave room for adjacent sections.
|
|
28
|
+
// Horizontal: 1rem mobile → 2rem desktop; handled via inner max-w container.
|
|
29
|
+
"py-10 px-4 md:py-12 md:px-8",
|
|
28
30
|
className,
|
|
29
31
|
]
|
|
30
32
|
.filter(Boolean)
|
|
@@ -15,7 +15,7 @@ function CategoryChip({ category }) {
|
|
|
15
15
|
const coverImage = category.display?.coverImage;
|
|
16
16
|
const initial = category.name[0]?.toUpperCase() ?? "?";
|
|
17
17
|
const productCount = category.metrics?.productCount ?? 0;
|
|
18
|
-
return (_jsxs(Link, { href: ROUTES.PUBLIC.CATEGORY_DETAIL(category.slug), className: "group flex w-full min-h-[220px] flex-col overflow-hidden rounded-xl border border-zinc-200 bg-white shadow-sm transition-all hover:border-primary-300 hover:shadow-md dark:border-slate-700 dark:bg-slate-900 dark:hover:border-primary-600", children: [coverImage && isImageUrl(coverImage) ? (_jsx("div", { className: "aspect-video w-full overflow-hidden bg-zinc-100 dark:bg-slate-800", children: _jsx(Image, { src: coverImage, alt: category.name, width: 320, height: 180, className: "h-full w-full object-cover transition-transform duration-300 group-hover:scale-105" }) })) : (_jsx("div", { className: "aspect-video w-full bg-gradient-to-br from-zinc-100 to-zinc-200 dark:from-slate-800 dark:to-slate-700" })), _jsxs("div", { className: "flex flex-1 flex-col p-3 text-left", children: [_jsx("div", { className: "mb-2 flex h-9 w-9 items-center justify-center rounded-lg bg-primary-100 text-sm font-bold text-primary-700 dark:bg-primary-900 dark:text-primary-300", children: iconSrc && isImageUrl(iconSrc) ? (_jsx(Image, { src: iconSrc, alt: "", width: 24, height: 24, className: "h-6 w-6 rounded object-cover", "aria-hidden": true })) : iconSrc ? (_jsx("span", { "aria-hidden": "true", className: "text-lg leading-none", children: iconSrc })) : (initial) }), _jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-semibold text-zinc-800 dark:text-zinc-200`, children: category.name }), _jsxs(Text, { className: "mt-1 text-xs text-zinc-500 dark:text-zinc-400", children: [productCount.toLocaleString(), " items"] }), _jsx(Text, { className: "mt-auto pt-3 text-xs font-medium text-primary dark:text-primary-400", children: "Browse category \u2192" })] })] }));
|
|
18
|
+
return (_jsxs(Link, { href: ROUTES.PUBLIC.CATEGORY_DETAIL(category.slug), className: "group flex w-full min-h-[180px] sm:min-h-[220px] flex-col overflow-hidden rounded-xl border border-zinc-200 bg-white shadow-sm transition-all hover:border-primary-300 hover:shadow-md dark:border-slate-700 dark:bg-slate-900 dark:hover:border-primary-600", children: [coverImage && isImageUrl(coverImage) ? (_jsx("div", { className: "aspect-video w-full overflow-hidden bg-zinc-100 dark:bg-slate-800", children: _jsx(Image, { src: coverImage, alt: category.name, width: 320, height: 180, className: "h-full w-full object-cover transition-transform duration-300 group-hover:scale-105" }) })) : (_jsx("div", { className: "aspect-video w-full bg-gradient-to-br from-zinc-100 to-zinc-200 dark:from-slate-800 dark:to-slate-700" })), _jsxs("div", { className: "flex flex-1 flex-col p-3 text-left", children: [_jsx("div", { className: "mb-2 flex h-9 w-9 items-center justify-center rounded-lg bg-primary-100 text-sm font-bold text-primary-700 dark:bg-primary-900 dark:text-primary-300", children: iconSrc && isImageUrl(iconSrc) ? (_jsx(Image, { src: iconSrc, alt: "", width: 24, height: 24, className: "h-6 w-6 rounded object-cover", "aria-hidden": true })) : iconSrc ? (_jsx("span", { "aria-hidden": "true", className: "text-lg leading-none", children: iconSrc })) : (initial) }), _jsx(Text, { className: `${THEME_CONSTANTS.utilities.textClamp2} text-sm font-semibold text-zinc-800 dark:text-zinc-200`, children: category.name }), _jsxs(Text, { className: "mt-1 text-xs text-zinc-500 dark:text-zinc-400", children: [productCount.toLocaleString(), " items"] }), _jsx(Text, { className: "mt-auto pt-3 text-xs font-medium text-primary dark:text-primary-400", children: "Browse category \u2192" })] })] }));
|
|
19
19
|
}
|
|
20
20
|
const CTA_CLASSES = {
|
|
21
21
|
filled: "rounded-lg bg-[var(--appkit-color-primary)] px-5 py-2 text-sm font-semibold text-white hover:opacity-90",
|
|
@@ -56,7 +56,7 @@ export function ShopByCategorySection({ title = "Shop by Category", subtitle, li
|
|
|
56
56
|
const categories = filtered.length > 0 ? filtered : allCategories;
|
|
57
57
|
if (!isLoading && allCategories.length === 0)
|
|
58
58
|
return null;
|
|
59
|
-
return (_jsx(Section, { className: `py-
|
|
59
|
+
return (_jsx(Section, { className: `py-10 px-4 md:py-12 ${themed.bgSecondary} ${className}`, children: _jsxs("div", { className: "mx-auto max-w-7xl", children: [_jsxs("div", { className: "mb-6 text-center", children: [_jsx(Heading, { level: 2, className: `text-2xl font-bold md:text-3xl ${themed.textPrimary}`, children: title }), subtitle && (_jsx(Text, { variant: "secondary", className: "mt-1 text-sm", children: subtitle }))] }), hasFilters && !isLoading && (_jsxs("div", { className: "mb-4 flex flex-wrap gap-2", children: [_jsx(FilterChip, { label: "All", active: activeFilter === "all", onClick: () => setActiveFilter("all") }), rootIds.slice(0, 5).map((id) => {
|
|
60
60
|
const cat = allCategories.find((c) => c.id === id);
|
|
61
61
|
if (!cat)
|
|
62
62
|
return null;
|
|
@@ -8,6 +8,7 @@ export interface ReviewRatingAggregate {
|
|
|
8
8
|
}
|
|
9
9
|
declare class ReviewRepository extends BaseRepository<ReviewDocument> {
|
|
10
10
|
constructor();
|
|
11
|
+
private decryptSieveResult;
|
|
11
12
|
private encryptReviewData;
|
|
12
13
|
protected mapDoc<D = ReviewDocument>(snap: import("../../../providers/db-firebase").DocumentSnapshot): D;
|
|
13
14
|
create(input: ReviewCreateInput): Promise<ReviewDocument>;
|
|
@@ -13,6 +13,14 @@ class ReviewRepository extends BaseRepository {
|
|
|
13
13
|
constructor() {
|
|
14
14
|
super(REVIEW_COLLECTION);
|
|
15
15
|
}
|
|
16
|
+
decryptSieveResult(result) {
|
|
17
|
+
return {
|
|
18
|
+
...result,
|
|
19
|
+
items: result.items.map((item) => decryptPiiFields(item, [
|
|
20
|
+
...REVIEW_PII_FIELDS,
|
|
21
|
+
])),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
16
24
|
encryptReviewData(data) {
|
|
17
25
|
let encrypted = encryptPiiFields(data, [...REVIEW_PII_FIELDS]);
|
|
18
26
|
encrypted = addPiiIndices(data, REVIEW_PII_INDEX_MAP);
|
|
@@ -181,25 +189,28 @@ class ReviewRepository extends BaseRepository {
|
|
|
181
189
|
}
|
|
182
190
|
async listForProduct(productId, model) {
|
|
183
191
|
const baseQuery = this.getCollection().where(REVIEW_FIELDS.PRODUCT_ID, "==", productId);
|
|
184
|
-
|
|
192
|
+
const result = await this.sieveQuery(model, ReviewRepository.SIEVE_FIELDS, {
|
|
185
193
|
baseQuery,
|
|
186
194
|
defaultPageSize: 10,
|
|
187
195
|
maxPageSize: 50,
|
|
188
196
|
});
|
|
197
|
+
return this.decryptSieveResult(result);
|
|
189
198
|
}
|
|
190
199
|
async listForStore(storeId, model) {
|
|
191
200
|
const baseQuery = this.getCollection().where(REVIEW_FIELDS.STORE_ID, "==", storeId);
|
|
192
|
-
|
|
201
|
+
const result = await this.sieveQuery(model, ReviewRepository.SIEVE_FIELDS, {
|
|
193
202
|
baseQuery,
|
|
194
203
|
defaultPageSize: 10,
|
|
195
204
|
maxPageSize: 100,
|
|
196
205
|
});
|
|
206
|
+
return this.decryptSieveResult(result);
|
|
197
207
|
}
|
|
198
208
|
async listAll(model) {
|
|
199
|
-
|
|
209
|
+
const result = await this.sieveQuery(model, ReviewRepository.SIEVE_FIELDS, {
|
|
200
210
|
defaultPageSize: 50,
|
|
201
211
|
maxPageSize: 200,
|
|
202
212
|
});
|
|
213
|
+
return this.decryptSieveResult(result);
|
|
203
214
|
}
|
|
204
215
|
}
|
|
205
216
|
ReviewRepository.SIEVE_FIELDS = {
|
|
@@ -56,7 +56,7 @@ export function StoreSidebar({ items, groups, activeHref, storeName, storeLogoUR
|
|
|
56
56
|
height: "calc(100vh - var(--header-height, 3.5rem))",
|
|
57
57
|
width: "18rem",
|
|
58
58
|
transform: desktopOpen ? "translateX(0)" : "translateX(calc(-100% + 1.25rem))",
|
|
59
|
-
}, children: [_jsxs("div", { className: "flex-1 bg-white dark:bg-slate-950 border-r border-zinc-200 dark:border-slate-700 flex flex-col overflow-hidden shadow-xl", children: [_jsx("div", { className: "px-4 py-3.5 border-b border-zinc-100 dark:border-slate-800 shrink-0", children: _jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [storeLogoURL ? (_jsx(Div, { role: "img", "aria-label": storeName, className: CLS_STORE_AVATAR, style: { backgroundImage: `url(${storeLogoURL})` } })) : (_jsx(Div, { className: CLS_STORE_FALLBACK, children: storeName?.[0]?.toUpperCase() })), _jsx(Text, { className: CLS_STORE_NAME, children: storeName || panelTitle })] }) }), _jsx("div", { className: "flex-1 overflow-y-auto", children: navContent })] }), _jsx("button", { type: "button", onClick: handleToggle, "aria-label": desktopOpen ? "Collapse sidebar" : "Expand sidebar", className: "w-5 shrink-0
|
|
59
|
+
}, children: [_jsxs("div", { className: "flex-1 bg-white dark:bg-slate-950 border-r border-zinc-200 dark:border-slate-700 flex flex-col overflow-hidden shadow-xl", children: [_jsx("div", { className: "px-4 py-3.5 border-b border-zinc-100 dark:border-slate-800 shrink-0", children: _jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [storeLogoURL ? (_jsx(Div, { role: "img", "aria-label": storeName, className: CLS_STORE_AVATAR, style: { backgroundImage: `url(${storeLogoURL})` } })) : (_jsx(Div, { className: CLS_STORE_FALLBACK, children: storeName?.[0]?.toUpperCase() })), _jsx(Text, { className: CLS_STORE_NAME, children: storeName || panelTitle })] }) }), _jsx("div", { className: "flex-1 overflow-y-auto", children: navContent })] }), _jsx("button", { type: "button", onClick: handleToggle, "aria-label": desktopOpen ? "Collapse sidebar" : "Expand sidebar", className: "w-5 shrink-0 flex items-center justify-center transition-opacity rounded-r-md shadow-md hover:opacity-85", style: { background: "linear-gradient(to bottom, var(--appkit-color-cobalt-700), var(--appkit-color-cobalt))" }, children: _jsx("svg", { className: "w-3 h-3 text-white", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: desktopOpen ? (_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M11 19l-7-7 7-7m8 14l-7-7 7-7" })) : (_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M13 5l7 7-7 7M5 5l7 7-7 7" })) }) })] }), _jsx("div", { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: panelTitle, children: groups ? (_jsx(GroupsContent, { groups: groups, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) : (_jsx(FlatContent, { items: items, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) }) })] }));
|
|
60
60
|
}
|
|
61
61
|
return (_jsxs(_Fragment, { children: [mounted && mobileOpen &&
|
|
62
62
|
createPortal(_jsx(DrawerPanel, { title: panelTitle, onClose: close, children: navContent }), document.body), _jsx("div", { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: panelTitle, children: groups ? (_jsx(GroupsContent, { groups: groups, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) : (_jsx(FlatContent, { items: items, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) }) })] }));
|
|
@@ -10,5 +10,5 @@ export function StoreAboutView({ store, labels = {}, renderSocialLinks, renderSt
|
|
|
10
10
|
month: "long",
|
|
11
11
|
})
|
|
12
12
|
: null;
|
|
13
|
-
return (_jsxs(Div, { className: `space-y-6 py-6 ${className}`, children: [store.bio && (_jsxs(Div, { children: [_jsx(Heading, { level: 2, className: "text-lg font-semibold mb-2", children: labels.aboutTitle ?? "About" }), _jsx(RichText, { html: normalizeRichTextHtml(store.bio)
|
|
13
|
+
return (_jsxs(Div, { className: `space-y-6 py-6 ${className}`, children: [store.bio && (_jsxs(Div, { children: [_jsx(Heading, { level: 2, className: "text-lg font-semibold mb-2", children: labels.aboutTitle ?? "About" }), _jsx(RichText, { html: normalizeRichTextHtml(store.bio) })] })), renderStats?.(store), _jsxs(Div, { className: "space-y-3 text-sm", children: [store.location && (_jsxs(Div, { className: "flex gap-2", children: [_jsx(Text, { className: CLS_LABEL, children: labels.locationLabel ?? "Location" }), _jsx(Text, { className: "", children: store.location })] })), joinDate && (_jsxs(Div, { className: "flex gap-2", children: [_jsx(Text, { className: CLS_LABEL, children: labels.memberSinceLabel ?? "Member since" }), _jsx(Text, { className: "", children: joinDate })] })), store.website && (_jsxs(Div, { className: "flex gap-2", children: [_jsx(Text, { className: CLS_LABEL, children: labels.websiteLabel ?? "Website" }), _jsx("a", { href: store.website, target: "_blank", rel: "noopener noreferrer", className: "text-primary hover:underline break-all", children: store.website })] }))] }), store.socialLinks && renderSocialLinks?.(store.socialLinks), store.returnPolicy && (_jsxs(Div, { children: [_jsx(Heading, { level: 3, className: "text-base font-semibold mb-2", children: labels.returnPolicyLabel ?? "Return Policy" }), _jsx(RichText, { html: normalizeRichTextHtml(store.returnPolicy) })] })), store.shippingPolicy && (_jsxs(Div, { children: [_jsx(Heading, { level: 3, className: "text-base font-semibold mb-2", children: labels.shippingPolicyLabel ?? "Shipping Policy" }), _jsx(RichText, { html: normalizeRichTextHtml(store.shippingPolicy) })] })), store.isVacationMode && (_jsxs(Div, { className: "bg-yellow-50 border border-yellow-200 rounded-lg p-4", children: [_jsx(Text, { className: "text-yellow-800 font-medium", children: labels.vacationModeLabel ?? "This store is on vacation mode" }), store.vacationMessage && (_jsx(Text, { className: "text-yellow-700 mt-1", children: store.vacationMessage }))] }))] }));
|
|
14
14
|
}
|
|
@@ -3,7 +3,7 @@ import { Button, Div, Heading, RichText, Row, Section, Span, Text, } from "../..
|
|
|
3
3
|
import { normalizeRichTextHtml } from "../../../utils/string.formatter";
|
|
4
4
|
import { ShareButton } from "../../products/components/ShareButton";
|
|
5
5
|
export function StoreHeader({ store, labels = {}, onFollow, className = "", }) {
|
|
6
|
-
return (_jsxs(Section, { className: `bg-white dark:bg-slate-900 border-b border-gray-200 dark:border-slate-700 ${className}`, children: [store.storeBannerURL && (_jsx(Div, { className: "h-40 md:h-56 overflow-hidden bg-gray-100 dark:bg-slate-800", children: _jsx(Div, { role: "img", "aria-label": `${store.storeName} banner`, className: "h-full w-full bg-center bg-cover", style: { backgroundImage: `url(${store.storeBannerURL})` } }) })), _jsxs(Div, { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4", children: [_jsxs(Div, { className: "flex items-end gap-4", children: [store.storeLogoURL ? (_jsx(Div, { role: "img", "aria-label": store.storeName, className: "-mt-8 h-16 w-16 rounded-xl border-2 border-white dark:border-slate-800 bg-center bg-cover shadow-sm", style: { backgroundImage: `url(${store.storeLogoURL})` } })) : (_jsx(Div, { className: "-mt-8 h-16 w-16 rounded-xl border-2 border-white dark:border-slate-800 bg-orange-100 dark:bg-orange-900/30 flex items-center justify-center text-orange-600 dark:text-orange-400 font-bold text-2xl shadow-sm", children: store.storeName[0]?.toUpperCase() })), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Div, { className: "flex flex-wrap items-center gap-2 mb-0.5", children: [_jsx(Heading, { level: 1, className: "text-xl font-bold text-gray-900 dark:text-zinc-100", children: store.storeName }), store.averageRating != null && store.averageRating > 0 && (_jsxs(Span, { className: "inline-flex items-center gap-1 text-sm font-medium text-amber-500", children: ["\u2605 ", store.averageRating.toFixed(1)] }))] }), _jsxs(Row, { className: "gap-3 text-xs text-gray-500 dark:text-zinc-400 mb-0.5", children: [store.category && _jsx(Span, { className: "capitalize", children: store.category }), store.totalProducts != null && store.totalProducts > 0 && (_jsxs(Span, { children: [store.totalProducts, " ", labels.products ?? "products"] })), store.totalReviews != null && store.totalReviews > 0 && (_jsxs(Span, { children: [store.totalReviews, " ", labels.reviews ?? "reviews"] })), store.itemsSold != null && store.itemsSold > 0 && (_jsxs(Span, { children: [store.itemsSold, " ", labels.sold ?? "sold"] }))] }), store.storeDescription && (_jsx(RichText, { html: normalizeRichTextHtml(store.storeDescription), copyableCode: true, className: "
|
|
6
|
+
return (_jsxs(Section, { className: `bg-white dark:bg-slate-900 border-b border-gray-200 dark:border-slate-700 ${className}`, children: [store.storeBannerURL && (_jsx(Div, { className: "h-40 md:h-56 overflow-hidden bg-gray-100 dark:bg-slate-800", children: _jsx(Div, { role: "img", "aria-label": `${store.storeName} banner`, className: "h-full w-full bg-center bg-cover", style: { backgroundImage: `url(${store.storeBannerURL})` } }) })), _jsxs(Div, { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4", children: [_jsxs(Div, { className: "flex items-end gap-4", children: [store.storeLogoURL ? (_jsx(Div, { role: "img", "aria-label": store.storeName, className: "-mt-8 h-16 w-16 rounded-xl border-2 border-white dark:border-slate-800 bg-center bg-cover shadow-sm", style: { backgroundImage: `url(${store.storeLogoURL})` } })) : (_jsx(Div, { className: "-mt-8 h-16 w-16 rounded-xl border-2 border-white dark:border-slate-800 bg-orange-100 dark:bg-orange-900/30 flex items-center justify-center text-orange-600 dark:text-orange-400 font-bold text-2xl shadow-sm", children: store.storeName[0]?.toUpperCase() })), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Div, { className: "flex flex-wrap items-center gap-2 mb-0.5", children: [_jsx(Heading, { level: 1, className: "text-xl font-bold text-gray-900 dark:text-zinc-100", children: store.storeName }), store.averageRating != null && store.averageRating > 0 && (_jsxs(Span, { className: "inline-flex items-center gap-1 text-sm font-medium text-amber-500", children: ["\u2605 ", store.averageRating.toFixed(1)] }))] }), _jsxs(Row, { className: "gap-3 text-xs text-gray-500 dark:text-zinc-400 mb-0.5", children: [store.category && _jsx(Span, { className: "capitalize", children: store.category }), store.totalProducts != null && store.totalProducts > 0 && (_jsxs(Span, { children: [store.totalProducts, " ", labels.products ?? "products"] })), store.totalReviews != null && store.totalReviews > 0 && (_jsxs(Span, { children: [store.totalReviews, " ", labels.reviews ?? "reviews"] })), store.itemsSold != null && store.itemsSold > 0 && (_jsxs(Span, { children: [store.itemsSold, " ", labels.sold ?? "sold"] }))] }), store.storeDescription && (_jsx(RichText, { html: normalizeRichTextHtml(store.storeDescription), copyableCode: true, className: "mt-0.5" }))] }), _jsxs(Row, { gap: "sm", align: "center", className: "shrink-0", children: [_jsx(ShareButton, { title: store.storeName }), onFollow && (_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onFollow(store.storeSlug), className: "rounded-lg border border-orange-500 px-4 py-2 text-sm font-medium text-orange-500 hover:bg-orange-50 transition-colors", children: labels.follow ?? "Follow" }))] })] }), store.isVacationMode && (_jsx(Text, { className: "mt-3 rounded-lg bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 px-3 py-2 text-sm text-yellow-700 dark:text-yellow-300", children: store.vacationMessage ??
|
|
7
7
|
labels.vacationMode ??
|
|
8
8
|
"Store is on vacation mode" }))] })] }));
|
|
9
9
|
}
|