PageSourceSearch

https://fyra.life/assets/ScanProduct-iZl082Fw.js

js fyra.life collected 2026-10-02 02:01:54 UTC 23,676 bytes, 2 lines download raw bytes

1const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/detectBookAndSaveAsMedia-Cw0SbQQW.js","assets/normalizeBookCoverUrl-CSpwtQu4.js","assets/persistExternalThumbnails-xoX97dVo.js","assets/index-CEISlULX.js","assets/index-CcMqAdLq.css"])))=>i.map(i=>d[i]);
2import{u as Fe,b as qe,r as x,s as m,v as f,_ as ge,w as V,j as e,B as w,C as ee,X as Me}from"./index-CEISlULX.js";import{I as G}from"./input-CaLoYHgx.js";import{u as Re}from"./useDefaultShareVisibility-CJnViBYM.js";import{u as ze}from"./useCamera-BM2GS31r.js";import{i as $e,l as Le,a as Oe,d as Ue,B as Ke,M as We,c as He}from"./BarcodeScanner-C8LZypjc.js";import{m as Ve}from"./moderateContent-BDHrihnJ.js";import{s as te}from"./humanizeTitle-2ZcthfUi.js";import{r as Ge}from"./recordChecklistMilestone-CFmUBPrs.js";import{A as Xe}from"./arrow-left-Dt5WA4Nk.js";import{K as Ye}from"./keyboard-BVXJEfl6.js";import{L as ae}from"./loader-circle-C0qiwHXp.js";import{S as re}from"./scan-barcode-CvSB7jiw.js";import{C as Q}from"./check-BFjtj0TV.js";import{P as xe}from"./pencil-DZdaQ7Ww.js";import{R as Qe}from"./rotate-ccw-BiNSGnP5.js";import{C as Z}from"./camera-CR32InGn.js";import{E as Ze}from"./eye-OdF1rFDD.js";import"./index-IYA0blDJ.js";import"./external-link-DoOQ4sOr.js";import"./triangle-alert-Byinhax_.js";const M={Footwear:57,Shoes:57,Apparel:58,Clothing:58,Fashion:58,Wine:49,"Sparkling Wine":50,"Port & Fortified Wine":51,Spirit:52,Spirits:52,Liquor:52,Beer:53,Ale:53,Lager:53,IPA:53,"Coffee & Tea":56,Coffee:56,Tea:56,Electronics:68,Gadgets:68,Computers:68,Computer:68,Audio:69,Headphones:69,Speakers:69,"Sports Equipment":71,Golf:73,Sports:71,Fitness:71,"Home Appliance":65,Appliance:65,Appliances:65,"Home Furniture":64,Furniture:64,Food:62,Snacks:62,"Packaged Food":62,Grocery:62,"Fresh Food":61,Health:63,Vitamins:63,Supplements:63,Medicine:63,"Personal Care":63,Beauty:60,Cosmetics:60,Skincare:60,Toys:70,Games:70,Baby:70,Pet:72,"Pet Supplies":72,Automotive:74,Car:74,Office:67,"Office Supplies":67,Home:64,Kitchen:65,Garden:66,Cleaning:63,Household:63},Je=["wine","cabernet","merlot","pinot","chardonnay","sauvignon","riesling","champagne","prosecco","cava","rosé","brut","sparkling","whiskey","whisky","bourbon","scotch","vodka","tequila","mezcal","gin","rum","cognac","brandy","liqueur","liquor","bitters","beer","ale","lager","ipa","stout","porter","pilsner","spirit","spirits","proof)","abv","750ml","750 ml","375ml","1.75l","1.75 l","80 proof","40%"];function se(j,C){const u=`${j} ${C}`.toLowerCase(),P=/beverage|drink|soda|juice|water|coffee|tea|cocoa|kombucha|cider/i.test(u);return Je.some(N=>u.includes(N))?/wine|cabernet|merlot|pinot|chardonnay|sauvignon|riesling|rosé/.test(u)?49:/champagne|prosecco|cava|sparkling wine|brut/.test(u)?50:/port|sherry|madeira|marsala|fortified/.test(u)?51:/beer|ale|lager|ipa|stout|porter|pilsner/.test(u)?53:52:P?56:0}function De(j){if(!j)return null;const C=j.split(/\s*[>/]\s*/);for(let u=C.length-1;u>=0;u--){const P=C[u].trim();if(M[P])return P;const N=Object.keys(M).find(X=>X.toLowerCase()===P.toLowerCase()||P.toLowerCase().includes(X.toLowerCase()));if(N)return N}return null}[...new Set(Object.keys(M))].sort();const bt=()=>{const j=Fe(),[C]=qe(),[u,P]=x.useState(null),{defaultVisibility:N}=Re(u),{openCamera:X,openCameraOnly:ye,isNative:oe,openSettingsForCamera:ve}=ze(),[S,v]=x.useState("scanning"),[s,R]=x.useState(null),[ne,ie]=x.useState(""),[we,J]=x.useState(!1),[z,$]=x.useState(!1),le=
2x.useRef(null),[F,A]=x.useState(""),[L,B]=x.useState(""),[K,T]=x.useState(""),[et,q]=x.useState(""),[be,I]=x.useState(""),[ce,_e]=x.useState(""),[_,W]=x.useState([]),[O,U]=x.useState(null),[je,Ne]=x.useState(null),[de,ue]=x.useState(null);x.useEffect(()=>{m.auth.getSession().then(({data:{session:a}})=>{P((a==null?void 0:a.user)??null)})},[]);const me=x.useRef(!1);x.useEffect(()=>{C.get("mode")==="photo"&&!me.current&&(me.current=!0,R({barcode:`photo-${Date.now()}`,name:null,brand:null,category:null,image_url:null,price:null,ean:null,upc:null,offers:[]}),v("capturing"),setTimeout(()=>H(),100))},[C]);const D=x.useCallback(async a=>{var r,p,h,o;if(v("loading"),J(!1),$e(a))try{const t=await Le(a);if(t&&u){const i=t.work_key,l=te(t.title)||`ISBN ${a}`,{data:d}=await m.from("user_vault_tastes").select("id").eq("user_id",u.id).eq("entity_id",i).maybeSingle();if(d){f.info("Already in your vault"),b();return}const{saveBookAsMedia:y}=await ge(async()=>{const{saveBookAsMedia:g}=await import("./detectBookAndSaveAsMedia-Cw0SbQQW.js");return{saveBookAsMedia:g}},__vite__mapDeps([0,1]));if(!await y(m,u.id,{workKey:i,title:l,authorName:t.author_name||void 0,coverUrl:t.cover_url||void 0,source:"scan-product",shareVisibility:N}))throw new Error("Could not save book");V(),f.success(`📚 "${l}" saved as a Book!`),b();return}const{data:n}=await m.functions.invoke("upcitemdb-lookup",{body:{barcode:a}});if(n!=null&&n.found&&n.title){if(u){const i=`isbn-${a.replace(/\D/g,"")}`,l=te(n.title)||`ISBN ${a}`,{data:d}=await m.from("user_vault_tastes").select("id").eq("user_id",u.id).eq("entity_id",i).maybeSingle();if(d){f.info("Already in your vault"),b();return}const{error:y}=await m.from("user_vault_tastes").insert({user_id:u.id,entity_type:"media",entity_id:i,source:"scan-product",share_visibility:N,taxonomy_id:575});if(y)if(y.code==="23505")f.info("Already in your vault");else throw y;else V(),f.success(`📚 "${l}" saved as a Book!`),Y(u.id,i,l,n.brand||"","Books",((r=n.images)==null?void 0:r[0])||null)}b();return}f.info("Book not found in our library. Try searching for it in Media → Books."),b();return}catch{f.error("Could not look up book"),b();return}const c=async t=>{if(!u)return!1;const i=`magazine-${a.replace(/\D/g,"")||Date.now()}`,l=te(t.title)||t.title||`Magazine ${a}`,{data:d}=await m.from("user_vault_tastes").select("id").eq("user_id",u.id).eq("entity_id",i).maybeSingle();if(d)return f.info("Already in your vault"),!0;const{error:y}=await m.from("user_vault_tastes").insert({user_id:u.id,entity_type:"media",entity_id:i,source:"scan-product",share_visibility:N,taxonomy_id:We});return y?y.code==="23505"?(f.info("Already in your vault"),!0):(console.error("saveScannedMagazine insert error:",y),!1):(V(),f.success(`📖 "${l}" saved as a Magazine!`),Y(u.id,i,l,t.brand||"","Magazines",t.imageUrl||null),!0)};if(Oe(a)&&u)try{const{data:t}=await m.functions.invoke("upcitemdb-lookup",{body:{barcode:a}}),n=(t==null?void 0:t.title)||`Magazine ${a}`,i=(t==null?void 0:t.brand)||null,l=((p=t==null?void 0:t.images)==null?void 0:p[0])||null;if(await c({title:n,brand:i,imageUrl:l})){b();return}}catch(t){console.warn("[scan] ISSN magazine lookup failed:",t)}try{const{data:t,error:n}=await m.functions.invoke("upcitemdb-lookup",{body:{barcode:a}});if(n)throw n;if(t!=null&&t.found&&u&&Ue({barcode:a,title:t.title,brand:t.brand,category:t.category})&&await c({title:t.title||`Magazine ${a}`,brand:t.brand||null,imageUrl:((h=t.images)==null?void 0:h[0])||null})){b();return}if(t!=null&&t.found){let i=null;const l=(t.offers||[]).map(g=>Number(g.price)).filter(g=>g>0&&isFinite(g));if(l.length>0){l.sort((k,Ee)=>k-Ee);const g=Math.floor(l.length/2);i=l.length%2===0?Math.round((l[g-1]+l[g])/2*100)/100:l[g]}else t.lowest_recorded_price!=null&&t.lowest_recorded_price>0&&(i=t.lowest_recorded_price);const d=t.category||null,y=De(d);let E=y||d;if(!y&&d&&/beverage/i.test(d)){const g=se(t.title||"",d);E={49:"Wine",50:"Sparkling Wine",51:"Port & Fortified Wine",52:"Spirit",53:"Beer",56:"Coffee & Tea"}[g]||d}R({barcode:t.barcode,name:t.title||null,brand:t.brand||null,category:E,image_url:((o=t.images)==null?void 0:o[0])||null,price:i,ean:t.ean||null,upc:t.upc||null,offers:t.offers||[]}),A(t.title||""),B(t.brand||""),T(E||""),q(i!=null?String(i):""),I(t.size||""),v("preview"),(t.title||d)&&m.functions.invoke("categorize-item",{body:{item_name:t.title||"",brand:t.brand||"",description:d||"",domain:"product"}}).then(({data:g})=>{g!=null&&g.level_2_name&&(T(g.level_2_name),R(k=>k&&{...k,category:g.level_2_name}))}).catch(()=>{})}else R({barcode:a,name:null,brand:null,category:null,image_url:null,price:null,ean:null,upc:null,offers:[]}),A(""),B(""),T(""),q(""),I(""),v("not-found")}catch(t){console.error("Lookup error:",t),f.error("Could not look up barcode — you can add it manually"),R({barcode:a,name:null,brand:null,category:null,image_url:null,price:null,ean:null,upc:null,offers:[]}),A(""),B(""),T(""),q(""),I(""),v("not-found")}},[u,N]),Se=x.useCallback(a=>
2{if(/^https?:\/\//i.test(a.trim())){(async()=>{try{await m.functions.invoke("ext-save-url",{body:{url:a.trim()}})}catch{}j("/saved-urls")})();return}D(a)},[D,j]),fe=()=>{const a=ne.replace(/\D/g,"");if(a.length<8){f.error("Enter a valid barcode (8+ digits)");return}D(a)},H=async(a=!1)=>{var c;if(oe)try{const r=a?await ye():await X();if(r==="permission-denied"){f.error("Fyra needs camera access. Tap here to open Settings.",{duration:6e3,action:{label:"Open Settings",onClick:()=>ve()}});return}if(!(r!=null&&r.webPath))return;const h=await(await fetch(r.webPath)).blob(),o=new FileReader;o.onloadend=()=>{const t=o.result;U(t),v("photo-review")},o.readAsDataURL(h)}catch(r){console.error("Camera error:",r),f.error("Could not open camera")}else(c=le.current)==null||c.click()},ke=a=>{const c=a.target.files;if(!c||c.length===0)return;const p=Array.from(c).map(h=>new Promise(o=>{const t=new FileReader;t.onloadend=()=>o(t.result),t.readAsDataURL(h)}));Promise.all(p).then(h=>{if(h.length>1){const o=h.slice(0,-1).map(t=>({base64:t,keep:!0}));W(t=>[...t,...o])}U(h[h.length-1]),v("photo-review")}),a.target.value=""},Ce=()=>{O&&W(a=>[...a,{base64:O,keep:!0}]),U(null),v("capturing"),setTimeout(()=>H(!0),150)},Pe=async()=>{if(!O)return;const a=[..._,{base64:O,keep:!0}];W(a),U(null),v("loading");const c=await Ve(a.map(r=>r.base64));if(!c.safe){f.error("This content can't be posted: "+(c.reason||"Policy violation")),v("capturing"),W([]);return}try{const{data:r,error:p}=await m.functions.invoke("extract-product-from-image",{body:{images:a.map(h=>h.base64)}});if(p)throw p;A((r==null?void 0:r.name)||""),B((r==null?void 0:r.brand)||""),T((r==null?void 0:r.category)||""),q((r==null?void 0:r.price)||""),I((r==null?void 0:r.size)||""),v("reviewing")}catch(r){console.error("Extraction error:",r),f.error("Could not analyze photo — add details manually"),A(""),B(""),T(""),q(""),I(""),v("reviewing")}},Ae=()=>{U(null),v("capturing"),setTimeout(()=>H(!0),150)},Be=async(a,c,r)=>{const p=a.filter(t=>t.keep);if(p.length===0)return null;let h=null;const o=[];for(const t of p){const n=await fetch(t.base64).then(d=>d.blob()),i=`${r}/${c}/${Date.now()}.jpg`,{error:l}=await m.storage.from("product-photos").upload(i,n,{contentType:"image/jpeg"});if(l){console.error("Photo upload error:",l);continue}if(o.push(i),!h){const{data:d}=m.storage.from("product-photos").getPublicUrl(i);h=d.publicUrl}}return(async()=>{for(let t=0;t<p.length&&t<o.length;t++)try{const n=await He(p[t].base64);if(n&&n!==p[t].base64){const i=await fetch(n).then(l=>l.blob());await m.storage.from("product-photos").upload(o[t],i,{contentType:"image/jpeg",upsert:!0})}}catch(n){console.warn("[bg cleanProductImage]",n)}})(),h},Y=async(a,c,r,p,h,o)=>{try{const{data:t}=await m.from("user_vault_tastes").select("id").eq("user_id",a).eq("entity_id",c).single();if(!t){console.warn("updateSearchRow: vault row not found for entity_id",c);return}const n=async()=>{const d=r&&!/^\d{8,14}$/.test(r)?r:"Unknown product",{error:y,count:E}=await m.from("user_vault_taste_search").update({title:d,subtitle:p||null,level_1:h||"Other",level_2:h||"Other",thumbnail_url:o,search_text:[r,p].filter(Boolean).join(" ")}).eq("vault_taste_id",t.id).select();return{error:y,count:E}};let{error:i,count:l}=await n();if(i){console.error("updateSearchRow update error:",i);return}l===0&&(console.warn("updateSearchRow: 0 rows updated, retrying in 1500ms for vault_taste_id",t.id),await new Promise(d=>setTimeout(d,1500)),{error:i,count:l}=await n(),i?console.error("updateSearchRow retry error:",i):l===0&&console.warn("updateSearchRow: still 0 rows after retry — search row may be missing for vault_taste_id",t.id)),o&&!o.includes("/storage/v1/object/public/")&&!o.startsWith("data:")&&ge(async()=>{const{persistExternalThumbnails:d}=await import("./persistExternalThumbnails-xoX97dVo.js");return{persistExternalThumbnails:d}},__vite__mapDeps([2,3,4])).then(({persistExternalThumbnails:d})=>{d(a,[{vault_taste_id:t.id,thumbnail_url:o,domain:"product"}])}).catch(()=>{})}catch(t){console.error("Search row update error:",t)}},pe=(a,c,r,p,h)=>{m.functions.invoke("categorize-item",{body:{item_name:r,brand:p,description:h,domain:"product"}}).then(async({data:o})=>{if(!(o!=null&&o.taxonomy_id)||!(o!=null&&o.level_2_name))return;await m.from("user_vault_tastes").update({taxonomy_id:o.taxonomy_id}).eq("user_id",a).eq("entity_id",c);let t=o.level_2_name;const{data:n}=await m.from("ref_taxonomy").select("parent_id").eq("id",o.taxonomy_id).maybeSingle();if(n!=null&&n.parent_id){const{data:l}=await m.from("ref_taxonomy").select("name").eq("id",n.parent_id).maybeSingle();l!=null&&l.name&&(t=l.name)}
2const{data:i}=await m.from("user_vault_tastes").select("id").eq("user_id",a).eq("entity_id",c).maybeSingle();i&&await m.from("user_vault_taste_search").update({level_1:t,level_2:o.level_2_name,taxonomy_id:o.taxonomy_id}).eq("vault_taste_id",i.id)}).catch(o=>{console.warn("[ScanProduct] Background taxonomy resolution failed:",o)})},he=async(a=!1)=>{if(!u){f.error("Sign in to save products");return}if(!s)return;if(!(F||(s==null?void 0:s.name)||"").trim()){f.error("Add a product name before saving");return}$(!0);try{let r=M[K]??M[(s==null?void 0:s.category)??""]??null;r||(r=se(F||(s==null?void 0:s.name)||"",K||(s==null?void 0:s.category)||"")),r||(r=3);const p={};s.ean&&(p.ean=s.ean),s.upc&&(p.upc=s.upc);const{data:h}=await m.from("user_vault_tastes").select("id").eq("user_id",u.id).eq("entity_id",s.barcode).maybeSingle();if(h){f.info("Already in your vault"),b(),$(!1);return}const{error:o}=await m.from("user_vault_tastes").insert({user_id:u.id,entity_type:"product",entity_id:s.barcode,source:"scan-product",share_visibility:N,taxonomy_id:r});if(o)if(o.code==="23505")f.info("Already in your vault");else throw o;else{V(),f.success("Saved to Fyra!"),await Y(u.id,s.barcode,F||s.name||"",L||s.brand||"",K||s.category||"",s.image_url);const t=F||s.name||"",n=L||s.brand||"",i=K||s.category||"";t&&pe(u.id,s.barcode,t,n,i)}a?b():j("/vault?type=product&openEntity="+encodeURIComponent(s.barcode))}catch(r){console.error("Save error:",r),f.error("Could not save product")}finally{$(!1)}},Te=async()=>{if(!u){f.error("Sign in to save products");return}const a=F.trim();if(!a){f.error("Add a product name before saving");return}const c=[..._],r=(s==null?void 0:s.barcode)||`photo-${Date.now()}`,p=a,h=L,o=K,t=ce,n=u.id,i=N,l=(s==null?void 0:s.category)??"";$(!0);try{const d=await Be(c,r,n);let y=M[o]??M[l]??null;y||(y=se(p||"",o||l||"")),y||(y=3);const{data:E}=await m.from("user_vault_tastes").select("id").eq("user_id",n).eq("entity_id",r).maybeSingle();if(E){f.info("Already in your vault"),b(),$(!1);return}const{error:g}=await m.from("user_vault_tastes").insert({user_id:n,entity_type:"product",entity_id:r,source:"scan-product",share_visibility:i,taxonomy_id:y});if(g)if(g.code==="23505")f.info("Already in your vault"),b();else throw g;else{if(await Y(n,r,p,h,o,d),p&&pe(n,r,p,h,o),t.trim()){const{data:k}=await m.from("user_vault_tastes").select("id").eq("user_id",n).eq("entity_id",r).single();k&&await m.from("vault_taste_notes").upsert({user_id:n,vault_taste_id:k.id,note_text:t.trim()},{onConflict:"user_id,vault_taste_id"})}d&&ue(d),Ne(r),ue(d||(c.length>0?c[0].base64:null)),v("saved"),V(),f.success("Saved to Fyra!"),Ge("barcode_scan")}}catch(d){console.error("Save error:",d),f.error("Failed to save — please try again")}finally{$(!1)}},b=()=>{v("scanning"),R(null),J(!1),ie(""),W([]),U(null)},Ie=()=>{v("capturing"),setTimeout(()=>H(),100)};return e.jsxs("div",{className:"min-h-screen bg-background flex flex-col",children:[e.jsx("input",{ref:le,type:"file",accept:"image/*",multiple:!0,className:"hidden",onChange:ke}),e.jsxs("header",{className:"pt-[env(safe-area-inset-top)] border-b border-border px-4 py-2 flex justify-between items-center gap-4",children:[e.jsx("div",{className:"flex items-center gap-2",children:e.jsx(w,{onClick:()=>j(C.get("returnTo")||"/home/add?domain=product"),variant:"ghost",size:"icon",className:"h-10 w-10",children:e.jsx(Xe,{className:"h-7 w-7"})})}),e.jsx("div",{className:"flex items-center gap-1"})]}),e.jsxs("div",{className:"flex-1 overflow-auto px-4 py-4 space-y-4",children:[S==="scanning"&&e.jsxs(e.Fragment,{children:[e.jsx(Ke,{onDetected:Se,active:S==="scanning",isNativeOverride:oe}),e.jsx("p",{className:"text-center text-sm text-muted-foreground",children:"Point camera at a barcode or QR code"}),we?e.jsxs("div",{className:"flex gap-2 max-w-sm mx-auto",children:[e.jsx(G,{placeholder:"Enter barcode…",value:ne,onChange:a=>ie(a.target.value),onKeyDown:a=>a.key==="Enter"&&fe(),className:"font-mono",autoFocus:!0}),e.jsx(w,{onClick:fe,size:"sm",children:"Look up"})]}):e.jsxs("button",{onClick:()=>J(!0),className:"flex items-center gap-1.5 mx-auto text-xs text-muted-foreground hover:text-foreground transition-colors",children:[e.jsx(Ye,{className:"h-3.5 w-3.5"}),"Paste barcode instead"]})]}),S==="loading"&&e.jsxs("div",{className:"flex flex-col items-center justify-center py-16 gap-3",children:[e.jsx(ae,{className:"h-8 w-8 animate-spin text-muted-foreground"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Analyzing…"})]}),S==="preview"&&s&&e.jsxs(ee,{className:"p-4 space-y-4",children:[e.jsxs("div",{className:"flex gap-4",children:[s.image_url?e.jsx("img",{src:s.image_url,alt:s.name||"Product",className:"w-24 h-24 object-contain rounded-md bg-muted flex-shrink-0"}):e.jsx("div",{className:"w-24 h-24 rounded-md bg-muted flex items-center justify-center flex-shrink-0",children:e.jsx(re,{className:"h-8 w-8 text-muted-foreground"})}),e.jsxs("div",{className:"flex-1 min-w-0 space-y-1",children:[e.jsx("h2",{className:"font-semibold text-lg leading-tight line-clamp-2",children:s.name||"Unknown product"}),s.brand&&e.jsx("p",{className:"text-sm text-muted-foreground",children:s.brand}),s.category&&e.jsx("p",{className:"text-xs text-muted-foreground line-clamp-1",children:s.category})]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(w,{onClick:()=>he(!1),disabled:z,className:"flex-1 gap-1.5",children:[z?e.jsx(ae,{className:"h-4 w-4 animate-spin"}):e.jsx(Q,{className:"h-4 w-4"}),"Save to Fyra"]}),e.jsxs(w,{onClick:()=>{A(s.name||""),B(s.brand||""),T(s.category||""),q(""),I(""),v("reviewing")},variant:"outline",className:"gap-1.5",children:[e.jsx(xe,{className:"h-4 w-4"}),"Edit"]})]}),e.jsxs(w,{onClick:()=>{z||he(!0)},disabled:z,variant:"secondary",size:"sm",className:"w-full gap-1.5",children:[e.jsx(Qe,{className:"h-3.5 w-3.5"}),"Save & scan another"]})]}),S==="not-found"&&s&&e.jsxs(ee,{className:"p-4 space-y-4",children:[e.jsxs("div",{className:"flex flex-col items-center gap-2 py-4",children:[e.jsx(re,{className:"h-10 w-10 text-muted-foreground"}),e.jsxs("p",{className:"text-sm text-muted-foreground text-center",children:["No product found for ",e.jsx("span",{className:"font-mono font-medium text-foreground",children:s.barcode})]})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs(w,{onClick:Ie,className:"gap-1.5",children:[e.jsx(Z,{className:"h-4 w-4"}),"Take a Photo"]}),e.jsxs(w,{onClick:()=>{A(""),B(""),T(""),q(""),I(""),v("reviewing")},variant:"outline",className:"gap-1.5",children:[e.jsx(xe,{className:"h-4 w-4"}),"Add manually"]})]}),e.jsx("button",{onClick:b,className:"text-xs text-muted-foreground hover:text-foreground mx-auto block",children:"Scan again"})]}),S==="capturing"&&e.jsxs("div",{className:"flex flex-col items-center gap-4 py-8",children:[_.length>0&&e.jsx("div",{className:"grid grid-cols-3 gap-3 w-full",children:_.map((a,c)=>e.jsx("img",{src:a.base64,alt:`Photo ${c+1}`,className:"w-full aspect-square object-cover rounded-lg border border-border"},c))}),e.jsx(Z,{className:"h-12 w-12 text-muted-foreground"}),_.length>0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:`${_.length} photo${_.length>
21?"s":""} taken`}),e.jsxs(w,{onClick:()=>H(),className:"gap-1.5 h-14 text-base px-8",children:[e.jsx(Z,{className:"h-5 w-5"}),"Take a Photo"]})]}),S==="photo-review"&&O&&e.jsxs("div",{className:"flex flex-col flex-1 gap-6",children:[_.length>0&&e.jsxs("div",{className:"space-y-1",children:[e.jsxs("p",{className:"text-xs text-muted-foreground",children:[_.length," photo",_.length>1?"s":""," already added"]}),e.jsx("div",{className:"flex gap-2 overflow-x-auto pb-1",children:_.map((a,c)=>e.jsx("img",{src:a.base64,alt:`Photo ${c+1}`,className:"w-14 h-14 object-cover rounded-md border border-border flex-shrink-0 opacity-70"},c))})]}),e.jsx("div",{className:"flex-1 flex items-center justify-center",children:e.jsx("img",{src:O,alt:"Photo to review",className:"w-full max-h-[60vh] object-contain rounded-xl border border-border"})}),e.jsxs("div",{className:"space-y-3 pb-4",children:[e.jsxs(w,{onClick:Ce,variant:"outline",className:"w-full h-12 text-sm gap-2",children:[e.jsx(Z,{className:"h-4 w-4"}),"Add another photo of this product"]}),e.jsxs(w,{onClick:Pe,className:"w-full h-14 text-base gap-2",children:[e.jsx(Q,{className:"h-5 w-5"}),"Done with photos — continue"]}),e.jsxs(w,{onClick:Ae,variant:"ghost",className:"w-full h-12 text-sm gap-2 text-muted-foreground",children:[e.jsx(Me,{className:"h-4 w-4"}),"Don't use — retake"]})]})]}),S==="reviewing"&&e.jsxs(ee,{className:"p-4 space-y-3",children:[_.length>0&&e.jsx("div",{className:"flex gap-2 overflow-x-auto pb-1",children:_.map((a,c)=>e.jsx("img",{src:a.base64,alt:`Photo ${c+1}`,className:"w-20 h-20 object-cover rounded-md border border-border flex-shrink-0"},c))}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(G,{placeholder:"Product name",value:F,onChange:a=>A(a.target.value),autoFocus:!0}),e.jsx(G,{placeholder:"Brand",value:L,onChange:a=>B(a.target.value)}),e.jsx(G,{placeholder:"Size (optional)",value:be,onChange:a=>I(a.target.value)}),e.jsx(G,{placeholder:"Notes (optional)",value:ce,onChange:a=>_e(a.target.value)})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(w,{onClick:Te,disabled:z,className:"flex-1 gap-1.5",children:[z?e.jsx(ae,{className:"h-4 w-4 animate-spin"}):e.jsx(Q,{className:"h-4 w-4"}),"Save to Fyra"]}),e.jsx(w,{onClick:()=>j("/home/add"),variant:"outline",children:"Cancel"})]})]}),S==="saved"&&e.jsxs("div",{className:"flex flex-col items-center gap-6 py-12 px-4 text-center",children:[de&&e.jsx("img",{src:de,alt:"Saved product",className:"w-32 h-32 object-cover rounded-xl border border-border"}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"flex items-center justify-center gap-2",children:e.jsx("div",{className:"h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center",children:e.jsx(Q,{className:"h-5 w-5 text-primary"})})}),e.jsxs("h2",{className:"text-lg font-semibold text-foreground",children:[F||"Product"," added!"]}),L&&e.jsx("p",{className:"text-sm text-muted-foreground",children:L})]}),e.jsxs("div",{className:"flex flex-col gap-3 w-full max-w-xs",children:[e.jsxs(w,{onClick:b,className:"h-14 text-base gap-2",children:[e.jsx(re,{className:"h-5 w-5"}),"Scan another"]}),e.jsxs(w,{onClick:()=>{j(`/vault?type=product&openEntity=${encodeURIComponent(je||"")}`,{replace:!0})},variant:"outline",className:"h-14 text-base gap-2",children:[e.jsx(Ze,{className:"h-5 w-5"}),"View in vault"]})]})]})]})]})};export{bt 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.