diff --git a/src/Web/lan-frontend/app/page.tsx b/src/Web/lan-frontend/app/page.tsx index 7358099..d725d36 100644 --- a/src/Web/lan-frontend/app/page.tsx +++ b/src/Web/lan-frontend/app/page.tsx @@ -40,7 +40,7 @@ export default function LandingPage() { return (
{/* Hero Section */} -
+
+
+ vBytes +
+ {/* Info Section */} -
- {(content.eventDate || content.eventTime || content.locationName || content.locationAddress || content.additionalInfo) && ( +
+ {(content.eventDate || + content.eventTime || + content.locationName || + content.locationAddress || + content.additionalInfo) && (
-

Information

+

+ Information +

{(content.eventDate || content.eventTime) && (
-

Tid/Datum

+

+ Tid/Datum +

{content.eventDate &&

{content.eventDate}

} {content.eventTime &&

{content.eventTime}

}
@@ -91,18 +110,25 @@ export default function LandingPage() { {content.whatToBring && (
-

Ta Med(bokad LAN-plats)

+

+ Ta Med(bokad LAN-plats) +

    - {content.whatToBring.split('\n').filter(line => line.trim()).map((line, i) => ( -
  • {line}
  • - ))} + {content.whatToBring + .split("\n") + .filter((line) => line.trim()) + .map((line, i) => ( +
  • {line}
  • + ))}
)} {content.rulesAndGdpr && (
-

Regler för LAN & GDPR

+

+ Regler för LAN & GDPR +

{content.rulesAndGdpr}

@@ -114,7 +140,9 @@ export default function LandingPage() {

Vill du delta?

-

Begränsade platser, Säkra din plats idag!

+

+ Begränsade platser, Säkra din plats idag! +

+ value.replace(/[\s\-+]/g, "").replace(/\D/g, ""); +const hasValidSsnLength = (value: string) => + value.length === 10 || value.length === 12; +const isValidEmail = (value: string) => + /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value); +const normalizeMobileNumber = (value: string) => { + const digitsOnly = value.replace(/\D/g, ""); + if (digitsOnly.startsWith("0046")) return `0${digitsOnly.slice(4)}`; + if (digitsOnly.startsWith("46")) return `0${digitsOnly.slice(2)}`; + if (digitsOnly.startsWith("7")) return `0${digitsOnly}`; + return digitsOnly; +}; +const isValidMobileNumber = (value: string) => + /^07\d{8}$/.test(normalizeMobileNumber(value)); + export default function RegisterPage() { const router = useRouter(); const [content, setContent] = useState(null); @@ -32,6 +49,7 @@ export default function RegisterPage() { const [isSubmitting, setIsSubmitting] = useState(false); const [message, setMessage] = useState({ type: "", text: "" }); + const [fieldErrors, setFieldErrors] = useState>({}); useEffect(() => { fetch("/api/Content") @@ -49,53 +67,142 @@ export default function RegisterPage() { return (
-

Registreringen är stängd

-

Vi tar tyvärr inte emot fler anmälningar just nu.

- Gå tillbaka till startsidan +

+ Registreringen är stängd +

+

+ Vi tar tyvärr inte emot fler anmälningar just nu. +

+ + Gå tillbaka till startsidan +
); } - const handleInputChange = (e: React.ChangeEvent) => { + const handleInputChange = ( + e: React.ChangeEvent< + HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement + >, + ) => { const { name, value, type } = e.target; - const val = type === "checkbox" ? (e.target as HTMLInputElement).checked : value; + const val = + type === "checkbox" ? (e.target as HTMLInputElement).checked : value; setFormData((prev) => ({ ...prev, [name]: val, })); + + setFieldErrors((prev) => ({ + ...prev, + [name]: "", + })); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - if (!formData.ssn) { - setMessage({ type: "error", text: "SSN is required for registration." }); + const normalizedSsn = normalizeSsn(formData.ssn); + const trimmedFirstName = formData.firstName.trim(); + const trimmedSurName = formData.surName.trim(); + const trimmedGrade = formData.grade.trim(); + const trimmedPhoneNumber = formData.phoneNumber.trim(); + const trimmedGuardianName = formData.guardianName.trim(); + const trimmedGuardianPhone = formData.guardianPhoneNumber.trim(); + const trimmedGuardianEmail = formData.guardianEmail.trim(); + const normalizedPhoneNumber = normalizeMobileNumber(trimmedPhoneNumber); + const normalizedGuardianPhone = normalizeMobileNumber(trimmedGuardianPhone); + const nextFieldErrors: Record = {}; + + if (!normalizedSsn) { + nextFieldErrors.ssn = "Personnummer krävs för registrering."; + } else if (!hasValidSsnLength(normalizedSsn)) { + nextFieldErrors.ssn = "Personnummer måste vara 10 eller 12 siffror."; + } + + if (!trimmedFirstName) + nextFieldErrors.firstName = "Förnamn är obligatoriskt."; + if (!trimmedSurName) + nextFieldErrors.surName = "Efternamn är obligatoriskt."; + if (!trimmedGrade) nextFieldErrors.grade = "Årskurs är obligatorisk."; + if (!trimmedGuardianName) + nextFieldErrors.guardianName = "Vårdnadshavares namn är obligatoriskt."; + if (!trimmedGuardianPhone) + nextFieldErrors.guardianPhoneNumber = + "Vårdnadshavares Mobilnummer är obligatoriskt."; + if (!trimmedGuardianEmail) + nextFieldErrors.guardianEmail = "Vårdnadshavares e-post är obligatorisk."; + + if (trimmedPhoneNumber && !isValidMobileNumber(trimmedPhoneNumber)) { + nextFieldErrors.phoneNumber = + "Mobilnummer måste vara ett giltigt svenskt mobilnummer."; + } + + if (trimmedGuardianPhone && !isValidMobileNumber(trimmedGuardianPhone)) { + nextFieldErrors.guardianPhoneNumber = + "Vårdnadshavares Mobilnummer måste vara ett giltigt svenskt mobilnummer."; + } + + if (trimmedGuardianEmail && !isValidEmail(trimmedGuardianEmail)) { + nextFieldErrors.guardianEmail = + "Vårdnadshavarens e-postadress är ogiltig."; + } + + if (formData.email.trim() && !isValidEmail(formData.email.trim())) { + nextFieldErrors.email = "Din e-postadress är ogiltig."; + } + + if (Object.keys(nextFieldErrors).length > 0) { + setFieldErrors(nextFieldErrors); + setMessage({ + type: "error", + text: "Kontrollera markerade fält och försök igen.", + }); return; } + setFieldErrors({}); + setIsSubmitting(true); setMessage({ type: "info", text: "Processing your registration..." }); try { // Returns Ok (200) if NOT registered, Conflict (409) if registered - const checkRes = await fetch(`/api/Registration/registered/${formData.ssn}`); + const checkRes = await fetch( + `/api/Registration/registered/${normalizedSsn}`, + ); if (checkRes.status === 409) { - setMessage({ type: "error", text: "This SSN is already registered for the LAN." }); + setMessage({ + type: "error", + text: "This SSN is already registered for the LAN.", + }); setIsSubmitting(false); return; } // Returns 200 (Ok) if member, 404 (NotFound) if not - const validateRes = await fetch(`/api/Registration/register/${formData.ssn}`); + const validateRes = await fetch( + `/api/Registration/register/${normalizedSsn}`, + ); const isMember = validateRes.ok; const { ssn, ...participantData } = formData; const finalPayload = { ...participantData, - isMember: isMember + firstName: trimmedFirstName, + surName: trimmedSurName, + grade: trimmedGrade, + phoneNumber: normalizedPhoneNumber, + email: formData.email.trim(), + guardianName: trimmedGuardianName, + guardianPhoneNumber: normalizedGuardianPhone, + guardianEmail: trimmedGuardianEmail, + friends: formData.friends.trim(), + specialDiet: formData.specialDiet.trim(), + isMember: isMember, }; const response = await fetch("/api/Participant/register", { @@ -107,18 +214,27 @@ export default function RegisterPage() { }); if (response.ok) { - setMessage({ type: "success", text: "Registration complete! You are now registered for the LAN." }); + setMessage({ + type: "success", + text: "Registration complete! You are now registered for the LAN.", + }); - await fetch(`/api/Registration/register/${formData.ssn}`, { + await fetch(`/api/Registration/register/${normalizedSsn}`, { method: "POST", }); } else { const errorData = await response.json(); - setMessage({ type: "error", text: errorData.message || "Event registration failed." }); + setMessage({ + type: "error", + text: errorData.message || "Event registration failed.", + }); } } catch (error) { console.error("Registration error:", error); - setMessage({ type: "error", text: "A connection error occurred. Please check your internet and try again." }); + setMessage({ + type: "error", + text: "A connection error occurred. Please check your internet and try again.", + }); } finally { setIsSubmitting(false); } @@ -128,145 +244,249 @@ export default function RegisterPage() {
- + ← Back to Information

Lan Registrering

-

Vänligen fyll i detta formulär för att anmäla dig till lanet.

+

+ Vänligen fyll i detta formulär för att anmäla dig till lanet. +

-
- + -

Används endast för att kolla om du redan är medlem eller inte. Sparas ej.

+ {fieldErrors.ssn && ( +

{fieldErrors.ssn}

+ )} +

+ Används endast för att kolla om du redan är medlem eller inte. + Sparas ej. +

- + + {fieldErrors.firstName && ( +

+ {fieldErrors.firstName} +

+ )}
- + + {fieldErrors.surName && ( +

+ {fieldErrors.surName} +

+ )}
- + + {fieldErrors.grade && ( +

{fieldErrors.grade}

+ )}
- + + {fieldErrors.phoneNumber && ( +

+ {fieldErrors.phoneNumber} +

+ )}
- + + {fieldErrors.email && ( +

{fieldErrors.email}

+ )}
-

Vårdnadshavares Information

+

+ Vårdnadshavares Information +

- + + {fieldErrors.guardianName && ( +

+ {fieldErrors.guardianName} +

+ )}
- + + {fieldErrors.guardianPhoneNumber && ( +

+ {fieldErrors.guardianPhoneNumber} +

+ )}
- + + {fieldErrors.guardianEmail && ( +

+ {fieldErrors.guardianEmail} +

+ )}
-

Yttrligare uppgifter

+

+ Yttrligare uppgifter +

- +
- +