deckhearth/.next/server/chunks/855.js

8 lines
310 KiB
JavaScript
Raw Normal View History

exports.id=855,exports.ids=[855],exports.modules={182:(a,b,c)=>{"use strict";c.a(a,async(a,d)=>{try{c.d(b,{A:()=>k});var e=c(8732),f=c(2015),g=c(8462),h=c(6659),i=c(3622),j=a([g,h,i]);[g,h,i]=j.then?(await j)():j;let k=()=>{let a=(0,g.useQueryClient)(),[b,c]=(0,f.useState)(!1),[d,j]=(0,f.useState)(null),[k,l]=(0,f.useState)({search:"",game:"",isFavorite:!1}),[m,n]=(0,f.useState)("grid"),{data:o=[],isLoading:p}=(0,g.useQuery)({queryKey:["collections",k],queryFn:()=>h.LO.collections.getCollections(k)}),q=(0,g.useMutation)({mutationFn:h.LO.collections.deleteCollection,onSuccess:()=>{a.invalidateQueries({queryKey:["collections"]})}}),r=(0,g.useMutation)({mutationFn:({id:a,isFavorite:b})=>h.LO.collections.updateCollection(a,{isFavorite:b}),onSuccess:()=>{a.invalidateQueries({queryKey:["collections"]})}}),s=o.filter(a=>{let b=!k.search||a.name.toLowerCase().includes(k.search.toLowerCase())||a.description?.toLowerCase().includes(k.search.toLowerCase()),c=!k.game||a.game===k.game,d=!k.isFavorite||a.isFavorite;return b&&c&&d});return(0,e.jsxs)("div",{className:"space-y-6",children:[(0,e.jsxs)("div",{className:"flex items-center justify-between",children:[(0,e.jsxs)("div",{children:[(0,e.jsx)("h1",{className:"text-2xl font-bold text-surface-900 dark:text-white",children:"Collections"}),(0,e.jsx)("p",{className:"text-surface-600 dark:text-surface-400 mt-1",children:"Organize and manage your card collections"})]}),(0,e.jsxs)("button",{onClick:()=>c(!0),className:"bg-gradient-to-r from-primary-500 to-accent-500 hover:from-primary-600 hover:to-accent-600 text-white px-4 py-2 rounded-xl font-medium transition-all duration-200 shadow-md hover:shadow-lg transform hover:-translate-y-0.5",children:[(0,e.jsx)("svg",{className:"w-4 h-4 mr-2 inline",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,e.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 6v6m0 0v6m0-6h6m-6 0H6"})}),"New Collection"]})]}),(0,e.jsx)("div",{className:"bg-white dark:bg-surface-800 rounded-xl border border-surface-200 dark:border-surface-700 p-4",children:(0,e.jsxs)("div",{className:"space-y-4",children:[(0,e.jsxs)("div",{className:"relative",children:[(0,e.jsx)("div",{className:"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none",children:(0,e.jsx)("svg",{className:"h-5 w-5 text-surface-400",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,e.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"})})}),(0,e.jsx)("input",{type:"text",value:k.search,onChange:a=>l(b=>({...b,search:a.target.value})),placeholder:"Search collections...",className:"w-full pl-10 pr-4 py-3 bg-surface-50 dark:bg-surface-700 border border-surface-300 dark:border-surface-600 rounded-xl text-surface-900 dark:text-white placeholder-surface-500 dark:placeholder-surface-400 focus:outline-none focus:ring-2 focus:ring-primary-500 transition-colors"})]}),(0,e.jsxs)("div",{className:"flex items-center justify-between",children:[(0,e.jsxs)("div",{className:"flex space-x-2 overflow-x-auto pb-2",children:[(0,e.jsxs)("select",{value:k.game,onChange:a=>l(b=>({...b,game:a.target.value})),className:"px-3 py-2 bg-surface-50 dark:bg-surface-700 border border-surface-300 dark:border-surface-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary-500 transition-colors whitespace-nowrap",children:[(0,e.jsx)("option",{value:"",children:"All Games"}),(0,e.jsx)("option",{value:"MTG",children:"Magic: The Gathering"}),(0,e.jsx)("option",{value:"POKEMON",children:"Pok\xe9mon"}),(0,e.jsx)("option",{value:"LORCANA",children:"Disney Lorcana"}),(0,e.jsx)("option",{value:"YUGIOH",children:"Yu-Gi-Oh!"}),(0,e.jsx)("option",{value:"OTHER",children:"Other"})]}),(0,e.jsx)("button",{onClick:()=>l(a=>({...a,isFavorite:!a.isFavorite})),className:`px-3 py-2 rounded-lg text-sm font-medium transition-colors whitespace-nowrap ${k.isFavorite?"bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-300":"bg-surface-50 dark:bg-surface-700 text-surface-700 dark:text-sur
1. Card name (exact spelling)
2. Set name and code
3. Game type (Magic: The Gathering, Pokemon, or Lorcana)
4. All visible text
5. Card type and rarity if visible
Provide accurate information only. Format as JSON with fields: cardName, setName, setCode, game, cardType, rarity, rawText`,images:[b],stream:!1})});if(!c.ok)throw Error(`Ollama API error: ${c.status}`);let d=(await c.json()).response;try{let a=JSON.parse(d);return{cardName:a.cardName||"",setName:a.setName,setCode:a.setCode,cardType:a.cardType,rarity:a.rarity,rawText:a.rawText||d,confidence:85,game:a.game?.toUpperCase()||"UNKNOWN"}}catch{return{cardName:this.extractCardNameFromText(d),rawText:d,confidence:75,game:this.detectGameFromText(d)}}}catch(a){throw console.error("Ollama OCR error:",a),Error(`Ollama OCR failed: ${a.message}`)}}extractCardNameFromText(a){return a.split("\n").map(a=>a.trim()).filter(a=>a.length>0).find(a=>a.length>3&&a.length<50)||"Unknown Card"}detectGameFromText(a){let b=a.toLowerCase();return b.includes("pokemon")||b.includes("hp")?"POKEMON":b.includes("mana")||b.includes("creature")?"MTG":b.includes("lorcana")?"LORCANA":"UNKNOWN"}}let k=new i,l=new j,m=({onCardScanned:a,onError:b,isActive:c,maxQueueSize:f=100})=>{let g=(0,e.useRef)(null),i=(0,e.useRef)(null),j=(0,e.useRef)(null),m=(0,e.useRef)(null),n=(0,e.useRef)(0),[o,p]=(0,e.useState)(!1),[q,r]=(0,e.useState)({isScanning:!1,isProcessing:!1,message:"",countdown:0}),[s,t]=(0,e.useState)(0),[u,v]=(0,e.useState)(new Set),[w,x]=(0,e.useState)(!1);(0,e.useEffect)(()=>{(async()=>{try{let a=localStorage.getItem("openai_api_key"),b=localStorage.getItem("tcg_vault_token");if(b)try{let a=await fetch("/api/user/preferences",{headers:{Authorization:`Bearer ${b}`,"Content-Type":"application/json"}});if(a.ok){let b=await a.json(),c=b.preferences?.ocrSettings?.openai_api_key;if(c){k.setApiKey(c),x(!0),console.log("✅ OCR configured with user preferences API key");return}}}catch(a){console.log("Could not load user preferences, checking localStorage...")}a?(k.setApiKey(a),x(!0),console.log("✅ OCR configured with localStorage API key")):(console.log("❌ No OpenAI API key found. OCR scanning will not work."),x(!1))}catch(a){console.error("Error initializing OCR:",a),x(!1)}})()},[]),(0,e.useEffect)(()=>(c?y():z(),()=>{z()}),[c]),(0,e.useEffect)(()=>{if(!o||!c||!w)return;let a=setInterval(()=>{Date.now()-n.current>5e3&&(()=>{if(q.isProcessing||s>=f)return;m.current&&clearTimeout(m.current),r(a=>({...a,isScanning:!0,message:"Card detected, stabilizing...",countdown:3}));let a=3,b=setInterval(()=>{a--,r(b=>({...b,countdown:a,message:a>0?`Scanning in ${a}...`:"Scanning card..."})),a<=0&&(clearInterval(b),B())},1e3);m.current=setTimeout(()=>{clearInterval(b),B()},3e3)})()},2e3);return()=>{clearInterval(a),m.current&&clearTimeout(m.current)}},[o,c,q.isProcessing,s,f,w]);let y=async()=>{try{let a=await navigator.mediaDevices.getUserMedia({video:{facingMode:"environment",width:{ideal:1920},height:{ideal:1080}}});g.current&&(g.current.srcObject=a,j.current=a,g.current.onloadedmetadata=()=>{g.current?.play().then(()=>{p(!0)})})}catch(a){console.error("Camera error:",a),b(`Camera access failed: ${a.message}`)}},z=()=>{j.current&&(j.current.getTracks().forEach(a=>a.stop()),j.current=null),p(!1),r({isScanning:!1,isProcessing:!1,message:"",countdown:0})},A=(0,e.useCallback)(()=>{if(!g.current||!i.current)return null;let a=g.current,b=i.current,c=b.getContext("2d");return c?(b.width=a.videoWidth,b.height=a.videoHeight,c.drawImage(a,0,0,b.width,b.height),b.toDataURL("image/jpeg",.8)):null},[]),B=(0,e.useCallback)(async()=>{if(!q.isProcessing&&!(s>=f)){if(!w){r(a=>({...a,isScanning:!1,isProcessing:!1,message:"OCR not configured - please set up your API key in Settings"})),setTimeout(()=>{r(a=>({...a,message:""}))},4e3);return}r(a=>({...a,isScanning:!1,isProcessing:!0,message:"Processing card with AI...",countdown:0}));try{let b,c=A();if(!c)throw Error("Failed to capture image");try{console.log("\uD83E\uDD16 Trying OpenAI Vision API..."),b=await k.analyzeCard(c),console.log("✅ OpenAI Vision result:",b)}catch(a){console.log("❌ OpenAI failed, trying Ollama:",a);try{b=await l.analyzeCard(c),console.log("✅ Ollama Vision result:",b)}catch(a){throw console.error("❌ All AI O