checkout: buttons verbessert, paddle zahlungsschritt schicker gemacht, schritt 4 optimiert+schick gemacht. Dashboard: translations ergänzt. Startseite vom Event Admin optimiert.
This commit is contained in:
@@ -50,6 +50,7 @@ export default function LoginForm({ onSuccess, canResetPassword = true, locale }
|
||||
const [errors, setErrors] = useState<FieldErrors>({});
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [hasTriedSubmit, setHasTriedSubmit] = useState(false);
|
||||
const [shouldFocusError, setShouldFocusError] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasTriedSubmit) {
|
||||
@@ -63,7 +64,7 @@ export default function LoginForm({ onSuccess, canResetPassword = true, locale }
|
||||
}, [errors, hasTriedSubmit]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasTriedSubmit) {
|
||||
if (!hasTriedSubmit || !shouldFocusError) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,11 +76,13 @@ export default function LoginForm({ onSuccess, canResetPassword = true, locale }
|
||||
const field = document.querySelector<HTMLInputElement>(`[name="${firstKey}"]`);
|
||||
field?.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||
field?.focus();
|
||||
}, [errors, hasTriedSubmit]);
|
||||
setShouldFocusError(false);
|
||||
}, [errors, hasTriedSubmit, shouldFocusError]);
|
||||
|
||||
const updateValue = (key: keyof typeof values, value: string | boolean) => {
|
||||
setValues((current) => ({ ...current, [key]: value }));
|
||||
setErrors((current) => ({ ...current, [key as string]: "" }));
|
||||
setShouldFocusError(false);
|
||||
};
|
||||
|
||||
const submit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
@@ -129,11 +132,13 @@ export default function LoginForm({ onSuccess, canResetPassword = true, locale }
|
||||
});
|
||||
|
||||
setErrors(fieldErrors);
|
||||
setShouldFocusError(true);
|
||||
toast.error(t("login.failed_generic", "Ungueltige Anmeldedaten"));
|
||||
return;
|
||||
}
|
||||
|
||||
toast.error(t("login.unexpected_error", "Beim Login ist ein Fehler aufgetreten."));
|
||||
setShouldFocusError(false);
|
||||
} catch (error) {
|
||||
console.error("Login request failed", error);
|
||||
toast.error(t("login.unexpected_error", "Beim Login ist ein Fehler aufgetreten."));
|
||||
@@ -205,4 +210,3 @@ export default function LoginForm({ onSuccess, canResetPassword = true, locale }
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -390,7 +390,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
|
||||
<div className="md:col-span-1">
|
||||
<label htmlFor="password_confirmation" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
{t('register.confirm_password')} {t('common:required')}
|
||||
{t('register.password_confirmation')} {t('common:required')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<Lock className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||
@@ -410,7 +410,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
}
|
||||
}}
|
||||
className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.password_confirmation ? 'border-red-500' : 'border-gray-300'}`}
|
||||
placeholder={t('register.confirm_password_placeholder')}
|
||||
placeholder={t('register.password_confirmation_placeholder')}
|
||||
/>
|
||||
</div>
|
||||
{errors.password_confirmation && <p className="text-sm text-red-600 mt-1">{errors.password_confirmation}</p>}
|
||||
@@ -442,7 +442,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
onClick={() => setPrivacyOpen(true)}
|
||||
className="text-[#FFB6C1] hover:underline inline bg-transparent border-none cursor-pointer p-0 font-medium"
|
||||
>
|
||||
{t('register.privacy_policy')}
|
||||
{t('register.privacy_policy_link')}
|
||||
</button>.
|
||||
</label>
|
||||
{errors.privacy_consent && <p className="mt-2 text-sm text-red-600">{errors.privacy_consent}</p>}
|
||||
@@ -485,5 +485,3 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -265,7 +265,7 @@ export default function Register({ package: initialPackage, privacyHtml }: Regis
|
||||
|
||||
<div className="md:col-span-1">
|
||||
<label htmlFor="password_confirmation" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
{t('register.confirm_password')} {t('common:required')}
|
||||
{t('register.password_confirmation')} {t('common:required')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<Lock className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||
@@ -285,7 +285,7 @@ export default function Register({ package: initialPackage, privacyHtml }: Regis
|
||||
}
|
||||
}}
|
||||
className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.password_confirmation ? 'border-red-500' : 'border-gray-300'}`}
|
||||
placeholder={t('register.confirm_password_placeholder')}
|
||||
placeholder={t('register.password_confirmation_placeholder')}
|
||||
/>
|
||||
</div>
|
||||
{errors.password_confirmation && <p key={`error-password_confirmation`} className="text-sm text-red-600 mt-1">{errors.password_confirmation}</p>}
|
||||
@@ -313,7 +313,7 @@ export default function Register({ package: initialPackage, privacyHtml }: Regis
|
||||
onClick={() => setPrivacyOpen(true)}
|
||||
className="text-[#FFB6C1] hover:underline inline bg-transparent border-none cursor-pointer p-0 font-medium"
|
||||
>
|
||||
{t('register.privacy_policy')}
|
||||
{t('register.privacy_policy_link')}
|
||||
</button>.
|
||||
</label>
|
||||
{errors.privacy_consent && <p className="mt-2 text-sm text-red-600">{errors.privacy_consent}</p>}
|
||||
|
||||
Reference in New Issue
Block a user