@mohasinac/appkit 3.2.19 → 3.3.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/checkout/actions.d.ts +2 -0
- package/dist/_internal/server/features/checkout/actions.js +239 -190
- package/dist/_internal/server/functions/scheduled.d.ts +2 -1
- package/dist/_internal/server/functions/scheduled.js +9 -1
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +8 -11
- package/dist/_internal/server/jobs/core/emiInstallmentReminder.d.ts +8 -0
- package/dist/_internal/server/jobs/core/emiInstallmentReminder.js +78 -0
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.d.ts +2 -2
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +15 -10
- package/dist/_internal/server/jobs/handlers/emiInstallmentReminder.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/emiInstallmentReminder.js +2 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
- package/dist/_internal/server/jobs/handlers/index.js +2 -0
- package/dist/_internal/server/providers/index.d.ts +4 -4
- package/dist/_internal/server/providers/index.js +4 -4
- package/dist/_internal/server/providers/payment/razorpay-mock.d.ts +3 -2
- package/dist/_internal/server/providers/payment/razorpay-mock.js +3 -1
- package/dist/_internal/server/providers/resolve.d.ts +10 -13
- package/dist/_internal/server/providers/resolve.js +9 -15
- package/dist/_internal/shared/actions/action-registry.js +28 -0
- package/dist/_internal/shared/checkout/rules/_defaults.js +1 -0
- package/dist/_internal/shared/checkout/rules/_registry.js +4 -0
- package/dist/_internal/shared/checkout/rules/art.rule.d.ts +9 -0
- package/dist/_internal/shared/checkout/rules/art.rule.js +5 -0
- package/dist/_internal/shared/checkout/rules/auction.rule.js +1 -0
- package/dist/_internal/shared/checkout/rules/classified.rule.js +1 -0
- package/dist/_internal/shared/checkout/rules/index.d.ts +2 -0
- package/dist/_internal/shared/checkout/rules/index.js +2 -0
- package/dist/_internal/shared/checkout/rules/stickers.rule.d.ts +9 -0
- package/dist/_internal/shared/checkout/rules/stickers.rule.js +5 -0
- package/dist/_internal/shared/checkout/rules/types.d.ts +6 -0
- package/dist/_internal/shared/features/checkout/config.d.ts +16 -1
- package/dist/_internal/shared/features/checkout/config.js +16 -1
- package/dist/_internal/shared/features/emi/schedule.d.ts +63 -0
- package/dist/_internal/shared/features/emi/schedule.js +62 -0
- package/dist/_internal/shared/fees/calculator.d.ts +53 -0
- package/dist/_internal/shared/fees/calculator.js +40 -0
- package/dist/_internal/shared/listing-types/_registry.d.ts +22 -66
- package/dist/_internal/shared/listing-types/_registry.js +19 -2
- package/dist/_internal/shared/listing-types/art/config.d.ts +15 -0
- package/dist/_internal/shared/listing-types/art/config.js +14 -0
- package/dist/_internal/shared/listing-types/art/ctas.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/ctas.js +3 -0
- package/dist/_internal/shared/listing-types/art/og.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/og.js +1 -0
- package/dist/_internal/shared/listing-types/art/schema.d.ts +2 -0
- package/dist/_internal/shared/listing-types/art/schema.js +3 -0
- package/dist/_internal/shared/listing-types/art/seed-factory.d.ts +1 -0
- package/dist/_internal/shared/listing-types/art/seed-factory.js +1 -0
- package/dist/_internal/shared/listing-types/auction/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/auction/config.js +6 -0
- package/dist/_internal/shared/listing-types/capabilities.js +17 -0
- package/dist/_internal/shared/listing-types/classified/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/classified/config.js +6 -0
- package/dist/_internal/shared/listing-types/digital-code/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/digital-code/config.js +6 -0
- package/dist/_internal/shared/listing-types/live/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/live/config.js +6 -0
- package/dist/_internal/shared/listing-types/pre-order/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/pre-order/config.js +6 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/prize-draw/config.js +6 -0
- package/dist/_internal/shared/listing-types/standard/config.d.ts +8 -0
- package/dist/_internal/shared/listing-types/standard/config.js +6 -0
- package/dist/_internal/shared/listing-types/stickers/config.d.ts +15 -0
- package/dist/_internal/shared/listing-types/stickers/config.js +14 -0
- package/dist/_internal/shared/listing-types/stickers/ctas.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/ctas.js +3 -0
- package/dist/_internal/shared/listing-types/stickers/og.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/og.js +1 -0
- package/dist/_internal/shared/listing-types/stickers/schema.d.ts +2 -0
- package/dist/_internal/shared/listing-types/stickers/schema.js +3 -0
- package/dist/_internal/shared/listing-types/stickers/seed-factory.d.ts +1 -0
- package/dist/_internal/shared/listing-types/stickers/seed-factory.js +1 -0
- package/dist/client.d.ts +7 -2
- package/dist/client.js +4 -2
- package/dist/constants/field-names.d.ts +2 -6
- package/dist/constants/field-names.js +2 -6
- package/dist/contracts/index.d.ts +4 -2
- package/dist/contracts/index.js +6 -0
- package/dist/contracts/payment.d.ts +14 -9
- package/dist/contracts/payment.js +11 -1
- package/dist/contracts/shipping.d.ts +14 -9
- package/dist/contracts/shipping.js +11 -1
- package/dist/features/about/components/PublicProfileView.js +3 -6
- package/dist/features/account/components/UserOffersPanel.js +0 -1
- package/dist/features/admin/components/AdminAddressBookView.d.ts +11 -0
- package/dist/features/admin/components/AdminAddressBookView.js +30 -0
- package/dist/features/admin/components/AdminArtView.d.ts +3 -0
- package/dist/features/admin/components/AdminArtView.js +45 -0
- package/dist/features/admin/components/AdminCarouselEditorView.js +2 -3
- package/dist/features/admin/components/AdminFulfillmentView.js +0 -1
- package/dist/features/admin/components/AdminSiteConfigGuideView.js +1 -1
- package/dist/features/admin/components/AdminSiteSettingsView.js +14 -9
- package/dist/features/admin/components/AdminStickersView.d.ts +3 -0
- package/dist/features/admin/components/AdminStickersView.js +45 -0
- package/dist/features/admin/components/index.d.ts +6 -0
- package/dist/features/admin/components/index.js +4 -0
- package/dist/features/admin/hooks/useChat.js +0 -1
- package/dist/features/admin/schemas/firestore.d.ts +19 -11
- package/dist/features/admin/schemas/firestore.js +12 -2
- package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +3 -2
- package/dist/features/auth/hooks/useAuth.js +35 -10
- package/dist/features/auth/schemas/firestore.d.ts +2 -6
- package/dist/features/cart/schemas/firestore.d.ts +3 -2
- package/dist/features/consultation/schemas/index.d.ts +2 -2
- package/dist/features/history/hooks/useHistory.js +0 -1
- package/dist/features/loyalty/schemas/index.d.ts +6 -6
- package/dist/features/messages/hooks/useConversation.js +0 -1
- package/dist/features/messages/hooks/useConversations.js +0 -1
- package/dist/features/orders/repository/orders.repository.d.ts +20 -2
- package/dist/features/orders/repository/orders.repository.js +34 -5
- package/dist/features/orders/schemas/firestore.d.ts +33 -7
- package/dist/features/orders/schemas/firestore.js +1 -1
- package/dist/features/orders/schemas/index.d.ts +176 -31
- package/dist/features/orders/schemas/index.js +20 -6
- package/dist/features/orders/types/index.d.ts +3 -3
- package/dist/features/payments/repository/payout.repository.js +2 -2
- package/dist/features/payments/schemas/firestore.d.ts +3 -3
- package/dist/features/payments/schemas/firestore.js +2 -2
- package/dist/features/payments/schemas/index.d.ts +5 -5
- package/dist/features/payments/schemas/index.js +2 -2
- package/dist/features/products/api/[id]/route.js +4 -1
- package/dist/features/products/api/route.js +4 -1
- package/dist/features/products/components/CompareOverlay.js +7 -9
- package/dist/features/products/components/ProductDetailPageView.d.ts +3 -1
- package/dist/features/products/components/ProductDetailPageView.js +2 -2
- package/dist/features/products/components/ProductForm.js +18 -7
- package/dist/features/products/components/ProductGrid.js +7 -12
- package/dist/features/products/components/ShowGroupSection.js +3 -5
- package/dist/features/products/components/SublistingCarouselSection.js +3 -6
- package/dist/features/products/constants/listing-tabs.d.ts +32 -0
- package/dist/features/products/constants/listing-tabs.js +8 -0
- package/dist/features/products/index.d.ts +1 -1
- package/dist/features/products/index.js +3 -1
- package/dist/features/products/schemas/firestore.d.ts +20 -1
- package/dist/features/products/schemas/firestore.js +2 -0
- package/dist/features/products/schemas/index.d.ts +48 -0
- package/dist/features/products/schemas/index.js +9 -0
- package/dist/features/products/schemas/product-features.d.ts +1 -1
- package/dist/features/products/types/index.d.ts +5 -3
- package/dist/features/products/utils/listing-type.d.ts +6 -0
- package/dist/features/products/utils/listing-type.js +3 -0
- package/dist/features/reviews/api/[id]/route.js +5 -4
- package/dist/features/seller/actions/seller-actions.d.ts +29 -14
- package/dist/features/seller/actions/seller-actions.js +101 -27
- package/dist/features/seller/components/FulfillmentView.js +0 -1
- package/dist/features/seller/components/SellerAddressesView.js +0 -1
- package/dist/features/seller/components/SellerArtView.d.ts +7 -0
- package/dist/features/seller/components/SellerArtView.js +114 -0
- package/dist/features/seller/components/SellerOffersPanel.js +0 -1
- package/dist/features/seller/components/SellerOrdersView.js +38 -1
- package/dist/features/seller/components/SellerProductShell.d.ts +5 -1
- package/dist/features/seller/components/SellerProductShell.js +69 -59
- package/dist/features/seller/components/SellerReviewsView.js +0 -1
- package/dist/features/seller/components/SellerShippingView.js +6 -25
- package/dist/features/seller/components/SellerStickersView.d.ts +7 -0
- package/dist/features/seller/components/SellerStickersView.js +114 -0
- package/dist/features/seller/components/index.d.ts +4 -0
- package/dist/features/seller/components/index.js +2 -0
- package/dist/features/seller/messages/en.json +1 -1
- package/dist/features/seller/schemas/index.d.ts +7 -7
- package/dist/features/seller/schemas/index.js +1 -1
- package/dist/features/seller/types/index.d.ts +1 -1
- package/dist/features/stores/components/StoreDetailLayoutView.js +18 -2
- package/dist/features/stores/schemas/firestore.d.ts +7 -1
- package/dist/features/stores/schemas/index.d.ts +19 -16
- package/dist/features/stores/schemas/index.js +1 -1
- package/dist/index.d.ts +21 -36
- package/dist/index.js +27 -39
- package/dist/next/routing/route-map.d.ts +22 -0
- package/dist/next/routing/route-map.js +10 -0
- package/dist/providers/payment-manual/index.d.ts +40 -0
- package/dist/providers/payment-manual/index.js +91 -0
- package/dist/providers/payment-razorpay/index.d.ts +4 -2
- package/dist/providers/payment-razorpay/index.js +4 -1
- package/dist/providers/shipping-manual/index.d.ts +22 -0
- package/dist/providers/shipping-manual/index.js +47 -0
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +5 -3
- package/dist/schemas/registry.d.ts +129 -70
- package/dist/schemas/registry.js +0 -4
- package/dist/security/pii-encrypt.js +0 -7
- package/dist/security/pii-redact.js +0 -1
- package/dist/seed/conversations-seed-data.js +2 -2
- package/dist/seed/faq-seed-data.js +7 -7
- package/dist/seed/grouped-listings-seed-data.d.ts +2 -0
- package/dist/seed/index.d.ts +2 -0
- package/dist/seed/index.js +2 -0
- package/dist/seed/manifest.js +20 -16
- package/dist/seed/payouts-seed-data.js +5 -5
- package/dist/seed/products-art-seed-data.d.ts +11 -0
- package/dist/seed/products-art-seed-data.js +125 -0
- package/dist/seed/products-preorders-seed-data.d.ts +2 -0
- package/dist/seed/products-stickers-seed-data.d.ts +11 -0
- package/dist/seed/products-stickers-seed-data.js +125 -0
- package/dist/seed/site-settings-seed-data.js +13 -4
- package/dist/seed/stores-seed-data.js +11 -11
- package/dist/server.d.ts +7 -15
- package/dist/server.js +17 -42
- package/dist/ui/rich-text/RichText.js +1 -1
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@ import { generatePayoutId, } from "../../../utils/id-generators";
|
|
|
5
5
|
export const PayoutStatusValues = {
|
|
6
6
|
PENDING: "pending",
|
|
7
7
|
PROCESSING: "processing",
|
|
8
|
-
|
|
8
|
+
PAID: "paid",
|
|
9
9
|
FAILED: "failed",
|
|
10
10
|
};
|
|
11
11
|
export const PAYOUT_COLLECTION = "payouts";
|
|
@@ -32,7 +32,7 @@ export const PAYOUT_FIELDS = {
|
|
|
32
32
|
STATUS_VALUES: {
|
|
33
33
|
PENDING: "pending",
|
|
34
34
|
PROCESSING: "processing",
|
|
35
|
-
|
|
35
|
+
PAID: "paid",
|
|
36
36
|
FAILED: "failed",
|
|
37
37
|
},
|
|
38
38
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from "./firestore";
|
|
2
2
|
export * from "./saved-methods-firestore";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
export declare const payoutStatusEnumSchema: z.ZodEnum<["pending", "processing", "
|
|
4
|
+
export declare const payoutStatusEnumSchema: z.ZodEnum<["pending", "processing", "paid", "failed"]>;
|
|
5
5
|
export declare const payoutPaymentMethodSchema: z.ZodEnum<["bank_transfer", "upi"]>;
|
|
6
6
|
export declare const payoutBankAccountSchema: z.ZodObject<{
|
|
7
7
|
accountHolderName: z.ZodString;
|
|
@@ -75,7 +75,7 @@ export declare const payoutFirestoreSchema: z.ZodObject<{
|
|
|
75
75
|
platformFee: z.ZodNumber;
|
|
76
76
|
platformFeeRate: z.ZodNumber;
|
|
77
77
|
currency: z.ZodString;
|
|
78
|
-
status: z.ZodEnum<["pending", "processing", "
|
|
78
|
+
status: z.ZodEnum<["pending", "processing", "paid", "failed"]>;
|
|
79
79
|
paymentMethod: z.ZodEnum<["bank_transfer", "upi"]>;
|
|
80
80
|
bankAccount: z.ZodOptional<z.ZodObject<{
|
|
81
81
|
accountHolderName: z.ZodString;
|
|
@@ -150,7 +150,7 @@ export declare const payoutFirestoreSchema: z.ZodObject<{
|
|
|
150
150
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
151
151
|
}, z.ZodTypeAny, "passthrough">>]>>;
|
|
152
152
|
}, "strip", z.ZodTypeAny, {
|
|
153
|
-
status: "pending" | "
|
|
153
|
+
status: "pending" | "paid" | "failed" | "processing";
|
|
154
154
|
currency: string;
|
|
155
155
|
storeId: string;
|
|
156
156
|
createdAt: string | Date | z.objectOutputType<{
|
|
@@ -200,7 +200,7 @@ export declare const payoutFirestoreSchema: z.ZodObject<{
|
|
|
200
200
|
toDate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodDate>;
|
|
201
201
|
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
202
202
|
}, {
|
|
203
|
-
status: "pending" | "
|
|
203
|
+
status: "pending" | "paid" | "failed" | "processing";
|
|
204
204
|
currency: string;
|
|
205
205
|
storeId: string;
|
|
206
206
|
createdAt: string | Date | z.objectInputType<{
|
|
@@ -252,7 +252,7 @@ export declare const payoutFirestoreSchema: z.ZodObject<{
|
|
|
252
252
|
}>;
|
|
253
253
|
export type PayoutFromSchema = z.infer<typeof payoutFirestoreSchema>;
|
|
254
254
|
/** Zod schema for payout status — use instead of inline `z.enum(["pending",...])`. */
|
|
255
|
-
export declare const payoutStatusSchema: z.ZodEnum<["pending", "processing", "
|
|
255
|
+
export declare const payoutStatusSchema: z.ZodEnum<["pending", "processing", "paid", "failed"]>;
|
|
256
256
|
/**
|
|
257
257
|
* Canonical payment gateway identifiers.
|
|
258
258
|
* Use these constants instead of bare string literals.
|
|
@@ -6,7 +6,7 @@ import { auditTimestampsShape, firestoreDateSchema, paiseSchema } from "../../..
|
|
|
6
6
|
// ─── Firestore document schema (W2) ───────────────────────────────────────────
|
|
7
7
|
// Mirrors PayoutDocument + PayoutRefundDeduction + PayoutBankAccount in
|
|
8
8
|
// ./firestore.ts. Registered into SCHEMAS.firestore.payouts.
|
|
9
|
-
export const payoutStatusEnumSchema = z.enum(["pending", "processing", "
|
|
9
|
+
export const payoutStatusEnumSchema = z.enum(["pending", "processing", "paid", "failed"]);
|
|
10
10
|
export const payoutPaymentMethodSchema = z.enum(["bank_transfer", "upi"]);
|
|
11
11
|
export const payoutBankAccountSchema = z.object({
|
|
12
12
|
accountHolderName: z.string(),
|
|
@@ -54,7 +54,7 @@ export const payoutFirestoreSchema = z.object({
|
|
|
54
54
|
export const payoutStatusSchema = z.enum([
|
|
55
55
|
"pending",
|
|
56
56
|
"processing",
|
|
57
|
-
"
|
|
57
|
+
"paid",
|
|
58
58
|
"failed",
|
|
59
59
|
]);
|
|
60
60
|
/**
|
|
@@ -18,6 +18,7 @@ import { storeRepository } from "../../../stores/repository/store.repository";
|
|
|
18
18
|
// SB-UNI-V — bundlesRepository deleted; bundle stock-sync moves to the
|
|
19
19
|
// `onProductStockChange` Firebase Function (see functions/src/bundle-stock-sync.ts).
|
|
20
20
|
import { sanitizeProductForPublic } from "../../utils/sanitize";
|
|
21
|
+
import { printMetaSchema } from "../../schemas/index";
|
|
21
22
|
import { isAdminUser, isModeratorUser } from "../../../auth/role-predicates";
|
|
22
23
|
import { normalizeError } from "../../../../errors/normalize";
|
|
23
24
|
const ERR_DB_NOT_REGISTERED = "Database provider not registered";
|
|
@@ -52,8 +53,10 @@ const productUpdateSchema = z
|
|
|
52
53
|
tags: z.array(z.string()).optional(),
|
|
53
54
|
featured: z.boolean().optional(),
|
|
54
55
|
isPromoted: z.boolean().optional(),
|
|
56
|
+
allowShipBeforeEmiComplete: z.boolean().optional(),
|
|
57
|
+
printMeta: printMetaSchema.optional(),
|
|
55
58
|
listingType: z
|
|
56
|
-
.enum(["standard", "auction", "pre-order", "prize-draw", "bundle", "classified", "digital-code", "live"])
|
|
59
|
+
.enum(["standard", "auction", "pre-order", "prize-draw", "bundle", "classified", "digital-code", "live", "art", "stickers"])
|
|
57
60
|
.optional(),
|
|
58
61
|
media: z.array(mediaFieldSchema).optional(),
|
|
59
62
|
})
|
|
@@ -17,6 +17,7 @@ import { z } from "zod";
|
|
|
17
17
|
import { getProviders } from "../../../contracts";
|
|
18
18
|
import { createRouteHandler } from "../../../next";
|
|
19
19
|
import { mediaFieldSchema } from "../../media/types/index";
|
|
20
|
+
import { printMetaSchema } from "../schemas/index";
|
|
20
21
|
import { sanitizeProductsForPublic } from "../utils/sanitize";
|
|
21
22
|
import { normalizeError } from "../../../errors/normalize";
|
|
22
23
|
// --- Mutation schemas ---------------------------------------------------------
|
|
@@ -42,12 +43,14 @@ const productMutateSchema = z
|
|
|
42
43
|
tags: z.array(z.string()).optional(),
|
|
43
44
|
featured: z.boolean().optional(),
|
|
44
45
|
isPromoted: z.boolean().optional(),
|
|
46
|
+
allowShipBeforeEmiComplete: z.boolean().optional(),
|
|
47
|
+
printMeta: printMetaSchema.optional(),
|
|
45
48
|
sellerId: z.string().optional(),
|
|
46
49
|
sellerName: z.string().optional(),
|
|
47
50
|
sellerEmail: z.string().email().optional(),
|
|
48
51
|
slug: z.string().optional(),
|
|
49
52
|
listingType: z
|
|
50
|
-
.enum(["standard", "auction", "pre-order", "prize-draw", "bundle", "classified", "digital-code", "live"])
|
|
53
|
+
.enum(["standard", "auction", "pre-order", "prize-draw", "bundle", "classified", "digital-code", "live", "art", "stickers"])
|
|
51
54
|
.optional(),
|
|
52
55
|
media: z.array(mediaFieldSchema).optional(),
|
|
53
56
|
})
|
|
@@ -14,10 +14,10 @@ import Link from "next/link";
|
|
|
14
14
|
import { X } from "lucide-react";
|
|
15
15
|
import { Button, Div, Heading, Row, Span, Stack, Text } from "../../../ui";
|
|
16
16
|
import { useSwipe } from "../../../react/hooks/useSwipe";
|
|
17
|
-
import { ROUTES } from "../../../next";
|
|
18
17
|
import { formatCurrency } from "../../../utils/number.formatter";
|
|
19
18
|
import { COMPARE_MAX_ITEMS } from "../constants/action-defs";
|
|
20
|
-
import {
|
|
19
|
+
import { normalizeListingType } from "../utils/listing-type";
|
|
20
|
+
import { pluginFor } from "../../../_internal/shared/listing-types/_registry";
|
|
21
21
|
const DEFAULT_LABELS = {
|
|
22
22
|
title: "Compare items",
|
|
23
23
|
empty: "Select up to 4 items from the listing to compare.",
|
|
@@ -40,13 +40,11 @@ const CHIP_CLASS = "inline-flex items-center rounded-full bg-[var(--appkit-color
|
|
|
40
40
|
const COLUMN_CARD_CLASS = "flex flex-col gap-3 rounded-xl border border-[var(--appkit-color-border-subtle)] bg-[var(--appkit-color-surface)] p-3";
|
|
41
41
|
function detailHref(item, type) {
|
|
42
42
|
const id = item.slug ?? item.id;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
return String(ROUTES.PUBLIC.PRODUCT_DETAIL(id));
|
|
43
|
+
// The caller-supplied `type` hint takes precedence — some compare contexts
|
|
44
|
+
// (e.g. an auction comparison page) feed items that don't carry their own
|
|
45
|
+
// `listingType` field, so the hint is the only signal available.
|
|
46
|
+
const listingType = type === "auction" ? "auction" : type === "preorder" ? "pre-order" : normalizeListingType(item);
|
|
47
|
+
return pluginFor(listingType).detailRoute(id);
|
|
50
48
|
}
|
|
51
49
|
function priceLabel(item) {
|
|
52
50
|
if (typeof item.price !== "number")
|
|
@@ -42,5 +42,7 @@ export interface ProductDetailPageViewProps {
|
|
|
42
42
|
* legacy bullets render unchanged.
|
|
43
43
|
*/
|
|
44
44
|
productFeatures?: ProductFeatureDocument[];
|
|
45
|
+
/** Site-wide COD availability (`siteSettings.payment.codEnabled`), threaded from the page's data layer. Drives the "Cash on Delivery" feature badge. */
|
|
46
|
+
codEnabled?: boolean;
|
|
45
47
|
}
|
|
46
|
-
export declare function ProductDetailPageView({ slug, initialProduct, renderOfferAction, renderPrimaryActions, productFeatures, }: ProductDetailPageViewProps): Promise<import("react/jsx-runtime").JSX.Element>;
|
|
48
|
+
export declare function ProductDetailPageView({ slug, initialProduct, renderOfferAction, renderPrimaryActions, productFeatures, codEnabled, }: ProductDetailPageViewProps): Promise<import("react/jsx-runtime").JSX.Element>;
|
|
@@ -106,7 +106,7 @@ function StarRating({ value }) {
|
|
|
106
106
|
// ---------------------------------------------------------------------------
|
|
107
107
|
// Component
|
|
108
108
|
// ---------------------------------------------------------------------------
|
|
109
|
-
export async function ProductDetailPageView({ slug, initialProduct, renderOfferAction, renderPrimaryActions, productFeatures, }) {
|
|
109
|
+
export async function ProductDetailPageView({ slug, initialProduct, renderOfferAction, renderPrimaryActions, productFeatures, codEnabled, }) {
|
|
110
110
|
// Use pre-fetched data when available to avoid a redundant repository call.
|
|
111
111
|
// The page layer wraps getProductForDetail in React.cache(), so both
|
|
112
112
|
// generateMetadata() and this component share the same in-flight promise.
|
|
@@ -262,7 +262,7 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
|
|
|
262
262
|
? ` — only ${effectiveStock} left`
|
|
263
263
|
: ""] })] })) : (_jsxs(Span, { layout: "inline-flex", gap: "xs", className: `w-fit .5 ${inStock ? CLS_STOCK_IN : CLS_STOCK_OUT}`, rounded: "full", padding: "pill-md", size: "xs", weight: "medium", children: [inStock ? "✓ In Stock" : "✗ Out of Stock", inStock && effectiveStock !== null && effectiveStock <= 10
|
|
264
264
|
? ` — only ${effectiveStock} left`
|
|
265
|
-
: ""] })), (categorySlugs.length > 0 || subcategory || brand) && (_jsxs(Row, { gap: "sm", wrap: true, children: [categorySlugs.map((slug, i) => (_jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(slug)), className: "inline-flex items-center rounded-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-2.5 py-1 text-xs font-medium text-[var(--appkit-color-text-muted)] transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: categoryNames[i] ?? slug }, slug))), subcategory && (_jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", border: "subtle", rounded: "full", padding: "pill-sm-tall", surface: "muted", color: "muted", transform: "capitalize", children: subcategory })), brand && brandSlug && (_jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "inline-flex items-center rounded-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-2.5 py-1 text-xs font-medium text-[var(--appkit-color-text-muted)] transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: brand })), brand && !brandSlug && (_jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", border: "subtle", rounded: "full", padding: "pill-sm-tall", surface: "muted", color: "muted", children: brand }))] })), bundleMemberships.length > 0 && (_jsx(Row, { gap: "sm", wrap: true, children: bundleMemberships.map((b) => (_jsxs(Link, { href: String(ROUTES.PUBLIC.BUNDLE_DETAIL(b.id)), className: CLS_BUNDLE_PILL, children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDCE6" }), "In bundle: ", b.title] }, b.id))) })), _jsx(ProductFeatureBadges, { featured: featured, freeShipping: freeShipping, condition: condition ?? undefined, returnable: returnPolicy != null && returnPolicy.length > 0, labels: {
|
|
265
|
+
: ""] })), (categorySlugs.length > 0 || subcategory || brand) && (_jsxs(Row, { gap: "sm", wrap: true, children: [categorySlugs.map((slug, i) => (_jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(slug)), className: "inline-flex items-center rounded-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-2.5 py-1 text-xs font-medium text-[var(--appkit-color-text-muted)] transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: categoryNames[i] ?? slug }, slug))), subcategory && (_jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", border: "subtle", rounded: "full", padding: "pill-sm-tall", surface: "muted", color: "muted", transform: "capitalize", children: subcategory })), brand && brandSlug && (_jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "inline-flex items-center rounded-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-2.5 py-1 text-xs font-medium text-[var(--appkit-color-text-muted)] transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: brand })), brand && !brandSlug && (_jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", border: "subtle", rounded: "full", padding: "pill-sm-tall", surface: "muted", color: "muted", children: brand }))] })), bundleMemberships.length > 0 && (_jsx(Row, { gap: "sm", wrap: true, children: bundleMemberships.map((b) => (_jsxs(Link, { href: String(ROUTES.PUBLIC.BUNDLE_DETAIL(b.id)), className: CLS_BUNDLE_PILL, children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDCE6" }), "In bundle: ", b.title] }, b.id))) })), _jsx(ProductFeatureBadges, { featured: featured, freeShipping: freeShipping, codAvailable: codEnabled === true, condition: condition ?? undefined, returnable: returnPolicy != null && returnPolicy.length > 0, labels: {
|
|
266
266
|
featured: "Featured",
|
|
267
267
|
fasterDelivery: "Faster Delivery",
|
|
268
268
|
ratedSeller: "Rated Seller",
|
|
@@ -12,8 +12,23 @@ import { useMediaUpload } from "../../media";
|
|
|
12
12
|
import { resolveDate } from "../../../utils/date.formatter";
|
|
13
13
|
import { normalizeRichTextHtml } from "../../../utils/string.formatter";
|
|
14
14
|
import { useListingTypeFlags } from "../../../react/hooks/useListingTypeFlags";
|
|
15
|
-
import { isAuctionListing, isPreOrderListing, isPrizeDrawListing, } from "../utils/listing-type";
|
|
15
|
+
import { isAuctionListing, isPreOrderListing, isPrizeDrawListing, normalizeListingType, } from "../utils/listing-type";
|
|
16
16
|
import { PrizeDrawItemsEditor } from "./PrizeDrawItemsEditor";
|
|
17
|
+
// ListingType uses the canonical SB1-G spellings ("standard", "pre-order");
|
|
18
|
+
// ProductFeatureProductType predates it with legacy spellings for 2 values.
|
|
19
|
+
// Replaces the old 2-case ternary that silently mapped every other type
|
|
20
|
+
// (classified/digital-code/live/prize-draw/art/stickers) to "product".
|
|
21
|
+
const LISTING_TYPE_TO_FEATURE_PRODUCT_TYPE = {
|
|
22
|
+
standard: "product",
|
|
23
|
+
auction: "auction",
|
|
24
|
+
"pre-order": "preorder",
|
|
25
|
+
"prize-draw": "prize-draw",
|
|
26
|
+
classified: "classified",
|
|
27
|
+
"digital-code": "digital-code",
|
|
28
|
+
live: "live",
|
|
29
|
+
art: "art",
|
|
30
|
+
stickers: "stickers",
|
|
31
|
+
};
|
|
17
32
|
export const PRODUCT_STATUS_OPTIONS = [
|
|
18
33
|
{ value: "draft", label: "Draft" },
|
|
19
34
|
{ value: "published", label: "Published" },
|
|
@@ -122,7 +137,7 @@ export function ProductForm({ product, onChange, isReadonly = false, renderDescr
|
|
|
122
137
|
.split(",")
|
|
123
138
|
.map((tag) => tag.trim())
|
|
124
139
|
.filter(Boolean),
|
|
125
|
-
}), disabled: isReadonly, placeholder: t("formTagsPlaceholder") }), _jsxs(FormGroup, { columns: 2, children: [_jsx(Checkbox, { label: t("formFeatured"), checked: !!product.featured, onChange: (e) => update({ featured: e.target.checked }), disabled: isReadonly }), _jsx(Checkbox, { label: t("formIsPromoted"), checked: !!product.isPromoted, onChange: (e) => update({ isPromoted: e.target.checked }), disabled: isReadonly })] }), _jsx(Heading, { level: 4, className: "mt-4", children: t("sectionConditionShipping") }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "condition", label: t("formCondition"), type: "select", value: product.condition || "new", onChange: (value) => update({
|
|
140
|
+
}), disabled: isReadonly, placeholder: t("formTagsPlaceholder") }), _jsxs(FormGroup, { columns: 2, children: [_jsx(Checkbox, { label: t("formFeatured"), checked: !!product.featured, onChange: (e) => update({ featured: e.target.checked }), disabled: isReadonly }), _jsx(Checkbox, { label: t("formIsPromoted"), checked: !!product.isPromoted, onChange: (e) => update({ isPromoted: e.target.checked }), disabled: isReadonly }), _jsx(Checkbox, { label: t("formAllowShipBeforeEmiComplete"), checked: !!product.allowShipBeforeEmiComplete, onChange: (e) => update({ allowShipBeforeEmiComplete: e.target.checked }), disabled: isReadonly })] }), _jsx(Heading, { level: 4, className: "mt-4", children: t("sectionConditionShipping") }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "condition", label: t("formCondition"), type: "select", value: product.condition || "new", onChange: (value) => update({
|
|
126
141
|
condition: value,
|
|
127
142
|
}), disabled: isReadonly, options: [
|
|
128
143
|
{ value: "new", label: t("formConditionNew") },
|
|
@@ -199,11 +214,7 @@ export function ProductForm({ product, onChange, isReadonly = false, renderDescr
|
|
|
199
214
|
value: product.groupId,
|
|
200
215
|
onChange: (id) => update({ groupId: id || undefined }),
|
|
201
216
|
disabled: isReadonly,
|
|
202
|
-
}), !isAuctionListing(product) && renderGroupSettings?.(product), _jsx(ProductFeaturesSelector, { value: product.features ?? [], onChange: (features) => update({ features }), productType: (
|
|
203
|
-
? "auction"
|
|
204
|
-
: isPreOrderListing(product)
|
|
205
|
-
? "preorder"
|
|
206
|
-
: "product"), storeId: product.storeId, disabled: isReadonly }), _jsxs(Div, { children: [_jsx(Heading, { level: 3, className: "mb-1", color: "muted", size: "sm", weight: "semibold", children: "Custom Sections" }), _jsx(Text, { className: "mb-3", color: "muted", size: "xs", children: "Add up to 3 custom tabs to your product page \u2014 e.g. \"Box Contents\", \"Compatibility\", \"Grading Details\"." }), _jsx(CustomSectionsEditor, { sections: product.customSections ?? [], onChange: (sections) => update({ customSections: sections }) })] }), _jsx(FormField, { name: "shippingInfo", label: t("formShipping"), type: "textarea", value: product.shippingInfo || "", onChange: (value) => update({ shippingInfo: value }), disabled: isReadonly, placeholder: "Shipping information..." }), _jsx(FormField, { name: "returnPolicy", label: t("formReturnPolicy"), type: "textarea", value: product.returnPolicy || "", onChange: (value) => update({ returnPolicy: value }), disabled: isReadonly, placeholder: "Return policy details..." }), _jsxs(Div, { children: [_jsx(Heading, { level: 3, className: "mb-1", color: "muted", size: "sm", weight: "semibold", children: "Physical Inventory" }), _jsx(Text, { className: "mb-3", color: "muted", size: "xs", children: "Assign a storage location for warehouse or shelf organisation. Used by the Print & Label Center." }), _jsxs(FormGroup, { columns: 3, children: [_jsx(FormField, { name: "physicalLocation.zone", label: "Zone", type: "text", placeholder: "e.g. A", value: product.physicalLocation?.zone ?? "", onChange: (v) => update({
|
|
217
|
+
}), !isAuctionListing(product) && renderGroupSettings?.(product), _jsx(ProductFeaturesSelector, { value: product.features ?? [], onChange: (features) => update({ features }), productType: LISTING_TYPE_TO_FEATURE_PRODUCT_TYPE[normalizeListingType(product)], storeId: product.storeId, disabled: isReadonly }), _jsxs(Div, { children: [_jsx(Heading, { level: 3, className: "mb-1", color: "muted", size: "sm", weight: "semibold", children: "Custom Sections" }), _jsx(Text, { className: "mb-3", color: "muted", size: "xs", children: "Add up to 3 custom tabs to your product page \u2014 e.g. \"Box Contents\", \"Compatibility\", \"Grading Details\"." }), _jsx(CustomSectionsEditor, { sections: product.customSections ?? [], onChange: (sections) => update({ customSections: sections }) })] }), _jsx(FormField, { name: "shippingInfo", label: t("formShipping"), type: "textarea", value: product.shippingInfo || "", onChange: (value) => update({ shippingInfo: value }), disabled: isReadonly, placeholder: "Shipping information..." }), _jsx(FormField, { name: "returnPolicy", label: t("formReturnPolicy"), type: "textarea", value: product.returnPolicy || "", onChange: (value) => update({ returnPolicy: value }), disabled: isReadonly, placeholder: "Return policy details..." }), _jsxs(Div, { children: [_jsx(Heading, { level: 3, className: "mb-1", color: "muted", size: "sm", weight: "semibold", children: "Physical Inventory" }), _jsx(Text, { className: "mb-3", color: "muted", size: "xs", children: "Assign a storage location for warehouse or shelf organisation. Used by the Print & Label Center." }), _jsxs(FormGroup, { columns: 3, children: [_jsx(FormField, { name: "physicalLocation.zone", label: "Zone", type: "text", placeholder: "e.g. A", value: product.physicalLocation?.zone ?? "", onChange: (v) => update({
|
|
207
218
|
physicalLocation: {
|
|
208
219
|
zone: v,
|
|
209
220
|
shelf: product.physicalLocation?.shelf ?? "",
|
|
@@ -11,15 +11,14 @@ import { useLongPress } from "../../../react/hooks/useLongPress";
|
|
|
11
11
|
import { FeatureBadgeList } from "./FeatureBadge";
|
|
12
12
|
import { useProductFeatures } from "./ProductFeaturesContext";
|
|
13
13
|
import { PRODUCT_FEATURE_CARD_MAX_VISIBLE } from "../constants/product-features.constants";
|
|
14
|
-
import {
|
|
14
|
+
import { normalizeListingType } from "../utils/listing-type";
|
|
15
|
+
import { pluginFor } from "../../../_internal/shared/listing-types/_registry";
|
|
15
16
|
const __P = {
|
|
16
17
|
p3: "p-3",
|
|
17
18
|
};
|
|
18
19
|
const __O = {
|
|
19
20
|
hidden: "overflow-hidden",
|
|
20
21
|
};
|
|
21
|
-
const CLS_BADGE_AUCTION = "bg-warning-surface text-white";
|
|
22
|
-
const CLS_BADGE_PREORDER = "bg-violet-600 text-white";
|
|
23
22
|
const CLS_BADGE_NEW = "rounded-full bg-error-surface px-2 py-0.5 text-[10px] text-white shadow-sm";
|
|
24
23
|
const CLS_BADGE_SALE = "rounded-full bg-success-surface px-2 py-0.5 text-[10px] font-bold text-white shadow-sm";
|
|
25
24
|
const CLS_BADGE_TRENDING = "rounded-full bg-indigo-600 px-2 py-0.5 text-[10px] font-bold text-white shadow-sm";
|
|
@@ -38,14 +37,10 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
|
|
|
38
37
|
? Math.round(((product.originalPrice - product.price) / product.originalPrice) *
|
|
39
38
|
100)
|
|
40
39
|
: null;
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
? { label: "Auction", cls: CLS_BADGE_AUCTION }
|
|
46
|
-
: isPreOrder
|
|
47
|
-
? { label: "Pre-Order", cls: CLS_BADGE_PREORDER }
|
|
48
|
-
: null;
|
|
40
|
+
const listingPlugin = pluginFor(normalizeListingType(product));
|
|
41
|
+
const typeBadge = listingPlugin.badge
|
|
42
|
+
? { label: listingPlugin.badge.label, cls: listingPlugin.badge.className }
|
|
43
|
+
: null;
|
|
49
44
|
const longPress = useLongPress(() => onSelect?.(product.id));
|
|
50
45
|
const featuresList = useProductFeatures();
|
|
51
46
|
const handleCardClick = selectionMode
|
|
@@ -97,7 +92,7 @@ export function ProductCard({ product, href, onClick, onAddToWishlist, isWishlis
|
|
|
97
92
|
return seller ? (_jsxs(Text, { className: "mt-0.5 text-[11px]", color: "faint", children: ["by ", seller] })) : null;
|
|
98
93
|
})(), product.rating !== undefined && (_jsxs(Row, { className: "mt-1", gap: "xs", children: [_jsx(Span, { className: CLS_STAR, children: "\u2605" }), _jsxs(Span, { className: "text-[11px]", color: "muted", children: [product.rating.toFixed(1), product.reviewCount ? ` (${product.reviewCount})` : ""] })] })), _jsxs(Div, { className: "mt-auto", padding: "t-xs", children: [_jsxs(Row, { align: "baseline", gap: "sm", children: [_jsx(Span, { size: "base", weight: "bold", className: "text-primary dark:text-primary-400", children: formatCurrency(product.price, getDefaultCurrency()) }), product.originalPrice && product.originalPrice > product.price && (_jsx(Span, { size: "xs", className: "line-through", color: "faint", children: formatCurrency(product.originalPrice, getDefaultCurrency()) }))] }), (() => {
|
|
99
94
|
const stock = product.stockCount ?? product.stockQuantity ?? product.availableQuantity;
|
|
100
|
-
if (stock === undefined ||
|
|
95
|
+
if (stock === undefined || !listingPlugin.showsStockQuantity)
|
|
101
96
|
return null;
|
|
102
97
|
if (stock <= 0) {
|
|
103
98
|
return (_jsx(Text, { className: CLS_DISCOUNT_TEXT, children: "Out of stock" }));
|
|
@@ -2,20 +2,18 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import Link from "next/link";
|
|
5
|
-
import { ROUTES } from "../../../next";
|
|
6
5
|
import { Div, Row, Span, Table, Thead, Tbody, Tr, Th, Td, Text, Modal, SideDrawer, Button } from "../../../ui";
|
|
7
6
|
import { MediaImage } from "../../media/MediaImage";
|
|
8
7
|
import { formatCurrency } from "../../../utils/number.formatter";
|
|
9
|
-
import {
|
|
8
|
+
import { normalizeListingType } from "../utils/listing-type";
|
|
9
|
+
import { pluginFor } from "../../../_internal/shared/listing-types/_registry";
|
|
10
10
|
const __O = {
|
|
11
11
|
hidden: "overflow-hidden",
|
|
12
12
|
xAuto: "overflow-x-auto",
|
|
13
13
|
};
|
|
14
14
|
function memberHref(m) {
|
|
15
15
|
const slug = m.slug ?? m.id;
|
|
16
|
-
|
|
17
|
-
return String(ROUTES.PUBLIC.PRE_ORDER_DETAIL(slug));
|
|
18
|
-
return String(ROUTES.PUBLIC.PRODUCT_DETAIL(slug));
|
|
16
|
+
return pluginFor(normalizeListingType(m)).detailRoute(slug);
|
|
19
17
|
}
|
|
20
18
|
function MemberThumb({ member, isCurrent }) {
|
|
21
19
|
const image = member.images?.[0] ?? "";
|
|
@@ -5,18 +5,15 @@ import Link from "next/link";
|
|
|
5
5
|
import { ROUTES } from "../../../next";
|
|
6
6
|
import { Div, Row, Span, Text } from "../../../ui";
|
|
7
7
|
import { formatCurrency } from "../../../utils/number.formatter";
|
|
8
|
-
import {
|
|
8
|
+
import { normalizeListingType } from "../utils/listing-type";
|
|
9
|
+
import { pluginFor } from "../../../_internal/shared/listing-types/_registry";
|
|
9
10
|
const __O = {
|
|
10
11
|
hidden: "overflow-hidden",
|
|
11
12
|
xAuto: "overflow-x-auto",
|
|
12
13
|
};
|
|
13
14
|
function getHref(listing) {
|
|
14
15
|
const slug = listing.slug ?? listing.id;
|
|
15
|
-
|
|
16
|
-
return String(ROUTES.PUBLIC.AUCTION_DETAIL(slug));
|
|
17
|
-
if (isPreOrderListing(listing))
|
|
18
|
-
return String(ROUTES.PUBLIC.PRE_ORDER_DETAIL(slug));
|
|
19
|
-
return String(ROUTES.PUBLIC.PRODUCT_DETAIL(slug));
|
|
16
|
+
return pluginFor(normalizeListingType(listing)).detailRoute(slug);
|
|
20
17
|
}
|
|
21
18
|
function ListingThumb({ listing, isCurrent, }) {
|
|
22
19
|
const image = listing.images?.[0] ?? listing.mainImage ?? "";
|
|
@@ -52,6 +52,14 @@ export declare const CATEGORY_PAGE_TABS: readonly [{
|
|
|
52
52
|
readonly id: "live";
|
|
53
53
|
readonly label: "Live Items";
|
|
54
54
|
readonly listingType: "live";
|
|
55
|
+
}, {
|
|
56
|
+
readonly id: "art";
|
|
57
|
+
readonly label: "Art";
|
|
58
|
+
readonly listingType: "art";
|
|
59
|
+
}, {
|
|
60
|
+
readonly id: "stickers";
|
|
61
|
+
readonly label: "Stickers";
|
|
62
|
+
readonly listingType: "stickers";
|
|
55
63
|
}, {
|
|
56
64
|
readonly id: "stores";
|
|
57
65
|
readonly label: "Stores";
|
|
@@ -91,6 +99,14 @@ export declare const STORE_PAGE_TABS: readonly [{
|
|
|
91
99
|
readonly id: "live";
|
|
92
100
|
readonly label: "Live Items";
|
|
93
101
|
readonly listingType: "live";
|
|
102
|
+
}, {
|
|
103
|
+
readonly id: "art";
|
|
104
|
+
readonly label: "Art";
|
|
105
|
+
readonly listingType: "art";
|
|
106
|
+
}, {
|
|
107
|
+
readonly id: "stickers";
|
|
108
|
+
readonly label: "Stickers";
|
|
109
|
+
readonly listingType: "stickers";
|
|
94
110
|
}];
|
|
95
111
|
export type StoreTabId = (typeof STORE_PAGE_TABS)[number]["id"];
|
|
96
112
|
/** Tabs shown on the seller-dashboard listings view + admin products list. */
|
|
@@ -125,6 +141,14 @@ export declare const SELLER_LISTING_TABS: readonly [{
|
|
|
125
141
|
readonly id: "live";
|
|
126
142
|
readonly label: "Live Items";
|
|
127
143
|
readonly listingType: "live";
|
|
144
|
+
}, {
|
|
145
|
+
readonly id: "art";
|
|
146
|
+
readonly label: "Art";
|
|
147
|
+
readonly listingType: "art";
|
|
148
|
+
}, {
|
|
149
|
+
readonly id: "stickers";
|
|
150
|
+
readonly label: "Stickers";
|
|
151
|
+
readonly listingType: "stickers";
|
|
128
152
|
}];
|
|
129
153
|
export type SellerListingTabId = (typeof SELLER_LISTING_TABS)[number]["id"];
|
|
130
154
|
/** Tabs shown on `/search` results. */
|
|
@@ -163,5 +187,13 @@ export declare const SEARCH_RESULT_TABS: readonly [{
|
|
|
163
187
|
readonly id: "live";
|
|
164
188
|
readonly label: "Live Items";
|
|
165
189
|
readonly listingType: "live";
|
|
190
|
+
}, {
|
|
191
|
+
readonly id: "art";
|
|
192
|
+
readonly label: "Art";
|
|
193
|
+
readonly listingType: "art";
|
|
194
|
+
}, {
|
|
195
|
+
readonly id: "stickers";
|
|
196
|
+
readonly label: "Stickers";
|
|
197
|
+
readonly listingType: "stickers";
|
|
166
198
|
}];
|
|
167
199
|
export type SearchTabId = (typeof SEARCH_RESULT_TABS)[number]["id"];
|
|
@@ -18,6 +18,8 @@ export const CATEGORY_PAGE_TABS = [
|
|
|
18
18
|
{ id: "classifieds", label: "Classifieds", listingType: "classified" },
|
|
19
19
|
{ id: "digital-codes", label: "Digital Codes", listingType: "digital-code" },
|
|
20
20
|
{ id: "live", label: "Live Items", listingType: "live" },
|
|
21
|
+
{ id: "art", label: "Art", listingType: "art" },
|
|
22
|
+
{ id: "stickers", label: "Stickers", listingType: "stickers" },
|
|
21
23
|
{ id: "stores", label: "Stores", entity: "stores" },
|
|
22
24
|
];
|
|
23
25
|
/** Tabs shown on the public `/stores/[slug]` nav bar. */
|
|
@@ -30,6 +32,8 @@ export const STORE_PAGE_TABS = [
|
|
|
30
32
|
{ id: "classifieds", label: "Classifieds", listingType: "classified" },
|
|
31
33
|
{ id: "digital-codes", label: "Digital Codes", listingType: "digital-code" },
|
|
32
34
|
{ id: "live", label: "Live Items", listingType: "live" },
|
|
35
|
+
{ id: "art", label: "Art", listingType: "art" },
|
|
36
|
+
{ id: "stickers", label: "Stickers", listingType: "stickers" },
|
|
33
37
|
];
|
|
34
38
|
/** Tabs shown on the seller-dashboard listings view + admin products list. */
|
|
35
39
|
export const SELLER_LISTING_TABS = [
|
|
@@ -41,6 +45,8 @@ export const SELLER_LISTING_TABS = [
|
|
|
41
45
|
{ id: "classifieds", label: "Classifieds", listingType: "classified" },
|
|
42
46
|
{ id: "digital-codes", label: "Digital Codes", listingType: "digital-code" },
|
|
43
47
|
{ id: "live", label: "Live Items", listingType: "live" },
|
|
48
|
+
{ id: "art", label: "Art", listingType: "art" },
|
|
49
|
+
{ id: "stickers", label: "Stickers", listingType: "stickers" },
|
|
44
50
|
];
|
|
45
51
|
/** Tabs shown on `/search` results. */
|
|
46
52
|
export const SEARCH_RESULT_TABS = [
|
|
@@ -53,4 +59,6 @@ export const SEARCH_RESULT_TABS = [
|
|
|
53
59
|
{ id: "classifieds", label: "Classifieds", listingType: "classified" },
|
|
54
60
|
{ id: "digital-codes", label: "Digital Codes", listingType: "digital-code" },
|
|
55
61
|
{ id: "live", label: "Live Items", listingType: "live" },
|
|
62
|
+
{ id: "art", label: "Art", listingType: "art" },
|
|
63
|
+
{ id: "stickers", label: "Stickers", listingType: "stickers" },
|
|
56
64
|
];
|
|
@@ -9,5 +9,5 @@ export * from "./components";
|
|
|
9
9
|
export * from "./schemas";
|
|
10
10
|
export * from "./columns";
|
|
11
11
|
export { manifest } from "./manifest";
|
|
12
|
-
export { normalizeListingType, isAuctionListing, isPreOrderListing, isStandardListing, isPrizeDrawListing, isClassifiedListing, isDigitalCodeListing, isLiveListing, } from "./utils/listing-type";
|
|
12
|
+
export { normalizeListingType, isAuctionListing, isPreOrderListing, isStandardListing, isPrizeDrawListing, isClassifiedListing, isDigitalCodeListing, isLiveListing, isArtListing, isStickersListing, } from "./utils/listing-type";
|
|
13
13
|
export { sanitizeProductForPublic, sanitizeProductsForPublic, } from "./utils/sanitize";
|
|
@@ -11,5 +11,7 @@ export * from "./columns";
|
|
|
11
11
|
export { manifest } from "./manifest";
|
|
12
12
|
export { normalizeListingType, isAuctionListing, isPreOrderListing, isStandardListing, isPrizeDrawListing,
|
|
13
13
|
// SB-UNI-F 2026-05-13 — Phase 2 predicates.
|
|
14
|
-
isClassifiedListing, isDigitalCodeListing, isLiveListing,
|
|
14
|
+
isClassifiedListing, isDigitalCodeListing, isLiveListing,
|
|
15
|
+
// Art/stickers session.
|
|
16
|
+
isArtListing, isStickersListing, } from "./utils/listing-type";
|
|
15
17
|
export { sanitizeProductForPublic, sanitizeProductsForPublic, } from "./utils/sanitize";
|
|
@@ -105,6 +105,21 @@ export interface ProductLiveItemMeta {
|
|
|
105
105
|
/** CITES permit number (Appendix I/II species). */
|
|
106
106
|
cites?: string;
|
|
107
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Print-specific metadata shared by the "art" and "stickers" listing types
|
|
110
|
+
* (both are printed-only physical goods). Every field optional so partial
|
|
111
|
+
* seller input still saves.
|
|
112
|
+
*/
|
|
113
|
+
export interface ProductPrintMeta {
|
|
114
|
+
/** e.g. "A4", "12x18 in", "5x5 cm sheet". */
|
|
115
|
+
size?: string;
|
|
116
|
+
/** e.g. "Matte photo paper", "Vinyl", "Canvas". */
|
|
117
|
+
material?: string;
|
|
118
|
+
/** e.g. "Glossy", "Matte", "Holographic". */
|
|
119
|
+
finish?: string;
|
|
120
|
+
/** Limited-edition print run size; omitted for open editions. */
|
|
121
|
+
editionSize?: number;
|
|
122
|
+
}
|
|
108
123
|
export interface ProductDocument extends BaseDocument {
|
|
109
124
|
title: string;
|
|
110
125
|
description: string;
|
|
@@ -178,6 +193,10 @@ export interface ProductDocument extends BaseDocument {
|
|
|
178
193
|
isPromoted?: boolean;
|
|
179
194
|
isOnSale?: boolean;
|
|
180
195
|
isSold?: boolean;
|
|
196
|
+
/** When true, an EMI order for this product ships as soon as it's confirmed instead of waiting for every installment to be paid. Default false. */
|
|
197
|
+
allowShipBeforeEmiComplete?: boolean;
|
|
198
|
+
/** Print-specific metadata for "art" / "stickers" listings — printed-only physical goods. Optional on every listing type; only populated for art/stickers. */
|
|
199
|
+
printMeta?: ProductPrintMeta;
|
|
181
200
|
promotionEndDate?: Date;
|
|
182
201
|
pickupAddressId?: string;
|
|
183
202
|
viewCount?: number;
|
|
@@ -313,7 +332,7 @@ export declare const PRODUCT_COLLECTION: "products";
|
|
|
313
332
|
export declare const PRODUCT_INDEXED_FIELDS: readonly ["storeId", "status", "category", "featured", "listingType", "isPromoted", "isOnSale", "isSold", "searchTokens", "createdAt", "barcodeId"];
|
|
314
333
|
export declare const DEFAULT_PRODUCT_DATA: Partial<ProductDocument>;
|
|
315
334
|
export declare const PRODUCT_PUBLIC_FIELDS: readonly ["id", "title", "description", "category", "subcategory", "brand", "price", "currency", "stockQuantity", "availableQuantity", "images", "status", "storeName", "featured", "tags", "specifications", "features", "shippingInfo", "returnPolicy", "listingType", "auctionEndDate", "startingBid", "currentBid", "bidCount", "reservePrice", "buyNowPrice", "minBidIncrement", "autoExtendable", "auctionExtensionMinutes", "auctionShippingPaidBy", "buyItNowPriceInPaise", "bidsHaveStarted", "grading", "card", "classified", "digitalCode", "liveItem", "catalogProductId", "preOrderDeliveryDate", "preOrderDepositPercent", "preOrderDepositAmount", "preOrderMaxQuantity", "preOrderCurrentCount", "preOrderProductionStatus", "preOrderCancellable", "condition", "insurance", "insuranceCost", "shippingPaidBy", "isPromoted", "isOnSale", "isSold", "slug", "seoTitle", "seoDescription", "seoKeywords", "viewCount", "customFields", "customSections", "sublistingCategoryId", "groupId", "isGroupParent", "groupParentSlug", "groupChildSlugs", "groupTitle", "createdAt"];
|
|
316
|
-
export declare const PRODUCT_UPDATABLE_FIELDS: readonly ["title", "description", "category", "subcategory", "brand", "price", "stockQuantity", "images", "status", "tags", "specifications", "features", "shippingInfo", "returnPolicy", "pickupAddressId", "condition", "insurance", "shippingPaidBy", "autoExtendable", "auctionExtensionMinutes", "auctionShippingPaidBy", "reservePrice", "buyNowPrice", "minBidIncrement", "buyItNowPriceInPaise", "bidsHaveStarted", "grading", "card", "classified", "digitalCode", "liveItem", "catalogProductId", "listingType", "preOrderDeliveryDate", "preOrderDepositPercent", "preOrderDepositAmount", "preOrderMaxQuantity", "preOrderProductionStatus", "preOrderCancellable", "isOnSale", "isSold", "seoTitle", "seoDescription", "seoKeywords", "customFields", "customSections", "sublistingCategoryId", "groupId", "isGroupParent", "groupParentSlug", "groupChildSlugs", "groupTitle", "barcodeId"];
|
|
335
|
+
export declare const PRODUCT_UPDATABLE_FIELDS: readonly ["title", "description", "category", "subcategory", "brand", "price", "stockQuantity", "images", "status", "tags", "specifications", "features", "shippingInfo", "returnPolicy", "pickupAddressId", "condition", "insurance", "shippingPaidBy", "autoExtendable", "auctionExtensionMinutes", "auctionShippingPaidBy", "reservePrice", "buyNowPrice", "minBidIncrement", "buyItNowPriceInPaise", "bidsHaveStarted", "grading", "card", "classified", "digitalCode", "liveItem", "catalogProductId", "listingType", "preOrderDeliveryDate", "preOrderDepositPercent", "preOrderDepositAmount", "preOrderMaxQuantity", "preOrderProductionStatus", "preOrderCancellable", "isOnSale", "isSold", "allowShipBeforeEmiComplete", "printMeta", "seoTitle", "seoDescription", "seoKeywords", "customFields", "customSections", "sublistingCategoryId", "groupId", "isGroupParent", "groupParentSlug", "groupChildSlugs", "groupTitle", "barcodeId"];
|
|
317
336
|
export type ProductCreateInput = Omit<ProductDocument, "id" | "createdAt" | "updatedAt" | "availableQuantity" | "bidCount" | "currentBid" | "auctionOriginalEndDate">;
|
|
318
337
|
export type ProductUpdateInput = Partial<Pick<ProductDocument, (typeof PRODUCT_UPDATABLE_FIELDS)[number]>>;
|
|
319
338
|
export type ProductAdminUpdateInput = Partial<Omit<ProductDocument, "id" | "createdAt">>;
|
|
@@ -29,6 +29,23 @@ export declare const productSeoSchema: z.ZodObject<{
|
|
|
29
29
|
description?: string | undefined;
|
|
30
30
|
keywords?: string[] | undefined;
|
|
31
31
|
}>;
|
|
32
|
+
/** Print-specific metadata for "art" / "stickers" listings. */
|
|
33
|
+
export declare const printMetaSchema: z.ZodObject<{
|
|
34
|
+
size: z.ZodOptional<z.ZodString>;
|
|
35
|
+
material: z.ZodOptional<z.ZodString>;
|
|
36
|
+
finish: z.ZodOptional<z.ZodString>;
|
|
37
|
+
editionSize: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
}, "strip", z.ZodTypeAny, {
|
|
39
|
+
size?: string | undefined;
|
|
40
|
+
material?: string | undefined;
|
|
41
|
+
finish?: string | undefined;
|
|
42
|
+
editionSize?: number | undefined;
|
|
43
|
+
}, {
|
|
44
|
+
size?: string | undefined;
|
|
45
|
+
material?: string | undefined;
|
|
46
|
+
finish?: string | undefined;
|
|
47
|
+
editionSize?: number | undefined;
|
|
48
|
+
}>;
|
|
32
49
|
/**
|
|
33
50
|
* Base Zod schema for a product item.
|
|
34
51
|
* Apps can extend this to add their own fields:
|
|
@@ -86,6 +103,23 @@ export declare const productItemSchema: z.ZodObject<{
|
|
|
86
103
|
}>>;
|
|
87
104
|
featured: z.ZodOptional<z.ZodBoolean>;
|
|
88
105
|
isPromoted: z.ZodOptional<z.ZodBoolean>;
|
|
106
|
+
allowShipBeforeEmiComplete: z.ZodOptional<z.ZodBoolean>;
|
|
107
|
+
printMeta: z.ZodOptional<z.ZodObject<{
|
|
108
|
+
size: z.ZodOptional<z.ZodString>;
|
|
109
|
+
material: z.ZodOptional<z.ZodString>;
|
|
110
|
+
finish: z.ZodOptional<z.ZodString>;
|
|
111
|
+
editionSize: z.ZodOptional<z.ZodNumber>;
|
|
112
|
+
}, "strip", z.ZodTypeAny, {
|
|
113
|
+
size?: string | undefined;
|
|
114
|
+
material?: string | undefined;
|
|
115
|
+
finish?: string | undefined;
|
|
116
|
+
editionSize?: number | undefined;
|
|
117
|
+
}, {
|
|
118
|
+
size?: string | undefined;
|
|
119
|
+
material?: string | undefined;
|
|
120
|
+
finish?: string | undefined;
|
|
121
|
+
editionSize?: number | undefined;
|
|
122
|
+
}>>;
|
|
89
123
|
currentBid: z.ZodOptional<z.ZodNumber>;
|
|
90
124
|
availableQuantity: z.ZodOptional<z.ZodNumber>;
|
|
91
125
|
category: z.ZodOptional<z.ZodString>;
|
|
@@ -337,6 +371,13 @@ export declare const productItemSchema: z.ZodObject<{
|
|
|
337
371
|
preOrderCurrentCount?: number | undefined;
|
|
338
372
|
preOrderProductionStatus?: "upcoming" | "in_production" | "ready_to_ship" | undefined;
|
|
339
373
|
preOrderCancellable?: boolean | undefined;
|
|
374
|
+
allowShipBeforeEmiComplete?: boolean | undefined;
|
|
375
|
+
printMeta?: {
|
|
376
|
+
size?: string | undefined;
|
|
377
|
+
material?: string | undefined;
|
|
378
|
+
finish?: string | undefined;
|
|
379
|
+
editionSize?: number | undefined;
|
|
380
|
+
} | undefined;
|
|
340
381
|
pickupAddressId?: string | undefined;
|
|
341
382
|
viewCount?: number | undefined;
|
|
342
383
|
avgRating?: number | undefined;
|
|
@@ -466,6 +507,13 @@ export declare const productItemSchema: z.ZodObject<{
|
|
|
466
507
|
preOrderCurrentCount?: number | undefined;
|
|
467
508
|
preOrderProductionStatus?: "upcoming" | "in_production" | "ready_to_ship" | undefined;
|
|
468
509
|
preOrderCancellable?: boolean | undefined;
|
|
510
|
+
allowShipBeforeEmiComplete?: boolean | undefined;
|
|
511
|
+
printMeta?: {
|
|
512
|
+
size?: string | undefined;
|
|
513
|
+
material?: string | undefined;
|
|
514
|
+
finish?: string | undefined;
|
|
515
|
+
editionSize?: number | undefined;
|
|
516
|
+
} | undefined;
|
|
469
517
|
pickupAddressId?: string | undefined;
|
|
470
518
|
viewCount?: number | undefined;
|
|
471
519
|
avgRating?: number | undefined;
|
|
@@ -13,6 +13,13 @@ export const productSeoSchema = z.object({
|
|
|
13
13
|
description: z.string().optional(),
|
|
14
14
|
keywords: z.array(z.string()).optional(),
|
|
15
15
|
});
|
|
16
|
+
/** Print-specific metadata for "art" / "stickers" listings. */
|
|
17
|
+
export const printMetaSchema = z.object({
|
|
18
|
+
size: z.string().max(80).optional(),
|
|
19
|
+
material: z.string().max(80).optional(),
|
|
20
|
+
finish: z.string().max(80).optional(),
|
|
21
|
+
editionSize: z.number().int().positive().optional(),
|
|
22
|
+
});
|
|
16
23
|
// --- Base item schema ---------------------------------------------------------
|
|
17
24
|
/**
|
|
18
25
|
* Base Zod schema for a product item.
|
|
@@ -43,6 +50,8 @@ export const productItemSchema = z.object({
|
|
|
43
50
|
.optional(),
|
|
44
51
|
featured: z.boolean().optional(),
|
|
45
52
|
isPromoted: z.boolean().optional(),
|
|
53
|
+
allowShipBeforeEmiComplete: z.boolean().optional(),
|
|
54
|
+
printMeta: printMetaSchema.optional(),
|
|
46
55
|
currentBid: z.number().optional(),
|
|
47
56
|
availableQuantity: z.number().optional(),
|
|
48
57
|
category: z.string().optional(),
|