Skip to content

Commit 7236a33

Browse files
author
markusvannorlen
committed
added registration
1 parent e893913 commit 7236a33

File tree

12 files changed

+415
-149
lines changed

12 files changed

+415
-149
lines changed

src/assets/js/pages/add-user.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ export default function AddUser() {
153153
tabIndex={1}
154154
autoComplete={getField('email')?.name}
155155
value={data.email as string}
156-
onChange={(e) => handleChangeDate('field', e.target.value)}
156+
onChange={(e) => handleChangeDate('email', e.target.value)}
157157
disabled={processing || page.props.view}
158158
placeholder={getField('email')?.label}
159159
/>
@@ -280,7 +280,7 @@ export default function AddUser() {
280280
{page.props.groups.length > 0 && (
281281
<>
282282
<h2 className="font-bold text-xl">{page.props.groupHead}</h2>
283-
<div className="flex flex-col">
283+
<div className="grid grid-cols-1 md:grid-cols-5 xl:grid-cols-6 gap-4">
284284
{page.props.groups.map(group => (
285285
<div className="grid gap-4" key={group.name}>
286286
<Label className="cursor-pointer"

src/assets/js/pages/list.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export default function List() {
138138
<Toaster position="top-center" richColors closeButton />
139139
<div className="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">
140140
<div className="flex gap-6">
141-
{page.props.header.crudActions?.viewsTitle && (
141+
{page.props.header.crudActions?.createTitle && (
142142
<Button className="mb-3" asChild>
143143
<Link href={`${page.props.header.entity.uri}/add`}>
144144
<Icon iconNode={SquarePlus}/>

src/assets/js/pages/login.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ interface LoginProps extends SharedData {
2424
captchaTask: number[]
2525
}
2626

27-
export default function Dashboard() {
27+
export default function Lodin() {
2828
const [captchaProcessing, setCaptchaProcessing] = useState(false);
2929

3030
const page = usePage<LoginProps>()
@@ -84,7 +84,7 @@ export default function Dashboard() {
8484

8585
}
8686

87-
const handleChangeDate = (fieldName: 'login' | 'password', value: string) => {
87+
const handleChangeDate = (fieldName: keyof typeof data, value: string) => {
8888
clearErrors()
8989
setData(fieldName, value);
9090
}

src/assets/js/pages/register.tsx

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import {Link, useForm, usePage} from "@inertiajs/react";
2+
import {SharedData} from "@/types";
3+
import {FormEventHandler} from "react";
4+
import {Label} from "@/components/ui/label.tsx";
5+
import {Input} from "@/components/ui/input.tsx";
6+
import InputError from "@/components/input-error.tsx";
7+
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from "@/components/ui/select.tsx";
8+
import {Button} from "@/components/ui/button.tsx";
9+
import {toast} from "sonner";
10+
import {Toaster} from "@/components/ui/sonner.tsx";
11+
12+
interface RegisterProps extends SharedData {
13+
header: {
14+
title: string
15+
desc: string
16+
}
17+
submitLink: string
18+
loginLabel: string
19+
fullNameLabel: string
20+
passwordLabel: string
21+
confirmPasswordLabel: string
22+
confirmError: string
23+
emailLabel: string
24+
localeLabel: string
25+
submitButton: string
26+
backToLogin: {
27+
link: string
28+
text: string
29+
}
30+
}
31+
32+
export default function Register() {
33+
const page = usePage<RegisterProps>();
34+
const {post, data, setData, processing, setError, errors, clearErrors} = useForm({
35+
locale: 'en',
36+
email: '',
37+
confirmPassword: '',
38+
password: '',
39+
fullName: '',
40+
login: '',
41+
})
42+
43+
const submit: FormEventHandler = (e) => {
44+
e.preventDefault()
45+
if (data.password !== data.confirmPassword) {
46+
setError('confirmPassword', page.props.confirmError)
47+
return
48+
}
49+
post(page.props.submitLink, {
50+
onSuccess: () => {
51+
},
52+
onError: (errors) => {
53+
for (const key of Object.keys(errors)) {
54+
toast.error(errors[key])
55+
}
56+
}
57+
})
58+
}
59+
60+
const handleChangeDate = (fieldName: keyof typeof data, value: string) => {
61+
clearErrors()
62+
setData(fieldName, value);
63+
}
64+
65+
return (
66+
<div className="bg-sidebar flex min-h-svh w-full justify-center items-center">
67+
<Toaster position="top-center" richColors closeButton/>
68+
<div className="rounded-xl border bg-card text-card-foreground shadow p-6 max-w-sm w-full h-fit">
69+
<h1 className="font-medium mb-2 text-xl">{page.props.header.title}</h1>
70+
<p className="text-muted-foreground text-sm">{page.props.header.desc}</p>
71+
<form onSubmit={submit} className="mt-6">
72+
<div className="grid gap-5">
73+
<div className="grid gap-4">
74+
<Label htmlFor="login">{page.props.loginLabel}<span
75+
className="text-red-500">*</span></Label>
76+
<div className="relative">
77+
<Input
78+
id="login"
79+
className={`${errors.login ? 'border-red-500' : ''}`}
80+
type="text"
81+
required
82+
tabIndex={1}
83+
autoComplete="login"
84+
value={data.login}
85+
disabled={processing}
86+
onChange={(e) => {
87+
handleChangeDate('login', e.target.value)
88+
}}
89+
placeholder={page.props.loginLabel}
90+
/>
91+
<InputError message={errors.login}/>
92+
</div>
93+
</div>
94+
<div className="grid gap-4">
95+
<Label htmlFor="fullName">{page.props.fullNameLabel}<span
96+
className="text-red-500">*</span></Label>
97+
<div className="relative">
98+
<Input
99+
id="fullName"
100+
className={`${errors.fullName ? 'border-red-500' : ''}`}
101+
type="text"
102+
required
103+
tabIndex={1}
104+
autoComplete="fullName"
105+
value={data.fullName}
106+
disabled={processing}
107+
onChange={(e) => {
108+
handleChangeDate('fullName', e.target.value)
109+
}}
110+
placeholder={page.props.fullNameLabel}
111+
/>
112+
<InputError message={errors.fullName}/>
113+
</div>
114+
</div>
115+
<div className="grid gap-4">
116+
<Label htmlFor="password">{page.props.passwordLabel}<span
117+
className="text-red-500">*</span></Label>
118+
<div className="relative">
119+
<Input
120+
id="password"
121+
className={`${errors.password ? 'border-red-500' : ''}`}
122+
type="password"
123+
required
124+
tabIndex={1}
125+
autoComplete="password"
126+
value={data.password}
127+
disabled={processing}
128+
onChange={(e) => {
129+
handleChangeDate('password', e.target.value)
130+
}}
131+
placeholder={page.props.fullNameLabel}
132+
/>
133+
<InputError message={errors.password}/>
134+
</div>
135+
</div>
136+
<div className="grid gap-4">
137+
<Label htmlFor="confirmPassword">{page.props.confirmPasswordLabel}<span
138+
className="text-red-500">*</span></Label>
139+
<div className="relative">
140+
<Input
141+
id="confirmPassword"
142+
className={`${errors.confirmPassword ? 'border-red-500' : ''}`}
143+
type="password"
144+
required
145+
tabIndex={1}
146+
autoComplete="confirmPassword"
147+
value={data.confirmPassword}
148+
disabled={processing}
149+
onChange={(e) => {
150+
handleChangeDate('confirmPassword', e.target.value)
151+
}}
152+
placeholder={page.props.confirmPasswordLabel}
153+
/>
154+
<InputError message={errors.confirmPassword}/>
155+
</div>
156+
</div>
157+
<div className="grid gap-4">
158+
<Label htmlFor="email">{page.props.emailLabel}<span
159+
className="text-red-500">*</span></Label>
160+
<div className="relative">
161+
<Input
162+
id="email"
163+
className={`${errors.email ? 'border-red-500' : ''}`}
164+
type="email"
165+
required
166+
tabIndex={1}
167+
autoComplete="email"
168+
value={data.email}
169+
disabled={processing}
170+
onChange={(e) => {
171+
handleChangeDate('email', e.target.value)
172+
}}
173+
placeholder={page.props.emailLabel}
174+
/>
175+
<InputError message={errors.email}/>
176+
</div>
177+
</div>
178+
<div className="grid gap-4">
179+
<Label htmlFor="locale">{page.props.localeLabel}</Label>
180+
<Select onValueChange={(value) => handleChangeDate('locale', value)}
181+
defaultValue="en" disabled={processing}>
182+
<SelectTrigger className="w-full cursor-pointer">
183+
<SelectValue placeholder={page.props.localeLabel}/>
184+
</SelectTrigger>
185+
<SelectContent>
186+
<SelectItem value="en">EN</SelectItem>
187+
</SelectContent>
188+
</Select>
189+
</div>
190+
<div className="flex gap-4">
191+
<Button type="submit" className="w-fit"
192+
disabled={processing}>{page.props.submitButton}</Button>
193+
<Button asChild variant="outline">
194+
<Link href={page.props.backToLogin.link}
195+
className={`${processing} ? 'pointer-events-none opacity-50' : ''`}>{page.props.backToLogin.text}</Link>
196+
</Button>
197+
</div>
198+
</div>
199+
</form>
200+
</div>
201+
</div>
202+
)
203+
}

src/controllers/list.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export default async function list(req: ReqType, res: ResType) {
3636
};
3737

3838
const nodeTable = new NodeTable(mockRequestBody, entity.model, fields);
39-
4039
await nodeTable.output((err: Error, data: NodeOutput) => {
4140
if (err) {
4241
Adminizer.log.error(err);

src/controllers/login.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,17 @@ export default async function login(req: ReqType, res: ResType) {
4141
return inertiaAdminMessage(req, "Wrong username", 'login');
4242
} else {
4343
if (req.adminizer.config.registration.confirmationRequired && !user.isConfirmed && !user.isAdministrator) {
44+
//Here we use the captchaSolution key to output messages unrelated to the form fields.
4445
return inertiaAdminMessage(req, "Profile is not confirmed, please contact to administrator", 'captchaSolution');
4546
}
4647

4748
if (passwordHash.verify(login + password, user.passwordHashed)) {
4849
if (user.expires && Date.now() > Date.parse(user.expires)) {
50+
//Here we use the captchaSolution key to output messages unrelated to the form fields.
4951
return inertiaAdminMessage(req, "Profile expired, contact the administrator", 'captchaSolution');
5052
}
5153
req.session.UserAP = user;
52-
return req.Inertia.redirect(`${req.adminizer.config.routePrefix}/`);
54+
return res.redirect(`${req.adminizer.config.routePrefix}`);
5355
} else {
5456
return inertiaAdminMessage(req, "Wrong password", 'password');
5557
}

0 commit comments

Comments
 (0)