Convert from React to Next.js for proper API route support

This commit is contained in:
Randall Stillwell 2025-07-23 08:25:58 -05:00
parent 09bb380da6
commit 873f4592c2
77 changed files with 1733 additions and 12418 deletions

1
.next/BUILD_ID Normal file
View file

@ -0,0 +1 @@
ta-9EOrBIQCfqkGzcHGYz

35
.next/build-manifest.json Normal file
View file

@ -0,0 +1,35 @@
{
"polyfillFiles": [
"static/chunks/polyfills-42372ed130431b0a.js"
],
"devFiles": [],
"ampDevFiles": [],
"lowPriorityFiles": [
"static/ta-9EOrBIQCfqkGzcHGYz/_buildManifest.js",
"static/ta-9EOrBIQCfqkGzcHGYz/_ssgManifest.js"
],
"rootMainFiles": [],
"rootMainFilesTree": {},
"pages": {
"/": [
"static/chunks/webpack-2514287f28c61aa9.js",
"static/chunks/framework-f75312fc4004b783.js",
"static/chunks/main-b0584c0399485cea.js",
"static/chunks/pages/index-a7c47e3ce924016f.js"
],
"/_app": [
"static/chunks/webpack-2514287f28c61aa9.js",
"static/chunks/framework-f75312fc4004b783.js",
"static/chunks/main-b0584c0399485cea.js",
"static/css/fd61543791679090.css",
"static/chunks/pages/_app-d59881a6b717b660.js"
],
"/_error": [
"static/chunks/webpack-2514287f28c61aa9.js",
"static/chunks/framework-f75312fc4004b783.js",
"static/chunks/main-b0584c0399485cea.js",
"static/chunks/pages/_error-e15c84159987e7e6.js"
]
},
"ampFirstPages": []
}

1
.next/cache/.previewinfo vendored Normal file
View file

@ -0,0 +1 @@
{"previewModeId":"d795978c4257309f42950b4abd879f23","previewModeSigningKey":"05927a0bce54694581c537bcb1e3ef04d9dc93dca3a5721274fafdff3c7f16e4","previewModeEncryptionKey":"e38ae08d93a646354e380eb4ec892454450f2b82dd4a29b998c52d47333cee57","expireAt":1754486679703}

1
.next/cache/.rscinfo vendored Normal file
View file

@ -0,0 +1 @@
{"encryption.key":"WgEDELVguOVMhJ15dXJTVDVIIZoO5w/NvPgcFODNPJs=","encryption.expire_at":1754486677664}

1
.next/cache/.tsbuildinfo vendored Normal file

File diff suppressed because one or more lines are too long

1
.next/cache/eslint/.cache_1s48lv4 vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,6 @@
{
"buildStage": "static-generation",
"buildOptions": {
"useBuildWorker": "true"
}
}

View file

@ -0,0 +1 @@
{"name":"Next.js","version":"15.4.2"}

View file

@ -0,0 +1 @@
[]

6
.next/export-marker.json Normal file
View file

@ -0,0 +1,6 @@
{
"version": 1,
"hasExportPathMap": false,
"exportTrailingSlash": false,
"isNextImageImported": false
}

View file

