Nicholai 1378bff909 updated the following components to use the API instead of hardcoded data:
### 1. __artists-grid.tsx__ (Main Artist Browsing)

- Uses  hook from
- Fetches from  endpoint
- Includes loading states, error handling, and filtering
- __Impact:__ Primary artist browsing experience now fully API-driven

### 2. __artist-portfolio.tsx__ (Individual Artist Pages)

- Uses  hook
- Fetches from  endpoint
- Fixed all TypeScript errors (changed image ID from number to string)
- Added loading/error states
- __Impact:__ Artist detail pages now fully API-driven

### 3. __booking-form.tsx__ (Artist Selection Dropdown)

- Uses  hook for artist selection
- Updated to use API data structure ( array, , etc.)
- Added loading state for dropdown
- __Impact:__ Booking flow now uses real artist data

## ⚠️ REMAINING (Decorative/Marketing Components)

Two complex components still use hardcoded :

### 4. __artists-section.tsx__ (Homepage Hero - 348 lines)

- Homepage marketing section with complex parallax scrolling
- Uses hardcoded artist data for visual cards
- __Non-blocking:__ This is a decorative homepage element

### 5. __artists-page-section.tsx__ (Artists Page Section - 413 lines)

- Full-page artists showcase with parallax effects
- Uses hardcoded artist data for visual layout
- __Non-blocking:__ Alternative to artists-grid.tsx (which IS using API)

##
2025-10-06 04:44:08 -06:00

72 lines
14 KiB
JavaScript

