@mohasinac/appkit 4.63.4 → 4.64.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.
Files changed (232) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/server/features/categories/adapters.d.ts +1 -1
  3. package/dist/_internal/server/features/categories/adapters.js +13 -0
  4. package/dist/_internal/server/features/checkout/actions.d.ts +2 -0
  5. package/dist/_internal/server/features/checkout/actions.js +22 -5
  6. package/dist/_internal/server/features/events/like-actions.d.ts +25 -0
  7. package/dist/_internal/server/features/events/like-actions.js +67 -0
  8. package/dist/_internal/server/features/events/likes.d.ts +65 -0
  9. package/dist/_internal/server/features/events/likes.js +146 -0
  10. package/dist/_internal/server/features/orders/adapters.js +3 -1
  11. package/dist/_internal/server/features/seo/index.d.ts +3 -0
  12. package/dist/_internal/server/features/seo/index.js +2 -0
  13. package/dist/_internal/server/features/seo/product-detail-types.d.ts +1 -0
  14. package/dist/_internal/server/features/seo/product-detail-types.js +26 -0
  15. package/dist/_internal/server/features/seo/robots.js +20 -1
  16. package/dist/_internal/server/features/seo/sitemap.js +125 -27
  17. package/dist/_internal/server/features/seo/static-params.d.ts +107 -0
  18. package/dist/_internal/server/features/seo/static-params.js +228 -0
  19. package/dist/_internal/server/features/seo/taxonomy-links.d.ts +44 -0
  20. package/dist/_internal/server/features/seo/taxonomy-links.js +85 -0
  21. package/dist/_internal/server/features/site-settings/adapters.js +20 -2
  22. package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
  23. package/dist/_internal/server/features/stores/adapters.js +88 -1
  24. package/dist/_internal/server/functions/scheduled.d.ts +16 -1
  25. package/dist/_internal/server/functions/scheduled.js +23 -1
  26. package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.js +5 -2
  27. package/dist/_internal/server/jobs/core/jobRunners.js +5 -0
  28. package/dist/_internal/server/jobs/core/onOrderCreate.js +104 -10
  29. package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +2 -0
  30. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +1 -0
  31. package/dist/_internal/server/jobs/core/onScamReportCreate.js +1 -0
  32. package/dist/_internal/server/jobs/core/onScamReportRejected.js +1 -0
  33. package/dist/_internal/server/jobs/core/onScamReportVerified.js +1 -0
  34. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +1 -0
  35. package/dist/_internal/server/jobs/core/pendingOrderTimeout.js +1 -0
  36. package/dist/_internal/server/jobs/core/sellerStandingRollup.d.ts +63 -0
  37. package/dist/_internal/server/jobs/core/sellerStandingRollup.js +412 -0
  38. package/dist/_internal/server/jobs/core/whatsappNotify.d.ts +35 -0
  39. package/dist/_internal/server/jobs/core/whatsappNotify.js +140 -0
  40. package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
  41. package/dist/_internal/server/jobs/handlers/index.js +1 -0
  42. package/dist/_internal/server/jobs/handlers/sellerStandingRollup.d.ts +12 -0
  43. package/dist/_internal/server/jobs/handlers/sellerStandingRollup.js +14 -0
  44. package/dist/_internal/server/notifications/channel-health.d.ts +8 -6
  45. package/dist/_internal/server/notifications/channel-health.js +2 -2
  46. package/dist/_internal/server/notifications/send-guard.d.ts +1 -1
  47. package/dist/_internal/server/notifications/send-guard.js +4 -2
  48. package/dist/_internal/shared/actions/action-registry.js +89 -0
  49. package/dist/_internal/shared/checkout/order-math.d.ts +1 -1
  50. package/dist/_internal/shared/checkout/order-math.js +1 -1
  51. package/dist/_internal/shared/features/checkout/config.d.ts +2 -0
  52. package/dist/_internal/shared/features/checkout/config.js +2 -0
  53. package/dist/_internal/shared/features/messaging/config.d.ts +5 -7
  54. package/dist/_internal/shared/features/messaging/config.js +4 -1
  55. package/dist/_internal/shared/features/seller-standing/config.d.ts +130 -0
  56. package/dist/_internal/shared/features/seller-standing/config.js +153 -0
  57. package/dist/_internal/shared/features/site-settings/fees.d.ts +2 -0
  58. package/dist/_internal/shared/features/site-settings/fees.js +2 -0
  59. package/dist/_internal/shared/features/site-settings/types.d.ts +27 -2
  60. package/dist/_internal/shared/fees/calculator.d.ts +8 -0
  61. package/dist/_internal/shared/fees/calculator.js +7 -0
  62. package/dist/cli/index.js +2 -0
  63. package/dist/client.d.ts +2 -2
  64. package/dist/client.js +1 -1
  65. package/dist/constants/api-endpoints.d.ts +39 -0
  66. package/dist/constants/api-endpoints.js +16 -0
  67. package/dist/constants/notification-types.d.ts +1 -1
  68. package/dist/constants/notification-types.js +1 -1
  69. package/dist/core/integration-keys.d.ts +5 -0
  70. package/dist/core/integration-keys.js +10 -0
  71. package/dist/features/about/components/FeesView.js +6 -0
  72. package/dist/features/about/components/HelpPageView.js +9 -1
  73. package/dist/features/account/components/BecomeSellerView.d.ts +15 -3
  74. package/dist/features/account/components/BecomeSellerView.js +2 -2
  75. package/dist/features/account/components/BuyerShoppingGuideView.js +1 -1
  76. package/dist/features/account/components/NotificationPreferencesPanel.js +4 -3
  77. package/dist/features/account/types/index.d.ts +2 -0
  78. package/dist/features/admin/actions/notification-actions.d.ts +17 -2
  79. package/dist/features/admin/actions/notification-actions.js +154 -9
  80. package/dist/features/admin/components/AdminOrderEditorView.d.ts +1 -1
  81. package/dist/features/admin/components/AdminOrdersView.js +2 -0
  82. package/dist/features/admin/components/AdminSiteSettingsView.js +66 -6
  83. package/dist/features/admin/components/AdminStoreEditorView.d.ts +12 -1
  84. package/dist/features/admin/components/AdminStoreEditorView.js +31 -2
  85. package/dist/features/admin/components/AdminStoresGuideView.js +1 -1
  86. package/dist/features/admin/components/AdminStoresView.js +59 -2
  87. package/dist/features/admin/components/AdminTrustGuideView.js +10 -0
  88. package/dist/features/admin/constants/site-settings-tabs.d.ts +12 -7
  89. package/dist/features/admin/constants/site-settings-tabs.js +12 -6
  90. package/dist/features/admin/repository/site-settings.repository.js +1 -1
  91. package/dist/features/admin/schemas/admin-editor-forms.d.ts +10 -0
  92. package/dist/features/admin/schemas/admin-editor-forms.js +34 -0
  93. package/dist/features/admin/schemas/admin-user-form.d.ts +61 -0
  94. package/dist/features/admin/schemas/admin-user-form.js +44 -3
  95. package/dist/features/admin/schemas/firestore.d.ts +73 -0
  96. package/dist/features/admin/schemas/firestore.js +8 -3
  97. package/dist/features/auth/checkout-value-otp.d.ts +1 -1
  98. package/dist/features/auth/checkout-value-otp.js +1 -1
  99. package/dist/features/auth/permissions/constants.d.ts +2 -2
  100. package/dist/features/auth/permissions/constants.js +2 -1
  101. package/dist/features/blog/components/BlogIndexPageView.js +2 -2
  102. package/dist/features/blog/components/BlogListView.js +2 -1
  103. package/dist/features/blog/components/BlogPostView.js +2 -1
  104. package/dist/features/blog/constants/category-badge.d.ts +33 -0
  105. package/dist/features/blog/constants/category-badge.js +40 -0
  106. package/dist/features/cart/components/CartPriceBreakdown.d.ts +2 -0
  107. package/dist/features/cart/components/CartPriceBreakdown.js +1 -1
  108. package/dist/features/cart/components/StoreAddonsPicker.d.ts +5 -2
  109. package/dist/features/cart/components/StoreAddonsPicker.js +5 -4
  110. package/dist/features/cart/repository/cart.repository.js +2 -1
  111. package/dist/features/cart/schemas/firestore.d.ts +2 -1
  112. package/dist/features/categories/components/TaxonomyLinkIndex.d.ts +39 -0
  113. package/dist/features/categories/components/TaxonomyLinkIndex.js +11 -0
  114. package/dist/features/categories/schemas/firestore.d.ts +25 -0
  115. package/dist/features/categories/utils/load-category-options.d.ts +33 -0
  116. package/dist/features/categories/utils/load-category-options.js +50 -0
  117. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +5 -10
  118. package/dist/features/checkout/actions/checkout-value-otp-actions.js +88 -2
  119. package/dist/features/events/components/EventCard.js +4 -12
  120. package/dist/features/events/components/EventInsights.d.ts +27 -0
  121. package/dist/features/events/components/EventInsights.js +10 -0
  122. package/dist/features/events/components/EventLikeButton.d.ts +21 -0
  123. package/dist/features/events/components/EventLikeButton.js +59 -0
  124. package/dist/features/events/components/EventLikersRail.d.ts +23 -0
  125. package/dist/features/events/components/EventLikersRail.js +54 -0
  126. package/dist/features/events/components/EventTypeBadge.d.ts +26 -0
  127. package/dist/features/events/components/EventTypeBadge.js +7 -0
  128. package/dist/features/events/components/EventsListPageView.js +2 -2
  129. package/dist/features/events/components/SpinWheel.d.ts +41 -0
  130. package/dist/features/events/components/SpinWheel.js +128 -0
  131. package/dist/features/events/components/SpinWheelView.js +36 -15
  132. package/dist/features/events/constants/event-type-meta.d.ts +54 -0
  133. package/dist/features/events/constants/event-type-meta.js +109 -0
  134. package/dist/features/events/repository/event-likes.repository.d.ts +57 -0
  135. package/dist/features/events/repository/event-likes.repository.js +151 -0
  136. package/dist/features/events/schemas/firestore.d.ts +111 -0
  137. package/dist/features/events/schemas/likes.d.ts +81 -0
  138. package/dist/features/events/schemas/likes.js +59 -0
  139. package/dist/features/events/types/index.d.ts +7 -0
  140. package/dist/features/events/utils/carousel-slide.d.ts +42 -0
  141. package/dist/features/events/utils/carousel-slide.js +174 -0
  142. package/dist/features/events/utils/event-charts.d.ts +65 -0
  143. package/dist/features/events/utils/event-charts.js +172 -0
  144. package/dist/features/faq/constants/help-guides.js +9 -0
  145. package/dist/features/faq/schemas/firestore.js +1 -0
  146. package/dist/features/faq/types/index.d.ts +19 -0
  147. package/dist/features/homepage/components/BrandsSection.js +25 -1
  148. package/dist/features/homepage/components/HeroCarousel.js +47 -10
  149. package/dist/features/homepage/lib/section-renderer.js +1 -1
  150. package/dist/features/homepage/types/index.d.ts +7 -0
  151. package/dist/features/orders/actions/refund-actions.js +1 -0
  152. package/dist/features/orders/components/OrderAddonBadges.d.ts +3 -1
  153. package/dist/features/orders/components/OrderAddonBadges.js +4 -3
  154. package/dist/features/orders/repository/orders.repository.d.ts +8 -0
  155. package/dist/features/orders/repository/orders.repository.js +2 -0
  156. package/dist/features/orders/schemas/firestore.d.ts +4 -0
  157. package/dist/features/orders/types/index.d.ts +5 -2
  158. package/dist/features/search/action-index/settings-entries.js +9 -0
  159. package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +6 -1
  160. package/dist/features/store-extensions/repository/store-extensions.repositories.js +10 -1
  161. package/dist/features/store-extensions/schemas/firestore.d.ts +17 -1
  162. package/dist/features/store-extensions/schemas/firestore.js +10 -0
  163. package/dist/features/stores/components/InteractiveStoreCard.js +2 -1
  164. package/dist/features/stores/components/SellerStandingPanel.d.ts +31 -0
  165. package/dist/features/stores/components/SellerStandingPanel.js +25 -0
  166. package/dist/features/stores/components/SellerTierBadge.d.ts +57 -0
  167. package/dist/features/stores/components/SellerTierBadge.js +19 -0
  168. package/dist/features/stores/components/StoreCapabilitiesGuideView.js +33 -2
  169. package/dist/features/stores/components/StoreCreateForm.d.ts +46 -0
  170. package/dist/features/stores/components/StoreCreateForm.js +107 -0
  171. package/dist/features/stores/components/StoreGuideHubView.js +18 -5
  172. package/dist/features/stores/components/StoreHeader.js +2 -1
  173. package/dist/features/stores/components/StoreSettingsGuideView.js +6 -2
  174. package/dist/features/stores/repository/store.repository.d.ts +23 -1
  175. package/dist/features/stores/repository/store.repository.js +52 -1
  176. package/dist/features/stores/schemas/firestore.d.ts +76 -7
  177. package/dist/features/stores/schemas/firestore.js +21 -6
  178. package/dist/features/stores/schemas/index.d.ts +88 -2
  179. package/dist/features/stores/schemas/index.js +14 -0
  180. package/dist/features/stores/schemas/store-create.d.ts +47 -0
  181. package/dist/features/stores/schemas/store-create.js +86 -0
  182. package/dist/features/stores/types/index.d.ts +42 -0
  183. package/dist/features/whatsapp-bot/api/send-status/route.d.ts +12 -0
  184. package/dist/features/whatsapp-bot/api/send-status/route.js +38 -0
  185. package/dist/features/whatsapp-bot/api/webhook/route.d.ts +12 -0
  186. package/dist/features/whatsapp-bot/api/webhook/route.js +43 -0
  187. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.d.ts +57 -0
  188. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +76 -0
  189. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.d.ts +9 -0
  190. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +7 -0
  191. package/dist/features/whatsapp-bot/components/index.d.ts +3 -0
  192. package/dist/features/whatsapp-bot/components/index.js +2 -0
  193. package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +52 -0
  194. package/dist/features/whatsapp-bot/helpers/whatsapp.js +288 -0
  195. package/dist/features/whatsapp-bot/index.d.ts +3 -0
  196. package/dist/features/whatsapp-bot/index.js +3 -0
  197. package/dist/features/whatsapp-bot/manifest.d.ts +2 -0
  198. package/dist/features/whatsapp-bot/manifest.js +13 -0
  199. package/dist/features/whatsapp-bot/messages/en.json +7 -0
  200. package/dist/features/whatsapp-bot/server.d.ts +7 -0
  201. package/dist/features/whatsapp-bot/server.js +7 -0
  202. package/dist/features/whatsapp-bot/types/index.d.ts +126 -0
  203. package/dist/features/whatsapp-bot/types/index.js +1 -0
  204. package/dist/index.d.ts +23 -6
  205. package/dist/index.js +38 -12
  206. package/dist/next/routing/route-map.d.ts +6 -1
  207. package/dist/next/routing/route-map.js +14 -0
  208. package/dist/providers/db-firebase/base.repository.d.ts +1 -1
  209. package/dist/providers/db-firebase/base.repository.js +1 -1
  210. package/dist/repositories/index.d.ts +1 -1
  211. package/dist/repositories/index.js +1 -1
  212. package/dist/schemas/registry.d.ts +115 -0
  213. package/dist/schemas/registry.js +2 -1
  214. package/dist/security/pii-encrypt.js +1 -1
  215. package/dist/server.d.ts +15 -2
  216. package/dist/server.js +32 -2
  217. package/dist/styles.css +36 -1
  218. package/dist/tailwind-utilities.css +1 -1
  219. package/dist/ui/components/HorizontalScroller.js +15 -2
  220. package/dist/ui/components/NavigationLoader.d.ts +14 -1
  221. package/dist/ui/components/NavigationLoader.js +79 -30
  222. package/dist/ui/components/PageHeroHeading.d.ts +40 -0
  223. package/dist/ui/components/PageHeroHeading.js +15 -0
  224. package/dist/ui/components/Typography.d.ts +3 -3
  225. package/dist/ui/components/Typography.js +59 -31
  226. package/dist/ui/components/Typography.style.css +35 -0
  227. package/dist/ui/index.d.ts +2 -0
  228. package/dist/ui/index.js +1 -0
  229. package/package.json +1 -1
  230. package/scripts/seed-cli.mjs +4 -2
  231. package/dist/features/orders/utils/order-announcement-message.d.ts +0 -18
  232. package/dist/features/orders/utils/order-announcement-message.js +0 -16