@ -0,0 +1,61 @@
{
"version": 1,
"images": {
"deviceSizes": [
640,
750,
828,
1080,
1200,
1920,
2048,
3840
],
"imageSizes": [
16,
32,
48,
64,
96,
128,
256,
384
],
"path": "/_next/image",
"loader": "default",
"loaderFile": "",
"domains": [
"api.scryfall.com",
"images.pokemontcg.io",
"lorcana-api.com"
],
"disableStaticImages": false,
"minimumCacheTTL": 60,
"formats": [
"image/webp"
],
"dangerouslyAllowSVG": false,
"contentSecurityPolicy": "script-src 'none'; frame-src 'none'; sandbox;",
"contentDispositionType": "attachment",
"remotePatterns": [],
"unoptimized": false,
"sizes": [
640,
750,
828,
1080,
1200,
1920,
2048,
3840,
16,
32,
48,
64,
96,
128,
256,
384
]
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
.next/package.json Normal file
View file

@ -0,0 +1 @@
{"type": "commonjs"}

View file

@ -0,0 +1,11 @@
{
"version": 4,
"routes": {},
"dynamicRoutes": {},
"preview": {
"previewModeId": "d795978c4257309f42950b4abd879f23",
"previewModeSigningKey": "05927a0bce54694581c537bcb1e3ef04d9dc93dca3a5721274fafdff3c7f16e4",
"previewModeEncryptionKey": "e38ae08d93a646354e380eb4ec892454450f2b82dd4a29b998c52d47333cee57"
},
"notFoundRoutes": []
}

View file

@ -0,0 +1,10 @@
{
"pages/index.tsx -> ../src/App": {
"id": 9639,
"files": [
"static/chunks/5330eab6.0e905b95dc8a5a19.js",
"static/chunks/469.31893841137c9659.js",
"static/chunks/639.879f3c63a68ab0ec.js"
]
}
}

View file

@ -0,0 +1,320 @@
{
"version": 1,
"config": {
"env": {},
"webpack": null,
"eslint": {
"ignoreDuringBuilds": false
},
"typescript": {
"ignoreBuildErrors": false,
"tsconfigPath": "tsconfig.json"
},
"distDir": ".next",
"cleanDistDir": true,
"assetPrefix": "",
"cacheMaxMemorySize": 52428800,
"configOrigin": "next.config.js",
"useFileSystemPublicRoutes": true,
"generateEtags": true,
"pageExtensions": [
"tsx",
"ts",
"jsx",
"js"
],
"poweredByHeader": true,
"compress": true,
"images": {
"deviceSizes": [
640,
750,
828,
1080,
1200,
1920,
2048,
3840
],
"imageSizes": [
16,
32,
48,
64,
96,
128,
256,
384
],
"path": "/_next/image",
"loader": "default",
"loaderFile": "",
"domains": [
"api.scryfall.com",
"images.pokemontcg.io",
"lorcana-api.com"
],
"disableStaticImages": false,
"minimumCacheTTL": 60,
"formats": [
"image/webp"
],
"dangerouslyAllowSVG": false,
"contentSecurityPolicy": "script-src 'none'; frame-src 'none'; sandbox;",
"contentDispositionType": "attachment",
"remotePatterns": [],
"unoptimized": false
},
"devIndicators": {
"position": "bottom-left"
},
"onDemandEntries": {
"maxInactiveAge": 60000,
"pagesBufferLength": 5
},
"amp": {
"canonicalBase": ""
},
"basePath": "",
"sassOptions": {},
"trailingSlash": false,
"i18n": null,
"productionBrowserSourceMaps": false,
"excludeDefaultMomentLocales": true,
"serverRuntimeConfig": {},
"publicRuntimeConfig": {},
"reactProductionProfiling": false,
"reactStrictMode": null,
"reactMaxHeadersLength": 6000,
"httpAgentOptions": {
"keepAlive": true
},
"logging": {},
"compiler": {},
"expireTime": 31536000,
"staticPageGenerationTimeout": 60,
"modularizeImports": {
"@mui/icons-material": {
"transform": "@mui/icons-material/{{member}}"
},
"lodash": {
"transform": "lodash/{{member}}"
}
},
"outputFileTracingRoot": "/Users/rstillw/Documents/tcg-vault",
"experimental": {
"useSkewCookie": false,
"nodeMiddleware": false,
"cacheLife": {
"default": {
"stale": 300,
"revalidate": 900,
"expire": 4294967294
},
"seconds": {
"stale": 0,
"revalidate": 1,
"expire": 60
},
"minutes": {
"stale": 300,
"revalidate": 60,
"expire": 3600
},
"hours": {
"stale": 300,
"revalidate": 3600,
"expire": 86400
},
"days": {
"stale": 300,
"revalidate": 86400,
"expire": 604800
},
"weeks": {
"stale": 300,
"revalidate": 604800,
"expire": 2592000
},
"max": {
"stale": 300,
"revalidate": 2592000,
"expire": 4294967294
}
},
"cacheHandlers": {},
"cssChunking": true,
"multiZoneDraftMode": false,
"appNavFailHandling": false,
"prerenderEarlyExit": true,
"serverMinification": true,
"serverSourceMaps": false,
"linkNoTouchStart": false,
"caseSensitiveRoutes": false,
"clientSegmentCache": false,
"dynamicOnHover": false,
"preloadEntriesOnStart": true,
"clientRouterFilter": true,
"clientRouterFilterRedirects": false,
"fetchCacheKeyPrefix": "",
"middlewarePrefetch": "flexible",
"optimisticClientCache": true,
"manualClientBasePath": false,
"cpus": 13,
"memoryBasedWorkersCount": false,
"imgOptConcurrency": null,
"imgOptTimeoutInSeconds": 7,
"imgOptMaxInputPixels": 268402689,
"imgOptSequentialRead": null,
"isrFlushToDisk": true,
"workerThreads": false,
"optimizeCss": false,
"nextScriptWorkers": false,
"scrollRestoration": false,
"externalDir": false,
"disableOptimizedLoading": false,
"gzipSize": true,
"craCompat": false,
"esmExternals": true,
"fullySpecified": false,
"swcTraceProfiling": false,
"forceSwcTransforms": false,
"largePageDataBytes": 128000,
"typedRoutes": false,
"typedEnv": false,
"parallelServerCompiles": false,
"parallelServerBuildTraces": false,
"ppr": false,
"authInterrupts": false,
"webpackMemoryOptimizations": false,
"optimizeServerReact": true,
"viewTransition": false,
"routerBFCache": false,
"removeUncaughtErrorAndRejectionListeners": false,
"validateRSCRequestHeaders": false,
"staleTimes": {
"dynamic": 0,
"static": 300
},
"serverComponentsHmrCache": true,
"staticGenerationMaxConcurrency": 8,
"staticGenerationMinPagesPerWorker": 25,
"dynamicIO": false,
"inlineCss": false,
"useCache": false,
"globalNotFound": false,
"devtoolNewPanelUI": false,
"devtoolSegmentExplorer": false,
"browserDebugInfoInTerminal": false,
"optimizeRouterScrolling": false,
"strictNextHead": true,
"optimizePackageImports": [
"lucide-react",
"date-fns",
"lodash-es",
"ramda",
"antd",
"react-bootstrap",
"ahooks",
"@ant-design/icons",
"@headlessui/react",
"@headlessui-float/react",
"@heroicons/react/20/solid",
"@heroicons/react/24/solid",
"@heroicons/react/24/outline",
"@visx/visx",
"@tremor/react",
"rxjs",
"@mui/material",
"@mui/icons-material",
"recharts",
"react-use",
"effect",
"@effect/schema",
"@effect/platform",
"@effect/platform-node",
"@effect/platform-browser",
"@effect/platform-bun",
"@effect/sql",
"@effect/sql-mssql",
"@effect/sql-mysql2",
"@effect/sql-pg",
"@effect/sql-sqlite-node",
"@effect/sql-sqlite-bun",
"@effect/sql-sqlite-wasm",
"@effect/sql-sqlite-react-native",
"@effect/rpc",
"@effect/rpc-http",
"@effect/typeclass",
"@effect/experimental",
"@effect/opentelemetry",
"@material-ui/core",
"@material-ui/icons",
"@tabler/icons-react",
"mui-core",
"react-icons/ai",
"react-icons/bi",
"react-icons/bs",
"react-icons/cg",
"react-icons/ci",
"react-icons/di",
"react-icons/fa",
"react-icons/fa6",
"react-icons/fc",
"react-icons/fi",
"react-icons/gi",
"react-icons/go",
"react-icons/gr",
"react-icons/hi",
"react-icons/hi2",
"react-icons/im",
"react-icons/io",
"react-icons/io5",
"react-icons/lia",
"react-icons/lib",
"react-icons/lu",
"react-icons/md",
"react-icons/pi",
"react-icons/ri",
"react-icons/rx",
"react-icons/si",
"react-icons/sl",
"react-icons/tb",
"react-icons/tfi",
"react-icons/ti",
"react-icons/vsc",
"react-icons/wi"
],
"trustHostHeader": false,
"isExperimentalCompile": false
},
"htmlLimitedBots": "Mediapartners-Google|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti",
"bundlePagesRouterDependencies": false,
"configFileName": "next.config.js",
"turbopack": {
"root": "/Users/rstillw/Documents/tcg-vault"
}
},
"appDir": "/Users/rstillw/Documents/tcg-vault",
"relativeAppDir": "",
"files": [
".next/routes-manifest.json",
".next/server/pages-manifest.json",
".next/build-manifest.json",
".next/prerender-manifest.json",
".next/server/functions-config-manifest.json",
".next/server/middleware-manifest.json",
".next/server/middleware-build-manifest.js",
".next/server/middleware-react-loadable-manifest.js",
".next/react-loadable-manifest.json",
".next/dynamic-css-manifest.json",
".next/server/dynamic-css-manifest.js",
".next/BUILD_ID",
".next/server/next-font-manifest.js",
".next/server/next-font-manifest.json",
".next/required-server-files.json"
],
"ignore": [
"node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*"
]
}

View file

@ -0,0 +1,66 @@
{
"version": 3,
"pages404": true,
"caseSensitive": false,
"basePath": "",
"redirects": [
{
"source": "/:path+/",
"destination": "/:path+",
"internal": true,
"statusCode": 308,
"regex": "^(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))/$"
}
],
"headers": [
{
"source": "/api/(.*)",
"headers": [
{
"key": "Access-Control-Allow-Origin",
"value": "*"
},
{
"key": "Access-Control-Allow-Methods",
"value": "GET, POST, PUT, DELETE, OPTIONS"
},
{
"key": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
}
],
"regex": "^/api(?:/(.*))(?:/)?$"
}
],
"rewrites": {
"beforeFiles": [],
"afterFiles": [],
"fallback": []
},
"dynamicRoutes": [],
"staticRoutes": [
{
"page": "/",
"regex": "^/(?:/)?$",
"routeKeys": {},
"namedRegex": "^/(?:/)?$"
}
],
"dataRoutes": [],
"rsc": {
"header": "RSC",
"varyHeader": "RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Router-Segment-Prefetch",
"prefetchHeader": "Next-Router-Prefetch",
"didPostponeHeader": "x-nextjs-postponed",
"contentTypeHeader": "text/x-component",
"suffix": ".rsc",
"prefetchSuffix": ".prefetch.rsc",
"prefetchSegmentHeader": "Next-Router-Segment-Prefetch",
"prefetchSegmentSuffix": ".segment.rsc",
"prefetchSegmentDirSuffix": ".segments"
},
"rewriteHeaders": {
"pathHeader": "x-nextjs-rewritten-path",
"queryHeader": "x-nextjs-rewritten-query"
}
}

File diff suppressed because one or more lines are too long

19
.next/server/chunks/64.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
self.__DYNAMIC_CSS_MANIFEST="[]";

View file

@ -0,0 +1,4 @@
{
"version": 1,
"functions": {}
}

View file

@ -0,0 +1 @@
self.__INTERCEPTION_ROUTE_REWRITE_MANIFEST="[]";

View file

@ -0,0 +1 @@
globalThis.__BUILD_MANIFEST={polyfillFiles:["static/chunks/polyfills-42372ed130431b0a.js"],devFiles:[],ampDevFiles:[],lowPriorityFiles:[],rootMainFiles:[],rootMainFilesTree:{},pages:{"/":["static/chunks/webpack-2514287f28c61aa9.js","static/chunks/framework-f75312fc4004b783.js","static/chunks/main-b0584c0399485cea.js","static/chunks/pages/index-a7c47e3ce924016f.js"],"/_app":["static/chunks/webpack-2514287f28c61aa9.js","static/chunks/framework-f75312fc4004b783.js","static/chunks/main-b0584c0399485cea.js","static/css/fd61543791679090.css","static/chunks/pages/_app-d59881a6b717b660.js"],"/_error":["static/chunks/webpack-2514287f28c61aa9.js","static/chunks/framework-f75312fc4004b783.js","static/chunks/main-b0584c0399485cea.js","static/chunks/pages/_error-e15c84159987e7e6.js"]},ampFirstPages:[]},globalThis.__BUILD_MANIFEST.lowPriorityFiles=["/static/"+process.env.__NEXT_BUILD_ID+"/_buildManifest.js",,"/static/"+process.env.__NEXT_BUILD_ID+"/_ssgManifest.js"];

View file

@ -0,0 +1,6 @@
{
"version": 3,
"middleware": {},
"functions": {},
"sortedMiddleware": []
}

View file

@ -0,0 +1 @@
self.__REACT_LOADABLE_MANIFEST='{"pages/index.tsx -> ../src/App":{"id":9639,"files":["static/chunks/5330eab6.0e905b95dc8a5a19.js","static/chunks/469.31893841137c9659.js","static/chunks/639.879f3c63a68ab0ec.js"]}}';

View file

@ -0,0 +1 @@
self.__NEXT_FONT_MANIFEST='{"pages":{},"app":{},"appUsingSizeAdjust":false,"pagesUsingSizeAdjust":false}';

View file

@ -0,0 +1 @@
{"pages":{},"app":{},"appUsingSizeAdjust":false,"pagesUsingSizeAdjust":false}

View file

@ -0,0 +1,7 @@
{
"/": "pages/index.html",
"/_app": "pages/_app.js",
"/_error": "pages/_error.js",
"/_document": "pages/_document.js",
"/404": "pages/404.html"
}

View file

@ -0,0 +1 @@
<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/><title data-next-head="">404: This page could not be found</title><link rel="preload" href="/_next/static/css/fd61543791679090.css" as="style"/><link rel="stylesheet" href="/_next/static/css/fd61543791679090.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-2514287f28c61aa9.js" defer=""></script><script src="/_next/static/chunks/framework-f75312fc4004b783.js" defer=""></script><script src="/_next/static/chunks/main-b0584c0399485cea.js" defer=""></script><script src="/_next/static/chunks/pages/_app-d59881a6b717b660.js" defer=""></script><script src="/_next/static/chunks/pages/_error-e15c84159987e7e6.js" defer=""></script><script src="/_next/static/ta-9EOrBIQCfqkGzcHGYz/_buildManifest.js" defer=""></script><script src="/_next/static/ta-9EOrBIQCfqkGzcHGYz/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">This page could not be found<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"ta-9EOrBIQCfqkGzcHGYz","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>

View file

@ -0,0 +1 @@
<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/><title data-next-head="">500: Internal Server Error</title><link rel="preload" href="/_next/static/css/fd61543791679090.css" as="style"/><link rel="stylesheet" href="/_next/static/css/fd61543791679090.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-2514287f28c61aa9.js" defer=""></script><script src="/_next/static/chunks/framework-f75312fc4004b783.js" defer=""></script><script src="/_next/static/chunks/main-b0584c0399485cea.js" defer=""></script><script src="/_next/static/chunks/pages/_app-d59881a6b717b660.js" defer=""></script><script src="/_next/static/chunks/pages/_error-e15c84159987e7e6.js" defer=""></script><script src="/_next/static/ta-9EOrBIQCfqkGzcHGYz/_buildManifest.js" defer=""></script><script src="/_next/static/ta-9EOrBIQCfqkGzcHGYz/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">500</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">Internal Server Error<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":500}},"page":"/_error","query":{},"buildId":"ta-9EOrBIQCfqkGzcHGYz","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>

