@mohasinac/appkit 3.0.3 → 3.0.4
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/filters/filter-load-options.js +11 -1
- package/dist/_internal/client/features/layout/filterNavItems.js +0 -1
- package/dist/_internal/client/features/layout/index.js +0 -1
- package/dist/_internal/client/features/maintenance/views/MaintenanceDashboardView.js +0 -1
- package/dist/_internal/client/features/maintenance/views/ServerErrorDetailView.js +0 -1
- package/dist/_internal/server/features/checkout/actions.js +9 -9
- package/dist/_internal/server/jobs/core/cleanupRtdbEvents.js +1 -1
- package/dist/_internal/shared/listing-types/action-tracker.js +1 -1
- package/dist/client/api/ApiError.d.ts +10 -4
- package/dist/client/api/surface-error.js +0 -1
- package/dist/client.d.ts +4 -0
- package/dist/client.js +2 -0
- package/dist/core/hooks/useSyncManager.js +4 -4
- package/dist/features/_guide-cls.d.ts +1 -1
- package/dist/features/_guide-cls.js +1 -1
- package/dist/features/about/components/AboutView.js +1 -4
- package/dist/features/about/components/FAQPageView.js +1 -1
- package/dist/features/about/components/FeesView.js +1 -1
- package/dist/features/about/components/HelpPageView.js +1 -1
- package/dist/features/about/components/HowOrdersWorkView.js +1 -1
- package/dist/features/about/components/PublicProfileView.js +6 -6
- package/dist/features/about/components/TrackOrderView.js +1 -1
- package/dist/features/account/components/AddressBook.js +1 -1
- package/dist/features/account/components/AddressForm.js +10 -2
- package/dist/features/account/components/AddressesIndexListing.js +1 -1
- package/dist/features/account/components/BuyerAccountGuideView.js +1 -1
- package/dist/features/account/components/BuyerAuctionsGuideView.js +1 -1
- package/dist/features/account/components/BuyerOrdersGuideView.js +1 -1
- package/dist/features/account/components/BuyerShoppingGuideView.js +1 -1
- package/dist/features/account/components/ChatWindow.js +1 -1
- package/dist/features/account/components/MessagesView.js +1 -1
- package/dist/features/account/components/NotificationBell.js +25 -10
- package/dist/features/account/components/NotificationPreferencesPanel.js +2 -2
- package/dist/features/account/components/UserOffersPanel.js +1 -0
- package/dist/features/account/components/UserSidebar.js +1 -6
- package/dist/features/account/components/UserSupportView.js +1 -1
- package/dist/features/admin/components/AdminAnalyticsGuideView.js +2 -2
- package/dist/features/admin/components/AdminBlogEditorView.js +1 -1
- package/dist/features/admin/components/AdminBundlesView.js +1 -1
- package/dist/features/admin/components/AdminCarouselEditorView.js +1 -1
- package/dist/features/admin/components/AdminCatalogGuideView.js +2 -2
- package/dist/features/admin/components/AdminContentGuideView.js +2 -2
- package/dist/features/admin/components/AdminEmployeeEditorView.js +2 -2
- package/dist/features/admin/components/AdminGuideHubView.js +1 -5
- package/dist/features/admin/components/AdminMediaView.js +1 -1
- package/dist/features/admin/components/AdminNavigationView.js +1 -1
- package/dist/features/admin/components/AdminOrdersGuideView.js +3 -3
- package/dist/features/admin/components/AdminPayoutsView.js +1 -4
- package/dist/features/admin/components/AdminSidebar.js +1 -6
- package/dist/features/admin/components/AdminSiteConfigGuideView.js +1 -1
- package/dist/features/admin/components/AdminSiteSettingsView.js +9 -1
- package/dist/features/admin/components/AdminStoreEditorView.js +1 -1
- package/dist/features/admin/components/AdminStoresGuideView.js +2 -2
- package/dist/features/admin/components/AdminSupportTicketDetailView.js +7 -7
- package/dist/features/admin/components/AdminTeamGuideView.js +2 -2
- package/dist/features/admin/components/AdminTrustGuideView.js +3 -3
- package/dist/features/admin/components/AdminUsersGuideView.js +3 -3
- package/dist/features/admin/components/DashboardStats.js +6 -5
- package/dist/features/admin/components/DataTable.js +2 -2
- package/dist/features/admin/components/analytics/AdminAnalyticsCharts.js +4 -6
- package/dist/features/admin/components/analytics/AdminStatCard.js +4 -3
- package/dist/features/admin/components/analytics/AdminTopProductsTable.js +1 -1
- package/dist/features/auctions/components/AuctionBidsTable.js +1 -1
- package/dist/features/auctions/components/AuctionDetailPageView.js +1 -1
- package/dist/features/auctions/components/MarketplaceAuctionCard.js +3 -3
- package/dist/features/auth/components/ForgotPasswordView.js +19 -8
- package/dist/features/auth/components/LoginForm.js +10 -2
- package/dist/features/auth/components/RegisterForm.js +10 -2
- package/dist/features/auth/components/ResetPasswordView.js +19 -8
- package/dist/features/auth/components/SocialAuthButtons.js +1 -1
- package/dist/features/before-after/components/BeforeAfterSlider.js +1 -1
- package/dist/features/blog/api/[slug]/route.js +1 -1
- package/dist/features/blog/components/BlogFeaturedCard.js +1 -1
- package/dist/features/blog/components/BlogListView.js +1 -1
- package/dist/features/blog/components/BlogPostView.js +1 -1
- package/dist/features/blog/schemas/index.d.ts +2 -2
- package/dist/features/cart/components/CartDrawer.js +2 -2
- package/dist/features/cart/components/CartView.js +1 -1
- package/dist/features/cart/components/CheckoutView.js +1 -1
- package/dist/features/categories/components/BrandDetailPageView.js +2 -1
- package/dist/features/categories/components/BundleDetailView.js +1 -1
- package/dist/features/categories/components/BundleItemsPicker.js +1 -1
- package/dist/features/categories/components/CategoryBundlesListing.js +3 -1
- package/dist/features/categories/components/CategoryDetailPageView.js +1 -1
- package/dist/features/categories/components/CategoryGrid.js +2 -1
- package/dist/features/categories/components/CategoryTableColumns.js +5 -2
- package/dist/features/categories/components/CategoryTree.js +3 -2
- package/dist/features/categories/components/ConcernCard.js +1 -1
- package/dist/features/categories/schemas/index.d.ts +2 -2
- package/dist/features/checkout/components/CheckoutStepper.js +1 -1
- package/dist/features/collections/components/CollectionCard.js +1 -1
- package/dist/features/contact/components/ContactPageView.js +27 -27
- package/dist/features/contact/email.js +4 -4
- package/dist/features/copilot/components/AdminCopilotView.js +3 -3
- package/dist/features/email/primitives.d.ts +4 -0
- package/dist/features/email/primitives.js +4 -0
- package/dist/features/events/components/EventCard.js +2 -2
- package/dist/features/events/components/EventOfferCard.js +1 -1
- package/dist/features/events/components/EventRaffleEntryForm.js +1 -1
- package/dist/features/events/components/EventRaffleWinnerView.js +2 -2
- package/dist/features/events/components/EventSaleBanner.js +0 -1
- package/dist/features/events/schemas/index.d.ts +2 -2
- package/dist/features/faq/components/ContactCTA.js +1 -1
- package/dist/features/faq/components/FAQAccordion.js +2 -2
- package/dist/features/faq/components/FAQCategorySidebar.js +2 -2
- package/dist/features/faq/components/FAQHelpfulButtons.js +2 -2
- package/dist/features/faq/components/RelatedFAQs.js +1 -1
- package/dist/features/faq/schemas/index.d.ts +2 -2
- package/dist/features/filters/AsyncFacetSection.js +3 -3
- package/dist/features/filters/FilterFacetSection.js +6 -6
- package/dist/features/filters/RangeFilter.js +2 -2
- package/dist/features/filters/SwitchFilter.js +1 -1
- package/dist/features/forms/Checkbox.js +1 -1
- package/dist/features/forms/Slider.js +7 -2
- package/dist/features/forms/utils.d.ts +2 -2
- package/dist/features/forms/utils.js +2 -2
- package/dist/features/history/hooks/useHistory.js +1 -1
- package/dist/features/homepage/components/AdSlot.js +3 -3
- package/dist/features/homepage/components/AdvertisementBanner.js +5 -4
- package/dist/features/homepage/components/BeforeAfterCard.js +9 -1
- package/dist/features/homepage/components/CharacterHotspot.js +42 -49
- package/dist/features/homepage/components/CharacterHotspotForm.js +18 -20
- package/dist/features/homepage/components/CollectionCardsSection.js +2 -2
- package/dist/features/homepage/components/CustomCardsSection.js +3 -6
- package/dist/features/homepage/components/CustomerReviewsSection.js +1 -1
- package/dist/features/homepage/components/FAQSection.js +2 -2
- package/dist/features/homepage/components/FeaturedResultsSection.js +1 -1
- package/dist/features/homepage/components/GoogleReviewsSection.js +4 -4
- package/dist/features/homepage/components/HeroBanner.js +12 -63
- package/dist/features/homepage/components/HeroCarousel.js +6 -6
- package/dist/features/homepage/components/HeroSection.js +1 -1
- package/dist/features/homepage/components/HowItWorksInfoView.js +1 -1
- package/dist/features/homepage/components/HowItWorksSection.js +5 -3
- package/dist/features/homepage/components/NewsletterBanner.js +3 -7
- package/dist/features/homepage/components/PromoGrid.js +2 -26
- package/dist/features/homepage/components/SectionCarousel.js +1 -1
- package/dist/features/homepage/components/SecurityHighlightsSection.js +6 -3
- package/dist/features/homepage/components/ShopByCategorySection.js +3 -3
- package/dist/features/homepage/components/SiteFeaturesSection.js +1 -1
- package/dist/features/homepage/components/SocialPostCard.js +2 -3
- package/dist/features/homepage/components/StatsCounterSection.js +6 -3
- package/dist/features/homepage/components/TestimonialsCarousel.js +2 -25
- package/dist/features/homepage/components/TrustBadges.js +1 -9
- package/dist/features/homepage/components/TrustFeaturesSection.js +6 -3
- package/dist/features/homepage/components/TrustIndicatorsSection.js +1 -1
- package/dist/features/homepage/components/WelcomeSection.js +2 -2
- package/dist/features/homepage/components/WhatsAppCommunitySection.js +1 -1
- package/dist/features/homepage/lib/franchise-colors.d.ts +7 -0
- package/dist/features/homepage/lib/franchise-colors.js +7 -0
- package/dist/features/homepage/lib/live-stats.js +5 -5
- package/dist/features/layout/AppLayoutShell.js +7 -9
- package/dist/features/layout/BottomNavbar.js +1 -2
- package/dist/features/messages/hooks/useConversation.js +2 -1
- package/dist/features/messages/hooks/useConversations.js +1 -0
- package/dist/features/orders/components/OrdersList.js +1 -1
- package/dist/features/orders/components/RefundHistoryTable.d.ts +6 -0
- package/dist/features/orders/components/RefundHistoryTable.js +3 -2
- package/dist/features/pre-orders/components/MarketplacePreorderCard.js +2 -2
- package/dist/features/pre-orders/components/PreOrderBadge.js +1 -1
- package/dist/features/pre-orders/components/PreOrderDetailPageView.js +2 -1
- package/dist/features/products/components/CompareOverlay.js +11 -8
- package/dist/features/products/components/CustomSectionTabContent.js +1 -1
- package/dist/features/products/components/FeatureBadge.js +11 -1
- package/dist/features/products/components/GroupSettingsPanel.js +2 -2
- package/dist/features/products/components/MarketplaceBundleCard.js +1 -1
- package/dist/features/products/components/MarketplacePrizeDrawCard.js +2 -2
- package/dist/features/products/components/PrizeDrawItemsEditor.js +1 -1
- package/dist/features/products/components/PrizeDrawsIndexListing.js +1 -1
- package/dist/features/products/components/ProductCardMetadataSection.js +0 -1
- package/dist/features/products/components/ProductDetailPageView.js +1 -1
- package/dist/features/products/components/ProductFeatureBadges.js +1 -1
- package/dist/features/products/components/ProductGalleryClient.js +1 -1
- package/dist/features/products/components/ProductGrid.js +7 -7
- package/dist/features/products/components/ShareButton.js +1 -1
- package/dist/features/products/components/ShowGroupSection.js +7 -5
- package/dist/features/products/components/SublistingCarouselSection.js +2 -2
- package/dist/features/products/schemas/index.d.ts +2 -2
- package/dist/features/promotions/components/CouponCard.js +2 -2
- package/dist/features/promotions/schemas/index.d.ts +2 -2
- package/dist/features/reviews/components/ReviewDetailShell.js +3 -3
- package/dist/features/reviews/components/ReviewModal.js +2 -4
- package/dist/features/reviews/components/ReviewSummary.js +3 -2
- package/dist/features/reviews/components/ReviewsList.js +1 -1
- package/dist/features/scams/actions/scam-actions.js +1 -1
- package/dist/features/scams/components/ScamProfileView.js +1 -1
- package/dist/features/search/components/Search.js +2 -2
- package/dist/features/search/components/SearchFiltersRow.js +1 -1
- package/dist/features/search/schemas/index.d.ts +1 -1
- package/dist/features/seller/components/PhysicalLocationModal.js +2 -3
- package/dist/features/seller/components/SellerAddressesView.js +2 -1
- package/dist/features/seller/components/SellerAnalyticsAlertsView.js +1 -1
- package/dist/features/seller/components/SellerBidsView.js +1 -1
- package/dist/features/seller/components/SellerCouponEditorView.js +1 -1
- package/dist/features/seller/components/SellerGoogleReviewsView.js +1 -1
- package/dist/features/seller/components/SellerLiveView.js +1 -1
- package/dist/features/seller/components/SellerOffersPanel.js +1 -0
- package/dist/features/seller/components/SellerOrdersView.js +1 -1
- package/dist/features/seller/components/SellerPayoutMethodsView.js +8 -2
- package/dist/features/seller/components/SellerPayoutRequestView.js +1 -1
- package/dist/features/seller/components/SellerPayoutSettingsView.js +1 -1
- package/dist/features/seller/components/SellerProductShell.js +2 -2
- package/dist/features/seller/components/SellerProductsCards.js +1 -1
- package/dist/features/seller/components/SellerProductsView.js +1 -1
- package/dist/features/seller/components/SellerReviewsView.js +2 -1
- package/dist/features/seller/components/SellerShippingConfigsView.js +9 -3
- package/dist/features/seller/components/SellerShippingView.js +1 -1
- package/dist/features/seller/components/SellerSidebar.js +3 -8
- package/dist/features/seller/components/SellerStoreCategoriesView.js +11 -3
- package/dist/features/seller/components/SellerTemplatesView.js +8 -2
- package/dist/features/seller/components/analytics/SellerRevenueChart.js +1 -1
- package/dist/features/seller/components/analytics/SellerTopProducts.js +1 -1
- package/dist/features/seller/schemas/index.d.ts +2 -2
- package/dist/features/shell/FormShell.js +2 -2
- package/dist/features/shell/QuickFormDrawer.js +1 -1
- package/dist/features/site-settings/components/NavPermissionsManager.js +1 -1
- package/dist/features/stores/components/StoreCapabilitiesGuideView.js +1 -1
- package/dist/features/stores/components/StoreGuideHubView.js +2 -9
- package/dist/features/stores/components/StoreHeader.js +1 -1
- package/dist/features/stores/components/StoreListingsGuideView.js +4 -4
- package/dist/features/stores/components/StoreOrdersGuideView.js +2 -2
- package/dist/features/stores/components/StoresIndexListing.js +1 -1
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +2 -2
- package/dist/features/wishlist/components/WishlistPage.js +1 -1
- package/dist/features/wishlist/components/WishlistToggleButton.js +3 -3
- package/dist/features/wishlist/hooks/useWishlistCount.js +1 -1
- package/dist/http/ApiClient.d.ts +1 -0
- package/dist/http/ApiClient.js +20 -0
- package/dist/monitoring/error-tracking.d.ts +0 -3
- package/dist/monitoring/error-tracking.js +1 -1
- package/dist/monitoring/server-logger.js +3 -3
- package/dist/next/components/GlobalError.js +1 -1
- package/dist/react/ErrorBoundary.js +1 -1
- package/dist/styles.css +45 -7
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/themes/default-light.js +3 -0
- package/dist/tokens/tokens.css +43 -6
- package/dist/ui/components/Anchor.d.ts +8 -1
- package/dist/ui/components/Anchor.js +16 -2
- package/dist/ui/components/Button.d.ts +5 -2
- package/dist/ui/components/Button.js +5 -2
- package/dist/ui/components/Details.d.ts +33 -2
- package/dist/ui/components/Details.js +73 -4
- package/dist/ui/components/Div.d.ts +3 -0
- package/dist/ui/components/Div.js +12 -1
- package/dist/ui/components/DynamicBgDiv.d.ts +13 -0
- package/dist/ui/components/DynamicBgDiv.js +18 -0
- package/dist/ui/components/Form.d.ts +3 -19
- package/dist/ui/components/Form.js +8 -1
- package/dist/ui/components/Layout.d.ts +12 -1
- package/dist/ui/components/Layout.js +9 -1
- package/dist/ui/components/Progress.d.ts +1 -1
- package/dist/ui/components/Progress.js +1 -0
- package/dist/ui/components/Progress.style.css +1 -0
- package/dist/ui/components/ProgressBarFill.d.ts +6 -0
- package/dist/ui/components/ProgressBarFill.js +11 -0
- package/dist/ui/components/Semantic.d.ts +26 -7
- package/dist/ui/components/Semantic.js +33 -8
- package/dist/ui/components/TextLink.d.ts +36 -1
- package/dist/ui/components/TextLink.js +30 -2
- package/dist/ui/components/Typography.d.ts +26 -6
- package/dist/ui/components/Typography.js +37 -13
- package/dist/ui/components/VacationBanner.js +0 -1
- package/dist/ui/components/surface-tokens.d.ts +12 -2
- package/dist/ui/components/surface-tokens.js +19 -1
- package/dist/ui/rich-text/RichText.js +1 -1
- package/dist/validation/schemas.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { normalizeError } from "../../../errors/normalize";
|
|
3
4
|
import { useCallback, useRef, useState } from "react";
|
|
4
|
-
import { Button, Div, Heading, Li, Row, Span, Spinner, Stack, Text, TextLink, Ul } from "../../../ui";
|
|
5
|
+
import { Button, Div, Heading, Li, Row, Span, Spinner, Stack, Text, TextLink, Ul, useToast } from "../../../ui";
|
|
5
6
|
import { useClickOutside, useMessage } from "../../../react";
|
|
6
7
|
import { formatRelativeTime } from "../../../utils";
|
|
7
8
|
import { useNotifications } from "../hooks/useNotifications";
|
|
@@ -32,6 +33,7 @@ export function NotificationBell({ limit = 10, viewAllHref, labels, icons, rende
|
|
|
32
33
|
const [isOpen, setIsOpen] = useState(false);
|
|
33
34
|
const dropdownRef = useRef(null);
|
|
34
35
|
const { showSuccess, showError } = useMessage();
|
|
36
|
+
const { showToast } = useToast();
|
|
35
37
|
const { notifications, unreadCount, isLoading, refetch, markRead, markAllRead, isMarkingAll, } = useNotifications(limit);
|
|
36
38
|
const notificationIcons = { ...DEFAULT_ICONS, ...icons };
|
|
37
39
|
useClickOutside(dropdownRef, () => setIsOpen(false), { enabled: isOpen });
|
|
@@ -43,9 +45,15 @@ export function NotificationBell({ limit = 10, viewAllHref, labels, icons, rende
|
|
|
43
45
|
});
|
|
44
46
|
}, [refetch]);
|
|
45
47
|
const handleMarkRead = useCallback(async (id) => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
try {
|
|
49
|
+
await markRead(id);
|
|
50
|
+
refetch();
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
void normalizeError(err);
|
|
54
|
+
showToast(err instanceof Error ? err.message : "Failed to mark notification as read", "error");
|
|
55
|
+
}
|
|
56
|
+
}, [markRead, refetch, showToast]);
|
|
49
57
|
const emitSuccess = onMarkAllReadSuccess ?? showSuccess;
|
|
50
58
|
const emitError = onMarkAllReadError ?? showError;
|
|
51
59
|
const handleMarkAllRead = useCallback(async () => {
|
|
@@ -54,16 +62,23 @@ export function NotificationBell({ limit = 10, viewAllHref, labels, icons, rende
|
|
|
54
62
|
refetch();
|
|
55
63
|
emitSuccess(labels.markAllRead);
|
|
56
64
|
}
|
|
57
|
-
catch {
|
|
58
|
-
|
|
65
|
+
catch (err) {
|
|
66
|
+
void normalizeError(err);
|
|
67
|
+
if (onMarkAllReadError) {
|
|
68
|
+
onMarkAllReadError(labels.error);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
showToast(err instanceof Error ? err.message : labels.error, "error");
|
|
72
|
+
}
|
|
59
73
|
}
|
|
60
74
|
}, [
|
|
61
|
-
|
|
75
|
+
onMarkAllReadError,
|
|
62
76
|
emitSuccess,
|
|
63
77
|
labels.error,
|
|
64
78
|
labels.markAllRead,
|
|
65
79
|
markAllRead,
|
|
66
80
|
refetch,
|
|
81
|
+
showToast,
|
|
67
82
|
]);
|
|
68
83
|
const handleMarkReadAndClose = useCallback((notification) => {
|
|
69
84
|
if (!notification.isRead)
|
|
@@ -81,11 +96,11 @@ export function NotificationBell({ limit = 10, viewAllHref, labels, icons, rende
|
|
|
81
96
|
}
|
|
82
97
|
function renderBellButton(props) {
|
|
83
98
|
const { hideOnMobile, buttonClassName, labels, unreadCount, handleToggle, isOpen } = props;
|
|
84
|
-
return (_jsxs(Button, { onClick: handleToggle, className: `${hideOnMobile ? "hidden md:flex" : "flex"} p-
|
|
99
|
+
return (_jsxs(Button, { onClick: handleToggle, rounded: "xl", className: `${hideOnMobile ? "hidden md:flex" : "flex"} p-[0.625rem] md:p-[0.75rem] transition-colors relative text-[var(--appkit-color-text-muted)] hover:bg-[var(--appkit-color-bg)] hover:text-[var(--appkit-color-text)] ${buttonClassName}`, "aria-label": labels.title, "aria-expanded": isOpen, children: [_jsx("svg", { className: "w-6 h-6 md:w-7 md:h-7", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" }) }), unreadCount > 0 && (_jsx(Span, { size: "xs", weight: "semibold", className: CLS_UNREAD_BADGE, children: unreadCount > 99 ? "99+" : unreadCount }))] }));
|
|
85
100
|
}
|
|
86
101
|
function renderNotificationDropdown(props) {
|
|
87
102
|
const { dropdownClassName, labels, unreadCount, isMarkingAll, handleMarkAllRead, isLoading, notifications, notificationIcons, handleMarkRead, handleMarkReadAndClose, renderActionLink, viewAllHref, setIsOpen } = props;
|
|
88
|
-
return (_jsxs(Div, { className: `absolute right-0 top-full mt-2 w-80 sm:w-96
|
|
103
|
+
return (_jsxs(Div, { className: `absolute right-0 top-full mt-2 w-80 sm:w-96 z-50 ${__O.hidden} ${dropdownClassName}`, rounded: "xl", surface: "default", border: "default", shadow: "2xl", children: [_jsxs(Row, { border: "default", justify: "between", gap: "none", className: "border-b border-[var(--appkit-color-border)]", padding: "inline", children: [_jsxs(Heading, { level: 3, weight: "semibold", color: "primary", children: [labels.title, unreadCount > 0 && _jsxs(Span, { size: "xs", weight: "medium", className: CLS_UNREAD_PILL, children: [unreadCount, " ", labels.unread] })] }), unreadCount > 0 && (_jsx(Button, { onClick: handleMarkAllRead, disabled: isMarkingAll, textSize: "xs", weight: "medium", className: "text-primary hover:underline disabled:opacity-50", children: isMarkingAll ? labels.loading : labels.markAllRead }))] }), _jsx(Div, { className: `max-h-96 ${__O.yAuto}`, children: renderNotificationListContent({ isLoading, notifications, notificationIcons, labels, handleMarkRead, handleMarkReadAndClose, renderActionLink }) }), viewAllHref && (_jsx(Div, { border: "default", className: "border-t border-[var(--appkit-color-border)] text-center", padding: "inline", children: renderActionLink({ href: viewAllHref, onClick: () => setIsOpen(false), className: "text-sm text-primary hover:underline font-medium", children: labels.viewAll }) }))] }));
|
|
89
104
|
}
|
|
90
105
|
function renderNotificationListContent(props) {
|
|
91
106
|
const { isLoading, notifications, notificationIcons, labels, handleMarkRead, handleMarkReadAndClose, renderActionLink } = props;
|
|
@@ -93,5 +108,5 @@ function renderNotificationListContent(props) {
|
|
|
93
108
|
return _jsx(Row, { align: "center", justify: "center", padding: "y-2xl", children: _jsx(Spinner, { size: "md" }) });
|
|
94
109
|
if (notifications.length === 0)
|
|
95
110
|
return (_jsxs(Stack, { justify: "center", className: "text-center", paddingY: "y-2xl", paddingX: "x-md", align: "center", children: [_jsx("svg", { className: "w-12 h-12 text-zinc-300 dark:text-zinc-600 mb-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" }) }), _jsx(Text, { weight: "medium", color: "primary", children: labels.empty }), _jsx(Text, { size: "sm", className: "mt-1", color: "muted", children: labels.emptyDesc })] }));
|
|
96
|
-
return (_jsx(Ul, { children: notifications.map((notification) => (_jsxs(Li, {
|
|
111
|
+
return (_jsx(Ul, { children: notifications.map((notification) => (_jsxs(Li, { layout: "flex-start", gap: "3", padding: "inline", className: `group border-b border-[var(--appkit-color-border)] last:border-0 transition-colors hover:bg-[var(--appkit-color-bg)] dark:hover:bg-[var(--appkit-color-surface-elevated)] ${!notification.isRead ? "bg-primary/5 dark:bg-primary/10" : ""}`, children: [_jsx(Span, { size: "xl", className: "flex-shrink-0 mt-0.5", children: notificationIcons[notification.type] ?? "🔔" }), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Row, { align: "start", justify: "between", gap: "xs", children: [_jsxs(Text, { size: "sm", className: "leading-tight", color: "primary", weight: "medium", children: [notification.title, !notification.isRead && _jsx(Span, { className: "ml-1.5 inline-block w-2 h-2 bg-primary flex-shrink-0 align-middle", rounded: "full" })] }), _jsx(Span, { size: "xs", className: "flex-shrink-0", color: "muted", children: formatRelativeTime(notification.createdAt) })] }), _jsx(Text, { size: "sm", className: `mt-0.5`, truncate: 2, color: "muted", children: notification.message }), _jsxs(Row, { gap: "3", className: "mt-1.5", children: [notification.actionUrl && renderActionLink({ href: notification.actionUrl, onClick: () => { void handleMarkReadAndClose(notification); }, className: "text-xs text-primary hover:underline font-medium", children: notification.actionLabel ?? labels.viewAction }), !notification.isRead && _jsx(Button, { variant: "ghost", onClick: () => void handleMarkRead(notification.id), className: "text-xs text-zinc-500 dark:text-zinc-400 hover:text-zinc-700 dark:hover:text-zinc-200 hover:underline p-0 h-auto", children: labels.markRead })] })] })] }, notification.id))) }));
|
|
97
112
|
}
|
|
@@ -56,7 +56,7 @@ export function NotificationPreferencesPanel({ fetchUrl = "/api/user/notificatio
|
|
|
56
56
|
if (prefs?.types)
|
|
57
57
|
setTypes((prev) => ({ ...prev, ...prefs.types }));
|
|
58
58
|
})
|
|
59
|
-
.catch(
|
|
59
|
+
.catch(console.error)
|
|
60
60
|
.finally(() => setLoading(false));
|
|
61
61
|
}, [fetchUrl]);
|
|
62
62
|
const setChannel = useCallback((key, val) => {
|
|
@@ -101,5 +101,5 @@ export function NotificationPreferencesPanel({ fetchUrl = "/api/user/notificatio
|
|
|
101
101
|
const whatsappAdminEnabled = adminChannels?.whatsapp?.enabled ?? false;
|
|
102
102
|
const smsAdminEnabled = adminChannels?.sms?.enabled ?? false;
|
|
103
103
|
const anyChannelEnabled = emailAdminEnabled || whatsappAdminEnabled || smsAdminEnabled;
|
|
104
|
-
return (_jsxs(Stack, { gap: "lg", children: [_jsx(SectionCard, { title: "In-app notifications", children: _jsxs(Row, { align: "center", justify: "between", gap: "md", padding: "y-sm", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[var(--appkit-color-text)]", size: "sm", weight: "medium", children: "In-app notifications" }), _jsx(Text, { variant: "secondary", className: "mt-0.5", size: "xs", children: "Always on \u2014 displayed in the notification bell and inbox" })] }), _jsx(Row, { className: "h-5 w-9 bg-[var(--appkit-color-primary)] px-0.
|
|
104
|
+
return (_jsxs(Stack, { gap: "lg", children: [_jsx(SectionCard, { title: "In-app notifications", children: _jsxs(Row, { align: "center", justify: "between", gap: "md", padding: "y-sm", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[var(--appkit-color-text)]", size: "sm", weight: "medium", children: "In-app notifications" }), _jsx(Text, { variant: "secondary", className: "mt-0.5", size: "xs", children: "Always on \u2014 displayed in the notification bell and inbox" })] }), _jsx(Row, { className: "h-5 w-9 bg-[var(--appkit-color-primary)] px-[0.125rem]", align: "center", justify: "end", rounded: "full", "aria-label": "Always on", children: _jsx(Span, { className: "h-4 w-4", rounded: "full", surface: "default", shadow: "default" }) })] }) }), anyChannelEnabled && (_jsxs(SectionCard, { title: "Notification channels", children: [emailAdminEnabled && (_jsx(ToggleRow, { label: "Email", description: "Receive notifications by email", checked: channels.email !== false, onChange: (v) => setChannel("email", v) })), whatsappAdminEnabled && (_jsx(ToggleRow, { label: "WhatsApp", description: "Receive notifications on WhatsApp", checked: channels.whatsapp !== false, onChange: (v) => setChannel("whatsapp", v) })), smsAdminEnabled && (_jsx(ToggleRow, { label: "SMS", description: "Receive SMS text notifications", checked: channels.sms !== false, onChange: (v) => setChannel("sms", v) }))] })), _jsx(SectionCard, { title: "Notification types", children: TYPE_ROWS.map((row) => (_jsx(ToggleRow, { label: row.label, description: row.description, checked: types[row.key] !== false, onChange: (v) => setType(row.key, v) }, row.key))) }), _jsxs(Row, { justify: "end", gap: "sm", children: [saved && (_jsx(Text, { className: "text-[var(--appkit-color-success)] self-center", size: "sm", children: "Preferences saved \u2713" })), _jsx(Button, { onClick: handleSave, isLoading: saving, size: "sm", children: "Save preferences" })] })] }));
|
|
105
105
|
}
|
|
@@ -83,6 +83,7 @@ export function UserOffersPanel({ fetchEndpoint = "/api/user/offers", onAcceptCo
|
|
|
83
83
|
setOffers(items);
|
|
84
84
|
}
|
|
85
85
|
catch (err) {
|
|
86
|
+
// toast-intentionally-silent: data load, error surfaced via fetchError state
|
|
86
87
|
void normalizeError(err);
|
|
87
88
|
setFetchError(err instanceof Error ? err.message : "Failed to load offers.");
|
|
88
89
|
}
|
|
@@ -77,12 +77,7 @@ export function UserSidebar({ items, groups, mobileOpen = false, onCloseMobile,
|
|
|
77
77
|
// ── Persistent sidebar variant (desktop left slide-over, mobile bottom-sheet) ──────
|
|
78
78
|
if (variant === "sidebar") {
|
|
79
79
|
const handleToggle = onToggle ?? close;
|
|
80
|
-
return (_jsxs(_Fragment, { children: [desktopOpen && (_jsx(Div, { surface: "overlay-xs", className: "hidden md:block fixed inset-0 backdrop-blur-[2px] z-30", onClick: handleToggle, "aria-hidden": "true" })), _jsxs(Div, { className:
|
|
81
|
-
top: "var(--header-height, 3.5rem)",
|
|
82
|
-
height: "calc(100vh - var(--header-height, 3.5rem))",
|
|
83
|
-
width: "13rem",
|
|
84
|
-
transform: desktopOpen ? "translateX(0)" : "translateX(calc(-100% + 1.25rem))",
|
|
85
|
-
}, children: [_jsxs(Stack, { border: "default", surface: "default", className: `flex-1 border-r dark:border-slate-800 ${__O.hidden}`, shadow: "xl", children: [_jsx(Div, { border: "bottom-subtle", paddingY: "y-sm-tall", className: "shrink-0", padding: "x-md", children: _jsx(Span, { size: "xs", weight: "semibold", transform: "uppercase", color: "muted", children: "My Account" }) }), _jsx(Div, { className: `flex-1 ${__O.yAuto}`, children: _jsx(DrawerContent, { groups: groups, items: items, activeHref: pathname }) })] }), _jsx(SidebarCollapseToggle, { expanded: desktopOpen, onToggle: handleToggle })] }), _jsx(Div, { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: "My Account", children: _jsx(DrawerContent, { groups: groups, items: items, activeHref: pathname, onItemClick: close }) }) })] }));
|
|
80
|
+
return (_jsxs(_Fragment, { children: [desktopOpen && (_jsx(Div, { surface: "overlay-xs", className: "hidden md:block fixed inset-0 backdrop-blur-[2px] z-30", onClick: handleToggle, "aria-hidden": "true" })), _jsxs(Div, { className: `hidden md:flex fixed left-0 z-40 transition-transform duration-300 top-[var(--header-height,3.5rem)] h-[calc(100vh-var(--header-height,3.5rem))] w-[13rem] ${desktopOpen ? "translate-x-0" : "-translate-x-[calc(100%-1.25rem)]"}`, children: [_jsxs(Stack, { border: "default", surface: "default", className: `flex-1 border-r dark:border-[var(--appkit-color-border)] ${__O.hidden}`, shadow: "xl", children: [_jsx(Div, { border: "bottom-subtle", paddingY: "y-sm-tall", className: "shrink-0", padding: "x-md", children: _jsx(Span, { size: "xs", weight: "semibold", transform: "uppercase", color: "muted", children: "My Account" }) }), _jsx(Div, { className: `flex-1 ${__O.yAuto}`, children: _jsx(DrawerContent, { groups: groups, items: items, activeHref: pathname }) })] }), _jsx(SidebarCollapseToggle, { expanded: desktopOpen, onToggle: handleToggle })] }), _jsx(Div, { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: "My Account", children: _jsx(DrawerContent, { groups: groups, items: items, activeHref: pathname, onItemClick: close }) }) })] }));
|
|
86
81
|
}
|
|
87
82
|
// ── Overlay variant (default) — portal on desktop, bottom-sheet on mobile ─
|
|
88
83
|
const content = (_jsx(DrawerContent, { groups: groups, items: items, activeHref: pathname, onItemClick: close }));
|
|
@@ -106,7 +106,7 @@ export function UserSupportView(_props) {
|
|
|
106
106
|
}
|
|
107
107
|
function renderTicketListArea(props) {
|
|
108
108
|
const { isLoading, error, tickets, setSelectedTicket, setDetailOpen } = props;
|
|
109
|
-
return (_jsxs(_Fragment, { children: [isLoading && (_jsx(Stack, { gap: "3", children: [1, 2, 3].map((i) => _jsx(Div, { className: "h-16 animate-pulse", surface: "subtle", rounded: "lg" }, i)) })), error && (_jsx(Div, { textSize: "sm", className: "border border-error/20", color: "error", surface: "danger-surface", padding: "inline", rounded: "xl", children: "Failed to load support tickets." })), !isLoading && tickets.length === 0 && (_jsx(Div, { className: "text-center", surface: "muted", paddingY: "y-2xl", paddingX: "x-lg", rounded: "xl", border: "default", children: _jsx(Text, { size: "sm", color: "muted", children: "You haven't opened any support tickets yet." }) })), _jsx(Ul, { spacing: "loose", children: tickets.map((ticket) => (_jsx(Li, { children: _jsx(Button, { rounded: "xl", variant: "ghost", type: "button", className: "w-full
|
|
109
|
+
return (_jsxs(_Fragment, { children: [isLoading && (_jsx(Stack, { gap: "3", children: [1, 2, 3].map((i) => _jsx(Div, { className: "h-16 animate-pulse", surface: "subtle", rounded: "lg" }, i)) })), error && (_jsx(Div, { textSize: "sm", className: "border border-error/20", color: "error", surface: "danger-surface", padding: "inline", rounded: "xl", children: "Failed to load support tickets." })), !isLoading && tickets.length === 0 && (_jsx(Div, { className: "text-center", surface: "muted", paddingY: "y-2xl", paddingX: "x-lg", rounded: "xl", border: "default", children: _jsx(Text, { size: "sm", color: "muted", children: "You haven't opened any support tickets yet." }) })), _jsx(Ul, { spacing: "loose", children: tickets.map((ticket) => (_jsx(Li, { children: _jsx(Button, { rounded: "xl", variant: "ghost", type: "button", shadow: "sm", border: "default", paddingX: "md", paddingY: "md", className: "w-full bg-[var(--appkit-color-surface)] text-left hover:border-[var(--appkit-color-primary-300)] transition-colors", onClick: () => { setSelectedTicket(ticket); setDetailOpen(true); }, children: _jsxs(Row, { align: "start", justify: "between", gap: "sm", children: [_jsxs(Div, { className: "min-w-0 flex-1", children: [_jsx(Text, { className: "truncate", color: "primary", weight: "medium", children: ticket.subject }), _jsxs(Text, { size: "xs", color: "muted", children: [ticket.category.replace(/_/g, " "), ticket.orderId ? ` · Order: ${ticket.orderId}` : ""] })] }), _jsx(Span, { size: "xs", weight: "medium", className: `shrink-0 inline-flex ${STATUS_BADGE[ticket.status] ?? STATUS_BADGE.open}`, padding: "pill-sm", rounded: "full", children: ticket.status.replace(/_/g, " ") })] }) }) }, ticket.id))) })] }));
|
|
110
110
|
}
|
|
111
111
|
function renderNewTicketDrawer(props) {
|
|
112
112
|
const { newTicketOpen, setNewTicketOpen, newCategory, setNewCategory, newSubject, setNewSubject, newOrderId, setNewOrderId, newDescription, setNewDescription, createMutation } = props;
|
|
@@ -3,7 +3,7 @@ import { BarChart2 } from "lucide-react";
|
|
|
3
3
|
import { Alert, Div, Heading, Li, Row, Section, Span, Stack, Text, Ul } from "../../../ui";
|
|
4
4
|
import { GC } from "../../_guide-cls";
|
|
5
5
|
export function AdminAnalyticsGuideView() {
|
|
6
|
-
return (_jsxs(Stack, { className: "max-w-3xl mx-auto", padding: "b-2xl", gap: "xl", children: [_jsxs(Section, { children: [_jsxs(Row, { className: "mb-2", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10
|
|
6
|
+
return (_jsxs(Stack, { className: "max-w-3xl mx-auto", padding: "b-2xl", gap: "xl", children: [_jsxs(Section, { children: [_jsxs(Row, { className: "mb-2", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10 [background:linear-gradient(135deg,var(--appkit-color-primary-700)_0%,var(--appkit-color-cobalt)_100%)]", align: "center", justify: "center", rounded: "xl", children: _jsx(BarChart2, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] tracking-widest", size: "sm", weight: "semibold", transform: "uppercase", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-[var(--appkit-color-text)] mb-2", mdSize: "3xl", size: "2xl", weight: "bold", children: "Analytics" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Revenue, order funnel, product performance, and store metrics on LetItRip." })] }), [
|
|
7
7
|
{
|
|
8
8
|
title: "Revenue Dashboard",
|
|
9
9
|
content: (_jsxs(Ul, { className: GC.listMuted, children: [_jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "GMV (Gross Merchandise Value)" }), ": Total order subtotals across all stores. Does not deduct platform commission or refunds."] }), _jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "Net Revenue" }), ": GMV \u00D7 platformFee \u2014 refunded orders excluded."] }), _jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "Period filter" }), ": Last 7 / 30 / 90 days, or custom date range. All monetary values shown in INR."] }), _jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "Payout total" }), ": Total disbursed to sellers in the same period. Revenue - Payout = Platform earnings."] })] })),
|
|
@@ -20,5 +20,5 @@ export function AdminAnalyticsGuideView() {
|
|
|
20
20
|
title: "Store-Level Metrics",
|
|
21
21
|
content: (_jsxs(_Fragment, { children: [_jsx(Text, { className: "text-[var(--appkit-color-text-muted)] mb-3", size: "sm", children: "Filter analytics by store to see individual seller performance. Available metrics:" }), _jsxs(Ul, { className: "list-inside text-[var(--appkit-color-text-muted)]", marker: "disc", spacing: "tight", size: "sm", children: [_jsx(Li, { children: "Total orders and completion rate" }), _jsx(Li, { children: "Average order value" }), _jsx(Li, { children: "Return and refund rate" }), _jsx(Li, { children: "Average seller rating" }), _jsx(Li, { children: "Payout history" })] }), _jsx(Alert, { variant: "info", className: "mt-4", children: "Store analytics are visible to the store owner in their seller dashboard. Admin sees the full platform view. Do not share a specific store's metrics with other stores." })] })),
|
|
22
22
|
},
|
|
23
|
-
].map(({ title, content }) => (_jsxs(Section, { className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]
|
|
23
|
+
].map(({ title, content }) => (_jsxs(Section, { overflow: "hidden", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "2xl", children: [_jsxs(Row, { className: "border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-2,var(--appkit-color-border))]/20", padding: "inlineLg", align: "center", gap: "3", children: [_jsx(BarChart2, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, size: "base", weight: "semibold", children: title })] }), _jsx(Div, { paddingY: "y-md-lg", padding: "x-lg", children: content })] }, title)))] }));
|
|
24
24
|
}
|
|
@@ -200,6 +200,6 @@ export function AdminBlogEditorView({ postId, onSaved, onDeleted, embedded, ...r
|
|
|
200
200
|
}
|
|
201
201
|
const previewSection = (_jsxs("div", { className: "rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-raised)] p-5 max-h-[calc(100vh-12rem)] overflow-y-auto", children: [_jsx(Row, { textSize: "xs", textWeight: "semibold", color: "muted", className: "mb-3 uppercase tracking-wide", align: "center", gap: "sm", children: _jsx(Span, { children: "Live preview" }) }), draft.coverImage ? (_jsx("img", { src: draft.coverImage, alt: "", className: "w-full rounded-md mb-4 object-cover max-h-64" })) : null, _jsx(Heading, { level: 1, className: "mb-1", size: "2xl", weight: "bold", children: draft.title || "Untitled post" }), _jsxs(Text, { className: "text-[var(--appkit-color-text-muted)] mb-4", size: "xs", children: [draft.authorName || "Anonymous", draft.category ? ` · ${draft.category}` : ""] }), draft.excerpt ? (_jsx(Text, { className: "italic text-[var(--appkit-color-text-secondary)] mb-4", children: draft.excerpt })) : null, _jsx(RichTextRenderer, { html: draft.content || "<em>No content yet…</em>" }), draft.tags.length > 0 ? (_jsx(Row, { wrap: true, gap: "xs", className: "mt-6", children: draft.tags.map((t) => (_jsxs(Span, { size: "xs", className: "bg-[var(--appkit-color-surface)] border border-[var(--appkit-color-border)]", rounded: "full", padding: "pill-xs", children: ["#", t] }, t))) })) : null] }, "preview"));
|
|
202
202
|
return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Post" : "New Blog Post", sections: [
|
|
203
|
-
_jsxs(Div, { className: "lg:grid lg:grid-cols-[3fr_2fr] lg:gap-
|
|
203
|
+
_jsxs(Div, { className: "lg:grid lg:grid-cols-[3fr_2fr] lg:gap-[1.5rem]", children: [_jsx(Div, { children: formContent }), _jsx(Div, { className: "mt-6 lg:mt-0 lg:sticky lg:top-4 lg:self-start", children: previewSection })] }, "split"),
|
|
204
204
|
] }));
|
|
205
205
|
}
|
|
@@ -98,7 +98,7 @@ export function AdminBundlesView({ getEditHref, newHref }) {
|
|
|
98
98
|
return parts.join(",") || undefined;
|
|
99
99
|
},
|
|
100
100
|
getRowHref: getEditHref,
|
|
101
|
-
toolbarExtra: (_jsx(Button, { asChild: true, size: "sm", variant: "primary", children: _jsxs(TextLink, { href: newHref,
|
|
101
|
+
toolbarExtra: (_jsx(Button, { asChild: true, size: "sm", variant: "primary", children: _jsxs(TextLink, { href: newHref, layout: "flex", align: "center", gap: "xs", children: ["+ ", BUNDLE_COPY.adminList.newButton] }) })),
|
|
102
102
|
buildBulkActions: (selection) => [
|
|
103
103
|
buildBulkAction(ACTIONS.ADMIN["activate-bundle"], async () => {
|
|
104
104
|
await Promise.all(selection.selectedIds.map((id) => fetch(ADMIN_ENDPOINTS.BUNDLE_BY_ID(id), {
|
|
@@ -67,7 +67,7 @@ const TEXT_ALIGN_OPTIONS = [
|
|
|
67
67
|
// ── Zone Picker ──────────────────────────────────────────────────────────────
|
|
68
68
|
function ZonePicker({ selected, onChange, disabled, }) {
|
|
69
69
|
const zones = [1, 2, 3, 4, 5, 6];
|
|
70
|
-
return (_jsxs(Div, { children: [_jsx(Text, { className: "mb-1", color: "muted", size: "xs", children: "Zone (row \u00D7 col grid)" }), _jsx(
|
|
70
|
+
return (_jsxs(Div, { children: [_jsx(Text, { className: "mb-1", color: "muted", size: "xs", children: "Zone (row \u00D7 col grid)" }), _jsx(Div, { layout: "grid", gap: "1", className: "grid-rows-2 grid-cols-3 w-[150px]", children: zones.map((z) => {
|
|
71
71
|
const isDisabled = disabled?.(z) ?? false;
|
|
72
72
|
return (_jsx("button", { type: "button", disabled: isDisabled, onClick: () => !isDisabled && onChange(z), className: `rounded text-xs font-mono py-2 border transition-colors ${selected === z
|
|
73
73
|
? "bg-primary text-white border-primary"
|
|
@@ -4,7 +4,7 @@ import { Alert, Code, Div, Heading, Li, Row, Section, Span, Stack, Text, Ul } fr
|
|
|
4
4
|
import { GC } from "../../_guide-cls";
|
|
5
5
|
const CLS_CODE = "text-xs bg-amber-100 dark:bg-amber-900/30 px-1 rounded";
|
|
6
6
|
export function AdminCatalogGuideView() {
|
|
7
|
-
return (_jsxs(Stack, { className: "max-w-3xl mx-auto", padding: "b-2xl", gap: "xl", children: [_jsxs(Section, { children: [_jsxs(Row, { className: "mb-2", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10
|
|
7
|
+
return (_jsxs(Stack, { className: "max-w-3xl mx-auto", padding: "b-2xl", gap: "xl", children: [_jsxs(Section, { children: [_jsxs(Row, { className: "mb-2", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10 [background:linear-gradient(135deg,var(--appkit-color-primary-700)_0%,var(--appkit-color-cobalt)_100%)]", align: "center", justify: "center", rounded: "xl", children: _jsx(Package, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] tracking-widest", size: "sm", weight: "semibold", transform: "uppercase", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-[var(--appkit-color-text)] mb-2", mdSize: "3xl", size: "2xl", weight: "bold", children: "Catalog" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Products, categories, brands, and reviews \u2014 how the LetItRip catalog is structured and managed." })] }), [
|
|
8
8
|
{
|
|
9
9
|
Icon: Package, title: "Product Management",
|
|
10
10
|
content: (_jsxs(Ul, { className: GC.listMuted, children: [_jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "Listing types" }), ": ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "standard" }), " (prefix ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "product-" }), "), ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "auction" }), " (prefix ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "auction-" }), "), ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "pre-order" }), " (prefix ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "preorder-" }), ")."] }), _jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "Admin vs store creation" }), ": Admins can create products on behalf of any store via the store picker in AdminProductEditorView."] }), _jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "Status lifecycle" }), ": DRAFT \u2192 PUBLISHED \u2192 ARCHIVED. Published products appear in search. Archived products are hidden but not deleted."] }), _jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "J13 rule" }), ": Always use ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "listingType" }), " field \u2014 the legacy ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "isAuction" }), "/", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "isPreOrder" }), " booleans have been removed. All queries use ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "where(\"listingType\", \"==\", x)" }), "."] }), _jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "Media URLs" }), ": Never write raw Firebase Storage URLs to Firestore. All product image URLs must use the ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "/api/media/[slug]" }), " proxy format."] })] })),
|
|
@@ -25,5 +25,5 @@ export function AdminCatalogGuideView() {
|
|
|
25
25
|
Icon: AlertTriangle, title: "Common Admin Mistakes",
|
|
26
26
|
content: (_jsx(Alert, { variant: "warning", children: _jsxs(Ul, { spacing: "tight", size: "sm", children: [_jsx(Li, { children: "\u2717 Publishing a product with no images \u2014 buyers cannot evaluate it." }), _jsxs(Li, { children: ["\u2717 Creating a subcategory without setting ", _jsx(Code, { className: CLS_CODE, children: "rootId" }), " \u2014 category tree breaks."] }), _jsxs(Li, { children: ["\u2717 Setting ", _jsx(Code, { className: CLS_CODE, children: "parentId" }), " of a root category to anything other than ", _jsx(Code, { className: CLS_CODE, children: "null" }), " \u2014 creates circular hierarchy."] }), _jsx(Li, { children: "\u2717 Duplicating brand slugs \u2014 Firestore document ID collision, second write silently overwrites the first." }), _jsx(Li, { children: "\u2717 Writing raw Firebase Storage URLs to Firestore \u2014 breaks the media watermark proxy and CDN caching." })] }) })),
|
|
27
27
|
},
|
|
28
|
-
].map(({ Icon, title, content }) => (_jsxs(Section, { className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]
|
|
28
|
+
].map(({ Icon, title, content }) => (_jsxs(Section, { overflow: "hidden", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "2xl", children: [_jsxs(Row, { className: "border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-2,var(--appkit-color-border))]/20", padding: "inlineLg", align: "center", gap: "3", children: [_jsx(Icon, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, size: "base", weight: "semibold", children: title })] }), _jsx(Div, { paddingY: "y-md-lg", padding: "x-lg", children: content })] }, title)))] }));
|
|
29
29
|
}
|
|
@@ -3,7 +3,7 @@ import { FileText, Calendar, BookOpen, Layout, Grid, Megaphone, Mail } from "luc
|
|
|
3
3
|
import { Alert, Code, Div, Heading, Li, Row, Section, Span, Stack, Text, Ul } from "../../../ui";
|
|
4
4
|
import { GC } from "../../_guide-cls";
|
|
5
5
|
export function AdminContentGuideView() {
|
|
6
|
-
return (_jsxs(Stack, { className: "max-w-3xl mx-auto", padding: "b-2xl", gap: "xl", children: [_jsxs(Section, { children: [_jsxs(Row, { className: "mb-2", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10
|
|
6
|
+
return (_jsxs(Stack, { className: "max-w-3xl mx-auto", padding: "b-2xl", gap: "xl", children: [_jsxs(Section, { children: [_jsxs(Row, { className: "mb-2", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10 [background:linear-gradient(135deg,var(--appkit-color-primary-700)_0%,var(--appkit-color-cobalt)_100%)]", align: "center", justify: "center", rounded: "xl", children: _jsx(FileText, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] tracking-widest", size: "sm", weight: "semibold", transform: "uppercase", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-[var(--appkit-color-text)] mb-2", mdSize: "3xl", size: "2xl", weight: "bold", children: "Content & Marketing" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Blog posts, events, FAQs, carousel, homepage sections, ads, and newsletter on LetItRip." })] }), [
|
|
7
7
|
{
|
|
8
8
|
Icon: FileText, title: "Blog Posts",
|
|
9
9
|
content: (_jsxs(Ul, { className: GC.listMuted, children: [_jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "Statuses" }), ": ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "draft" }), " (not public), ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "published" }), " (live, indexed)."] }), _jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "readTimeMinutes" }), ": Auto-calculated from content word count (200 wpm). Override manually if the post has heavy media."] }), _jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "youtubeId" }), ": Optional embedded YouTube video. Use only the video ID (e.g. ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "dQw4w9WgXcQ" }), "), not the full URL."] }), _jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "Media in body" }), ": All images in rich text must use the ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "/api/media/" }), " proxy URL, not raw Firebase Storage links."] }), _jsxs(Li, { children: [_jsx(Span, { weight: "bold", children: "isFeatured" }), ": Sets the post as featured in the blog listing. Different from the homepage featured section \u2014 that is driven by a separate ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "homepageSections" }), " config."] })] })),
|
|
@@ -32,5 +32,5 @@ export function AdminContentGuideView() {
|
|
|
32
32
|
Icon: Mail, title: "Newsletter",
|
|
33
33
|
content: (_jsxs(_Fragment, { children: [_jsxs(Text, { className: "text-[var(--appkit-color-text-muted)] mb-3", size: "sm", children: ["Subscribers are stored in the ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "newsletter" }), " collection. The admin panel supports subscriber export and campaign send."] }), _jsx(Alert, { variant: "warning", children: "Legal obligation: every email sent must include a working unsubscribe link. Under the Indian IT Act and CAN-SPAM, unsubscribe requests must be honoured within 10 business days. Never send to unsubscribed addresses. All newsletter exports are de-identified by default." })] })),
|
|
34
34
|
},
|
|
35
|
-
].map(({ Icon, title, content }) => (_jsxs(Section, { className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]
|
|
35
|
+
].map(({ Icon, title, content }) => (_jsxs(Section, { overflow: "hidden", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "2xl", children: [_jsxs(Row, { className: "border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-2,var(--appkit-color-border))]/20", padding: "inlineLg", align: "center", gap: "3", children: [_jsx(Icon, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, size: "base", weight: "semibold", children: title })] }), _jsx(Div, { paddingY: "y-md-lg", padding: "x-lg", children: content })] }, title)))] }));
|
|
36
36
|
}
|
|
@@ -79,7 +79,7 @@ function PermissionDomainsPanel({ permissions, togglePerm }) {
|
|
|
79
79
|
if (domainPerms.length === 0)
|
|
80
80
|
return null;
|
|
81
81
|
const checked = domainPerms.filter((p) => permissions.has(p)).length;
|
|
82
|
-
return (_jsxs(Details, { className: "group", children: [_jsxs(Summary, {
|
|
82
|
+
return (_jsxs(Details, { className: "group", children: [_jsxs(Summary, { paddingX: "x-sm", paddingY: "y-xs", weight: "semibold", color: "muted", layout: "flex", align: "center", justify: "between", className: "uppercase tracking-wide hover:bg-[var(--appkit-color-bg)] transition-colors", children: [_jsx(Span, { size: "xs", children: domain.label }), _jsxs(Span, { size: "xs", weight: "normal", className: "normal-case", color: "faint", children: [checked, "/", domainPerms.length] })] }), _jsx(Div, { layout: "grid", paddingY: "y-xs-tall", className: "grid-cols-2 gap-x-2 gap-y-1.5", surface: "muted", padding: "x-sm", children: domainPerms.map((perm) => (_jsxs("label", { className: "flex items-center gap-2 cursor-pointer text-xs text-zinc-700 dark:text-zinc-300", children: [_jsx("input", { type: "checkbox", checked: permissions.has(perm), onChange: () => togglePerm(perm), className: "h-3.5 w-3.5 rounded border-zinc-300 dark:border-slate-600 accent-primary" }), formatPermLabel(perm)] }, perm))) })] }, domain.prefix));
|
|
83
83
|
}) })] }));
|
|
84
84
|
}
|
|
85
85
|
// --- Component ---------------------------------------------------------------
|
|
@@ -171,5 +171,5 @@ export function AdminEmployeeEditorView({ open, onClose, mode, userId, displayNa
|
|
|
171
171
|
else
|
|
172
172
|
updateMutation.mutate();
|
|
173
173
|
};
|
|
174
|
-
return (_jsxs(_Fragment, { children: [_jsx(SideDrawer, { isOpen: open, onClose: onClose, title: mode === "invite" ? "Invite Employee" : `Edit — ${displayName ?? "Employee"}`, children: _jsxs(Form, { onSubmit: handleSubmit,
|
|
174
|
+
return (_jsxs(_Fragment, { children: [_jsx(SideDrawer, { isOpen: open, onClose: onClose, title: mode === "invite" ? "Invite Employee" : `Edit — ${displayName ?? "Employee"}`, children: _jsxs(Form, { onSubmit: handleSubmit, spacing: "lg", padding: "md", children: [mode === "invite" && (_jsxs(Stack, { gap: "xs", className: "", children: [_jsx(Label, { size: "sm", weight: "medium", color: "primary", children: "Email address" }), _jsx("input", { type: "email", required: true, value: email, onChange: (e) => setEmail(e.target.value), placeholder: "employee@example.com", className: "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 focus:outline-none focus:ring-2 focus:ring-primary/60 transition" })] })), _jsxs(Stack, { gap: "xs", className: "", children: [_jsx(Label, { size: "sm", weight: "medium", color: "primary", children: "Permission group" }), _jsx(Select, { value: group, onChange: (e) => applyGroupPreset(e.target.value), options: GROUP_OPTIONS }), _jsx(Text, { size: "xs", color: "muted", children: "Selecting a group auto-fills the permissions below. You can still customise individual permissions." })] }), _jsx(PermissionDomainsPanel, { permissions: permissions, togglePerm: togglePerm }), _jsxs(FormActions, { children: [_jsx(Button, { type: "submit", variant: "primary", disabled: isBusy, isLoading: isBusy, children: mode === "invite" ? "Send Invite" : "Save" }), mode === "edit" && userId && (_jsx(Button, { type: "button", variant: "danger", disabled: isBusy, onClick: () => setRevokeOpen(true), children: "Revoke Access" }))] })] }) }), mode === "edit" && (_jsx(ConfirmDeleteModal, { isOpen: revokeOpen, onClose: () => setRevokeOpen(false), onConfirm: () => revokeMutation.mutate(), isDeleting: revokeMutation.isPending, title: "Revoke employee access?", message: `${displayName ?? "This employee"} will lose admin panel access immediately. Their user account remains active — only their role is reset to user.`, confirmText: "Revoke Access", variant: "danger" }))] }));
|
|
175
175
|
}
|
|
@@ -74,9 +74,5 @@ export function AdminGuideHubView({ permissions = [], isFullAdmin = false }) {
|
|
|
74
74
|
const hasPermission = (perm) => isFullAdmin || permissions.includes(perm);
|
|
75
75
|
const visibleCards = GUIDE_CARDS.filter((c) => hasPermission(c.permission));
|
|
76
76
|
const hasAny = visibleCards.length > 0;
|
|
77
|
-
return (_jsxs(Stack, { gap: "xl", padding: "b-2xl", children: [_jsx(Section, {
|
|
78
|
-
background: "linear-gradient(135deg,var(--appkit-color-primary-700) 0%,var(--appkit-color-cobalt) 60%,var(--appkit-color-secondary-400) 100%)",
|
|
79
|
-
}, children: [_jsxs(Row, { className: "mb-3", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10", surface: "default", align: "center", justify: "center", rounded: "xl", children: _jsx(BookOpen, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { color: "inverse", className: "/80 tracking-widest", size: "sm", weight: "semibold", transform: "uppercase", children: "Admin & Employee Guide" })] }), _jsx(Heading, { color: "inverse", level: 1, className: "mb-2", mdSize: "3xl", size: "2xl", weight: "bold", children: "LetItRip Internal Guide" }), _jsx(Text, { color: "inverse", className: "/80", size: "base", children: "Everything you need to operate and manage LetItRip \u2014 India's largest collectibles marketplace." })] }) }), _jsx(Alert, { variant: "info", compact: true, children: "These guides describe expected platform behaviour. Real access to each section is enforced independently by the permission system \u2014 this page is reference only." }), !hasAny && (_jsx(Alert, { variant: "info", title: "Limited access", children: "Your permission set doesn't include read access to any admin sections yet. Contact your admin to request the permissions you need." })), hasAny && (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "text-[var(--appkit-color-text)] mb-4", size: "lg", weight: "semibold", children: "Guides" }), _jsx(Div, { layout: "grid", gap: "4", className: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3", children: visibleCards.map(({ Icon, title, description, href }) => (_jsxs("a", { href: href, className: "group flex flex-col gap-3 rounded-xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] p-5 hover:border-[var(--appkit-color-primary)] hover:shadow-md transition-all", children: [_jsxs(Row, { align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-9 h-9", align: "center", justify: "center", rounded: "lg", style: {
|
|
80
|
-
background: "linear-gradient(135deg,var(--appkit-color-primary-700) 0%,var(--appkit-color-cobalt) 100%)",
|
|
81
|
-
}, children: _jsx(Icon, { className: "w-4 h-4 text-white" }) }), _jsx(Text, { className: "text-[var(--appkit-color-text)] group-hover:text-[var(--appkit-color-primary)] transition-colors", weight: "semibold", children: title })] }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] leading-relaxed", size: "sm", children: description }), _jsx(Text, { className: "text-[var(--appkit-color-primary)] mt-auto", size: "xs", weight: "medium", children: "Read guide \u2192" })] }, title))) })] })), _jsx(Section, { className: CLS_WARN_PANEL, children: _jsxs(Row, { align: "start", gap: "3", children: [_jsx(AlertTriangle, { className: "w-5 h-5 text-warning flex-shrink-0 mt-0.5" }), _jsxs(Div, { children: [_jsx(Text, { className: CLS_WARN_HEAD, children: "Remember: with great access comes responsibility" }), _jsx(Text, { className: CLS_WARN_BODY, children: "Admin actions are logged. Never access user PII (email, phone) without a legitimate support reason. Never grant capabilities or permissions without documented approval. When in doubt, escalate to a senior admin." })] })] }) })] }));
|
|
77
|
+
return (_jsxs(Stack, { gap: "xl", padding: "b-2xl", children: [_jsx(Section, { overflow: "hidden", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "2xl", shadow: "sm", children: _jsxs(Div, { paddingX: "x-md-xl", paddingY: "y-xl", className: "[background:linear-gradient(135deg,var(--appkit-color-primary-700)_0%,var(--appkit-color-cobalt)_60%,var(--appkit-color-secondary-400)_100%)]", children: [_jsxs(Row, { className: "mb-3", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10", surface: "default", align: "center", justify: "center", rounded: "xl", children: _jsx(BookOpen, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { color: "inverse", className: "/80 tracking-widest", size: "sm", weight: "semibold", transform: "uppercase", children: "Admin & Employee Guide" })] }), _jsx(Heading, { color: "inverse", level: 1, className: "mb-2", mdSize: "3xl", size: "2xl", weight: "bold", children: "LetItRip Internal Guide" }), _jsx(Text, { color: "inverse", className: "/80", size: "base", children: "Everything you need to operate and manage LetItRip \u2014 India's largest collectibles marketplace." })] }) }), _jsx(Alert, { variant: "info", compact: true, children: "These guides describe expected platform behaviour. Real access to each section is enforced independently by the permission system \u2014 this page is reference only." }), !hasAny && (_jsx(Alert, { variant: "info", title: "Limited access", children: "Your permission set doesn't include read access to any admin sections yet. Contact your admin to request the permissions you need." })), hasAny && (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "text-[var(--appkit-color-text)] mb-4", size: "lg", weight: "semibold", children: "Guides" }), _jsx(Div, { layout: "grid", gap: "4", className: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3", children: visibleCards.map(({ Icon, title, description, href }) => (_jsxs("a", { href: href, className: "group flex flex-col gap-3 rounded-xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] p-5 hover:border-[var(--appkit-color-primary)] hover:shadow-md transition-all", children: [_jsxs(Row, { align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-9 h-9 [background:linear-gradient(135deg,var(--appkit-color-primary-700)_0%,var(--appkit-color-cobalt)_100%)]", align: "center", justify: "center", rounded: "lg", children: _jsx(Icon, { className: "w-4 h-4 text-white" }) }), _jsx(Text, { className: "text-[var(--appkit-color-text)] group-hover:text-[var(--appkit-color-primary)] transition-colors", weight: "semibold", children: title })] }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] leading-relaxed", size: "sm", children: description }), _jsx(Text, { className: "text-[var(--appkit-color-primary)] mt-auto", size: "xs", weight: "medium", children: "Read guide \u2192" })] }, title))) })] })), _jsx(Section, { className: CLS_WARN_PANEL, children: _jsxs(Row, { align: "start", gap: "3", children: [_jsx(AlertTriangle, { className: "w-5 h-5 text-warning flex-shrink-0 mt-0.5" }), _jsxs(Div, { children: [_jsx(Text, { className: CLS_WARN_HEAD, children: "Remember: with great access comes responsibility" }), _jsx(Text, { className: CLS_WARN_BODY, children: "Admin actions are logged. Never access user PII (email, phone) without a legitimate support reason. Never grant capabilities or permissions without documented approval. When in doubt, escalate to a senior admin." })] })] }) })] }));
|
|
82
78
|
}
|
|
@@ -67,7 +67,7 @@ function MediaBrowser({ onCopy }) {
|
|
|
67
67
|
const isImage = (f.contentType ?? "").startsWith("image/");
|
|
68
68
|
return (_jsxs(Div, { className: "group overflow-hidden", surface: "muted", rounded: "lg", border: "default", children: [_jsx(Row, { color: "muted", textSize: "xs", className: "aspect-square", surface: "subtle", align: "center", justify: "center", children: isImage ? (
|
|
69
69
|
// eslint-disable-next-line @next/next/no-img-element
|
|
70
|
-
_jsx("img", { src: f.downloadURL, alt: f.name, className: "h-full w-full object-cover", loading: "lazy" })) : (_jsx(Text, { align: "center",
|
|
70
|
+
_jsx("img", { src: f.downloadURL, alt: f.name, className: "h-full w-full object-cover", loading: "lazy" })) : (_jsx(Text, { align: "center", paddingX: "x-xs", className: "break-all", children: f.contentType ?? "file" })) }), _jsxs(Div, { className: "p-[0.375rem]", children: [_jsx(Text, { className: "truncate text-[10px] font-mono", color: "muted", children: f.name.split("/").pop() }), _jsx(Button, { type: "button", variant: "ghost", textSize: "xs", className: "mt-1 w-full", onClick: () => onCopy(f.downloadURL), children: ACTIONS.MEDIA["copy-url"].label })] })] }, f.name));
|
|
71
71
|
}), filtered.length === 0 && !isLoading && (_jsx(Text, { paddingY: "lg", className: "col-span-full", color: "muted", size: "sm", align: "center", children: "No files found." }))] }), _jsxs(Row, { align: "center", justify: "between", children: [_jsxs(Text, { size: "xs", color: "muted", children: [filtered.length, " file(s)", nextPageToken ? " · more available" : ""] }), nextPageToken && (_jsx(Button, { type: "button", variant: "outline", onClick: () => void load(nextPageToken), disabled: isLoading, children: isLoading ? "Loading…" : "Load more" }))] })] }));
|
|
72
72
|
}
|
|
73
73
|
function MediaUploaderPanel({ onUpload, isUploadPending, isCleanupPending, heroAssetUrl, setHeroAssetUrl, galleryAssets, setGalleryAssets, stagedUrls, setHeroStagedUrls, setGalleryStagedUrls, handleAbort, copiedUrl, onCopy, onClearPreviews, onDiscardStaged, }) {
|
|
@@ -12,7 +12,7 @@ const __O = {
|
|
|
12
12
|
hidden: "overflow-hidden",
|
|
13
13
|
};
|
|
14
14
|
function NavItemRow({ item, idx, total, reorderPending, onMoveUp, onMoveDown, onVisibilityChange, onEdit, onDelete, }) {
|
|
15
|
-
return (_jsxs(Row, { surface: "default", padding: "inline", align: "center", gap: "3", children: [_jsxs(Stack, { className: "
|
|
15
|
+
return (_jsxs(Row, { surface: "default", padding: "inline", align: "center", gap: "3", children: [_jsxs(Stack, { className: "shrink-0 gap-[0.125rem]", children: [_jsx(Button, { variant: "ghost", type: "button", onClick: () => onMoveUp(idx), disabled: idx === 0 || reorderPending, className: "text-zinc-400 hover:text-zinc-700 dark:hover:text-zinc-200 disabled:opacity-30 leading-none text-xs p-0 min-h-0 h-auto rounded-none", "aria-label": "Move up", children: "\u25B2" }), _jsx(Button, { variant: "ghost", type: "button", onClick: () => onMoveDown(idx), disabled: idx >= total - 1 || reorderPending, className: "text-zinc-400 hover:text-zinc-700 dark:hover:text-zinc-200 disabled:opacity-30 leading-none text-xs p-0 min-h-0 h-auto rounded-none", "aria-label": "Move down", children: "\u25BC" })] }), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Text, { className: "truncate", color: "primary", size: "sm", weight: "medium", children: [item.parentId ? _jsx(Span, { className: "mr-1", color: "faint", children: "\u21B3" }) : null, item.label] }), _jsx(Text, { className: "truncate", color: "muted", size: "xs", children: item.href })] }), _jsx(Toggle, { checked: item.isVisible ?? true, onChange: (val) => onVisibilityChange(item.id, val), label: "" }), _jsx(RowActionMenu, { actions: [
|
|
16
16
|
{ label: ROW_ACTION_META[ROW_ACTION_ID.EDIT].label, onClick: () => onEdit(item) },
|
|
17
17
|
{ label: ROW_ACTION_META[ROW_ACTION_ID.DELETE].label, destructive: true, onClick: () => onDelete(item) },
|
|
18
18
|
] })] }));
|
|
@@ -3,7 +3,7 @@ import { ShoppingBag, Hash, Scale, Wallet, RotateCcw, DollarSign, Gavel } from "
|
|
|
3
3
|
import { Code, Div, Heading, Li, Row, Section, Span, Stack, Text, Ul } from "../../../ui";
|
|
4
4
|
import { GC } from "../../_guide-cls";
|
|
5
5
|
export function AdminOrdersGuideView() {
|
|
6
|
-
return (_jsxs(Stack, { className: "max-w-3xl mx-auto", padding: "b-2xl", gap: "xl", children: [_jsxs(Section, { children: [_jsxs(Row, { className: "mb-2", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10
|
|
6
|
+
return (_jsxs(Stack, { className: "max-w-3xl mx-auto", padding: "b-2xl", gap: "xl", children: [_jsxs(Section, { children: [_jsxs(Row, { className: "mb-2", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10 [background:linear-gradient(135deg,var(--appkit-color-primary-700)_0%,var(--appkit-color-cobalt)_100%)]", align: "center", justify: "center", rounded: "xl", children: _jsx(ShoppingBag, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] tracking-widest", size: "sm", weight: "semibold", transform: "uppercase", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-[var(--appkit-color-text)] mb-2", mdSize: "3xl", size: "2xl", weight: "bold", children: "Orders & Finance" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Order statuses, payouts, disputes, returns, and commission math on LetItRip." })] }), [
|
|
7
7
|
{
|
|
8
8
|
Icon: ShoppingBag, title: "Order Statuses",
|
|
9
9
|
content: (_jsxs(Stack, { textSize: "sm", gap: "sm", children: [[
|
|
@@ -14,7 +14,7 @@ export function AdminOrdersGuideView() {
|
|
|
14
14
|
["RETURN_REQUESTED", "Buyer opened a return. Seller has 3 days to respond."],
|
|
15
15
|
["REFUNDED", "Return accepted and refund issued via Razorpay."],
|
|
16
16
|
["CANCELLED", "Cancelled before shipping. Payment returned."],
|
|
17
|
-
].map(([status, note]) => (_jsxs(Row, { gap: "3", children: [_jsx(Text, { className: "flex-shrink-0 font-mono text-[var(--appkit-color-primary)] w-40", size: "xs", weight: "semibold", children: status }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: note })] }, status))), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] pt-
|
|
17
|
+
].map(([status, note]) => (_jsxs(Row, { gap: "3", children: [_jsx(Text, { className: "flex-shrink-0 font-mono text-[var(--appkit-color-primary)] w-40", size: "xs", weight: "semibold", children: status }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: note })] }, status))), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] pt-[0.5rem]", size: "sm", children: "Admin-only transitions: force-cancel (any status before DELIVERED), force-refund (post-DELIVERED dispute)." })] })),
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
Icon: Hash, title: "Order ID Format",
|
|
@@ -40,5 +40,5 @@ export function AdminOrdersGuideView() {
|
|
|
40
40
|
Icon: Gavel, title: "Auction Settlement",
|
|
41
41
|
content: (_jsxs(Ul, { className: GC.listMuted, children: [_jsx(Li, { children: "When an auction ends and the winner does not pay within 48 hours: the order auto-cancels and the system notifies the next-highest bidder." }), _jsx(Li, { children: "If the auto-cancel system fails (rare), admin can manually cancel from the order detail page and trigger the next-bidder flow via a support action." }), _jsxs(Li, { children: ["Repeat non-paying winners can receive a ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "place_bids" }), " soft ban from the Trust & Safety section."] })] })),
|
|
42
42
|
},
|
|
43
|
-
].map(({ Icon, title, content }) => (_jsxs(Section, { className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]
|
|
43
|
+
].map(({ Icon, title, content }) => (_jsxs(Section, { overflow: "hidden", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "2xl", children: [_jsxs(Row, { className: "border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-2,var(--appkit-color-border))]/20", padding: "inlineLg", align: "center", gap: "3", children: [_jsx(Icon, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, size: "base", weight: "semibold", children: title })] }), _jsx(Div, { paddingY: "y-md-lg", padding: "x-lg", children: content })] }, title)))] }));
|
|
44
44
|
}
|
|
@@ -40,10 +40,7 @@ export function AdminPayoutsView({ children, ...props }) {
|
|
|
40
40
|
});
|
|
41
41
|
const handleExportCsv = async () => {
|
|
42
42
|
try {
|
|
43
|
-
const
|
|
44
|
-
if (!res.ok)
|
|
45
|
-
throw new Error("Export failed");
|
|
46
|
-
const blob = await res.blob();
|
|
43
|
+
const blob = await apiClient.blob(ADMIN_ENDPOINTS.PAYOUTS_EXPORT);
|
|
47
44
|
const url = URL.createObjectURL(blob);
|
|
48
45
|
const a = document.createElement("a");
|
|
49
46
|
a.href = url;
|
|
@@ -47,12 +47,7 @@ export function AdminSidebar({ renderNavItems, renderHeader, renderFooter, activ
|
|
|
47
47
|
const mobileNavContent = groups ? (_jsx(GroupsContent, { groups: groups, activePath: activePath, onItemClick: close })) : (_jsxs(Nav, { "aria-label": "Admin sidebar", padding: "y-sm", children: [renderHeader?.(), renderNavItems?.(activePath), renderFooter?.()] }));
|
|
48
48
|
if (variant === "sidebar") {
|
|
49
49
|
const handleToggle = onToggle ?? close;
|
|
50
|
-
return (_jsxs(_Fragment, { children: [desktopOpen && (_jsx(Div, { surface: "overlay-xs", className: "hidden md:block fixed inset-0 backdrop-blur-[2px] z-30", onClick: handleToggle, "aria-hidden": "true" })), _jsxs(Div, { className:
|
|
51
|
-
top: "var(--header-height, 3.5rem)",
|
|
52
|
-
height: "calc(100vh - var(--header-height, 3.5rem))",
|
|
53
|
-
width: "18rem",
|
|
54
|
-
transform: desktopOpen ? "translateX(0)" : "translateX(calc(-100% + 1.25rem))",
|
|
55
|
-
}, children: [_jsxs(Stack, { border: "default", surface: "sidePanel", className: `flex-1 border-r dark:border-slate-800 ${__O.hidden}`, shadow: "xl", children: [_jsx(Div, { border: "bottom-subtle", paddingY: "y-sm-tall", className: "shrink-0", padding: "x-md", children: renderHeader ? renderHeader() : _jsx(Span, { size: "xs", weight: "semibold", transform: "uppercase", color: "muted", children: "Admin Panel" }) }), _jsx(Div, { className: `flex-1 ${__O.yAuto}`, children: navContent }), renderFooter && _jsx(Div, { border: "top", padding: "inline", children: renderFooter() })] }), _jsx(SidebarCollapseToggle, { expanded: desktopOpen, onToggle: handleToggle })] }), _jsx(Div, { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: "Admin Panel", children: mobileNavContent }) })] }));
|
|
50
|
+
return (_jsxs(_Fragment, { children: [desktopOpen && (_jsx(Div, { surface: "overlay-xs", className: "hidden md:block fixed inset-0 backdrop-blur-[2px] z-30", onClick: handleToggle, "aria-hidden": "true" })), _jsxs(Div, { className: `hidden md:flex fixed left-0 z-40 transition-transform duration-300 top-[var(--header-height,3.5rem)] h-[calc(100vh-var(--header-height,3.5rem))] w-[18rem] ${desktopOpen ? "translate-x-0" : "-translate-x-[calc(100%-1.25rem)]"}`, children: [_jsxs(Stack, { border: "default", surface: "sidePanel", className: `flex-1 border-r dark:border-[var(--appkit-color-border)] ${__O.hidden}`, shadow: "xl", children: [_jsx(Div, { border: "bottom-subtle", paddingY: "y-sm-tall", className: "shrink-0", padding: "x-md", children: renderHeader ? renderHeader() : _jsx(Span, { size: "xs", weight: "semibold", transform: "uppercase", color: "muted", children: "Admin Panel" }) }), _jsx(Div, { className: `flex-1 ${__O.yAuto}`, children: navContent }), renderFooter && _jsx(Div, { border: "top", padding: "inline", children: renderFooter() })] }), _jsx(SidebarCollapseToggle, { expanded: desktopOpen, onToggle: handleToggle })] }), _jsx(Div, { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: "Admin Panel", children: mobileNavContent }) })] }));
|
|
56
51
|
}
|
|
57
52
|
return (_jsxs(_Fragment, { children: [mounted && mobileOpen &&
|
|
58
53
|
createPortal(_jsx(DrawerPanel, { title: "Admin Panel", onClose: close, children: navContent }), document.body), _jsx(Div, { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: "Admin Panel", children: mobileNavContent }) })] }));
|
|
@@ -18,5 +18,5 @@ export function AdminSiteConfigGuideView() {
|
|
|
18
18
|
{ name: "platformLimits", desc: "Cart item cap (50), wishlist cap (20), history cap (50), support ticket limits (2 general + 1 per order)." },
|
|
19
19
|
{ name: "legalPages", desc: "Body HTML for Terms of Service, Privacy Policy, Refund Policy, and Shipping Policy. Rendered on their respective static pages." },
|
|
20
20
|
];
|
|
21
|
-
return (_jsxs(Stack, { className: "max-w-3xl mx-auto", padding: "b-2xl", gap: "xl", children: [_jsxs(Section, { children: [_jsxs(Row, { className: "mb-2", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10
|
|
21
|
+
return (_jsxs(Stack, { className: "max-w-3xl mx-auto", padding: "b-2xl", gap: "xl", children: [_jsxs(Section, { children: [_jsxs(Row, { className: "mb-2", align: "center", gap: "3", children: [_jsx(Row, { className: "flex-shrink-0 w-10 h-10 [background:linear-gradient(135deg,var(--appkit-color-primary-700)_0%,var(--appkit-color-cobalt)_100%)]", align: "center", justify: "center", rounded: "xl", children: _jsx(Settings, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)] tracking-widest", size: "sm", weight: "semibold", transform: "uppercase", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-[var(--appkit-color-text)] mb-2", mdSize: "3xl", size: "2xl", weight: "bold", children: "Site Configuration" }), _jsxs(Text, { className: "text-[var(--appkit-color-text-muted)]", children: ["All site settings are stored in a single Firestore document at ", _jsx(Code, { size: "xs", children: "site_settings/global" }), ". Changes take effect on the next page render (ISR or cache revalidation)."] })] }), _jsxs(Section, { className: GC.sectionWrap, children: [_jsxs(Div, { className: GC.sectionHeader, children: [_jsx(Settings, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, className: GC.sectionTitle, children: "Settings Groups" })] }), _jsx(Stack, { paddingY: "y-md-lg", padding: "x-lg", gap: "md", children: SETTING_GROUPS.map(({ name, desc }) => (_jsxs(Row, { textSize: "sm", gap: "3", children: [_jsx(Text, { className: "flex-shrink-0 font-mono text-[var(--appkit-color-primary)] w-40", size: "xs", weight: "semibold", children: name }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: desc })] }, name))) })] }), _jsxs(Section, { className: GC.sectionWrap, children: [_jsxs(Div, { className: GC.sectionHeader, children: [_jsx(Settings, { className: CLS_HEADER_ICON }), _jsx(Heading, { level: 2, className: GC.sectionTitle, children: "API Keys & Integrations" })] }), _jsx(Div, { paddingY: "y-md-lg", padding: "x-lg", children: _jsxs(Alert, { variant: "warning", children: ["API keys in ", _jsx(Code, { size: "xs", children: "integrations" }), " are stored encrypted. They are masked in the admin UI \u2014 you see ", _jsx(Code, { size: "xs", children: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }), " by design. To rotate a key: paste the new value into the field and save. The old key is immediately invalidated on your payment/shipping provider's side \u2014 test in staging first. Never paste API keys into Slack, email, or any external service."] }) })] }), _jsxs(Section, { className: GC.sectionWrap, children: [_jsxs(Div, { className: GC.sectionHeader, children: [_jsx(Settings, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, className: GC.sectionTitle, children: "Feature Flags" })] }), _jsxs(Stack, { paddingY: "y-md-lg", padding: "x-lg", gap: "3", children: [_jsxs(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: ["Feature flags are boolean toggles under ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "siteSettings" }), ". They control platform-wide features without a code deploy:"] }), _jsxs(Ul, { className: "list-inside text-[var(--appkit-color-text-muted)]", marker: "disc", spacing: "tight", size: "sm", children: [_jsxs(Li, { children: [_jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "enableAuctions" }), " \u2014 globally enable/disable all auction listings."] }), _jsxs(Li, { children: [_jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "enablePreOrders" }), " \u2014 globally enable/disable pre-order creation."] }), _jsxs(Li, { children: [_jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "maintenanceMode" }), " \u2014 shows a maintenance banner and blocks non-admin access."] })] }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "Flags are evaluated per-request via ISR cache \u2014 a change may take up to the revalidation interval (3600s default) to propagate to all pages." })] })] })] }));
|
|
22
22
|
}
|