@mohasinac/appkit 2.3.1 → 2.3.2

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 (253) hide show
  1. package/dist/client.d.ts +12 -8
  2. package/dist/client.js +7 -4
  3. package/dist/constants/api-endpoints.d.ts +4 -0
  4. package/dist/constants/api-endpoints.js +2 -0
  5. package/dist/core/contact-submissions.repository.d.ts +32 -0
  6. package/dist/core/contact-submissions.repository.js +49 -0
  7. package/dist/core/index.d.ts +2 -0
  8. package/dist/core/index.js +1 -0
  9. package/dist/features/about/components/HowPayoutsWorkView.js +1 -1
  10. package/dist/features/account/components/AddressFilters.d.ts +5 -0
  11. package/dist/features/account/components/AddressFilters.js +20 -0
  12. package/dist/features/account/components/AddressesIndexListing.d.ts +6 -0
  13. package/dist/features/account/components/AddressesIndexListing.js +51 -0
  14. package/dist/features/account/components/UserSidebar.d.ts +7 -3
  15. package/dist/features/account/components/UserSidebar.js +55 -7
  16. package/dist/features/account/hooks/useAddresses.d.ts +7 -0
  17. package/dist/features/account/hooks/useAddresses.js +12 -1
  18. package/dist/features/admin/actions/admin-read-actions.d.ts +12 -0
  19. package/dist/features/admin/actions/admin-read-actions.js +18 -0
  20. package/dist/features/admin/components/AdminBlogView.js +26 -2
  21. package/dist/features/admin/components/AdminCarouselView.js +18 -2
  22. package/dist/features/admin/components/AdminCategoriesView.js +27 -2
  23. package/dist/features/admin/components/AdminContactView.d.ts +4 -0
  24. package/dist/features/admin/components/AdminContactView.js +50 -0
  25. package/dist/features/admin/components/AdminFaqsView.js +19 -2
  26. package/dist/features/admin/components/AdminListingScaffold.d.ts +11 -2
  27. package/dist/features/admin/components/AdminListingScaffold.js +14 -3
  28. package/dist/features/admin/components/AdminNewsletterView.d.ts +4 -0
  29. package/dist/features/admin/components/AdminNewsletterView.js +50 -0
  30. package/dist/features/admin/components/AdminProductsView.js +30 -2
  31. package/dist/features/admin/components/AdminReviewsView.js +26 -2
  32. package/dist/features/admin/components/AdminStoresView.js +17 -2
  33. package/dist/features/admin/components/AdminUsersView.js +27 -2
  34. package/dist/features/admin/components/DataTable.d.ts +2 -1
  35. package/dist/features/admin/components/DataTable.js +18 -4
  36. package/dist/features/admin/components/index.d.ts +6 -0
  37. package/dist/features/admin/components/index.js +3 -0
  38. package/dist/features/admin/hooks/useAdminListingData.d.ts +3 -1
  39. package/dist/features/admin/hooks/useAdminListingData.js +12 -7
  40. package/dist/features/admin/server.d.ts +3 -0
  41. package/dist/features/admin/server.js +2 -0
  42. package/dist/features/auctions/components/AuctionDetailPageView.js +93 -47
  43. package/dist/features/auctions/components/AuctionFilters.d.ts +8 -0
  44. package/dist/features/auctions/components/AuctionFilters.js +12 -0
  45. package/dist/features/auctions/components/AuctionsListView.d.ts +6 -1
  46. package/dist/features/auctions/components/AuctionsListView.js +37 -5
  47. package/dist/features/auctions/schemas/index.d.ts +4 -4
  48. package/dist/features/blog/components/BlogFeaturedCard.d.ts +1 -7
  49. package/dist/features/blog/components/BlogFeaturedCard.js +4 -5
  50. package/dist/features/blog/components/BlogFilters.js +2 -1
  51. package/dist/features/blog/components/BlogIndexListing.js +14 -9
  52. package/dist/features/blog/components/BlogIndexPageView.d.ts +6 -1
  53. package/dist/features/blog/components/BlogIndexPageView.js +10 -2
  54. package/dist/features/blog/components/BlogListView.d.ts +2 -1
  55. package/dist/features/blog/components/BlogListView.js +10 -3
  56. package/dist/features/categories/components/CategoriesIndexListing.d.ts +1 -1
  57. package/dist/features/categories/components/CategoriesIndexListing.js +41 -38
  58. package/dist/features/categories/components/CategoriesIndexPageView.d.ts +6 -1
  59. package/dist/features/categories/components/CategoriesIndexPageView.js +41 -2
  60. package/dist/features/categories/components/CategoryDetailPageView.js +13 -6
  61. package/dist/features/categories/components/CategoryDetailTabs.d.ts +5 -0
  62. package/dist/features/categories/components/CategoryDetailTabs.js +17 -0
  63. package/dist/features/categories/components/CategoryFilters.js +2 -1
  64. package/dist/features/categories/components/CategoryGrid.d.ts +2 -1
  65. package/dist/features/categories/components/CategoryGrid.js +8 -6
  66. package/dist/features/categories/components/CategoryProductsListing.js +22 -11
  67. package/dist/features/categories/components/index.d.ts +2 -0
  68. package/dist/features/categories/components/index.js +1 -0
  69. package/dist/features/categories/hooks/useCategories.d.ts +20 -0
  70. package/dist/features/categories/hooks/useCategories.js +50 -1
  71. package/dist/features/categories/hooks/useCategoryTree.d.ts +17 -0
  72. package/dist/features/categories/hooks/useCategoryTree.js +65 -0
  73. package/dist/features/events/components/AdminEventEditorView.d.ts +6 -0
  74. package/dist/features/events/components/AdminEventEditorView.js +203 -0
  75. package/dist/features/events/components/AdminEventsView.js +28 -2
  76. package/dist/features/events/components/EventCard.js +4 -2
  77. package/dist/features/events/components/EventFilters.js +2 -1
  78. package/dist/features/events/components/EventsIndexListing.js +40 -10
  79. package/dist/features/events/components/EventsListPageView.d.ts +6 -1
  80. package/dist/features/events/components/EventsListPageView.js +40 -7
  81. package/dist/features/events/components/index.d.ts +2 -0
  82. package/dist/features/events/components/index.js +1 -0
  83. package/dist/features/events/hooks/useEvents.js +2 -0
  84. package/dist/features/events/types/index.d.ts +1 -0
  85. package/dist/features/homepage/components/BlogArticlesSection.js +1 -1
  86. package/dist/features/homepage/components/EventsSection.js +1 -1
  87. package/dist/features/homepage/components/FeaturedAuctionsSection.js +1 -1
  88. package/dist/features/homepage/components/FeaturedPreOrdersSection.js +1 -1
  89. package/dist/features/homepage/components/FeaturedProductsSection.js +1 -1
  90. package/dist/features/homepage/components/FeaturedStoresSection.js +1 -1
  91. package/dist/features/homepage/components/HeroCarousel.js +1 -1
  92. package/dist/features/homepage/components/MarketplaceHomepageView.js +27 -17
  93. package/dist/features/homepage/components/SectionCarousel.js +4 -4
  94. package/dist/features/homepage/components/ShopByCategorySection.js +2 -2
  95. package/dist/features/homepage/schemas/firestore.d.ts +1 -1
  96. package/dist/features/homepage/schemas/firestore.js +2 -1
  97. package/dist/features/layout/AppLayoutShell.d.ts +6 -2
  98. package/dist/features/layout/AppLayoutShell.js +7 -3
  99. package/dist/features/pre-orders/components/MarketplacePreorderCard.d.ts +3 -1
  100. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +6 -2
  101. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +80 -12
  102. package/dist/features/pre-orders/components/PreOrderFilters.d.ts +8 -0
  103. package/dist/features/pre-orders/components/PreOrderFilters.js +21 -0
  104. package/dist/features/pre-orders/components/PreOrdersIndexListing.d.ts +2 -1
  105. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +69 -10
  106. package/dist/features/pre-orders/components/PreOrdersListView.d.ts +6 -1
  107. package/dist/features/pre-orders/components/PreOrdersListView.js +26 -7
  108. package/dist/features/pre-orders/components/index.d.ts +2 -0
  109. package/dist/features/pre-orders/components/index.js +1 -0
  110. package/dist/features/products/components/AuctionsIndexListing.d.ts +2 -1
  111. package/dist/features/products/components/AuctionsIndexListing.js +61 -9
  112. package/dist/features/products/components/InteractiveProductCard.d.ts +2 -4
  113. package/dist/features/products/components/InteractiveProductCard.js +2 -2
  114. package/dist/features/products/components/ProductDetailPageView.d.ts +1 -1
  115. package/dist/features/products/components/ProductDetailPageView.js +116 -25
  116. package/dist/features/products/components/ProductFilters.d.ts +6 -11
  117. package/dist/features/products/components/ProductFilters.js +5 -3
  118. package/dist/features/products/components/ProductGrid.d.ts +8 -2
  119. package/dist/features/products/components/ProductGrid.js +20 -5
  120. package/dist/features/products/components/ProductTabsShell.d.ts +3 -11
  121. package/dist/features/products/components/ProductTabsShell.js +14 -14
  122. package/dist/features/products/components/ProductsIndexListing.js +73 -9
  123. package/dist/features/products/components/ProductsIndexPageView.d.ts +6 -1
  124. package/dist/features/products/components/ProductsIndexPageView.js +39 -6
  125. package/dist/features/products/components/RelatedProductsCarousel.d.ts +7 -0
  126. package/dist/features/products/components/RelatedProductsCarousel.js +11 -0
  127. package/dist/features/products/components/index.d.ts +1 -0
  128. package/dist/features/products/components/index.js +1 -0
  129. package/dist/features/products/hooks/useProducts.js +16 -0
  130. package/dist/features/products/repository/products.repository.d.ts +8 -0
  131. package/dist/features/products/repository/products.repository.js +2 -0
  132. package/dist/features/products/schemas/index.d.ts +8 -8
  133. package/dist/features/products/types/index.d.ts +12 -0
  134. package/dist/features/promotions/components/CouponsIndexListing.d.ts +9 -0
  135. package/dist/features/promotions/components/CouponsIndexListing.js +86 -0
  136. package/dist/features/promotions/components/PromotionsView.d.ts +11 -5
  137. package/dist/features/promotions/components/PromotionsView.js +6 -1
  138. package/dist/features/promotions/components/index.d.ts +4 -2
  139. package/dist/features/promotions/components/index.js +2 -1
  140. package/dist/features/reviews/components/ReviewDetailPageView.d.ts +4 -0
  141. package/dist/features/reviews/components/ReviewDetailPageView.js +20 -0
  142. package/dist/features/reviews/components/ReviewDetailShell.d.ts +7 -0
  143. package/dist/features/reviews/components/ReviewDetailShell.js +80 -0
  144. package/dist/features/reviews/components/ReviewFilters.d.ts +3 -3
  145. package/dist/features/reviews/components/ReviewFilters.js +5 -4
  146. package/dist/features/reviews/components/ReviewsIndexListing.d.ts +4 -3
  147. package/dist/features/reviews/components/ReviewsIndexListing.js +35 -51
  148. package/dist/features/reviews/components/ReviewsIndexPageView.d.ts +6 -1
  149. package/dist/features/reviews/components/ReviewsIndexPageView.js +49 -3
  150. package/dist/features/reviews/components/ReviewsList.js +9 -1
  151. package/dist/features/reviews/components/index.d.ts +1 -0
  152. package/dist/features/reviews/hooks/useReviews.js +15 -1
  153. package/dist/features/reviews/types/index.d.ts +6 -1
  154. package/dist/features/seller/components/SellerSidebar.d.ts +8 -4
  155. package/dist/features/seller/components/SellerSidebar.js +6 -4
  156. package/dist/features/seller/components/index.d.ts +30 -0
  157. package/dist/features/seller/components/index.js +17 -0
  158. package/dist/features/seller/hooks/useSellerStore.d.ts +2 -0
  159. package/dist/features/seller/hooks/useSellerStore.js +2 -0
  160. package/dist/features/seller/permission-map.d.ts +4 -2
  161. package/dist/features/seller/permission-map.js +16 -14
  162. package/dist/features/seller/schemas/index.d.ts +2 -2
  163. package/dist/features/stores/api/[storeSlug]/reviews/route.d.ts +1 -1
  164. package/dist/features/stores/api/[storeSlug]/reviews/route.js +24 -19
  165. package/dist/features/stores/components/InteractiveStoreCard.d.ts +0 -5
  166. package/dist/features/stores/components/InteractiveStoreCard.js +9 -9
  167. package/dist/features/stores/components/StoreAuctionsListing.js +27 -9
  168. package/dist/features/stores/components/StoreDetailLayoutView.js +2 -0
  169. package/dist/features/stores/components/StoreFilters.d.ts +5 -0
  170. package/dist/features/stores/components/StoreFilters.js +20 -0
  171. package/dist/features/stores/components/StoreHeader.js +2 -2
  172. package/dist/features/stores/components/StorePreOrdersListing.d.ts +5 -0
  173. package/dist/features/stores/components/StorePreOrdersListing.js +40 -0
  174. package/dist/features/stores/components/StorePreOrdersPageView.d.ts +4 -0
  175. package/dist/features/stores/components/StorePreOrdersPageView.js +21 -0
  176. package/dist/features/stores/components/StoreProductsListing.js +21 -11
  177. package/dist/features/stores/components/StoreReviewsListing.js +2 -7
  178. package/dist/features/stores/components/StoresIndexListing.js +42 -8
  179. package/dist/features/stores/components/StoresIndexPageView.d.ts +6 -1
  180. package/dist/features/stores/components/StoresIndexPageView.js +9 -2
  181. package/dist/features/stores/components/index.d.ts +3 -0
  182. package/dist/features/stores/components/index.js +1 -0
  183. package/dist/features/stores/hooks/useStores.d.ts +7 -1
  184. package/dist/features/stores/hooks/useStores.js +16 -3
  185. package/dist/features/stores/schemas/index.d.ts +2 -2
  186. package/dist/features/stores/types/index.d.ts +3 -0
  187. package/dist/features/wishlist/hooks/useGuestWishlist.d.ts +20 -0
  188. package/dist/features/wishlist/hooks/useGuestWishlist.js +49 -0
  189. package/dist/features/wishlist/hooks/useWishlistCount.d.ts +7 -0
  190. package/dist/features/wishlist/hooks/useWishlistCount.js +31 -0
  191. package/dist/features/wishlist/hooks/useWishlistWithGuest.d.ts +56 -0
  192. package/dist/features/wishlist/hooks/useWishlistWithGuest.js +57 -0
  193. package/dist/features/wishlist/index.d.ts +3 -0
  194. package/dist/features/wishlist/index.js +3 -0
  195. package/dist/features/wishlist/utils/guest-wishlist.d.ts +22 -0
  196. package/dist/features/wishlist/utils/guest-wishlist.js +70 -0
  197. package/dist/index.d.ts +50 -1
  198. package/dist/index.js +63 -1
  199. package/dist/next/routing/route-map.d.ts +70 -36
  200. package/dist/next/routing/route-map.js +30 -22
  201. package/dist/seed/addresses-seed-data.js +62 -261
  202. package/dist/seed/beyblade-seed-data.d.ts +7 -0
  203. package/dist/seed/beyblade-seed-data.js +947 -0
  204. package/dist/seed/bids-seed-data.d.ts +10 -2
  205. package/dist/seed/bids-seed-data.js +220 -1071
  206. package/dist/seed/blog-posts-seed-data.d.ts +2 -2
  207. package/dist/seed/blog-posts-seed-data.js +455 -117
  208. package/dist/seed/cart-seed-data.d.ts +9 -9
  209. package/dist/seed/cart-seed-data.js +73 -74
  210. package/dist/seed/coupons-seed-data.d.ts +3 -4
  211. package/dist/seed/coupons-seed-data.js +3 -509
  212. package/dist/seed/events-seed-data.d.ts +2 -2
  213. package/dist/seed/events-seed-data.js +315 -476
  214. package/dist/seed/faq-seed-data.d.ts +18 -41
  215. package/dist/seed/faq-seed-data.js +1059 -1172
  216. package/dist/seed/hot-wheels-seed-data.d.ts +7 -0
  217. package/dist/seed/hot-wheels-seed-data.js +1365 -0
  218. package/dist/seed/index.d.ts +6 -1
  219. package/dist/seed/index.js +6 -1
  220. package/dist/seed/pokemon-carousel-slides-seed-data.d.ts +4 -2
  221. package/dist/seed/pokemon-carousel-slides-seed-data.js +152 -268
  222. package/dist/seed/pokemon-categories-seed-data.d.ts +18 -21
  223. package/dist/seed/pokemon-categories-seed-data.js +424 -1004
  224. package/dist/seed/pokemon-coupons-seed-data.d.ts +6 -0
  225. package/dist/seed/pokemon-coupons-seed-data.js +465 -0
  226. package/dist/seed/pokemon-homepage-sections-seed-data.d.ts +3 -2
  227. package/dist/seed/pokemon-homepage-sections-seed-data.js +67 -289
  228. package/dist/seed/pokemon-products-seed-data.js +662 -0
  229. package/dist/seed/pokemon-seed-bundle.d.ts +32 -11
  230. package/dist/seed/pokemon-seed-bundle.js +41 -11
  231. package/dist/seed/pokemon-stores-seed-data.d.ts +2 -3
  232. package/dist/seed/pokemon-stores-seed-data.js +56 -31
  233. package/dist/seed/pokemon-users-seed-data.d.ts +2 -2
  234. package/dist/seed/pokemon-users-seed-data.js +245 -261
  235. package/dist/seed/reviews-seed-data.d.ts +17 -2
  236. package/dist/seed/reviews-seed-data.js +519 -483
  237. package/dist/seed/site-settings-seed-data.js +14 -14
  238. package/dist/seed/store-addresses-seed-data.js +68 -50
  239. package/dist/seed/transformers-seed-data.d.ts +7 -0
  240. package/dist/seed/transformers-seed-data.js +510 -0
  241. package/dist/seed/wishlists-seed-data.d.ts +5 -1
  242. package/dist/seed/wishlists-seed-data.js +82 -4
  243. package/dist/server.d.ts +1 -0
  244. package/dist/server.js +2 -0
  245. package/dist/tokens/index.d.ts +6 -0
  246. package/dist/tokens/index.js +2 -0
  247. package/dist/ui/components/BaseListingCard.js +24 -26
  248. package/dist/ui/components/BaseListingCard.style.css +5 -5
  249. package/dist/ui/components/HorizontalScroller.d.ts +1 -1
  250. package/dist/ui/components/HorizontalScroller.js +19 -5
  251. package/dist/ui/components/SideDrawer.style.css +3 -11
  252. package/dist/ui/rich-text/RichText.js +19 -1
  253. package/package.json +1 -1