View file

@ -0,0 +1 @@
(()=>{var a={};a.id=636,a.ids=[636],a.modules={2015:a=>{"use strict";a.exports=require("react")},2386:(a,b,c)=>{"use strict";c.a(a,async(a,d)=>{try{c.r(b),c.d(b,{default:()=>i});var e=c(8732);c(2015);var f=c(8462),g=c(4670);c(8754);var h=a([f]);let j=new(f=(h.then?(await h)():h)[0]).QueryClient({defaultOptions:{queries:{retry:1,refetchOnWindowFocus:!1}}});function i({Component:a,pageProps:b}){return(0,e.jsx)(f.QueryClientProvider,{client:j,children:(0,e.jsx)(g.O,{children:(0,e.jsx)(a,{...b})})})}d()}catch(a){d(a)}})},4670:(a,b,c)=>{"use strict";c.d(b,{A:()=>g,O:()=>h});var d=c(8732),e=c(2015);let f=(0,e.createContext)(void 0),g=()=>{let a=(0,e.useContext)(f);if(void 0===a)throw Error("useAuth must be used within an AuthProvider");return a},h=({children:a})=>{let[b,c]=(0,e.useState)(null),[g,h]=(0,e.useState)(null),[i,j]=(0,e.useState)(!0);(0,e.useEffect)(()=>{let a=localStorage.getItem("tcg_vault_token"),b=localStorage.getItem("tcg_vault_user");if(a&&b)try{let d=JSON.parse(b);h(a),c(d)}catch(a){console.error("Error parsing saved user data:",a),localStorage.removeItem("tcg_vault_token"),localStorage.removeItem("tcg_vault_user")}j(!1)},[]);let k=async(a,b)=>{try{let d=await fetch("/api/auth/login",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:a,password:b})}),e=await d.json();if(e.success)return c(e.user),h(e.token),localStorage.setItem("tcg_vault_token",e.token),localStorage.setItem("tcg_vault_user",JSON.stringify(e.user)),{success:!0};return{success:!1,error:e.error||"Login failed"}}catch(a){return console.error("Login error:",a),{success:!1,error:"Network error. Please try again."}}},l=async a=>{try{let b=await fetch("/api/auth/register",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)}),d=await b.json();if(d.success)return c(d.user),h(d.token),localStorage.setItem("tcg_vault_token",d.token),localStorage.setItem("tcg_vault_user",JSON.stringify(d.user)),{success:!0};return{success:!1,error:d.error||"Registration failed"}}catch(a){return console.error("Registration error:",a),{success:!1,error:"Network error. Please try again."}}},m=a=>b?.roles?.includes(a)||!1;return(0,d.jsx)(f.Provider,{value:{user:b,token:g,login:k,register:l,logout:()=>{c(null),h(null),localStorage.removeItem("tcg_vault_token"),localStorage.removeItem("tcg_vault_user")},isLoading:i,hasRole:m,hasPermission:a=>b?.permissions?.includes(a)||!1,isAdmin:()=>m("admin")},children:a})}},8462:a=>{"use strict";a.exports=import("@tanstack/react-query")},8732:a=>{"use strict";a.exports=require("react/jsx-runtime")},8754:()=>{}};var b=require("../webpack-runtime.js");b.C(a);var c=b(b.s=2386);module.exports=c})();

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
"use strict";(()=>{var a={};a.id=220,a.ids=[220],a.modules={361:a=>{a.exports=require("next/dist/compiled/next-server/pages.runtime.prod.js")},2015:a=>{a.exports=require("react")},3873:a=>{a.exports=require("path")},8732:a=>{a.exports=require("react/jsx-runtime")}};var b=require("../webpack-runtime.js");b.C(a);var c=b.X(0,[616],()=>b(b.s=9616));module.exports=c})();

