@mohasinac/appkit 2.7.49 → 2.7.52
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/client/features/layout/SidebarCollapseToggle.d.ts +19 -0
- package/dist/_internal/client/features/layout/SidebarCollapseToggle.js +15 -0
- package/dist/_internal/client/features/layout/index.d.ts +2 -0
- package/dist/_internal/client/features/layout/index.js +1 -0
- package/dist/_internal/server/features/checkout/actions.js +25 -2
- package/dist/_internal/server/features/promotions/actions.js +3 -1
- package/dist/_internal/server/jobs/core/__tests__/couponExpiry.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/couponExpiry.test.js +65 -0
- package/dist/_internal/server/jobs/core/__tests__/listingProcessor.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/listingProcessor.test.js +163 -0
- package/dist/_internal/server/jobs/core/__tests__/mediaTmpCleanup.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/mediaTmpCleanup.test.js +115 -0
- package/dist/_internal/server/jobs/core/__tests__/pendingOrderTimeout.test.d.ts +1 -0
- package/dist/_internal/server/jobs/core/__tests__/pendingOrderTimeout.test.js +96 -0
- package/dist/_internal/shared/actions/action-registry.js +149 -0
- package/dist/client.d.ts +45 -6
- package/dist/client.js +27 -4
- package/dist/constants/api-endpoints.d.ts +42 -0
- package/dist/constants/api-endpoints.js +14 -0
- package/dist/features/_guide-cls.d.ts +13 -0
- package/dist/features/_guide-cls.js +14 -0
- package/dist/features/about/components/HelpPageView.js +29 -26
- package/dist/features/account/components/BuyerAccountGuideView.d.ts +1 -0
- package/dist/features/account/components/BuyerAccountGuideView.js +39 -0
- package/dist/features/account/components/BuyerAuctionsGuideView.d.ts +1 -0
- package/dist/features/account/components/BuyerAuctionsGuideView.js +38 -0
- package/dist/features/account/components/BuyerOrdersGuideView.d.ts +1 -0
- package/dist/features/account/components/BuyerOrdersGuideView.js +48 -0
- package/dist/features/account/components/BuyerShoppingGuideView.d.ts +1 -0
- package/dist/features/account/components/BuyerShoppingGuideView.js +38 -0
- package/dist/features/account/components/UserSidebar.js +2 -1
- package/dist/features/admin/components/AdminAnalyticsGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminAnalyticsGuideView.js +24 -0
- package/dist/features/admin/components/AdminBlogEditorView.js +102 -75
- package/dist/features/admin/components/AdminBundleEditorView.js +20 -14
- package/dist/features/admin/components/AdminBundlesView.d.ts +1 -3
- package/dist/features/admin/components/AdminBundlesView.js +173 -52
- package/dist/features/admin/components/AdminCatalogGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminCatalogGuideView.js +28 -0
- package/dist/features/admin/components/AdminContentGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminContentGuideView.js +36 -0
- package/dist/features/admin/components/AdminCouponEditorView.js +1 -1
- package/dist/features/admin/components/AdminGuideHubView.d.ts +5 -0
- package/dist/features/admin/components/AdminGuideHubView.js +79 -0
- package/dist/features/admin/components/AdminOrdersGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminOrdersGuideView.js +44 -0
- package/dist/features/admin/components/AdminProductsView.js +8 -3
- package/dist/features/admin/components/AdminSidebar.js +2 -1
- package/dist/features/admin/components/AdminSiteConfigGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminSiteConfigGuideView.js +21 -0
- package/dist/features/admin/components/AdminStoresGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminStoresGuideView.js +32 -0
- package/dist/features/admin/components/AdminTeamGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminTeamGuideView.js +33 -0
- package/dist/features/admin/components/AdminTrustGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminTrustGuideView.js +40 -0
- package/dist/features/admin/components/AdminUsersGuideView.d.ts +1 -0
- package/dist/features/admin/components/AdminUsersGuideView.js +38 -0
- package/dist/features/auth/repository/session.repository.js +16 -1
- package/dist/features/cart/hooks/useAddToCart.d.ts +2 -0
- package/dist/features/cart/hooks/useAddToCart.js +2 -0
- package/dist/features/cart/hooks/useGuestCart.d.ts +2 -0
- package/dist/features/cart/utils/guest-cart.d.ts +7 -0
- package/dist/features/cart/utils/pending-ops.d.ts +6 -0
- package/dist/features/categories/components/CategoryBundlesListing.js +3 -25
- package/dist/features/categories/components/CategoryProductsListing.js +6 -10
- package/dist/features/categories/components/index.d.ts +0 -2
- package/dist/features/categories/components/index.js +0 -1
- package/dist/features/categories/schemas/firestore.d.ts +9 -0
- package/dist/features/events/components/AdminEventEditorView.js +223 -269
- package/dist/features/events/components/EventRaffleWinnerView.d.ts +9 -1
- package/dist/features/events/components/EventRaffleWinnerView.js +3 -3
- package/dist/features/events/components/SpinWheelView.js +3 -3
- package/dist/features/grouped/repository/grouped-listings.repository.d.ts +9 -0
- package/dist/features/grouped/repository/grouped-listings.repository.js +12 -0
- package/dist/features/layout/BottomNavLayout.d.ts +5 -0
- package/dist/features/layout/BottomNavLayout.js +21 -0
- package/dist/features/layout/TitleBar.js +7 -1
- package/dist/features/layout/TitleBarLayout.d.ts +8 -2
- package/dist/features/layout/TitleBarLayout.js +11 -7
- package/dist/features/media/upload/MediaUploadField.js +1 -1
- package/dist/features/orders/schemas/index.d.ts +2 -2
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +12 -6
- package/dist/features/products/components/AuctionsIndexListing.js +3 -1
- package/dist/features/products/components/MarketplaceBundleCard.d.ts +21 -0
- package/dist/features/products/components/MarketplaceBundleCard.js +56 -0
- package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
- package/dist/features/products/components/PrizeDrawEntryActions.d.ts +3 -1
- package/dist/features/products/components/PrizeDrawEntryActions.js +8 -12
- package/dist/features/products/components/ProductDetailActions.d.ts +5 -1
- package/dist/features/products/components/ProductDetailActions.js +3 -1
- package/dist/features/products/components/ProductDetailPageView.d.ts +2 -0
- package/dist/features/products/components/ProductDetailPageView.js +4 -0
- package/dist/features/products/components/ProductGrid.js +3 -3
- package/dist/features/products/components/ProductsIndexListing.js +18 -9
- package/dist/features/products/components/index.d.ts +2 -4
- package/dist/features/products/components/index.js +1 -2
- package/dist/features/promotions/components/CouponCard.d.ts +11 -1
- package/dist/features/promotions/components/CouponCard.js +36 -2
- package/dist/features/promotions/repository/claimed-coupons.repository.d.ts +27 -0
- package/dist/features/promotions/repository/claimed-coupons.repository.js +115 -0
- package/dist/features/promotions/schemas/firestore.d.ts +34 -0
- package/dist/features/promotions/schemas/firestore.js +14 -1
- package/dist/features/reviews/components/index.d.ts +0 -2
- package/dist/features/reviews/components/index.js +0 -1
- package/dist/features/seller/components/BrandInlineSelect.js +23 -3
- package/dist/features/seller/components/CategoryInlineSelect.js +20 -3
- package/dist/features/seller/components/SellerAddressesView.js +3 -2
- package/dist/features/seller/components/SellerAnalyticsAlertsView.d.ts +6 -0
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +124 -0
- package/dist/features/seller/components/SellerAnalyticsView.d.ts +2 -0
- package/dist/features/seller/components/SellerAnalyticsView.js +17 -9
- package/dist/features/seller/components/SellerBidsView.js +33 -3
- package/dist/features/seller/components/SellerBundlesView.d.ts +5 -0
- package/dist/features/seller/components/SellerBundlesView.js +104 -0
- package/dist/features/seller/components/SellerClassifiedView.d.ts +5 -0
- package/dist/features/seller/components/SellerClassifiedView.js +113 -0
- package/dist/features/seller/components/SellerDashboardView.js +19 -7
- package/dist/features/seller/components/SellerDigitalCodesView.d.ts +5 -0
- package/dist/features/seller/components/SellerDigitalCodesView.js +115 -0
- package/dist/features/seller/components/SellerGoogleReviewsView.d.ts +14 -0
- package/dist/features/seller/components/SellerGoogleReviewsView.js +95 -0
- package/dist/features/seller/components/SellerGroupedListingsView.d.ts +6 -0
- package/dist/features/seller/components/SellerGroupedListingsView.js +112 -0
- package/dist/features/seller/components/SellerLiveView.d.ts +5 -0
- package/dist/features/seller/components/SellerLiveView.js +113 -0
- package/dist/features/seller/components/SellerOrdersView.js +53 -2
- package/dist/features/seller/components/SellerPayoutMethodsView.d.ts +7 -0
- package/dist/features/seller/components/SellerPayoutMethodsView.js +120 -0
- package/dist/features/seller/components/SellerPayoutSettingsView.js +50 -12
- package/dist/features/seller/components/SellerProductShell.d.ts +3 -1
- package/dist/features/seller/components/SellerProductShell.js +35 -11
- package/dist/features/seller/components/SellerProductsCards.d.ts +19 -0
- package/dist/features/seller/components/SellerProductsCards.js +19 -0
- package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +14 -0
- package/dist/features/seller/components/SellerProductsFilterDrawer.js +22 -0
- package/dist/features/seller/components/SellerProductsView.d.ts +3 -1
- package/dist/features/seller/components/SellerProductsView.js +92 -49
- package/dist/features/seller/components/SellerReviewsView.js +67 -4
- package/dist/features/seller/components/SellerShippingConfigsView.d.ts +7 -0
- package/dist/features/seller/components/SellerShippingConfigsView.js +149 -0
- package/dist/features/seller/components/SellerShippingView.js +37 -10
- package/dist/features/seller/components/SellerSidebar.js +2 -1
- package/dist/features/seller/components/SellerStoreCategoriesView.d.ts +9 -0
- package/dist/features/seller/components/SellerStoreCategoriesView.js +122 -0
- package/dist/features/seller/components/SellerStorefrontView.d.ts +0 -7
- package/dist/features/seller/components/SellerStorefrontView.js +26 -29
- package/dist/features/seller/components/SellerTemplatesView.d.ts +10 -0
- package/dist/features/seller/components/SellerTemplatesView.js +265 -0
- package/dist/features/seller/components/index.d.ts +26 -0
- package/dist/features/seller/components/index.js +13 -0
- package/dist/features/seller/components/seller-products-styles.d.ts +7 -0
- package/dist/features/seller/components/seller-products-styles.js +14 -0
- package/dist/features/shell/FormShell.d.ts +7 -1
- package/dist/features/shell/FormShell.js +5 -2
- package/dist/features/store-extensions/index.d.ts +4 -0
- package/dist/features/store-extensions/index.js +4 -0
- package/dist/features/store-extensions/repository/rbac.repositories.d.ts +23 -0
- package/dist/features/store-extensions/repository/rbac.repositories.js +32 -0
- package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +91 -0
- package/dist/features/store-extensions/repository/store-extensions.repositories.js +127 -0
- package/dist/features/store-extensions/schemas/firestore.d.ts +244 -0
- package/dist/features/store-extensions/schemas/firestore.js +158 -0
- package/dist/features/store-extensions/schemas/rbac.d.ts +65 -0
- package/dist/features/store-extensions/schemas/rbac.js +43 -0
- package/dist/features/stores/api/[storeSlug]/reviews/route.js +49 -7
- package/dist/features/stores/components/InteractiveStoreCard.js +7 -3
- package/dist/features/stores/components/StoreCapabilitiesGuideView.d.ts +3 -0
- package/dist/features/stores/components/StoreCapabilitiesGuideView.js +101 -0
- package/dist/features/stores/components/StoreFinanceGuideView.d.ts +3 -0
- package/dist/features/stores/components/StoreFinanceGuideView.js +79 -0
- package/dist/features/stores/components/StoreGuideHubView.d.ts +5 -0
- package/dist/features/stores/components/StoreGuideHubView.js +89 -0
- package/dist/features/stores/components/StoreListingsGuideView.d.ts +3 -0
- package/dist/features/stores/components/StoreListingsGuideView.js +151 -0
- package/dist/features/stores/components/StoreOrdersGuideView.d.ts +3 -0
- package/dist/features/stores/components/StoreOrdersGuideView.js +122 -0
- package/dist/features/stores/components/StoreProductsListing.js +6 -10
- package/dist/features/stores/components/StoreReviewsListing.js +100 -23
- package/dist/features/stores/components/StoreSettingsGuideView.d.ts +3 -0
- package/dist/features/stores/components/StoreSettingsGuideView.js +56 -0
- package/dist/features/stores/components/index.d.ts +12 -1
- package/dist/features/stores/components/index.js +6 -1
- package/dist/features/stores/hooks/useStores.d.ts +5 -0
- package/dist/features/stores/hooks/useStores.js +10 -0
- package/dist/features/stores/manifest.js +1 -1
- package/dist/features/stores/schemas/firestore.d.ts +2 -0
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +13 -2
- package/dist/index.d.ts +60 -9
- package/dist/index.js +66 -15
- package/dist/next/routing/route-map.d.ts +134 -0
- package/dist/next/routing/route-map.js +59 -0
- package/dist/providers/db-firebase/__tests__/filter-aliases.test.d.ts +1 -0
- package/dist/providers/db-firebase/__tests__/filter-aliases.test.js +93 -0
- package/dist/providers/db-firebase/sieve.d.ts +49 -0
- package/dist/providers/db-firebase/sieve.js +61 -8
- package/dist/react/hooks/useFormStatePreservation.d.ts +17 -0
- package/dist/react/hooks/useFormStatePreservation.js +62 -0
- package/dist/react/hooks/useInlineRowEdit.d.ts +24 -0
- package/dist/react/hooks/useInlineRowEdit.js +68 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.js +4 -0
- package/dist/repositories/index.d.ts +5 -0
- package/dist/repositories/index.js +7 -0
- package/dist/seed/actions/demo-seed-actions.d.ts +1 -1
- package/dist/seed/claimed-coupons-seed-data.d.ts +13 -0
- package/dist/seed/claimed-coupons-seed-data.js +79 -0
- package/dist/seed/index.d.ts +2 -0
- package/dist/seed/index.js +3 -0
- package/dist/seed/manifest.js +17 -0
- package/dist/seed/store-extensions-seed-data.d.ts +19 -0
- package/dist/seed/store-extensions-seed-data.js +421 -0
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/Button.style.css +20 -12
- package/dist/ui/components/ClaimCouponButton.d.ts +28 -0
- package/dist/ui/components/ClaimCouponButton.js +89 -0
- package/dist/ui/components/ListingToolbar.d.ts +8 -1
- package/dist/ui/components/ListingToolbar.js +4 -2
- package/dist/ui/components/QuickCreateModal.d.ts +15 -0
- package/dist/ui/components/QuickCreateModal.js +48 -0
- package/dist/ui/components/QuickCreateModal.style.css +84 -0
- package/dist/ui/components/StickyBottomBar.d.ts +22 -0
- package/dist/ui/components/StickyBottomBar.js +20 -0
- package/dist/ui/components/VacationBanner.d.ts +11 -0
- package/dist/ui/components/VacationBanner.js +16 -0
- package/dist/ui/components/__tests__/BulkActionBar.test.d.ts +1 -0
- package/dist/ui/components/__tests__/BulkActionBar.test.js +96 -0
- package/dist/ui/components/__tests__/ListingToolbar.test.d.ts +1 -0
- package/dist/ui/components/__tests__/ListingToolbar.test.js +125 -0
- package/dist/ui/index.d.ts +9 -1
- package/dist/ui/index.js +4 -0
- package/package.json +8 -2
|
@@ -41,6 +41,10 @@ export const DEFAULT_ROUTE_MAP = {
|
|
|
41
41
|
CONTACT: "/contact",
|
|
42
42
|
BLOG: "/blog",
|
|
43
43
|
HELP: "/help",
|
|
44
|
+
HELP_SHOPPING: "/help/shopping",
|
|
45
|
+
HELP_AUCTIONS: "/help/auctions",
|
|
46
|
+
HELP_ORDERS: "/help/orders",
|
|
47
|
+
HELP_ACCOUNT: "/help/account",
|
|
44
48
|
TERMS: "/terms",
|
|
45
49
|
PRIVACY: "/privacy",
|
|
46
50
|
SECURITY: "/security",
|
|
@@ -68,6 +72,10 @@ export const DEFAULT_ROUTE_MAP = {
|
|
|
68
72
|
SCAMS: "/scams",
|
|
69
73
|
SCAM_DETAIL: (id) => `/scams/${id}`,
|
|
70
74
|
SCAM_REPORT: "/scams/report",
|
|
75
|
+
REPORT_ENTITY: "/report",
|
|
76
|
+
ITEM_REQUESTS: "/item-requests",
|
|
77
|
+
ITEM_REQUEST_DETAIL: (id) => `/item-requests/${id}`,
|
|
78
|
+
ITEM_REQUESTS_NEW: "/item-requests/new",
|
|
71
79
|
SCAM_TYPES: "/scams/types",
|
|
72
80
|
SCAM_FAQS: "/scams/faqs",
|
|
73
81
|
CLASSIFIED: "/classified",
|
|
@@ -104,6 +112,8 @@ export const DEFAULT_ROUTE_MAP = {
|
|
|
104
112
|
ORDER_INVOICE: (id) => `/user/orders/${id}/invoice`,
|
|
105
113
|
NOTIFICATIONS: "/user/notifications",
|
|
106
114
|
MESSAGES: "/user/messages",
|
|
115
|
+
/** Plan §10 — claimed-coupons wallet (Active / Expired / Used tabs). */
|
|
116
|
+
CLAIMED_COUPONS: "/user/coupons",
|
|
107
117
|
BECOME_SELLER: "/user/become-seller",
|
|
108
118
|
CART: "/cart",
|
|
109
119
|
CHECKOUT: "/checkout",
|
|
@@ -175,6 +185,32 @@ export const DEFAULT_ROUTE_MAP = {
|
|
|
175
185
|
LIVE_ITEMS_EDIT: (id) => `/store/live/${id}/edit`,
|
|
176
186
|
PRINT_CENTER: "/store/print-center",
|
|
177
187
|
INVENTORY_PRINT: "/store/inventory/print",
|
|
188
|
+
// S-STORE Tier — new extension routes
|
|
189
|
+
PAYOUT_METHODS: "/store/payout-methods",
|
|
190
|
+
PAYOUT_METHODS_NEW: "/store/payout-methods/new",
|
|
191
|
+
PAYOUT_METHODS_EDIT: (id) => `/store/payout-methods/${id}/edit`,
|
|
192
|
+
SHIPPING_CONFIGS: "/store/shipping-configs",
|
|
193
|
+
SHIPPING_CONFIGS_NEW: "/store/shipping-configs/new",
|
|
194
|
+
SHIPPING_CONFIGS_EDIT: (id) => `/store/shipping-configs/${id}/edit`,
|
|
195
|
+
ANALYTICS_CARDS: "/store/analytics/cards",
|
|
196
|
+
ANALYTICS_ALERTS: "/store/analytics/alerts",
|
|
197
|
+
GROUPED_LISTINGS: "/store/grouped-listings",
|
|
198
|
+
GROUPED_LISTINGS_NEW: "/store/grouped-listings/new",
|
|
199
|
+
GROUPED_LISTINGS_EDIT: (id) => `/store/grouped-listings/${id}/edit`,
|
|
200
|
+
STORE_CATEGORIES: "/store/categories",
|
|
201
|
+
STORE_CATEGORIES_NEW: "/store/categories/new",
|
|
202
|
+
STORE_CATEGORIES_EDIT: (id) => `/store/categories/${id}/edit`,
|
|
203
|
+
LISTING_TEMPLATES: "/store/listing-templates",
|
|
204
|
+
LISTING_TEMPLATES_NEW: "/store/listing-templates/new",
|
|
205
|
+
LISTING_TEMPLATES_EDIT: (id) => `/store/listing-templates/${id}/edit`,
|
|
206
|
+
GOOGLE_REVIEWS: "/store/google-reviews",
|
|
207
|
+
// GD1–GD6 — Store Guide Hub + sub-pages
|
|
208
|
+
GUIDE: "/store/guide",
|
|
209
|
+
GUIDE_LISTINGS: "/store/guide/listings",
|
|
210
|
+
GUIDE_ORDERS: "/store/guide/orders",
|
|
211
|
+
GUIDE_FINANCE: "/store/guide/finance",
|
|
212
|
+
GUIDE_CAPABILITIES: "/store/guide/capabilities",
|
|
213
|
+
GUIDE_SETTINGS: "/store/guide/settings",
|
|
178
214
|
},
|
|
179
215
|
ADMIN: {
|
|
180
216
|
DASHBOARD: "/admin/dashboard",
|
|
@@ -258,6 +294,29 @@ export const DEFAULT_ROUTE_MAP = {
|
|
|
258
294
|
SETTINGS_ACTIONS: "/admin/settings/actions",
|
|
259
295
|
SETTINGS_NAVIGATION: "/admin/settings/navigation",
|
|
260
296
|
PRINT_CENTER: "/admin/print-center",
|
|
297
|
+
// S-STORE Tier — admin moderation + reports + item requests
|
|
298
|
+
MODERATION: "/admin/moderation",
|
|
299
|
+
MODERATION_DETAIL: (id) => `/admin/moderation/${id}`,
|
|
300
|
+
REPORTS: "/admin/reports",
|
|
301
|
+
REPORT_DETAIL: (id) => `/admin/reports/${id}`,
|
|
302
|
+
ITEM_REQUESTS: "/admin/item-requests",
|
|
303
|
+
ITEM_REQUEST_DETAIL: (id) => `/admin/item-requests/${id}`,
|
|
304
|
+
ROLES: "/admin/roles",
|
|
305
|
+
ROLES_NEW: "/admin/roles/new",
|
|
306
|
+
ROLES_EDIT: (id) => `/admin/roles/${id}/edit`,
|
|
307
|
+
PERMISSIONS: "/admin/permissions",
|
|
308
|
+
ADMIN_NOTIFICATIONS: "/admin/admin-notifications",
|
|
309
|
+
// GD13–GD22 — Admin Guide Hub + sub-pages
|
|
310
|
+
GUIDE: "/admin/guide",
|
|
311
|
+
GUIDE_USERS: "/admin/guide/users",
|
|
312
|
+
GUIDE_CATALOG: "/admin/guide/catalog",
|
|
313
|
+
GUIDE_STORES: "/admin/guide/stores",
|
|
314
|
+
GUIDE_ORDERS: "/admin/guide/orders",
|
|
315
|
+
GUIDE_CONTENT: "/admin/guide/content",
|
|
316
|
+
GUIDE_SITE: "/admin/guide/site",
|
|
317
|
+
GUIDE_TEAM: "/admin/guide/team",
|
|
318
|
+
GUIDE_ANALYTICS: "/admin/guide/analytics",
|
|
319
|
+
GUIDE_TRUST: "/admin/guide/trust",
|
|
261
320
|
},
|
|
262
321
|
DEMO: {
|
|
263
322
|
SEED: "/demo/seed",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { expandFilterAliases } from "../filter-aliases";
|
|
3
|
+
describe("expandFilterAliases", () => {
|
|
4
|
+
it("returns undefined when filters is undefined", () => {
|
|
5
|
+
const aliases = { scope: () => "status==active" };
|
|
6
|
+
expect(expandFilterAliases(undefined, aliases)).toBeUndefined();
|
|
7
|
+
});
|
|
8
|
+
it("returns filters unchanged when aliases is undefined", () => {
|
|
9
|
+
expect(expandFilterAliases("status==active", undefined)).toBe("status==active");
|
|
10
|
+
});
|
|
11
|
+
it("returns filters unchanged when aliases is empty object", () => {
|
|
12
|
+
expect(expandFilterAliases("status==active", {})).toBe("status==active");
|
|
13
|
+
});
|
|
14
|
+
it("expands a single alias clause", () => {
|
|
15
|
+
const aliases = {
|
|
16
|
+
scope: (value) => value === "publicAuctions" ? "status==published,listingType==auction" : "",
|
|
17
|
+
};
|
|
18
|
+
expect(expandFilterAliases("scope==publicAuctions", aliases)).toBe("status==published,listingType==auction");
|
|
19
|
+
});
|
|
20
|
+
it("passes the operator to the alias function", () => {
|
|
21
|
+
const received = [];
|
|
22
|
+
const aliases = {
|
|
23
|
+
myField: (value, op) => {
|
|
24
|
+
received.push({ value, op });
|
|
25
|
+
return "x==1";
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
expandFilterAliases("myField!=foo", aliases);
|
|
29
|
+
expect(received).toEqual([{ value: "foo", op: "!=" }]);
|
|
30
|
+
});
|
|
31
|
+
it("expands an alias and passes through unknown clauses", () => {
|
|
32
|
+
const aliases = {
|
|
33
|
+
scope: () => "status==published,listingType==auction",
|
|
34
|
+
};
|
|
35
|
+
const result = expandFilterAliases("scope==publicAuctions,storeId==store-abc", aliases);
|
|
36
|
+
expect(result).toBe("status==published,listingType==auction,storeId==store-abc");
|
|
37
|
+
});
|
|
38
|
+
it("passes through a clause whose field has no alias", () => {
|
|
39
|
+
const aliases = { scope: () => "status==active" };
|
|
40
|
+
expect(expandFilterAliases("category==brand-pokemon", aliases)).toBe("category==brand-pokemon");
|
|
41
|
+
});
|
|
42
|
+
it("drops a clause when the alias returns empty string", () => {
|
|
43
|
+
const aliases = {
|
|
44
|
+
scope: () => "",
|
|
45
|
+
};
|
|
46
|
+
expect(expandFilterAliases("scope==unknown", aliases)).toBe("");
|
|
47
|
+
});
|
|
48
|
+
it("drops an empty-expansion clause while keeping other clauses", () => {
|
|
49
|
+
const aliases = {
|
|
50
|
+
scope: (value) => (value === "known" ? "status==active" : ""),
|
|
51
|
+
};
|
|
52
|
+
const result = expandFilterAliases("scope==notknown,listingType==standard", aliases);
|
|
53
|
+
expect(result).toBe("listingType==standard");
|
|
54
|
+
});
|
|
55
|
+
it("handles multiple alias fields in one filter string", () => {
|
|
56
|
+
const aliases = {
|
|
57
|
+
scope: () => "status==active",
|
|
58
|
+
type: () => "listingType==auction",
|
|
59
|
+
};
|
|
60
|
+
const result = expandFilterAliases("scope==any,type==any", aliases);
|
|
61
|
+
expect(result).toBe("status==active,listingType==auction");
|
|
62
|
+
});
|
|
63
|
+
it("trims whitespace around clauses", () => {
|
|
64
|
+
const aliases = { scope: () => "status==active" };
|
|
65
|
+
const result = expandFilterAliases(" scope==x , name==foo ", aliases);
|
|
66
|
+
expect(result).toBe("status==active,name==foo");
|
|
67
|
+
});
|
|
68
|
+
it("passes through a clause that does not match the operator pattern", () => {
|
|
69
|
+
const aliases = { scope: () => "status==active" };
|
|
70
|
+
// A malformed clause has no operator — should pass through unchanged
|
|
71
|
+
expect(expandFilterAliases("malformed", aliases)).toBe("malformed");
|
|
72
|
+
});
|
|
73
|
+
it("handles @= operator", () => {
|
|
74
|
+
const received = [];
|
|
75
|
+
const aliases = {
|
|
76
|
+
tags: (_v, op) => { received.push(op); return "tags@=value"; },
|
|
77
|
+
};
|
|
78
|
+
expandFilterAliases("tags@=value", aliases);
|
|
79
|
+
expect(received[0]).toBe("@=");
|
|
80
|
+
});
|
|
81
|
+
it("handles @=* operator", () => {
|
|
82
|
+
const received = [];
|
|
83
|
+
const aliases = {
|
|
84
|
+
tags: (_v, op) => { received.push(op); return "tags@=*value"; },
|
|
85
|
+
};
|
|
86
|
+
expandFilterAliases("tags@=*value", aliases);
|
|
87
|
+
expect(received[0]).toBe("@=*");
|
|
88
|
+
});
|
|
89
|
+
it("returns empty string when all clauses expand to empty", () => {
|
|
90
|
+
const aliases = { scope: () => "" };
|
|
91
|
+
expect(expandFilterAliases("scope==x", aliases)).toBe("");
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -16,6 +16,55 @@
|
|
|
16
16
|
* }, { baseQuery });
|
|
17
17
|
* }
|
|
18
18
|
* ```
|
|
19
|
+
*
|
|
20
|
+
* ## Known Sieve ↔ Firestore incompatibilities
|
|
21
|
+
*
|
|
22
|
+
* These Sieve DSL features are silently unsupported or produce wrong results
|
|
23
|
+
* when translated to Firestore queries. Document them here to avoid surprise.
|
|
24
|
+
*
|
|
25
|
+
* ### 1. String-contains `@=*` (case-insensitive full-text)
|
|
26
|
+
* Sieve's `title@=*query` is a substring/CI match. Firestore has no native
|
|
27
|
+
* LIKE or ILIKE operator. The Firebase adapter maps it to `>=` / `<` prefix
|
|
28
|
+
* range tricks that only work for prefix matches on ASCII strings, not
|
|
29
|
+
* arbitrary substrings. Use a Firebase Function or in-memory post-filter for
|
|
30
|
+
* real substring search; never rely on `@=*` to match mid-string.
|
|
31
|
+
*
|
|
32
|
+
* ### 2. OR across different fields (`|` pipe between clauses)
|
|
33
|
+
* Sieve's `field1==v1|field2==v2` (OR across two different fields) is
|
|
34
|
+
* translated to `whereOr` by the stock Firebase adapter. Firestore's Admin SDK
|
|
35
|
+
* v6+ supports `Query.where(Filter.or(...))`, but the stock adapter version
|
|
36
|
+
* bundled with sievejs may emit an unsupported form. The enhanced adapter in
|
|
37
|
+
* this file only upgrades single-field OR groups (same-field equality → `in`
|
|
38
|
+
* query). Multi-field OR is still unsupported — apply it in memory.
|
|
39
|
+
*
|
|
40
|
+
* ### 3. OR on the same field (`field==v1|v2`) → Firestore `in`
|
|
41
|
+
* The custom `createEnhancedFirebaseAdapter` in this file upgrades these to
|
|
42
|
+
* Firestore `.where(field, "in", [v1, v2])`. Firestore supports up to 30
|
|
43
|
+
* values in an `in` clause. More than 30 values will throw. The stock adapter
|
|
44
|
+
* would have emitted a `whereOr` call that fails entirely.
|
|
45
|
+
*
|
|
46
|
+
* ### 4. Multi-field `orderBy` without a matching composite index
|
|
47
|
+
* Firestore requires a composite index for every combination of `where` +
|
|
48
|
+
* `orderBy` fields. Sieve sorts like `-createdAt,price` translate to two
|
|
49
|
+
* `orderBy` calls; if the Firestore collection has no index for that
|
|
50
|
+
* combination the query throws `FAILED_PRECONDITION`. Add the index to
|
|
51
|
+
* `appkit/firebase/base/firestore.indexes.json` and deploy before shipping.
|
|
52
|
+
*
|
|
53
|
+
* ### 5. Inequality filter + `orderBy` on a different field
|
|
54
|
+
* Firestore's rule: if you have an inequality filter (`!=`, `<`, `>`, `<=`,
|
|
55
|
+
* `>=`) on field A, the first `orderBy` must also be on field A. Sieve queries
|
|
56
|
+
* like `price>=100 & sorts=-createdAt` translate to an inequality on `price`
|
|
57
|
+
* with `orderBy createdAt`, which Firestore rejects. Work-arounds:
|
|
58
|
+
* (a) move the inequality filter to the Firebase Function path where it can
|
|
59
|
+
* be handled server-side, (b) apply it in-memory in the fallback path,
|
|
60
|
+
* (c) restructure the sort to use the same field as the filter.
|
|
61
|
+
*
|
|
62
|
+
* ### 6. Dot-notation nested field filters (`address.city==Delhi`)
|
|
63
|
+
* Sieve parses the field name verbatim; the Firebase adapter passes it as the
|
|
64
|
+
* Firestore field path. Firestore Admin SDK supports dot-notation for nested
|
|
65
|
+
* fields, so `address.city==Delhi` works — but only if the field is indexed.
|
|
66
|
+
* Add nested-field indexes explicitly; Firestore does not auto-index nested
|
|
67
|
+
* paths in composite indexes declared at the root level.
|
|
19
68
|
*/
|
|
20
69
|
import type { CollectionReference, DocumentData, Query } from "firebase-admin/firestore";
|
|
21
70
|
import { FirebaseRepository } from "./base";
|
|
@@ -16,6 +16,55 @@
|
|
|
16
16
|
* }, { baseQuery });
|
|
17
17
|
* }
|
|
18
18
|
* ```
|
|
19
|
+
*
|
|
20
|
+
* ## Known Sieve ↔ Firestore incompatibilities
|
|
21
|
+
*
|
|
22
|
+
* These Sieve DSL features are silently unsupported or produce wrong results
|
|
23
|
+
* when translated to Firestore queries. Document them here to avoid surprise.
|
|
24
|
+
*
|
|
25
|
+
* ### 1. String-contains `@=*` (case-insensitive full-text)
|
|
26
|
+
* Sieve's `title@=*query` is a substring/CI match. Firestore has no native
|
|
27
|
+
* LIKE or ILIKE operator. The Firebase adapter maps it to `>=` / `<` prefix
|
|
28
|
+
* range tricks that only work for prefix matches on ASCII strings, not
|
|
29
|
+
* arbitrary substrings. Use a Firebase Function or in-memory post-filter for
|
|
30
|
+
* real substring search; never rely on `@=*` to match mid-string.
|
|
31
|
+
*
|
|
32
|
+
* ### 2. OR across different fields (`|` pipe between clauses)
|
|
33
|
+
* Sieve's `field1==v1|field2==v2` (OR across two different fields) is
|
|
34
|
+
* translated to `whereOr` by the stock Firebase adapter. Firestore's Admin SDK
|
|
35
|
+
* v6+ supports `Query.where(Filter.or(...))`, but the stock adapter version
|
|
36
|
+
* bundled with sievejs may emit an unsupported form. The enhanced adapter in
|
|
37
|
+
* this file only upgrades single-field OR groups (same-field equality → `in`
|
|
38
|
+
* query). Multi-field OR is still unsupported — apply it in memory.
|
|
39
|
+
*
|
|
40
|
+
* ### 3. OR on the same field (`field==v1|v2`) → Firestore `in`
|
|
41
|
+
* The custom `createEnhancedFirebaseAdapter` in this file upgrades these to
|
|
42
|
+
* Firestore `.where(field, "in", [v1, v2])`. Firestore supports up to 30
|
|
43
|
+
* values in an `in` clause. More than 30 values will throw. The stock adapter
|
|
44
|
+
* would have emitted a `whereOr` call that fails entirely.
|
|
45
|
+
*
|
|
46
|
+
* ### 4. Multi-field `orderBy` without a matching composite index
|
|
47
|
+
* Firestore requires a composite index for every combination of `where` +
|
|
48
|
+
* `orderBy` fields. Sieve sorts like `-createdAt,price` translate to two
|
|
49
|
+
* `orderBy` calls; if the Firestore collection has no index for that
|
|
50
|
+
* combination the query throws `FAILED_PRECONDITION`. Add the index to
|
|
51
|
+
* `appkit/firebase/base/firestore.indexes.json` and deploy before shipping.
|
|
52
|
+
*
|
|
53
|
+
* ### 5. Inequality filter + `orderBy` on a different field
|
|
54
|
+
* Firestore's rule: if you have an inequality filter (`!=`, `<`, `>`, `<=`,
|
|
55
|
+
* `>=`) on field A, the first `orderBy` must also be on field A. Sieve queries
|
|
56
|
+
* like `price>=100 & sorts=-createdAt` translate to an inequality on `price`
|
|
57
|
+
* with `orderBy createdAt`, which Firestore rejects. Work-arounds:
|
|
58
|
+
* (a) move the inequality filter to the Firebase Function path where it can
|
|
59
|
+
* be handled server-side, (b) apply it in-memory in the fallback path,
|
|
60
|
+
* (c) restructure the sort to use the same field as the filter.
|
|
61
|
+
*
|
|
62
|
+
* ### 6. Dot-notation nested field filters (`address.city==Delhi`)
|
|
63
|
+
* Sieve parses the field name verbatim; the Firebase adapter passes it as the
|
|
64
|
+
* Firestore field path. Firestore Admin SDK supports dot-notation for nested
|
|
65
|
+
* fields, so `address.city==Delhi` works — but only if the field is indexed.
|
|
66
|
+
* Add nested-field indexes explicitly; Firestore does not auto-index nested
|
|
67
|
+
* paths in composite indexes declared at the root level.
|
|
19
68
|
*/
|
|
20
69
|
import { SieveProcessorBase } from "@mohasinac/sievejs/services";
|
|
21
70
|
import { createFirebaseAdapter } from "@mohasinac/sievejs/adapters/firebase";
|
|
@@ -81,15 +130,18 @@ export async function applySieveToFirestore(params) {
|
|
|
81
130
|
options: merged,
|
|
82
131
|
fields,
|
|
83
132
|
});
|
|
133
|
+
const page = Math.max(1, Number(model.page ?? 1));
|
|
134
|
+
const pageSize = Math.min(merged.maxPageSize, Math.max(1, Number(model.pageSize ?? merged.defaultPageSize)));
|
|
135
|
+
// Apply filters + sorts once; count without reading docs.
|
|
84
136
|
const filteredQ = processor.apply(effective, baseQuery, {
|
|
85
137
|
applyPagination: false,
|
|
86
138
|
});
|
|
87
139
|
const total = await getFirestoreCount(filteredQ);
|
|
88
|
-
|
|
140
|
+
// Apply pagination on top of the already-filtered query — avoids re-applying
|
|
141
|
+
// the full Sieve DSL from the base.
|
|
142
|
+
const pagedQ = filteredQ.offset((page - 1) * pageSize).limit(pageSize);
|
|
89
143
|
const snap = await pagedQ.get();
|
|
90
144
|
const items = snap.docs.map((d) => deserializeTimestamps({ id: d.id, ...d.data() }));
|
|
91
|
-
const page = Math.max(1, Number(model.page ?? 1));
|
|
92
|
-
const pageSize = Math.min(merged.maxPageSize, Math.max(1, Number(model.pageSize ?? merged.defaultPageSize)));
|
|
93
145
|
const totalPages = total === 0 ? 0 : Math.max(1, Math.ceil(total / pageSize));
|
|
94
146
|
return {
|
|
95
147
|
items,
|
|
@@ -120,17 +172,18 @@ export class FirebaseSieveRepository extends FirebaseRepository {
|
|
|
120
172
|
options: merged,
|
|
121
173
|
fields,
|
|
122
174
|
});
|
|
123
|
-
|
|
175
|
+
const page = Math.max(1, Number(model.page ?? 1));
|
|
176
|
+
const pageSize = Math.min(merged.maxPageSize, Math.max(1, Number(model.pageSize ?? merged.defaultPageSize)));
|
|
177
|
+
// Apply filters + sorts once; count without reading docs.
|
|
124
178
|
const filteredQ = processor.apply(effective, base, {
|
|
125
179
|
applyPagination: false,
|
|
126
180
|
});
|
|
127
181
|
const total = await getFirestoreCount(filteredQ);
|
|
128
|
-
//
|
|
129
|
-
|
|
182
|
+
// Apply pagination on top of the already-filtered query — avoids re-applying
|
|
183
|
+
// the full Sieve DSL from the base.
|
|
184
|
+
const pagedQ = filteredQ.offset((page - 1) * pageSize).limit(pageSize);
|
|
130
185
|
const snap = await pagedQ.get();
|
|
131
186
|
const items = snap.docs.map((d) => deserializeTimestamps({ id: d.id, ...d.data() }));
|
|
132
|
-
const page = Math.max(1, Number(model.page ?? 1));
|
|
133
|
-
const pageSize = Math.min(merged.maxPageSize, Math.max(1, Number(model.pageSize ?? merged.defaultPageSize)));
|
|
134
187
|
const totalPages = total === 0 ? 0 : Math.max(1, Math.ceil(total / pageSize));
|
|
135
188
|
return {
|
|
136
189
|
items,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface FormStatePreservationOptions<TValues> {
|
|
2
|
+
/** Current form values to persist. */
|
|
3
|
+
values: TValues;
|
|
4
|
+
/** Callback invoked with restored values on mount (if any). */
|
|
5
|
+
onRestore: (values: TValues) => void;
|
|
6
|
+
/** Field paths whose values are stripped before encoding (PII). */
|
|
7
|
+
stripFields?: string[];
|
|
8
|
+
/** URL query-param name. Default: "_s". */
|
|
9
|
+
paramName?: string;
|
|
10
|
+
/** Debounce in ms. Default: 500. */
|
|
11
|
+
debounceMs?: number;
|
|
12
|
+
/** Disable persistence (e.g. while submitting). */
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function useFormStatePreservation<TValues extends Record<string, unknown>>({ values, onRestore, stripFields, paramName, debounceMs, enabled, }: FormStatePreservationOptions<TValues>): {
|
|
16
|
+
clearPreservedState: () => void;
|
|
17
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useRef, useCallback } from "react";
|
|
3
|
+
const PARAM_DEFAULT = "_s";
|
|
4
|
+
function stripPii(values, stripFields) {
|
|
5
|
+
if (!stripFields.length || typeof values !== "object" || values === null) {
|
|
6
|
+
return values;
|
|
7
|
+
}
|
|
8
|
+
const clone = { ...values };
|
|
9
|
+
for (const path of stripFields) {
|
|
10
|
+
if (path in clone) {
|
|
11
|
+
delete clone[path];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return clone;
|
|
15
|
+
}
|
|
16
|
+
export function useFormStatePreservation({ values, onRestore, stripFields = [], paramName = PARAM_DEFAULT, debounceMs = 500, enabled = true, }) {
|
|
17
|
+
const restoredRef = useRef(false);
|
|
18
|
+
const timerRef = useRef(null);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (restoredRef.current || typeof window === "undefined")
|
|
21
|
+
return;
|
|
22
|
+
restoredRef.current = true;
|
|
23
|
+
const url = new URL(window.location.href);
|
|
24
|
+
const encoded = url.searchParams.get(paramName);
|
|
25
|
+
if (!encoded)
|
|
26
|
+
return;
|
|
27
|
+
try {
|
|
28
|
+
const decoded = JSON.parse(atob(encoded));
|
|
29
|
+
onRestore(decoded);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// ignore corrupt payloads
|
|
33
|
+
}
|
|
34
|
+
}, [paramName, onRestore]);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!enabled || typeof window === "undefined" || !restoredRef.current)
|
|
37
|
+
return;
|
|
38
|
+
if (timerRef.current)
|
|
39
|
+
clearTimeout(timerRef.current);
|
|
40
|
+
timerRef.current = setTimeout(() => {
|
|
41
|
+
const stripped = stripPii(values, stripFields);
|
|
42
|
+
const encoded = btoa(JSON.stringify(stripped));
|
|
43
|
+
const url = new URL(window.location.href);
|
|
44
|
+
url.searchParams.set(paramName, encoded);
|
|
45
|
+
window.history.replaceState({}, "", url.toString());
|
|
46
|
+
}, debounceMs);
|
|
47
|
+
return () => {
|
|
48
|
+
if (timerRef.current)
|
|
49
|
+
clearTimeout(timerRef.current);
|
|
50
|
+
};
|
|
51
|
+
}, [values, enabled, paramName, debounceMs, stripFields]);
|
|
52
|
+
const clearPreservedState = useCallback(() => {
|
|
53
|
+
if (typeof window === "undefined")
|
|
54
|
+
return;
|
|
55
|
+
const url = new URL(window.location.href);
|
|
56
|
+
if (url.searchParams.has(paramName)) {
|
|
57
|
+
url.searchParams.delete(paramName);
|
|
58
|
+
window.history.replaceState({}, "", url.toString());
|
|
59
|
+
}
|
|
60
|
+
}, [paramName]);
|
|
61
|
+
return { clearPreservedState };
|
|
62
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface InlineEditOptions<TValue> {
|
|
2
|
+
rowId: string;
|
|
3
|
+
field: string;
|
|
4
|
+
initialValue: TValue;
|
|
5
|
+
save: (rowId: string, field: string, value: TValue) => Promise<unknown>;
|
|
6
|
+
onError?: (err: unknown, previous: TValue) => void;
|
|
7
|
+
}
|
|
8
|
+
export interface InlineToggleResult {
|
|
9
|
+
value: boolean;
|
|
10
|
+
isSaving: boolean;
|
|
11
|
+
toggle: () => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export declare function useInlineToggle({ rowId, field, initialValue, save, onError, }: InlineEditOptions<boolean>): InlineToggleResult;
|
|
14
|
+
export interface InlineTextResult {
|
|
15
|
+
value: string;
|
|
16
|
+
draft: string;
|
|
17
|
+
isEditing: boolean;
|
|
18
|
+
isSaving: boolean;
|
|
19
|
+
startEdit: () => void;
|
|
20
|
+
cancelEdit: () => void;
|
|
21
|
+
commitEdit: () => Promise<void>;
|
|
22
|
+
setDraft: (next: string) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare function useInlineTextEdit({ rowId, field, initialValue, save, onError, }: InlineEditOptions<string>): InlineTextResult;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback, useState } from "react";
|
|
3
|
+
export function useInlineToggle({ rowId, field, initialValue, save, onError, }) {
|
|
4
|
+
const [value, setValue] = useState(initialValue);
|
|
5
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
6
|
+
const toggle = useCallback(async () => {
|
|
7
|
+
const previous = value;
|
|
8
|
+
const next = !previous;
|
|
9
|
+
setValue(next);
|
|
10
|
+
setIsSaving(true);
|
|
11
|
+
try {
|
|
12
|
+
await save(rowId, field, next);
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
setValue(previous);
|
|
16
|
+
onError?.(err, previous);
|
|
17
|
+
}
|
|
18
|
+
finally {
|
|
19
|
+
setIsSaving(false);
|
|
20
|
+
}
|
|
21
|
+
}, [value, save, rowId, field, onError]);
|
|
22
|
+
return { value, isSaving, toggle };
|
|
23
|
+
}
|
|
24
|
+
export function useInlineTextEdit({ rowId, field, initialValue, save, onError, }) {
|
|
25
|
+
const [value, setValue] = useState(initialValue);
|
|
26
|
+
const [draft, setDraft] = useState(initialValue);
|
|
27
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
28
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
29
|
+
const startEdit = useCallback(() => {
|
|
30
|
+
setDraft(value);
|
|
31
|
+
setIsEditing(true);
|
|
32
|
+
}, [value]);
|
|
33
|
+
const cancelEdit = useCallback(() => {
|
|
34
|
+
setDraft(value);
|
|
35
|
+
setIsEditing(false);
|
|
36
|
+
}, [value]);
|
|
37
|
+
const commitEdit = useCallback(async () => {
|
|
38
|
+
if (draft === value) {
|
|
39
|
+
setIsEditing(false);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const previous = value;
|
|
43
|
+
setValue(draft);
|
|
44
|
+
setIsEditing(false);
|
|
45
|
+
setIsSaving(true);
|
|
46
|
+
try {
|
|
47
|
+
await save(rowId, field, draft);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
setValue(previous);
|
|
51
|
+
setDraft(previous);
|
|
52
|
+
onError?.(err, previous);
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
setIsSaving(false);
|
|
56
|
+
}
|
|
57
|
+
}, [draft, value, save, rowId, field, onError]);
|
|
58
|
+
return {
|
|
59
|
+
value,
|
|
60
|
+
draft,
|
|
61
|
+
isEditing,
|
|
62
|
+
isSaving,
|
|
63
|
+
startEdit,
|
|
64
|
+
cancelEdit,
|
|
65
|
+
commitEdit,
|
|
66
|
+
setDraft,
|
|
67
|
+
};
|
|
68
|
+
}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -30,6 +30,10 @@ export type { UseBulkSelectionOptions, UseBulkSelectionReturn, } from "./hooks/u
|
|
|
30
30
|
export { useSyncManager } from "../core/hooks/useSyncManager";
|
|
31
31
|
export { useUrlTable } from "./hooks/useUrlTable";
|
|
32
32
|
export type { UseUrlTableOptions } from "./hooks/useUrlTable";
|
|
33
|
+
export { useInlineToggle, useInlineTextEdit, } from "./hooks/useInlineRowEdit";
|
|
34
|
+
export type { InlineEditOptions, InlineToggleResult, InlineTextResult, } from "./hooks/useInlineRowEdit";
|
|
35
|
+
export { useFormStatePreservation } from "./hooks/useFormStatePreservation";
|
|
36
|
+
export type { FormStatePreservationOptions } from "./hooks/useFormStatePreservation";
|
|
33
37
|
export { usePendingFilters } from "./hooks/usePendingFilters";
|
|
34
38
|
export type { UsePendingFiltersOptions, UsePendingFiltersReturn, } from "./hooks/usePendingFilters";
|
|
35
39
|
export { usePendingTable } from "./hooks/usePendingTable";
|
package/dist/react/index.js
CHANGED
|
@@ -28,6 +28,10 @@ export { useBulkSelection } from "./hooks/useBulkSelection";
|
|
|
28
28
|
export { useSyncManager } from "../core/hooks/useSyncManager";
|
|
29
29
|
// URL-driven table / list state
|
|
30
30
|
export { useUrlTable } from "./hooks/useUrlTable";
|
|
31
|
+
// Inline row editing (S-STORE-CROSS-B)
|
|
32
|
+
export { useInlineToggle, useInlineTextEdit, } from "./hooks/useInlineRowEdit";
|
|
33
|
+
// Form state preservation in URL (S-STORE-CROSS-C)
|
|
34
|
+
export { useFormStatePreservation } from "./hooks/useFormStatePreservation";
|
|
31
35
|
// Staged (pending) filter management
|
|
32
36
|
export { usePendingFilters } from "./hooks/usePendingFilters";
|
|
33
37
|
export { usePendingTable } from "./hooks/usePendingTable";
|
|
@@ -24,9 +24,14 @@ export { carouselsRepository, CarouselsRepository } from "../features/homepage/r
|
|
|
24
24
|
export { homepageSectionsRepository } from "../features/homepage/repository/homepage-sections.repository";
|
|
25
25
|
export { CategoriesRepository, categoriesRepository, } from "../features/categories/repository/categories.repository";
|
|
26
26
|
export { couponsRepository } from "../features/promotions/repository/coupons.repository";
|
|
27
|
+
export { ClaimedCouponsRepository, claimedCouponsRepository, } from "../features/promotions/repository/claimed-coupons.repository";
|
|
28
|
+
export type { ClaimedCouponCreateInput } from "../features/promotions/repository/claimed-coupons.repository";
|
|
27
29
|
export { FAQsRepository, FirebaseFAQsRepository, faqsRepository, } from "../features/faq/repository/faqs.repository";
|
|
28
30
|
export { BlogRepository, blogRepository, } from "../features/blog/repository/blog.repository";
|
|
29
31
|
export { payoutRepository } from "../features/payments/repository/payout.repository";
|
|
32
|
+
export { GroupedListingsRepository, groupedListingsRepository, } from "../features/grouped/repository/grouped-listings.repository";
|
|
33
|
+
export { payoutMethodsRepository, shippingConfigsRepository, analyticsCardsRepository, analyticsAlertsRepository, storeCategoriesRepository, listingTemplatesRepository, moderationQueueRepository, reportsRepository, itemRequestsRepository, storeWhatsAppConfigRepository, storeGoogleConfigRepository, PayoutMethodsRepository, ShippingConfigsRepository, AnalyticsCardsRepository, AnalyticsAlertsRepository, StoreCategoriesRepository, ListingTemplatesRepository, ModerationQueueRepository, ReportsRepository, ItemRequestsRepository, StoreWhatsAppConfigRepository, StoreGoogleConfigRepository, } from "../features/store-extensions/repository/store-extensions.repositories";
|
|
34
|
+
export { roleOverridesRepository, customRolesRepository, adminNotificationsRepository, RoleOverridesRepository, CustomRolesRepository, AdminNotificationsRepository, } from "../features/store-extensions/repository/rbac.repositories";
|
|
30
35
|
export { OfferRepository, offerRepository, } from "../features/seller/repository/offer.repository";
|
|
31
36
|
export { wishlistRepository, type UserWishlistItem as WishlistItem, WishlistFullError, } from "../features/wishlist/repository/user-wishlist.repository";
|
|
32
37
|
export { historyRepository, type UserHistoryItem, type HistoryProductType, } from "../features/history/repository/user-history.repository";
|
|
@@ -31,9 +31,16 @@ export { carouselsRepository, CarouselsRepository } from "../features/homepage/r
|
|
|
31
31
|
export { homepageSectionsRepository } from "../features/homepage/repository/homepage-sections.repository";
|
|
32
32
|
export { CategoriesRepository, categoriesRepository, } from "../features/categories/repository/categories.repository";
|
|
33
33
|
export { couponsRepository } from "../features/promotions/repository/coupons.repository";
|
|
34
|
+
export { ClaimedCouponsRepository, claimedCouponsRepository, } from "../features/promotions/repository/claimed-coupons.repository";
|
|
34
35
|
export { FAQsRepository, FirebaseFAQsRepository, faqsRepository, } from "../features/faq/repository/faqs.repository";
|
|
35
36
|
export { BlogRepository, blogRepository, } from "../features/blog/repository/blog.repository";
|
|
36
37
|
export { payoutRepository } from "../features/payments/repository/payout.repository";
|
|
38
|
+
// Grouped listings repository
|
|
39
|
+
export { GroupedListingsRepository, groupedListingsRepository, } from "../features/grouped/repository/grouped-listings.repository";
|
|
40
|
+
// S-STORE-CROSS — 11 new collection repositories
|
|
41
|
+
export { payoutMethodsRepository, shippingConfigsRepository, analyticsCardsRepository, analyticsAlertsRepository, storeCategoriesRepository, listingTemplatesRepository, moderationQueueRepository, reportsRepository, itemRequestsRepository, storeWhatsAppConfigRepository, storeGoogleConfigRepository, PayoutMethodsRepository, ShippingConfigsRepository, AnalyticsCardsRepository, AnalyticsAlertsRepository, StoreCategoriesRepository, ListingTemplatesRepository, ModerationQueueRepository, ReportsRepository, ItemRequestsRepository, StoreWhatsAppConfigRepository, StoreGoogleConfigRepository, } from "../features/store-extensions/repository/store-extensions.repositories";
|
|
42
|
+
// S-STORE RBAC + admin notifications
|
|
43
|
+
export { roleOverridesRepository, customRolesRepository, adminNotificationsRepository, RoleOverridesRepository, CustomRolesRepository, AdminNotificationsRepository, } from "../features/store-extensions/repository/rbac.repositories";
|
|
37
44
|
export { OfferRepository, offerRepository, } from "../features/seller/repository/offer.repository";
|
|
38
45
|
export { wishlistRepository, WishlistFullError, } from "../features/wishlist/repository/user-wishlist.repository";
|
|
39
46
|
export { historyRepository, } from "../features/history/repository/user-history.repository";
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* the actual collection-specific seeding logic (800+ lines with PII encryption,
|
|
7
7
|
* Auth user creation, subcollection handling, etc.).
|
|
8
8
|
*/
|
|
9
|
-
export type SeedCollectionName = "users" | "addresses" | "categories" | "stores" | "products" | "orders" | "reviews" | "bids" | "coupons" | "carousels" | "carouselSlides" | "homepageSections" | "siteSettings" | "faqs" | "notifications" | "payouts" | "blogPosts" | "events" | "eventEntries" | "sessions" | "carts" | "wishlists" | "history" | "conversations" | "groupedListings" | "scammerProfiles" | "supportTickets" | "productFeatures" | "offers";
|
|
9
|
+
export type SeedCollectionName = "users" | "addresses" | "categories" | "stores" | "products" | "orders" | "reviews" | "bids" | "coupons" | "carousels" | "carouselSlides" | "homepageSections" | "siteSettings" | "faqs" | "notifications" | "payouts" | "blogPosts" | "events" | "eventEntries" | "sessions" | "carts" | "wishlists" | "history" | "conversations" | "groupedListings" | "scammerProfiles" | "supportTickets" | "productFeatures" | "offers" | "payoutMethods" | "shippingConfigs" | "analyticsCards" | "analyticsAlerts" | "storeCategories" | "listingTemplates" | "moderationQueue" | "reports" | "itemRequests" | "storeWhatsAppConfig" | "storeGoogleConfig" | "roleOverrides" | "customRoles" | "adminNotifications";
|
|
10
10
|
export interface SeedOperationResult {
|
|
11
11
|
success?: boolean;
|
|
12
12
|
message: string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claimed Coupons Seed Data — plan §10.
|
|
3
|
+
*
|
|
4
|
+
* Top-level `claimedCoupons` collection (one doc per user × coupon). These
|
|
5
|
+
* rows populate the /user/coupons wallet with one example per status so the
|
|
6
|
+
* tabs (Active / Expired / Used) all have something to render in demo.
|
|
7
|
+
*
|
|
8
|
+
* Coupon snapshots mirror coupons-seed-data.ts (WELCOME10, POKEMON25,
|
|
9
|
+
* FREESHIP999) so the discount badge labels render correctly. Seed user is
|
|
10
|
+
* `user-mohsin-c` to match the dev-account convention used elsewhere.
|
|
11
|
+
*/
|
|
12
|
+
import type { ClaimedCouponDocument } from "../features/promotions/schemas";
|
|
13
|
+
export declare const claimedCouponsSeedData: ClaimedCouponDocument[];
|