Better UI

This commit is contained in:
2026-03-06 15:33:05 +01:00 Unverified
parent e98a537882
commit 683368a354
14 changed files with 1060 additions and 309 deletions
+115 -1
View File
@@ -3,12 +3,50 @@
'use client';
import { useActionState, useEffect, useState } from 'react';
import { FaPlus, FaTrash, FaArrowUp, FaArrowDown } from 'react-icons/fa'; // Importera pilarna
import { saveConfigAction } from './actions';
export default function AdminForm({ initialConfig }: { initialConfig: any }) {
const [state, formAction, isPending] = useActionState(saveConfigAction, null);
const [showToast, setShowToast] = useState(false);
const [classes, setClasses] = useState<Array<{ name: string, color: string, desc: string }>>(
Array.isArray(initialConfig.beachPage.classes)
? initialConfig.beachPage.classes
: [
{ name: 'Grön', color: '#16a34a', desc: 'Nybörjare' },
{ name: 'Blå', color: '#2563eb', desc: 'Spelat lite' },
{ name: 'Svart', color: '#111827', desc: 'Spelat mycket' }
]
);
const addClass = () => setClasses([...classes, { name: '', color: '#406185', desc: '' }]);
const removeClass = (index: number) => {
setClasses(classes.filter((_, i) => i !== index));
};
const updateClass = (index: number, field: keyof typeof classes[0], value: string) => {
const newClasses = [...classes];
newClasses[index][field] = value;
setClasses(newClasses);
};
// Funktioner för att byta plats på klasserna
const moveUp = (index: number) => {
if (index === 0) return;
const newClasses = [...classes];
[newClasses[index - 1], newClasses[index]] = [newClasses[index], newClasses[index - 1]];
setClasses(newClasses);
};
const moveDown = (index: number) => {
if (index === classes.length - 1) return;
const newClasses = [...classes];
[newClasses[index + 1], newClasses[index]] = [newClasses[index], newClasses[index + 1]];
setClasses(newClasses);
};
useEffect(() => {
if (state?.success) {
setShowToast(true);
@@ -70,7 +108,83 @@ export default function AdminForm({ initialConfig }: { initialConfig: any }) {
</label>
</section>
<button type="submit" disabled={isPending} className="bg-[#406185] text-white py-4 rounded-lg font-bold text-lg hover:bg-black transition-all active:scale-95 disabled:bg-gray-400">
{/* SPELKLASSER - Moderniserad för att matcha */}
<section className="flex flex-col gap-4">
<div className="flex justify-between items-center mb-2">
<h2 className="text-xl font-bold border-l-4 border-[#fdb84b] pl-2 text-[#406185]">Spelklasser</h2>
<button
type="button"
onClick={addClass}
className="flex items-center gap-2 text-sm font-bold text-white bg-[#406185] px-4 py-2 rounded hover:brightness-110 transition-all active:scale-95"
>
<FaPlus size={12} /> Lägg till
</button>
</div>
<div className="space-y-3">
{classes.map((c, index) => (
<div key={index} className="flex flex-col md:flex-row gap-3 items-center w-full">
{/* Sorteringspilar */}
<div className="flex md:flex-col gap-1 text-gray-400">
<button type="button" onClick={() => moveUp(index)} disabled={index === 0} className="hover:text-[#406185] disabled:opacity-30 disabled:hover:text-gray-400 p-1">
<FaArrowUp size={14} />
</button>
<button type="button" onClick={() => moveDown(index)} disabled={index === classes.length - 1} className="hover:text-[#406185] disabled:opacity-30 disabled:hover:text-gray-400 p-1">
<FaArrowDown size={14} />
</button>
</div>
<div className="flex-1 flex gap-2 w-full">
{/* Färgplockare som ser ut som ett vanligt inputfält */}
<div className="w-12 h-10 border rounded overflow-hidden shrink-0 focus-within:ring-2 focus-within:ring-[#406185]">
<input
type="color"
value={c.color}
onChange={(e) => updateClass(index, 'color', e.target.value)}
className="w-16 h-16 -m-2 cursor-pointer outline-none"
title="Välj färg"
/>
</div>
<input
type="text"
value={c.name}
onChange={(e) => updateClass(index, 'name', e.target.value)}
placeholder="Lagnamn (t.ex. Grön)"
required
className="w-1/3 border p-2 rounded focus:ring-2 focus:ring-[#406185] outline-none min-w-25"
/>
<input
type="text"
value={c.desc}
onChange={(e) => updateClass(index, 'desc', e.target.value)}
placeholder="Beskrivning (t.ex. Nybörjare)"
className="flex-1 border p-2 rounded focus:ring-2 focus:ring-[#406185] outline-none min-w-30"
/>
</div>
<button
type="button"
onClick={() => removeClass(index)}
className="text-gray-400 hover:text-red-500 p-2 rounded transition-colors self-end md:self-auto shrink-0"
title="Ta bort klass"
>
<FaTrash />
</button>
</div>
))}
{classes.length === 0 && (
<p className="text-gray-500 italic text-sm">Inga klasser inlagda. Besökarna kommer inte kunna välja nivå.</p>
)}
</div>
{/* Dold JSON-sträng för Server Action */}
<input type="hidden" name="classesJSON" value={JSON.stringify(classes)} />
</section>
<button type="submit" disabled={isPending} className="bg-[#406185] text-white py-4 mt-4 rounded-lg font-bold text-lg hover:bg-black transition-all active:scale-95 disabled:bg-gray-400 shadow-lg">
{isPending ? 'Sparar...' : 'Spara inställningar'}
</button>
</form>
+9
View File
@@ -8,6 +8,14 @@ import { revalidatePath } from 'next/cache';
export async function saveConfigAction(prevState: any, formData: FormData) {
const config = await getConfig();
let parsedClasses = [];
try {
const classesJSON = formData.get('classesJSON') as string;
if (classesJSON) parsedClasses = JSON.parse(classesJSON);
} catch (e) {
console.error("Kunde inte parsa klasser", e);
}
const newConfig = {
...config,
showBeachPromo: formData.get('showBeachPromo') === 'on',
@@ -19,6 +27,7 @@ export async function saveConfigAction(prevState: any, formData: FormData) {
otherInfo: formData.get('otherInfo') as string,
prizesText: formData.get('prizesText') as string,
isClosedOverride: formData.get('isClosedOverride') === 'on',
classes: parsedClasses,
}
};