View file

@ -0,0 +1 @@
{"version":1,"files":["../../../node_modules/client-only/index.js","../../../node_modules/client-only/package.json","../../../node_modules/next/dist/client/components/app-router-headers.js","../../../node_modules/next/dist/compiled/@opentelemetry/api/index.js","../../../node_modules/next/dist/compiled/@opentelemetry/api/package.json","../../../node_modules/next/dist/compiled/jsonwebtoken/index.js","../../../node_modules/next/dist/compiled/jsonwebtoken/package.json","../../../node_modules/next/dist/compiled/next-server/pages.runtime.prod.js","../../../node_modules/next/dist/lib/constants.js","../../../node_modules/next/dist/lib/interop-default.js","../../../node_modules/next/dist/lib/is-error.js","../../../node_modules/next/dist/lib/semver-noop.js","../../../node_modules/next/dist/pages/_document.js","../../../node_modules/next/dist/server/app-render/async-local-storage.js","../../../node_modules/next/dist/server/app-render/work-async-storage-instance.js","../../../node_modules/next/dist/server/app-render/work-async-storage.external.js","../../../node_modules/next/dist/server/app-render/work-unit-async-storage-instance.js","../../../node_modules/next/dist/server/app-render/work-unit-async-storage.external.js","../../../node_modules/next/dist/server/lib/cache-handlers/default.external.js","../../../node_modules/next/dist/server/lib/incremental-cache/memory-cache.external.js","../../../node_modules/next/dist/server/lib/incremental-cache/shared-cache-controls.external.js","../../../node_modules/next/dist/server/lib/incremental-cache/tags-manifest.external.js","../../../node_modules/next/dist/server/lib/lru-cache.js","../../../node_modules/next/dist/server/lib/router-utils/instrumentation-globals.external.js","../../../node_modules/next/dist/server/lib/trace/constants.js","../../../node_modules/next/dist/server/lib/trace/tracer.js","../../../node_modules/next/dist/server/load-manifest.external.js","../../../node_modules/next/dist/server/response-cache/types.js","../../../node_modules/next/dist/shared/lib/deep-freeze.js","../../../node_modules/next/dist/shared/lib/is-plain-object.js","../../../node_modules/next/dist/shared/lib/is-thenable.js","../../../node_modules/next/package.json","../../../node_modules/react-dom/cjs/react-dom-server-legacy.browser.development.js","../../../node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.min.js","../../../node_modules/react-dom/cjs/react-dom-server.browser.development.js","../../../node_modules/react-dom/cjs/react-dom-server.browser.production.min.js","../../../node_modules/react-dom/package.json","../../../node_modules/react-dom/server.browser.js","../../../node_modules/react/cjs/react-jsx-runtime.development.js","../../../node_modules/react/cjs/react-jsx-runtime.production.min.js","../../../node_modules/react/cjs/react.development.js","../../../node_modules/react/cjs/react.production.min.js","../../../node_modules/react/index.js","../../../node_modules/react/jsx-runtime.js","../../../node_modules/react/package.json","../../../node_modules/styled-jsx/dist/index/index.js","../../../node_modules/styled-jsx/index.js","../../../node_modules/styled-jsx/package.json","../../../package.json","../../package.json","../chunks/616.js","../webpack-runtime.js"]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/><link rel="preload" href="/_next/static/css/fd61543791679090.css" as="style"/><link rel="stylesheet" href="/_next/static/css/fd61543791679090.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-2514287f28c61aa9.js" defer=""></script><script src="/_next/static/chunks/framework-f75312fc4004b783.js" defer=""></script><script src="/_next/static/chunks/main-b0584c0399485cea.js" defer=""></script><script src="/_next/static/chunks/pages/_app-d59881a6b717b660.js" defer=""></script><script src="/_next/static/chunks/pages/index-a7c47e3ce924016f.js" defer=""></script><script src="/_next/static/ta-9EOrBIQCfqkGzcHGYz/_buildManifest.js" defer=""></script><script src="/_next/static/ta-9EOrBIQCfqkGzcHGYz/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"ta-9EOrBIQCfqkGzcHGYz","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
(()=>{"use strict";var a={},b={};function c(d){var e=b[d];if(void 0!==e)return e.exports;var f=b[d]={exports:{}},g=!0;try{a[d](f,f.exports,c),g=!1}finally{g&&delete b[d]}return f.exports}c.m=a,(()=>{var a="function"==typeof Symbol?Symbol("webpack queues"):"__webpack_queues__",b="function"==typeof Symbol?Symbol("webpack exports"):"__webpack_exports__",d="function"==typeof Symbol?Symbol("webpack error"):"__webpack_error__",e=a=>{a&&a.d<1&&(a.d=1,a.forEach(a=>a.r--),a.forEach(a=>a.r--?a.r++:a()))};c.a=(c,f,g)=>{g&&((h=[]).d=-1);var h,i,j,k,l=new Set,m=c.exports,n=new Promise((a,b)=>{k=b,j=a});n[b]=m,n[a]=a=>(h&&a(h),l.forEach(a),n.catch(a=>{})),c.exports=n,f(c=>{i=c.map(c=>{if(null!==c&&"object"==typeof c){if(c[a])return c;if(c.then){var f=[];f.d=0,c.then(a=>{g[b]=a,e(f)},a=>{g[d]=a,e(f)});var g={};return g[a]=a=>a(f),g}}var h={};return h[a]=a=>{},h[b]=c,h});var f,g=()=>i.map(a=>{if(a[d])throw a[d];return a[b]}),j=new Promise(b=>{(f=()=>b(g)).r=0;var c=a=>a!==h&&!l.has(a)&&(l.add(a),a&&!a.d&&(f.r++,a.push(f)));i.map(b=>b[a](c))});return f.r?j:g()},a=>(a?k(n[d]=a):j(m),e(h))),h&&h.d<0&&(h.d=0)}})(),c.n=a=>{var b=a&&a.__esModule?()=>a.default:()=>a;return c.d(b,{a:b}),b},c.d=(a,b)=>{for(var d in b)c.o(b,d)&&!c.o(a,d)&&Object.defineProperty(a,d,{enumerable:!0,get:b[d]})},c.f={},c.e=a=>Promise.all(Object.keys(c.f).reduce((b,d)=>(c.f[d](a,b),b),[])),c.u=a=>""+a+".js",c.o=(a,b)=>Object.prototype.hasOwnProperty.call(a,b),c.r=a=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(a,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(a,"__esModule",{value:!0})},c.X=(a,b,d)=>{var e=b;d||(b=a,d=()=>c(c.s=e)),b.map(c.e,c);var f=d();return void 0===f?a:f},(()=>{var a={311:1},b=b=>{var d=b.modules,e=b.ids,f=b.runtime;for(var g in d)c.o(d,g)&&(c.m[g]=d[g]);f&&f(c);for(var h=0;h<e.length;h++)a[e[h]]=1};c.f.require=(d,e)=>{a[d]||(311!=d?b(require("./chunks/"+c.u(d))):a[d]=1)},module.exports=c,c.C=b})()})();

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[796],{8116:(t,e,a)=>{var n,r;function i(){return(i=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var a=arguments[e];for(var n in a)Object.prototype.hasOwnProperty.call(a,n)&&(t[n]=a[n])}return t}).apply(this,arguments)}function s(t,e){if(!1===t||null==t)throw Error(e)}function h(t){let{pathname:e="/",search:a="",hash:n=""}=t;return a&&"?"!==a&&(e+="?"===a.charAt(0)?a:"?"+a),n&&"#"!==n&&(e+="#"===n.charAt(0)?n:"#"+n),e}function l(t){let e={};if(t){let a=t.indexOf("#");a>=0&&(e.hash=t.substr(a),t=t.substr(0,a));let n=t.indexOf("?");n>=0&&(e.search=t.substr(n),t=t.substr(0,n)),t&&(e.pathname=t)}return e}function o(t,e){if("/"===e)return t;if(!t.toLowerCase().startsWith(e.toLowerCase()))return null;let a=e.endsWith("/")?e.length-1:e.length,n=t.charAt(a);return n&&"/"!==n?null:t.slice(a)||"/"}function u(t,e,a,n){return"Cannot include a '"+t+"' character in a manually specified "+("`to."+e+"` field [")+JSON.stringify(n)+"]. Please separate it out to the `to."+a+'` field. Alternatively you may provide the full path as a string in <Link to="..."> and the router will parse it for you.'}function p(t,e){let a=t.filter((t,e)=>0===e||t.route.path&&t.route.path.length>0);return e?a.map((t,e)=>e===a.length-1?t.pathname:t.pathnameBase):a.map(t=>t.pathnameBase)}function c(t,e,a,n){let r,h;void 0===n&&(n=!1),"string"==typeof t?r=l(t):(s(!(r=i({},t)).pathname||!r.pathname.includes("?"),u("?","pathname","search",r)),s(!r.pathname||!r.pathname.includes("#"),u("#","pathname","hash",r)),s(!r.search||!r.search.includes("#"),u("#","search","hash",r)));let o=""===t||""===r.pathname,p=o?"/":r.pathname;if(null==p)h=a;else{let t=e.length-1;if(!n&&p.startsWith("..")){let e=p.split("/");for(;".."===e[0];)e.shift(),t-=1;r.pathname=e.join("/")}h=t>=0?e[t]:"/"}let c=function(t,e){var a;let n;void 0===e&&(e="/");let{pathname:r,search:i="",hash:s=""}="string"==typeof t?l(t):t;return{pathname:r?r.startsWith("/")?r:(a=r,n=e.replace(/\/+$/,"").split("/"),a.split("/").forEach(t=>{".."===t?n.length>1&&n.pop():"."!==t&&n.push(t)}),n.length>1?n.join("/"):"/"):e,search:d(i),hash:m(s)}}(r,h),f=p&&"/"!==p&&p.endsWith("/"),g=(o||"."===p)&&a.endsWith("/");return!c.pathname.endsWith("/")&&(f||g)&&(c.pathname+="/"),c}a.d(e,{AO:()=>h,Gh:()=>c,HS:()=>f,Oi:()=>s,pb:()=>o,tH:()=>g,yD:()=>p}),function(t){t.Pop="POP",t.Push="PUSH",t.Replace="REPLACE"}(n||(n={})),function(t){t.data="data",t.deferred="deferred",t.redirect="redirect",t.error="error"}(r||(r={}));let f=t=>t.join("/").replace(/\/\/+/g,"/"),d=t=>t&&"?"!==t?t.startsWith("?")?t:"?"+t:"",m=t=>t&&"#"!==t?t.startsWith("#")?t:"#"+t:"";class g extends Error{}Symbol("deferred")}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[731],{2164:(_,n,e)=>{(window.__NEXT_P=window.__NEXT_P||[]).push(["/_error",function(){return e(4100)}])}},_=>{_.O(0,[636,593,792],()=>_(_.s=2164)),_N_E=_.O()}]);

