1const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/imageUpload-BIv5lkJD.js","assets/index-CEISlULX.js","assets/index-CcMqAdLq.css"])))=>i.map(i=>d[i]); 2import{u as mt,a0 as ht,b as ft,a as pt,r as c,s as k,_ as gt,j as e,B as T,C as re,e as oe,U as xt}from"./index-CEISlULX.js";import{b as yt}from"./normalizeBookCoverUrl-CSpwtQu4.js";import{I as qe}from"./input-CaLoYHgx.js";import{T as wt}from"./textarea-DmWS1sXw.js";import{C as ye}from"./checkbox-CEKeZsY9.js";import{B as Ge}from"./badge-CmNrSZhw.js";import{P as vt}from"./progress-DpNZy0Ke.js";import{D as bt,a as _t,b as jt,c as kt,d as Nt,e as St}from"./dialog-DL4GLjds.js";import{p as He,a as Ke}from"./pdfToText-BChaoK4d.js";import{safeInsertVaultTaste as Ct}from"./safeVaultInsert-DUrA829o.js";import{a as It}from"./resizeForAI-BVHwt2i8.js";import{f as ne}from"./friendlyError-UL1BAfr1.js";import{A as $t}from"./arrow-left-Dt5WA4Nk.js";import{L as Je}from"./loader-circle-C0qiwHXp.js";import{C as Ye}from"./check-BFjtj0TV.js";import{F as Et}from"./file-text-CamhJ3w8.js";import{I as Tt}from"./image-UOq2Pr3V.js";import{C as we}from"./camera-CR32InGn.js";import{S as Pt}from"./sparkles-BpeD-uNo.js";import{a as Rt,F as Lt,S as Ft,D as Ut}from"./store-CkUsUNn0.js";import{H as Vt}from"./heart-BdtuOGcS.js";import{P as At}from"./package-CJ2GCcQQ.js";import{S as Qe}from"./shopping-bag-u8-RJDu1.js";import{W as ve}from"./wine-Cbzkns94.js";import{L as Mt}from"./landmark-DMJlToWM.js";import{H as Dt}from"./hotel-DboxzOQB.js";import{U as Xe}from"./utensils-crossed-BO4e05Nu.js";import{H as Bt}from"./headphones-Ca_UJjsb.js";import{B as Ot}from"./book-open-CJtqdthI.js";import{T as Ze}from"./tv-C88hoGGy.js";import{F as Wt}from"./film-kc4h8MJx.js";import"./index-CzOLp-Ui.js";import"./index-CKv5A6hs.js";import"./index-yCNHGKsJ.js";const zt={movie:e.jsx(Wt,{className:"h-4 w-4"}),show:e.jsx(Ze,{className:"h-4 w-4"}),"tv show":e.jsx(Ze,{className:"h-4 w-4"}),book:e.jsx(Ot,{className:"h-4 w-4"}),podcast:e.jsx(Bt,{className:"h-4 w-4"}),song:e.jsx(xt,{className:"h-4 w-4"}),album:e.jsx(Ut,{className:"h-4 w-4"}),restaurant:e.jsx(Xe,{className:"h-4 w-4"}),bar:e.jsx(Xe,{className:"h-4 w-4"}),hotel:e.jsx(Dt,{className:"h-4 w-4"}),attraction:e.jsx(Mt,{className:"h-4 w-4"}),store:e.jsx(Ft,{className:"h-4 w-4"}),wine:e.jsx(ve,{className:"h-4 w-4"}),spirits:e.jsx(ve,{className:"h-4 w-4"}),beer:e.jsx(ve,{className:"h-4 w-4"}),footwear:e.jsx(Qe,{className:"h-4 w-4"}),apparel:e.jsx(Qe,{className:"h-4 w-4"}),electronics:e.jsx(At,{className:"h-4 w-4"})},qt={media:"bg-primary/10 text-primary border-primary/20",place:"bg-accent/50 text-accent-foreground border-accent",product:"bg-orange-100 text-orange-800 border-orange-200 dark:bg-orange-900/30 dark:text-orange-300 dark:border-orange-700"},Gt=(S,F)=>{const h=(S||"").toLowerCase().trim();return h?["song","songs","music","album","albums","track","tracks"].includes(h)?"Music":["movie","movies","film","films"].includes(h)?"Movies":["show","shows","tv","tv show","series"].includes(h)?"Shows":["book","books","novel"].includes(h)?"Books":["podcast","podcasts"].includes(h)?"Podcasts":["creator","youtuber","channel"].includes(h)?"Creators":["game","games","video game"].includes(h)?"Games":["restaurant","cafe","bar","bakery","diner"].includes(h)?"Dining":["hotel","lodging","inn","resort"].includes(h)?"Stays":["attraction","landmark","museum","park"].includes(h)?"Attractions":["store","shop","boutique","market"].includes(h)?"Shopping":["wine","spirits","beer","cocktail"].includes(h)?"Wine & Spirits":["footwear","apparel","clothing","accessory"].includes(h)?"Fashion":["electronics","tech","gadget"].includes(h)?"Electronics":h.charAt(0).toUpperCase()+h.slice(1):F?F.charAt(0).toUpperCase()+F.slice(1):"Item"},be=S=>S&&S.split(` 3`).map(F=>{let h=F.replace(/(?:rated\s*)?\b\d(?:[.,]\d)?\s*(?:â |â|â|\/\s*5|\s*stars?\b)/gi," ").replace(/(?:â |â|â)\s*\d(?:[.,]\d)?/g," ").replace(/[â ââ]+/g," ").replace(/\(\s*[\d,]+\s*(?:reviews?)?\s*\)/gi," ").replace(/\b[\d,]{3,}\s+reviews?\b/gi," ");return h=h.replace(/\s+/g," ").replace(/\s*[ââ-]\s*(?=\s*[ââ-])/g,"").replace(/\s*[ââ-]\s*$/,"").replace(/^\s*[*â¢\u2022]\s*[ââ-]\s*/,"* ").replace(/\s*([ââ])\s*/g," $1 ").replace(/\s+/g," ").trim(),h}).join(` 4`),$s=()=>{var Be,Oe,We;const S=mt(),F=ht(),[h]=ft(),{toast:_}=pt(),K=c.useRef(null),ie=c.useRef(null),_e=c.useRef(null),je=c.useRef(null),et=!!((Oe=(Be=F.state)==null?void 0:Be.autoFiles)!=null&&Oe.length),[C,P]=c.useState(et?"processing":"upload"),[I,A]=c.useState([]),[O,W]=c.useState(new Set),[le,ce]=c.useState(!1),[ke,M]=c.useState(""),[Ne,D]=c.useState(0),[tt,U]=c.useState(""),[de,te]=c.useState(null),[Se,Ce]=c.useState(""),[J,ue]=c.useState(""),[Ht,me]=c.useState(null),[Kt,st]=c.useState(!1),Ie=c.useRef(null),$e=c.useRef(null),[z,q]=c.useState(!1),[Ee,he]=c.useState(""),[B,Y]=c.useState(!1),[se,at]=c.useState([]),[R,Te]=c.useState(""),[$,Pe]=c.useState(null),Re=c.useRef(!1);c.useEffect(()=>{if(Re.current||C!=="upload")return;const t=h.get("mode");t&&(Re.current=!0,setTimeout(()=>{var a,l,d;t==="photo"?(a=ie.current)==null||a.click():t==="file"?(l=K.current)==null||l.click():t==="list"&&((d=je.current)==null||d.focus())},100))},[C,h]);const Le=c.useRef(!1),fe=c.useRef(null);if(!Le.current){const t=F.state;(We=t==null?void 0:t.autoFiles)!=null&&We.length&&(fe.current=t.autoFiles,Le.current=!0)}c.useEffect(()=>{C==="review"&&(async()=>{const{data:{user:t}}=await k.auth.getUser();if(!t)return;const{data:a}=await k.from("user_guides").select("id, name").eq("user_id",t.id).order("created_at",{ascending:!1});a&&at([...a].sort((l,d)=>l.name.localeCompare(d.name)))})()},[C]);const Q="fyra:extraction-job",Fe=c.useCallback(async t=>{for(;;){const{data:a,error:l}=await k.from("extraction_jobs").select("status, progress, message, result_items, result_stats, error").eq("id",t).maybeSingle();if(l)throw l;if(!a)throw new Error("Extraction job not found â it may have expired.");const d=typeof a.progress=="number"?a.progress:0;if(D(Math.max(5,Math.min(d,85))),a.message&&U(a.message),a.status==="completed")return{items:a.result_items||[],stats:a.result_stats||{total:0,matched:0,unmatched:0}};if(a.status==="failed")throw new Error(a.error||"Extraction failed on the server.");await new Promise(o=>setTimeout(o,2e3))}},[]),E=c.useCallback(async(t,a,l)=>{var d,o;st(!1),P("processing"),D(l?10:5),U(l?"Resuming extraction...":"Starting extraction...");try{let u=l;if(!u){let n=a;if(a&&a.length>0){n=[];for(const i of a)try{n.push(await It(i))}catch{n.push(i)}}const{data:p,error:g}=await k.functions.invoke("extract-tastes-job",{body:{text:t,imageDataUrls:n}});if(g)throw g;if(!(p!=null&&p.jobId))throw new Error("Failed to start extraction job");u=p.jobId;try{localStorage.setItem(Q,u)}catch{}}const{items:v,stats:b}=await Fe(u);let y={total:b.total||v.length,matched:b.matched||0,unmatched:b.unmatched||0};if(v.length===0){try{localStorage.removeItem(Q)}catch{}_({title:"No items found",description:"We couldn't identify any items from that c
4ontent. Try a different source.",variant:"destructive"});const n=h.get("returnTo");S(n||"/home/add",{replace:!0});return}D(90),U("Checking your Vault for duplicates...");const f=v.filter(n=>n.matched||n.can_create),{data:{user:G}}=await k.auth.getUser();if(G&&f.length>0){const n=f.map(i=>i.entity_id).filter(Boolean),p=new Map;if(f.forEach(i=>{var s,r;if(i.entity_id&&(((s=i.category)==null?void 0:s.toLowerCase())==="book"||((r=i.category)==null?void 0:r.toLowerCase())==="books")){const j=i.entity_id.match(/(OL\d+W)/i);if(j){const m=j[1].toUpperCase(),w=`/works/${m}`;p.set(i.id,[m,w,i.entity_id]),n.includes(m)||n.push(m),n.includes(w)||n.push(w)}}}),n.length>0){const{data:i}=await k.from("user_vault_tastes").select("entity_id, entity_type").eq("user_id",G.id).in("entity_id",n);if(i&&i.length>0){const s=new Set(i.map(r=>`${r.entity_type}:${r.entity_id}`));f.forEach(r=>{if(r.entity_id&&s.has(`${r.domain}:${r.entity_id}`)&&(r.alreadyInVault=!0),!r.alreadyInVault&&p.has(r.id)){const j=p.get(r.id);for(const m of j)if(s.has(`media:${m}`)||s.has(`product:${m}`)){r.alreadyInVault=!0;break}}})}}const g=f.filter(i=>{var s,r;return!i.alreadyInVault&&(((s=i.category)==null?void 0:s.toLowerCase())==="book"||((r=i.category)==null?void 0:r.toLowerCase())==="books")});if(g.length>0){const i=r=>r.toLowerCase().replace(/[^a-z0-9]/g,"");if(g.map(r=>i(r.name)).filter(Boolean).length>0){const{data:r}=await k.from("user_vault_taste_search").select("title, vault_taste_id").eq("user_id",G.id).eq("level_2","Books");if(r&&r.length>0){const j=new Set(r.map(m=>i(m.title||"")));g.forEach(m=>{const w=i(m.name);w&&j.has(w)&&(m.alreadyInVault=!0)})}}}}A(f),me(y);const V=f.filter(n=>!n.alreadyInVault&&(n.matched||n.can_create)).map(n=>n.id);if(W(new Set(V)),f.length===0){_({title:"No items found",description:"We couldn't identify any items from that content. Try a different source.",variant:"destructive"});const n=h.get("returnTo");S(n||"/home/add",{replace:!0});return}D(95),U("Fetching cover art...");const L=f.filter(n=>{var p,g;return n.domain==="media"&&!n.thumbnail_url&&(((p=n.category)==null?void 0:p.toLowerCase())==="book"||((g=n.category)==null?void 0:g.toLowerCase())==="books")&&n.entity_id&&/OL\d+W/i.test(n.entity_id)});if(L.length>0)try{const n=L.map(g=>g.entity_id),{data:p}=await k.from("corpus_media_book").select("work_key, cover_id").in("work_key",n);if(p){const g=new Map;p.forEach(i=>{i.cover_id&&g.set(i.work_key,i.cover_id)}),f.forEach(i=>{i.entity_id&&g.has(i.entity_id)&&(i.thumbnail_url=yt(g.get(i.entity_id)))}),g.size>0&&A([...f])}}catch(n){console.warn("Corpus book cover lookup failed:",n)}const H=n=>{const p=n==null?void 0:n.toLowerCase();return p==="movie"?"movies":p==="show"||p==="tv show"?"shows":p==="book"?"books":p==="song"||p==="album"?"songs":null},ae=f.filter(n=>n.domain==="media"&&!n.thumbnail_url&&H(n.category));if(ae.length>0)try{const n=new Map,p=ae.map(i=>{const s=H(i.category),r=s==="songs"&&i.entity_id;return r&&n.set(i.entity_id,i.id),{id:r?i.entity_id:i.id,title:i.name,category:s,entity_id:i.entity_id||void 0}}),{data:g}=await k.functions.invoke("resolve-media-images",{body:{items:p,persist:!1}});if(g!=null&&g.images){const i=g.images;f.forEach(s=>{const r=i[s.id]||(s.entity_id?i[s.entity_id]:void 0);r&&(s.thumbnail_url=r)}),A([...f])}}catch(n){console.warn("Image resolution failed, continuing without:",n)}D(100),U("Done!");try{localStorage.removeItem(Q)}catch{}Ie.current=null,$e.current=null,setTimeout(()=>P("review"),500)}catch(u){console.error("Extraction error:",u);try{localStorage.removeItem(Q)}catch{}Ie.current=null,$e.current=null,_({title:"Extraction failed",description:(d=u.message)!=null&&d.includes("Failed to fetch")||(o=u.message)!=null&&o.includes("Failed to send")?"The request timed out â try a shorter document or paste key sections as text":u.message||"Failed to extract tastes from document",variant:"destructive"});const v=h.get("returnTo");S(v||"/home/add",{replace:!0})}},[_,S,h,Fe]),Ue=c.useRef(!1);c.useEffect(()=>{if(Ue.current)return;Ue.current=!0;let t=null;try{t=localStorage.getItem(Q)}catch{}t&&(console.log("[Extraction] Resuming extraction job",t),E(void 0,void 0,t))},[]);const Ve=c.useCallback((t,a=1600,l=.7)=>new Promise((d,o)=>{const u=new window.Image,v=URL.createObjectURL(t);u.onload=()=>{URL.revokeObjectURL(v);let{width:b,height:y}=u;if(b>a||y>
4a){const V=a/Math.max(b,y);b=Math.round(b*V),y=Math.round(y*V)}const f=document.createElement("canvas");f.width=b,f.height=y,f.getContext("2d").drawImage(u,0,0,b,y),d(f.toDataURL("image/jpeg",l))},u.onerror=()=>{URL.revokeObjectURL(v),o(new Error("Failed to load image"))},u.src=v}),[]);c.useEffect(()=>{const t=fe.current;if(!t)return;if(fe.current=null,t.every(l=>l.type.startsWith("image/")))E(void 0,t.map(l=>l.dataUrl));else{const l=t[0];if(l.type==="application/pdf")fetch(l.dataUrl).then(d=>d.blob()).then(d=>{const o=new File([d],l.name,{type:l.type});He(o).then(u=>E(u))});else{const d=l.dataUrl.split(",")[1]||"";let o="";try{const u=atob(d),v=Uint8Array.from(u,b=>b.charCodeAt(0));o=new TextDecoder("utf-8").decode(v)}catch{o=atob(d)}E(be(o))}}},[E]);const pe=c.useCallback(async t=>{const a=t.target.files;if(!a||a.length===0)return;const l=20*1024*1024;if(Array.from(a).every(o=>o.type.startsWith("image/"))&&a.length>=1){const o=Array.from(a).filter(u=>u.size<=l);if(o.length===0){_({title:"Files too large",description:"Max 20MB each",variant:"destructive"});return}P("processing"),D(5),U(`Compressing ${o.length} image${o.length>1?"s":""}...`);try{const u=await Promise.all(o.map(v=>Ve(v)));U(`Reading ${o.length} image${o.length>1?"s":""}...`),await E(void 0,u)}catch(u){_({title:"Image read failed",description:ne(u),variant:"destructive"}),P("upload")}}else{const o=a[0];if(o.size>l){_({title:"File too large",description:"Max 20MB",variant:"destructive"});return}if(o.type==="application/pdf"){P("processing"),D(5),U("Reading PDF...");try{const u=await He(o);await E(u)}catch(u){_({title:"PDF read failed",description:ne(u),variant:"destructive"}),P("upload")}}else if(o.type==="application/json"||o.name.endsWith(".json")){const u=await o.text();await E(u)}else if(o.type==="text/plain"||o.type==="text/markdown"||o.name.endsWith(".md")||o.name.endsWith(".txt")){const u=await o.text();await E(be(u))}else _({title:"Unsupported file",description:"Use PDF, text, JSON, or image files",variant:"destructive"})}K.current&&(K.current.value="")},[E,_,Ve]),rt=c.useCallback(async()=>{J.trim()&&await E(be(J.trim()))},[J,E]),ot=t=>{const a=I.find(l=>l.id===t);a!=null&&a.alreadyInVault||W(l=>{const d=new Set(l);return d.has(t)?d.delete(t):d.add(t),d})},nt=()=>{const t=I.filter(a=>!a.alreadyInVault);O.size===t.length?W(new Set):W(new Set(t.map(a=>a.id)))},it=async()=>{var a,l,d;const t=I.filter(o=>O.has(o.id)&&(o.matched||o.can_create)&&!o.alreadyInVault);if(t.length===0){_({title:"No items to save",description:"Select items to add to your Vault"});return}ce(!0),M(`Saving ${t.length} item${t.length===1?"":"s"}...`);try{const{data:{user:o}}=await k.auth.getUser();if(!o)throw new Error("Not logged in");const u={};for(const s of t)u[s.domain]=(u[s.domain]||0)+1;const v=((a=Object.entries(u).sort((s,r)=>r[1]-s[1])[0])==null?void 0:a[0])||"media";let b=0;const y=[],f=async(s,r,j)=>await Promise.race([Promise.resolve(s),new Promise((m,w)=>setTimeout(()=>w(new Error(`${j} timed out after ${r}ms`)),r))]),G=async s=>{let r=s.entity_id;if(s.matched&&s.domain==="media"&&(s.category==="song"||s.category==="album")&&s.isrc&&(r=s.isrc.toUpperCase()),!s.matched&&s.can_create&&!r)try{const{data:w,error:x}=await f(k.from("corpus_media_unmatched").insert({display_name:s.name,taxonomy_id:s.taxonomy_id,creator_name:s.subtitle||null,description:s.context||null,review_status:"pending",source_domain:"extraction"}).select("id").single(),15e3,`unmatched insert "${s.name}"`);if(x){console.error(`Error creating unmatched entry for ${s.name}:`,x);return}r=String(w.id)}catch(w){console.error(`Unmatched insert failed for ${s.name}:`,w);return}if(!r){console.warn(`Skipping ${s.name}: no entity_id`);return}
4const j=await Ct({userId:o.id,entityType:s.domain,entityId:r,row:{user_id:o.id,entity_type:s.domain,entity_id:r,source:"document-extraction",taxonomy_id:s.taxonomy_id,updated_at:new Date().toISOString()}}),m=j.vaultTasteId;if(!m){console.error(`Error saving ${s.name}:`,j.error);return}if(b++,j.created){const w={title:s.name,search_text:[s.name,s.subtitle].filter(Boolean).join(" ")};s.category&&(w.level_2=s.category.toLowerCase()),s.subtitle&&(w.subtitle=s.subtitle),s.thumbnail_url&&(w.thumbnail_url=s.thumbnail_url);try{await f(k.from("user_vault_taste_search").update(w).eq("vault_taste_id",m),1e4,`search patch "${s.name}"`)}catch(x){console.warn(`Search patch failed for ${s.name}:`,x)}}y.push({vault_taste_id:m,display_name:s.name})},V=5;for(let s=0;s<t.length;s+=V)M(`Saving items ${s+1}-${Math.min(s+V,t.length)} of ${t.length}...`),await Promise.allSettled(t.slice(s,s+V).map(G));if(y.length===0){_({title:"Couldn't save these items",description:"Nothing was added to your Vault. Please try again.",variant:"destructive"}),ce(!1),M("");return}let L=null;const H=Ee.trim()||`Extraction ${new Date().toLocaleDateString()}`;if(z&&y.length>0)try{M("Creating stash..."),console.log(`Creating stash "${H}" with ${y.length} items, domain=${v}`);const{data:s,error:r}=await f(k.from("user_guides").insert({user_id:o.id,name:H,extra:{domain:v}}).select("id").single(),15e3,"stash creation");if(r||!s)throw console.error("Guide creation failed:",r),r;L=s.id,console.log(`Guide created: ${L}`);const j=new Set,m=y.filter(N=>j.has(N.vault_taste_id)?!1:(j.add(N.vault_taste_id),!0));M(`Adding ${m.length} item${m.length===1?"":"s"} to stash...`);const w=await Promise.allSettled(m.map(N=>f(k.from("user_guide_items").insert({guide_id:s.id,taste_id:N.vault_taste_id,display_name:N.display_name,added_by_user_id:o.id}),1e4,`stash insert "${N.display_name}"`)));let x=0;w.forEach((N,Z)=>{var ee,ze;N.status==="fulfilled"&&!((ee=N.value)!=null&&ee.error)?x++:console.warn(`Guide item insert failed for "${m[Z].display_name}":`,N.status==="rejected"?N.reason:(ze=N.value)==null?void 0:ze.error)}),console.log(`Stash items added: ${x}/${m.length}`),x>0&&Ke(s.id,m.map(N=>N.vault_taste_id)).catch(()=>{}),x===0&&m.length>0&&_({title:"Stash created but items could not be added",description:"Check RLS policies",variant:"destructive"})}catch(s){console.error("Stash creation error:",s),_({title:"Items saved but Stash creation failed",variant:"destructive"})}if(B&&R&&y.length>0)try{M("Adding items to stash...");const s=new Set,r=y.filter(x=>s.has(x.vault_taste_id)?!1:(s.add(x.vault_taste_id),!0)),j=await Promise.allSettled(r.map(x=>f(k.from("user_guide_items").insert({guide_id:R,taste_id:x.vault_taste_id,display_name:x.display_name,added_by_user_id:o.id}),1e4,`stash insert "${x.display_name}"`)));let m=0;j.forEach((x,N)=>{var ee;const Z=x.status==="fulfilled"?(ee=x.value)==null?void 0:ee.error:{message:String(x.reason)};!Z||Z.code==="23505"?m++:console.warn(`Guide item insert failed for "${r[N].display_name}":`,Z.message)}),console.log(`Added ${m} items to existing stash ${R}`),m>0&&Ke(R,r.map(x=>x.vault_taste_id)).catch(()=>{});const w=((l=se.find(x=>x.id===R))==null?void 0:l.name)||"stash";L||(L=R)}catch(s){console.error("Add to stash error:",s),_({title:"Items saved but adding to stash failed",variant:"destructive"})}const ae=t.filter(s=>s.domain==="media"&&(s.category==="book"||s.category==="Book"||s.category==="Books"));for(const s of ae){const r=s.entity_id||"";/OL\d+W/i.test(r)&&k.functions.invoke("fetch-poster-book",{body:{work_key:r,title:s.name,author_name:s.subtitle||void 0}}).catch(m=>console.warn(`fetch-poster-book failed for ${s.name}:`,m))}const n=t.filter(s=>s.matched&&s.domain==="media"&&(s.category==="song"||s.category==="album")&&s.isrc);n.length>0&&(async()=>{for(const s of n)try{const r={isrc:s.isrc.toUpperCase(),updated_at:new Date().toISOString()};s.spotify_track_id&&(r.spotify_track_id=s.spotify_track_id),s.apple_catalog_id&&(r.apple_catalog_id=s.apple_catalog_id),await f(k.from("song_crosswalk").upsert(r,{onConflict:"isrc"}),5e3,`crosswalk seed "${s.name}"`)}catch(r){console.warn(`Crosswalk seed failed for ${s.name}:`,r)}})();const p=!!L,g=B&&!!R,i=g?((d=se.find(s=>
4s.id===R))==null?void 0:d.name)||"stash":H;Pe({savedCount:b,topDomain:v,stashCreated:p,addedToExistingStash:g,guideId:L,guideName:i}),A([]),W(new Set),q(!1),he(""),Y(!1),Te(""),P("done")}catch(o){console.error("Save error:",o),_({title:"Save failed",description:ne(o),variant:"destructive"})}finally{ce(!1),M("")}},lt=t=>{te(t),Ce(t.name)},ct=()=>{de&&(A(t=>t.map(a=>a.id===de.id?{...a,name:Se}:a)),te(null))},X=c.useRef(null),[ge,xe]=c.useState(null),dt=c.useCallback(async t=>{var l;const a=(l=t.target.files)==null?void 0:l[0];if(!(!a||!ge))try{const{data:{user:d}}=await k.auth.getUser();if(!d)return;const{uploadTastePhoto:o}=await gt(async()=>{const{uploadTastePhoto:b}=await import("./imageUpload-BIv5lkJD.js");return{uploadTastePhoto:b}},__vite__mapDeps([0,1,2])),u=`${d.id}/${crypto.randomUUID()}.jpg`,v=await o(u,a);A(b=>b.map(y=>y.id===ge?{...y,thumbnail_url:v}:y))}catch(d){console.error("Photo upload error:",d),_({title:"Upload failed",description:ne(d),variant:"destructive"})}finally{xe(null),X.current&&(X.current.value="")}},[ge,_]),Ae=I.filter(t=>!t.alreadyInVault),Me=I.filter(t=>O.has(t.id)&&(t.matched||t.can_create)&&!t.alreadyInVault).length,De=I.filter(t=>t.alreadyInVault).length,ut=c.useMemo(()=>{const t=I.filter(l=>!l.alreadyInVault),a=I.filter(l=>l.alreadyInVault);return[...t,...a]},[I]);return e.jsxs("div",{className:"min-h-screen bg-background overflow-x-hidden max-w-full",children:[e.jsx("div",{className:"sticky top-0 z-40 bg-background/95 backdrop-blur border-b border-border pt-[env(safe-area-inset-top)]",children:e.jsxs("div",{className:"flex items-center gap-3 px-4 py-3 max-w-lg mx-auto",children:[e.jsx(T,{variant:"ghost",size:"icon",onClick:()=>S(h.get("returnTo")||-1),children:e.jsx($t,{className:"h-5 w-5"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h1",{className:"text-lg font-semibold",children:C==="review"?"Extracted items":C==="processing"?"Processing upload...":"Extract"}),e.jsxs("p",{className:"text-xs text-muted-foreground truncate",children:[C==="upload"&&"",C==="processing"&&"",C==="review"&&`${I.length} items found${De>0?` · ${De} already in Vault`:""}`]})]}),C==="review"&&I.length>0&&e.jsxs(T,{onClick:it,disabled:le||Me===0,size:"sm",className:"flex-shrink-0",children:[le?e.jsx(Je,{className:"h-4 w-4 animate-spin mr-1"}):e.jsx(Ye,{className:"h-4 w-4 mr-1"}),"Add ",Me]})]})}),e.jsxs("div",{className:"max-w-lg mx-auto px-4 py-4 space-y-4 overflow-hidden",children:[C==="upload"&&e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsxs("button",{onClick:()=>{var t;return(t=K.current)==null?void 0:t.click()},className:"w-full flex items-center gap-3 p-4 rounded-lg border border-border bg-card hover:bg-accent/50 transition-colors text-left",children:[e.jsx("div",{className:"p-2 rounded-full bg-primary/10",children:e.jsx(Et,{className:"h-5 w-5 text-primary"})}),e.jsx("div",{children:e.jsx("p",{className:"text-sm font-medium text-foreground",children:"File"})})]}),e.jsxs("button",{onClick:()=>{var t;return(t=ie.current)==null?void 0:t.click()},className:"w-full flex items-center gap-3 p-4 rounded-lg border border-border bg-card hover:bg-accent/50 transition-colors text-left",children:[e.jsx("div",{className:"p-2 rounded-full bg-primary/10",children:e.jsx(Tt,{className:"h-5 w-5 text-primary"})}),e.jsx("div",{children:e.jsx("p",{className:"text-sm font-medium text-foreground",children:"Photo(s)"})})]}),e.jsxs("button",{onClick:()=>{var t;return(t=_e.current)==null?void 0:t.click()},className:"w-full flex items-center gap-3 p-4 rounded-lg border border-border bg-card hover:bg-accent/50 transition-colors text-left",children:[e.jsx("div",{className:"p-2 rounded-full bg-primary/10",children:e.jsx(we,{className:"h-5 w-5 text-primary"})}),e.jsx("div",{children:e.jsx("p",{className:"text-sm font-medium text-foreground",children:"Camera"})})]})]}),e.jsx("input",{ref:K,type:"file",accept:".pdf,.json,.txt,.md",className:"hidden",onChange:pe}),e.jsx("input",{ref:ie,type:"file",accept:"image/*",multiple:!0,className:"hidden",onChange:pe}),e.jsx("input",{ref:_e,type:"file",accept:"image/*",capture:"environment",className:"hidden",onChange:pe}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"h-px flex-1 bg-border"}),e.jsx("span",{className:"text-xs text-muted-foreground uppercase tracking-wider",children:"or paste"}),e.jsx("div",{className:"h-px flex-1 bg-border"})]}),e.jsx(wt,{ref:je,placeholder:"List of restaurants, movies, sites, etc.",value:J,onChange:t=>ue(t.target.value),rows:6}),J.trim()&&e.jsxs(T,{onClick:rt,className:"w-full",children:[e.jsx(Pt,{className:"h-4 w-4 mr-2"}),"Extract tastes"]})]})]}),C==="processing"&&e.jsx(re,{children:e.jsxs(oe,{className:"py-12 flex flex-col items-center gap-4",children:[e.jsx(Je,{className:"h-10 w-10 animate-spin text-primary"}),e.jsxs("div",{className:"text-center space-y-2",children:[e.jsx("p",{className:"font-medium",children:tt}),e.jsx(vt,{value:Ne,className:"w-64"}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[Ne,"%"]})]})]})}),C==="review"&&e.jsxs("div",{className:"space-y-3",children:[le&&ke&&e.jsx("div",{className:"rounded-md border border-border bg-card px-3 py-2 text-xs text-muted-foreground",children:ke}),I.length>0&&e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("div",{className:`flex items-center gap-2 px-3 py-1.5 rounded-lg border cursor-pointer transition-colors ${z?"bg-green-100 border-green-300 dark:bg-green-900/30 dark:border-green-700":"bg-card border-border"}`,onClick:()=>{q(!z),z||Y(!1)},children:[e.jsx(ye,{checked:z,onCheckedChange:t=>{q(!!t),t&&Y(!1)},onClick:t=>t.stopPropagation(),id:"create-stash",className:"flex-shrink-0"}),e.jsxs("label",{htmlFor:"create-stash",className:"flex items-center gap-1.5 text-xs font-medium cursor-pointer whitespace-nowrap",children:[e.jsx(Rt,{className:"h-3.5 w-3.5 text-primary flex-shrink-0"}),"Create stash"]})]}),se.length>0&&e.jsxs("div",{className:`flex items-center gap-2 px-3 py-1.5 rounded-lg border cursor-pointer transition-colors ${B?"bg-blue-100 border-blue-300 dark:bg-blue-900/30 dark:border-blue-700":"bg-card border-border"}`,onClick:()=>{Y(!B),B||q(!1)},children:[e.jsx(ye,{checked:B,onCheckedChange:t=>{Y(!!t),t&&q(!1)},onClick:t=>t.stopPropagation(),id:"add-to-stash",className:"flex-shrink-0"}),e.jsxs("label",{htmlFor:"add-to-stash",className:"flex items-center gap-1.5 text-xs font-medium cursor-pointer whitespace-nowrap",children:[e.jsx(Lt,{className:"h-3.5 w-3.5 text-primary flex-shrink-0"}),"Add to stash"]})]}),e.jsx("div",{className:"flex-1"}),e.jsx(T,{variant:"ghost",size:"sm",onClick:nt,className:"text-xs flex-shrink-0",children:O.size===Ae.length&&Ae.length>0?"Deselect all":"Select all"})]}),z&&e.jsx(qe,{placeholder:"Stash name, e.g. 'Napa Valley trip'",value:Ee,onChange:t=>he(t.target.value),className:"text-sm"}),B&&e.jsxs("select",{value:R,onChange:t=>Te(t.target.value),className:"w-full h-9 rounded-md border border-input bg-background px-3 text-sm r
4ing-offset-background focus:outline-none focus:ring-2 focus:ring-ring",children:[e.jsx("option",{value:"",children:"Select a stashâ¦"}),se.map(t=>e.jsx("option",{value:t.id,children:t.name},t.id))]}),I.length===0&&e.jsx(re,{children:e.jsxs(oe,{className:"py-12 text-center",children:[e.jsx("p",{className:"text-muted-foreground",children:"No more items to review."}),e.jsx(T,{variant:"outline",className:"mt-4",onClick:()=>S(h.get("returnTo")||"/home/add",{replace:!0}),children:"Back to Save"})]})}),e.jsx("div",{className:"grid gap-3 w-full overflow-hidden",children:ut.map(t=>{var l;const a=t.alreadyInVault;return e.jsx(re,{className:`transition-all w-full overflow-hidden ${a?"opacity-50":O.has(t.id)?"border-primary shadow-[0_0_0_1px_hsl(var(--primary)/0.4)]":"opacity-80"} ${!t.matched&&!t.can_create?"border-dashed":""}`,children:e.jsxs(oe,{className:"p-3 flex items-center gap-3 w-full overflow-hidden",children:[e.jsx(ye,{checked:a?!1:O.has(t.id),onCheckedChange:()=>ot(t.id),className:"flex-shrink-0",disabled:!t.matched&&!t.can_create||a}),t.thumbnail_url?e.jsxs("div",{className:"relative w-10 h-10 flex-shrink-0 group/thumb",children:[e.jsx("img",{src:t.thumbnail_url,alt:t.name,className:"w-10 h-10 rounded object-cover",onError:d=>{d.target.style.display="none"}}),!a&&e.jsx("button",{className:"absolute inset-0 rounded bg-black/40 flex items-center justify-center opacity-0 group-hover/thumb:opacity-100 transition-opacity",onClick:d=>{var o;d.stopPropagation(),xe(t.id),(o=X.current)==null||o.click()},children:e.jsx(we,{className:"h-3.5 w-3.5 text-white"})})]}):e.jsx("button",{className:"w-10 h-10 rounded bg-muted flex items-center justify-center flex-shrink-0 hover:bg-muted/80 transition-colors relative group/thumb",onClick:d=>{var o;a||(d.stopPropagation(),xe(t.id),(o=X.current)==null||o.click())},disabled:a,children:a?e.jsx(Vt,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(e.Fragment,{children:e.jsx(we,{className:"h-4 w-4 text-muted-foreground"})})}),e.jsxs("div",{className:"flex-1 min-w-0 overflow-hidden",onClick:()=>!a&<(t),children:[e.jsx("p",{className:`font-medium text-sm truncate ${a?"":"underline decoration-dotted underline-offset-2 cursor-pointer"}`,children:t.name}),a?e.jsx("p",{className:"text-xs text-muted-foreground italic",children:"Already in Vault"}):e.jsxs(e.Fragment,{children:[t.subtitle&&e.jsx("p",{className:"text-xs text-muted-foreground truncate",children:t.subtitle}),t.context&&!t.subtitle&&e.jsx("p",{className:"text-xs text-muted-foreground truncate",children:t.context})]}),e.jsxs("div",{className:"flex flex-wrap gap-1 mt-1",children:[e.jsx(Ge,{variant:"outline",className:`text-[10px] px-1.5 py-0 ${qt[t.domain]||""}`,children:t.domain}),e.jsxs(Ge,{variant:"outline",className:"text-[10px] px-1.5 py-0",children:[zt[(l=t.category)==null?void 0:l.toLowerCase()],e.jsx("span",{className:"ml-0.5 truncate max-w-[80px]",children:Gt(t.category,t.domain)})]})]})]})]})},t.id)})}),I.length>0&&e.jsx(T,{variant:"outline",className:"w-full",onClick:()=>{P("upload"),A([]),W(new Set),ue(""),me(null),q(!1),he("")},children:"Start over with new document"})]}),C==="done"&&$&&e.jsx(re,{children:e.jsxs(oe,{className:"py-12 flex flex-col items-center gap-5 text-center",children:[e.jsx("div",{className:"rounded-full bg-primary/10 p-4",children:e.jsx(Ye,{className:"h-10 w-10 text-primary"})}),e.jsxs("div",{className:"space-y-1",children:[e.jsxs("p",{className:"text-xl font-semibold",children:[$.savedCount," ",$.savedCount===1?"item":"items"," added to your Vault!"]}),$.stashCreated&&e.jsx("p",{className:"text-sm text-muted-foreground",children:$.addedToExistingStash?`Added to stash "${$.guideName}"`:`Stash "${$.guideName}" created`})]}),e.jsxs("div",{className:"flex flex-col gap-2 w-full max-w-xs",children:[e.jsx(T,{onClick:()=>S(`/vault?type=${$.topDomain}`),className:"w-full",children:"Go to Vault"}),$.stashCreated&&$.guideId&&e.jsx(T,{variant:"outline",onClick:()=>S(`/vault?guide=${$.guideId}&guideName=${encodeURIComponent($.guideName)}`),className:"w-full",children:"Go to Stash"}),e.jsx(T,{variant:"ghost",onClick:()=>{P("upload"),Pe(null),ue(""),me(null)},className:"w-full",children:"Upload another"})]})]})})]}),e.jsx(bt,{open:!!de,onOpenChange:t=>!t&&te(null),children:e.jsxs(_t,{className:"max-w-sm",children:[e.jsxs(jt,{children:[e.jsx(kt,{children:"Edit item"}),e.jsx(Nt,{children:"Update the name used for matching"})]}),e.jsx(qe,{value:Se,onChange:t=>Ce(t.target.value)}),e.jsxs(St,{children:[e.jsx(T,{variant:"outline",onClick:()=>te(null),children:"Cancel"}),e.jsx(T,{onClick:ct,children:"Save"})]})]})}),e.jsx("input",{ref:X,type:"file",accept:"image/*",className:"hidden",onChange:dt})]})};export{$s 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.