feat: Bottle Split System (Flaschenteilung)
- Add bottle_splits and split_participants tables with RLS - Implement soft-lock: pending requests count as reserved - Create /splits/create wizard (3 steps: bottle, pricing, shipping) - Create /splits/[slug] public page with price calculator - Create /splits/manage host dashboard with participant workflow - Add SplitProgressBar component for visual volume display - Status workflow: PENDING -> APPROVED -> PAID -> SHIPPED - Forum export (BBCode format) - Saved defaults in localStorage for glass/shipping costs
This commit is contained in:
101
src/components/SplitProgressBar.tsx
Normal file
101
src/components/SplitProgressBar.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
interface SplitProgressBarProps {
|
||||
totalVolume: number;
|
||||
hostShare: number;
|
||||
taken: number;
|
||||
reserved: number;
|
||||
showLabels?: boolean;
|
||||
height?: 'sm' | 'md' | 'lg';
|
||||
}
|
||||
|
||||
export default function SplitProgressBar({
|
||||
totalVolume,
|
||||
hostShare,
|
||||
taken,
|
||||
reserved,
|
||||
showLabels = true,
|
||||
height = 'md',
|
||||
}: SplitProgressBarProps) {
|
||||
const available = totalVolume - hostShare - taken - reserved;
|
||||
|
||||
const hostPercent = (hostShare / totalVolume) * 100;
|
||||
const takenPercent = (taken / totalVolume) * 100;
|
||||
const reservedPercent = (reserved / totalVolume) * 100;
|
||||
const availablePercent = (available / totalVolume) * 100;
|
||||
|
||||
const heightClass = height === 'sm' ? 'h-3' : height === 'lg' ? 'h-8' : 'h-5';
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<div className={`w-full ${heightClass} rounded-full overflow-hidden flex bg-zinc-800`}>
|
||||
{/* Host Share - Grey */}
|
||||
{hostPercent > 0 && (
|
||||
<div
|
||||
className="bg-zinc-600 flex items-center justify-center text-[8px] font-bold text-white/70"
|
||||
style={{ width: `${hostPercent}%` }}
|
||||
>
|
||||
{height !== 'sm' && hostPercent > 10 && 'Host'}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Taken - Orange/Red */}
|
||||
{takenPercent > 0 && (
|
||||
<div
|
||||
className="bg-orange-600 flex items-center justify-center text-[8px] font-bold text-white"
|
||||
style={{ width: `${takenPercent}%` }}
|
||||
>
|
||||
{height !== 'sm' && takenPercent > 8 && `${taken}cl`}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Reserved/Pending - Yellow */}
|
||||
{reservedPercent > 0 && (
|
||||
<div
|
||||
className="bg-yellow-500 flex items-center justify-center text-[8px] font-bold text-black/70"
|
||||
style={{ width: `${reservedPercent}%` }}
|
||||
>
|
||||
{height !== 'sm' && reservedPercent > 8 && `${reserved}cl`}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Available - Green */}
|
||||
{availablePercent > 0 && (
|
||||
<div
|
||||
className="bg-green-500 flex items-center justify-center text-[8px] font-bold text-white"
|
||||
style={{ width: `${availablePercent}%` }}
|
||||
>
|
||||
{height !== 'sm' && availablePercent > 8 && `${available}cl`}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{showLabels && (
|
||||
<div className="flex flex-wrap gap-3 text-[10px] font-bold">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<div className="w-2.5 h-2.5 rounded-sm bg-zinc-600" />
|
||||
<span className="text-zinc-500">Host ({hostShare}cl)</span>
|
||||
</div>
|
||||
{taken > 0 && (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<div className="w-2.5 h-2.5 rounded-sm bg-orange-600" />
|
||||
<span className="text-zinc-500">Vergeben ({taken}cl)</span>
|
||||
</div>
|
||||
)}
|
||||
{reserved > 0 && (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<div className="w-2.5 h-2.5 rounded-sm bg-yellow-500" />
|
||||
<span className="text-zinc-500">Reserviert ({reserved}cl)</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-1.5">
|
||||
<div className="w-2.5 h-2.5 rounded-sm bg-green-500" />
|
||||
<span className="text-zinc-500">Verfügbar ({available}cl)</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user