@mohasinac/appkit 2.8.0 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/features/about/components/PublicProfileView.js +8 -8
- package/dist/features/admin/components/AdminSiteSettingsView.js +4 -5
- package/dist/features/admin/components/AdminUserEditorView.js +7 -11
- package/dist/features/admin/components/AdminViewCards.js +15 -15
- package/dist/features/blog/components/BlogFeaturedCard.js +1 -0
- package/dist/features/events/components/AdminEventEditorView.js +10 -13
- package/dist/features/events/components/EventCard.js +1 -0
- package/dist/features/faq/components/FAQPageContent.js +1 -0
- package/dist/features/homepage/components/AdvertisementBanner.js +6 -6
- package/dist/features/homepage/components/HomepageSkeleton.js +2 -2
- package/dist/features/homepage/components/WelcomeSection.js +3 -3
- package/dist/features/layout/TitleBar.js +1 -0
- package/dist/features/products/components/ProductGrid.js +1 -0
- package/dist/features/promotions/components/CouponsIndexListing.js +4 -4
- package/dist/features/reviews/components/ReviewDetailShell.js +3 -3
- package/dist/features/seller/components/SellerAddressesView.js +4 -5
- package/dist/features/shell/FormShell.js +3 -3
- package/dist/styles.css +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/package.json +1 -1
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
5
|
-
import { Alert, Button, Div, Heading, Input, RichTextEditor, Select, StackedViewShell, TagInput, Text, Toggle, } from "../../../ui";
|
|
5
|
+
import { Alert, Button, Div, Grid, Heading, Input, Label, RichTextEditor, Row, Select, Stack, StackedViewShell, TagInput, Text, Textarea, Toggle, } from "../../../ui";
|
|
6
6
|
import { apiClient } from "../../../http";
|
|
7
7
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
8
8
|
import { StepForm } from "../../shell";
|
|
9
|
-
// --- Constants ---------------------------------------------------------------
|
|
10
|
-
const CLS_PANEL_SM = "rounded-lg border border-zinc-200 dark:border-zinc-700 bg-zinc-50 dark:bg-zinc-800 p-3 space-y-2";
|
|
11
|
-
const CLS_PANEL_LG = "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-4";
|
|
12
9
|
const EVENT_TYPE_OPTIONS = [
|
|
13
10
|
{ label: "Sale", value: "sale" },
|
|
14
11
|
{ label: "Offer / Coupon", value: "offer" },
|
|
@@ -49,11 +46,11 @@ function FormFieldBuilder({ fields, setFields }) {
|
|
|
49
46
|
const addField = () => setFields([...fields, { id: `field-${Date.now()}`, type: "text", label: "", required: false, order: fields.length }]);
|
|
50
47
|
const removeField = (id) => setFields(fields.filter((f) => f.id !== id));
|
|
51
48
|
const updateField = (id, patch) => setFields(fields.map((f) => (f.id === id ? { ...f, ...patch } : f)));
|
|
52
|
-
return (_jsxs(
|
|
49
|
+
return (_jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "xs", weight: "medium", color: "muted", className: "uppercase tracking-wide", children: "Form fields" }), fields.length === 0 && (_jsx(Text, { size: "xs", color: "muted", children: "No fields yet. Add fields to collect responses from participants." })), fields.map((field, idx) => {
|
|
53
50
|
const hasOptions = FIELD_TYPES_WITH_OPTIONS.includes(field.type);
|
|
54
51
|
const isNumeric = field.type === "number" || field.type === "rating";
|
|
55
52
|
const isText = field.type === "text" || field.type === "textarea" || field.type === "email";
|
|
56
|
-
return (_jsxs(
|
|
53
|
+
return (_jsxs(Stack, { gap: "xs", surface: "default", rounded: "lg", border: "default", padding: "sm", children: [_jsxs(Row, { justify: "between", gap: "xs", children: [_jsxs(Text, { size: "xs", weight: "medium", color: "muted", children: ["Field ", idx + 1] }), _jsx("button", { type: "button", onClick: () => removeField(field.id), className: "text-zinc-400 hover:text-red-500 transition-colors text-lg leading-none px-1", "aria-label": "Remove field", children: "\u00D7" })] }), _jsxs(Grid, { cols: 2, gap: "xs", children: [_jsx(Select, { label: "Type", value: field.type, options: FORM_FIELD_TYPE_OPTIONS, onChange: (e) => updateField(field.id, { type: e.target.value, options: undefined }) }), _jsx(Input, { label: "Label", value: field.label, onChange: (e) => updateField(field.id, { label: e.target.value }), placeholder: "e.g. Describe your entry", required: true })] }), !hasOptions && field.type !== "date" && field.type !== "file" && field.type !== "rating" && (_jsx(Input, { label: "Placeholder (optional)", value: field.placeholder ?? "", onChange: (e) => updateField(field.id, { placeholder: e.target.value || undefined }), placeholder: "Hint shown inside the field" })), hasOptions && (_jsx(Textarea, { label: "Options \u2014 one per line", value: (field.options ?? []).join("\n"), onChange: (e) => updateField(field.id, { options: e.target.value.split("\n").map((s) => s.trim()).filter(Boolean) }), placeholder: "Option A\nOption B\nOption C", rows: 3 })), (isText || isNumeric) && (_jsxs(Stack, { gap: "xs", surface: "muted", rounded: "md", padding: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Validation (optional)" }), _jsxs(Grid, { gap: "xs", className: "grid-cols-2", children: [isText && (_jsxs(_Fragment, { children: [_jsx(Input, { label: "Min length", type: "number", value: String(field.validation?.minLength ?? ""), onChange: (e) => updateField(field.id, { validation: { ...field.validation, minLength: e.target.value ? Number(e.target.value) : undefined } }), placeholder: "0" }), _jsx(Input, { label: "Max length", type: "number", value: String(field.validation?.maxLength ?? ""), onChange: (e) => updateField(field.id, { validation: { ...field.validation, maxLength: e.target.value ? Number(e.target.value) : undefined } }), placeholder: "500" })] })), isNumeric && (_jsxs(_Fragment, { children: [_jsx(Input, { label: "Min value", type: "number", value: String(field.validation?.min ?? ""), onChange: (e) => updateField(field.id, { validation: { ...field.validation, min: e.target.value ? Number(e.target.value) : undefined } }), placeholder: "0" }), _jsx(Input, { label: "Max value", type: "number", value: String(field.validation?.max ?? ""), onChange: (e) => updateField(field.id, { validation: { ...field.validation, max: e.target.value ? Number(e.target.value) : undefined } }), placeholder: "100" })] }))] }), field.type === "text" && (_jsx(Input, { label: "Pattern (regex, optional)", value: field.validation?.pattern ?? "", onChange: (e) => updateField(field.id, { validation: { ...field.validation, pattern: e.target.value || undefined } }), placeholder: "^[A-Z].*" }))] })), _jsx(Toggle, { checked: field.required, onChange: (v) => updateField(field.id, { required: v }), label: "Required" })] }, field.id));
|
|
57
54
|
}), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: addField, children: "+ Add field" })] }));
|
|
58
55
|
}
|
|
59
56
|
const POLL_VISIBILITY_OPTIONS = [
|
|
@@ -299,14 +296,14 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, ...rest }) {
|
|
|
299
296
|
return "End date is required";
|
|
300
297
|
return null;
|
|
301
298
|
},
|
|
302
|
-
render: ({ values, onChange }) => (_jsxs(
|
|
299
|
+
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Event Details" }), !isEdit && (_jsx(Select, { label: "Event type", value: values.type, options: EVENT_TYPE_OPTIONS, onChange: (e) => onChange({ type: e.target.value }) })), _jsx(Input, { label: "Title", value: values.title, onChange: (e) => {
|
|
303
300
|
const v = e.target.value;
|
|
304
301
|
onChange({ title: v, ...(!slugManual && { slug: toEventSlug(v) }) });
|
|
305
|
-
}, placeholder: "Charizard Flash Sale 2026", required: true }), _jsx(Input, { label: "Slug", value: values.slug, onChange: (e) => { setSlugManual(true); onChange({ slug: e.target.value }); }, placeholder: "event-charizard-flash-sale-2026", helperText: "Auto-generated from title. Must start with 'event-'." }), _jsxs(
|
|
302
|
+
}, placeholder: "Charizard Flash Sale 2026", required: true }), _jsx(Input, { label: "Slug", value: values.slug, onChange: (e) => { setSlugManual(true); onChange({ slug: e.target.value }); }, placeholder: "event-charizard-flash-sale-2026", helperText: "Auto-generated from title. Must start with 'event-'." }), _jsxs(Stack, { gap: "xs", children: [_jsx(Label, { children: "Description" }), _jsx(RichTextEditor, { value: values.description, onChange: (v) => onChange({ description: v }), minHeightClassName: "min-h-[120px]", placeholder: "Describe this event\u2026" })] }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Input, { label: "Starts at", type: "datetime-local", value: values.startsAt, onChange: (e) => onChange({ startsAt: e.target.value }), required: true }), _jsx(Input, { label: "Ends at", type: "datetime-local", value: values.endsAt, onChange: (e) => onChange({ endsAt: e.target.value }), required: true })] }), _jsx(TagInput, { label: "Tags", value: values.tags, onChange: (t) => onChange({ tags: t }), placeholder: "e.g. pokemon, sale, 2026" })] })),
|
|
306
303
|
},
|
|
307
304
|
{
|
|
308
305
|
label: "Media",
|
|
309
|
-
render: ({ values, onChange }) => (_jsxs(
|
|
306
|
+
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Media" }), _jsx(Input, { label: "Cover Image URL (optional)", value: values.coverImageUrl, onChange: (e) => onChange({ coverImageUrl: e.target.value }), placeholder: "https://\u2026", helperText: "Direct link to the event cover image." })] })),
|
|
310
307
|
},
|
|
311
308
|
{
|
|
312
309
|
label: "Settings",
|
|
@@ -319,7 +316,7 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, ...rest }) {
|
|
|
319
316
|
return "Poll events require at least 2 options";
|
|
320
317
|
return null;
|
|
321
318
|
},
|
|
322
|
-
render: ({ values, onChange }) => (_jsxs(
|
|
319
|
+
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Event Settings" }), isEdit && (_jsx(Select, { label: "Status", value: values.status, options: EVENT_STATUS_OPTIONS, onChange: (e) => onChange({ status: e.target.value }) })), values.createdBy && (_jsxs(Stack, { gap: "none", children: [_jsx(Text, { size: "sm", weight: "medium", className: "mb-1", children: "Created by" }), _jsx(Text, { size: "sm", color: "muted", children: values.createdBy })] })), values.type === "sale" && (_jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Sale configuration" }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Input, { label: "Discount %", type: "number", value: values.discountPercent, onChange: (e) => onChange({ discountPercent: e.target.value }), placeholder: "10" }), _jsx(Input, { label: "Banner text (optional)", value: values.saleBannerText, onChange: (e) => onChange({ saleBannerText: e.target.value }), placeholder: "Limited time \u2014 ends Sunday!" })] })] })), values.type === "offer" && (_jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Offer configuration" }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Input, { label: "Coupon ID", value: values.couponId, onChange: (e) => onChange({ couponId: e.target.value }), placeholder: "Firestore coupon document ID", required: true }), _jsx(Input, { label: "Display code", value: values.displayCode, onChange: (e) => onChange({ displayCode: e.target.value }), placeholder: "CHARIZARD25", required: true })] }), _jsx(Input, { label: "Banner text (optional)", value: values.offerBannerText, onChange: (e) => onChange({ offerBannerText: e.target.value }), placeholder: "Use CHARIZARD25 at checkout" })] })), values.type === "poll" && (_jsxs(Stack, { gap: "md", rounded: "xl", border: "default", padding: "md", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Poll configuration" }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Options (minimum 2)" }), values.pollOptions.map((opt, idx) => (_jsxs(Row, { gap: "xs", children: [_jsx(Div, { className: "flex-1", children: _jsx(Input, { value: opt.label, onChange: (e) => onChange({ pollOptions: values.pollOptions.map((o) => o.id === opt.id ? { ...o, label: e.target.value } : o) }), placeholder: `Option ${idx + 1}` }) }), values.pollOptions.length > 2 && (_jsx("button", { type: "button", onClick: () => onChange({ pollOptions: values.pollOptions.filter((o) => o.id !== opt.id) }), className: "text-zinc-400 hover:text-red-500 transition-colors px-2 py-1 text-lg leading-none", "aria-label": "Remove option", children: "\u00D7" }))] }, opt.id))), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onChange({ pollOptions: [...values.pollOptions, { id: `opt${Date.now()}`, label: "" }] }), children: "+ Add option" })] }), _jsx(Select, { label: "Results visibility", value: values.resultsVisibility, options: POLL_VISIBILITY_OPTIONS, onChange: (e) => onChange({ resultsVisibility: e.target.value }) }), _jsxs(Stack, { gap: "sm", children: [_jsx(Toggle, { checked: values.allowMultiSelect, onChange: (v) => onChange({ allowMultiSelect: v }), label: "Allow multi-select" }), _jsx(Toggle, { checked: values.allowComment, onChange: (v) => onChange({ allowComment: v }), label: "Allow comment with vote" })] })] })), values.type === "survey" && (_jsxs(Stack, { gap: "md", rounded: "xl", border: "default", padding: "md", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Survey configuration" }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Input, { label: "Max entries per user", type: "number", value: values.maxEntriesPerUser, onChange: (e) => onChange({ maxEntriesPerUser: e.target.value }), placeholder: "1" }), values.hasPointSystem && (_jsx(Input, { label: "Points label", value: values.pointsLabel, onChange: (e) => onChange({ pointsLabel: e.target.value }), placeholder: "Points" }))] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Toggle, { checked: values.requireLogin, onChange: (v) => onChange({ requireLogin: v }), label: "Require login to participate" }), _jsx(Toggle, { checked: values.hasLeaderboard, onChange: (v) => onChange({ hasLeaderboard: v }), label: "Show leaderboard" }), _jsx(Toggle, { checked: values.hasPointSystem, onChange: (v) => onChange({ hasPointSystem: v }), label: "Enable point system" }), _jsx(Toggle, { checked: values.entryReviewRequired, onChange: (v) => onChange({ entryReviewRequired: v }), label: "Require employee review before entry is approved" })] }), _jsx(FormFieldBuilder, { fields: values.surveyFields, setFields: (f) => onChange({ surveyFields: f }) })] })), values.type === "feedback" && (_jsxs(Stack, { gap: "md", rounded: "xl", border: "default", padding: "md", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "Feedback configuration" }), _jsx(Toggle, { checked: values.anonymous, onChange: (v) => onChange({ anonymous: v }), label: "Allow anonymous submissions" }), _jsx(FormFieldBuilder, { fields: values.feedbackFields, setFields: (f) => onChange({ feedbackFields: f }) })] }))] })),
|
|
323
320
|
},
|
|
324
321
|
{
|
|
325
322
|
label: "Raffle / Spin",
|
|
@@ -327,14 +324,14 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, ...rest }) {
|
|
|
327
324
|
const isRaffleType = values.type === "raffle" || values.type === "spin_wheel";
|
|
328
325
|
const showRaffleConfig = isRaffleType || values.hasRaffle;
|
|
329
326
|
const isSpinMode = values.type === "spin_wheel" || values.raffleType === "spin_wheel";
|
|
330
|
-
return (_jsxs(
|
|
327
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Raffle & Spin Wheel" }), !isRaffleType && (_jsx(Toggle, { checked: values.hasRaffle, onChange: (v) => onChange({ hasRaffle: v }), label: "Attach a raffle to this event" })), !isRaffleType && !values.hasRaffle && (_jsx(Text, { size: "sm", color: "muted", children: "Enable the toggle above to attach a raffle draw to this event. Not applicable for this event type by default." })), showRaffleConfig && (_jsxs(Stack, { gap: "md", rounded: "xl", border: "default", padding: "md", children: [_jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Select, { label: "Raffle type", value: values.type === "spin_wheel" ? "spin_wheel" : values.raffleType, options: RAFFLE_TYPE_OPTIONS, onChange: (e) => onChange({ raffleType: e.target.value }), disabled: values.type === "spin_wheel" }), _jsx(Input, { label: "Top N (for top-N raffle types)", type: "number", value: values.raffleTopN, onChange: (e) => onChange({ raffleTopN: e.target.value }), placeholder: "10" })] }), _jsx(Input, { label: "Prize description", value: values.rafflePrize, onChange: (e) => onChange({ rafflePrize: e.target.value }), placeholder: "\u20B92,000 store credit + exclusive Pikachu sticker" }), _jsx(Input, { label: "Coupon ID for winner (optional)", value: values.rafflePrizeCouponId, onChange: (e) => onChange({ rafflePrizeCouponId: e.target.value }), placeholder: "coupon-vip-winner-2026" }), isSpinMode && (_jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "sm", children: [_jsx(Text, { size: "xs", weight: "medium", color: "muted", children: "Spin prizes (weighted random)" }), values.spinPrizes.length === 0 && (_jsx(Text, { size: "xs", color: "muted", children: "No spin prizes yet. Add at least one to enable spinning." })), values.spinPrizes.map((p) => (_jsxs(Grid, { gap: "xs", className: "grid-cols-12 items-end", children: [_jsx(Div, { className: "col-span-5", children: _jsx(Input, { label: "Label", value: p.label, onChange: (e) => onChange({ spinPrizes: values.spinPrizes.map((sp) => sp.id === p.id ? { ...sp, label: e.target.value } : sp) }), placeholder: "\u20B9100 off" }) }), _jsx(Div, { className: "col-span-3", children: _jsx(Input, { label: "Coupon ID", value: p.couponId ?? "", onChange: (e) => onChange({ spinPrizes: values.spinPrizes.map((sp) => sp.id === p.id ? { ...sp, couponId: e.target.value || undefined } : sp) }) }) }), _jsx(Div, { className: "col-span-2", children: _jsx(Input, { label: "Weight", type: "number", value: String(p.weight), onChange: (e) => onChange({ spinPrizes: values.spinPrizes.map((sp) => sp.id === p.id ? { ...sp, weight: Number(e.target.value) || 0 } : sp) }) }) }), _jsx(Row, { centered: true, className: "col-span-1 pb-2", children: _jsx(Toggle, { checked: p.isActive, onChange: (v) => onChange({ spinPrizes: values.spinPrizes.map((sp) => sp.id === p.id ? { ...sp, isActive: v } : sp) }), label: "" }) }), _jsx(Row, { centered: true, className: "col-span-1 pb-2", children: _jsx("button", { type: "button", onClick: () => onChange({ spinPrizes: values.spinPrizes.filter((sp) => sp.id !== p.id) }), className: "text-zinc-400 hover:text-red-500 text-lg leading-none px-2", "aria-label": "Remove prize", children: "\u00D7" }) })] }, p.id))), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onChange({ spinPrizes: [...values.spinPrizes, { id: `prize-${Date.now()}`, label: "", couponId: undefined, weight: 1, isActive: true }] }), children: "+ Add spin prize" }), _jsx(Input, { label: "Max spins per user", type: "number", value: values.spinMaxPerUser, onChange: (e) => onChange({ spinMaxPerUser: e.target.value }), placeholder: "1" }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Input, { label: "Spin window start", type: "datetime-local", value: values.spinWindowStart, onChange: (e) => onChange({ spinWindowStart: e.target.value }) }), _jsx(Input, { label: "Spin window end", type: "datetime-local", value: values.spinWindowEnd, onChange: (e) => onChange({ spinWindowEnd: e.target.value }) })] })] })), isEdit && (_jsxs(Stack, { gap: "xs", rounded: "lg", padding: "sm", className: "border border-amber-200 bg-amber-50 dark:border-amber-700 dark:bg-amber-900/20", children: [_jsxs(Row, { justify: "between", gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", className: "text-amber-900 dark:text-amber-100", children: raffleWinnerName ? `Winner: ${raffleWinnerName}` : "Raffle not yet triggered" }), _jsx(Button, { type: "button", variant: "primary", size: "sm", onClick: () => triggerRaffleMutation.mutate(), disabled: triggerRaffleMutation.isPending || Boolean(raffleWinnerName), children: triggerRaffleMutation.isPending ? "Triggering…" : raffleWinnerName ? "Already triggered" : "Trigger Raffle Now" })] }), raffleEntryCount !== null && _jsxs(Text, { size: "xs", className: "text-amber-800 dark:text-amber-200", children: ["Pool size: ", raffleEntryCount] }), raffleGithubUrl && _jsxs(Text, { size: "xs", className: "break-all text-amber-800 dark:text-amber-200", children: ["Fairness proof: ", raffleGithubUrl] }), triggerMessage && _jsx(Text, { size: "xs", className: "text-amber-900 dark:text-amber-100", children: triggerMessage })] }))] }))] }));
|
|
331
328
|
},
|
|
332
329
|
},
|
|
333
330
|
];
|
|
334
331
|
const alertSection = eventQuery.error ? (_jsx(Alert, { variant: "error", title: "Could not load event", children: eventQuery.error instanceof Error ? eventQuery.error.message : "Unknown error" })) : null;
|
|
335
|
-
const formContent = (_jsxs(
|
|
332
|
+
const formContent = (_jsxs(Stack, { gap: "sm", children: [alertSection, _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: () => { saveMutation.mutate(); }, formId: "admin-event", currentStep: currentStep, onStepChange: setCurrentStep, completeLabel: isEdit ? "Save Changes" : "Create Event", isLoading: isLoading }), saveMessage && (_jsx(Alert, { variant: saveMessage.toLowerCase().includes("fail") || saveMessage.toLowerCase().includes("error") ? "error" : "success", title: "Save status", children: saveMessage }))] }));
|
|
336
333
|
if (embedded) {
|
|
337
|
-
return _jsx(
|
|
334
|
+
return _jsx(Div, { className: "overflow-y-auto p-4", children: formContent });
|
|
338
335
|
}
|
|
339
336
|
return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Event" : "Create Event", sections: [formContent] }));
|
|
340
337
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { THEME_CONSTANTS } from "../../../tokens";
|
|
3
|
-
import { Button, Heading, Row, Section, Span, Text } from "../../../ui";
|
|
3
|
+
import { Button, Div, Grid, Heading, Row, Section, Span, Stack, Text } from "../../../ui";
|
|
4
4
|
import { MediaImage } from "../../media/MediaImage";
|
|
5
5
|
import { ArrowRight, Sparkles } from "lucide-react";
|
|
6
6
|
// --- Constants ---------------------------------------------------------------
|
|
@@ -9,17 +9,17 @@ const CLS_CONTAINER = "w-full max-w-7xl mx-auto";
|
|
|
9
9
|
export function AdvertisementBanner({ title, subtitle, ctaLabel = "Shop now", onCtaClick, backgroundImage, backgroundColor, tagLabel, isLoading = false, compact = false, className = "", }) {
|
|
10
10
|
const wrapClass = "bg-gradient-to-br from-amber-50/40 to-orange-50/20 dark:from-amber-950/10 dark:to-orange-950/5";
|
|
11
11
|
if (isLoading) {
|
|
12
|
-
return (_jsx(Section, { className: `p-8 ${wrapClass} ${className}`, children: _jsx(
|
|
12
|
+
return (_jsx(Section, { className: `p-8 ${wrapClass} ${className}`, children: _jsx(Div, { className: CLS_CONTAINER, children: _jsx(Div, { className: "h-72 bg-zinc-200 dark:bg-slate-700 rounded-2xl animate-pulse" }) }) }));
|
|
13
13
|
}
|
|
14
14
|
// -- Split layout: when a backgroundImage is provided --
|
|
15
15
|
if (backgroundImage) {
|
|
16
|
-
return (_jsx(Section, { className: `p-8 ${wrapClass} ${className}`, children: _jsx(
|
|
16
|
+
return (_jsx(Section, { className: `p-8 ${wrapClass} ${className}`, children: _jsx(Div, { className: CLS_CONTAINER, children: _jsx(Div, { className: "relative overflow-hidden rounded-2xl bg-zinc-900 shadow-xl", children: _jsxs(Grid, { className: `${THEME_CONSTANTS.grid.cols2Md} min-h-[clamp(300px,40vh,420px)]`, children: [_jsxs(Div, { className: `relative ${THEME_CONSTANTS.card.aspectBanner} order-last md:order-first min-h-0 min-h-[clamp(300px,40vh,420px)]`, children: [_jsx(MediaImage, { src: backgroundImage, alt: title, size: "banner", priority: true }), _jsx(Div, { className: "hidden md:block absolute inset-y-0 right-0 w-24 bg-gradient-to-r from-transparent to-zinc-900/60 pointer-events-none" })] }), _jsxs(Stack, { className: "relative justify-center px-8 py-10 md:px-12 md:py-14", children: [_jsx(Div, { className: "absolute top-0 right-0 w-32 h-32 opacity-10 pointer-events-none bg-[radial-gradient(circle,_white_1px,_transparent_1px)] bg-[length:12px_12px]", "aria-hidden": true }), tagLabel && (_jsxs(Span, { className: "inline-flex items-center gap-1.5 self-start bg-white/10 text-white/80 text-xs font-semibold uppercase tracking-widest px-3 py-1 rounded-full mb-5 backdrop-blur-sm", children: [_jsx(Sparkles, { className: "w-3.5 h-3.5" }), tagLabel] })), _jsx(Heading, { level: 2, variant: "none", className: "text-3xl md:text-4xl lg:text-5xl font-extrabold text-white mb-4 leading-tight", children: title }), subtitle && (_jsx(Text, { variant: "none", className: "text-white/75 text-base md:text-lg mb-8 leading-relaxed", children: subtitle })), ctaLabel && onCtaClick && (_jsxs(Button, { variant: "secondary", size: "lg", onClick: onCtaClick, className: "self-start bg-white text-zinc-900 hover:bg-zinc-100 dark:bg-zinc-100 dark:text-zinc-900 dark:hover:bg-zinc-200 font-semibold shadow-lg gap-2", children: [ctaLabel, _jsx(ArrowRight, { className: "w-4 h-4" })] }))] })] }) }) }) }));
|
|
17
17
|
}
|
|
18
18
|
// -- Full-width gradient layout --
|
|
19
|
-
return (_jsx(Section, { className: `p-8 ${wrapClass} ${className}`, children: _jsx(
|
|
20
|
-
"relative overflow-hidden rounded-2xl
|
|
19
|
+
return (_jsx(Section, { className: `p-8 ${wrapClass} ${className}`, children: _jsx(Div, { className: CLS_CONTAINER, children: _jsxs(Row, { align: "center", className: [
|
|
20
|
+
"relative overflow-hidden rounded-2xl",
|
|
21
21
|
compact
|
|
22
22
|
? "h-[clamp(112px,16vh,160px)]"
|
|
23
23
|
: "min-h-[clamp(240px,34vh,360px)]",
|
|
24
|
-
].join(" "), style: backgroundColor ? { backgroundColor } : undefined,
|
|
24
|
+
].join(" "), style: backgroundColor ? { backgroundColor } : undefined, children: [!backgroundColor && (_jsx(Div, { className: "absolute inset-0 bg-gradient-to-br from-indigo-600 via-purple-600 to-fuchsia-600", "aria-hidden": true })), _jsxs(Div, { className: "absolute inset-0 overflow-hidden", "aria-hidden": true, children: [_jsx(Div, { className: "absolute -top-16 -left-16 w-64 h-64 rounded-full bg-primary/20 blur-3xl animate-pulse" }), _jsx(Div, { className: "absolute -bottom-16 right-0 w-80 h-80 rounded-full bg-cobalt/20 blur-3xl animate-pulse" })] }), compact ? (_jsxs(Row, { justify: "between", className: "relative z-10 w-full px-6 py-4 gap-4 flex-wrap", children: [_jsxs(Span, { className: "inline-flex items-center gap-2", children: [_jsx(Sparkles, { className: "w-4 h-4 text-white/80" }), _jsx(Span, { className: "text-white font-semibold text-sm", children: title })] }), ctaLabel && onCtaClick && (_jsxs(Button, { variant: "secondary", size: "sm", onClick: onCtaClick, className: "bg-white dark:bg-zinc-100 text-indigo-700 hover:bg-zinc-50 dark:hover:bg-zinc-200 font-semibold gap-1.5 flex-shrink-0", children: [ctaLabel, _jsx(ArrowRight, { className: "w-3.5 h-3.5" })] }))] })) : (_jsxs(Div, { className: "relative z-10 w-full max-w-4xl mx-auto px-6 py-12 md:py-16 text-center", children: [tagLabel && (_jsxs(Span, { className: "inline-flex items-center gap-1.5 bg-white/15 text-white/90 text-xs font-semibold uppercase tracking-widest px-4 py-1.5 rounded-full mb-5 backdrop-blur-sm shadow-sm", children: [_jsx(Sparkles, { className: "w-3.5 h-3.5" }), tagLabel] })), _jsx(Heading, { level: 2, variant: "none", className: "text-3xl md:text-5xl lg:text-6xl font-extrabold text-white mb-4 drop-shadow-lg leading-tight", children: title }), subtitle && (_jsx(Text, { variant: "none", className: "text-white text-base md:text-xl mb-10 max-w-2xl mx-auto", children: subtitle })), ctaLabel && onCtaClick && (_jsxs(Button, { variant: "secondary", size: "lg", onClick: onCtaClick, className: "bg-white dark:bg-zinc-100 text-indigo-700 hover:bg-zinc-50 dark:hover:bg-zinc-200 font-semibold shadow-lg gap-2", children: [ctaLabel, _jsx(ArrowRight, { className: "w-4 h-4" })] }))] }))] }) }) }));
|
|
25
25
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { THEME_CONSTANTS } from "../../../tokens";
|
|
3
|
-
import { Grid, Section } from "../../../ui";
|
|
3
|
+
import { Div, Grid, Row, Section, Stack } from "../../../ui";
|
|
4
4
|
/** Full-page skeleton shown while homepage data loads. */
|
|
5
5
|
export function HomepageSkeleton() {
|
|
6
6
|
const { skeleton, flex, themed } = THEME_CONSTANTS;
|
|
@@ -9,5 +9,5 @@ export function HomepageSkeleton() {
|
|
|
9
9
|
const trustCardH = "h-[clamp(120px,18vh,170px)]";
|
|
10
10
|
const categoryTileH = "h-[clamp(112px,16vh,160px)]";
|
|
11
11
|
const newsletterH = "h-[clamp(220px,28vh,320px)]";
|
|
12
|
-
return (_jsxs(
|
|
12
|
+
return (_jsxs(Div, { className: "w-full overflow-hidden", children: [_jsx(Div, { className: `${skeleton.card} w-full ${heroSkeletonH}`, "aria-hidden": "true" }), _jsx(Section, { className: `p-8 ${themed.bgPrimary}`, children: _jsx(Grid, { className: "grid-cols-2 md:grid-cols-4 xl:grid-cols-4 2xl:grid-cols-4", children: Array.from({ length: 4 }).map((_, i) => (_jsx(Div, { className: `${skeleton.card} flex flex-col items-center gap-3 p-6 ${trustCardH}` }, i))) }) }), _jsxs(Section, { className: `p-8 ${themed.bgSecondary}`, children: [_jsx(Div, { className: `${skeleton.heading} w-48 mx-auto mb-6` }), _jsx(Grid, { className: "grid-cols-2 sm:grid-cols-4", children: Array.from({ length: 6 }).map((_, i) => (_jsx(Div, { className: `${skeleton.card} ${categoryTileH}` }, i))) })] }), _jsxs(Section, { className: `p-8 ${themed.bgPrimary}`, children: [_jsxs(Row, { className: `${flex.between} mb-6`, children: [_jsx(Div, { className: `${skeleton.heading} w-52` }), _jsx(Div, { className: `${skeleton.text} w-24` })] }), _jsx(Grid, { className: "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-4 2xl:grid-cols-5", children: Array.from({ length: 5 }).map((_, i) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Div, { className: `${skeleton.image} w-full pb-[100%]` }), _jsx(Div, { className: `${skeleton.text} w-3/4` }), _jsx(Div, { className: `${skeleton.text} w-1/2` })] }, i))) })] }), _jsxs(Section, { className: `p-8 ${themed.bgSecondary}`, children: [_jsxs(Row, { className: `${flex.between} mb-6`, children: [_jsx(Div, { className: `${skeleton.heading} w-56` }), _jsx(Div, { className: `${skeleton.text} w-24` })] }), _jsx(Grid, { className: "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-4 2xl:grid-cols-5", children: Array.from({ length: 5 }).map((_, i) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Div, { className: `${skeleton.image} w-full pb-[100%]` }), _jsx(Div, { className: `${skeleton.text} w-3/4` }), _jsx(Div, { className: `${skeleton.text} w-1/2` })] }, i))) })] }), _jsx(Section, { className: `p-8 ${themed.bgPrimary}`, children: _jsx(Div, { className: `${skeleton.card} rounded-2xl max-w-2xl mx-auto ${newsletterH}` }) })] }));
|
|
13
13
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { THEME_CONSTANTS } from "../../../tokens";
|
|
4
|
-
import { Button, Grid, Heading, Row, Section, SiteLogo, Span, Text, TextLink } from "../../../ui";
|
|
4
|
+
import { Button, Div, Grid, Heading, Row, Section, SiteLogo, Span, Text, TextLink } from "../../../ui";
|
|
5
5
|
// --- Component ---------------------------------------------------------------
|
|
6
6
|
export function WelcomeSection({ title, subtitle, pillLabel, showCTA = true, ctaLabel = "Shop now", ctaHref, onCtaClick, secondaryCtaLabel = "Browse products", secondaryCtaHref, onSecondaryCtaClick, trustChips = [], isLoading = false, brandLogoText = "", className = "", }) {
|
|
7
7
|
const { themed, flex } = THEME_CONSTANTS;
|
|
8
8
|
if (isLoading) {
|
|
9
|
-
return (_jsx(Section, { className: `relative overflow-hidden py-16 md:py-24 px-4 ${className}`, children: _jsxs(
|
|
9
|
+
return (_jsx(Section, { className: `relative overflow-hidden py-16 md:py-24 px-4 ${className}`, children: _jsxs(Div, { className: "animate-pulse max-w-4xl mx-auto text-center", children: [_jsx(Div, { className: "h-6 bg-zinc-200 dark:bg-slate-700 rounded-full w-52 mx-auto mb-6" }), _jsx(Div, { className: "h-20 bg-zinc-200 dark:bg-slate-700 rounded-lg mb-4 max-w-2xl mx-auto" }), _jsx(Div, { className: "h-6 bg-zinc-200 dark:bg-slate-700 rounded-lg mb-8 max-w-lg mx-auto" }), _jsxs(Row, { justify: "center", gap: "md", children: [_jsx(Div, { className: "h-12 bg-zinc-200 dark:bg-slate-700 rounded-xl w-36" }), _jsx(Div, { className: "h-12 bg-zinc-200 dark:bg-slate-700 rounded-xl w-36" })] })] }) }));
|
|
10
10
|
}
|
|
11
|
-
return (_jsxs(Section, { className: `relative overflow-hidden py-20 md:py-28 px-4 ${className}`, children: [_jsx(
|
|
11
|
+
return (_jsxs(Section, { className: `relative overflow-hidden py-20 md:py-28 px-4 ${className}`, children: [_jsx(Div, { className: "pointer-events-none absolute -top-32 -left-32 w-[28rem] h-[28rem] rounded-full bg-primary/10 blur-3xl", "aria-hidden": "true" }), _jsx(Div, { className: "pointer-events-none absolute -bottom-40 -right-40 w-[36rem] h-[36rem] rounded-full bg-secondary/10 dark:bg-secondary/15 blur-3xl", "aria-hidden": "true" }), _jsx(Div, { className: "relative z-10 max-w-7xl mx-auto", children: _jsxs(Grid, { gap: "2xl", className: "grid-cols-1 lg:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-2 items-center", children: [_jsxs(Div, { className: "text-center lg:text-left", children: [pillLabel && (_jsx(Div, { children: _jsxs(Span, { className: "inline-flex items-center gap-2 rounded-full border border-primary-500/30 bg-primary-500/10 px-5 py-1.5 text-xs font-medium tracking-[0.2em] uppercase text-primary-700 dark:text-primary-400 backdrop-blur-sm", children: [_jsx(Span, { className: "w-1.5 h-1.5 rounded-full bg-primary-500 inline-block", "aria-hidden": "true" }), pillLabel, _jsx(Span, { className: "w-1.5 h-1.5 rounded-full bg-primary-500 inline-block", "aria-hidden": "true" })] }) })), _jsx(Heading, { level: 1, variant: "none", className: "mt-4 font-display text-5xl md:text-6xl lg:text-7xl xl:text-8xl bg-gradient-to-r from-primary-700 via-cobalt to-secondary-400 dark:from-primary dark:via-cobalt-400 dark:to-primary-300 bg-clip-text text-transparent leading-[1.1] tracking-tight", children: title }), subtitle && (_jsx(Text, { className: `mt-4 text-xl ${themed.textSecondary} max-w-xl leading-relaxed mx-auto lg:mx-0`, children: subtitle })), showCTA && (_jsxs(Row, { wrap: true, gap: "md", className: "mt-8 justify-center lg:justify-start", children: [ctaHref ? (_jsx(TextLink, { href: ctaHref, className: "inline-flex items-center justify-center rounded-xl px-8 py-3.5 text-base font-bold !bg-primary hover:!bg-primary-600 text-white dark:!bg-primary dark:hover:!bg-primary-600 dark:text-white btn-glow transition-all hover:scale-[1.02]", children: ctaLabel })) : (_jsx(Button, { variant: "primary", size: "lg", onClick: onCtaClick, children: ctaLabel })), secondaryCtaHref ? (_jsx(TextLink, { href: secondaryCtaHref, className: "inline-flex items-center justify-center rounded-xl border-2 border-cobalt/40 dark:border-cobalt-400/40 px-8 py-3.5 text-base font-semibold text-cobalt-700 dark:text-cobalt-300 hover:bg-cobalt-50 dark:hover:bg-cobalt-900/20 transition-all hover:scale-[1.02]", children: secondaryCtaLabel })) : (_jsx(Button, { variant: "outline", size: "lg", onClick: onSecondaryCtaClick, children: secondaryCtaLabel }))] })), trustChips.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mt-6 justify-center lg:justify-start", children: trustChips.map((chip) => (_jsxs(Span, { className: "inline-flex items-center gap-1.5 bg-zinc-100 dark:bg-slate-800 border border-zinc-200 dark:border-slate-700 rounded-full px-3.5 py-1.5 text-xs font-medium text-zinc-700 dark:text-zinc-300", children: [chip.emoji, " ", chip.label] }, chip.key))) }))] }), _jsx(Div, { className: "hidden lg:block", children: _jsxs(Div, { className: `relative rounded-3xl overflow-hidden aspect-[4/3] bg-gradient-to-br from-primary-100 via-cobalt-100/60 to-secondary-100 dark:from-primary-950/60 dark:via-cobalt-950/40 dark:to-secondary-950/60 border ${themed.border} shadow-2xl`, children: [_jsx(Div, { className: "absolute inset-0 bg-gradient-to-br from-primary/5 via-transparent to-cobalt/5" }), _jsx(Row, { centered: true, className: `absolute inset-0 ${flex.center} px-10`, children: _jsx(SiteLogo, { title: brandLogoText || "LetItRip.in", className: "h-24 xl:h-32 2xl:h-40 max-w-full" }) })] }) })] }) })] }));
|
|
12
12
|
}
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useState, useCallback, useMemo } from "react";
|
|
4
4
|
import { Search, SlidersHorizontal, X } from "lucide-react";
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
|
-
import { ListingFilterDrawer, Pagination, SortDropdown, Div, Text, Heading } from "../../../ui";
|
|
6
|
+
import { ListingFilterDrawer, Pagination, SortDropdown, Div, Grid, Row, Span, Stack, Text, Heading } from "../../../ui";
|
|
7
7
|
import { usePromotions } from "../hooks/usePromotions";
|
|
8
8
|
import { CouponCard } from "./CouponCard";
|
|
9
9
|
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
@@ -89,14 +89,14 @@ export function CouponsIndexListing({ initialCoupons, storeSlug, storeId, }) {
|
|
|
89
89
|
const clearFilters = () => {
|
|
90
90
|
table.setMany({ type: "", [TABLE_KEYS.DATE_FROM]: "", [TABLE_KEYS.DATE_TO]: "" });
|
|
91
91
|
};
|
|
92
|
-
return (_jsxs(
|
|
92
|
+
return (_jsxs(Div, { className: "min-h-[40vh]", children: [_jsxs(Div, { className: "sticky top-[var(--header-height,0px)] z-20 border-b border-zinc-200 dark:border-slate-700 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm py-2.5 px-4", children: [_jsxs(Row, { gap: "xs", className: "max-w-full", children: [_jsxs("button", { type: "button", onClick: openFilters, className: `flex shrink-0 items-center gap-2 rounded-lg border px-3.5 py-2 text-sm font-medium transition-colors ${hasActiveFilters
|
|
93
93
|
? "border-primary bg-primary-50 text-primary-700 dark:bg-primary-900/30 dark:text-primary-300"
|
|
94
|
-
: "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-200 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: [_jsx(SlidersHorizontal, { className: "h-4 w-4" }), _jsxs(
|
|
94
|
+
: "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-200 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: [_jsx(SlidersHorizontal, { className: "h-4 w-4" }), _jsxs(Span, { className: "hidden sm:inline", children: ["Filters", hasActiveFilters ? " •" : ""] })] }), _jsxs(Row, { className: "flex-1 overflow-hidden rounded-lg border border-zinc-300 dark:border-slate-600 bg-white dark:bg-slate-900", children: [_jsx("input", { type: "text", value: searchInput, onChange: (e) => setSearchInput(e.target.value), onKeyDown: handleKeyDown, placeholder: "Search by name or description\u2026", className: "min-w-0 flex-1 bg-transparent px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 outline-none" }), searchInput && (_jsx("button", { type: "button", onClick: () => { setSearchInput(""); table.set(TABLE_KEYS.QUERY, ""); }, className: "p-2 text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300", "aria-label": "Clear search", children: _jsx(X, { className: "h-3.5 w-3.5" }) })), _jsx("button", { type: "button", onClick: commitSearch, className: "flex shrink-0 items-center justify-center px-3 py-2 text-zinc-400 hover:text-primary dark:hover:text-primary-400 transition-colors", "aria-label": "Search", children: _jsx(Search, { className: "h-4 w-4" }) })] }), _jsxs(Row, { gap: "xs", className: "shrink-0 text-sm text-zinc-500 dark:text-zinc-400", children: [_jsx(Span, { className: "hidden md:inline whitespace-nowrap", children: "Sort by" }), _jsx(SortDropdown, { value: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, onChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, options: COUPON_SORT_OPTIONS })] })] }), hasActiveFilters && (_jsxs(Row, { gap: "xs", wrap: true, className: "mt-2", children: [activeType && (_jsxs(Span, { className: "flex items-center gap-1 rounded-full bg-primary-50 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300 text-xs font-medium px-2.5 py-1", children: [COUPON_TYPES.find((t) => t.value === activeType)?.label ?? activeType, _jsx("button", { type: "button", onClick: () => { table.set(TABLE_KEYS.TYPE, ""); }, "aria-label": "Remove type filter", children: _jsx(X, { className: "h-3 w-3" }) })] })), table.get(TABLE_KEYS.DATE_FROM) && (_jsxs(Span, { className: "flex items-center gap-1 rounded-full bg-primary-50 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300 text-xs font-medium px-2.5 py-1", children: ["From: ", table.get(TABLE_KEYS.DATE_FROM), _jsx("button", { type: "button", onClick: () => { table.set(TABLE_KEYS.DATE_FROM, ""); }, "aria-label": "Remove from-date filter", children: _jsx(X, { className: "h-3 w-3" }) })] })), table.get(TABLE_KEYS.DATE_TO) && (_jsxs(Span, { className: "flex items-center gap-1 rounded-full bg-primary-50 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300 text-xs font-medium px-2.5 py-1", children: ["To: ", table.get(TABLE_KEYS.DATE_TO), _jsx("button", { type: "button", onClick: () => { table.set(TABLE_KEYS.DATE_TO, ""); }, "aria-label": "Remove to-date filter", children: _jsx(X, { className: "h-3 w-3" }) })] })), _jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 dark:text-zinc-400 hover:text-zinc-700 dark:hover:text-zinc-300 underline", children: "Clear all" })] }))] }), _jsxs(Div, { className: "py-6 px-4", children: [isLoading ? (_jsx(Grid, { gap: "sm", className: "md:grid-cols-2 lg:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Stack, { gap: "sm", rounded: "xl", padding: "md", className: "border-2 border-zinc-100 dark:border-slate-700 animate-pulse", children: [_jsx(Div, { className: "h-6 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" }), _jsx(Div, { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx(Div, { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/2" })] }, i))) })) : displayCoupons.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: "No coupons match your search." }) })) : (_jsx(Grid, { gap: "sm", className: "md:grid-cols-2 lg:grid-cols-3", children: displayCoupons.map((coupon) => (_jsx(CouponCard, { coupon: coupon, labels: {
|
|
95
95
|
copy: "Copy",
|
|
96
96
|
copied: "Copied!",
|
|
97
97
|
expires: "Expires",
|
|
98
98
|
minOrder: "Min. order",
|
|
99
99
|
off: "OFF",
|
|
100
100
|
freeShipping: "Free Shipping",
|
|
101
|
-
} }, coupon.id))) })), totalPages > 1 && (_jsx("
|
|
101
|
+
} }, coupon.id))) })), totalPages > 1 && (_jsx(Row, { justify: "center", className: "mt-8", children: _jsx(Pagination, { currentPage: table.getNumber("page", 1), totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), !isLoading && total > 0 && (_jsx(Div, { className: "mt-4 text-center", children: _jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400", children: [total, " coupon", total !== 1 ? "s" : "", " available"] }) }))] }), _jsxs(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearPending, activeCount: activeFilterCount, children: [_jsxs(_Fragment, { children: [_jsx(Heading, { level: 6, className: "text-xs font-semibold uppercase tracking-wider text-zinc-500 dark:text-zinc-400 mb-3", children: "Discount Type" }), _jsxs(Stack, { gap: "xs", children: [COUPON_TYPES.map((t) => (_jsxs("label", { className: "flex items-center gap-2 cursor-pointer text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx("input", { type: "radio", name: "coupon-type", value: t.value, checked: pendingTable.get(TABLE_KEYS.TYPE) === t.value, onChange: () => { pendingTable.set(TABLE_KEYS.TYPE, t.value); }, className: "accent-primary" }), t.label] }, t.value))), pendingTable.get(TABLE_KEYS.TYPE) && (_jsx("button", { type: "button", onClick: () => { pendingTable.set(TABLE_KEYS.TYPE, ""); }, className: "text-xs text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300 underline", children: "Clear type" }))] })] }), _jsxs(_Fragment, { children: [_jsx(Heading, { level: 6, className: "text-xs font-semibold uppercase tracking-wider text-zinc-500 dark:text-zinc-400 mb-3", children: "Valid Date Range" }), _jsxs(Stack, { gap: "sm", children: [_jsxs(_Fragment, { children: [_jsx("label", { className: "block text-xs text-zinc-500 dark:text-zinc-400 mb-1", children: "From date" }), _jsx("input", { type: "date", value: pendingTable.get(TABLE_KEYS.DATE_FROM) || "", onChange: (e) => { pendingTable.set(TABLE_KEYS.DATE_FROM, e.target.value); }, className: "w-full rounded-lg border border-zinc-300 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 outline-none focus:ring-2 focus:ring-primary" })] }), _jsxs(_Fragment, { children: [_jsx("label", { className: "block text-xs text-zinc-500 dark:text-zinc-400 mb-1", children: "To date" }), _jsx("input", { type: "date", value: pendingTable.get(TABLE_KEYS.DATE_TO) || "", onChange: (e) => { pendingTable.set(TABLE_KEYS.DATE_TO, e.target.value); }, className: "w-full rounded-lg border border-zinc-300 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 outline-none focus:ring-2 focus:ring-primary" })] })] })] })] })] }));
|
|
102
102
|
}
|
|
@@ -5,7 +5,7 @@ const CLS_RELATED_LINK = "group flex items-center gap-3 rounded-xl border border
|
|
|
5
5
|
const CLS_RELATED_LABEL = "text-xs text-zinc-400 dark:text-zinc-400 mb-0.5";
|
|
6
6
|
const CLS_RELATED_TITLE = "text-sm font-medium text-neutral-900 dark:text-white truncate group-hover:text-primary transition-colors";
|
|
7
7
|
import Link from "next/link";
|
|
8
|
-
import { Heading, RichText, Section, Span, StarRating, Text } from "../../../ui";
|
|
8
|
+
import { Div, Grid, Heading, RichText, Row, Section, Span, StarRating, Stack, Text } from "../../../ui";
|
|
9
9
|
import { maskName } from "../../../security";
|
|
10
10
|
import { getDefaultLocale } from "../../../core/baseline-resolver";
|
|
11
11
|
import { normalizeRichTextHtml } from "../../../utils/string.formatter";
|
|
@@ -77,9 +77,9 @@ export function ReviewDetailShell({ review, storeHref }) {
|
|
|
77
77
|
? String(ROUTES.PUBLIC.PROFILE(reviewerProfileId))
|
|
78
78
|
: null;
|
|
79
79
|
const currentImage = lightboxIdx !== null ? images[lightboxIdx] : null;
|
|
80
|
-
return (_jsxs(_Fragment, { children: [_jsx(
|
|
80
|
+
return (_jsxs(_Fragment, { children: [_jsx(Div, { className: "border-b border-neutral-200 dark:border-zinc-800 bg-white dark:bg-zinc-900 pb-8 pt-10", children: _jsxs(Div, { className: "mx-auto max-w-3xl px-4", children: [_jsxs(Row, { gap: "sm", className: "mb-4", children: [_jsx(StarRating, { value: review.rating, size: "lg", readOnly: true }), _jsxs(Span, { weight: "bold", className: "text-2xl text-neutral-900 dark:text-white", children: [review.rating, ".0"] }), review.verified && (_jsx(Span, { className: "inline-flex items-center gap-1 rounded-full bg-success-surface px-3 py-1 text-xs font-semibold text-success", children: "\u2713 Verified Purchase" })), review.featured && (_jsx(Span, { className: "inline-flex items-center gap-1 rounded-full bg-yellow-100 px-3 py-1 text-xs font-semibold text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400", children: "\u2605 Featured" }))] }), review.title && (_jsx(Heading, { level: 1, className: "text-2xl font-bold text-neutral-900 dark:text-white mb-4 leading-snug", children: review.title })), _jsxs(Row, { gap: "sm", children: [review.userAvatar ? (_jsx(Div, { role: "img", "aria-label": displayName, className: "h-11 w-11 flex-shrink-0 rounded-full bg-center bg-cover ring-2 ring-white dark:ring-zinc-800", style: { backgroundImage: `url(${review.userAvatar})` } })) : (_jsx(Row, { centered: true, className: "h-11 w-11 flex-shrink-0 rounded-full bg-primary/10 text-base font-bold text-primary ring-2 ring-white dark:ring-zinc-800", children: initials })), _jsxs(Div, { className: "min-w-0", children: [reviewerHref ? (_jsx(Link, { href: reviewerHref, className: "text-sm font-semibold text-neutral-900 dark:text-white hover:text-primary transition-colors", children: displayName })) : (_jsx(Span, { weight: "semibold", className: "text-sm text-neutral-900 dark:text-white", children: review.isAnonymous ? "Anonymous" : displayName })), date && (_jsx(Text, { size: "xs", color: "muted", className: "mt-0.5", children: date }))] })] })] }) }), _jsxs(Stack, { gap: "xl", className: "mx-auto max-w-3xl px-4 py-8", children: [review.comment && (_jsx(Section, { children: _jsx(RichText, { html: normalizeRichTextHtml(review.comment), proseClass: "prose prose-neutral dark:prose-invert max-w-none prose-p:leading-relaxed prose-headings:font-semibold prose-img:rounded-lg prose-a:text-primary", className: "text-neutral-700 dark:text-zinc-300" }) })), images.length > 0 && (_jsxs(Section, { children: [_jsxs(Heading, { level: 2, className: "text-sm font-semibold uppercase tracking-wide text-zinc-400 dark:text-zinc-400 mb-3", children: ["Photos (", images.length, ")"] }), _jsx(Grid, { gap: "xs", className: "grid-cols-3 sm:grid-cols-4", children: images.map((img, i) => (_jsxs("button", { type: "button", onClick: () => setLightboxIdx(i), "aria-label": `View photo ${i + 1}`, className: "group relative aspect-square overflow-hidden rounded-xl border border-neutral-200 dark:border-zinc-700 bg-neutral-100 dark:bg-zinc-800 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary", children: [_jsx(Div, { className: "h-full w-full bg-center bg-cover transition-transform duration-300 group-hover:scale-105", style: { backgroundImage: `url(${img.thumbnailUrl ?? img.url})` } }), _jsx(Row, { centered: true, className: "absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity bg-black/30", children: _jsx(Span, { className: "text-white text-xl", children: "\uD83D\uDD0D" }) })] }, i))) })] })), review.video && (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "text-sm font-semibold uppercase tracking-wide text-zinc-400 dark:text-zinc-400 mb-3", children: "Video" }), _jsx(Div, { className: "overflow-hidden rounded-xl border border-neutral-200 dark:border-zinc-700 bg-black aspect-video", children: _jsx("video", { src: review.video.url, poster: review.video.thumbnailUrl, controls: true, className: "h-full w-full", preload: "metadata" }) })] })), _jsxs(Section, { className: "flex items-center gap-4 py-4 border-t border-neutral-100 dark:border-zinc-800", children: [_jsx(Div, { className: "text-sm text-neutral-500 dark:text-zinc-400", children: helpfulCount > 0 && (_jsxs(Span, { children: [_jsx(Span, { weight: "bold", className: "text-neutral-900 dark:text-white", children: helpfulCount }), " ", helpfulCount === 1 ? "person" : "people", " found this helpful"] })) }), _jsxs("button", { type: "button", onClick: handleVote, disabled: voted || voting, className: `ml-auto flex items-center gap-2 rounded-lg border px-4 py-2 text-sm font-medium transition-colors ${voted
|
|
81
81
|
? "border-emerald-200 bg-success-surface text-success dark:border-emerald-800 cursor-default"
|
|
82
|
-
: "border-neutral-300 dark:border-zinc-600 text-neutral-700 dark:text-zinc-200 hover:border-primary hover:text-primary dark:hover:border-primary dark:hover:text-primary disabled:opacity-50"}`, children: [_jsx("span", { "aria-hidden": "true", children: voted ? "✓" : "👍" }), voted ? "Marked helpful" : voting ? "Saving…" : "Helpful?"] })] }), _jsxs(Section, { className: "grid gap-3 sm:grid-cols-3", children: [productHref && (_jsxs(Link, { href: productHref, className: CLS_RELATED_LINK, children: [_jsx("span", { className: "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg bg-orange-100 dark:bg-orange-900/30 text-xl", children: "\uD83D\uDCE6" }), _jsxs(
|
|
82
|
+
: "border-neutral-300 dark:border-zinc-600 text-neutral-700 dark:text-zinc-200 hover:border-primary hover:text-primary dark:hover:border-primary dark:hover:text-primary disabled:opacity-50"}`, children: [_jsx("span", { "aria-hidden": "true", children: voted ? "✓" : "👍" }), voted ? "Marked helpful" : voting ? "Saving…" : "Helpful?"] })] }), _jsxs(Section, { className: "grid gap-3 sm:grid-cols-3", children: [productHref && (_jsxs(Link, { href: productHref, className: CLS_RELATED_LINK, children: [_jsx("span", { className: "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg bg-orange-100 dark:bg-orange-900/30 text-xl", children: "\uD83D\uDCE6" }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: CLS_RELATED_LABEL, children: "Product" }), _jsx(Text, { className: CLS_RELATED_TITLE, children: review.productTitle ?? "View Product" })] })] })), sellerHref && (_jsxs(Link, { href: sellerHref, className: CLS_RELATED_LINK, children: [_jsx("span", { className: "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg bg-blue-100 dark:bg-blue-900/30 text-xl", children: "\uD83C\uDFEA" }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: CLS_RELATED_LABEL, children: "Seller" }), _jsx(Text, { className: CLS_RELATED_TITLE, children: "View Seller" })] })] })), reviewerHref ? (_jsxs(Link, { href: reviewerHref, className: CLS_RELATED_LINK, children: [_jsx("span", { className: "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg bg-purple-100 dark:bg-purple-900/30 text-xl", children: "\uD83D\uDC64" }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: CLS_RELATED_LABEL, children: "Reviewer" }), _jsx(Text, { className: CLS_RELATED_TITLE, children: displayName })] })] })) : (_jsxs(Row, { gap: "sm", className: "rounded-xl border border-neutral-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 p-4", children: [_jsx(Span, { className: "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg bg-purple-100 dark:bg-purple-900/30 text-xl", children: "\uD83D\uDC64" }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Span, { className: "block text-xs text-zinc-400 dark:text-zinc-400 mb-0.5", children: "Reviewer" }), _jsx(Span, { className: "block text-sm font-medium text-neutral-900 dark:text-white truncate", children: "Anonymous" })] })] }))] })] }), lightboxIdx !== null && currentImage && (_jsxs(Row, { centered: true, className: "fixed inset-0 z-50 bg-black/95", onClick: closeLightbox, role: "dialog", "aria-modal": "true", "aria-label": "Image lightbox", children: [_jsx("button", { type: "button", onClick: closeLightbox, "aria-label": "Close lightbox", className: "absolute top-4 right-4 z-10 flex h-10 w-10 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/20 transition-colors text-xl", children: "\u00D7" }), _jsxs(Div, { className: "absolute top-4 left-1/2 -translate-x-1/2 text-white/70 text-sm", children: [lightboxIdx + 1, " / ", images.length] }), images.length > 1 && (_jsx("button", { type: "button", onClick: (e) => { e.stopPropagation(); prevImage(); }, "aria-label": "Previous image", className: "absolute left-4 top-1/2 -translate-y-1/2 z-10 flex h-12 w-12 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/25 transition-colors text-2xl", children: "\u2039" })), _jsx(Row, { centered: true, className: "max-h-[85vh] max-w-[85vw]", onClick: (e) => e.stopPropagation(), children: _jsx("img", { src: currentImage.url, alt: `Review photo ${lightboxIdx + 1}`, className: "max-h-[85vh] max-w-[85vw] rounded-lg object-contain shadow-2xl" }) }), images.length > 1 && (_jsx("button", { type: "button", onClick: (e) => { e.stopPropagation(); nextImage(); }, "aria-label": "Next image", className: "absolute right-4 top-1/2 -translate-y-1/2 z-10 flex h-12 w-12 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/25 transition-colors text-2xl", children: "\u203A" })), images.length > 1 && (_jsx(Row, { justify: "center", gap: "xs", className: "absolute bottom-4 left-0 right-0 px-4", children: images.map((img, i) => (_jsx("button", { type: "button", onClick: (e) => { e.stopPropagation(); setLightboxIdx(i); }, "aria-label": `Go to image ${i + 1}`, className: `h-12 w-12 flex-shrink-0 rounded-md bg-center bg-cover border-2 transition-all ${i === lightboxIdx
|
|
83
83
|
? "border-white scale-110"
|
|
84
84
|
: "border-transparent opacity-60 hover:opacity-100"}`, style: { backgroundImage: `url(${img.thumbnailUrl ?? img.url})` } }, i))) }))] }))] }));
|
|
85
85
|
}
|
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useState } from "react";
|
|
4
4
|
import { MapPin, Pencil, Plus, Trash2, Star } from "lucide-react";
|
|
5
|
-
import { Button, ConfirmDeleteModal, Div, Heading, Row, SideDrawer, Text } from "../../../ui";
|
|
5
|
+
import { Button, ConfirmDeleteModal, Div, Grid, Heading, Label, Row, SideDrawer, Span, Stack, Text } from "../../../ui";
|
|
6
6
|
import { ROW_ACTION_META, ROW_ACTION_ID } from "../../../features/products/constants/action-defs";
|
|
7
7
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
8
8
|
import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
|
|
9
9
|
const INPUT_CLS = "w-full rounded-lg border border-zinc-300 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 dark:placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-[var(--appkit-color-primary)]";
|
|
10
|
-
const CLS_GRID_2_COL = "grid grid-cols-2 gap-3";
|
|
11
10
|
function Field({ label, hint, children }) {
|
|
12
|
-
return (_jsxs(
|
|
11
|
+
return (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { className: "block text-xs font-medium text-zinc-700 dark:text-zinc-300", children: label }), children, hint && _jsx(Text, { size: "xs", color: "muted", children: hint })] }));
|
|
13
12
|
}
|
|
14
13
|
// ---------------------------------------------------------------------------
|
|
15
14
|
// Helpers
|
|
@@ -43,7 +42,7 @@ function fromDoc(doc) {
|
|
|
43
42
|
};
|
|
44
43
|
}
|
|
45
44
|
function AddressCard({ address, onEdit, onDelete, }) {
|
|
46
|
-
return (_jsxs(Div, { surface: "card", padding: "sm", className: "flex flex-col gap-2", children: [_jsxs(
|
|
45
|
+
return (_jsxs(Div, { surface: "card", padding: "sm", className: "flex flex-col gap-2", children: [_jsxs(Row, { align: "start", justify: "between", gap: "xs", children: [_jsxs(Row, { gap: "xs", className: "min-w-0", children: [_jsx(MapPin, { className: "h-4 w-4 shrink-0 text-[var(--appkit-color-primary)]" }), _jsx(Span, { weight: "semibold", className: "text-sm text-zinc-900 dark:text-zinc-100 truncate", children: address.label }), address.isDefault && (_jsxs(Span, { className: "inline-flex items-center gap-1 rounded-full bg-amber-50 dark:bg-amber-950/40 text-amber-700 dark:text-amber-300 border border-amber-200 dark:border-amber-800 text-xs px-2 py-0.5 font-medium", children: [_jsx(Star, { className: "h-3 w-3" }), "Default"] }))] }), _jsxs(Row, { gap: "px", className: "shrink-0", children: [_jsx("button", { type: "button", onClick: onEdit, title: "Edit address", className: "rounded-lg p-1.5 text-zinc-500 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 hover:text-zinc-700 dark:hover:text-zinc-300 transition-colors", children: _jsx(Pencil, { className: "h-4 w-4" }) }), _jsx("button", { type: "button", onClick: onDelete, title: "Delete address", className: "rounded-lg p-1.5 text-zinc-500 dark:text-zinc-400 hover:bg-red-50 dark:hover:bg-red-950/40 hover:text-red-600 dark:hover:text-red-400 transition-colors", children: _jsx(Trash2, { className: "h-4 w-4" }) })] })] }), _jsxs(Text, { className: "text-sm text-zinc-700 dark:text-zinc-300", children: [address.fullName, " \u00B7 ", address.phone] }), _jsxs(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 leading-relaxed", children: [address.addressLine1, address.addressLine2 ? `, ${address.addressLine2}` : "", address.landmark ? ` (near ${address.landmark})` : "", _jsx("br", {}), address.city, ", ", address.state, " ", address.postalCode, ", ", address.country] })] }));
|
|
47
46
|
}
|
|
48
47
|
// ---------------------------------------------------------------------------
|
|
49
48
|
// Main Component
|
|
@@ -135,5 +134,5 @@ export function SellerAddressesView({ apiBase = SELLER_ENDPOINTS.STORE_ADDRESSES
|
|
|
135
134
|
const handleDelete = (addr) => setDeleteTargetAddr(addr);
|
|
136
135
|
const set = (key, value) => setDraft((p) => ({ ...p, [key]: value }));
|
|
137
136
|
const handleTextField = (key) => (e) => set(key, e.target.value);
|
|
138
|
-
return (_jsxs(
|
|
137
|
+
return (_jsxs(Div, { className: "min-h-screen", children: [_jsxs(Row, { justify: "between", className: "sticky z-10 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-4 py-3", style: { top: "var(--header-height, 0px)" }, children: [_jsxs(Stack, { gap: "none", children: [_jsx(Heading, { level: 2, className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Pickup Addresses" }), _jsx(Text, { size: "xs", color: "muted", className: "mt-0.5", children: "Manage your store's pickup and return locations" })] }), _jsxs(Button, { size: "sm", onClick: openAdd, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx(Span, { children: "Add Address" })] })] }), _jsxs(Div, { className: "py-6 px-4 sm:px-6 max-w-2xl", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-error/20 bg-error-surface px-4 py-3 text-sm text-error", children: errorMessage })), isLoading ? (_jsx(Row, { justify: "center", className: "py-16", children: _jsx(Div, { className: "h-6 w-6 animate-spin rounded-full border-2 border-[var(--appkit-color-primary)] border-t-transparent" }) })) : addresses.length === 0 ? (_jsxs(Div, { className: "rounded-xl border-2 border-dashed border-zinc-200 dark:border-slate-700 py-16 flex flex-col items-center gap-3", children: [_jsx(MapPin, { className: "h-8 w-8 text-zinc-300 dark:text-slate-600" }), _jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "No pickup addresses yet" }), _jsx(Button, { size: "sm", variant: "outline", onClick: openAdd, children: "Add your first address" })] })) : (_jsxs(_Fragment, { children: [_jsxs(Row, { justify: "end", className: "mb-2", children: [_jsx(Button, { size: "sm", variant: listView === "table" ? "primary" : "ghost", onClick: () => setListView("table"), children: "Table" }), _jsx(Button, { size: "sm", variant: listView === "cards" ? "primary" : "ghost", onClick: () => setListView("cards"), children: "Cards" })] }), listView === "cards" ? (_jsx(Grid, { gap: "sm", children: addresses.map((addr) => (_jsx(Div, { className: deletingId === addr.id ? "opacity-50 pointer-events-none" : "", children: _jsx(AddressCard, { address: addr, onEdit: () => openEdit(addr), onDelete: () => handleDelete(addr) }) }, addr.id))) })) : (_jsx(Div, { className: "overflow-x-auto rounded-lg border border-zinc-200 dark:border-slate-700", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "bg-zinc-50 dark:bg-slate-800", children: _jsxs("tr", { children: [_jsx("th", { className: "text-left px-3 py-2 font-semibold", children: "Label" }), _jsx("th", { className: "text-left px-3 py-2 font-semibold", children: "Name" }), _jsx("th", { className: "text-left px-3 py-2 font-semibold", children: "City" }), _jsx("th", { className: "text-left px-3 py-2 font-semibold", children: "Phone" }), _jsx("th", { className: "text-right px-3 py-2 font-semibold", children: "Actions" })] }) }), _jsx("tbody", { children: addresses.map((addr) => (_jsxs("tr", { className: `border-t border-zinc-100 dark:border-slate-700 ${deletingId === addr.id ? "opacity-50" : ""}`, children: [_jsx("td", { className: "px-3 py-2", children: addr.label }), _jsx("td", { className: "px-3 py-2", children: addr.fullName }), _jsxs("td", { className: "px-3 py-2", children: [addr.city, ", ", addr.state] }), _jsx("td", { className: "px-3 py-2 tabular-nums", children: addr.phone }), _jsx("td", { className: "px-3 py-2 text-right", children: _jsxs(Row, { justify: "end", className: "gap-1", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => openEdit(addr), children: ROW_ACTION_META[ROW_ACTION_ID.EDIT].label }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => handleDelete(addr), children: ROW_ACTION_META[ROW_ACTION_ID.DELETE].label })] }) })] }, addr.id))) })] }) }))] }))] }), _jsx(SideDrawer, { isOpen: drawerOpen, onClose: closeDrawer, title: editingId ? "Edit Address" : "Add Address", footer: _jsxs(Row, { gap: "xs", children: [_jsx(Button, { variant: "outline", onClick: closeDrawer, className: "flex-1", children: "Cancel" }), _jsx(Button, { onClick: handleSave, disabled: saving, className: "flex-1", children: saving ? "Saving…" : editingId ? "Save Changes" : "Add Address" })] }), children: _jsxs(Stack, { gap: "md", className: "py-1", children: [saveError && (_jsx(Div, { className: "rounded-lg border border-error/20 bg-error-surface px-3 py-2 text-sm text-error", children: saveError })), _jsx(Field, { label: "Label *", hint: "e.g. Warehouse, Shop, Home", children: _jsx("input", { type: "text", value: draft.label, onChange: handleTextField("label"), placeholder: "Warehouse", maxLength: 60, className: INPUT_CLS }) }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Field, { label: "Full Name *", children: _jsx("input", { type: "text", value: draft.fullName, onChange: handleTextField("fullName"), placeholder: "Ravi Kumar", maxLength: 100, className: INPUT_CLS }) }), _jsx(Field, { label: "Phone *", children: _jsx("input", { type: "tel", value: draft.phone, onChange: handleTextField("phone"), placeholder: "+91 98765 43210", maxLength: 20, className: INPUT_CLS }) })] }), _jsx(Field, { label: "Address Line 1 *", children: _jsx("input", { type: "text", value: draft.addressLine1, onChange: handleTextField("addressLine1"), placeholder: "Shop 12, Main Market", maxLength: 200, className: INPUT_CLS }) }), _jsx(Field, { label: "Address Line 2", children: _jsx("input", { type: "text", value: draft.addressLine2, onChange: handleTextField("addressLine2"), placeholder: "Building / Floor (optional)", maxLength: 200, className: INPUT_CLS }) }), _jsx(Field, { label: "Landmark", children: _jsx("input", { type: "text", value: draft.landmark, onChange: handleTextField("landmark"), placeholder: "Near metro station (optional)", maxLength: 100, className: INPUT_CLS }) }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Field, { label: "City *", children: _jsx("input", { type: "text", value: draft.city, onChange: handleTextField("city"), placeholder: "Mumbai", maxLength: 100, className: INPUT_CLS }) }), _jsx(Field, { label: "State *", children: _jsx("input", { type: "text", value: draft.state, onChange: handleTextField("state"), placeholder: "Maharashtra", maxLength: 100, className: INPUT_CLS }) })] }), _jsxs(Grid, { cols: 2, gap: "sm", children: [_jsx(Field, { label: "Postal Code *", children: _jsx("input", { type: "text", value: draft.postalCode, onChange: handleTextField("postalCode"), placeholder: "400001", maxLength: 10, className: INPUT_CLS }) }), _jsx(Field, { label: "Country *", children: _jsx("input", { type: "text", value: draft.country, onChange: handleTextField("country"), placeholder: "India", maxLength: 60, className: INPUT_CLS }) })] }), _jsxs("label", { className: "flex items-center gap-3 cursor-pointer", children: [_jsx("input", { type: "checkbox", checked: draft.isDefault, onChange: (e) => set("isDefault", e.target.checked), className: "h-4 w-4 rounded border-zinc-300 dark:border-slate-600 text-[var(--appkit-color-primary)] focus:ring-[var(--appkit-color-primary)]" }), _jsx(Span, { className: "text-sm text-zinc-700 dark:text-zinc-300", children: "Set as default pickup address" })] })] }) }), deleteTargetAddr && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Address", message: `Delete address "${deleteTargetAddr.label}"? This cannot be undone.`, onConfirm: () => { deleteById(deleteTargetAddr.id); setDeleteTargetAddr(null); }, onClose: () => setDeleteTargetAddr(null), isDeleting: deletingId === deleteTargetAddr.id }))] }));
|
|
139
138
|
}
|