@@ -0,0 +1,203 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import React from "react";
4
+ import { useMutation, useQuery } from "@tanstack/react-query";
5
+ import { Alert, Button, Form, FormActions, Input, Select, StackedViewShell, Text, Toggle, } from "../../../ui";
6
+ import { apiClient } from "../../../http";
7
+ import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
+ function toLocalDatetime(iso) {
9
+ if (!iso)
10
+ return "";
11
+ try {
12
+ const d = new Date(iso);
13
+ const offset = d.getTimezoneOffset();
14
+ const local = new Date(d.getTime() - offset * 60000);
15
+ return local.toISOString().slice(0, 16);
16
+ }
17
+ catch {
18
+ return "";
19
+ }
20
+ }
21
+ function toISOString(local) {
22
+ if (!local)
23
+ return "";
24
+ try {
25
+ return new Date(local).toISOString();
26
+ }
27
+ catch {
28
+ return "";
29
+ }
30
+ }
31
+ const EVENT_TYPE_OPTIONS = [
32
+ { label: "Sale", value: "sale" },
33
+ { label: "Offer / Coupon", value: "offer" },
34
+ { label: "Poll", value: "poll" },
35
+ { label: "Survey", value: "survey" },
36
+ { label: "Feedback", value: "feedback" },
37
+ ];
38
+ const EVENT_STATUS_OPTIONS = [
39
+ { label: "Draft", value: "draft" },
40
+ { label: "Active", value: "active" },
41
+ { label: "Paused", value: "paused" },
42
+ { label: "Ended", value: "ended" },
43
+ ];
44
+ const POLL_VISIBILITY_OPTIONS = [
45
+ { label: "Always visible", value: "always" },
46
+ { label: "After voting", value: "after_vote" },
47
+ { label: "After event ends", value: "after_end" },
48
+ ];
49
+ export function AdminEventEditorView({ eventId, onSaved, ...rest }) {
50
+ const [type, setType] = React.useState("sale");
51
+ const [title, setTitle] = React.useState("");
52
+ const [description, setDescription] = React.useState("");
53
+ const [startsAt, setStartsAt] = React.useState("");
54
+ const [endsAt, setEndsAt] = React.useState("");
55
+ const [coverImageUrl, setCoverImageUrl] = React.useState("");
56
+ const [status, setStatus] = React.useState("draft");
57
+ const [discountPercent, setDiscountPercent] = React.useState("10");
58
+ const [saleBannerText, setSaleBannerText] = React.useState("");
59
+ const [couponId, setCouponId] = React.useState("");
60
+ const [displayCode, setDisplayCode] = React.useState("");
61
+ const [offerBannerText, setOfferBannerText] = React.useState("");
62
+ const [pollOptions, setPollOptions] = React.useState([
63
+ { id: "opt1", label: "" },
64
+ { id: "opt2", label: "" },
65
+ ]);
66
+ const [allowMultiSelect, setAllowMultiSelect] = React.useState(false);
67
+ const [allowComment, setAllowComment] = React.useState(false);
68
+ const [resultsVisibility, setResultsVisibility] = React.useState("always");
69
+ const [requireLogin, setRequireLogin] = React.useState(true);
70
+ const [maxEntriesPerUser, setMaxEntriesPerUser] = React.useState("1");
71
+ const [hasLeaderboard, setHasLeaderboard] = React.useState(false);
72
+ const [anonymous, setAnonymous] = React.useState(false);
73
+ const [saveMessage, setSaveMessage] = React.useState(null);
74
+ const eventQuery = useQuery({
75
+ queryKey: ["admin-event-by-id", eventId],
76
+ queryFn: () => apiClient.get(`${ADMIN_ENDPOINTS.EVENTS}/${eventId}`),
77
+ enabled: Boolean(eventId),
78
+ staleTime: 15000,
79
+ });
80
+ React.useEffect(() => {
81
+ const event = eventQuery.data?.data ?? eventQuery.data;
82
+ if (!event?.id)
83
+ return;
84
+ setType(event.type || "sale");
85
+ setTitle(event.title || "");
86
+ setDescription(event.description || "");
87
+ setStartsAt(toLocalDatetime(event.startsAt));
88
+ setEndsAt(toLocalDatetime(event.endsAt));
89
+ setCoverImageUrl(event.coverImageUrl || event.coverImage?.url || "");
90
+ setStatus(event.status || "draft");
91
+ if (event.saleConfig) {
92
+ setDiscountPercent(String(event.saleConfig.discountPercent ?? 10));
93
+ setSaleBannerText(event.saleConfig.bannerText || "");
94
+ }
95
+ if (event.offerConfig) {
96
+ setCouponId(event.offerConfig.couponId || "");
97
+ setDisplayCode(event.offerConfig.displayCode || "");
98
+ setOfferBannerText(event.offerConfig.bannerText || "");
99
+ }
100
+ if (event.pollConfig) {
101
+ if (event.pollConfig.options?.length)
102
+ setPollOptions(event.pollConfig.options);
103
+ setAllowMultiSelect(Boolean(event.pollConfig.allowMultiSelect));
104
+ setAllowComment(Boolean(event.pollConfig.allowComment));
105
+ setResultsVisibility(event.pollConfig.resultsVisibility || "always");
106
+ }
107
+ if (event.surveyConfig) {
108
+ setRequireLogin(event.surveyConfig.requireLogin !== false);
109
+ setMaxEntriesPerUser(String(event.surveyConfig.maxEntriesPerUser ?? 1));
110
+ setHasLeaderboard(Boolean(event.surveyConfig.hasLeaderboard));
111
+ }
112
+ if (event.feedbackConfig) {
113
+ setAnonymous(Boolean(event.feedbackConfig.anonymous));
114
+ }
115
+ }, [eventQuery.data]);
116
+ const saveMutation = useMutation({
117
+ mutationFn: async () => {
118
+ const buildTypeConfig = () => {
119
+ if (type === "sale")
120
+ return {
121
+ saleConfig: {
122
+ discountPercent: Number(discountPercent) || 10,
123
+ bannerText: saleBannerText || undefined,
124
+ },
125
+ };
126
+ if (type === "offer")
127
+ return {
128
+ offerConfig: { couponId, displayCode, bannerText: offerBannerText || undefined },
129
+ };
130
+ if (type === "poll")
131
+ return {
132
+ pollConfig: {
133
+ options: pollOptions.filter((o) => o.label.trim()),
134
+ allowMultiSelect,
135
+ allowComment,
136
+ resultsVisibility,
137
+ },
138
+ };
139
+ if (type === "survey")
140
+ return {
141
+ surveyConfig: {
142
+ requireLogin,
143
+ maxEntriesPerUser: Number(maxEntriesPerUser) || 1,
144
+ hasLeaderboard,
145
+ hasPointSystem: false,
146
+ entryReviewRequired: false,
147
+ formFields: [],
148
+ },
149
+ };
150
+ if (type === "feedback")
151
+ return {
152
+ feedbackConfig: { anonymous, formFields: [] },
153
+ };
154
+ return {};
155
+ };
156
+ const payload = {
157
+ type,
158
+ title,
159
+ description,
160
+ startsAt: toISOString(startsAt),
161
+ endsAt: toISOString(endsAt),
162
+ coverImageUrl: coverImageUrl || undefined,
163
+ ...buildTypeConfig(),
164
+ };
165
+ if (eventId) {
166
+ payload.status = status;
167
+ await apiClient.patch(`${ADMIN_ENDPOINTS.EVENTS}/${eventId}`, payload);
168
+ return eventId;
169
+ }
170
+ const created = await apiClient.post(ADMIN_ENDPOINTS.EVENTS, payload);
171
+ return created.data?.id ?? created.id ?? "";
172
+ },
173
+ onSuccess: (savedId) => {
174
+ setSaveMessage("Saved successfully.");
175
+ if (savedId)
176
+ onSaved?.(savedId);
177
+ },
178
+ onError: (error) => {
179
+ setSaveMessage(error instanceof Error ? error.message : "Save failed");
180
+ },
181
+ });
182
+ const addPollOption = () => {
183
+ setPollOptions((prev) => [...prev, { id: `opt${Date.now()}`, label: "" }]);
184
+ };
185
+ const removePollOption = (id) => {
186
+ setPollOptions((prev) => prev.filter((o) => o.id !== id));
187
+ };
188
+ const updatePollOption = (id, label) => {
189
+ setPollOptions((prev) => prev.map((o) => (o.id === id ? { ...o, label } : o)));
190
+ };
191
+ const isValid = !!title.trim() &&
192
+ !!startsAt &&
193
+ !!endsAt &&
194
+ (type !== "poll" || pollOptions.filter((o) => o.label.trim()).length >= 2) &&
195
+ (type !== "offer" || (!!couponId.trim() && !!displayCode.trim()));
196
+ return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: eventId ? "Edit Event" : "Create Event", sections: [
197
+ eventQuery.error ? (_jsx(Alert, { variant: "error", title: "Could not load event", children: eventQuery.error instanceof Error ? eventQuery.error.message : "Unknown error" })) : null,
198
+ _jsxs(Form, { onSubmit: (e) => {
199
+ e.preventDefault();
200
+ saveMutation.mutate();
201
+ }, className: "space-y-6", children: [!eventId && (_jsx(Select, { label: "Event type", value: type, options: EVENT_TYPE_OPTIONS, onChange: (e) => setType(e.target.value) })), _jsx(Input, { label: "Title", value: title, onChange: (e) => setTitle(e.target.value), placeholder: "Charizard Flash Sale 2026", required: true }), _jsxs("div", { children: [_jsx("label", { className: "block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1", children: "Description" }), _jsx("textarea", { value: description, onChange: (e) => setDescription(e.target.value), rows: 3, className: "w-full rounded-lg border border-zinc-300 dark:border-slate-600 bg-white dark:bg-slate-900 px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-primary/30", placeholder: "Describe this event\u2026" })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [_jsx(Input, { label: "Starts at", type: "datetime-local", value: startsAt, onChange: (e) => setStartsAt(e.target.value), required: true }), _jsx(Input, { label: "Ends at", type: "datetime-local", value: endsAt, onChange: (e) => setEndsAt(e.target.value), required: true })] }), _jsx(Input, { label: "Cover image URL (optional)", value: coverImageUrl, onChange: (e) => setCoverImageUrl(e.target.value), placeholder: "https://\u2026" }), eventId && (_jsx(Select, { label: "Status", value: status, options: EVENT_STATUS_OPTIONS, onChange: (e) => setStatus(e.target.value) })), type === "sale" && (_jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-3", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Sale configuration" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [_jsx(Input, { label: "Discount %", type: "number", value: discountPercent, onChange: (e) => setDiscountPercent(e.target.value), placeholder: "10" }), _jsx(Input, { label: "Banner text (optional)", value: saleBannerText, onChange: (e) => setSaleBannerText(e.target.value), placeholder: "Limited time \u2014 ends Sunday!" })] })] })), type === "offer" && (_jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-3", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Offer configuration" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [_jsx(Input, { label: "Coupon ID", value: couponId, onChange: (e) => setCouponId(e.target.value), placeholder: "Firestore coupon document ID", required: true }), _jsx(Input, { label: "Display code", value: displayCode, onChange: (e) => setDisplayCode(e.target.value), placeholder: "CHARIZARD25", required: true })] }), _jsx(Input, { label: "Banner text (optional)", value: offerBannerText, onChange: (e) => setOfferBannerText(e.target.value), placeholder: "Use CHARIZARD25 at checkout" })] })), type === "poll" && (_jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-4", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Poll configuration" }), _jsxs("div", { className: "space-y-2", children: [_jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Options (minimum 2)" }), pollOptions.map((opt, idx) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex-1", children: _jsx(Input, { value: opt.label, onChange: (e) => updatePollOption(opt.id, e.target.value), placeholder: `Option ${idx + 1}` }) }), pollOptions.length > 2 && (_jsx("button", { type: "button", onClick: () => removePollOption(opt.id), className: "text-zinc-400 hover:text-red-500 transition-colors px-2 py-1 text-lg leading-none", "aria-label": "Remove option", children: "\u00D7" }))] }, opt.id))), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: addPollOption, children: "+ Add option" })] }), _jsx(Select, { label: "Results visibility", value: resultsVisibility, options: POLL_VISIBILITY_OPTIONS, onChange: (e) => setResultsVisibility(e.target.value) }), _jsxs("div", { className: "space-y-3", children: [_jsx(Toggle, { checked: allowMultiSelect, onChange: setAllowMultiSelect, label: "Allow multi-select" }), _jsx(Toggle, { checked: allowComment, onChange: setAllowComment, label: "Allow comment with vote" })] })] })), type === "survey" && (_jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-3", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Survey configuration" }), _jsx(Input, { label: "Max entries per user", type: "number", value: maxEntriesPerUser, onChange: (e) => setMaxEntriesPerUser(e.target.value), placeholder: "1" }), _jsx(Toggle, { checked: requireLogin, onChange: setRequireLogin, label: "Require login to participate" }), _jsx(Toggle, { checked: hasLeaderboard, onChange: setHasLeaderboard, label: "Show leaderboard" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Form fields can be configured from the event detail page after saving." })] })), type === "feedback" && (_jsxs("div", { className: "rounded-xl border border-zinc-200 dark:border-slate-700 p-4 space-y-3", children: [_jsx(Text, { className: "text-sm font-semibold text-zinc-700 dark:text-zinc-300", children: "Feedback configuration" }), _jsx(Toggle, { checked: anonymous, onChange: setAnonymous, label: "Allow anonymous submissions" }), _jsx(Text, { className: "text-xs text-zinc-500 dark:text-zinc-400", children: "Form fields can be configured from the event detail page after saving." })] })), _jsxs(FormActions, { align: "right", children: [_jsx(Button, { type: "button", variant: "outline", onClick: () => { window.location.href = "/admin/events"; }, children: "Cancel" }), _jsx(Button, { type: "submit", disabled: saveMutation.isPending || !isValid, children: saveMutation.isPending ? "Saving…" : eventId ? "Save changes" : "Create event" })] }), saveMessage && (_jsx(Alert, { variant: saveMessage.toLowerCase().includes("fail") ? "error" : "success", title: "Save status", children: saveMessage }))] }),
202
+ ] }));
203
+ }
@@ -7,9 +7,22 @@ import { toRecordArray, toRelativeDate, toStringValue, useAdminListingData, } fr
7
7
  import { AdminListingScaffold } from "../../admin/components/AdminListingScaffold";
