@fayz-ai/storefront 0.8.3 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import React7, { createContext, useState, useRef, useEffect, useMemo, useContext
8
8
  import { hashRouterAdapter, normalizePostalCode, lookupPostalCode, registerScaffold, registerBlock, formatPostalCode, renderBlocks, defineApp } from '@fayz-ai/core';
9
9
  export { getSupabaseClientOptional, renderApp } from '@fayz-ai/core';
10
10
  import * as LucideIcons from 'lucide-react';
11
- import { ChevronLeft, ChevronRight, ShoppingBag, X, Trash2, Phone, Mail, Search, User, UserCircle, Package, CreditCard, LogOut, Truck, RefreshCcw, ShieldCheck, Lock, Minus, Plus, MapPin, Info, AlertCircle, Check, Send, MessageCircle, PackageCheck, QrCode, XCircle, RotateCcw, Clock } from 'lucide-react';
11
+ import { ChevronLeft, ChevronRight, ShoppingBag, X, Trash2, Phone, Mail, Search, User, UserCircle, Package, CreditCard, LogOut, Menu, Truck, RefreshCcw, ShieldCheck, Lock, Minus, Plus, MapPin, Info, AlertCircle, Check, Send, MessageCircle, PackageCheck, QrCode, XCircle, RotateCcw, Clock } from 'lucide-react';
12
12
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
13
13
  import { validateDiscount } from '@fayz-ai/shop';
14
14
 
@@ -909,7 +909,7 @@ function SearchInput({ className, iconOnly = false }) {
909
909
  )
910
910
  ] });
911
911
  }
912
- function HeaderActions() {
912
+ function HeaderActions({ onMenuClick }) {
913
913
  const config = useStorefrontConfig();
914
914
  const count = useCartStore(selectCount);
915
915
  const openDrawer = useCartStore((s) => s.openDrawer);
@@ -1007,6 +1007,16 @@ function HeaderActions() {
1007
1007
  )
1008
1008
  ]
1009
1009
  }
1010
+ ),
1011
+ onMenuClick && /* @__PURE__ */ jsx(
1012
+ "button",
1013
+ {
1014
+ type: "button",
1015
+ "aria-label": "Abrir menu",
1016
+ onClick: onMenuClick,
1017
+ className: "relative rounded-full p-2.5 transition-opacity hover:opacity-70 md:hidden",
1018
+ children: /* @__PURE__ */ jsx(Menu, { className: "h-5 w-5" })
1019
+ }
1010
1020
  )
1011
1021
  ] });
1012
1022
  }
@@ -1047,12 +1057,94 @@ function NavLinks({ className }) {
1047
1057
  ))
1048
1058
  ] });
1049
1059
  }
1060
+ function MobileMenuDrawer({ open, onClose }) {
1061
+ const config = useStorefrontConfig();
1062
+ const { categories } = useCategories();
1063
+ const setCategoryId = useCatalogStore((s) => s.setCategoryId);
1064
+ const showCategories = config.theme?.header?.showCategories !== false;
1065
+ const goCategory = (categoryId) => {
1066
+ useCatalogStore.getState().reset();
1067
+ setCategoryId(categoryId);
1068
+ navigateTo(config.catalogPath);
1069
+ onClose();
1070
+ };
1071
+ React7.useEffect(() => {
1072
+ if (!open) return;
1073
+ const onKey = (e) => {
1074
+ if (e.key === "Escape") onClose();
1075
+ };
1076
+ document.addEventListener("keydown", onKey);
1077
+ return () => document.removeEventListener("keydown", onKey);
1078
+ }, [open, onClose]);
1079
+ if (!open) return null;
1080
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 md:hidden", children: [
1081
+ /* @__PURE__ */ jsx(
1082
+ "div",
1083
+ {
1084
+ className: "absolute inset-0 animate-fade-in bg-black/40",
1085
+ "aria-hidden": true,
1086
+ onClick: onClose
1087
+ }
1088
+ ),
1089
+ /* @__PURE__ */ jsxs(
1090
+ "div",
1091
+ {
1092
+ "data-testid": "mobile-menu-drawer",
1093
+ role: "dialog",
1094
+ "aria-label": "Menu Principal",
1095
+ className: "absolute right-0 top-0 flex h-full w-full max-w-[280px] animate-slide-in-from-right flex-col bg-background shadow-2xl",
1096
+ children: [
1097
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b px-5 py-4", children: [
1098
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: "Menu" }),
1099
+ /* @__PURE__ */ jsx(
1100
+ "button",
1101
+ {
1102
+ type: "button",
1103
+ "aria-label": "Fechar menu",
1104
+ onClick: onClose,
1105
+ className: "rounded-full p-1.5 hover:bg-muted",
1106
+ children: /* @__PURE__ */ jsx(X, { className: "h-5 w-5" })
1107
+ }
1108
+ )
1109
+ ] }),
1110
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto p-5", children: /* @__PURE__ */ jsxs("nav", { className: "flex flex-col gap-4", children: [
1111
+ config.nav.map((link) => /* @__PURE__ */ jsx(
1112
+ Link,
1113
+ {
1114
+ to: link.to,
1115
+ onClick: onClose,
1116
+ className: "text-base font-semibold transition-opacity hover:opacity-70",
1117
+ children: link.label
1118
+ },
1119
+ link.to
1120
+ )),
1121
+ showCategories && categories.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1122
+ /* @__PURE__ */ jsx("div", { className: "my-2 border-t" }),
1123
+ /* @__PURE__ */ jsx("div", { className: "mb-2 text-xs font-bold uppercase tracking-wider text-muted-foreground", children: "Categorias" }),
1124
+ categories.map((c) => /* @__PURE__ */ jsx(
1125
+ "button",
1126
+ {
1127
+ type: "button",
1128
+ onClick: () => goCategory(c.id),
1129
+ className: "text-left text-sm font-medium transition-opacity hover:opacity-80",
1130
+ children: c.name
1131
+ },
1132
+ c.id
1133
+ ))
1134
+ ] })
1135
+ ] }) })
1136
+ ]
1137
+ }
1138
+ )
1139
+ ] });
1140
+ }
1050
1141
  function StorefrontHeader() {
1051
1142
  const config = useStorefrontConfig();
1052
1143
  const variant = config.theme?.header?.variant ?? "classic";
1053
1144
  const scrolled = useScrolled();
1054
1145
  const showSearch = config.theme?.header?.showSearch !== false;
1055
1146
  const iconSearch = config.theme?.header?.searchStyle === "icon";
1147
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
1056
1148
  const logo = /* @__PURE__ */ jsx(Link, { to: "/", className: "sf-heading shrink-0 text-xl font-bold tracking-tight", children: config.logo ?? config.name });
1057
1149
  return /* @__PURE__ */ jsxs(
1058
1150
  "header",
@@ -1093,14 +1185,20 @@ function StorefrontHeader() {
1093
1185
  ] })
