Added emergency, jobinfo and beginner admin page

This commit is contained in:
2026-03-13 00:37:01 +01:00 Verified
parent d317eccc9e
commit 66bc2152dc
8 changed files with 258 additions and 49 deletions
+18 -15
View File
@@ -1,38 +1,38 @@
// src/App.tsx
import { Calendar, FileText, Home as HomeIcon, Leaf, Map, ShieldAlert } from 'lucide-react';
import { Link, Route, BrowserRouter as Router, Routes, useLocation } from 'react-router-dom';
import { BrowserRouter as Router, Routes, Route, Link, useLocation } from 'react-router-dom';
import { Calendar, FileText, Home as HomeIcon, Map, Leaf, Briefcase, LifeBuoy, Lock } from 'lucide-react';
import { Documents } from './pages/Documents';
import { FAQ } from './pages/FAQ';
import { Home } from './pages/Home';
import { JobInfo } from './pages/JobInfo';
import { FAQ } from './pages/FAQ';
import { Documents } from './pages/Documents';
import { Schedule } from './pages/Schedule';
import { Emergency } from './pages/Emergency';
import { Admin } from './pages/admin/AdminDashboard';
const Admin = () => <div className="p-6"><h2>Admin Dashboard (Kräver pinkod)</h2></div>;
const NavItem = ({ to, icon: Icon, label }: { to: string, icon: any, label: string }) => {
const NavItem = ({ to, icon: Icon, label, className = "" }: { to: string, icon: any, label: string, className?: string }) => {
const location = useLocation();
const isActive = location.pathname === to;
return (
<Link
to={to}
className={`flex items-center px-4 py-3 whitespace-nowrap text-sm font-bold transition-all border-b-[3px] ${isActive
className={`flex flex-col items-center justify-center px-4 py-2 min-w-18 transition-colors border-b-[3px] ${className} ${isActive
? 'border-gold text-gold bg-ebony/30'
: 'border-transparent text-eggshell/80 hover:text-eggshell hover:bg-eggshell/5'
}`}
>
<Icon size={18} className="mr-2" strokeWidth={isActive ? 2.5 : 2} />
{label}
<Icon size={20} className="mb-1" strokeWidth={isActive ? 2.5 : 2} />
<span className="text-[10px] font-bold uppercase tracking-wider">{label}</span>
</Link>
);
};
function AppContent() {
return (
<div className="min-h-screen bg-eggshell font-sans text-ebony selection:bg-gold selection:text-ebony">
<div className="min-h-screen bg-eggshell font-sans text-ebony selection:bg-gold selection:text-ebony pb-10">
{/* Creative, vibrant header using only your colors */}
{/* Header & Navigation */}
<header className="sticky top-0 z-50 bg-ebony shadow-md">
<div className="max-w-5xl mx-auto">
{/* App Title Bar */}
@@ -46,10 +46,12 @@ function AppContent() {
{/* Scrollable Tab Navigation */}
<nav className="flex overflow-x-auto scrollbar-hide border-t border-eggshell/10">
<NavItem to="/" icon={HomeIcon} label="Hem" />
<NavItem to="/faq" icon={Map} label="FAQ" />
<NavItem to="/schedule" icon={Calendar} label="Schema" />
<NavItem to="/documents" icon={FileText} label="Info & Dok" />
<NavItem to="/admin" icon={ShieldAlert} label="Admin" />
<NavItem to="/faq" icon={Map} label="FAQ" />
<NavItem to="/info" icon={Briefcase} label="Info" />
<NavItem to="/documents" icon={FileText} label="Filer" />
<NavItem to="/emergency" icon={LifeBuoy} label="Nödläge" className='text-emergency' />
<NavItem to="/admin" icon={Lock} label="Admin" className="md:ml-auto" />
</nav>
</div>
</header>
@@ -62,6 +64,7 @@ function AppContent() {
<Route path="/faq" element={<FAQ />} />
<Route path="/documents" element={<Documents />} />
<Route path="/schedule" element={<Schedule />} />
<Route path="/emergency" element={<Emergency />} />
<Route path="/admin" element={<Admin />} />
</Routes>
</main>
+1
View File
@@ -11,6 +11,7 @@
--color-slate-teal: #456466;
--color-seafoam: #5B8C8A;
--color-emergency: #EB514C;
}
body {
+1 -1
View File
@@ -33,7 +33,7 @@ export const Documents: React.FC = () => {
className="group flex items-center justify-between bg-white/60 backdrop-blur-sm p-5 rounded-2xl border border-white hover:-translate-y-1 hover:shadow-xl hover:shadow-moss/10 transition-all duration-300"
>
<div className="flex items-center text-slate-teal">
<div className="bg-gradient-to-br from-seafoam to-slate-teal p-3 rounded-xl mr-4 text-eggshell shadow-inner">{doc.icon}</div>
<div className="bg-linear-to-br from-seafoam to-slate-teal p-3 rounded-xl mr-4 text-eggshell shadow-inner">{doc.icon}</div>
<span className="font-bold text-sm">{doc.title}</span>
</div>
<Download size={20} className="text-moss group-hover:text-slate-teal transition-colors" />
+87
View File
@@ -0,0 +1,87 @@
// src/pages/Emergency.tsx
import React from 'react';
import { Phone, AlertTriangle, MapPin, HeartPulse } from 'lucide-react';
export const Emergency: React.FC = () => {
return (
<div className="space-y-6 animate-fade-in w-full mx-auto">
<div>
<h1 className="text-3xl font-black text-emergency tracking-tight uppercase flex items-center">
<AlertTriangle className="mr-3 text-emergency" size={32} />
Vid Nödsituation
</h1>
<p className="text-ebony font-medium mt-2 ml-11">Agera lugnt, stanna kvar platsen och tillkalla hjälp.</p>
</div>
{/* 112 Card */}
<div className="bg-emergency/20 border-l-4 border-emergency p-6 rounded-r-xl shadow-sm">
<h2 className="text-2xl font-black text-ebony flex items-center mb-2">
<Phone className="mr-3 text-emergency" size={24} />
Ring 112
</h2>
<p className="text-ebony/80 font-medium mb-4">
Vid olycka, brand eller livshotande tillstånd. Berätta vem du är och vad som har hänt.
</p>
<div className="bg-eggshell/50 p-4 rounded-lg border border-emergency/30">
<h3 className="font-bold text-ebony flex items-center mb-1 text-sm uppercase tracking-wider">
<MapPin className="mr-2 text-emergency" size={16} />
Uppge din position
</h3>
<p className="text-ebony font-medium text-sm">
Använd appen <strong>112</strong> eller GPS i telefonen. Säg att du befinner dig i Kullabergs Naturreservat. Var specifik (t.ex. "Nära fyren" eller "Vid Josefinelust").
</p>
</div>
</div>
{/* First Aid / HLR Card */}
<div className="bg-eggshell border-2 border-slate-teal/20 p-6 rounded-xl shadow-sm">
<h2 className="text-xl font-black text-slate-teal flex items-center mb-4 uppercase tracking-wide">
<HeartPulse className="mr-3 text-seafoam" size={24} />
Första Hjälpen & Hjärtstartare
</h2>
<ul className="space-y-3 text-ebony font-medium">
<li className="flex items-start">
<span className="bg-seafoam text-eggshell font-bold px-2 py-0.5 rounded mr-3 text-sm">1</span>
Säkra platsen se till att varken du eller personen utsätts för mer fara.
</li>
<li className="flex items-start">
<span className="bg-seafoam text-eggshell font-bold px-2 py-0.5 rounded mr-3 text-sm shrink-0">2</span>
{/* Mobile View: Standard wrapping text (hides on medium screens and up) */}
<p className="text-ebony font-medium">
Finns hjärtstartare? Ja, närmaste hjärtstartare finns inne <strong className="text-ebony font-black">Naturum Kullaberg</strong> (vid fyren) under deras öppettider.
</p>
</li>
</ul>
</div>
{/* Internal Contact */}
<div className="bg-eggshell border-2 border-slate-teal/20 p-6 rounded-xl shadow-sm">
<h2 className="text-xl font-black text-slate-teal mb-2 uppercase tracking-wide">
Intern Rapportering
</h2>
<p className="text-ebony/80 font-medium mb-4 text-sm">
När situationen är under kontroll, meddela alltid arbetsledaren om vad som inträffat.
</p>
<div>
<div className="flex justify-between items-center pb-4 border-b border-moss/20">
<span className="text-base font-bold text-ebony">William Söderberg</span>
<div className='flex gap-2 flex-wrap justify-end'>
<a href="tel:0722470291" className="text-sm text-slate-teal font-mono font-bold bg-seafoam/20 hover:bg-seafoam/40 px-3 py-1.5 rounded-lg transition-colors">072-247 02 91</a>
<a href="tel:078389355810604" className="text-sm text-slate-teal font-mono font-bold bg-seafoam/20 hover:bg-seafoam/40 px-3 py-1.5 rounded-lg transition-colors">078-389 35 58 10 604</a>
</div>
</div>
<div className="flex justify-between items-center pt-4">
<span className="text-base font-bold text-ebony">Oliver Nilsson</span>
<div className='flex gap-2 flex-wrap justify-end'>
<a href="tel:0727177440" className="text-sm text-slate-teal font-mono font-bold bg-seafoam/20 hover:bg-seafoam/40 px-3 py-1.5 rounded-lg transition-colors">072-717 74 40</a>
<a href="tel:078389355810605" className="text-sm text-slate-teal font-mono font-bold bg-seafoam/20 hover:bg-seafoam/40 px-3 py-1.5 rounded-lg transition-colors">078-389 35 58 10 605</a>
</div>
</div>
</div>
</div>
</div>
);
};
+3 -3
View File
@@ -16,9 +16,9 @@ export const FAQ: React.FC = () => {
<div className="mb-8">
<h1 className="text-3xl font-black text-slate-teal tracking-tight flex items-center">
<MessageCircleQuestionMark className="mr-3 text-seafoam" size={32} />
Veckoschema
Vanliga Frågor (FAQ)
</h1>
<p className="text-moss font-medium mt-2 ml-11">Här hittar du när vi bemannar Kullaberg.</p>
<p className="text-moss font-medium mt-2 ml-11">Använd den här guiden för att snabbt svara turisternas vanligaste frågor.</p>
</div>
<div className="columns-1 lg:columns-2 gap-6 space-y-6">
@@ -42,7 +42,7 @@ export const FAQ: React.FC = () => {
{isOpen ? <ChevronUp size={16} /> : <ChevronDown size={16} />}
</div>
</button>
<div className={`transition-all duration-300 ease-in-out ${isOpen ? 'max-h-[500px] opacity-100' : 'max-h-0 opacity-0 overflow-hidden'}`}>
<div className={`transition-all duration-300 ease-in-out ${isOpen ? 'max-h-125 opacity-100' : 'max-h-0 opacity-0 overflow-hidden'}`}>
<div className="p-4 pt-0 text-ebony font-medium text-sm leading-relaxed border-t border-ebony/5 mx-4 mt-2">
{item.a}
</div>
+48 -29
View File
@@ -1,43 +1,62 @@
// src/pages/Info.tsx
// src/pages/JobInfo.tsx
import React from 'react';
import { Briefcase, CheckCircle2, Navigation } from 'lucide-react';
export const JobInfo: React.FC = () => {
return (
<div className="p-4 max-w-md mx-auto space-y-6">
<h1 className="text-2xl font-bold text-green-800">Jobbinfo & Regler</h1>
<div className="space-y-8 animate-fade-in w-full mx-auto">
<div>
<h1 className="text-3xl font-black text-slate-teal tracking-tight flex items-center">
<Briefcase className="mr-3 text-seafoam" size={32} />
Jobbinfo & Regler
</h1>
<p className="text-moss font-medium mt-2 ml-11">Läs igenom detta noggrant inför dina arbetspass.</p>
</div>
<section className="bg-white p-4 rounded-xl shadow-sm border border-gray-100">
<h2 className="text-lg font-bold text-gray-800 mb-2">Förväntningar</h2>
<p className="text-sm text-gray-600 mb-2">
<section className="bg-eggshell border-2 border-slate-teal/20 p-6 rounded-2xl shadow-sm">
<h2 className="text-lg font-black text-ebony uppercase tracking-widest mb-3 flex items-center">
<CheckCircle2 className="mr-2 text-moss" size={20} /> Förväntningar
</h2>
<p className="text-sm text-ebony/80 font-medium mb-4 leading-relaxed">
Vi förväntar oss att du tar ansvar, visar respekt för både natur och varandra, samt gör ditt bästa med dina arbetsuppgifter.
</p>
<ul className="list-disc pl-5 text-sm text-gray-600 space-y-1">
<li><strong>Period 1:</strong> Start 23 juni kl 08:10 (Buss station Mölle)</li>
<li><strong>Period 2:</strong> Start 7 juli kl 08:10</li>
<div className="bg-moss/10 rounded-xl p-4 space-y-2 border border-moss/20">
<div className="flex justify-between items-center">
<span className="font-bold text-ebony text-sm">Period 1</span>
<span className="text-xs font-bold bg-eggshell text-moss px-2 py-1 rounded">23 juni kl 08:10 (Buss Mölle)</span>
</div>
<div className="flex justify-between items-center border-t border-moss/20 pt-2">
<span className="font-bold text-ebony text-sm">Period 2</span>
<span className="text-xs font-bold bg-eggshell text-moss px-2 py-1 rounded">7 juli kl 08:10</span>
</div>
</div>
</section>
<section className="bg-eggshell border-2 border-slate-teal/20 p-6 rounded-2xl shadow-sm">
<h2 className="text-lg font-black text-ebony uppercase tracking-widest mb-3 flex items-center">
<Navigation className="mr-2 text-moss" size={20} /> Daglig Utrustning
</h2>
<ul className="grid grid-cols-1 md:grid-cols-2 gap-3">
{['Bra promenadskor (mycket gång!)', 'Oömma/väderanpassade kläder', 'En bekväm ryggsäck', 'Egen lunch (ingen kyl/mikro)', 'Minst 1 liter vatten', 'Myggmedel & Solkräm'].map((item, idx) => (
<li key={idx} className="flex items-center text-sm font-bold text-ebony/80 bg-seafoam/10 p-3 rounded-lg border border-seafoam/20">
<div className="w-2 h-2 rounded-full bg-slate-teal mr-3 shrink-0"></div>
{item}
</li>
))}
</ul>
</section>
<section className="bg-white p-4 rounded-xl shadow-sm border border-gray-100">
<h2 className="text-lg font-bold text-gray-800 mb-2">Daglig Utrustning</h2>
<ul className="list-disc pl-5 text-sm text-gray-600 space-y-2">
<li>Bra promenadskor (du kommer mycket!)</li>
<li>Oömma och väderanpassade kläder</li>
<li>En bekväm ryggsäck</li>
<li>Egen lunch (ingen tillgång till kyl/mikro)</li>
<li>Minst 1 liter vatten</li>
<li>Myggmedel & Solkräm</li>
</ul>
</section>
<section className="bg-white p-4 rounded-xl shadow-sm border border-gray-100">
<h2 className="text-lg font-bold text-gray-800 mb-2">Exempel uppgifter</h2>
<ul className="list-disc pl-5 text-sm text-gray-600 space-y-1">
<li>Parkeringsguide</li>
<li>Naturvägledare för besökare</li>
<li>Plocka skräp & ta bort invasiva växter</li>
<li>Städa anläggningar</li>
<li>Allmänt underhåll (olja skyltar, fixa staket)</li>
<section className="bg-eggshell border-2 border-slate-teal/20 p-6 rounded-2xl shadow-sm">
<h2 className="text-lg font-black text-ebony uppercase tracking-widest mb-3 flex items-center">
<Briefcase className="mr-2 text-moss" size={20} /> Exempel uppgifter
</h2>
<ul className="space-y-2 text-sm font-bold text-ebony/80">
{['Parkeringsguide', 'Naturvägledare för besökare', 'Plocka skräp & ta bort invasiva växter', 'Städa anläggningar', 'Allmänt underhåll (olja skyltar, fixa staket)'].map((task, idx) => (
<li key={idx} className="flex items-center">
<span className="text-seafoam mr-2"></span> {task}
</li>
))}
</ul>
</section>
</div>
+99
View File
@@ -0,0 +1,99 @@
// src/pages/admin/AdminDashboard.tsx
import React, { useState } from 'react';
import { Lock, Unlock, Upload, Users } from 'lucide-react';
export const Admin: React.FC = () => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [pin, setPin] = useState('');
const [error, setError] = useState('');
const CORRECT_PIN = "1234"; // You can change this later
const handleLogin = (e: React.FormEvent) => {
e.preventDefault();
if (pin === CORRECT_PIN) {
setIsAuthenticated(true);
setError('');
} else {
setError('Ogiltig pinkod.');
setPin('');
}
};
// --- VIEW: LOCKED ---
if (!isAuthenticated) {
return (
<div className="flex flex-col items-center justify-center py-20 animate-fade-in px-4">
<div className="bg-eggshell border-2 border-slate-teal/20 p-8 rounded-2xl shadow-lg w-full max-w-sm text-center">
<div className="bg-slate-teal/10 w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4">
<Lock size={32} className="text-slate-teal" />
</div>
<h2 className="text-2xl font-black text-ebony tracking-wide uppercase mb-2">Admin Login</h2>
<p className="text-sm font-medium text-ebony/70 mb-6">Ange pinkod för att hantera schema och närvaro.</p>
<form onSubmit={handleLogin} className="space-y-4">
<input
type="password"
inputMode="numeric"
value={pin}
onChange={(e) => setPin(e.target.value)}
placeholder="••••"
className="w-full bg-eggshell/50 border-2 border-slate-teal/30 text-center text-2xl tracking-[0.5em] text-ebony font-mono p-3 rounded-xl focus:outline-none focus:border-slate-teal focus:ring-1 focus:ring-slate-teal transition-all"
autoFocus
/>
{error && <p className="text-goldenrod font-bold text-sm">{error}</p>}
<button
type="submit"
className="w-full bg-slate-teal text-eggshell font-black uppercase tracking-widest py-3 rounded-xl hover:bg-ebony transition-colors shadow-md shadow-slate-teal/20"
>
Lås upp
</button>
</form>
</div>
</div>
);
}
// --- VIEW: UNLOCKED (ADMIN DASHBOARD) ---
return (
<div className="space-y-8 animate-fade-in w-full">
<div className="flex justify-between items-end border-b-2 border-slate-teal/20 pb-4">
<div>
<h1 className="text-3xl font-black text-slate-teal tracking-tight uppercase flex items-center">
<Unlock className="mr-3 text-seafoam" size={28} />
Admin Dashboard
</h1>
<p className="text-moss font-bold mt-2 ml-10">Hantera personal, scheman och närvaro.</p>
</div>
<button
onClick={() => setIsAuthenticated(false)}
className="text-sm font-bold text-ebony/60 hover:text-goldenrod transition-colors"
>
Logga ut
</button>
</div>
{/* Attendance Tracker Section Shell */}
<section className="bg-eggshell border-2 border-slate-teal/20 rounded-2xl p-6 shadow-sm">
<div className="flex justify-between items-center mb-6">
<h2 className="text-xl font-black text-ebony uppercase tracking-widest flex items-center">
<Users className="mr-3 text-slate-teal" size={24} />
Närvarorapport
</h2>
{/* Fake Upload Button for now */}
<button className="flex items-center bg-seafoam/20 hover:bg-seafoam/40 text-slate-teal font-bold px-4 py-2 rounded-lg transition-colors border border-seafoam/30">
<Upload size={18} className="mr-2" />
Ladda upp CSV
</button>
</div>
<div className="bg-slate-teal/5 border-2 border-dashed border-slate-teal/30 rounded-xl p-10 text-center flex flex-col items-center justify-center">
<p className="text-ebony/60 font-medium mb-2">Ingen data uppladdad ännu.</p>
<p className="text-sm text-ebony/40 font-medium">Ladda upp Timeedit CSV-filen för att visa interaktiv närvarolista här.</p>
</div>
</section>
</div>
);
};