8
8
  export function AdminEventsView({ children, ...props }) {
9
9
  const hasChildren = React.Children.count(children) > 0;
10
+ const [q, setQ] = React.useState("");
11
+ const [statusFilter, setStatusFilter] = React.useState("");
12
+ const [typeFilter, setTypeFilter] = React.useState("");
13
+ const filterParts = [];
14
+ if (statusFilter && statusFilter !== "All") {
15
+ filterParts.push(`status==${statusFilter}`);
16
+ }
17
+ if (typeFilter && typeFilter !== "All") {
18
+ filterParts.push(`type==${typeFilter}`);
19
+ }
20
+ const filters = filterParts.join(",") || undefined;
10
21
  const { rows, total, isLoading, errorMessage } = useAdminListingData({
11
- queryKey: ["admin", "events", "listing"],
22
+ queryKey: ["admin", "events", "listing", q, filters ?? ""],
12
23
  endpoint: ADMIN_ENDPOINTS.EVENTS,
24
+ filters,
25
+ q: q || undefined,
13
26
  mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
14
27
  id: toStringValue(item.id, `event-${index}`),
15
28
  primary: toStringValue(item.title, "Untitled event"),
@@ -31,5 +44,18 @@ export function AdminEventsView({ children, ...props }) {
31
44
  if (hasChildren) {
32
45
  return _jsx(ListingViewShell, { portal: "admin", ...props, children: children });
33
46
  }
34
- return (_jsx(AdminListingScaffold, { portal: "admin", ...props, title: "Events", subtitle: "Manage sales events, offers, polls, surveys, and feedback campaigns.", actionLabel: "New event", searchPlaceholder: "Search events by title or type", rows: rows, isLoading: isLoading, errorMessage: errorMessage, emptyLabel: "No events found", resultSummary: `Showing ${rows.length} of ${total} events` }));
47
+ return (_jsx(AdminListingScaffold, { portal: "admin", ...props, title: "Events", subtitle: "Manage sales events, offers, polls, surveys, and feedback campaigns.", actionLabel: "New event", actionHref: "/admin/events/new", getRowHref: (row) => `/admin/events/${row.id}/edit`, searchPlaceholder: "Search events by title or type", rows: rows, isLoading: isLoading, errorMessage: errorMessage, emptyLabel: "No events found", resultSummary: `Showing ${rows.length} of ${total} events`, onSearch: setQ, searchValue: q, filterGroups: [
48
+ {
49
+ title: "Status",
50
+ options: ["All", "published", "draft", "active", "ended"],
51
+ active: statusFilter || "All",
52
+ onSelect: (opt) => setStatusFilter(opt === "All" ? "" : opt),
53
+ },
54
+ {
55
+ title: "Type",
56
+ options: ["All", "contest", "giveaway", "sale", "poll", "survey", "flash-sale"],
57
+ active: typeFilter || "All",
58
+ onSelect: (opt) => setTypeFilter(opt === "All" ? "" : opt),
59
+ },
60
+ ] }));
35
61
  }
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import Link from "next/link";
2
3
  import { Article, Button, Div, Heading, RichText, Span, TextLink } from "../../../ui";
3
4
  import { THEME_CONSTANTS, LAYOUT } from "../../../tokens";
4
5
  import { normalizeRichTextHtml } from "../../../utils/string.formatter";
@@ -18,6 +19,7 @@ export function EventCard({ event, labels = {}, onParticipate, className = "", }
18
19
  const endsAt = new Date(event.endsAt);
19
20
  const msLeft = endsAt.getTime() - now.getTime();
20
21
  const daysLeft = Math.max(0, Math.ceil(msLeft / (1000 * 60 * 60 * 24)));
21
- return (_jsxs(Article, { className: `flex h-full ${LAYOUT.cardHeight.event} flex-col overflow-hidden rounded-xl border border-zinc-200 bg-white shadow-sm transition-shadow hover:shadow-md dark:border-slate-700 dark:bg-slate-900 ${className}`, children: [event.coverImageUrl ? (_jsx(Div, { className: "aspect-video overflow-hidden", children: _jsx(Div, { role: "img", "aria-label": safeTitle, className: "h-full w-full bg-cover bg-center", style: { backgroundImage: `url(${event.coverImageUrl})` } }) })) : (_jsx(Div, { className: "aspect-video bg-gradient-to-br from-zinc-100 to-zinc-200 dark:from-slate-800 dark:to-slate-700" })), _jsxs(Div, { className: "flex flex-1 flex-col p-4", children: [_jsxs(Div, { className: "flex items-start justify-between gap-2 mb-2", children: [_jsx(Span, { className: "text-lg", "aria-hidden": "true", children: TYPE_ICONS[event.type] }), _jsx(EventStatusBadge, { status: event.status })] }), _jsx(Heading, { level: 3, className: "font-semibold text-gray-900 dark:text-zinc-100 text-base leading-snug mb-1", children: safeTitle }), _jsx(RichText, { html: normalizeRichTextHtml(event.description ?? ""), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: `mb-3 ${THEME_CONSTANTS.utilities.textClamp3} text-sm text-zinc-600 dark:text-zinc-400` }), _jsxs(Div, { className: "mb-3 mt-auto flex items-center justify-between text-xs text-zinc-500 dark:text-zinc-500", children: [event.status === EVENT_FIELDS.STATUS_VALUES.ACTIVE &&
22
- daysLeft > 0 && _jsxs(Span, { children: [daysLeft, "d remaining"] }), _jsxs(Span, { children: [event.stats.totalEntries, " ", labels.entries ?? "entries"] })] }), event.status === EVENT_FIELDS.STATUS_VALUES.ACTIVE && onParticipate ? (_jsx(Button, { type: "button", onClick: () => onParticipate(event), className: "w-full rounded-lg bg-primary py-2 text-sm font-medium text-white transition-colors hover:bg-primary-600", children: labels.participate ?? "Participate" })) : (_jsx(TextLink, { href: ROUTES.PUBLIC.EVENT_DETAIL(event.id), className: "inline-flex w-full items-center justify-center rounded-lg border border-zinc-300 px-3 py-2 text-sm font-medium text-zinc-700 transition-colors hover:bg-zinc-100 dark:border-slate-600 dark:text-zinc-200 dark:hover:bg-slate-800", children: labels.viewDetails ?? "View details" }))] })] }));
22
+ const detailHref = String(ROUTES.PUBLIC.EVENT_DETAIL(event.id));
23
+ return (_jsxs(Article, { className: `group flex h-full ${LAYOUT.cardHeight.event} flex-col overflow-hidden rounded-xl border border-zinc-200 bg-white shadow-sm transition-shadow hover:shadow-md dark:border-slate-700 dark:bg-slate-900 ${className}`, children: [_jsx(Link, { href: detailHref, className: "block flex-shrink-0", children: event.coverImageUrl ? (_jsx(Div, { className: "aspect-video overflow-hidden", children: _jsx(Div, { role: "img", "aria-label": safeTitle, className: "h-full w-full bg-cover bg-center transition-transform duration-300 group-hover:scale-105", style: { backgroundImage: `url(${event.coverImageUrl})` } }) })) : (_jsx(Div, { className: "aspect-video bg-gradient-to-br from-zinc-100 to-zinc-200 dark:from-slate-800 dark:to-slate-700 flex items-center justify-center", children: _jsx("span", { className: "text-5xl opacity-40", "aria-hidden": "true", children: TYPE_ICONS[event.type] }) })) }), _jsxs(Div, { className: "flex flex-1 flex-col p-4", children: [_jsxs(Div, { className: "flex items-start justify-between gap-2 mb-2", children: [_jsx(Span, { className: "text-lg", "aria-hidden": "true", children: TYPE_ICONS[event.type] }), _jsx(EventStatusBadge, { status: event.status })] }), _jsx(Link, { href: detailHref, className: "block", children: _jsx(Heading, { level: 3, className: "font-semibold text-gray-900 dark:text-zinc-100 text-base leading-snug mb-1 group-hover:text-primary transition-colors", children: safeTitle }) }), _jsx(RichText, { html: normalizeRichTextHtml(event.description ?? ""), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: `mb-3 ${THEME_CONSTANTS.utilities.textClamp3} text-sm text-zinc-600 dark:text-zinc-400` }), _jsxs(Div, { className: "mb-3 mt-auto flex items-center justify-between text-xs text-zinc-500 dark:text-zinc-500", children: [event.status === EVENT_FIELDS.STATUS_VALUES.ACTIVE &&
24
+ daysLeft > 0 && _jsxs(Span, { children: ["\u23F1 ", daysLeft, "d remaining"] }), _jsxs(Span, { children: ["\uD83D\uDC65 ", event.stats.totalEntries, " ", labels.entries ?? "entries"] })] }), event.status === EVENT_FIELDS.STATUS_VALUES.ACTIVE && onParticipate ? (_jsx(Button, { type: "button", onClick: () => onParticipate(event), className: "w-full rounded-lg bg-primary py-2 text-sm font-medium text-white transition-colors hover:bg-primary-600", children: labels.participate ?? "Participate" })) : (_jsxs(TextLink, { href: detailHref, className: "inline-flex w-full items-center justify-center gap-1.5 rounded-lg border border-zinc-300 px-3 py-2 text-sm font-medium text-zinc-700 transition-colors hover:bg-zinc-100 dark:border-slate-600 dark:text-zinc-200 dark:hover:bg-slate-800", children: [labels.viewDetails ?? "View details", " \u2192"] }))] })] }));
23
25
  }
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useTranslations } from "next-intl";
3
3
  import { FilterFacetSection } from "../../filters/FilterFacetSection";
4
4
  import { RangeFilter } from "../../filters/RangeFilter";
5
+ import { SwitchFilter } from "../../filters/SwitchFilter";
5
6
  import { Div } from "../../../ui";
6
7
  export const EVENT_FILTER_KEYS = {
7
8
  admin: ["type", "status", "dateFrom", "dateTo"],
@@ -68,5 +69,5 @@ export function EventFilters({ table, variant = "admin" }) {
68
69
  const selectedStatus = table.get("status")
69
70
  ? table.get("status").split("|").filter(Boolean)
70
71
  : [];
71
- return (_jsxs(Div, { children: [_jsx(FilterFacetSection, { title: t("type"), options: typeOptions, selected: selectedType, onChange: (vals) => table.set("type", vals.join("|")), searchable: false, defaultCollapsed: false }), _jsx(FilterFacetSection, { title: t("status"), options: statusOptions, selected: selectedStatus, onChange: (vals) => table.set("status", vals.join("|")), searchable: false, defaultCollapsed: false }), _jsx(RangeFilter, { title: t("dateRange"), type: "date", minValue: table.get("dateFrom"), maxValue: table.get("dateTo"), onMinChange: (v) => table.set("dateFrom", v), onMaxChange: (v) => table.set("dateTo", v), minPlaceholder: t("minDate"), maxPlaceholder: t("maxDate"), defaultCollapsed: true })] }));
72
+ return (_jsxs(Div, { children: [_jsx(FilterFacetSection, { title: t("type"), options: typeOptions, selected: selectedType, onChange: (vals) => table.set("type", vals.join("|")), searchable: false, defaultCollapsed: false }), _jsx(FilterFacetSection, { title: t("status"), options: statusOptions, selected: selectedStatus, onChange: (vals) => table.set("status", vals.join("|")), searchable: false, defaultCollapsed: false }), _jsx(RangeFilter, { title: t("dateRange"), type: "date", minValue: table.get("dateFrom"), maxValue: table.get("dateTo"), onMinChange: (v) => table.set("dateFrom", v), onMaxChange: (v) => table.set("dateTo", v), minPlaceholder: t("minDate"), maxPlaceholder: t("maxDate"), defaultCollapsed: true }), _jsx(SwitchFilter, { title: t("expired"), label: t("showExpiredOnly"), checked: table.get("showExpired") === "true", onChange: (v) => table.set("showExpired", v ? "true" : ""), defaultCollapsed: true })] }));
72
73
  }
@@ -1,24 +1,54 @@
1
1
  "use client";
2
- import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useState, useCallback } from "react";
4
+ import { Search, SlidersHorizontal, X } from "lucide-react";
3
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
4
6
  import { useEvents } from "../hooks/useEvents";
5
- import { Div, Input, Pagination, SlottedListingView, SortDropdown, Stack, Text, } from "../../../ui";
7
+ import { Pagination, SortDropdown } from "../../../ui";
6
8
  import { EventCard } from "./EventCard";
7
- import { EventFilters, EVENT_PUBLIC_SORT_OPTIONS, } from "./EventFilters";
9
+ import { EventFilters, EVENT_PUBLIC_SORT_OPTIONS } from "./EventFilters";
8
10
  const PAGE_SIZE = 24;
9
11
  export function EventsIndexListing({ initialData }) {
10
12
  const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: "startsAt" } });