View file

@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[332],{1147:(e,t,l)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),!function(e,t){for(var l in t)Object.defineProperty(e,l,{enumerable:!0,get:t[l]})}(t,{default:function(){return o},noSSR:function(){return u}});let r=l(4252);l(7876),l(4232);let a=r._(l(2100));function n(e){return{default:(null==e?void 0:e.default)||e}}function u(e,t){return delete t.webpack,delete t.modules,e(t)}function o(e,t){let l=a.default,r={loading:e=>{let{error:t,isLoading:l,pastDelay:r}=e;return null}};e instanceof Promise?r.loader=()=>e:"function"==typeof e?r.loader=e:"object"==typeof e&&(r={...r,...e});let o=(r={...r,...t}).loader;return(r.loadableGenerated&&(r={...r,...r.loadableGenerated},delete r.loadableGenerated),"boolean"!=typeof r.ssr||r.ssr)?l({...r,loader:()=>null!=o?o().then(n):Promise.resolve(n(()=>null))}):(delete r.webpack,delete r.modules,u(l,r))}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)},1650:(e,t,l)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"LoadableContext",{enumerable:!0,get:function(){return r}});let r=l(4252)._(l(4232)).default.createContext(null)},2100:(e,t,l)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return f}});let r=l(4252)._(l(4232)),a=l(1650),n=[],u=[],o=!1;function s(e){let t=e(),l={loading:!0,loaded:null,error:null};return l.promise=t.then(e=>(l.loading=!1,l.loaded=e,e)).catch(e=>{throw l.loading=!1,l.error=e,e}),l}class i{promise(){return this._res.promise}retry(){this._clearTimeouts(),this._res=this._loadFn(this._opts.loader),this._state={pastDelay:!1,timedOut:!1};let{_res:e,_opts:t}=this;e.loading&&("number"==typeof t.delay&&(0===t.delay?this._state.pastDelay=!0:this._delay=setTimeout(()=>{this._update({pastDelay:!0})},t.delay)),"number"==typeof t.timeout&&(this._timeout=setTimeout(()=>{this._update({timedOut:!0})},t.timeout))),this._res.promise.then(()=>{this._update({}),this._clearTimeouts()}).catch(e=>{this._update({}),this._clearTimeouts()}),this._update({})}_update(e){this._state={...this._state,error:this._res.error,loaded:this._res.loaded,loading:this._res.loading,...e},this._callbacks.forEach(e=>e())}_clearTimeouts(){clearTimeout(this._delay),clearTimeout(this._timeout)}getCurrentValue(){return this._state}subscribe(e){return this._callbacks.add(e),()=>{this._callbacks.delete(e)}}constructor(e,t){this._loadFn=e,this._opts=t,this._callbacks=new Set,this._delay=null,this._timeout=null,this.retry()}}function d(e){return function(e,t){let l=Object.assign({loader:null,loading:null,delay:200,timeout:null,webpack:null,modules:null},t),n=null;function s(){if(!n){let t=new i(e,l);n={getCurrentValue:t.getCurrentValue.bind(t),subscribe:t.subscribe.bind(t),retry:t.retry.bind(t),promise:t.promise.bind(t)}}return n.promise()}if(!o){let e=l.webpack&&1?l.webpack():l.modules;e&&u.push(t=>{for(let l of e)if(t.includes(l))return s()})}function d(e,t){s();let u=r.default.useContext(a.LoadableContext);u&&Array.isArray(l.modules)&&l.modules.forEach(e=>{u(e)});let o=r.default.useSyncExternalStore(n.subscribe,n.getCurrentValue,n.getCurrentValue);return r.default.useImperativeHandle(t,()=>({retry:n.retry}),[]),r.default.useMemo(()=>{var t;return o.loading||o.error?r.default.createElement(l.loading,{isLoading:o.loading,pastDelay:o.pastDelay,timedOut:o.timedOut,error:o.error,retry:n.retry}):o.loaded?r.default.createElement((t=o.loaded)&&t.default?t.default:t,e):null},[e,o])}return d.preload=()=>s(),d.displayName="LoadableComponent",r.default.forwardRef(d)}(s,e)}function c(e,t){let l=[];for(;e.length;){let r=e.pop();l.push(r(t))}return Promise.all(l).then(()=>{if(e.length)return c(e,t)})}d.preloadAll=()=>new Promise((e,t)=>{c(n).then(e,t)}),d.preloadReady=e=>(void 0===e&&(e=[]),new Promise(t=>{let l=()=>(o=!0,t());c(u,e).then(l,l)})),window.__NEXT_PRELOADREADY=d.preloadReady;let f=d},3757:(e,t,l)=>{"use strict";l.r(t),l.d(t,{default:()=>u});var r=l(7876);l(4232);var a=l(8847);let n=l.n(a)()(()=>Promise.all([l.e(796),l.e(469),l.e(639)]).then(l.bind(l,9639)),{loadableGenerated:{webpack:()=>[9639]},ssr:!1});function u(){return(0,r.jsx)(n,{})}},6760:(e,t,l)=>{(window.__NEXT_P=window.__NEXT_P||[]).push(["/",function(){return l(3757)}])},8847:(e,t,l)=>{e.exports=l(1147)}},e=>{e.O(0,[636,593,792],()=>e(e.s=6760)),_N_E=e.O()}]);

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
(()=>{"use strict";var e={},t={};function r(o){var n=t[o];if(void 0!==n)return n.exports;var a=t[o]={exports:{}},i=!0;try{e[o](a,a.exports,r),i=!1}finally{i&&delete t[o]}return a.exports}r.m=e,(()=>{var e=[];r.O=(t,o,n,a)=>{if(o){a=a||0;for(var i=e.length;i>0&&e[i-1][2]>a;i--)e[i]=e[i-1];e[i]=[o,n,a];return}for(var u=1/0,i=0;i<e.length;i++){for(var[o,n,a]=e[i],d=!0,l=0;l<o.length;l++)(!1&a||u>=a)&&Object.keys(r.O).every(e=>r.O[e](o[l]))?o.splice(l--,1):(d=!1,a<u&&(u=a));if(d){e.splice(i--,1);var f=n();void 0!==f&&(t=f)}}return t}})(),r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;r.t=function(o,n){if(1&n&&(o=this(o)),8&n||"object"==typeof o&&o&&(4&n&&o.__esModule||16&n&&"function"==typeof o.then))return o;var a=Object.create(null);r.r(a);var i={};e=e||[null,t({}),t([]),t(t)];for(var u=2&n&&o;"object"==typeof u&&!~e.indexOf(u);u=t(u))Object.getOwnPropertyNames(u).forEach(e=>i[e]=()=>o[e]);return i.default=()=>o,r.d(a,i),a}})(),r.d=(e,t)=>{for(var o in t)r.o(t,o)&&!r.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((t,o)=>(r.f[o](e,t),t),[])),r.u=e=>"static/chunks/"+(796===e?"5330eab6":e)+"."+({469:"31893841137c9659",639:"879f3c63a68ab0ec",796:"0e905b95dc8a5a19"})[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={},t="_N_E:";r.l=(o,n,a,i)=>{if(e[o])return void e[o].push(n);if(void 0!==a)for(var u,d,l=document.getElementsByTagName("script"),f=0;f<l.length;f++){var c=l[f];if(c.getAttribute("src")==o||c.getAttribute("data-webpack")==t+a){u=c;break}}u||(d=!0,(u=document.createElement("script")).charset="utf-8",u.timeout=120,r.nc&&u.setAttribute("nonce",r.nc),u.setAttribute("data-webpack",t+a),u.src=r.tu(o)),e[o]=[n];var s=(t,r)=>{u.onerror=u.onload=null,clearTimeout(p);var n=e[o];if(delete e[o],u.parentNode&&u.parentNode.removeChild(u),n&&n.forEach(e=>e(r)),t)return t(r)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:u}),12e4);u.onerror=s.bind(null,u.onerror),u.onload=s.bind(null,u.onload),d&&document.head.appendChild(u)}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:e=>e},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("nextjs#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="/_next/",(()=>{var e={68:0};r.f.j=(t,o)=>{var n=r.o(e,t)?e[t]:void 0;if(0!==n)if(n)o.push(n[2]);else if(68!=t){var a=new Promise((r,o)=>n=e[t]=[r,o]);o.push(n[2]=a);var i=r.p+r.u(t),u=Error();r.l(i,o=>{if(r.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var a=o&&("load"===o.type?"missing":o.type),i=o&&o.target&&o.target.src;u.message="Loading chunk "+t+" failed.\n("+a+": "+i+")",u.name="ChunkLoadError",u.type=a,u.request=i,n[1](u)}},"chunk-"+t,t)}else e[t]=0},r.O.j=t=>0===e[t];var t=(t,o)=>{var n,a,[i,u,d]=o,l=0;if(i.some(t=>0!==e[t])){for(n in u)r.o(u,n)&&(r.m[n]=u[n]);if(d)var f=d(r)}for(t&&t(o);l<i.length;l++)a=i[l],r.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return r.O(f)},o=self.webpackChunk_N_E=self.webpackChunk_N_E||[];o.forEach(t.bind(null,0)),o.push=t.bind(null,o.push.bind(o))})()})();

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
self.__BUILD_MANIFEST=function(e,r,s){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},__routerFilterStatic:{numItems:0,errorRate:1e-4,numBits:0,numHashes:null,bitArray:[]},__routerFilterDynamic:{numItems:e,errorRate:1e-4,numBits:e,numHashes:null,bitArray:[]},"/":["static/chunks/pages/index-a7c47e3ce924016f.js"],"/_error":["static/chunks/pages/_error-e15c84159987e7e6.js"],sortedPages:["/","/_app","/_error"]}}(0,1e-4,null),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

