PageSourceSearch

https://planmymeal.ai/assets/shopping-list-BI1Z-mGf.js

js planmymeal.ai collected 2026-10-05 12:49:54 UTC 11,314 bytes, 6 lines download raw bytes

1import{c as J,b as V,a as _,r as b,f as U,g as C,j as e,C as x,m as S,n as D,a7 as k,h as L,I as T,B as p,p as l,a5 as F,V as W,W as Y,Y as Z,Z as X,_ as ee,a8 as E,u as se,S as te}from"./index-CMe2EXTk.js";import{C as ae}from"./checkbox-CKobEZl5.js";import{S as G}from"./shopping-cart-JyGk952r.js";import{P as ie,T as M}from"./trash-2-CfOcasWp.js";import{A as ne}from"./archive-DhZKGGcq.js";import{A as re}from"./AppShell-3FP4qaG2.js";import"./index-BO4IXonq.js";/**
2 * @license lucide-react v0.453.0 - ISC
3 *
4 * This source code is licensed under the ISC license.
5 * See the LICENSE file in the root directory of this source tree.
6 */const ce=J("Eye",[["path",{d:"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",key:"1nclc0"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]);function oe(){const{toast:d}=V(),[q]=_(),[h,u]=b.useState({startDate:new Date().toISOString().split("T")[0],endDate:new Date(Date.now()+10080*60*1e3).toISOString().split("T")[0]}),[c,$]=b.useState(null);b.useEffect(()=>{const s=new URLSearchParams(window.location.search),t=s.get("startDate"),a=s.get("endDate");t&&a&&u({startDate:t,endDate:a})},[q]);const{data:j,isLoading:z}=U({queryKey:["/api/shopping-lists"],enabled:!0}),g=(j==null?void 0:j.shoppingLists)||[],f=C({mutationFn:async s=>{const t=await fetch("/api/generate-shopping-list",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!t.ok){const a=await t.json().catch(()=>({}));throw new Error(a.message||"Failed to generate shopping list")}return t.json()},onSuccess:s=>{E.invalidateQueries({queryKey:["/api/shopping-lists"]}),d({title:"Shopping list generated!",description:`Created shopping list with ${s.shoppingList.items.length} items`})},onError:s=>{const t=s.message,a=t.includes("no meals found")||t.includes("Add some meals to your meal planner");d({title:a?"No meals found":"Error generating shopping list",description:a?`${t} Go to the meal planner to add meals first.`:t,variant:"destructive"})}}),v=C({mutationFn:async({listId:s,items:t,isArchived:a,action:i})=>{const o=await fetch(`/api/shopping-lists/${s}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({items:t,...a!==void 0&&{isArchived:a}})});if(!o.ok){const n=await o.json().catch(()=>({}));throw new Error(n.message||"Failed to update shopping list")}return{...await o.json(),action:i,isArchived:a}},onSuccess:s=>{E.invalidateQueries({queryKey:["/api/shopping-lists"]}),s.action==="archive"?d({title:"Shopping list archived",description:"List has been moved to archive."}):s.action==="toggle"&&s.isArchived&&d({title:"Shopping list completed!",description:"List has been moved to archive."})},onError:s=>{d({title:"Error updating shopping list",description:s.message,variant:"destructive"})}}),N=C({mutationFn:async s=>{const t=await fetch(`/api/shopping-lists/${s}`,{method:"DELETE"});if(!t.ok){const a=await t.json().catch(()=>({}));throw new Error(a.message||"Failed to delete shopping list")}return t.json()},onSuccess:()=>{E.invalidateQueries({queryKey:["/api/shopping-lists"]}),d({title:"Shopping list deleted",description:"Shopping list has been successfully deleted"})},onError:s=>{d({title:"Error deleting shopping list",description:s.message,variant:"destructive"})}}),B=()=>{if(!h.startDate||!h.endDate){d({title:"Invalid date range",description:"Please select both start and end dates",variant:"destructive"});return}f.mutate(h)},I=s=>{confirm("Are you sure you want to delete this shopping list?")&&N.mutate(s)},K=(s,t)=>{v.mutate({listId:s,items:t,isArchived:!0,action:"archive"})},Q=(s,t,a)=>{const i=a.map((n,m)=>m===t?{...n,checked:!n.checked}:n),o=i.every(n=>n.checked);v.mutate({listId:s,items:i,isArchived:o,action:"toggle"})},P=s=>s.reduce((t,a)=>{const i=a.category||"Other";return t[i]||(t[i]=[]),t[i].push(a),t},{}),A=s=>{const t={Produce:"bg-accent text-accent-foreground",Protein:"bg-accent text-accent-foreground",Dairy:"bg-accent text-accent-foreground",Pantry:"bg-accent text-accent-foreground",Other:"bg-muted text-muted-foreground"};return t[s]||t.Other};return z?e.jsx("div",{className:"flex justify-center p-8",children:"Loading shopping lists..."}):e.jsxs("div",{className:"space-y-6",children:[e.jsxs(x,{"data-testid":"card-generate-shopping-list",children:[e.jsxs(S,{children:[e.jsxs(D,{className:"flex items-center gap-2",children:[e.jsx(G,{className:"h-5 w-5"}),"Smart Shopping List Generator"]}),e.jsx(k,{children:"Generate a shopping list from your meal plans for any date range"})]}),e.jsx(L,{children:e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"grid grid-cols-1 gap-4 sm:grid-cols-2",children:[e.jsxs("div",{className:"min-w-0 flex flex-col gap-2",children:[e.jsx("label",{htmlFor:"start-date",className:"text-sm font-medium",children:"Start Date"}),e.jsx(T,{id:"start-date",type:"date",value:h.startDate,onChange:s=>u(t=>({...t,startDate:s.target.value})),className:"[color-scheme:light] dark:[color-scheme:dark]","data-testid":"input-start-date"})]}),e.jsxs("div",{className:"min-w-0 flex flex-col gap-2",children:[e.jsx("label",{htmlFor:"end-date",className:"text-sm font-medium",children:"End Date"}),e.jsx(T,{id:"end-date",type:"date",value:h.endDate,onChange:s=>u(t=>({...t,endDate:s.target.value})),className:"[color-scheme:light] dark:[color-scheme:dark]","data-testid":"input-end-date"})]})]}),e.jsxs(p,{onClick:B,disabled:f.isPending,className:"w-fit","data-testid":"button-generate-shopping-list",children:[e.jsx(ie,{className:"h-4 w-4 mr-2"}),f.isPending?"Generating...":"Generate Shopping List"]})]})})]}),e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-4",children:[e.jsx("h2",{className:"text-xl font-semibold",children:"Active Shopping Lists"}),g.filter(s=>!s.isArchived).length===0?e.jsx(x,{children:e.jsx(L,{className:"pt-6",children:e.jsxs("div",{className:"text-center text-muted-foreground",children:[e.jsx(G,{className:"h-12 w-12 mx-auto mb-4 opacity-50"}),e.jsx("p",{children:"No active shopping lists. Generate your first one above!"})]})})}):g.filter(s=>!s.isArchived).map(s=>{const t=s.items||[],a=P(t),i=t.filter(n=>n.checked).length,o=t.length;return e.jsxs(x,{"data-testid":`card-shopping-list-${s.id}`,children:[e.jsx(S,{children:e.jsxs("div",{className:"flex justify-between items-start",children:[e.jsxs("div",{children:[e.jsx(D,{className:"text-lg",children:s.name}),e.jsxs(k,{children:[i," of ",o," items completed"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(l,{variant:"outline",children:[o>0?Math.round(i/o*100):0,"% Complete"]}),e.jsx(p,{size:"icon",variant:"ghost",onClick:()=>
6K(s.id,t),disabled:v.isPending,"data-testid":`button-archive-shopping-list-${s.id}`,className:"h-8 w-8",children:e.jsx(ne,{className:"h-4 w-4"})}),e.jsx(p,{size:"icon",variant:"ghost",onClick:()=>I(s.id),disabled:N.isPending,"data-testid":`button-delete-shopping-list-${s.id}`,className:"h-8 w-8 text-destructive hover:text-destructive",children:e.jsx(M,{className:"h-4 w-4"})})]})]})}),e.jsx(L,{children:e.jsx("div",{className:"space-y-4",children:Object.entries(a).map(([n,m])=>e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(l,{className:A(n),children:n}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[m.length," item",m.length!==1?"s":""]})]}),e.jsx("div",{className:"grid gap-2",children:m.map((r,H)=>{const O=s.items||[],R=O.findIndex(w=>w.ingredient===r.ingredient&&w.amount===r.amount&&w.unit===r.unit),y=r.checked||!1;return e.jsxs("div",{className:"flex items-center gap-3 p-2 rounded-lg border hover-elevate","data-testid":`item-${r.ingredient.replace(/\s+/g,"-").toLowerCase()}`,children:[e.jsx(ae,{checked:y,onCheckedChange:()=>Q(s.id,R,O),"data-testid":`checkbox-${r.ingredient.replace(/\s+/g,"-").toLowerCase()}`}),e.jsxs("div",{className:`flex-1 ${y?"line-through text-muted-foreground":""}`,children:[e.jsx("span",{className:"font-medium",children:r.ingredient}),r.amount&&r.unit&&e.jsxs("span",{className:"text-sm text-muted-foreground ml-2",children:[r.amount," ",r.unit]})]}),y&&e.jsx(F,{className:"h-4 w-4 text-primary"})]},`${r.ingredient}-${H}`)})})]},n))})})]},s.id)})]}),g.filter(s=>s.isArchived).length>0&&e.jsxs("div",{className:"space-y-4",children:[e.jsx("h2",{className:"text-xl font-semibold text-muted-foreground",children:"Archived Lists"}),g.filter(s=>s.isArchived).map(s=>{const t=s.items||[];t.filter(i=>i.checked).length;const a=t.length;return e.jsx(x,{"data-testid":`card-archived-shopping-list-${s.id}`,className:"opacity-60",children:e.jsx(S,{children:e.jsxs("div",{className:"flex justify-between items-start",children:[e.jsxs("div",{children:[e.jsxs(D,{className:"text-lg flex items-center gap-2",children:[s.name,e.jsx(l,{variant:"secondary",className:"text-xs",children:"Archived"})]}),e.jsxs(k,{children:["Completed with ",a," items"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(l,{variant:"outline",className:"bg-accent text-accent-foreground border-primary/20",children:"100% Complete"}),e.jsx(p,{size:"icon",variant:"ghost",onClick:()=>$(s),"data-testid":`button-view-archived-shopping-list-${s.id}`,className:"h-8 w-8",children:e.jsx(ce,{className:"h-4 w-4"})}),e.jsx(p,{size:"icon",variant:"ghost",onClick:()=>I(s.id),disabled:N.isPending,"data-testid":`button-delete-archived-shopping-list-${s.id}`,className:"h-8 w-8 text-destructive hover:text-destructive",children:e.jsx(M,{className:"h-4 w-4"})})]})]})})},s.id)})]})]}),e.jsx(W,{open:!!c,onOpenChange:()=>$(null),children:e.jsxs(Y,{className:"max-w-2xl max-h-[80vh] overflow-y-auto",children:[e.jsxs(Z,{children:[e.jsxs(X,{className:"flex items-center gap-2",children:[c==null?void 0:c.name,e.jsx(l,{variant:"secondary",className:"text-xs",children:"Archived"})]}),e.jsxs(ee,{children:["Completed shopping list with ",((c==null?void 0:c.items)||[]).length," items"]})]}),c&&e.jsx("div",{className:"space-y-4 mt-4",children:Object.entries(P(c.items||[])).map(([s,t])=>e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(l,{className:A(s),children:s}),e.jsxs("span",{className:"text-sm text-muted-foreground",children:[t.length," item",t.length!==1?"s":""]})]}),e.jsx("div",{className:"grid gap-2",children:t.map((a,i)=>e.jsxs("div",{className:"flex items-center gap-3 p-2 rounded-lg border opacity-75","data-testid":`archived-item-${a.ingredient.replace(/\s+/g,"-").toLowerCase()}`,children:[e.jsx(F,{className:"h-4 w-4 text-primary"}),e.jsxs("div",{className:"flex-1 line-through text-muted-foreground",children:[e.jsx("span",{className:"font-medium",children:a.ingredient}),a.amount&&a.unit&&e.jsxs("span",{className:"text-sm text-muted-foreground ml-2",children:[a.amount," ",a.unit]})]})]},`${a.ingredient}-${i}`))})]},s))})]})})]})}function ue(){return se(te.shoppingList),e.jsxs(re,{children:[e.jsxs("div",{className:"mb-6",children:[e.jsx("h1",{className:"text-3xl font-semibold tracking-tight",children:"Smart Shopping Lists"}),e.jsx("p",{className:"mt-1 text-muted-foreground text-sm",children:"Generate organised shopping lists from your meal plans and track y
6our grocery shopping progress."})]}),e.jsx(oe,{})]})}export{ue as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.