diff --git a/src/App.tsx b/src/App.tsx index 18daf2e90..3a8e4f4dc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,6 +5,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { BrowserRouter, Routes, Route } from "react-router-dom"; import Index from "./pages/Index"; import NotFound from "./pages/NotFound"; +import ScrollToTop from "./components/ScrollTop"; const queryClient = new QueryClient(); @@ -14,6 +15,7 @@ const App = () => ( + } /> {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */} diff --git a/src/components/AdresseInput.tsx b/src/components/AdresseInput.tsx new file mode 100644 index 000000000..0e3e4b693 --- /dev/null +++ b/src/components/AdresseInput.tsx @@ -0,0 +1,51 @@ +import { useState } from "react"; +import { Input } from "@/components/ui/input"; + +const AdresseInput = () => { + const [query, setQuery] = useState(""); + const [suggestions, setSuggestions] = useState([]); + + const handleChange = async (e: React.ChangeEvent) => { + const value = e.target.value; + setQuery(value); + + if (value.length >= 3) { + const response = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(value)}&addressdetails=1&limit=5`); + const data = await response.json(); + setSuggestions(data); + } else { + setSuggestions([]); + } + }; + + const handleSelect = (address: string) => { + setQuery(address); + setSuggestions([]); + }; + + return ( +
+ + {suggestions.length > 0 && ( +
+ {suggestions.map((suggestion, index) => ( +
handleSelect(suggestion.display_name)} + className="px-4 py-2 hover:bg-frog-50 cursor-pointer text-sm" + > + {suggestion.display_name} +
+ ))} +
+ )} +
+ ); +}; + +export default AdresseInput; diff --git a/src/components/IbanInput.tsx b/src/components/IbanInput.tsx new file mode 100644 index 000000000..767a058ea --- /dev/null +++ b/src/components/IbanInput.tsx @@ -0,0 +1,59 @@ +import { useState } from "react"; +import { Input } from "@/components/ui/input"; + +const IbanInput = ({ onValidIban }: { onValidIban?: (iban: string) => void }) => { + const [iban, setIban] = useState(""); + const [error, setError] = useState(""); + + const formatIban = (value: string) => { + const alphanumeric = value.replace(/[^a-zA-Z0-9]/g, "").toUpperCase(); + const formatted = alphanumeric.replace(/(.{4})/g, "$1 ").trim(); + return formatted; + }; + + const validateIban = (rawIban: string) => { + // IBAN Validierung nach Mod-97-10 Regel + const rearranged = rawIban.slice(4) + rawIban.slice(0, 4); + const converted = rearranged.replace(/[A-Z]/g, (char) => (char.charCodeAt(0) - 55).toString()); + const mod97 = BigInt(converted) % 97n; + return mod97 === 1n; + }; + + const handleChange = (e: React.ChangeEvent) => { + const input = e.target.value; + if (input.length <= 27) { + setIban(formatIban(input)); + setError(""); // Fehler zurücksetzen während der Eingabe + } + }; + + const handleBlur = () => { + const rawIban = iban.replace(/\s/g, ""); // Leerzeichen entfernen + if (rawIban.length >= 15) { // Minimum Länge einer IBAN + if (!validateIban(rawIban)) { + setError("Ungültige IBAN"); + } else { + setError(""); + if (onValidIban) { + onValidIban(rawIban); + } + } + } + }; + + return ( +
+ + {error && {error}} +
+ ); +}; + +export default IbanInput; diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index fd80b6157..49cf067ea 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; import { Button } from "@/components/ui/button"; -import { Menu, X, Volleyball, ChevronDown } from "lucide-react"; +import { Menu, X, Volleyball, ChevronDown, Users } from "lucide-react"; import { Link } from "react-router-dom"; const Navbar = () => { @@ -15,10 +15,10 @@ const Navbar = () => {