1094
1186
  ] })
1095
1187
  ) : (
1096
- // classic: logo left, nav, then a right-aligned search + actions cluster
1097
- /* @__PURE__ */ jsxs("div", { className: "mx-auto flex h-16 max-w-7xl items-center gap-6 px-4 sm:px-6", children: [
1098
- logo,
1099
- /* @__PURE__ */ jsx(NavLinks, { className: "hidden md:flex" }),
1100
- /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2 sm:gap-3", children: [
1101
- showSearch && /* @__PURE__ */ jsx(SearchInput, { iconOnly: iconSearch, className: iconSearch ? "" : "hidden w-full max-w-sm sm:block" }),
1102
- /* @__PURE__ */ jsx(HeaderActions, {})
1103
- ] })
1188
+ // classic: logo left, nav, then a right-aligned search + actions cluster.
1189
+ // NavLinks is hidden below md in the primary row (no room for it there)
1190
+ // below md a hamburger opens MobileMenuDrawer instead, otherwise mobile
1191
+ // has no way to reach nav/category links at all.
1192
+ /* @__PURE__ */ jsxs(Fragment, { children: [
1193
+ /* @__PURE__ */ jsxs("div", { className: "mx-auto flex h-16 max-w-7xl items-center gap-6 px-4 sm:px-6", children: [
1194
+ logo,
1195
+ /* @__PURE__ */ jsx(NavLinks, { className: "hidden md:flex" }),
1196
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2 sm:gap-3", children: [
1197
+ showSearch && /* @__PURE__ */ jsx(SearchInput, { iconOnly: iconSearch, className: iconSearch ? "" : "hidden w-full max-w-sm sm:block" }),
1198
+ /* @__PURE__ */ jsx(HeaderActions, { onMenuClick: () => setMobileMenuOpen(true) })
1199
+ ] })
1200
+ ] }),
1201
+ /* @__PURE__ */ jsx(MobileMenuDrawer, { open: mobileMenuOpen, onClose: () => setMobileMenuOpen(false) })
1104
1202
  ] })
1105
1203
  )
1106
1204
  ]
@@ -3704,7 +3802,7 @@ function CheckoutPage() {
3704
3802
  ];
3705
3803
  const minDuration = sleep(stepMs * 2);
3706
3804
  try {
3707
- const { order } = await placeStorefrontOrder({
3805
+ const { order, customerId } = await placeStorefrontOrder({
3708
3806
  config,
3709
3807
  cart,
3710
3808
  session,
@@ -3727,6 +3825,7 @@ function CheckoutPage() {
3727
3825
  // declare it settled. The order is now born `pending` and only the
3728
3826
  // merchant (or a PSP webhook) can confirm the money arrived.
3729
3827
  });
3828
+ if (customerId) session.setSession({ customerId, email: form.email, name: form.name });
3730
3829
  await minDuration;
3731
3830
  cart.clear();
3732
3831
  navigateTo(`/order/${order.id}`);
@@ -4830,6 +4929,10 @@ function storefrontDiscountToSeed(discount) {
4830
4929
  value: discount.percent,
4831
4930
  usageLimit: null,
4832
4931
  oncePerCustomer: false,
4932
+ minSubtotal: null,
4933
+ appliesTo: "all",
4934
+ productIds: [],
4935
+ categoryIds: [],
4833
4936
  startsAt: ts,
4834
4937
  endsAt: null,
4835
4938
  status: "active",