"use strict";(()=>{var e={};e.id=5701,e.ids=[5701,1035],e.modules={72934:e=>{e.exports=require("next/dist/client/components/action-async-storage.external.js")},54580:e=>{e.exports=require("next/dist/client/components/request-async-storage.external.js")},45869:e=>{e.exports=require("next/dist/client/components/static-generation-async-storage.external.js")},20399:e=>{e.exports=require("next/dist/compiled/next-server/app-page.runtime.prod.js")},30517:e=>{e.exports=require("next/dist/compiled/next-server/app-route.runtime.prod.js")},27790:e=>{e.exports=require("assert")},78893:e=>{e.exports=require("buffer")},84770:e=>{e.exports=require("crypto")},17702:e=>{e.exports=require("events")},32615:e=>{e.exports=require("http")},35240:e=>{e.exports=require("https")},86624:e=>{e.exports=require("querystring")},17360:e=>{e.exports=require("url")},21764:e=>{e.exports=require("util")},71568:e=>{e.exports=require("zlib")},56710:(e,r,t)=>{t.r(r),t.d(r,{originalPathname:()=>I,patchFetch:()=>h,requestAsyncStorage:()=>g,routeModule:()=>f,serverHooks:()=>T,staticGenerationAsyncStorage:()=>R});var i={};t.r(i),t.d(i,{GET:()=>_,POST:()=>m,dynamic:()=>c});var a=t(73278),s=t(45002),n=t(54877),o=t(71309),u=t(18445),l=t(33897),d=t(1035),p=t(29628);let c="force-dynamic",E=p.z.object({name:p.z.string().min(1),email:p.z.string().email(),role:p.z.enum(["SUPER_ADMIN","SHOP_ADMIN","ARTIST","CLIENT"])});async function _(e,{params:r}={},t){try{let r=await (0,u.getServerSession)(l.Lz);if(!r?.user)return o.NextResponse.json({error:"Unauthorized"},{status:401});let{searchParams:i}=new URL(e.url),a=i.get("email"),s=(0,d.VK)(t?.env);if(a){let e=s.prepare("SELECT * FROM users WHERE email = ?"),r=await e.bind(a).first();if(!r)return o.NextResponse.json({error:"User not found"},{status:404});return o.NextResponse.json({user:r})}{let e=s.prepare("SELECT * FROM users ORDER BY created_at DESC"),r=await e.all();return o.NextResponse.json({users:r.results})}}catch(e){return console.error("Error fetching users:",e),o.NextResponse.json({error:"Failed to fetch users"},{status:500})}}async function m(e,{params:r}={},t){try{let r=await (0,u.getServerSession)(l.Lz);if(!r?.user)return o.NextResponse.json({error:"Unauthorized"},{status:401});let i=await e.json(),a=E.parse(i),s=(0,d.VK)(t?.env),n=s.prepare("SELECT id FROM users WHERE email = ?"),p=await n.bind(a.email).first();if(p)return o.NextResponse.json({user:p});let c=crypto.randomUUID(),_=s.prepare(`
INSERT INTO users (id, email, name, role, created_at, updated_at)
VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
`);await _.bind(c,a.email,a.name,a.role).run();let m=s.prepare("SELECT * FROM users WHERE id = ?"),f=await m.bind(c).first();return o.NextResponse.json({user:f},{status:201})}catch(e){if(console.error("Error creating user:",e),e instanceof p.z.ZodError)return o.NextResponse.json({error:"Invalid user data",details:e.errors},{status:400});return o.NextResponse.json({error:"Failed to create user"},{status:500})}}let f=new a.AppRouteRouteModule({definition:{kind:s.x.APP_ROUTE,page:"/api/users/route",pathname:"/api/users",filename:"route",bundlePath:"app/api/users/route"},resolvedPagePath:"/home/Nicholai/Documents/Dev/united_v03/united-tattoo/united-tattoo/app/api/users/route.ts",nextConfigOutput:"standalone",userland:i}),{requestAsyncStorage:g,staticGenerationAsyncStorage:R,serverHooks:T}=f,I="/api/users/route";function h(){return(0,n.patchFetch)({serverHooks:T,staticGenerationAsyncStorage:R})}},33897:(e,r,t)=>{t.d(r,{Lz:()=>d,KR:()=>_,Z1:()=>p,GJ:()=>E,KN:()=>m,mk:()=>c});var i=t(22571),a=t(43016),s=t(76214),n=t(29628);let o=n.z.object({DATABASE_URL:n.z.string().url(),DIRECT_URL:n.z.string().url().optional(),NEXTAUTH_URL:n.z.string().url(),NEXTAUTH_SECRET:n.z.string().min(1),GOOGLE_CLIENT_ID:n.z.string().optional(),GOOGLE_CLIENT_SECRET:n.z.string().optional(),GITHUB_CLIENT_ID:n.z.string().optional(),GITHUB_CLIENT_SECRET:n.z.string().optional(),AWS_ACCESS_KEY_ID:n.z.string().min(1),AWS_SECRET_ACCESS_KEY:n.z.string().min(1),AWS_REGION:n.z.string().min(1),AWS_BUCKET_NAME:n.z.string().min(1),AWS_ENDPOINT_URL:n.z.string().url().optional(),NODE_ENV:n.z.enum(["development","production","test"]).default("development"),SMTP_HOST:n.z.string().optional(),SMTP_PORT:n.z.string().optional(),SMTP_USER:n.z.string().optional(),SMTP_PASSWORD:n.z.string().optional(),VERCEL_ANALYTICS_ID:n.z.string().optional()}),u=function(){try{return o.parse(process.env)}catch(e){if(e instanceof n.z.ZodError){let r=e.errors.map(e=>e.path.join(".")).join(", ");throw Error(`Missing or invalid environment variables: ${r}`)}throw e}}();var l=t(74725);let d={providers:[(0,s.Z)({name:"credentials",credentials:{email:{label:"Email",type:"email"},password:{label:"Password",type:"password"}},async authorize(e){if(console.log("Authorize called with:",e),!e?.email||!e?.password)return console.log("Missing email or password"),null;if(console.log("Email received:",e.email),console.log("Password received:",e.password?"***":"empty"),"nicholai@biohazardvfx.com"===e.email)return console.log("Admin user recognized!"),{id:"admin-nicholai",email:"nicholai@biohazardvfx.com",name:"Nicholai",role:l.i.SUPER_ADMIN};console.log("Using fallback user creation");let r={id:"dev-user-"+Date.now(),email:e.email,name:e.email.split("@")[0],role:l.i.SUPER_ADMIN};return console.log("Created user:",r),r}}),...u.GOOGLE_CLIENT_ID&&u.GOOGLE_CLIENT_SECRET?[(0,i.Z)({clientId:u.GOOGLE_CLIENT_ID,clientSecret:u.GOOGLE_CLIENT_SECRET})]:[],...u.GITHUB_CLIENT_ID&&u.GITHUB_CLIENT_SECRET?[(0,a.Z)({clientId:u.GITHUB_CLIENT_ID,clientSecret:u.GITHUB_CLIENT_SECRET})]:[]],session:{strategy:"jwt",maxAge:2592e3},callbacks:{jwt:async({token:e,user:r,account:t})=>(r&&(e.role=r.role||l.i.CLIENT,e.userId=r.id),e),session:async({session:e,token:r})=>(r&&(e.user.id=r.userId,e.user.role=r.role),e),signIn:async({user:e,account:r,profile:t})=>!0,redirect:async({url:e,baseUrl:r})=>e.startsWith("/")?`${r}${e}`:new URL(e).origin===r?e:`${r}/admin`},pages:{signIn:"/auth/signin",error:"/auth/error"},events:{async signIn({user:e,account:r,profile:t,isNewUser:i}){console.log(`User ${e.email} signed in`)},async signOut({session:e,token:r}){console.log("User signed out")}},debug:"development"===u.NODE_ENV};async function p(){let{getServerSession:e}=await t.e(4128).then(t.bind(t,4128));return e(d)}async function c(e){let r=await p();if(!r)throw Error("Authentication required");if(e&&!function(e,r){let t={[l.i.CLIENT]:0,[l.i.ARTIST]:1,[l.i.SHOP_ADMIN]:2,[l.i.SUPER_ADMIN]:3};return t[e]>=t[r]}(r.user.role,e))throw Error("Insufficient permissions");return r}function E(e){return e===l.i.SHOP_ADMIN||e===l.i.SUPER_ADMIN}async function _(){let e=await p();if(!e?.user)return null;let r=e.user.role;if(r!==l.i.ARTIST&&!E(r))return null;let{getArtistByUserId:i}=await t.e(1035).then(t.bind(t,1035)),a=await i(e.user.id);return a?{artist:a,user:e.user}:null}async function m(){let e=await _();if(!e)throw Error("Artist authentication required");return e}},1035:(e,r,t)=>{function i(e){if(e?.DB)return e.DB;let r=globalThis[Symbol.for("__cloudflare-context__")],t=r?.env?.DB,i=globalThis.DB||globalThis.env?.DB,a=t||i;if(!a)throw Error("Cloudflare D1 binding (env.DB) is unavailable");return a}async function a(e,r){let t=i(r),a=`
SELECT
a.id,
a.slug,
a.name,
a.bio,
a.specialties,
a.instagram_handle,
a.is_active,
a.hourly_rate
FROM artists a
WHERE a.is_active = 1
`,s=[];e?.specialty&&(a+=" AND a.specialties LIKE ?",s.push(`%${e.specialty}%`)),e?.search&&(a+=" AND (a.name LIKE ? OR a.bio LIKE ?)",s.push(`%${e.search}%`,`%${e.search}%`)),a+=" ORDER BY a.created_at DESC",e?.limit&&(a+=" LIMIT ?",s.push(e.limit)),e?.offset&&(a+=" OFFSET ?",s.push(e.offset));let n=await t.prepare(a).bind(...s).all();return await Promise.all(n.results.map(async e=>{let r=await t.prepare(`
SELECT * FROM portfolio_images
WHERE artist_id = ? AND is_public = 1
ORDER BY order_index ASC, created_at DESC
`).bind(e.id).all();return{id:e.id,slug:e.slug,name:e.name,bio:e.bio,specialties:e.specialties?JSON.parse(e.specialties):[],instagramHandle:e.instagram_handle,isActive:!!e.is_active,hourlyRate:e.hourly_rate,portfolioImages:r.results.map(e=>({id:e.id,artistId:e.artist_id,url:e.url,caption:e.caption,tags:e.tags?JSON.parse(e.tags):[],orderIndex:e.order_index,isPublic:!!e.is_public,createdAt:new Date(e.created_at)}))}}))}async function s(e,r){let t=i(r),a=await t.prepare(`
SELECT
a.*,
u.name as user_name,
u.email as user_email,
u.avatar as user_avatar
FROM artists a
LEFT JOIN users u ON a.user_id = u.id
WHERE a.id = ?
`).bind(e).first();if(!a)return null;let s=await t.prepare(`
SELECT * FROM portfolio_images
WHERE artist_id = ?
ORDER BY order_index ASC, created_at DESC
`).bind(e).all();return{id:a.id,userId:a.user_id,slug:a.slug,name:a.name,bio:a.bio,specialties:a.specialties?JSON.parse(a.specialties):[],instagramHandle:a.instagram_handle,isActive:!!a.is_active,hourlyRate:a.hourly_rate,portfolioImages:s.results.map(e=>({id:e.id,artistId:e.artist_id,url:e.url,caption:e.caption,tags:e.tags?JSON.parse(e.tags):[],orderIndex:e.order_index,isPublic:!!e.is_public,createdAt:new Date(e.created_at)})),availability:[],createdAt:new Date(a.created_at),updatedAt:new Date(a.updated_at),user:{name:a.user_name,email:a.user_email,avatar:a.user_avatar}}}async function n(e,r){let t=i(r),a=await t.prepare(`
SELECT
a.*,
u.name as user_name,
u.email as user_email,
u.avatar as user_avatar
FROM artists a
LEFT JOIN users u ON a.user_id = u.id
WHERE a.slug = ?
`).bind(e).first();return a?s(a.id,r):null}async function o(e,r){let t=i(r),a=await t.prepare(`
SELECT
a.*,
u.name as user_name,
u.email as user_email
FROM artists a
LEFT JOIN users u ON a.user_id = u.id
WHERE a.user_id = ?
`).bind(e).first();return a?{id:a.id,userId:a.user_id,slug:a.slug,name:a.name,bio:a.bio,specialties:a.specialties?JSON.parse(a.specialties):[],instagramHandle:a.instagram_handle,isActive:!!a.is_active,hourlyRate:a.hourly_rate,portfolioImages:[],availability:[],createdAt:new Date(a.created_at),updatedAt:new Date(a.updated_at)}:null}async function u(e,r){let t=i(r),a=crypto.randomUUID(),s=e.userId;if(!s){let r=await t.prepare(`
INSERT INTO users (id, email, name, role)
VALUES (?, ?, ?, 'ARTIST')
RETURNING id
`).bind(crypto.randomUUID(),e.email||`${e.name.toLowerCase().replace(/\s+/g,".")}@unitedtattoo.com`,e.name).first();s=r?.id}return await t.prepare(`
INSERT INTO artists (id, user_id, name, bio, specialties, instagram_handle, hourly_rate, is_active)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
RETURNING *
`).bind(a,s,e.name,e.bio,JSON.stringify(e.specialties),e.instagramHandle||null,e.hourlyRate||null,!1!==e.isActive).first()}async function l(e,r,t){let a=i(t),s=[],n=[];return void 0!==r.name&&(s.push("name = ?"),n.push(r.name)),void 0!==r.bio&&(s.push("bio = ?"),n.push(r.bio)),void 0!==r.specialties&&(s.push("specialties = ?"),n.push(JSON.stringify(r.specialties))),void 0!==r.instagramHandle&&(s.push("instagram_handle = ?"),n.push(r.instagramHandle)),void 0!==r.hourlyRate&&(s.push("hourly_rate = ?"),n.push(r.hourlyRate)),void 0!==r.isActive&&(s.push("is_active = ?"),n.push(r.isActive)),s.push("updated_at = CURRENT_TIMESTAMP"),n.push(e),await a.prepare(`
UPDATE artists
SET ${s.join(", ")}
WHERE id = ?
RETURNING *
`).bind(...n).first()}async function d(e,r){let t=i(r);await t.prepare("UPDATE artists SET is_active = 0 WHERE id = ?").bind(e).run()}async function p(e,r,t){let a=i(t),s=crypto.randomUUID();return await a.prepare(`
INSERT INTO portfolio_images (id, artist_id, url, caption, tags, order_index, is_public)
VALUES (?, ?, ?, ?, ?, ?, ?)
RETURNING *
`).bind(s,e,r.url,r.caption||null,r.tags?JSON.stringify(r.tags):null,r.orderIndex||0,!1!==r.isPublic).first()}async function c(e,r,t){let a=i(t),s=[],n=[];return void 0!==r.url&&(s.push("url = ?"),n.push(r.url)),void 0!==r.caption&&(s.push("caption = ?"),n.push(r.caption)),void 0!==r.tags&&(s.push("tags = ?"),n.push(r.tags?JSON.stringify(r.tags):null)),void 0!==r.orderIndex&&(s.push("order_index = ?"),n.push(r.orderIndex)),void 0!==r.isPublic&&(s.push("is_public = ?"),n.push(r.isPublic)),n.push(e),await a.prepare(`
UPDATE portfolio_images
SET ${s.join(", ")}
WHERE id = ?
RETURNING *
`).bind(...n).first()}async function E(e,r){let t=i(r);await t.prepare("DELETE FROM portfolio_images WHERE id = ?").bind(e).run()}function _(e){if(e?.R2_BUCKET)return e.R2_BUCKET;let r=globalThis[Symbol.for("__cloudflare-context__")],t=r?.env?.R2_BUCKET,i=globalThis.R2_BUCKET||globalThis.env?.R2_BUCKET,a=t||i;if(!a)throw Error("Cloudflare R2 binding (env.R2_BUCKET) is unavailable");return a}t.d(r,{Hf:()=>a,Ms:()=>_,Rw:()=>u,VK:()=>i,W0:()=>c,cP:()=>E,ce:()=>s,ep:()=>l,ex:()=>n,getArtistByUserId:()=>o,vB:()=>d,xd:()=>p})},32482:(e,r)=>{Object.defineProperty(r,"__esModule",{value:!0})},18445:(e,r,t)=>{Object.defineProperty(r,"__esModule",{value:!0});var i={};Object.defineProperty(r,"default",{enumerable:!0,get:function(){return s.default}});var a=t(32482);Object.keys(a).forEach(function(e){!("default"===e||"__esModule"===e||Object.prototype.hasOwnProperty.call(i,e))&&(e in r&&r[e]===a[e]||Object.defineProperty(r,e,{enumerable:!0,get:function(){return a[e]}}))});var s=function(e,r){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=n(void 0);if(t&&t.has(e))return t.get(e);var i={__proto__:null},a=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var s in e)if("default"!==s&&({}).hasOwnProperty.call(e,s)){var o=a?Object.getOwnPropertyDescriptor(e,s):null;o&&(o.get||o.set)?Object.defineProperty(i,s,o):i[s]=e[s]}return i.default=e,t&&t.set(e,i),i}(t(4128));function n(e){if("function"!=typeof WeakMap)return null;var r=new WeakMap,t=new WeakMap;return(n=function(e){return e?t:r})(e)}Object.keys(s).forEach(function(e){!("default"===e||"__esModule"===e||Object.prototype.hasOwnProperty.call(i,e))&&(e in r&&r[e]===s[e]||Object.defineProperty(r,e,{enumerable:!0,get:function(){return s[e]}}))})},74725:(e,r,t)=>{var i,a;t.d(r,{Z:()=>a,i:()=>i}),function(e){e.SUPER_ADMIN="SUPER_ADMIN",e.SHOP_ADMIN="SHOP_ADMIN",e.ARTIST="ARTIST",e.CLIENT="CLIENT"}(i||(i={})),function(e){e.PENDING="PENDING",e.CONFIRMED="CONFIRMED",e.IN_PROGRESS="IN_PROGRESS",e.COMPLETED="COMPLETED",e.CANCELLED="CANCELLED"}(a||(a={}))}};var r=require("../../../webpack-runtime.js");r.C(e);var t=e=>r(r.s=e),i=r.X(0,[9379,3670,4128,4833],()=>t(56710));module.exports=i})();