Basic error validation in the form
This commit is contained in:
parent
d085a2ab19
commit
4d576b07da
@ -1,7 +1,7 @@
|
|||||||
/* Copyright (C) 2024 Manuel Bustillo*/
|
/* Copyright (C) 2024 Manuel Bustillo*/
|
||||||
|
|
||||||
import { getCsrfToken, getSlug } from '@/app/lib/utils';
|
import { asArray, getCsrfToken, getSlug } from '@/app/lib/utils';
|
||||||
import { Captcha, User } from '@/app/lib/definitions';
|
import { Captcha, StructuredErrors, User } from '@/app/lib/definitions';
|
||||||
|
|
||||||
export function login({ email, password, onLogin }: { email: string, password: string, onLogin: (user: User) => void }) {
|
export function login({ email, password, onLogin }: { email: string, password: string, onLogin: (user: User) => void }) {
|
||||||
return fetch(`/api/${getSlug()}/users/sign_in`, {
|
return fetch(`/api/${getSlug()}/users/sign_in`, {
|
||||||
@ -34,13 +34,23 @@ export function logout({ onLogout }: { onLogout: () => void }) {
|
|||||||
.catch((error) => console.error(error));
|
.catch((error) => console.error(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function register({slug, email, password, passwordConfirmation, captcha, onRegister}: {
|
function flattenErrors(errors: StructuredErrors): string[] {
|
||||||
|
if(errors instanceof Array) {
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
return Object.keys(errors).map((key) => {
|
||||||
|
return `${key}: ${asArray(errors[key]).join(', ')}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function register({slug, email, password, passwordConfirmation, captcha, onRegister, onError}: {
|
||||||
slug: string,
|
slug: string,
|
||||||
email: string,
|
email: string,
|
||||||
password: string,
|
password: string,
|
||||||
passwordConfirmation: string,
|
passwordConfirmation: string,
|
||||||
captcha: Captcha,
|
captcha: Captcha,
|
||||||
onRegister: () => void
|
onRegister: () => void,
|
||||||
|
onError: (errors: string[]) => void
|
||||||
}){
|
}){
|
||||||
fetch(`/api/${slug}/users`, {
|
fetch(`/api/${slug}/users`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -55,6 +65,13 @@ export function register({slug, email, password, passwordConfirmation, captcha,
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'X-CSRF-TOKEN': getCsrfToken(),
|
'X-CSRF-TOKEN': getCsrfToken(),
|
||||||
}
|
}
|
||||||
}).then(onRegister)
|
}).then((response) => {
|
||||||
.catch((error) => console.error(error));
|
if(response.ok) {
|
||||||
|
response.json().then(onRegister);
|
||||||
|
} else {
|
||||||
|
response.json().then((data: any) => {
|
||||||
|
onError(data.errors && flattenErrors(data.errors) || [data.error]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -69,4 +69,8 @@ export type User = {
|
|||||||
export type Captcha = {
|
export type Captcha = {
|
||||||
id: string;
|
id: string;
|
||||||
answer: string;
|
answer: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type StructuredErrors = {
|
||||||
|
[key: string]: string[]|string;
|
||||||
|
};
|
@ -13,3 +13,8 @@ export const getSlug = () => localStorage.getItem('slug') || 'default';
|
|||||||
export const capitalize = (val:string) => {
|
export const capitalize = (val:string) => {
|
||||||
return String(val).charAt(0).toUpperCase() + String(val).slice(1);
|
return String(val).charAt(0).toUpperCase() + String(val).slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From https://stackoverflow.com/a/62118163/3607039
|
||||||
|
export function asArray<T>(value: T | T[]): T[] {
|
||||||
|
return ([] as T[]).concat(value)
|
||||||
|
}
|
@ -11,6 +11,8 @@ import { register } from '@/app/api/authentication';
|
|||||||
import { getCaptchaChallenge } from '@/app/api/captcha';
|
import { getCaptchaChallenge } from '@/app/api/captcha';
|
||||||
|
|
||||||
export default function RegistrationForm() {
|
export default function RegistrationForm() {
|
||||||
|
const [errors, setErrors] = useState<string[]>([]);
|
||||||
|
|
||||||
const [email, setEmail] = useState<string>("");
|
const [email, setEmail] = useState<string>("");
|
||||||
const [password, setPassword] = useState<string>("");
|
const [password, setPassword] = useState<string>("");
|
||||||
const [passwordConfirmation, setPasswordConfirmation] = useState<string>("");
|
const [passwordConfirmation, setPasswordConfirmation] = useState<string>("");
|
||||||
@ -26,6 +28,7 @@ export default function RegistrationForm() {
|
|||||||
console.log(id, url);
|
console.log(id, url);
|
||||||
setCaptchaId(id);
|
setCaptchaId(id);
|
||||||
setCaptchaUrl(url);
|
setCaptchaUrl(url);
|
||||||
|
setCaptchaAnswer("");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -52,10 +55,14 @@ export default function RegistrationForm() {
|
|||||||
</FloatLabel>
|
</FloatLabel>
|
||||||
<img className="w-96" src={captchaUrl} alt="captcha" />
|
<img className="w-96" src={captchaUrl} alt="captcha" />
|
||||||
<FloatLabel className="my-4">
|
<FloatLabel className="my-4">
|
||||||
<InputText id="captcha" type="text" className='rounded-sm' onChange={(e) => setCaptchaAnswer(e.target.value)} />
|
<InputText id="captcha" type="text" className='rounded-sm' value={captchaAnswer} onChange={(e) => setCaptchaAnswer(e.target.value)} />
|
||||||
<label htmlFor="captcha">Captcha</label>
|
<label htmlFor="captcha">Captcha</label>
|
||||||
</FloatLabel>
|
</FloatLabel>
|
||||||
|
|
||||||
|
{errors.map((error, index) => (
|
||||||
|
<div key={index} className="text-red-500">{error}</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
className={classNames('primary')}
|
className={classNames('primary')}
|
||||||
@ -70,7 +77,8 @@ export default function RegistrationForm() {
|
|||||||
id: captchaId,
|
id: captchaId,
|
||||||
answer: captchaAnswer
|
answer: captchaAnswer
|
||||||
},
|
},
|
||||||
onRegister: () => { console.log("registered") }
|
onRegister: () => { setErrors([]) },
|
||||||
|
onError: (errors) => { refreshCaptcha(); setErrors(errors) }
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user