redesign the homepage
Build & Deploy / Build & Push Docker Image (push) Failing after 47s
Build & Deploy / Deploy to VPS (push) Has been skipped
Test / API Unit Tests (push) Failing after 5m4s
Test / Marketplace Unit Tests (push) Failing after 4m55s
Test / Admin Unit Tests (push) Successful in 9m37s
Test / Dashboard Unit Tests (push) Successful in 9m37s
Test / API Integration Tests (push) Successful in 9m54s
Build & Deploy / Build & Push Docker Image (push) Failing after 47s
Build & Deploy / Deploy to VPS (push) Has been skipped
Test / API Unit Tests (push) Failing after 5m4s
Test / Marketplace Unit Tests (push) Failing after 4m55s
Test / Admin Unit Tests (push) Successful in 9m37s
Test / Dashboard Unit Tests (push) Successful in 9m37s
Test / API Integration Tests (push) Successful in 9m54s
This commit is contained in:
@@ -1,117 +1,147 @@
|
||||
'use client'
|
||||
"use client";
|
||||
|
||||
import Image from 'next/image'
|
||||
import { useState } from 'react'
|
||||
import { apiFetch } from '@/lib/api'
|
||||
import PublicShell from '@/components/layout/PublicShell'
|
||||
import { useDashboardI18n } from '@/components/I18nProvider'
|
||||
import { marketplaceUrl } from '@/lib/urls'
|
||||
import Image from "next/image";
|
||||
import { useState } from "react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { apiFetch } from "@/lib/api";
|
||||
import PublicShell from "@/components/layout/PublicShell";
|
||||
import { useDashboardI18n } from "@/components/I18nProvider";
|
||||
import { marketplaceUrl } from "@/lib/urls";
|
||||
|
||||
export default function SignUpForm() {
|
||||
const { language, setLanguage } = useDashboardI18n()
|
||||
const { language, setLanguage } = useDashboardI18n();
|
||||
const searchParams = useSearchParams();
|
||||
const requestedLanguage = searchParams.get("lang");
|
||||
const initialLanguage =
|
||||
requestedLanguage === "en" ||
|
||||
requestedLanguage === "fr" ||
|
||||
requestedLanguage === "ar"
|
||||
? requestedLanguage
|
||||
: language;
|
||||
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [showPassword, setShowPassword] = useState(false)
|
||||
const [preferredLanguage, setPreferredLanguage] = useState<'en' | 'fr' | 'ar'>(language)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [success, setSuccess] = useState(false)
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [preferredLanguage, setPreferredLanguage] = useState<
|
||||
"en" | "fr" | "ar"
|
||||
>(initialLanguage);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [success, setSuccess] = useState(false);
|
||||
|
||||
const dict = {
|
||||
en: {
|
||||
title: 'Create your workspace',
|
||||
subtitle: 'Enter your email and password to get started.',
|
||||
email: 'Email',
|
||||
emailPlaceholder: 'you@company.com',
|
||||
password: 'Password',
|
||||
passwordPlaceholder: '\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022',
|
||||
passwordHint: 'Minimum 8 characters',
|
||||
languageLabel: 'Preferred language',
|
||||
create: 'Create workspace',
|
||||
creating: 'Creating\u2026',
|
||||
alreadyHave: 'Already have an account?',
|
||||
signIn: 'Sign in',
|
||||
errorEmailTaken: 'An account with this email already exists.',
|
||||
errorGeneric: 'Something went wrong. Please try again.',
|
||||
successTitle: 'Check your email',
|
||||
successMessage: 'We sent a verification link to {email}. Click the link to activate your account, then sign in.',
|
||||
successSignIn: 'Go to sign in',
|
||||
title: "Create your workspace",
|
||||
subtitle: "Enter your email and password to get started.",
|
||||
email: "Email",
|
||||
emailPlaceholder: "you@company.com",
|
||||
password: "Password",
|
||||
passwordPlaceholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
||||
passwordHint: "Minimum 8 characters",
|
||||
languageLabel: "Preferred language",
|
||||
create: "Create workspace",
|
||||
creating: "Creating\u2026",
|
||||
alreadyHave: "Already have an account?",
|
||||
signIn: "Sign in",
|
||||
errorEmailTaken: "An account with this email already exists.",
|
||||
errorGeneric: "Something went wrong. Please try again.",
|
||||
successTitle: "Check your email",
|
||||
successMessage:
|
||||
"We sent a verification link to {email}. Click the link to activate your account, then sign in.",
|
||||
successSignIn: "Go to sign in",
|
||||
},
|
||||
fr: {
|
||||
title: 'Cr\u00e9ez votre espace',
|
||||
subtitle: 'Saisissez votre email et mot de passe pour commencer.',
|
||||
email: 'Email',
|
||||
emailPlaceholder: 'vous@entreprise.com',
|
||||
password: 'Mot de passe',
|
||||
passwordPlaceholder: '\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022',
|
||||
passwordHint: 'Minimum 8 caract\u00e8res',
|
||||
languageLabel: 'Langue pr\u00e9f\u00e9r\u00e9e',
|
||||
create: 'Cr\u00e9er mon espace',
|
||||
creating: 'Cr\u00e9ation\u2026',
|
||||
alreadyHave: 'Vous avez d\u00e9j\u00e0 un compte ?',
|
||||
signIn: 'Se connecter',
|
||||
errorEmailTaken: 'Un compte avec cet email existe d\u00e9j\u00e0.',
|
||||
errorGeneric: 'Une erreur est survenue. Veuillez r\u00e9essayer.',
|
||||
successTitle: 'V\u00e9rifiez votre email',
|
||||
successMessage: 'Nous avons envoy\u00e9 un lien de v\u00e9rification \u00e0 {email}. Cliquez sur le lien pour activer votre compte, puis connectez-vous.',
|
||||
successSignIn: 'Aller \u00e0 la connexion',
|
||||
title: "Cr\u00e9ez votre espace",
|
||||
subtitle: "Saisissez votre email et mot de passe pour commencer.",
|
||||
email: "Email",
|
||||
emailPlaceholder: "vous@entreprise.com",
|
||||
password: "Mot de passe",
|
||||
passwordPlaceholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
||||
passwordHint: "Minimum 8 caract\u00e8res",
|
||||
languageLabel: "Langue pr\u00e9f\u00e9r\u00e9e",
|
||||
create: "Cr\u00e9er mon espace",
|
||||
creating: "Cr\u00e9ation\u2026",
|
||||
alreadyHave: "Vous avez d\u00e9j\u00e0 un compte ?",
|
||||
signIn: "Se connecter",
|
||||
errorEmailTaken: "Un compte avec cet email existe d\u00e9j\u00e0.",
|
||||
errorGeneric: "Une erreur est survenue. Veuillez r\u00e9essayer.",
|
||||
successTitle: "V\u00e9rifiez votre email",
|
||||
successMessage:
|
||||
"Nous avons envoy\u00e9 un lien de v\u00e9rification \u00e0 {email}. Cliquez sur le lien pour activer votre compte, puis connectez-vous.",
|
||||
successSignIn: "Aller \u00e0 la connexion",
|
||||
},
|
||||
ar: {
|
||||
title: '\u0623\u0646\u0634\u0626 \u0645\u0633\u0627\u062d\u0629 \u0639\u0645\u0644\u0643',
|
||||
subtitle: '\u0623\u062f\u062e\u0644 \u0628\u0631\u064a\u062f\u0643 \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a \u0648\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0644\u0644\u0628\u062f\u0621.',
|
||||
email: '\u0627\u0644\u0628\u0631\u064a\u062f \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a',
|
||||
emailPlaceholder: 'you@company.com',
|
||||
password: '\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631',
|
||||
passwordPlaceholder: '\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022',
|
||||
passwordHint: '\u0627\u0644\u062d\u062f \u0627\u0644\u0623\u062f\u0646\u0649 8 \u0623\u062d\u0631\u0641',
|
||||
languageLabel: '\u0627\u0644\u0644\u063a\u0629 \u0627\u0644\u0645\u0641\u0636\u0644\u0629',
|
||||
create: '\u0623\u0646\u0634\u0626 \u0627\u0644\u0645\u0633\u0627\u062d\u0629',
|
||||
creating: '\u062c\u0627\u0631\u064d \u0627\u0644\u0625\u0646\u0634\u0627\u0621\u2026',
|
||||
alreadyHave: '\u0647\u0644 \u0644\u062f\u064a\u0643 \u062d\u0633\u0627\u0628 \u0628\u0627\u0644\u0641\u0639\u0644\u061f',
|
||||
signIn: '\u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644',
|
||||
errorEmailTaken: '\u064a\u0648\u062c\u062f \u062d\u0633\u0627\u0628 \u0628\u0647\u0630\u0627 \u0627\u0644\u0628\u0631\u064a\u062f \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a \u0628\u0627\u0644\u0641\u0639\u0644.',
|
||||
errorGeneric: '\u062d\u062f\u062b \u062e\u0637\u0623 \u0645\u0627. \u064a\u0631\u062c\u0649 \u0627\u0644\u0645\u062d\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062e\u0631\u0649.',
|
||||
successTitle: '\u062a\u062d\u0642\u0642 \u0645\u0646 \u0628\u0631\u064a\u062f\u0643 \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a',
|
||||
successMessage: '\u0623\u0631\u0633\u0644\u0646\u0627 \u0631\u0627\u0628\u0637 \u062a\u062d\u0642\u0642 \u0625\u0644\u0649 {email}. \u0627\u0646\u0642\u0631 \u0639\u0644\u0649 \u0627\u0644\u0631\u0627\u0628\u0637 \u0644\u062a\u0641\u0639\u064a\u0644 \u062d\u0633\u0627\u0628\u0643\u060c \u062b\u0645 \u0642\u0645 \u0628\u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644.',
|
||||
successSignIn: '\u0627\u0644\u0630\u0647\u0627\u0628 \u0625\u0644\u0649 \u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644',
|
||||
title:
|
||||
"\u0623\u0646\u0634\u0626 \u0645\u0633\u0627\u062d\u0629 \u0639\u0645\u0644\u0643",
|
||||
subtitle:
|
||||
"\u0623\u062f\u062e\u0644 \u0628\u0631\u064a\u062f\u0643 \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a \u0648\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631 \u0644\u0644\u0628\u062f\u0621.",
|
||||
email:
|
||||
"\u0627\u0644\u0628\u0631\u064a\u062f \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a",
|
||||
emailPlaceholder: "you@company.com",
|
||||
password: "\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631",
|
||||
passwordPlaceholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
||||
passwordHint:
|
||||
"\u0627\u0644\u062d\u062f \u0627\u0644\u0623\u062f\u0646\u0649 8 \u0623\u062d\u0631\u0641",
|
||||
languageLabel:
|
||||
"\u0627\u0644\u0644\u063a\u0629 \u0627\u0644\u0645\u0641\u0636\u0644\u0629",
|
||||
create:
|
||||
"\u0623\u0646\u0634\u0626 \u0627\u0644\u0645\u0633\u0627\u062d\u0629",
|
||||
creating:
|
||||
"\u062c\u0627\u0631\u064d \u0627\u0644\u0625\u0646\u0634\u0627\u0621\u2026",
|
||||
alreadyHave:
|
||||
"\u0647\u0644 \u0644\u062f\u064a\u0643 \u062d\u0633\u0627\u0628 \u0628\u0627\u0644\u0641\u0639\u0644\u061f",
|
||||
signIn:
|
||||
"\u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644",
|
||||
errorEmailTaken:
|
||||
"\u064a\u0648\u062c\u062f \u062d\u0633\u0627\u0628 \u0628\u0647\u0630\u0627 \u0627\u0644\u0628\u0631\u064a\u062f \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a \u0628\u0627\u0644\u0641\u0639\u0644.",
|
||||
errorGeneric:
|
||||
"\u062d\u062f\u062b \u062e\u0637\u0623 \u0645\u0627. \u064a\u0631\u062c\u0649 \u0627\u0644\u0645\u062d\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062e\u0631\u0649.",
|
||||
successTitle:
|
||||
"\u062a\u062d\u0642\u0642 \u0645\u0646 \u0628\u0631\u064a\u062f\u0643 \u0627\u0644\u0625\u0644\u0643\u062a\u0631\u0648\u0646\u064a",
|
||||
successMessage:
|
||||
"\u0623\u0631\u0633\u0644\u0646\u0627 \u0631\u0627\u0628\u0637 \u062a\u062d\u0642\u0642 \u0625\u0644\u0649 {email}. \u0627\u0646\u0642\u0631 \u0639\u0644\u0649 \u0627\u0644\u0631\u0627\u0628\u0637 \u0644\u062a\u0641\u0639\u064a\u0644 \u062d\u0633\u0627\u0628\u0643\u060c \u062b\u0645 \u0642\u0645 \u0628\u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644.",
|
||||
successSignIn:
|
||||
"\u0627\u0644\u0630\u0647\u0627\u0628 \u0625\u0644\u0649 \u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644",
|
||||
},
|
||||
}[preferredLanguage]
|
||||
}[preferredLanguage];
|
||||
|
||||
async function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault()
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
await apiFetch('/auth/account/start', {
|
||||
method: 'POST',
|
||||
await apiFetch("/auth/account/start", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ email, password, preferredLanguage }),
|
||||
})
|
||||
});
|
||||
|
||||
setLanguage(preferredLanguage)
|
||||
document.cookie = `rentaldrivego-language=${preferredLanguage}; path=/; max-age=31536000; samesite=lax`
|
||||
setSuccess(true)
|
||||
setLanguage(preferredLanguage);
|
||||
document.cookie = `rentaldrivego-language=${preferredLanguage}; path=/; max-age=31536000; samesite=lax`;
|
||||
setSuccess(true);
|
||||
} catch (err: any) {
|
||||
if (err?.message?.includes('email_taken') || err?.code === 'email_taken') {
|
||||
setError(dict.errorEmailTaken)
|
||||
if (
|
||||
err?.message?.includes("email_taken") ||
|
||||
err?.code === "email_taken"
|
||||
) {
|
||||
setError(dict.errorEmailTaken);
|
||||
} else {
|
||||
setError(dict.errorGeneric)
|
||||
setError(dict.errorGeneric);
|
||||
}
|
||||
} finally {
|
||||
setLoading(false)
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
return (
|
||||
<PublicShell>
|
||||
<PublicShell hideHeaderActions>
|
||||
<main className="flex flex-1 items-center justify-center px-4 py-16">
|
||||
<div className="w-full max-w-md text-center">
|
||||
<div className="flex justify-center mb-6">
|
||||
<Image
|
||||
src="/dashboard/rentalcardrive.png"
|
||||
alt="FleetOS"
|
||||
alt="RentalDriveGo"
|
||||
width={80}
|
||||
height={80}
|
||||
priority
|
||||
@@ -123,7 +153,7 @@ export default function SignUpForm() {
|
||||
{dict.successTitle}
|
||||
</h1>
|
||||
<p className="mt-4 text-sm leading-7 text-stone-600 dark:text-stone-300">
|
||||
{dict.successMessage.replace('{email}', email)}
|
||||
{dict.successMessage.replace("{email}", email)}
|
||||
</p>
|
||||
<a
|
||||
href="/sign-in"
|
||||
@@ -135,11 +165,11 @@ export default function SignUpForm() {
|
||||
</div>
|
||||
</main>
|
||||
</PublicShell>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<PublicShell>
|
||||
<PublicShell hideHeaderActions>
|
||||
<main className="flex flex-1 items-center justify-center px-4 py-16">
|
||||
<div className="w-full max-w-md">
|
||||
<div className="mb-8 text-center">
|
||||
@@ -147,7 +177,7 @@ export default function SignUpForm() {
|
||||
<a href={marketplaceUrl} target="_top">
|
||||
<Image
|
||||
src="/dashboard/rentalcardrive.png"
|
||||
alt="FleetOS"
|
||||
alt="RentalDriveGo"
|
||||
width={80}
|
||||
height={80}
|
||||
priority
|
||||
@@ -191,34 +221,64 @@ export default function SignUpForm() {
|
||||
{dict.password} <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
required
|
||||
minLength={8}
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
placeholder={'\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022'}
|
||||
className="w-full rounded-2xl border border-stone-200 bg-white px-4 py-3 pr-10 text-sm text-stone-900 transition-colors placeholder:text-stone-400 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-orange-500 dark:border-blue-800 dark:bg-blue-950/80 dark:text-stone-100 dark:placeholder:text-stone-500"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowPassword((v) => !v)}
|
||||
className="absolute inset-y-0 right-3 flex items-center text-stone-400 hover:text-stone-700 dark:text-stone-500 dark:hover:text-stone-200"
|
||||
tabIndex={-1}
|
||||
>
|
||||
{showPassword ? (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
<input
|
||||
type={showPassword ? "text" : "password"}
|
||||
required
|
||||
minLength={8}
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
placeholder={
|
||||
"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"
|
||||
}
|
||||
className="w-full rounded-2xl border border-stone-200 bg-white px-4 py-3 pr-10 text-sm text-stone-900 transition-colors placeholder:text-stone-400 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-orange-500 dark:border-blue-800 dark:bg-blue-950/80 dark:text-stone-100 dark:placeholder:text-stone-500"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowPassword((v) => !v)}
|
||||
className="absolute inset-y-0 right-3 flex items-center text-stone-400 hover:text-stone-700 dark:text-stone-500 dark:hover:text-stone-200"
|
||||
tabIndex={-1}
|
||||
>
|
||||
{showPassword ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"
|
||||
/>
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<p className="mt-1 text-xs text-stone-400 dark:text-stone-500">{dict.passwordHint}</p>
|
||||
<p className="mt-1 text-xs text-stone-400 dark:text-stone-500">
|
||||
{dict.passwordHint}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -226,18 +286,22 @@ export default function SignUpForm() {
|
||||
{dict.languageLabel} <span className="text-red-500">*</span>
|
||||
</span>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
{(['en', 'fr', 'ar'] as const).map((lang) => (
|
||||
{(["en", "fr", "ar"] as const).map((lang) => (
|
||||
<button
|
||||
key={lang}
|
||||
type="button"
|
||||
onClick={() => setPreferredLanguage(lang)}
|
||||
className={`rounded-2xl border py-3 text-sm font-semibold transition ${
|
||||
preferredLanguage === lang
|
||||
? 'border-blue-900 bg-blue-900 text-white dark:bg-orange-500 dark:border-orange-400'
|
||||
: 'border-stone-200 bg-white text-stone-600 hover:border-stone-300 hover:bg-stone-50 dark:border-blue-800 dark:bg-blue-950/50 dark:text-stone-300 dark:hover:border-blue-600'
|
||||
? "border-blue-900 bg-blue-900 text-white dark:bg-orange-500 dark:border-orange-400"
|
||||
: "border-stone-200 bg-white text-stone-600 hover:border-stone-300 hover:bg-stone-50 dark:border-blue-800 dark:bg-blue-950/50 dark:text-stone-300 dark:hover:border-blue-600"
|
||||
}`}
|
||||
>
|
||||
{lang === 'en' ? 'English' : lang === 'fr' ? 'Fran\u00e7ais' : '\u0627\u0644\u0639\u0631\u0628\u064a\u0629'}
|
||||
{lang === "en"
|
||||
? "English"
|
||||
: lang === "fr"
|
||||
? "Fran\u00e7ais"
|
||||
: "\u0627\u0644\u0639\u0631\u0628\u064a\u0629"}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
@@ -253,7 +317,7 @@ export default function SignUpForm() {
|
||||
</form>
|
||||
|
||||
<p className="mt-6 text-center text-sm text-stone-500 dark:text-stone-400">
|
||||
{dict.alreadyHave}{' '}
|
||||
{dict.alreadyHave}{" "}
|
||||
<a
|
||||
href="/sign-in"
|
||||
className="font-semibold text-orange-700 hover:text-orange-800 dark:text-orange-300 dark:hover:text-orange-200"
|
||||
@@ -265,5 +329,5 @@ export default function SignUpForm() {
|
||||
</div>
|
||||
</main>
|
||||
</PublicShell>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user