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.
1 line
12 KiB
JavaScript
1 line
12 KiB
JavaScript
"use strict";(()=>{var e={};e.id=3196,e.ids=[3196],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")},60349:(e,i,t)=>{t.r(i),t.d(i,{originalPathname:()=>I,patchFetch:()=>f,requestAsyncStorage:()=>b,routeModule:()=>c,serverHooks:()=>x,staticGenerationAsyncStorage:()=>v});var a={};t.r(a),t.d(a,{GET:()=>p,POST:()=>z,dynamic:()=>g});var n=t(73278),r=t(45002),s=t(54877),o=t(71309),l=t(33897),m=t(74725),d=t(69362),u=t(1035);let g="force-dynamic";async function p(e,{params:i}={},t){try{let{searchParams:i}=new URL(e.url),a=d.dC.parse({page:i.get("page")||"1",limit:i.get("limit")||"10"}),n=d.NK.parse({isActive:i.get("isActive"),specialty:i.get("specialty"),search:i.get("search")}),r=await (0,u.fC)(t?.env);if(void 0!==n.isActive&&(r=r.filter(e=>e.isActive===n.isActive)),n.specialty&&(r=r.filter(e=>e.specialties.some(e=>e.toLowerCase().includes(n.specialty.toLowerCase())))),n.search){let e=n.search.toLowerCase();r=r.filter(i=>i.name.toLowerCase().includes(e)||i.bio.toLowerCase().includes(e))}let s=(a.page-1)*a.limit,l=s+a.limit,m=r.slice(s,l);return o.NextResponse.json({artists:m,pagination:{page:a.page,limit:a.limit,total:r.length,totalPages:Math.ceil(r.length/a.limit)},filters:n})}catch(e){return console.error("Error fetching artists:",e),o.NextResponse.json({error:"Failed to fetch artists"},{status:500})}}async function z(e,{params:i}={},t){try{let i=await (0,l.mk)(m.i.SHOP_ADMIN),a=await e.json(),n=d.Jt.parse(a),r=await (0,u.Rw)({...n,userId:i.user.id},t?.env);return o.NextResponse.json(r,{status:201})}catch(e){if(console.error("Error creating artist:",e),e instanceof Error){if(e.message.includes("Authentication required"))return o.NextResponse.json({error:"Authentication required"},{status:401});if(e.message.includes("Insufficient permissions"))return o.NextResponse.json({error:"Insufficient permissions"},{status:403})}return o.NextResponse.json({error:"Failed to create artist"},{status:500})}}let c=new n.AppRouteRouteModule({definition:{kind:r.x.APP_ROUTE,page:"/api/artists/route",pathname:"/api/artists",filename:"route",bundlePath:"app/api/artists/route"},resolvedPagePath:"/home/Nicholai/Documents/Dev/united_v03/united-tattoo/united-tattoo/app/api/artists/route.ts",nextConfigOutput:"standalone",userland:a}),{requestAsyncStorage:b,staticGenerationAsyncStorage:v,serverHooks:x}=c,I="/api/artists/route";function f(){return(0,s.patchFetch)({serverHooks:x,staticGenerationAsyncStorage:v})}},69362:(e,i,t)=>{t.d(i,{IF:()=>m,Jt:()=>r,NK:()=>u,dC:()=>d,xD:()=>s});var a=t(29628),n=t(74725);a.z.object({id:a.z.string().uuid(),email:a.z.string().email(),name:a.z.string().min(1,"Name is required"),role:a.z.nativeEnum(n.i),avatar:a.z.string().url().optional()}),a.z.object({email:a.z.string().email("Invalid email address"),name:a.z.string().min(1,"Name is required").max(100,"Name too long"),password:a.z.string().min(8,"Password must be at least 8 characters"),role:a.z.nativeEnum(n.i).default(n.i.CLIENT)}).partial().extend({id:a.z.string().uuid()}),a.z.object({id:a.z.string().uuid(),userId:a.z.string().uuid(),name:a.z.string().min(1,"Artist name is required"),bio:a.z.string().min(10,"Bio must be at least 10 characters"),specialties:a.z.array(a.z.string()).min(1,"At least one specialty is required"),instagramHandle:a.z.string().optional(),isActive:a.z.boolean().default(!0),hourlyRate:a.z.number().positive().optional()});let r=a.z.object({name:a.z.string().min(1,"Artist name is required").max(100,"Name too long"),bio:a.z.string().min(10,"Bio must be at least 10 characters").max(1e3,"Bio too long"),specialties:a.z.array(a.z.string().min(1)).min(1,"At least one specialty is required").max(10,"Too many specialties"),instagramHandle:a.z.string().regex(/^[a-zA-Z0-9._]+$/,"Invalid Instagram handle").optional(),hourlyRate:a.z.number().positive("Hourly rate must be positive").max(1e3,"Hourly rate too high").optional(),isActive:a.z.boolean().default(!0)}),s=r.partial().extend({id:a.z.string().uuid()});a.z.object({id:a.z.string().uuid(),artistId:a.z.string().uuid(),url:a.z.string().url("Invalid image URL"),caption:a.z.string().max(500,"Caption too long").optional(),tags:a.z.array(a.z.string()).max(20,"Too many tags"),order:a.z.number().int().min(0),isPublic:a.z.boolean().default(!0)}),a.z.object({artistId:a.z.string().uuid(),url:a.z.string().url("Invalid image URL"),caption:a.z.string().max(500,"Caption too long").optional(),tags:a.z.array(a.z.string().min(1)).max(20,"Too many tags").default([]),order:a.z.number().int().min(0).default(0),isPublic:a.z.boolean().default(!0)}).partial().extend({id:a.z.string().uuid()}),a.z.object({id:a.z.string().uuid(),artistId:a.z.string().uuid(),clientId:a.z.string().uuid(),title:a.z.string().min(1,"Title is required"),description:a.z.string().optional(),startTime:a.z.date(),endTime:a.z.date(),status:a.z.nativeEnum(n.Z),depositAmount:a.z.number().positive().optional(),totalAmount:a.z.number().positive().optional(),notes:a.z.string().optional()}),a.z.object({artistId:a.z.string().uuid("Invalid artist ID"),clientId:a.z.string().uuid("Invalid client ID"),title:a.z.string().min(1,"Title is required").max(200,"Title too long"),description:a.z.string().max(1e3,"Description too long").optional(),startTime:a.z.string().datetime("Invalid start time"),endTime:a.z.string().datetime("Invalid end time"),depositAmount:a.z.number().positive("Deposit must be positive").optional(),totalAmount:a.z.number().positive("Total amount must be positive").optional(),notes:a.z.string().max(1e3,"Notes too long").optional()}).refine(e=>new Date(e.endTime)>new Date(e.startTime),{message:"End time must be after start time",path:["endTime"]}),a.z.object({id:a.z.string().uuid(),artistId:a.z.string().uuid("Invalid artist ID").optional(),clientId:a.z.string().uuid("Invalid client ID").optional(),title:a.z.string().min(1,"Title is required").max(200,"Title too long").optional(),description:a.z.string().max(1e3,"Description too long").optional(),startTime:a.z.string().datetime("Invalid start time").optional(),endTime:a.z.string().datetime("Invalid end time").optional(),status:a.z.nativeEnum(n.Z).optional(),depositAmount:a.z.number().positive("Deposit must be positive").optional(),totalAmount:a.z.number().positive("Total amount must be positive").optional(),notes:a.z.string().max(1e3,"Notes too long").optional()}).refine(e=>!e.startTime||!e.endTime||new Date(e.endTime)>new Date(e.startTime),{message:"End time must be after start time",path:["endTime"]});let o=a.z.object({instagram:a.z.string().url("Invalid Instagram URL").optional(),facebook:a.z.string().url("Invalid Facebook URL").optional(),twitter:a.z.string().url("Invalid Twitter URL").optional(),tiktok:a.z.string().url("Invalid TikTok URL").optional()}),l=a.z.object({dayOfWeek:a.z.number().int().min(0).max(6),openTime:a.z.string().regex(/^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/,"Invalid time format (HH:mm)"),closeTime:a.z.string().regex(/^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/,"Invalid time format (HH:mm)"),isClosed:a.z.boolean().default(!1)});a.z.object({id:a.z.string().uuid(),studioName:a.z.string().min(1,"Studio name is required"),description:a.z.string().min(10,"Description must be at least 10 characters"),address:a.z.string().min(5,"Address is required"),phone:a.z.string().regex(/^[\+]?[1-9][\d]{0,15}$/,"Invalid phone number"),email:a.z.string().email("Invalid email address"),socialMedia:o,businessHours:a.z.array(l),heroImage:a.z.string().url("Invalid hero image URL").optional(),logoUrl:a.z.string().url("Invalid logo URL").optional()});let m=a.z.object({studioName:a.z.string().min(1,"Studio name is required").max(100,"Studio name too long").optional(),description:a.z.string().min(10,"Description must be at least 10 characters").max(1e3,"Description too long").optional(),address:a.z.string().min(5,"Address is required").max(200,"Address too long").optional(),phone:a.z.string().regex(/^[\+]?[1-9][\d]{0,15}$/,"Invalid phone number").optional(),email:a.z.string().email("Invalid email address").optional(),socialMedia:o.optional(),businessHours:a.z.array(l).optional(),heroImage:a.z.string().url("Invalid hero image URL").optional(),logoUrl:a.z.string().url("Invalid logo URL").optional()});a.z.object({id:a.z.string().uuid(),filename:a.z.string().min(1,"Filename is required"),originalName:a.z.string().min(1,"Original name is required"),mimeType:a.z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9!#$&\-\^_]*\/[a-zA-Z0-9][a-zA-Z0-9!#$&\-\^_.]*$/,"Invalid MIME type"),size:a.z.number().positive("File size must be positive"),url:a.z.string().url("Invalid file URL"),uploadedBy:a.z.string().uuid("Invalid user ID")}),a.z.object({filename:a.z.string().min(1,"Filename is required"),originalName:a.z.string().min(1,"Original name is required"),mimeType:a.z.string().regex(/^image\/(jpeg|jpg|png|gif|webp)$/,"Only image files are allowed"),size:a.z.number().positive("File size must be positive").max(10485760,"File too large (max 10MB)"),uploadedBy:a.z.string().uuid("Invalid user ID")});let d=a.z.object({page:a.z.string().nullable().transform(e=>e||"1").pipe(a.z.string().regex(/^\d+$/).transform(Number).pipe(a.z.number().int().min(1))),limit:a.z.string().nullable().transform(e=>e||"10").pipe(a.z.string().regex(/^\d+$/).transform(Number).pipe(a.z.number().int().min(1).max(100)))}),u=a.z.object({isActive:a.z.string().nullable().transform(e=>"true"===e||"false"!==e&&void 0).optional(),specialty:a.z.string().nullable().optional(),search:a.z.string().nullable().optional()});a.z.object({artistId:a.z.string().nullable().refine(e=>!e||a.z.string().uuid().safeParse(e).success,"Invalid artist ID").optional(),clientId:a.z.string().nullable().refine(e=>!e||a.z.string().uuid().safeParse(e).success,"Invalid client ID").optional(),status:a.z.string().nullable().refine(e=>!e||Object.values(n.Z).includes(e),"Invalid status").optional(),startDate:a.z.string().nullable().refine(e=>!e||a.z.string().datetime().safeParse(e).success,"Invalid start date").optional(),endDate:a.z.string().nullable().refine(e=>!e||a.z.string().datetime().safeParse(e).success,"Invalid end date").optional()}),a.z.object({email:a.z.string().email("Invalid email address"),password:a.z.string().min(1,"Password is required")}),a.z.object({name:a.z.string().min(1,"Name is required").max(100,"Name too long"),email:a.z.string().email("Invalid email address"),password:a.z.string().min(8,"Password must be at least 8 characters"),confirmPassword:a.z.string().min(1,"Please confirm your password")}).refine(e=>e.password===e.confirmPassword,{message:"Passwords don't match",path:["confirmPassword"]}),a.z.object({name:a.z.string().min(1,"Name is required").max(100,"Name too long"),email:a.z.string().email("Invalid email address"),phone:a.z.string().regex(/^[\+]?[1-9][\d]{0,15}$/,"Invalid phone number").optional(),subject:a.z.string().min(1,"Subject is required").max(200,"Subject too long"),message:a.z.string().min(10,"Message must be at least 10 characters").max(1e3,"Message too long")}),a.z.object({artistId:a.z.string().uuid("Please select an artist"),name:a.z.string().min(1,"Name is required").max(100,"Name too long"),email:a.z.string().email("Invalid email address"),phone:a.z.string().regex(/^[\+]?[1-9][\d]{0,15}$/,"Invalid phone number"),preferredDate:a.z.string().min(1,"Please select a preferred date"),tattooDescription:a.z.string().min(10,"Please provide more details about your tattoo").max(1e3,"Description too long"),size:a.z.enum(["small","medium","large","sleeve"],{required_error:"Please select a size"}),placement:a.z.string().min(1,"Please specify placement").max(100,"Placement description too long"),budget:a.z.string().optional(),hasAllergies:a.z.boolean().default(!1),allergies:a.z.string().max(500,"Allergies description too long").optional(),additionalNotes:a.z.string().max(500,"Additional notes too long").optional()})}};var i=require("../../../webpack-runtime.js");i.C(e);var t=e=>i(i.s=e),a=i.X(0,[9379,8213,4833,1253],()=>t(60349));module.exports=a})(); |