-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* List Users Finaaalllyy, list users again in a new branch * Add Admin flag on User Admin flag to determine if the user has admin privileges. * hide users in menu * Update Databases.kt check if user and admin on each end point * authenticate and authorize all the user endpoints handle general response Delete User * Remove benasher44/uuid * refactor authentication * Allow to enter Keycloak ID Still hidden in the table, only to create or edit. --------- Co-authored-by: Erik van Velzen <[email protected]>
- Loading branch information
Showing
13 changed files
with
418 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import {useState} from "react"; | ||
import {useOnce} from "../hooks/use-once"; | ||
import {User, usersFromJson } from "zero-zummon" | ||
|
||
type UseUserReturn = { | ||
loadingUsers: boolean, | ||
users: User[], | ||
changeUser: (newUser: User) => void, | ||
removeUser: (userId: string) => void, | ||
} | ||
|
||
export const useUsers = (): UseUserReturn => { | ||
const [loadingUsers, setLoading] = useState(true) | ||
const [users, setUsers] = useState<User[]>([]) | ||
|
||
const changeUser = (newUser: User) => { | ||
setUsers(users.map(user => user.id.toString() === newUser.id.toString() ? newUser : user)) | ||
} | ||
|
||
useOnce(async () => { | ||
try { | ||
const response = await fetch(import.meta.env.VITE_ZTOR_URL + '/users', { | ||
credentials: 'include', | ||
}) | ||
if (response.status === 401) { | ||
redirectToLogin() | ||
return | ||
} | ||
if (!response.ok) { | ||
throw new Error(`Could not load users: ${response.status} ${response.statusText}`) | ||
} | ||
|
||
setUsers(usersFromJson(await response.text())) | ||
} catch (error) { | ||
alert((error as Error).message) | ||
} finally { | ||
setLoading(false) | ||
} | ||
}) | ||
|
||
const removeUser = (userId: any) => { | ||
setUsers(users.filter(user => user.id.toString() !== userId.toString())) | ||
} | ||
|
||
return { | ||
loadingUsers, | ||
users, | ||
changeUser, | ||
removeUser, | ||
} | ||
} | ||
|
||
export const redirectToLogin = () => { | ||
window.location.href = import.meta.env.VITE_ZTOR_URL + '/login?redirectUrl=' + encodeURIComponent(window.location.href) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import React, { FormEvent, FunctionComponent, useEffect, useState } from "react"; | ||
import { useParams, useNavigate } from "react-router-dom"; | ||
import { PrimeReactProvider } from "primereact/api"; | ||
import { InputText } from "primereact/inputtext"; | ||
import { Button } from "primereact/button"; | ||
import { User } from "zero-zummon"; | ||
import { redirectToLogin } from "./use-users"; | ||
|
||
export const UserForm: FunctionComponent = () => { | ||
const {userId} = useParams<{ userId: string }>(); | ||
const [user, setUser] = useState<User | null>(null); | ||
const [originalData, setOriginalData] = useState<User | null>(null); | ||
|
||
const [loading, setLoading] = useState(false); | ||
const [isEditing, setIsEditing] = useState(false); | ||
const navigate = useNavigate(); | ||
|
||
const handleCancel = () => { | ||
if (originalData) { | ||
setUser(originalData); // Revert to original data | ||
} | ||
setIsEditing(false); | ||
}; | ||
|
||
const handleEditToggle = () => { | ||
setIsEditing(true); | ||
}; | ||
|
||
const handleInputChange =(e: React.ChangeEvent<HTMLInputElement>) => { | ||
const { name, value, type, checked } = e.target; | ||
setUser((prev) => ({...prev, | ||
[name]: type === "checkbox" ? checked : value, | ||
} as User)); | ||
}; | ||
|
||
useEffect(() => { | ||
if (userId) { | ||
const fetchUser = async () => { | ||
setLoading(true); | ||
try { | ||
const response = await fetch(`${import.meta.env.VITE_ZTOR_URL}/users/${userId}`, { | ||
credentials: "include", | ||
}); | ||
if (response.status === 401) { | ||
redirectToLogin(); | ||
return; | ||
} | ||
if (response.ok) { | ||
const userData = await response.json(); | ||
setUser(userData); | ||
setOriginalData(userData); | ||
} else { | ||
alert(`Error fetching user: ${response.statusText}`); | ||
} | ||
} catch (error) { | ||
alert((error as Error).message); | ||
} finally { | ||
setLoading(false); | ||
} | ||
}; | ||
fetchUser(); | ||
} else { | ||
setIsEditing(true); | ||
} | ||
}, [userId]); | ||
|
||
const handleSubmit = async (event: FormEvent) => { | ||
event.preventDefault(); | ||
setLoading(true); | ||
try { | ||
const method = userId ? "PUT" : "POST"; | ||
const url = `${import.meta.env.VITE_ZTOR_URL}/users` | ||
const response = await fetch(url, { | ||
method, | ||
headers: { | ||
"Content-Type": "application/json", | ||
}, | ||
credentials: "include", | ||
body: JSON.stringify(user), | ||
}); | ||
if (response.status === 401) { | ||
redirectToLogin(); | ||
return; | ||
} | ||
if (!response.ok) { | ||
alert(`Error: ${response.statusText}`); | ||
} | ||
|
||
navigate(`/users`); | ||
} finally { | ||
setIsEditing(false); | ||
setLoading(false); | ||
} | ||
}; | ||
|
||
return ( | ||
<PrimeReactProvider> | ||
<div style={{ padding: "20px", maxWidth: "500px", margin: "0 auto" }}> | ||
<h3>{userId ? "Edit User" : "Add User"}</h3> | ||
<form | ||
onSubmit={handleSubmit} | ||
style={{ display: "flex", flexDirection: "column", gap: "10px" }} | ||
> | ||
<label htmlFor="name">Keycloak ID:</label> | ||
<InputText | ||
id="id" | ||
name="id" | ||
value={user?.id || ""} | ||
onChange={handleInputChange} | ||
disabled={!isEditing} | ||
/> | ||
<label htmlFor="name">Note:</label> | ||
<InputText | ||
id="note" | ||
name="note" | ||
value={user?.note || ""} | ||
onChange={handleInputChange} | ||
disabled={!isEditing} | ||
/> | ||
<div> | ||
<label htmlFor="isAdmin" style={{ display: "flex", alignItems: "center", gap: "8px" }}> | ||
<input | ||
type="checkbox" | ||
id="isAdmin" | ||
name="isAdmin" | ||
checked={user?.isAdmin || false} | ||
onChange={handleInputChange} | ||
disabled={!isEditing} | ||
/> | ||
Admin | ||
</label> | ||
</div> | ||
|
||
<div style={{ display: "flex", justifyContent: "space-between", marginTop: "10px" }}> | ||
{isEditing ? ( | ||
<> | ||
<Button label="Cancel" onClick={handleCancel} type="button" disabled={loading} /> | ||
<Button label={loading ? "Saving..." : "Save"} type="submit" disabled={loading} /> | ||
</> | ||
) : ( | ||
<Button label="Edit" onClick={handleEditToggle} type="button" disabled={loading} /> | ||
)} | ||
</div> | ||
</form> | ||
</div> | ||
</PrimeReactProvider> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import React, {FunctionComponent} from "react"; | ||
import { DataTable } from 'primereact/datatable'; | ||
import { Column } from 'primereact/column'; | ||
import {useUsers} from "./use-users"; | ||
import {PrimeReactProvider} from "primereact/api"; | ||
import {User} from "zero-zummon" | ||
|
||
import "primereact/resources/themes/lara-light-cyan/theme.css" | ||
import 'primeicons/primeicons.css' | ||
import {DeleteButton} from "./delete-button"; | ||
import {EditButton} from "./edit-button"; | ||
import {Button} from "primereact/button"; | ||
import {useNavigate} from "react-router-dom" | ||
|
||
export const Users: FunctionComponent = () => { | ||
const {loadingUsers, users, changeUser, removeUser} = useUsers() | ||
const navigate = useNavigate(); | ||
|
||
return ( | ||
<PrimeReactProvider> | ||
<div css={{ | ||
display: 'flex', | ||
justifyContent: 'space-between', | ||
alignItems: 'center', | ||
padding: '1em 1em', | ||
boxShadow: '1px solid #ddd' | ||
}}> | ||
<h3>Users List</h3> | ||
<Button | ||
label="Nieuw" | ||
icon="pi pi-pencil" | ||
onClick={(event) => navigate(`/users/new-user`)} | ||
/> | ||
</div> | ||
<DataTable | ||
value={users} | ||
loading={loadingUsers} | ||
sortField="created" | ||
sortOrder={-1} | ||
filterDisplay="row" | ||
> | ||
<Column field="note" header="Note" sortable filter/> | ||
<Column | ||
field="isAdmin" | ||
header="Admin" | ||
body={(user: User) => ( | ||
<div style={{ textAlign: 'center' }}> | ||
{user.isAdmin ? ( | ||
<span style={{ color: 'green' }}>✔</span> | ||
) : ( | ||
<span style={{ color: 'red' }}>✘</span> | ||
)} | ||
</div> | ||
)} | ||
/> | ||
<Column body={(user: User) => ( | ||
<div css={{ | ||
display: 'flex', | ||
'> *': { | ||
margin: `${1 / 6}rem` | ||
}, | ||
}}> | ||
<DeleteButton type="users" id={user.id} onDelete={removeUser}/> | ||
<EditButton type="users" id={user.id}/> | ||
</div> | ||
)}/> | ||
</DataTable> | ||
</PrimeReactProvider> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ALTER TABLE "user" ADD COLUMN is_admin BOOLEAN DEFAULT FALSE; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.