@@ -158,7 +158,20 @@ export function HorizontalScroller({ children, className = "", gap = 16, snapToI
158
158
  return;
159
159
  const observer = new ResizeObserver(([entry]) => {
160
160
  const w = entry.contentRect.width;
161
- const count = resolvePerView(perView, w);
161
+ /*
162
+ * šŸ›‘ Clamp the column count to how many items there actually ARE.
163
+ *
164
+ * `perView` says "four across at lg", and the width was divided by that
165
+ * unconditionally — so a rail holding ONE item pinned it to 25% of the
166
+ * row and left three empty columns. The nav also hides itself at
167
+ * `pageCount <= 1`, so nothing filled or explained the gap: the live
168
+ * "Events & Offers" section rendered one card against ~75% whitespace.
169
+ *
170
+ * Clamping makes a short rail lay its items out across the full width,
171
+ * which is what every other grid in the app already does. A full rail is
172
+ * unaffected — `min` is a no-op once itemCount >= perView.
173
+ */
174
+ const count = Math.min(resolvePerView(perView, w), Math.max(itemCount, 1));
162
175
  if (count > 0) {
163
176
  setColCount(count);
164
177
  setItemWidth((w - (count - 1) * gap) / count);
@@ -167,7 +180,7 @@ export function HorizontalScroller({ children, className = "", gap = 16, snapToI
167
180
  });
168
181
  observer.observe(el);
169
182
  return () => observer.disconnect();
170
- }, [perView, gap, containerRef, updateExtents]);
183
+ }, [perView, gap, containerRef, updateExtents, itemCount]);
171
184
  // Recompute extents when content size changes (itemWidth resolved, items count changes).
172
185
  useEffect(() => {
173
186
  updateExtents();
@@ -8,7 +8,12 @@ export interface NavigationLoaderProps {
8
8
  label?: string;
9
9
  /**
10
10
  * Safety valve: hides the overlay if the route never settles.
11
- * @default 15000 (ms)
11
+ *
12
+ * 10s, matching the sync-function ceiling this app is written against — an
13
+ * RSC payload that has not arrived by then is not arriving, so holding a
14
+ * blocking overlay any longer only hides the page the user still has.
15
+ *
16
+ * @default 10000 (ms)
12
17
  */
13
18
  timeoutMs?: number;
14
19
  /** Additional className on the overlay div. */
@@ -24,6 +29,14 @@ export interface NavigationLoaderProps {
24
29
  * - Start: intercept `history.pushState` + `popstate`
25
30
  * - End: `usePathname()` changing means React has settled
26
31
  *
32
+ * šŸ›‘ It must never start for a navigation whose path+query cannot change,
33
+ * because the end condition would then be unreachable and the overlay would
34
+ * block the whole viewport until `timeoutMs`. An in-page anchor is exactly
35
+ * that: clicking `#section` fires `popstate` (Chrome does, for the App
36
+ * Router's hash entry) while `usePathname()` and `useSearchParams()` both stay
37
+ * put — measured against production, 15s of stranded overlay on the way in AND
38
+ * again on Back. Hence the `live === prev` gate in `onPopState`.
39
+ *
27
40
  * Mount once at the app shell level (e.g. inside LayoutShellClient).
28
41
  */
29
42
  export declare function NavigationLoader({ spinnerVariant, label, timeoutMs, className, }: NavigationLoaderProps): import("react").JSX.Element | null;
@@ -1,9 +1,21 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { normalizeError } from "../../errors/normalize.js";
4
- import { useEffect, useRef, useState } from "react";
4
+ import { useCallback, useEffect, useRef, useState } from "react";
5
5
  import { usePathname, useSearchParams } from "next/navigation.js";
6
6
  import { Spinner } from "./Spinner.js";
7
+ /**
8
+ * The route key this component settles on: path + query, NEVER the hash.
9
+ *
10
+ * It has to match what `usePathname()` + `useSearchParams()` can observe,
11
+ * because those two hooks are the only thing that can hide the overlay. A hash
12
+ * is invisible to both, so including it here would promise a settle signal
13
+ * that can never arrive.
14
+ */
15
+ function windowRouteKey() {
16
+ const url = new URL(window.location.href);
17
+ return `${url.pathname}?${url.searchParams.toString()}`;
18
+ }
7
19
  /**
8
20
  * NavigationLoader
9
21
  *
@@ -14,9 +26,17 @@ import { Spinner } from "./Spinner.js";
14
26
  * - Start: intercept `history.pushState` + `popstate`
15
27
  * - End: `usePathname()` changing means React has settled
16
28
  *
29
+ * šŸ›‘ It must never start for a navigation whose path+query cannot change,
30
+ * because the end condition would then be unreachable and the overlay would
31
+ * block the whole viewport until `timeoutMs`. An in-page anchor is exactly
32
+ * that: clicking `#section` fires `popstate` (Chrome does, for the App
33
+ * Router's hash entry) while `usePathname()` and `useSearchParams()` both stay
34
+ * put — measured against production, 15s of stranded overlay on the way in AND
35
+ * again on Back. Hence the `live === prev` gate in `onPopState`.
36
+ *
17
37
  * Mount once at the app shell level (e.g. inside LayoutShellClient).
18
38
  */
19
- export function NavigationLoader({ spinnerVariant = "pokeball", label = "Loading page…", timeoutMs = 15000, className = "", }) {
39
+ export function NavigationLoader({ spinnerVariant = "pokeball", label = "Loading page…", timeoutMs = 10000, className = "", }) {
20
40
  const pathname = usePathname();
21
41
  const searchParams = useSearchParams();
22
42
  const [visible, setVisible] = useState(false);
@@ -28,39 +48,55 @@ export function NavigationLoader({ spinnerVariant = "pokeball", label = "Loading
28
48
  const pendingUrl = useRef(null);
29
49
  const visibleRef = useRef(false);
30
50
  const activeRef = useRef(false);
51
+ /** Last path+query seen on `window.location`. Null until the first effect. */
52
+ const lastWindowKey = useRef(null);
31
53
  const currentUrl = `${pathname ?? ""}?${searchParams?.toString() ?? ""}`;
32
54
  const prevUrl = useRef(currentUrl);
33
55
  useEffect(() => {
34
56
  visibleRef.current = visible;
35
57
  }, [visible]);
36
- // Hide once the route URL (path + query/hash) has settled in React.
58
+ /** Drop the overlay and every timer behind it. Safe to call when hidden. */
59
+ const hideNow = useCallback(() => {
60
+ activeRef.current = false;
61
+ visibleRef.current = false;
62
+ setVisible(false);
63
+ if (showTimer.current) {
64
+ clearTimeout(showTimer.current);
65
+ showTimer.current = null;
66
+ }
67
+ if (safetyTimer.current) {
68
+ clearTimeout(safetyTimer.current);
69
+ safetyTimer.current = null;
70
+ }
71
+ if (tickTimer.current) {
72
+ clearInterval(tickTimer.current);
73
+ tickTimer.current = null;
74
+ }
75
+ startTime.current = null;
76
+ pendingUrl.current = null;
77
+ }, []);
78
+ // Hide once the route URL (path + query) has settled in React.
37
79
  useEffect(() => {
38
80
  if (currentUrl !== prevUrl.current) {
39
81
  prevUrl.current = currentUrl;
40
- activeRef.current = false;
41
- visibleRef.current = false;
42
- setVisible(false);
43
- if (showTimer.current) {
44
- clearTimeout(showTimer.current);
45
- showTimer.current = null;
46
- }
47
- if (safetyTimer.current)
48
- clearTimeout(safetyTimer.current);
49
- if (tickTimer.current)
50
- clearInterval(tickTimer.current);
51
- startTime.current = null;
52
- pendingUrl.current = null;
82
+ lastWindowKey.current = windowRouteKey();
83
+ hideNow();
53
84
  }
54
- }, [currentUrl]);
85
+ }, [currentUrl, hideNow]);
55
86
  useEffect(() => {
87
+ if (lastWindowKey.current === null)
88
+ lastWindowKey.current = windowRouteKey();
56
89
  function showOverlay(nextKey) {
57
90
  if (activeRef.current || visibleRef.current)
58
91
  return;
59
92
  if (showTimer.current)
60
93
  return;
61
- activeRef.current = true;
94
+ // Checked BEFORE claiming `activeRef`: returning with it already set
95
+ // would leave the flag stuck true, and every later navigation would
96
+ // early-return above — the loader would silently never show again.
62
97
  if (nextKey && pendingUrl.current === nextKey)
63
98
  return;
99
+ activeRef.current = true;
64
100
  pendingUrl.current = nextKey ?? pendingUrl.current;
65
101
  // Defer to next macrotask to avoid updates during router insertion effects.
66
102
  showTimer.current = setTimeout(() => {
@@ -76,15 +112,7 @@ export function NavigationLoader({ spinnerVariant = "pokeball", label = "Loading
76
112
  setVisible(true);
77
113
  if (safetyTimer.current)
78
114
  clearTimeout(safetyTimer.current);
79
- safetyTimer.current = setTimeout(() => {
80
- activeRef.current = false;
81
- visibleRef.current = false;
82
- setVisible(false);
83
- if (tickTimer.current)
84
- clearInterval(tickTimer.current);
85
- startTime.current = null;
86
- pendingUrl.current = null;
87
- }, timeoutMs);
115
+ safetyTimer.current = setTimeout(hideNow, timeoutMs);
88
116
  }, 0);
89
117
  }
90
118
  function shouldShowForNextUrl(next) {
@@ -122,15 +150,36 @@ export function NavigationLoader({ spinnerVariant = "pokeball", label = "Loading
122
150
  showOverlay();
123
151
  }
124
152
  }
125
- return origPush(...args);
153
+ const result = origPush(...args);
154
+ lastWindowKey.current = windowRouteKey();
155
+ return result;
126
156
  };
127
157
  function onPopState() {
128
- showOverlay();
158
+ // `popstate` fires AFTER the URL has changed, so this is the destination.
159
+ const live = windowRouteKey();
160
+ const prev = lastWindowKey.current;
161
+ lastWindowKey.current = live;
162
+ // Same path+query means an in-page anchor or a second history entry for
163
+ // the route we are already on. React will never re-render, so the hide
164
+ // effect above can never fire — showing the overlay here strands it.
165
+ if (live === prev) {
166
+ hideNow();
167
+ return;
168
+ }
169
+ showOverlay(live);
170
+ }
171
+ // Belt to the braces above: a hash change that reaches us some other way
172
+ // is still, by definition, not a route change.
173
+ function onHashChange() {
174
+ lastWindowKey.current = windowRouteKey();
175
+ hideNow();
129
176
  }
130
177
  window.addEventListener("popstate", onPopState);
178
+ window.addEventListener("hashchange", onHashChange);
131
179
  return () => {
132
180
  history.pushState = origPush;
133
181
  window.removeEventListener("popstate", onPopState);
182
+ window.removeEventListener("hashchange", onHashChange);
134
183
  if (showTimer.current)
135
184
  clearTimeout(showTimer.current);
136
185
  if (safetyTimer.current)
@@ -142,7 +191,7 @@ export function NavigationLoader({ spinnerVariant = "pokeball", label = "Loading
142
191
  startTime.current = null;
143
192
  pendingUrl.current = null;
144
193
  };
145
- }, [timeoutMs]);
194
+ }, [timeoutMs, hideNow]);
146
195
  if (!visible)
147
196
  return null;
148
197
  return (_jsxs("div", { role: "status", "aria-label": label, className: `appkit-nav-loader ${className}`, "data-section": "navigationloader-div-566", children: [_jsx(Spinner, { size: "xl", variant: spinnerVariant, label: label }), _jsxs("span", { className: "appkit-nav-loader__timer", "aria-hidden": "true", children: [elapsed.toFixed(1), "s"] })] }));
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The editorial page header — pill, display heading, rule, subtitle.
3
+ *
4
+ * ## Why this is a component rather than markup in two pages
5
+ *
6
+ * This treatment already existed and was UNREACHABLE. It lived inlined inside
7
+ * `SectionCarousel`, gated on `headingVariant === "editorial"`, so the only
8
+ * surfaces that could use it were homepage rails. `/blog` and `/events` are
9
+ * the two pages the treatment was designed for and they got
10
+ * `<Heading level={1} size="3xl">Blog</Heading>` — one word, no description,
11
+ * no count, no rule — because they had no way to reach it.
12
+ *
13
+ * šŸ›‘ The ornament is `justify="center"` INSIDE a left-aligned parent in the
14
+ * carousel, so the rule floats mid-column away from the heading it belongs to.
15
+ * Here it is aligned with the heading, which is what it was for.
16
+ *
17
+ * Server-safe: no hooks, no DOM, no `"use client"`. A Server Component page
18
+ * can render it directly.
19
+ *
20
+ * @tag layer:ui
21
+ */
22
+ import React from "react";
23
+ export interface PageHeroHeadingProps {
24
+ /** Small uppercase label above the heading. */
25
+ pill?: string;
26
+ title: string;
27
+ /** One line under the rule. Say what the page is for. */
28
+ description?: string;
29
+ /**
30
+ * A live figure — "4 running now", "25 guides". Rendered beside the pill.
31
+ *
32
+ * šŸ›‘ Pass a real count or nothing. A hardcoded "Hundreds of articles" on a
33
+ * page showing 25 is the kind of claim nobody re-checks when the number
34
+ * moves.
35
+ */
36
+ meta?: string;
37
+ align?: "start" | "center";
38
+ className?: string;
39
+ }
40
+ export declare function PageHeroHeading({ pill, title, description, meta, align, className, }: PageHeroHeadingProps): React.JSX.Element;
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Each from its DEFINING module, never the `ui` barrel — a barrel import from
3
+ // inside `ui/components` is a cycle waiting to happen, and Root Cause #18 is
4
+ // the standing rule against convenience re-exports.
5
+ import { Div } from "./Div.js";
6
+ import { Row, Stack } from "./Layout.js";
7
+ import { Heading, Span, Text } from "./Typography.js";
8
+ const PILL_CLASS = "inline-flex items-center gap-[var(--appkit-space-2)] rounded-full " +
9
+ "border border-primary-500/30 bg-primary-500/10 px-[var(--appkit-space-5)] " +
10
+ "py-[var(--appkit-space-1-5)] text-[length:var(--appkit-text-xs)] font-medium " +
11
+ "tracking-[0.2em] uppercase text-primary-700 dark:text-primary-400 backdrop-blur-sm";
12
+ export function PageHeroHeading({ pill, title, description, meta, align = "start", className = "", }) {
13
+ const alignClass = align === "center" ? "text-center" : "text-left";
14
+ return (_jsxs(Stack, { gap: "xs", className: `${alignClass} ${className}`, children: [(pill || meta) && (_jsxs(Row, { align: "center", justify: align === "center" ? "center" : "start", gap: "sm", wrap: true, className: "mb-3", children: [pill && (_jsxs(Span, { className: PILL_CLASS, children: [_jsx(Span, { className: "w-1.5 h-1.5 bg-primary-500 inline-block", rounded: "full", "aria-hidden": "true" }), pill, _jsx(Span, { className: "w-1.5 h-1.5 bg-primary-500 inline-block", rounded: "full", "aria-hidden": "true" })] })), meta && (_jsx(Text, { size: "xs", color: "muted", transform: "uppercase", className: "tracking-widest", children: meta }))] })), _jsx(Heading, { level: 1, size: "3xl", mdSize: "4xl", weight: "bold", family: "display", className: "mb-1", children: title }), _jsxs(Row, { align: "center", justify: align === "center" ? "center" : "start", gap: "sm", textSize: "xs", color: "faint", className: "mt-1 select-none", "aria-hidden": "true", children: [_jsx(Span, { className: "h-px w-6 bg-current" }), _jsx(Span, { size: "xs", children: "\u2736" }), _jsx(Span, { className: "h-px w-6 bg-current" })] }), description && (_jsx(Div, { className: "mt-3 max-w-2xl", children: _jsx(Text, { size: "base", color: "muted", children: description }) }))] }));
15
+ }
@@ -19,9 +19,9 @@ declare const TYPOGRAPHY: {
19
19
  readonly "3xl": "appkit-text--3xl";
20
20
  readonly "4xl": "appkit-text--4xl";
21
21
  readonly "5xl": "appkit-text--5xl";
22
- readonly "6xl": "text-[length:var(--appkit-text-6xl)]";
23
- readonly "7xl": "text-[length:var(--appkit-text-7xl)]";
24
- readonly "8xl": "text-[length:var(--appkit-text-8xl)]";
22
+ readonly "6xl": "appkit-text--6xl";
23
+ readonly "7xl": "appkit-text--7xl";
24
+ readonly "8xl": "appkit-text--8xl";
25
25
  };
26
26
  readonly textWeight: {
27
27
  readonly light: "appkit-font--light";
@@ -21,9 +21,15 @@ const TYPOGRAPHY = {
21
21
  "3xl": "appkit-text--3xl",
22
22
  "4xl": "appkit-text--4xl",
23
23
  "5xl": "appkit-text--5xl",
24
- "6xl": "text-[length:var(--appkit-text-6xl)]",
25
- "7xl": "text-[length:var(--appkit-text-7xl)]",
26
- "8xl": "text-[length:var(--appkit-text-8xl)]",
24
+ /*
25
+ * šŸ›‘ Real classes, not `text-[length:…]` arbitrary utilities. An arbitrary
26
+ * utility carries only the property its bracket names, so these three set
27
+ * font-size and left line-height to whatever the BASE size class had —
28
+ * 40px under 96px glyphs on the hero carousel. See Typography.style.css.
29
+ */
30
+ "6xl": "appkit-text--6xl",
31
+ "7xl": "appkit-text--7xl",
32
+ "8xl": "appkit-text--8xl",
27
33
  },
28
34
  textWeight: {
29
35
  light: "appkit-font--light",
@@ -91,6 +97,28 @@ function shapingClasses(opts) {
91
97
  * candidate to the scanner, which copies it verbatim into the generated CSS
92
98
  * and produces an unparsable declaration. Every combination below appears as
93
99
  * a complete literal so the scanner only ever sees real, generatable classes.
100
+ *
101
+ * ── šŸ›‘ EACH ENTRY CARRIES ITS LINE-HEIGHT TOO ────────────────────────────
102
+ *
103
+ * `text-[length:…]` sets FONT-SIZE AND NOTHING ELSE. So before this, a
104
+ * responsive size changed the glyph size at the breakpoint and left
105
+ * line-height at whatever the BASE size class had declared — the two
106
+ * properties came from different breakpoints and nothing reconciled them.
107
+ *
108
+ * Measured on the live hero carousel (`size="4xl" mdSize="6xl" lgSize="8xl"`):
109
+ * at >=1024px the title drew 96px glyphs inside `.appkit-text--4xl`'s 40px
110
+ * line box. Two lines overlapped each other and spilled ~28px into the eyebrow
111
+ * above and the description below — the reported unreadable Diwali headline.
112
+ *
113
+ * The paired value is the SAME line-height that size's base class declares in
114
+ * Typography.style.css, so the responsive path now behaves exactly like the
115
+ * base path at that size. That is the invariant that should always have held.
116
+ *
117
+ * šŸ›‘ `xs`–`xl` deliberately carry NO leading. Those sizes declare none in the
118
+ * base CSS either, so the element keeps its component default — 1.15 under
119
+ * `.appkit-heading`, 1.65 under `.appkit-text`. Pinning one value here would
120
+ * have to pick a winner and would silently retune every small responsive
121
+ * `<Text>` in the app.
94
122
  */
95
123
  const RESPONSIVE_TEXT_SIZE_CLASS = {
96
124
  "sm:": {
@@ -99,13 +127,13 @@ const RESPONSIVE_TEXT_SIZE_CLASS = {
99
127
  base: "sm:text-[length:var(--appkit-text-base)]",
100
128
  lg: "sm:text-[length:var(--appkit-text-lg)]",
101
129
  xl: "sm:text-[length:var(--appkit-text-xl)]",
102
- "2xl": "sm:text-[length:var(--appkit-text-2xl)]",
103
- "3xl": "sm:text-[length:var(--appkit-text-3xl)]",
104
- "4xl": "sm:text-[length:var(--appkit-text-4xl)]",
105
- "5xl": "sm:text-[length:var(--appkit-text-5xl)]",
106
- "6xl": "sm:text-[length:var(--appkit-text-6xl)]",
107
- "7xl": "sm:text-[length:var(--appkit-text-7xl)]",
108
- "8xl": "sm:text-[length:var(--appkit-text-8xl)]",
130
+ "2xl": "sm:text-[length:var(--appkit-text-2xl)] sm:leading-[2rem]",
131
+ "3xl": "sm:text-[length:var(--appkit-text-3xl)] sm:leading-[2.25rem]",
132
+ "4xl": "sm:text-[length:var(--appkit-text-4xl)] sm:leading-[2.5rem]",
133
+ "5xl": "sm:text-[length:var(--appkit-text-5xl)] sm:leading-[1]",
134
+ "6xl": "sm:text-[length:var(--appkit-text-6xl)] sm:leading-[1.15]",
135
+ "7xl": "sm:text-[length:var(--appkit-text-7xl)] sm:leading-[1.15]",
136
+ "8xl": "sm:text-[length:var(--appkit-text-8xl)] sm:leading-[1.15]",
109
137
  },
110
138
  "md:": {
111
139
  xs: "md:text-[length:var(--appkit-text-xs)]",
@@ -113,13 +141,13 @@ const RESPONSIVE_TEXT_SIZE_CLASS = {
113
141
  base: "md:text-[length:var(--appkit-text-base)]",
114
142
  lg: "md:text-[length:var(--appkit-text-lg)]",
115
143
  xl: "md:text-[length:var(--appkit-text-xl)]",
116
- "2xl": "md:text-[length:var(--appkit-text-2xl)]",
117
- "3xl": "md:text-[length:var(--appkit-text-3xl)]",
118
- "4xl": "md:text-[length:var(--appkit-text-4xl)]",
119
- "5xl": "md:text-[length:var(--appkit-text-5xl)]",
120
- "6xl": "md:text-[length:var(--appkit-text-6xl)]",
121
- "7xl": "md:text-[length:var(--appkit-text-7xl)]",
122
- "8xl": "md:text-[length:var(--appkit-text-8xl)]",
144
+ "2xl": "md:text-[length:var(--appkit-text-2xl)] md:leading-[2rem]",
145
+ "3xl": "md:text-[length:var(--appkit-text-3xl)] md:leading-[2.25rem]",
146
+ "4xl": "md:text-[length:var(--appkit-text-4xl)] md:leading-[2.5rem]",
147
+ "5xl": "md:text-[length:var(--appkit-text-5xl)] md:leading-[1]",
148
+ "6xl": "md:text-[length:var(--appkit-text-6xl)] md:leading-[1.15]",
149
+ "7xl": "md:text-[length:var(--appkit-text-7xl)] md:leading-[1.15]",
150
+ "8xl": "md:text-[length:var(--appkit-text-8xl)] md:leading-[1.15]",
123
151
  },
124
152
  "lg:": {
125
153
  xs: "lg:text-[length:var(--appkit-text-xs)]",
@@ -127,13 +155,13 @@ const RESPONSIVE_TEXT_SIZE_CLASS = {
127
155
  base: "lg:text-[length:var(--appkit-text-base)]",
128
156
  lg: "lg:text-[length:var(--appkit-text-lg)]",
129
157
  xl: "lg:text-[length:var(--appkit-text-xl)]",
130
- "2xl": "lg:text-[length:var(--appkit-text-2xl)]",
131
- "3xl": "lg:text-[length:var(--appkit-text-3xl)]",
132
- "4xl": "lg:text-[length:var(--appkit-text-4xl)]",
133
- "5xl": "lg:text-[length:var(--appkit-text-5xl)]",
134
- "6xl": "lg:text-[length:var(--appkit-text-6xl)]",
135
- "7xl": "lg:text-[length:var(--appkit-text-7xl)]",
136
- "8xl": "lg:text-[length:var(--appkit-text-8xl)]",
158
+ "2xl": "lg:text-[length:var(--appkit-text-2xl)] lg:leading-[2rem]",
159
+ "3xl": "lg:text-[length:var(--appkit-text-3xl)] lg:leading-[2.25rem]",
160
+ "4xl": "lg:text-[length:var(--appkit-text-4xl)] lg:leading-[2.5rem]",
161
+ "5xl": "lg:text-[length:var(--appkit-text-5xl)] lg:leading-[1]",
162
+ "6xl": "lg:text-[length:var(--appkit-text-6xl)] lg:leading-[1.15]",
163
+ "7xl": "lg:text-[length:var(--appkit-text-7xl)] lg:leading-[1.15]",
164
+ "8xl": "lg:text-[length:var(--appkit-text-8xl)] lg:leading-[1.15]",
137
165
  },
138
166
  "xl:": {
139
167
  xs: "xl:text-[length:var(--appkit-text-xs)]",
@@ -141,13 +169,13 @@ const RESPONSIVE_TEXT_SIZE_CLASS = {
141
169
  base: "xl:text-[length:var(--appkit-text-base)]",
142
170
  lg: "xl:text-[length:var(--appkit-text-lg)]",
143
171
  xl: "xl:text-[length:var(--appkit-text-xl)]",
144
- "2xl": "xl:text-[length:var(--appkit-text-2xl)]",
145
- "3xl": "xl:text-[length:var(--appkit-text-3xl)]",
146
- "4xl": "xl:text-[length:var(--appkit-text-4xl)]",
147
- "5xl": "xl:text-[length:var(--appkit-text-5xl)]",
148
- "6xl": "xl:text-[length:var(--appkit-text-6xl)]",
149
- "7xl": "xl:text-[length:var(--appkit-text-7xl)]",
150
- "8xl": "xl:text-[length:var(--appkit-text-8xl)]",
172
+ "2xl": "xl:text-[length:var(--appkit-text-2xl)] xl:leading-[2rem]",
173
+ "3xl": "xl:text-[length:var(--appkit-text-3xl)] xl:leading-[2.25rem]",
174
+ "4xl": "xl:text-[length:var(--appkit-text-4xl)] xl:leading-[2.5rem]",
175
+ "5xl": "xl:text-[length:var(--appkit-text-5xl)] xl:leading-[1]",
176
+ "6xl": "xl:text-[length:var(--appkit-text-6xl)] xl:leading-[1.15]",
177
+ "7xl": "xl:text-[length:var(--appkit-text-7xl)] xl:leading-[1.15]",
178
+ "8xl": "xl:text-[length:var(--appkit-text-8xl)] xl:leading-[1.15]",
151
179
  },
152
180
  };
153
181
  function responsiveSizeClass(prefix, size) {
@@ -87,6 +87,41 @@
87
87
  line-height: 1;
88
88
  }
89
89
 
90
+ /*
91
+ * šŸ›‘ 6xl–8xl MUST declare a line-height, and the reason is a live bug.
92
+ *
93
+ * These three tiers used to exist only as Tailwind arbitrary utilities in
94
+ * `TYPOGRAPHY.textSize` (`text-[length:var(--appkit-text-6xl)]`), which set
95
+ * FONT-SIZE ONLY — and with `important: true` in both configs, at that.
96
+ * `.appkit-heading`'s `line-height: var(--appkit-leading-tight)` is then
97
+ * overridden by whichever size class the element also carries: a
98
+ * `size="4xl" lgSize="8xl"` heading resolved to `.appkit-text--4xl`'s
99
+ * `line-height: 2.5rem` at EVERY breakpoint, because no `lg:` rule ever
100
+ * touched line-height.
101
+ *
102
+ * Measured on the live hero carousel: 96px glyphs in a 40px line box. A
103
+ * two-line title overlapped itself and spilled ~28px above and below into the
104
+ * eyebrow and the description — the reported "Diwali title is unreadable".
105
+ *
106
+ * So each tier carries BOTH properties, exactly like 2xl–5xl above. Keep them
107
+ * as real classes rather than arbitrary utilities: an arbitrary utility can
108
+ * only carry the one property its bracket names.
109
+ */
110
+ .appkit-text--6xl {
111
+ font-size: var(--appkit-text-6xl, 3.75rem);
112
+ line-height: var(--appkit-leading-tight, 1.15);
113
+ }
114
+
115
+ .appkit-text--7xl {
116
+ font-size: var(--appkit-text-7xl, 4.5rem);
117
+ line-height: var(--appkit-leading-tight, 1.15);
118
+ }
119
+
120
+ .appkit-text--8xl {
121
+ font-size: var(--appkit-text-8xl, 6rem);
122
+ line-height: var(--appkit-leading-tight, 1.15);
123
+ }
124
+
90
125
  .appkit-font--light {
91
126
  font-weight: 300;
92
127
  }
@@ -16,6 +16,8 @@ export type { SectionProps, SectionBackgroundConfig, ArticleProps, MainProps, As
16
16
  export { Section, sectionBackgroundStyle, Article, Main, Aside, Nav, BlockHeader, BlockFooter, Ul, Ol, Li, Table, Thead, Tbody, Tr, Th, Td, Code, Pre, Blockquote, Figure, Figcaption, Dl, Dt, Dd, } from "./components/Semantic";
17
17
  export type { DivProps } from "./components/Div";
18
18
  export { Div } from "./components/Div";
19
+ export type { PageHeroHeadingProps } from "./components/PageHeroHeading";
20
+ export { PageHeroHeading } from "./components/PageHeroHeading";
19
21
  export { Disclaimer } from "./components/Disclaimer";
20
22
  export type { DisclaimerProps } from "./components/Disclaimer";
21
23
  export type { SpecTableProps, SpecTableRow } from "./components/SpecTable";
package/dist/ui/index.js CHANGED
@@ -30,6 +30,7 @@ export { FormErrorSummary } from "./forms/index.js";
30
30
  export { buildColumns, createColumnBuilder, renderBoolean, renderCurrency, renderCurrencyCompact, renderCount, renderNullable, renderRating, getStatusTone, getResourceIcon, } from "./columns/index.js";
31
31
  export { Section, sectionBackgroundStyle, Article, Main, Aside, Nav, BlockHeader, BlockFooter, Ul, Ol, Li, Table, Thead, Tbody, Tr, Th, Td, Code, Pre, Blockquote, Figure, Figcaption, Dl, Dt, Dd, } from "./components/Semantic.js";
32
32
  export { Div } from "./components/Div.js";
33
+ export { PageHeroHeading } from "./components/PageHeroHeading.js";
33
34
  /*
34
35
  * Phase 12 — the one way to render a disclaimer. `id` only: there is no `text`
35
36
  * prop, because an escape hatch would make it a styled box and the legally
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mohasinac/appkit",
3
- "version": "4.63.4",
3
+ "version": "4.64.0",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -267,7 +267,7 @@ const {
267
267
  FRANCHISE_BY_CATEGORY_ROOT,
268
268
  ordersSeedData, reviewsSeedData, cartsSeedData, bidsSeedData,
269
269
  couponsSeedData, couponUsageSeedData,
270
- eventsSeedData, eventEntriesSeedData, payoutsSeedData, offersSeedData,
270
+ eventsSeedData, eventEntriesSeedData, eventLikesSeedData, payoutsSeedData, offersSeedData,
271
271
  notificationsSeedData, blogPostsSeedData,
272
272
  carouselsSeedData, carouselSlidesSeedData, homepageSectionsSeedData,
273
273
  siteSettingsSeedData, faqSeedData,
@@ -290,7 +290,7 @@ const {
290
290
  COUPONS_COLLECTION, CAROUSELS_COLLECTION, CAROUSEL_SLIDES_COLLECTION,
291
291
  HOMEPAGE_SECTIONS_COLLECTION, SITE_SETTINGS_COLLECTION, FAQS_COLLECTION,
292
292
  NOTIFICATIONS_COLLECTION, PAYOUT_COLLECTION, OFFER_COLLECTION, BLOG_POSTS_COLLECTION,
293
- EVENTS_COLLECTION, EVENT_ENTRIES_COLLECTION, SESSION_COLLECTION,
293
+ EVENTS_COLLECTION, EVENT_ENTRIES_COLLECTION, EVENT_LIKES_COLLECTION, SESSION_COLLECTION,
294
294
  CART_COLLECTION,
295
295
  GROUPED_LISTINGS_COLLECTION, SCAMMER_COLLECTION,
296
296
  WISHLIST_COLLECTION, HISTORY_COLLECTION, PRODUCT_FEATURES_COLLECTION,
@@ -376,6 +376,7 @@ const COLLECTION_MAP = {
376
376
  blogPosts: BLOG_POSTS_COLLECTION,
377
377
  events: EVENTS_COLLECTION,
378
378
  eventEntries: EVENT_ENTRIES_COLLECTION,
379
+ eventLikes: EVENT_LIKES_COLLECTION,
379
380
  sessions: SESSION_COLLECTION,
380
381
  carts: CART_COLLECTION,
381
382
  wishlists: WISHLIST_COLLECTION,
@@ -760,6 +761,7 @@ const SEED_DATA_MAP = {
760
761
  blogPosts: blogPostsSeedData,
761
762
  events: eventsSeedData,
762
763
  eventEntries: eventEntriesSeedData,
764
+ eventLikes: eventLikesSeedData,
763
765
  sessions: sessionsSeedData,
764
766
  carts: cartsSeedData,
765
767
  wishlists: wishlistsSeedData,
@@ -1,18 +0,0 @@
1
- export interface PurchaseAnnouncementInput {
2
- buyerName: string;
3
- firstItemName: string;
4
- /** 0 if only one item in the order */
5
- additionalItemCount: number;
6
- /** Total order amount in decimal rupees */
7
- totalAmount: number;
8
- orderId: string;
9
- }
10
- /**
11
- * Plain-text body for the "New order placed" staff notification row.
12
- *
13
- * Originally built for the WhatsApp purchase announcement. That integration
14
- * was removed 2026-10-20, but the builder survives because its output is now
15
- * the `adminNotifications` body the admin inbox renders and the daily digest
16
- * counts — a durable record rather than a per-admin blast.
17
- */
18
- export declare function buildPurchaseAnnouncementMessage(input: PurchaseAnnouncementInput): string;
@@ -1,16 +0,0 @@
1
- /**
2
- * Plain-text body for the "New order placed" staff notification row.
3
- *
4
- * Originally built for the WhatsApp purchase announcement. That integration
5
- * was removed 2026-10-20, but the builder survives because its output is now
6
- * the `adminNotifications` body the admin inbox renders and the daily digest
7
- * counts — a durable record rather than a per-admin blast.
8
- */
9
- export function buildPurchaseAnnouncementMessage(input) {
10
- const { buyerName, firstItemName, additionalItemCount, totalAmount, orderId } = input;
11
- const extra = additionalItemCount > 0
12
- ? ` + ${additionalItemCount} more item${additionalItemCount > 1 ? "s" : ""}`
13
- : "";
14
- const amount = totalAmount.toLocaleString("en-IN");
15
- return `šŸ›ļø New order! ${buyerName} purchased ${firstItemName}${extra} for ₹${amount}. Order #${orderId}`;
16
- }