@mohasinac/appkit 4.14.0 → 4.16.0
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/server/features/auctions/actions.js +2 -2
- package/dist/_internal/server/features/cart/service.d.ts +3 -3
- package/dist/_internal/server/features/checkout/actions.js +19 -0
- package/dist/_internal/server/features/checkout/source-context.d.ts +5 -0
- package/dist/_internal/server/features/checkout/source-context.js +157 -0
- package/dist/_internal/server/features/offers/adapters.d.ts +103 -0
- package/dist/_internal/server/features/offers/adapters.js +88 -0
- package/dist/_internal/server/features/offers/index.d.ts +2 -0
- package/dist/_internal/server/features/offers/index.js +1 -0
- package/dist/_internal/server/features/orders/adapters.js +24 -0
- package/dist/_internal/server/jobs/core/offerExpiry.js +10 -10
- package/dist/_internal/shared/actions/action-registry.d.ts +9 -2
- package/dist/_internal/shared/actions/action-registry.js +458 -7
- package/dist/_internal/shared/features/auctions/schema.d.ts +14 -2
- package/dist/_internal/shared/features/auctions/schema.js +13 -1
- package/dist/_internal/shared/features/blog/schema.d.ts +4 -4
- package/dist/_internal/shared/features/cart/schema.d.ts +25 -20
- package/dist/_internal/shared/features/cart/schema.js +15 -0
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +22 -22
- package/dist/_internal/shared/features/orders/schema.d.ts +4 -4
- package/dist/_internal/shared/features/products/schema.d.ts +27 -27
- package/dist/_internal/shared/features/promotions/schema.d.ts +4 -4
- package/dist/_internal/shared/features/reviews/schema.d.ts +2 -2
- package/dist/_internal/shared/history/history.d.ts +22 -0
- package/dist/_internal/shared/history/history.js +41 -1
- package/dist/client.d.ts +13 -2
- package/dist/client.js +20 -2
- package/dist/constants/field-names.d.ts +8 -6
- package/dist/constants/field-names.js +48 -6
- package/dist/contracts/extend.d.ts +29 -0
- package/dist/contracts/extend.js +20 -0
- package/dist/contracts/index.d.ts +2 -1
- package/dist/contracts/index.js +2 -0
- package/dist/features/account/components/UserBidsView.js +12 -4
- package/dist/features/account/components/UserReturnsView.d.ts +3 -0
- package/dist/features/account/components/UserReturnsView.js +17 -1
- package/dist/features/admin/components/AdminAuditLogView.js +1 -0
- package/dist/features/admin/components/AdminBidsView.js +15 -2
- package/dist/features/admin/components/AdminBlogEditorView.js +65 -33
- package/dist/features/admin/components/AdminFeatureEditorView.js +35 -6
- package/dist/features/admin/components/AdminNavEditorView.js +15 -5
- package/dist/features/admin/components/AdminNewsletterView.js +18 -2
- package/dist/features/admin/components/AdminOffersView.js +62 -18
- package/dist/features/admin/components/AdminPaymentMethodsView.js +24 -4
- package/dist/features/admin/components/AdminScammerEditorView.d.ts +2 -1
- package/dist/features/admin/components/AdminScammerEditorView.js +3 -13
- package/dist/features/admin/components/AdminScammersView.js +3 -8
- package/dist/features/admin/components/AdminSectionsView.js +32 -23
- package/dist/features/admin/components/AdminSessionsView.js +17 -2
- package/dist/features/admin/components/AdminViewCards.js +24 -17
- package/dist/features/admin/components/DataListingView.js +15 -1
- package/dist/features/admin/components/DataTable.js +7 -17
- package/dist/features/admin/components/ViewAuditLogEntryModal.js +1 -0
- package/dist/features/admin/components/sections/adminSectionsTypes.d.ts +4 -2
- package/dist/features/admin/components/sections/adminSectionsTypes.js +45 -27
- package/dist/features/admin/constants/filter-tabs.d.ts +3 -0
- package/dist/features/admin/constants/filter-tabs.js +1 -0
- package/dist/features/admin/schemas/homepage-section-form.d.ts +22 -0
- package/dist/features/admin/schemas/homepage-section-form.js +68 -0
- package/dist/features/admin/schemas/nav-item-form.d.ts +74 -0
- package/dist/features/admin/schemas/nav-item-form.js +72 -0
- package/dist/features/auctions/components/AuctionBidsTable.d.ts +10 -1
- package/dist/features/auctions/components/AuctionBidsTable.js +22 -4
- package/dist/features/auctions/components/bid-detail-fields.d.ts +29 -0
- package/dist/features/auctions/components/bid-detail-fields.js +103 -0
- package/dist/features/auctions/schemas/index.d.ts +14 -14
- package/dist/features/audit-log/schemas/firestore.d.ts +14 -0
- package/dist/features/audit-log/schemas/firestore.js +7 -0
- package/dist/features/auth/schemas/index.d.ts +2 -2
- package/dist/features/blog/actions/blog-actions.d.ts +7 -7
- package/dist/features/blog/schemas/blog-form.d.ts +80 -0
- package/dist/features/blog/schemas/blog-form.js +100 -0
- package/dist/features/blog/schemas/index.d.ts +10 -10
- package/dist/features/cart/schemas/index.d.ts +3 -3
- package/dist/features/catalogue/schemas/validation.d.ts +12 -12
- package/dist/features/categories/schemas/index.d.ts +16 -16
- package/dist/features/collections/schemas/index.d.ts +8 -8
- package/dist/features/events/components/AdminEventEditorView.js +32 -54
- package/dist/features/events/components/AdminEventEntriesView.js +22 -3
- package/dist/features/events/schemas/event-form.d.ts +113 -0
- package/dist/features/events/schemas/event-form.js +82 -0
- package/dist/features/events/schemas/index.d.ts +2 -2
- package/dist/features/faq/actions/faq-actions.d.ts +6 -6
- package/dist/features/faq/schemas/index.d.ts +6 -6
- package/dist/features/grouped/schemas/grouped-listing-form.d.ts +101 -0
- package/dist/features/grouped/schemas/grouped-listing-form.js +89 -0
- package/dist/features/grouped/schemas/index.d.ts +4 -4
- package/dist/features/homepage/actions/homepage-section-actions.d.ts +11 -3
- package/dist/features/homepage/actions/homepage-section-actions.js +33 -1
- package/dist/features/homepage/schemas/index.d.ts +71 -40
- package/dist/features/homepage/schemas/index.js +24 -0
- package/dist/features/messages/schemas/index.d.ts +2 -2
- package/dist/features/orders/components/OrderStatusTimeline.d.ts +5 -1
- package/dist/features/orders/components/OrderStatusTimeline.js +39 -20
- package/dist/features/orders/repository/orders.repository.js +5 -0
- package/dist/features/orders/schemas/firestore.d.ts +36 -1
- package/dist/features/orders/schemas/index.d.ts +24 -24
- package/dist/features/orders/types/index.d.ts +35 -7
- package/dist/features/pre-orders/schemas/index.d.ts +4 -4
- package/dist/features/products/components/GroupSettingsPanel.js +5 -1
- package/dist/features/products/schemas/index.d.ts +38 -38
- package/dist/features/products/schemas/product-features.validators.d.ts +75 -2
- package/dist/features/products/schemas/product-features.validators.js +63 -0
- package/dist/features/promotions/schemas/index.d.ts +14 -14
- package/dist/features/reviews/schemas/index.d.ts +14 -14
- package/dist/features/scams/constants/scammer-status-display.d.ts +28 -0
- package/dist/features/scams/constants/scammer-status-display.js +79 -0
- package/dist/features/scams/schemas/index.d.ts +2 -2
- package/dist/features/search/schemas/index.d.ts +2 -2
- package/dist/features/seller/actions/offer-actions.js +32 -2
- package/dist/features/seller/components/OfferPhaseTimeline.d.ts +59 -0
- package/dist/features/seller/components/OfferPhaseTimeline.js +107 -0
- package/dist/features/seller/components/SellerBidsView.js +11 -4
- package/dist/features/seller/components/SellerCouponEditorView.js +17 -17
- package/dist/features/seller/components/SellerOffersView.js +2 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +38 -14
- package/dist/features/seller/repository/offer.repository.d.ts +69 -8
- package/dist/features/seller/repository/offer.repository.js +127 -23
- package/dist/features/seller/schemas/coupon-form.d.ts +72 -0
- package/dist/features/seller/schemas/coupon-form.js +116 -0
- package/dist/features/seller/schemas/firestore.d.ts +56 -2
- package/dist/features/seller/schemas/firestore.js +27 -0
- package/dist/features/seller/schemas/index.d.ts +2 -2
- package/dist/features/seller/schemas/offer-forms.d.ts +21 -0
- package/dist/features/seller/schemas/offer-forms.js +21 -0
- package/dist/features/shell/build-sections.d.ts +63 -0
- package/dist/features/shell/build-sections.js +207 -0
- package/dist/features/shell/field-ui-meta.d.ts +115 -0
- package/dist/features/shell/field-ui-meta.js +324 -0
- package/dist/features/shell/index.d.ts +4 -0
- package/dist/features/shell/index.js +2 -0
- package/dist/features/shipments/schemas/validation.d.ts +22 -22
- package/dist/features/status-history/components/StatusTimeline.d.ts +74 -0
- package/dist/features/status-history/components/StatusTimeline.js +46 -0
- package/dist/features/status-history/index.d.ts +11 -0
- package/dist/features/status-history/index.js +10 -0
- package/dist/features/store-extensions/components/ReviewDecisionModal.d.ts +27 -0
- package/dist/features/store-extensions/components/ReviewDecisionModal.js +82 -0
- package/dist/features/store-extensions/index.d.ts +12 -0
- package/dist/features/store-extensions/index.js +12 -0
- package/dist/features/store-extensions/schemas/admin-notification-form.d.ts +36 -0
- package/dist/features/store-extensions/schemas/admin-notification-form.js +114 -0
- package/dist/features/store-extensions/schemas/analytics-forms.d.ts +57 -0
- package/dist/features/store-extensions/schemas/analytics-forms.js +158 -0
- package/dist/features/store-extensions/schemas/custom-role-form.d.ts +85 -0
- package/dist/features/store-extensions/schemas/custom-role-form.js +118 -0
- package/dist/features/store-extensions/schemas/firestore.d.ts +21 -1
- package/dist/features/store-extensions/schemas/firestore.js +60 -0
- package/dist/features/store-extensions/schemas/google-config-form.d.ts +53 -0
- package/dist/features/store-extensions/schemas/google-config-form.js +105 -0
- package/dist/features/store-extensions/schemas/item-request-create-form.d.ts +28 -0
- package/dist/features/store-extensions/schemas/item-request-create-form.js +80 -0
- package/dist/features/store-extensions/schemas/listing-template-form.d.ts +78 -0
- package/dist/features/store-extensions/schemas/listing-template-form.js +87 -0
- package/dist/features/store-extensions/schemas/moderation-review-form.d.ts +49 -0
- package/dist/features/store-extensions/schemas/moderation-review-form.js +101 -0
- package/dist/features/store-extensions/schemas/payout-method-form.d.ts +153 -0
- package/dist/features/store-extensions/schemas/payout-method-form.js +155 -0
- package/dist/features/store-extensions/schemas/report-create-form.d.ts +25 -0
- package/dist/features/store-extensions/schemas/report-create-form.js +79 -0
- package/dist/features/store-extensions/schemas/report-review-form.d.ts +47 -0
- package/dist/features/store-extensions/schemas/report-review-form.js +111 -0
- package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +148 -0
- package/dist/features/store-extensions/schemas/shipping-config-form.js +104 -0
- package/dist/features/store-extensions/schemas/store-category-form.d.ts +54 -0
- package/dist/features/store-extensions/schemas/store-category-form.js +73 -0
- package/dist/features/stores/schemas/index.d.ts +4 -4
- package/dist/features/support/schemas/index.d.ts +4 -4
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +350 -0
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- package/dist/index.d.ts +12 -2
- package/dist/index.js +12 -2
- package/dist/next/routing/route-map.d.ts +16 -2
- package/dist/next/routing/route-map.js +9 -2
- package/dist/schemas/firestore-value.d.ts +8 -0
- package/dist/schemas/firestore-value.js +44 -0
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/index.js +1 -1
- package/dist/schemas/registry.d.ts +734 -101
- package/dist/schemas/registry.js +64 -1
- package/dist/seed/bids-seed-data.js +30 -0
- package/dist/seed/offers-seed-data.js +212 -7
- package/dist/seed/orders-seed-data.js +336 -1
- package/dist/seed/products-auctions-seed-data.js +41 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +5 -0
- package/dist/styles.css +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/DataTable.js +4 -2
- package/dist/ui/columns/build-columns.d.ts +6 -1
- package/dist/ui/columns/build-columns.js +53 -0
- package/dist/ui/columns/cell-renderers.d.ts +68 -0
- package/dist/ui/columns/cell-renderers.js +111 -0
- package/dist/ui/columns/column-renderers.d.ts +6 -1
- package/dist/ui/columns/column-renderers.js +6 -1
- package/dist/ui/columns/index.d.ts +2 -1
- package/dist/ui/columns/index.js +5 -1
- package/dist/ui/components/Button.js +27 -2
- package/dist/ui/components/RecordDetailModal.d.ts +10 -1
- package/dist/ui/components/RecordDetailModal.js +2 -2
- package/dist/ui/icons/icon-registry.d.ts +65 -0
- package/dist/ui/icons/icon-registry.js +115 -0
- package/package.json +2 -1
- package/scripts/node-esm-loader.mjs +65 -0
- package/scripts/seed-cli-loader.mjs +6 -49
- package/scripts/seed-cli.mjs +1 -1
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { normalizeError } from "../../../errors/normalize";
|
|
4
4
|
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
5
|
-
import React, { useEffect
|
|
6
|
-
import { z } from "zod";
|
|
5
|
+
import React, { useEffect } from "react";
|
|
7
6
|
import { useQuery } from "@tanstack/react-query";
|
|
8
7
|
import { Alert, Button, Div, Grid, Heading, Input, Label, RichTextEditor, Row, Select, Stack, StackedViewShell, TagInput, Text, Textarea, Toggle, } from "../../../ui";
|
|
9
8
|
import { FormShellContext, useFormShellState, applyZodIssues, FormErrorSummary } from "../../../ui/forms";
|
|
10
9
|
import { apiClient } from "../../../http";
|
|
11
10
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
12
|
-
import {
|
|
11
|
+
import { SectionForm, useSectionFormNav } from "../../shell";
|
|
12
|
+
import { eventDraftSchema } from "../schemas/event-form";
|
|
13
13
|
import { ProductInlineSelect } from "../../seller/components/ProductInlineSelect";
|
|
14
14
|
import { CouponInlineSelect } from "../../seller/components/CouponInlineSelect";
|
|
15
15
|
// Covers the cross-type required fields plus the two conditional rules the
|
|
@@ -19,27 +19,6 @@ import { CouponInlineSelect } from "../../seller/components/CouponInlineSelect";
|
|
|
19
19
|
// form-builder arrays, raffle/spin config) are deliberately left unvalidated
|
|
20
20
|
// — modeling their full conditional shape correctly would need much deeper
|
|
21
21
|
// per-type domain rules than this pass is scoped for.
|
|
22
|
-
const eventDraftSchema = z.object({
|
|
23
|
-
type: z.string(),
|
|
24
|
-
title: z.string().min(1, "Title is required"),
|
|
25
|
-
startsAt: z.string().min(1, "Start date is required"),
|
|
26
|
-
endsAt: z.string().min(1, "End date is required"),
|
|
27
|
-
couponId: z.string(),
|
|
28
|
-
displayCode: z.string(),
|
|
29
|
-
pollOptions: z.array(z.object({ id: z.string(), label: z.string() })),
|
|
30
|
-
}).passthrough().superRefine((v, ctx) => {
|
|
31
|
-
if (v.type === "offer") {
|
|
32
|
-
if (!v.couponId.trim()) {
|
|
33
|
-
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["couponId"], message: "Coupon is required for offer events" });
|
|
34
|
-
}
|
|
35
|
-
if (!v.displayCode.trim()) {
|
|
36
|
-
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["displayCode"], message: "Display code is required for offer events" });
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (v.type === "poll" && v.pollOptions.filter((o) => o.label.trim()).length < 2) {
|
|
40
|
-
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["pollOptions"], message: "Poll events require at least 2 options" });
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
22
|
const __P = {
|
|
44
23
|
p4: "p-[var(--appkit-space-4)]",
|
|
45
24
|
};
|
|
@@ -226,7 +205,6 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, allowedTypes,
|
|
|
226
205
|
const isEdit = Boolean(eventId);
|
|
227
206
|
const [draft, setDraft] = React.useState(DEFAULT_DRAFT);
|
|
228
207
|
const [slugManual, setSlugManual] = React.useState(false);
|
|
229
|
-
const [currentStep, setCurrentStep] = React.useState(0);
|
|
230
208
|
const [saveMessage, setSaveMessage] = React.useState(null);
|
|
231
209
|
const [triggerMessage, setTriggerMessage] = React.useState(null);
|
|
232
210
|
const [raffleWinnerName, setRaffleWinnerName] = React.useState("");
|
|
@@ -358,44 +336,49 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, allowedTypes,
|
|
|
358
336
|
});
|
|
359
337
|
const isLoading = saveMutation.isPending || eventQuery.isLoading;
|
|
360
338
|
// --- steps ---
|
|
361
|
-
|
|
339
|
+
/**
|
|
340
|
+
* Sections, not steps — every field reachable at once, one submit at the
|
|
341
|
+
* bottom. The old wizard gated Settings behind Details validating, so a
|
|
342
|
+
* missing end date made an event's poll options unreachable.
|
|
343
|
+
*
|
|
344
|
+
* Ids match the schema's `section` annotations exactly, which is what lets
|
|
345
|
+
* `<FormErrorSummary>` jump to the right panel.
|
|
346
|
+
*/
|
|
347
|
+
const sections = [
|
|
362
348
|
{
|
|
349
|
+
id: "details",
|
|
350
|
+
required: true,
|
|
351
|
+
quick: true,
|
|
363
352
|
label: "Details",
|
|
364
353
|
fields: ["type", "title", "slug", "description", "startsAt", "endsAt", "tags"],
|
|
365
|
-
validate:
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
if (!values.startsAt)
|
|
369
|
-
return "Start date is required";
|
|
370
|
-
if (!values.endsAt)
|
|
371
|
-
return "End date is required";
|
|
372
|
-
return null;
|
|
373
|
-
},
|
|
354
|
+
// The per-step `validate` is gone: every rule it stated is already in
|
|
355
|
+
// eventDraftSchema (title/startsAt/endsAt are .min(1)), and it only ever
|
|
356
|
+
// acted as a gate to the next step.
|
|
374
357
|
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: allowedTypes ? EVENT_TYPE_OPTIONS.filter((o) => allowedTypes.includes(o.value)) : EVENT_TYPE_OPTIONS, onChange: (e) => onChange({ type: e.target.value }) })), _jsx(Input, { label: "Title", value: values.title, onChange: (e) => {
|
|
375
358
|
const v = e.target.value;
|
|
376
359
|
onChange({ title: v, ...(!slugManual && { slug: toEventSlug(v) }) });
|
|
377
360
|
}, 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" })] })),
|
|
378
361
|
},
|
|
379
362
|
{
|
|
363
|
+
id: "media",
|
|
380
364
|
label: "Media",
|
|
365
|
+
// <Collapse> unmounts its children — without this, collapsing the
|
|
366
|
+
// section mid-upload discards the transfer.
|
|
367
|
+
keepMounted: true,
|
|
381
368
|
fields: ["coverImageUrl"],
|
|
382
369
|
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." })] })),
|
|
383
370
|
},
|
|
384
371
|
{
|
|
372
|
+
id: "settings",
|
|
385
373
|
label: "Settings",
|
|
386
374
|
fields: ["status", "allowGuestParticipation", "discountPercent", "saleBannerText", "couponId", "displayCode", "offerBannerText", "pollOptions", "resultsVisibility", "allowMultiSelect", "allowComment", "maxEntriesPerUser", "hasLeaderboard", "hasPointSystem", "pointsLabel", "entryReviewRequired", "surveyFields", "anonymous", "feedbackFields"],
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
if (values.type === "offer" && !values.displayCode.trim())
|
|
391
|
-
return "Display code is required for offer events";
|
|
392
|
-
if (values.type === "poll" && values.pollOptions.filter((o) => o.label.trim()).length < 2)
|
|
393
|
-
return "Poll events require at least 2 options";
|
|
394
|
-
return null;
|
|
395
|
-
},
|
|
375
|
+
// Same: the offer-coupon, offer-display-code and poll-minimum-options
|
|
376
|
+
// rules are all stated in eventDraftSchema's superRefine, which now
|
|
377
|
+
// surfaces them inline on the field instead of as a step-blocking banner.
|
|
396
378
|
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 })] })), _jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "sm", children: [_jsx(Toggle, { checked: values.allowGuestParticipation, onChange: (v) => onChange({ allowGuestParticipation: v }), label: "Allow guest participation (no login required)" }), _jsx(Text, { size: "xs", color: "muted", children: "When enabled, unauthenticated visitors can participate in this event (poll vote, survey/feedback response, raffle entry, or wheel spin), identified by a hashed IP address instead of an account. Applies uniformly to whatever entry mechanism this event type uses." })] }), 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: [_jsxs(Div, { children: [_jsx(Text, { size: "sm", weight: "medium", className: "mb-1", children: "Coupon" }), _jsx(CouponInlineSelect, { scope: "admin", value: values.couponId, onChange: (id) => onChange({ couponId: id ?? "" }), placeholder: "Search coupons\u2026", allowCreate: false })] }), _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, { variant: "ghost", type: "button", onClick: () => onChange({ pollOptions: values.pollOptions.filter((o) => o.id !== opt.id) }), className: CLS_REMOVE_BTN_PX2, "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 }) })] }))] })),
|
|
397
379
|
},
|
|
398
380
|
{
|
|
381
|
+
id: "raffle",
|
|
399
382
|
label: "Raffle / Spin",
|
|
400
383
|
fields: ["hasRaffle", "raffleType", "raffleTopN", "rafflePrize", "rafflePrizeCouponId", "rafflePrizeProductIds", "spinPrizes", "spinMaxPerUser", "spinWindowStart", "spinWindowEnd"],
|
|
401
384
|
render: ({ values, onChange }) => {
|
|
@@ -407,16 +390,11 @@ export function AdminEventEditorView({ eventId, onSaved, embedded, allowedTypes,
|
|
|
407
390
|
},
|
|
408
391
|
];
|
|
409
392
|
const alertSection = eventQuery.error ? (_jsx(Alert, { variant: "error", title: "Could not load event", children: eventQuery.error instanceof Error ? eventQuery.error.message : "Unknown error" })) : null;
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
return map;
|
|
416
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
417
|
-
}, [steps.length]);
|
|
418
|
-
const wizardShellCtx = useMemo(() => ({ ...shellCtx, fieldToStepIndex, goToStep: (n) => setCurrentStep(n) }), [shellCtx, fieldToStepIndex, setCurrentStep]);
|
|
419
|
-
const formContent = (_jsxs(Stack, { gap: "sm", children: [alertSection, _jsxs(FormShellContext.Provider, { value: wizardShellCtx, children: [_jsx(FormErrorSummary, {}), _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 }))] }));
|
|
393
|
+
// Replaces the hand-rolled fieldToStepIndex + goToStep pair. The hook owns
|
|
394
|
+
// the expand-then-scroll ordering a raw setState cannot: a collapsed panel
|
|
395
|
+
// must MOUNT before scrollIntoView and focus can reach the offending field.
|
|
396
|
+
const { openIds, setOpenIds, goToSection, fieldToSectionIndex, sectionMeta } = useSectionFormNav(sections, draft);
|
|
397
|
+
const formContent = (_jsxs(Stack, { gap: "sm", children: [alertSection, _jsxs(FormShellContext.Provider, { value: shellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(SectionForm, { sections: sections, values: draft, onChange: update, onSubmit: () => { saveMutation.mutate(); }, schema: eventDraftSchema, openIds: openIds, onOpenChange: setOpenIds, submitLabel: 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 }))] }));
|
|
420
398
|
if (embedded) {
|
|
421
399
|
return _jsx(Div, { className: `${__O.yAuto} ${__P.p4}`, children: formContent });
|
|
422
400
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useApiMutation, sieveFilter, SIEVE_OP, sortBy } from "@mohasinac/appkit/client";
|
|
4
|
-
import React from "react";
|
|
4
|
+
import React, { useState } from "react";
|
|
5
5
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
6
|
-
import { Alert, Button, Div, Input, Row, Select, Stack, Text, useToast } from "../../../ui";
|
|
6
|
+
import { Alert, Button, Div, Input, Row, Select, Stack, Text, useToast, RecordDetailModal, } from "../../../ui";
|
|
7
7
|
import { apiClient } from "../../../http";
|
|
8
8
|
import { normalizeError } from "../../../errors/normalize";
|
|
9
9
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
@@ -128,6 +128,10 @@ export function AdminEventEntriesView({ eventId, entriesEndpoint, entryReviewEnd
|
|
|
128
128
|
},
|
|
129
129
|
];
|
|
130
130
|
const eventTitle = statsQuery.data?.event?.title;
|
|
131
|
+
// Approve / Waitlist / Cancel were offered on an entry the admin could never
|
|
132
|
+
// read — the poll vote, the comment and the survey answers were all invisible
|
|
133
|
+
// (Root Cause #56, "acting blind"). The row already carries the whole entry.
|
|
134
|
+
const [detail, setDetail] = useState(null);
|
|
131
135
|
const config = {
|
|
132
136
|
portal: "admin",
|
|
133
137
|
title: eventTitle ? `${eventTitle} Entries` : "Event Entries",
|
|
@@ -139,6 +143,7 @@ export function AdminEventEntriesView({ eventId, entriesEndpoint, entryReviewEnd
|
|
|
139
143
|
endpoint: resolvedEntriesEndpoint,
|
|
140
144
|
sortOptions: [{ value: sortBy("submittedAt", "DESC"), label: "Most recent" }],
|
|
141
145
|
columns,
|
|
146
|
+
onRowClick: (row) => setDetail(row),
|
|
142
147
|
mapRows: (response) => response.items ?? [],
|
|
143
148
|
getTotal: (response) => response.total ?? (response.items ?? []).length,
|
|
144
149
|
buildFilters: (state) => state.reviewStatus ? sieveFilter("reviewStatus", SIEVE_OP.EQ, state.reviewStatus) : undefined,
|
|
@@ -146,5 +151,19 @@ export function AdminEventEntriesView({ eventId, entriesEndpoint, entryReviewEnd
|
|
|
146
151
|
toolbarExtra: eventId ? (_jsx(Button, { variant: "ghost", action: ACTIONS.ADMIN["export-event-entries"], onClick: handleExportReport })) : undefined,
|
|
147
152
|
renderAboveContent: () => (_jsxs(Stack, { gap: "3", className: "px-[var(--appkit-space-3)] pb-[var(--appkit-space-2)]", children: [!eventId ? (_jsx(Alert, { variant: "warning", title: "Missing event id", children: "Event id is required to load entries." })) : null, statsQuery.error ? (_jsx(Alert, { variant: "error", title: "Could not load event stats", children: statsQuery.error instanceof Error ? statsQuery.error.message : "Unknown error" })) : null, _jsxs(Div, { layout: "grid", gap: "3", className: "grid-cols-1 sm:grid-cols-3", children: [_jsx(Alert, { variant: "info", title: "Total entries", children: String(statsQuery.data?.stats?.totalEntries ?? 0) }), _jsx(Alert, { variant: "success", title: "Approved", children: String(statsQuery.data?.stats?.approvedEntries ?? 0) }), _jsx(Alert, { variant: "warning", title: "Flagged", children: String(statsQuery.data?.stats?.flaggedEntries ?? 0) })] })] })),
|
|
148
153
|
};
|
|
149
|
-
return _jsx(DataListingView, { config: config })
|
|
154
|
+
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(RecordDetailModal, { isOpen: detail !== null, onClose: () => setDetail(null), title: detail?.userDisplayName || detail?.userEmail || "Entry", badges: detail ? [{ label: detail.reviewStatus }] : undefined, description: detail?.pollComment, fields: detail
|
|
155
|
+
? [
|
|
156
|
+
{ label: "Entrant", value: detail.userDisplayName ?? detail.userId ?? "—" },
|
|
157
|
+
{ label: "Email", value: detail.userEmail ?? "—" },
|
|
158
|
+
{ label: "Review status", value: detail.reviewStatus },
|
|
159
|
+
{ label: "Points", value: detail.points != null ? String(detail.points) : "—" },
|
|
160
|
+
{ label: "Raffle eligible", value: detail.raffleEligible ? "Yes" : "No" },
|
|
161
|
+
{ label: "Poll votes", value: detail.pollVotes?.join(", ") || "—" },
|
|
162
|
+
{ label: "Reviewed by", value: detail.reviewedBy ?? "—" },
|
|
163
|
+
{ label: "Review note", value: detail.reviewNote ?? "—" },
|
|
164
|
+
{ label: "Entry ID", value: detail.id },
|
|
165
|
+
]
|
|
166
|
+
: undefined,
|
|
167
|
+
// The survey/feedback answers — the actual submission being judged.
|
|
168
|
+
metadata: detail?.formResponses })] }));
|
|
150
169
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* ## `.passthrough()` STAYS here, deliberately
|
|
4
|
+
*
|
|
5
|
+
* `EventDraft` carries ~40 fields; this schema names seven. The blog form's
|
|
6
|
+
* equivalent was safe to tighten because its draft had fourteen fields and all
|
|
7
|
+
* fourteen could be named in one sitting. This one cannot: most of its fields
|
|
8
|
+
* are per-event-type (poll options, survey fields, spin prizes, raffle config)
|
|
9
|
+
* and only apply under a `type` discriminator, so naming them correctly means
|
|
10
|
+
* modelling the discriminated union rather than listing keys.
|
|
11
|
+
*
|
|
12
|
+
* Tightening it blind is the single most dangerous edit available in this
|
|
13
|
+
* codebase — `z.object()` strips unknown keys, so every field this schema
|
|
14
|
+
* failed to name would vanish from the draft the moment passthrough came off.
|
|
15
|
+
* That is exactly how `productBaseSchema` came to eat every `classified*` /
|
|
16
|
+
* `digitalCode*` / `liveItem*` / `prize*` field.
|
|
17
|
+
*
|
|
18
|
+
* The wire payload is NOT at risk either way: it is built explicitly below
|
|
19
|
+
* (`type`, `title`, `slug`, … plus `buildEventTypeConfig` /
|
|
20
|
+
* `buildEventRaffleFields`), never by spreading the draft.
|
|
21
|
+
*
|
|
22
|
+
* Prerequisite for removing it: a FULL-collection `roundtrip-diff --entity
|
|
23
|
+
* event --full`, not a sample — per the data-integrity protocol.
|
|
24
|
+
*
|
|
25
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
26
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
27
|
+
*/
|
|
28
|
+
export declare const eventDraftSchema: z.ZodEffects<z.ZodObject<{
|
|
29
|
+
type: z.ZodString;
|
|
30
|
+
title: z.ZodString;
|
|
31
|
+
startsAt: z.ZodString;
|
|
32
|
+
endsAt: z.ZodString;
|
|
33
|
+
couponId: z.ZodString;
|
|
34
|
+
displayCode: z.ZodString;
|
|
35
|
+
pollOptions: z.ZodArray<z.ZodObject<{
|
|
36
|
+
id: z.ZodString;
|
|
37
|
+
label: z.ZodString;
|
|
38
|
+
}, "strip", z.ZodTypeAny, {
|
|
39
|
+
id: string;
|
|
40
|
+
label: string;
|
|
41
|
+
}, {
|
|
42
|
+
id: string;
|
|
43
|
+
label: string;
|
|
44
|
+
}>, "many">;
|
|
45
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
46
|
+
type: z.ZodString;
|
|
47
|
+
title: z.ZodString;
|
|
48
|
+
startsAt: z.ZodString;
|
|
49
|
+
endsAt: z.ZodString;
|
|
50
|
+
couponId: z.ZodString;
|
|
51
|
+
displayCode: z.ZodString;
|
|
52
|
+
pollOptions: z.ZodArray<z.ZodObject<{
|
|
53
|
+
id: z.ZodString;
|
|
54
|
+
label: z.ZodString;
|
|
55
|
+
}, "strip", z.ZodTypeAny, {
|
|
56
|
+
id: string;
|
|
57
|
+
label: string;
|
|
58
|
+
}, {
|
|
59
|
+
id: string;
|
|
60
|
+
label: string;
|
|
61
|
+
}>, "many">;
|
|
62
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
63
|
+
type: z.ZodString;
|
|
64
|
+
title: z.ZodString;
|
|
65
|
+
startsAt: z.ZodString;
|
|
66
|
+
endsAt: z.ZodString;
|
|
67
|
+
couponId: z.ZodString;
|
|
68
|
+
displayCode: z.ZodString;
|
|
69
|
+
pollOptions: z.ZodArray<z.ZodObject<{
|
|
70
|
+
id: z.ZodString;
|
|
71
|
+
label: z.ZodString;
|
|
72
|
+
}, "strip", z.ZodTypeAny, {
|
|
73
|
+
id: string;
|
|
74
|
+
label: string;
|
|
75
|
+
}, {
|
|
76
|
+
id: string;
|
|
77
|
+
label: string;
|
|
78
|
+
}>, "many">;
|
|
79
|
+
}, z.ZodTypeAny, "passthrough">>, z.objectOutputType<{
|
|
80
|
+
type: z.ZodString;
|
|
81
|
+
title: z.ZodString;
|
|
82
|
+
startsAt: z.ZodString;
|
|
83
|
+
endsAt: z.ZodString;
|
|
84
|
+
couponId: z.ZodString;
|
|
85
|
+
displayCode: z.ZodString;
|
|
86
|
+
pollOptions: z.ZodArray<z.ZodObject<{
|
|
87
|
+
id: z.ZodString;
|
|
88
|
+
label: z.ZodString;
|
|
89
|
+
}, "strip", z.ZodTypeAny, {
|
|
90
|
+
id: string;
|
|
91
|
+
label: string;
|
|
92
|
+
}, {
|
|
93
|
+
id: string;
|
|
94
|
+
label: string;
|
|
95
|
+
}>, "many">;
|
|
96
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
97
|
+
type: z.ZodString;
|
|
98
|
+
title: z.ZodString;
|
|
99
|
+
startsAt: z.ZodString;
|
|
100
|
+
endsAt: z.ZodString;
|
|
101
|
+
couponId: z.ZodString;
|
|
102
|
+
displayCode: z.ZodString;
|
|
103
|
+
pollOptions: z.ZodArray<z.ZodObject<{
|
|
104
|
+
id: z.ZodString;
|
|
105
|
+
label: z.ZodString;
|
|
106
|
+
}, "strip", z.ZodTypeAny, {
|
|
107
|
+
id: string;
|
|
108
|
+
label: string;
|
|
109
|
+
}, {
|
|
110
|
+
id: string;
|
|
111
|
+
label: string;
|
|
112
|
+
}>, "many">;
|
|
113
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: Same reason as the blog form schema — keeping it in the `.tsx` view
|
|
3
|
+
* would have dragged a React component tree into every API route through
|
|
4
|
+
* `SCHEMAS` -> `routeHandler`.
|
|
5
|
+
* WHAT: The event editor's form schema, with its UI metadata.
|
|
6
|
+
*
|
|
7
|
+
* EXPORTS:
|
|
8
|
+
* eventDraftSchema
|
|
9
|
+
*
|
|
10
|
+
* @tag domain:events
|
|
11
|
+
* @tag layer:schema
|
|
12
|
+
* @tag pattern:none
|
|
13
|
+
* @tag access:isomorphic
|
|
14
|
+
* @tag consumers:AdminEventEditorView,SCHEMAS.forms
|
|
15
|
+
* @tag sideEffects:none
|
|
16
|
+
*/
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
import { annotate } from "../../shell/field-ui-meta";
|
|
19
|
+
/**
|
|
20
|
+
* ## `.passthrough()` STAYS here, deliberately
|
|
21
|
+
*
|
|
22
|
+
* `EventDraft` carries ~40 fields; this schema names seven. The blog form's
|
|
23
|
+
* equivalent was safe to tighten because its draft had fourteen fields and all
|
|
24
|
+
* fourteen could be named in one sitting. This one cannot: most of its fields
|
|
25
|
+
* are per-event-type (poll options, survey fields, spin prizes, raffle config)
|
|
26
|
+
* and only apply under a `type` discriminator, so naming them correctly means
|
|
27
|
+
* modelling the discriminated union rather than listing keys.
|
|
28
|
+
*
|
|
29
|
+
* Tightening it blind is the single most dangerous edit available in this
|
|
30
|
+
* codebase — `z.object()` strips unknown keys, so every field this schema
|
|
31
|
+
* failed to name would vanish from the draft the moment passthrough came off.
|
|
32
|
+
* That is exactly how `productBaseSchema` came to eat every `classified*` /
|
|
33
|
+
* `digitalCode*` / `liveItem*` / `prize*` field.
|
|
34
|
+
*
|
|
35
|
+
* The wire payload is NOT at risk either way: it is built explicitly below
|
|
36
|
+
* (`type`, `title`, `slug`, … plus `buildEventTypeConfig` /
|
|
37
|
+
* `buildEventRaffleFields`), never by spreading the draft.
|
|
38
|
+
*
|
|
39
|
+
* Prerequisite for removing it: a FULL-collection `roundtrip-diff --entity
|
|
40
|
+
* event --full`, not a sample — per the data-integrity protocol.
|
|
41
|
+
*
|
|
42
|
+
* 🛑 `annotate()` must be the OUTERMOST call on each field — it keys a WeakMap
|
|
43
|
+
* by schema instance and every zod wrapper returns a new one.
|
|
44
|
+
*/
|
|
45
|
+
export const eventDraftSchema = z.object({
|
|
46
|
+
type: annotate(z.string(), {
|
|
47
|
+
section: "details", sectionLabel: "Details", sectionRequired: true,
|
|
48
|
+
quick: true, order: 1, row: "pair", kind: "select",
|
|
49
|
+
}),
|
|
50
|
+
title: annotate(z.string().min(1, "Title is required"), {
|
|
51
|
+
section: "details", quick: true, order: 2, row: "full",
|
|
52
|
+
}),
|
|
53
|
+
startsAt: annotate(z.string().min(1, "Start date is required"), {
|
|
54
|
+
section: "details", quick: true, order: 3, row: "pair", kind: "date",
|
|
55
|
+
}),
|
|
56
|
+
endsAt: annotate(z.string().min(1, "End date is required"), {
|
|
57
|
+
section: "details", quick: true, order: 4, row: "pair", kind: "date",
|
|
58
|
+
}),
|
|
59
|
+
couponId: annotate(z.string(), {
|
|
60
|
+
section: "settings", sectionLabel: "Settings", order: 1, row: "pair",
|
|
61
|
+
help: "Required for offer events.",
|
|
62
|
+
}),
|
|
63
|
+
displayCode: annotate(z.string(), {
|
|
64
|
+
section: "settings", order: 2, row: "pair",
|
|
65
|
+
help: "Required for offer events.",
|
|
66
|
+
}),
|
|
67
|
+
pollOptions: annotate(z.array(z.object({ id: z.string(), label: z.string() })), {
|
|
68
|
+
section: "settings", order: 3, row: "full", kind: "list",
|
|
69
|
+
}),
|
|
70
|
+
}).passthrough().superRefine((v, ctx) => {
|
|
71
|
+
if (v.type === "offer") {
|
|
72
|
+
if (!v.couponId.trim()) {
|
|
73
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["couponId"], message: "Coupon is required for offer events" });
|
|
74
|
+
}
|
|
75
|
+
if (!v.displayCode.trim()) {
|
|
76
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["displayCode"], message: "Display code is required for offer events" });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (v.type === "poll" && v.pollOptions.filter((o) => o.label.trim()).length < 2) {
|
|
80
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["pollOptions"], message: "Poll events require at least 2 options" });
|
|
81
|
+
}
|
|
82
|
+
});
|
|
@@ -943,10 +943,10 @@ export declare const eventItemSchema: z.ZodObject<{
|
|
|
943
943
|
title: string;
|
|
944
944
|
createdAt: string;
|
|
945
945
|
updatedAt: string;
|
|
946
|
+
createdBy: string;
|
|
946
947
|
description: string;
|
|
947
948
|
startsAt: string;
|
|
948
949
|
endsAt: string;
|
|
949
|
-
createdBy: string;
|
|
950
950
|
stats: {
|
|
951
951
|
totalEntries: number;
|
|
952
952
|
approvedEntries: number;
|
|
@@ -1098,10 +1098,10 @@ export declare const eventItemSchema: z.ZodObject<{
|
|
|
1098
1098
|
title: string;
|
|
1099
1099
|
createdAt: string;
|
|
1100
1100
|
updatedAt: string;
|
|
1101
|
+
createdBy: string;
|
|
1101
1102
|
description: string;
|
|
1102
1103
|
startsAt: string;
|
|
1103
1104
|
endsAt: string;
|
|
1104
|
-
createdBy: string;
|
|
1105
1105
|
stats: {
|
|
1106
1106
|
totalEntries: number;
|
|
1107
1107
|
approvedEntries: number;
|
|
@@ -27,10 +27,10 @@ export declare const faqCreateSchema: z.ZodEffects<z.ZodObject<{
|
|
|
27
27
|
template: z.ZodOptional<z.ZodString>;
|
|
28
28
|
}, "strip", z.ZodTypeAny, {
|
|
29
29
|
category: string;
|
|
30
|
+
priority: number;
|
|
30
31
|
isActive: boolean;
|
|
31
32
|
order: number;
|
|
32
33
|
showOnHomepage: boolean;
|
|
33
|
-
priority: number;
|
|
34
34
|
question: string;
|
|
35
35
|
answer: {
|
|
36
36
|
text: string;
|
|
@@ -51,11 +51,11 @@ export declare const faqCreateSchema: z.ZodEffects<z.ZodObject<{
|
|
|
51
51
|
format?: "html" | "plain" | "markdown" | undefined;
|
|
52
52
|
};
|
|
53
53
|
template?: string | undefined;
|
|
54
|
+
priority?: number | undefined;
|
|
54
55
|
tags?: string[] | undefined;
|
|
55
56
|
isActive?: boolean | undefined;
|
|
56
57
|
order?: number | undefined;
|
|
57
58
|
showOnHomepage?: boolean | undefined;
|
|
58
|
-
priority?: number | undefined;
|
|
59
59
|
showInFooter?: boolean | undefined;
|
|
60
60
|
isPinned?: boolean | undefined;
|
|
61
61
|
relatedFAQs?: string[] | undefined;
|
|
@@ -63,10 +63,10 @@ export declare const faqCreateSchema: z.ZodEffects<z.ZodObject<{
|
|
|
63
63
|
variables?: Record<string, string> | undefined;
|
|
64
64
|
}>, {
|
|
65
65
|
category: string;
|
|
66
|
+
priority: number;
|
|
66
67
|
isActive: boolean;
|
|
67
68
|
order: number;
|
|
68
69
|
showOnHomepage: boolean;
|
|
69
|
-
priority: number;
|
|
70
70
|
question: string;
|
|
71
71
|
answer: {
|
|
72
72
|
text: string;
|
|
@@ -87,11 +87,11 @@ export declare const faqCreateSchema: z.ZodEffects<z.ZodObject<{
|
|
|
87
87
|
format?: "html" | "plain" | "markdown" | undefined;
|
|
88
88
|
};
|
|
89
89
|
template?: string | undefined;
|
|
90
|
+
priority?: number | undefined;
|
|
90
91
|
tags?: string[] | undefined;
|
|
91
92
|
isActive?: boolean | undefined;
|
|
92
93
|
order?: number | undefined;
|
|
93
94
|
showOnHomepage?: boolean | undefined;
|
|
94
|
-
priority?: number | undefined;
|
|
95
95
|
showInFooter?: boolean | undefined;
|
|
96
96
|
isPinned?: boolean | undefined;
|
|
97
97
|
relatedFAQs?: string[] | undefined;
|
|
@@ -125,11 +125,11 @@ export declare const faqUpdateSchema: z.ZodObject<{
|
|
|
125
125
|
}, "strip", z.ZodTypeAny, {
|
|
126
126
|
template?: string | undefined;
|
|
127
127
|
category?: string | undefined;
|
|
128
|
+
priority?: number | undefined;
|
|
128
129
|
tags?: string[] | undefined;
|
|
129
130
|
isActive?: boolean | undefined;
|
|
130
131
|
order?: number | undefined;
|
|
131
132
|
showOnHomepage?: boolean | undefined;
|
|
132
|
-
priority?: number | undefined;
|
|
133
133
|
question?: string | undefined;
|
|
134
134
|
answer?: {
|
|
135
135
|
text: string;
|
|
@@ -143,11 +143,11 @@ export declare const faqUpdateSchema: z.ZodObject<{
|
|
|
143
143
|
}, {
|
|
144
144
|
template?: string | undefined;
|
|
145
145
|
category?: string | undefined;
|
|
146
|
+
priority?: number | undefined;
|
|
146
147
|
tags?: string[] | undefined;
|
|
147
148
|
isActive?: boolean | undefined;
|
|
148
149
|
order?: number | undefined;
|
|
149
150
|
showOnHomepage?: boolean | undefined;
|
|
150
|
-
priority?: number | undefined;
|
|
151
151
|
question?: string | undefined;
|
|
152
152
|
answer?: {
|
|
153
153
|
text: string;
|
|
@@ -91,6 +91,7 @@ export declare const faqSchema: z.ZodObject<{
|
|
|
91
91
|
};
|
|
92
92
|
createdAt?: string | undefined;
|
|
93
93
|
updatedAt?: string | undefined;
|
|
94
|
+
priority?: number | undefined;
|
|
94
95
|
tags?: string[] | undefined;
|
|
95
96
|
isActive?: boolean | undefined;
|
|
96
97
|
order?: number | undefined;
|
|
@@ -100,7 +101,6 @@ export declare const faqSchema: z.ZodObject<{
|
|
|
100
101
|
notHelpful?: number | undefined;
|
|
101
102
|
} | undefined;
|
|
102
103
|
showOnHomepage?: boolean | undefined;
|
|
103
|
-
priority?: number | undefined;
|
|
104
104
|
showInFooter?: boolean | undefined;
|
|
105
105
|
isPinned?: boolean | undefined;
|
|
106
106
|
relatedFAQs?: string[] | undefined;
|
|
@@ -117,6 +117,7 @@ export declare const faqSchema: z.ZodObject<{
|
|
|
117
117
|
};
|
|
118
118
|
createdAt?: string | undefined;
|
|
119
119
|
updatedAt?: string | undefined;
|
|
120
|
+
priority?: number | undefined;
|
|
120
121
|
tags?: string[] | undefined;
|
|
121
122
|
isActive?: boolean | undefined;
|
|
122
123
|
order?: number | undefined;
|
|
@@ -126,7 +127,6 @@ export declare const faqSchema: z.ZodObject<{
|
|
|
126
127
|
notHelpful?: number | undefined;
|
|
127
128
|
} | undefined;
|
|
128
129
|
showOnHomepage?: boolean | undefined;
|
|
129
|
-
priority?: number | undefined;
|
|
130
130
|
showInFooter?: boolean | undefined;
|
|
131
131
|
isPinned?: boolean | undefined;
|
|
132
132
|
relatedFAQs?: string[] | undefined;
|
|
@@ -282,10 +282,11 @@ export declare const faqFirestoreSchema: z.ZodObject<{
|
|
|
282
282
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
283
283
|
}, z.ZodTypeAny, "passthrough">;
|
|
284
284
|
category: "orders_payment" | "shipping_delivery" | "returns_refunds" | "product_information" | "account_security" | "technical_support" | "general";
|
|
285
|
+
createdBy: string;
|
|
286
|
+
priority: number;
|
|
285
287
|
tags: string[];
|
|
286
288
|
isActive: boolean;
|
|
287
289
|
order: number;
|
|
288
|
-
createdBy: string;
|
|
289
290
|
stats: {
|
|
290
291
|
views: number;
|
|
291
292
|
helpful: number;
|
|
@@ -295,7 +296,6 @@ export declare const faqFirestoreSchema: z.ZodObject<{
|
|
|
295
296
|
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
296
297
|
};
|
|
297
298
|
showOnHomepage: boolean;
|
|
298
|
-
priority: number;
|
|
299
299
|
question: string;
|
|
300
300
|
answer: {
|
|
301
301
|
text: string;
|
|
@@ -321,10 +321,11 @@ export declare const faqFirestoreSchema: z.ZodObject<{
|
|
|
321
321
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
322
322
|
}, z.ZodTypeAny, "passthrough">;
|
|
323
323
|
category: "orders_payment" | "shipping_delivery" | "returns_refunds" | "product_information" | "account_security" | "technical_support" | "general";
|
|
324
|
+
createdBy: string;
|
|
325
|
+
priority: number;
|
|
324
326
|
tags: string[];
|
|
325
327
|
isActive: boolean;
|
|
326
328
|
order: number;
|
|
327
|
-
createdBy: string;
|
|
328
329
|
stats: {
|
|
329
330
|
views: number;
|
|
330
331
|
helpful: number;
|
|
@@ -334,7 +335,6 @@ export declare const faqFirestoreSchema: z.ZodObject<{
|
|
|
334
335
|
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
335
336
|
};
|
|
336
337
|
showOnHomepage: boolean;
|
|
337
|
-
priority: number;
|
|
338
338
|
question: string;
|
|
339
339
|
answer: {
|
|
340
340
|
text: string;
|