@aurora-studio/starter-core 0.1.4 → 0.1.7
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/components/AddToCartButton.js +1 -1
- package/dist/components/AddToCartFly.js +1 -1
- package/dist/components/AuthProvider.js +1 -1
- package/dist/components/CartLink.js +1 -1
- package/dist/components/CartProvider.js +1 -1
- package/dist/components/CatalogueEmptyState.js +1 -1
- package/dist/components/CatalogueFilters.js +1 -1
- package/dist/components/CheckoutButton.js +1 -1
- package/dist/components/ConditionalHolmesScript.js +1 -1
- package/dist/components/FloatingLabelInput.js +1 -1
- package/dist/components/HolmesHomeRefresher.js +1 -1
- package/dist/components/HolmesProductViewTracker.js +1 -1
- package/dist/components/HolmesSprinkleIcon.js +1 -1
- package/dist/components/HolmesTidbits.js +1 -1
- package/dist/components/ProductCardSkeleton.js +1 -1
- package/dist/components/ProductDetailTabs.js +1 -1
- package/dist/components/ProductImage.js +1 -1
- package/dist/components/ProductImageGallery.js +1 -1
- package/dist/components/SearchDropdown.js +1 -1
- package/dist/components/SmartCartPanel.js +1 -1
- package/dist/components/SortDropdown.js +1 -1
- package/dist/components/StoreConfigContext.js +1 -1
- package/dist/components/StoreContext.js +1 -1
- package/dist/components/StoreContextBar.js +1 -1
- package/dist/lib/aurora.js +1 -1
- package/dist/lib/format-price.js +1 -1
- package/dist/lib/holmes-events.js +1 -1
- package/dist/lib/image-url.js +1 -1
- package/dist/lib/utils.js +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useState}from"react";import{Check}from"lucide-react";import{useCart}from"./CartProvider";import{useAddToCartFly}from"./AddToCartFly";export function AddToCartButton({recordId:recordId,tableSlug:tableSlug,name:name,unitAmount:unitAmount,sellByWeight:sellByWeight,unit:unit="kg",imageUrl:imageUrl,className:className}){const{items:items,addItem:addItem}=useCart();const flyCtx=useAddToCartFly();const[weight,setWeight]=useState("1");const cartId=`${tableSlug}:${recordId}`;const inCart=items.some(i=>i.id===cartId);if(sellByWeight){const handleAdd=e=>{const w=parseFloat(weight);if(!Number.isFinite(w)||w<=0)return;const rect=e.currentTarget.getBoundingClientRect();flyCtx?.triggerFly(imageUrl??null,rect);addItem({recordId:recordId,tableSlug:tableSlug,name:name,unitAmount:unitAmount,quantity:w,sellByWeight:true,unit:unit,imageUrl:imageUrl})};return _jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[_jsxs("div",{className:"flex items-center gap-2",children:[_jsx("input",{type:"number",step:"0.1",min:"0.1",value:weight,onChange:e=>setWeight(e.target.value),className:"w-20 px-2 py-2 rounded-lg border border-aurora-border bg-aurora-surface text-aurora-text"}),_jsx("span",{className:"text-aurora-muted",children:unit})]}),_jsx("button",{type:"button",onClick:handleAdd,disabled:inCart,className:inCart?`inline-flex items-center gap-1.5 text-aurora-primary font-medium cursor-default ${className??""}`.trim():className??"h-12 px-4 rounded-xl bg-aurora-primary text-white font-semibold hover:bg-aurora-primary-dark transition-colors",children:inCart?_jsxs(_Fragment,{children:[_jsx(Check,{className:"w-4 h-4 shrink-0","aria-hidden":true}),"Added"]}):"Add to cart"})]})}const handleAdd=e=>{const rect=e.currentTarget.getBoundingClientRect();flyCtx?.triggerFly(imageUrl??null,rect);addItem({recordId:recordId,tableSlug:tableSlug,name:name,unitAmount:unitAmount,imageUrl:imageUrl})};const baseClass=className??"h-12 px-4 rounded-xl bg-aurora-primary text-white font-semibold hover:bg-aurora-primary-dark transition-colors";return _jsx("button",{type:"button",onClick:handleAdd,disabled:inCart,className:inCart?`inline-flex items-center gap-1.5 text-aurora-primary font-medium cursor-default ${className??""}`.trim():baseClass,children:inCart?_jsxs(_Fragment,{children:[_jsx(Check,{className:"w-4 h-4 shrink-0","aria-hidden":true}),"Added"]}):"Add to cart"})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{createContext,useContext,useCallback,useState,useRef,useEffect}from"react";import{createPortal}from"react-dom";const AddToCartFlyContext=createContext(null);export function useAddToCartFly(){const ctx=useContext(AddToCartFlyContext);return ctx}export function AddToCartFlyProvider({children:children}){const[fly,setFly]=useState(null);const cartRef=useRef(null);const setCartRef=useCallback(el=>{cartRef.current=el},[]);const triggerFly=useCallback((imageUrl,fromRect)=>{const toRect=cartRef.current?.getBoundingClientRect()??new DOMRect(0,0,0,0);setFly({imageUrl:imageUrl,fromRect:fromRect,toRect:toRect,key:Date.now()})},[]);useEffect(()=>{if(!fly)return;const t=setTimeout(()=>setFly(null),500);return()=>clearTimeout(t)},[fly]);return _jsxs(AddToCartFlyContext.Provider,{value:{triggerFly:triggerFly,setCartRef:setCartRef},children:[children,fly&&typeof window!=="undefined"&&createPortal(_jsx("div",{className:"add-to-cart-fly fixed inset-0 pointer-events-none z-[99999]","aria-hidden":true,children:_jsx("div",{className:"add-to-cart-fly-img absolute w-12 h-12 rounded-xl overflow-hidden bg-aurora-surface border-2 border-aurora-primary shadow-lg",style:{["--fly-from-x"]:`${(fly.fromRect?.left??0)+(fly.fromRect?.width??0)/2-24}px`,["--fly-from-y"]:`${(fly.fromRect?.top??0)+(fly.fromRect?.height??0)/2-24}px`,["--fly-to-x"]:`${(fly.toRect?.left??0)+(fly.toRect?.width??0)/2-24}px`,["--fly-to-y"]:`${(fly.toRect?.top??0)+(fly.toRect?.height??0)/2-24}px`,animation:"add-to-cart-fly 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards"},children:fly.imageUrl?_jsx("img",{src:fly.imageUrl,alt:"",className:"w-full h-full object-cover"}):_jsx("div",{className:"w-full h-full flex items-center justify-center text-aurora-primary text-lg",children:"+"})})},fly.key),document.body)]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx}from"react/jsx-runtime";import{createContext,useCallback,useContext,useEffect,useState}from"react";const AUTH_TOKEN_KEY="aurora_app_token";const AuthContext=createContext(null);export function AuthProvider({children:children}){const[state,setState]=useState({user:null,token:null,loading:true});const fetchSession=useCallback(async()=>{if(typeof window==="undefined")return;const token=localStorage.getItem(AUTH_TOKEN_KEY);if(!token){setState(s=>({...s,user:null,token:null,loading:false}));return}try{const res=await fetch("/api/auth/session",{headers:{Authorization:`Bearer ${token}`}});if(res.ok){const data=await res.json();setState(s=>({...s,user:data.user,token:token,loading:false}))}else{localStorage.removeItem(AUTH_TOKEN_KEY);setState(s=>({...s,user:null,token:null,loading:false}))}}catch{localStorage.removeItem(AUTH_TOKEN_KEY);setState(s=>({...s,user:null,token:null,loading:false}))}},[]);useEffect(()=>{fetchSession()},[fetchSession]);const setSession=useCallback((token,user)=>{if(typeof window!=="undefined"){localStorage.setItem(AUTH_TOKEN_KEY,token)}setState(s=>({...s,user:user,token:token,loading:false}))},[]);const signOut=useCallback(async()=>{const token=state.token??(typeof window!=="undefined"?localStorage.getItem(AUTH_TOKEN_KEY):null);if(token){try{await fetch("/api/auth/signout",{method:"POST",headers:{Authorization:`Bearer ${token}`}})}catch{}}if(typeof window!=="undefined"){localStorage.removeItem(AUTH_TOKEN_KEY)}setState(s=>({...s,user:null,token:null}))},[state.token]);const value={...state,setSession:setSession,signOut:signOut,fetchSession:fetchSession};return _jsx(AuthContext.Provider,{value:value,children:children})}export function useAuth(){const ctx=useContext(AuthContext);if(!ctx){throw new Error("useAuth must be used within AuthProvider")}return ctx}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import Link from"next/link";import{ShoppingCart}from"lucide-react";import{useCart}from"./CartProvider";import{useAddToCartFly}from"./AddToCartFly";import{formatPrice}from"../lib/format-price";import{useState,useRef,useEffect}from"react";export function CartLink(){const{items:items,total:total}=useCart();const flyCtx=useAddToCartFly();const[open,setOpen]=useState(false);const ref=useRef(null);const linkRef=useRef(null);const count=items.reduce((sum,i)=>sum+i.quantity,0);useEffect(()=>{flyCtx?.setCartRef(linkRef.current);return()=>flyCtx?.setCartRef(null)},[flyCtx]);useEffect(()=>{function handleClickOutside(e){if(ref.current&&!ref.current.contains(e.target)){setOpen(false)}}document.addEventListener("mousedown",handleClickOutside);return()=>document.removeEventListener("mousedown",handleClickOutside)},[]);return _jsxs("div",{ref:ref,className:"relative",onMouseEnter:()=>setOpen(true),onMouseLeave:()=>setOpen(false),children:[_jsxs(Link,{ref:linkRef,href:"/cart",className:"flex items-center gap-2 text-sm text-aurora-muted hover:text-aurora-text transition-colors font-medium",children:[_jsx(ShoppingCart,{className:"w-5 h-5 shrink-0"}),_jsx("span",{children:"Cart"}),count>0&&_jsx("span",{className:"inline-flex items-center justify-center min-w-[1.25rem] h-5 px-2 rounded-full bg-aurora-primary text-white text-xs font-semibold cart-badge",children:count},count)]}),open&&count>0&&_jsx("div",{className:"absolute top-full right-0 mt-1 pt-1 z-[200]",children:_jsxs("div",{className:"rounded-xl bg-aurora-surface border border-aurora-border shadow-xl w-80 max-h-96 overflow-hidden",children:[_jsxs("div",{className:"p-4 border-b border-aurora-border",children:[_jsxs("p",{className:"font-semibold text-sm",children:[count," ",count===1?"item":"items"]}),_jsx("p",{className:"text-lg font-bold text-aurora-primary mt-0.5",children:formatPrice(total)})]}),_jsxs("div",{className:"max-h-48 overflow-y-auto",children:[items.slice(0,5).map(item=>_jsxs("div",{className:"flex gap-3 p-3 border-b border-aurora-border last:border-0",children:[_jsx("div",{className:"w-12 h-12 rounded-lg bg-aurora-surface-hover shrink-0 overflow-hidden",children:item.imageUrl?_jsx("img",{src:item.imageUrl,alt:"",className:"w-full h-full object-cover"}):_jsx("div",{className:"w-full h-full flex items-center justify-center text-aurora-muted text-lg",children:"-"})}),_jsxs("div",{className:"flex-1 min-w-0",children:[_jsx("p",{className:"text-sm font-medium truncate",children:item.name}),_jsxs("p",{className:"text-xs text-aurora-muted",children:[formatPrice(item.unitAmount)," × ",item.quantity,item.sellByWeight?` ${item.unit||"kg"}`:""]})]})]},item.id)),items.length>5&&_jsxs("p",{className:"text-xs text-aurora-muted p-3 text-center",children:["+",items.length-5," more"]})]}),_jsx("div",{className:"p-4",children:_jsx(Link,{href:"/cart",onClick:()=>setOpen(false),className:"block w-full py-3 rounded-xl bg-aurora-primary text-white text-center font-semibold hover:bg-aurora-primary-dark transition-colors",children:"View cart · Checkout"})})]})})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx}from"react/jsx-runtime";import{createContext,useContext,useCallback,useState,useEffect,useRef}from"react";import{holmesCartUpdate}from"../lib/holmes-events";const CART_KEY="aurora-cart";function loadCart(){if(typeof window==="undefined")return[];try{const stored=localStorage.getItem(CART_KEY);return stored?JSON.parse(stored):[]}catch{return[]}}function saveCart(items){if(typeof window==="undefined")return;localStorage.setItem(CART_KEY,JSON.stringify(items))}const CartContext=createContext(null);export function CartProvider({children:children}){const[items,setItems]=useState([]);const[mounted,setMounted]=useState(false);const itemsRef=useRef(items);const bootstrapFiredRef=useRef(false);itemsRef.current=items;useEffect(()=>{setItems(loadCart());setMounted(true)},[]);useEffect(()=>{if(mounted)saveCart(items)},[items,mounted]);useEffect(()=>{if(!mounted)return;const count=items.reduce((s,i)=>s+i.quantity,0);const holmesItems=items.map(i=>({id:i.recordId,name:i.name,price:i.unitAmount}));holmesCartUpdate(count,holmesItems)},[items,mounted]);useEffect(()=>{if(!mounted)return;const fireBootstrap=()=>{if(bootstrapFiredRef.current)return;bootstrapFiredRef.current=true;const currentItems=itemsRef.current;const count=currentItems.reduce((s,i)=>s+i.quantity,0);const holmesItems=currentItems.map(i=>({id:i.recordId,name:i.name,price:i.unitAmount}));holmesCartUpdate(count,holmesItems,true)};const onReady=()=>fireBootstrap();if(window.holmes?.getSessionId&&!bootstrapFiredRef.current){fireBootstrap()}document.addEventListener("holmes:ready",onReady);return()=>document.removeEventListener("holmes:ready",onReady)},[mounted]);const addItem=useCallback(item=>{const qty=item.quantity??1;const cartId=`${item.tableSlug}:${item.recordId}`;const isNew=!itemsRef.current.some(i=>i.id===cartId);setItems(prev=>{const existing=prev.find(i=>i.id===cartId);if(existing&&existing.sellByWeight===item.sellByWeight){return prev.map(i=>i.id===cartId?{...i,quantity:i.quantity+qty}:i)}return[...prev,{...item,id:cartId,recordId:item.recordId,quantity:qty}]});if(isNew&&typeof window!=="undefined"){window.dispatchEvent(new CustomEvent("cart:itemAdded",{detail:{name:item.name}}))}},[]);useEffect(()=>{if(!mounted)return;const handler=e=>{const d=e.detail;if(!d?.products?.length||!d.tableSlug)return;for(const p of d.products){addItem({recordId:p.id,tableSlug:d.tableSlug,name:p.name,unitAmount:p.price,imageUrl:p.image})}};document.addEventListener("holmes:addBundle",handler);return()=>document.removeEventListener("holmes:addBundle",handler)},[addItem,mounted]);const removeItem=useCallback(id=>{setItems(prev=>prev.filter(i=>i.id!==id))},[]);const updateQuantity=useCallback((id,quantity)=>{if(quantity<=0){setItems(prev=>prev.filter(i=>i.id!==id));return}setItems(prev=>prev.map(i=>i.id===id?{...i,quantity:quantity}:i))},[]);const clearCart=useCallback(()=>setItems([]),[]);const total=items.reduce((sum,i)=>sum+i.unitAmount*i.quantity,0);return _jsx(CartContext.Provider,{value:{items:items,addItem:addItem,removeItem:removeItem,updateQuantity:updateQuantity,clearCart:clearCart,total:total},children:children})}export function useCart(){const ctx=useContext(CartContext);if(!ctx)throw new Error("useCart must be used within CartProvider");return ctx}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import Link from"next/link";import{ShoppingBag,Store,LayoutGrid}from"lucide-react";export function CatalogueEmptyState({hasCategory:hasCategory,hasStore:hasStore,categories:categories=[]}){if(!hasStore){return _jsxs("div",{className:"flex flex-col items-center justify-center py-16 px-6 text-center max-w-md mx-auto",children:[_jsx("div",{className:"w-20 h-20 rounded-full bg-aurora-surface-hover flex items-center justify-center mb-6 ring-4 ring-aurora-primary/10",children:_jsx(Store,{className:"w-10 h-10 text-aurora-primary"})}),_jsx("h2",{className:"text-xl font-bold text-aurora-text mb-2",children:"Select a store to browse"}),_jsx("p",{className:"text-aurora-muted mb-8",children:"Choose your local store to see products and start shopping."}),_jsxs(Link,{href:"/stores",className:"inline-flex items-center justify-center gap-2 h-12 px-6 rounded-xl bg-aurora-primary text-white font-semibold hover:bg-aurora-primary-dark transition-colors",children:[_jsx(Store,{className:"w-5 h-5"}),"Find your store"]})]})}if(hasCategory){return _jsxs("div",{className:"flex flex-col items-center justify-center py-16 px-6 text-center max-w-md mx-auto",children:[_jsx("div",{className:"w-20 h-20 rounded-full bg-aurora-surface-hover flex items-center justify-center mb-6 ring-4 ring-aurora-primary/10",children:_jsx(LayoutGrid,{className:"w-10 h-10 text-aurora-primary"})}),_jsx("h2",{className:"text-xl font-bold text-aurora-text mb-2",children:"No products in this category yet"}),_jsx("p",{className:"text-aurora-muted mb-8",children:"This category is empty. Try another category or browse all products."}),_jsxs("div",{className:"flex flex-wrap justify-center gap-3",children:[_jsxs(Link,{href:"/catalogue",className:"inline-flex items-center justify-center gap-2 h-12 px-6 rounded-xl bg-aurora-primary text-white font-semibold hover:bg-aurora-primary-dark transition-colors",children:[_jsx(LayoutGrid,{className:"w-5 h-5"}),"View all products"]}),categories.slice(0,3).map(cat=>_jsx(Link,{href:`/catalogue?category=${cat.slug}`,className:"inline-flex items-center h-12 px-5 rounded-xl border-2 border-aurora-border text-aurora-text font-medium hover:border-aurora-primary hover:text-aurora-primary transition-colors",children:cat.name},cat.slug))]})]})}return _jsxs("div",{className:"flex flex-col items-center justify-center py-16 px-6 text-center max-w-md mx-auto",children:[_jsx("div",{className:"w-20 h-20 rounded-full bg-aurora-surface-hover flex items-center justify-center mb-6 ring-4 ring-aurora-primary/10",children:_jsx(ShoppingBag,{className:"w-10 h-10 text-aurora-primary"})}),_jsx("h2",{className:"text-xl font-bold text-aurora-text mb-2",children:"No products yet"}),_jsx("p",{className:"text-aurora-muted mb-8",children:"Products will appear here once they're added. Check back soon or browse our categories."}),_jsxs(Link,{href:"/catalogue",className:"inline-flex items-center justify-center gap-2 h-12 px-6 rounded-xl bg-aurora-primary text-white font-semibold hover:bg-aurora-primary-dark transition-colors",children:[_jsx(ShoppingBag,{className:"w-5 h-5"}),"Browse catalogue"]})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import Link from"next/link";import{useState}from"react";import{ChevronDown,Baby,Beer,Candy,Cat,Wheat,Sparkles,CupSoda,Droplets,HeartPulse,Apple,Drumstick,Shirt}from"lucide-react";import{HolmesSprinkleIcon}from"./HolmesSprinkleIcon";function getCategoryIcon(slug){const s=slug.toLowerCase();const map={"baby-food":Baby,baby:Baby,beer:Beer,candy:Candy,"cat-food":Cat,cat:Cat,cereal:Wheat,cleaning:Sparkles,dishwashing:Sparkles,tea:CupSoda,water:Droplets,"health-care":HeartPulse,healthcare:HeartPulse,juices:Apple,juice:Apple,poultry:Drumstick,"skin-care":Shirt,skincare:Shirt,vegetables:Apple,fruits:Apple,dairy:Droplets,bakery:Wheat,snacks:Candy,beverages:CupSoda};return map[s]??Wheat}export const SORT_OPTIONS=[{id:"featured",label:"Featured"},{id:"bestsellers",label:"Bestsellers"},{id:"new",label:"New Arrivals"},{id:"sale",label:"On Sale"}];function FilterSection({title:title,children:children,defaultOpen:defaultOpen=true}){const[open,setOpen]=useState(defaultOpen);return _jsxs("section",{className:"border-b border-aurora-border last:border-0",children:[_jsxs("button",{type:"button",onClick:()=>setOpen(o=>!o),className:"flex items-center justify-between w-full py-3 text-left",children:[_jsx("h3",{className:"text-xs font-semibold uppercase tracking-wider text-aurora-muted",children:title}),_jsx(ChevronDown,{className:`w-4 h-4 text-aurora-muted transition-transform ${open?"rotate-180":""}`})]}),open&&_jsx("div",{className:"pb-3",children:children})]})}export function CatalogueFilters({categories:categories,currentCategory:currentCategory,currentSort:currentSort,onSortChange:onSortChange,storeName:storeName,onClose:onClose,variant:variant="sidebar",suggestedSlugs:suggestedSlugs=[],missionPrioritySlugs:missionPrioritySlugs=[]}){const sortedCategories=[...categories].sort((a,b)=>{const aSuggested=suggestedSlugs.includes(a.slug);const bSuggested=suggestedSlugs.includes(b.slug);if(aSuggested&&!bSuggested)return-1;if(!aSuggested&&bSuggested)return 1;if(missionPrioritySlugs.length>0){const aIdx=missionPrioritySlugs.indexOf(a.slug);const bIdx=missionPrioritySlugs.indexOf(b.slug);if(aIdx>=0&&bIdx<0)return-1;if(aIdx<0&&bIdx>=0)return 1;if(aIdx>=0&&bIdx>=0)return aIdx-bIdx}return 0});const content=_jsxs("div",{className:"space-y-0",children:[_jsx(FilterSection,{title:"Categories",children:_jsxs("nav",{className:"space-y-1",children:[_jsx(Link,{href:"/catalogue",onClick:onClose,className:`flex min-h-10 items-center px-3 py-2 rounded-component text-sm font-medium transition-colors ${!currentCategory?"bg-aurora-accent/20 text-aurora-accent border border-aurora-accent/40":"text-aurora-muted hover:text-aurora-text hover:bg-aurora-surface-hover border border-transparent"}`,children:"All categories"}),sortedCategories.map(cat=>{const isSuggested=suggestedSlugs.includes(cat.slug);return _jsxs(Link,{href:`/catalogue?category=${encodeURIComponent(cat.slug)}`,onClick:onClose,className:`flex min-h-10 items-center gap-2 px-3 py-2 rounded-component text-sm font-medium transition-colors ${currentCategory===cat.slug?"bg-aurora-accent/20 text-aurora-accent border border-aurora-accent/40":"text-aurora-muted hover:text-aurora-text hover:bg-aurora-surface-hover border border-transparent"}`,children:[(()=>{const Icon=getCategoryIcon(cat.slug);return _jsx(Icon,{className:"h-4 w-4 shrink-0 text-aurora-muted","aria-hidden":true})})(),isSuggested?_jsx(HolmesSprinkleIcon,{className:"shrink-0"}):null,cat.name]},cat.slug)})]})}),_jsx(FilterSection,{title:"Sort by",defaultOpen:true,children:_jsx("div",{className:"space-y-1",children:SORT_OPTIONS.map(opt=>_jsx("button",{type:"button",onClick:()=>{onSortChange(opt.id);onClose?.()},className:`w-full text-left px-3 py-2 rounded-component text-sm font-medium transition-colors ${currentSort===opt.id?"bg-aurora-accent/20 text-aurora-accent border border-aurora-accent/40":"text-aurora-muted hover:text-aurora-text hover:bg-aurora-surface-hover border border-transparent"}`,children:opt.label},opt.id))})}),storeName&&_jsxs("p",{className:"text-xs text-aurora-muted pt-2 border-t border-aurora-border",children:["Showing products from ",storeName]})]});if(variant==="drawer"){return _jsx("div",{className:"bg-aurora-surface border-t border-aurora-border p-6",children:content})}return _jsx("aside",{className:"hidden md:block w-full md:w-56 shrink-0 order-first",children:_jsx("div",{className:"pattern-well sticky top-24 space-y-6 rounded-component border border-aurora-border p-4",children:content})})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx}from"react/jsx-runtime";import{useState}from"react";import{useCart}from"./CartProvider";import{getApiBase,getTenantSlug}from"../lib/aurora";export function CheckoutButton(){const{items:items,clearCart:clearCart}=useCart();const[loading,setLoading]=useState(false);const handleCheckout=async()=>{if(items.length===0)return;setLoading(true);const apiBase=getApiBase();const tenantSlug=getTenantSlug();if(!apiBase||!tenantSlug){alert("API not configured. Set NEXT_PUBLIC_AURORA_API_URL and NEXT_PUBLIC_TENANT_SLUG.");setLoading(false);return}const origin=typeof window!=="undefined"?window.location.origin:"";const successUrl=`${origin}/checkout/success`;const cancelUrl=`${origin}/cart`;const lineItems=items.map(i=>({productId:i.recordId,tableSlug:i.tableSlug,quantity:i.quantity,priceData:{unitAmount:i.unitAmount,currency:"GBP",productData:{name:i.name}}}));const holmes_session_id=typeof window!=="undefined"?window.holmes?.getSessionId?.():undefined;const holmes_mission_start_timestamp=typeof window!=="undefined"?window.holmes?.getMissionStartTimestamp?.():undefined;try{const res=await fetch("/api/checkout/sessions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({successUrl:successUrl,cancelUrl:cancelUrl,lineItems:lineItems,...holmes_session_id&&{holmes_session_id:holmes_session_id},...holmes_mission_start_timestamp!=null&&{holmes_mission_start_timestamp:holmes_mission_start_timestamp}})});if(!res.ok){const err=await res.json().catch(()=>({}));throw new Error(err.error??"Checkout failed")}const data=await res.json();if(data.url){clearCart();window.location.href=data.url}else{throw new Error("No checkout URL returned")}}catch(e){alert(e instanceof Error?e.message:"Checkout failed")}finally{setLoading(false)}};return _jsx("button",{type:"button",onClick:handleCheckout,disabled:loading||items.length===0,className:"w-full sm:w-auto px-6 py-3 rounded-component bg-aurora-accent text-aurora-bg font-semibold hover:opacity-90 disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-aurora-primary focus:ring-offset-2 focus:ring-offset-aurora-surface transition-opacity",children:loading?"Processing…":"Proceed to checkout"})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as _jsx}from"react/jsx-runtime";import Script from"next/script";import{getHolmesScriptUrl}from"@aurora-studio/sdk";export function ConditionalHolmesScript(){const apiUrl=process.env.NEXT_PUBLIC_AURORA_API_URL;const tenantSlug=process.env.NEXT_PUBLIC_TENANT_SLUG;if(!apiUrl||!tenantSlug){return null}const src=getHolmesScriptUrl(apiUrl,tenantSlug);return _jsx(Script,{src:src,strategy:"afterInteractive"})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useId,useRef,useState}from"react";export function FloatingLabelInput({label:label,error:error,id:id,className:className="",value:value,...props}){const generatedId=useId();const inputId=id??generatedId;const inputRef=useRef(null);const[focused,setFocused]=useState(false);const floatLabel=focused||Boolean(value!=null&&value!=="");return _jsxs("div",{className:"relative",children:[_jsx("input",{ref:inputRef,id:inputId,value:value,onFocus:e=>{setFocused(true);props.onFocus?.(e)},onBlur:e=>{setFocused(false);props.onBlur?.(e)},placeholder:" ",className:`peer w-full h-12 px-4 rounded-xl bg-aurora-bg border text-aurora-text placeholder:text-transparent focus:outline-none focus:ring-2 focus:ring-aurora-primary/50 focus:border-aurora-primary transition-colors ${error?"border-aurora-error":"border-aurora-border"} ${className}`,...props}),_jsx("label",{htmlFor:inputId,className:`absolute left-4 transition-all duration-200 pointer-events-none ${floatLabel?"-top-1 -translate-y-full text-xs text-aurora-muted bg-aurora-bg px-1":"top-1/2 -translate-y-1/2 text-base text-aurora-muted"}`,children:label}),error&&_jsx("p",{className:"mt-1 text-sm text-aurora-error",children:error})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useEffect
|
|
1
|
+
"use client";import{useEffect}from"react";export function HolmesHomeRefresher(){useEffect(()=>{document.dispatchEvent(new CustomEvent("holmes:refreshHome"));const onReady=()=>{document.dispatchEvent(new CustomEvent("holmes:refreshHome"))};document.addEventListener("holmes:ready",onReady);return()=>document.removeEventListener("holmes:ready",onReady)},[]);return null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useEffect
|
|
1
|
+
"use client";import{useEffect}from"react";import{holmesProductView}from"../lib/holmes-events";const STORAGE_KEY="holmes_products_viewed";const MAX_VIEWED=20;function getViewedIds(){if(typeof window==="undefined")return[];try{const raw=sessionStorage.getItem(STORAGE_KEY);if(!raw)return[];return JSON.parse(raw)}catch{return[]}}function appendViewed(productId){const current=getViewedIds();const filtered=current.filter(id=>id!==productId);const next=[productId,...filtered].slice(0,MAX_VIEWED);try{sessionStorage.setItem(STORAGE_KEY,JSON.stringify(next))}catch{}return next}export function HolmesProductViewTracker({productId:productId}){useEffect(()=>{if(!productId)return;const allIds=appendViewed(productId);holmesProductView(allIds)},[productId]);return null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";export function HolmesSprinkleIcon({className:className}){return _jsx("span",{className:`inline-flex items-center justify-center ${className??""}`,title:"Personalised for you","aria-label":"Personalised for you",children:_jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",className:"w-3.5 h-3.5 text-aurora-accent",children:[_jsx("path",{d:"M12 1l1.5 4.5L18 7l-4.5 1.5L12 13l-1.5-4.5L6 7l4.5-1.5L12 1z"}),_jsx("path",{d:"M5 16l1 3 3 1-3 1-1 3-1-3-3-1 3-1 1-3z",opacity:"0.7"}),_jsx("path",{d:"M19 19l1 3 3 1-3 1-1 3-1-3-3-1 3-1 1-3z",opacity:"0.7"})]})})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useState,useEffect}from"react";import Link from"next/link";import{holmesTidbits}from"../lib/aurora";import{HolmesSprinkleIcon}from"./HolmesSprinkleIcon";const CATEGORY_LABELS={origin:"Origin",pairing:"Pairs well",tip:"Tip"};export function HolmesTidbits({entity:entity,entityType:entityType="recipe",variant:variant="default"}){const[tidbits,setTidbits]=useState([]);useEffect(()=>{if(!entity?.trim()){setTidbits([]);return}holmesTidbits(entity.trim(),entityType).then(res=>setTidbits(res.tidbits??[])).catch(()=>setTidbits([]))},[entity,entityType]);if(tidbits.length===0)return null;if(variant==="compact"){return _jsx("div",{className:"flex flex-wrap gap-2",children:tidbits.slice(0,2).map(t=>_jsxs("span",{className:"inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md bg-aurora-primary/10 text-aurora-muted text-xs border border-aurora-primary/20",children:[_jsx(HolmesSprinkleIcon,{}),_jsx("span",{children:t.content})]},t.id))})}return _jsxs("div",{className:"p-4 rounded-xl bg-aurora-surface/60 border border-aurora-border",children:[_jsxs("div",{className:"flex items-center gap-2 mb-2.5",children:[_jsx(HolmesSprinkleIcon,{className:"shrink-0"}),_jsx("span",{className:"text-xs font-medium text-aurora-muted uppercase tracking-wider",children:"Holmes insight"})]}),_jsx("div",{className:"space-y-2.5",children:tidbits.slice(0,3).map(t=>_jsxs("div",{children:[_jsx("span",{className:"text-[10px] uppercase tracking-wider text-aurora-muted/80 mr-1.5",children:CATEGORY_LABELS[t.category]??t.category}),_jsxs("p",{className:"text-sm text-aurora-text leading-relaxed",children:[t.content,t.source_url&&_jsx(Link,{href:t.source_url,target:"_blank",rel:"noopener noreferrer",className:"ml-1.5 text-aurora-accent hover:underline text-xs",children:"Learn more"})]})]},t.id))})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";export function ProductCardSkeleton(){return _jsxs("div",{className:"group p-4 rounded-xl bg-aurora-surface border border-aurora-border overflow-hidden w-full min-w-[160px] min-h-[280px] flex flex-col",children:[_jsxs("div",{className:"block",children:[_jsx("div",{className:"aspect-square rounded-lg bg-aurora-surface-hover mb-3 overflow-hidden skeleton-shimmer"}),_jsx("div",{className:"h-4 rounded skeleton-shimmer w-3/4 mb-1"}),_jsx("div",{className:"h-4 rounded skeleton-shimmer w-1/4"})]}),_jsx("div",{className:"mt-auto pt-3",children:_jsx("div",{className:"h-12 rounded-xl skeleton-shimmer w-full"})})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useState}from"react";export function ProductDetailTabs({record:record}){const[active,setActive]=useState("details");const features=record.features;const featuresList=Array.isArray(features)?features:typeof features==="string"?(()=>{try{const p=JSON.parse(features);return Array.isArray(p)?p:[]}catch{return[]}})():[];const storageInstructions=record.storage_instructions;const tabs=[{id:"details",label:"Product Details"},{id:"nutrition",label:"Nutrition Facts"},{id:"feedback",label:"Customer Feedback"}];return _jsxs("div",{className:"pattern-well rounded-xl border border-aurora-border p-6",children:[_jsx("div",{className:"flex gap-4 border-b border-aurora-border",children:tabs.map(t=>_jsx("button",{type:"button",onClick:()=>setActive(t.id),className:`py-3 font-medium border-b-2 transition-colors -mb-[2px] ${active===t.id?"border-aurora-accent text-aurora-accent":"border-transparent text-aurora-muted hover:text-aurora-text"}`,children:t.label},t.id))}),_jsxs("div",{className:"py-6",children:[active==="details"&&_jsxs("div",{className:"space-y-4",children:[_jsxs("p",{className:"text-aurora-muted",children:[String(record.description??record.name??"")," - High quality product."]}),featuresList.length>0&&_jsx("ul",{className:"list-disc list-inside space-y-1",children:featuresList.map((f,i)=>_jsx("li",{children:String(f)},i))}),storageInstructions&&_jsxs("div",{children:[_jsx("h4",{className:"font-semibold mb-2",children:"Storage Instructions"}),_jsx("p",{className:"text-aurora-muted text-sm",children:storageInstructions})]})]}),active==="nutrition"&&_jsx("p",{className:"text-aurora-muted",children:"Nutrition information will be displayed here when available."}),active==="feedback"&&_jsx("p",{className:"text-aurora-muted",children:"Customer reviews will be displayed here when available."})]})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx}from"react/jsx-runtime";import{useState}from"react";import{resolveProductImageUrl,getImageUrlFromRecord,getThumbnailImageUrl}from"../lib/image-url";import{useStoreConfigImageBase}from"./StoreConfigContext";const DEFAULT_FALLBACK=_jsx("span",{className:"w-full h-full flex items-center justify-center text-aurora-muted text-2xl","aria-hidden":true,children:"–"});const objectFitClass={cover:"object-cover",contain:"object-contain"};export function ProductImage({src:src,alt:alt="",baseUrl:baseUrl,className:className,fallback:fallback=DEFAULT_FALLBACK,record:record,objectFit:objectFit="cover",thumbnail:thumbnail=false}){const[errored,setErrored]=useState(false);const configBase=useStoreConfigImageBase();const rawUrl=record!==undefined?getImageUrlFromRecord(record):src;let resolved=resolveProductImageUrl(rawUrl,baseUrl??configBase);if(resolved&&thumbnail){resolved=getThumbnailImageUrl(resolved)??resolved}const fitClass=objectFitClass[objectFit];const base=(className??"w-full h-full").replace(/\bobject-(cover|contain)\b/g,"").trim();const mergedClassName=base?`${base} ${fitClass}`.trim():`w-full h-full ${fitClass}`;if(!resolved||errored){return _jsx("div",{className:"w-full h-full flex items-center justify-center min-h-[1px]",children:fallback})}return _jsx("img",{src:resolved,alt:alt,className:mergedClassName,onError:()=>setErrored(true),suppressHydrationWarning:true})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useState}from"react";import{ProductImage}from"./ProductImage";function getImageUrls(record){const images=record.images;if(Array.isArray(images)&&images.length>0){return[...new Set(images.filter(u=>typeof u==="string"))]}const primary=["image_url","image","thumbnail","photo"].find(f=>record[f]);const primaryUrl=primary?String(record[primary]):null;const extras=["image_2","image_3","image_4"].filter(f=>record[f]).map(f=>String(record[f]));if(primaryUrl)return[primaryUrl,...extras];return extras}export function ProductImageGallery({record:record}){const urls=getImageUrls(record);const[selected,setSelected]=useState(0);if(urls.length===0){return _jsx("div",{className:"pattern-well rounded-component overflow-hidden aspect-square flex items-center justify-center text-aurora-muted text-6xl",children:"-"})}const mainUrl=urls[selected]??urls[0];return _jsxs("div",{className:"space-y-3",children:[_jsx("div",{className:"pattern-well rounded-xl overflow-hidden aspect-square shadow-sm ring-1 ring-aurora-border/50 p-4",children:_jsx(ProductImage,{src:mainUrl,className:"w-full h-full object-contain cursor-zoom-in",fallback:_jsx("span",{className:"w-full h-full flex items-center justify-center text-aurora-muted text-4xl",children:"-"})})}),urls.length>1&&_jsx("div",{className:"flex gap-2 overflow-x-auto pb-1",children:urls.map((url,i)=>_jsx("button",{type:"button",onClick:()=>setSelected(i),className:`shrink-0 w-16 h-16 rounded-lg overflow-hidden border-2 bg-aurora-surface-hover transition-colors ${selected===i?"border-aurora-primary":"border-aurora-border hover:border-aurora-primary/50"}`,children:_jsx(ProductImage,{src:url,className:"w-full h-full object-contain",fallback:_jsx("span",{className:"w-full h-full flex items-center justify-center text-aurora-muted text-sm",children:"-"})})},i))})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useState,useEffect,useRef,useCallback}from"react";import Link from"next/link";import{Search}from"lucide-react";import{formatPrice,toCents}from"../lib/format-price";import{search}from"../lib/aurora";import{holmesSearch}from"../lib/holmes-events";import{useCart}from"./CartProvider";import{ProductImage}from"./ProductImage";const RECENT_KEY="aurora-search-recent";const RECENT_MAX=5;function loadRecent(){if(typeof window==="undefined")return[];try{const stored=localStorage.getItem(RECENT_KEY);return stored?JSON.parse(stored):[]}catch{return[]}}function saveRecent(terms){if(typeof window==="undefined")return;localStorage.setItem(RECENT_KEY,JSON.stringify(terms.slice(0,RECENT_MAX)))}export function SearchDropdown({vendorId:vendorId,placeholder:placeholder="Search milk, bananas, pasta…",fullWidth:fullWidth,variant:variant="default",excludeDietary:excludeDietary=[],getRecipeSuggestion:getRecipeSuggestion}){const[query,setQuery]=useState("");const[hits,setHits]=useState([]);const[loading,setLoading]=useState(false);const[open,setOpen]=useState(false);const[recentSearches,setRecentSearches]=useState([]);const debounceRef=useRef(null);const containerRef=useRef(null);const{addItem:addItem}=useCart();useEffect(()=>{setRecentSearches(loadRecent())},[]);const addToRecent=useCallback(term=>{const t=term.trim().toLowerCase();if(!t)return;setRecentSearches(prev=>{const next=[t,...prev.filter(x=>x!==t)].slice(0,RECENT_MAX);saveRecent(next);return next})},[]);const doSearch=useCallback(async q=>{if(!q.trim()){setHits([]);return}holmesSearch(q.trim());setLoading(true);try{const res=await search({q:q.trim(),limit:12,vendorId:vendorId,excludeDietary:excludeDietary.length?excludeDietary:undefined});setHits(res.hits??[])}catch{setHits([])}finally{setLoading(false)}},[vendorId,excludeDietary]);useEffect(()=>{if(debounceRef.current)clearTimeout(debounceRef.current);if(!query.trim()){setHits([]);if(!open)return;setOpen(true);return}setOpen(true);debounceRef.current=setTimeout(()=>doSearch(query),180);return()=>{if(debounceRef.current)clearTimeout(debounceRef.current)}},[query,doSearch,open]);useEffect(()=>{function handleClickOutside(e){if(containerRef.current&&!containerRef.current.contains(e.target)){setOpen(false)}}document.addEventListener("mousedown",handleClickOutside);return()=>document.removeEventListener("mousedown",handleClickOutside)},[]);const categories=[...new Set(hits.map(h=>h.category_name??h.category).filter(Boolean))].slice(0,3);const brands=[...new Set(hits.map(h=>h.brand??h.brand_name).filter(Boolean))].slice(0,3);const handleProductSelect=(hit,quickAdd)=>{addToRecent(query);if(quickAdd&&hit.price!=null&&Number(hit.price)>0&&hit.tableSlug){addItem({recordId:hit.recordId,tableSlug:hit.tableSlug,name:hit.name??hit.title??hit.snippet??hit.recordId??"",unitAmount:toCents(hit.price)??0,imageUrl:hit.image_url})}};const showRecent=open&&query.trim()&&!loading&&hits.length===0&&recentSearches.length>0;const recipeSuggestion=getRecipeSuggestion?.(query)??null;const showRecipeSuggestion=open&&query.trim().length>=2&&recipeSuggestion&&!loading;const fieldShell=variant==="default"?"flex w-full items-center rounded-lg border border-aurora-border/90 bg-aurora-surface shadow-sm transition-colors focus-within:border-aurora-primary/70 focus-within:ring-1 focus-within:ring-aurora-primary/40":"flex w-full items-center rounded-lg bg-transparent";const inputClass="flex-1 min-w-0 h-10 py-0 pr-3 text-sm leading-normal text-aurora-text placeholder:text-aurora-muted "+"border-0 bg-transparent shadow-none outline-none ring-0 focus:outline-none focus:ring-0 "+"[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none";return _jsxs("div",{ref:containerRef,className:`relative w-full ${fullWidth?"":"max-w-[280px]"}`,children:[_jsxs("div",{className:fieldShell,children:[_jsx("span",{className:"flex h-10 w-10 shrink-0 items-center justify-center text-aurora-muted pointer-events-none","aria-hidden":true,children:_jsx(Search,{className:"h-4 w-4 shrink-0"})}),_jsx("input",{type:"search",value:query,onChange:e=>setQuery(e.target.value),onFocus:()=>(query.trim()||recentSearches.length)&&setOpen(true),placeholder:placeholder,className:inputClass,"aria-label":"Search products"})]}),open&&(query.trim()||showRecent)&&_jsx("div",{className:"absolute top-full left-0 right-0 mt-1 rounded-component bg-aurora-surface border border-aurora-border shadow-xl z-[9999] max-h-96 overflow-y-auto",children:loading?_jsx("div",{className:"p-4 text-aurora-muted text-sm",children:"Searching…"}):hits.length===0&&!showRecent&&!showRecipeSuggestion?_jsx("div",{className:"p-4 text-aurora-muted text-sm",children:"No results"}):_jsxs("div",{className:"py-2",children:[showRecipeSuggestion&&_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-b border-aurora-border",children:"Suggestions"}),showRecipeSuggestion&&_jsxs(Link,{href:`/catalogue?q=${encodeURIComponent(recipeSuggestion.replace("?","").split(" ")[0].toLowerCase())}`,onClick:()=>{addToRecent(recipeSuggestion);setOpen(false)},className:"flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors border-b border-aurora-border",children:[_jsx(Search,{className:"w-4 h-4 text-aurora-muted shrink-0"}),_jsx("span",{className:"font-medium truncate",children:recipeSuggestion})]}),hits.length>0&&_jsxs(_Fragment,{children:[_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-b border-aurora-border",children:"Products"}),_jsx("ul",{children:hits.slice(0,6).map(hit=>_jsx("li",{className:"group/item",children:_jsxs("div",{className:"flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors",children:[_jsxs(Link,{href:`/catalogue/${hit.recordId}`,onClick:()=>{handleProductSelect(hit);setOpen(false)},className:"flex items-center gap-3 flex-1 min-w-0",children:[_jsx("div",{className:"w-10 h-10 rounded-component bg-aurora-surface-hover shrink-0 overflow-hidden",children:_jsx(ProductImage,{src:hit.image_url,className:"w-full h-full",objectFit:"contain",thumbnail:true,fallback:_jsx("div",{className:"w-full h-full flex items-center justify-center text-aurora-muted text-xs",children:"-"})})}),_jsxs("div",{className:"flex-1 min-w-0",children:[_jsx("p",{className:"font-medium truncate",children:hit.name??hit.title??hit.snippet??hit.recordId}),hit.price!=null&&Number(hit.price)>0&&_jsx("p",{className:"text-sm text-aurora-primary font-semibold",children:formatPrice(toCents(hit.price)??0)})]})]}),hit.price!=null&&Number(hit.price)>0&&_jsx("button",{type:"button",onClick:e=>{e.preventDefault();handleProductSelect(hit,true);setOpen(false)},className:"shrink-0 px-3 py-1.5 rounded-lg bg-aurora-primary text-white text-xs font-medium hover:bg-aurora-primary-dark transition-colors opacity-0 group-hover/item:opacity-100",children:"Quick add"})]})},`${hit.tableSlug}-${hit.recordId}`))}),categories.length>0&&_jsxs(_Fragment,{children:[_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-t border-b border-aurora-border mt-1",children:"Categories"}),_jsx("ul",{children:categories.map(cat=>_jsx("li",{children:_jsx(Link,{href:`/catalogue?category=${encodeURIComponent(String(cat).toLowerCase().replace(/\s+/g,"-"))}`,onClick:()=>{addToRecent(query);setOpen(false)},className:"flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors",children:_jsx("span",{className:"font-medium truncate",children:cat})})},cat))})]}),brands.length>0&&_jsxs(_Fragment,{children:[_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-t border-b border-aurora-border mt-1",children:"Brands"}),_jsx("ul",{children:brands.map(brand=>_jsx("li",{children:_jsx(Link,{href:`/catalogue?q=${encodeURIComponent(brand)}`,onClick:()=>{addToRecent(query);setOpen(false)},className:"flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors",children:_jsx("span",{className:"font-medium truncate",children:brand})})},brand))})]})]}),showRecent&&_jsxs(_Fragment,{children:[_jsx("div",{className:"px-3 py-1.5 text-xs font-semibold uppercase tracking-wider text-aurora-muted border-b border-aurora-border",children:"Recent searches"}),_jsx("ul",{children:recentSearches.map(term=>_jsx("li",{children:_jsxs("button",{type:"button",onClick:()=>{setQuery(term);doSearch(term)},className:"w-full text-left flex items-center gap-3 px-4 py-2 hover:bg-aurora-surface-hover transition-colors",children:[_jsx(Search,{className:"w-4 h-4 text-aurora-muted shrink-0"}),_jsx("span",{className:"font-medium truncate",children:term})]})},term))})]})]})})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import Link from"next/link";import{useCart}from"./CartProvider";import{formatPrice}from"../lib/format-price";import{ShoppingBag}from"lucide-react";const SHIPPING_CENTS=250;const FREE_DELIVERY_THRESHOLD_CENTS=2500;export function SmartCartPanel(){const{items:items,total:total}=useCart();const count=items.reduce((s,i)=>s+i.quantity,0);const shipping=count>0?SHIPPING_CENTS:0;const grandTotal=total+shipping;const toFreeDelivery=Math.max(0,FREE_DELIVERY_THRESHOLD_CENTS-total);if(count===0)return null;return _jsx("div",{className:"sticky bottom-0 z-40 mt-10 px-6 py-4 rounded-2xl bg-aurora-surface border border-aurora-border shadow-xl shadow-aurora-primary/5",children:_jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between sm:gap-6 gap-3 max-w-4xl mx-auto",children:[_jsxs("div",{className:"flex items-center gap-4 min-w-0",children:[_jsx("span",{className:"flex items-center justify-center w-11 h-11 shrink-0 rounded-xl bg-aurora-primary/15 text-aurora-primary",children:_jsx(ShoppingBag,{className:"w-5 h-5"})}),_jsxs("div",{className:"min-w-0",children:[_jsxs("p",{className:"font-semibold text-aurora-text text-base",children:[count," ",count===1?"item":"items"," · ",formatPrice(grandTotal)]}),toFreeDelivery>0&&_jsxs("p",{className:"text-sm text-aurora-primary font-medium mt-0.5",children:["Add ",formatPrice(toFreeDelivery)," more for free delivery"]}),toFreeDelivery<=0&&total>0&&_jsx("p",{className:"text-sm text-aurora-primary font-medium mt-0.5",children:"You've unlocked free delivery"})]})]}),_jsx(Link,{href:"/cart",className:"inline-flex items-center justify-center px-6 py-2.5 rounded-xl bg-aurora-primary text-white font-semibold text-sm hover:bg-aurora-primary-dark transition-colors shrink-0 shadow-lg shadow-aurora-primary/25",children:"View cart · Checkout"})]})})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useState,useRef,useEffect}from"react";import{ChevronDown}from"lucide-react";import{SORT_OPTIONS}from"./CatalogueFilters";export function SortDropdown({value:value,onChange:onChange}){const[open,setOpen]=useState(false);const ref=useRef(null);const currentLabel=SORT_OPTIONS.find(o=>o.id===value)?.label??"Featured";useEffect(()=>{function handleClickOutside(e){if(ref.current&&!ref.current.contains(e.target)){setOpen(false)}}document.addEventListener("mousedown",handleClickOutside);return()=>document.removeEventListener("mousedown",handleClickOutside)},[]);return _jsxs("div",{ref:ref,className:"relative",children:[_jsxs("button",{type:"button",onClick:()=>setOpen(o=>!o),className:"flex items-center gap-1.5 px-4 py-2 rounded-xl border border-aurora-border bg-aurora-surface text-sm font-medium text-aurora-text hover:border-aurora-primary/40 transition-colors",children:[currentLabel,_jsx(ChevronDown,{className:`w-4 h-4 text-aurora-muted transition-transform ${open?"rotate-180":""}`})]}),open&&_jsx("div",{className:"absolute top-full right-0 mt-1 py-1 rounded-xl bg-aurora-surface border border-aurora-border shadow-xl min-w-[180px] z-50",children:SORT_OPTIONS.map(opt=>_jsx("button",{type:"button",onClick:()=>{onChange(opt.id);setOpen(false)},className:`w-full text-left px-4 py-2.5 text-sm font-medium transition-colors ${value===opt.id?"text-aurora-primary bg-aurora-accent/10":"text-aurora-muted hover:text-aurora-text hover:bg-aurora-surface-hover"}`,children:opt.label},opt.id))})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx}from"react/jsx-runtime";import{createContext,useContext,useEffect,useState}from"react";import{getStoreConfig}from"../lib/aurora";const StoreConfigContext=createContext(null);export function StoreConfigProvider({children:children}){const[imageBaseUrl,setImageBaseUrl]=useState(null);useEffect(()=>{let cancelled=false;getStoreConfig().then(config=>{if(!cancelled&&config){const base=config.imageBaseUrl;if(typeof base==="string")setImageBaseUrl(base)}}).catch(()=>{});return()=>{cancelled=true}},[]);return _jsx(StoreConfigContext.Provider,{value:{imageBaseUrl:imageBaseUrl},children:children})}export function useStoreConfigImageBase(){const ctx=useContext(StoreConfigContext);return ctx?.imageBaseUrl??null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx}from"react/jsx-runtime";import{createContext,useContext,useCallback,useState,useEffect}from"react";const LOCATION_KEY="aurora-location";const STORE_KEY="aurora-selected-store";function loadLocation(){if(typeof window==="undefined")return null;try{const stored=localStorage.getItem(LOCATION_KEY);return stored?JSON.parse(stored):null}catch{return null}}function saveLocation(loc){if(typeof window==="undefined")return;localStorage.setItem(LOCATION_KEY,JSON.stringify(loc))}function loadStore(){if(typeof window==="undefined")return null;try{const stored=localStorage.getItem(STORE_KEY);return stored?JSON.parse(stored):null}catch{return null}}function saveStore(store){if(typeof window==="undefined")return;if(store){localStorage.setItem(STORE_KEY,JSON.stringify(store))}else{localStorage.removeItem(STORE_KEY)}}const StoreContext=createContext(null);export function StoreProvider({children:children}){const[location,setLocationState]=useState(null);const[store,setStoreState]=useState(null);const[mounted,setMounted]=useState(false);useEffect(()=>{setLocationState(loadLocation());setStoreState(loadStore());setMounted(true)},[]);const setLocation=useCallback(loc=>{setLocationState(loc);saveLocation(loc)},[]);const setStore=useCallback(s=>{setStoreState(s);saveStore(s)},[]);return _jsx(StoreContext.Provider,{value:{location:mounted?location:null,setLocation:setLocation,store:mounted?store:null,setStore:setStore},children:children})}export function useStore(){const ctx=useContext(StoreContext);if(!ctx)throw new Error("useStore must be used within StoreProvider");return ctx}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
"use client";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import Link from"next/link";import{Store,MapPin}from"lucide-react";import{useStore}from"./StoreContext";export function StoreContextBar(){const{store:store}=useStore();if(store){return _jsx("div",{className:"border-b border-aurora-border bg-aurora-bg px-4 py-2.5",children:_jsxs("div",{className:"max-w-6xl mx-auto flex items-center justify-between gap-4",children:[_jsxs("div",{className:"flex items-center gap-2 text-sm text-aurora-muted",children:[_jsx(Store,{className:"w-4 h-4 shrink-0"}),_jsxs("span",{children:["Shopping from: ",store.name]}),_jsx(Link,{href:"/stores",className:"text-aurora-primary hover:underline ml-1 font-medium",children:"View Store Details"})]}),_jsx(Link,{href:"/stores",className:"text-sm font-medium text-aurora-primary hover:underline",children:"Change Store"})]})})}return _jsx("div",{className:"border-b border-aurora-border bg-aurora-primary/10 px-4 py-3",children:_jsxs("div",{className:"max-w-6xl mx-auto flex flex-wrap items-center justify-between gap-3",children:[_jsx("p",{className:"text-sm text-aurora-text font-medium",children:"Select a store to search products and see availability."}),_jsxs(Link,{href:"/location",className:"inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-aurora-primary text-white font-semibold text-sm hover:bg-aurora-primary-dark transition-colors",children:[_jsx(MapPin,{className:"w-4 h-4 shrink-0"}),"Set location & choose store"]})]})})}
|
package/dist/lib/aurora.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AuroraClient
|
|
1
|
+
import{AuroraClient}from"@aurora-studio/sdk";const baseUrl=process.env.AURORA_API_URL??process.env.NEXT_PUBLIC_AURORA_API_URL??"";const apiKey=process.env.AURORA_API_KEY??process.env.NEXT_PUBLIC_AURORA_API_KEY??"";const tenantSlug=process.env.NEXT_PUBLIC_TENANT_SLUG??"";const specUrl=baseUrl?`${baseUrl.replace(/\/$/,"")}/v1/openapi.json`:undefined;export function createAuroraClient(){if(!baseUrl||baseUrl.startsWith("/")){throw new Error("Aurora API URL is not configured. Set AURORA_API_URL (or NEXT_PUBLIC_AURORA_API_URL) to your Aurora API root (e.g. https://api.youraurora.com).")}return new AuroraClient({baseUrl:baseUrl,apiKey:apiKey,specUrl:specUrl})}export function getApiBase(){return baseUrl.replace(/\/$/,"")}export function getTenantSlug(){return tenantSlug}export async function getStoreConfig(){if(typeof window!=="undefined"){const res=await fetch("/api/store/config");if(!res.ok)return null;return res.json()}const client=createAuroraClient();return client.store.config()}function excludeOffersFromSearch(result){const hits=result.hits??[];const filtered=hits.filter(h=>h.tableSlug!=="offers");return{...result,hits:filtered}}export async function search(params){let result;if(typeof window!=="undefined"){const qs=new URLSearchParams;if(params.q!=null&¶ms.q!=="")qs.set("q",params.q);if(params.limit!=null)qs.set("limit",String(params.limit));if(params.offset!=null)qs.set("offset",String(params.offset));if(params.vendorId)qs.set("vendorId",params.vendorId);if(params.category)qs.set("category",params.category);if(params.sort)qs.set("sort",params.sort);if(params.order)qs.set("order",params.order);if(params.excludeDietary?.length){qs.set("excludeDietary",params.excludeDietary.join(","))}const res=await fetch(`/api/search?${qs.toString()}`);if(!res.ok){const err=await res.json().catch(()=>({}));throw new Error(err.error??"Search failed")}result=await res.json()}else{const client=createAuroraClient();result=await client.site.search(params)}return excludeOffersFromSearch(result)}export async function getDeliverySlots(lat,lng){const client=createAuroraClient();return client.store.deliverySlots(lat,lng)}export async function getStores(){const client=createAuroraClient();return client.site.stores()}export async function createCheckoutSession(params){const client=createAuroraClient();return client.store.checkout.sessions.create(params)}export async function getAcmeSession(sessionId){const client=createAuroraClient();return client.store.checkout.acme.get(sessionId)}export async function completeAcmeCheckout(sessionId,shippingAddress){const client=createAuroraClient();return client.store.checkout.acme.complete(sessionId,shippingAddress)}export async function holmesInfer(sessionId){const client=createAuroraClient();return client.holmes.infer(sessionId)}export async function holmesRecipeProducts(recipe,limit=12,opts){if(typeof window!=="undefined"){const qs=new URLSearchParams({recipe:recipe,limit:String(limit)});if(opts?.excludeDietary?.length)qs.set("excludeDietary",opts.excludeDietary.join(","));const res=await fetch(`/api/holmes/recipe-products?${qs.toString()}`);if(!res.ok){const err=await res.json().catch(()=>({}));throw new Error(err.error??"Recipe products failed")}return res.json()}const client=createAuroraClient();return client.store.holmesRecipeProducts(recipe,limit,opts)}export async function holmesRecentRecipes(limit=8,timeOfDay,opts){if(typeof window!=="undefined"){const qs=new URLSearchParams({limit:String(limit)});if(timeOfDay)qs.set("time_of_day",timeOfDay);if(opts?.excludeDietary?.length)qs.set("excludeDietary",opts.excludeDietary.join(","));const res=await fetch(`/api/holmes/recipes?${qs.toString()}`);if(!res.ok)return{recipes:[]};return res.json()}const client=createAuroraClient();return client.store.holmesRecentRecipes(limit,timeOfDay,opts)}export async function holmesRecipe(slug){if(typeof window!=="undefined"){const res=await fetch(`/api/holmes/recipe/${encodeURIComponent(slug)}`);if(!res.ok)return null;return res.json()}const client=createAuroraClient();return client.store.holmesRecipe(slug)}export async function holmesTidbits(entity,entityType="recipe"){if(typeof window!=="undefined"){const qs=new URLSearchParams({entity:entity,entity_type:entityType});const res=await fetch(`/api/holmes/tidbits?${qs.toString()}`);if(!res.ok)return{tidbits:[]};return res.json()}const client=createAuroraClient();return client.store.holmesTidbits(entity,entityType)}export async function holmesGoesWith(productId,limit=8,opts){if(typeof window!=="undefined"){const qs=new URLSearchParams({product_id:productId,limit:String(limit)});if(opts?.excludeDietary?.length)qs.set("excludeDietary",opts.excludeDietary.join(","));const res=await fetch(`/api/holmes/goes-with?${qs.toString()}`);if(!res.ok){const err=await res.json().catch(()=>({}));throw new Error(err.error??"Goes-with failed")}return res.json()}const client=createAuroraClient();return client.store.holmesGoesWith(productId,limit,opts)}export async function holmesCombosForCart(params){const qs=new URLSearchParams({cart_ids:params.cartIds.join(",")});if(params.cartNames?.length)qs.set("cart_names",params.cartNames.join(","));if(params.limit)qs.set("limit",String(params.limit));if(params.sid)qs.set("sid",params.sid);const res=await fetch(`/api/holmes/combos-for-cart?${qs.toString()}`);if(!res.ok)return{combos:[]};return res.json()}export async function holmesSelectCombo(params){const res=await fetch("/api/holmes/select-combo",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(params)});if(!res.ok)throw new Error("Failed to set selected combo");return res.json()}export async function holmesSimilarProducts(productId,limit=8,productName,opts){if(typeof window!=="undefined"){const qs=new URLSearchParams({product_id:productId,limit:String(limit)});if(productName?.trim())qs.set("product_name",productName.trim());if(opts?.excludeDietary?.length)qs.set("excludeDietary",opts.excludeDietary.join(","));const res=await fetch(`/api/holmes/similar?${qs.toString()}`);if(!res.ok){const err=await res.json().catch(()=>({}));throw new Error(err.error??"Similar products failed")}return res.json()}const client=createAuroraClient();return client.store.holmesSimilar(productId,limit,productName,opts)}export async function getHomePersonalization(sid,opts){try{const client=createAuroraClient();const result=await client.store.homePersonalization(sid??"",undefined,opts);return result}catch{return null}}export async function getMe(userId){const client=createAuroraClient();return client.me({userId:userId})}
|
package/dist/lib/format-price.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export function formatPrice(
|
|
1
|
+
export function formatPrice(cents,currency="GBP"){return new Intl.NumberFormat("en-GB",{style:"currency",currency:currency}).format(cents/100)}export function toCents(rawPrice){if(rawPrice==null||!Number.isFinite(rawPrice))return undefined;return Math.round(Number(rawPrice)*100)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function holmesRecipeView(
|
|
1
|
+
export function holmesRecipeView(slug,title){if(typeof document==="undefined")return;const s=String(slug||"").trim();const t=String(title||"").trim();if(!s||!t)return;holmesMissionLockCombo();if(window.holmes?.setRecipeViewed)window.holmes.setRecipeViewed(s,t);document.dispatchEvent(new CustomEvent("holmes:recipeView",{detail:{slug:s,title:t}}))}export function holmesAddBundle(products,tableSlug){if(typeof document==="undefined")return;document.dispatchEvent(new CustomEvent("holmes:addBundle",{detail:{products:products,tableSlug:tableSlug}}))}const MEAL_SEARCH_LOCK_RE=/dinner|lunch|breakfast|brunch|supper|recipe|cook\b|meal\b|paella|curry|pasta|steak|roast|ingredient|grill|bbq|beef|lamb|pork|salmon|chicken|fish/i;export function holmesMissionLockCombo(){if(typeof document==="undefined")return;document.dispatchEvent(new CustomEvent("holmes:missionLock",{detail:{key:"combo_mission"}}))}export function holmesMissionLockClear(){if(typeof document==="undefined")return;document.dispatchEvent(new CustomEvent("holmes:missionLockClear"))}export function holmesSearch(query){if(typeof window==="undefined")return;const q=String(query||"").trim();if(!q)return;if(MEAL_SEARCH_LOCK_RE.test(q))holmesMissionLockCombo();if(window.holmes)window.holmes.setSearch(q);document.dispatchEvent(new CustomEvent("holmes:search",{detail:{q:q}}))}export function holmesProductView(productIds){if(typeof window==="undefined")return;const ids=Array.isArray(productIds)?productIds:[];if(ids.length===0)return;if(window.holmes)window.holmes.setProductsViewed(ids);document.dispatchEvent(new CustomEvent("holmes:productView",{detail:{productIds:ids}}))}export function holmesCartUpdate(count,items,bootstrap){if(typeof window==="undefined")return;if(window.holmes){window.holmes.setCartCount(count);if(items)window.holmes.setCartItems(items)}document.dispatchEvent(new CustomEvent("holmes:cartUpdate",{detail:{count:count,items:items??[],bootstrap:bootstrap===true}}))}
|
package/dist/lib/image-url.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const IMAGE_FIELDS=["image_url","image","thumbnail","photo"];const CONTENTFUL_CDN_RE=/^(https?:)?\/\/images\.(eu\.)?ctfassets\.net\//i;export function getThumbnailImageUrl(url,width=400,height=400){const raw=typeof url==="string"?url.trim():"";if(!raw)return null;if(!CONTENTFUL_CDN_RE.test(raw))return raw;try{const u=new URL(raw.startsWith("//")?`https:${raw}`:raw);const params=u.searchParams;if(params.has("w")||params.has("h"))return raw.startsWith("//")?`https:${raw}`:raw;params.set("w",String(Math.min(4e3,width)));params.set("h",String(Math.min(4e3,height)));params.set("fit","pad");params.set("fm","webp");return u.toString()}catch{return raw}}export function getImageUrlFromRecord(record){const field=IMAGE_FIELDS.find(f=>record[f]);return field?String(record[field]).trim()||null:null}export function resolveProductImageUrl(url,baseUrl){const raw=typeof url==="string"?url.trim():"";if(!raw)return null;if(raw.startsWith("http://")||raw.startsWith("https://")){return raw}if(raw.startsWith("//")){return`https:${raw}`}const base=baseUrl??process.env.NEXT_PUBLIC_IMAGE_BASE_URL?.trim()??(typeof window!=="undefined"?window.location?.origin:null)??process.env.NEXT_PUBLIC_APP_URL?.trim()??"";if(!base)return raw.startsWith("/")?raw:`/${raw}`;const normalized=base.replace(/\/$/,"");const path=raw.startsWith("/")?raw:`/${raw}`;return`${normalized}${path}`}
|
package/dist/lib/utils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export function getTimeOfDay(){const
|
|
1
|
+
export function getTimeOfDay(){const hour=(new Date).getHours();if(hour>=5&&hour<12)return"morning";if(hour>=12&&hour<17)return"afternoon";return"evening"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aurora-studio/starter-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build": "tsc -p tsconfig.build.json && node scripts/minify-dist.mjs",
|
|
6
6
|
"prepare": "tsc -p tsconfig.build.json && node scripts/minify-dist.mjs",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
"access": "public"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"@aurora-studio/sdk": "^0.2.
|
|
34
|
+
"@aurora-studio/sdk": "^0.2.29",
|
|
35
35
|
"lucide-react": ">=0.400",
|
|
36
36
|
"next": ">=14",
|
|
37
37
|
"react": "^18 || ^19",
|
|
38
38
|
"react-dom": "^18 || ^19"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@aurora-studio/sdk": "^0.2.
|
|
41
|
+
"@aurora-studio/sdk": "^0.2.29",
|
|
42
42
|
"@eslint/js": "^10.0.1",
|
|
43
43
|
"@types/node": "^22.0.0",
|
|
44
44
|
"@types/react": "^19.0.0",
|