@mohasinac/appkit 4.11.3 → 4.12.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 +36 -3
- package/dist/_internal/server/features/checkout/actions.js +122 -44
- package/dist/_internal/server/features/orders/adapters.js +13 -0
- package/dist/_internal/server/features/products/list-public.d.ts +28 -0
- package/dist/_internal/server/features/products/list-public.js +92 -0
- package/dist/_internal/server/jobs/core/auctionSettlement.js +5 -2
- package/dist/_internal/shared/checkout/lanes.d.ts +20 -0
- package/dist/_internal/shared/checkout/lanes.js +28 -0
- package/dist/_internal/shared/features/checkout/config.d.ts +4 -0
- package/dist/_internal/shared/features/checkout/config.js +8 -0
- package/dist/_internal/shared/fees/calculator.d.ts +34 -2
- package/dist/_internal/shared/fees/calculator.js +45 -1
- package/dist/client.d.ts +7 -1
- package/dist/client.js +4 -1
- package/dist/constants/api-endpoints.d.ts +6 -0
- package/dist/constants/api-endpoints.js +2 -0
- package/dist/features/admin/components/AdminAddressesView.js +18 -10
- package/dist/features/admin/components/AdminArtView.d.ts +9 -0
- package/dist/features/admin/components/AdminArtView.js +11 -35
- package/dist/features/admin/components/AdminClassifiedView.d.ts +9 -0
- package/dist/features/admin/components/AdminClassifiedView.js +11 -35
- package/dist/features/admin/components/AdminDigitalCodesView.d.ts +9 -0
- package/dist/features/admin/components/AdminDigitalCodesView.js +11 -42
- package/dist/features/admin/components/AdminLiveView.d.ts +9 -0
- package/dist/features/admin/components/AdminLiveView.js +11 -41
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +8 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +4 -3
- package/dist/features/admin/components/AdminOrdersView.js +14 -1
- package/dist/features/admin/components/AdminPaymentMethodsView.js +15 -10
- package/dist/features/admin/components/AdminSiteConfigGuideView.js +1 -1
- package/dist/features/admin/components/AdminSiteSettingsView.js +4 -2
- package/dist/features/admin/components/AdminStickersView.d.ts +9 -0
- package/dist/features/admin/components/AdminStickersView.js +11 -35
- package/dist/features/admin/hooks/useAdminListing.js +7 -2
- package/dist/features/admin/schemas/firestore.d.ts +5 -0
- package/dist/features/admin/schemas/firestore.js +1 -0
- package/dist/features/auctions/actions/bid-actions.js +2 -2
- package/dist/features/cart/components/CartDrawer.d.ts +9 -1
- package/dist/features/cart/components/CartDrawer.js +4 -3
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +61 -0
- package/dist/features/cart/components/CartPriceBreakdown.js +25 -0
- package/dist/features/cart/components/StoreAddonsPicker.d.ts +47 -0
- package/dist/features/cart/components/StoreAddonsPicker.js +21 -0
- package/dist/features/cart/components/index.d.ts +4 -0
- package/dist/features/cart/components/index.js +2 -0
- package/dist/features/cart/repository/cart.repository.d.ts +20 -2
- package/dist/features/cart/repository/cart.repository.js +49 -0
- package/dist/features/cart/schemas/firestore.d.ts +26 -0
- package/dist/features/layout/BottomActions.js +37 -4
- package/dist/features/layout/BottomActionsContext.d.ts +12 -0
- package/dist/features/layout/BottomActionsContext.js +5 -0
- package/dist/features/layout/hooks/useBottomActions.d.ts +6 -0
- package/dist/features/layout/hooks/useBottomActions.js +11 -1
- package/dist/features/orders/components/OrderAddonBadges.d.ts +36 -0
- package/dist/features/orders/components/OrderAddonBadges.js +28 -0
- package/dist/features/orders/components/index.d.ts +1 -0
- package/dist/features/orders/components/index.js +1 -0
- package/dist/features/orders/repository/orders.repository.d.ts +32 -0
- package/dist/features/orders/repository/orders.repository.js +14 -0
- package/dist/features/orders/types/index.d.ts +22 -0
- package/dist/features/products/components/ArtStickersListView.js +5 -4
- package/dist/features/products/components/PrizeDrawsListingView.js +18 -33
- package/dist/features/products/components/ProductsIndexListing.js +87 -11
- package/dist/features/products/components/ProductsIndexPageView.js +14 -2
- package/dist/features/products/config/listing-type-listing-config.d.ts +31 -0
- package/dist/features/products/config/listing-type-listing-config.js +74 -0
- package/dist/features/products/hooks/useProducts.js +14 -0
- package/dist/features/products/types/index.d.ts +15 -0
- package/dist/features/seller/components/SellerOrdersView.js +2 -1
- package/dist/features/stores/components/StoreArtStickersPageView.d.ts +21 -0
- package/dist/features/stores/components/StoreArtStickersPageView.js +30 -0
- package/dist/features/stores/components/StoreAuctionsPageView.d.ts +4 -1
- package/dist/features/stores/components/StoreAuctionsPageView.js +17 -17
- package/dist/features/stores/components/StoreClassifiedsListing.js +7 -0
- package/dist/features/stores/components/StoreClassifiedsPageView.d.ts +4 -1
- package/dist/features/stores/components/StoreClassifiedsPageView.js +16 -12
- package/dist/features/stores/components/StoreDetailLayoutView.js +4 -3
- package/dist/features/stores/components/StoreDigitalCodesListing.js +5 -0
- package/dist/features/stores/components/StoreDigitalCodesPageView.d.ts +4 -1
- package/dist/features/stores/components/StoreDigitalCodesPageView.js +16 -12
- package/dist/features/stores/components/StoreLiveItemsListing.js +7 -0
- package/dist/features/stores/components/StoreLiveItemsPageView.d.ts +4 -1
- package/dist/features/stores/components/StoreLiveItemsPageView.js +16 -12
- package/dist/features/stores/components/StorePreOrdersPageView.d.ts +4 -1
- package/dist/features/stores/components/StorePreOrdersPageView.js +17 -17
- package/dist/features/stores/components/StorePrizeDrawsPageView.d.ts +4 -8
- package/dist/features/stores/components/StorePrizeDrawsPageView.js +17 -22
- package/dist/features/stores/components/StoreProductsListing.d.ts +7 -1
- package/dist/features/stores/components/StoreProductsListing.js +3 -2
- package/dist/features/stores/components/StoreProductsPageView.d.ts +1 -1
- package/dist/features/stores/components/StoreProductsPageView.js +16 -21
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +602 -0
- package/dist/next/routing/route-map.d.ts +2 -0
- package/dist/next/routing/route-map.js +5 -0
- package/dist/seed/reviews-seed-data.js +52 -0
- package/dist/server-entry.d.ts +1 -0
- package/dist/server-entry.js +1 -0
- package/dist/styles.css +12 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Checkbox.d.ts +10 -1
- package/dist/ui/components/Checkbox.js +14 -2
- package/dist/ui/components/Checkbox.style.css +11 -0
- package/package.json +1 -1
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export declare const CHECKOUT_DEFAULT_COMMISSIONS: {
|
|
2
|
+
readonly platformFeePercent: 5;
|
|
3
|
+
readonly gstPercent: 18;
|
|
4
|
+
readonly minimumTransactionFee: 0;
|
|
5
|
+
readonly platformFeeMax: 10;
|
|
2
6
|
readonly codDepositPercent: 10;
|
|
3
7
|
readonly codHandlingFeeMin: 200;
|
|
4
8
|
readonly codHandlingFeePercent: 10;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
export const CHECKOUT_DEFAULT_COMMISSIONS = {
|
|
2
|
+
// Platform-commission rates. Previously absent here because no checkout path
|
|
3
|
+
// computed a buyer-facing platform fee — the moment one did, a siteSettings
|
|
4
|
+
// document that failed to load would have produced NaN fees rather than a
|
|
5
|
+
// sane fallback. Mirrors the SiteSettingsDocument defaults.
|
|
6
|
+
platformFeePercent: 5,
|
|
7
|
+
gstPercent: 18,
|
|
8
|
+
minimumTransactionFee: 0,
|
|
9
|
+
platformFeeMax: 10,
|
|
2
10
|
codDepositPercent: 10,
|
|
3
11
|
codHandlingFeeMin: 200,
|
|
4
12
|
codHandlingFeePercent: 10,
|
|
@@ -18,17 +18,49 @@ export interface FeeCommissionRates {
|
|
|
18
18
|
platformFeePercent: number;
|
|
19
19
|
gstPercent: number;
|
|
20
20
|
/** Rupee floor (not paise) — matches the existing `minimumTransactionFee` doc convention. */ minimumTransactionFee?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Rupee ceiling on the buyer-facing platform commission. Optional so
|
|
23
|
+
* siteSettings documents saved before this field existed keep working —
|
|
24
|
+
* falls back to DEFAULT_PLATFORM_FEE_MAX (₹10).
|
|
25
|
+
*
|
|
26
|
+
* Applies to `computeCheckoutFees` (what the BUYER pays) only. The seller-side
|
|
27
|
+
* `computePayoutDeduction` is deliberately uncapped — that is a separate
|
|
28
|
+
* commercial decision, not the same number.
|
|
29
|
+
*/ platformFeeMax?: number;
|
|
21
30
|
gatewayFeePercent?: number;
|
|
22
31
|
}
|
|
23
32
|
export interface CheckoutFees {
|
|
24
|
-
/** Platform commission in decimal rupees
|
|
33
|
+
/** Platform commission in decimal rupees, capped at `platformFeeMax`. */
|
|
25
34
|
platformFee: number;
|
|
26
|
-
/** GST on the platform fee, in decimal rupees. */
|
|
35
|
+
/** GST on the (already capped) platform fee, in decimal rupees. */
|
|
27
36
|
gstOnFee: number;
|
|
28
37
|
/** platformFee + gstOnFee, floored at minimumTransactionFee. */
|
|
29
38
|
totalFee: number;
|
|
30
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* What the buyer pays on top of the subtotal.
|
|
42
|
+
*
|
|
43
|
+
* The cap is applied to the commission BEFORE GST is computed, because GST is
|
|
44
|
+
* levied on the commission actually charged — capping afterwards would bill tax
|
|
45
|
+
* on money that was never collected.
|
|
46
|
+
*/
|
|
31
47
|
export declare function computeCheckoutFees(subtotal: number, commissions: FeeCommissionRates): CheckoutFees;
|
|
48
|
+
/**
|
|
49
|
+
* Split one checkout's platform commission across the orders it produces.
|
|
50
|
+
*
|
|
51
|
+
* The buyer is charged a single capped commission for the transaction, but the
|
|
52
|
+
* cart splits into one order per store, and each `OrderDocument` records its own
|
|
53
|
+
* `platformFee` (invoices, reconciliation). Apportioning pro-rata by group
|
|
54
|
+
* subtotal keeps those per-order figures meaningful; giving the last group the
|
|
55
|
+
* rounding remainder guarantees they sum to exactly what was charged, so the
|
|
56
|
+
* orders can never quietly total a rupee more or less than the buyer paid.
|
|
57
|
+
*
|
|
58
|
+
* @param groupSubtotals `[storeId, subtotal]` pairs, in stable order.
|
|
59
|
+
*/
|
|
60
|
+
export declare function allocateCheckoutFees(groupSubtotals: readonly (readonly [string, number])[], fees: CheckoutFees): Map<string, {
|
|
61
|
+
platformFee: number;
|
|
62
|
+
gstOnFee: number;
|
|
63
|
+
}>;
|
|
32
64
|
export interface PayoutDeduction {
|
|
33
65
|
/** Platform commission in decimal rupees. */
|
|
34
66
|
platformFee: number;
|
|
@@ -15,12 +15,56 @@
|
|
|
15
15
|
* All money amounts are in decimal rupees.
|
|
16
16
|
*/
|
|
17
17
|
import { roundRupees } from "../../../utils/number.formatter";
|
|
18
|
+
/** Buyer-facing platform commission ceiling, in decimal rupees. */
|
|
19
|
+
const DEFAULT_PLATFORM_FEE_MAX = 10;
|
|
20
|
+
/**
|
|
21
|
+
* What the buyer pays on top of the subtotal.
|
|
22
|
+
*
|
|
23
|
+
* The cap is applied to the commission BEFORE GST is computed, because GST is
|
|
24
|
+
* levied on the commission actually charged — capping afterwards would bill tax
|
|
25
|
+
* on money that was never collected.
|
|
26
|
+
*/
|
|
18
27
|
export function computeCheckoutFees(subtotal, commissions) {
|
|
19
|
-
const
|
|
28
|
+
const uncapped = roundRupees(subtotal * (commissions.platformFeePercent / 100));
|
|
29
|
+
const cap = commissions.platformFeeMax ?? DEFAULT_PLATFORM_FEE_MAX;
|
|
30
|
+
const platformFee = Math.min(uncapped, cap);
|
|
20
31
|
const gstOnFee = roundRupees(platformFee * (commissions.gstPercent / 100));
|
|
21
32
|
const totalFee = Math.max(platformFee + gstOnFee, commissions.minimumTransactionFee ?? 0);
|
|
22
33
|
return { platformFee, gstOnFee, totalFee };
|
|
23
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Split one checkout's platform commission across the orders it produces.
|
|
37
|
+
*
|
|
38
|
+
* The buyer is charged a single capped commission for the transaction, but the
|
|
39
|
+
* cart splits into one order per store, and each `OrderDocument` records its own
|
|
40
|
+
* `platformFee` (invoices, reconciliation). Apportioning pro-rata by group
|
|
41
|
+
* subtotal keeps those per-order figures meaningful; giving the last group the
|
|
42
|
+
* rounding remainder guarantees they sum to exactly what was charged, so the
|
|
43
|
+
* orders can never quietly total a rupee more or less than the buyer paid.
|
|
44
|
+
*
|
|
45
|
+
* @param groupSubtotals `[storeId, subtotal]` pairs, in stable order.
|
|
46
|
+
*/
|
|
47
|
+
export function allocateCheckoutFees(groupSubtotals, fees) {
|
|
48
|
+
const allocation = new Map();
|
|
49
|
+
if (groupSubtotals.length === 0)
|
|
50
|
+
return allocation;
|
|
51
|
+
const total = groupSubtotals.reduce((sum, [, subtotal]) => sum + subtotal, 0);
|
|
52
|
+
let platformRemaining = fees.platformFee;
|
|
53
|
+
let gstRemaining = fees.gstOnFee;
|
|
54
|
+
groupSubtotals.forEach(([storeId, subtotal], index) => {
|
|
55
|
+
const isLast = index === groupSubtotals.length - 1;
|
|
56
|
+
// An all-zero cart can't be apportioned by share — fall back to giving the
|
|
57
|
+
// whole (necessarily zero-ish) fee to the last group rather than dividing
|
|
58
|
+
// by zero.
|
|
59
|
+
const share = total > 0 ? subtotal / total : 0;
|
|
60
|
+
const platformFee = isLast ? roundRupees(platformRemaining) : roundRupees(fees.platformFee * share);
|
|
61
|
+
const gstOnFee = isLast ? roundRupees(gstRemaining) : roundRupees(fees.gstOnFee * share);
|
|
62
|
+
platformRemaining = roundRupees(platformRemaining - platformFee);
|
|
63
|
+
gstRemaining = roundRupees(gstRemaining - gstOnFee);
|
|
64
|
+
allocation.set(storeId, { platformFee, gstOnFee });
|
|
65
|
+
});
|
|
66
|
+
return allocation;
|
|
67
|
+
}
|
|
24
68
|
export function computePayoutDeduction(grossAmount, commissions) {
|
|
25
69
|
const platformFee = roundRupees(grossAmount * (commissions.platformFeePercent / 100));
|
|
26
70
|
const gatewayFee = roundRupees(grossAmount * ((commissions.gatewayFeePercent ?? 0) / 100));
|
package/dist/client.d.ts
CHANGED
|
@@ -207,7 +207,9 @@ export { ProtectedRoute, AuthStatusPanel, ForgotPasswordView, LoginForm, Registe
|
|
|
207
207
|
export type { AuthGuardUser, ForgotPasswordViewProps, LoginFormProps, LoginFormValues, RegisterFormProps, RegisterFormValues, ResetPasswordViewProps, VerifyEmailViewProps, } from "./features/auth/index";
|
|
208
208
|
export { useLogout, useLogin, useGoogleLogin, useLinkGoogleAccount, useRegister, useForgotPassword, useResetPassword, useVerifyEmail, useChangeEmail } from "./features/auth/index";
|
|
209
209
|
export type { LoginCredentials, RegisterData, ForgotPasswordData, ResetPasswordData, VerifyEmailData, ChangeEmailData } from "./features/auth/index";
|
|
210
|
-
export { CartView, CartItemRow, CartSummary, CartDrawer, CheckoutView, CheckoutSuccessView, CheckoutAddressStep, useGuestCart, useCartCount, useAddToCart, useCart, useGuestCartMerge, useCartQuery } from "./features/cart/index";
|
|
210
|
+
export { CartView, CartItemRow, CartSummary, CartPriceBreakdown, CartDrawer, CheckoutView, CheckoutSuccessView, CheckoutAddressStep, useGuestCart, useCartCount, useAddToCart, useCart, useGuestCartMerge, useCartQuery } from "./features/cart/index";
|
|
211
|
+
export { StoreAddonsPicker } from "./features/cart/index";
|
|
212
|
+
export type { CartPriceBreakdownData, CartPriceBreakdownStore, StoreAddonsValue, StoreAddonsRates } from "./features/cart/index";
|
|
211
213
|
export { getCartOps, CART_OPS_CHANGE_EVENT } from "./features/cart/utils/pending-ops";
|
|
212
214
|
export type { CartOp } from "./features/cart/utils/pending-ops";
|
|
213
215
|
export type { CartItem, CartItemMeta, CartData, GuestCartItem } from "./features/cart/index";
|
|
@@ -300,6 +302,10 @@ export type { UserAccountHubViewProps, UserAccountHubViewLabels, UserOrdersViewP
|
|
|
300
302
|
export { useOrders, useOrder, OrdersList } from "./features/orders/index";
|
|
301
303
|
export { OrderStatusTimeline } from "./features/orders/components/OrderStatusTimeline";
|
|
302
304
|
export type { OrderStatusTimelineProps } from "./features/orders/components/OrderStatusTimeline";
|
|
305
|
+
export { CountdownDisplay } from "./ui/components/CountdownDisplay";
|
|
306
|
+
export type { CountdownDisplayProps } from "./ui/components/CountdownDisplay";
|
|
307
|
+
export { OrderAddonBadges } from "./features/orders/components/OrderAddonBadges";
|
|
308
|
+
export type { OrderAddonBadgesOrder, OrderAddonBadgesProps } from "./features/orders/components/OrderAddonBadges";
|
|
303
309
|
export { MANUAL_PAYMENT_METHODS, isManualPaymentMethod, PAYMENT_REVIEW_QUEUE_MODES, isPaymentReviewQueueMode, PAYMENT_WINDOW_MINUTES, } from "./features/orders/constants/payment-window";
|
|
304
310
|
export type { PaymentReviewQueueMode } from "./features/orders/constants/payment-window";
|
|
305
311
|
export { UserOrderTrackView } from "./features/account/components/UserOrderTrackView";
|
package/dist/client.js
CHANGED
|
@@ -238,7 +238,8 @@ export { PAGE_VIEW_ENTITY_TYPES } from "./features/analytics/types";
|
|
|
238
238
|
export { AuctionBidsTable } from "./features/auctions/components/AuctionBidsTable";
|
|
239
239
|
export { ProtectedRoute, AuthStatusPanel, ForgotPasswordView, LoginForm, RegisterForm, ResetPasswordView, VerifyEmailView } from "./features/auth/index";
|
|
240
240
|
export { useLogout, useLogin, useGoogleLogin, useLinkGoogleAccount, useRegister, useForgotPassword, useResetPassword, useVerifyEmail, useChangeEmail } from "./features/auth/index";
|
|
241
|
-
export { CartView, CartItemRow, CartSummary, CartDrawer, CheckoutView, CheckoutSuccessView, CheckoutAddressStep, useGuestCart, useCartCount, useAddToCart, useCart, useGuestCartMerge, useCartQuery } from "./features/cart/index";
|
|
241
|
+
export { CartView, CartItemRow, CartSummary, CartPriceBreakdown, CartDrawer, CheckoutView, CheckoutSuccessView, CheckoutAddressStep, useGuestCart, useCartCount, useAddToCart, useCart, useGuestCartMerge, useCartQuery } from "./features/cart/index";
|
|
242
|
+
export { StoreAddonsPicker } from "./features/cart/index";
|
|
242
243
|
export { getCartOps, CART_OPS_CHANGE_EVENT } from "./features/cart/utils/pending-ops";
|
|
243
244
|
export { useAddresses, useCreateAddress, useUpdateAddress, useDeleteAddress, useSetDefaultAddress, useAddress } from "./features/account/index";
|
|
244
245
|
export { AddressBook, AddressCard, AddressForm } from "./features/account/index";
|
|
@@ -301,6 +302,8 @@ export { SellerPayoutSettingsView, SellerShippingView, SellerReviewsView, Seller
|
|
|
301
302
|
export { UserAccountHubView, UserOrdersView, UserBidsView, OrderDetailView, UserNotificationsView, UserReturnsView, UserSupportView, useNotifications } from "./features/account/index";
|
|
302
303
|
export { useOrders, useOrder, OrdersList } from "./features/orders/index";
|
|
303
304
|
export { OrderStatusTimeline } from "./features/orders/components/OrderStatusTimeline";
|
|
305
|
+
export { CountdownDisplay } from "./ui/components/CountdownDisplay";
|
|
306
|
+
export { OrderAddonBadges } from "./features/orders/components/OrderAddonBadges";
|
|
304
307
|
// Manual-payment (cash / UPI / EMI) shared constants — pure data + predicates,
|
|
305
308
|
// no server deps. Used by the buyer proof-upload page and order-detail CTAs.
|
|
306
309
|
export { MANUAL_PAYMENT_METHODS, isManualPaymentMethod, PAYMENT_REVIEW_QUEUE_MODES, isPaymentReviewQueueMode, PAYMENT_WINDOW_MINUTES, } from "./features/orders/constants/payment-window";
|
|
@@ -234,6 +234,8 @@ export declare const CART_ENDPOINTS: {
|
|
|
234
234
|
readonly BY_ITEM_ID: (itemId: string) => string;
|
|
235
235
|
readonly VALIDATE: "/api/cart/validate";
|
|
236
236
|
readonly SELECTION: "/api/cart/selection";
|
|
237
|
+
/** Per-store paid add-on selections — the source of truth for what's charged. */
|
|
238
|
+
readonly ADDONS: "/api/cart/addons";
|
|
237
239
|
readonly COUPON: "/api/cart/coupon";
|
|
238
240
|
};
|
|
239
241
|
export declare const CATEGORY_ENDPOINTS: {
|
|
@@ -686,6 +688,8 @@ export declare const API_ENDPOINTS: {
|
|
|
686
688
|
readonly BY_ITEM_ID: (itemId: string) => string;
|
|
687
689
|
readonly VALIDATE: "/api/cart/validate";
|
|
688
690
|
readonly SELECTION: "/api/cart/selection";
|
|
691
|
+
/** Per-store paid add-on selections — the source of truth for what's charged. */
|
|
692
|
+
readonly ADDONS: "/api/cart/addons";
|
|
689
693
|
readonly COUPON: "/api/cart/coupon";
|
|
690
694
|
};
|
|
691
695
|
readonly CATEGORIES: {
|
|
@@ -1140,6 +1144,8 @@ export declare const API_ROUTES: {
|
|
|
1140
1144
|
readonly BY_ITEM_ID: (itemId: string) => string;
|
|
1141
1145
|
readonly VALIDATE: "/api/cart/validate";
|
|
1142
1146
|
readonly SELECTION: "/api/cart/selection";
|
|
1147
|
+
/** Per-store paid add-on selections — the source of truth for what's charged. */
|
|
1148
|
+
readonly ADDONS: "/api/cart/addons";
|
|
1143
1149
|
readonly COUPON: "/api/cart/coupon";
|
|
1144
1150
|
};
|
|
1145
1151
|
readonly CATEGORIES: {
|
|
@@ -274,6 +274,8 @@ export const CART_ENDPOINTS = {
|
|
|
274
274
|
BY_ITEM_ID: (itemId) => `/api/cart/${encodeURIComponent(itemId)}`,
|
|
275
275
|
VALIDATE: "/api/cart/validate",
|
|
276
276
|
SELECTION: "/api/cart/selection",
|
|
277
|
+
/** Per-store paid add-on selections — the source of truth for what's charged. */
|
|
278
|
+
ADDONS: "/api/cart/addons",
|
|
277
279
|
COUPON: "/api/cart/coupon",
|
|
278
280
|
};
|
|
279
281
|
// ---------------------------------------------------------------------------
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { sortBy } from "@mohasinac/appkit/client";
|
|
4
|
-
import {
|
|
4
|
+
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
5
5
|
import { useQueryClient } from "@tanstack/react-query";
|
|
6
6
|
import { Badge, Div, FilterChipGroup, Span, Stack, Text, useToast } from "../../../ui";
|
|
7
7
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
@@ -47,18 +47,22 @@ const ADDRESS_COLUMNS = [
|
|
|
47
47
|
render: (row) => _jsx(Span, { size: "sm", color: "muted", children: row.updatedAt }),
|
|
48
48
|
},
|
|
49
49
|
];
|
|
50
|
-
function buildAddressConfig(
|
|
50
|
+
function buildAddressConfig(onAction) {
|
|
51
51
|
return {
|
|
52
52
|
portal: "admin",
|
|
53
53
|
title: "Address Management",
|
|
54
54
|
searchPlaceholder: "Search by city or owner",
|
|
55
55
|
emptyLabel: "No addresses found",
|
|
56
|
-
filterKeys
|
|
56
|
+
// URL-synced via filterKeys (2026-08-21). The ban-status chips used to
|
|
57
|
+
// live outside this config in local useState, so the selection was not in
|
|
58
|
+
// the URL, not shareable, not counted by activeFilterCount, and lost on
|
|
59
|
+
// back-navigation. banStatus is a plain query param rather than a Sieve
|
|
60
|
+
// clause, which is exactly what buildExtraParams is for.
|
|
61
|
+
filterKeys: ["banStatus"],
|
|
57
62
|
defaultSort: sortBy("bannedAt", "DESC"),
|
|
58
|
-
queryKey: ["admin", "addresses"
|
|
59
|
-
endpoint:
|
|
60
|
-
|
|
61
|
-
: ADMIN_ENDPOINTS.ADDRESSES,
|
|
63
|
+
queryKey: ["admin", "addresses"],
|
|
64
|
+
endpoint: ADMIN_ENDPOINTS.ADDRESSES,
|
|
65
|
+
buildExtraParams: (state) => state.banStatus ? { banStatus: state.banStatus } : undefined,
|
|
62
66
|
sortOptions: [
|
|
63
67
|
// -bannedAt (newest flagged first) to match defaultSort — the option was
|
|
64
68
|
// "bannedAt" (oldest first), so the dropdown opened with nothing selected.
|
|
@@ -121,7 +125,11 @@ function buildAddressConfig(banStatus, onAction) {
|
|
|
121
125
|
};
|
|
122
126
|
}
|
|
123
127
|
export function AdminAddressesView(_props) {
|
|
124
|
-
|
|
128
|
+
// Independent useUrlTable() against the same URL param DataListingView's own
|
|
129
|
+
// table reads via filterKeys — safe because useUrlTable holds no local state
|
|
130
|
+
// (the documented Root Cause #35 pattern).
|
|
131
|
+
const chipTable = useUrlTable({ defaults: {} });
|
|
132
|
+
const banStatus = chipTable.get("banStatus");
|
|
125
133
|
const queryClient = useQueryClient();
|
|
126
134
|
const { showToast } = useToast();
|
|
127
135
|
const actionMutation = useApiMutation({
|
|
@@ -139,6 +147,6 @@ export function AdminAddressesView(_props) {
|
|
|
139
147
|
const handleAction = (id, action) => {
|
|
140
148
|
actionMutation.mutate({ id, action });
|
|
141
149
|
};
|
|
142
|
-
const config = buildAddressConfig(
|
|
143
|
-
return (_jsxs(Stack, { gap: "md", children: [_jsx(Div, { padding: "inline", border: "default", className: "border-b", children: _jsx(FilterChipGroup, { label: "Status", tabs: BAN_STATUS_TABS, value: banStatus, onChange: (v) =>
|
|
150
|
+
const config = buildAddressConfig(handleAction);
|
|
151
|
+
return (_jsxs(Stack, { gap: "md", children: [_jsx(Div, { padding: "inline", border: "default", className: "border-b", children: _jsx(FilterChipGroup, { label: "Status", tabs: BAN_STATUS_TABS, value: banStatus, onChange: (v) => chipTable.set("banStatus", v) }) }), _jsx(DataListingView, { config: config })] }));
|
|
144
152
|
}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdminArtView — admin browse of art listings.
|
|
3
|
+
*
|
|
4
|
+
* A thin wrapper over the shared per-listing-type config. This file (and its
|
|
5
|
+
* four siblings) used to carry a full hand-written ListingViewConfig; all five
|
|
6
|
+
* were the same config with a different listingType, and all five shipped
|
|
7
|
+
* an empty filterKeys array — no filter drawer at all — plus their own copy
|
|
8
|
+
* of a three-option sort array. See listing-type-listing-config.ts.
|
|
9
|
+
*/
|
|
1
10
|
import React from "react";
|
|
2
11
|
import type { ListingLayoutProps } from "../../../ui";
|
|
3
12
|
export type AdminArtViewProps = ListingLayoutProps;
|
|
@@ -1,50 +1,26 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
/**
|
|
4
|
-
* AdminArtView — admin browse of art
|
|
5
|
-
*
|
|
4
|
+
* AdminArtView — admin browse of art listings.
|
|
5
|
+
*
|
|
6
|
+
* A thin wrapper over the shared per-listing-type config. This file (and its
|
|
7
|
+
* four siblings) used to carry a full hand-written ListingViewConfig; all five
|
|
8
|
+
* were the same config with a different listingType, and all five shipped
|
|
9
|
+
* an empty filterKeys array — no filter drawer at all — plus their own copy
|
|
10
|
+
* of a three-option sort array. See listing-type-listing-config.ts.
|
|
6
11
|
*/
|
|
7
|
-
import { sortBy } from "@mohasinac/appkit/client";
|
|
8
12
|
import React from "react";
|
|
9
13
|
import { ListingLayout } from "../../../ui";
|
|
10
|
-
import {
|
|
11
|
-
import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../hooks/useAdminListingData";
|
|
14
|
+
import { buildListingTypeListingConfig } from "../../products/config/listing-type-listing-config";
|
|
12
15
|
import { DataListingView } from "./DataListingView";
|
|
13
|
-
|
|
14
|
-
const ADMIN_ART_CONFIG = {
|
|
15
|
-
portal: "admin",
|
|
16
|
+
const CONFIG = buildListingTypeListingConfig("art", {
|
|
16
17
|
title: "Art",
|
|
17
18
|
searchPlaceholder: "Search art prints by name or seller",
|
|
18
19
|
emptyLabel: "No art listings",
|
|
19
|
-
|
|
20
|
-
defaultSort: sortBy("createdAt", "DESC"),
|
|
21
|
-
queryKey: ["admin", "art", "listing"],
|
|
22
|
-
endpoint: ADMIN_ENDPOINTS.PRODUCTS,
|
|
23
|
-
sortOptions: [
|
|
24
|
-
{ value: sortBy("createdAt", "DESC"), label: "Newest" },
|
|
25
|
-
{ value: sortBy("createdAt", "ASC"), label: "Oldest" },
|
|
26
|
-
{ value: "title", label: "Title A–Z" },
|
|
27
|
-
],
|
|
28
|
-
mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
|
|
29
|
-
id: toStringValue(item.id, `art-${index}`),
|
|
30
|
-
primary: toStringValue(item.title ?? item.productTitle, "Untitled print"),
|
|
31
|
-
secondary: [
|
|
32
|
-
toStringValue(item.sellerName, "Unknown seller"),
|
|
33
|
-
toCurrency(item.price),
|
|
34
|
-
].join(" · "),
|
|
35
|
-
status: toStringValue(item.status, "draft"),
|
|
36
|
-
updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
|
|
37
|
-
image: toStringValue(item.mainImage, "") || undefined,
|
|
38
|
-
})),
|
|
39
|
-
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
40
|
-
buildFilters: () => "listingType==art",
|
|
41
|
-
// Art listings are products (filtered by listingType) — reuse the real
|
|
42
|
-
// admin product edit page rather than leaving rows non-navigable.
|
|
43
|
-
rowHrefTemplate: String(ROUTES.ADMIN.PRODUCTS_EDIT("{id}")),
|
|
44
|
-
};
|
|
20
|
+
});
|
|
45
21
|
export function AdminArtView({ children, ...props }) {
|
|
46
22
|
if (React.Children.count(children) > 0) {
|
|
47
23
|
return (_jsx(ListingLayout, { portal: "admin", ...props, children: children }));
|
|
48
24
|
}
|
|
49
|
-
return _jsx(DataListingView, { config:
|
|
25
|
+
return _jsx(DataListingView, { config: CONFIG });
|
|
50
26
|
}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdminClassifiedView — admin browse of classified listings.
|
|
3
|
+
*
|
|
4
|
+
* A thin wrapper over the shared per-listing-type config. This file (and its
|
|
5
|
+
* four siblings) used to carry a full hand-written ListingViewConfig; all five
|
|
6
|
+
* were the same config with a different listingType, and all five shipped
|
|
7
|
+
* an empty filterKeys array — no filter drawer at all — plus their own copy
|
|
8
|
+
* of a three-option sort array. See listing-type-listing-config.ts.
|
|
9
|
+
*/
|
|
1
10
|
import React from "react";
|
|
2
11
|
import type { ListingLayoutProps } from "../../../ui";
|
|
3
12
|
export type AdminClassifiedViewProps = ListingLayoutProps;
|
|
@@ -1,50 +1,26 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
/**
|
|
4
|
-
* AdminClassifiedView — admin browse of classified listings
|
|
5
|
-
*
|
|
4
|
+
* AdminClassifiedView — admin browse of classified listings.
|
|
5
|
+
*
|
|
6
|
+
* A thin wrapper over the shared per-listing-type config. This file (and its
|
|
7
|
+
* four siblings) used to carry a full hand-written ListingViewConfig; all five
|
|
8
|
+
* were the same config with a different listingType, and all five shipped
|
|
9
|
+
* an empty filterKeys array — no filter drawer at all — plus their own copy
|
|
10
|
+
* of a three-option sort array. See listing-type-listing-config.ts.
|
|
6
11
|
*/
|
|
7
|
-
import { sortBy } from "@mohasinac/appkit/client";
|
|
8
12
|
import React from "react";
|
|
9
13
|
import { ListingLayout } from "../../../ui";
|
|
10
|
-
import {
|
|
11
|
-
import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../hooks/useAdminListingData";
|
|
14
|
+
import { buildListingTypeListingConfig } from "../../products/config/listing-type-listing-config";
|
|
12
15
|
import { DataListingView } from "./DataListingView";
|
|
13
|
-
|
|
14
|
-
const ADMIN_CLASSIFIED_CONFIG = {
|
|
15
|
-
portal: "admin",
|
|
16
|
+
const CONFIG = buildListingTypeListingConfig("classified", {
|
|
16
17
|
title: "Classified",
|
|
17
18
|
searchPlaceholder: "Search classified by name or seller",
|
|
18
19
|
emptyLabel: "No classified listings",
|
|
19
|
-
|
|
20
|
-
defaultSort: sortBy("createdAt", "DESC"),
|
|
21
|
-
queryKey: ["admin", "classified", "listing"],
|
|
22
|
-
endpoint: ADMIN_ENDPOINTS.PRODUCTS,
|
|
23
|
-
sortOptions: [
|
|
24
|
-
{ value: sortBy("createdAt", "DESC"), label: "Newest" },
|
|
25
|
-
{ value: sortBy("createdAt", "ASC"), label: "Oldest" },
|
|
26
|
-
{ value: "title", label: "Title A–Z" },
|
|
27
|
-
],
|
|
28
|
-
mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
|
|
29
|
-
id: toStringValue(item.id, `classified-${index}`),
|
|
30
|
-
primary: toStringValue(item.title ?? item.productTitle, "Untitled classified"),
|
|
31
|
-
secondary: [
|
|
32
|
-
toStringValue(item.sellerName, "Unknown seller"),
|
|
33
|
-
toCurrency(item.price),
|
|
34
|
-
].join(" · "),
|
|
35
|
-
status: toStringValue(item.status, "draft"),
|
|
36
|
-
updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
|
|
37
|
-
image: toStringValue(item.mainImage, "") || undefined,
|
|
38
|
-
})),
|
|
39
|
-
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
40
|
-
buildFilters: () => "listingType==classified",
|
|
41
|
-
// Classified listings are products (filtered by listingType) — reuse the
|
|
42
|
-
// real admin product edit page rather than leaving rows non-navigable.
|
|
43
|
-
rowHrefTemplate: String(ROUTES.ADMIN.PRODUCTS_EDIT("{id}")),
|
|
44
|
-
};
|
|
20
|
+
});
|
|
45
21
|
export function AdminClassifiedView({ children, ...props }) {
|
|
46
22
|
if (React.Children.count(children) > 0) {
|
|
47
23
|
return (_jsx(ListingLayout, { portal: "admin", ...props, children: children }));
|
|
48
24
|
}
|
|
49
|
-
return _jsx(DataListingView, { config:
|
|
25
|
+
return _jsx(DataListingView, { config: CONFIG });
|
|
50
26
|
}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdminDigitalCodesView — admin browse of digital codes listings.
|
|
3
|
+
*
|
|
4
|
+
* A thin wrapper over the shared per-listing-type config. This file (and its
|
|
5
|
+
* four siblings) used to carry a full hand-written ListingViewConfig; all five
|
|
6
|
+
* were the same config with a different listingType, and all five shipped
|
|
7
|
+
* an empty filterKeys array — no filter drawer at all — plus their own copy
|
|
8
|
+
* of a three-option sort array. See listing-type-listing-config.ts.
|
|
9
|
+
*/
|
|
1
10
|
import React from "react";
|
|
2
11
|
import type { ListingLayoutProps } from "../../../ui";
|
|
3
12
|
export type AdminDigitalCodesViewProps = ListingLayoutProps;
|
|
@@ -1,57 +1,26 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
/**
|
|
4
|
-
* AdminDigitalCodesView — admin browse of digital
|
|
4
|
+
* AdminDigitalCodesView — admin browse of digital codes listings.
|
|
5
|
+
*
|
|
6
|
+
* A thin wrapper over the shared per-listing-type config. This file (and its
|
|
7
|
+
* four siblings) used to carry a full hand-written ListingViewConfig; all five
|
|
8
|
+
* were the same config with a different listingType, and all five shipped
|
|
9
|
+
* an empty filterKeys array — no filter drawer at all — plus their own copy
|
|
10
|
+
* of a three-option sort array. See listing-type-listing-config.ts.
|
|
5
11
|
*/
|
|
6
|
-
import { sortBy } from "@mohasinac/appkit/client";
|
|
7
12
|
import React from "react";
|
|
8
13
|
import { ListingLayout } from "../../../ui";
|
|
9
|
-
import {
|
|
10
|
-
import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../hooks/useAdminListingData";
|
|
14
|
+
import { buildListingTypeListingConfig } from "../../products/config/listing-type-listing-config";
|
|
11
15
|
import { DataListingView } from "./DataListingView";
|
|
12
|
-
|
|
13
|
-
const ADMIN_DIGITAL_CODES_CONFIG = {
|
|
14
|
-
portal: "admin",
|
|
16
|
+
const CONFIG = buildListingTypeListingConfig("digital-code", {
|
|
15
17
|
title: "Digital Codes",
|
|
16
18
|
searchPlaceholder: "Search digital code listings",
|
|
17
19
|
emptyLabel: "No digital code listings",
|
|
18
|
-
|
|
19
|
-
defaultSort: sortBy("createdAt", "DESC"),
|
|
20
|
-
queryKey: ["admin", "digital-codes", "listing"],
|
|
21
|
-
endpoint: ADMIN_ENDPOINTS.PRODUCTS,
|
|
22
|
-
sortOptions: [
|
|
23
|
-
{ value: sortBy("createdAt", "DESC"), label: "Newest" },
|
|
24
|
-
{ value: sortBy("createdAt", "ASC"), label: "Oldest" },
|
|
25
|
-
{ value: "title", label: "Title A–Z" },
|
|
26
|
-
],
|
|
27
|
-
mapRows: (response) => toRecordArray(response.items).map((item, index) => {
|
|
28
|
-
const dc = (item.digitalCode ?? {});
|
|
29
|
-
return {
|
|
30
|
-
id: toStringValue(item.id, `dc-${index}`),
|
|
31
|
-
primary: toStringValue(item.title ?? item.productTitle, "Untitled digital code"),
|
|
32
|
-
secondary: [
|
|
33
|
-
toStringValue(item.sellerName, "Unknown seller"),
|
|
34
|
-
toCurrency(item.price),
|
|
35
|
-
typeof dc.codesAvailable === "number"
|
|
36
|
-
? `${dc.codesAvailable} avail`
|
|
37
|
-
: null,
|
|
38
|
-
]
|
|
39
|
-
.filter(Boolean)
|
|
40
|
-
.join(" · "),
|
|
41
|
-
status: toStringValue(item.status, "draft"),
|
|
42
|
-
updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
|
|
43
|
-
image: toStringValue(item.mainImage, "") || undefined,
|
|
44
|
-
};
|
|
45
|
-
}),
|
|
46
|
-
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
47
|
-
buildFilters: () => "listingType==digital-code",
|
|
48
|
-
// Digital-code listings are products (filtered by listingType) — reuse
|
|
49
|
-
// the real admin product edit page rather than leaving rows non-navigable.
|
|
50
|
-
rowHrefTemplate: String(ROUTES.ADMIN.PRODUCTS_EDIT("{id}")),
|
|
51
|
-
};
|
|
20
|
+
});
|
|
52
21
|
export function AdminDigitalCodesView({ children, ...props }) {
|
|
53
22
|
if (React.Children.count(children) > 0) {
|
|
54
23
|
return (_jsx(ListingLayout, { portal: "admin", ...props, children: children }));
|
|
55
24
|
}
|
|
56
|
-
return _jsx(DataListingView, { config:
|
|
25
|
+
return _jsx(DataListingView, { config: CONFIG });
|
|
57
26
|
}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdminLiveView — admin browse of live items listings.
|
|
3
|
+
*
|
|
4
|
+
* A thin wrapper over the shared per-listing-type config. This file (and its
|
|
5
|
+
* four siblings) used to carry a full hand-written ListingViewConfig; all five
|
|
6
|
+
* were the same config with a different listingType, and all five shipped
|
|
7
|
+
* an empty filterKeys array — no filter drawer at all — plus their own copy
|
|
8
|
+
* of a three-option sort array. See listing-type-listing-config.ts.
|
|
9
|
+
*/
|
|
1
10
|
import React from "react";
|
|
2
11
|
import type { ListingLayoutProps } from "../../../ui";
|
|
3
12
|
export type AdminLiveViewProps = ListingLayoutProps;
|
|
@@ -1,56 +1,26 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
/**
|
|
4
|
-
* AdminLiveView — admin browse of live
|
|
4
|
+
* AdminLiveView — admin browse of live items listings.
|
|
5
|
+
*
|
|
6
|
+
* A thin wrapper over the shared per-listing-type config. This file (and its
|
|
7
|
+
* four siblings) used to carry a full hand-written ListingViewConfig; all five
|
|
8
|
+
* were the same config with a different listingType, and all five shipped
|
|
9
|
+
* an empty filterKeys array — no filter drawer at all — plus their own copy
|
|
10
|
+
* of a three-option sort array. See listing-type-listing-config.ts.
|
|
5
11
|
*/
|
|
6
|
-
import { sortBy } from "@mohasinac/appkit/client";
|
|
7
12
|
import React from "react";
|
|
8
13
|
import { ListingLayout } from "../../../ui";
|
|
9
|
-
import {
|
|
10
|
-
import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../hooks/useAdminListingData";
|
|
14
|
+
import { buildListingTypeListingConfig } from "../../products/config/listing-type-listing-config";
|
|
11
15
|
import { DataListingView } from "./DataListingView";
|
|
12
|
-
|
|
13
|
-
const ADMIN_LIVE_CONFIG = {
|
|
14
|
-
portal: "admin",
|
|
16
|
+
const CONFIG = buildListingTypeListingConfig("live", {
|
|
15
17
|
title: "Live Items",
|
|
16
18
|
searchPlaceholder: "Search live items",
|
|
17
19
|
emptyLabel: "No live item listings",
|
|
18
|
-
|
|
19
|
-
defaultSort: sortBy("createdAt", "DESC"),
|
|
20
|
-
queryKey: ["admin", "live-items", "listing"],
|
|
21
|
-
endpoint: ADMIN_ENDPOINTS.PRODUCTS,
|
|
22
|
-
sortOptions: [
|
|
23
|
-
{ value: sortBy("createdAt", "DESC"), label: "Newest" },
|
|
24
|
-
{ value: sortBy("createdAt", "ASC"), label: "Oldest" },
|
|
25
|
-
{ value: "title", label: "Title A–Z" },
|
|
26
|
-
],
|
|
27
|
-
mapRows: (response) => toRecordArray(response.items).map((item, index) => {
|
|
28
|
-
const live = (item.liveItem ?? {});
|
|
29
|
-
return {
|
|
30
|
-
id: toStringValue(item.id, `live-${index}`),
|
|
31
|
-
primary: toStringValue(item.title ?? item.productTitle, "Untitled live item"),
|
|
32
|
-
secondary: [
|
|
33
|
-
toStringValue(item.sellerName, "Unknown seller"),
|
|
34
|
-
toCurrency(item.price),
|
|
35
|
-
toStringValue(live.species, ""),
|
|
36
|
-
Boolean(live.vendorVerified) ? "verified" : "pending",
|
|
37
|
-
]
|
|
38
|
-
.filter(Boolean)
|
|
39
|
-
.join(" · "),
|
|
40
|
-
status: toStringValue(item.status, "draft"),
|
|
41
|
-
updatedAt: toRelativeDate(item.updatedAt ?? item.createdAt),
|
|
42
|
-
image: toStringValue(item.mainImage, "") || undefined,
|
|
43
|
-
};
|
|
44
|
-
}),
|
|
45
|
-
getTotal: (response, mappedRows) => typeof response.total === "number" ? response.total : mappedRows.length,
|
|
46
|
-
buildFilters: () => "listingType==live",
|
|
47
|
-
// Live-item listings are products (filtered by listingType) — reuse the
|
|
48
|
-
// real admin product edit page rather than leaving rows non-navigable.
|
|
49
|
-
rowHrefTemplate: String(ROUTES.ADMIN.PRODUCTS_EDIT("{id}")),
|
|
50
|
-
};
|
|
20
|
+
});
|
|
51
21
|
export function AdminLiveView({ children, ...props }) {
|
|
52
22
|
if (React.Children.count(children) > 0) {
|
|
53
23
|
return (_jsx(ListingLayout, { portal: "admin", ...props, children: children }));
|
|
54
24
|
}
|
|
55
|
-
return _jsx(DataListingView, { config:
|
|
25
|
+
return _jsx(DataListingView, { config: CONFIG });
|
|
56
26
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type OrderAddonBadgesOrder } from "../../orders/components/OrderAddonBadges";
|
|
1
2
|
import React from "react";
|
|
2
3
|
export interface AdminOrderItemRow {
|
|
3
4
|
productId: string;
|
|
@@ -23,5 +24,11 @@ export interface AdminOrderEditorViewProps {
|
|
|
23
24
|
paymentUpiMismatch?: boolean;
|
|
24
25
|
buyerMarkedPaid?: boolean;
|
|
25
26
|
buyerFraudAgreementAccepted?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Paid add-ons + applied coupon for this order. Operational, not decorative:
|
|
29
|
+
* `whatsappNotifyAddon` is who a status change should message, and the
|
|
30
|
+
* coupon is what an admin needs when reconciling a discounted order.
|
|
31
|
+
*/
|
|
32
|
+
addons?: OrderAddonBadgesOrder;
|
|
26
33
|
}
|
|
27
|
-
export declare function AdminOrderEditorView({ open, onClose, orderId, orderLabel, currentStatus, items, paymentProofUrl, paymentTransactionId, paymentMethod, paymentStatus, displayedUpiId, buyerReportedUpiId, paymentUpiMismatch, buyerMarkedPaid, buyerFraudAgreementAccepted, }: AdminOrderEditorViewProps): React.JSX.Element;
|
|
34
|
+
export declare function AdminOrderEditorView({ open, onClose, orderId, orderLabel, currentStatus, items, paymentProofUrl, paymentTransactionId, paymentMethod, paymentStatus, displayedUpiId, buyerReportedUpiId, paymentUpiMismatch, buyerMarkedPaid, buyerFraudAgreementAccepted, addons, }: AdminOrderEditorViewProps): React.JSX.Element;
|