@mohasinac/appkit 4.62.0 → 4.62.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-stamp.json +3 -3
- package/dist/_internal/server/features/checkout/actions.d.ts +80 -0
- package/dist/_internal/server/features/checkout/actions.js +542 -26
- package/dist/_internal/server/features/invoicing/allocate.d.ts +63 -0
- package/dist/_internal/server/features/invoicing/allocate.js +162 -0
- package/dist/_internal/server/features/invoicing/credit-note.d.ts +57 -0
- package/dist/_internal/server/features/invoicing/credit-note.js +126 -0
- package/dist/_internal/server/features/invoicing/gstr1.d.ts +74 -0
- package/dist/_internal/server/features/invoicing/gstr1.js +251 -0
- package/dist/_internal/server/features/invoicing/issue.d.ts +96 -0
- package/dist/_internal/server/features/invoicing/issue.js +202 -0
- package/dist/_internal/server/features/orders/actions.d.ts +8 -1
- package/dist/_internal/server/features/orders/actions.js +81 -8
- package/dist/_internal/server/features/orders/adapters.js +33 -0
- package/dist/_internal/server/features/orders/cancellation-refund.d.ts +15 -9
- package/dist/_internal/server/features/orders/cancellation-refund.js +15 -9
- package/dist/_internal/server/features/points/award.js +46 -4
- package/dist/_internal/server/features/refunds/actions.js +26 -0
- package/dist/_internal/server/features/shipping/courier-block.d.ts +69 -0
- package/dist/_internal/server/features/shipping/courier-block.js +239 -0
- package/dist/_internal/server/features/site-settings/adapters.d.ts +1 -1
- package/dist/_internal/server/features/site-settings/adapters.js +15 -0
- package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
- package/dist/_internal/server/features/stores/adapters.js +51 -0
- package/dist/_internal/server/functions/scheduled.js +38 -1
- package/dist/_internal/server/jobs/core/autoPayoutEligibility.js +9 -2
- package/dist/_internal/server/jobs/core/dailyStatusDigest.d.ts +4 -0
- package/dist/_internal/server/jobs/core/dailyStatusDigest.js +19 -2
- package/dist/_internal/server/jobs/core/index.d.ts +2 -1
- package/dist/_internal/server/jobs/core/index.js +2 -1
- package/dist/_internal/server/jobs/core/onJobCreated.d.ts +30 -7
- package/dist/_internal/server/jobs/core/onJobCreated.js +78 -45
- package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +7 -0
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +62 -0
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +33 -0
- package/dist/_internal/server/jobs/core/runJobOnce.d.ts +48 -0
- package/dist/_internal/server/jobs/core/runJobOnce.js +195 -0
- package/dist/_internal/server/jobs/core/weeklyPayoutEligibility.js +10 -2
- package/dist/_internal/server/jobs/handlers/onOrderStatusChange.js +17 -0
- package/dist/_internal/server/notifications/channel-health.d.ts +26 -3
- package/dist/_internal/shared/actions/action-registry.js +28 -0
- package/dist/_internal/shared/checkout/coupon-discount.d.ts +43 -1
- package/dist/_internal/shared/checkout/coupon-discount.js +26 -1
- package/dist/_internal/shared/checkout/order-math.d.ts +145 -0
- package/dist/_internal/shared/checkout/order-math.js +173 -0
- package/dist/_internal/shared/checkout/refundable-base.d.ts +25 -0
- package/dist/_internal/shared/checkout/refundable-base.js +13 -1
- package/dist/_internal/shared/checkout/split.d.ts +87 -0
- package/dist/_internal/shared/checkout/split.js +100 -0
- package/dist/_internal/shared/content/disclaimers.d.ts +88 -0
- package/dist/_internal/shared/content/disclaimers.js +217 -0
- package/dist/_internal/shared/content/published-values.d.ts +88 -0
- package/dist/_internal/shared/content/published-values.js +198 -0
- package/dist/_internal/shared/features/admin/integrations.d.ts +109 -0
- package/dist/_internal/shared/features/admin/integrations.js +253 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.d.ts +113 -0
- package/dist/_internal/shared/features/orders/dispute-reasons.js +181 -0
- package/dist/_internal/shared/features/orders/refund-copy.d.ts +1 -1
- package/dist/_internal/shared/features/orders/refund-copy.js +18 -1
- package/dist/_internal/shared/features/points/accepts.d.ts +36 -0
- package/dist/_internal/shared/features/points/accepts.js +43 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.d.ts +91 -0
- package/dist/_internal/shared/features/shipping/shared-purchase.js +108 -0
- package/dist/_internal/shared/features/site-settings/types.d.ts +11 -0
- package/dist/_internal/shared/fees/calculator.d.ts +33 -1
- package/dist/_internal/shared/fees/calculator.js +32 -2
- package/dist/client.d.ts +11 -0
- package/dist/client.js +30 -0
- package/dist/constants/api-endpoints.d.ts +42 -0
- package/dist/constants/api-endpoints.js +14 -0
- package/dist/constants/field-names.d.ts +1 -0
- package/dist/constants/field-names.js +5 -0
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/shipping.d.ts +45 -0
- package/dist/contracts/shipping.js +15 -0
- package/dist/features/about/components/AboutView.js +1 -1
- package/dist/features/account/components/BuyerAuctionsGuideView.js +4 -1
- package/dist/features/account/components/UserOrdersView.js +19 -33
- package/dist/features/admin/components/AdminCouponEditorView.js +17 -0
- package/dist/features/admin/components/AdminInvoicingView.d.ts +2 -0
- package/dist/features/admin/components/AdminInvoicingView.js +65 -0
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +18 -1
- package/dist/features/admin/components/AdminOrderEditorView.js +11 -2
- package/dist/features/admin/components/AdminOrdersGuideView.js +23 -2
- package/dist/features/admin/components/AdminOrdersView.js +67 -5
- package/dist/features/admin/components/OwnerQuickActions.js +24 -2
- package/dist/features/admin/constants/filter-tabs.d.ts +6 -0
- package/dist/features/admin/constants/filter-tabs.js +6 -0
- package/dist/features/admin/constants/site-settings-tabs.d.ts +1 -1
- package/dist/features/admin/hooks/useAdminListingData.js +16 -0
- package/dist/features/admin/schemas/admin-user-form.d.ts +2 -2
- package/dist/features/admin/schemas/firestore.d.ts +30 -0
- package/dist/features/admin/schemas/firestore.js +5 -0
- package/dist/features/audit-log/schemas/firestore.d.ts +30 -0
- package/dist/features/audit-log/schemas/firestore.js +15 -0
- package/dist/features/auth/permissions/constants.js +13 -0
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +13 -0
- package/dist/features/cart/components/CartPriceBreakdown.js +6 -2
- package/dist/features/cart/components/PointsTenderPicker.d.ts +61 -0
- package/dist/features/cart/components/PointsTenderPicker.js +15 -0
- package/dist/features/cart/components/StoreAddonsPicker.js +2 -1
- package/dist/features/cart/components/index.d.ts +2 -0
- package/dist/features/cart/components/index.js +1 -0
- package/dist/features/cart/repository/cart.repository.d.ts +19 -0
- package/dist/features/cart/repository/cart.repository.js +27 -0
- package/dist/features/cart/schemas/firestore.d.ts +92 -0
- package/dist/features/contact/email.d.ts +27 -10
- package/dist/features/contact/email.js +20 -3
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.d.ts +38 -0
- package/dist/features/dispute-reasons/repository/dispute-reasons.repository.js +80 -0
- package/dist/features/dispute-reasons/schemas/firestore.d.ts +64 -0
- package/dist/features/dispute-reasons/schemas/firestore.js +40 -0
- package/dist/features/faq/components/FAQAccordion.d.ts +13 -1
- package/dist/features/faq/components/FAQAccordion.js +29 -4
- package/dist/features/invoicing/schemas/firestore.d.ts +112 -0
- package/dist/features/invoicing/schemas/firestore.js +45 -0
- package/dist/features/invoicing/utils/financial-year.d.ts +43 -0
- package/dist/features/invoicing/utils/financial-year.js +53 -0
- package/dist/features/jobs/actions/enqueue-job.js +18 -1
- package/dist/features/jobs/repository/jobs.repository.d.ts +62 -1
- package/dist/features/jobs/repository/jobs.repository.js +84 -1
- package/dist/features/jobs/schemas/firestore.d.ts +80 -0
- package/dist/features/jobs/schemas/firestore.js +37 -0
- package/dist/features/lottery/schemas/zod.d.ts +6 -6
- package/dist/features/media/MediaImage.js +22 -1
- package/dist/features/media/upload/ImageUpload.js +1 -1
- package/dist/features/obligations/constants/policies.js +24 -1
- package/dist/features/orders/components/OrderPaymentSummary.js +10 -1
- package/dist/features/orders/components/OrderProvenanceCard.d.ts +8 -0
- package/dist/features/orders/components/OrderProvenanceCard.js +185 -0
- package/dist/features/orders/components/RaiseDisputeForm.d.ts +14 -0
- package/dist/features/orders/components/RaiseDisputeForm.js +111 -0
- package/dist/features/orders/components/RefundRequestView.js +19 -1
- package/dist/features/orders/components/index.d.ts +4 -0
- package/dist/features/orders/components/index.js +2 -0
- package/dist/features/orders/constants/order-lane-tabs.d.ts +69 -0
- package/dist/features/orders/constants/order-lane-tabs.js +88 -0
- package/dist/features/orders/repository/orders.repository.d.ts +57 -0
- package/dist/features/orders/repository/orders.repository.js +145 -0
- package/dist/features/orders/schemas/firestore.d.ts +196 -1
- package/dist/features/orders/schemas/index.d.ts +54 -6
- package/dist/features/orders/schemas/index.js +12 -0
- package/dist/features/orders/types/index.d.ts +26 -0
- package/dist/features/orders/utils/courier-block.d.ts +25 -0
- package/dist/features/orders/utils/courier-block.js +23 -0
- package/dist/features/payment-cases/schemas/firestore.d.ts +26 -1
- package/dist/features/payment-cases/schemas/firestore.js +1 -0
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
- package/dist/features/products/components/ProductDetailPageView.d.ts +17 -1
- package/dist/features/products/components/ProductDetailPageView.js +2 -2
- package/dist/features/products/schemas/product-features.validators.d.ts +10 -10
- package/dist/features/promotions/actions/coupon-stacking.d.ts +30 -3
- package/dist/features/promotions/actions/coupon-stacking.js +21 -2
- package/dist/features/promotions/components/CouponCard.js +13 -0
- package/dist/features/promotions/constants/coupon-help.d.ts +2 -2
- package/dist/features/promotions/constants/coupon-help.js +9 -1
- package/dist/features/promotions/schemas/firestore.d.ts +24 -0
- package/dist/features/promotions/schemas/firestore.js +4 -0
- package/dist/features/promotions/types/index.d.ts +19 -1
- package/dist/features/scams/components/ScamProfileView.js +2 -2
- package/dist/features/scams/components/ScamRegistryView.js +2 -2
- package/dist/features/search/action-index/tab-entries.js +1 -1
- package/dist/features/seller/actions/seller-actions.js +33 -3
- package/dist/features/seller/components/SellerOrdersView.js +129 -27
- package/dist/features/seller/hooks/useSellerListingData.js +25 -0
- package/dist/features/shipments/schemas/validation.d.ts +4 -4
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.d.ts +43 -0
- package/dist/features/shipping-boxes/repository/shipping-boxes.repository.js +90 -0
- package/dist/features/shipping-boxes/schemas/firestore.d.ts +82 -0
- package/dist/features/shipping-boxes/schemas/firestore.js +53 -0
- package/dist/features/store-extensions/schemas/report-create-form.d.ts +2 -2
- package/dist/features/store-extensions/schemas/shipping-config-form.d.ts +2 -2
- package/dist/features/stores/components/StoreOrdersGuideView.js +6 -1
- package/dist/features/stores/schemas/firestore.d.ts +71 -0
- package/dist/features/stores/types/index.d.ts +19 -0
- package/dist/features/support/schemas/index.d.ts +6 -6
- package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +14 -1
- package/dist/next/routing/route-map.d.ts +20 -0
- package/dist/next/routing/route-map.js +10 -0
- package/dist/providers/shipping-shiprocket/index.d.ts +27 -1
- package/dist/providers/shipping-shiprocket/index.js +84 -1
- package/dist/schemas/registry.d.ts +47 -18
- package/dist/schemas/sieve.d.ts +2 -2
- package/dist/server-entry.d.ts +2 -2
- package/dist/server-entry.js +8 -1
- package/dist/server.d.ts +10 -1
- package/dist/server.js +39 -1
- package/dist/styles.css +64 -80
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-dark.js +1 -0
- package/dist/tokens/themes/default-light.js +1 -0
- package/dist/tokens/themes/required.d.ts +1 -1
- package/dist/tokens/themes/required.js +1 -0
- package/dist/tokens/tokens.css +15 -0
- package/dist/ui/components/Disclaimer.d.ts +19 -0
- package/dist/ui/components/Disclaimer.js +74 -0
- package/dist/ui/components/tabs-overflow.js +64 -11
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +6 -0
- package/dist/ui/rich-text/RichText.style.css +48 -79
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +1831 -1822
package/dist/client.js
CHANGED
|
@@ -335,6 +335,10 @@ export { ProtectedRoute, ForgotPasswordView, LoginForm, RegisterForm, ResetPassw
|
|
|
335
335
|
export { useLogout, useLogin, useGoogleLogin, useLinkGoogleAccount, useRegister, useForgotPassword, useResetPassword, useVerifyEmail, useChangeEmail } from "./features/auth/index.js";
|
|
336
336
|
export { CartView, CartItemRow, CartGroupLineRow, CartSummary, CartPriceBreakdown, CartDrawer, CheckoutView, CheckoutSuccessView, CheckoutAddressStep, useGuestCart, useCartCount, useAddToCart, useCart, useGuestCartMerge, useCartQuery } from "./features/cart/index.js";
|
|
337
337
|
export { StoreAddonsPicker, hasAnyStoreAddon } from "./features/cart/index.js";
|
|
338
|
+
// D46/D47 — the cart's single "pay with my points" control. One per CART, not
|
|
339
|
+
// per store, unlike the add-ons picker above it: points are the buyer's balance
|
|
340
|
+
// rather than something bought from a seller.
|
|
341
|
+
export { PointsTenderPicker } from "./features/cart/index.js";
|
|
338
342
|
export { clientLineTotal } from "./features/cart/utils/line-total.js";
|
|
339
343
|
// `clearCartOps` / `removeCartOpsFor` are exported because the cart page has to
|
|
340
344
|
// drain the queue after a removal succeeds server-side — without them a cleared
|
|
@@ -416,6 +420,9 @@ export { couponDraftToPayload } from "./features/seller/schemas/coupon-form.js";
|
|
|
416
420
|
export { UserAccountHubView, UserOrdersView, UserBidsView, OrderDetailView, UserReturnsView, useNotifications } from "./features/account/index.js";
|
|
417
421
|
export { useOrders, useOrder, OrdersList } from "./features/orders/index.js";
|
|
418
422
|
export { OrderStatusTimeline } from "./features/orders/components/OrderStatusTimeline.js";
|
|
423
|
+
export { OrderProvenanceCard } from "./features/orders/components/OrderProvenanceCard.js";
|
|
424
|
+
// The buyer's dispute form: pick a kind, pick a reason, say what happened.
|
|
425
|
+
export { RaiseDisputeForm } from "./features/orders/components/RaiseDisputeForm.js";
|
|
419
426
|
/*
|
|
420
427
|
* The buyer's completion surface. Client entry only — it fetches and posts.
|
|
421
428
|
*/
|
|
@@ -634,6 +641,29 @@ export { REFUND_COPY } from "./_internal/shared/features/orders/refund-copy.js";
|
|
|
634
641
|
// See the module docstring for why the exempt set is "seller or carrier fault"
|
|
635
642
|
// rather than "serious reasons".
|
|
636
643
|
export { RETURN_REASON, FINAL_SALE_EXEMPT_REASONS, RETURN_REASON_LABEL, RETURN_REASON_GROUP_LABEL, isFinalSaleExempt, isReturnReason, selectableReturnReasons, } from "./_internal/shared/features/orders/return-reasons.js";
|
|
644
|
+
// Dispute KINDS and their gates. Exported for the same reason the return
|
|
645
|
+
// reasons above are: the buyer's form renders the labels and needs to show the
|
|
646
|
+
// date a `not_reached` dispute becomes filable from, and
|
|
647
|
+
// `@mohasinac/appkit/_internal/*` is NOT a subpath export — `_internal` is
|
|
648
|
+
// reachable only through a barrel.
|
|
649
|
+
export { DISPUTE_KIND, DISPUTE_KIND_LABEL, DISPUTE_GATE, DISPUTE_TRANSIT_WINDOW_DAYS, DISPUTE_NOT_REACHED_GRACE_DAYS, isDisputeKind, checkDisputeGate, resolveDisputeEtd, disputeNotReachedFilableFrom, } from "./_internal/shared/features/orders/dispute-reasons.js";
|
|
650
|
+
/*
|
|
651
|
+
* The integration switches. Exported from the CLIENT entry because the admin
|
|
652
|
+
* integrations page is a "use client" surface — it renders each row's label and
|
|
653
|
+
* `offConsequence` and needs `readIntegrationStates` to show the current
|
|
654
|
+
* position.
|
|
655
|
+
*
|
|
656
|
+
* 🛑 The SAME module is re-exported from `server.ts`, deliberately, because the
|
|
657
|
+
* route guards resolve their answer through `readIntegrationStates` too. One
|
|
658
|
+
* expression, two entries — which is the point: a hand-written copy of "is this
|
|
659
|
+
* integration on" in a guard is how the page and the enforcement drift apart,
|
|
660
|
+
* and that had already happened once inside the module itself (the payments OR
|
|
661
|
+
* across both gateways).
|
|
662
|
+
*
|
|
663
|
+
* Safe in a client bundle: the file's only import is `import type`, so its
|
|
664
|
+
* runtime graph is empty and it cannot reach firebase-admin.
|
|
665
|
+
*/
|
|
666
|
+
export { INTEGRATIONS, INTEGRATION_ORDER, readIntegrationStates, integrationPatch, allIntegrationsPatch, } from "./_internal/shared/features/admin/integrations.js";
|
|
637
667
|
// Buyer-facing return/refund request form and the window it is gated on.
|
|
638
668
|
// Exported from the CLIENT entry because the page that renders it is a
|
|
639
669
|
// "use client" route — importing it from the main entry there would drag the
|
|
@@ -150,6 +150,14 @@ export declare const ADMIN_ENDPOINTS: {
|
|
|
150
150
|
readonly PAYOUTS_EXPORT: "/api/admin/payouts/export";
|
|
151
151
|
readonly AUDIT_LOG: "/api/admin/audit-log";
|
|
152
152
|
readonly AUDIT_LOG_BY_ID: (id: string) => string;
|
|
153
|
+
/**
|
|
154
|
+
* Phase 7 — the GSTR-1 DRAFT export. Takes `?from=&to=` as YYYY-MM-DD and
|
|
155
|
+
* returns a CSV.
|
|
156
|
+
*
|
|
157
|
+
* 🛑 "draft" is in the filename for a reason: nothing in this codebase talks
|
|
158
|
+
* to the GST portal, and the file is the input to a human filing.
|
|
159
|
+
*/
|
|
160
|
+
readonly INVOICING_GSTR1: "/api/admin/invoicing/gstr1";
|
|
153
161
|
readonly PAYMENT_CASES: "/api/admin/payment-cases";
|
|
154
162
|
readonly PAYMENT_CASE_BY_ID: (id: string) => string;
|
|
155
163
|
readonly PROTECTION_CLAIMS: "/api/admin/protection-claims";
|
|
@@ -272,6 +280,12 @@ export declare const CART_ENDPOINTS: {
|
|
|
272
280
|
readonly SELECTION: "/api/cart/selection";
|
|
273
281
|
/** Per-store paid add-on selections — the source of truth for what's charged. */
|
|
274
282
|
readonly ADDONS: "/api/cart/addons";
|
|
283
|
+
/**
|
|
284
|
+
* Pay with points, on or off (D46/D47). A boolean and nothing else — the
|
|
285
|
+
* AMOUNT is derived server-side from the live balance and the 50% cap, which
|
|
286
|
+
* is why there is no `/api/cart/points/amount`.
|
|
287
|
+
*/
|
|
288
|
+
readonly POINTS: "/api/cart/points";
|
|
275
289
|
readonly COUPON: "/api/cart/coupon";
|
|
276
290
|
/**
|
|
277
291
|
* Add a buyer-assembled group selection as ONE line. Separate from `GET`'s
|
|
@@ -733,6 +747,14 @@ export declare const API_ENDPOINTS: {
|
|
|
733
747
|
readonly PAYOUTS_EXPORT: "/api/admin/payouts/export";
|
|
734
748
|
readonly AUDIT_LOG: "/api/admin/audit-log";
|
|
735
749
|
readonly AUDIT_LOG_BY_ID: (id: string) => string;
|
|
750
|
+
/**
|
|
751
|
+
* Phase 7 — the GSTR-1 DRAFT export. Takes `?from=&to=` as YYYY-MM-DD and
|
|
752
|
+
* returns a CSV.
|
|
753
|
+
*
|
|
754
|
+
* 🛑 "draft" is in the filename for a reason: nothing in this codebase talks
|
|
755
|
+
* to the GST portal, and the file is the input to a human filing.
|
|
756
|
+
*/
|
|
757
|
+
readonly INVOICING_GSTR1: "/api/admin/invoicing/gstr1";
|
|
736
758
|
readonly PAYMENT_CASES: "/api/admin/payment-cases";
|
|
737
759
|
readonly PAYMENT_CASE_BY_ID: (id: string) => string;
|
|
738
760
|
readonly PROTECTION_CLAIMS: "/api/admin/protection-claims";
|
|
@@ -855,6 +877,12 @@ export declare const API_ENDPOINTS: {
|
|
|
855
877
|
readonly SELECTION: "/api/cart/selection";
|
|
856
878
|
/** Per-store paid add-on selections — the source of truth for what's charged. */
|
|
857
879
|
readonly ADDONS: "/api/cart/addons";
|
|
880
|
+
/**
|
|
881
|
+
* Pay with points, on or off (D46/D47). A boolean and nothing else — the
|
|
882
|
+
* AMOUNT is derived server-side from the live balance and the 50% cap, which
|
|
883
|
+
* is why there is no `/api/cart/points/amount`.
|
|
884
|
+
*/
|
|
885
|
+
readonly POINTS: "/api/cart/points";
|
|
858
886
|
readonly COUPON: "/api/cart/coupon";
|
|
859
887
|
/**
|
|
860
888
|
* Add a buyer-assembled group selection as ONE line. Separate from `GET`'s
|
|
@@ -1281,6 +1309,14 @@ export declare const API_ROUTES: {
|
|
|
1281
1309
|
readonly PAYOUTS_EXPORT: "/api/admin/payouts/export";
|
|
1282
1310
|
readonly AUDIT_LOG: "/api/admin/audit-log";
|
|
1283
1311
|
readonly AUDIT_LOG_BY_ID: (id: string) => string;
|
|
1312
|
+
/**
|
|
1313
|
+
* Phase 7 — the GSTR-1 DRAFT export. Takes `?from=&to=` as YYYY-MM-DD and
|
|
1314
|
+
* returns a CSV.
|
|
1315
|
+
*
|
|
1316
|
+
* 🛑 "draft" is in the filename for a reason: nothing in this codebase talks
|
|
1317
|
+
* to the GST portal, and the file is the input to a human filing.
|
|
1318
|
+
*/
|
|
1319
|
+
readonly INVOICING_GSTR1: "/api/admin/invoicing/gstr1";
|
|
1284
1320
|
readonly PAYMENT_CASES: "/api/admin/payment-cases";
|
|
1285
1321
|
readonly PAYMENT_CASE_BY_ID: (id: string) => string;
|
|
1286
1322
|
readonly PROTECTION_CLAIMS: "/api/admin/protection-claims";
|
|
@@ -1403,6 +1439,12 @@ export declare const API_ROUTES: {
|
|
|
1403
1439
|
readonly SELECTION: "/api/cart/selection";
|
|
1404
1440
|
/** Per-store paid add-on selections — the source of truth for what's charged. */
|
|
1405
1441
|
readonly ADDONS: "/api/cart/addons";
|
|
1442
|
+
/**
|
|
1443
|
+
* Pay with points, on or off (D46/D47). A boolean and nothing else — the
|
|
1444
|
+
* AMOUNT is derived server-side from the live balance and the 50% cap, which
|
|
1445
|
+
* is why there is no `/api/cart/points/amount`.
|
|
1446
|
+
*/
|
|
1447
|
+
readonly POINTS: "/api/cart/points";
|
|
1406
1448
|
readonly COUPON: "/api/cart/coupon";
|
|
1407
1449
|
/**
|
|
1408
1450
|
* Add a buyer-assembled group selection as ONE line. Separate from `GET`'s
|
|
@@ -187,6 +187,14 @@ export const ADMIN_ENDPOINTS = {
|
|
|
187
187
|
PAYOUTS_EXPORT: "/api/admin/payouts/export",
|
|
188
188
|
AUDIT_LOG: "/api/admin/audit-log",
|
|
189
189
|
AUDIT_LOG_BY_ID: (id) => `/api/admin/audit-log/${id}`,
|
|
190
|
+
/**
|
|
191
|
+
* Phase 7 — the GSTR-1 DRAFT export. Takes `?from=&to=` as YYYY-MM-DD and
|
|
192
|
+
* returns a CSV.
|
|
193
|
+
*
|
|
194
|
+
* 🛑 "draft" is in the filename for a reason: nothing in this codebase talks
|
|
195
|
+
* to the GST portal, and the file is the input to a human filing.
|
|
196
|
+
*/
|
|
197
|
+
INVOICING_GSTR1: "/api/admin/invoicing/gstr1",
|
|
190
198
|
/*
|
|
191
199
|
* Payment protection. `payment-cases` is NOT under `maintenance/` — see the
|
|
192
200
|
* route-map entry for why: maintenance means "something broke, look when you
|
|
@@ -325,6 +333,12 @@ export const CART_ENDPOINTS = {
|
|
|
325
333
|
SELECTION: "/api/cart/selection",
|
|
326
334
|
/** Per-store paid add-on selections — the source of truth for what's charged. */
|
|
327
335
|
ADDONS: "/api/cart/addons",
|
|
336
|
+
/**
|
|
337
|
+
* Pay with points, on or off (D46/D47). A boolean and nothing else — the
|
|
338
|
+
* AMOUNT is derived server-side from the live balance and the 50% cap, which
|
|
339
|
+
* is why there is no `/api/cart/points/amount`.
|
|
340
|
+
*/
|
|
341
|
+
POINTS: "/api/cart/points",
|
|
328
342
|
COUPON: "/api/cart/coupon",
|
|
329
343
|
/**
|
|
330
344
|
* Add a buyer-assembled group selection as ONE line. Separate from `GET`'s
|
|
@@ -835,6 +835,7 @@ export declare const COUPON_FIELDS: {
|
|
|
835
835
|
readonly FIXED: "fixed";
|
|
836
836
|
readonly FREE_SHIPPING: "free_shipping";
|
|
837
837
|
readonly BUY_X_GET_Y: "buy_x_get_y";
|
|
838
|
+
readonly POINTS_EARN: "points_earn";
|
|
838
839
|
};
|
|
839
840
|
readonly SCOPE_VALUES: {
|
|
840
841
|
readonly ADMIN: "admin";
|
|
@@ -1003,6 +1003,11 @@ export const COUPON_FIELDS = {
|
|
|
1003
1003
|
FIXED: "fixed",
|
|
1004
1004
|
FREE_SHIPPING: "free_shipping",
|
|
1005
1005
|
BUY_X_GET_Y: "buy_x_get_y",
|
|
1006
|
+
// D51. 🛑 This file calls itself canonical and has been stale twice
|
|
1007
|
+
// (EVENT_FIELDS invented a "published" status, SCAMMER_FIELDS lost
|
|
1008
|
+
// "removed") — Root Cause #34. The authority is `CouponType` in
|
|
1009
|
+
// features/promotions/types; this mirror has to follow it.
|
|
1010
|
+
POINTS_EARN: "points_earn",
|
|
1006
1011
|
},
|
|
1007
1012
|
SCOPE_VALUES: {
|
|
1008
1013
|
ADMIN: "admin",
|
|
@@ -4,7 +4,7 @@ export type { EmailAttachment, EmailOptions, EmailResult, IEmailProvider, } from
|
|
|
4
4
|
export type { UploadOptions, StorageFile, IStorageProvider } from "./storage";
|
|
5
5
|
export type { PaymentOrder, PaymentCapture, Refund, Dispute, GatewayPaymentRecord, } from "./payment";
|
|
6
6
|
export { IPaymentProvider } from "./payment";
|
|
7
|
-
export type { ShippingAddress, CreateShipmentInput, Shipment, TrackingEvent, TrackingInfo, ServiceabilityResult, } from "./shipping";
|
|
7
|
+
export type { ShippingAddress, CreateShipmentInput, Shipment, TrackingEvent, TrackingInfo, ServiceabilityResult, WalletBalance, } from "./shipping";
|
|
8
8
|
export { IShippingProvider } from "./shipping";
|
|
9
9
|
export type { SearchOptions, SearchHit, SearchResult, SuggestOptions, ISearchProvider, } from "./search";
|
|
10
10
|
export type { ICacheProvider, QueueJob, IQueueProvider, EventHandler, IEventBus, } from "./infra";
|
|
@@ -50,6 +50,38 @@ export interface ServiceabilityResult {
|
|
|
50
50
|
rate: number;
|
|
51
51
|
}>;
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* A courier provider's prepaid balance.
|
|
55
|
+
*
|
|
56
|
+
* 🛑 THREE states, not two, and collapsing them is the whole hazard:
|
|
57
|
+
*
|
|
58
|
+
* - `{ known: false, supported: false }` — this provider has no wallet at all
|
|
59
|
+
* (manual shipping). Nothing to check, ever.
|
|
60
|
+
* - `{ known: false, supported: true }` — it HAS one and we could not read it
|
|
61
|
+
* right now (network, malformed payload, auth). **Treat as "attempt the
|
|
62
|
+
* booking"**: the attempt's own failure is the authority, and refusing on an
|
|
63
|
+
* unreadable balance would degrade every order on a transient blip.
|
|
64
|
+
* - `{ known: true, amount }` — a real figure.
|
|
65
|
+
*
|
|
66
|
+
* A balance of `0` is the LAST of those, and is a decision to skip. "I could
|
|
67
|
+
* not read it" is not "there is no money".
|
|
68
|
+
*
|
|
69
|
+
* 🛑 There is deliberately NO `creditLimit` field. Measured against the live
|
|
70
|
+
* Shiprocket API 2026-10-22: `GET /account/details/wallet-balance` returns
|
|
71
|
+
* `{ data: { balance_amount: string } }` and nothing else, and
|
|
72
|
+
* `/account/details` is a 404. So postpaid credit is not readable, and a field
|
|
73
|
+
* with no producer is the speculative-infra pattern this codebase refuses.
|
|
74
|
+
* When postpaid is granted, re-probe and add it then.
|
|
75
|
+
*/
|
|
76
|
+
export type WalletBalance = {
|
|
77
|
+
known: true;
|
|
78
|
+
amount: number;
|
|
79
|
+
currency?: string;
|
|
80
|
+
} | {
|
|
81
|
+
known: false;
|
|
82
|
+
supported: boolean;
|
|
83
|
+
reason?: string;
|
|
84
|
+
};
|
|
53
85
|
/**
|
|
54
86
|
* Shipping carrier adapter contract. An abstract base class rather than a
|
|
55
87
|
* plain interface so every provider (manual, and any future carrier
|
|
@@ -66,4 +98,17 @@ export declare abstract class IShippingProvider {
|
|
|
66
98
|
abstract cancelShipment(shipmentId: string): Promise<void>;
|
|
67
99
|
abstract checkServiceability(pincode: string, weight: number): Promise<ServiceabilityResult>;
|
|
68
100
|
abstract generateLabel(shipmentId: string): Promise<ArrayBuffer>;
|
|
101
|
+
/**
|
|
102
|
+
* The provider's prepaid balance, when it HAS one.
|
|
103
|
+
*
|
|
104
|
+
* 🛑 Deliberately NOT abstract. Manual shipping has no wallet — a seller
|
|
105
|
+
* posts the parcel and claims the cost back — so an abstract member would
|
|
106
|
+
* force every implementation to invent an answer. A non-abstract default is
|
|
107
|
+
* the established shape here for a capability a provider lacks (the dispute
|
|
108
|
+
* contract's `listDisputes() => []` is the precedent).
|
|
109
|
+
*
|
|
110
|
+
* The default says "I do not have one", which is TRUE for manual and is not
|
|
111
|
+
* the same statement as "I have one and it is empty".
|
|
112
|
+
*/
|
|
113
|
+
getWalletBalance(): Promise<WalletBalance>;
|
|
69
114
|
}
|
|
@@ -9,4 +9,19 @@
|
|
|
9
9
|
* Implemented by the manual provider (default) and its mock.
|
|
10
10
|
*/
|
|
11
11
|
export class IShippingProvider {
|
|
12
|
+
/**
|
|
13
|
+
* The provider's prepaid balance, when it HAS one.
|
|
14
|
+
*
|
|
15
|
+
* 🛑 Deliberately NOT abstract. Manual shipping has no wallet — a seller
|
|
16
|
+
* posts the parcel and claims the cost back — so an abstract member would
|
|
17
|
+
* force every implementation to invent an answer. A non-abstract default is
|
|
18
|
+
* the established shape here for a capability a provider lacks (the dispute
|
|
19
|
+
* contract's `listDisputes() => []` is the precedent).
|
|
20
|
+
*
|
|
21
|
+
* The default says "I do not have one", which is TRUE for manual and is not
|
|
22
|
+
* the same statement as "I have one and it is empty".
|
|
23
|
+
*/
|
|
24
|
+
async getWalletBalance() {
|
|
25
|
+
return { known: false, supported: false };
|
|
26
|
+
}
|
|
12
27
|
}
|
|
@@ -2,5 +2,5 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Anchor, Avatar, Badge, Card, Div, Heading, Row, Section, Span, Stack, Text, TextLink } from "../../../ui/index.js";
|
|
3
3
|
import { ROUTES } from "../../../constants/index.js";
|
|
4
4
|
export function AboutView({ labels = {}, howItems = [], valueItems = [], milestones = [], teamMembers = [], ctaBannerClass = "", renderCtaButtons, }) {
|
|
5
|
-
return (_jsxs(Div, { className: "-mx-4 md:-mx-6 lg:-mx-8 -mt-6 sm:-mt-8 lg:-mt-10", children: [_jsx(Section, { color: "inverse", tone: "accent-banner", padding: "y-4xl", children: _jsxs(Div, { paddingX: "x-page", className: "max-w-4xl mx-auto text-center", children: [_jsx(Heading, { color: "inverse", level: 1, variant: "none", className: "mb-6", mdSize: "5xl", size: "4xl", weight: "bold", children: labels.title }), _jsx(Text, { color: "inverse-muted", variant: "none", className: "max-w-2xl mx-auto", size: "xl", children: labels.subtitle })] }) }), _jsxs(
|
|
5
|
+
return (_jsxs(Div, { className: "-mx-4 md:-mx-6 lg:-mx-8 -mt-6 sm:-mt-8 lg:-mt-10", children: [_jsx(Section, { color: "inverse", tone: "accent-banner", padding: "y-4xl", children: _jsxs(Div, { paddingX: "x-page", className: "max-w-4xl mx-auto text-center", children: [_jsx(Heading, { color: "inverse", level: 1, variant: "none", className: "mb-6", mdSize: "5xl", size: "4xl", weight: "bold", children: labels.title }), _jsx(Text, { color: "inverse-muted", variant: "none", className: "max-w-2xl mx-auto", size: "xl", children: labels.subtitle })] }) }), _jsxs(Stack, { gap: "section", paddingX: "x-page", className: "max-w-5xl mx-auto", padding: "y-4xl", children: [_jsxs(Section, { className: "text-center max-w-3xl mx-auto", children: [_jsx(Heading, { level: 2, className: "mb-4", children: labels.missionTitle }), _jsx(Text, { size: "lg", variant: "secondary", className: "leading-relaxed", children: labels.missionText })] }), _jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "mb-12", align: "center", children: labels.howItWorksTitle }), _jsx(Div, { className: "grid md:grid-cols-3", gap: "6", children: howItems.map(({ title, text, icon, tone }) => (_jsxs(Card, { variant: `gradient-${tone ?? "indigo"}`, padding: "md", spacing: "sm", children: [_jsx(Div, { children: _jsx(Span, { size: "4xl", children: icon }) }), _jsx(Heading, { level: 3, color: "inverse", variant: "none", children: title }), _jsx(Text, { size: "sm", color: "inverse-muted", variant: "none", className: "leading-relaxed", children: text })] }, title))) })] }), _jsxs(Section, { children: [_jsx(Heading, { level: 2, className: labels.valuesSubtitle ? "mb-3" : "mb-12", align: "center", children: labels.valuesTitle }), labels.valuesSubtitle && (_jsx(Text, { size: "base", variant: "secondary", align: "center", className: "mb-12 max-w-2xl mx-auto leading-relaxed", children: labels.valuesSubtitle })), _jsx(Div, { className: "grid md:grid-cols-3", gap: "5", children: valueItems.map(({ title, text, icon, detail }) => (_jsxs(Stack, { gap: "3", surface: "default", padding: "lg", rounded: "xl", border: "default", children: [_jsx(Div, { children: _jsx(Span, { size: "3xl", children: icon }) }), _jsx(Heading, { level: 3, children: title }), _jsx(Text, { size: "sm", variant: "secondary", className: "leading-relaxed", children: text }), detail && (_jsx(Text, { size: "sm", color: "muted", className: "leading-relaxed", children: detail }))] }, title))) }), labels.valuesLinkLabel && (_jsx(Div, { className: "mt-8 text-center", children: _jsx(TextLink, { href: String(ROUTES.PUBLIC.ETHICS), size: "sm", children: labels.valuesLinkLabel }) }))] }), _jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "mb-10", align: "center", children: labels.milestonesTitle }), _jsx(Stack, { className: "relative border-l-2 border-primary/30 max-w-2xl mx-auto pl-[2rem]", gap: "xl", children: milestones.map(({ year, text }) => (_jsxs(Div, { className: "relative", children: [_jsx(Div, { className: "absolute -left-10 top-1 w-4 h-4 bg-primary border-2 border-white", rounded: "full" }), _jsx(Span, { size: "xs", weight: "bold", className: "text-primary tracking-wide", transform: "uppercase", children: year }), _jsx(Text, { className: "mt-1", children: text })] }, year))) })] }), teamMembers.length > 0 && (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "mb-2", align: "center", children: labels.teamTitle }), labels.teamSubtitle && (_jsx(Text, { size: "lg", variant: "secondary", align: "center", className: "mb-12 max-w-2xl mx-auto", children: labels.teamSubtitle })), _jsx(Div, { className: "grid md:grid-cols-3", gap: "6", children: teamMembers.map((member) => (_jsxs(Stack, { gap: "3", surface: "default", padding: "lg", rounded: "xl", border: "default", align: "center", className: "text-center", children: [_jsx(Avatar, { src: member.photoUrl, name: member.name, alt: member.name, size: "lg" }), _jsx(Heading, { level: 3, children: member.name }), _jsxs(Row, { gap: "xs", wrap: true, justify: "center", children: [_jsx(Span, { size: "xs", weight: "bold", className: "text-primary tracking-wide", transform: "uppercase", children: member.role }), member.isFounder && _jsx(Badge, { variant: "primary", size: "xs", children: "Founder" }), member.isDeveloper && _jsx(Badge, { variant: "secondary", size: "xs", children: "Developer" })] }), _jsx(Text, { size: "sm", variant: "secondary", className: "leading-relaxed", children: member.bio }), member.githubUrl && (_jsx(Anchor, { href: member.githubUrl, tone: "muted", size: "sm", underline: "hover", children: "GitHub \u2197" }))] }, member.name))) })] })), _jsxs(Section, { color: "inverse", tone: "accent-banner", className: `text-center ${ctaBannerClass}`, padding: "xl", rounded: "2xl", children: [_jsx(Heading, { color: "inverse", level: 2, variant: "none", className: "mb-8", size: "3xl", weight: "bold", children: labels.ctaTitle }), renderCtaButtons ? (renderCtaButtons()) : (_jsx(Row, { justify: "center", gap: "3", wrap: true, children: _jsxs(Span, { color: "inverse-muted", size: "sm", children: [labels.ctaSell, " \u00B7 ", labels.ctaShop] }) }))] })] })] }));
|
|
6
6
|
}
|
|
@@ -2,6 +2,9 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { Gavel, TrendingUp, Trophy, AlertTriangle, Package, XCircle, ShieldCheck } from "lucide-react";
|
|
3
3
|
import { Alert, Div, Heading, Li, Row, Section, Span, Stack, Text, Ul } from "../../../ui/index.js";
|
|
4
4
|
import { GC } from "../../_guide-cls.js";
|
|
5
|
+
import { resolvePublishedValues } from "../../../_internal/shared/content/published-values.js";
|
|
6
|
+
/* Phase 9 — one definition of the refund timeline. See the 🛑 at the call site. */
|
|
7
|
+
const { refundBusinessDaysMin: REFUND_DAYS_MIN, refundBusinessDaysMax: REFUND_DAYS_MAX } = resolvePublishedValues();
|
|
5
8
|
const SECTIONS = [
|
|
6
9
|
{
|
|
7
10
|
Icon: Gavel, title: "How Auctions Work",
|
|
@@ -25,7 +28,7 @@ const SECTIONS = [
|
|
|
25
28
|
},
|
|
26
29
|
{
|
|
27
30
|
Icon: XCircle, iconCls: "w-5 h-5 text-rose-500", title: "Pre-order Cancellations",
|
|
28
|
-
content: (_jsxs(_Fragment, { children: [_jsxs(Text, { className: `${GC.textMuted} mb-3`, children: ["To cancel a pre-order before the item is shipped, open a support ticket with category ", _jsx(Span, { weight: "bold", children: "Billing & Payment" }), " or ", _jsx(Span, { weight: "bold", children: "Order Issue" }), " and reference your order ID."] }),
|
|
31
|
+
content: (_jsxs(_Fragment, { children: [_jsxs(Text, { className: `${GC.textMuted} mb-3`, children: ["To cancel a pre-order before the item is shipped, open a support ticket with category ", _jsx(Span, { weight: "bold", children: "Billing & Payment" }), " or ", _jsx(Span, { weight: "bold", children: "Order Issue" }), " and reference your order ID."] }), _jsxs(Text, { className: GC.textMuted, children: ["After cancellation is accepted, refunds follow the standard timeline:", " ", REFUND_DAYS_MIN, "\u2013", REFUND_DAYS_MAX, " business days to your original payment method."] })] })),
|
|
29
32
|
},
|
|
30
33
|
{
|
|
31
34
|
Icon: ShieldCheck, iconCls: "w-5 h-5 text-emerald-500", title: "Bidding Safety Tips",
|
|
@@ -9,6 +9,7 @@ import { PaginatedSelect } from "../../../ui/components/PaginatedSelect.js";
|
|
|
9
9
|
import { DataListingView } from "../../admin/components/DataListingView.js";
|
|
10
10
|
import { OrderCard } from "../../orders/components/OrdersList.js";
|
|
11
11
|
import { useOrderScope } from "../../orders/components/OrderScopeTabs.js";
|
|
12
|
+
import { ORDER_LANE_TABS } from "../../orders/constants/order-lane-tabs.js";
|
|
12
13
|
import { useSearchParams } from "next/navigation.js";
|
|
13
14
|
const CANCELLABLE_STATUSES = new Set(["pending", "confirmed", "processing"]);
|
|
14
15
|
/*
|
|
@@ -34,40 +35,20 @@ const SORT_OPTIONS = [
|
|
|
34
35
|
{ value: sortBy("totalPrice", "DESC"), label: "Highest total" },
|
|
35
36
|
{ value: sortBy("totalPrice", "ASC"), label: "Lowest total" },
|
|
36
37
|
];
|
|
37
|
-
|
|
38
|
-
* Lane tabs
|
|
39
|
-
*
|
|
40
|
-
* `OrderDocument.orderType` value (or "" for All): a tab id that doesn't
|
|
41
|
-
* match a real stored value returns zero rows forever with no error anywhere
|
|
42
|
-
* (CLAUDE.md Root Cause #33).
|
|
38
|
+
/*
|
|
39
|
+
* Lane tabs now come from `features/orders/constants/order-lane-tabs`, shared
|
|
40
|
+
* with the seller's order list.
|
|
43
41
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
42
|
+
* They were defined here as a local array literal, which meant the seller's
|
|
43
|
+
* list could not have them without a tenth hand-written copy of one union
|
|
44
|
+
* (Root Cause #61). The shared version derives from a
|
|
45
|
+
* `Record<OrderType, string>`, so a sixth lane is a compile error rather than
|
|
46
|
+
* a tab that silently never appears — which is the bug this array already had
|
|
47
|
+
* once, shipping four tabs for five lanes.
|
|
48
|
+
*
|
|
49
|
+
* Every id-correctness note that lived here (byte-exact stored values, the
|
|
50
|
+
* unhyphenated `preorder`, and the in-memory `standard` filter) moved with it.
|
|
47
51
|
*/
|
|
48
|
-
const ORDER_LANE_TABS = [
|
|
49
|
-
{ id: "", label: "All" },
|
|
50
|
-
{ id: "standard", label: "Normal" },
|
|
51
|
-
{ id: "auction", label: "Auction wins" },
|
|
52
|
-
{ id: "offer", label: "Offer wins" },
|
|
53
|
-
/*
|
|
54
|
-
* 🛑 `"preorder"` WITHOUT A HYPHEN, and this is not a typo to tidy up.
|
|
55
|
-
*
|
|
56
|
-
* `OrderType` (`orders/utils/order-splitter.ts`) spells it `"preorder"`,
|
|
57
|
-
* while `ListingType` spells the same concept `"pre-order"` WITH a hyphen.
|
|
58
|
-
* Two unions, two spellings, and the tab must match the one actually stored
|
|
59
|
-
* on `OrderDocument.orderType` — a tab id matching no stored value returns
|
|
60
|
-
* zero rows forever with no error anywhere (Root Cause #33), which is
|
|
61
|
-
* exactly the failure this file's own comment above warns about.
|
|
62
|
-
*
|
|
63
|
-
* These two lanes existed in the union and had no tab, so pre-order and
|
|
64
|
-
* prize-draw orders were reachable only by landing on "All" and scrolling.
|
|
65
|
-
* Five lanes, four tabs — the eighth instance this session of a
|
|
66
|
-
* hand-written enumeration drifting from the union it filters.
|
|
67
|
-
*/
|
|
68
|
-
{ id: "preorder", label: "Pre-orders" },
|
|
69
|
-
{ id: "prize-draw", label: "Prize draws" },
|
|
70
|
-
];
|
|
71
52
|
/**
|
|
72
53
|
* Payment-method tabs — a THIRD axis, independent of the lane tabs above and
|
|
73
54
|
* the lifecycle scope beside them.
|
|
@@ -162,7 +143,12 @@ export function UserOrdersView({ onOrderClick }) {
|
|
|
162
143
|
// in flight" without those two questions fighting over one control.
|
|
163
144
|
buildExtraParams: () => orderScope.extraParams,
|
|
164
145
|
renderAboveContent: orderScope.renderAboveContent,
|
|
165
|
-
renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(Stack, { gap: "md", children: [_jsx(FilterChipGroup, { label: "Type",
|
|
146
|
+
renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(Stack, { gap: "md", children: [_jsx(FilterChipGroup, { label: "Type",
|
|
147
|
+
// No cast: `FilterChipGroup.tabs` is `readonly FilterChipGroupTab[]`,
|
|
148
|
+
// which the shared constant already satisfies. The `as unknown as`
|
|
149
|
+
// here was working around the local `as const` literal, not a real
|
|
150
|
+
// mismatch.
|
|
151
|
+
tabs: ORDER_LANE_TABS, value: pendingFilters.orderType ?? "", onChange: (id) => setPendingFilters((prev) => ({ ...prev, orderType: id })) }), _jsx(FilterChipGroup, { label: "Payment", tabs: PAYMENT_METHOD_TABS, value: pendingFilters.paymentMethod ?? "", onChange: (id) => setPendingFilters((prev) => ({ ...prev, paymentMethod: id })) }), _jsx(Div, { children: _jsx(PaginatedSelect, { value: pendingFilters.status || null, onChange: (v) => setPendingFilters((p) => ({ ...p, status: v ?? "" })), options: STATUS_OPTIONS, placeholder: "All statuses", ariaLabel: "Filter by order status" }) })] })),
|
|
166
152
|
renderCards: (rows, _view, _selection, isLoading) => {
|
|
167
153
|
if (isLoading) {
|
|
168
154
|
return (_jsx(Stack, { gap: "md", children: Array.from({ length: 3 }).map((_, i) => (_jsx(Div, { className: "h-24 animate-pulse border border-[var(--appkit-color-border)]", rounded: "xl" }, i))) }));
|
|
@@ -22,11 +22,28 @@ const __P = {
|
|
|
22
22
|
const __O = {
|
|
23
23
|
yAuto: "overflow-y-auto",
|
|
24
24
|
};
|
|
25
|
+
/*
|
|
26
|
+
* 🛑 Not derived from `COUPON_TYPE_LABELS` on purpose, and the reason is the
|
|
27
|
+
* opposite of what the duplication framework usually says.
|
|
28
|
+
*
|
|
29
|
+
* `points_earn` is OFFERED here, so an admin can create a points offer — but
|
|
30
|
+
* the editor's discount fields (`discount.value`, `maxDiscount`,
|
|
31
|
+
* `minPurchase`) are meaningless for it, and it carries `pointsPercent`
|
|
32
|
+
* instead. Deriving the list would silently add the option the moment the
|
|
33
|
+
* union grew, which is how `AdminEventsView` ended up offering `contest`,
|
|
34
|
+
* `giveaway` and `flash-sale` — three values `EventType` never had, each
|
|
35
|
+
* matching zero rows forever (Root Cause #72).
|
|
36
|
+
*
|
|
37
|
+
* So the list is explicit and the entry is deliberate.
|
|
38
|
+
* `audit-filter-tab-enums` covers the chip row, which is the surface where
|
|
39
|
+
* coverage actually matters.
|
|
40
|
+
*/
|
|
25
41
|
const TYPE_OPTIONS = [
|
|
26
42
|
{ label: "Percentage Discount", value: "percentage" },
|
|
27
43
|
{ label: "Fixed Amount Discount", value: "fixed" },
|
|
28
44
|
{ label: "Free Shipping", value: "free_shipping" },
|
|
29
45
|
{ label: "Buy X Get Y", value: "buy_x_get_y" },
|
|
46
|
+
{ label: "Points Back (awards points, no discount)", value: "points_earn" },
|
|
30
47
|
];
|
|
31
48
|
// --- Helpers -----------------------------------------------------------------
|
|
32
49
|
function toCouponCode(str) {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Button, Card, Disclaimer, Div, Heading, Row, Stack, Text } from "../../../ui/index.js";
|
|
5
|
+
import { FieldInput } from "../../../ui/forms/FieldInput.js";
|
|
6
|
+
import { Icon } from "../../../ui/components/Icon.js";
|
|
7
|
+
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints.js";
|
|
8
|
+
/**
|
|
9
|
+
* Admin → Finance → Invoicing: the GSTR-1 draft export (Phase 7d).
|
|
10
|
+
*
|
|
11
|
+
* ## 🛑 Why this page exists at all
|
|
12
|
+
*
|
|
13
|
+
* The export is an API route, and an API route with no surface is a dead end —
|
|
14
|
+
* reachable only by someone who already knows the URL, which is Root Cause
|
|
15
|
+
* #56's shape (16 of 70 listing views had no way to open a row). The person
|
|
16
|
+
* who needs this is an accountant at quarter end, and they will not type a
|
|
17
|
+
* query string.
|
|
18
|
+
*
|
|
19
|
+
* ## 🛑 It downloads; it does not file
|
|
20
|
+
*
|
|
21
|
+
* Nothing here talks to the GST portal — there is no webhook facility in
|
|
22
|
+
* existence and no GSP contract. The copy says "draft" everywhere it can,
|
|
23
|
+
* because a page that implied a return had been FILED when it had not is the
|
|
24
|
+
* most consequential thing this feature could get wrong.
|
|
25
|
+
*/
|
|
26
|
+
/** Indian FY quarters, which is the unit a GSTR-1 is filed in. */
|
|
27
|
+
const QUARTERS = [
|
|
28
|
+
{ label: "Q1 — Apr to Jun", fromMonth: "04-01", toMonth: "06-30" },
|
|
29
|
+
{ label: "Q2 — Jul to Sep", fromMonth: "07-01", toMonth: "09-30" },
|
|
30
|
+
{ label: "Q3 — Oct to Dec", fromMonth: "10-01", toMonth: "12-31" },
|
|
31
|
+
/*
|
|
32
|
+
* 🛑 Q4 SPANS A CALENDAR YEAR BOUNDARY. Jan–Mar of FY 26-27 is calendar
|
|
33
|
+
* 2027, not 2026 — the same off-by-one the `financialYearLabel` helper
|
|
34
|
+
* exists to contain, surfacing here because a quarter picker has to know it
|
|
35
|
+
* too. `yearOffset` is what carries it; dropping it would export the wrong
|
|
36
|
+
* three months with no visible error.
|
|
37
|
+
*/
|
|
38
|
+
{ label: "Q4 — Jan to Mar", fromMonth: "01-01", toMonth: "03-31", yearOffset: 1 },
|
|
39
|
+
];
|
|
40
|
+
function defaultFyStartYear() {
|
|
41
|
+
const now = new Date();
|
|
42
|
+
// Zero-based month: April is 3. Jan–Mar belongs to the FY that started last
|
|
43
|
+
// calendar year.
|
|
44
|
+
return now.getMonth() >= 3 ? now.getFullYear() : now.getFullYear() - 1;
|
|
45
|
+
}
|
|
46
|
+
export function AdminInvoicingView() {
|
|
47
|
+
const [fyStart, setFyStart] = useState(String(defaultFyStartYear()));
|
|
48
|
+
const [from, setFrom] = useState("");
|
|
49
|
+
const [to, setTo] = useState("");
|
|
50
|
+
const applyQuarter = (q) => {
|
|
51
|
+
const start = Number(fyStart);
|
|
52
|
+
if (!Number.isFinite(start))
|
|
53
|
+
return;
|
|
54
|
+
const offset = "yearOffset" in q ? q.yearOffset : 0;
|
|
55
|
+
setFrom(`${start + offset}-${q.fromMonth}`);
|
|
56
|
+
setTo(`${start + offset}-${q.toMonth}`);
|
|
57
|
+
};
|
|
58
|
+
const href = from && to
|
|
59
|
+
? `${ADMIN_ENDPOINTS.INVOICING_GSTR1}?from=${from}&to=${to}`
|
|
60
|
+
: undefined;
|
|
61
|
+
return (_jsxs(Stack, { gap: "lg", children: [_jsxs(Div, { children: [_jsx(Heading, { level: 1, children: "Invoicing" }), _jsx(Text, { color: "muted", size: "sm", children: "Export the invoice and credit-note register for a period, as a draft for your accountant." })] }), _jsx(Card, { padding: "md", children: _jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 2, children: "GSTR-1 draft" }), _jsx(Disclaimer, { id: "accounting-output" }), _jsx(Row, { gap: "sm", wrap: true, children: _jsx(Div, { className: "w-40", children: _jsx(FieldInput, { name: "fyStart", label: "FY starting", value: fyStart, onChange: setFyStart, hint: "e.g. 2026 for FY 26-27" }) }) }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Quarter" }), _jsx(Row, { gap: "sm", wrap: true, children: QUARTERS.map((q) => (_jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => applyQuarter(q), children: q.label }, q.label))) })] }), _jsxs(Row, { gap: "sm", wrap: true, children: [_jsx(Div, { className: "w-48", children: _jsx(FieldInput, { name: "from", label: "From", value: from, onChange: setFrom }) }), _jsx(Div, { className: "w-48", children: _jsx(FieldInput, { name: "to", label: "To", value: to, onChange: setTo }) })] }), _jsxs(Row, { gap: "sm", align: "center", children: [_jsxs(Button, { type: "button", variant: "primary", disabled: !href, onClick: () => {
|
|
62
|
+
if (href)
|
|
63
|
+
window.location.href = href;
|
|
64
|
+
}, children: [_jsx(Icon, { name: "download", size: "sm" }), "Download draft CSV"] }), !href && (_jsx(Text, { color: "muted", size: "xs", children: "Pick a quarter, or enter both dates as YYYY-MM-DD." }))] }), _jsx(Text, { color: "muted", size: "xs", children: "Credit notes appear as negative rows, so the TOTAL row is net of refunds. Any paid order in the window that carries no invoice number is listed at the bottom of the file as a warning \u2014 those are not included in the totals and need looking at." })] }) })] }));
|
|
65
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type OrderAddonBadgesOrder } from "../../orders/components/OrderAddonBadges";
|
|
2
|
+
import type { OrderSourceContext } from "../../orders/schemas/firestore";
|
|
2
3
|
import React from "react";
|
|
3
4
|
export interface AdminOrderItemRow {
|
|
4
5
|
productId: string;
|
|
@@ -7,6 +8,10 @@ export interface AdminOrderItemRow {
|
|
|
7
8
|
quantity: number;
|
|
8
9
|
unitPrice: number;
|
|
9
10
|
totalPrice: number;
|
|
11
|
+
groupSlug?: string;
|
|
12
|
+
groupTitle?: string;
|
|
13
|
+
bundleCategorySlug?: string;
|
|
14
|
+
bundleProductIds?: string[];
|
|
10
15
|
}
|
|
11
16
|
export interface AdminOrderEditorViewProps {
|
|
12
17
|
open: boolean;
|
|
@@ -36,5 +41,17 @@ export interface AdminOrderEditorViewProps {
|
|
|
36
41
|
* coupon is what an admin needs when reconciling a discounted order.
|
|
37
42
|
*/
|
|
38
43
|
addons?: OrderAddonBadgesOrder;
|
|
44
|
+
/**
|
|
45
|
+
* How the buyer earned this price — a won auction, a buyout, an agreed
|
|
46
|
+
* offer, a pre-order deposit, prize-draw entries.
|
|
47
|
+
*
|
|
48
|
+
* Support is the surface that needs this most: a buyer disputing "I agreed
|
|
49
|
+
* ₹X" is otherwise unanswerable from the admin side, because the negotiated
|
|
50
|
+
* amount lives only in `sourceContext` and nothing rendered it anywhere.
|
|
51
|
+
* `GET /api/admin/orders/[id]` already returns it via `maskedOrder`.
|
|
52
|
+
*/
|
|
53
|
+
sourceContext?: OrderSourceContext;
|
|
54
|
+
/** For the provenance card's money formatting; falls back to the default. */
|
|
55
|
+
currency?: string;
|
|
39
56
|
}
|
|
40
|
-
export declare function AdminOrderEditorView({ open, onClose, orderId, orderLabel, currentStatus, items, paymentProofUrl, paymentTransactionId, paymentMethod, paymentStatus, displayedUpiId, buyerReportedUpiId, paymentUpiMismatch, buyerMarkedPaid, buyerFraudAgreementAccepted, paymentReviewOutcome, addons, }: AdminOrderEditorViewProps): React.JSX.Element;
|
|
57
|
+
export declare function AdminOrderEditorView({ open, onClose, orderId, orderLabel, currentStatus, items, sourceContext, currency, paymentProofUrl, paymentTransactionId, paymentMethod, paymentStatus, displayedUpiId, buyerReportedUpiId, paymentUpiMismatch, buyerMarkedPaid, buyerFraudAgreementAccepted, paymentReviewOutcome, addons, }: AdminOrderEditorViewProps): React.JSX.Element;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { OrderAddonBadges } from "../../orders/components/OrderAddonBadges.js";
|
|
4
|
+
import { OrderProvenanceCard } from "../../orders/components/OrderProvenanceCard.js";
|
|
5
|
+
import { groupOrderItemsByLine } from "../../orders/utils/bundle-grouping.js";
|
|
4
6
|
import { isManualPaymentMethod } from "../../orders/constants/payment-window.js";
|
|
5
7
|
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
6
8
|
import React, { useState } from "react";
|
|
@@ -18,6 +20,13 @@ import { useFormShellState, FormShellContext } from "../../../ui/forms/index.js"
|
|
|
18
20
|
import { applyZodIssues } from "../../../ui/forms/apply-zod-issues.js";
|
|
19
21
|
import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary.js";
|
|
20
22
|
import { ValidationError } from "../../../errors/validation-error.js";
|
|
23
|
+
/**
|
|
24
|
+
* One item row. Extracted so the single and grouped render paths share exactly
|
|
25
|
+
* one piece of markup rather than two that can drift.
|
|
26
|
+
*/
|
|
27
|
+
function adminOrderItemRow(item, key) {
|
|
28
|
+
return (_jsxs(Div, { layout: "flex", align: "center", gap: "3", padding: "sm", children: [_jsx(Div, { className: "h-10 w-10 shrink-0", rounded: "md", overflow: "hidden", children: _jsx(MediaImage, { src: item.image, alt: item.title, size: "thumbnail" }) }), _jsxs(Div, { className: "min-w-0 flex-1", children: [_jsx(Text, { size: "sm", className: "truncate", weight: "medium", children: item.title }), _jsxs(Text, { size: "xs", color: "muted", children: ["Qty: ", item.quantity, " \u00D7 ", toCurrency(item.unitPrice)] })] }), _jsx(Text, { size: "sm", className: "shrink-0", weight: "semibold", children: toCurrency(item.totalPrice) })] }, key));
|
|
29
|
+
}
|
|
21
30
|
const STATUS_OPTIONS = [
|
|
22
31
|
{ label: "Pending", value: "pending" },
|
|
23
32
|
{ label: "Processing", value: "processing" },
|
|
@@ -37,7 +46,7 @@ const CARRIER_OPTIONS = [
|
|
|
37
46
|
{ label: "Other", value: "Other" },
|
|
38
47
|
];
|
|
39
48
|
// --- Component ---------------------------------------------------------------
|
|
40
|
-
export function AdminOrderEditorView({ open, onClose, orderId, orderLabel, currentStatus, items, paymentProofUrl, paymentTransactionId, paymentMethod, paymentStatus, displayedUpiId, buyerReportedUpiId, paymentUpiMismatch, buyerMarkedPaid, buyerFraudAgreementAccepted, paymentReviewOutcome, addons, }) {
|
|
49
|
+
export function AdminOrderEditorView({ open, onClose, orderId, orderLabel, currentStatus, items, sourceContext, currency, paymentProofUrl, paymentTransactionId, paymentMethod, paymentStatus, displayedUpiId, buyerReportedUpiId, paymentUpiMismatch, buyerMarkedPaid, buyerFraudAgreementAccepted, paymentReviewOutcome, addons, }) {
|
|
41
50
|
const queryClient = useQueryClient();
|
|
42
51
|
const { showToast } = useToast();
|
|
43
52
|
const [draft, setDraft] = React.useState({
|
|
@@ -207,7 +216,7 @@ export function AdminOrderEditorView({ open, onClose, orderId, orderLabel, curre
|
|
|
207
216
|
setIsRejectingFraud(false);
|
|
208
217
|
}
|
|
209
218
|
};
|
|
210
|
-
return (_jsx(SideDrawer, { isOpen: open, onClose: onClose, title: orderLabel ? `Order: ${orderLabel}` : "Update Order", children: _jsx(FormShellContext.Provider, { value: form.shellCtx, children: _jsxs(Stack, { gap: "md", padding: "md", children: [_jsx(FormErrorSummary, {}), addons && _jsx(OrderAddonBadges, { order: addons, variant: "detail" }), items && items.length > 0 && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Label, { size: "sm", weight: "medium", color: "primary", children: ["Items (", items.length, ")"] }), _jsx(Div, { className: "divide-y divide-[var(--appkit-color-border)] border border-[var(--appkit-color-border)]", rounded: "lg", children: items.map((
|
|
219
|
+
return (_jsx(SideDrawer, { isOpen: open, onClose: onClose, title: orderLabel ? `Order: ${orderLabel}` : "Update Order", children: _jsx(FormShellContext.Provider, { value: form.shellCtx, children: _jsxs(Stack, { gap: "md", padding: "md", children: [_jsx(FormErrorSummary, {}), addons && _jsx(OrderAddonBadges, { order: addons, variant: "detail" }), _jsx(OrderProvenanceCard, { sourceContext: sourceContext, currency: currency }), items && items.length > 0 && (_jsxs(Stack, { gap: "xs", children: [_jsxs(Label, { size: "sm", weight: "medium", color: "primary", children: ["Items (", items.length, ")"] }), _jsx(Div, { className: "divide-y divide-[var(--appkit-color-border)] border border-[var(--appkit-color-border)]", rounded: "lg", children: groupOrderItemsByLine(items).map((group, gi) => group.kind === "single" ? (adminOrderItemRow(group.item, `s-${group.index}`)) : (_jsxs(Div, { children: [_jsxs(Div, { layout: "flex", align: "center", gap: "2", padding: "x-sm", surface: "muted", children: [_jsx(Text, { size: "xs", weight: "semibold", children: group.groupTitle ?? "Grouped purchase" }), _jsx(Text, { size: "xs", color: "muted", children: `${group.memberCount} ${group.memberCount === 1 ? "item" : "items"} · one line` })] }), _jsx(Div, { className: "pl-4", children: group.items.map(({ item, index }) => adminOrderItemRow(item, `m-${index}`)) })] }, `g-${gi}`))) })] })), _jsx(SectionForm, { sections: sections, values: draft, onChange: (partial) => setDraft((d) => ({ ...d, ...partial })), onSubmit: () => {
|
|
211
220
|
// SectionForm surfaces errors and then submits regardless, so the
|
|
212
221
|
// guard is here.
|
|
213
222
|
form.clearErrors();
|