View file

@ -0,0 +1 @@
self.__SSG_MANIFEST=new Set,self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB();

2
.next/trace Normal file

File diff suppressed because one or more lines are too long

5
next-env.d.ts vendored Normal file
View file

@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.

29
next.config.js Normal file
View file

@ -0,0 +1,29 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
domains: ['api.scryfall.com', 'images.pokemontcg.io', 'lorcana-api.com'],
},
async headers() {
return [
{
source: '/api/(.*)',
headers: [
{
key: 'Access-Control-Allow-Origin',
value: '*',
},
{
key: 'Access-Control-Allow-Methods',
value: 'GET, POST, PUT, DELETE, OPTIONS',
},
{
key: 'Access-Control-Allow-Headers',
value: 'Content-Type, Authorization',
},
],
},
];
},
};
module.exports = nextConfig;

13197
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,16 @@
{
"name": "frontend",
"name": "tcg-vault",
"version": "0.1.0",
"private": true,
"engines": {
"node": "22.x"
},
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@stackframe/stack": "^2.8.22",
"@tanstack/react-query": "^5.83.0",
@ -15,7 +21,6 @@
"@types/bcryptjs": "^2.4.6",
"@types/jest": "^27.5.2",
"@types/jsonwebtoken": "^9.0.10",
"@types/next": "^8.0.7",
"@types/node": "^16.18.126",
"@types/pg": "^8.15.4",
"@types/react": "^18.3.17",
@ -23,6 +28,7 @@
"@types/react-router-dom": "^5.3.3",
"@vercel/analytics": "^1.5.0",
"@vercel/blob": "^1.1.1",
"@vercel/postgres": "^0.7.2",
"@vercel/speed-insights": "^1.2.0",
"axios": "^1.10.0",
"bcryptjs": "^3.0.2",
@ -32,19 +38,11 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.28.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
"next"
]
},
"browserslist": {
@ -60,7 +58,10 @@
]
},
"devDependencies": {
"@types/node": "^16.18.126",
"autoprefixer": "^10.4.21",
"eslint": "^8",
"eslint-config-next": "15.4.2",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.17",
"typescript": "^4.9.5"

24
pages/_app.tsx Normal file
View file

@ -0,0 +1,24 @@
import React from 'react';
import type { AppProps } from 'next/app';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { AuthProvider } from '../src/contexts/AuthContext';
import '../src/index.css';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 1,
refetchOnWindowFocus: false,
},
},
});
export default function App({ Component, pageProps }: AppProps) {
return (
<QueryClientProvider client={queryClient}>
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
</QueryClientProvider>
);
}