13
+ const [searchInput, setSearchInput] = useState(table.get("q") || "");
14
+ const [filterOpen, setFilterOpen] = useState(false);
15
+ // Build client-side filter string from URL params
16
+ const typeRaw = table.get("type");
17
+ const statusRaw = table.get("status");
18
+ const dateFrom = table.get("dateFrom");
19
+ const dateTo = table.get("dateTo");
20
+ const filterParts = [];
21
+ if (typeRaw) {
22
+ const types = typeRaw.split("|").filter(Boolean);
23
+ if (types.length === 1)
24
+ filterParts.push(`type==${types[0]}`);
25
+ else if (types.length > 1)
26
+ filterParts.push(`type==${types.join("|")}`);
27
+ }
28
+ if (statusRaw) {
29
+ const statuses = statusRaw.split("|").filter(Boolean);
30
+ if (statuses.length === 1)
31
+ filterParts.push(`status==${statuses[0]}`);
32
+ else if (statuses.length > 1)
33
+ filterParts.push(`status==${statuses.join("|")}`);
34
+ }
35
+ if (dateFrom)
36
+ filterParts.push(`startsAt>=${dateFrom}`);
37
+ if (dateTo)
38
+ filterParts.push(`endsAt<=${dateTo}`);
11
39
  const params = {
40
+ q: table.get("q") || undefined,
12
41
  page: table.getNumber("page", 1),
13
42
  pageSize: table.getNumber("pageSize", PAGE_SIZE),
14
43
  sort: table.get("sort") || "startsAt",
15
- type: table.get("type") || undefined,
16
- status: table.get("status") || "published",
17
- filters: table.get("filters") || undefined,
44
+ filters: filterParts.length > 0 ? filterParts.join(",") : undefined,
18
45
  };
