@mohasinac/appkit 3.2.3 → 3.2.5

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.
@@ -77,6 +77,10 @@ function useResponsiveDrawer(storageKey) {
77
77
  setMobileOpen(false);
78
78
  });
79
79
  }, [isDesktop, storageKey]);
80
+ // Close only the mobile drawer — used on route change so desktop sidebar stays persistent.
81
+ const closeMobile = useCallback(() => {
82
+ startTransition(() => { setMobileOpen(false); });
83
+ }, []);
80
84
  const toggle = useCallback(() => {
81
85
  startTransition(() => {
82
86
  if (isDesktop()) {
@@ -97,7 +101,7 @@ function useResponsiveDrawer(storageKey) {
97
101
  registerNav({ open, close, toggle });
98
102
  return () => unregisterNav();
99
103
  }, [registerNav, unregisterNav, open, close, toggle]);
100
- return { desktopOpen, mobileOpen, close, toggle };
104
+ return { desktopOpen, mobileOpen, close, closeMobile, toggle };
101
105
  }
102
106
  /** Filter nav groups by navConfig (enabled toggle) + requiredPermission. */
103
107
  function filterGroups(groups, navConfig, permissions) {
@@ -117,7 +121,8 @@ export function DashboardLayoutClient({ variant, groups, permissions, activeHref
117
121
  const pathname = usePathname();
118
122
  const activeHref = explicitActiveHref ?? pathname ?? "";
119
123
  const storageKey = `appkit:sidebar-open:${variant}`;
120
- const { desktopOpen, mobileOpen, close, toggle } = useResponsiveDrawer(storageKey);
124
+ const { desktopOpen, mobileOpen, close, closeMobile, toggle } = useResponsiveDrawer(storageKey);
125
+ useEffect(() => { closeMobile(); }, [pathname, closeMobile]);
121
126
  const { data: settings } = useSiteSettings();
122
127
  const navConfig = settings?.navConfig;
123
128
  const filteredGroups = filterGroups(groups, navConfig, permissions);
@@ -1,11 +1,11 @@
1
- export declare const getHomepageSections: () => Promise<never[] | import("../../../..").HomepageSectionDocument[]>;
1
+ export declare const getHomepageSections: () => Promise<import("../../../..").HomepageSectionDocument[]>;
2
2
  export declare const getHeroCarouselSlides: () => Promise<never[] | import("../../../..").CarouselSlideDocument[]>;
3
3
  /**
4
4
  * One parallel fetch returning every piece of data the homepage sections need.
5
5
  * Page components call this once; React.cache() deduplicates per request.
6
6
  */
7
7
  export declare const getHomepageInitial: () => Promise<{
8
- sections: never[] | import("../../../..").HomepageSectionDocument[];
8
+ sections: import("../../../..").HomepageSectionDocument[];
9
9
  carouselSlides: never[] | import("../../../..").CarouselSlideDocument[];
10
10
  featuredProducts: never[] | import("../../../..").ProductDocument[];
11
11
  activeAuctions: never[] | import("../../../..").ProductDocument[];
@@ -1,8 +1,29 @@
1
1
  import { cache } from "react";
2
- import { homepageSectionsRepository, carouselRepository, productRepository, reviewRepository, blogRepository, eventRepository, categoriesRepository, } from "../../../../repositories";
2
+ import { homepageSectionsRepository, carouselRepository, productRepository, reviewRepository, blogRepository, eventRepository, categoriesRepository, siteSettingsRepository, } from "../../../../repositories";
3
3
  import { HOMEPAGE_FEATURED_REVIEWS_LIMIT, HOMEPAGE_RECENT_BLOG_POSTS_LIMIT, } from "../../../shared/features/homepage/config";
4
+ /** Section types that require a feature flag to be enabled to show on the homepage. */
5
+ const SECTION_FEATURE_GATE = {
6
+ auctions: "auctions",
7
+ "pre-orders": "preOrders",
8
+ events: "events",
9
+ "event-raffles": "events",
10
+ "prize-draws": "events",
11
+ "blog-articles": "blog",
12
+ };
4
13
  export const getHomepageSections = cache(async () => {
5
- return homepageSectionsRepository.getEnabledSections().catch(() => []);
14
+ const [sections, settings] = await Promise.all([
15
+ homepageSectionsRepository.getEnabledSections().catch(() => []),
16
+ siteSettingsRepository.getSingleton().catch(() => null),
17
+ ]);
18
+ const flags = settings?.featureFlags;
19
+ if (!flags)
20
+ return sections;
21
+ return sections.filter((s) => {
22
+ const flagKey = SECTION_FEATURE_GATE[s.type];
23
+ if (!flagKey)
24
+ return true;
25
+ return flags[flagKey] !== false;
26
+ });
6
27
  });
7
28
  export const getHeroCarouselSlides = cache(async () => {
8
29
  return carouselRepository.getActiveSlides().catch(() => []);
@@ -12,8 +33,9 @@ export const getHeroCarouselSlides = cache(async () => {
12
33
  * Page components call this once; React.cache() deduplicates per request.
13
34
  */
14
35
  export const getHomepageInitial = cache(async () => {
15
- const [sections, carouselSlides, featuredProducts, activeAuctions, activePreOrders, activeBrands, featuredReviews, recentBlogPosts, activeEvents, featuredCategories,] = await Promise.all([
36
+ const [rawSections, settings, carouselSlides, featuredProducts, activeAuctions, activePreOrders, activeBrands, featuredReviews, recentBlogPosts, activeEvents, featuredCategories,] = await Promise.all([
16
37
  homepageSectionsRepository.getEnabledSections().catch(() => []),
38
+ siteSettingsRepository.getSingleton().catch(() => null),
17
39
  carouselRepository.getActiveSlides().catch(() => []),
18
40
  productRepository.findFeatured().catch(() => []),
19
41
  productRepository.findActiveAuctions().catch(() => []),
@@ -24,6 +46,15 @@ export const getHomepageInitial = cache(async () => {
24
46
  eventRepository.listActive().catch(() => []),
25
47
  categoriesRepository.getFeaturedCategories().catch(() => []),
26
48
  ]);
49
+ const flags = settings?.featureFlags;
50
+ const sections = flags
51
+ ? rawSections.filter((s) => {
52
+ const flagKey = SECTION_FEATURE_GATE[s.type];
53
+ if (!flagKey)
54
+ return true;
55
+ return flags[flagKey] !== false;
56
+ })
57
+ : rawSections;
27
58
  return {
28
59
  sections,
29
60
  carouselSlides,
@@ -26,6 +26,7 @@ import { SidebarLayout } from "./SidebarLayout";
26
26
  import { TitleBar } from "./TitleBar";
27
27
  import { BackToTop } from "./BackToTop";
28
28
  import { useDashboardNav } from "./DashboardNavContext";
29
+ import { usePathname } from "next/navigation";
29
30
  // Background defaults consumed by BackgroundRenderer — these are seed values
30
31
  // written into siteSettings on first deploy and may be overridden at runtime.
31
32
  // audit-hex-tokens-ok: seed defaults for siteSettings.theme.background
@@ -113,6 +114,8 @@ export function AppLayoutShell({ children, navItems, sidebarItems = [], sidebarS
113
114
  // a single consumer-level QueryProvider is the correct architecture.
114
115
  const [sidebarOpen, setSidebarOpen] = useState(false);
115
116
  const [searchOpen, setSearchOpen] = useState(false);
117
+ const pathname = usePathname();
118
+ useEffect(() => { setSidebarOpen(false); }, [pathname]);
116
119
  const { theme, toggleTheme } = useTheme();
117
120
  const { closeNav: closeDashboardNav, hasNav: hasDashboardNav, toggleNav: toggleDashboardNav } = useDashboardNav();
118
121
  const { state: bottomActionsState } = useBottomActionsContext();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mohasinac/appkit",
3
- "version": "3.2.3",
3
+ "version": "3.2.5",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"