@mohasinac/appkit 3.6.5 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/client/features/layout/DashboardLayoutClient.d.ts +17 -3
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +7 -2
- package/dist/_internal/client/features/tour/TourProvider.d.ts +5 -2
- package/dist/_internal/client/features/tour/TourProvider.js +125 -12
- package/dist/_internal/client/theme/ThemeProvider.js +1 -1
- package/dist/_internal/server/features/faqs/og.js +5 -1
- package/dist/_internal/server/features/reviews/og.js +5 -1
- package/dist/_internal/server/features/seo/manifest.js +2 -1
- package/dist/_internal/server/features/seo/og.js +7 -1
- package/dist/_internal/server/features/tester/visibility.d.ts +13 -0
- package/dist/_internal/server/features/tester/visibility.js +28 -0
- package/dist/_internal/server/functions/scheduled.d.ts +2 -1
- package/dist/_internal/server/functions/scheduled.js +9 -1
- package/dist/_internal/server/jobs/core/jobRunners.js +5 -0
- package/dist/_internal/server/jobs/core/resetOtpVerification.d.ts +17 -0
- package/dist/_internal/server/jobs/core/resetOtpVerification.js +88 -0
- package/dist/_internal/server/jobs/core/testerSandboxCleanup.d.ts +6 -0
- package/dist/_internal/server/jobs/core/testerSandboxCleanup.js +35 -0
- package/dist/_internal/server/jobs/handlers/_helpers.d.ts +6 -0
- package/dist/_internal/server/jobs/handlers/_helpers.js +12 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
- package/dist/_internal/server/jobs/handlers/index.js +2 -0
- package/dist/_internal/server/jobs/handlers/messages.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/messages.js +2 -0
- package/dist/_internal/server/jobs/handlers/testerSandboxCleanup.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/testerSandboxCleanup.js +2 -0
- package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
- package/dist/_internal/shared/actions/action-registry.js +48 -0
- package/dist/_internal/shared/tokens/index.d.ts +12 -12
- package/dist/client.d.ts +15 -3
- package/dist/client.js +10 -2
- package/dist/constants/api-endpoints.d.ts +36 -12
- package/dist/constants/api-endpoints.js +16 -8
- package/dist/constants/field-names.d.ts +9 -0
- package/dist/constants/field-names.js +12 -0
- package/dist/constants/index.d.ts +1 -1
- package/dist/constants/index.js +1 -1
- package/dist/features/account/components/LinkedAccountsSection.d.ts +11 -0
- package/dist/features/account/components/LinkedAccountsSection.js +11 -0
- package/dist/features/account/components/UserSidebar.d.ts +3 -1
- package/dist/features/account/components/UserSidebar.js +9 -13
- package/dist/features/account/hooks/useCollapsedSections.d.ts +20 -0
- package/dist/features/account/hooks/useCollapsedSections.js +63 -0
- package/dist/features/account/hooks/useProfile.d.ts +8 -0
- package/dist/features/account/index.d.ts +1 -0
- package/dist/features/account/index.js +1 -0
- package/dist/features/admin/components/AdminAddressEditorView.js +2 -2
- package/dist/features/admin/components/AdminCarouselView.js +2 -2
- package/dist/features/admin/components/AdminCategoryEditorView.js +2 -2
- package/dist/features/admin/components/AdminProductEditorView.js +5 -2
- package/dist/features/admin/components/AdminSectionsView.js +3 -18
- package/dist/features/admin/components/AdminSidebar.js +8 -6
- package/dist/features/admin/components/AdminSiteSettingsView.js +133 -127
- package/dist/features/admin/components/AdminTesterChecklistItemEditorView.d.ts +9 -0
- package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +129 -0
- package/dist/features/admin/components/AdminTesterChecklistView.d.ts +6 -0
- package/dist/features/admin/components/AdminTesterChecklistView.js +93 -0
- package/dist/features/admin/components/AdminUserEditorView.d.ts +3 -1
- package/dist/features/admin/components/AdminUserEditorView.js +7 -1
- package/dist/features/admin/components/AdminUsersView.js +1 -1
- package/dist/features/admin/components/DataListingView.js +2 -2
- package/dist/features/admin/components/analytics/AdminPageViewsReportView.d.ts +8 -0
- package/dist/features/admin/components/analytics/AdminPageViewsReportView.js +41 -0
- package/dist/features/admin/components/index.d.ts +6 -0
- package/dist/features/admin/components/index.js +3 -0
- package/dist/features/admin/schemas/firestore.d.ts +0 -7
- package/dist/features/admin/schemas/firestore.js +6 -6
- package/dist/features/analytics/components/PageViewTracker.d.ts +12 -0
- package/dist/features/analytics/components/PageViewTracker.js +22 -0
- package/dist/features/analytics/repository/page-views.repository.d.ts +32 -0
- package/dist/features/analytics/repository/page-views.repository.js +43 -0
- package/dist/features/analytics/types.d.ts +6 -0
- package/dist/features/analytics/types.js +13 -0
- package/dist/features/auth/components/SocialAuthButtons.js +1 -1
- package/dist/features/auth/hooks/useAuth.d.ts +12 -0
- package/dist/features/auth/hooks/useAuth.js +109 -0
- package/dist/features/auth/permissions/constants.d.ts +1 -1
- package/dist/features/auth/schemas/firestore.d.ts +17 -1
- package/dist/features/auth/schemas/firestore.js +2 -0
- package/dist/features/blog/components/BlogIndexListing.js +2 -2
- package/dist/features/blog/schemas/firestore.d.ts +4 -0
- package/dist/features/cart/actions/cart-actions.js +20 -2
- package/dist/features/categories/components/CategoriesIndexListing.js +2 -2
- package/dist/features/categories/components/CategoryBundlesListing.js +2 -2
- package/dist/features/categories/components/CategoryDetailPageView.js +3 -1
- package/dist/features/categories/components/CategoryProductsListing.js +2 -2
- package/dist/features/categories/schemas/firestore.d.ts +4 -0
- package/dist/features/classified/components/ClassifiedIndexListing.js +2 -2
- package/dist/features/digital-codes/components/DigitalCodesIndexListing.js +2 -2
- package/dist/features/email/primitives.d.ts +2 -2
- package/dist/features/email/primitives.js +2 -2
- package/dist/features/events/components/EventsIndexListing.js +2 -2
- package/dist/features/events/schemas/firestore.d.ts +4 -0
- package/dist/features/layout/BackToTop.d.ts +6 -1
- package/dist/features/layout/BackToTop.js +31 -6
- package/dist/features/live/components/LiveItemsIndexListing.js +2 -2
- package/dist/features/media/MediaVideo.js +5 -1
- package/dist/features/pre-orders/components/PreOrdersIndexListing.js +2 -2
- package/dist/features/products/components/AuctionsIndexListing.js +2 -2
- package/dist/features/products/components/PrizeDrawsIndexListing.js +2 -2
- package/dist/features/products/components/ProductsIndexListing.js +2 -2
- package/dist/features/products/constants/action-defs.d.ts +2 -0
- package/dist/features/products/constants/action-defs.js +2 -0
- package/dist/features/products/schemas/firestore.d.ts +4 -0
- package/dist/features/promotions/components/CouponsIndexListing.js +2 -2
- package/dist/features/reviews/components/ReviewsIndexListing.js +2 -2
- package/dist/features/seller/actions/seller-actions.js +11 -6
- package/dist/features/seller/components/SellerAddressesView.js +2 -2
- package/dist/features/seller/components/SellerBidsView.js +2 -2
- package/dist/features/seller/components/SellerOrdersView.js +2 -2
- package/dist/features/seller/components/SellerProductsView.js +2 -2
- package/dist/features/seller/components/SellerSidebar.d.ts +3 -1
- package/dist/features/seller/components/SellerSidebar.js +9 -8
- package/dist/features/seller/components/SellerStoreCategoriesView.js +2 -2
- package/dist/features/seller/components/SellerTemplatesView.js +2 -2
- package/dist/features/shell/StepForm.js +4 -4
- package/dist/features/stores/actions/store-query-actions.d.ts +5 -4
- package/dist/features/stores/actions/store-query-actions.js +11 -8
- package/dist/features/stores/components/StoreAuctionsListing.js +2 -2
- package/dist/features/stores/components/StoreClassifiedsListing.js +2 -2
- package/dist/features/stores/components/StoreDigitalCodesListing.js +2 -2
- package/dist/features/stores/components/StoreLiveItemsListing.js +2 -2
- package/dist/features/stores/components/StorePreOrdersListing.js +2 -2
- package/dist/features/stores/components/StoreProductsListing.js +2 -2
- package/dist/features/stores/components/StoreReviewsListing.js +2 -2
- package/dist/features/stores/components/StoresIndexListing.js +2 -2
- package/dist/features/stores/schemas/firestore.d.ts +4 -0
- package/dist/features/tester/actions/checklist-item-actions.d.ts +69 -0
- package/dist/features/tester/actions/checklist-item-actions.js +42 -0
- package/dist/features/tester/actions/index.d.ts +1 -0
- package/dist/features/tester/actions/index.js +1 -0
- package/dist/features/tester/components/AdminTesterFeedbackIssuesView.d.ts +2 -0
- package/dist/features/tester/components/AdminTesterFeedbackIssuesView.js +22 -0
- package/dist/features/tester/components/AdminTesterFeedbackListView.d.ts +3 -0
- package/dist/features/tester/components/AdminTesterFeedbackListView.js +100 -0
- package/dist/features/tester/components/AdminTesterFeedbackReportView.d.ts +2 -0
- package/dist/features/tester/components/AdminTesterFeedbackReportView.js +30 -0
- package/dist/features/tester/components/AdminTesterFeedbackView.d.ts +2 -0
- package/dist/features/tester/components/AdminTesterFeedbackView.js +9 -0
- package/dist/features/tester/components/TesterChecklistStepRow.d.ts +18 -0
- package/dist/features/tester/components/TesterChecklistStepRow.js +29 -0
- package/dist/features/tester/components/TesterFeedbackChart.d.ts +14 -0
- package/dist/features/tester/components/TesterFeedbackChart.js +18 -0
- package/dist/features/tester/components/TesterHubView.d.ts +5 -0
- package/dist/features/tester/components/TesterHubView.js +71 -0
- package/dist/features/tester/components/index.d.ts +11 -0
- package/dist/features/tester/components/index.js +7 -0
- package/dist/features/tester/index.d.ts +2 -0
- package/dist/features/tester/index.js +2 -0
- package/dist/features/tester/repository/index.d.ts +2 -0
- package/dist/features/tester/repository/index.js +2 -0
- package/dist/features/tester/repository/tester-checklist-item.repository.d.ts +13 -0
- package/dist/features/tester/repository/tester-checklist-item.repository.js +55 -0
- package/dist/features/tester/repository/tester-checklist-response.repository.d.ts +42 -0
- package/dist/features/tester/repository/tester-checklist-response.repository.js +98 -0
- package/dist/features/tester/schemas/firestore.d.ts +85 -0
- package/dist/features/tester/schemas/firestore.js +93 -0
- package/dist/features/tester/schemas/index.d.ts +1 -0
- package/dist/features/tester/schemas/index.js +1 -0
- package/dist/features/tester/seed-data/blog-tester-seed-data.d.ts +2 -0
- package/dist/features/tester/seed-data/blog-tester-seed-data.js +40 -0
- package/dist/features/tester/seed-data/categories-tester-seed-data.d.ts +2 -0
- package/dist/features/tester/seed-data/categories-tester-seed-data.js +177 -0
- package/dist/features/tester/seed-data/events-tester-seed-data.d.ts +2 -0
- package/dist/features/tester/seed-data/events-tester-seed-data.js +50 -0
- package/dist/features/tester/seed-data/index.d.ts +6 -0
- package/dist/features/tester/seed-data/index.js +6 -0
- package/dist/features/tester/seed-data/products-tester-seed-data.d.ts +2 -0
- package/dist/features/tester/seed-data/products-tester-seed-data.js +151 -0
- package/dist/features/tester/seed-data/stores-tester-seed-data.d.ts +2 -0
- package/dist/features/tester/seed-data/stores-tester-seed-data.js +40 -0
- package/dist/features/tester/seed-data/tester-checklist-seed-data.d.ts +2 -0
- package/dist/features/tester/seed-data/tester-checklist-seed-data.js +248 -0
- package/dist/features/tester/seed-data/tester-ttl.d.ts +4 -0
- package/dist/features/tester/seed-data/tester-ttl.js +6 -0
- package/dist/features/tester/server.d.ts +9 -0
- package/dist/features/tester/server.js +8 -0
- package/dist/index.d.ts +28 -2
- package/dist/index.js +51 -1
- package/dist/next/api/api-response.js +5 -1
- package/dist/next/api/routeHandler.js +10 -1
- package/dist/next/middleware/chain.js +1 -1
- package/dist/next/routing/route-map.d.ts +6 -7
- package/dist/next/routing/route-map.js +3 -7
- package/dist/providers/payment-manual/index.d.ts +2 -2
- package/dist/providers/payment-manual/index.js +2 -2
- package/dist/react/contexts/SessionContext.d.ts +4 -0
- package/dist/react/contexts/SessionContext.js +4 -0
- package/dist/repositories/index.d.ts +4 -0
- package/dist/repositories/index.js +3 -0
- package/dist/security/pii-encrypt.js +12 -2
- package/dist/seed/addresses-seed-data.js +1 -1
- package/dist/seed/bids-seed-data.js +1 -1
- package/dist/seed/blog-posts-seed-data.js +1 -1
- package/dist/seed/carousel-slides-seed-data.js +22 -16
- package/dist/seed/carousels-seed-data.js +1 -1
- package/dist/seed/cart-seed-data.js +1 -1
- package/dist/seed/categories-seed-data.js +1 -1
- package/dist/seed/claimed-coupons-seed-data.js +1 -1
- package/dist/seed/conversations-seed-data.js +1 -1
- package/dist/seed/coupon-usage-seed-data.js +1 -1
- package/dist/seed/coupons-seed-data.js +1 -1
- package/dist/seed/events-seed-data.js +1 -1
- package/dist/seed/faq-seed-data.js +119 -3
- package/dist/seed/grouped-listings-seed-data.d.ts +2 -0
- package/dist/seed/grouped-listings-seed-data.js +1 -1
- package/dist/seed/history-seed-data.js +1 -1
- package/dist/seed/homepage-sections-seed-data.js +1 -1
- package/dist/seed/index.d.ts +2 -2
- package/dist/seed/index.js +7 -3
- package/dist/seed/lottery-entries-seed-data.js +1 -1
- package/dist/seed/manifest.d.ts +4 -3
- package/dist/seed/manifest.js +13 -6
- package/dist/seed/notifications-seed-data.js +1 -1
- package/dist/seed/offers-seed-data.js +1 -1
- package/dist/seed/orders-seed-data.js +1 -1
- package/dist/seed/payouts-seed-data.js +1 -1
- package/dist/seed/products-art-seed-data.js +1 -1
- package/dist/seed/products-auctions-seed-data.js +1 -1
- package/dist/seed/products-classifieds-seed-data.js +1 -1
- package/dist/seed/products-digital-codes-seed-data.js +1 -1
- package/dist/seed/products-live-items-seed-data.js +1 -1
- package/dist/seed/products-preorders-seed-data.d.ts +2 -0
- package/dist/seed/products-preorders-seed-data.js +1 -1
- package/dist/seed/products-prize-draws-seed-data.js +1 -1
- package/dist/seed/products-standard-seed-data.js +1 -1
- package/dist/seed/products-stickers-seed-data.js +1 -1
- package/dist/seed/reviews-seed-data.js +1 -1
- package/dist/seed/scammers-seed-data.js +1 -1
- package/dist/seed/sessions-seed-data.js +1 -1
- package/dist/seed/site-settings-seed-data.js +22 -16
- package/dist/seed/store-addresses-seed-data.js +1 -1
- package/dist/seed/store-extensions-seed-data.js +1 -1
- package/dist/seed/stores-seed-data.js +1 -1
- package/dist/seed/support-tickets-seed-data.js +1 -1
- package/dist/seed/tester-checklist-seed-data.d.ts +2 -0
- package/dist/seed/tester-checklist-seed-data.js +248 -0
- package/dist/seed/users-seed-data.js +1 -1
- package/dist/seed/wishlists-seed-data.js +1 -1
- package/dist/server.d.ts +7 -2
- package/dist/server.js +19 -12
- package/dist/styles.css +163 -147
- package/dist/tailwind-utilities.css +1 -1
- package/dist/tokens/color-pairs.d.ts +46 -0
- package/dist/tokens/color-pairs.js +93 -0
- package/dist/tokens/index.d.ts +60 -60
- package/dist/tokens/index.js +30 -30
- package/dist/tokens/themes/cobalt-night.d.ts +3 -2
- package/dist/tokens/themes/cobalt-night.js +3 -2
- package/dist/tokens/themes/default-dark.d.ts +4 -1
- package/dist/tokens/themes/default-dark.js +44 -41
- package/dist/tokens/themes/default-light.d.ts +5 -1
- package/dist/tokens/themes/default-light.js +39 -35
- package/dist/tokens/themes/sunset.js +4 -4
- package/dist/tokens/tokens.css +110 -104
- package/dist/ui/components/CollapsibleSection.d.ts +15 -0
- package/dist/ui/components/CollapsibleSection.js +13 -0
- package/dist/ui/components/ListingToolbar.js +2 -1
- package/dist/ui/components/Semantic.style.css +3 -3
- package/dist/ui/components/SideDrawer.style.css +19 -19
- package/dist/ui/components/Slider.js +1 -1
- package/dist/ui/components/StickyToolbar.d.ts +36 -7
- package/dist/ui/components/StickyToolbar.js +63 -5
- package/dist/ui/components/Tabs.js +17 -1
- package/dist/ui/components/Tabs.style.css +10 -0
- package/dist/ui/components/Typography.js +7 -0
- package/dist/ui/components/surface-tokens.d.ts +0 -7
- package/dist/ui/components/surface-tokens.js +7 -0
- package/dist/ui/index.d.ts +6 -0
- package/dist/ui/index.js +3 -0
- package/dist/ui/rich-text/RichText.style.css +20 -20
- package/dist/utils/id-generators.d.ts +13 -0
- package/dist/utils/id-generators.js +17 -0
- package/package.json +1 -1
- package/scripts/seed-cli-loader.mjs +15 -0
- package/scripts/seed-cli.mjs +71 -17
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface UseCollapsedSectionsOptions {
|
|
2
|
+
/** Every section ID this page manages, in display order. IDs must be
|
|
3
|
+
* globally unique across pages (prefix with a page key, e.g.
|
|
4
|
+
* "admin-dashboard:alerts") — uiPreferences.collapsedSections is a single
|
|
5
|
+
* flat list shared by the whole user document, not namespaced server-side.
|
|
6
|
+
* A section ID absent from the saved list defaults to collapsed, which is
|
|
7
|
+
* also the state for a user who has never touched this page. */
|
|
8
|
+
sectionIds: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface UseCollapsedSectionsResult {
|
|
11
|
+
isCollapsed: (id: string) => boolean;
|
|
12
|
+
/** Accordion within this hook's own sectionIds — expanding one collapses
|
|
13
|
+
* every other section this call manages; collapsing the open one leaves
|
|
14
|
+
* everything collapsed. */
|
|
15
|
+
toggle: (id: string) => void;
|
|
16
|
+
}
|
|
17
|
+
/** Persisted, per-user, accordion-scoped collapse state for a page's
|
|
18
|
+
* dashboard sections. Debounces writes to PATCH /api/user/profile so rapid
|
|
19
|
+
* toggling doesn't fire a request per click. */
|
|
20
|
+
export declare function useCollapsedSections({ sectionIds, }: UseCollapsedSectionsOptions): UseCollapsedSectionsResult;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useCurrentProfile, useUpdateCurrentProfile } from "./useProfile";
|
|
4
|
+
const PERSIST_DEBOUNCE_MS = 600;
|
|
5
|
+
/** Persisted, per-user, accordion-scoped collapse state for a page's
|
|
6
|
+
* dashboard sections. Debounces writes to PATCH /api/user/profile so rapid
|
|
7
|
+
* toggling doesn't fire a request per click. */
|
|
8
|
+
export function useCollapsedSections({ sectionIds, }) {
|
|
9
|
+
const { data: profile } = useCurrentProfile();
|
|
10
|
+
const updateProfile = useUpdateCurrentProfile();
|
|
11
|
+
// Full server-side list, including other pages' entries this hook must
|
|
12
|
+
// never clobber when it persists its own page's next state.
|
|
13
|
+
const savedFullListRef = useRef([]);
|
|
14
|
+
const [localCollapsed, setLocalCollapsed] = useState(null);
|
|
15
|
+
const debounceRef = useRef(null);
|
|
16
|
+
const sectionIdsRef = useRef(sectionIds);
|
|
17
|
+
sectionIdsRef.current = sectionIds;
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!profile)
|
|
20
|
+
return;
|
|
21
|
+
const serverList = profile.uiPreferences?.collapsedSections;
|
|
22
|
+
savedFullListRef.current = serverList ?? [];
|
|
23
|
+
setLocalCollapsed((prev) => {
|
|
24
|
+
if (prev !== null)
|
|
25
|
+
return prev; // local interaction already in progress — don't clobber it
|
|
26
|
+
const known = new Set(serverList ?? []);
|
|
27
|
+
const initial = new Set();
|
|
28
|
+
for (const id of sectionIdsRef.current) {
|
|
29
|
+
// Never-set user (serverList undefined) → default every section collapsed.
|
|
30
|
+
if (serverList === undefined || known.has(id))
|
|
31
|
+
initial.add(id);
|
|
32
|
+
}
|
|
33
|
+
return initial;
|
|
34
|
+
});
|
|
35
|
+
}, [profile]);
|
|
36
|
+
useEffect(() => () => {
|
|
37
|
+
if (debounceRef.current)
|
|
38
|
+
clearTimeout(debounceRef.current);
|
|
39
|
+
}, []);
|
|
40
|
+
const persist = useCallback((nextForThisPage) => {
|
|
41
|
+
if (debounceRef.current)
|
|
42
|
+
clearTimeout(debounceRef.current);
|
|
43
|
+
debounceRef.current = setTimeout(() => {
|
|
44
|
+
const ids = sectionIdsRef.current;
|
|
45
|
+
const others = savedFullListRef.current.filter((id) => !ids.includes(id));
|
|
46
|
+
const merged = [...others, ...nextForThisPage];
|
|
47
|
+
savedFullListRef.current = merged;
|
|
48
|
+
updateProfile.mutate({ uiPreferences: { collapsedSections: merged } });
|
|
49
|
+
}, PERSIST_DEBOUNCE_MS);
|
|
50
|
+
}, [updateProfile]);
|
|
51
|
+
const isCollapsed = useCallback((id) => localCollapsed?.has(id) ?? true, [localCollapsed]);
|
|
52
|
+
const toggle = useCallback((id) => {
|
|
53
|
+
setLocalCollapsed((prev) => {
|
|
54
|
+
const wasCollapsed = prev?.has(id) ?? true;
|
|
55
|
+
const next = wasCollapsed
|
|
56
|
+
? new Set(sectionIdsRef.current.filter((s) => s !== id)) // opening id collapses every sibling
|
|
57
|
+
: new Set(sectionIdsRef.current); // closing the open one — back to all-collapsed
|
|
58
|
+
persist(next);
|
|
59
|
+
return next;
|
|
60
|
+
});
|
|
61
|
+
}, [persist]);
|
|
62
|
+
return { isCollapsed, toggle };
|
|
63
|
+
}
|
|
@@ -9,6 +9,11 @@ export interface UserProfile {
|
|
|
9
9
|
emailVerified: boolean;
|
|
10
10
|
createdAt: Date;
|
|
11
11
|
updatedAt: Date;
|
|
12
|
+
googleLinked?: boolean;
|
|
13
|
+
googleLinkedEmail?: string | null;
|
|
14
|
+
uiPreferences?: {
|
|
15
|
+
collapsedSections?: string[];
|
|
16
|
+
};
|
|
12
17
|
}
|
|
13
18
|
export interface UpdateCurrentProfileInput {
|
|
14
19
|
displayName?: string;
|
|
@@ -24,6 +29,9 @@ export interface UpdateCurrentProfileInput {
|
|
|
24
29
|
};
|
|
25
30
|
bio?: string;
|
|
26
31
|
profileIsPublic?: boolean;
|
|
32
|
+
uiPreferences?: {
|
|
33
|
+
collapsedSections?: string[];
|
|
34
|
+
};
|
|
27
35
|
}
|
|
28
36
|
export declare function useCurrentProfile(options?: {
|
|
29
37
|
enabled?: boolean;
|
|
@@ -7,6 +7,7 @@ export * from "./hooks/useAddressForm";
|
|
|
7
7
|
export * from "./hooks/useAddressSelector";
|
|
8
8
|
export * from "./hooks/useNotifications";
|
|
9
9
|
export * from "./hooks/useProfileStats";
|
|
10
|
+
export * from "./hooks/useCollapsedSections";
|
|
10
11
|
export { useCurrentProfile as useProfile, useUpdateCurrentProfile as useUpdateProfile, } from "./hooks/useProfile";
|
|
11
12
|
export * from "./hooks/usePublicProfile";
|
|
12
13
|
export * from "./constants/addresses";
|
|
@@ -7,6 +7,7 @@ export * from "./hooks/useAddressForm";
|
|
|
7
7
|
export * from "./hooks/useAddressSelector";
|
|
8
8
|
export * from "./hooks/useNotifications";
|
|
9
9
|
export * from "./hooks/useProfileStats";
|
|
10
|
+
export * from "./hooks/useCollapsedSections";
|
|
10
11
|
export { useCurrentProfile as useProfile, useUpdateCurrentProfile as useUpdateProfile, } from "./hooks/useProfile";
|
|
11
12
|
export * from "./hooks/usePublicProfile";
|
|
12
13
|
export * from "./constants/addresses";
|
|
@@ -4,7 +4,7 @@ import { Row } from "@mohasinac/appkit/ui";
|
|
|
4
4
|
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
5
5
|
import React from "react";
|
|
6
6
|
import { useQuery } from "@tanstack/react-query";
|
|
7
|
-
import { Button, Card, CardBody, Checkbox, ConfirmDeleteModal, Div, Form, Input, Select, Span, Stack, StackedViewShell, Text, Toggle, useToast } from "../../../ui";
|
|
7
|
+
import { Button, Card, CardBody, Checkbox, ConfirmDeleteModal, Div, Form, Input, Select, Span, Stack, StackedViewShell, Text, Toggle, useToast, Show, StickyToolbar } from "../../../ui";
|
|
8
8
|
import { apiClient } from "../../../http";
|
|
9
9
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
10
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
@@ -114,6 +114,6 @@ export function AdminAddressEditorView({ addressId, onSaved, onDeleted, ...rest
|
|
|
114
114
|
}, className: "accent-[var(--appkit-color-primary)]" }), _jsx(Span, { size: "sm", className: "text-[var(--appkit-color-text)]", transform: "capitalize", children: type })] }, type))) }), _jsx(Input, { label: form.ownerType === "user" ? "User ID" : "Store ID (slug)", value: form.ownerId, onChange: (e) => set("ownerId", e.target.value), required: true, placeholder: form.ownerType === "user" ? "user-mohsin-c" : "store-pokemon-palace", helperText: form.ownerType === "user"
|
|
115
115
|
? "Firebase Auth UID or user slug"
|
|
116
116
|
: "Store slug (e.g. store-pokemon-palace)" })] })] }), _jsxs(Card, { variant: "outlined", padding: "lg", children: [_jsx(SectionHeading, { children: "Contact & Location" }), _jsxs(Stack, { gap: "md", children: [_jsxs(Div, { layout: "grid", gap: "4", className: "sm:grid-cols-2", children: [_jsx(Input, { label: "Label", value: form.label, onChange: (e) => set("label", e.target.value), required: true, placeholder: "Home / Office / Pickup" }), _jsx(Input, { label: "Full Name", value: form.fullName, onChange: (e) => set("fullName", e.target.value), required: true, placeholder: "Recipient name (PII)" })] }), _jsx(Input, { label: "Phone", value: form.phone, onChange: (e) => set("phone", e.target.value), required: true, type: "tel", placeholder: "+91 9876543210 (PII)" }), _jsx(Input, { label: "Address Line 1", value: form.addressLine1, onChange: (e) => set("addressLine1", e.target.value), required: true, placeholder: "House/flat no., street (PII)" }), _jsxs(Div, { layout: "grid", gap: "4", className: "sm:grid-cols-2", children: [_jsx(Input, { label: "Address Line 2", value: form.addressLine2 ?? "", onChange: (e) => set("addressLine2", e.target.value), placeholder: "Area, locality (optional)" }), _jsx(Input, { label: "Landmark", value: form.landmark ?? "", onChange: (e) => set("landmark", e.target.value), placeholder: "Near hospital, etc. (optional)" })] }), _jsxs(Div, { layout: "grid", gap: "4", className: "sm:grid-cols-3", children: [_jsx(Input, { label: "City", value: form.city, onChange: (e) => set("city", e.target.value), required: true, placeholder: "Mumbai" }), _jsx(Select, { label: "State", value: form.state, onValueChange: (val) => set("state", val), options: STATE_OPTIONS, placeholder: "Select state", required: true }), _jsx(Input, { label: "Postal Code", value: form.postalCode, onChange: (e) => set("postalCode", e.target.value), required: true, placeholder: "400001", maxLength: 6 })] }), _jsx(Input, { label: "Country", value: form.country, onChange: (e) => set("country", e.target.value), placeholder: "India" })] })] }), _jsxs(Card, { variant: "outlined", padding: "lg", children: [_jsx(SectionHeading, { children: "Flags" }), _jsx(Toggle, { label: "Set as default address", checked: form.isDefault, onChange: (v) => set("isDefault", v) })] }), _jsxs(Row, { gap: "3", className: "lg:hidden", children: [_jsx(Button, { type: "submit", isLoading: isSubmitting, disabled: !canSave || isSubmitting, children: isEdit ? ACTIONS.ADMIN["save-changes"].label : "Create address" }), isEdit && (_jsx(Button, { type: "button", variant: "danger", isLoading: deleteMutation.isPending, onClick: () => setDeleteOpen(true), children: "Delete address" }))] })] }, "address-form"));
|
|
117
|
-
const twoPanel = (_jsxs(Div, { layout: "grid", gap: "6", lgAlign: "start", className: "lg:grid-cols-[1fr_280px]", children: [_jsx(CardBody, { className: "min-w-0 space-y-6 p-[var(--appkit-space-0)]", children: formContent }), _jsx(
|
|
117
|
+
const twoPanel = (_jsxs(Div, { layout: "grid", gap: "6", lgAlign: "start", className: "lg:grid-cols-[1fr_280px]", children: [_jsx(CardBody, { className: "min-w-0 space-y-6 p-[var(--appkit-space-0)]", children: formContent }), _jsx(Show, { above: "lg", children: _jsx(StickyToolbar, { offset: "header", tone: "default", border: false, padding: "none", children: actionSidebar }) })] }));
|
|
118
118
|
return (_jsxs(_Fragment, { children: [_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Address" : "New Address", sections: [twoPanel] }), _jsx(ConfirmDeleteModal, { isOpen: deleteOpen, onClose: () => setDeleteOpen(false), onConfirm: () => deleteMutation.mutate(), isDeleting: deleteMutation.isPending, title: "Delete this address?", message: "This address will be permanently removed. This action cannot be undone.", confirmText: "Delete address", variant: "danger" })] }));
|
|
119
119
|
}
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
4
4
|
import React, { useState, useCallback } from "react";
|
|
5
5
|
import { useQueryClient } from "@tanstack/react-query";
|
|
6
|
-
import { Badge, BulkActionBar, Button, ConfirmDeleteModal, Div, ListingFilterDrawer, ListingLayout, ListingToolbar, Pagination, Row, Span, Stack, Text } from "../../../ui";
|
|
6
|
+
import { Badge, BulkActionBar, Button, ConfirmDeleteModal, Div, ListingFilterDrawer, ListingLayout, ListingToolbar, Pagination, Row, Span, Stack, Text, StickyToolbar } from "../../../ui";
|
|
7
7
|
import { useBottomActions } from "../../layout";
|
|
8
8
|
import { MediaImage } from "../../media/MediaImage";
|
|
9
9
|
import { ADMIN_ENDPOINTS, HOMEPAGE_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
@@ -145,5 +145,5 @@ export function AdminCarouselView({ children, onBulkDelete, ...props }) {
|
|
|
145
145
|
] })),
|
|
146
146
|
},
|
|
147
147
|
];
|
|
148
|
-
return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search slide titles", onSearchChange: setSearchInput, onSearchCommit: commitSearch, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx(
|
|
148
|
+
return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search slide titles", onSearchChange: setSearchInput, onSearchCommit: commitSearch, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx(StickyToolbar, { offset: "header+pagination", tone: "translucent", border: true, padding: "toolbar", children: _jsx(Row, { justify: "center", 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, { paddingX: "x-sm-md", padding: "y-md", children: [errorMessage && (_jsx(Div, { textSize: "sm", className: "mb-4 border border-error/20", color: "error", surface: "danger-surface", padding: "inline", rounded: "xl", children: errorMessage })), _jsx(DataTable, { rows: displayRows, columns: columns, isLoading: isLoading, emptyLabel: "No carousel slides \u2014 use 'New slide' to add one", getRowHref: (row) => `/admin/carousel/${row.id}/edit` })] }), _jsx(ListingFilterDrawer, { open: filterOpen, onClose: () => setFilterOpen(false), onApply: applyFilters, onClear: clearFilters, activeCount: activeFilterCount, children: _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "Status" }), _jsx(Row, { wrap: true, gap: "sm", children: [{ label: "All", value: "" }, { label: "Active", value: "true" }, { label: "Inactive", value: "false" }].map((opt) => (_jsx(Button, { variant: "ghost", type: "button", onClick: () => setPendingFilters((p) => ({ ...p, active: opt.value })), className: `rounded-full px-[var(--appkit-space-3)] py-[var(--appkit-space-1)] text-[length:var(--appkit-text-xs)] font-medium border transition-colors min-h-0 h-auto ${(pendingFilters.active || "") === opt.value ? "bg-primary text-white border-primary" : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]"}`, children: opt.label }, opt.label))) })] }) }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Carousel Slide", message: "Delete this carousel slide? This cannot be undone.", onConfirm: () => { deleteMutation.mutate(deleteTargetId); setDeleteTargetId(null); }, onClose: () => setDeleteTargetId(null), isDeleting: deleteMutation.isPending }))] }));
|
|
149
149
|
}
|
|
@@ -5,7 +5,7 @@ import { useApiMutation } from "@mohasinac/appkit/client";
|
|
|
5
5
|
import React from "react";
|
|
6
6
|
import { useQuery } from "@tanstack/react-query";
|
|
7
7
|
import { z } from "zod";
|
|
8
|
-
import { Button, Card, CardBody, ConfirmDeleteModal, Div, Form, Input, PaginatedSelect, Stack, StackedViewShell, Text, Toggle, useToast } from "../../../ui";
|
|
8
|
+
import { Button, Card, CardBody, ConfirmDeleteModal, Div, Form, Input, PaginatedSelect, Stack, StackedViewShell, Text, Toggle, useToast, Show, StickyToolbar } from "../../../ui";
|
|
9
9
|
import { apiClient } from "../../../http";
|
|
10
10
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
11
11
|
import { CategoryQuickCreateForm } from "./CategoryQuickCreateForm";
|
|
@@ -131,6 +131,6 @@ export function AdminCategoryEditorView({ categoryId, onSaved, onDeleted, embedd
|
|
|
131
131
|
if (embedded) {
|
|
132
132
|
return _jsx(Div, { className: `${__O.yAuto} ${__P.p4}`, children: formContent });
|
|
133
133
|
}
|
|
134
|
-
const twoPanel = (_jsxs(Div, { layout: "grid", gap: "6", lgAlign: "start", className: "lg:grid-cols-[1fr_280px]", children: [_jsx(CardBody, { className: "min-w-0 space-y-6 p-[var(--appkit-space-0)]", children: formContent }), _jsx(
|
|
134
|
+
const twoPanel = (_jsxs(Div, { layout: "grid", gap: "6", lgAlign: "start", className: "lg:grid-cols-[1fr_280px]", children: [_jsx(CardBody, { className: "min-w-0 space-y-6 p-[var(--appkit-space-0)]", children: formContent }), _jsx(Show, { above: "lg", children: _jsx(StickyToolbar, { offset: "header", tone: "default", border: false, padding: "none", children: actionSidebar }) })] }));
|
|
135
135
|
return (_jsxs(_Fragment, { children: [_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Category" : "Create Category", sections: [twoPanel] }), _jsx(ConfirmDeleteModal, { isOpen: deleteOpen, onClose: () => setDeleteOpen(false), onConfirm: () => deleteMutation.mutate(), isDeleting: deleteMutation.isPending, title: "Delete this category?", message: "Products in this category will become uncategorized. This action cannot be undone.", confirmText: "Delete category", variant: "danger" })] }));
|
|
136
136
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
// audit-form-mutation-hook-multi-ok: saveMutation is the single combined save
|
|
4
|
+
// across all tabs; deleteMutation is a separate destructive action, not a
|
|
5
|
+
// second per-tab save.
|
|
3
6
|
import { Row } from "@mohasinac/appkit/ui";
|
|
4
7
|
import { useApiMutation } from "@mohasinac/appkit/client";
|
|
5
8
|
import React from "react";
|
|
6
9
|
import { useQuery } from "@tanstack/react-query";
|
|
7
|
-
import { Button, Card, CardBody, ConfirmDeleteModal, Div, PaginatedSelect, Form, Stack, StackedViewShell, Tabs, TabsContent, TabsList, TabsTrigger, Text, useToast, } from "../../../ui";
|
|
10
|
+
import { Button, Card, CardBody, ConfirmDeleteModal, Div, PaginatedSelect, Form, Stack, StackedViewShell, Tabs, TabsContent, TabsList, TabsTrigger, Text, useToast, Show, StickyToolbar, } from "../../../ui";
|
|
8
11
|
import { apiClient } from "../../../http";
|
|
9
12
|
import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
10
13
|
import { ProductForm } from "../../products/components/ProductForm";
|
|
@@ -175,6 +178,6 @@ export function AdminProductEditorView({ productId, onSaved, onDeleted, embedded
|
|
|
175
178
|
if (embedded) {
|
|
176
179
|
return _jsx(Div, { className: `${__O.yAuto} ${__P.p4}`, children: formContent });
|
|
177
180
|
}
|
|
178
|
-
const twoPanel = (_jsxs(Div, { layout: "grid", gap: "6", lgAlign: "start", className: "lg:grid-cols-[1fr_280px]", children: [_jsx(CardBody, { className: "min-w-0 space-y-6 p-[var(--appkit-space-0)]", children: formContent }), _jsx(
|
|
181
|
+
const twoPanel = (_jsxs(Div, { layout: "grid", gap: "6", lgAlign: "start", className: "lg:grid-cols-[1fr_280px]", children: [_jsx(CardBody, { className: "min-w-0 space-y-6 p-[var(--appkit-space-0)]", children: formContent }), _jsx(Show, { above: "lg", children: _jsx(StickyToolbar, { offset: "header", tone: "default", border: false, padding: "none", children: actionSidebar }) })] }));
|
|
179
182
|
return (_jsxs(_Fragment, { children: [_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Product" : "Create Product", sections: [twoPanel] }), _jsx(ConfirmDeleteModal, { isOpen: deleteOpen, onClose: () => setDeleteOpen(false), onConfirm: () => deleteMutation.mutate(), isDeleting: deleteMutation.isPending, title: "Delete this product?", message: "This product will be permanently removed. This action cannot be undone.", confirmText: "Delete product", variant: "danger" })] }));
|
|
180
183
|
}
|
|
@@ -6,9 +6,9 @@ import React from "react";
|
|
|
6
6
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
7
7
|
import { ProductInlineSelect } from "../../seller/components/ProductInlineSelect";
|
|
8
8
|
import { CategoryInlineSelect } from "../../seller/components/CategoryInlineSelect";
|
|
9
|
-
import { Button, Checkbox,
|
|
9
|
+
import { Button, Checkbox, Div, Form, FormActions, Input, Modal, Row, Select, Stack, Text, Textarea, useToast } from "../../../ui";
|
|
10
10
|
import { apiClient } from "../../../http";
|
|
11
|
-
import { ADMIN_ENDPOINTS
|
|
11
|
+
import { ADMIN_ENDPOINTS } from "../../../constants";
|
|
12
12
|
import { ROUTES } from "../../../next/routing/route-map";
|
|
13
13
|
import { useAdminSectionsListing } from "../hooks/useAdminSectionsListing";
|
|
14
14
|
import { DataTable } from "./DataTable";
|
|
@@ -29,7 +29,6 @@ export function AdminSectionsView({ children }) {
|
|
|
29
29
|
const hasChildren = React.Children.count(children) > 0;
|
|
30
30
|
const queryClient = useQueryClient();
|
|
31
31
|
const [isModalOpen, setIsModalOpen] = React.useState(false);
|
|
32
|
-
const [seedResetOpen, setSeedResetOpen] = React.useState(false);
|
|
33
32
|
const [mode, setMode] = React.useState("create");
|
|
34
33
|
const [selectedSectionId, setSelectedSectionId] = React.useState("");
|
|
35
34
|
const [sectionType, setSectionType] = React.useState("products");
|
|
@@ -208,20 +207,6 @@ export function AdminSectionsView({ children }) {
|
|
|
208
207
|
toast.showToast(error instanceof Error ? error.message : "Failed to save section.", "error");
|
|
209
208
|
},
|
|
210
209
|
});
|
|
211
|
-
const resetSeed = useApiMutation({
|
|
212
|
-
mutationFn: () => apiClient.post(DEMO_ENDPOINTS.SEED, {
|
|
213
|
-
action: "load",
|
|
214
|
-
collections: ["homepageSections"],
|
|
215
|
-
}),
|
|
216
|
-
onSuccess: async () => {
|
|
217
|
-
await queryClient.invalidateQueries({ queryKey: ["admin", "sections", "listing"] });
|
|
218
|
-
setSeedResetOpen(false);
|
|
219
|
-
toast.showToast("Homepage sections seed data reloaded.", "success");
|
|
220
|
-
},
|
|
221
|
-
onError: () => {
|
|
222
|
-
toast.showToast("Seed reset failed.", "error");
|
|
223
|
-
},
|
|
224
|
-
});
|
|
225
210
|
const reorderSections = useApiMutation({
|
|
226
211
|
mutationFn: async () => {
|
|
227
212
|
await Promise.all(reorderDraft.map((item) => apiClient.patch(`${ADMIN_ENDPOINTS.SECTIONS}/${item.id}`, {
|
|
@@ -965,7 +950,7 @@ export function AdminSectionsView({ children }) {
|
|
|
965
950
|
}));
|
|
966
951
|
const hasReorderChanges = reorderDraft.some((item) => sectionOrderMap.get(item.id) !== item.order);
|
|
967
952
|
const canUndoReorderChanges = reorderUndoStack.length > 0;
|
|
968
|
-
return (_jsxs(_Fragment, { children: [_jsxs(Div, { paddingX: "x-sm-md", padding: "y-md", children: [_jsxs(Row, { className: "mb-4", align: "center", justify: "between", gap: "3", children: [_jsxs(Div, { children: [_jsx(Text, { size: "base", weight: "semibold", color: "primary", children: "Homepage Sections" }), _jsx(Text, { size: "sm", color: "muted", children: "Manage homepage sections and their display order" })] }),
|
|
953
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Div, { paddingX: "x-sm-md", padding: "y-md", children: [_jsxs(Row, { className: "mb-4", align: "center", justify: "between", gap: "3", children: [_jsxs(Div, { children: [_jsx(Text, { size: "base", weight: "semibold", color: "primary", children: "Homepage Sections" }), _jsx(Text, { size: "sm", color: "muted", children: "Manage homepage sections and their display order" })] }), _jsx(Row, { align: "center", gap: "sm", children: _jsx(Button, { type: "button", variant: "primary", size: "sm", onClick: () => setIsModalOpen(true), children: "Manage Sections" }) })] }), errorMessage && (_jsx(Div, { textSize: "sm", className: "mb-4 border border-error/20", color: "error", surface: "danger-surface", padding: "inline", rounded: "xl", children: errorMessage })), _jsx(DataTable, { rows: rows, isLoading: isLoading, emptyLabel: "No sections found" })] }), _jsxs(Stack, { className: `mt-4 ${__P.p4}`, gap: "3", rounded: "xl", surface: "default", border: "default", children: [_jsxs(Row, { align: "center", justify: "between", gap: "3", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "primary", children: "Reorder Sections" }), _jsxs(Row, { align: "center", gap: "sm", children: [_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: reindexDraft, disabled: reorderSections.isPending || reorderDraft.length === 0, children: "Reindex 1..N" }), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: undoReorderChange, disabled: reorderSections.isPending || !canUndoReorderChanges, children: "Undo unsaved" }), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: resetToServerOrder, disabled: reorderSections.isPending || !hasReorderChanges, children: "Reset to server" }), _jsx(Button, { type: "button", variant: "primary", size: "sm", onClick: () => reorderSections.mutate(), disabled: !hasReorderChanges || reorderSections.isPending, children: reorderSections.isPending ? "Saving order..." : "Save order" })] })] }), reorderDraft.length === 0 ? (_jsx(Text, { size: "sm", color: "muted", children: "No sections to reorder." })) : (_jsx(Stack, { gap: "sm", children: reorderDraft.map((item, index) => (_jsxs(Div, { layout: "grid", gap: "2", align: "center", className: "grid-cols-[auto_1fr_auto_auto_auto]", rounded: "md", padding: "xs", border: "default", draggable: true, onDragStart: () => setDragIndex(index), onDragOver: (event) => event.preventDefault(), onDrop: () => handleReorderDrop(index), onDragEnd: () => setDragIndex(null), children: [_jsx(Text, { size: "sm", weight: "semibold", color: "muted", children: "\u2261" }), _jsxs(Text, { size: "sm", color: "primary", children: [item.type, " #", item.order] }), _jsx(Input, { type: "number", min: 1, max: reorderDraft.length, value: String(item.order), onChange: (event) => updateReorderItemOrder(index, Number(event.target.value) || 1), className: "w-24" }), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => moveReorderItem(index, -1), disabled: index === 0, children: "Up" }), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => moveReorderItem(index, 1), disabled: index === reorderDraft.length - 1, children: "Down" })] }, `reorder-${item.id}`))) }))] }), _jsx(Modal, { isOpen: isModalOpen, onClose: () => setIsModalOpen(false), title: "Manage Homepage Section", size: "lg", children: _jsxs(Form, { onSubmit: (event) => {
|
|
969
954
|
event.preventDefault();
|
|
970
955
|
saveSection.mutate();
|
|
971
956
|
}, spacing: "md", children: [_jsx(Select, { label: "Mode", value: mode, onValueChange: (value) => setMode(value), options: [
|
|
@@ -19,13 +19,15 @@ function NavLink({ item, isActive, onClick }) {
|
|
|
19
19
|
: "text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]/60 hover:text-zinc-800 hover:text-[var(--appkit-color-text-muted)]"}`, children: [item.icon && _jsx(Span, { size: "base", className: "shrink-0 opacity-60", children: item.icon }), _jsx(Span, { className: "truncate", children: item.label })] }));
|
|
20
20
|
}
|
|
21
21
|
function GroupsContent({ groups, activePath, onItemClick, }) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
// Accordion — only one group open at a time. Initial pick: the first group
|
|
23
|
+
// whose defaultOpen is true, or that contains the active path.
|
|
24
|
+
const [openGroup, setOpenGroup] = useState(() => {
|
|
25
|
+
const match = groups.find((g) => g.defaultOpen ?? g.items.some((i) => activePath === i.href || activePath.startsWith(i.href + "/")));
|
|
26
|
+
return match?.title ?? null;
|
|
27
|
+
});
|
|
28
|
+
const toggle = useCallback((title) => setOpenGroup((p) => (p === title ? null : title)), []);
|
|
27
29
|
return (_jsx(Nav, { "aria-label": "Admin navigation", padding: "y-xs", children: groups.map((group) => {
|
|
28
|
-
const isOpen =
|
|
30
|
+
const isOpen = openGroup === group.title;
|
|
29
31
|
const hasActive = group.items.some((i) => activePath === i.href || activePath.startsWith(i.href + "/"));
|
|
30
32
|
return (_jsxs(Div, { className: "mb-0.5", children: [_jsx(Button, { type: "button", variant: "ghost", onClick: () => toggle(group.title), paddingX: "md", paddingY: "sm", weight: "semibold", rounded: "none", className: `w-full text-[0.6875rem] uppercase tracking-widest transition-colors ${hasActive && !isOpen
|
|
31
33
|
? "text-[var(--appkit-color-text-muted)]"
|