@mohasinac/appkit 2.7.17 → 2.7.18
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/bundles/actions.d.ts +15 -0
- package/dist/_internal/server/features/bundles/actions.js +48 -0
- package/dist/_internal/server/features/bundles/index.d.ts +1 -0
- package/dist/_internal/server/features/bundles/index.js +1 -0
- package/dist/_internal/server/features/checkout/actions.d.ts +4 -0
- package/dist/_internal/server/features/checkout/actions.js +23 -12
- package/dist/_internal/server/features/payments/data.d.ts +5 -3
- package/dist/_internal/server/features/payments/data.js +13 -8
- package/dist/_internal/server/features/payments/index.d.ts +1 -1
- package/dist/_internal/server/features/payments/index.js +1 -1
- package/dist/_internal/shared/features/categories/bundle-config.d.ts +24 -0
- package/dist/_internal/shared/features/categories/bundle-config.js +28 -0
- package/dist/_internal/shared/features/categories/bundle-copy.d.ts +7 -0
- package/dist/_internal/shared/features/categories/bundle-copy.js +9 -0
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +69 -19
- package/dist/_internal/shared/features/categories/bundle-schemas.js +20 -2
- package/dist/_internal/shared/features/checkout/config.d.ts +1 -1
- package/dist/_internal/shared/features/checkout/config.js +1 -1
- package/dist/_internal/shared/features/payments/config.d.ts +2 -1
- package/dist/_internal/shared/features/payments/config.js +2 -1
- package/dist/_internal/shared/features/products/schema.d.ts +8 -8
- package/dist/constants/field-names.d.ts +8 -1
- package/dist/constants/field-names.js +9 -2
- package/dist/constants/table-keys.d.ts +3 -0
- package/dist/constants/table-keys.js +3 -0
- package/dist/features/admin/components/AdminSiteSettingsView.js +17 -15
- package/dist/features/admin/components/DashboardStats.js +20 -12
- package/dist/features/admin/components/analytics/AdminAnalyticsCharts.js +18 -2
- package/dist/features/admin/components/analytics/AdminStatCard.d.ts +7 -1
- package/dist/features/admin/components/analytics/AdminStatCard.js +13 -2
- package/dist/features/admin/schemas/firestore.d.ts +18 -4
- package/dist/features/admin/schemas/firestore.js +11 -1
- package/dist/features/categories/components/BundleBuyNowCta.d.ts +3 -1
- package/dist/features/categories/components/BundleBuyNowCta.js +3 -3
- package/dist/features/categories/components/BundleDynamicRuleEditor.d.ts +1 -1
- package/dist/features/categories/components/BundleDynamicRuleEditor.js +2 -1
- package/dist/features/categories/components/BundlesListView.d.ts +4 -1
- package/dist/features/categories/components/BundlesListView.js +2 -2
- package/dist/features/categories/components/CategoryBundlesListing.d.ts +4 -1
- package/dist/features/categories/components/CategoryBundlesListing.js +9 -8
- package/dist/features/categories/schemas/firestore.d.ts +29 -1
- package/dist/features/checkout/actions/checkout-actions.d.ts +11 -0
- package/dist/features/checkout/actions/checkout-actions.js +26 -0
- package/dist/features/filters/FilterFacetSection.d.ts +6 -1
- package/dist/features/filters/FilterFacetSection.js +25 -2
- package/dist/features/homepage/components/FeaturedBundlesSection.d.ts +4 -1
- package/dist/features/homepage/components/FeaturedBundlesSection.js +9 -8
- package/dist/features/orders/actions/refund-actions.js +10 -7
- package/dist/features/orders/schemas/firestore.d.ts +16 -13
- package/dist/features/orders/schemas/firestore.js +6 -5
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +1 -1
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +2 -1
- package/dist/features/products/components/AuctionsIndexListing.js +2 -1
- package/dist/features/products/components/ProductDetailPageView.js +3 -1
- package/dist/features/products/components/ProductDetailView.d.ts +3 -1
- package/dist/features/products/components/ProductDetailView.js +2 -2
- package/dist/features/products/components/ProductFilters.d.ts +10 -4
- package/dist/features/products/components/ProductFilters.js +20 -16
- package/dist/features/products/components/ProductGrid.js +2 -2
- package/dist/features/products/components/ProductsIndexListing.js +2 -1
- package/dist/features/products/constants/product-features.constants.js +5 -1
- package/dist/features/products/schemas/index.d.ts +2 -2
- package/dist/features/products/schemas/product-features.d.ts +1 -1
- package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
- package/dist/features/products/schemas/product-features.validators.js +4 -0
- package/dist/features/seller/components/SellerCouponEditorView.js +2 -2
- package/dist/features/seller/components/analytics/SellerAnalyticsStats.js +10 -4
- package/dist/features/stores/components/StoreBundlesPageView.d.ts +4 -1
- package/dist/features/stores/components/StoreBundlesPageView.js +2 -2
- package/dist/features/stores/components/StoresIndexListing.js +2 -1
- package/dist/providers/db-firebase/admin-app-lite.js +8 -2
- package/dist/providers/db-firebase/admin.js +8 -2
- package/dist/seed/addresses-seed-data.js +24 -7
- package/dist/seed/cart-seed-data.d.ts +10 -10
- package/dist/seed/cart-seed-data.js +39 -2
- package/dist/seed/grouped-listings-seed-data.js +47 -0
- package/dist/seed/orders-seed-data.js +150 -0
- package/dist/seed/products-standard-seed-data.js +42 -0
- package/dist/seed/site-settings-seed-data.js +11 -4
- package/dist/seed/users-seed-data.js +1 -1
- package/dist/seed/wishlists-seed-data.js +7 -0
- package/dist/server-entry.d.ts +2 -1
- package/dist/server-entry.js +2 -1
- package/dist/server.d.ts +2 -1
- package/dist/server.js +3 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/SideDrawer.style.css +49 -11
- package/package.json +1 -1
|
@@ -8,8 +8,16 @@
|
|
|
8
8
|
* client too if the admin form ever pre-validates.
|
|
9
9
|
*/
|
|
10
10
|
import { z } from "zod";
|
|
11
|
-
import { BUNDLE_MAX_ITEMS } from "./bundle-config";
|
|
11
|
+
import { BUNDLE_MAX_ITEMS, BUNDLE_DRAW_COUNT_MAX, BUNDLE_KIND_SPECIAL, BUNDLE_KIND_BRAND, } from "./bundle-config";
|
|
12
12
|
const productIdsSchema = z.array(z.string().min(1)).min(0).max(BUNDLE_MAX_ITEMS);
|
|
13
|
+
/**
|
|
14
|
+
* Per-member detail — mirrors BundleItemDetail in the Firestore schema.
|
|
15
|
+
* `drawCount` is required when the member is a prize-draw listing (1–BUNDLE_DRAW_COUNT_MAX).
|
|
16
|
+
*/
|
|
17
|
+
const bundleItemDetailSchema = z.object({
|
|
18
|
+
productId: z.string().min(1),
|
|
19
|
+
drawCount: z.number().int().min(1).max(BUNDLE_DRAW_COUNT_MAX).optional(),
|
|
20
|
+
});
|
|
13
21
|
export const bundleQueryRuleSchema = z.discriminatedUnion("type", [
|
|
14
22
|
z.object({
|
|
15
23
|
type: z.literal("static"),
|
|
@@ -21,7 +29,8 @@ export const bundleQueryRuleSchema = z.discriminatedUnion("type", [
|
|
|
21
29
|
categorySlug: z.string().optional(),
|
|
22
30
|
brandSlug: z.string().optional(),
|
|
23
31
|
tags: z.array(z.string()).optional(),
|
|
24
|
-
|
|
32
|
+
/** Eligible listing types for a dynamic bundle rule. */
|
|
33
|
+
listingType: z.enum(["standard", "pre-order", "prize-draw"]).optional(),
|
|
25
34
|
}),
|
|
26
35
|
orderBy: z
|
|
27
36
|
.enum(["price-asc", "price-desc", "createdAt-desc"])
|
|
@@ -38,18 +47,27 @@ export const bundleCreateSchema = z.object({
|
|
|
38
47
|
name: z.string().min(2).max(120),
|
|
39
48
|
slug: z.string().min(2).max(120).optional(),
|
|
40
49
|
description: z.string().max(2000).optional(),
|
|
50
|
+
/**
|
|
51
|
+
* "special" — curated bundle; updates partOfBundleIds on member products.
|
|
52
|
+
* "brand" — brand discovery collection; does not touch product reverse pointers.
|
|
53
|
+
*/
|
|
54
|
+
bundleKind: z.enum([BUNDLE_KIND_SPECIAL, BUNDLE_KIND_BRAND]),
|
|
41
55
|
bundlePriceInPaise: z.number().int().min(100),
|
|
42
56
|
bundleQueryRule: bundleQueryRuleSchema,
|
|
43
57
|
bundleProductIds: productIdsSchema,
|
|
58
|
+
/** Richer per-member metadata (draw counts for prize-draws). */
|
|
59
|
+
bundleItemDetails: z.array(bundleItemDetailSchema).optional(),
|
|
44
60
|
display: bundleDisplaySchema.optional(),
|
|
45
61
|
isActive: z.boolean().optional(),
|
|
46
62
|
});
|
|
47
63
|
export const bundleUpdateSchema = z.object({
|
|
48
64
|
name: z.string().min(2).max(120).optional(),
|
|
49
65
|
description: z.string().max(2000).optional(),
|
|
66
|
+
bundleKind: z.enum([BUNDLE_KIND_SPECIAL, BUNDLE_KIND_BRAND]).optional(),
|
|
50
67
|
bundlePriceInPaise: z.number().int().min(100).optional(),
|
|
51
68
|
bundleQueryRule: bundleQueryRuleSchema.optional(),
|
|
52
69
|
bundleProductIds: productIdsSchema.optional(),
|
|
70
|
+
bundleItemDetails: z.array(bundleItemDetailSchema).optional(),
|
|
53
71
|
display: bundleDisplaySchema.optional(),
|
|
54
72
|
isActive: z.boolean().optional(),
|
|
55
73
|
});
|
|
@@ -4,5 +4,5 @@ export declare const CHECKOUT_DEFAULT_COMMISSIONS: {
|
|
|
4
4
|
readonly platformShippingPercent: 10;
|
|
5
5
|
readonly platformShippingFixedMin: 50;
|
|
6
6
|
};
|
|
7
|
-
export declare const CHECKOUT_PAYMENT_METHODS: readonly ["cod", "online", "upi_manual"];
|
|
7
|
+
export declare const CHECKOUT_PAYMENT_METHODS: readonly ["cod", "online", "upi_manual", "admin_bypass"];
|
|
8
8
|
export type CheckoutPaymentMethod = (typeof CHECKOUT_PAYMENT_METHODS)[number];
|
|
@@ -4,4 +4,4 @@ export const CHECKOUT_DEFAULT_COMMISSIONS = {
|
|
|
4
4
|
platformShippingPercent: 10,
|
|
5
5
|
platformShippingFixedMin: 50,
|
|
6
6
|
};
|
|
7
|
-
export const CHECKOUT_PAYMENT_METHODS = ["cod", "online", "upi_manual"];
|
|
7
|
+
export const CHECKOUT_PAYMENT_METHODS = ["cod", "online", "upi_manual", "admin_bypass"];
|
|
@@ -34,12 +34,12 @@ export declare const productInputSchema: z.ZodObject<{
|
|
|
34
34
|
availableQuantity: number;
|
|
35
35
|
mainImage: string;
|
|
36
36
|
condition?: "new" | "used" | "refurbished" | "broken" | "like_new" | "good" | "fair" | "poor" | undefined;
|
|
37
|
+
features?: string[] | undefined;
|
|
37
38
|
description?: string | undefined;
|
|
38
39
|
seoTitle?: string | undefined;
|
|
39
40
|
seoDescription?: string | undefined;
|
|
40
41
|
seoKeywords?: string[] | undefined;
|
|
41
42
|
brandSlug?: string | undefined;
|
|
42
|
-
features?: string[] | undefined;
|
|
43
43
|
shippingInfo?: string | undefined;
|
|
44
44
|
returnPolicy?: string | undefined;
|
|
45
45
|
insurance?: boolean | undefined;
|
|
@@ -55,6 +55,7 @@ export declare const productInputSchema: z.ZodObject<{
|
|
|
55
55
|
currency?: string | undefined;
|
|
56
56
|
condition?: "new" | "used" | "refurbished" | "broken" | "like_new" | "good" | "fair" | "poor" | undefined;
|
|
57
57
|
tags?: string[] | undefined;
|
|
58
|
+
features?: string[] | undefined;
|
|
58
59
|
images?: string[] | undefined;
|
|
59
60
|
description?: string | undefined;
|
|
60
61
|
seoTitle?: string | undefined;
|
|
@@ -63,7 +64,6 @@ export declare const productInputSchema: z.ZodObject<{
|
|
|
63
64
|
brandSlug?: string | undefined;
|
|
64
65
|
stockQuantity?: number | undefined;
|
|
65
66
|
availableQuantity?: number | undefined;
|
|
66
|
-
features?: string[] | undefined;
|
|
67
67
|
shippingInfo?: string | undefined;
|
|
68
68
|
returnPolicy?: string | undefined;
|
|
69
69
|
insurance?: boolean | undefined;
|
|
@@ -103,6 +103,7 @@ export declare const productUpdateSchema: z.ZodObject<{
|
|
|
103
103
|
price?: number | undefined;
|
|
104
104
|
condition?: "new" | "used" | "refurbished" | "broken" | "like_new" | "good" | "fair" | "poor" | undefined;
|
|
105
105
|
tags?: string[] | undefined;
|
|
106
|
+
features?: string[] | undefined;
|
|
106
107
|
images?: string[] | undefined;
|
|
107
108
|
description?: string | undefined;
|
|
108
109
|
seoTitle?: string | undefined;
|
|
@@ -112,7 +113,6 @@ export declare const productUpdateSchema: z.ZodObject<{
|
|
|
112
113
|
stockQuantity?: number | undefined;
|
|
113
114
|
availableQuantity?: number | undefined;
|
|
114
115
|
mainImage?: string | undefined;
|
|
115
|
-
features?: string[] | undefined;
|
|
116
116
|
shippingInfo?: string | undefined;
|
|
117
117
|
returnPolicy?: string | undefined;
|
|
118
118
|
insurance?: boolean | undefined;
|
|
@@ -127,6 +127,7 @@ export declare const productUpdateSchema: z.ZodObject<{
|
|
|
127
127
|
price?: number | undefined;
|
|
128
128
|
condition?: "new" | "used" | "refurbished" | "broken" | "like_new" | "good" | "fair" | "poor" | undefined;
|
|
129
129
|
tags?: string[] | undefined;
|
|
130
|
+
features?: string[] | undefined;
|
|
130
131
|
images?: string[] | undefined;
|
|
131
132
|
description?: string | undefined;
|
|
132
133
|
seoTitle?: string | undefined;
|
|
@@ -136,7 +137,6 @@ export declare const productUpdateSchema: z.ZodObject<{
|
|
|
136
137
|
stockQuantity?: number | undefined;
|
|
137
138
|
availableQuantity?: number | undefined;
|
|
138
139
|
mainImage?: string | undefined;
|
|
139
|
-
features?: string[] | undefined;
|
|
140
140
|
shippingInfo?: string | undefined;
|
|
141
141
|
returnPolicy?: string | undefined;
|
|
142
142
|
insurance?: boolean | undefined;
|
|
@@ -194,12 +194,12 @@ export declare const auctionInputSchema: z.ZodObject<{
|
|
|
194
194
|
startingBid: number;
|
|
195
195
|
autoExtendable: boolean;
|
|
196
196
|
condition?: "new" | "used" | "refurbished" | "broken" | "like_new" | "good" | "fair" | "poor" | undefined;
|
|
197
|
+
features?: string[] | undefined;
|
|
197
198
|
description?: string | undefined;
|
|
198
199
|
seoTitle?: string | undefined;
|
|
199
200
|
seoDescription?: string | undefined;
|
|
200
201
|
seoKeywords?: string[] | undefined;
|
|
201
202
|
brandSlug?: string | undefined;
|
|
202
|
-
features?: string[] | undefined;
|
|
203
203
|
shippingInfo?: string | undefined;
|
|
204
204
|
returnPolicy?: string | undefined;
|
|
205
205
|
insurance?: boolean | undefined;
|
|
@@ -223,6 +223,7 @@ export declare const auctionInputSchema: z.ZodObject<{
|
|
|
223
223
|
currency?: string | undefined;
|
|
224
224
|
condition?: "new" | "used" | "refurbished" | "broken" | "like_new" | "good" | "fair" | "poor" | undefined;
|
|
225
225
|
tags?: string[] | undefined;
|
|
226
|
+
features?: string[] | undefined;
|
|
226
227
|
images?: string[] | undefined;
|
|
227
228
|
description?: string | undefined;
|
|
228
229
|
seoTitle?: string | undefined;
|
|
@@ -231,7 +232,6 @@ export declare const auctionInputSchema: z.ZodObject<{
|
|
|
231
232
|
brandSlug?: string | undefined;
|
|
232
233
|
stockQuantity?: number | undefined;
|
|
233
234
|
availableQuantity?: number | undefined;
|
|
234
|
-
features?: string[] | undefined;
|
|
235
235
|
shippingInfo?: string | undefined;
|
|
236
236
|
returnPolicy?: string | undefined;
|
|
237
237
|
insurance?: boolean | undefined;
|
|
@@ -292,12 +292,12 @@ export declare const preOrderInputSchema: z.ZodObject<{
|
|
|
292
292
|
preOrderDeliveryDate: string;
|
|
293
293
|
preOrderCancellable: boolean;
|
|
294
294
|
condition?: "new" | "used" | "refurbished" | "broken" | "like_new" | "good" | "fair" | "poor" | undefined;
|
|
295
|
+
features?: string[] | undefined;
|
|
295
296
|
description?: string | undefined;
|
|
296
297
|
seoTitle?: string | undefined;
|
|
297
298
|
seoDescription?: string | undefined;
|
|
298
299
|
seoKeywords?: string[] | undefined;
|
|
299
300
|
brandSlug?: string | undefined;
|
|
300
|
-
features?: string[] | undefined;
|
|
301
301
|
shippingInfo?: string | undefined;
|
|
302
302
|
returnPolicy?: string | undefined;
|
|
303
303
|
insurance?: boolean | undefined;
|
|
@@ -318,6 +318,7 @@ export declare const preOrderInputSchema: z.ZodObject<{
|
|
|
318
318
|
condition?: "new" | "used" | "refurbished" | "broken" | "like_new" | "good" | "fair" | "poor" | undefined;
|
|
319
319
|
tags?: string[] | undefined;
|
|
320
320
|
preOrderProductionStatus?: "upcoming" | "in_production" | "ready_to_ship" | undefined;
|
|
321
|
+
features?: string[] | undefined;
|
|
321
322
|
images?: string[] | undefined;
|
|
322
323
|
description?: string | undefined;
|
|
323
324
|
seoTitle?: string | undefined;
|
|
@@ -326,7 +327,6 @@ export declare const preOrderInputSchema: z.ZodObject<{
|
|
|
326
327
|
brandSlug?: string | undefined;
|
|
327
328
|
stockQuantity?: number | undefined;
|
|
328
329
|
availableQuantity?: number | undefined;
|
|
329
|
-
features?: string[] | undefined;
|
|
330
330
|
shippingInfo?: string | undefined;
|
|
331
331
|
returnPolicy?: string | undefined;
|
|
332
332
|
insurance?: boolean | undefined;
|
|
@@ -407,7 +407,9 @@ export declare const CATEGORY_FIELDS: {
|
|
|
407
407
|
readonly DISPLAY_ORDER: "displayOrder";
|
|
408
408
|
readonly IS_ACTIVE: "isActive";
|
|
409
409
|
readonly CATEGORY_TYPE: "categoryType";
|
|
410
|
+
readonly BUNDLE_KIND: "bundleKind";
|
|
410
411
|
readonly BUNDLE_PRODUCT_IDS: "bundleProductIds";
|
|
412
|
+
readonly BUNDLE_ITEM_DETAILS: "bundleItemDetails";
|
|
411
413
|
readonly BUNDLE_STOCK_STATUS: "bundleStockStatus";
|
|
412
414
|
readonly BUNDLE_QUERY_RESOLVED_AT: "bundleQueryResolvedAt";
|
|
413
415
|
readonly DISPLAY: "display";
|
|
@@ -766,11 +768,16 @@ export declare const SITE_SETTINGS_FIELDS: {
|
|
|
766
768
|
};
|
|
767
769
|
readonly COMMISSIONS: "commissions";
|
|
768
770
|
readonly COMMISSION_FIELDS: {
|
|
769
|
-
readonly
|
|
771
|
+
readonly PLATFORM_FEE_PERCENT: "commissions.platformFeePercent";
|
|
772
|
+
readonly GST_PERCENT: "commissions.gstPercent";
|
|
773
|
+
readonly MINIMUM_TRANSACTION_FEE: "commissions.minimumTransactionFee";
|
|
774
|
+
readonly GATEWAY_FEE_PERCENT: "commissions.gatewayFeePercent";
|
|
770
775
|
readonly COD_DEPOSIT_PERCENT: "commissions.codDepositPercent";
|
|
771
776
|
readonly SELLER_SHIPPING_FIXED: "commissions.sellerShippingFixed";
|
|
772
777
|
readonly PLATFORM_SHIPPING_PERCENT: "commissions.platformShippingPercent";
|
|
773
778
|
readonly PLATFORM_SHIPPING_FIXED_MIN: "commissions.platformShippingFixedMin";
|
|
779
|
+
readonly PAYOUT_HOLD_DAYS: "commissions.payoutHoldDays";
|
|
780
|
+
readonly MIN_PAYOUT_AMOUNT: "commissions.minPayoutAmount";
|
|
774
781
|
};
|
|
775
782
|
readonly SOCIAL_LINKS: "socialLinks";
|
|
776
783
|
readonly EMAIL_SETTINGS: "emailSettings";
|
|
@@ -448,8 +448,10 @@ export const CATEGORY_FIELDS = {
|
|
|
448
448
|
IS_ACTIVE: "isActive",
|
|
449
449
|
// SB-UNI — categoryType discriminator (category/brand/sublisting/bundle)
|
|
450
450
|
CATEGORY_TYPE: "categoryType",
|
|
451
|
-
// Bundle-specific fields (SB3)
|
|
451
|
+
// Bundle-specific fields (SB3 + bundle-eligibility rules)
|
|
452
|
+
BUNDLE_KIND: "bundleKind",
|
|
452
453
|
BUNDLE_PRODUCT_IDS: "bundleProductIds",
|
|
454
|
+
BUNDLE_ITEM_DETAILS: "bundleItemDetails",
|
|
453
455
|
BUNDLE_STOCK_STATUS: "bundleStockStatus",
|
|
454
456
|
BUNDLE_QUERY_RESOLVED_AT: "bundleQueryResolvedAt",
|
|
455
457
|
DISPLAY: "display",
|
|
@@ -862,11 +864,16 @@ export const SITE_SETTINGS_FIELDS = {
|
|
|
862
864
|
},
|
|
863
865
|
COMMISSIONS: "commissions",
|
|
864
866
|
COMMISSION_FIELDS: {
|
|
865
|
-
|
|
867
|
+
PLATFORM_FEE_PERCENT: "commissions.platformFeePercent",
|
|
868
|
+
GST_PERCENT: "commissions.gstPercent",
|
|
869
|
+
MINIMUM_TRANSACTION_FEE: "commissions.minimumTransactionFee",
|
|
870
|
+
GATEWAY_FEE_PERCENT: "commissions.gatewayFeePercent",
|
|
866
871
|
COD_DEPOSIT_PERCENT: "commissions.codDepositPercent",
|
|
867
872
|
SELLER_SHIPPING_FIXED: "commissions.sellerShippingFixed",
|
|
868
873
|
PLATFORM_SHIPPING_PERCENT: "commissions.platformShippingPercent",
|
|
869
874
|
PLATFORM_SHIPPING_FIXED_MIN: "commissions.platformShippingFixedMin",
|
|
875
|
+
PAYOUT_HOLD_DAYS: "commissions.payoutHoldDays",
|
|
876
|
+
MIN_PAYOUT_AMOUNT: "commissions.minPayoutAmount",
|
|
870
877
|
},
|
|
871
878
|
SOCIAL_LINKS: "socialLinks",
|
|
872
879
|
EMAIL_SETTINGS: "emailSettings",
|
|
@@ -38,6 +38,9 @@ export declare const TABLE_KEYS: {
|
|
|
38
38
|
readonly CATEGORY_SLUG: "categorySlug";
|
|
39
39
|
readonly SHOW_UNREAD: "showUnread";
|
|
40
40
|
readonly TYPE: "type";
|
|
41
|
+
readonly IS_PART_OF_BUNDLE: "isPartOfBundle";
|
|
42
|
+
readonly SUBLISTING_CATEGORY: "sublistingCategory";
|
|
43
|
+
readonly FEATURES: "features";
|
|
41
44
|
};
|
|
42
45
|
export type TableKey = (typeof TABLE_KEYS)[keyof typeof TABLE_KEYS];
|
|
43
46
|
export declare const VIEW_MODE: {
|
|
@@ -38,6 +38,9 @@ export const TABLE_KEYS = {
|
|
|
38
38
|
CATEGORY_SLUG: "categorySlug",
|
|
39
39
|
SHOW_UNREAD: "showUnread",
|
|
40
40
|
TYPE: "type",
|
|
41
|
+
IS_PART_OF_BUNDLE: "isPartOfBundle",
|
|
42
|
+
SUBLISTING_CATEGORY: "sublistingCategory",
|
|
43
|
+
FEATURES: "features",
|
|
41
44
|
};
|
|
42
45
|
export const VIEW_MODE = {
|
|
43
46
|
GRID: "grid",
|
|
@@ -70,10 +70,11 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
|
|
|
70
70
|
const [watermarkImageUrl, setWatermarkImageUrl] = React.useState("");
|
|
71
71
|
const [watermarkSize, setWatermarkSize] = React.useState(30);
|
|
72
72
|
const [watermarkOpacity, setWatermarkOpacity] = React.useState(20);
|
|
73
|
-
// ⑦ Fees
|
|
74
|
-
const [
|
|
75
|
-
const [
|
|
76
|
-
const [
|
|
73
|
+
// ⑦ Fees — all read/written under commissions key
|
|
74
|
+
const [platformFeePercent, setPlatformFeePercent] = React.useState(5);
|
|
75
|
+
const [gstPercent, setGstPercent] = React.useState(18);
|
|
76
|
+
const [minimumTransactionFee, setMinimumTransactionFee] = React.useState(0);
|
|
77
|
+
const [gatewayFeePercent, setGatewayFeePercent] = React.useState(2);
|
|
77
78
|
const [payoutHoldDays, setPayoutHoldDays] = React.useState(7);
|
|
78
79
|
const [minPayoutAmount, setMinPayoutAmount] = React.useState(100);
|
|
79
80
|
const [auctionListingFee, setAuctionListingFee] = React.useState(0);
|
|
@@ -172,15 +173,16 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
|
|
|
172
173
|
setWatermarkImageUrl(s.watermark?.imageUrl ?? "");
|
|
173
174
|
setWatermarkSize(s.watermark?.size ?? 30);
|
|
174
175
|
setWatermarkOpacity(s.watermark?.opacity ?? 20);
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
176
|
+
setPlatformFeePercent(s.commissions?.platformFeePercent ?? 5);
|
|
177
|
+
setGstPercent(s.commissions?.gstPercent ?? 18);
|
|
178
|
+
setMinimumTransactionFee(s.commissions?.minimumTransactionFee ?? 0);
|
|
179
|
+
setGatewayFeePercent(s.commissions?.gatewayFeePercent ?? 2);
|
|
180
|
+
setPayoutHoldDays(s.commissions?.payoutHoldDays ?? 7);
|
|
181
|
+
setMinPayoutAmount(s.commissions?.minPayoutAmount ?? 100);
|
|
182
|
+
setAuctionListingFee(s.commissions?.auctionListingFee ?? 0);
|
|
183
|
+
setPreOrderListingFee(s.commissions?.preOrderListingFee ?? 0);
|
|
184
|
+
setFeaturedSlotFee(s.commissions?.featuredSlotFee ?? 999);
|
|
185
|
+
setPromotedSlotFee(s.commissions?.promotedSlotFee ?? 499);
|
|
184
186
|
setRazorpayKeyId(s.credentialsMasked?.razorpayKeyId ?? "");
|
|
185
187
|
setRazorpaySecret(s.credentialsMasked?.razorpaySecret ?? "");
|
|
186
188
|
setShiprocketToken(s.credentialsMasked?.shiprocketToken ?? "");
|
|
@@ -259,7 +261,7 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
|
|
|
259
261
|
watermark: { type: watermarkType, text: watermarkText, imageUrl: watermarkImageUrl, size: watermarkSize, opacity: watermarkOpacity },
|
|
260
262
|
}));
|
|
261
263
|
const feesMutation = useSave("Fees", () => ({
|
|
262
|
-
|
|
264
|
+
commissions: { platformFeePercent, gstPercent, minimumTransactionFee, gatewayFeePercent, payoutHoldDays, minPayoutAmount, auctionListingFee, preOrderListingFee, featuredSlotFee, promotedSlotFee },
|
|
263
265
|
}));
|
|
264
266
|
const integrationsMutation = useSave("Integrations", () => ({
|
|
265
267
|
credentials: {
|
|
@@ -328,7 +330,7 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
|
|
|
328
330
|
["limits", "⑪ Limits"],
|
|
329
331
|
["legal", "⑫ Legal"],
|
|
330
332
|
["whatsapp", "⑬ WhatsApp"],
|
|
331
|
-
].map(([value, label]) => (_jsx(TabsTrigger, { value: value, children: label }, value))) }), _jsx(TabsContent, { value: "about", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); aboutMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Override the About page hero and mission text. Leave blank to use the platform defaults." }), _jsx(Input, { label: "Hero title", value: aboutTitle, onChange: (e) => setAboutTitle(e.target.value), placeholder: "About LetItRip" }), _jsx(Input, { label: "Hero subtitle", value: aboutSubtitle, onChange: (e) => setAboutSubtitle(e.target.value), placeholder: "Connecting buyers, sellers, and bidders in one vibrant marketplace" }), _jsx(Input, { label: "Mission section title", value: aboutMissionTitle, onChange: (e) => setAboutMissionTitle(e.target.value), placeholder: "Our Mission" }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Mission text" }), _jsx("textarea", { value: aboutMissionText, onChange: (e) => setAboutMissionText(e.target.value), placeholder: "LetItRip was built to democratise commerce\u2026", rows: 4, className: "w-full rounded-md border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-800 p-3 text-sm text-zinc-800 dark:text-zinc-200 resize-y focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), _jsx(Input, { label: "CTA banner title", value: aboutCtaTitle, onChange: (e) => setAboutCtaTitle(e.target.value), placeholder: "Ready to get started?" }), _jsx(GroupSaveButton, { isPending: aboutMutation.isPending })] }) }), _jsx(TabsContent, { value: "branding", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); brandingMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx(Input, { label: "Site name", value: siteName, onChange: (e) => setSiteName(e.target.value), placeholder: "LetItRip" }), _jsx(Input, { label: "Tagline", value: tagline, onChange: (e) => setTagline(e.target.value), placeholder: "India's Largest Collectibles Marketplace" }), _jsx(ImageUpload, { label: "Logo", currentImage: logoUrl, onUpload: (file) => upload(file, "store"), onChange: setLogoUrl }), _jsx(ImageUpload, { label: "Favicon", currentImage: faviconUrl, onUpload: (file) => upload(file, "store"), onChange: setFaviconUrl }), _jsxs("div", { className: "space-y-3 rounded-lg border border-zinc-200 dark:border-zinc-700 p-4", children: [_jsx(Toggle, { label: "Maintenance mode", checked: maintenanceMode, onChange: setMaintenanceMode }), _jsx(Input, { label: "Maintenance message", value: maintenanceMessage, onChange: (e) => setMaintenanceMessage(e.target.value), placeholder: "We're back soon.", disabled: !maintenanceMode })] }), _jsx(GroupSaveButton, { isPending: brandingMutation.isPending })] }) }), _jsx(TabsContent, { value: "appearance", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); appearanceMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsxs("div", { className: "grid grid-cols-3 gap-4", children: [_jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Primary color" }), _jsx("input", { type: "color", value: primaryColor || "#000000", onChange: (e) => setPrimaryColor(e.target.value), className: "h-10 w-full rounded border border-zinc-200 dark:border-zinc-700 cursor-pointer" })] }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Secondary color" }), _jsx("input", { type: "color", value: secondaryColor || "#000000", onChange: (e) => setSecondaryColor(e.target.value), className: "h-10 w-full rounded border border-zinc-200 dark:border-zinc-700 cursor-pointer" })] }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Accent color" }), _jsx("input", { type: "color", value: accentColor || "#000000", onChange: (e) => setAccentColor(e.target.value), className: "h-10 w-full rounded border border-zinc-200 dark:border-zinc-700 cursor-pointer" })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Select, { label: "Default theme", options: THEME_OPTIONS, value: defaultTheme, onValueChange: setDefaultTheme }), _jsx(Select, { label: "Font family", options: FONT_OPTIONS, value: fontFamily, onValueChange: setFontFamily })] }), _jsx(GroupSaveButton, { isPending: appearanceMutation.isPending })] }) }), _jsx(TabsContent, { value: "announcement", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); announcementMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx(Toggle, { label: "Show announcement bar", checked: announcementEnabled, onChange: setAnnouncementEnabled }), _jsx(Input, { label: "Announcement text", value: announcementText, onChange: (e) => setAnnouncementText(e.target.value), placeholder: "\uD83C\uDF89 Free shipping on orders \u20B9999+", disabled: !announcementEnabled }), _jsx(Input, { label: "Link URL (optional)", value: announcementLink, onChange: (e) => setAnnouncementLink(e.target.value), placeholder: "/products", disabled: !announcementEnabled }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Background color" }), _jsx("input", { type: "color", value: announcementBg || "#1d4ed8", onChange: (e) => setAnnouncementBg(e.target.value), className: "h-10 w-32 rounded border border-zinc-200 dark:border-zinc-700 cursor-pointer", disabled: !announcementEnabled })] }), _jsx(GroupSaveButton, { isPending: announcementMutation.isPending })] }) }), _jsx(TabsContent, { value: "seo", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); seoMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx(Input, { label: "Default meta title", value: seoTitle, onChange: (e) => setSeoTitle(e.target.value), placeholder: "LetItRip \u2014 Buy, Sell & Auction Collectibles in India", maxLength: 60, helperText: "Max 60 chars. Use {page} token for dynamic insertion." }), _jsx(Input, { label: "Default meta description", value: seoDescription, onChange: (e) => setSeoDescription(e.target.value), placeholder: "India's largest collectibles marketplace\u2026", maxLength: 160, helperText: "Max 160 chars." }), _jsx(ImageUpload, { label: "Default OG image", currentImage: seoOgImage, onUpload: (file) => upload(file, "store"), onChange: setSeoOgImage }), _jsx(Input, { label: "Canonical base URL", value: canonicalUrl, onChange: (e) => setCanonicalUrl(e.target.value), placeholder: "https://letitrip.in" }), _jsx(Toggle, { label: "Robots noindex (disables search indexing \u2014 use carefully)", checked: seoNoIndex, onChange: setSeoNoIndex }), _jsx(GroupSaveButton, { isPending: seoMutation.isPending })] }) }), _jsx(TabsContent, { value: "contact", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); contactMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Support email", value: supportEmail, onChange: (e) => setSupportEmail(e.target.value), type: "email", placeholder: "support@letitrip.in" }), _jsx(Input, { label: "Support phone", value: supportPhone, onChange: (e) => setSupportPhone(e.target.value), placeholder: "+91 XXXXX XXXXX" })] }), _jsx(Input, { label: "Physical address", value: supportAddress, onChange: (e) => setSupportAddress(e.target.value), placeholder: "Mumbai, Maharashtra, India" }), _jsx(Input, { label: "Support hours", value: supportHours, onChange: (e) => setSupportHours(e.target.value), placeholder: "Mon\u2013Fri, 10 AM \u2013 6 PM IST" }), _jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400 pt-2", children: "Social links" }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Instagram URL", value: instagram, onChange: (e) => setInstagram(e.target.value), placeholder: "https://instagram.com/letitrip" }), _jsx(Input, { label: "Twitter / X URL", value: twitter, onChange: (e) => setTwitter(e.target.value), placeholder: "https://twitter.com/letitrip" }), _jsx(Input, { label: "Facebook URL", value: facebook, onChange: (e) => setFacebook(e.target.value), placeholder: "https://facebook.com/letitrip" }), _jsx(Input, { label: "YouTube URL", value: youtube, onChange: (e) => setYoutube(e.target.value), placeholder: "https://youtube.com/@letitrip" }), _jsx(Input, { label: "WhatsApp number", value: whatsapp, onChange: (e) => setWhatsapp(e.target.value), placeholder: "+91XXXXXXXXXX" }), _jsx(Input, { label: "LinkedIn URL", value: linkedin, onChange: (e) => setLinkedin(e.target.value), placeholder: "https://linkedin.com/company/letitrip" }), _jsx(Input, { label: "Pinterest URL", value: pinterest, onChange: (e) => setPinterest(e.target.value), placeholder: "https://pinterest.com/letitrip" })] }), _jsx(GroupSaveButton, { isPending: contactMutation.isPending })] }) }), _jsx(TabsContent, { value: "watermark", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); watermarkMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx(Select, { label: "Watermark type", options: [{ label: "Text", value: "text" }, { label: "Image", value: "image" }], value: watermarkType, onValueChange: (v) => setWatermarkType(v) }), watermarkType === "text" ? (_jsx(Input, { label: "Watermark text", value: watermarkText, onChange: (e) => setWatermarkText(e.target.value), placeholder: "letitrip.in" })) : (_jsx(ImageUpload, { label: "Watermark image", currentImage: watermarkImageUrl, onUpload: (file) => upload(file, "store"), onChange: setWatermarkImageUrl })), _jsx(Slider, { label: `Size — ${watermarkSize}% of image width`, value: watermarkSize, onChange: setWatermarkSize, min: 5, max: 100, step: 5 }), _jsx(Slider, { label: `Opacity — ${watermarkOpacity}%`, value: watermarkOpacity, onChange: setWatermarkOpacity, min: 5, max: 100, step: 5 }), _jsxs("div", { className: "rounded-lg border border-zinc-200 dark:border-zinc-700 p-4 bg-zinc-50 dark:bg-zinc-800", children: [_jsx("p", { className: "text-xs text-zinc-500 mb-2", children: "Preview (text watermark only)" }), _jsx("div", { className: "relative bg-white dark:bg-zinc-900 rounded h-32 flex items-end justify-end overflow-hidden", children: _jsx("span", { className: "text-zinc-400 select-none p-2 font-medium", style: { fontSize: `${Math.max(10, watermarkSize / 5)}px`, opacity: watermarkOpacity / 100 }, children: watermarkText }) })] }), _jsx(GroupSaveButton, { isPending: watermarkMutation.isPending })] }) }), _jsx(TabsContent, { value: "fees", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); feesMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Platform commission (%)", value: String(platformCommission), onChange: (e) => setPlatformCommission(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100, step: 0.1 }), _jsx(Input, { label: "Buyer convenience fee (%)", value: String(buyerFee), onChange: (e) => setBuyerFee(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100, step: 0.1 }), _jsx(Input, { label: "Razorpay gateway fee (%)", value: String(razorpayFee), onChange: (e) => setRazorpayFee(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 10, step: 0.01 }), _jsx(Input, { label: "Seller payout hold (days)", value: String(payoutHoldDays), onChange: (e) => setPayoutHoldDays(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Minimum payout amount (\u20B9)", value: String(minPayoutAmount), onChange: (e) => setMinPayoutAmount(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Auction listing fee (\u20B9)", value: String(auctionListingFee), onChange: (e) => setAuctionListingFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Pre-order listing fee (\u20B9)", value: String(preOrderListingFee), onChange: (e) => setPreOrderListingFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Featured slot fee (\u20B9)", value: String(featuredSlotFee), onChange: (e) => setFeaturedSlotFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Promoted slot fee (\u20B9)", value: String(promotedSlotFee), onChange: (e) => setPromotedSlotFee(parseInt(e.target.value) || 0), type: "number", min: 0 })] }), _jsx(GroupSaveButton, { isPending: feesMutation.isPending })] }) }), _jsx(TabsContent, { value: "integrations", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); integrationsMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Keys are masked in transit and stored encrypted. Click Reveal to view." }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "Razorpay" }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(MaskedInput, { label: "Razorpay Key ID", value: razorpayKeyId, onChange: setRazorpayKeyId, placeholder: "rzp_live_\u2026" }), _jsx(MaskedInput, { label: "Razorpay Secret", value: razorpaySecret, onChange: setRazorpaySecret, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] })] }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "Shiprocket" }), _jsx(MaskedInput, { label: "Shiprocket API token", value: shiprocketToken, onChange: setShiprocketToken, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "SMTP / Email" }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "SMTP host", value: smtpHost, onChange: (e) => setSmtpHost(e.target.value), placeholder: "smtp.sendgrid.net" }), _jsx(Input, { label: "SMTP port", value: smtpPort, onChange: (e) => setSmtpPort(e.target.value), type: "number", placeholder: "587" }), _jsx(Input, { label: "SMTP user", value: smtpUser, onChange: (e) => setSmtpUser(e.target.value), placeholder: "apikey" }), _jsx(MaskedInput, { label: "SMTP password", value: smtpPassword, onChange: setSmtpPassword, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] }), _jsx(Input, { label: "From address", value: smtpFrom, onChange: (e) => setSmtpFrom(e.target.value), placeholder: "noreply@letitrip.in", type: "email" })] }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "Analytics & Tracking" }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Google Analytics ID", value: gaMeasurementId, onChange: (e) => setGaMeasurementId(e.target.value), placeholder: "G-XXXXXXXXXX" }), _jsx(Input, { label: "Facebook Pixel ID", value: fbPixelId, onChange: (e) => setFbPixelId(e.target.value), placeholder: "XXXXXXXXXXXXXXXX" }), _jsx(Input, { label: "GTM Container ID", value: gtmContainerId, onChange: (e) => setGtmContainerId(e.target.value), placeholder: "GTM-XXXXXXX" })] })] }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "Meta (Instagram & Facebook Social Feed)" }), _jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Used by the Social Feed section to fetch Instagram and Facebook posts via Meta Graph API v19." }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(MaskedInput, { label: "Page Access Token", value: metaPageAccessToken, onChange: setMetaPageAccessToken, placeholder: "EAAxxxxxxx\u2026" }), _jsx(Input, { label: "Page ID (or handle)", value: metaPageId, onChange: (e) => setMetaPageId(e.target.value), placeholder: "letitrip" })] })] }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "TikTok for Developers (Social Feed)" }), _jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Client credentials + long-lived access token from TikTok for Developers. Used to list your account's public videos." }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(MaskedInput, { label: "Client Key", value: tiktokClientKey, onChange: setTiktokClientKey, placeholder: "aw\u2026" }), _jsx(MaskedInput, { label: "Client Secret", value: tiktokClientSecret, onChange: setTiktokClientSecret, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }), _jsx(MaskedInput, { label: "Access Token (long-lived)", value: tiktokAccessToken, onChange: setTiktokAccessToken, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] })] }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "DeviantArt OAuth2 (Social Feed)" }), _jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Client credentials for DeviantArt gallery fetching (client-credentials OAuth2 flow \u2014 no user login required)." }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(MaskedInput, { label: "Client ID", value: deviantartClientId, onChange: setDeviantartClientId, placeholder: "1234" }), _jsx(MaskedInput, { label: "Client Secret", value: deviantartClientSecret, onChange: setDeviantartClientSecret, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] })] }), _jsx(GroupSaveButton, { isPending: integrationsMutation.isPending })] }) }), _jsx(TabsContent, { value: "shipping", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); shippingMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx(Input, { label: "Free shipping threshold (\u20B9)", value: String(freeShippingThreshold), onChange: (e) => setFreeShippingThreshold(parseInt(e.target.value) || 0), type: "number", min: 0, helperText: "Orders above this amount get free shipping." }), _jsx(Toggle, { label: "Cash on delivery (COD) enabled", checked: codEnabled, onChange: setCodEnabled }), _jsx(Select, { label: "Default carrier", options: CARRIER_OPTIONS, value: defaultCarrier, onValueChange: setDefaultCarrier }), _jsx(Input, { label: "Max delivery radius (km, 0 = no limit)", value: String(maxDeliveryRadius), onChange: (e) => setMaxDeliveryRadius(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(GroupSaveButton, { isPending: shippingMutation.isPending })] }) }), _jsx(TabsContent, { value: "auction", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); auctionMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx(Input, { label: "Minimum bid increment (\u20B9)", value: String(minBidIncrement), onChange: (e) => setMinBidIncrement(parseInt(e.target.value) || 0), type: "number", min: 1, helperText: "Global default \u2014 individual auctions may override." }), _jsx(Input, { label: "Auto-extend window (minutes before end)", value: String(autoExtendWindow), onChange: (e) => setAutoExtendWindow(parseInt(e.target.value) || 0), type: "number", min: 0, helperText: "Extend auction end time if a bid arrives within this window." }), _jsx(Input, { label: "Settlement grace period (hours)", value: String(settlementGrace), onChange: (e) => setSettlementGrace(parseInt(e.target.value) || 0), type: "number", min: 1, helperText: "Time winner has to pay before the auction is re-listed." }), _jsx(GroupSaveButton, { isPending: auctionMutation.isPending })] }) }), _jsx(TabsContent, { value: "limits", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); limitsMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Max products per store", value: String(maxProductsPerStore), onChange: (e) => setMaxProductsPerStore(parseInt(e.target.value) || 0), type: "number", min: 1 }), _jsx(Input, { label: "Max images per product", value: String(maxImagesPerProduct), onChange: (e) => setMaxImagesPerProduct(parseInt(e.target.value) || 0), type: "number", min: 1 }), _jsx(Input, { label: "Max video size (MB)", value: String(maxVideoSizeMb), onChange: (e) => setMaxVideoSizeMb(parseInt(e.target.value) || 0), type: "number", min: 1 }), _jsx(Input, { label: "Max custom fields per product", value: String(maxCustomFields), onChange: (e) => setMaxCustomFields(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Max custom sections per product", value: String(maxCustomSections), onChange: (e) => setMaxCustomSections(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Order cancellation window (hours)", value: String(orderCancelWindow), onChange: (e) => setOrderCancelWindow(parseInt(e.target.value) || 0), type: "number", min: 0 })] }), _jsx(GroupSaveButton, { isPending: limitsMutation.isPending })] }) }), _jsx(TabsContent, { value: "whatsapp", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); whatsappMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Platform-level WhatsApp Business Cloud API credentials. Used for automated purchase announcements to admin numbers when orders are placed. Store owners configure their own credentials in Store \u2192 WhatsApp." }), _jsx(Input, { label: "Phone Number ID", value: waPhoneNumberId, onChange: (e) => setWaPhoneNumberId(e.target.value), placeholder: "987654321098765", helperText: "From Meta for Developers \u2192 App \u2192 WhatsApp \u2192 API Setup" }), _jsx(MaskedInput, { label: "Cloud API System User Token", value: waCloudApiToken, onChange: setWaCloudApiToken, placeholder: "EAAxxxxxxxx\u2026", helperText: "Long-lived system user access token with WhatsApp Business permissions" }), _jsx(Input, { label: "Admin Notify Numbers", value: waAdminNotifyNumbers, onChange: (e) => setWaAdminNotifyNumbers(e.target.value), placeholder: "919876543210,918765432109", helperText: "Comma-separated, digits-only, include country code. These receive a WhatsApp message when any order is placed." }), _jsx(GroupSaveButton, { isPending: whatsappMutation.isPending })] }) }), _jsx(TabsContent, { value: "legal", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); legalMutation.mutate(); }, className: "space-y-5 pt-4", children: [[
|
|
333
|
+
].map(([value, label]) => (_jsx(TabsTrigger, { value: value, children: label }, value))) }), _jsx(TabsContent, { value: "about", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); aboutMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Override the About page hero and mission text. Leave blank to use the platform defaults." }), _jsx(Input, { label: "Hero title", value: aboutTitle, onChange: (e) => setAboutTitle(e.target.value), placeholder: "About LetItRip" }), _jsx(Input, { label: "Hero subtitle", value: aboutSubtitle, onChange: (e) => setAboutSubtitle(e.target.value), placeholder: "Connecting buyers, sellers, and bidders in one vibrant marketplace" }), _jsx(Input, { label: "Mission section title", value: aboutMissionTitle, onChange: (e) => setAboutMissionTitle(e.target.value), placeholder: "Our Mission" }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Mission text" }), _jsx("textarea", { value: aboutMissionText, onChange: (e) => setAboutMissionText(e.target.value), placeholder: "LetItRip was built to democratise commerce\u2026", rows: 4, className: "w-full rounded-md border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-800 p-3 text-sm text-zinc-800 dark:text-zinc-200 resize-y focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), _jsx(Input, { label: "CTA banner title", value: aboutCtaTitle, onChange: (e) => setAboutCtaTitle(e.target.value), placeholder: "Ready to get started?" }), _jsx(GroupSaveButton, { isPending: aboutMutation.isPending })] }) }), _jsx(TabsContent, { value: "branding", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); brandingMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx(Input, { label: "Site name", value: siteName, onChange: (e) => setSiteName(e.target.value), placeholder: "LetItRip" }), _jsx(Input, { label: "Tagline", value: tagline, onChange: (e) => setTagline(e.target.value), placeholder: "India's Largest Collectibles Marketplace" }), _jsx(ImageUpload, { label: "Logo", currentImage: logoUrl, onUpload: (file) => upload(file, "store"), onChange: setLogoUrl }), _jsx(ImageUpload, { label: "Favicon", currentImage: faviconUrl, onUpload: (file) => upload(file, "store"), onChange: setFaviconUrl }), _jsxs("div", { className: "space-y-3 rounded-lg border border-zinc-200 dark:border-zinc-700 p-4", children: [_jsx(Toggle, { label: "Maintenance mode", checked: maintenanceMode, onChange: setMaintenanceMode }), _jsx(Input, { label: "Maintenance message", value: maintenanceMessage, onChange: (e) => setMaintenanceMessage(e.target.value), placeholder: "We're back soon.", disabled: !maintenanceMode })] }), _jsx(GroupSaveButton, { isPending: brandingMutation.isPending })] }) }), _jsx(TabsContent, { value: "appearance", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); appearanceMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsxs("div", { className: "grid grid-cols-3 gap-4", children: [_jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Primary color" }), _jsx("input", { type: "color", value: primaryColor || "#000000", onChange: (e) => setPrimaryColor(e.target.value), className: "h-10 w-full rounded border border-zinc-200 dark:border-zinc-700 cursor-pointer" })] }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Secondary color" }), _jsx("input", { type: "color", value: secondaryColor || "#000000", onChange: (e) => setSecondaryColor(e.target.value), className: "h-10 w-full rounded border border-zinc-200 dark:border-zinc-700 cursor-pointer" })] }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Accent color" }), _jsx("input", { type: "color", value: accentColor || "#000000", onChange: (e) => setAccentColor(e.target.value), className: "h-10 w-full rounded border border-zinc-200 dark:border-zinc-700 cursor-pointer" })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Select, { label: "Default theme", options: THEME_OPTIONS, value: defaultTheme, onValueChange: setDefaultTheme }), _jsx(Select, { label: "Font family", options: FONT_OPTIONS, value: fontFamily, onValueChange: setFontFamily })] }), _jsx(GroupSaveButton, { isPending: appearanceMutation.isPending })] }) }), _jsx(TabsContent, { value: "announcement", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); announcementMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx(Toggle, { label: "Show announcement bar", checked: announcementEnabled, onChange: setAnnouncementEnabled }), _jsx(Input, { label: "Announcement text", value: announcementText, onChange: (e) => setAnnouncementText(e.target.value), placeholder: "\uD83C\uDF89 Free shipping on orders \u20B9999+", disabled: !announcementEnabled }), _jsx(Input, { label: "Link URL (optional)", value: announcementLink, onChange: (e) => setAnnouncementLink(e.target.value), placeholder: "/products", disabled: !announcementEnabled }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Background color" }), _jsx("input", { type: "color", value: announcementBg || "#1d4ed8", onChange: (e) => setAnnouncementBg(e.target.value), className: "h-10 w-32 rounded border border-zinc-200 dark:border-zinc-700 cursor-pointer", disabled: !announcementEnabled })] }), _jsx(GroupSaveButton, { isPending: announcementMutation.isPending })] }) }), _jsx(TabsContent, { value: "seo", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); seoMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx(Input, { label: "Default meta title", value: seoTitle, onChange: (e) => setSeoTitle(e.target.value), placeholder: "LetItRip \u2014 Buy, Sell & Auction Collectibles in India", maxLength: 60, helperText: "Max 60 chars. Use {page} token for dynamic insertion." }), _jsx(Input, { label: "Default meta description", value: seoDescription, onChange: (e) => setSeoDescription(e.target.value), placeholder: "India's largest collectibles marketplace\u2026", maxLength: 160, helperText: "Max 160 chars." }), _jsx(ImageUpload, { label: "Default OG image", currentImage: seoOgImage, onUpload: (file) => upload(file, "store"), onChange: setSeoOgImage }), _jsx(Input, { label: "Canonical base URL", value: canonicalUrl, onChange: (e) => setCanonicalUrl(e.target.value), placeholder: "https://letitrip.in" }), _jsx(Toggle, { label: "Robots noindex (disables search indexing \u2014 use carefully)", checked: seoNoIndex, onChange: setSeoNoIndex }), _jsx(GroupSaveButton, { isPending: seoMutation.isPending })] }) }), _jsx(TabsContent, { value: "contact", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); contactMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Support email", value: supportEmail, onChange: (e) => setSupportEmail(e.target.value), type: "email", placeholder: "support@letitrip.in" }), _jsx(Input, { label: "Support phone", value: supportPhone, onChange: (e) => setSupportPhone(e.target.value), placeholder: "+91 XXXXX XXXXX" })] }), _jsx(Input, { label: "Physical address", value: supportAddress, onChange: (e) => setSupportAddress(e.target.value), placeholder: "Mumbai, Maharashtra, India" }), _jsx(Input, { label: "Support hours", value: supportHours, onChange: (e) => setSupportHours(e.target.value), placeholder: "Mon\u2013Fri, 10 AM \u2013 6 PM IST" }), _jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400 pt-2", children: "Social links" }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Instagram URL", value: instagram, onChange: (e) => setInstagram(e.target.value), placeholder: "https://instagram.com/letitrip" }), _jsx(Input, { label: "Twitter / X URL", value: twitter, onChange: (e) => setTwitter(e.target.value), placeholder: "https://twitter.com/letitrip" }), _jsx(Input, { label: "Facebook URL", value: facebook, onChange: (e) => setFacebook(e.target.value), placeholder: "https://facebook.com/letitrip" }), _jsx(Input, { label: "YouTube URL", value: youtube, onChange: (e) => setYoutube(e.target.value), placeholder: "https://youtube.com/@letitrip" }), _jsx(Input, { label: "WhatsApp number", value: whatsapp, onChange: (e) => setWhatsapp(e.target.value), placeholder: "+91XXXXXXXXXX" }), _jsx(Input, { label: "LinkedIn URL", value: linkedin, onChange: (e) => setLinkedin(e.target.value), placeholder: "https://linkedin.com/company/letitrip" }), _jsx(Input, { label: "Pinterest URL", value: pinterest, onChange: (e) => setPinterest(e.target.value), placeholder: "https://pinterest.com/letitrip" })] }), _jsx(GroupSaveButton, { isPending: contactMutation.isPending })] }) }), _jsx(TabsContent, { value: "watermark", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); watermarkMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx(Select, { label: "Watermark type", options: [{ label: "Text", value: "text" }, { label: "Image", value: "image" }], value: watermarkType, onValueChange: (v) => setWatermarkType(v) }), watermarkType === "text" ? (_jsx(Input, { label: "Watermark text", value: watermarkText, onChange: (e) => setWatermarkText(e.target.value), placeholder: "letitrip.in" })) : (_jsx(ImageUpload, { label: "Watermark image", currentImage: watermarkImageUrl, onUpload: (file) => upload(file, "store"), onChange: setWatermarkImageUrl })), _jsx(Slider, { label: `Size — ${watermarkSize}% of image width`, value: watermarkSize, onChange: setWatermarkSize, min: 5, max: 100, step: 5 }), _jsx(Slider, { label: `Opacity — ${watermarkOpacity}%`, value: watermarkOpacity, onChange: setWatermarkOpacity, min: 5, max: 100, step: 5 }), _jsxs("div", { className: "rounded-lg border border-zinc-200 dark:border-zinc-700 p-4 bg-zinc-50 dark:bg-zinc-800", children: [_jsx("p", { className: "text-xs text-zinc-500 mb-2", children: "Preview (text watermark only)" }), _jsx("div", { className: "relative bg-white dark:bg-zinc-900 rounded h-32 flex items-end justify-end overflow-hidden", children: _jsx("span", { className: "text-zinc-400 select-none p-2 font-medium", style: { fontSize: `${Math.max(10, watermarkSize / 5)}px`, opacity: watermarkOpacity / 100 }, children: watermarkText }) })] }), _jsx(GroupSaveButton, { isPending: watermarkMutation.isPending })] }) }), _jsx(TabsContent, { value: "fees", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); feesMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Platform fee \u2014 our cut (%)", helperText: "% charged on order value. Buyer pays this.", value: String(platformFeePercent), onChange: (e) => setPlatformFeePercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100, step: 0.1 }), _jsx(Input, { label: "GST on platform fee (%)", helperText: "Applied to our fee only (not full order). Usually 18%.", value: String(gstPercent), onChange: (e) => setGstPercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100, step: 0.1 }), _jsx(Input, { label: "Razorpay gateway cost (%)", helperText: "Gateway's own fee \u2014 absorbed by platform, not passed through.", value: String(gatewayFeePercent), onChange: (e) => setGatewayFeePercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 10, step: 0.01 }), _jsx(Input, { label: "Minimum transaction fee (\u20B9)", helperText: "Per-transaction floor. Total charge will never be below base + this.", value: String(minimumTransactionFee), onChange: (e) => setMinimumTransactionFee(parseFloat(e.target.value) || 0), type: "number", min: 0, step: 0.01 }), _jsx(Input, { label: "Seller payout hold (days)", value: String(payoutHoldDays), onChange: (e) => setPayoutHoldDays(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Minimum payout amount (\u20B9)", value: String(minPayoutAmount), onChange: (e) => setMinPayoutAmount(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Auction listing fee (\u20B9)", value: String(auctionListingFee), onChange: (e) => setAuctionListingFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Pre-order listing fee (\u20B9)", value: String(preOrderListingFee), onChange: (e) => setPreOrderListingFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Featured slot fee (\u20B9)", value: String(featuredSlotFee), onChange: (e) => setFeaturedSlotFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Promoted slot fee (\u20B9)", value: String(promotedSlotFee), onChange: (e) => setPromotedSlotFee(parseInt(e.target.value) || 0), type: "number", min: 0 })] }), _jsx(GroupSaveButton, { isPending: feesMutation.isPending })] }) }), _jsx(TabsContent, { value: "integrations", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); integrationsMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Keys are masked in transit and stored encrypted. Click Reveal to view." }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "Razorpay" }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(MaskedInput, { label: "Razorpay Key ID", value: razorpayKeyId, onChange: setRazorpayKeyId, placeholder: "rzp_live_\u2026" }), _jsx(MaskedInput, { label: "Razorpay Secret", value: razorpaySecret, onChange: setRazorpaySecret, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] })] }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "Shiprocket" }), _jsx(MaskedInput, { label: "Shiprocket API token", value: shiprocketToken, onChange: setShiprocketToken, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "SMTP / Email" }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "SMTP host", value: smtpHost, onChange: (e) => setSmtpHost(e.target.value), placeholder: "smtp.sendgrid.net" }), _jsx(Input, { label: "SMTP port", value: smtpPort, onChange: (e) => setSmtpPort(e.target.value), type: "number", placeholder: "587" }), _jsx(Input, { label: "SMTP user", value: smtpUser, onChange: (e) => setSmtpUser(e.target.value), placeholder: "apikey" }), _jsx(MaskedInput, { label: "SMTP password", value: smtpPassword, onChange: setSmtpPassword, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] }), _jsx(Input, { label: "From address", value: smtpFrom, onChange: (e) => setSmtpFrom(e.target.value), placeholder: "noreply@letitrip.in", type: "email" })] }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "Analytics & Tracking" }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Google Analytics ID", value: gaMeasurementId, onChange: (e) => setGaMeasurementId(e.target.value), placeholder: "G-XXXXXXXXXX" }), _jsx(Input, { label: "Facebook Pixel ID", value: fbPixelId, onChange: (e) => setFbPixelId(e.target.value), placeholder: "XXXXXXXXXXXXXXXX" }), _jsx(Input, { label: "GTM Container ID", value: gtmContainerId, onChange: (e) => setGtmContainerId(e.target.value), placeholder: "GTM-XXXXXXX" })] })] }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "Meta (Instagram & Facebook Social Feed)" }), _jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Used by the Social Feed section to fetch Instagram and Facebook posts via Meta Graph API v19." }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(MaskedInput, { label: "Page Access Token", value: metaPageAccessToken, onChange: setMetaPageAccessToken, placeholder: "EAAxxxxxxx\u2026" }), _jsx(Input, { label: "Page ID (or handle)", value: metaPageId, onChange: (e) => setMetaPageId(e.target.value), placeholder: "letitrip" })] })] }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "TikTok for Developers (Social Feed)" }), _jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Client credentials + long-lived access token from TikTok for Developers. Used to list your account's public videos." }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(MaskedInput, { label: "Client Key", value: tiktokClientKey, onChange: setTiktokClientKey, placeholder: "aw\u2026" }), _jsx(MaskedInput, { label: "Client Secret", value: tiktokClientSecret, onChange: setTiktokClientSecret, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }), _jsx(MaskedInput, { label: "Access Token (long-lived)", value: tiktokAccessToken, onChange: setTiktokAccessToken, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] })] }), _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-sm font-medium text-zinc-600 dark:text-zinc-400", children: "DeviantArt OAuth2 (Social Feed)" }), _jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Client credentials for DeviantArt gallery fetching (client-credentials OAuth2 flow \u2014 no user login required)." }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(MaskedInput, { label: "Client ID", value: deviantartClientId, onChange: setDeviantartClientId, placeholder: "1234" }), _jsx(MaskedInput, { label: "Client Secret", value: deviantartClientSecret, onChange: setDeviantartClientSecret, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] })] }), _jsx(GroupSaveButton, { isPending: integrationsMutation.isPending })] }) }), _jsx(TabsContent, { value: "shipping", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); shippingMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx(Input, { label: "Free shipping threshold (\u20B9)", value: String(freeShippingThreshold), onChange: (e) => setFreeShippingThreshold(parseInt(e.target.value) || 0), type: "number", min: 0, helperText: "Orders above this amount get free shipping." }), _jsx(Toggle, { label: "Cash on delivery (COD) enabled", checked: codEnabled, onChange: setCodEnabled }), _jsx(Select, { label: "Default carrier", options: CARRIER_OPTIONS, value: defaultCarrier, onValueChange: setDefaultCarrier }), _jsx(Input, { label: "Max delivery radius (km, 0 = no limit)", value: String(maxDeliveryRadius), onChange: (e) => setMaxDeliveryRadius(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(GroupSaveButton, { isPending: shippingMutation.isPending })] }) }), _jsx(TabsContent, { value: "auction", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); auctionMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx(Input, { label: "Minimum bid increment (\u20B9)", value: String(minBidIncrement), onChange: (e) => setMinBidIncrement(parseInt(e.target.value) || 0), type: "number", min: 1, helperText: "Global default \u2014 individual auctions may override." }), _jsx(Input, { label: "Auto-extend window (minutes before end)", value: String(autoExtendWindow), onChange: (e) => setAutoExtendWindow(parseInt(e.target.value) || 0), type: "number", min: 0, helperText: "Extend auction end time if a bid arrives within this window." }), _jsx(Input, { label: "Settlement grace period (hours)", value: String(settlementGrace), onChange: (e) => setSettlementGrace(parseInt(e.target.value) || 0), type: "number", min: 1, helperText: "Time winner has to pay before the auction is re-listed." }), _jsx(GroupSaveButton, { isPending: auctionMutation.isPending })] }) }), _jsx(TabsContent, { value: "limits", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); limitsMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsx(Input, { label: "Max products per store", value: String(maxProductsPerStore), onChange: (e) => setMaxProductsPerStore(parseInt(e.target.value) || 0), type: "number", min: 1 }), _jsx(Input, { label: "Max images per product", value: String(maxImagesPerProduct), onChange: (e) => setMaxImagesPerProduct(parseInt(e.target.value) || 0), type: "number", min: 1 }), _jsx(Input, { label: "Max video size (MB)", value: String(maxVideoSizeMb), onChange: (e) => setMaxVideoSizeMb(parseInt(e.target.value) || 0), type: "number", min: 1 }), _jsx(Input, { label: "Max custom fields per product", value: String(maxCustomFields), onChange: (e) => setMaxCustomFields(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Max custom sections per product", value: String(maxCustomSections), onChange: (e) => setMaxCustomSections(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Order cancellation window (hours)", value: String(orderCancelWindow), onChange: (e) => setOrderCancelWindow(parseInt(e.target.value) || 0), type: "number", min: 0 })] }), _jsx(GroupSaveButton, { isPending: limitsMutation.isPending })] }) }), _jsx(TabsContent, { value: "whatsapp", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); whatsappMutation.mutate(); }, className: "space-y-4 pt-4", children: [_jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Platform-level WhatsApp Business Cloud API credentials. Used for automated purchase announcements to admin numbers when orders are placed. Store owners configure their own credentials in Store \u2192 WhatsApp." }), _jsx(Input, { label: "Phone Number ID", value: waPhoneNumberId, onChange: (e) => setWaPhoneNumberId(e.target.value), placeholder: "987654321098765", helperText: "From Meta for Developers \u2192 App \u2192 WhatsApp \u2192 API Setup" }), _jsx(MaskedInput, { label: "Cloud API System User Token", value: waCloudApiToken, onChange: setWaCloudApiToken, placeholder: "EAAxxxxxxxx\u2026", helperText: "Long-lived system user access token with WhatsApp Business permissions" }), _jsx(Input, { label: "Admin Notify Numbers", value: waAdminNotifyNumbers, onChange: (e) => setWaAdminNotifyNumbers(e.target.value), placeholder: "919876543210,918765432109", helperText: "Comma-separated, digits-only, include country code. These receive a WhatsApp message when any order is placed." }), _jsx(GroupSaveButton, { isPending: whatsappMutation.isPending })] }) }), _jsx(TabsContent, { value: "legal", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); legalMutation.mutate(); }, className: "space-y-5 pt-4", children: [[
|
|
332
334
|
["Terms of Service", termsHtml, setTermsHtml],
|
|
333
335
|
["Privacy Policy", privacyHtml, setPrivacyHtml],
|
|
334
336
|
["Refund Policy", refundHtml, setRefundHtml],
|
|
@@ -1,21 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
+
import { TrendingUp, ShoppingBag, Users, Package, Clock, Star } from "lucide-react";
|
|
4
|
+
import { Grid } from "../../../ui";
|
|
3
5
|
import { formatCurrency } from "../../../utils/number.formatter";
|
|
4
6
|
import { getDefaultCurrency } from "../../../core/baseline-resolver";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return (_jsxs(
|
|
7
|
+
// Brand gradient stop colors (mirrors SiteLogo wordmark gradient)
|
|
8
|
+
const BRAND_FROM = "var(--appkit-color-primary-700, #1343de)";
|
|
9
|
+
const BRAND_MID = "var(--appkit-color-cobalt, #3570fc)";
|
|
10
|
+
const BRAND_TO = "var(--appkit-color-secondary-400, #84e122)";
|
|
11
|
+
function StatCard({ label, value, sub, icon: Icon, gradient, iconColor }) {
|
|
12
|
+
return (_jsxs("div", { className: "relative rounded-xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] overflow-hidden shadow-sm hover:shadow-md transition-shadow", children: [_jsx("div", { className: "absolute top-0 left-0 right-0 h-[3px]", style: { background: gradient }, "aria-hidden": "true" }), _jsxs("div", { className: "px-5 pb-5 pt-6 flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "text-[11px] font-semibold uppercase tracking-widest text-[var(--appkit-color-text-muted)]", children: label }), _jsx("p", { className: "mt-2 text-2xl font-bold text-[var(--appkit-color-text)] tabular-nums leading-none", children: value }), sub && (_jsx("p", { className: "mt-1.5 text-xs text-[var(--appkit-color-text-muted)]", children: sub }))] }), _jsx("div", { className: "flex-shrink-0 w-10 h-10 rounded-lg flex items-center justify-center", style: { background: gradient, opacity: 0.92 }, children: _jsx(Icon, { className: "w-5 h-5 text-white drop-shadow-sm" }) })] })] }));
|
|
13
|
+
}
|
|
14
|
+
function SkeletonCard() {
|
|
15
|
+
return (_jsxs("div", { className: "relative rounded-xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] overflow-hidden p-5 animate-pulse", children: [_jsx("div", { className: "absolute top-0 left-0 right-0 h-[3px] bg-[var(--appkit-color-border)]" }), _jsxs("div", { className: "flex items-start justify-between gap-3 pt-1", children: [_jsxs("div", { className: "flex-1 space-y-2", children: [_jsx("div", { className: "h-2.5 w-20 rounded bg-[var(--appkit-color-border)]" }), _jsx("div", { className: "h-7 w-24 rounded bg-[var(--appkit-color-border)]" })] }), _jsx("div", { className: "w-10 h-10 rounded-lg bg-[var(--appkit-color-border)]" })] })] }));
|
|
14
16
|
}
|
|
15
17
|
export function DashboardStatsGrid({ stats, isLoading, labels = {}, }) {
|
|
16
18
|
if (isLoading) {
|
|
17
|
-
return (_jsx(Grid, { cols: "statTiles", children: Array.from({ length: 4 }).map((_, i) =>
|
|
19
|
+
return (_jsx(Grid, { cols: "statTiles", children: Array.from({ length: 4 }).map((_, i) => _jsx(SkeletonCard, {}, i)) }));
|
|
18
20
|
}
|
|
19
21
|
const currency = stats.currency ?? getDefaultCurrency();
|
|
20
|
-
|
|
22
|
+
// Brand gradient (left→right, matches logo wordmark)
|
|
23
|
+
const brandGrad = `linear-gradient(135deg, ${BRAND_FROM} 0%, ${BRAND_MID} 55%, ${BRAND_TO} 100%)`;
|
|
24
|
+
const blueGrad = `linear-gradient(135deg, ${BRAND_FROM} 0%, ${BRAND_MID} 100%)`;
|
|
25
|
+
const greenGrad = `linear-gradient(135deg, ${BRAND_MID} 0%, ${BRAND_TO} 100%)`;
|
|
26
|
+
const amberGrad = "linear-gradient(135deg, #f59e0b 0%, #f97316 100%)";
|
|
27
|
+
const roseGrad = "linear-gradient(135deg, #f43f5e 0%, #e11d48 100%)";
|
|
28
|
+
return (_jsxs(Grid, { cols: "statTiles", children: [_jsx(StatCard, { label: labels.totalOrders ?? "Total Orders", value: stats.totalOrders ?? 0, icon: ShoppingBag, gradient: brandGrad, iconColor: "#fff" }), _jsx(StatCard, { label: labels.totalRevenue ?? "Total Revenue", value: formatCurrency(stats.totalRevenue ?? 0, currency), icon: TrendingUp, gradient: greenGrad, iconColor: "#fff" }), _jsx(StatCard, { label: labels.totalUsers ?? "Total Users", value: stats.totalUsers ?? 0, icon: Users, gradient: blueGrad, iconColor: "#fff" }), _jsx(StatCard, { label: labels.totalProducts ?? "Total Products", value: stats.totalProducts ?? 0, icon: Package, gradient: brandGrad, iconColor: "#fff" }), stats.pendingOrders !== undefined && (_jsx(StatCard, { label: labels.pendingOrders ?? "Pending Orders", value: stats.pendingOrders, icon: Clock, gradient: amberGrad, iconColor: "#fff" })), stats.pendingReviews !== undefined && (_jsx(StatCard, { label: labels.pendingReviews ?? "Pending Reviews", value: stats.pendingReviews, icon: Star, gradient: roseGrad, iconColor: "#fff" }))] }));
|
|
21
29
|
}
|
|
@@ -13,9 +13,25 @@ const XAxis = dynamic(() => import("recharts").then((m) => m.XAxis), { ssr: fals
|
|
|
13
13
|
const YAxis = dynamic(() => import("recharts").then((m) => m.YAxis), { ssr: false });
|
|
14
14
|
const CartesianGrid = dynamic(() => import("recharts").then((m) => m.CartesianGrid), { ssr: false });
|
|
15
15
|
const Tooltip = dynamic(() => import("recharts").then((m) => m.Tooltip), { ssr: false });
|
|
16
|
+
// Shared chart card wrapper
|
|
17
|
+
function ChartCard({ title, children, className = "", }) {
|
|
18
|
+
return (_jsxs(Div, { className: `relative rounded-xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] overflow-hidden shadow-sm ${className}`, children: [_jsx("div", { className: "absolute top-0 left-0 right-0 h-[3px]", style: {
|
|
19
|
+
background: "linear-gradient(to right, var(--appkit-color-primary-700,#1343de) 0%, var(--appkit-color-cobalt,#3570fc) 55%, var(--appkit-color-secondary-400,#84e122) 100%)",
|
|
20
|
+
}, "aria-hidden": "true" }), _jsxs(Div, { className: "p-4 sm:p-6 pt-5 sm:pt-7", children: [title && (_jsx(Heading, { level: 3, className: "text-sm font-semibold text-[var(--appkit-color-text)] mb-4", children: title })), children] })] }));
|
|
21
|
+
}
|
|
16
22
|
export function AdminRevenueChart({ data, labels = {}, className = "", }) {
|
|
17
|
-
return (
|
|
23
|
+
return (_jsx(ChartCard, { title: labels.title, className: className, children: _jsx(ResponsiveContainer, { width: "100%", height: 280, children: _jsxs(AreaChart, { data: data, margin: { top: 4, right: 4, left: 0, bottom: 0 }, children: [_jsxs("defs", { children: [_jsxs("linearGradient", { id: "revenueGrad", x1: "0", y1: "0", x2: "1", y2: "0", children: [_jsx("stop", { offset: "0%", stopColor: "#1343de" }), _jsx("stop", { offset: "55%", stopColor: "#3570fc" }), _jsx("stop", { offset: "100%", stopColor: "#84e122" })] }), _jsxs("linearGradient", { id: "revenueAreaGrad", x1: "0", y1: "0", x2: "0", y2: "1", children: [_jsx("stop", { offset: "5%", stopColor: "#3570fc", stopOpacity: 0.25 }), _jsx("stop", { offset: "95%", stopColor: "#3570fc", stopOpacity: 0 })] })] }), _jsx(CartesianGrid, { strokeDasharray: "4 4", stroke: "var(--appkit-color-border)", vertical: false }), _jsx(XAxis, { dataKey: "month", tick: { fontSize: 11, fill: "var(--appkit-color-text-muted)" }, axisLine: false, tickLine: false }), _jsx(YAxis, { tick: { fontSize: 11, fill: "var(--appkit-color-text-muted)" }, axisLine: false, tickLine: false, width: 48 }), _jsx(Tooltip, { contentStyle: {
|
|
24
|
+
background: "var(--appkit-color-surface)",
|
|
25
|
+
border: "1px solid var(--appkit-color-border)",
|
|
26
|
+
borderRadius: "8px",
|
|
27
|
+
fontSize: 12,
|
|
28
|
+
}, cursor: { stroke: "var(--appkit-color-border)", strokeWidth: 1 } }), _jsx(Area, { type: "monotone", dataKey: "revenue", stroke: "url(#revenueGrad)", strokeWidth: 2.5, fillOpacity: 1, fill: "url(#revenueAreaGrad)", dot: false, activeDot: { r: 4, fill: "#3570fc" } })] }) }) }));
|
|
18
29
|
}
|
|
19
30
|
export function AdminOrdersChart({ data, labels = {}, className = "", }) {
|
|
20
|
-
return (
|
|
31
|
+
return (_jsx(ChartCard, { title: labels.title, className: className, children: _jsx(ResponsiveContainer, { width: "100%", height: 280, children: _jsxs(BarChart, { data: data, margin: { top: 4, right: 4, left: 0, bottom: 0 }, barSize: 20, children: [_jsx("defs", { children: _jsxs("linearGradient", { id: "ordersBarGrad", x1: "0", y1: "0", x2: "0", y2: "1", children: [_jsx("stop", { offset: "0%", stopColor: "#3570fc", stopOpacity: 0.9 }), _jsx("stop", { offset: "100%", stopColor: "#84e122", stopOpacity: 0.7 })] }) }), _jsx(CartesianGrid, { strokeDasharray: "4 4", stroke: "var(--appkit-color-border)", vertical: false }), _jsx(XAxis, { dataKey: "month", tick: { fontSize: 11, fill: "var(--appkit-color-text-muted)" }, axisLine: false, tickLine: false }), _jsx(YAxis, { tick: { fontSize: 11, fill: "var(--appkit-color-text-muted)" }, axisLine: false, tickLine: false, width: 40 }), _jsx(Tooltip, { contentStyle: {
|
|
32
|
+
background: "var(--appkit-color-surface)",
|
|
33
|
+
border: "1px solid var(--appkit-color-border)",
|
|
34
|
+
borderRadius: "8px",
|
|
35
|
+
fontSize: 12,
|
|
36
|
+
}, cursor: { fill: "var(--appkit-color-border)", opacity: 0.3 } }), _jsx(Bar, { dataKey: "orders", fill: "url(#ordersBarGrad)", radius: [4, 4, 0, 0] })] }) }) }));
|
|
21
37
|
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
declare const GRADIENTS: Record<string, string>;
|
|
2
3
|
export interface AdminStatCardProps {
|
|
3
4
|
label: string;
|
|
4
5
|
value: string;
|
|
6
|
+
sub?: string;
|
|
7
|
+
/** Emoji or ReactNode icon */
|
|
5
8
|
icon?: React.ReactNode | string;
|
|
9
|
+
/** Named preset or raw CSS gradient string */
|
|
10
|
+
gradient?: keyof typeof GRADIENTS | string;
|
|
6
11
|
className?: string;
|
|
7
12
|
}
|
|
8
|
-
export declare function AdminStatCard({ label, value, icon, className, }: AdminStatCardProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function AdminStatCard({ label, value, sub, icon, gradient, className, }: AdminStatCardProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Div, Text, Heading } from "../../../../ui";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const BRAND_FROM = "var(--appkit-color-primary-700, #1343de)";
|
|
4
|
+
const BRAND_MID = "var(--appkit-color-cobalt, #3570fc)";
|
|
5
|
+
const BRAND_TO = "var(--appkit-color-secondary-400, #84e122)";
|
|
6
|
+
const GRADIENTS = {
|
|
7
|
+
brand: `linear-gradient(135deg, ${BRAND_FROM} 0%, ${BRAND_MID} 55%, ${BRAND_TO} 100%)`,
|
|
8
|
+
blue: `linear-gradient(135deg, ${BRAND_FROM} 0%, ${BRAND_MID} 100%)`,
|
|
9
|
+
green: `linear-gradient(135deg, ${BRAND_MID} 0%, ${BRAND_TO} 100%)`,
|
|
10
|
+
amber: "linear-gradient(135deg, #f59e0b 0%, #f97316 100%)",
|
|
11
|
+
rose: "linear-gradient(135deg, #f43f5e 0%, #e11d48 100%)",
|
|
12
|
+
};
|
|
13
|
+
export function AdminStatCard({ label, value, sub, icon, gradient = "brand", className = "", }) {
|
|
14
|
+
const resolvedGradient = GRADIENTS[gradient] ?? gradient;
|
|
15
|
+
return (_jsxs(Div, { className: `relative rounded-xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] overflow-hidden shadow-sm hover:shadow-md transition-shadow ${className}`, children: [_jsx("div", { className: "absolute top-0 left-0 right-0 h-[3px]", style: { background: resolvedGradient }, "aria-hidden": "true" }), _jsxs(Div, { className: "px-5 pb-5 pt-6 flex items-start justify-between gap-3", children: [_jsxs(Div, { className: "min-w-0 flex-1", children: [_jsx(Text, { className: "text-[11px] font-semibold uppercase tracking-widest text-[var(--appkit-color-text-muted)]", children: label }), _jsx(Heading, { level: 3, className: "mt-2 text-2xl font-bold tabular-nums leading-none text-[var(--appkit-color-text)]", children: value }), sub && (_jsx(Text, { className: "mt-1.5 text-xs text-[var(--appkit-color-text-muted)]", children: sub }))] }), icon && (_jsx(Div, { className: "flex-shrink-0 w-10 h-10 rounded-lg flex items-center justify-center text-xl", style: { background: resolvedGradient }, children: icon }))] })] }));
|
|
5
16
|
}
|