modify commission ordering form

This commit is contained in:
2025-07-06 10:52:05 +02:00
parent ebb5bf9a52
commit f4db985695
4 changed files with 73 additions and 103 deletions

View File

@ -34,7 +34,7 @@ model CommissionOption {
updatedAt DateTime @updatedAt
sortIndex Int @default(0)
name String @unique
name String
description String?
@ -47,7 +47,7 @@ model CommissionExtra {
updatedAt DateTime @updatedAt
sortIndex Int @default(0)
name String @unique
name String
description String?
@ -91,84 +91,3 @@ model CommissionTypeExtra {
@@unique([typeId, extraId])
}
// model User {
// id String @id @default(cuid())
// email String @unique
// name String?
// role Role @default(ADMIN)
// createdAt DateTime @default(now())
// }
// enum Role {
// ADMIN
// ARTIST
// }
// model CommissionType {
// id String @id @default(cuid())
// title String
// description String?
// basePrice Float
// deliveryEst String? // e.g. "2 weeks"
// tags String[] // e.g. shaded, sketch, full-body
// active Boolean @default(true)
// createdAt DateTime @default(now())
// CommissionRequest CommissionRequest[]
// }
// model CommissionRequest {
// id String @id @default(cuid())
// name String
// email String
// message String
// typeId String
// status RequestStatus @default(PENDING)
// createdAt DateTime @default(now())
// type CommissionType @relation(fields: [typeId], references: [id])
// }
// enum RequestStatus {
// PENDING
// ACCEPTED
// IN_PROGRESS
// DONE
// REJECTED
// }
// model Artwork {
// id String @id @default(cuid())
// title String
// imageUrl String
// description String?
// tags String[]
// formats String[]
// isPublic Boolean @default(true)
// groupId String?
// createdAt DateTime @default(now())
// group PresentationGroup? @relation(fields: [groupId], references: [id])
// }
// model PresentationGroup {
// id String @id @default(cuid())
// name String
// description String?
// createdAt DateTime @default(now())
// Artwork Artwork[]
// }
// model Preferences {
// id String @id @default(cuid())
// commissionOpen Boolean @default(true)
// defaultDelivery String? // e.g. "7 days"
// autoReplyMessage String?
// notifyByEmail Boolean @default(true)
// }
// model TOS {
// id String @id @default(cuid())
// content String // Markdown or rich text
// createdAt DateTime @default(now())
// }

View File

@ -3,7 +3,7 @@
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { CommissionExtra, CommissionOption, CommissionType, CommissionTypeExtra, CommissionTypeOption } from "@/generated/prisma"
// import { useState } from "react"
import { Badge } from "../ui/badge"
// import { Badge } from "../ui/badge"
type CommissionTypeWithItems = CommissionType & {
options: (CommissionTypeOption & {
@ -85,13 +85,13 @@ export function CommissionCard({ commission }: { commission: CommissionTypeWithI
</ul>
</div>
<div className="flex flex-wrap gap-2">
{/* <div className="flex flex-wrap gap-2">
{commission.extras.map((extra) => (
<Badge variant="outline" key={extra.id}>
{extra.extra?.name}
</Badge>
))}
</div>
</div> */}
</CardContent>
</Card>
</div>

View File

@ -77,7 +77,6 @@ export function CommissionOrderForm({ types }: Props) {
async function onSubmit(values: z.infer<typeof commissionOrderSchema>) {
console.log("Submit:", { ...values, files })
// TODO: send to server
}
return (
@ -220,12 +219,23 @@ export function CommissionOrderForm({ types }: Props) {
)}
/>
<div>
<FormItem>
<FormLabel>Reference Images</FormLabel>
<FileDropzone onFilesSelected={(f: File[]) => setFiles(f)} />
<FormControl>
<div className="space-y-2">
<FileDropzone onFilesSelected={setFiles} />
{files.length > 0 && (
<ul className="list-disc pl-4 text-sm text-muted-foreground">
{files.map((file, i) => (
<li key={i}>{file.name}</li>
))}
</ul>
)}
</div>
</FormControl>
</FormItem>
<div className="text-xl font-semibold">
<div className="text-lg font-semibold">
Estimated Price: {price.toFixed(2)}
</div>

View File

@ -1,24 +1,65 @@
// components/form/FileDropzone.tsx
"use client"
import { useCallback } from "react"
import { cn } from "@/lib/utils"
import { useCallback, useRef, useState } from "react"
export function FileDropzone({
onFilesSelected,
}: {
onFilesSelected: (files: File[]) => void
}) {
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files) {
onFilesSelected(Array.from(e.target.files))
const [isDragging, setIsDragging] = useState(false)
const inputRef = useRef<HTMLInputElement | null>(null)
const handleFiles = (files: FileList | null) => {
if (files) {
onFilesSelected(Array.from(files))
}
}, [onFilesSelected])
}
const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault()
setIsDragging(false)
handleFiles(e.dataTransfer.files)
}
const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault()
setIsDragging(true)
}
const handleDragLeave = () => {
setIsDragging(false)
}
const handleChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
handleFiles(e.target.files)
},
[onFilesSelected]
)
return (
<div
onClick={() => inputRef.current?.click()}
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
className={cn(
"w-full border-2 border-dashed rounded-md p-6 text-center cursor-pointer transition-colors",
isDragging ? "border-primary bg-muted" : "border-muted-foreground/30"
)}
>
<input
ref={inputRef}
type="file"
multiple
onChange={handleChange}
className="border p-2 rounded-md"
className="hidden"
/>
<p className="text-sm text-muted-foreground">
Drag & drop images here or click to upload
</p>
</div>
)
}