@mohasinac/appkit 4.40.1 → 4.41.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/categories/repository/categories.repository.js +2 -2
- package/dist/features/shell/SectionForm.js +44 -5
- package/dist/features/tester/seed-data/_money-flows.js +65 -49
- package/dist/features/tester/seed-data/authored/admin__admin-detail-round-trips.js +6 -4
- package/dist/features/tester/seed-data/authored/admin__coupons.js +14 -13
- package/dist/features/tester/seed-data/authored/buying__bidding.js +154 -140
- package/dist/features/tester/seed-data/authored/buying__browsing-search.js +4 -4
- package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +59 -56
- package/dist/features/tester/seed-data/authored/buying__buying-coupons.js +18 -18
- package/dist/features/tester/seed-data/authored/buying__cart.js +105 -79
- package/dist/features/tester/seed-data/authored/buying__image-tile-layout.js +6 -8
- package/dist/features/tester/seed-data/authored/buying__my-orders.js +13 -13
- package/dist/features/tester/seed-data/authored/buying__offers.js +6 -6
- package/dist/features/tester/seed-data/authored/buying__order-detail-actions.js +8 -7
- package/dist/features/tester/seed-data/authored/buying__product-detail.js +62 -56
- package/dist/features/tester/seed-data/authored/buying__return-request.js +6 -6
- package/dist/features/tester/seed-data/authored/buying__reviews-pagination.js +4 -4
- package/dist/features/tester/seed-data/authored/buying__reviews.js +1 -1
- package/dist/features/tester/seed-data/authored/buying__user-dashboard-extras.js +8 -8
- package/dist/features/tester/seed-data/authored/content-discovery__category-counts-and-rollup.js +1 -1
- package/dist/features/tester/seed-data/authored/content-discovery__coupons.js +29 -16
- package/dist/features/tester/seed-data/authored/content-discovery__event-detail-subroutes.js +9 -9
- package/dist/features/tester/seed-data/authored/content-discovery__events.js +69 -36
- package/dist/features/tester/seed-data/authored/content-discovery__notifications.js +1 -1
- package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.js +2 -2
- package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.js +2 -2
- package/dist/features/tester/seed-data/authored/design-ux__general-design.js +1 -1
- package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.js +1 -1
- package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.js +3 -3
- package/dist/features/tester/seed-data/authored/index.js +0 -2
- package/dist/features/tester/seed-data/authored/page-wiring__data-loss.js +2 -2
- package/dist/features/tester/seed-data/authored/page-wiring__reachability.js +6 -4
- package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.js +2 -2
- package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.js +1 -1
- package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.js +8 -10
- package/dist/features/tester/seed-data/authored/selling__become-seller.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__digital-content-delivery.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__listing-a-product.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__listing-edit-roundtrip.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.js +2 -2
- package/dist/features/tester/seed-data/authored/selling__seller-listing-types.js +2 -2
- package/dist/features/tester/seed-data/authored/seo__og-images.js +3 -4
- package/dist/features/tester/seed-data/authored/seo__page-metadata.js +6 -8
- package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.js +5 -5
- package/dist/features/tester/seed-data/index.d.ts +0 -10
- package/dist/features/tester/seed-data/index.js +0 -10
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +75 -89
- package/dist/features/tester/seed-data/tester-responses-seed-data.js +5 -5
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -21
- package/dist/seed/addresses-seed-data.js +0 -34
- package/dist/seed/index.d.ts +1 -1
- package/dist/seed/index.js +4 -3
- package/dist/seed/manifest.js +11 -12
- package/dist/seed/notifications-seed-data.js +4 -4
- package/dist/seed/stores-seed-data.js +7 -52
- package/dist/seed/users-seed-data.js +3 -83
- package/package.json +2 -2
- package/scripts/seed-cli.mjs +15 -20
- package/dist/_internal/server/features/classified/actions.d.ts +0 -12
- package/dist/_internal/server/features/classified/actions.js +0 -33
- package/dist/_internal/server/features/digital-code/actions.d.ts +0 -12
- package/dist/_internal/server/features/digital-code/actions.js +0 -33
- package/dist/_internal/server/features/homepage/data.d.ts +0 -18
- package/dist/_internal/server/features/homepage/data.js +0 -70
- package/dist/_internal/server/features/live/actions.d.ts +0 -6
- package/dist/_internal/server/features/live/actions.js +0 -27
- package/dist/_internal/server/features/messages/actions.d.ts +0 -6
- package/dist/_internal/server/features/messages/actions.js +0 -6
- package/dist/_internal/server/features/messages/data.d.ts +0 -10
- package/dist/_internal/server/features/messages/data.js +0 -24
- package/dist/_internal/server/features/messages/index.d.ts +0 -2
- package/dist/_internal/server/features/messages/index.js +0 -2
- package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +0 -12
- package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +0 -112
- package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +0 -2
- package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +0 -2
- package/dist/_internal/shared/features/homepage/section-gate.d.ts +0 -14
- package/dist/_internal/shared/features/homepage/section-gate.js +0 -51
- package/dist/_internal/shared/features/lottery/config-form.d.ts +0 -58
- package/dist/_internal/shared/features/lottery/config-form.js +0 -71
- package/dist/client/api/useFeatureFlags.d.ts +0 -22
- package/dist/client/api/useFeatureFlags.js +0 -27
- package/dist/features/account/address-validation.d.ts +0 -20
- package/dist/features/account/address-validation.js +0 -35
- package/dist/features/account/components/ChatList.d.ts +0 -14
- package/dist/features/account/components/ChatList.js +0 -9
- package/dist/features/account/components/ChatWindow.d.ts +0 -17
- package/dist/features/account/components/ChatWindow.js +0 -6
- package/dist/features/account/components/MessagesView.d.ts +0 -16
- package/dist/features/account/components/MessagesView.js +0 -5
- package/dist/features/account/components/UserOffersView.d.ts +0 -10
- package/dist/features/account/components/UserOffersView.js +0 -5
- package/dist/features/account/constants/addresses.d.ts +0 -13
- package/dist/features/account/constants/addresses.js +0 -43
- package/dist/features/account/hooks/useAddressForm.d.ts +0 -24
- package/dist/features/account/hooks/useAddressForm.js +0 -58
- package/dist/features/admin/actions/chat-actions.d.ts +0 -29
- package/dist/features/admin/actions/chat-actions.js +0 -101
- package/dist/features/admin/components/AdminFeatureFlagsView.d.ts +0 -9
- package/dist/features/admin/components/AdminFeatureFlagsView.js +0 -109
- package/dist/features/admin/components/AdminSiteView.d.ts +0 -10
- package/dist/features/admin/components/AdminSiteView.js +0 -52
- package/dist/features/admin/hooks/useChat.d.ts +0 -24
- package/dist/features/admin/hooks/useChat.js +0 -100
- package/dist/features/admin/permission-map.d.ts +0 -3
- package/dist/features/admin/permission-map.js +0 -26
- package/dist/features/admin/repository/chat.repository.d.ts +0 -50
- package/dist/features/admin/repository/chat.repository.js +0 -223
- package/dist/features/auth/actions/password-change-otp-actions.d.ts +0 -18
- package/dist/features/auth/actions/password-change-otp-actions.js +0 -88
- package/dist/features/auth/actions/realtime-token-actions.d.ts +0 -11
- package/dist/features/auth/actions/realtime-token-actions.js +0 -38
- package/dist/features/auth/password-change-otp.d.ts +0 -34
- package/dist/features/auth/password-change-otp.js +0 -56
- package/dist/features/classified/components/ClassifiedContactSellerPanel.d.ts +0 -12
- package/dist/features/classified/components/ClassifiedContactSellerPanel.js +0 -49
- package/dist/features/events/api/route.d.ts +0 -12
- package/dist/features/events/api/route.js +0 -90
- package/dist/features/faq/api/route.d.ts +0 -11
- package/dist/features/faq/api/route.js +0 -52
- package/dist/features/faq/hooks/useFAQs.d.ts +0 -22
- package/dist/features/faq/hooks/useFAQs.js +0 -41
- package/dist/features/media/upload/video-poster.test.d.ts +0 -1
- package/dist/features/media/upload/video-poster.test.js +0 -42
- package/dist/features/messages/actions/index.d.ts +0 -2
- package/dist/features/messages/actions/index.js +0 -2
- package/dist/features/messages/actions/messages-actions.d.ts +0 -15
- package/dist/features/messages/actions/messages-actions.js +0 -33
- package/dist/features/messages/actions/ping-rtdb.d.ts +0 -2
- package/dist/features/messages/actions/ping-rtdb.js +0 -26
- package/dist/features/messages/hooks/useConversation.d.ts +0 -22
- package/dist/features/messages/hooks/useConversation.js +0 -155
- package/dist/features/messages/hooks/useConversations.d.ts +0 -15
- package/dist/features/messages/hooks/useConversations.js +0 -104
- package/dist/features/messages/index.d.ts +0 -6
- package/dist/features/messages/index.js +0 -4
- package/dist/features/messages/realtime.d.ts +0 -32
- package/dist/features/messages/realtime.js +0 -39
- package/dist/features/messages/repository/conversations.repository.d.ts +0 -71
- package/dist/features/messages/repository/conversations.repository.js +0 -284
- package/dist/features/messages/schemas/firestore.d.ts +0 -34
- package/dist/features/messages/schemas/firestore.js +0 -16
- package/dist/features/messages/schemas/index.d.ts +0 -177
- package/dist/features/messages/schemas/index.js +0 -35
- package/dist/features/messages/server.d.ts +0 -6
- package/dist/features/messages/server.js +0 -6
- package/dist/features/products/components/MakeOfferForm.d.ts +0 -20
- package/dist/features/products/components/MakeOfferForm.js +0 -9
- package/dist/features/reviews/api/route.d.ts +0 -21
- package/dist/features/reviews/api/route.js +0 -174
- package/dist/features/seller/api/offers/route.d.ts +0 -17
- package/dist/features/seller/api/offers/route.js +0 -63
- package/dist/features/seller/components/SellerAuctionsView.d.ts +0 -9
- package/dist/features/seller/components/SellerAuctionsView.js +0 -113
- package/dist/features/seller/components/SellerOffersPanel.d.ts +0 -21
- package/dist/features/seller/components/SellerOffersPanel.js +0 -160
- package/dist/features/seller/components/SellerPreOrdersView.d.ts +0 -6
- package/dist/features/seller/components/SellerPreOrdersView.js +0 -148
- package/dist/features/seller/components/SellerPrizeDrawsView.d.ts +0 -6
- package/dist/features/seller/components/SellerPrizeDrawsView.js +0 -152
- package/dist/features/seller/permission-map.d.ts +0 -5
- package/dist/features/seller/permission-map.js +0 -17
- package/dist/features/shell/StepForm.d.ts +0 -80
- package/dist/features/shell/StepForm.js +0 -136
- package/dist/features/stores/api/route.d.ts +0 -12
- package/dist/features/stores/api/route.js +0 -110
- package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.d.ts +0 -2
- package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.js +0 -33
- package/dist/features/tester/seed-data/authored/account-auth__testing-program.d.ts +0 -2
- package/dist/features/tester/seed-data/authored/account-auth__testing-program.js +0 -138
- package/dist/features/tester/seed-data/bids-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/bids-tester-seed-data.js +0 -37
- package/dist/features/tester/seed-data/blog-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/blog-tester-seed-data.js +0 -40
- package/dist/features/tester/seed-data/carts-tester-seed-data.d.ts +0 -3
- package/dist/features/tester/seed-data/carts-tester-seed-data.js +0 -70
- package/dist/features/tester/seed-data/categories-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/categories-tester-seed-data.js +0 -218
- package/dist/features/tester/seed-data/coupons-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/coupons-tester-seed-data.js +0 -76
- package/dist/features/tester/seed-data/events-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/events-tester-seed-data.js +0 -193
- package/dist/features/tester/seed-data/offers-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/offers-tester-seed-data.js +0 -191
- package/dist/features/tester/seed-data/orders-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/orders-tester-seed-data.js +0 -329
- package/dist/features/tester/seed-data/products-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/products-tester-seed-data.js +0 -815
- package/dist/features/tester/seed-data/stores-tester-seed-data.d.ts +0 -2
- package/dist/features/tester/seed-data/stores-tester-seed-data.js +0 -79
- package/dist/features/wishlist/components/WishlistToggleButton.d.ts +0 -12
- package/dist/features/wishlist/components/WishlistToggleButton.js +0 -36
- package/dist/monitoring/analytics.d.ts +0 -80
- package/dist/monitoring/analytics.js +0 -176
- package/dist/next/middleware/pii-redactor.d.ts +0 -32
- package/dist/next/middleware/pii-redactor.js +0 -84
- package/dist/providers/db-firebase/realtime.d.ts +0 -42
- package/dist/providers/db-firebase/realtime.js +0 -138
- package/dist/security/rbac/Can.d.ts +0 -31
- package/dist/security/rbac/Can.js +0 -22
- package/dist/security/rbac/default-roles.d.ts +0 -2
- package/dist/security/rbac/default-roles.js +0 -83
- package/dist/security/rbac/hook.d.ts +0 -20
- package/dist/security/rbac/hook.js +0 -30
- package/dist/security/rbac/index.d.ts +0 -8
- package/dist/security/rbac/index.js +0 -6
- package/dist/security/rbac/middleware.d.ts +0 -51
- package/dist/security/rbac/middleware.js +0 -51
- package/dist/security/rbac/resolver.d.ts +0 -5
- package/dist/security/rbac/resolver.js +0 -38
- package/dist/security/rbac/server.d.ts +0 -24
- package/dist/security/rbac/server.js +0 -42
- package/dist/security/rbac/types.d.ts +0 -22
- package/dist/security/rbac/types.js +0 -2
- package/dist/seed/conversations-seed-data.d.ts +0 -2
- package/dist/seed/conversations-seed-data.js +0 -292
- package/dist/utils/filter.helper.d.ts +0 -18
- package/dist/utils/filter.helper.js +0 -21
- package/dist/utils/pagination.helper.d.ts +0 -23
- package/dist/utils/pagination.helper.js +0 -24
- package/dist/utils/search-tokens.d.ts +0 -2
- package/dist/utils/search-tokens.js +0 -21
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
4
|
-
import { Check } from "lucide-react";
|
|
5
|
-
import { Button } from "../../ui/components/Button";
|
|
6
|
-
import { classNames } from "../../ui/style.helper";
|
|
7
|
-
import { Div, Nav, Row, Span, Stack, Text, useToast } from "../../ui";
|
|
8
|
-
import { normalizeError } from "../../errors/normalize";
|
|
9
|
-
import { FormSchemaContext } from "./FormShell";
|
|
10
|
-
/** Standalone step nav bar — use as `renderBottomBar` in FormShell. */
|
|
11
|
-
export function StepFormActions({ currentStep, totalSteps, onNext, onPrev, completeLabel = "Publish Now", isLoading = false, disabled = false, }) {
|
|
12
|
-
const isFirst = currentStep === 0;
|
|
13
|
-
const isLast = currentStep === totalSteps - 1;
|
|
14
|
-
const nextStepLabel = `Next →`;
|
|
15
|
-
return (_jsxs(Row, { paddingX: "x-5", className: "border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", padding: "y-sm", align: "center", justify: "between", gap: "sm", children: [_jsx(_Fragment, { children: !isFirst && onPrev && (_jsx(Button, { variant: "outline", size: "sm", onClick: onPrev, disabled: disabled || isLoading, children: "\u2190 Back" })) }), _jsxs(Row, { align: "center", gap: "3", children: [_jsxs(Span, { size: "xs", color: "muted", children: [currentStep + 1, " / ", totalSteps] }), _jsx(Button, { variant: "primary", size: "sm", onClick: onNext, disabled: disabled || isLoading, isLoading: isLoading && isLast, children: isLast ? completeLabel : nextStepLabel })] })] }));
|
|
16
|
-
}
|
|
17
|
-
/** Step indicator bar shown above step content. */
|
|
18
|
-
export function StepIndicator({ steps, currentStep, onStepClick, stepErrors, }) {
|
|
19
|
-
return (_jsx(Nav, { "aria-label": "Form steps", layout: "flex", gap: "none", className: "mb-6 overflow-x-auto", children: steps.map((step, i) => {
|
|
20
|
-
const isDone = i < currentStep;
|
|
21
|
-
const isActive = i === currentStep;
|
|
22
|
-
const hasError = stepErrors?.[i] === true;
|
|
23
|
-
return (_jsxs(Row, { className: "flex-shrink-0", align: "center", gap: "none", children: [_jsxs(Button, { variant: "ghost", type: "button", onClick: () => onStepClick?.(i), gap: "sm", rounded: "lg", paddingX: "sm", paddingY: "xs", textSize: "sm", className: classNames("cursor-pointer", isActive
|
|
24
|
-
? "font-semibold text-[var(--appkit-color-primary)]"
|
|
25
|
-
: isDone
|
|
26
|
-
? "text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-text)]"
|
|
27
|
-
: "text-[var(--appkit-color-text-faint)] hover:text-[var(--appkit-color-text-muted)]"), children: [_jsxs(Span, { className: "relative flex-shrink-0", children: [hasError && (_jsx(Span, { className: "absolute -top-0.5 -right-0.5 w-2 h-2 bg-[var(--appkit-color-error)] z-10", rounded: "full", "aria-label": "This step has errors" })), _jsx(Span, { className: classNames("flex-shrink-0 w-6 h-6 rounded-full flex items-center justify-center text-[length:var(--appkit-text-xs)] font-bold border-2", hasError
|
|
28
|
-
? "border-[var(--appkit-color-error)] bg-[var(--appkit-color-error)] text-white"
|
|
29
|
-
: isActive
|
|
30
|
-
? "border-[var(--appkit-color-primary)] bg-[var(--appkit-color-primary)] text-white"
|
|
31
|
-
: isDone
|
|
32
|
-
? "border-[var(--appkit-color-primary)] bg-[var(--appkit-color-primary)] text-white"
|
|
33
|
-
: "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-faint)]"), children: isDone && !hasError ? _jsx(Check, { className: "w-3 h-3" }) : hasError ? "!" : i + 1 })] }), _jsx(Span, { className: "hidden sm:inline", children: step.label })] }), i < steps.length - 1 && (_jsx(Div, { className: classNames("w-6 h-px flex-shrink-0 mx-1", i < currentStep
|
|
34
|
-
? "bg-[var(--appkit-color-primary)]"
|
|
35
|
-
: "bg-[var(--appkit-color-border)]") }))] }, i));
|
|
36
|
-
}) }));
|
|
37
|
-
}
|
|
38
|
-
export function StepForm({ steps, values, onChange, onComplete, completeLabel = "Publish Now", isLoading = false, formId, currentStep, onStepChange, hideActions = false, stepErrors, schema, onValidationChange, }) {
|
|
39
|
-
const { showToast } = useToast();
|
|
40
|
-
const inheritedSchema = useContext(FormSchemaContext);
|
|
41
|
-
const [fieldErrors, setFieldErrors] = useState({});
|
|
42
|
-
const [stepError, setStepError] = useState(null);
|
|
43
|
-
const fieldToStepIndex = useMemo(() => {
|
|
44
|
-
const map = {};
|
|
45
|
-
steps.forEach((step, i) => {
|
|
46
|
-
step.fields?.forEach((field) => { map[field] = i; });
|
|
47
|
-
});
|
|
48
|
-
return map;
|
|
49
|
-
}, [steps]);
|
|
50
|
-
const runValidation = useCallback((nextValues) => {
|
|
51
|
-
const activeSchema = steps[currentStep]?.schema ?? schema ?? inheritedSchema;
|
|
52
|
-
if (!activeSchema)
|
|
53
|
-
return;
|
|
54
|
-
// audit-unvalidated-safeparse-ok: bulk-replaces fieldErrors from the full
|
|
55
|
-
// parse result (clears fields that just became valid); applyZodIssues'
|
|
56
|
-
// incremental setFieldError-per-issue can't do that.
|
|
57
|
-
const parsed = activeSchema.safeParse(nextValues);
|
|
58
|
-
if (parsed.success) {
|
|
59
|
-
setFieldErrors({});
|
|
60
|
-
onValidationChange?.({}, fieldToStepIndex);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
const next = {};
|
|
64
|
-
for (const issue of parsed.error.issues) {
|
|
65
|
-
if (!issue.path || issue.path.length === 0)
|
|
66
|
-
continue;
|
|
67
|
-
next[issue.path.map(String).join(".")] = issue.message;
|
|
68
|
-
}
|
|
69
|
-
setFieldErrors(next);
|
|
70
|
-
onValidationChange?.(next, fieldToStepIndex);
|
|
71
|
-
}, [steps, currentStep, schema, inheritedSchema, fieldToStepIndex, onValidationChange]);
|
|
72
|
-
// Re-run validation whenever the active step or schema changes, so
|
|
73
|
-
// switching steps (or arriving with pre-filled values) shows accurate
|
|
74
|
-
// live errors immediately rather than only after the next keystroke.
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
runValidation(values);
|
|
77
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
78
|
-
}, [currentStep, steps[currentStep]?.schema, schema, inheritedSchema]);
|
|
79
|
-
const handleFieldChange = useCallback((partial) => {
|
|
80
|
-
const merged = { ...values, ...partial };
|
|
81
|
-
onChange(partial);
|
|
82
|
-
runValidation(merged);
|
|
83
|
-
}, [values, onChange, runValidation]);
|
|
84
|
-
// Persist step to localStorage if formId provided
|
|
85
|
-
useEffect(() => {
|
|
86
|
-
if (formId)
|
|
87
|
-
localStorage.setItem(`stepform:${formId}`, String(currentStep));
|
|
88
|
-
}, [formId, currentStep]);
|
|
89
|
-
// Restore step from localStorage on mount
|
|
90
|
-
useEffect(() => {
|
|
91
|
-
if (!formId)
|
|
92
|
-
return;
|
|
93
|
-
const saved = localStorage.getItem(`stepform:${formId}`);
|
|
94
|
-
if (saved !== null) {
|
|
95
|
-
const n = Number(saved);
|
|
96
|
-
if (!isNaN(n) && n >= 0 && n < steps.length)
|
|
97
|
-
onStepChange(n);
|
|
98
|
-
}
|
|
99
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
100
|
-
}, [formId]);
|
|
101
|
-
const goNext = useCallback(async () => {
|
|
102
|
-
const step = steps[currentStep];
|
|
103
|
-
if (step?.validate) {
|
|
104
|
-
const err = step.validate(values);
|
|
105
|
-
if (err) {
|
|
106
|
-
setStepError(err);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
setStepError(null);
|
|
111
|
-
if (currentStep < steps.length - 1) {
|
|
112
|
-
onStepChange(currentStep + 1);
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
try {
|
|
116
|
-
await onComplete();
|
|
117
|
-
}
|
|
118
|
-
catch (err) {
|
|
119
|
-
void normalizeError(err);
|
|
120
|
-
showToast(err instanceof Error ? err.message : "Something went wrong.", "error");
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}, [currentStep, steps, values, onComplete, onStepChange, showToast]);
|
|
124
|
-
const goPrev = useCallback(() => {
|
|
125
|
-
if (currentStep > 0) {
|
|
126
|
-
setStepError(null);
|
|
127
|
-
onStepChange(currentStep - 1);
|
|
128
|
-
}
|
|
129
|
-
}, [currentStep, onStepChange]);
|
|
130
|
-
const currentStepDef = steps[currentStep];
|
|
131
|
-
const isLast = currentStep === steps.length - 1;
|
|
132
|
-
return (_jsxs(Stack, { children: [_jsx(StepIndicator, { steps: steps, currentStep: currentStep, stepErrors: stepErrors, onStepClick: (i) => { if (i !== currentStep) {
|
|
133
|
-
setStepError(null);
|
|
134
|
-
onStepChange(i);
|
|
135
|
-
} } }), _jsx(Div, { className: "flex-1", children: currentStepDef?.render({ values, onChange: handleFieldChange, errors: fieldErrors }) }), !hideActions && stepError && (_jsx(Text, { className: "mt-3 text-[var(--appkit-color-error)]", size: "sm", children: stepError })), !hideActions && (_jsx(StepFormActions, { currentStep: currentStep, totalSteps: steps.length, onNext: () => void goNext(), onPrev: currentStep > 0 ? goPrev : undefined, completeLabel: completeLabel, isLoading: isLoading && isLast, disabled: isLoading }))] }));
|
|
136
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* feat-stores — Next.js App Router API handlers (GET /api/stores)
|
|
3
|
-
*
|
|
4
|
-
* Consuming projects can create a 2-line stub:
|
|
5
|
-
*
|
|
6
|
-
* ```ts
|
|
7
|
-
* // app/api/stores/route.ts
|
|
8
|
-
* export { GET } from "@mohasinac/feat-stores";
|
|
9
|
-
* ```
|
|
10
|
-
*/
|
|
11
|
-
import { NextResponse } from "next/server.js";
|
|
12
|
-
export declare function GET(request: Request): Promise<NextResponse>;
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* feat-stores — Next.js App Router API handlers (GET /api/stores)
|
|
3
|
-
*
|
|
4
|
-
* Consuming projects can create a 2-line stub:
|
|
5
|
-
*
|
|
6
|
-
* ```ts
|
|
7
|
-
* // app/api/stores/route.ts
|
|
8
|
-
* export { GET } from "@mohasinac/feat-stores";
|
|
9
|
-
* ```
|
|
10
|
-
*/
|
|
11
|
-
import { NextResponse } from "next/server.js";
|
|
12
|
-
import { getProviders } from "../../../contracts";
|
|
13
|
-
import { parseListingParams } from "../../../utils/listing-params";
|
|
14
|
-
import { normalizeError } from "../../../errors/normalize";
|
|
15
|
-
const DEFAULT_PAGE = 1;
|
|
16
|
-
const DEFAULT_PAGE_SIZE = 24;
|
|
17
|
-
const DEFAULT_SORT = "-createdAt";
|
|
18
|
-
function param(url, key) {
|
|
19
|
-
return url.searchParams.get(key);
|
|
20
|
-
}
|
|
21
|
-
const SAFE_STORE_FILTER_FIELDS = new Set([
|
|
22
|
-
"storeName",
|
|
23
|
-
"storeCategory",
|
|
24
|
-
"status",
|
|
25
|
-
"isPublic",
|
|
26
|
-
"isFeatured",
|
|
27
|
-
"averageRating",
|
|
28
|
-
"stats.totalProducts",
|
|
29
|
-
]);
|
|
30
|
-
function validateSieveFilters(raw, allowedFields) {
|
|
31
|
-
return raw
|
|
32
|
-
.split(",")
|
|
33
|
-
.map((c) => c.trim())
|
|
34
|
-
.filter((c) => {
|
|
35
|
-
const m = c.match(/^([^<>=!@]+)\s*(?:==|!=|<=|>=|<|>|@=\*?)/);
|
|
36
|
-
return m ? allowedFields.has(m[1].trim()) : false;
|
|
37
|
-
})
|
|
38
|
-
.join(",");
|
|
39
|
-
}
|
|
40
|
-
// --- GET /api/stores --------------------------------------------------------
|
|
41
|
-
export async function GET(request) {
|
|
42
|
-
try {
|
|
43
|
-
const url = new URL(request.url);
|
|
44
|
-
const std = parseListingParams(url);
|
|
45
|
-
const page = std.page ?? DEFAULT_PAGE;
|
|
46
|
-
const pageSize = std.pageSize ?? DEFAULT_PAGE_SIZE;
|
|
47
|
-
// Translate user-friendly sort names to Firestore nested field paths.
|
|
48
|
-
const rawSort = std.sorts ?? DEFAULT_SORT;
|
|
49
|
-
const sort = rawSort
|
|
50
|
-
.replace(/^-itemsSold$/, "-stats.itemsSold")
|
|
51
|
-
.replace(/^itemsSold$/, "stats.itemsSold")
|
|
52
|
-
.replace(/^-averageRating$/, "-stats.averageRating")
|
|
53
|
-
.replace(/^averageRating$/, "stats.averageRating");
|
|
54
|
-
const parts = ["status==active,isPublic==true"];
|
|
55
|
-
if (std.q)
|
|
56
|
-
parts.push(`storeName@=*${std.q}`);
|
|
57
|
-
const category = param(url, "category");
|
|
58
|
-
if (category)
|
|
59
|
-
parts.push(`storeCategory==${category}`);
|
|
60
|
-
if (std.filters) {
|
|
61
|
-
const safe = validateSieveFilters(std.filters, SAFE_STORE_FILTER_FIELDS);
|
|
62
|
-
if (safe)
|
|
63
|
-
parts.push(safe);
|
|
64
|
-
}
|
|
65
|
-
const filters = parts.join(",");
|
|
66
|
-
const { db } = getProviders();
|
|
67
|
-
if (!db) {
|
|
68
|
-
return NextResponse.json({ success: false, error: "Database provider not registered" }, { status: 503 });
|
|
69
|
-
}
|
|
70
|
-
const repo = db.getRepository("stores");
|
|
71
|
-
const result = await repo.findAll({
|
|
72
|
-
filters,
|
|
73
|
-
sort,
|
|
74
|
-
page,
|
|
75
|
-
perPage: pageSize,
|
|
76
|
-
});
|
|
77
|
-
// Map to public-safe shape (strip sensitive fields)
|
|
78
|
-
const items = result.data.map((s) => ({
|
|
79
|
-
id: s.id,
|
|
80
|
-
storeSlug: s.storeSlug,
|
|
81
|
-
ownerId: s.ownerId,
|
|
82
|
-
storeName: s.storeName,
|
|
83
|
-
storeDescription: s.storeDescription,
|
|
84
|
-
storeCategory: s.storeCategory,
|
|
85
|
-
storeLogoURL: s.storeLogoURL,
|
|
86
|
-
storeBannerURL: s.storeBannerURL,
|
|
87
|
-
status: s.status,
|
|
88
|
-
isPublic: s.isPublic,
|
|
89
|
-
totalProducts: s.stats?.totalProducts ?? s.totalProducts ?? undefined,
|
|
90
|
-
itemsSold: s.stats?.itemsSold ?? s.itemsSold ?? undefined,
|
|
91
|
-
totalReviews: s.stats?.totalReviews ?? s.totalReviews ?? undefined,
|
|
92
|
-
averageRating: s.stats?.averageRating ?? s.averageRating,
|
|
93
|
-
createdAt: s.createdAt,
|
|
94
|
-
}));
|
|
95
|
-
const body = {
|
|
96
|
-
items,
|
|
97
|
-
total: result.total,
|
|
98
|
-
page: result.page,
|
|
99
|
-
pageSize: result.perPage,
|
|
100
|
-
totalPages: result.totalPages,
|
|
101
|
-
hasMore: result.page < result.totalPages,
|
|
102
|
-
};
|
|
103
|
-
return NextResponse.json({ success: true, data: body });
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
void normalizeError(error);
|
|
107
|
-
console.error("[feat-stores] GET /api/stores failed", error);
|
|
108
|
-
return NextResponse.json({ success: false, error: "Failed to fetch stores" }, { status: 500 });
|
|
109
|
-
}
|
|
110
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* WHY: Authored six-part procedures for the account-auth/testing-program checklist page.
|
|
3
|
-
* WHAT: 1 case(s), keyed by full checklist id.
|
|
4
|
-
*
|
|
5
|
-
* Generated by `node tester/scripts/merge-authored.mjs --page account-auth/testing-program`, then
|
|
6
|
-
* reviewed by a human before merge — the review is the gate, not the generation.
|
|
7
|
-
* Hand edits are safe and expected: re-running the merge for this page replaces
|
|
8
|
-
* the file, so re-author only when you mean to discard them.
|
|
9
|
-
*
|
|
10
|
-
* @tag domain:tester
|
|
11
|
-
* @tag layer:seed
|
|
12
|
-
* @tag pattern:none
|
|
13
|
-
* @tag access:server-only
|
|
14
|
-
* @tag consumers:seed-data/authored/index.ts
|
|
15
|
-
* @tag sideEffects:none
|
|
16
|
-
*/
|
|
17
|
-
export const authored = {
|
|
18
|
-
"checklist-account-auth-testing-program-admin-testing-section": {
|
|
19
|
-
roles: ["admin"],
|
|
20
|
-
startPage: "/admin/dashboard",
|
|
21
|
-
steps: [
|
|
22
|
-
"Sign in as admin@letitrip.in.",
|
|
23
|
-
"Open /admin/dashboard.",
|
|
24
|
-
"Locate the 'Admin Panel' sidebar on the right side of the page.",
|
|
25
|
-
"Click the 'Testing' section heading in the sidebar to expand it.",
|
|
26
|
-
"Locate the 'Test Cases' link in the Testing section.",
|
|
27
|
-
"Locate the 'Results' link in the Testing section.",
|
|
28
|
-
],
|
|
29
|
-
expectedBehaviour: "The admin sidebar renders a 'Testing' collapsible section containing at least two links: 'Test Cases' (pointing to /admin/tester-checklist) and 'Results' (pointing to /admin/tester-feedback). Both links are clickable and navigate to their respective pages.",
|
|
30
|
-
expectedUiState: "The Testing section is visible in the Admin Panel sidebar. It contains a 'Test Cases' link and a 'Results' link. Both links are present and labelled exactly 'Test Cases' and 'Results'.",
|
|
31
|
-
endResult: "After reload, the sidebar still shows the Testing section with both links. No data is persisted by this case — it is a read-only navigation check.",
|
|
32
|
-
},
|
|
33
|
-
};
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* WHY: Authored six-part procedures for the account-auth/testing-program checklist page.
|
|
3
|
-
* WHAT: 6 case(s), keyed by full checklist id.
|
|
4
|
-
*
|
|
5
|
-
* Written by hand, case by case, against the label each one states. There is no
|
|
6
|
-
* generator: the authoring scripts were deleted once it was clear they were
|
|
7
|
-
* scaffolding around work that is simply writing.
|
|
8
|
-
*
|
|
9
|
-
* This page used to be split across two modules, `--admin` and nothing else, a
|
|
10
|
-
* convention the deleted authoring bot needed because it batched a page by the
|
|
11
|
-
* identity it ran as. Hand-written, one file per page is the whole rule, and the
|
|
12
|
-
* split only made the five buyer-side cases easy to lose track of — which is what
|
|
13
|
-
* happened: five of six sat unauthored while the page looked started.
|
|
14
|
-
*
|
|
15
|
-
* @tag domain:tester
|
|
16
|
-
* @tag layer:seed
|
|
17
|
-
* @tag pattern:none
|
|
18
|
-
* @tag access:server-only
|
|
19
|
-
* @tag consumers:seed-data/authored/index.ts
|
|
20
|
-
* @tag sideEffects:none
|
|
21
|
-
*/
|
|
22
|
-
export const authored = {
|
|
23
|
-
"checklist-account-auth-testing-program-admin-tester-access": {
|
|
24
|
-
roles: ["admin"],
|
|
25
|
-
startPage: "/user/tester",
|
|
26
|
-
steps: [
|
|
27
|
-
"Sign in as admin@letitrip.in / TempPass123!.",
|
|
28
|
-
"Open /user/tester.",
|
|
29
|
-
"Read the group headings down the page.",
|
|
30
|
-
"Expand the 'Buying' group and then the 'Cart' page inside it.",
|
|
31
|
-
"Expand the 'Admin (Testing)' group.",
|
|
32
|
-
],
|
|
33
|
-
inputs: { email: "admin@letitrip.in" },
|
|
34
|
-
expectedBehaviour: "An admin reaches the Tester Hub on the strength of their role alone, without an isTester flag, and sees the same catalogue a tester does — including the adminOnly cases, which a plain tester without canTestAdmin does not get.",
|
|
35
|
-
expectedUiState: "/user/tester renders the grouped checklist rather than a 'Testers only' warning. The Buying group expands to its pages and the Admin (Testing) group is present and expandable.",
|
|
36
|
-
expectedData: { adminOnlyGroupVisible: true },
|
|
37
|
-
endResult: "Reloading /user/tester still shows the full checklist. Nothing is written by this case; it is a read-only access check.",
|
|
38
|
-
},
|
|
39
|
-
"checklist-account-auth-testing-program-admin-testing-section": {
|
|
40
|
-
roles: ["admin"],
|
|
41
|
-
startPage: "/admin/dashboard",
|
|
42
|
-
steps: [
|
|
43
|
-
"Sign in as admin@letitrip.in / TempPass123!.",
|
|
44
|
-
"Open /admin/dashboard.",
|
|
45
|
-
"Expand the 'Testing' section in the admin sidebar.",
|
|
46
|
-
"Click 'Test Cases' and note where it lands.",
|
|
47
|
-
"Go back to /admin/dashboard and expand 'Testing' again.",
|
|
48
|
-
"Click 'Results' and note where it lands.",
|
|
49
|
-
],
|
|
50
|
-
inputs: { email: "admin@letitrip.in" },
|
|
51
|
-
expectedBehaviour: "The Testing section carries both links and each one reaches a real page — 'Test Cases' to /admin/tester-checklist, the admin-managed catalogue, and 'Results' to /admin/tester-feedback, where answers are triaged. A nav entry pointing at a page that does not exist is the failure this catches.",
|
|
52
|
-
expectedUiState: "The sidebar shows a 'Testing' section holding exactly the links 'Test Cases' and 'Results'. Clicking each renders its page with content, not a 404 and not an empty shell.",
|
|
53
|
-
expectedData: {
|
|
54
|
-
testCasesHref: "/admin/tester-checklist",
|
|
55
|
-
resultsHref: "/admin/tester-feedback",
|
|
56
|
-
},
|
|
57
|
-
endResult: "After reload the Testing section still holds both links and both still resolve. Read-only; nothing persists.",
|
|
58
|
-
},
|
|
59
|
-
"checklist-account-auth-testing-program-tester-flag-live-refresh": {
|
|
60
|
-
roles: ["admin", "buyer"],
|
|
61
|
-
startPage: "/user/tester",
|
|
62
|
-
steps: [
|
|
63
|
-
"In browser window A, sign in as karthik.new@gmail.com / TempPass123! and open /user/tester.",
|
|
64
|
-
"Leave window A open on that page without reloading it for the rest of this case.",
|
|
65
|
-
"In a separate browser window B, sign in as admin@letitrip.in / TempPass123!.",
|
|
66
|
-
"In window B open /admin/users and search for karthik.new@gmail.com.",
|
|
67
|
-
"Open that user and set the 'Is tester' flag to on, then save.",
|
|
68
|
-
"Return to window A and navigate between /user and /user/tester using the sidebar, without reloading.",
|
|
69
|
-
"Keep navigating that way for up to 6 minutes.",
|
|
70
|
-
"In window B, set 'Is tester' back to off for karthik.new@gmail.com and save.",
|
|
71
|
-
],
|
|
72
|
-
inputs: { testerEmail: "karthik.new@gmail.com", isTester: true },
|
|
73
|
-
expectedBehaviour: "The client session re-reads role, isTester, canTestAdmin, disabled and storeId on the 5-minute activity ping, so a flag an admin flips reaches an already-open tab without a sign-out. Before this was fixed those fields refreshed only on login or a full page reload, so the grant was invisible for as long as the tab stayed open.",
|
|
74
|
-
expectedUiState: "Window A starts on /user/tester showing 'Testers only' — karthik.new@gmail.com has no tester flag. Within about 5 minutes, and with no reload and no re-login, the same page starts rendering the checklist instead. What must not happen is the warning persisting indefinitely until the tab is reloaded.",
|
|
75
|
-
expectedData: { isTester: true },
|
|
76
|
-
endResult: "Window A gains access without reloading. The flag is set back to off in the final step so karthik.new@gmail.com stays a plain buyer for other cases.",
|
|
77
|
-
},
|
|
78
|
-
"checklist-account-auth-testing-program-tester-hub-answer-saves": {
|
|
79
|
-
roles: ["buyer"],
|
|
80
|
-
startPage: "/user/tester",
|
|
81
|
-
steps: [
|
|
82
|
-
"Sign in as tester@letitrip.in / TempPass123!.",
|
|
83
|
-
"Open /user/tester.",
|
|
84
|
-
"Expand the 'Buying' group and then the 'Cart' page.",
|
|
85
|
-
"Click 'Yes' on the first case in that page.",
|
|
86
|
-
"Type 'QA Comment testing-program-tester-hub-answer-saves' in that case's comment box.",
|
|
87
|
-
"Wait for the save indicator to settle without touching the browser reload button.",
|
|
88
|
-
"Reload the page.",
|
|
89
|
-
"Expand the 'Buying' group and then the 'Cart' page.",
|
|
90
|
-
],
|
|
91
|
-
inputs: {
|
|
92
|
-
answer: "yes",
|
|
93
|
-
comment: "QA Comment testing-program-tester-hub-answer-saves",
|
|
94
|
-
},
|
|
95
|
-
expectedBehaviour: "The answer and the comment are written against a document keyed on tester and case together, so re-answering updates that one row rather than accumulating duplicates. The page does not navigate or reload to save.",
|
|
96
|
-
expectedUiState: "The 'Yes' control becomes selected and a saved indicator appears, with no full-page flash. After reload the same case still shows 'Yes' selected and the comment text still in its box.",
|
|
97
|
-
expectedData: {
|
|
98
|
-
answer: "yes",
|
|
99
|
-
comment: "QA Comment testing-program-tester-hub-answer-saves",
|
|
100
|
-
},
|
|
101
|
-
endResult: "The answer and comment survive the reload. A save that appears to work and is gone after F5 is exactly the failure this case exists to catch.",
|
|
102
|
-
},
|
|
103
|
-
"checklist-account-auth-testing-program-tester-hub-loads": {
|
|
104
|
-
roles: ["buyer"],
|
|
105
|
-
startPage: "/user/tester",
|
|
106
|
-
steps: [
|
|
107
|
-
"Sign in as tester@letitrip.in / TempPass123!.",
|
|
108
|
-
"Open /user/tester.",
|
|
109
|
-
"Read the group headings down the page.",
|
|
110
|
-
"Expand the 'Buying' group.",
|
|
111
|
-
"Expand the 'Cart' page inside it.",
|
|
112
|
-
"Expand a case's 'Steps' toggle.",
|
|
113
|
-
],
|
|
114
|
-
inputs: { email: "tester@letitrip.in" },
|
|
115
|
-
expectedBehaviour: "The whole catalogue loads, grouped and then sub-grouped by page, and each case can be opened to reveal its roles, start page, steps, input values, expectations and end result. A tester without canTestAdmin does not see the Admin (Testing) group at all.",
|
|
116
|
-
expectedUiState: "Group headings are visible — Account & Auth, Buying, Selling, Content & Discovery, Community & Support, Design & UX, Public & Marketing Pages, Page Wiring, CTA & Action Rows, Addresses, Search & navigation, Money Flows. Expanding Buying reveals its pages, and expanding a case shows its procedure rather than only the one-line label.",
|
|
117
|
-
expectedData: { adminOnlyGroupVisible: false },
|
|
118
|
-
endResult: "Reloading keeps the checklist rendered. Read-only; nothing is written. An empty hub, or one showing labels with no procedure behind them, both fail.",
|
|
119
|
-
},
|
|
120
|
-
"checklist-account-auth-testing-program-tester-hub-search": {
|
|
121
|
-
roles: ["buyer"],
|
|
122
|
-
startPage: "/user/tester",
|
|
123
|
-
steps: [
|
|
124
|
-
"Sign in as tester@letitrip.in / TempPass123!.",
|
|
125
|
-
"Open /user/tester.",
|
|
126
|
-
"Type coupon in the search box.",
|
|
127
|
-
"Read the results.",
|
|
128
|
-
"Clear the box and type /store/payouts instead.",
|
|
129
|
-
"Read the results.",
|
|
130
|
-
"Clear the box and type zzzznope instead.",
|
|
131
|
-
"Read the results.",
|
|
132
|
-
],
|
|
133
|
-
inputs: { titleQuery: "coupon", routeQuery: "/store/payouts", nonsenseQuery: "zzzznope" },
|
|
134
|
-
expectedBehaviour: "Search matches on the case title AND on the route it links to, so a tester who knows only the page they are on can find its cases. It filters — it does not merely highlight while still listing everything.",
|
|
135
|
-
expectedUiState: "'coupon' narrows the list to coupon-related cases. '/store/payouts' returns the payout cases, which is the whole point of route matching — those titles do not contain the word 'payouts' as typed with a slash. 'zzzznope' returns an empty state with a readable message, NOT the full unfiltered checklist.",
|
|
136
|
-
endResult: "The nonsense query is the control: if it returns everything, the box is not filtering and the two real queries proved nothing. Read-only; nothing persists.",
|
|
137
|
-
},
|
|
138
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* WHY: Shared tester sandbox — one winning bid on the already-ended auction-tester-sandbox-won
|
|
3
|
-
* (kept separate from the still-biddable auction-tester-sandbox-1 so testers can still
|
|
4
|
-
* place a live bid on the latter) so testers (and the paired orders-tester-seed-data.ts
|
|
5
|
-
* auction-win order) can exercise the "winning an auction creates a payable order" flow.
|
|
6
|
-
* Auto-expires in 7 days, cascading with the parent auction product.
|
|
7
|
-
* WHAT: Exports bidsTesterSeedData — 1 Partial<BidDocument> for the seed runner.
|
|
8
|
-
*
|
|
9
|
-
* EXPORTS:
|
|
10
|
-
* bidsTesterSeedData — Array of 1 Partial<BidDocument> for the seed runner
|
|
11
|
-
*
|
|
12
|
-
* @tag domain:auctions,bids,tester
|
|
13
|
-
* @tag layer:seed
|
|
14
|
-
* @tag pattern:none
|
|
15
|
-
* @tag access:server-only
|
|
16
|
-
* @tag consumers:seed/index.ts,seed-cli.mjs
|
|
17
|
-
* @tag sideEffects:none
|
|
18
|
-
*/
|
|
19
|
-
const NOW = new Date();
|
|
20
|
-
const daysAgo = (n) => new Date(NOW.getTime() - n * 86400000);
|
|
21
|
-
export const bidsTesterSeedData = [
|
|
22
|
-
{
|
|
23
|
-
id: "bid-tester-sandbox-won-tester-qa",
|
|
24
|
-
productId: "auction-tester-sandbox-won",
|
|
25
|
-
productTitle: "Test Auction — Already Won",
|
|
26
|
-
userId: "user-tester-qa",
|
|
27
|
-
userName: "QA Tester",
|
|
28
|
-
userEmail: "tester@letitrip.in",
|
|
29
|
-
bidAmount: 15000,
|
|
30
|
-
currency: "INR",
|
|
31
|
-
status: "won",
|
|
32
|
-
isWinning: true,
|
|
33
|
-
bidDate: daysAgo(1),
|
|
34
|
-
createdAt: daysAgo(1),
|
|
35
|
-
updatedAt: daysAgo(1),
|
|
36
|
-
},
|
|
37
|
-
];
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* WHY: Shared tester sandbox — 1 disposable test blog post so testers can exercise the
|
|
3
|
-
* blog reading flow. Auto-expires after 7 days (testerSandboxCleanup).
|
|
4
|
-
* WHAT: Exports blogTesterSeedData — 1 Partial<BlogPostDocument> tagged isTestData:true.
|
|
5
|
-
*
|
|
6
|
-
* EXPORTS:
|
|
7
|
-
* blogTesterSeedData — Array of 1 Partial<BlogPostDocument> for the seed runner
|
|
8
|
-
*
|
|
9
|
-
* @tag domain:blog,tester
|
|
10
|
-
* @tag layer:seed
|
|
11
|
-
* @tag pattern:none
|
|
12
|
-
* @tag access:server-only
|
|
13
|
-
* @tag consumers:seed/index.ts,seed-cli.mjs
|
|
14
|
-
* @tag sideEffects:none
|
|
15
|
-
*/
|
|
16
|
-
import { seedPhoto } from "../../../seed/_helpers/media";
|
|
17
|
-
import { testDataExpiresAt } from "./tester-ttl";
|
|
18
|
-
export const blogTesterSeedData = [
|
|
19
|
-
{
|
|
20
|
-
id: "blog-tester-sandbox-post",
|
|
21
|
-
title: "Welcome to the Tester Sandbox",
|
|
22
|
-
slug: "tester-sandbox-post",
|
|
23
|
-
excerpt: "A disposable test blog post for the tester QA program — check that images, formatting, and reading flow work correctly.",
|
|
24
|
-
content: `<h2>This is a test post</h2><p>It exists only for the tester QA program and will be deleted automatically after 7 days.</p><p>Check: does this render correctly? Are images loading? Is the layout readable?</p>`,
|
|
25
|
-
coverImage: { type: "image", url: seedPhoto("blog-cover-tester-sandbox-post-20260101", 1200, 600), alt: "Test cover image" },
|
|
26
|
-
category: "guides",
|
|
27
|
-
tags: ["test"],
|
|
28
|
-
isFeatured: false,
|
|
29
|
-
status: "published",
|
|
30
|
-
publishedAt: new Date(),
|
|
31
|
-
authorId: "user-admin-letitrip",
|
|
32
|
-
authorName: "LetItRip Admin",
|
|
33
|
-
readTimeMinutes: 1,
|
|
34
|
-
views: 0,
|
|
35
|
-
isTestData: true,
|
|
36
|
-
testDataExpiresAt: testDataExpiresAt(),
|
|
37
|
-
createdAt: new Date(),
|
|
38
|
-
updatedAt: new Date(),
|
|
39
|
-
},
|
|
40
|
-
];
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* WHY: Shared tester sandbox — the LOCKED cart line a settled auction leaves behind.
|
|
3
|
-
* WHAT: One cart for user-tester-qa holding the win from auction-tester-sandbox-won.
|
|
4
|
-
*
|
|
5
|
-
* 🛑 WHY THIS FILE HAD TO EXIST.
|
|
6
|
-
*
|
|
7
|
-
* The sandbox seeded a won auction, its winning bid, and a delivered order made
|
|
8
|
-
* from it — the shape settlement produced BEFORE Root Cause #60, when it wrote an
|
|
9
|
-
* order document directly. That order was in a shape no orders list could render
|
|
10
|
-
* and no checkout could accept, so a winner had no way to pay at all; the fix
|
|
11
|
-
* routed a win through the CART as a locked line instead.
|
|
12
|
-
*
|
|
13
|
-
* The fixtures were never updated to match. So `win-auction` — the case whose
|
|
14
|
-
* label is literally "creates a payable locked cart line, not a stuck order" —
|
|
15
|
-
* could not pass: /user/bids offered "Pay now", it led to /checkout?lane=auction,
|
|
16
|
-
* and the cart was empty. Found by the tester 2026-09-06, which is exactly the
|
|
17
|
-
* kind of thing a case can only prove by being run.
|
|
18
|
-
*
|
|
19
|
-
* The delivered order fixture STAYS. It is the "win already completed" state and
|
|
20
|
-
* other cases read it. This adds the missing "win awaiting payment" state.
|
|
21
|
-
*
|
|
22
|
-
* 🛑 `isAuctionWin` is not decoration. `laneOf()` keys on `isAuctionWin || bidId`
|
|
23
|
-
* and ignores `listingType` and `locked` entirely — a line without it lands in the
|
|
24
|
-
* STANDARD lane, so the Won Auctions tab stays empty while a non-removable line
|
|
25
|
-
* sits in the ordinary cart. Both fields are set here so the lane is unambiguous.
|
|
26
|
-
*
|
|
27
|
-
* @tag domain:tester
|
|
28
|
-
* @tag layer:seed
|
|
29
|
-
* @tag pattern:none
|
|
30
|
-
* @tag access:server-only
|
|
31
|
-
* @tag consumers:seed/index.ts,seed/manifest.ts
|
|
32
|
-
* @tag sideEffects:none
|
|
33
|
-
*/
|
|
34
|
-
import { testDataExpiresAt } from "./tester-ttl";
|
|
35
|
-
const NOW = new Date();
|
|
36
|
-
const hoursAgo = (n) => new Date(NOW.getTime() - n * 3600000);
|
|
37
|
-
/** The cart document id IS the user id — one cart per account. */
|
|
38
|
-
export const cartsTesterSeedData = [
|
|
39
|
-
{
|
|
40
|
-
id: "user-tester-qa",
|
|
41
|
-
userId: "user-tester-qa",
|
|
42
|
-
items: [
|
|
43
|
-
{
|
|
44
|
-
itemId: "cartitem-tester-sandbox-auction-won",
|
|
45
|
-
productId: "auction-tester-sandbox-won",
|
|
46
|
-
productTitle: "Test Auction — Already Won",
|
|
47
|
-
price: 15000,
|
|
48
|
-
currency: "INR",
|
|
49
|
-
quantity: 1,
|
|
50
|
-
storeId: "store-tester-qa-seller",
|
|
51
|
-
storeName: "Tester QA Seller",
|
|
52
|
-
listingType: "auction",
|
|
53
|
-
// Both, deliberately — see the lane note in the header.
|
|
54
|
-
isAuctionWin: true,
|
|
55
|
-
bidId: "bid-tester-sandbox-won-tester-qa",
|
|
56
|
-
// A win is non-removable and fixed-quantity: settlement is the only writer
|
|
57
|
-
// of this line, and declining to pay is handled by the forfeit sweep rather
|
|
58
|
-
// than by the buyer deleting it.
|
|
59
|
-
locked: true,
|
|
60
|
-
lockedPrice: 15000,
|
|
61
|
-
addedAt: hoursAgo(2),
|
|
62
|
-
updatedAt: hoursAgo(2),
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
isTestData: true,
|
|
66
|
-
testDataExpiresAt: testDataExpiresAt(),
|
|
67
|
-
createdAt: hoursAgo(2),
|
|
68
|
-
updatedAt: hoursAgo(2),
|
|
69
|
-
},
|
|
70
|
-
];
|