Files
app/app/admin/SetupTab.tsx
T

171 lines
10 KiB
TypeScript

// app/admin/SetupTab.tsx
"use client";
import { CalendarPlus, Trash2, UserPlus } from 'lucide-react';
import Image from 'next/image';
import React, { useState } from 'react';
import falconIcon from '../assets/falcon.svg';
import porpoiseIcon from '../assets/porpoise.svg';
import { type Period, type Youth } from './adminTypes';
interface Props {
periods: Period[]; createPeriod: (name: string, start: string) => void;
deletePeriod: (id: string) => void; bulkAddYouth: (periodId: string, text: string, team: 'PF' | 'TU') => void;
removeYouth: (periodId: string, youthId: string) => void; isOffline: boolean;
}
export const SetupTab: React.FC<Props> = ({ periods, createPeriod, deletePeriod, bulkAddYouth, removeYouth, isOffline }) => {
const [bulkText, setBulkText] = useState('');
const [bulkTeam, setBulkTeam] = useState<'PF' | 'TU'>('PF');
const [expandedPeriod, setExpandedPeriod] = useState<string | null>(null);
const handleCreate = () => {
if (isOffline) { alert("Du måste vara ansluten till internet för att skapa en ny period."); return; }
const name = (document.getElementById('periodName') as HTMLInputElement).value;
const start = (document.getElementById('periodStart') as HTMLInputElement).value;
if (name && start) createPeriod(name, start);
};
const handleDeletePeriod = (id: string) => {
if (isOffline) { alert("Åtgärd nekad: Du måste vara ansluten till internet för att ta bort en period."); return; }
if (window.confirm('Är du säker på att du vill ta bort hela perioden?')) deletePeriod(id);
};
const handleRemoveYouth = (periodId: string, youthId: string, youthName: string) => {
if (isOffline) { alert("Åtgärd nekad: Du måste vara ansluten till internet för att ta bort en ungdom."); return; }
if (window.confirm(`Är du säker på att du vill ta bort ${youthName} från perioden?`)) removeYouth(periodId, youthId);
};
const handleBulkAdd = () => {
if (isOffline) { alert("Åtgärd nekad!"); return; }
if (expandedPeriod) {
const processedText = bulkText.split('\n').map(line => {
const parts = line.split(/[,|-]/).map(p => p.trim());
if (parts.length > 1) {
const t = parts[1].toUpperCase();
if (t === 'P' || t === 'PILGRIMSFALK' || t === 'PILGRIMSFALKARNA') parts[1] = 'PF';
if (t === 'T' || t === 'TUMLARE' || t === 'TUMLARNA') parts[1] = 'TU';
return parts.join(', ');
}
return line;
}).join('\n');
bulkAddYouth(expandedPeriod, processedText, bulkTeam);
setBulkText('');
}
};
const renderYouthGroup = (youthList: Youth[], periodId: string) => {
if (youthList.length === 0) return null;
return (
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 mb-6">
{youthList.map(youth => (
<div key={youth.id} className="flex justify-between items-center bg-white border border-slate-teal/10 p-3 rounded-xl shadow-sm hover:shadow-md transition-shadow">
<div className="flex items-center gap-3">
<div className={`flex items-center justify-center w-8 h-8 rounded-xl ${youth.team === 'PF' ? 'bg-gold' : 'bg-seafoam'} shrink-0 shadow-inner`}>
<Image src={youth.team === 'PF' ? falconIcon : porpoiseIcon} alt={youth.team === 'PF' ? 'PF' : 'TU'} width={16} height={16} />
</div>
<span className="font-bold text-ebony text-base">{youth.name}</span>
</div>
<button onClick={() => handleRemoveYouth(periodId, youth.id, youth.name)} className={`p-2 transition-colors rounded-lg ${isOffline ? 'text-goldenrod/40 cursor-not-allowed' : 'text-goldenrod hover:bg-emergency/10 hover:text-emergency'}`}>
<Trash2 size={18} />
</button>
</div>
))}
</div>
);
};
return (
<div className="space-y-6 animate-fade-in">
<div className="rounded-3xl shadow-sm transition-all duration-300 bg-white/40 backdrop-blur-md border border-white/40 p-3 sm:p-5 hover:shadow-md">
<h2 className="text-sm font-black text-ebony uppercase tracking-widest flex items-center mb-4">
<CalendarPlus className="mr-2 text-slate-teal" size={20} /> Skapa Ny Period
</h2>
{/* Changed from Grid to Flex */}
<div className="flex flex-col md:flex-row gap-4 w-full">
{/* Wrapping inputs in flex-1 min-w-0 forces Safari to respect the bounds */}
<div className="flex-1 min-w-0">
<input
type="text"
id="periodName"
placeholder="T.ex. Period 1"
className="w-full appearance-none bg-white border border-slate-teal/10 p-3 rounded-xl text-sm font-bold focus:outline-none focus:border-slate-teal shadow-sm"
disabled={isOffline}
/>
</div>
<div className="flex-1 min-w-0">
<input
type="date"
id="periodStart"
className="w-full appearance-none bg-white border border-slate-teal/10 p-3 rounded-xl text-sm font-bold focus:outline-none focus:border-slate-teal shadow-sm"
disabled={isOffline}
/>
</div>
<button
onClick={handleCreate}
disabled={isOffline}
className="w-full md:w-auto md:px-8 shrink-0 bg-slate-teal text-eggshell font-black uppercase tracking-widest text-xs py-3 rounded-xl hover:bg-ebony transition-colors disabled:opacity-50 shadow-sm"
>
Starta
</button>
</div>
</div>
{periods.map(period => {
const pfYouth = period.youthList.filter(y => y.team === 'PF').sort((a, b) => a.name.localeCompare(b.name));
const tuYouth = period.youthList.filter(y => y.team === 'TU').sort((a, b) => a.name.localeCompare(b.name));
return (
<div key={period.id} className="rounded-3xl shadow-sm transition-all duration-300 bg-white/40 backdrop-blur-md border border-white/40 hover:shadow-md overflow-hidden">
<div className="p-5 flex justify-between items-center cursor-pointer hover:bg-moss/10 transition-colors" onClick={() => setExpandedPeriod(expandedPeriod === period.id ? null : period.id)}>
<div>
<h3 className="text-xl font-black text-ebony uppercase tracking-wide">{period.name}</h3>
<p className="text-xs font-bold text-moss mt-1">{period.startDate} till {period.endDate} {period.youthList.length} ungdomar</p>
</div>
<button onClick={(e) => { e.stopPropagation(); handleDeletePeriod(period.id); }} className={`p-2.5 rounded-xl transition-colors ${isOffline ? 'text-goldenrod/40 cursor-not-allowed' : 'text-goldenrod bg-white shadow-sm hover:bg-emergency hover:text-white'}`}>
<Trash2 size={20} />
</button>
</div>
{expandedPeriod === period.id && (
<div className="p-5 border-t border-slate-teal/10 bg-moss/10">
<h4 className="font-black text-slate-teal mb-4 flex items-center uppercase tracking-widest text-xs">
<UserPlus size={16} className="mr-2" /> Bulk-lägg till ungdomar
</h4>
<div className="flex flex-col md:flex-row gap-4 mb-8">
<textarea
value={bulkText}
onChange={(e) => setBulkText(e.target.value)}
placeholder="Klistra in namn, ett per rad.&#10;T.ex. 'Anna' eller 'Anna, P'"
className="w-full h-32 md:h-40 bg-white border border-slate-teal/10 p-4 rounded-2xl text-sm font-bold resize-none focus:outline-none focus:border-slate-teal shadow-sm"
disabled={isOffline}
/>
<div className="flex flex-col gap-3 shrink-0">
<select value={bulkTeam} onChange={(e) => setBulkTeam(e.target.value as 'PF' | 'TU')} className="bg-white border border-slate-teal/10 p-3 rounded-xl text-sm font-bold focus:outline-none shadow-sm" disabled={isOffline}>
<option value="PF">Standard: Pilgrimsfalk (P)</option>
<option value="TU">Standard: Tumlare (T)</option>
</select>
<button onClick={handleBulkAdd} disabled={isOffline} className="bg-seafoam text-eggshell font-black uppercase tracking-widest text-xs px-6 py-3 rounded-xl hover:bg-slate-teal transition-colors h-full disabled:opacity-50 shadow-sm">
Importera
</button>
</div>
</div>
{pfYouth.length > 0 && <h4 className="text-xs font-black text-moss uppercase tracking-widest mb-3 flex items-center"><span className="w-2.5 h-2.5 rounded-full bg-gold mr-2 shadow-sm"></span> Pilgrimsfalkarna</h4>}
{renderYouthGroup(pfYouth, period.id)}
{tuYouth.length > 0 && <h4 className="text-xs font-black text-moss uppercase tracking-widest mb-3 flex items-center"><span className="w-2.5 h-2.5 rounded-full bg-seafoam mr-2 shadow-sm"></span> Tumlarna</h4>}
{renderYouthGroup(tuYouth, period.id)}
</div>
)}
</div>
);
})}
</div>
);
};