Skip to content

Commit

Permalink
Merge pull request #231 from FalkorDB/fix-add-user-dialog
Browse files Browse the repository at this point in the history
fix #220 Fix add user dialog
  • Loading branch information
Anchel123 authored Jul 2, 2024
2 parents d904176 + 071b7c8 commit 6c66125
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 21 deletions.
2 changes: 1 addition & 1 deletion app/components/DialogComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function DialogComponent({ children, title, description, classNam
</button>
</DialogClose>
</DialogHeader>
<div className="h-[90%] p-8 flex flex-col gap-10">
<div className="h-[90%] p-8 flex flex-col gap-10 overflow-auto">
{
description &&
<DialogDescription className="text-2xl">
Expand Down
166 changes: 147 additions & 19 deletions app/settings/users/AddUser.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,39 @@
import { Dispatch, FormEvent, SetStateAction, useState } from "react"
import { Toast, securedFetch } from "@/lib/utils";
import { PlusCircle } from "lucide-react";
import { Eye, PlusCircle } from "lucide-react";
import { User } from "@/app/api/user/model";
import Button from "@/app/components/Button";
import Input from "@/app/components/Input";
import DialogComponent from "@/app/components/DialogComponent";
import { Dialog, DialogClose, DialogTrigger } from "@/components/ui/dialog";
import { Dialog, DialogTrigger } from "@/components/ui/dialog";
import Combobox from "../../components/combobox";

// eslint-disable-next-line no-useless-escape
const PATTERN = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&#+]{8,}$"

export default function AddUser({ setUsers }: {
setUsers: Dispatch<SetStateAction<User[]>>
}) {
const [open, setOpen] = useState(false)
const [username, setUsername] = useState("")
const [password, setPassword] = useState("")
const [confirmPassword, setConfirmPassword] = useState("")
const [showPassword, setShowPassword] = useState(false)
const [showConfirmPassword, setConfirmShowPassword] = useState(false)
const [role, setRole] = useState("")

const addUser = async (event: FormEvent) => {
event.preventDefault();
const addUser = async (e: FormEvent) => {
e.preventDefault();

if (!username || !password) return
if (!role) {
Toast("select role is required")
return
}

if (password !== confirmPassword) {
Toast("Passwords do not match")
return
}

const response = await securedFetch('/api/user/', {
method: 'POST',
Expand All @@ -33,15 +47,16 @@ export default function AddUser({ setUsers }: {
Toast("Success", "User added successfully")
setUsers(prev => [...prev, { username, role, selected: false }])
}
setOpen(false)
};

return (
<Dialog>
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button
variant="Primary"
icon={<PlusCircle />}
label="ADD USER"
label="Add User"
/>
</DialogTrigger>
<DialogComponent
Expand All @@ -52,21 +67,134 @@ export default function AddUser({ setUsers }: {
<Combobox type="Role" options={["Admin", "Read-Write", "Read-Only"]} selectedValue={role} setSelectedValue={setRole} />
<div className="flex flex-col gap-2">
<p>Username</p>
<Input variant="Small" onChange={(e) => setUsername(e.target.value)} required />
<Input
type="text"
variant="Small"
onChange={(e) => {
setUsername(e.target.value)
e.currentTarget.setCustomValidity("")
}}
onInvalid={(e) => e.currentTarget.setCustomValidity("Username is required")}
required
/>
</div>
<div className="flex flex-col gap-2">
<p>Password</p>
<Input variant="Small" type="password" onChange={(e) => setPassword(e.target.value)} required />
<div className="relative flex flex-col gap-2">
<p title="Password">Password</p>
<button
className="absolute top-10 right-2 p-0"
title="Show Password"
type="button"
aria-label="Show Password"
onClick={() => setShowPassword(prev => !prev)}
>
<Eye strokeWidth={0.5} />
</button>
<Input
pattern={PATTERN}
variant="Small"
type={showPassword ? "text" : "password"}
onChange={(e) => {
setPassword(e.target.value)
e.currentTarget.setCustomValidity("")
if (!e.target.checkValidity()) {
if (!e.target.value) {
e.currentTarget.setCustomValidity("Password is required");
} else if (e.target.validity.patternMismatch) {
e.currentTarget.setCustomValidity(`
Password must contain:
- At least one lowercase letter
- At least one uppercase letter
- At least one digit
- At least one special character (@$!%*?&#+)
- At least 8 characters
`);
}
} else {
// If the value is valid or the input is empty, clear the custom validity message
e.currentTarget.setCustomValidity("");
}
}}
value={password}
onInvalid={(e) => {
if (!e.currentTarget.value) {
e.currentTarget.setCustomValidity("Password is required");
} else if (e.currentTarget.validity.patternMismatch) {
e.currentTarget.setCustomValidity(`
password must contain:
- At least one lowercase letter
- At least one uppercase letter
- At least one digit
- At least one special (@$!%*?&)
- At least 8 characters
`);
}
e.currentTarget.reportValidity();
}}
required
/>
</div>
<div className="relative flex flex-col gap-2">
<p title="Confirm Password">Confirm Password</p>
<button
className="absolute top-10 right-2 p-0"
title="Show Confirm Password"
type="button"
aria-label="Show Confirm Password"
onClick={() => setConfirmShowPassword(prev => !prev)}
>
<Eye strokeWidth={0.5} />
</button>
<Input
pattern={PATTERN}
variant="Small"
type={showConfirmPassword ? "text" : "password"}
onChange={(e) => {
setConfirmPassword(e.target.value)
e.currentTarget.setCustomValidity("")
if (!e.target.checkValidity()) {
if (!e.target.value) {
e.currentTarget.setCustomValidity("Password is required");
} else if (e.target.validity.patternMismatch) {
e.currentTarget.setCustomValidity(`
Password must contain:
- At least one lowercase letter
- At least one uppercase letter
- At least one digit
- At least one special character (@$!%*?&#+)
- At least 8 characters
`);
}
} else {
// If the value is valid or the input is empty, clear the custom validity message
e.currentTarget.setCustomValidity("");
}
}}
value={confirmPassword}
onInvalid={(e) => {
if (!e.currentTarget.value) {
e.currentTarget.setCustomValidity("Confirm Password is required");
} else if (e.currentTarget.validity.patternMismatch) {
e.currentTarget.setCustomValidity(`
password must contain:
- At least one lowercase letter
- At least one uppercase letter
- At least one digit
- At least one special (@$!%*?&)
- At least 8 characters
`);
}
e.currentTarget.reportValidity();
}}
required
/>
</div>
<div className="flex flex-row justify-end">
<DialogClose asChild>
<Button
variant="Primary"
label="ADD USER"
icon={<PlusCircle />}
type="submit"
/>
</DialogClose>
<Button
variant="Primary"
label="Add User"
icon={<PlusCircle />}
type="submit"
/>
</div>
</form>
</DialogComponent>
Expand Down
2 changes: 1 addition & 1 deletion app/settings/users/DeleteUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default function DeleteUser({ isDeleteSelected, users, setUsers }: Delete
disabled={users.length === 0}
variant="Primary"
icon={<Trash2 />}
label="Delete User"
label="Delete Users"
/>
: <button
title="Delete"
Expand Down

0 comments on commit 6c66125

Please sign in to comment.