deckhearth/.next/static/chunks/639.879f3c63a68ab0ec.js

8 lines
252 KiB
JavaScript
Raw Normal View History

"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[639],{9639:(e,a,r)=>{r.r(a),r.d(a,{default:()=>ep});var t=r(7876),s=r(4232),n=r(9099),l=r(973),i=r(8990),c=r(4403);let o=(0,s.createContext)(void 0),d=e=>{let{children:a}=e,[r,n]=(0,s.useState)(()=>localStorage.getItem("tcg-vault-theme")||"system"),[l,i]=(0,s.useState)("light");return(0,s.useEffect)(()=>{let e=()=>{"system"===r?i(window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"):i(r)};e();let a=window.matchMedia("(prefers-color-scheme: dark)"),t=()=>{"system"===r&&e()};return a.addEventListener("change",t),()=>a.removeEventListener("change",t)},[r]),(0,s.useEffect)(()=>{let e=document.documentElement;"dark"===l?e.classList.add("dark"):e.classList.remove("dark");let a=document.querySelector('meta[name="theme-color"]');a&&a.setAttribute("content","dark"===l?"#0f172a":"#8b5cf6"),localStorage.setItem("tcg-vault-theme",r)},[r,l]),(0,t.jsx)(o.Provider,{value:{theme:r,effectiveTheme:l,setTheme:e=>{n(e)},toggleTheme:()=>{"light"===r?n("dark"):"dark"===r?n("system"):n("light")}},children:a})};var m=r(8307),u=r(4952);let x=e=>{let{children:a}=e,{user:r,logout:n,isAdmin:l}=(0,c.A)(),{toggleTheme:i,effectiveTheme:d}=(()=>{let e=(0,s.useContext)(o);if(void 0===e)throw Error("useTheme must be used within a ThemeProvider");return e})(),x=(0,m.zy)(),h=(0,m.Zp)(),[g,p]=(0,s.useState)(!1),[f,b]=(0,s.useState)(!1),v=()=>{n(),p(!1),b(!1),h("/login")},j=[{name:"Dashboard",href:"/dashboard",icon:"\uD83D\uDCCA",mobileIcon:"\uD83C\uDFE0"},{name:"Cards",href:"/cards",icon:"\uD83C\uDCCF",mobileIcon:"\uD83C\uDCCF"},{name:"Collections",href:"/collections",icon:"\uD83D\uDCDA",mobileIcon:"\uD83D\uDCDA"},{name:"Decks",href:"/decks",icon:"\uD83C\uDFAF",mobileIcon:"\uD83C\uDFAF"},{name:"Scanner",href:"/scanner",icon:"\uD83D\uDCF7",mobileIcon:"\uD83D\uDCF7"}];return(0,t.jsxs)("div",{className:"min-h-screen bg-surface-50 dark:bg-surface-900 transition-colors",children:[(0,t.jsxs)("div",{className:"hidden lg:flex h-screen",children:[(0,t.jsxs)("div",{className:"w-64 bg-white dark:bg-surface-800 border-r border-surface-200 dark:border-surface-700 flex flex-col",children:[(0,t.jsx)("div",{className:"p-6 border-b border-surface-200 dark:border-surface-700",children:(0,t.jsxs)(u.N_,{to:"/dashboard",className:"flex items-center space-x-3",children:[(0,t.jsx)("div",{className:"bg-gradient-to-r from-primary-500 to-accent-500 text-white p-3 rounded-xl",children:(0,t.jsx)("svg",{className:"w-6 h-6",fill:"currentColor",viewBox:"0 0 20 20",children:(0,t.jsx)("path",{d:"M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"})})}),(0,t.jsxs)("div",{children:[(0,t.jsx)("h1",{className:"text-xl font-bold text-surface-900 dark:text-white",children:"TCG Vault"}),(0,t.jsxs)("p",{className:"text-sm text-surface-600 dark:text-surface-400",children:["Hi, ",r?.firstName||r?.username]})]})]})}),(0,t.jsx)("nav",{className:"flex-1 p-4 space-y-2",children:j.map(e=>{let a;return(0,t.jsxs)(u.N_,{to:e.href,className:`flex items-center space-x-3 px-4 py-3 rounded-xl text-sm font-medium transition-all duration-200 ${(a=e.href,x.pathname===a)?"bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300":"text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-white hover:bg-surface-100 dark:hover:bg-surface-700"}`,children:[(0,t.jsx)("span",{className:"text-lg",children:e.icon}),(0,t.jsx)("span",{children:e.name})]},e.name)})}),(0,t.jsxs)("div",{className:"p-4 border-t border-surface-200 dark:border-surface-700",children:[(0,t.jsxs)("div",{className:"flex items-center space-x-3 p-3 rounded-xl bg-surface-50 dark:bg-surface-700",children:[(0,t.jsx)("div",{className:"w-10 h-10 bg-gradient-to-r from-primary-500 to-accent-500 rounded-xl flex items-center justify-center text-white font-semibold",children:r?.firstName?.[0]||r?.username?.[0]?.toUpperCase()||"U"}),(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsx)("p",{className:"text-sm font-medium text-s
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:[a],stream:!1})});if(!r.ok)throw Error(`Ollama API error: ${r.status}`);let t=(await r.json()).response;try{let e=JSON.parse(t);return{cardName:e.cardName||"",setName:e.setName,setCode:e.setCode,cardType:e.cardType,rarity:e.rarity,rawText:e.rawText||t,confidence:85,game:e.game?.toUpperCase()||"UNKNOWN"}}catch{return{cardName:this.extractCardNameFromText(t),rawText:t,confidence:75,game:this.detectGameFromText(t)}}}catch(e){throw console.error("Ollama OCR error:",e),Error(`Ollama OCR failed: ${e.message}`)}}extractCardNameFromText(e){return e.split("\n").map(e=>e.trim()).filter(e=>e.length>0).find(e=>e.length>3&&e.length<50)||"Unknown Card"}detectGameFromText(e){let a=e.toLowerCase();return a.includes("pokemon")||a.includes("hp")?"POKEMON":a.includes("mana")||a.includes("creature")?"MTG":a.includes("lorcana")?"LORCANA":"UNKNOWN"}}let J=new Y,X=new Q,Z=e=>{let{onCardScanned:a,onError:r,isActive:n,maxQueueSize:l=100}=e,i=(0,s.useRef)(null),c=(0,s.useRef)(null),o=(0,s.useRef)(null),d=(0,s.useRef)(null),m=(0,s.useRef)(0),[u,x]=(0,s.useState)(!1),[h,g]=(0,s.useState)({isScanning:!1,isProcessing:!1,message:"",countdown:0}),[p,f]=(0,s.useState)(0),[b,v]=(0,s.useState)(new Set),[j,y]=(0,s.useState)(!1);(0,s.useEffect)(()=>{(async()=>{try{let e=localStorage.getItem("openai_api_key"),a=localStorage.getItem("tcg_vault_token");if(a)try{let e=await fetch("/api/user/preferences",{headers:{Authorization:`Bearer ${a}`,"Content-Type":"application/json"}});if(e.ok){let a=await e.json(),r=a.preferences?.ocrSettings?.openai_api_key;if(r){J.setApiKey(r),y(!0),console.log("✅ OCR configured with user preferences API key");return}}}catch(e){console.log("Could not load user preferences, checking localStorage...")}e?(J.setApiKey(e),y(!0),console.log("✅ OCR configured with localStorage API key")):(console.log("❌ No OpenAI API key found. OCR scanning will not work."),y(!1))}catch(e){console.error("Error initializing OCR:",e),y(!1)}})()},[]),(0,s.useEffect)(()=>(n?k():w(),()=>{w()}),[n]),(0,s.useEffect)(()=>{if(!u||!n||!j)return;let e=setInterval(()=>{Date.now()-m.current>5e3&&(()=>{if(h.isProcessing||p>=l)return;d.current&&clearTimeout(d.current),g(e=>({...e,isScanning:!0,message:"Card detected, stabilizing...",countdown:3}));let e=3,a=setInterval(()=>{e--,g(a=>({...a,countdown:e,message:e>0?`Scanning in ${e}...`:"Scanning card..."})),e<=0&&(clearInterval(a),C())},1e3);d.current=setTimeout(()=>{clearInterval(a),C()},3e3)})()},2e3);return()=>{clearInterval(e),d.current&&clearTimeout(d.current)}},[u,n,h.isProcessing,p,l,j]);let k=async()=>{try{let e=await navigator.mediaDevices.getUserMedia({video:{facingMode:"environment",width:{ideal:1920},height:{ideal:1080}}});i.current&&(i.current.srcObject=e,o.current=e,i.current.onloadedmetadata=()=>{i.current?.play().then(()=>{x(!0)})})}catch(e){console.error("Camera error:",e),r(`Camera access failed: ${e.message}`)}},w=()=>{o.current&&(o.current.getTracks().forEach(e=>e.stop()),o.current=null),x(!1),g({isScanning:!1,isProcessing:!1,message:"",countdown:0})},N=(0,s.useCallback)(()=>{if(!i.current||!c.current)return null;let e=i.current,a=c.current,r=a.getContext("2d");return r?(a.width=e.videoWidth,a.height=e.videoHeight,r.drawImage(e,0,0,a.width,a.height),a.toDataURL("image/jpeg",.8)):null},[]),C=(0,s.useCallback)(async()=>{if(!h.isProcessing&&!(p>=l)){if(!j){g(e=>({...e,isScanning:!1,isProcessing:!1,message:"OCR not configured - please set up your API key in Settings"})),setTimeout(()=>{g(e=>({...e,message:""}))},4e3);return}g(e=>({...e,isScanning:!1,isProcessing:!0,message:"Processing card with AI...",countdown:0}));try{let e,r=N();if(!r)throw Error("Failed to capture image");try{console.log("\uD83E\uDD16 Trying OpenAI Vision API..."),e=await J.analyzeCard(r),console.log("✅ OpenAI Vision result:",e)}catch(a){console.log("❌ OpenAI failed, trying Ollama:",a);try{e=await X.analyzeCard(r),console.log("✅ Ollama Vision result:",e)}catch(e){throw console.error("❌ All AI