Nicholai 16cee69250 __Admin dashboard scaffolded with D1 database and R2 file uploads__
This commit implements the core admin dashboard functionality including NextAuth authentication, Cloudflare D1 database integration with complete schema, and Cloudflare R2 file upload system for portfolio images. Features include artist management, appointment scheduling, and data migration capabilities.
2025-09-17 16:08:34 -06:00

22 lines
5.1 KiB
JavaScript

"use strict";exports.id=1253,exports.ids=[1253],exports.modules={33897:(e,i,r)=>{r.d(i,{Lz:()=>_,mk:()=>u});var n=r(22571),t=r(43016),a=r(76214),o=r(29628);let s=o.z.object({DATABASE_URL:o.z.string().url(),DIRECT_URL:o.z.string().url().optional(),NEXTAUTH_URL:o.z.string().url(),NEXTAUTH_SECRET:o.z.string().min(1),GOOGLE_CLIENT_ID:o.z.string().optional(),GOOGLE_CLIENT_SECRET:o.z.string().optional(),GITHUB_CLIENT_ID:o.z.string().optional(),GITHUB_CLIENT_SECRET:o.z.string().optional(),AWS_ACCESS_KEY_ID:o.z.string().min(1),AWS_SECRET_ACCESS_KEY:o.z.string().min(1),AWS_REGION:o.z.string().min(1),AWS_BUCKET_NAME:o.z.string().min(1),AWS_ENDPOINT_URL:o.z.string().url().optional(),NODE_ENV:o.z.enum(["development","production","test"]).default("development"),SMTP_HOST:o.z.string().optional(),SMTP_PORT:o.z.string().optional(),SMTP_USER:o.z.string().optional(),SMTP_PASSWORD:o.z.string().optional(),VERCEL_ANALYTICS_ID:o.z.string().optional()}),l=function(){try{return s.parse(process.env)}catch(e){if(e instanceof o.z.ZodError){let i=e.errors.map(e=>e.path.join(".")).join(", ");throw Error(`Missing or invalid environment variables: ${i}`)}throw e}}();var E=r(74725);let _={providers:[(0,a.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:E.i.SUPER_ADMIN};console.log("Using fallback user creation");let i={id:"dev-user-"+Date.now(),email:e.email,name:e.email.split("@")[0],role:E.i.SUPER_ADMIN};return console.log("Created user:",i),i}}),...l.GOOGLE_CLIENT_ID&&l.GOOGLE_CLIENT_SECRET?[(0,n.Z)({clientId:l.GOOGLE_CLIENT_ID,clientSecret:l.GOOGLE_CLIENT_SECRET})]:[],...l.GITHUB_CLIENT_ID&&l.GITHUB_CLIENT_SECRET?[(0,t.Z)({clientId:l.GITHUB_CLIENT_ID,clientSecret:l.GITHUB_CLIENT_SECRET})]:[]],session:{strategy:"jwt",maxAge:2592e3},callbacks:{jwt:async({token:e,user:i,account:r})=>(i&&(e.role=i.role||E.i.CLIENT,e.userId=i.id),e),session:async({session:e,token:i})=>(i&&(e.user.id=i.userId,e.user.role=i.role),e),signIn:async({user:e,account:i,profile:r})=>!0,redirect:async({url:e,baseUrl:i})=>e.startsWith("/")?`${i}${e}`:new URL(e).origin===i?e:`${i}/admin`},pages:{signIn:"/auth/signin",error:"/auth/error"},events:{async signIn({user:e,account:i,profile:r,isNewUser:n}){console.log(`User ${e.email} signed in`)},async signOut({session:e,token:i}){console.log("User signed out")}},debug:"development"===l.NODE_ENV};async function c(){let{getServerSession:e}=await r.e(4128).then(r.bind(r,4128));return e(_)}async function u(e){let i=await c();if(!i)throw Error("Authentication required");if(e&&!function(e,i){let r={[E.i.CLIENT]:0,[E.i.ARTIST]:1,[E.i.SHOP_ADMIN]:2,[E.i.SUPER_ADMIN]:3};return r[e]>=r[i]}(i.user.role,e))throw Error("Insufficient permissions");return i}},1035:(e,i,r)=>{function n(e){if(e?.DB)return e.DB;let i=globalThis[Symbol.for("__cloudflare-context__")],r=i?.env?.DB,n=globalThis.DB||globalThis.env?.DB,t=r||n;if(!t)throw Error("Cloudflare D1 binding (env.DB) is unavailable");return t}async function t(e){let i=n(e);return(await i.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.is_active = 1
ORDER BY a.created_at DESC
`).all()).results}async function a(e,i){let r=n(i),t=crypto.randomUUID(),a=e.userId;if(!a){let i=await r.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();a=i?.id}return await r.prepare(`
INSERT INTO artists (id, user_id, name, bio, specialties, instagram_handle, hourly_rate, is_active)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
RETURNING *
`).bind(t,a,e.name,e.bio,JSON.stringify(e.specialties),e.instagramHandle||null,e.hourlyRate||null,!1!==e.isActive).first()}async function o(e,i,r){let t=n(r),a=crypto.randomUUID();return await t.prepare(`
INSERT INTO portfolio_images (id, artist_id, url, caption, tags, order_index, is_public)
VALUES (?, ?, ?, ?, ?, ?, ?)
RETURNING *
`).bind(a,e,i.url,i.caption||null,i.tags?JSON.stringify(i.tags):null,i.orderIndex||0,!1!==i.isPublic).first()}function s(e){if(e?.R2_BUCKET)return e.R2_BUCKET;let i=globalThis[Symbol.for("__cloudflare-context__")],r=i?.env?.R2_BUCKET,n=globalThis.R2_BUCKET||globalThis.env?.R2_BUCKET,t=r||n;if(!t)throw Error("Cloudflare R2 binding (env.R2_BUCKET) is unavailable");return t}r.d(i,{Ms:()=>s,Rw:()=>a,VK:()=>n,fC:()=>t,xd:()=>o})},74725:(e,i,r)=>{var n,t;r.d(i,{Z:()=>t,i:()=>n}),function(e){e.SUPER_ADMIN="SUPER_ADMIN",e.SHOP_ADMIN="SHOP_ADMIN",e.ARTIST="ARTIST",e.CLIENT="CLIENT"}(n||(n={})),function(e){e.PENDING="PENDING",e.CONFIRMED="CONFIRMED",e.IN_PROGRESS="IN_PROGRESS",e.COMPLETED="COMPLETED",e.CANCELLED="CANCELLED"}(t||(t={}))}};