@mohasinac/appkit 2.7.58 → 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/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 +3 -0
- package/dist/client.js +2 -0
- package/dist/configs/next.js +11 -0
- package/dist/features/account/components/AddressesIndexListing.js +3 -4
- package/dist/features/account/components/UserSidebar.js +14 -10
- package/dist/features/admin/components/AdminAllEventEntriesView.js +3 -9
- package/dist/features/admin/components/AdminBidsView.js +2 -8
- 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 +39 -58
- package/dist/features/admin/components/AdminCarouselView.js +7 -20
- package/dist/features/admin/components/AdminCartsView.js +3 -4
- package/dist/features/admin/components/AdminCategoriesView.js +4 -9
- package/dist/features/admin/components/AdminCategoryEditorView.js +1 -5
- package/dist/features/admin/components/AdminContactView.js +6 -24
- 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/AdminNewsletterView.js +4 -14
- package/dist/features/admin/components/AdminNotificationsView.js +2 -8
- package/dist/features/admin/components/AdminOrdersView.js +2 -8
- package/dist/features/admin/components/AdminPayoutsView.js +2 -8
- 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 +4 -9
- package/dist/features/admin/components/AdminReviewsView.js +2 -8
- package/dist/features/admin/components/AdminScammersView.js +2 -8
- package/dist/features/admin/components/AdminSessionsView.js +2 -8
- package/dist/features/admin/components/AdminStoresView.js +2 -8
- package/dist/features/admin/components/AdminSublistingCategoriesView.js +2 -6
- package/dist/features/admin/components/AdminSublistingCategoryEditorView.js +17 -20
- package/dist/features/admin/components/AdminSupportTicketsView.js +2 -8
- package/dist/features/admin/components/AdminTeamView.js +5 -14
- package/dist/features/admin/components/AdminUsersView.js +2 -8
- package/dist/features/admin/hooks/useAdminListing.d.ts +58 -0
- package/dist/features/admin/hooks/useAdminListing.js +71 -0
- package/dist/features/auth/schemas/firestore.d.ts +1 -0
- package/dist/features/blog/components/BlogIndexListing.js +3 -6
- package/dist/features/categories/components/CategoriesIndexListing.js +3 -6
- package/dist/features/events/components/AdminEventsView.js +4 -4
- package/dist/features/events/components/EventsIndexListing.js +3 -4
- package/dist/features/homepage/components/AnnouncementBar.d.ts +4 -1
- package/dist/features/homepage/components/AnnouncementBar.js +51 -4
- 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/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/products/components/GroupSettingsPanel.js +64 -48
- 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 +5 -5
- package/dist/features/promotions/components/CouponsIndexListing.js +3 -2
- package/dist/features/reviews/components/ReviewsIndexListing.js +3 -4
- 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 +10 -20
- package/dist/features/seller/components/SellerAuctionsView.js +13 -22
- package/dist/features/seller/components/SellerBidsView.js +5 -5
- package/dist/features/seller/components/SellerBundlesView.js +11 -19
- package/dist/features/seller/components/SellerClassifiedView.js +11 -19
- package/dist/features/seller/components/SellerCouponsView.js +14 -20
- package/dist/features/seller/components/SellerDigitalCodesView.js +11 -19
- package/dist/features/seller/components/SellerGroupedListingsView.js +6 -10
- package/dist/features/seller/components/SellerLiveView.js +11 -19
- package/dist/features/seller/components/SellerOffersView.js +3 -4
- package/dist/features/seller/components/SellerOrdersView.js +8 -22
- package/dist/features/seller/components/SellerPayoutMethodsView.js +11 -23
- package/dist/features/seller/components/SellerPayoutsView.js +3 -4
- package/dist/features/seller/components/SellerPreOrdersView.js +13 -22
- package/dist/features/seller/components/SellerPrizeDrawsView.js +13 -22
- 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 +9 -22
- package/dist/features/seller/components/SellerShippingConfigsView.js +11 -23
- package/dist/features/seller/components/SellerStoreCategoriesView.js +14 -33
- package/dist/features/seller/components/SellerTemplatesView.js +25 -41
- package/dist/features/stores/components/StoreReviewsListing.js +3 -4
- package/dist/features/stores/components/StoresIndexListing.js +3 -4
- package/dist/index.d.ts +2 -6
- package/dist/index.js +3 -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 +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/ListingFilterDrawer.d.ts +10 -0
- package/dist/ui/components/ListingFilterDrawer.js +8 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/package.json +1 -1
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useState } from "react";
|
|
4
4
|
import { MapPin, Pencil, Plus, Trash2, Star } from "lucide-react";
|
|
5
|
-
import { Button, Div, Heading, Row, SideDrawer, Text } from "../../../ui";
|
|
5
|
+
import { Button, ConfirmDeleteModal, Div, Heading, Row, SideDrawer, Text } from "../../../ui";
|
|
6
6
|
import { ROW_ACTION_META, ROW_ACTION_ID } from "../../../features/products/constants/action-defs";
|
|
7
7
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
8
|
+
import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
|
|
8
9
|
const INPUT_CLS = "w-full rounded-lg border border-zinc-300 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 dark:placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-[var(--appkit-color-primary)]";
|
|
9
10
|
const CLS_GRID_2_COL = "grid grid-cols-2 gap-3";
|
|
10
11
|
function Field({ label, hint, children }) {
|
|
@@ -57,7 +58,7 @@ export function SellerAddressesView({ apiBase = SELLER_ENDPOINTS.STORE_ADDRESSES
|
|
|
57
58
|
const [draft, setDraft] = useState(BLANK);
|
|
58
59
|
const [saving, setSaving] = useState(false);
|
|
59
60
|
const [saveError, setSaveError] = useState(null);
|
|
60
|
-
const [
|
|
61
|
+
const [deleteTargetAddr, setDeleteTargetAddr] = useState(null);
|
|
61
62
|
const load = useCallback(async () => {
|
|
62
63
|
setIsLoading(true);
|
|
63
64
|
setErrorMessage(null);
|
|
@@ -126,24 +127,13 @@ export function SellerAddressesView({ apiBase = SELLER_ENDPOINTS.STORE_ADDRESSES
|
|
|
126
127
|
setSaving(false);
|
|
127
128
|
}
|
|
128
129
|
};
|
|
129
|
-
const handleDelete =
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (!res.ok)
|
|
136
|
-
throw new Error("Delete failed");
|
|
137
|
-
await load();
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
alert("Failed to delete address. Please try again.");
|
|
141
|
-
}
|
|
142
|
-
finally {
|
|
143
|
-
setDeletingId(null);
|
|
144
|
-
}
|
|
145
|
-
};
|
|
130
|
+
const { deletingId, handleDelete: deleteById } = useEntityDelete({
|
|
131
|
+
endpoint: apiBase,
|
|
132
|
+
successMessage: "Address deleted.",
|
|
133
|
+
onSuccess: () => { load(); },
|
|
134
|
+
});
|
|
135
|
+
const handleDelete = (addr) => setDeleteTargetAddr(addr);
|
|
146
136
|
const set = (key, value) => setDraft((p) => ({ ...p, [key]: value }));
|
|
147
137
|
const handleTextField = (key) => (e) => set(key, e.target.value);
|
|
148
|
-
return (_jsxs("div", { className: "min-h-screen", children: [_jsxs("div", { className: "sticky z-10 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-4 py-3 flex items-center justify-between", style: { top: "var(--header-height, 0px)" }, children: [_jsxs(_Fragment, { children: [_jsx(Heading, { level: 2, className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Pickup Addresses" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 mt-0.5", children: "Manage your store's pickup and return locations" })] }), _jsxs(Button, { size: "sm", onClick: openAdd, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "Add Address" })] })] }), _jsxs("div", { className: "py-6 px-4 sm:px-6 max-w-2xl", 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: "flex justify-center py-16", children: _jsx("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-[var(--appkit-color-primary)] border-t-transparent" }) })) : addresses.length === 0 ? (_jsxs(Div, { className: "rounded-xl border-2 border-dashed border-zinc-200 dark:border-slate-700 py-16 flex flex-col items-center gap-3", children: [_jsx(MapPin, { className: "h-8 w-8 text-zinc-300 dark:text-slate-600" }), _jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "No pickup addresses yet" }), _jsx(Button, { size: "sm", variant: "outline", onClick: openAdd, children: "Add your first address" })] })) : (_jsxs(_Fragment, { children: [_jsxs(Row, { justify: "end", className: "mb-2", children: [_jsx(Button, { size: "sm", variant: listView === "table" ? "primary" : "ghost", onClick: () => setListView("table"), children: "Table" }), _jsx(Button, { size: "sm", variant: listView === "cards" ? "primary" : "ghost", onClick: () => setListView("cards"), children: "Cards" })] }), listView === "cards" ? (_jsx("div", { className: "grid gap-3", children: addresses.map((addr) => (_jsx("div", { className: deletingId === addr.id ? "opacity-50 pointer-events-none" : "", children: _jsx(AddressCard, { address: addr, onEdit: () => openEdit(addr), onDelete: () => handleDelete(addr) }) }, addr.id))) })) : (_jsx("div", { className: "overflow-x-auto rounded-lg border border-zinc-200 dark:border-slate-700", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "bg-zinc-50 dark:bg-slate-800", children: _jsxs("tr", { children: [_jsx("th", { className: "text-left px-3 py-2 font-semibold", children: "Label" }), _jsx("th", { className: "text-left px-3 py-2 font-semibold", children: "Name" }), _jsx("th", { className: "text-left px-3 py-2 font-semibold", children: "City" }), _jsx("th", { className: "text-left px-3 py-2 font-semibold", children: "Phone" }), _jsx("th", { className: "text-right px-3 py-2 font-semibold", children: "Actions" })] }) }), _jsx("tbody", { children: addresses.map((addr) => (_jsxs("tr", { className: `border-t border-zinc-100 dark:border-slate-700 ${deletingId === addr.id ? "opacity-50" : ""}`, children: [_jsx("td", { className: "px-3 py-2", children: addr.label }), _jsx("td", { className: "px-3 py-2", children: addr.fullName }), _jsxs("td", { className: "px-3 py-2", children: [addr.city, ", ", addr.state] }), _jsx("td", { className: "px-3 py-2 tabular-nums", children: addr.phone }), _jsx("td", { className: "px-3 py-2 text-right", children: _jsxs(Row, { justify: "end", className: "gap-1", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => openEdit(addr), children: ROW_ACTION_META[ROW_ACTION_ID.EDIT].label }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => handleDelete(addr), children: ROW_ACTION_META[ROW_ACTION_ID.DELETE].label })] }) })] }, addr.id))) })] }) }))] }))] }), _jsx(SideDrawer, { isOpen: drawerOpen, onClose: closeDrawer, title: editingId ? "Edit Address" : "Add Address", footer: _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: "outline", onClick: closeDrawer, className: "flex-1", children: "Cancel" }), _jsx(Button, { onClick: handleSave, disabled: saving, className: "flex-1", children: saving ? "Saving…" : editingId ? "Save Changes" : "Add Address" })] }), children: _jsxs("div", { className: "space-y-4 py-1", children: [saveError && (_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: saveError })), _jsx(Field, { label: "Label *", hint: "e.g. Warehouse, Shop, Home", children: _jsx("input", { type: "text", value: draft.label, onChange: handleTextField("label"), placeholder: "Warehouse", maxLength: 60, className: INPUT_CLS }) }), _jsxs("div", { className: CLS_GRID_2_COL, children: [_jsx(Field, { label: "Full Name *", children: _jsx("input", { type: "text", value: draft.fullName, onChange: handleTextField("fullName"), placeholder: "Ravi Kumar", maxLength: 100, className: INPUT_CLS }) }), _jsx(Field, { label: "Phone *", children: _jsx("input", { type: "tel", value: draft.phone, onChange: handleTextField("phone"), placeholder: "+91 98765 43210", maxLength: 20, className: INPUT_CLS }) })] }), _jsx(Field, { label: "Address Line 1 *", children: _jsx("input", { type: "text", value: draft.addressLine1, onChange: handleTextField("addressLine1"), placeholder: "Shop 12, Main Market", maxLength: 200, className: INPUT_CLS }) }), _jsx(Field, { label: "Address Line 2", children: _jsx("input", { type: "text", value: draft.addressLine2, onChange: handleTextField("addressLine2"), placeholder: "Building / Floor (optional)", maxLength: 200, className: INPUT_CLS }) }), _jsx(Field, { label: "Landmark", children: _jsx("input", { type: "text", value: draft.landmark, onChange: handleTextField("landmark"), placeholder: "Near metro station (optional)", maxLength: 100, className: INPUT_CLS }) }), _jsxs("div", { className: CLS_GRID_2_COL, children: [_jsx(Field, { label: "City *", children: _jsx("input", { type: "text", value: draft.city, onChange: handleTextField("city"), placeholder: "Mumbai", maxLength: 100, className: INPUT_CLS }) }), _jsx(Field, { label: "State *", children: _jsx("input", { type: "text", value: draft.state, onChange: handleTextField("state"), placeholder: "Maharashtra", maxLength: 100, className: INPUT_CLS }) })] }), _jsxs("div", { className: CLS_GRID_2_COL, children: [_jsx(Field, { label: "Postal Code *", children: _jsx("input", { type: "text", value: draft.postalCode, onChange: handleTextField("postalCode"), placeholder: "400001", maxLength: 10, className: INPUT_CLS }) }), _jsx(Field, { label: "Country *", children: _jsx("input", { type: "text", value: draft.country, onChange: handleTextField("country"), placeholder: "India", maxLength: 60, className: INPUT_CLS }) })] }), _jsxs("label", { className: "flex items-center gap-3 cursor-pointer", children: [_jsx("input", { type: "checkbox", checked: draft.isDefault, onChange: (e) => set("isDefault", e.target.checked), className: "h-4 w-4 rounded border-zinc-300 dark:border-slate-600 text-[var(--appkit-color-primary)] focus:ring-[var(--appkit-color-primary)]" }), _jsx("span", { className: "text-sm text-zinc-700 dark:text-zinc-300", children: "Set as default pickup address" })] })] }) })] }));
|
|
138
|
+
return (_jsxs("div", { className: "min-h-screen", children: [_jsxs("div", { className: "sticky z-10 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-4 py-3 flex items-center justify-between", style: { top: "var(--header-height, 0px)" }, children: [_jsxs(_Fragment, { children: [_jsx(Heading, { level: 2, className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Pickup Addresses" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400 mt-0.5", children: "Manage your store's pickup and return locations" })] }), _jsxs(Button, { size: "sm", onClick: openAdd, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "Add Address" })] })] }), _jsxs("div", { className: "py-6 px-4 sm:px-6 max-w-2xl", 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: "flex justify-center py-16", children: _jsx("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-[var(--appkit-color-primary)] border-t-transparent" }) })) : addresses.length === 0 ? (_jsxs(Div, { className: "rounded-xl border-2 border-dashed border-zinc-200 dark:border-slate-700 py-16 flex flex-col items-center gap-3", children: [_jsx(MapPin, { className: "h-8 w-8 text-zinc-300 dark:text-slate-600" }), _jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "No pickup addresses yet" }), _jsx(Button, { size: "sm", variant: "outline", onClick: openAdd, children: "Add your first address" })] })) : (_jsxs(_Fragment, { children: [_jsxs(Row, { justify: "end", className: "mb-2", children: [_jsx(Button, { size: "sm", variant: listView === "table" ? "primary" : "ghost", onClick: () => setListView("table"), children: "Table" }), _jsx(Button, { size: "sm", variant: listView === "cards" ? "primary" : "ghost", onClick: () => setListView("cards"), children: "Cards" })] }), listView === "cards" ? (_jsx("div", { className: "grid gap-3", children: addresses.map((addr) => (_jsx("div", { className: deletingId === addr.id ? "opacity-50 pointer-events-none" : "", children: _jsx(AddressCard, { address: addr, onEdit: () => openEdit(addr), onDelete: () => handleDelete(addr) }) }, addr.id))) })) : (_jsx("div", { className: "overflow-x-auto rounded-lg border border-zinc-200 dark:border-slate-700", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "bg-zinc-50 dark:bg-slate-800", children: _jsxs("tr", { children: [_jsx("th", { className: "text-left px-3 py-2 font-semibold", children: "Label" }), _jsx("th", { className: "text-left px-3 py-2 font-semibold", children: "Name" }), _jsx("th", { className: "text-left px-3 py-2 font-semibold", children: "City" }), _jsx("th", { className: "text-left px-3 py-2 font-semibold", children: "Phone" }), _jsx("th", { className: "text-right px-3 py-2 font-semibold", children: "Actions" })] }) }), _jsx("tbody", { children: addresses.map((addr) => (_jsxs("tr", { className: `border-t border-zinc-100 dark:border-slate-700 ${deletingId === addr.id ? "opacity-50" : ""}`, children: [_jsx("td", { className: "px-3 py-2", children: addr.label }), _jsx("td", { className: "px-3 py-2", children: addr.fullName }), _jsxs("td", { className: "px-3 py-2", children: [addr.city, ", ", addr.state] }), _jsx("td", { className: "px-3 py-2 tabular-nums", children: addr.phone }), _jsx("td", { className: "px-3 py-2 text-right", children: _jsxs(Row, { justify: "end", className: "gap-1", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => openEdit(addr), children: ROW_ACTION_META[ROW_ACTION_ID.EDIT].label }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => handleDelete(addr), children: ROW_ACTION_META[ROW_ACTION_ID.DELETE].label })] }) })] }, addr.id))) })] }) }))] }))] }), _jsx(SideDrawer, { isOpen: drawerOpen, onClose: closeDrawer, title: editingId ? "Edit Address" : "Add Address", footer: _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: "outline", onClick: closeDrawer, className: "flex-1", children: "Cancel" }), _jsx(Button, { onClick: handleSave, disabled: saving, className: "flex-1", children: saving ? "Saving…" : editingId ? "Save Changes" : "Add Address" })] }), children: _jsxs("div", { className: "space-y-4 py-1", children: [saveError && (_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: saveError })), _jsx(Field, { label: "Label *", hint: "e.g. Warehouse, Shop, Home", children: _jsx("input", { type: "text", value: draft.label, onChange: handleTextField("label"), placeholder: "Warehouse", maxLength: 60, className: INPUT_CLS }) }), _jsxs("div", { className: CLS_GRID_2_COL, children: [_jsx(Field, { label: "Full Name *", children: _jsx("input", { type: "text", value: draft.fullName, onChange: handleTextField("fullName"), placeholder: "Ravi Kumar", maxLength: 100, className: INPUT_CLS }) }), _jsx(Field, { label: "Phone *", children: _jsx("input", { type: "tel", value: draft.phone, onChange: handleTextField("phone"), placeholder: "+91 98765 43210", maxLength: 20, className: INPUT_CLS }) })] }), _jsx(Field, { label: "Address Line 1 *", children: _jsx("input", { type: "text", value: draft.addressLine1, onChange: handleTextField("addressLine1"), placeholder: "Shop 12, Main Market", maxLength: 200, className: INPUT_CLS }) }), _jsx(Field, { label: "Address Line 2", children: _jsx("input", { type: "text", value: draft.addressLine2, onChange: handleTextField("addressLine2"), placeholder: "Building / Floor (optional)", maxLength: 200, className: INPUT_CLS }) }), _jsx(Field, { label: "Landmark", children: _jsx("input", { type: "text", value: draft.landmark, onChange: handleTextField("landmark"), placeholder: "Near metro station (optional)", maxLength: 100, className: INPUT_CLS }) }), _jsxs("div", { className: CLS_GRID_2_COL, children: [_jsx(Field, { label: "City *", children: _jsx("input", { type: "text", value: draft.city, onChange: handleTextField("city"), placeholder: "Mumbai", maxLength: 100, className: INPUT_CLS }) }), _jsx(Field, { label: "State *", children: _jsx("input", { type: "text", value: draft.state, onChange: handleTextField("state"), placeholder: "Maharashtra", maxLength: 100, className: INPUT_CLS }) })] }), _jsxs("div", { className: CLS_GRID_2_COL, children: [_jsx(Field, { label: "Postal Code *", children: _jsx("input", { type: "text", value: draft.postalCode, onChange: handleTextField("postalCode"), placeholder: "400001", maxLength: 10, className: INPUT_CLS }) }), _jsx(Field, { label: "Country *", children: _jsx("input", { type: "text", value: draft.country, onChange: handleTextField("country"), placeholder: "India", maxLength: 60, className: INPUT_CLS }) })] }), _jsxs("label", { className: "flex items-center gap-3 cursor-pointer", children: [_jsx("input", { type: "checkbox", checked: draft.isDefault, onChange: (e) => set("isDefault", e.target.checked), className: "h-4 w-4 rounded border-zinc-300 dark:border-slate-600 text-[var(--appkit-color-primary)] focus:ring-[var(--appkit-color-primary)]" }), _jsx("span", { className: "text-sm text-zinc-700 dark:text-zinc-300", children: "Set as default pickup address" })] })] }) }), deleteTargetAddr && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Address", message: `Delete address "${deleteTargetAddr.label}"? This cannot be undone.`, onConfirm: () => { deleteById(deleteTargetAddr.id); setDeleteTargetAddr(null); }, onClose: () => setDeleteTargetAddr(null), isDeleting: deletingId === deleteTargetAddr.id }))] }));
|
|
149
139
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
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 React, { useState, useCallback } from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
|
|
5
5
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
6
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
7
|
import { AdminViewCards } from "../../admin/components/AdminViewCards";
|
|
8
|
-
import { BulkActionBar, ConfirmDeleteModal, FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, RowActionMenu
|
|
8
|
+
import { BulkActionBar, ConfirmDeleteModal, FilterChipGroup, ListingFilterDrawer, ListingToolbar, Pagination, ListingViewShell, RowActionMenu } from "../../../ui";
|
|
9
9
|
import { useBottomActions } from "../../layout";
|
|
10
10
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
11
11
|
import { SELLER_AUCTION_STATUS_TABS } from "../../admin/constants/filter-tabs";
|
|
@@ -27,8 +27,12 @@ export function SellerAuctionsView({ renderHeader, children, onEditClick, onDele
|
|
|
27
27
|
const hasChildren = React.Children.count(children) > 0;
|
|
28
28
|
const [view, setView] = useState("table");
|
|
29
29
|
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
30
|
-
const
|
|
31
|
-
|
|
30
|
+
const { deletingId, handleDelete: performDelete } = useEntityDelete({
|
|
31
|
+
endpoint: (id) => `/api/store/products/${id}`,
|
|
32
|
+
deleteFn: onDelete,
|
|
33
|
+
successMessage: "Auction deleted.",
|
|
34
|
+
fetchOptions: { credentials: "include" },
|
|
35
|
+
});
|
|
32
36
|
const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
|
|
33
37
|
const [searchInput, setSearchInput] = useState(table.get("q") || "");
|
|
34
38
|
const [filterOpen, setFilterOpen] = useState(false);
|
|
@@ -93,22 +97,9 @@ export function SellerAuctionsView({ renderHeader, children, onEditClick, onDele
|
|
|
93
97
|
}]
|
|
94
98
|
: [];
|
|
95
99
|
const handleDelete = useCallback(async (id) => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
await onDelete(id);
|
|
100
|
-
else
|
|
101
|
-
await fetch(`/api/store/products/${id}`, { method: "DELETE", credentials: "include" });
|
|
102
|
-
showToast("Auction deleted.", "success");
|
|
103
|
-
}
|
|
104
|
-
catch (err) {
|
|
105
|
-
showToast(err instanceof Error ? err.message : "Failed to delete auction.", "error");
|
|
106
|
-
}
|
|
107
|
-
finally {
|
|
108
|
-
setDeletingId(null);
|
|
109
|
-
setDeleteTargetId(null);
|
|
110
|
-
}
|
|
111
|
-
}, [onDelete, showToast]);
|
|
100
|
+
await performDelete(id);
|
|
101
|
+
setDeleteTargetId(null);
|
|
102
|
+
}, [performDelete]);
|
|
112
103
|
const handleEdit = useCallback((id) => {
|
|
113
104
|
if (onEditClick)
|
|
114
105
|
onEditClick(id);
|
|
@@ -122,5 +113,5 @@ export function SellerAuctionsView({ renderHeader, children, onEditClick, onDele
|
|
|
122
113
|
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search auctions by product name", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), 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) }) })), selection.selectedCount > 0 && bulkActions.length > 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 px-4 py-3 text-sm text-error dark:border-red-900/60", children: errorMessage })), view === "table" ? (_jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No auctions found", selectedIds: selection.selectedIdSet, onToggleSelect: (id) => selection.toggle(id), onToggleSelectAll: () => selection.toggleAll(), renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
|
|
123
114
|
{ label: ACTIONS.STORE["edit-listing"].label, onClick: () => handleEdit(row.id) },
|
|
124
115
|
{ label: ACTIONS.STORE["delete-listing"].label, destructive: true, onClick: () => setDeleteTargetId(row.id), disabled: deletingId === row.id },
|
|
125
|
-
] })) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No auctions found", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }),
|
|
116
|
+
] })) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No auctions found", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Auction", message: "Are you sure you want to delete this auction? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
|
|
126
117
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
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 React, { useState, useCallback } from "react";
|
|
4
|
-
import { X } from "lucide-react";
|
|
5
4
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
5
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
|
-
import { Badge, BulkActionBar, Div, FilterChipGroup, ListingToolbar, Pagination, Text, useToast } from "../../../ui";
|
|
6
|
+
import { Badge, BulkActionBar, Div, FilterChipGroup, ListingFilterDrawer, ListingToolbar, Pagination, Text, useToast } from "../../../ui";
|
|
8
7
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
8
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
9
|
+
import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
|
|
10
10
|
import { SELLER_BID_STATUS_TABS } from "../../admin/constants/filter-tabs";
|
|
11
11
|
import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
12
12
|
import { DataTable } from "../../admin/components/DataTable";
|
|
@@ -162,11 +162,11 @@ export function SellerBidsView({ endpoint = SELLER_ENDPOINTS.BIDS }) {
|
|
|
162
162
|
}
|
|
163
163
|
}, [selection, showToast]);
|
|
164
164
|
const bulkActions = [
|
|
165
|
-
|
|
165
|
+
buildBulkAction(ACTIONS.SELLER["cancel-bid"], () => void bulkCancel()),
|
|
166
166
|
];
|
|
167
167
|
useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
|
|
168
168
|
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by bidder name", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), 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) }) })), selection.selectedIds.length > 0 && (_jsx("div", { className: "sticky z-20 px-3 sm:px-4 py-2 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700", style: { top: "calc(var(--header-height, 0px) + 88px)" }, children: _jsx(BulkActionBar, { selectedCount: selection.selectedIds.length, onClearSelection: selection.clearSelection, actions: bulkActions }) })), _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 })), table.get("grouped") === "0" ? (_jsx(DataTable, { rows: rows, columns: columns, isLoading: isLoading, emptyLabel: "No bids found for your auctions", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: () => selection.toggleAll() })) : (_jsxs("div", { className: "space-y-3", children: [groupedRows.length === 0 && !isLoading && (_jsx(Text, { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "No bids found for your auctions." })), groupedRows.map((group) => {
|
|
169
169
|
const collapsed = collapsedGroups.has(group.id);
|
|
170
170
|
return (_jsxs(Div, { className: "rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", children: [_jsxs("button", { type: "button", onClick: () => toggleGroup(group.id), className: "w-full flex items-center justify-between px-4 py-2.5 text-sm font-semibold text-[var(--appkit-color-text)] hover:bg-[var(--appkit-color-surface-raised)]", children: [_jsxs("span", { className: "truncate", children: [group.title, " ", _jsxs("span", { className: "text-xs text-[var(--appkit-color-text-muted)] font-normal", children: ["\u00B7 ", group.bids.length, " bid", group.bids.length === 1 ? "" : "s"] })] }), _jsx("span", { "aria-hidden": true, className: "text-[var(--appkit-color-text-muted)]", children: collapsed ? "▸" : "▾" })] }), !collapsed && (_jsx("div", { className: "border-t border-[var(--appkit-color-border)]", children: _jsx(DataTable, { rows: group.bids, columns: columns, isLoading: false, emptyLabel: "", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle }) }))] }, group.id));
|
|
171
|
-
})] }))] }),
|
|
171
|
+
})] }))] }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsx(FilterChipGroup, { label: "Bid Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })), allId: "" }) })] }));
|
|
172
172
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useCallback } 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";
|
|
7
|
-
import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text,
|
|
8
|
+
import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, } from "../../../ui";
|
|
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";
|
|
@@ -55,8 +56,12 @@ export function SellerBundlesView({ onCreateClick, onEditClick, onDelete, onBulk
|
|
|
55
56
|
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
56
57
|
const [view, setView] = useState("table");
|
|
57
58
|
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
58
|
-
const
|
|
59
|
-
|
|
59
|
+
const { deletingId, handleDelete: performDelete } = useEntityDelete({
|
|
60
|
+
endpoint: (id) => `/api/store/products/${id}`,
|
|
61
|
+
deleteFn: onDelete,
|
|
62
|
+
successMessage: "Bundle deleted.",
|
|
63
|
+
fetchOptions: { credentials: "include" },
|
|
64
|
+
});
|
|
60
65
|
const commitSearch = useCallback(() => {
|
|
61
66
|
table.set(TABLE_KEYS.QUERY, searchInput.trim());
|
|
62
67
|
}, [searchInput, table]);
|
|
@@ -98,22 +103,9 @@ export function SellerBundlesView({ onCreateClick, onEditClick, onDelete, onBulk
|
|
|
98
103
|
}]
|
|
99
104
|
: [];
|
|
100
105
|
const handleDelete = useCallback(async (id) => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
await onDelete(id);
|
|
105
|
-
else
|
|
106
|
-
await fetch(`/api/store/products/${id}`, { method: "DELETE", credentials: "include" });
|
|
107
|
-
showToast("Bundle deleted.", "success");
|
|
108
|
-
}
|
|
109
|
-
catch (err) {
|
|
110
|
-
showToast(err instanceof Error ? err.message : "Failed to delete bundle.", "error");
|
|
111
|
-
}
|
|
112
|
-
finally {
|
|
113
|
-
setDeletingId(null);
|
|
114
|
-
setDeleteTargetId(null);
|
|
115
|
-
}
|
|
116
|
-
}, [onDelete, showToast]);
|
|
106
|
+
await performDelete(id);
|
|
107
|
+
setDeleteTargetId(null);
|
|
108
|
+
}, [performDelete]);
|
|
117
109
|
const handleEdit = useCallback((id) => {
|
|
118
110
|
if (onEditClick)
|
|
119
111
|
onEditClick(id);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useCallback } 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";
|
|
7
|
-
import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text,
|
|
8
|
+
import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, } from "../../../ui";
|
|
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";
|
|
@@ -61,8 +62,12 @@ export function SellerClassifiedView({ onCreateClick, onEditClick, onDelete, onB
|
|
|
61
62
|
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
62
63
|
const [view] = useState("table");
|
|
63
64
|
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
64
|
-
const
|
|
65
|
-
|
|
65
|
+
const { deletingId, handleDelete: performDelete } = useEntityDelete({
|
|
66
|
+
endpoint: (id) => `/api/store/products/${id}`,
|
|
67
|
+
deleteFn: onDelete,
|
|
68
|
+
successMessage: "Listing deleted.",
|
|
69
|
+
fetchOptions: { credentials: "include" },
|
|
70
|
+
});
|
|
66
71
|
const commitSearch = useCallback(() => {
|
|
67
72
|
table.set(TABLE_KEYS.QUERY, searchInput.trim());
|
|
68
73
|
}, [searchInput, table]);
|
|
@@ -107,22 +112,9 @@ export function SellerClassifiedView({ onCreateClick, onEditClick, onDelete, onB
|
|
|
107
112
|
}]
|
|
108
113
|
: [];
|
|
109
114
|
const handleDelete = useCallback(async (id) => {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
await onDelete(id);
|
|
114
|
-
else
|
|
115
|
-
await fetch(`/api/store/products/${id}`, { method: "DELETE", credentials: "include" });
|
|
116
|
-
showToast("Listing deleted.", "success");
|
|
117
|
-
}
|
|
118
|
-
catch (err) {
|
|
119
|
-
showToast(err instanceof Error ? err.message : "Failed to delete listing.", "error");
|
|
120
|
-
}
|
|
121
|
-
finally {
|
|
122
|
-
setDeletingId(null);
|
|
123
|
-
setDeleteTargetId(null);
|
|
124
|
-
}
|
|
125
|
-
}, [onDelete, showToast]);
|
|
115
|
+
await performDelete(id);
|
|
116
|
+
setDeleteTargetId(null);
|
|
117
|
+
}, [performDelete]);
|
|
126
118
|
const handleEdit = useCallback((id) => {
|
|
127
119
|
if (onEditClick)
|
|
128
120
|
onEditClick(id);
|
|
@@ -1,10 +1,11 @@
|
|
|
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 React, { useState, useCallback } from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
|
|
5
|
+
import { Plus } from "lucide-react";
|
|
5
6
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
7
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
|
-
import { Button, Div, ListingToolbar, Pagination, ListingViewShell, Text, useToast } from "../../../ui";
|
|
8
|
+
import { Button, Div, ListingFilterDrawer, ListingToolbar, Pagination, ListingViewShell, Text, useToast } from "../../../ui";
|
|
8
9
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
10
|
import { toRecordArray, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
10
11
|
import { CouponCard } from "../../promotions/components/CouponCard";
|
|
@@ -33,7 +34,11 @@ export function SellerCouponsView({ onCreateClick, onEditClick, onToggle, onDele
|
|
|
33
34
|
const hasChildren = React.Children.count(children) > 0;
|
|
34
35
|
const [view, setView] = useState("table");
|
|
35
36
|
const [togglingId, setTogglingId] = useState(null);
|
|
36
|
-
const
|
|
37
|
+
const { deletingId, handleDelete: performDelete } = useEntityDelete({
|
|
38
|
+
deleteFn: onDelete,
|
|
39
|
+
successMessage: "Coupon deleted.",
|
|
40
|
+
onSuccess: () => { refetch?.(); },
|
|
41
|
+
});
|
|
37
42
|
const { showToast } = useToast();
|
|
38
43
|
const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
|
|
39
44
|
const [searchInput, setSearchInput] = useState(table.get("q") || "");
|
|
@@ -102,26 +107,15 @@ export function SellerCouponsView({ onCreateClick, onEditClick, onToggle, onDele
|
|
|
102
107
|
const handleDelete = useCallback(async (id) => {
|
|
103
108
|
if (!onDelete)
|
|
104
109
|
return;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
await onDelete(id);
|
|
108
|
-
refetch?.();
|
|
109
|
-
showToast("Coupon deleted.", "success");
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
showToast(err instanceof Error ? err.message : "Failed to delete coupon.", "error");
|
|
113
|
-
}
|
|
114
|
-
finally {
|
|
115
|
-
setDeletingId(null);
|
|
116
|
-
}
|
|
117
|
-
}, [onDelete, refetch, showToast]);
|
|
110
|
+
await performDelete(id);
|
|
111
|
+
}, [onDelete, performDelete]);
|
|
118
112
|
const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
|
|
119
113
|
if (hasChildren) {
|
|
120
114
|
return _jsx(ListingViewShell, { portal: "seller", ...props, children: children });
|
|
121
115
|
}
|
|
122
116
|
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by coupon code", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState, extra: onCreateClick
|
|
123
117
|
? (_jsxs(Button, { size: "sm", onClick: onCreateClick, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "Add Coupon" })] }))
|
|
124
|
-
: undefined }), 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) }) })), _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: "fluid-grid-card gap-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Div, { className: "rounded-xl border-2 border-zinc-100 dark:border-slate-700 p-4 animate-pulse space-y-3", children: [_jsx(Div, { className: "h-6 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" }), _jsx(Div, { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx(Div, { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/2" })] }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: "No coupons found \u2014 create your first coupon" }) })) : (_jsx(Div, { className: "fluid-grid-card gap-3", children: rows.map((row) => (_jsx(CouponCard, { coupon: row.raw, onEdit: onEditClick ? handleEdit : undefined, onToggleActive: onToggle ? handleToggle : undefined, onDelete: onDelete ? handleDelete : undefined, className: togglingId === row.id || deletingId === row.id ? "pointer-events-none opacity-60" : undefined }, row.id))) }))] }),
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
: undefined }), 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) }) })), _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: "fluid-grid-card gap-3", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Div, { className: "rounded-xl border-2 border-zinc-100 dark:border-slate-700 p-4 animate-pulse space-y-3", children: [_jsx(Div, { className: "h-6 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" }), _jsx(Div, { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx(Div, { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-1/2" })] }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-400", children: "No coupons found \u2014 create your first coupon" }) })) : (_jsx(Div, { className: "fluid-grid-card gap-3", children: rows.map((row) => (_jsx(CouponCard, { coupon: row.raw, onEdit: onEditClick ? handleEdit : undefined, onToggleActive: onToggle ? handleToggle : undefined, onDelete: onDelete ? handleDelete : undefined, className: togglingId === row.id || deletingId === row.id ? "pointer-events-none opacity-60" : undefined }, row.id))) }))] }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs font-semibold uppercase tracking-widest text-zinc-500 dark:text-zinc-400", children: "Status" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value
|
|
119
|
+
? "bg-[var(--appkit-color-primary)] text-white border-[var(--appkit-color-primary)]"
|
|
120
|
+
: "border-zinc-300 dark:border-slate-600 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-slate-800"}`, children: opt.label }, opt.label))) })] }) })] }));
|
|
127
121
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useCallback } 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";
|
|
7
|
-
import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text,
|
|
8
|
+
import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, } from "../../../ui";
|
|
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";
|
|
@@ -63,8 +64,12 @@ export function SellerDigitalCodesView({ onCreateClick, onEditClick, onDelete, o
|
|
|
63
64
|
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
64
65
|
const [view] = useState("table");
|
|
65
66
|
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
66
|
-
const
|
|
67
|
-
|
|
67
|
+
const { deletingId, handleDelete: performDelete } = useEntityDelete({
|
|
68
|
+
endpoint: (id) => `/api/store/products/${id}`,
|
|
69
|
+
deleteFn: onDelete,
|
|
70
|
+
successMessage: "Code deleted.",
|
|
71
|
+
fetchOptions: { credentials: "include" },
|
|
72
|
+
});
|
|
68
73
|
const commitSearch = useCallback(() => {
|
|
69
74
|
table.set(TABLE_KEYS.QUERY, searchInput.trim());
|
|
70
75
|
}, [searchInput, table]);
|
|
@@ -109,22 +114,9 @@ export function SellerDigitalCodesView({ onCreateClick, onEditClick, onDelete, o
|
|
|
109
114
|
}]
|
|
110
115
|
: [];
|
|
111
116
|
const handleDelete = useCallback(async (id) => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
await onDelete(id);
|
|
116
|
-
else
|
|
117
|
-
await fetch(`/api/store/products/${id}`, { method: "DELETE", credentials: "include" });
|
|
118
|
-
showToast("Code deleted.", "success");
|
|
119
|
-
}
|
|
120
|
-
catch (err) {
|
|
121
|
-
showToast(err instanceof Error ? err.message : "Failed to delete code.", "error");
|
|
122
|
-
}
|
|
123
|
-
finally {
|
|
124
|
-
setDeletingId(null);
|
|
125
|
-
setDeleteTargetId(null);
|
|
126
|
-
}
|
|
127
|
-
}, [onDelete, showToast]);
|
|
117
|
+
await performDelete(id);
|
|
118
|
+
setDeleteTargetId(null);
|
|
119
|
+
}, [performDelete]);
|
|
128
120
|
const handleEdit = useCallback((id) => {
|
|
129
121
|
if (onEditClick)
|
|
130
122
|
onEditClick(id);
|
|
@@ -7,6 +7,7 @@ import { Badge, BulkActionBar, Button, ListingToolbar, Pagination } from "../../
|
|
|
7
7
|
import { useBottomActions } from "../../layout";
|
|
8
8
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
9
9
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
10
|
+
import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
|
|
10
11
|
import { toRecordArray, toRelativeDate, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
|
|
11
12
|
import { DataTable } from "../../admin/components/DataTable";
|
|
12
13
|
// ---------------------------------------------------------------------------
|
|
@@ -99,16 +100,11 @@ export function SellerGroupedListingsView({ onCreateClick, onEditClick, onDelete
|
|
|
99
100
|
const totalPages = Math.ceil(total / PAGE_SIZE);
|
|
100
101
|
const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
|
|
101
102
|
const bulkActions = [
|
|
102
|
-
{
|
|
103
|
-
id
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
for (const id of selection.selectedIds)
|
|
108
|
-
onDeleteClick?.(id);
|
|
109
|
-
selection.clearSelection();
|
|
110
|
-
},
|
|
111
|
-
},
|
|
103
|
+
buildBulkAction(ACTIONS.STORE["delete-listing"], () => {
|
|
104
|
+
for (const id of selection.selectedIds)
|
|
105
|
+
onDeleteClick?.(id);
|
|
106
|
+
selection.clearSelection();
|
|
107
|
+
}),
|
|
112
108
|
];
|
|
113
109
|
useBottomActions(selection.selectedCount > 0 ? { bulk: { selectedCount: selection.selectedCount, onClearSelection: selection.clearSelection, actions: bulkActions } } : {});
|
|
114
110
|
return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { searchValue: searchInput, searchPlaceholder: "Search grouped listings", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: onCreateClick ? (_jsx(Button, { size: "sm", onClick: onCreateClick, children: "+ New Group" })) : null }), selection.selectedCount > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), 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(DataTable, { columns: COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: errorMessage ?? "No grouped listings yet", selectedIds: selection.selectedIdSet, onToggleSelect: (id, _selected) => selection.toggle(id), onToggleSelectAll: (_next) => selection.toggleAll(), renderRowActions: (row) => (_jsxs("div", { className: "flex gap-1", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => onEditClick?.(row.id), children: ACTIONS.STORE["edit-listing"].label }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => onDeleteClick?.(row.id), children: ACTIONS.STORE["delete-listing"].label })] })) })] }));
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useCallback } 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";
|
|
7
|
-
import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text,
|
|
8
|
+
import { BulkActionBar, Button, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, } from "../../../ui";
|
|
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";
|
|
@@ -61,8 +62,12 @@ export function SellerLiveView({ onCreateClick, onEditClick, onDelete, onBulkDel
|
|
|
61
62
|
const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
|
|
62
63
|
const [view] = useState("table");
|
|
63
64
|
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
|
64
|
-
const
|
|
65
|
-
|
|
65
|
+
const { deletingId, handleDelete: performDelete } = useEntityDelete({
|
|
66
|
+
endpoint: (id) => `/api/store/products/${id}`,
|
|
67
|
+
deleteFn: onDelete,
|
|
68
|
+
successMessage: "Listing deleted.",
|
|
69
|
+
fetchOptions: { credentials: "include" },
|
|
70
|
+
});
|
|
66
71
|
const commitSearch = useCallback(() => {
|
|
67
72
|
table.set(TABLE_KEYS.QUERY, searchInput.trim());
|
|
68
73
|
}, [searchInput, table]);
|
|
@@ -107,22 +112,9 @@ export function SellerLiveView({ onCreateClick, onEditClick, onDelete, onBulkDel
|
|
|
107
112
|
}]
|
|
108
113
|
: [];
|
|
109
114
|
const handleDelete = useCallback(async (id) => {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
await onDelete(id);
|
|
114
|
-
else
|
|
115
|
-
await fetch(`/api/store/products/${id}`, { method: "DELETE", credentials: "include" });
|
|
116
|
-
showToast("Listing deleted.", "success");
|
|
117
|
-
}
|
|
118
|
-
catch (err) {
|
|
119
|
-
showToast(err instanceof Error ? err.message : "Failed to delete listing.", "error");
|
|
120
|
-
}
|
|
121
|
-
finally {
|
|
122
|
-
setDeletingId(null);
|
|
123
|
-
setDeleteTargetId(null);
|
|
124
|
-
}
|
|
125
|
-
}, [onDelete, showToast]);
|
|
115
|
+
await performDelete(id);
|
|
116
|
+
setDeleteTargetId(null);
|
|
117
|
+
}, [performDelete]);
|
|
126
118
|
const handleEdit = useCallback((id) => {
|
|
127
119
|
if (onEditClick)
|
|
128
120
|
onEditClick(id);
|
|
@@ -1,11 +1,10 @@
|
|
|
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 React, { useState, useCallback } from "react";
|
|
4
|
-
import { X } from "lucide-react";
|
|
5
4
|
import { useUrlTable } from "../../../react/hooks/useUrlTable";
|
|
6
5
|
import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
|
|
7
6
|
import { AdminViewCards } from "../../admin/components/AdminViewCards";
|
|
8
|
-
import { FilterChipGroup, ListingToolbar, Pagination, ListingViewShell, RowActionMenu } from "../../../ui";
|
|
7
|
+
import { FilterChipGroup, ListingFilterDrawer, ListingToolbar, Pagination, ListingViewShell, RowActionMenu } from "../../../ui";
|
|
9
8
|
import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
9
|
import { SELLER_OFFER_STATUS_TABS } from "../../admin/constants/filter-tabs";
|
|
11
10
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
@@ -84,5 +83,5 @@ export function SellerOffersView({ children, onAcceptOffer, onRejectOffer, onCou
|
|
|
84
83
|
...(onAcceptOffer ? [{ label: ACTIONS.STORE["accept-offer"].label, onClick: () => void onAcceptOffer(row.id) }] : []),
|
|
85
84
|
...(onCounterOffer ? [{ label: ACTIONS.STORE["counter-offer"].label, onClick: () => onCounterOffer(row.id) }] : []),
|
|
86
85
|
...(onRejectOffer ? [{ label: ACTIONS.STORE["reject-offer"].label, destructive: true, onClick: () => void onRejectOffer(row.id) }] : []),
|
|
87
|
-
] })) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No offers received", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }),
|
|
86
|
+
] })) })) : (_jsx(AdminViewCards, { rows: rows, view: view, isLoading: isLoading, emptyLabel: "No offers received", onRowClick: undefined, selectedIdSet: selection.selectedIdSet, onToggleSelect: selection.toggle }))] }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) })] }));
|
|
88
87
|
}
|