@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
export type ProductListingMode = "standard" | "auction" | "pre-order" | "prize-draw" | "bundle" | "classified" | "digital-code" | "live";
|
|
2
|
+
export type ProductListingMode = "standard" | "auction" | "pre-order" | "prize-draw" | "bundle" | "classified" | "digital-code" | "live" | "art" | "stickers";
|
|
3
3
|
export interface SellerProductDraft {
|
|
4
4
|
title?: string;
|
|
5
5
|
slug?: string;
|
|
@@ -61,6 +61,10 @@ export interface SellerProductDraft {
|
|
|
61
61
|
liveCites?: boolean;
|
|
62
62
|
/** Barcode ID of the physical sticker on this item. Auto-generated on save if blank. */
|
|
63
63
|
barcodeId?: string;
|
|
64
|
+
printSize?: string;
|
|
65
|
+
printMaterial?: string;
|
|
66
|
+
printFinish?: string;
|
|
67
|
+
printEditionSize?: number;
|
|
64
68
|
}
|
|
65
69
|
export interface SellerProductShellProps {
|
|
66
70
|
mode: "create" | "edit";
|
|
@@ -10,7 +10,21 @@ import { ImageUpload, MediaUploadField, MediaUploadList, useMediaUpload } from "
|
|
|
10
10
|
import { StoreAddressSelectorCreate } from "../../stores/components/StoreAddressSelectorCreate";
|
|
11
11
|
import { QuickProductForm } from "./QuickProductForm";
|
|
12
12
|
import { BarcodeField } from "./BarcodeField";
|
|
13
|
+
import { pluginFor } from "../../../_internal/shared/listing-types/_registry";
|
|
13
14
|
import { normalizeError } from "../../../errors/normalize";
|
|
15
|
+
/**
|
|
16
|
+
* "bundle" is a categoryType, not a ListingType, so it can't live in
|
|
17
|
+
* LISTING_TYPE_REGISTRY — this is the single, explicit escape hatch that
|
|
18
|
+
* lets the seller form's registry lookups also cover it.
|
|
19
|
+
*/
|
|
20
|
+
const BUNDLE_PLUGIN_FALLBACK = {
|
|
21
|
+
priceLabel: "Price (₹)",
|
|
22
|
+
typeLabel: "Bundle",
|
|
23
|
+
showsStockQuantity: false,
|
|
24
|
+
};
|
|
25
|
+
function pluginForMode(mode) {
|
|
26
|
+
return mode === "bundle" ? BUNDLE_PLUGIN_FALLBACK : pluginFor(mode);
|
|
27
|
+
}
|
|
14
28
|
const sellerProductSchema = z.object({
|
|
15
29
|
title: z.string().min(1, "Product title is required").max(200),
|
|
16
30
|
description: z.string().max(10000).optional().or(z.literal("")),
|
|
@@ -114,18 +128,59 @@ const LIVE_TRANSPORT_OPTIONS = [
|
|
|
114
128
|
function StepLiveItemSettings({ values, onChange, }) {
|
|
115
129
|
return (_jsxs(Stack, { gap: "md", children: [_jsx(Alert, { variant: "warning", children: "Live animal / plant listings must comply with all applicable laws, CITES regulations, and local jurisdiction rules. LetItRip is not responsible for legal compliance \u2014 this is solely the seller's responsibility." }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "liveSpecies", label: "Species / Common Name", type: "text", value: values.liveSpecies ?? "", onChange: (v) => onChange({ liveSpecies: v }), placeholder: "e.g. Axolotl (Ambystoma mexicanum)" }), _jsx(FormField, { name: "liveAgeMonths", label: "Age (months, optional)", type: "number", value: String(values.liveAgeMonths ?? ""), onChange: (v) => onChange({ liveAgeMonths: v ? Number(v) : undefined }), placeholder: "e.g. 6" })] }), _jsx(FormField, { name: "liveSex", label: "Sex", type: "select", value: values.liveSex ?? "unknown", onChange: (v) => onChange({ liveSex: v }), options: LIVE_SEX_OPTIONS }), _jsx(FormField, { name: "liveCareInfo", label: "Care Instructions (optional)", type: "textarea", value: values.liveCareInfo ?? "", onChange: (v) => onChange({ liveCareInfo: v }), placeholder: "Diet, temperature, habitat requirements\u2026" }), _jsx(FormField, { name: "liveTransportMethod", label: "Transport Method", type: "select", value: values.liveTransportMethod ?? "in-person", onChange: (v) => onChange({ liveTransportMethod: v }), options: LIVE_TRANSPORT_OPTIONS }), values.liveTransportMethod !== "in-person" && (_jsx(FormField, { name: "liveHandlingFee", label: "Handling / Transport Fee (\u20B9, optional)", type: "number", value: toRupees(values.liveHandlingFee), onChange: (v) => onChange({ liveHandlingFee: v ? toPaise(v) : undefined }), placeholder: "0" })), _jsx(FormField, { name: "liveJurisdictions", label: "Jurisdictions where sale is permitted (comma-separated)", type: "text", value: (values.liveJurisdictions ?? []).join(", "), onChange: (v) => onChange({ liveJurisdictions: v.split(",").map((s) => s.trim()).filter(Boolean) }), placeholder: "e.g. Maharashtra, Karnataka", helpText: "List all Indian states / UTs where you can legally sell" }), _jsx(Toggle, { checked: !!values.liveCites, onChange: (checked) => onChange({ liveCites: checked }), label: "This species requires CITES documentation" })] }));
|
|
116
130
|
}
|
|
131
|
+
// ── Step: Print Meta (art / stickers) ───────────────────────────────────────
|
|
132
|
+
// Shared by both "art" and "stickers" — identical field set, only the intro
|
|
133
|
+
// copy differs (set by the caller via `intro`).
|
|
134
|
+
function StepPrintMetaSettings({ values, onChange, intro, }) {
|
|
135
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsx(Alert, { variant: "info", children: intro }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "printSize", label: "Size", type: "text", value: values.printSize ?? "", onChange: (v) => onChange({ printSize: v }), placeholder: "e.g. A4, 12x18 in" }), _jsx(FormField, { name: "printMaterial", label: "Material", type: "text", value: values.printMaterial ?? "", onChange: (v) => onChange({ printMaterial: v }), placeholder: "e.g. Matte photo paper, Vinyl" })] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "printFinish", label: "Finish (optional)", type: "text", value: values.printFinish ?? "", onChange: (v) => onChange({ printFinish: v }), placeholder: "e.g. Glossy, Matte, Holographic" }), _jsx(FormField, { name: "printEditionSize", label: "Edition Size (optional)", type: "number", value: String(values.printEditionSize ?? ""), onChange: (v) => onChange({ printEditionSize: v ? Number(v) : undefined }), placeholder: "Leave blank for an open edition" })] })] }));
|
|
136
|
+
}
|
|
137
|
+
const TYPE_SPECIFIC_STEPS = {
|
|
138
|
+
auction: {
|
|
139
|
+
id: "auction",
|
|
140
|
+
label: "Auction Settings",
|
|
141
|
+
render: ({ values, onChange }) => (_jsx(StepAuctionSettings, { values: values, onChange: onChange })),
|
|
142
|
+
validate: (v) => (!v.startingBid ? "Starting bid is required" : !v.auctionEndDate ? "Auction end date is required" : null),
|
|
143
|
+
},
|
|
144
|
+
"pre-order": {
|
|
145
|
+
id: "preorder",
|
|
146
|
+
label: "Pre-Order",
|
|
147
|
+
sectionHeading: "Pre-Order Settings",
|
|
148
|
+
render: ({ values, onChange }) => (_jsx(StepPreOrderSettings, { values: values, onChange: onChange })),
|
|
149
|
+
validate: (v) => (!v.preOrderDeliveryDate ? "Estimated delivery date is required" : null),
|
|
150
|
+
},
|
|
151
|
+
classified: {
|
|
152
|
+
id: "classified",
|
|
153
|
+
label: "Meetup Details",
|
|
154
|
+
render: ({ values, onChange }) => (_jsx(StepClassifiedSettings, { values: values, onChange: onChange })),
|
|
155
|
+
validate: (v) => (!v.classifiedCity?.trim() ? "City is required for classified listings" : null),
|
|
156
|
+
},
|
|
157
|
+
"digital-code": {
|
|
158
|
+
id: "digitalcode",
|
|
159
|
+
label: "Code Details",
|
|
160
|
+
render: ({ values, onChange }) => (_jsx(StepDigitalCodeSettings, { values: values, onChange: onChange })),
|
|
161
|
+
},
|
|
162
|
+
live: {
|
|
163
|
+
id: "live",
|
|
164
|
+
label: "Live Item Details",
|
|
165
|
+
render: ({ values, onChange }) => (_jsx(StepLiveItemSettings, { values: values, onChange: onChange })),
|
|
166
|
+
validate: (v) => (!v.liveSpecies?.trim() ? "Species name is required" : null),
|
|
167
|
+
},
|
|
168
|
+
art: {
|
|
169
|
+
id: "printmeta",
|
|
170
|
+
label: "Print Details",
|
|
171
|
+
render: ({ values, onChange }) => (_jsx(StepPrintMetaSettings, { values: values, onChange: onChange, intro: "Art prints are sold as physical, printed-only reproductions \u2014 no original artwork or digital files." })),
|
|
172
|
+
},
|
|
173
|
+
stickers: {
|
|
174
|
+
id: "printmeta",
|
|
175
|
+
label: "Print Details",
|
|
176
|
+
render: ({ values, onChange }) => (_jsx(StepPrintMetaSettings, { values: values, onChange: onChange, intro: "Sticker listings are sold as physical, printed sheets or packs \u2014 no digital files." })),
|
|
177
|
+
},
|
|
178
|
+
};
|
|
117
179
|
// ── Step: Pricing ─────────────────────────────────────────────────────────
|
|
118
180
|
function StepPricing({ values, onChange, listingType, }) {
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
? "Pre-Order Price (₹)"
|
|
123
|
-
: listingType === "classified"
|
|
124
|
-
? "Asking Price (₹)"
|
|
125
|
-
: listingType === "digital-code"
|
|
126
|
-
? "Price per Code (₹)"
|
|
127
|
-
: "Price (₹)";
|
|
128
|
-
return (_jsxs(Stack, { gap: "md", children: [_jsx(Alert, { variant: "info", children: "All prices in Indian Rupees (\u20B9)." }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "price", label: priceLabel, type: "number", value: toRupees(values.price), onChange: (v) => onChange({ price: toPaise(v) }), placeholder: "999" }), _jsx(FormField, { name: "compareAtPrice", label: "Compare-at Price (\u20B9, optional)", type: "number", value: toRupees(values.compareAtPrice), onChange: (v) => onChange({ compareAtPrice: v ? toPaise(v) : undefined }), placeholder: "1299", helpText: "Original price shown as strikethrough" })] }), (listingType === "standard" || listingType === "classified" || listingType === "live") && (_jsx(FormField, { name: "stockQuantity", label: "Stock Quantity", type: "number", value: String(values.stockQuantity ?? ""), onChange: (v) => onChange({ stockQuantity: Number(v) }), placeholder: "1" })), _jsxs(FormGroup, { columns: 2, children: [_jsx(Toggle, { checked: !!values.featured, onChange: (checked) => onChange({ featured: checked }), label: "Mark as Featured" }), _jsx(Toggle, { checked: !!values.isNew, onChange: (checked) => onChange({ isNew: checked }), label: "Mark as New Arrival" })] })] }));
|
|
181
|
+
const listingPlugin = pluginForMode(listingType);
|
|
182
|
+
const priceLabel = listingPlugin.priceLabel;
|
|
183
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsx(Alert, { variant: "info", children: "All prices in Indian Rupees (\u20B9)." }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "price", label: priceLabel, type: "number", value: toRupees(values.price), onChange: (v) => onChange({ price: toPaise(v) }), placeholder: "999" }), _jsx(FormField, { name: "compareAtPrice", label: "Compare-at Price (\u20B9, optional)", type: "number", value: toRupees(values.compareAtPrice), onChange: (v) => onChange({ compareAtPrice: v ? toPaise(v) : undefined }), placeholder: "1299", helpText: "Original price shown as strikethrough" })] }), listingPlugin.showsStockQuantity && (_jsx(FormField, { name: "stockQuantity", label: "Stock Quantity", type: "number", value: String(values.stockQuantity ?? ""), onChange: (v) => onChange({ stockQuantity: Number(v) }), placeholder: "1" })), _jsxs(FormGroup, { columns: 2, children: [_jsx(Toggle, { checked: !!values.featured, onChange: (checked) => onChange({ featured: checked }), label: "Mark as Featured" }), _jsx(Toggle, { checked: !!values.isNew, onChange: (checked) => onChange({ isNew: checked }), label: "Mark as New Arrival" })] })] }));
|
|
129
184
|
}
|
|
130
185
|
// ── Step: Shipping ────────────────────────────────────────────────────────
|
|
131
186
|
function StepShipping({ values, onChange, renderAddressSelector, }) {
|
|
@@ -235,49 +290,8 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
|
|
|
235
290
|
showToast(err instanceof Error ? err.message : "Failed to publish.", "error");
|
|
236
291
|
}
|
|
237
292
|
}, [draft, onPublish, markClean, showToast]);
|
|
238
|
-
const listingTypeLabel = listingType
|
|
239
|
-
|
|
240
|
-
: listingType === "pre-order"
|
|
241
|
-
? "Pre-Order"
|
|
242
|
-
: listingType === "bundle"
|
|
243
|
-
? "Bundle"
|
|
244
|
-
: listingType === "classified"
|
|
245
|
-
? "Classified"
|
|
246
|
-
: listingType === "digital-code"
|
|
247
|
-
? "Digital Code"
|
|
248
|
-
: listingType === "live"
|
|
249
|
-
? "Live Item"
|
|
250
|
-
: "Product";
|
|
251
|
-
const typeSpecificStep = listingType === "auction"
|
|
252
|
-
? {
|
|
253
|
-
label: "Auction Settings",
|
|
254
|
-
render: ({ values, onChange }) => (_jsx(StepAuctionSettings, { values: values, onChange: onChange })),
|
|
255
|
-
validate: (v) => (!v.startingBid ? "Starting bid is required" : !v.auctionEndDate ? "Auction end date is required" : null),
|
|
256
|
-
}
|
|
257
|
-
: listingType === "pre-order"
|
|
258
|
-
? {
|
|
259
|
-
label: "Pre-Order",
|
|
260
|
-
render: ({ values, onChange }) => (_jsx(StepPreOrderSettings, { values: values, onChange: onChange })),
|
|
261
|
-
validate: (v) => (!v.preOrderDeliveryDate ? "Estimated delivery date is required" : null),
|
|
262
|
-
}
|
|
263
|
-
: listingType === "classified"
|
|
264
|
-
? {
|
|
265
|
-
label: "Meetup Details",
|
|
266
|
-
render: ({ values, onChange }) => (_jsx(StepClassifiedSettings, { values: values, onChange: onChange })),
|
|
267
|
-
validate: (v) => (!v.classifiedCity?.trim() ? "City is required for classified listings" : null),
|
|
268
|
-
}
|
|
269
|
-
: listingType === "digital-code"
|
|
270
|
-
? {
|
|
271
|
-
label: "Code Details",
|
|
272
|
-
render: ({ values, onChange }) => (_jsx(StepDigitalCodeSettings, { values: values, onChange: onChange })),
|
|
273
|
-
}
|
|
274
|
-
: listingType === "live"
|
|
275
|
-
? {
|
|
276
|
-
label: "Live Item Details",
|
|
277
|
-
render: ({ values, onChange }) => (_jsx(StepLiveItemSettings, { values: values, onChange: onChange })),
|
|
278
|
-
validate: (v) => (!v.liveSpecies?.trim() ? "Species name is required" : null),
|
|
279
|
-
}
|
|
280
|
-
: null;
|
|
293
|
+
const listingTypeLabel = pluginForMode(listingType).typeLabel;
|
|
294
|
+
const typeSpecificStep = TYPE_SPECIFIC_STEPS[listingType] ?? null;
|
|
281
295
|
const steps = [
|
|
282
296
|
{
|
|
283
297
|
label: "Basic",
|
|
@@ -349,11 +363,7 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
|
|
|
349
363
|
// Edit mode — FormShell with section nav + full form
|
|
350
364
|
const editSections = [
|
|
351
365
|
...EDIT_SECTIONS,
|
|
352
|
-
...(
|
|
353
|
-
...(listingType === "pre-order" ? [{ id: "preorder", label: "Pre-Order" }] : []),
|
|
354
|
-
...(listingType === "classified" ? [{ id: "classified", label: "Meetup Details" }] : []),
|
|
355
|
-
...(listingType === "digital-code" ? [{ id: "digitalcode", label: "Code Details" }] : []),
|
|
356
|
-
...(listingType === "live" ? [{ id: "live", label: "Live Item" }] : []),
|
|
366
|
+
...(typeSpecificStep ? [{ id: typeSpecificStep.id, label: typeSpecificStep.label }] : []),
|
|
357
367
|
];
|
|
358
|
-
return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, sections: editSections, onSaveDraft: handleSave, onPublish: handlePublish, saveLabel: "Save Changes", publishLabel: "Update", previewSlot: previewSlot, children: _jsx(FormShellProvider, { isDirty: isDirty, values: draft, children: _jsxs(Stack, { gap: "lg", children: [_jsxs(Section, { id: "basic", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Basic Info" }), _jsx(StepBasic, { values: draft, onChange: update, renderCategorySelector: renderCategorySelector, renderBrandSelector: renderBrandSelector, renderTemplateSelector: renderTemplateSelector })] }), _jsxs(Section, { id: "media", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Media" }), _jsx(StepMedia, { values: draft, onChange: update, storeSlug: storeSlug })] }),
|
|
368
|
+
return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, sections: editSections, onSaveDraft: handleSave, onPublish: handlePublish, saveLabel: "Save Changes", publishLabel: "Update", previewSlot: previewSlot, children: _jsx(FormShellProvider, { isDirty: isDirty, values: draft, children: _jsxs(Stack, { gap: "lg", children: [_jsxs(Section, { id: "basic", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Basic Info" }), _jsx(StepBasic, { values: draft, onChange: update, renderCategorySelector: renderCategorySelector, renderBrandSelector: renderBrandSelector, renderTemplateSelector: renderTemplateSelector })] }), _jsxs(Section, { id: "media", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Media" }), _jsx(StepMedia, { values: draft, onChange: update, storeSlug: storeSlug })] }), typeSpecificStep && (_jsxs(Section, { id: typeSpecificStep.id, children: [_jsx(Heading, { level: 3, className: "mb-4", children: typeSpecificStep.sectionHeading ?? typeSpecificStep.label }), typeSpecificStep.render({ values: draft, onChange: update, errors: {} })] })), _jsxs(Section, { id: "pricing", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Pricing" }), _jsx(StepPricing, { values: draft, onChange: update, listingType: listingType })] }), _jsxs(Section, { id: "shipping", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Shipping" }), _jsx(StepShipping, { values: draft, onChange: update, renderAddressSelector: renderAddressSelector })] }), _jsxs(Section, { id: "publish", children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Publish" }), _jsx(StepPublish, { values: draft, onChange: update }), onSaveAsTemplate && (_jsxs(Div, { className: "mt-4 border-t border-[var(--appkit-color-border)]", padding: "t-md", children: [_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onSaveAsTemplate(draft), children: "Save as Template" }), _jsx(Text, { className: "mt-1 text-[var(--appkit-color-secondary-text)]", size: "xs", children: "Save these settings as a reusable template for future listings." })] }))] })] }) }) }));
|
|
359
369
|
}
|
|
@@ -94,7 +94,6 @@ export function SellerReviewsView({ reviewsApiBase = "/api/store/reviews", reply
|
|
|
94
94
|
}, [feedbackTarget, feedbackText]);
|
|
95
95
|
const fetchReviewsRef = useMemo(() => ({ current: null }), []);
|
|
96
96
|
const fetchReviews = useCallback(async () => {
|
|
97
|
-
// toast-intentionally-silent: background data loader — error displayed in inline error state
|
|
98
97
|
setLoading(true);
|
|
99
98
|
setError(null);
|
|
100
99
|
try {
|
|
@@ -7,11 +7,8 @@ import { StoreAddressSelectorCreate } from "../../stores/components/StoreAddress
|
|
|
7
7
|
import { StepForm } from "../../shell";
|
|
8
8
|
import { normalizeError } from "../../../errors/normalize";
|
|
9
9
|
const DEFAULT_DRAFT = {
|
|
10
|
-
method: "custom",
|
|
11
10
|
customCarrierName: "",
|
|
12
11
|
customShippingPrice: "",
|
|
13
|
-
shiprocketEmail: "",
|
|
14
|
-
shiprocketPassword: "",
|
|
15
12
|
pickupAddressId: "",
|
|
16
13
|
freeShippingThreshold: "",
|
|
17
14
|
fragileSurcharge: "",
|
|
@@ -31,11 +28,8 @@ export function SellerShippingView({ apiBase = "/api/store/shipping" }) {
|
|
|
31
28
|
const cfg = res?.data?.shippingConfig ?? { method: "custom", isConfigured: false };
|
|
32
29
|
setCurrent(cfg);
|
|
33
30
|
setDraft({
|
|
34
|
-
method: cfg.method,
|
|
35
31
|
customCarrierName: cfg.customCarrierName ?? "",
|
|
36
32
|
customShippingPrice: cfg.customShippingPrice ? String(cfg.customShippingPrice / 100) : "",
|
|
37
|
-
shiprocketEmail: cfg.shiprocketEmail ?? "",
|
|
38
|
-
shiprocketPassword: "",
|
|
39
33
|
pickupAddressId: "",
|
|
40
34
|
freeShippingThreshold: (res?.data?.freeShippingThreshold ?? 0)
|
|
41
35
|
? String(res.data.freeShippingThreshold / 100)
|
|
@@ -57,20 +51,9 @@ export function SellerShippingView({ apiBase = "/api/store/shipping" }) {
|
|
|
57
51
|
setSuccess(false);
|
|
58
52
|
setSaving(true);
|
|
59
53
|
try {
|
|
60
|
-
const methodFields = draft.method === "custom"
|
|
61
|
-
? {
|
|
62
|
-
method: "custom",
|
|
63
|
-
customCarrierName: draft.customCarrierName.trim(),
|
|
64
|
-
customShippingPrice: Math.round(parseFloat(draft.customShippingPrice || "0") * 100),
|
|
65
|
-
}
|
|
66
|
-
: {
|
|
67
|
-
method: "shiprocket",
|
|
68
|
-
...(draft.shiprocketPassword
|
|
69
|
-
? { shiprocketCredentials: { email: draft.shiprocketEmail, password: draft.shiprocketPassword } }
|
|
70
|
-
: {}),
|
|
71
|
-
};
|
|
72
54
|
const body = {
|
|
73
|
-
|
|
55
|
+
customCarrierName: draft.customCarrierName.trim(),
|
|
56
|
+
customShippingPrice: Math.round(parseFloat(draft.customShippingPrice || "0") * 100),
|
|
74
57
|
...(draft.pickupAddressId ? { pickupAddressId: draft.pickupAddressId } : {}),
|
|
75
58
|
freeShippingThreshold: Math.round(parseFloat(draft.freeShippingThreshold || "0") * 100),
|
|
76
59
|
fragileSurcharge: Math.round(parseFloat(draft.fragileSurcharge || "0") * 100),
|
|
@@ -84,7 +67,7 @@ export function SellerShippingView({ apiBase = "/api/store/shipping" }) {
|
|
|
84
67
|
if (!res.ok)
|
|
85
68
|
throw new Error(json?.error ?? "Failed to save");
|
|
86
69
|
setSuccess(true);
|
|
87
|
-
const cfg = json?.data?.shippingConfig ?? { method:
|
|
70
|
+
const cfg = json?.data?.shippingConfig ?? { method: "custom", isConfigured: false };
|
|
88
71
|
setCurrent(cfg);
|
|
89
72
|
}
|
|
90
73
|
catch (err) {
|
|
@@ -98,14 +81,12 @@ export function SellerShippingView({ apiBase = "/api/store/shipping" }) {
|
|
|
98
81
|
const busy = loading || saving;
|
|
99
82
|
const steps = [
|
|
100
83
|
{
|
|
101
|
-
label: "
|
|
102
|
-
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Shipping
|
|
103
|
-
? "Set a fixed shipping fee and carrier name for all orders."
|
|
104
|
-
: "Automated shipping via Shiprocket — connect your account for label generation and tracking." })] })] }, m))) }), values.method === "custom" && (_jsxs(Stack, { gap: "md", className: "mt-2", children: [_jsx(FormField, { name: "customCarrierName", label: "Carrier Name", type: "text", value: values.customCarrierName, onChange: (v) => onChange({ customCarrierName: v }), placeholder: "e.g. India Post, DTDC, Delhivery", disabled: busy }), _jsx(FormField, { name: "customShippingPrice", label: "Shipping Price (\u20B9)", type: "number", value: values.customShippingPrice, onChange: (v) => onChange({ customShippingPrice: v }), placeholder: "0 for free shipping", helpText: "Charged to buyer at checkout. Enter 0 for free shipping.", disabled: busy })] })), values.method === "shiprocket" && (_jsxs(Stack, { gap: "md", className: "mt-2", children: [_jsx(FormField, { name: "shiprocketEmail", label: "Shiprocket Email", type: "email", value: values.shiprocketEmail, onChange: (v) => onChange({ shiprocketEmail: v }), placeholder: "your@email.com", disabled: busy }), _jsx(FormField, { name: "shiprocketPassword", label: current?.isTokenValid ? "Password (leave blank to keep existing token)" : "Password", type: "password", value: values.shiprocketPassword, onChange: (v) => onChange({ shiprocketPassword: v }), placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", helpText: current?.isTokenValid ? "Only fill this to re-authenticate." : "Required to connect your Shiprocket account.", disabled: busy })] }))] })),
|
|
84
|
+
label: "Carrier",
|
|
85
|
+
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Shipping Carrier" }), current && (_jsx(Row, { className: "mb-2", align: "center", gap: "sm", children: _jsx(Badge, { variant: current.isConfigured ? "success" : "warning", children: current.isConfigured ? "Configured" : "Not configured" }) })), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Set a fixed shipping fee and carrier name for all orders. You enter the carrier and tracking number yourself when you ship each order." }), _jsxs(Stack, { gap: "md", className: "mt-2", children: [_jsx(FormField, { name: "customCarrierName", label: "Carrier Name", type: "text", value: values.customCarrierName, onChange: (v) => onChange({ customCarrierName: v }), placeholder: "e.g. India Post, DTDC, Delhivery", disabled: busy }), _jsx(FormField, { name: "customShippingPrice", label: "Shipping Price (\u20B9)", type: "number", value: values.customShippingPrice, onChange: (v) => onChange({ customShippingPrice: v }), placeholder: "0 for free shipping", helpText: "Charged to buyer at checkout. Enter 0 for free shipping.", disabled: busy })] })] })),
|
|
105
86
|
},
|
|
106
87
|
{
|
|
107
88
|
label: "Pickup Address",
|
|
108
|
-
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Pickup Address" }), current?.pickupAddress && (_jsxs(Alert, { variant: "info", children: ["Current pickup: ", current.pickupAddress.locationName ?? "", current.pickupAddress.city ? `, ${current.pickupAddress.city}` : ""
|
|
89
|
+
render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Pickup Address" }), current?.pickupAddress && (_jsxs(Alert, { variant: "info", children: ["Current pickup: ", current.pickupAddress.locationName ?? "", current.pickupAddress.city ? `, ${current.pickupAddress.city}` : ""] })), _jsx(StoreAddressSelectorCreate, { value: values.pickupAddressId, onChange: (id) => onChange({ pickupAddressId: id }), label: "Pickup Address", disabled: busy })] })),
|
|
109
90
|
},
|
|
110
91
|
{
|
|
111
92
|
label: "Rules",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface SellerStickersViewProps {
|
|
2
|
+
onCreateClick?: () => void;
|
|
3
|
+
onEditClick?: (id: string) => void;
|
|
4
|
+
onDelete?: (id: string) => Promise<void>;
|
|
5
|
+
onBulkDelete?: (ids: string[]) => Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare function SellerStickersView({ onCreateClick, onEditClick, onDelete, onBulkDelete, }: SellerStickersViewProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* SellerStickersView — seller browse/manage of sticker listings
|
|
5
|
+
* (EMI/art-stickers session). Mirrors SellerClassifiedView's pattern.
|
|
6
|
+
*/
|
|
7
|
+
import { Badge, sortBy } from "@mohasinac/appkit";
|
|
8
|
+
import { useState, useCallback } from "react";
|
|
9
|
+
import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
|
|
10
|
+
import { ConfirmDeleteModal, RowActionMenu, Text } from "../../../ui";
|
|
11
|
+
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
12
|
+
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
13
|
+
import { ROUTES } from "../../..";
|
|
14
|
+
import { toRecordArray, toRelativeDate, toRupees, toStringValue, } from "../../admin/hooks/useAdminListingData";
|
|
15
|
+
import { DataListingView } from "../../admin/components/DataListingView";
|
|
16
|
+
const COLUMNS = [
|
|
17
|
+
{ key: "title", header: "Listing", render: (row) => _jsx(Text, { size: "sm", weight: "medium", children: row.title }) },
|
|
18
|
+
{ key: "price", header: "Price", render: (row) => _jsx(Text, { className: "tabular-nums", size: "sm", children: row.price }) },
|
|
19
|
+
{
|
|
20
|
+
key: "size",
|
|
21
|
+
header: "Size",
|
|
22
|
+
render: (row) => _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: row.size || "—" }),
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
key: "status",
|
|
26
|
+
header: "Status",
|
|
27
|
+
render: (row) => (_jsx(Badge, { variant: row.status === "active" ? "active" : "inactive", size: "xs", className: "capitalize", children: row.status })),
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
key: "createdAt",
|
|
31
|
+
header: "Created",
|
|
32
|
+
render: (row) => _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: row.createdAt }),
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
export function SellerStickersView({ onCreateClick, onEditClick, onDelete, onBulkDelete, }) {
|
|
36
|
+
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
37
|
+
const { deletingId, handleDelete: performDelete } = useEntityDelete({
|
|
38
|
+
endpoint: (id) => `/api/store/products/${id}`,
|
|
39
|
+
deleteFn: onDelete,
|
|
40
|
+
successMessage: "Listing deleted.",
|
|
41
|
+
fetchOptions: { credentials: "include" },
|
|
42
|
+
});
|
|
43
|
+
const handleDelete = useCallback(async (id) => {
|
|
44
|
+
await performDelete(id);
|
|
45
|
+
setDeleteTargetId(null);
|
|
46
|
+
}, [performDelete]);
|
|
47
|
+
const handleEdit = useCallback((id) => {
|
|
48
|
+
if (onEditClick)
|
|
49
|
+
onEditClick(id);
|
|
50
|
+
else
|
|
51
|
+
window.location.href = String(ROUTES.STORE.STICKERS_EDIT(id));
|
|
52
|
+
}, [onEditClick]);
|
|
53
|
+
const handleCreate = useCallback(() => {
|
|
54
|
+
if (onCreateClick)
|
|
55
|
+
onCreateClick();
|
|
56
|
+
else
|
|
57
|
+
window.location.href = String(ROUTES.STORE.STICKERS_NEW);
|
|
58
|
+
}, [onCreateClick]);
|
|
59
|
+
const config = {
|
|
60
|
+
portal: "seller",
|
|
61
|
+
title: "Stickers",
|
|
62
|
+
searchPlaceholder: "Search sticker listings...",
|
|
63
|
+
emptyLabel: "No sticker listings yet — list your first pack",
|
|
64
|
+
filterKeys: [],
|
|
65
|
+
defaultSort: sortBy("createdAt", "DESC"),
|
|
66
|
+
queryKey: ["seller", "stickers"],
|
|
67
|
+
endpoint: SELLER_ENDPOINTS.PRODUCTS,
|
|
68
|
+
sortOptions: [
|
|
69
|
+
{ value: sortBy("createdAt", "DESC"), label: "Newest" },
|
|
70
|
+
{ value: sortBy("createdAt", "ASC"), label: "Oldest" },
|
|
71
|
+
{ value: "productTitle", label: "Name A–Z" },
|
|
72
|
+
{ value: sortBy("price", "ASC"), label: "Price: Low–High" },
|
|
73
|
+
{ value: sortBy("price", "DESC"), label: "Price: High–Low" },
|
|
74
|
+
],
|
|
75
|
+
columns: COLUMNS,
|
|
76
|
+
mapRows: (response) => toRecordArray(response.products).map((item, index) => {
|
|
77
|
+
const printMeta = (item.printMeta ?? {});
|
|
78
|
+
return {
|
|
79
|
+
id: toStringValue(item.id, `stickers-${index}`),
|
|
80
|
+
title: toStringValue(item.productTitle ?? item.title, "Untitled"),
|
|
81
|
+
price: toRupees(item.price),
|
|
82
|
+
size: toStringValue(printMeta.size, ""),
|
|
83
|
+
status: toStringValue(item.status, "draft"),
|
|
84
|
+
createdAt: toRelativeDate(item.createdAt),
|
|
85
|
+
};
|
|
86
|
+
}),
|
|
87
|
+
getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
|
|
88
|
+
buildFilters: () => "listingType==stickers",
|
|
89
|
+
primaryAction: { label: "New Sticker Listing", onClick: () => handleCreate() },
|
|
90
|
+
buildBulkActions: onBulkDelete
|
|
91
|
+
? (selection) => [
|
|
92
|
+
{
|
|
93
|
+
id: "bulk-delete",
|
|
94
|
+
label: ACTIONS.STORE["delete-listing"].label,
|
|
95
|
+
variant: "danger",
|
|
96
|
+
onClick: async () => {
|
|
97
|
+
await onBulkDelete(selection.selectedIds);
|
|
98
|
+
selection.clearSelection();
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
]
|
|
102
|
+
: undefined,
|
|
103
|
+
renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
104
|
+
{ label: ACTIONS.STORE["edit-listing"].label, onClick: () => handleEdit(row.id) },
|
|
105
|
+
{
|
|
106
|
+
label: ACTIONS.STORE["delete-listing"].label,
|
|
107
|
+
destructive: true,
|
|
108
|
+
onClick: () => setDeleteTargetId(row.id),
|
|
109
|
+
disabled: deletingId === row.id,
|
|
110
|
+
},
|
|
111
|
+
] })),
|
|
112
|
+
};
|
|
113
|
+
return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Sticker Listing", message: "Are you sure you want to delete this sticker listing? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
|
|
114
|
+
}
|
|
@@ -124,6 +124,10 @@ export { SellerBundlesView } from "./SellerBundlesView";
|
|
|
124
124
|
export type { SellerBundlesViewProps } from "./SellerBundlesView";
|
|
125
125
|
export { SellerClassifiedView } from "./SellerClassifiedView";
|
|
126
126
|
export type { SellerClassifiedViewProps } from "./SellerClassifiedView";
|
|
127
|
+
export { SellerArtView } from "./SellerArtView";
|
|
128
|
+
export type { SellerArtViewProps } from "./SellerArtView";
|
|
129
|
+
export { SellerStickersView } from "./SellerStickersView";
|
|
130
|
+
export type { SellerStickersViewProps } from "./SellerStickersView";
|
|
127
131
|
export { SellerDigitalCodesView } from "./SellerDigitalCodesView";
|
|
128
132
|
export type { SellerDigitalCodesViewProps } from "./SellerDigitalCodesView";
|
|
129
133
|
export { SellerLiveView } from "./SellerLiveView";
|
|
@@ -65,6 +65,8 @@ export { SellerShippingConfigsView } from "./SellerShippingConfigsView";
|
|
|
65
65
|
export { SellerGoogleReviewsView } from "./SellerGoogleReviewsView";
|
|
66
66
|
export { SellerBundlesView } from "./SellerBundlesView";
|
|
67
67
|
export { SellerClassifiedView } from "./SellerClassifiedView";
|
|
68
|
+
export { SellerArtView } from "./SellerArtView";
|
|
69
|
+
export { SellerStickersView } from "./SellerStickersView";
|
|
68
70
|
export { SellerDigitalCodesView } from "./SellerDigitalCodesView";
|
|
69
71
|
export { SellerLiveView } from "./SellerLiveView";
|
|
70
72
|
export { BarcodeField } from "./BarcodeField";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from "./firestore";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
export declare const storeStatusSchema: z.ZodEnum<["pending", "active", "suspended", "rejected"]>;
|
|
4
|
-
export declare const payoutStatusSchema: z.ZodEnum<["pending", "processing", "
|
|
4
|
+
export declare const payoutStatusSchema: z.ZodEnum<["pending", "processing", "paid", "failed"]>;
|
|
5
5
|
export declare const payoutPaymentMethodSchema: z.ZodEnum<["bank_transfer", "upi"]>;
|
|
6
6
|
export declare const socialLinksSchema: z.ZodObject<{
|
|
7
7
|
twitter: z.ZodOptional<z.ZodString>;
|
|
@@ -159,7 +159,7 @@ export declare const payoutRecordSchema: z.ZodObject<{
|
|
|
159
159
|
platformFee: z.ZodNumber;
|
|
160
160
|
platformFeeRate: z.ZodNumber;
|
|
161
161
|
currency: z.ZodString;
|
|
162
|
-
status: z.ZodEnum<["pending", "processing", "
|
|
162
|
+
status: z.ZodEnum<["pending", "processing", "paid", "failed"]>;
|
|
163
163
|
paymentMethod: z.ZodEnum<["bank_transfer", "upi"]>;
|
|
164
164
|
orderIds: z.ZodArray<z.ZodString, "many">;
|
|
165
165
|
requestedAt: z.ZodString;
|
|
@@ -167,7 +167,7 @@ export declare const payoutRecordSchema: z.ZodObject<{
|
|
|
167
167
|
createdAt: z.ZodString;
|
|
168
168
|
updatedAt: z.ZodString;
|
|
169
169
|
}, "strip", z.ZodTypeAny, {
|
|
170
|
-
status: "pending" | "
|
|
170
|
+
status: "pending" | "paid" | "failed" | "processing";
|
|
171
171
|
currency: string;
|
|
172
172
|
createdAt: string;
|
|
173
173
|
id: string;
|
|
@@ -184,7 +184,7 @@ export declare const payoutRecordSchema: z.ZodObject<{
|
|
|
184
184
|
sellerId: string;
|
|
185
185
|
processedAt?: string | undefined;
|
|
186
186
|
}, {
|
|
187
|
-
status: "pending" | "
|
|
187
|
+
status: "pending" | "paid" | "failed" | "processing";
|
|
188
188
|
currency: string;
|
|
189
189
|
createdAt: string;
|
|
190
190
|
id: string;
|
|
@@ -225,18 +225,18 @@ export declare const sellerListParamsSchema: z.ZodObject<{
|
|
|
225
225
|
}>;
|
|
226
226
|
export declare const payoutListParamsSchema: z.ZodObject<{
|
|
227
227
|
sellerId: z.ZodOptional<z.ZodString>;
|
|
228
|
-
status: z.ZodOptional<z.ZodEnum<["pending", "processing", "
|
|
228
|
+
status: z.ZodOptional<z.ZodEnum<["pending", "processing", "paid", "failed"]>>;
|
|
229
229
|
page: z.ZodOptional<z.ZodNumber>;
|
|
230
230
|
perPage: z.ZodOptional<z.ZodNumber>;
|
|
231
231
|
sort: z.ZodOptional<z.ZodString>;
|
|
232
232
|
}, "strip", z.ZodTypeAny, {
|
|
233
|
-
status?: "pending" | "
|
|
233
|
+
status?: "pending" | "paid" | "failed" | "processing" | undefined;
|
|
234
234
|
sort?: string | undefined;
|
|
235
235
|
page?: number | undefined;
|
|
236
236
|
perPage?: number | undefined;
|
|
237
237
|
sellerId?: string | undefined;
|
|
238
238
|
}, {
|
|
239
|
-
status?: "pending" | "
|
|
239
|
+
status?: "pending" | "paid" | "failed" | "processing" | undefined;
|
|
240
240
|
sort?: string | undefined;
|
|
241
241
|
page?: number | undefined;
|
|
242
242
|
perPage?: number | undefined;
|
|
@@ -32,7 +32,7 @@ export interface SellerStore {
|
|
|
32
32
|
createdAt: string;
|
|
33
33
|
updatedAt: string;
|
|
34
34
|
}
|
|
35
|
-
export type PayoutStatus = "pending" | "processing" | "
|
|
35
|
+
export type PayoutStatus = "pending" | "processing" | "paid" | "failed";
|
|
36
36
|
export type PayoutPaymentMethod = "bank_transfer" | "upi";
|
|
37
37
|
export interface PayoutBankAccount {
|
|
38
38
|
accountHolderName: string;
|
|
@@ -17,6 +17,10 @@ const STORE_LISTING_HREF = {
|
|
|
17
17
|
classifieds: (slug) => String(ROUTES.PUBLIC.STORE_CLASSIFIEDS(slug)),
|
|
18
18
|
"digital-codes": (slug) => String(ROUTES.PUBLIC.STORE_DIGITAL_CODES(slug)),
|
|
19
19
|
live: (slug) => String(ROUTES.PUBLIC.STORE_LIVE(slug)),
|
|
20
|
+
// Art / stickers have no dedicated storefront tab page — they're browsable
|
|
21
|
+
// (alongside everything else the store sells) on the "Products" tab.
|
|
22
|
+
art: (slug) => String(ROUTES.PUBLIC.STORE_PRODUCTS(slug)),
|
|
23
|
+
stickers: (slug) => String(ROUTES.PUBLIC.STORE_PRODUCTS(slug)),
|
|
20
24
|
};
|
|
21
25
|
export const getStoreBySlug = cache((slug) => storeRepository.findBySlug(slug).catch(() => undefined));
|
|
22
26
|
function tabLabel(base, count) {
|
|
@@ -31,7 +35,7 @@ export async function StoreDetailLayoutView({ storeSlug, activeTab, children, })
|
|
|
31
35
|
}
|
|
32
36
|
const storeId = store?.id;
|
|
33
37
|
const settings = await siteSettingsRepository.findById("global").catch(() => null);
|
|
34
|
-
const [productsCount, auctionsCount, preOrdersCount, prizeDrawsCount, bundlesCount, classifiedsCount, digitalCodesCount, liveCount, couponsCount, reviewsCount] = storeId
|
|
38
|
+
const [productsCount, auctionsCount, preOrdersCount, prizeDrawsCount, bundlesCount, classifiedsCount, digitalCodesCount, liveCount, artCount, stickersCount, couponsCount, reviewsCount] = storeId
|
|
35
39
|
? await Promise.all([
|
|
36
40
|
productRepository
|
|
37
41
|
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "standard")), page: 1, pageSize: 1 })
|
|
@@ -67,6 +71,14 @@ export async function StoreDetailLayoutView({ storeSlug, activeTab, children, })
|
|
|
67
71
|
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "live")), page: 1, pageSize: 1 })
|
|
68
72
|
.then((r) => r.total)
|
|
69
73
|
.catch(() => 0),
|
|
74
|
+
productRepository
|
|
75
|
+
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "art")), page: 1, pageSize: 1 })
|
|
76
|
+
.then((r) => r.total)
|
|
77
|
+
.catch(() => 0),
|
|
78
|
+
productRepository
|
|
79
|
+
.list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("status", SIEVE_OP.EQ, "published"), sieveFilter("listingType", SIEVE_OP.EQ, "stickers")), page: 1, pageSize: 1 })
|
|
80
|
+
.then((r) => r.total)
|
|
81
|
+
.catch(() => 0),
|
|
70
82
|
couponsRepository
|
|
71
83
|
.list({ filters: sieveAnd(sieveFilter("sellerId", SIEVE_OP.EQ, storeId), sieveFilter("validity.isActive", SIEVE_OP.EQ, "true")), page: 1, pageSize: 1 })
|
|
72
84
|
.then((r) => r.total)
|
|
@@ -76,7 +88,7 @@ export async function StoreDetailLayoutView({ storeSlug, activeTab, children, })
|
|
|
76
88
|
.then((r) => r.total)
|
|
77
89
|
.catch(() => 0),
|
|
78
90
|
])
|
|
79
|
-
: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
91
|
+
: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
80
92
|
const listingCounts = {
|
|
81
93
|
products: productsCount,
|
|
82
94
|
auctions: auctionsCount,
|
|
@@ -86,6 +98,8 @@ export async function StoreDetailLayoutView({ storeSlug, activeTab, children, })
|
|
|
86
98
|
classifieds: classifiedsCount,
|
|
87
99
|
"digital-codes": digitalCodesCount,
|
|
88
100
|
live: liveCount,
|
|
101
|
+
art: artCount,
|
|
102
|
+
stickers: stickersCount,
|
|
89
103
|
};
|
|
90
104
|
const TAB_LISTING_TYPE = {
|
|
91
105
|
products: "standard",
|
|
@@ -95,6 +109,8 @@ export async function StoreDetailLayoutView({ storeSlug, activeTab, children, })
|
|
|
95
109
|
classifieds: "classified",
|
|
96
110
|
"digital-codes": "digital-code",
|
|
97
111
|
live: "live",
|
|
112
|
+
art: "art",
|
|
113
|
+
stickers: "stickers",
|
|
98
114
|
};
|
|
99
115
|
const visibleStoreTabs = STORE_PAGE_TABS.filter((tab) => {
|
|
100
116
|
if (tab.id === "bundles")
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { StoreCapability } from "../../auth/permissions/constants";
|
|
8
8
|
import type { BaseDocument } from "../../../_internal/shared/types/base-document";
|
|
9
|
-
export type ShippingProviderType = "
|
|
9
|
+
export type ShippingProviderType = "self-courier" | "store-pickup" | "custom";
|
|
10
10
|
export interface ShippingProviderConfig {
|
|
11
11
|
/** Stable slug — never changes after creation. */
|
|
12
12
|
providerId: string;
|
|
@@ -101,6 +101,12 @@ export interface StoreDocument extends BaseDocument {
|
|
|
101
101
|
* ShippingPicker; the chosen provider + fee lock onto each CartItem.
|
|
102
102
|
*/
|
|
103
103
|
shippingConfig?: StoreShippingConfig;
|
|
104
|
+
/**
|
|
105
|
+
* Seller opt-in for EMI (installment) checkout. EMI is offered on this
|
|
106
|
+
* store's items only when this AND `siteSettings.emi.enabled` are both
|
|
107
|
+
* true. Default false — sellers must explicitly opt in.
|
|
108
|
+
*/
|
|
109
|
+
emiEnabled?: boolean;
|
|
104
110
|
whatsappConfig?: {
|
|
105
111
|
/** Seller's WhatsApp Business phone number, digits-only with country code e.g. "919876543210" */
|
|
106
112
|
phoneNumber?: string;
|