19
- const { events, total, totalPages, isLoading } = useEvents(params, {
20
- initialData,
21
- });
46
+ const { events, total, totalPages, isLoading } = useEvents(params, { initialData });
22
47
  const currentPage = table.getNumber("page", 1);
23
- return (_jsx(Div, { className: "min-h-screen", children: _jsx(SlottedListingView, { portal: "public", manageSearch: true, manageSort: true, inlineToolbar: true, renderSearch: (search, setSearch) => (_jsx(Input, { value: search, onChange: (e) => setSearch(e.target.value), placeholder: "Search events...", className: "max-w-sm" })), renderSort: (value, onChange) => (_jsx(SortDropdown, { value: value, onChange: onChange, options: EVENT_PUBLIC_SORT_OPTIONS })), renderFilters: () => (_jsx(EventFilters, { table: table, variant: "public" })), renderTable: () => events.length === 0 && !isLoading ? (_jsx(Stack, { align: "center", gap: "3", className: "justify-center py-24 text-center", children: _jsx(Text, { className: "text-xl font-medium text-zinc-900 dark:text-zinc-50", children: "No events found" }) })) : (_jsx(Div, { className: "grid gap-6 sm:grid-cols-2 lg:grid-cols-3", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })), renderPagination: () => totalPages > 1 ? (_jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) })) : null, total: total, isLoading: isLoading }) }));
48
+ const commitSearch = useCallback(() => {
49
+ table.set("q", searchInput.trim());
50
+ table.setPage(1);
51
+ }, [searchInput, table]);
52
+ const closeFilters = () => setFilterOpen(false);
53
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx("div", { className: "sticky top-0 z-20 border-b border-zinc-200 dark:border-slate-700 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm py-2.5 px-4", children: _jsxs("div", { className: "flex items-center gap-2.5 max-w-full", children: [_jsxs("button", { type: "button", onClick: () => setFilterOpen(true), className: "flex shrink-0 items-center gap-2 rounded-lg border border-zinc-300 dark:border-slate-600 px-3.5 py-2 text-sm font-medium text-zinc-700 dark:text-zinc-200 hover:bg-zinc-50 dark:hover:bg-slate-800 transition-colors", children: [_jsx(SlidersHorizontal, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: "Filters" })] }), _jsxs("div", { className: "flex flex-1 items-center overflow-hidden rounded-lg border border-zinc-300 dark:border-slate-600 bg-white dark:bg-slate-900", children: [_jsx("input", { type: "text", value: searchInput, onChange: (e) => setSearchInput(e.target.value), onKeyDown: (e) => e.key === "Enter" && commitSearch(), placeholder: "Search events...", className: "min-w-0 flex-1 bg-transparent px-3 py-2 text-sm text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 outline-none" }), searchInput && (_jsx("button", { type: "button", onClick: () => { setSearchInput(""); table.set("q", ""); }, className: "px-2 text-zinc-400 hover:text-zinc-600 transition-colors", "aria-label": "Clear search", children: _jsx(X, { className: "h-3.5 w-3.5" }) })), _jsx("button", { type: "button", onClick: commitSearch, className: "flex shrink-0 items-center justify-center px-3 py-2 text-zinc-400 hover:text-primary dark:hover:text-primary-400 transition-colors", "aria-label": "Search", children: _jsx(Search, { className: "h-4 w-4" }) })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5 text-sm text-zinc-500 dark:text-zinc-400", children: [_jsx("span", { className: "hidden md:inline whitespace-nowrap", children: "Sort by" }), _jsx(SortDropdown, { value: table.get("sort") || "startsAt", onChange: (v) => { table.set("sort", v); table.setPage(1); }, options: EVENT_PUBLIC_SORT_OPTIONS })] })] }) }), _jsxs("div", { className: "py-6", children: [isLoading ? (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: Array.from({ length: 6 }).map((_, i) => (_jsxs("div", { className: "rounded-xl border border-zinc-100 dark:border-slate-700 overflow-hidden animate-pulse", children: [_jsx("div", { className: "aspect-video bg-zinc-200 dark:bg-slate-700" }), _jsxs("div", { className: "p-4 space-y-2", children: [_jsx("div", { className: "h-4 bg-zinc-200 dark:bg-slate-700 rounded w-3/4" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-full" }), _jsx("div", { className: "h-3 bg-zinc-200 dark:bg-slate-700 rounded w-2/3" }), _jsx("div", { className: "h-8 bg-zinc-200 dark:bg-slate-700 rounded mt-2" })] })] }, i))) })) : events.length === 0 ? (_jsx("p", { className: "py-12 text-center text-sm text-zinc-500 dark:text-zinc-400", children: "No events found." })) : (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: events.map((event) => (_jsx(EventCard, { event: event }, event.id))) })), totalPages > 1 && (_jsx("div", { className: "mt-8 flex justify-center", children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) }))] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: closeFilters }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsxs("span", { className: "flex items-center gap-2 text-base font-semibold text-zinc-900 dark:text-zinc-100", children: [_jsx(SlidersHorizontal, { className: "h-4 w-4" }), "Filters"] }), _jsx("button", { type: "button", onClick: closeFilters, "aria-label": "Close filters", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4", children: _jsx(EventFilters, { table: table, variant: "public" }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsx("button", { type: "button", onClick: closeFilters, className: "w-full rounded-lg bg-primary py-2.5 text-sm font-semibold text-white hover:bg-primary-600 transition-colors", children: "Apply filters" }) })] })] }))] }));
24
54
  }
@@ -1 +1,6 @@
1
- export declare function EventsListPageView(): Promise<import("react/jsx-runtime").JSX.Element>;
1
+ type SearchParams = Record<string, string | string[]>;
2
+ export interface EventsListPageViewProps {
3
+ searchParams?: SearchParams;
4
+ }
5
+ export declare function EventsListPageView({ searchParams }: EventsListPageViewProps): Promise<import("react/jsx-runtime").JSX.Element>;
6
+ export {};
@@ -3,14 +3,47 @@ import { eventRepository } from "../../../repositories";
3
3
  import { AdSlot } from "../../homepage/components/AdSlot";
4
4
  import { Container, Heading, Main, Section } from "../../../ui";
5
5
  import { EventsIndexListing } from "./EventsIndexListing";
6
- export async function EventsListPageView() {
6
+ function sp(params, key) {
7
+ const v = params[key];
8
+ return Array.isArray(v) ? v[0] ?? "" : v ?? "";
9
+ }
10
+ function buildEventFilters(params) {
11
+ // Public page defaults to published status; allow overriding to active/ended
12
+ const statusRaw = sp(params, "status");
13
+ const parts = [];
14
+ if (statusRaw) {
15
+ const values = statusRaw.split("|").filter(Boolean);
16
+ if (values.length === 1)
17
+ parts.push(`status==${values[0]}`);
18
+ else if (values.length > 1)
19
+ parts.push(`status==${values.join("|")}`);
20
+ }
21
+ else {
22
+ parts.push("status==published");
23
+ }
24
+ const type = sp(params, "type");
25
+ if (type) {
26
+ const values = type.split("|").filter(Boolean);
27
+ if (values.length === 1)
28
+ parts.push(`type==${values[0]}`);
29
+ else if (values.length > 1)
30
+ parts.push(`type==${values.join("|")}`);
31
+ }
32
+ const dateFrom = sp(params, "dateFrom");
33
+ const dateTo = sp(params, "dateTo");
34
+ if (dateFrom)
35
+ parts.push(`startsAt>=${dateFrom}`);
36
+ if (dateTo)
37
+ parts.push(`endsAt<=${dateTo}`);
38
+ return parts.join(",");
39
+ }
40
+ export async function EventsListPageView({ searchParams = {} }) {
41
+ const sort = sp(searchParams, "sort") || "startsAt";
42
+ const page = Number(sp(searchParams, "page")) || 1;
43
+ const pageSize = Number(sp(searchParams, "pageSize")) || 24;
44
+ const filters = buildEventFilters(searchParams);
7
45
  const result = await eventRepository
8
- .list({
9
- filters: "status==published",
10
- sorts: "startsAt",
11
- page: 1,
12
- pageSize: 24,
13
- })
46
+ .list({ filters, sorts: sort, page, pageSize })
14
47
  .catch(() => null);
15
48
  return (_jsx(Main, { children: _jsx(Section, { className: "py-10", children: _jsxs(Container, { size: "xl", children: [_jsx(Heading, { level: 1, className: "mb-8 text-3xl font-semibold text-zinc-900 dark:text-zinc-50", children: "Events" }), _jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-6" }), _jsx(EventsIndexListing, { initialData: result }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] }) }) }));
16
49
  }
@@ -13,6 +13,8 @@ export { EventLeaderboard } from "./EventLeaderboard";
13
13
  export type { EventLeaderboardProps } from "./EventLeaderboard";
14
14
  export { AdminEventsView } from "./AdminEventsView";
15
15
  export type { AdminEventsViewProps } from "./AdminEventsView";
16
+ export { AdminEventEditorView } from "./AdminEventEditorView";
17
+ export type { AdminEventEditorViewProps } from "./AdminEventEditorView";
16
18
  export { AdminEventEntriesView } from "./AdminEventEntriesView";
17
19
  export type { AdminEventEntriesViewProps } from "./AdminEventEntriesView";
18
20
  export { EventFormDrawer } from "./EventFormDrawer";
@@ -7,6 +7,7 @@ export { EventDetailView } from "./EventDetailView";
7
7
  export { EventParticipateView } from "./EventParticipateView";
8
8
  export { EventLeaderboard } from "./EventLeaderboard";
9
9
  export { AdminEventsView } from "./AdminEventsView";
10
+ export { AdminEventEditorView } from "./AdminEventEditorView";
10
11
  export { AdminEventEntriesView } from "./AdminEventEntriesView";
11
12
  export { EventFormDrawer } from "./EventFormDrawer";
12
13
  export { EventBanner } from "./EventBanner";
@@ -3,6 +3,8 @@ import { apiClient } from "../../../http";
3
3
  import { EVENT_ENDPOINTS } from "../../../constants/api-endpoints";
4
4
  export function useEvents(params = {}, opts) {
5
5
  const sp = new URLSearchParams();
6
+ if (params.q)
7
+ sp.set("q", params.q);
6
8
  if (params.status)
7
9
  sp.set("status", params.status);
8
10
  if (params.type)
@@ -124,6 +124,7 @@ export interface CreateEventEntryInput {
124
124
  formResponses?: Record<string, unknown>;
125
125
  }
126
126
  export interface EventListParams {
127
+ q?: string;
127
128
  status?: EventStatus;
128
129
  type?: EventType;
129
130
  page?: number;
@@ -8,5 +8,5 @@ import { ROUTES } from "../../../next";
8
8
  export function BlogArticlesSection({ title = "From Our Blog", description, viewMoreHref, viewMoreLabel = "View all posts →", className = "", }) {
9
9
  const { data, isLoading } = useBlogArticles();
10
10
  const items = data?.posts ?? [];
11
- return (_jsx(SectionCarousel, { title: title, description: description, viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 4, perView: THEME_CONSTANTS.carousel.perView.cards, gap: 16, keyExtractor: (post) => post.id, renderItem: (post) => (_jsx(BlogFeaturedCard, { post: post, href: ROUTES.BLOG.ARTICLE(post.slug) })), className: className }));
11
+ return (_jsx(SectionCarousel, { title: title, description: description, pillLabel: "From Our Blog", headingVariant: "editorial", viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 4, perView: THEME_CONSTANTS.carousel.perView.standard, gap: 16, keyExtractor: (post) => post.id, renderItem: (post) => (_jsx(BlogFeaturedCard, { post: post, href: ROUTES.BLOG.ARTICLE(post.slug) })), className: className }));
12
12
  }
@@ -6,5 +6,5 @@ import { useHomepageEvents } from "../hooks/useHomepageEvents";
6
6
  import { EventCard } from "../../events/components/EventCard";
7
7
  export function EventsSection({ title = "Events & Offers", description, viewMoreHref, viewMoreLabel = "View all events →", limit = 6, className = "", }) {
8
8
  const { data: items = [], isLoading } = useHomepageEvents(limit);
9
- return (_jsx(SectionCarousel, { title: title, description: description, viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 3, perView: THEME_CONSTANTS.carousel.perView.events, gap: 16, keyExtractor: (event) => event.id, renderItem: (event) => (_jsx(EventCard, { event: event })), className: className }));
9
+ return (_jsx(SectionCarousel, { title: title, description: description, pillLabel: "Events & Offers", headingVariant: "editorial", viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 3, perView: THEME_CONSTANTS.carousel.perView.events, gap: 16, keyExtractor: (event) => event.id, renderItem: (event) => (_jsx(EventCard, { event: event })), className: className }));
10
10
  }
@@ -6,5 +6,5 @@ import { useFeaturedAuctions } from "../hooks/useFeaturedAuctions";
6
6
  import { MarketplaceAuctionCard } from "../../auctions/components/MarketplaceAuctionCard";
7
7
  export function FeaturedAuctionsSection({ title = "Live Auctions", description, viewMoreHref, viewMoreLabel = "View all auctions →", className = "", }) {
8
8
  const { data: items = [], isLoading } = useFeaturedAuctions();
9
- return (_jsx(SectionCarousel, { title: title, description: description, viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 4, perView: THEME_CONSTANTS.carousel.perView.compact, gap: 16, keyExtractor: (product) => product.id, renderItem: (product) => (_jsx(MarketplaceAuctionCard, { product: product })), className: className }));
9
+ return (_jsx(SectionCarousel, { title: title, description: description, pillLabel: "Live Auctions", headingVariant: "editorial", viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 4, perView: THEME_CONSTANTS.carousel.perView.standard, gap: 16, keyExtractor: (product) => product.id, renderItem: (product) => (_jsx(MarketplaceAuctionCard, { product: product })), className: className }));
10
10
  }
@@ -6,5 +6,5 @@ import { useFeaturedPreOrders } from "../hooks/useFeaturedPreOrders";
6
6
  import { MarketplacePreorderCard } from "../../pre-orders/components/MarketplacePreorderCard";
7
7
  export function FeaturedPreOrdersSection({ title = "Reserve Before It Ships", description, viewMoreHref, viewMoreLabel = "View all pre-orders →", className = "", }) {
8
8
  const { data: items = [], isLoading } = useFeaturedPreOrders();
9
- return (_jsx(SectionCarousel, { title: title, description: description, viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 4, perView: THEME_CONSTANTS.carousel.perView.compact, gap: 16, keyExtractor: (product) => product.id, renderItem: (product) => (_jsx(MarketplacePreorderCard, { product: product })), className: className }));
9
+ return (_jsx(SectionCarousel, { title: title, description: description, pillLabel: "Pre-Order Incoming", headingVariant: "editorial", viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 4, perView: THEME_CONSTANTS.carousel.perView.standard, gap: 16, keyExtractor: (product) => product.id, renderItem: (product) => (_jsx(MarketplacePreorderCard, { product: product })), className: className }));
10
10
  }
@@ -7,5 +7,5 @@ import { ROUTES } from "../../../next";
7
7
  export function FeaturedProductsSection({ title = "Featured Products", description, viewMoreHref, viewMoreLabel = "View all products →", className = "", }) {
8
8
  const { data, isLoading } = useFeaturedProducts();
9
9
  const items = data?.items ?? [];
10
- return (_jsx(SectionCarousel, { title: title, description: description, viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 4, perView: { base: 1 }, gap: 16, rows: 2, keyExtractor: (product) => product.id, renderItem: (product) => (_jsx(InteractiveProductCard, { product: product, href: ROUTES.PUBLIC.PRODUCT_DETAIL(product.slug ?? product.id) })), className: className }));
10
+ return (_jsx(SectionCarousel, { title: title, description: description, pillLabel: "Featured Products", headingVariant: "editorial", viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 4, gap: 16, keyExtractor: (product) => product.id, renderItem: (product) => (_jsx(InteractiveProductCard, { product: product, href: ROUTES.PUBLIC.PRODUCT_DETAIL(product.slug ?? product.id) })), className: className }));
11
11
  }
@@ -7,5 +7,5 @@ import { InteractiveStoreCard } from "../../stores/components/InteractiveStoreCa
7
7
  import { ROUTES } from "../../../next";
8
8
  export function FeaturedStoresSection({ title = "Featured Stores", description, viewMoreHref, viewMoreLabel = "View all stores →", limit = 8, className = "", }) {
9
9
  const { data: items = [], isLoading } = useFeaturedStores(limit);
10
- return (_jsx(SectionCarousel, { title: title, description: description, viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 4, perView: THEME_CONSTANTS.carousel.perView.cards, gap: 16, keyExtractor: (store) => store.id, renderItem: (store) => (_jsx(InteractiveStoreCard, { store: store, href: ROUTES.PUBLIC.STORE_DETAIL(store.storeSlug) })), className: className }));
10
+ return (_jsx(SectionCarousel, { title: title, description: description, pillLabel: "Top Stores", headingVariant: "editorial", viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 4, perView: THEME_CONSTANTS.carousel.perView.standard, gap: 16, keyExtractor: (store) => store.id, renderItem: (store) => (_jsx(InteractiveStoreCard, { store: store, href: ROUTES.PUBLIC.STORE_DETAIL(store.storeSlug) })), className: className }));
11
11
  }
@@ -146,5 +146,5 @@ export function HeroCarousel({ initialSlides, push } = {}) {
146
146
  }
147
147
  }, children: _jsx(Span, { className: "text-lg md:text-2xl", children: card.buttons[0].text }) }))] }, card.id))) }))] }, slide.id))) }) }), slides.length > 1 && (_jsx(Div, { className: "absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-2 z-10", children: slides.map((_, index) => (_jsx(Button, { variant: "ghost", className: `relative overflow-hidden rounded-full transition-all duration-500 p-0 !min-h-0 ${index === currentSlide
148
148
  ? THEME_CONSTANTS.carousel.dotActive
149
- : `${THEME_CONSTANTS.carousel.dotInactive} hover:bg-white/75`}`, onClick: () => goToSlide(index), "aria-label": `Go to slide ${index + 1}`, children: index === currentSlide && (_jsx(Span, { className: "absolute inset-y-0 left-0 bg-black/20 rounded-full animate-[progress-fill_4s_linear_forwards]", "aria-hidden": "true" })) }, index))) })), _jsx(Div, { className: "absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-white dark:from-slate-950 to-transparent pointer-events-none z-[5]", "aria-hidden": "true" }), slides.length > 1 && (_jsxs(Div, { className: "absolute bottom-4 right-4 z-20 flex gap-2", children: [_jsx(Button, { variant: "ghost", className: `p-0 ${THEME_CONSTANTS.carousel.arrow}`, onClick: goPrev, "aria-label": "Previous slide", children: _jsx("svg", { className: "w-7 h-7", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M15 19l-7-7 7-7" }) }) }), _jsx(Button, { variant: "ghost", className: `p-0 ${THEME_CONSTANTS.carousel.arrow}`, onClick: goNext, "aria-label": "Next slide", children: _jsx("svg", { className: "w-7 h-7", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M9 5l7 7-7 7" }) }) })] }))] }));
149
+ : `${THEME_CONSTANTS.carousel.dotInactive} hover:bg-white/75`}`, onClick: () => goToSlide(index), "aria-label": `Go to slide ${index + 1}`, children: index === currentSlide && (_jsx(Span, { className: "absolute inset-y-0 left-0 bg-black/20 rounded-full animate-[progress-fill_4s_linear_forwards]", "aria-hidden": "true" })) }, index))) })), slides.length > 1 && (_jsxs(Div, { className: "absolute bottom-4 right-4 z-20 flex gap-2", children: [_jsx(Button, { variant: "ghost", className: `p-0 ${THEME_CONSTANTS.carousel.arrow}`, onClick: goPrev, "aria-label": "Previous slide", children: _jsx("svg", { className: "w-7 h-7", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M15 19l-7-7 7-7" }) }) }), _jsx(Button, { variant: "ghost", className: `p-0 ${THEME_CONSTANTS.carousel.arrow}`, onClick: goNext, "aria-label": "Next slide", children: _jsx("svg", { className: "w-7 h-7", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M9 5l7 7-7 7" }) }) })] }))] }));
150
150
  }