10
pages/index.tsx Normal file
View file

@ -0,0 +1,10 @@
import React from 'react';
import dynamic from 'next/dynamic';
const App = dynamic(() => import('../src/App'), {
ssr: false,
});
export default function HomePage() {
return <App />;
}

View file

@ -1,9 +1,8 @@
import React from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import { Analytics } from '@vercel/analytics/react';
import { SpeedInsights } from '@vercel/speed-insights/react';
import { AuthProvider, useAuth } from './contexts/AuthContext';
import { useAuth } from './contexts/AuthContext';
import { ThemeProvider } from './contexts/ThemeContext';
import ResponsiveLayout from './components/ResponsiveLayout';
import Dashboard from './pages/Dashboard';
@ -16,18 +15,10 @@ import LoginForm from './components/auth/LoginForm';
import RegisterForm from './components/auth/RegisterForm';
import AdminPanel from './components/admin/AdminPanel';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 1,
refetchOnWindowFocus: false,
},
},
});
// Protected Route Component
const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const { user, isLoading } = useAuth();
const router = useRouter();
if (isLoading) {
return (
@ -45,7 +36,8 @@ const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({ children }) =
}
if (!user) {
return <Navigate to="/login" replace />;
router.push('/login');
return null;
}
return <>{children}</>;
@ -54,6 +46,7 @@ const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({ children }) =
// Public Route Component (redirect if authenticated)
const PublicRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const { user, isLoading } = useAuth();
const router = useRouter();
if (isLoading) {
return (
@ -71,7 +64,8 @@ const PublicRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
}
if (user) {
return <Navigate to="/dashboard" replace />;
router.push('/dashboard');
return null;
}
return <>{children}</>;
@ -98,91 +92,97 @@ const AuthLayout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
};
function App() {
const router = useRouter();
const { pathname } = router;
return (
<QueryClientProvider client={queryClient}>
<ThemeProvider>
<AuthProvider>
<Router>
<Routes>
{/* Public Routes */}
<Route path="/login" element={
{pathname === '/login' && (
<PublicRoute>
<AuthLayout>
<LoginForm />
</AuthLayout>
</PublicRoute>
} />
<Route path="/register" element={
)}
{pathname === '/register' && (
<PublicRoute>
<AuthLayout>
<RegisterForm />
</AuthLayout>
</PublicRoute>
} />
)}
{/* Protected Routes */}
<Route path="/dashboard" element={
{pathname === '/dashboard' && (
<ProtectedRoute>
<AppLayout>
<Dashboard />
</AppLayout>
</ProtectedRoute>
} />
)}
<Route path="/collections" element={
{pathname === '/collections' && (
<ProtectedRoute>
<AppLayout>
<Collections />
</AppLayout>
</ProtectedRoute>
} />
)}
<Route path="/decks" element={
{pathname === '/decks' && (
<ProtectedRoute>
<AppLayout>
<Decks />
</AppLayout>
</ProtectedRoute>
} />
)}
<Route path="/cards" element={
{pathname === '/cards' && (
<ProtectedRoute>
<AppLayout>
<Cards />
</AppLayout>
</ProtectedRoute>
} />
)}
<Route path="/scanner" element={
{pathname === '/scanner' && (
<ProtectedRoute>
<AppLayout>
<Scanner />
</AppLayout>
</ProtectedRoute>
} />
)}
<Route path="/settings" element={
{pathname === '/settings' && (
<ProtectedRoute>
<AppLayout>
<Settings />
</AppLayout>
</ProtectedRoute>
} />
)}
{/* Admin Routes */}
<Route path="/admin" element={
{pathname === '/admin' && (
<ProtectedRoute>
<AppLayout>
<AdminPanel />
</AppLayout>
</ProtectedRoute>
} />
)}
{/* Default redirect */}
<Route path="/" element={<Navigate to="/dashboard" replace />} />
{pathname === '/' && (
<ProtectedRoute>
<AppLayout>
<Dashboard />
</AppLayout>
</ProtectedRoute>
)}
{/* 404 fallback */}
<Route path="*" element={
{!['/login', '/register', '/dashboard', '/collections', '/decks', '/cards', '/scanner', '/settings', '/admin', '/'].includes(pathname) && (
<AppLayout>
<div className="text-center py-12">
<div className="w-16 h-16 bg-surface-200 dark:bg-surface-700 rounded-2xl flex items-center justify-center mx-auto mb-6">
@ -191,23 +191,20 @@ function App() {
</svg>
</div>
<h1 className="text-2xl font-bold text-surface-900 dark:text-white mb-2">Page Not Found</h1>
<p className="text-surface-600 dark:text-surface-400 mb-6">The page you're looking for doesn't exist.</p>
<p className="text-surface-600 dark:text-surface-400 mb-6">The page you&apos;re looking for doesn&apos;t exist.</p>
<button
onClick={() => window.history.back()}
onClick={() => router.back()}
className="bg-primary-600 hover:bg-primary-700 text-white px-6 py-3 rounded-xl font-medium transition-colors"
>
Go Back
</button>
</div>
</AppLayout>
} />
</Routes>
)}
<Analytics />
<SpeedInsights />
</Router>
</AuthProvider>
</ThemeProvider>
</QueryClientProvider>
);
}

View file

@ -221,7 +221,7 @@ const CameraScanner: React.FC<CameraScannerProps> = ({ onCardScanned, onError })
<div className="text-white text-center">
<div className="text-4xl mb-2">📹</div>
<div className="font-medium">Camera Preview</div>
<div className="text-sm opacity-75">Click "Start Camera" to begin</div>
<div className="text-sm opacity-75">Click &quot;Start Camera&quot; to begin</div>
</div>
</div>
)}

View file

@ -137,7 +137,7 @@ const LoginForm: React.FC = () => {
<div className="text-center">
<p className="text-surface-600 dark:text-surface-400">
Don't have an account?{' '}
Don&apos;t have an account?{' '}
<Link
to="/register"
className="text-primary-600 dark:text-primary-400 hover:text-primary-700 dark:hover:text-primary-300 font-medium transition-colors"

View file

@ -18,9 +18,13 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
"jsx": "preserve",
"incremental": true
},
"include": [
"src"
],
"exclude": [
"node_modules"
]
}