This commit is contained in:
parent
c6f49e3c3f
commit
412b5fcea8
1200
package-lock.json
generated
1200
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -39,6 +39,7 @@
|
|||||||
"@radix-ui/react-toggle": "^1.1.0",
|
"@radix-ui/react-toggle": "^1.1.0",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.0",
|
"@radix-ui/react-toggle-group": "^1.1.0",
|
||||||
"@radix-ui/react-tooltip": "^1.1.4",
|
"@radix-ui/react-tooltip": "^1.1.4",
|
||||||
|
"@react-pdf/renderer": "^4.3.0",
|
||||||
"@tanstack/react-query": "^5.56.2",
|
"@tanstack/react-query": "^5.56.2",
|
||||||
"axios": "^1.9.0",
|
"axios": "^1.9.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
@ -52,6 +53,7 @@
|
|||||||
"keen-slider": "^6.8.6",
|
"keen-slider": "^6.8.6",
|
||||||
"lucide-react": "^0.462.0",
|
"lucide-react": "^0.462.0",
|
||||||
"next-themes": "^0.3.0",
|
"next-themes": "^0.3.0",
|
||||||
|
"pdfjs-dist": "^5.2.133",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^8.10.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
@ -59,6 +61,7 @@
|
|||||||
"react-hook-form": "^7.53.0",
|
"react-hook-form": "^7.53.0",
|
||||||
"react-loading-skeleton": "^3.5.0",
|
"react-loading-skeleton": "^3.5.0",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
|
"react-pdf": "^9.2.1",
|
||||||
"react-quill": "^2.0.0",
|
"react-quill": "^2.0.0",
|
||||||
"react-resizable-panels": "^2.1.3",
|
"react-resizable-panels": "^2.1.3",
|
||||||
"react-responsive-carousel": "^3.2.23",
|
"react-responsive-carousel": "^3.2.23",
|
||||||
|
|||||||
0
public/pdfjs-dist/pdf.worker.min.js
vendored
Normal file
0
public/pdfjs-dist/pdf.worker.min.js
vendored
Normal file
BIN
public/uploads/satzung.pdf
Normal file
BIN
public/uploads/satzung.pdf
Normal file
Binary file not shown.
@ -1,11 +1,51 @@
|
|||||||
|
import { useState } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
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 { MapPin, Phone, Mail, Clock } from "lucide-react";
|
import { MapPin, Phone, Mail } from "lucide-react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
const apiBase = import.meta.env.VITE_API_URL;
|
||||||
|
|
||||||
const ContactSection = () => {
|
const ContactSection = () => {
|
||||||
|
const [form, setForm] = useState({
|
||||||
|
firstName: "",
|
||||||
|
lastName: "",
|
||||||
|
email: "",
|
||||||
|
subject: "",
|
||||||
|
message: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const [submitting, setSubmitting] = useState(false);
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
setForm({ ...form, [e.target.id]: e.target.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
setSubmitting(true);
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${apiBase}/api/contact`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(form),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) throw new Error("Fehler beim Senden der Nachricht");
|
||||||
|
|
||||||
|
toast.success("Nachricht erfolgreich gesendet!");
|
||||||
|
setForm({ firstName: "", lastName: "", email: "", subject: "", message: "" });
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
toast.error("Fehler beim Senden der Nachricht");
|
||||||
|
} finally {
|
||||||
|
setSubmitting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section id="contact" className="py-16 bg-gray-50">
|
<section id="contact" className="py-16 bg-gray-50">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
@ -18,35 +58,38 @@ const ContactSection = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent className="p-6">
|
<CardContent className="p-6">
|
||||||
<form className="space-y-4">
|
<form className="space-y-4" onSubmit={handleSubmit}>
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label htmlFor="firstName" className="text-sm font-medium">Vorname</label>
|
<label htmlFor="firstName" className="text-sm font-medium">Vorname</label>
|
||||||
<Input id="firstName" placeholder="Dein Vorname" />
|
<Input id="firstName" value={form.firstName} onChange={handleChange} />
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label htmlFor="lastName" className="text-sm font-medium">Nachname</label>
|
<label htmlFor="lastName" className="text-sm font-medium">Nachname</label>
|
||||||
<Input id="lastName" placeholder="Dein Nachname" />
|
<Input id="lastName" value={form.lastName} onChange={handleChange} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label htmlFor="email" className="text-sm font-medium">E-Mail</label>
|
<label htmlFor="email" className="text-sm font-medium">E-Mail</label>
|
||||||
<Input id="email" type="email" placeholder="deine@email.de" />
|
<Input id="email" type="email" value={form.email} onChange={handleChange} />
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label htmlFor="subject" className="text-sm font-medium">Betreff</label>
|
<label htmlFor="subject" className="text-sm font-medium">Betreff</label>
|
||||||
<Input id="subject" placeholder="Worum geht es?" />
|
<Input id="subject" value={form.subject} onChange={handleChange} />
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label htmlFor="message" className="text-sm font-medium">Nachricht</label>
|
<label htmlFor="message" className="text-sm font-medium">Nachricht</label>
|
||||||
<Textarea id="message" placeholder="Deine Nachricht an uns" rows={4} />
|
<Textarea id="message" value={form.message} onChange={handleChange} rows={4} />
|
||||||
</div>
|
</div>
|
||||||
<Button className="w-full bg-frog-500 hover:bg-frog-600">Nachricht senden</Button>
|
<Button type="submit" className="w-full bg-frog-500 hover:bg-frog-600" disabled={submitting}>
|
||||||
|
{submitting ? "Wird gesendet..." : "Nachricht senden"}
|
||||||
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Kontaktinfos & Karte */}
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="bg-white rounded-lg shadow p-6">
|
<div className="bg-white rounded-lg shadow p-6">
|
||||||
<h3 className="text-xl font-bold mb-4">Kontaktinformationen</h3>
|
<h3 className="text-xl font-bold mb-4">Kontaktinformationen</h3>
|
||||||
@ -77,7 +120,7 @@ const ContactSection = () => {
|
|||||||
|
|
||||||
<div className="bg-white rounded-lg shadow overflow-hidden">
|
<div className="bg-white rounded-lg shadow overflow-hidden">
|
||||||
<iframe
|
<iframe
|
||||||
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2585.923358188726!2d8.63338731565!3d49.58872697936459!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x4797ca97ea4a7e55%3A0x4e3bd89fc8fa7adc!2sLaudenbach%2C%20Germany!5e0!3m2!1sen!2sus!4v1644950297175!5m2!1sen!2sus"
|
src="https://www.google.com/maps/embed?pb=!1m14!1m12!1m3!1d646.3176722545943!2d8.640956290509195!3d49.61150128349905!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!5e0!3m2!1sde!2sde!4v1746366691389!5m2!1sde!2sde"
|
||||||
width="100%"
|
width="100%"
|
||||||
height="250"
|
height="250"
|
||||||
style={{ border: 0 }}
|
style={{ border: 0 }}
|
||||||
|
|||||||
@ -55,10 +55,10 @@ const Footer = () => {
|
|||||||
<div>
|
<div>
|
||||||
<h3 className="font-bold text-lg mb-4">Infos</h3>
|
<h3 className="font-bold text-lg mb-4">Infos</h3>
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
<li><a href="#" className="text-gray-400 hover:text-white">Datenschutz</a></li>
|
<li><a href="/datenschutz" className="text-gray-400 hover:text-white">Datenschutz</a></li>
|
||||||
<li><a href="#" className="text-gray-400 hover:text-white">Impressum</a></li>
|
<li><a href="/impressum" className="text-gray-400 hover:text-white">Impressum</a></li>
|
||||||
<li><a href="#" className="text-gray-400 hover:text-white">Satzung</a></li>
|
<li><a href="/satzung" className="text-gray-400 hover:text-white">Satzung</a></li>
|
||||||
<li><a href="#" className="text-gray-400 hover:text-white">Beiträge</a></li>
|
<li><a href="/beitraege" className="text-gray-400 hover:text-white">Beiträge</a></li>
|
||||||
<li><a href="#" className="text-gray-400 hover:text-white">Sponsoren</a></li>
|
<li><a href="#" className="text-gray-400 hover:text-white">Sponsoren</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -72,9 +72,15 @@
|
|||||||
@apply border-border;
|
@apply border-border;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@apply bg-background text-foreground;
|
@apply bg-background text-foreground;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html{
|
||||||
|
overflow-y: scroll;
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
|
|||||||
@ -28,6 +28,10 @@ import PlayerManagementPage from "./admin/PlayerManagementPage";
|
|||||||
import GalleryManager from "./admin/GalleryManager";
|
import GalleryManager from "./admin/GalleryManager";
|
||||||
import GalleryPage from "./pages/GalleryPage";
|
import GalleryPage from "./pages/GalleryPage";
|
||||||
import EventsAdmin from "./admin/EventsAdmin";
|
import EventsAdmin from "./admin/EventsAdmin";
|
||||||
|
import Datenschutz from "./pages/Datenschutz";
|
||||||
|
import Impressum from "./pages/Impressum";
|
||||||
|
import Satzung from "./pages/Satzung";
|
||||||
|
import Beitraege from "./pages/Beitraege";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -64,6 +68,10 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
|
|||||||
<Route path="/login" element={<Layout><LoginPage /></Layout>}/>
|
<Route path="/login" element={<Layout><LoginPage /></Layout>}/>
|
||||||
<Route path="/gallery" element={<Layout><GalleryPage /></Layout>}/>
|
<Route path="/gallery" element={<Layout><GalleryPage /></Layout>}/>
|
||||||
<Route path="/admin/login" element={<LoginPage />} />
|
<Route path="/admin/login" element={<LoginPage />} />
|
||||||
|
<Route path="/datenschutz" element={<Layout><Datenschutz /></Layout>} />
|
||||||
|
<Route path="/satzung" element={<Layout><Satzung /></Layout>} />
|
||||||
|
<Route path="/impressum" element={<Layout><Impressum /></Layout>} />
|
||||||
|
<Route path="/beitraege" element={<Layout><Beitraege /></Layout>} />
|
||||||
<Route path="/admin" element={<PrivateRoute><Layout><AdminDashboard /></Layout></PrivateRoute>} />
|
<Route path="/admin" element={<PrivateRoute><Layout><AdminDashboard /></Layout></PrivateRoute>} />
|
||||||
<Route path="/admin/news" element={<PrivateRoute><Layout><NewsManager /></Layout></PrivateRoute>} />
|
<Route path="/admin/news" element={<PrivateRoute><Layout><NewsManager /></Layout></PrivateRoute>} />
|
||||||
<Route path="/admin/users" element={<PrivateRoute><Layout><UserManagementPage /></Layout></PrivateRoute>} />
|
<Route path="/admin/users" element={<PrivateRoute><Layout><UserManagementPage /></Layout></PrivateRoute>} />
|
||||||
|
|||||||
60
src/pages/Beitraege.tsx
Normal file
60
src/pages/Beitraege.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const Beitraege = () => {
|
||||||
|
return (
|
||||||
|
<section className="max-w-4xl mx-auto px-4 py-16">
|
||||||
|
<h1 className="text-3xl font-bold text-frog-600 mb-6">Mitgliedsbeiträge</h1>
|
||||||
|
<p className="text-gray-700 mb-6">Gültig ab: <strong>01.01.2024</strong></p>
|
||||||
|
|
||||||
|
<div className="bg-white shadow rounded-lg overflow-hidden">
|
||||||
|
<table className="w-full table-auto">
|
||||||
|
<thead className="bg-frog-100 text-frog-800">
|
||||||
|
<tr>
|
||||||
|
<th className="text-left px-4 py-3 font-semibold">Beitragsgruppe</th>
|
||||||
|
<th className="text-right px-4 py-3 font-semibold">Jahresbeitrag</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="text-gray-800">
|
||||||
|
<tr className="border-t">
|
||||||
|
<td className="px-4 py-3">
|
||||||
|
Kinder / Jugendliche / Schüler über 18 Jahre / Studenten / Rentner / Arbeitslose (auf Antrag)
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-3 text-right">64,00 €</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="border-t">
|
||||||
|
<td className="px-4 py-3">
|
||||||
|
Rentnerehepaar / arbeitsloses Ehepaar (auf Antrag) / 2 Geschwister unter 18 J. ohne Eltern
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-3 text-right">99,00 €</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="border-t">
|
||||||
|
<td className="px-4 py-3">
|
||||||
|
Erwachsener ab 18 Jahre / 3 und mehr Geschwister unter 18 J. ohne Eltern
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-3 text-right">112,00 €</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="border-t">
|
||||||
|
<td className="px-4 py-3">
|
||||||
|
Ehepaar ohne Kinder / 1 Elternteil mit beliebig vielen Kindern unter 18 J.
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-3 text-right">162,00 €</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="border-t">
|
||||||
|
<td className="px-4 py-3">
|
||||||
|
Ehepaar mit beliebig vielen Kindern
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-3 text-right">168,00 €</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-sm text-gray-500 mt-6">
|
||||||
|
Hinweis: Vergünstigungen gelten nur auf Antrag und ggf. mit Nachweis.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Beitraege;
|
||||||
|
|
||||||
66
src/pages/Datenschutz.tsx
Normal file
66
src/pages/Datenschutz.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const Datenschutz = () => {
|
||||||
|
return (
|
||||||
|
<section className="max-w-4xl mx-auto px-4 py-16">
|
||||||
|
<h1 className="text-3xl font-bold text-frog-600 mb-6">Datenschutzerklärung</h1>
|
||||||
|
|
||||||
|
<p className="mb-4">
|
||||||
|
Der Schutz deiner persönlichen Daten ist uns ein wichtiges Anliegen. Nachfolgend informieren wir dich über die Erhebung, Verarbeitung und Nutzung personenbezogener Daten im Rahmen der Nutzung unserer Website.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">1. Verantwortliche Stelle</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
TG Laudenbach – Abteilung Volleyball<br />
|
||||||
|
Eleker Straße 3<br />
|
||||||
|
69514 Laudenbach<br />
|
||||||
|
E-Mail: info@tg-laudenbach-volleyball.de
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">2. Erhebung und Verarbeitung personenbezogener Daten</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Wir erheben personenbezogene Daten nur, wenn du uns diese im Rahmen einer Anfrage über unser Kontaktformular mitteilst oder dich einloggst.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">3. Kontaktformular</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Wenn du uns über das Kontaktformular kontaktierst, werden deine Angaben inklusive der von dir dort angegebenen Kontaktdaten zum Zweck der Bearbeitung der Anfrage und für den Fall von Anschlussfragen bei uns gespeichert.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">4. Login-Bereich</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Der Login-Bereich verwendet ein Token-basiertes Authentifizierungssystem (JWT). Dabei werden keine Passwörter im Klartext gespeichert. Die Authentifizierung erfolgt verschlüsselt.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">5. Google reCAPTCHA</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Wir verwenden „Google reCAPTCHA“ (Google LLC) zum Schutz gegen Spam und Bots. Es kann dabei zu einer Übertragung personenbezogener Daten an Google kommen. Mehr Informationen findest du unter{" "}
|
||||||
|
<a
|
||||||
|
href="https://policies.google.com/privacy"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-frog-600 underline"
|
||||||
|
>
|
||||||
|
Google's Datenschutzerklärung
|
||||||
|
</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">6. Eingebettete Karten (Google Maps)</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Diese Website nutzt Google Maps zur Darstellung von Standorten. Beim Laden der Karte können Daten an Google übermittelt werden.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">7. Deine Rechte</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Du hast das Recht auf Auskunft über deine bei uns gespeicherten personenbezogenen Daten, sowie auf Berichtigung, Sperrung oder Löschung dieser Daten. Wende dich dazu bitte an uns über die oben genannte Kontaktadresse.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">8. Änderungen</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Wir behalten uns vor, diese Datenschutzerklärung bei Bedarf anzupassen, um sie stets aktuell zu halten.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Datenschutz;
|
||||||
52
src/pages/Impressum.tsx
Normal file
52
src/pages/Impressum.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const Impressum = () => {
|
||||||
|
return (
|
||||||
|
<section className="max-w-4xl mx-auto px-4 py-16">
|
||||||
|
<h1 className="text-3xl font-bold text-frog-600 mb-6">Impressum</h1>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mb-2">Angaben gemäß § 5 TMG</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
TG Laudenbach – Abteilung Volleyball<br />
|
||||||
|
Eleker Straße 3<br />
|
||||||
|
69514 Laudenbach
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">Vertreten durch:</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Max Mustermann (Abteilungsleiter)<br />
|
||||||
|
E-Mail: info@tg-laudenbach-volleyball.de
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">Kontakt</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Telefon: +49 6201 7835919<br />
|
||||||
|
E-Mail: info@tg-laudenbach-volleyball.de
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Max Mustermann<br />
|
||||||
|
Eleker Straße 3<br />
|
||||||
|
69514 Laudenbach
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">Haftung für Inhalte</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">Haftung für Links</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Unser Angebot enthält Links zu externen Websites Dritter, auf deren Inhalte wir keinen Einfluss haben. Für diese Inhalte übernehmen wir keine Gewähr. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber verantwortlich.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 className="text-xl font-semibold mt-6 mb-2">Urheberrecht</h2>
|
||||||
|
<p className="mb-4">
|
||||||
|
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Beiträge Dritter sind als solche gekennzeichnet. Die Vervielfältigung, Bearbeitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Impressum;
|
||||||
@ -1,52 +1,127 @@
|
|||||||
|
import { useState } from "react";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent } from "@/components/ui/card";
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import IbanInput from "@/components/IbanInput";
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||||
import AdresseInput from "@/components/AdresseInput";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const MitgliedWerdenPage = () => {
|
const MitgliedWerdenPage = () => {
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center mt-10">
|
<div className="flex justify-center mt-10 px-4">
|
||||||
<Card className="w-full max-w-2xl">
|
<Card className="w-full max-w-3xl">
|
||||||
<CardContent className="p-6">
|
<CardContent className="p-6">
|
||||||
<h1 className="text-2xl font-bold mb-4 text-center">Mitglied werden</h1>
|
<h1 className="text-2xl font-bold mb-6 text-center text-frog-600">Mitglied werden</h1>
|
||||||
<form className="space-y-4">
|
|
||||||
{/* Mitgliedsdaten */}
|
|
||||||
<h2 className="text-lg font-semibold">Persönliche Daten</h2>
|
|
||||||
<Input placeholder="Vorname" required />
|
|
||||||
<Input placeholder="Nachname" required />
|
|
||||||
{/*<AdresseInput /> -> Für die spätere Verwendung zum AutoComplete*/}
|
|
||||||
<Input placeholder="Straße und Hausnummer" required />
|
|
||||||
<Input placeholder="PLZ und Wohnort" required />
|
|
||||||
<Input placeholder="Telefonnummer" required />
|
|
||||||
<Input placeholder="E-Mail-Adresse" type="email" required />
|
|
||||||
<div className="flex flex-col space-y-1">
|
|
||||||
<label htmlFor="birthdate" className="text-sm font-medium text-gray-700">
|
|
||||||
Geburtsdatum*
|
|
||||||
</label>
|
|
||||||
<Input id="birthdate" type="date" required />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col space-y-1">
|
<form className="space-y-6">
|
||||||
<label htmlFor="entrydate" className="text-sm font-medium text-gray-700">
|
{/* Persönliche Daten */}
|
||||||
Eintrittsdatum*
|
<div className="grid gap-4">
|
||||||
</label>
|
<h2 className="text-lg font-semibold text-gray-800">Persönliche Daten</h2>
|
||||||
<Input id="entrydate" type="date" required />
|
<div className="grid md:grid-cols-2 gap-4">
|
||||||
</div>
|
<Select>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="Anrede*" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="Herr">Herr</SelectItem>
|
||||||
|
<SelectItem value="Frau">Frau</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<Select>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="Titel (optional)" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="Dipl.-Ing.">Dipl.-Ing.</SelectItem>
|
||||||
|
<SelectItem value="Dr.">Dr.</SelectItem>
|
||||||
|
<SelectItem value="Prof.">Prof.</SelectItem>
|
||||||
|
<SelectItem value="Prof. Dr.">Prof. Dr.</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div className="grid md:grid-cols-2 gap-4">
|
||||||
|
<Input placeholder="Vorname*" required />
|
||||||
|
<Input placeholder="Nachname*" required />
|
||||||
|
</div>
|
||||||
|
<Input type="date" placeholder="Geburtsdatum*" required />
|
||||||
|
<div className="grid md:grid-cols-2 gap-4">
|
||||||
|
<Input placeholder="Straße*" required />
|
||||||
|
<Input placeholder="Hausnummer*" required />
|
||||||
|
</div>
|
||||||
|
<div className="grid md:grid-cols-2 gap-4">
|
||||||
|
<Input placeholder="PLZ*" required />
|
||||||
|
<Input placeholder="Ort*" required />
|
||||||
|
</div>
|
||||||
|
<div className="grid md:grid-cols-2 gap-4">
|
||||||
|
<Input placeholder="Telefon" />
|
||||||
|
<Input type="email" placeholder="E-Mail-Adresse*" required />
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<input type="checkbox" id="newsletter" />
|
||||||
|
<label htmlFor="newsletter" className="text-sm">Newsletter (per E-Mail + WhatsApp)</label>
|
||||||
|
</div>
|
||||||
|
<Input type="date" placeholder="Eintrittsdatum*" required />
|
||||||
|
<Select>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="Beitrag/Tarif auswählen*" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="1">64,00€ - Kinder / Jugendliche / Studenten / Rentner</SelectItem>
|
||||||
|
<SelectItem value="2">99,00€ - Rentnerehepaar / 2 Geschwister unter 18 J.</SelectItem>
|
||||||
|
<SelectItem value="3">112,00€ - Erwachsener / 3+ Geschwister</SelectItem>
|
||||||
|
<SelectItem value="4">162,00€ - Elternteil + Kinder</SelectItem>
|
||||||
|
<SelectItem value="5">168,00€ - Ehepaar mit Kindern</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<input type="checkbox" id="no-membership" />
|
||||||
|
<label htmlFor="no-membership" className="text-sm">Ich beantrage selbst keine Mitgliedschaft</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Abteilungen */}
|
||||||
|
<div className="grid gap-4">
|
||||||
|
<h2 className="text-lg font-semibold text-gray-800">Gewünschte Abteilungen</h2>
|
||||||
|
<div className="grid md:grid-cols-2 gap-2 text-sm">
|
||||||
|
{[
|
||||||
|
"Boule", "Fitness und Gesundheitssport", "Handball Damen", "Handball Herren",
|
||||||
|
"Handball Jugend (m.)", "Handball Jugend (w.)", "Leichtathletik", "Tanz & Bodyworkout",
|
||||||
|
"Tischtennis", "Turnen / Gymnastik (Erw.)", "Turnen / Gymnastik (Kinder + Jugend)",
|
||||||
|
"Volleyball", "Wandern"
|
||||||
|
].map((abteilung, idx) => (
|
||||||
|
<label key={idx} className="flex items-center space-x-2">
|
||||||
|
<input type="checkbox" />
|
||||||
|
<span>{abteilung}</span>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Bankverbindung */}
|
{/* Bankverbindung */}
|
||||||
<h2 className="text-lg font-semibold mt-6">Bankverbindung</h2>
|
<div className="grid gap-4">
|
||||||
<Input placeholder="Kontoinhaber (Name, Vorname)" required />
|
<h2 className="text-lg font-semibold text-gray-800">Bankverbindung</h2>
|
||||||
<Input placeholder="Straße und Hausnummer (falls abweichend)" />
|
<Input placeholder="Kontoinhaber (Name, Vorname)*" required />
|
||||||
<Input placeholder="PLZ und Wohnort (falls abweichend)" />
|
<Input placeholder="Straße (falls abweichend)" />
|
||||||
<IbanInput />
|
<Input placeholder="PLZ und Ort (falls abweichend)" />
|
||||||
<Input placeholder="BIC" required />
|
<Input placeholder="IBAN*" required />
|
||||||
|
<Input placeholder="Name der Bank*" required />
|
||||||
|
<Input placeholder="BIC" />
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Submit Button */}
|
{/* Zustimmung */}
|
||||||
<Button type="submit" className="w-full bg-frog-500 hover:bg-frog-600 text-white mt-6">
|
<div className="grid gap-2 text-sm">
|
||||||
Absenden
|
<label className="flex items-center space-x-2">
|
||||||
|
<input type="checkbox" required />
|
||||||
|
<span>Ich habe die <a href="/beitraege" className="underline text-frog-600">Beitragsordnung</a> gelesen und akzeptiere sie.</span>
|
||||||
|
</label>
|
||||||
|
<label className="flex items-center space-x-2">
|
||||||
|
<input type="checkbox" required />
|
||||||
|
<span>Ich habe die <a href="/satzung" className="underline text-frog-600">Satzung</a> der TG Laudenbach gelesen und akzeptiere sie.</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Absenden */}
|
||||||
|
<Button type="submit" className="w-full bg-frog-500 hover:bg-frog-600 text-white mt-4">
|
||||||
|
Anmeldung absenden
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
35
src/pages/Satzung.tsx
Normal file
35
src/pages/Satzung.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { Document, Page, pdfjs } from "react-pdf";
|
||||||
|
import { useState } from "react";
|
||||||
|
import "react-pdf/dist/esm/Page/AnnotationLayer.css";
|
||||||
|
|
||||||
|
|
||||||
|
const Satzung = () => {
|
||||||
|
return (
|
||||||
|
<section className="max-w-5xl mx-auto px-4 py-16">
|
||||||
|
<h1 className="text-3xl font-bold text-frog-600 mb-6">Satzung der TG Laudenbach 1889 e.V.</h1>
|
||||||
|
|
||||||
|
<div className="bg-white border rounded-lg shadow overflow-hidden">
|
||||||
|
<iframe
|
||||||
|
src="/uploads/satzung.pdf"
|
||||||
|
width="100%"
|
||||||
|
height="800px"
|
||||||
|
style={{ border: "none" }}
|
||||||
|
title="Satzung TG Laudenbach"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="mt-4 text-sm text-gray-500">
|
||||||
|
<a
|
||||||
|
href="/uploads/satzung.pdf"
|
||||||
|
download
|
||||||
|
className="underline text-frog-600 hover:text-frog-800"
|
||||||
|
>
|
||||||
|
Satzung als PDF herunterladen
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Satzung;
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user