Fix incosistencies in the custom commission types

This commit is contained in:
2026-02-01 23:21:35 +01:00
parent 145770afbe
commit d6695e4c1d
3 changed files with 145 additions and 114 deletions

View File

@ -42,28 +42,33 @@ export default async function CommissionsPage() {
<div className="mx-auto w-full max-w-6xl px-4 py-8 flex flex-col gap-8"> <div className="mx-auto w-full max-w-6xl px-4 py-8 flex flex-col gap-8">
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between"> <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<h1 className="text-3xl font-bold">Commission Pricing</h1> <h1 className="text-3xl font-bold">Commission Pricing</h1>
{guidelines?.exampleImageUrl ? ( <div className="flex flex-wrap gap-3">
<Dialog> <Button asChild>
<DialogTrigger asChild> <a href="#commission-request-form">Get to the request form</a>
<Button variant="secondary">View example</Button> </Button>
</DialogTrigger> {guidelines?.exampleImageUrl ? (
<DialogContent className="flex w-auto! max-w-[95vw]! flex-col p-4 sm:p-6"> <Dialog>
<DialogHeader className="sr-only"> <DialogTrigger asChild>
<DialogTitle>Commission example</DialogTitle> <Button variant="secondary">View example</Button>
</DialogHeader> </DialogTrigger>
<div className="flex max-h-[85vh] max-w-[85vw] items-center justify-center rounded-xl border-border/60 bg-muted p-2 shadow-2xl"> <DialogContent className="flex w-auto! max-w-[95vw]! flex-col p-4 sm:p-6">
<Image <DialogHeader className="sr-only">
src={guidelines.exampleImageUrl} <DialogTitle>Commission example</DialogTitle>
alt="Commission example" </DialogHeader>
width={1600} <div className="flex max-h-[85vh] max-w-[85vw] items-center justify-center rounded-xl border-border/60 bg-muted p-2 shadow-2xl">
height={1200} <Image
sizes="85vw" src={guidelines.exampleImageUrl}
className="h-auto max-h-[85vh] w-auto max-w-[85vw] rounded-lg object-contain" alt="Commission example"
/> width={1600}
</div> height={1200}
</DialogContent> sizes="85vw"
</Dialog> className="h-auto max-h-[85vh] w-auto max-w-[85vw] rounded-lg object-contain"
) : null} />
</div>
</DialogContent>
</Dialog>
) : null}
</div>
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 items-start"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 items-start">
{commissions.map((commission) => ( {commissions.map((commission) => (
@ -75,7 +80,9 @@ export default async function CommissionsPage() {
<CommissionGuidelines /> <CommissionGuidelines />
</div> </div>
<hr /> <hr />
<h2 className="text-2xl font-semibold">Request a Commission</h2> <h2 id="commission-request-form" className="text-2xl font-semibold scroll-mt-24">
Request a Commission
</h2>
<CommissionOrderForm types={commissions} customCards={customCards} /> <CommissionOrderForm types={commissions} customCards={customCards} />
</div> </div>
); );

View File

@ -8,6 +8,7 @@ import {
DialogTitle, DialogTitle,
DialogTrigger, DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { cn } from "@/lib/utils";
import Image from "next/image"; import Image from "next/image";
type CustomCardOption = { type CustomCardOption = {
@ -43,98 +44,107 @@ export function CommissionCustomCard({
}) { }) {
return ( return (
<div className="flex flex-col h-full"> <div className="flex flex-col h-full">
<Card className="flex flex-col flex-1 relative overflow-hidden border-2 border-primary/50 shadow-sm"> <div className="overflow-hidden h-full">
{card.isSpecialOffer ? ( <Card
<div className="pointer-events-none absolute right-0 top-0 z-10"> className={cn(
<div className="absolute right-0 top-16 h-7 w-36 origin-top-right translate-x-10 rotate-45 bg-primary text-primary-foreground shadow-md"> "flex flex-col h-full relative shadow-sm",
<span className="flex h-full w-full items-center justify-center text-xs font-semibold uppercase tracking-wide"> card.isSpecialOffer
Special ? "border-2 border-primary/50"
</span> : "border-border"
)}
>
{card.isSpecialOffer ? (
<div className="pointer-events-none absolute right-0 top-0 z-10 overflow-visible">
<div className="absolute right-0 top-16 h-7 w-36 origin-top-right translate-x-10 rotate-45 bg-primary text-primary-foreground shadow-md">
<span className="flex h-full w-full items-center justify-center text-xs font-semibold uppercase tracking-wide">
Special
</span>
</div>
</div> </div>
</div>
) : null}
<CardHeader className="gap-2">
<CardTitle className="text-xl font-bold">{card.name}</CardTitle>
<p className="text-muted-foreground text-sm">{card.description}</p>
{card.referenceImageUrl ? (
<Dialog>
<DialogTrigger asChild>
<button
type="button"
className="group relative overflow-hidden rounded-lg border border-border/60 bg-muted/40"
>
<Image
src={card.referenceImageUrl}
alt={`${card.name} reference`}
width={800}
height={600}
sizes="(max-width: 768px) 90vw, 400px"
className="h-auto w-full object-cover transition-transform duration-200 group-hover:scale-[1.02]"
/>
<span className="absolute inset-x-0 bottom-0 bg-background/70 px-2 py-1 text-xs text-foreground/80">
Click to enlarge
</span>
</button>
</DialogTrigger>
<DialogContent className="flex w-auto! max-w-[95vw]! flex-col p-4 sm:p-6">
<DialogHeader className="sr-only">
<DialogTitle>{card.name} reference</DialogTitle>
</DialogHeader>
<div className="flex max-h-[85vh] max-w-[85vw] items-center justify-center rounded-xl border-border/60 bg-muted p-2 shadow-2xl">
<Image
src={card.referenceImageUrl}
alt={`${card.name} reference`}
width={1600}
height={1200}
sizes="85vw"
className="h-auto max-h-[85vh] w-auto max-w-[85vw] rounded-lg object-contain"
/>
</div>
</DialogContent>
</Dialog>
) : null} ) : null}
</CardHeader> <CardHeader className="gap-2">
<CardTitle className="text-xl font-bold">{card.name}</CardTitle>
<CardContent className="flex flex-col justify-start gap-4"> <p className="text-muted-foreground text-sm">{card.description}</p>
<div> {card.referenceImageUrl ? (
<h4 className="font-semibold">Options</h4> <Dialog>
<ul className="pl-4 list-disc"> <DialogTrigger asChild>
{card.options.map((option) => ( <button
<li key={option.id}> type="button"
{option.option?.name}:{" "} className="group relative overflow-hidden rounded-lg border border-border/60 bg-muted/40"
{option.price && option.price !== 0 >
? `${option.price}` <Image
: option.pricePercent src={card.referenceImageUrl}
? `+${option.pricePercent}%` alt={`${card.name} reference`}
: option.priceRange && option.priceRange !== "00" width={800}
? `${option.priceRange}` height={600}
: "Included"} sizes="(max-width: 768px) 90vw, 400px"
</li> className="h-auto w-full object-cover transition-transform duration-200 group-hover:scale-[1.02]"
))} />
</ul> <span className="absolute inset-x-0 bottom-0 bg-background/70 px-2 py-1 text-xs text-foreground/80">
</div> Click to enlarge
</span>
<div> </button>
{card.extras.length > 0 ? ( </DialogTrigger>
<h4 className="font-semibold">Extras</h4> <DialogContent className="flex w-auto! max-w-[95vw]! flex-col p-4 sm:p-6">
<DialogHeader className="sr-only">
<DialogTitle>{card.name} reference</DialogTitle>
</DialogHeader>
<div className="flex max-h-[85vh] max-w-[85vw] items-center justify-center rounded-xl border-border/60 bg-muted p-2 shadow-2xl">
<Image
src={card.referenceImageUrl}
alt={`${card.name} reference`}
width={1600}
height={1200}
sizes="85vw"
className="h-auto max-h-[85vh] w-auto max-w-[85vw] rounded-lg object-contain"
/>
</div>
</DialogContent>
</Dialog>
) : null} ) : null}
<ul className="pl-4 list-disc"> </CardHeader>
{card.extras.map((extra) => (
<li key={extra.id}> <CardContent className="flex flex-1 flex-col justify-start gap-4">
{extra.extra?.name}:{" "} <div>
{extra.price && extra.price !== 0 <h4 className="font-semibold">Options</h4>
? `${extra.price}` <ul className="pl-4 list-disc">
: extra.pricePercent {card.options.map((option) => (
? `+${extra.pricePercent}%` <li key={option.id}>
: extra.priceRange && extra.priceRange !== "00" {option.option?.name}:{" "}
? `${extra.priceRange}` {option.price && option.price !== 0
: "Included"} ? `${option.price}`
</li> : option.pricePercent
))} ? `+${option.pricePercent}%`
</ul> : option.priceRange && option.priceRange !== "00"
</div> ? `${option.priceRange}`
</CardContent> : "Included"}
</Card> </li>
))}
</ul>
</div>
<div>
{card.extras.length > 0 ? (
<h4 className="font-semibold">Extras</h4>
) : null}
<ul className="pl-4 list-disc">
{card.extras.map((extra) => (
<li key={extra.id}>
{extra.extra?.name}:{" "}
{extra.price && extra.price !== 0
? `${extra.price}`
: extra.pricePercent
? `+${extra.pricePercent}%`
: extra.priceRange && extra.priceRange !== "00"
? `${extra.priceRange}`
: "Included"}
</li>
))}
</ul>
</div>
</CardContent>
</Card>
</div>
</div> </div>
); );
} }

View File

@ -5,6 +5,7 @@ import { Button } from "@/components/ui/button";
import { import {
Form, Form,
FormControl, FormControl,
FormDescription,
FormField, FormField,
FormItem, FormItem,
FormLabel, FormLabel,
@ -13,10 +14,10 @@ import {
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
import type { import type {
CommissionCustomInput,
CommissionCustomCard, CommissionCustomCard,
CommissionCustomCardExtra, CommissionCustomCardExtra,
CommissionCustomCardOption, CommissionCustomCardOption,
CommissionCustomInput,
CommissionExtra, CommissionExtra,
CommissionOption, CommissionOption,
CommissionType, CommissionType,
@ -319,8 +320,15 @@ export function CommissionOrderForm({ types, customCards }: Props) {
<FormItem> <FormItem>
<FormLabel>Your Name</FormLabel> <FormLabel>Your Name</FormLabel>
<FormControl> <FormControl>
<Input placeholder="Nickname, real name, how you want to be called..." {...field} disabled={isSubmitting} /> <Input
placeholder="Nickname, real name, how you want to be called..."
{...field}
disabled={isSubmitting}
/>
</FormControl> </FormControl>
<FormDescription>
This name will be visible on the commission status page.
</FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
)} )}
@ -339,6 +347,9 @@ export function CommissionOrderForm({ types, customCards }: Props) {
disabled={isSubmitting} disabled={isSubmitting}
/> />
</FormControl> </FormControl>
<FormDescription>
Will be used for sending the invoice via paypal
</FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
)} )}
@ -357,6 +368,9 @@ export function CommissionOrderForm({ types, customCards }: Props) {
disabled={isSubmitting} disabled={isSubmitting}
/> />
</FormControl> </FormControl>
<FormDescription>
Optional. But if filled out, we need handle and which platform. Currently supported are fediverse, bsky and telegram
</FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
)} )}