@mohasinac/appkit 2.7.57 → 2.7.59
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/DashboardLayoutClient.d.ts +7 -1
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +8 -2
- package/dist/_internal/server/features/scams/og.js +1 -1
- package/dist/_internal/shared/actions/bulk-helpers.d.ts +3 -0
- package/dist/_internal/shared/actions/bulk-helpers.js +19 -0
- package/dist/_internal/shared/config/schema.d.ts +4 -4
- package/dist/client.d.ts +4 -1
- package/dist/client.js +3 -1
- package/dist/configs/next.js +11 -0
- package/dist/configs/tailwind.d.ts +16 -3
- package/dist/configs/tailwind.js +18 -5
- package/dist/features/account/components/AddressBook.js +1 -1
- package/dist/features/account/components/AddressesIndexListing.js +3 -4
- package/dist/features/account/components/BuyerAccountGuideView.js +7 -7
- package/dist/features/account/components/BuyerAuctionsGuideView.js +7 -7
- package/dist/features/account/components/BuyerOrdersGuideView.js +6 -6
- package/dist/features/account/components/BuyerShoppingGuideView.js +7 -7
- package/dist/features/account/components/UserOffersPanel.js +1 -1
- package/dist/features/account/components/UserSidebar.js +14 -10
- package/dist/features/account/components/UserSupportView.js +4 -4
- package/dist/features/admin/components/AdminAdsView.js +1 -1
- package/dist/features/admin/components/AdminAllEventEntriesView.js +4 -10
- package/dist/features/admin/components/AdminAnalyticsGuideView.js +3 -3
- package/dist/features/admin/components/AdminBidsView.js +3 -9
- package/dist/features/admin/components/AdminBlogView.js +4 -9
- package/dist/features/admin/components/AdminBrandEditorView.js +14 -17
- package/dist/features/admin/components/AdminBrandsView.js +4 -9
- package/dist/features/admin/components/AdminBundlesView.js +40 -59
- package/dist/features/admin/components/AdminCarouselView.js +8 -21
- package/dist/features/admin/components/AdminCartsView.js +3 -4
- package/dist/features/admin/components/AdminCatalogGuideView.js +5 -5
- package/dist/features/admin/components/AdminCategoriesView.js +4 -9
- package/dist/features/admin/components/AdminCategoryEditorView.js +1 -5
- package/dist/features/admin/components/AdminContactEditorView.js +2 -2
- package/dist/features/admin/components/AdminContactView.js +7 -25
- package/dist/features/admin/components/AdminContentGuideView.js +6 -6
- package/dist/features/admin/components/AdminCouponEditorView.js +14 -17
- package/dist/features/admin/components/AdminCouponsView.js +8 -16
- package/dist/features/admin/components/AdminFaqEditorView.js +14 -17
- package/dist/features/admin/components/AdminFaqsView.js +18 -69
- package/dist/features/admin/components/AdminFeatureEditorView.js +7 -9
- package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -1
- package/dist/features/admin/components/AdminFeaturesView.js +1 -1
- package/dist/features/admin/components/AdminGuideHubView.js +1 -1
- package/dist/features/admin/components/AdminHistoryView.js +1 -1
- package/dist/features/admin/components/AdminListingScaffold.js +1 -1
- package/dist/features/admin/components/AdminNewsletterView.js +5 -15
- package/dist/features/admin/components/AdminNotificationsView.js +3 -9
- package/dist/features/admin/components/AdminOrdersGuideView.js +5 -5
- package/dist/features/admin/components/AdminOrdersView.js +3 -9
- package/dist/features/admin/components/AdminPayoutsView.js +3 -9
- package/dist/features/admin/components/AdminPrizeDrawsView.js +4 -9
- package/dist/features/admin/components/AdminProductEditorView.js +1 -5
- package/dist/features/admin/components/AdminProductsView.js +5 -10
- package/dist/features/admin/components/AdminReturnRequestsView.js +1 -1
- package/dist/features/admin/components/AdminReviewsView.js +3 -9
- package/dist/features/admin/components/AdminScammerEditorView.js +3 -3
- package/dist/features/admin/components/AdminScammersView.js +6 -12
- package/dist/features/admin/components/AdminSectionsView.js +1 -1
- package/dist/features/admin/components/AdminSessionsView.js +3 -9
- package/dist/features/admin/components/AdminSiteSettingsView.js +1 -1
- package/dist/features/admin/components/AdminStoreAddressesView.js +1 -1
- package/dist/features/admin/components/AdminStoresGuideView.js +6 -6
- package/dist/features/admin/components/AdminStoresView.js +3 -9
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +3 -7
- package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +17 -20
- package/dist/features/admin/components/AdminSupportTicketDetailView.js +4 -4
- package/dist/features/admin/components/AdminSupportTicketsView.js +9 -15
- package/dist/features/admin/components/AdminTeamGuideView.js +4 -4
- package/dist/features/admin/components/AdminTeamView.js +6 -15
- package/dist/features/admin/components/AdminTrustGuideView.js +5 -5
- package/dist/features/admin/components/AdminUserEditorView.js +1 -1
- package/dist/features/admin/components/AdminUsersGuideView.js +5 -5
- package/dist/features/admin/components/AdminUsersView.js +3 -9
- package/dist/features/admin/components/AdminViewCards.js +1 -1
- package/dist/features/admin/components/AdminWishlistsView.js +1 -1
- package/dist/features/admin/components/DataTable.js +1 -1
- package/dist/features/admin/hooks/useAdminListing.d.ts +58 -0
- package/dist/features/admin/hooks/useAdminListing.js +71 -0
- package/dist/features/auctions/components/AuctionBidsTable.js +1 -1
- package/dist/features/auctions/components/AuctionDetailPageView.js +2 -2
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +2 -2
- package/dist/features/auctions/components/PlaceBidFormClient.js +1 -1
- package/dist/features/auth/components/VerifyEmailView.js +1 -1
- package/dist/features/auth/schemas/firestore.d.ts +1 -0
- package/dist/features/blog/components/BlogIndexListing.js +3 -6
- package/dist/features/blog/components/BlogListView.js +1 -1
- package/dist/features/blog/components/BlogPostView.js +1 -1
- package/dist/features/cart/components/CartDrawer.js +1 -1
- package/dist/features/categories/components/CategoriesIndexListing.js +3 -6
- package/dist/features/categories/components/CategoryDetailPageView.js +1 -1
- package/dist/features/checkout/components/CheckoutStepper.js +1 -1
- package/dist/features/collections/components/CollectionCard.js +1 -1
- package/dist/features/copilot/components/AdminCopilotView.js +2 -2
- package/dist/features/events/components/AdminEventsView.js +4 -4
- package/dist/features/events/components/EventPollWidget.js +2 -2
- package/dist/features/events/components/EventStatusBadge.js +4 -4
- package/dist/features/events/components/EventsIndexListing.js +3 -4
- package/dist/features/events/components/SpinWheelView.js +1 -1
- package/dist/features/faq/components/FAQAccordion.js +2 -2
- package/dist/features/forms/Input.js +3 -3
- package/dist/features/forms/Select.js +2 -2
- package/dist/features/forms/Textarea.js +2 -2
- package/dist/features/forms/utils.d.ts +1 -1
- package/dist/features/forms/utils.js +1 -1
- package/dist/features/homepage/components/AnnouncementBar.d.ts +4 -1
- package/dist/features/homepage/components/AnnouncementBar.js +51 -4
- package/dist/features/homepage/components/CharacterHotspotForm.js +2 -2
- package/dist/features/homepage/components/MarketplaceHomepageView.d.ts +3 -1
- package/dist/features/homepage/components/MarketplaceHomepageView.js +2 -2
- package/dist/features/homepage/components/index.d.ts +1 -1
- package/dist/features/homepage/components/index.js +1 -1
- package/dist/features/homepage/lib/section-renderer.d.ts +2 -2
- package/dist/features/homepage/lib/section-renderer.js +2 -2
- package/dist/features/layout/BottomActions.js +2 -2
- package/dist/features/layout/ListingLayout.js +3 -3
- package/dist/features/layout/TitleBarLayout.js +1 -1
- package/dist/features/media/index.d.ts +2 -0
- package/dist/features/media/index.js +1 -0
- package/dist/features/media/modals/ImageCropModal.js +1 -1
- package/dist/features/media/modals/ImageEditor.d.ts +12 -0
- package/dist/features/media/modals/ImageEditor.js +73 -0
- package/dist/features/media/upload/ImageUpload.d.ts +5 -1
- package/dist/features/media/upload/ImageUpload.js +33 -8
- package/dist/features/media/upload/MediaUploadField.d.ts +5 -1
- package/dist/features/media/upload/MediaUploadField.js +26 -12
- package/dist/features/orders/components/OrdersList.js +7 -7
- package/dist/features/orders/components/RefundHistoryTable.js +2 -2
- package/dist/features/orders/components/RefundRequestView.js +3 -3
- package/dist/features/orders/repository/orders.repository.d.ts +0 -1
- package/dist/features/orders/repository/orders.repository.js +0 -1
- package/dist/features/orders/server.d.ts +1 -1
- package/dist/features/orders/server.js +1 -1
- package/dist/features/pre-orders/components/PreOrderActionsClient.js +1 -1
- package/dist/features/pre-orders/components/PreOrderBadge.js +4 -4
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -1
- package/dist/features/pre-orders/components/PreorderCard.js +2 -2
- package/dist/features/products/components/CustomSectionsEditor.js +1 -1
- package/dist/features/products/components/GroupSettingsPanel.js +64 -48
- package/dist/features/products/components/MakeOfferButton.js +2 -2
- package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -2
- package/dist/features/products/components/PrizeDrawItemsEditor.js +3 -3
- package/dist/features/products/components/PrizeRevealModal.js +3 -3
- package/dist/features/products/components/ProductDetailPageView.js +4 -4
- package/dist/features/products/components/ProductFeaturesSelector.js +1 -1
- package/dist/features/products/components/ProductGrid.js +3 -3
- package/dist/features/products/repository/products.repository.d.ts +0 -2
- package/dist/features/products/repository/products.repository.js +0 -2
- package/dist/features/products/server.d.ts +1 -1
- package/dist/features/products/server.js +1 -1
- package/dist/features/promotions/components/CouponCard.js +7 -7
- package/dist/features/promotions/components/CouponsIndexListing.js +3 -2
- package/dist/features/promotions/components/PromotionsView.js +1 -1
- package/dist/features/reviews/components/ReviewDetailShell.js +2 -2
- package/dist/features/reviews/components/ReviewsIndexListing.js +3 -4
- package/dist/features/reviews/components/ReviewsList.js +1 -1
- package/dist/features/reviews/repository/reviews.repository.d.ts +0 -1
- package/dist/features/reviews/repository/reviews.repository.js +0 -1
- package/dist/features/reviews/server.d.ts +1 -1
- package/dist/features/reviews/server.js +1 -1
- package/dist/features/seller/components/SellerAddressesView.js +11 -21
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +2 -2
- package/dist/features/seller/components/SellerAuctionsView.js +14 -23
- package/dist/features/seller/components/SellerBidsView.js +6 -6
- package/dist/features/seller/components/SellerBundlesView.js +13 -21
- package/dist/features/seller/components/SellerClassifiedView.js +14 -22
- package/dist/features/seller/components/SellerCouponEditorView.js +2 -2
- package/dist/features/seller/components/SellerCouponsView.js +14 -20
- package/dist/features/seller/components/SellerDigitalCodesView.js +13 -21
- package/dist/features/seller/components/SellerFeaturesView.js +1 -1
- package/dist/features/seller/components/SellerGroupedListingsView.js +6 -10
- package/dist/features/seller/components/SellerLiveView.js +15 -23
- package/dist/features/seller/components/SellerOffersPanel.js +2 -2
- package/dist/features/seller/components/SellerOffersView.js +4 -5
- package/dist/features/seller/components/SellerOrdersView.js +9 -23
- package/dist/features/seller/components/SellerPayoutMethodsView.js +13 -25
- package/dist/features/seller/components/SellerPayoutsView.js +4 -5
- package/dist/features/seller/components/SellerPreOrdersView.js +13 -22
- package/dist/features/seller/components/SellerPrizeDrawsView.js +13 -22
- package/dist/features/seller/components/SellerProductsCards.js +1 -1
- package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +1 -1
- package/dist/features/seller/components/SellerProductsFilterDrawer.js +3 -6
- package/dist/features/seller/components/SellerProductsView.js +10 -23
- package/dist/features/seller/components/SellerReviewsView.js +1 -1
- package/dist/features/seller/components/SellerShippingConfigsView.js +14 -26
- package/dist/features/seller/components/SellerStoreCategoriesView.js +16 -35
- package/dist/features/seller/components/SellerTemplatesView.js +27 -43
- package/dist/features/seller/components/analytics/SellerTopProducts.js +1 -1
- package/dist/features/stores/components/StoreFinanceGuideView.js +2 -2
- package/dist/features/stores/components/StoreHeader.js +1 -1
- package/dist/features/stores/components/StoreListingsGuideView.js +3 -3
- package/dist/features/stores/components/StoreOrdersGuideView.js +4 -4
- package/dist/features/stores/components/StoreReviewsListing.js +3 -4
- package/dist/features/stores/components/StoreSettingsGuideView.js +2 -2
- package/dist/features/stores/components/StoresIndexListing.js +3 -4
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +4 -4
- package/dist/features/wishlist/components/WishlistPage.js +1 -1
- package/dist/index.d.ts +4 -6
- package/dist/index.js +6 -12
- package/dist/react/contexts/SessionContext.d.ts +2 -0
- package/dist/react/contexts/SessionContext.js +2 -0
- package/dist/react/hooks/useEntityDelete.d.ts +15 -0
- package/dist/react/hooks/useEntityDelete.js +39 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +2 -0
- package/dist/repositories/index.d.ts +3 -3
- package/dist/repositories/index.js +3 -3
- package/dist/styles.css +286 -3
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/motion.d.ts +162 -0
- package/dist/tokens/motion.js +89 -0
- package/dist/ui/DataTable.js +3 -2
- package/dist/ui/components/Accordion.js +2 -1
- package/dist/ui/components/Card.d.ts +5 -2
- package/dist/ui/components/Card.js +29 -11
- package/dist/ui/components/Div.d.ts +2 -16
- package/dist/ui/components/Div.js +2 -16
- package/dist/ui/components/Layout.d.ts +9 -19
- package/dist/ui/components/Layout.js +9 -7
- package/dist/ui/components/ListingFilterDrawer.d.ts +10 -0
- package/dist/ui/components/ListingFilterDrawer.js +8 -0
- package/dist/ui/components/Modal.js +7 -4
- package/dist/ui/components/Motion.d.ts +75 -0
- package/dist/ui/components/Motion.js +122 -0
- package/dist/ui/components/Semantic.d.ts +81 -14
- package/dist/ui/components/Semantic.js +75 -10
- package/dist/ui/components/Semantic.style.css +261 -2
- package/dist/ui/components/SideDrawer.d.ts +1 -1
- package/dist/ui/components/SideDrawer.js +8 -6
- package/dist/ui/components/SideModal.d.ts +1 -1
- package/dist/ui/components/SideModal.js +11 -9
- package/dist/ui/components/StackedViewShell.js +6 -1
- package/dist/ui/components/Toast.js +5 -2
- package/dist/ui/components/Typography.d.ts +44 -3
- package/dist/ui/components/Typography.js +15 -30
- package/dist/ui/components/Typography.style.css +24 -0
- package/dist/ui/components/VacationBanner.js +2 -1
- package/dist/ui/components/surface-tokens.d.ts +70 -0
- package/dist/ui/components/surface-tokens.js +68 -0
- package/dist/ui/forms/FormShell.d.ts +6 -1
- package/dist/ui/forms/FormShell.js +32 -4
- package/dist/ui/index.d.ts +11 -2
- package/dist/ui/index.js +5 -2
- package/dist/validation/schemas.d.ts +28 -28
- package/package.json +3 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useCallback, useMemo } from "react";
|
|
4
|
+
import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
|
|
4
5
|
import { Plus } from "lucide-react";
|
|
5
6
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
7
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
@@ -8,6 +9,7 @@ import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, FilterDrawer
|
|
|
8
9
|
import { useBottomActions } from "../../layout";
|
|
9
10
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
11
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
12
|
+
import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
|
|
11
13
|
import { toRecordArray, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
12
14
|
import { TABLE_KEYS } from "../../../constants/table-keys";
|
|
13
15
|
const PAGE_SIZE = 25;
|
|
@@ -68,7 +70,13 @@ export function SellerTemplatesView({ onDelete, onBulkDelete, onDuplicate, }) {
|
|
|
68
70
|
const [savingError, setSavingError] = useState(null);
|
|
69
71
|
// Delete state
|
|
70
72
|
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
71
|
-
const
|
|
73
|
+
const { deletingId, handleDelete: performDelete } = useEntityDelete({
|
|
74
|
+
endpoint: SELLER_ENDPOINTS.TEMPLATE_BY_ID,
|
|
75
|
+
deleteFn: onDelete,
|
|
76
|
+
successMessage: "Template deleted.",
|
|
77
|
+
onSuccess: () => { refetch?.(); },
|
|
78
|
+
fetchOptions: { credentials: "include" },
|
|
79
|
+
});
|
|
72
80
|
const [duplicatingId, setDuplicatingId] = useState(null);
|
|
73
81
|
const { showToast } = useToast();
|
|
74
82
|
const commitSearch = useCallback(() => {
|
|
@@ -184,28 +192,9 @@ export function SellerTemplatesView({ onDelete, onBulkDelete, onDuplicate, }) {
|
|
|
184
192
|
}
|
|
185
193
|
}, [draft, drawerMode, editingId, closeDrawer, refetch, showToast]);
|
|
186
194
|
const handleDelete = useCallback(async (id) => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
await onDelete(id);
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
await fetch(SELLER_ENDPOINTS.TEMPLATE_BY_ID(id), {
|
|
194
|
-
method: "DELETE",
|
|
195
|
-
credentials: "include",
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
refetch?.();
|
|
199
|
-
showToast("Template deleted.", "success");
|
|
200
|
-
}
|
|
201
|
-
catch (err) {
|
|
202
|
-
showToast(err instanceof Error ? err.message : "Failed to delete template.", "error");
|
|
203
|
-
}
|
|
204
|
-
finally {
|
|
205
|
-
setDeletingId(null);
|
|
206
|
-
setDeleteTargetId(null);
|
|
207
|
-
}
|
|
208
|
-
}, [onDelete, refetch, showToast]);
|
|
195
|
+
await performDelete(id);
|
|
196
|
+
setDeleteTargetId(null);
|
|
197
|
+
}, [performDelete]);
|
|
209
198
|
const handleDuplicate = useCallback(async (row) => {
|
|
210
199
|
setDuplicatingId(row.id);
|
|
211
200
|
try {
|
|
@@ -237,27 +226,22 @@ export function SellerTemplatesView({ onDelete, onBulkDelete, onDuplicate, }) {
|
|
|
237
226
|
}
|
|
238
227
|
}, [onDuplicate, refetch, showToast]);
|
|
239
228
|
const bulkActions = [
|
|
240
|
-
{
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}
|
|
254
|
-
selection.clearSelection();
|
|
255
|
-
refetch?.();
|
|
256
|
-
},
|
|
257
|
-
},
|
|
229
|
+
buildBulkAction(ACTIONS.STORE["delete-template"], async () => {
|
|
230
|
+
if (onBulkDelete) {
|
|
231
|
+
await onBulkDelete(selection.selectedIds);
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
await Promise.all(selection.selectedIds.map((id) => fetch(SELLER_ENDPOINTS.TEMPLATE_BY_ID(id), {
|
|
235
|
+
method: "DELETE",
|
|
236
|
+
credentials: "include",
|
|
237
|
+
})));
|
|
238
|
+
}
|
|
239
|
+
selection.clearSelection();
|
|
240
|
+
refetch?.();
|
|
241
|
+
}),
|
|
258
242
|
];
|
|
259
243
|
useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
|
|
260
|
-
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search templates by name...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: sort, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, showTableView: true, view: "table", onViewChange: () => { }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: openCreate, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Template" })] }) }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: safePage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), selection.selectedCount > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-
|
|
244
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search templates by name...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: sort, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, showTableView: true, view: "table", onViewChange: () => { }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: openCreate, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Template" })] }) }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: safePage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), selection.selectedCount > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-error-surface dark:border-red-900/60 px-4 py-3 text-sm text-error", children: errorMessage })), isLoading ? (_jsx(Div, { className: "space-y-2", children: Array.from({ length: 5 }).map((_, i) => (_jsx(Div, { className: "h-14 animate-pulse rounded-xl border border-zinc-100 dark:border-slate-700 bg-zinc-50 dark:bg-slate-800" }, i))) })) : pageRows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: q || conditionFilter
|
|
261
245
|
? "No templates match your search or filters"
|
|
262
246
|
: "No templates yet — add your first product template" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: pageRows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids), actions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
263
247
|
{
|
|
@@ -275,5 +259,5 @@ export function SellerTemplatesView({ onDelete, onBulkDelete, onDuplicate, }) {
|
|
|
275
259
|
onClick: () => setDeleteTargetId(row.id),
|
|
276
260
|
disabled: deletingId === row.id,
|
|
277
261
|
},
|
|
278
|
-
] })) }))] }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: () => setPendingCondition(""), activeCount: filterActiveCount, hideTrigger: true, children: _jsx(Div, { className: "space-y-4 p-4", children: _jsxs(Div, { children: [_jsx("label", { className: "mb-1.5 block text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Condition" }), _jsx(Select, { value: pendingCondition, onValueChange: setPendingCondition, options: CONDITION_OPTIONS })] }) }) }), _jsx(SideDrawer, { isOpen: drawerOpen, onClose: closeDrawer, title: drawerMode === "create" ? "New Template" : "Edit Template", mode: drawerMode, isDirty: draft.name !== "" || draft.category !== "" || draft.brand !== "", footer: _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: closeDrawer, disabled: saving, children: "Cancel" }), _jsx(Button, { size: "sm", isLoading: saving, onClick: handleSave, children: drawerMode === "create" ? "Create Template" : "Save Changes" })] }), children: _jsxs(Stack, { gap: "md", children: [savingError && (_jsx(Div, { className: "rounded-lg border border-red-200 bg-
|
|
262
|
+
] })) }))] }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: () => setPendingCondition(""), activeCount: filterActiveCount, hideTrigger: true, children: _jsx(Div, { className: "space-y-4 p-4", children: _jsxs(Div, { children: [_jsx("label", { className: "mb-1.5 block text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Condition" }), _jsx(Select, { value: pendingCondition, onValueChange: setPendingCondition, options: CONDITION_OPTIONS })] }) }) }), _jsx(SideDrawer, { isOpen: drawerOpen, onClose: closeDrawer, title: drawerMode === "create" ? "New Template" : "Edit Template", mode: drawerMode, isDirty: draft.name !== "" || draft.category !== "" || draft.brand !== "", footer: _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: closeDrawer, disabled: saving, children: "Cancel" }), _jsx(Button, { size: "sm", isLoading: saving, onClick: handleSave, children: drawerMode === "create" ? "Create Template" : "Save Changes" })] }), children: _jsxs(Stack, { gap: "md", children: [savingError && (_jsx(Div, { className: "rounded-lg border border-red-200 bg-error-surface dark:border-red-900/60 px-3 py-2 text-sm text-error", children: savingError })), _jsx(Input, { id: "tpl-name", label: "Template Name", value: draft.name, onChange: (e) => setDraft((d) => ({ ...d, name: e.target.value })), placeholder: "e.g. Pok\u00E9mon Card Standard", required: true, autoComplete: "off" }), _jsx(Input, { id: "tpl-description", label: "Description (optional)", value: draft.description, onChange: (e) => setDraft((d) => ({ ...d, description: e.target.value })), placeholder: "Short note about when to use this template", autoComplete: "off" }), _jsx(Input, { id: "tpl-category", label: "Category (optional)", value: draft.category, onChange: (e) => setDraft((d) => ({ ...d, category: e.target.value })), placeholder: "e.g. trading-cards", autoComplete: "off" }), _jsx(Input, { id: "tpl-brand", label: "Brand (optional)", value: draft.brand, onChange: (e) => setDraft((d) => ({ ...d, brand: e.target.value })), placeholder: "e.g. Pok\u00E9mon Company", autoComplete: "off" }), _jsx(Select, { label: "Condition (optional)", name: "tpl-condition", value: draft.condition, onValueChange: (v) => setDraft((d) => ({ ...d, condition: v })), options: CONDITION_OPTIONS })] }) }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Template", message: "Are you sure you want to delete this template? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
|
|
279
263
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Div, Heading, Span, Text } from "../../../../ui";
|
|
3
3
|
export function SellerTopProducts({ products, labels = {}, formatRevenue = (amount) => String(amount), renderProductLink, renderEmptyAction, className = "", }) {
|
|
4
|
-
return (_jsxs(Div, { className: `bg-white dark:bg-neutral-900 rounded-xl border border-neutral-200 dark:border-neutral-800 p-4 sm:p-6 ${className}`, children: [labels.title && (_jsx(Heading, { level: 3, className: "text-base font-semibold mb-4", children: labels.title })), products.length > 0 ? (_jsx(Div, { className: "divide-y divide-neutral-100 dark:divide-neutral-800", children: products.map((product, index) => (_jsxs(Div, { className: "flex items-center gap-4 py-3", children: [_jsxs(Span, { className: "w-6 text-sm font-bold text-neutral-500 dark:text-neutral-400", children: [index + 1, "."] }), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsx(Text, { className: "text-sm font-medium truncate", children: product.title }), _jsxs(Text, { className: "text-xs text-neutral-500 dark:text-neutral-400", children: [product.orders, " ", labels.ordersLabel ?? "orders"] })] }), _jsxs(Div, { className: "text-right ml-2", children: [_jsx(Span, { className: "text-sm font-semibold text-
|
|
4
|
+
return (_jsxs(Div, { className: `bg-white dark:bg-neutral-900 rounded-xl border border-neutral-200 dark:border-neutral-800 p-4 sm:p-6 ${className}`, children: [labels.title && (_jsx(Heading, { level: 3, className: "text-base font-semibold mb-4", children: labels.title })), products.length > 0 ? (_jsx(Div, { className: "divide-y divide-neutral-100 dark:divide-neutral-800", children: products.map((product, index) => (_jsxs(Div, { className: "flex items-center gap-4 py-3", children: [_jsxs(Span, { className: "w-6 text-sm font-bold text-neutral-500 dark:text-neutral-400", children: [index + 1, "."] }), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsx(Text, { className: "text-sm font-medium truncate", children: product.title }), _jsxs(Text, { className: "text-xs text-neutral-500 dark:text-neutral-400", children: [product.orders, " ", labels.ordersLabel ?? "orders"] })] }), _jsxs(Div, { className: "text-right ml-2", children: [_jsx(Span, { className: "text-sm font-semibold text-success", children: formatRevenue(product.revenue) }), renderProductLink?.(product)] })] }, product.productId))) })) : (_jsxs(Div, { className: "text-center py-8", children: [_jsx(Text, { className: "text-sm font-medium", children: labels.noData ?? "No data available" }), labels.noDataDescription && (_jsx(Text, { className: "text-xs text-neutral-500 dark:text-neutral-400 mt-1", children: labels.noDataDescription })), renderEmptyAction?.()] }))] }));
|
|
5
5
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ArrowLeft } from "lucide-react";
|
|
3
|
-
import { Alert, Div, Heading, Section, Text } from "../../../ui";
|
|
3
|
+
import { Alert, Div, Heading, Section, Span, Text } from "../../../ui";
|
|
4
4
|
import { ROUTES } from "../../../next/routing/route-map";
|
|
5
5
|
const SUBHEADING = "mb-1 font-semibold text-[var(--appkit-color-text)]";
|
|
6
6
|
const LIST_DISC = "list-disc leading-relaxed";
|
|
@@ -64,7 +64,7 @@ const COUPON_FIELDS = [
|
|
|
64
64
|
},
|
|
65
65
|
];
|
|
66
66
|
function CouponsSection() {
|
|
67
|
-
return (_jsxs(Div, { className: SECTION_BODY, children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Admin coupons vs store coupons" }), _jsxs("ul", { className: "space-y-1 pl-5", children: [_jsxs("li", { className: LIST_DISC, children: [_jsx("
|
|
67
|
+
return (_jsxs(Div, { className: SECTION_BODY, children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Admin coupons vs store coupons" }), _jsxs("ul", { className: "space-y-1 pl-5", children: [_jsxs("li", { className: LIST_DISC, children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Admin coupons" }), " \u2014 created by LetItRip and apply platform-wide (all stores). You cannot create these."] }), _jsxs("li", { className: LIST_DISC, children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Store coupons" }), " \u2014 created by you. Apply only to purchases from your store. You control the terms."] }), _jsx("li", { className: LIST_DISC, children: "Admin coupons and store coupons can stack if the admin coupon has \"Combine with seller coupons\" enabled. If not, only the better coupon is applied automatically." })] })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Coupon field reference" }), _jsx(Div, { className: "space-y-3", children: COUPON_FIELDS.map(({ field, detail }) => (_jsxs(Div, { className: "flex gap-3", children: [_jsx(Text, { className: "shrink-0 w-32 font-semibold text-[var(--appkit-color-text)] text-sm", children: field }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] text-sm leading-relaxed", children: detail })] }, field))) })] })] }));
|
|
68
68
|
}
|
|
69
69
|
// -- Section 4: Promoted & featured listings ----------------------------------
|
|
70
70
|
function PromotedSection() {
|
|
@@ -3,7 +3,7 @@ import { Button, Div, Heading, RichText, Row, Section, Span, Text, } from "../..
|
|
|
3
3
|
import { normalizeRichTextHtml } from "../../../utils/string.formatter";
|
|
4
4
|
import { ShareButton } from "../../products/components/ShareButton";
|
|
5
5
|
export function StoreHeader({ store, labels = {}, onFollow, className = "", }) {
|
|
6
|
-
return (_jsxs(Section, {
|
|
6
|
+
return (_jsxs(Section, { surface: "default", className: `border-b border-gray-200 dark:border-slate-700 ${className}`, children: [store.storeBannerURL && (_jsx(Div, { className: "h-40 md:h-56 overflow-hidden bg-gray-100 dark:bg-slate-800", children: _jsx(Div, { role: "img", "aria-label": `${store.storeName} banner`, className: "h-full w-full bg-center bg-cover", style: { backgroundImage: `url(${store.storeBannerURL})` } }) })), _jsxs(Div, { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4", children: [_jsxs(Div, { className: "flex items-end gap-4", children: [store.storeLogoURL ? (_jsx(Div, { role: "img", "aria-label": store.storeName, className: "-mt-8 h-16 w-16 rounded-xl border-2 border-white dark:border-slate-800 bg-center bg-cover shadow-sm", style: { backgroundImage: `url(${store.storeLogoURL})` } })) : (_jsx(Div, { className: "-mt-8 h-16 w-16 rounded-xl border-2 border-white dark:border-slate-800 bg-orange-100 dark:bg-orange-900/30 flex items-center justify-center text-orange-600 dark:text-orange-400 font-bold text-2xl shadow-sm", children: store.storeName[0]?.toUpperCase() })), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Div, { className: "flex flex-wrap items-center gap-2 mb-0.5", children: [_jsx(Heading, { level: 1, className: "text-xl font-bold text-gray-900 dark:text-zinc-100", children: store.storeName }), store.averageRating != null && store.averageRating > 0 && (_jsxs(Span, { className: "inline-flex items-center gap-1 text-sm font-medium text-amber-500", children: ["\u2605 ", store.averageRating.toFixed(1)] }))] }), _jsxs(Row, { className: "gap-3 text-xs text-gray-500 dark:text-zinc-400 mb-0.5", children: [store.category && _jsx(Span, { className: "capitalize", children: store.category }), store.totalProducts != null && store.totalProducts > 0 && (_jsxs(Span, { children: [store.totalProducts, " ", labels.products ?? "products"] })), store.totalReviews != null && store.totalReviews > 0 && (_jsxs(Span, { children: [store.totalReviews, " ", labels.reviews ?? "reviews"] })), store.itemsSold != null && store.itemsSold > 0 && (_jsxs(Span, { children: [store.itemsSold, " ", labels.sold ?? "sold"] }))] }), store.storeDescription && (_jsx(RichText, { html: normalizeRichTextHtml(store.storeDescription), copyableCode: true, className: "mt-0.5" }))] }), _jsxs(Row, { gap: "sm", align: "center", className: "shrink-0", children: [_jsx(ShareButton, { title: store.storeName }), onFollow && (_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onFollow(store.storeSlug), className: "rounded-lg border border-orange-500 px-4 py-2 text-sm font-medium text-orange-500 hover:bg-orange-50 transition-colors", children: labels.follow ?? "Follow" }))] })] }), store.isVacationMode && (_jsx(Text, { className: "mt-3 rounded-lg bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 px-3 py-2 text-sm text-yellow-700 dark:text-yellow-300", children: store.vacationMessage ??
|
|
7
7
|
labels.vacationMode ??
|
|
8
8
|
"Store is on vacation mode" }))] })] }));
|
|
9
9
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ArrowLeft } from "lucide-react";
|
|
3
|
-
import { Alert, Div, Heading, Section, Text } from "../../../ui";
|
|
3
|
+
import { Alert, Div, Heading, Section, Span, Text } from "../../../ui";
|
|
4
4
|
import { ROUTES } from "../../../next/routing/route-map";
|
|
5
5
|
const SUBHEADING = "mb-1 font-semibold text-[var(--appkit-color-text)]";
|
|
6
6
|
const LIST_DISC = "list-disc leading-relaxed";
|
|
@@ -91,7 +91,7 @@ function StandardWalkthrough() {
|
|
|
91
91
|
}
|
|
92
92
|
// -- Section 3: Auction walkthrough --------------------------------------------
|
|
93
93
|
function AuctionWalkthrough() {
|
|
94
|
-
return (_jsxs(Div, { className: "space-y-4 text-sm text-[var(--appkit-color-text-muted)]", children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Reserve price vs starting bid" }), _jsxs(Text, { className: "leading-relaxed", children: ["The ", _jsx("
|
|
94
|
+
return (_jsxs(Div, { className: "space-y-4 text-sm text-[var(--appkit-color-text-muted)]", children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Reserve price vs starting bid" }), _jsxs(Text, { className: "leading-relaxed", children: ["The ", _jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "starting bid" }), " is the minimum first bid a buyer can place. The ", _jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "reserve price" }), " is the minimum price you are willing to accept \u2014 if bidding does not reach the reserve, you are not obligated to sell. The reserve is hidden from buyers."] })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Bid increment" }), _jsx(Div, { className: "overflow-x-auto", children: _jsxs("table", { className: "text-xs min-w-[320px]", children: [_jsx("thead", { children: _jsxs("tr", { className: "border-b border-[var(--appkit-color-border)]", children: [_jsx("th", { className: "py-2 pr-4 text-left font-semibold text-[var(--appkit-color-text)]", children: "Current high bid" }), _jsx("th", { className: "py-2 text-left font-semibold text-[var(--appkit-color-text)]", children: "Minimum increment" })] }) }), _jsx("tbody", { className: "divide-y divide-[var(--appkit-color-border)]", children: [
|
|
95
95
|
["₹0 – ₹499", "₹10"],
|
|
96
96
|
["₹500 – ₹1,999", "₹25"],
|
|
97
97
|
["₹2,000 – ₹9,999", "₹100"],
|
|
@@ -101,7 +101,7 @@ function AuctionWalkthrough() {
|
|
|
101
101
|
}
|
|
102
102
|
// -- Section 4: Pre-order walkthrough ------------------------------------------
|
|
103
103
|
function PreorderWalkthrough() {
|
|
104
|
-
return (_jsxs(Div, { className: "space-y-4 text-sm text-[var(--appkit-color-text-muted)]", children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Deposit mechanic" }), _jsxs(Text, { className: "leading-relaxed", children: ["Set a ", _jsx("
|
|
104
|
+
return (_jsxs(Div, { className: "space-y-4 text-sm text-[var(--appkit-color-text-muted)]", children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Deposit mechanic" }), _jsxs(Text, { className: "leading-relaxed", children: ["Set a ", _jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "deposit percentage" }), " (e.g. 20%). Buyers pay the deposit at checkout. The balance is collected when the item arrives and you mark the pre-order ready. Buyers see both amounts clearly on the checkout page."] })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Expected delivery date" }), _jsx(Text, { className: "leading-relaxed", children: "Set a realistic estimate. Buyers rely on this to decide whether to pre-order. You can update the date later, but repeated delays hurt your store rating." })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "\"Confirmed supplier\" requirement" }), _jsx(Text, { className: "leading-relaxed", children: "Only list pre-orders for items you have confirmed supply for \u2014 e.g. you have placed a purchase order with a distributor or manufacturer. Speculative pre-orders without supplier confirmation violate platform rules and may result in store suspension." })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Cancellation rules" }), _jsx(Text, { className: "leading-relaxed", children: "Buyers can cancel a pre-order within 24 hours of placing it. After 24 hours, cancellation requires seller approval. If you cannot fulfill the pre-order, initiate cancellation promptly \u2014 the deposit is refunded automatically." })] })] }));
|
|
105
105
|
}
|
|
106
106
|
// -- Section 5: Product status lifecycle ---------------------------------------
|
|
107
107
|
const STATUS_LIFECYCLE = `
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ArrowLeft } from "lucide-react";
|
|
3
|
-
import { Accordion, Alert, Div, Heading, Section, Text } from "../../../ui";
|
|
3
|
+
import { Accordion, Alert, Div, Heading, Section, Span, Text } from "../../../ui";
|
|
4
4
|
import { ROUTES } from "../../../next/routing/route-map";
|
|
5
5
|
const SUBHEADING = "mb-1 font-semibold text-[var(--appkit-color-text)]";
|
|
6
6
|
const LIST_DISC = "list-disc leading-relaxed";
|
|
@@ -85,15 +85,15 @@ function CarriersSection() {
|
|
|
85
85
|
}
|
|
86
86
|
// -- Section 4: Cancellations -------------------------------------------------
|
|
87
87
|
function CancellationsSection() {
|
|
88
|
-
return (_jsxs(Div, { className: SECTION_BODY, children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Who can cancel" }), _jsxs("ul", { className: "space-y-1 pl-5", children: [_jsxs("li", { className: LIST_DISC, children: [_jsx("
|
|
88
|
+
return (_jsxs(Div, { className: SECTION_BODY, children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Who can cancel" }), _jsxs("ul", { className: "space-y-1 pl-5", children: [_jsxs("li", { className: LIST_DISC, children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Buyer" }), " \u2014 can self-cancel any time before the order reaches SHIPPED status."] }), _jsxs("li", { className: LIST_DISC, children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "Seller (you)" }), " \u2014 can cancel any time before SHIPPED (e.g. item found damaged during packaging)."] }), _jsxs("li", { className: LIST_DISC, children: [_jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "LetItRip admin" }), " \u2014 can force-cancel at any status for policy violations or unresolved disputes."] })] })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Refund timeline" }), _jsxs(Text, { className: "leading-relaxed", children: ["Cancellation triggers an automatic Razorpay refund. Funds typically reach the buyer in", _jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: " 3\u20137 business days" }), " depending on the payment method (UPI is usually 1\u20132 business days)."] })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Already shipped?" }), _jsx(Text, { className: "leading-relaxed", children: "If you have already dispatched the item but the order is still PROCESSING (tracking not yet entered), enter the tracking number and mark it SHIPPED first \u2014 then contact the buyer via order notes. Do not cancel after shipping; work with the buyer to return the item through the normal return flow." })] }), _jsx(Alert, { variant: "warning", title: "Repeated cancellations affect your rating", children: "Cancelling more than 5% of your orders per month will reduce your store rating and may result in listing restrictions. Only cancel if you genuinely cannot fulfil \u2014 never as a price-change workaround." })] }));
|
|
89
89
|
}
|
|
90
90
|
// -- Section 5: Return requests -----------------------------------------------
|
|
91
91
|
function ReturnsSection() {
|
|
92
|
-
return (_jsxs(Div, { className: SECTION_BODY, children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "When a buyer can raise a return" }), _jsxs(Text, { className: "leading-relaxed", children: ["Buyers can open a return request within the ", _jsx("
|
|
92
|
+
return (_jsxs(Div, { className: SECTION_BODY, children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "When a buyer can raise a return" }), _jsxs(Text, { className: "leading-relaxed", children: ["Buyers can open a return request within the ", _jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "return window" }), " after the order is marked DELIVERED. The default return window is 7 days. Stores with the ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "extended_return_window" }), " capability can offer 30 days."] })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "What you see" }), _jsxs("ul", { className: "space-y-1 pl-5", children: [_jsx("li", { className: LIST_DISC, children: "The buyer's reason for return (pre-defined category + optional description)." }), _jsx("li", { className: LIST_DISC, children: "Photos of the item as received." }), _jsx("li", { className: LIST_DISC, children: "A 3-day SLA to respond before LetItRip mediates." })] })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Accepting a return" }), _jsx(Text, { className: "leading-relaxed", children: "Click \"Accept return\" in the order detail. The buyer will receive a return shipping label or instructions. Once the item is received by you and you confirm it, the refund is triggered automatically via Razorpay. The payout for this order is withheld." })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Rejecting a return" }), _jsx(Text, { className: "leading-relaxed", children: "You can reject a return request with a reason. If the buyer disagrees, they can escalate to LetItRip support. LetItRip will mediate \u2014 if the evidence supports the buyer, the return will be approved regardless of your rejection. Unjustified rejections count against your seller rating." })] })] }));
|
|
93
93
|
}
|
|
94
94
|
// -- Section 6: Auction orders ------------------------------------------------
|
|
95
95
|
function AuctionOrdersSection() {
|
|
96
|
-
return (_jsxs(Div, { className: SECTION_BODY, children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Payment window" }), _jsxs(Text, { className: "leading-relaxed", children: ["Auction winners have ", _jsx("
|
|
96
|
+
return (_jsxs(Div, { className: SECTION_BODY, children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Payment window" }), _jsxs(Text, { className: "leading-relaxed", children: ["Auction winners have ", _jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "48 hours" }), " from auction end to complete payment. You will receive a notification when the auction closes and again when the winner pays."] })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "If the winner does not pay" }), _jsxs("ul", { className: "space-y-1 pl-5", children: [_jsx("li", { className: LIST_DISC, children: "The order is automatically cancelled after 48 hours." }), _jsx("li", { className: LIST_DISC, children: "You are notified. The winner may receive a bid restriction on their account." }), _jsx("li", { className: LIST_DISC, children: "If \"offer to next bidder\" is enabled in your auction settings, the next-highest bidder is contacted automatically." }), _jsx("li", { className: LIST_DISC, children: "You can re-list the item immediately." })] })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Fulfilment after payment" }), _jsx(Text, { className: "leading-relaxed", children: "Once the auction order is paid, it enters PENDING status \u2014 the same fulfilment flow as a standard order applies. Process and ship within your stated dispatch time." })] }), _jsx(Alert, { variant: "info", title: "Auction orders cannot be cancelled by the buyer", children: "Unlike standard orders, auction orders cannot be self-cancelled by the buyer after payment. If a buyer requests a cancel, it requires seller approval. Treat winning bids as binding commitments." })] }));
|
|
97
97
|
}
|
|
98
98
|
// -- Section 7: Common questions (FAQ collapsibles) ----------------------------
|
|
99
99
|
const FAQS = [
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useCallback, useMemo } from "react";
|
|
4
|
-
import { X } from "lucide-react";
|
|
5
4
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
|
-
import { ListingToolbar, Pagination, Row, Span, Text } from "../../../ui";
|
|
5
|
+
import { ListingFilterDrawer, ListingToolbar, Pagination, Row, Span, Text } from "../../../ui";
|
|
7
6
|
import { ReviewCard } from "../../reviews/components/ReviewsList";
|
|
8
7
|
import { ReviewFilters, REVIEW_PUBLIC_SORT_OPTIONS } from "../../reviews/components/ReviewFilters";
|
|
9
8
|
import { useStoreReviews } from "../hooks/useStores";
|
|
@@ -102,5 +101,5 @@ export function StoreReviewsListing({ storeSlug }) {
|
|
|
102
101
|
value: opt.value,
|
|
103
102
|
label: SORT_OPTION_LABELS[opt.key] ?? opt.key,
|
|
104
103
|
}));
|
|
105
|
-
return (_jsxs("div", { className: "min-h-screen", children: [totalReviews > 0 && (_jsxs(Row, { align: "center", gap: "sm", className: "px-4 py-3 border-b border-zinc-200 dark:border-slate-700", children: [_jsx(Span, { className: "text-2xl font-bold text-zinc-900 dark:text-zinc-100", children: averageRating.toFixed(1) }), _jsxs(Span, { className: "text-zinc-500 dark:text-zinc-400 text-sm", children: ["/ 5 \u00B7 ", totalReviews, " reviews"] })] })), _jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search reviews...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: sort, sortOptions: sortOptions, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6 px-4", children: isLoading ? (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: Array.from({ length: 6 }).map((_, i) => (_jsx("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: _jsxs("div", { className: "p-4 space-y-3", children: [_jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" })] }) }, i))) })) : reviews.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No reviews found." })) : view === "list" ? (_jsx("div", { className: "flex flex-col divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800", children: reviews.map((review) => (_jsx(ReviewCard, { review: review, context: "store" }, review.id))) })) : (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: reviews.map((review) => (_jsx(ReviewCard, { review: review, context: "store" }, review.id))) })) }),
|
|
104
|
+
return (_jsxs("div", { className: "min-h-screen", children: [totalReviews > 0 && (_jsxs(Row, { align: "center", gap: "sm", className: "px-4 py-3 border-b border-zinc-200 dark:border-slate-700", children: [_jsx(Span, { className: "text-2xl font-bold text-zinc-900 dark:text-zinc-100", children: averageRating.toFixed(1) }), _jsxs(Span, { className: "text-zinc-500 dark:text-zinc-400 text-sm", children: ["/ 5 \u00B7 ", totalReviews, " reviews"] })] })), _jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search reviews...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: sort, sortOptions: sortOptions, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, view: view, onViewChange: handleViewToggle, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6 px-4", children: isLoading ? (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: Array.from({ length: 6 }).map((_, i) => (_jsx("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: _jsxs("div", { className: "p-4 space-y-3", children: [_jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" })] }) }, i))) })) : reviews.length === 0 ? (_jsx(Text, { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No reviews found." })) : view === "list" ? (_jsx("div", { className: "flex flex-col divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800", children: reviews.map((review) => (_jsx(ReviewCard, { review: review, context: "store" }, review.id))) })) : (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: reviews.map((review) => (_jsx(ReviewCard, { review: review, context: "store" }, review.id))) })) }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsx(ReviewFilters, { table: pendingTable, variant: "public" }) })] }));
|
|
106
105
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ArrowLeft } from "lucide-react";
|
|
3
|
-
import { Alert, Div, Heading, Section, Text } from "../../../ui";
|
|
3
|
+
import { Alert, Div, Heading, Section, Span, Text } from "../../../ui";
|
|
4
4
|
import { ROUTES } from "../../../next/routing/route-map";
|
|
5
5
|
const SUBHEADING = "mb-1 font-semibold text-[var(--appkit-color-text)]";
|
|
6
6
|
const LIST_DISC = "list-disc leading-relaxed";
|
|
@@ -19,7 +19,7 @@ function ShippingSection() {
|
|
|
19
19
|
}
|
|
20
20
|
// -- Section 3: Return policy -------------------------------------------------
|
|
21
21
|
function ReturnPolicySection() {
|
|
22
|
-
return (_jsxs(Div, { className: SECTION_BODY, children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Store-level return window" }), _jsxs(Text, { className: "leading-relaxed", children: ["The default return window is ", _jsx("
|
|
22
|
+
return (_jsxs(Div, { className: SECTION_BODY, children: [_jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Store-level return window" }), _jsxs(Text, { className: "leading-relaxed", children: ["The default return window is ", _jsx(Span, { weight: "bold", className: "text-[var(--appkit-color-text)]", children: "7 days" }), " from the DELIVERED date. Stores with the", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded mx-1", children: "extended_return_window" }), "capability can offer 30 days. The return window is displayed on every product detail page in the Returns tab."] })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "Non-returnable categories" }), _jsxs("ul", { className: "space-y-1 pl-5", children: [_jsx("li", { className: LIST_DISC, children: "Opened card packs (boosters, elite trainer boxes)." }), _jsx("li", { className: LIST_DISC, children: "Cracked or opened graded slabs \u2014 unless the defect was documented before shipping." }), _jsx("li", { className: LIST_DISC, children: "Items explicitly marked \"Final Sale\" in the listing." })] })] }), _jsxs(Div, { children: [_jsx(Text, { className: SUBHEADING, children: "What buyers see" }), _jsx(Text, { className: "leading-relaxed", children: "Buyers see the return window and non-returnable note in the product detail page Returns tab before purchasing. This cannot be suppressed \u2014 it is platform policy to always show return terms." })] })] }));
|
|
23
23
|
}
|
|
24
24
|
// -- Section 4: Vacation mode -------------------------------------------------
|
|
25
25
|
function VacationModeSection() {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useCallback, useMemo } from "react";
|
|
4
|
-
import { SlidersHorizontal, X } from "lucide-react";
|
|
5
4
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
5
|
import { useStores } from "../hooks/useStores";
|
|
7
|
-
import { BulkActionBar, ListingToolbar, Pagination, Text } from "../../../ui";
|
|
6
|
+
import { BulkActionBar, ListingFilterDrawer, ListingToolbar, Pagination, Text } from "../../../ui";
|
|
8
7
|
import { ROUTES } from "../../../next";
|
|
9
8
|
import { InteractiveStoreCard } from "./InteractiveStoreCard";
|
|
10
9
|
import { StoreFilters } from "./StoreFilters";
|
|
@@ -150,5 +149,5 @@ export function StoresIndexListing({ initialData }) {
|
|
|
150
149
|
},
|
|
151
150
|
] } } : {});
|
|
152
151
|
return (_jsx(InteractiveStoreCard, { store: store, href: String(ROUTES.PUBLIC.STORE_DETAIL(storeKey)), selectable: selection.isSelecting, isSelected: selection.isSelected(store.id ?? store.storeSlug), onSelect: (id, sel) => { void sel; selection.toggle(id); } }, storeKey));
|
|
153
|
-
}) })) }),
|
|
152
|
+
}) })) }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: pendingFilterCount, children: _jsx(StoreFilters, { table: pendingTable }) })] }));
|
|
154
153
|
}
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import React from "react";
|
|
4
4
|
const CLS_SECTION_CARD = "border border-zinc-200 dark:border-zinc-700 rounded-xl p-5";
|
|
5
5
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
6
|
-
import { Alert, Badge, Button, Div, Form, FormActions, Heading, Input, Row, Section, Stack, Text, Toggle, useToast } from "../../../ui";
|
|
6
|
+
import { Alert, Badge, Button, Div, Form, FormActions, Heading, Input, Row, Section, Span, Stack, Text, Toggle, useToast } from "../../../ui";
|
|
7
7
|
import { apiClient } from "../../../http";
|
|
8
8
|
import { WHATSAPP_SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
9
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
@@ -157,13 +157,13 @@ export function SellerWhatsAppSettingsView({ hasCapability }) {
|
|
|
157
157
|
}) })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsxs(Row, { justify: "between", align: "center", className: "mb-4", children: [_jsx(Heading, { level: 2, className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100", children: "Connection" }), isLoading ? null : cfg?.connected ? (_jsx(Badge, { variant: "success", children: "Connected" })) : (_jsx(Badge, { variant: "default", children: "Not configured" }))] }), _jsxs(Form, { onSubmit: (e) => {
|
|
158
158
|
e.preventDefault();
|
|
159
159
|
saveMutation.mutate();
|
|
160
|
-
}, className: "space-y-4", children: [_jsx(Input, { label: "WhatsApp Business Phone Number", value: phoneNumber, onChange: (e) => setPhoneNumber(e.target.value), placeholder: "919876543210", helperText: "Digits only, include country code (e.g. 91 for India)" }), _jsx(Input, { label: "WABA ID (WhatsApp Business Account ID)", value: wabaId, onChange: (e) => setWabaId(e.target.value), placeholder: "123456789012345", helperText: "From Meta Business Manager \u2192 WhatsApp Accounts" }), _jsx(Input, { label: "Catalog ID", value: catalogId, onChange: (e) => setCatalogId(e.target.value), placeholder: "987654321098765", helperText: "From Meta Commerce Manager \u2192 Catalogs" }), _jsx(MaskedTokenInput, { label: "System User Access Token", value: accessToken, onChange: setAccessToken, placeholder: "EAAxxxxxxxx\u2026", helperText: "Long-lived token with WhatsApp Business permissions" }), _jsx(FormActions, { align: "right", children: _jsx(Button, { type: "submit", isLoading: saveMutation.isPending, disabled: saveMutation.isPending, children: saveMutation.isPending ? "Saving…" : ACTIONS.STORE["whatsapp-connect"].label }) })] })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsx(Heading, { level: 2, className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100 mb-4", children: "Catalog Sync" }), _jsxs(Row, { justify: "between", align: "center", className: "mb-4", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-sm text-zinc-700 dark:text-zinc-300", children: "Enable catalog sync" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "When enabled, your published standard products can be synced to WhatsApp." })] }), _jsx(Toggle, { checked: syncEnabled, onChange: setSyncEnabled, disabled: !cfg?.connected })] }), cfg?.lastCatalogSyncAt && (_jsxs(Row, { gap: "sm", align: "center", className: "text-xs text-zinc-500 dark:text-zinc-400 mb-3", children: [_jsxs(Text, { children: ["Last sync: ", new Date(cfg.lastCatalogSyncAt).toLocaleString("en-IN")] }), cfg.lastSyncCount !== undefined && _jsxs(Text, { children: ["\u00B7 ", cfg.lastSyncCount, " products"] }), cfg.lastSyncStatus && (_jsx(Badge, { variant: STATUS_VARIANT[cfg.lastSyncStatus] ?? "default", children: cfg.lastSyncStatus }))] })), _jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400 mb-3", children: "Only published standard products are synced. Auctions and pre-orders are excluded. Batches of up to 50 products per call." }), _jsxs(Div, { className: "flex gap-3", children: [_jsx(Button, { onClick: () => syncMutation.mutate(), isLoading: syncMutation.isPending, disabled: !cfg?.connected || !syncEnabled || syncMutation.isPending, variant: "secondary", children: syncMutation.isPending ? "Syncing…" : ACTIONS.STORE["whatsapp-catalog-sync"].label }), _jsx(Button, { onClick: () => importMutation.mutate(), isLoading: importMutation.isPending, disabled: !cfg?.connected || !syncEnabled || importMutation.isPending, variant: "secondary", children: importMutation.isPending ? "Importing…" : ACTIONS.STORE["whatsapp-catalog-import"].label })] }), _jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400 mt-3", children: [_jsx("
|
|
160
|
+
}, className: "space-y-4", children: [_jsx(Input, { label: "WhatsApp Business Phone Number", value: phoneNumber, onChange: (e) => setPhoneNumber(e.target.value), placeholder: "919876543210", helperText: "Digits only, include country code (e.g. 91 for India)" }), _jsx(Input, { label: "WABA ID (WhatsApp Business Account ID)", value: wabaId, onChange: (e) => setWabaId(e.target.value), placeholder: "123456789012345", helperText: "From Meta Business Manager \u2192 WhatsApp Accounts" }), _jsx(Input, { label: "Catalog ID", value: catalogId, onChange: (e) => setCatalogId(e.target.value), placeholder: "987654321098765", helperText: "From Meta Commerce Manager \u2192 Catalogs" }), _jsx(MaskedTokenInput, { label: "System User Access Token", value: accessToken, onChange: setAccessToken, placeholder: "EAAxxxxxxxx\u2026", helperText: "Long-lived token with WhatsApp Business permissions" }), _jsx(FormActions, { align: "right", children: _jsx(Button, { type: "submit", isLoading: saveMutation.isPending, disabled: saveMutation.isPending, children: saveMutation.isPending ? "Saving…" : ACTIONS.STORE["whatsapp-connect"].label }) })] })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsx(Heading, { level: 2, className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100 mb-4", children: "Catalog Sync" }), _jsxs(Row, { justify: "between", align: "center", className: "mb-4", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-sm text-zinc-700 dark:text-zinc-300", children: "Enable catalog sync" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "When enabled, your published standard products can be synced to WhatsApp." })] }), _jsx(Toggle, { checked: syncEnabled, onChange: setSyncEnabled, disabled: !cfg?.connected })] }), cfg?.lastCatalogSyncAt && (_jsxs(Row, { gap: "sm", align: "center", className: "text-xs text-zinc-500 dark:text-zinc-400 mb-3", children: [_jsxs(Text, { children: ["Last sync: ", new Date(cfg.lastCatalogSyncAt).toLocaleString("en-IN")] }), cfg.lastSyncCount !== undefined && _jsxs(Text, { children: ["\u00B7 ", cfg.lastSyncCount, " products"] }), cfg.lastSyncStatus && (_jsx(Badge, { variant: STATUS_VARIANT[cfg.lastSyncStatus] ?? "default", children: cfg.lastSyncStatus }))] })), _jsx(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400 mb-3", children: "Only published standard products are synced. Auctions and pre-orders are excluded. Batches of up to 50 products per call." }), _jsxs(Div, { className: "flex gap-3", children: [_jsx(Button, { onClick: () => syncMutation.mutate(), isLoading: syncMutation.isPending, disabled: !cfg?.connected || !syncEnabled || syncMutation.isPending, variant: "secondary", children: syncMutation.isPending ? "Syncing…" : ACTIONS.STORE["whatsapp-catalog-sync"].label }), _jsx(Button, { onClick: () => importMutation.mutate(), isLoading: importMutation.isPending, disabled: !cfg?.connected || !syncEnabled || importMutation.isPending, variant: "secondary", children: importMutation.isPending ? "Importing…" : ACTIONS.STORE["whatsapp-catalog-import"].label })] }), _jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-400 mt-3", children: [_jsx(Span, { weight: "bold", children: "Push" }), " sends your published standard products to WhatsApp.", " ", _jsx(Span, { weight: "bold", children: "Import" }), " creates draft products from your WhatsApp catalog. Products are matched by slug in the description field."] })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsx(Heading, { level: 2, className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100 mb-2", children: "Purchase Announcement Preview" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 mb-3", children: "This message is sent automatically to your phone and the platform admin when a new order is placed." }), _jsx(Div, { className: "bg-zinc-50 dark:bg-zinc-800/60 rounded-lg px-4 py-3 text-sm text-zinc-700 dark:text-zinc-200 font-mono", children: buildPurchaseAnnouncementMessage({
|
|
161
161
|
buyerName: "Ravi K.",
|
|
162
162
|
firstItemName: "Charizard PSA 9",
|
|
163
163
|
additionalItemCount: 2,
|
|
164
164
|
totalAmount: 450000,
|
|
165
165
|
orderId: "order-3-20260510-a1b2c3",
|
|
166
|
-
}) })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsx(Heading, { level: 2, className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100 mb-2", children: "Catalog Preview" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 mb-4", children: "This is how your products appear in the WhatsApp Catalog when a buyer taps \"View Catalog\" in the chat. Only published standard products are included." }), _jsxs(Div, { className: "border border-zinc-200 dark:border-zinc-700 rounded-xl overflow-hidden bg-[#ECE5DD] dark:bg-zinc-800 p-3", children: [_jsxs(Row, { gap: "sm", align: "center", className: "mb-3", children: [_jsx(Div, { className: "w-8 h-8 rounded-full bg-[#25D366] flex items-center justify-center", children: _jsx(Text, { className: "text-white text-xs font-bold", children: "W" }) }), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs font-semibold text-zinc-900 dark:text-zinc-100", children: cfg?.connected ? "Your Store" : "Store Name" }), _jsx(Text, { className: "text-[10px] text-zinc-500 dark:text-zinc-400", children: "WhatsApp Business" })] })] }), _jsx(Div, { className: "grid grid-cols-2 gap-2", children: SAMPLE_CATALOG_ITEMS.map((item) => (_jsxs(Div, {
|
|
166
|
+
}) })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsx(Heading, { level: 2, className: "text-sm font-semibold text-zinc-900 dark:text-zinc-100 mb-2", children: "Catalog Preview" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 mb-4", children: "This is how your products appear in the WhatsApp Catalog when a buyer taps \"View Catalog\" in the chat. Only published standard products are included." }), _jsxs(Div, { className: "border border-zinc-200 dark:border-zinc-700 rounded-xl overflow-hidden bg-[#ECE5DD] dark:bg-zinc-800 p-3", children: [_jsxs(Row, { gap: "sm", align: "center", className: "mb-3", children: [_jsx(Div, { className: "w-8 h-8 rounded-full bg-[#25D366] flex items-center justify-center", children: _jsx(Text, { className: "text-white text-xs font-bold", children: "W" }) }), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs font-semibold text-zinc-900 dark:text-zinc-100", children: cfg?.connected ? "Your Store" : "Store Name" }), _jsx(Text, { className: "text-[10px] text-zinc-500 dark:text-zinc-400", children: "WhatsApp Business" })] })] }), _jsx(Div, { className: "grid grid-cols-2 gap-2", children: SAMPLE_CATALOG_ITEMS.map((item) => (_jsxs(Div, { surface: "card", className: "overflow-hidden", children: [_jsx(Div, { className: "aspect-square bg-zinc-100 dark:bg-zinc-800 flex items-center justify-center", children: _jsx(Text, { className: "text-2xl", children: item.emoji }) }), _jsxs(Div, { className: "p-2", children: [_jsx(Text, { className: "text-xs font-medium text-zinc-900 dark:text-zinc-100 line-clamp-2 leading-tight", children: item.name }), _jsx(Text, { className: "text-xs text-[#25D366] font-semibold mt-0.5", children: item.price })] })] }, item.id))) }), _jsx(Div, { className: "mt-3 text-center", children: _jsx(Text, { className: "text-[10px] text-zinc-500 dark:text-zinc-400", children: cfg?.lastSyncCount
|
|
167
167
|
? `${cfg.lastSyncCount} products synced to catalog`
|
|
168
|
-
: "Sync your products to populate the catalog" }) })] }), !cfg?.connected && (_jsx(Text, { className: "text-xs text-
|
|
168
|
+
: "Sync your products to populate the catalog" }) })] }), !cfg?.connected && (_jsx(Text, { className: "text-xs text-warning mt-2", children: "Connect your WhatsApp Business account above to enable the catalog." }))] })] }));
|
|
169
169
|
}
|
|
@@ -3,7 +3,7 @@ import { Button, Div, Stack, Text } from "../../../ui";
|
|
|
3
3
|
import { formatCurrency } from "../../../utils/number.formatter";
|
|
4
4
|
import { THEME_CONSTANTS } from "../../../tokens";
|
|
5
5
|
export function WishlistCard({ item, onRemove, onProductClick, }) {
|
|
6
|
-
return (_jsxs(Div, {
|
|
6
|
+
return (_jsxs(Div, { surface: "card", padding: "sm", className: "flex gap-4", children: [_jsx(Div, { role: onProductClick ? "button" : undefined, tabIndex: onProductClick ? 0 : undefined, onClick: onProductClick ? () => onProductClick(item) : undefined, onKeyDown: onProductClick
|
|
7
7
|
? (e) => e.key === "Enter" && onProductClick(item)
|
|
8
8
|
: undefined, className: `h-20 w-20 flex-shrink-0 overflow-hidden rounded-lg bg-neutral-100 dark:bg-slate-800 ${onProductClick ? "cursor-pointer" : ""}`, children: item.productImage && (_jsx(Div, { role: "img", "aria-label": item.productTitle ?? "", className: "h-full w-full bg-center bg-cover", style: { backgroundImage: `url(${item.productImage})` } })) }), _jsxs(Div, { className: "flex flex-1 flex-col justify-between", children: [_jsx(Text, { className: `font-medium text-neutral-900 dark:text-zinc-100 ${THEME_CONSTANTS.utilities.textClamp2}`, children: item.productTitle }), item.productPrice !== undefined && (_jsx(Text, { className: "text-sm font-semibold text-neutral-900 dark:text-zinc-100", children: formatCurrency(item.productPrice, item.productCurrency) }))] }), onRemove && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onRemove(item.id), "aria-label": "Remove from wishlist", className: "self-start text-zinc-400 dark:text-zinc-400 transition hover:text-red-500", children: "\u2715" }))] }));
|
|
9
9
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -501,12 +501,9 @@ export { FirebaseFAQsRepository } from "./repositories/index";
|
|
|
501
501
|
export { NewsletterRepository } from "./repositories/index";
|
|
502
502
|
export { OfferRepository } from "./repositories/index";
|
|
503
503
|
export { OrderRepository } from "./repositories/index";
|
|
504
|
-
export { OrdersRepository } from "./repositories/index";
|
|
505
504
|
export { PasswordResetTokenRepository } from "./repositories/index";
|
|
506
505
|
export { ProductRepository } from "./repositories/index";
|
|
507
|
-
export { ProductsRepository } from "./repositories/index";
|
|
508
506
|
export { ReviewRepository } from "./repositories/index";
|
|
509
|
-
export { ReviewsRepository } from "./repositories/index";
|
|
510
507
|
export { SessionRepository } from "./repositories/index";
|
|
511
508
|
export { SmsCounterRepository } from "./repositories/index";
|
|
512
509
|
export { StoreRepository } from "./repositories/index";
|
|
@@ -1162,7 +1159,6 @@ export { DEFAULT_NOTIFICATION_DATA } from "./features/admin/index";
|
|
|
1162
1159
|
export { DEFAULT_SITE_SETTINGS_DATA } from "./features/admin/index";
|
|
1163
1160
|
export { DEFAULT_TRUST_BAR_ITEMS } from "./features/admin/index";
|
|
1164
1161
|
export { DashboardStatsGrid } from "./features/admin/index";
|
|
1165
|
-
export { DemoSeedView } from "./features/admin/index";
|
|
1166
1162
|
export { AdminTeamView } from "./features/admin/index";
|
|
1167
1163
|
export { AdminEmployeeEditorView } from "./features/admin/index";
|
|
1168
1164
|
export { AdminSupportTicketsView } from "./features/admin/index";
|
|
@@ -1240,7 +1236,6 @@ export type { ChatRoomCreateInput } from "./features/admin/index";
|
|
|
1240
1236
|
export type { ChatRoomDocument } from "./features/admin/index";
|
|
1241
1237
|
export type { ChatRoomUpdateInput } from "./features/admin/index";
|
|
1242
1238
|
export type { DashboardStats } from "./features/admin/index";
|
|
1243
|
-
export type { DemoSeedViewProps } from "./features/admin/index";
|
|
1244
1239
|
export type { AdminTeamViewProps } from "./features/admin/index";
|
|
1245
1240
|
export type { AdminEmployeeEditorViewProps } from "./features/admin/index";
|
|
1246
1241
|
export type { AdminSupportTicketsViewProps } from "./features/admin/index";
|
|
@@ -2137,6 +2132,7 @@ export { LoyaltyRepository } from "./features/loyalty/server";
|
|
|
2137
2132
|
export { AvatarUpload } from "./features/media/index";
|
|
2138
2133
|
export { CameraCapture } from "./features/media/index";
|
|
2139
2134
|
export { ImageCropModal } from "./features/media/index";
|
|
2135
|
+
export { ImageEditor } from "./features/media/index";
|
|
2140
2136
|
export { ImageUpload } from "./features/media/index";
|
|
2141
2137
|
export { MediaAvatar } from "./features/media/index";
|
|
2142
2138
|
export { MediaImage } from "./features/media/index";
|
|
@@ -2157,6 +2153,7 @@ export { useMediaUpload } from "./features/media/index";
|
|
|
2157
2153
|
export type { AvatarUploadProps } from "./features/media/index";
|
|
2158
2154
|
export type { CameraCaptureProps } from "./features/media/index";
|
|
2159
2155
|
export type { ImageCropData } from "./features/media/index";
|
|
2156
|
+
export type { ImageEditorProps } from "./features/media/index";
|
|
2160
2157
|
export type { ImageCropModalProps } from "./features/media/index";
|
|
2161
2158
|
export type { ImageUploadProps } from "./features/media/index";
|
|
2162
2159
|
export type { LightboxItem } from "./features/media/index";
|
|
@@ -2382,6 +2379,7 @@ export { isListingTypeEnabled, isCategoryTypeEnabled, enabledListingTypes, enabl
|
|
|
2382
2379
|
export { actionTracker, setActionTrackerSink, resetActionTrackerSink, type ActionEvent, type ActionTrackerSink, } from "./_internal/shared/listing-types/action-tracker";
|
|
2383
2380
|
export { cartRequiresShipping, cartIsDigitalOnly, cartIsChatOnly, } from "./_internal/shared/listing-types/cart-shipping";
|
|
2384
2381
|
export { ACTIONS, action, act, canPerformAction, actionsForListingType, actionLabel, type ActionDef, type ActionKind, type ActionResource, type ActionTree, type ActionConfirmation, } from "./_internal/shared/actions/action-registry";
|
|
2382
|
+
export { buildBulkAction } from "./_internal/shared/actions/bulk-helpers";
|
|
2385
2383
|
export { isAdminUser, isSellerUser, isModeratorUser, isEmployeeUser, isBuyerUser, } from "./features/auth/role-predicates";
|
|
2386
2384
|
export { sanitizeProductForPublic, sanitizeProductsForPublic } from "./features/products/index";
|
|
2387
2385
|
export { productAdminColumns } from "./features/products/index";
|
|
@@ -3004,7 +3002,7 @@ export { API_ENDPOINTS, API_ROUTES, LOGS_ENDPOINTS, AUTH_ENDPOINTS, ACCOUNT_ENDP
|
|
|
3004
3002
|
export { WishlistFullError } from "./features/wishlist/server";
|
|
3005
3003
|
export { useHistory, useHistoryMergeOnLogin, getGuestHistory, trackGuestHistory, removeGuestHistoryItem, clearGuestHistory, getGuestHistoryCount, type GuestHistoryItem, type GuestHistoryType, type UserHistoryItem, type HistoryProductType, type HistoryItemSnapshot, type TrackArgs as TrackHistoryArgs, } from "./features/history";
|
|
3006
3004
|
export { historyRepository, UserHistoryRepository, trackHistoryView, getHistoryForUser, removeHistoryItem, clearHistory, mergeGuestHistory, } from "./features/history/server";
|
|
3007
|
-
export { useMediaQuery, useBreakpoint, useClickOutside, useKeyPress, useLongPress, useGesture, useSwipe, ThemeProvider, useTheme, useSession, useAuth, useCountdown, useCamera, useBulkSelection, useUrlTable, usePendingFilters, usePendingTable, useUnsavedChanges, UNSAVED_CHANGES_EVENT, useBulkAction, useContainerGrid, useMessage, useVisibleItems, useModalStack, RTDBPayloadStatus, } from "./react/index";
|
|
3005
|
+
export { useMediaQuery, useBreakpoint, useClickOutside, useKeyPress, useLongPress, useGesture, useSwipe, ThemeProvider, useTheme, useSession, useAuth, useCountdown, useCamera, useBulkSelection, useUrlTable, usePendingFilters, usePendingTable, useUnsavedChanges, UNSAVED_CHANGES_EVENT, useBulkAction, useEntityDelete, useContainerGrid, useMessage, useVisibleItems, useModalStack, RTDBPayloadStatus, } from "./react/index";
|
|
3008
3006
|
export { RoleGate, ProtectedRoute, SocialAuthButtons, AuthStatusPanel, LoginForm, RegisterForm, ForgotPasswordView, ResetPasswordView, VerifyEmailView, OAuthLoadingView, } from "./features/auth/index";
|
|
3009
3007
|
export type { RoleGateProps, ProtectedRouteProps, AuthGuardUser, AuthRouteConfig, LoginFormProps, LoginFormValues, RegisterFormProps, RegisterFormValues, ForgotPasswordViewProps, ResetPasswordViewProps, VerifyEmailViewProps, } from "./features/auth/index";
|
|
3010
3008
|
export { CartItemRow, CartDrawer, CartView, CartSummary, ShippingPicker } from "./features/cart/index";
|
package/dist/index.js
CHANGED
|
@@ -977,24 +977,15 @@ export { OfferRepository } from "./repositories/index";
|
|
|
977
977
|
// OrderRepository - Shared export for order repository.
|
|
978
978
|
export { OrderRepository } from "./repositories/index";
|
|
979
979
|
// [DB]-Database layer â€" uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
|
|
980
|
-
// OrdersRepository - Shared export for orders repository.
|
|
981
|
-
export { OrdersRepository } from "./repositories/index";
|
|
982
|
-
// [DB]-Database layer â€" uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
|
|
983
980
|
// PasswordResetTokenRepository - Shared export for password reset token repository.
|
|
984
981
|
export { PasswordResetTokenRepository } from "./repositories/index";
|
|
985
982
|
// [DB]-Database layer â€" uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
|
|
986
983
|
// ProductRepository - Shared export for product repository.
|
|
987
984
|
export { ProductRepository } from "./repositories/index";
|
|
988
985
|
// [DB]-Database layer â€" uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
|
|
989
|
-
// ProductsRepository - Shared export for products repository.
|
|
990
|
-
export { ProductsRepository } from "./repositories/index";
|
|
991
|
-
// [DB]-Database layer â€" uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
|
|
992
986
|
// ReviewRepository - Shared export for review repository.
|
|
993
987
|
export { ReviewRepository } from "./repositories/index";
|
|
994
988
|
// [DB]-Database layer â€" uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
|
|
995
|
-
// ReviewsRepository - Shared export for reviews repository.
|
|
996
|
-
export { ReviewsRepository } from "./repositories/index";
|
|
997
|
-
// [DB]-Database layer â€" uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
|
|
998
989
|
// SessionRepository - Shared export for session repository.
|
|
999
990
|
export { SessionRepository } from "./repositories/index";
|
|
1000
991
|
// [DB]-Database layer â€" uses firebase-admin or another server-side DB SDK; can only run in a trusted server environment.
|
|
@@ -2258,8 +2249,7 @@ export { DEFAULT_TRUST_BAR_ITEMS } from "./features/admin/index";
|
|
|
2258
2249
|
// DashboardStatsGrid - Component for dashboard stats grid.
|
|
2259
2250
|
export { DashboardStatsGrid } from "./features/admin/index";
|
|
2260
2251
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
2261
|
-
// DemoSeedView -
|
|
2262
|
-
export { DemoSeedView } from "./features/admin/index";
|
|
2252
|
+
// DemoSeedView — removed from main barrel (dev-only, load via dynamic import)
|
|
2263
2253
|
// AdminTeamView - Employee management list view.
|
|
2264
2254
|
export { AdminTeamView } from "./features/admin/index";
|
|
2265
2255
|
// AdminEmployeeEditorView - Invite/edit employee permissions SideDrawer.
|
|
@@ -3986,6 +3976,9 @@ export { CameraCapture } from "./features/media/index";
|
|
|
3986
3976
|
// [CLIENT-ONLY]-Cannot run in SSR mode â€" uses browser-only APIs (window, navigator, localStorage, matchMedia, DOM events) that do not exist in Node.js.
|
|
3987
3977
|
// ImageCropModal - Component for image crop modal.
|
|
3988
3978
|
export { ImageCropModal } from "./features/media/index";
|
|
3979
|
+
// [CLIENT-ONLY]-Cannot run in SSR mode — uses browser-only APIs.
|
|
3980
|
+
// ImageEditor - Advanced crop/rotate/zoom editor (react-advanced-cropper).
|
|
3981
|
+
export { ImageEditor } from "./features/media/index";
|
|
3989
3982
|
// [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
|
|
3990
3983
|
// ImageUpload - Shared export for image upload.
|
|
3991
3984
|
export { ImageUpload } from "./features/media/index";
|
|
@@ -4432,6 +4425,7 @@ export { actionTracker, setActionTrackerSink, resetActionTrackerSink, } from "./
|
|
|
4432
4425
|
export { cartRequiresShipping, cartIsDigitalOnly, cartIsChatOnly, } from "./_internal/shared/listing-types/cart-shipping";
|
|
4433
4426
|
// SB-UNI-W-1 2026-05-13 â€" CTA action registry shell.
|
|
4434
4427
|
export { ACTIONS, action, act, canPerformAction, actionsForListingType, actionLabel, } from "./_internal/shared/actions/action-registry";
|
|
4428
|
+
export { buildBulkAction } from "./_internal/shared/actions/bulk-helpers";
|
|
4435
4429
|
// User-role predicates â€" SB-UNI-E 2026-05-13.
|
|
4436
4430
|
export { isAdminUser, isSellerUser, isModeratorUser, isEmployeeUser, isBuyerUser, } from "./features/auth/role-predicates";
|
|
4437
4431
|
// [SERVER-ONLY]-Safe in browser but intended for server routes.
|
|
@@ -5437,7 +5431,7 @@ export { WishlistFullError } from "./features/wishlist/server";
|
|
|
5437
5431
|
export { useHistory, useHistoryMergeOnLogin, getGuestHistory, trackGuestHistory, removeGuestHistoryItem, clearGuestHistory, getGuestHistoryCount, } from "./features/history";
|
|
5438
5432
|
export { historyRepository, UserHistoryRepository, trackHistoryView, getHistoryForUser, removeHistoryItem, clearHistory, mergeGuestHistory, } from "./features/history/server";
|
|
5439
5433
|
// Missing React hooks and providers
|
|
5440
|
-
export { useMediaQuery, useBreakpoint, useClickOutside, useKeyPress, useLongPress, useGesture, useSwipe, ThemeProvider, useTheme, useSession, useAuth, useCountdown, useCamera, useBulkSelection, useUrlTable, usePendingFilters, usePendingTable, useUnsavedChanges, UNSAVED_CHANGES_EVENT, useBulkAction, useContainerGrid, useMessage, useVisibleItems, useModalStack, RTDBPayloadStatus, } from "./react/index";
|
|
5434
|
+
export { useMediaQuery, useBreakpoint, useClickOutside, useKeyPress, useLongPress, useGesture, useSwipe, ThemeProvider, useTheme, useSession, useAuth, useCountdown, useCamera, useBulkSelection, useUrlTable, usePendingFilters, usePendingTable, useUnsavedChanges, UNSAVED_CHANGES_EVENT, useBulkAction, useEntityDelete, useContainerGrid, useMessage, useVisibleItems, useModalStack, RTDBPayloadStatus, } from "./react/index";
|
|
5441
5435
|
// Missing core types (already exported above; skipped to avoid duplicates)
|
|
5442
5436
|
// Missing auth feature components
|
|
5443
5437
|
export { RoleGate, ProtectedRoute, SocialAuthButtons, AuthStatusPanel, LoginForm, RegisterForm, ForgotPasswordView, ResetPasswordView, VerifyEmailView, OAuthLoadingView, } from "./features/auth/index";
|
|
@@ -32,6 +32,8 @@ export interface SessionUser {
|
|
|
32
32
|
scamAwarenessAcknowledgedAt?: Date | null;
|
|
33
33
|
/** RBAC permission keys granted to this user (from their role's permission set). */
|
|
34
34
|
permissions?: string[];
|
|
35
|
+
/** Hash of the last dismissed announcement banner. */
|
|
36
|
+
dismissedBannerHash?: string;
|
|
35
37
|
}
|
|
36
38
|
export interface SessionContextValue {
|
|
37
39
|
user: SessionUser | null;
|