626 lines
23 KiB
TypeScript
626 lines
23 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import router from "next/router";
|
|
|
|
interface EventContent {
|
|
registrationEnabled: boolean;
|
|
visitorOnly: boolean;
|
|
volunteerAreas: string;
|
|
}
|
|
|
|
const normalizeSsn = (value: string) =>
|
|
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 [content, setContent] = useState<EventContent | null>(null);
|
|
const [formData, setFormData] = useState({
|
|
firstName: "",
|
|
surName: "",
|
|
grade: "",
|
|
phoneNumber: "",
|
|
email: "",
|
|
guardianName: "",
|
|
guardianPhoneNumber: "",
|
|
guardianEmail: "",
|
|
isVisitor: false,
|
|
hasApprovedGdpr: false,
|
|
friends: "",
|
|
specialDiet: "",
|
|
ssn: "",
|
|
});
|
|
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
const [message, setMessage] = useState({ type: "", text: "" });
|
|
const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});
|
|
const [showBecomeMemberCta, setShowBecomeMemberCta] = useState(false);
|
|
|
|
useEffect(() => {
|
|
fetch("/api/Content")
|
|
.then((res) => res.json())
|
|
.then((data) => {
|
|
setContent(data);
|
|
if (data.visitorOnly) {
|
|
setFormData((prev) => ({ ...prev, isVisitor: true }));
|
|
}
|
|
})
|
|
.catch((err) => console.error("Failed to fetch content", err));
|
|
}, []);
|
|
|
|
if (content && !content.registrationEnabled) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-gray-50 px-4">
|
|
<div className="max-w-md w-full bg-white p-8 rounded-xl shadow-md text-center">
|
|
<h1 className="text-2xl font-bold text-gray-900 mb-4">
|
|
Registreringen är stängd
|
|
</h1>
|
|
<p className="text-gray-600 mb-6">
|
|
Vi tar tyvärr inte emot fler anmälningar just nu.
|
|
</p>
|
|
<Link href="/" className="text-blue-600 hover:underline">
|
|
Gå tillbaka till startsidan
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const handleInputChange = (
|
|
e: React.ChangeEvent<
|
|
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
|
|
>,
|
|
) => {
|
|
const { name, value, type } = e.target;
|
|
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();
|
|
|
|
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<string, string> = {};
|
|
|
|
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({});
|
|
setShowBecomeMemberCta(false);
|
|
|
|
setIsSubmitting(true);
|
|
setMessage({ type: "info", text: "Behandlar din anmälan..." });
|
|
|
|
try {
|
|
// Returns Ok (200) if NOT registered, Conflict (409) if registered
|
|
const checkRes = await fetch(
|
|
`/api/Registration/registered/${normalizedSsn}`,
|
|
);
|
|
|
|
if (checkRes.status === 409) {
|
|
setMessage({
|
|
type: "error",
|
|
text: "Detta personnummer är redan registrerat för LAN:et.",
|
|
});
|
|
setIsSubmitting(false);
|
|
return;
|
|
}
|
|
|
|
// Returns 200 (Ok) if member, 404 (NotFound) if not
|
|
const validateRes = await fetch(
|
|
`/api/Registration/register/${normalizedSsn}`,
|
|
);
|
|
const isMember = validateRes.ok;
|
|
|
|
const { ssn, ...participantData } = formData;
|
|
const finalPayload = {
|
|
...participantData,
|
|
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", {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(finalPayload),
|
|
});
|
|
|
|
if (response.ok) {
|
|
setMessage({
|
|
type: "success",
|
|
text: "Registreringen är klar! Du är nu anmäld till LAN:et.",
|
|
});
|
|
setShowBecomeMemberCta(!isMember);
|
|
|
|
await fetch(`/api/Registration/register/${normalizedSsn}`, {
|
|
method: "POST",
|
|
});
|
|
} else {
|
|
const errorData = await response.json();
|
|
setMessage({
|
|
type: "error",
|
|
text: errorData.message || "Registreringen misslyckades.",
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error("Registration error:", error);
|
|
setMessage({
|
|
type: "error",
|
|
text: "Ett anslutningsfel uppstod. Kontrollera internet och försök igen.",
|
|
});
|
|
} finally {
|
|
setIsSubmitting(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
|
<div className="max-w-2xl mx-auto bg-white p-8 rounded-xl shadow-md">
|
|
<div className="mb-3">
|
|
<button
|
|
type="button"
|
|
onClick={() => router.push("/")}
|
|
className="inline-flex items-center gap-1 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50"
|
|
>
|
|
<span>←</span>
|
|
<span className="sm:hidden">Tillbaka</span>
|
|
<span className="hidden sm:inline">Tillbaka till information</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div className="flex justify-center mb-6">
|
|
<Image
|
|
src="/vBytes_Logotyp.png"
|
|
alt="vBytes"
|
|
width={320}
|
|
height={128}
|
|
className="h-auto w-44"
|
|
priority
|
|
/>
|
|
</div>
|
|
<div className="text-center mb-10">
|
|
<h1 className="text-3xl font-bold text-gray-900">LAN-registrering</h1>
|
|
<p className="mt-2 text-gray-600">
|
|
Vänligen fyll i detta formulär för att anmäla dig till lanet.
|
|
</p>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-6">
|
|
<div className="grid grid-cols-1 gap-y-6 gap-x-4 sm:grid-cols-2">
|
|
<div className="sm:col-span-2">
|
|
<label
|
|
htmlFor="ssn"
|
|
className="block text-sm font-medium text-gray-700"
|
|
>
|
|
Personnummer*
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="ssn"
|
|
id="ssn"
|
|
placeholder="YYYYMMDD-XXXX"
|
|
required
|
|
className={`mt-1 block w-full rounded-md shadow-sm sm:text-sm p-2 border text-gray-900 ${fieldErrors.ssn ? "border-red-500 focus:border-red-500 focus:ring-red-500" : "border-gray-300 focus:border-blue-500 focus:ring-blue-500"}`}
|
|
value={formData.ssn}
|
|
onChange={handleInputChange}
|
|
/>
|
|
{fieldErrors.ssn && (
|
|
<p className="mt-1 text-xs text-red-600">{fieldErrors.ssn}</p>
|
|
)}
|
|
<p className="mt-1 text-xs text-gray-500">
|
|
Används endast för att kolla om du redan är medlem eller inte.
|
|
Sparas ej.
|
|
</p>
|
|
</div>
|
|
|
|
<div>
|
|
<label
|
|
htmlFor="firstName"
|
|
className="block text-sm font-medium text-gray-700"
|
|
>
|
|
Förnamn *
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="firstName"
|
|
id="firstName"
|
|
required
|
|
className={`mt-1 block w-full rounded-md shadow-sm sm:text-sm p-2 border text-gray-900 ${fieldErrors.firstName ? "border-red-500 focus:border-red-500 focus:ring-red-500" : "border-gray-300 focus:border-blue-500 focus:ring-blue-500"}`}
|
|
value={formData.firstName}
|
|
onChange={handleInputChange}
|
|
/>
|
|
{fieldErrors.firstName && (
|
|
<p className="mt-1 text-xs text-red-600">
|
|
{fieldErrors.firstName}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div>
|
|
<label
|
|
htmlFor="surName"
|
|
className="block text-sm font-medium text-gray-700"
|
|
>
|
|
Efternamn *
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="surName"
|
|
id="surName"
|
|
required
|
|
className={`mt-1 block w-full rounded-md shadow-sm sm:text-sm p-2 border text-gray-900 ${fieldErrors.surName ? "border-red-500 focus:border-red-500 focus:ring-red-500" : "border-gray-300 focus:border-blue-500 focus:ring-blue-500"}`}
|
|
value={formData.surName}
|
|
onChange={handleInputChange}
|
|
/>
|
|
{fieldErrors.surName && (
|
|
<p className="mt-1 text-xs text-red-600">
|
|
{fieldErrors.surName}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div>
|
|
<label
|
|
htmlFor="grade"
|
|
className="block text-sm font-medium text-gray-700"
|
|
>
|
|
Årskurs *
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="grade"
|
|
id="grade"
|
|
required
|
|
className={`mt-1 block w-full rounded-md shadow-sm sm:text-sm p-2 border text-gray-900 ${fieldErrors.grade ? "border-red-500 focus:border-red-500 focus:ring-red-500" : "border-gray-300 focus:border-blue-500 focus:ring-blue-500"}`}
|
|
value={formData.grade}
|
|
onChange={handleInputChange}
|
|
/>
|
|
{fieldErrors.grade && (
|
|
<p className="mt-1 text-xs text-red-600">{fieldErrors.grade}</p>
|
|
)}
|
|
</div>
|
|
|
|
<div>
|
|
<label
|
|
htmlFor="phoneNumber"
|
|
className="block text-sm font-medium text-gray-700"
|
|
>
|
|
Mobilnummer
|
|
</label>
|
|
<input
|
|
type="tel"
|
|
name="phoneNumber"
|
|
id="phoneNumber"
|
|
inputMode="tel"
|
|
placeholder="07XXXXXXXX"
|
|
className={`mt-1 block w-full rounded-md shadow-sm sm:text-sm p-2 border text-gray-900 ${fieldErrors.phoneNumber ? "border-red-500 focus:border-red-500 focus:ring-red-500" : "border-gray-300 focus:border-blue-500 focus:ring-blue-500"}`}
|
|
value={formData.phoneNumber}
|
|
onChange={handleInputChange}
|
|
/>
|
|
{fieldErrors.phoneNumber && (
|
|
<p className="mt-1 text-xs text-red-600">
|
|
{fieldErrors.phoneNumber}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="sm:col-span-2">
|
|
<label
|
|
htmlFor="email"
|
|
className="block text-sm font-medium text-gray-700"
|
|
>
|
|
E-post
|
|
</label>
|
|
<input
|
|
type="email"
|
|
name="email"
|
|
id="email"
|
|
className={`mt-1 block w-full rounded-md shadow-sm sm:text-sm p-2 border text-gray-900 ${fieldErrors.email ? "border-red-500 focus:border-red-500 focus:ring-red-500" : "border-gray-300 focus:border-blue-500 focus:ring-blue-500"}`}
|
|
value={formData.email}
|
|
onChange={handleInputChange}
|
|
/>
|
|
{fieldErrors.email && (
|
|
<p className="mt-1 text-xs text-red-600">{fieldErrors.email}</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="sm:col-span-2 pt-4 border-t border-gray-100 mt-4">
|
|
<h3 className="text-lg font-medium text-gray-900 mb-4">
|
|
Vårdnadshavares Information
|
|
</h3>
|
|
</div>
|
|
|
|
<div>
|
|
<label
|
|
htmlFor="guardianName"
|
|
className="block text-sm font-medium text-gray-700"
|
|
>
|
|
Vårdnadshavares Namn *
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="guardianName"
|
|
id="guardianName"
|
|
required
|
|
className={`mt-1 block w-full rounded-md shadow-sm sm:text-sm p-2 border text-gray-900 ${fieldErrors.guardianName ? "border-red-500 focus:border-red-500 focus:ring-red-500" : "border-gray-300 focus:border-blue-500 focus:ring-blue-500"}`}
|
|
value={formData.guardianName}
|
|
onChange={handleInputChange}
|
|
/>
|
|
{fieldErrors.guardianName && (
|
|
<p className="mt-1 text-xs text-red-600">
|
|
{fieldErrors.guardianName}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div>
|
|
<label
|
|
htmlFor="guardianPhoneNumber"
|
|
className="block text-sm font-medium text-gray-700"
|
|
>
|
|
Vårdnadshavares Mobilnummer *
|
|
</label>
|
|
<input
|
|
type="tel"
|
|
name="guardianPhoneNumber"
|
|
id="guardianPhoneNumber"
|
|
required
|
|
inputMode="tel"
|
|
placeholder="07XXXXXXXX"
|
|
className={`mt-1 block w-full rounded-md shadow-sm sm:text-sm p-2 border text-gray-900 ${fieldErrors.guardianPhoneNumber ? "border-red-500 focus:border-red-500 focus:ring-red-500" : "border-gray-300 focus:border-blue-500 focus:ring-blue-500"}`}
|
|
value={formData.guardianPhoneNumber}
|
|
onChange={handleInputChange}
|
|
/>
|
|
{fieldErrors.guardianPhoneNumber && (
|
|
<p className="mt-1 text-xs text-red-600">
|
|
{fieldErrors.guardianPhoneNumber}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="sm:col-span-2">
|
|
<label
|
|
htmlFor="guardianEmail"
|
|
className="block text-sm font-medium text-gray-700"
|
|
>
|
|
Vårdnadshavares E-post *
|
|
</label>
|
|
<input
|
|
type="email"
|
|
name="guardianEmail"
|
|
id="guardianEmail"
|
|
required
|
|
className={`mt-1 block w-full rounded-md shadow-sm sm:text-sm p-2 border text-gray-900 ${fieldErrors.guardianEmail ? "border-red-500 focus:border-red-500 focus:ring-red-500" : "border-gray-300 focus:border-blue-500 focus:ring-blue-500"}`}
|
|
value={formData.guardianEmail}
|
|
onChange={handleInputChange}
|
|
/>
|
|
{fieldErrors.guardianEmail && (
|
|
<p className="mt-1 text-xs text-red-600">
|
|
{fieldErrors.guardianEmail}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="sm:col-span-2 pt-4 border-t border-gray-100 mt-4">
|
|
<h3 className="text-lg font-medium text-gray-900 mb-4">
|
|
Ytterligare uppgifter
|
|
</h3>
|
|
</div>
|
|
|
|
<div className="sm:col-span-2">
|
|
<label
|
|
htmlFor="friends"
|
|
className="block text-sm font-medium text-gray-700"
|
|
>
|
|
"Önska" Vänner (att sitta jämte)
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="friends"
|
|
id="friends"
|
|
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm p-2 border text-gray-900"
|
|
value={formData.friends}
|
|
onChange={handleInputChange}
|
|
/>
|
|
</div>
|
|
|
|
<div className="sm:col-span-2">
|
|
<label
|
|
htmlFor="specialDiet"
|
|
className="block text-sm font-medium text-gray-700"
|
|
>
|
|
Specialkost / Allergier
|
|
</label>
|
|
<textarea
|
|
name="specialDiet"
|
|
id="specialDiet"
|
|
rows={3}
|
|
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm p-2 border text-gray-900"
|
|
value={formData.specialDiet}
|
|
onChange={handleInputChange}
|
|
/>
|
|
</div>
|
|
|
|
<div className="sm:col-span-2 space-y-4 pt-4 mt-4 border-t border-gray-100">
|
|
<div className="flex items-start">
|
|
<div className="flex items-center h-5">
|
|
<input
|
|
id="isVisitor"
|
|
name="isVisitor"
|
|
type="checkbox"
|
|
className="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded disabled:bg-gray-100 disabled:cursor-not-allowed"
|
|
checked={formData.isVisitor}
|
|
onChange={handleInputChange}
|
|
disabled={content?.visitorOnly}
|
|
/>
|
|
</div>
|
|
<div className="ml-3 text-sm">
|
|
<label
|
|
htmlFor="isVisitor"
|
|
className="font-medium text-gray-700"
|
|
>
|
|
Registrera dig som besökare
|
|
</label>
|
|
<p className="text-gray-500">
|
|
{content?.visitorOnly
|
|
? "Just nu tillåts endast besöks-registreringar."
|
|
: "Klicka i denna om du bara ska besöka och inte planerar på att ta med dator eller annan form av konsol."}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-start">
|
|
<div className="flex items-center h-5">
|
|
<input
|
|
id="hasApprovedGdpr"
|
|
name="hasApprovedGdpr"
|
|
type="checkbox"
|
|
className="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded"
|
|
checked={formData.hasApprovedGdpr}
|
|
onChange={handleInputChange}
|
|
/>
|
|
</div>
|
|
<div className="ml-3 text-sm">
|
|
<label
|
|
htmlFor="hasApprovedGdpr"
|
|
className="font-medium text-gray-700"
|
|
>
|
|
GDPR-godkännande *
|
|
</label>
|
|
<p className="text-gray-500">
|
|
Jag godkänner att mina personuppgifter sparas och hanteras i
|
|
syfte för detta event.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{message.text && (
|
|
<div
|
|
className={`p-4 rounded-md ${
|
|
message.type === "success"
|
|
? "bg-green-50 text-green-800 border border-green-200"
|
|
: message.type === "error"
|
|
? "bg-red-50 text-red-800 border border-red-200"
|
|
: "bg-blue-50 text-blue-800 border border-blue-200"
|
|
}`}
|
|
>
|
|
{message.text}
|
|
</div>
|
|
)}
|
|
|
|
{showBecomeMemberCta && message.type === "success" && (
|
|
<a
|
|
href="https://ebas.sverok.se/blimedlem/22393"
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
className="w-full inline-flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-gray-800 hover:bg-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-700"
|
|
>
|
|
Klicka här för att bli medlem i vBytes
|
|
</a>
|
|
)}
|
|
|
|
<div className="pt-6">
|
|
<button
|
|
type="submit"
|
|
disabled={isSubmitting}
|
|
className="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:bg-blue-400"
|
|
>
|
|
{isSubmitting ? "Registrerar..." : "Anmäl dig till LAN"}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|