Skip to content

Commit

Permalink
Merge pull request EGCETSII#39 from Full-Tortuga/feature/EGCETSII#17-…
Browse files Browse the repository at this point in the history
…list-users-and-provide-actions

EGCETSII#17-feat: fetch data for user list and provide state/role actions
  • Loading branch information
JSnow11 authored Dec 19, 2021
2 parents 472fc29 + 6532a62 commit 7636790
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 55 deletions.
30 changes: 18 additions & 12 deletions decide-tortuga-1.code-workspace
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
{
"folders": [
{
"path": "."
},
{
"path": "decide/administration"
},
{
"path": "decide/administration/frontend"
}
],
"settings": {}
"folders": [
{
"name": "decide-full-tortuga-admin",
"path": "."
},
{
"name": "decide",
"path": "decide"
},
{
"name": "administration",
"path": "decide/administration"
},
{
"name": "src",
"path": "decide/administration/frontend/src"
}
]
}
4 changes: 2 additions & 2 deletions decide/administration/frontend/src/api/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ axios.interceptors.request.use((config: AxiosRequestConfig) => {
// Auth interceptor (logout)
axios.interceptors.response.use(
(response) => {
return response.data;
return response;
},
(error) => {
if (error.response?.status === 403) {
Expand All @@ -37,7 +37,7 @@ axios.interceptors.response.use(
// Error handling interceptor
axios.interceptors.response.use(
(response) => {
return response.data;
return response;
},
(error) => {
// todo: handle errors
Expand Down
32 changes: 25 additions & 7 deletions decide/administration/frontend/src/api/userApiUtils.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import { axios } from "api/axios";
import { userType } from "types";

const userApi = {
// bulk operations
// bulk simple operations
getUsers: () => axios.get("/users"),
//createUsers: (user: any) => axios.post("/users/", user),
deleteUsers: () => axios.delete("/users"),
deleteUsers: (idList: number[]) =>
axios.delete("/users", { data: { idList: idList.join(",") } }),

// individual operations
// bulk role/status operations
updateUsersActive: (idList: number[], value: boolean) =>
axios.post("/users/state", {
idList: idList.join(","),
state: "Active",
value: value ? "True" : "False",
}),
updateUsersRole: (
idList: number[],
value: boolean,
role: "Staff" | "Superuser"
) =>
axios.post("/users/state", {
idList: idList.join(","),
state: role,
value: value ? "True" : "False",
}),

// individual simple operations
getUser: (id: string) => axios.get(`/users/${id}`),
createUser: (user: any) => axios.post("/users", user),
updateUser: (user: any) => axios.put(`/users/${user.id}`, user),
createUser: (user: userType.User) => axios.post("/users", user),
updateUser: (user: userType.User) => axios.put(`/users/${user.id}`, user),
deleteUser: (id: string) => axios.delete(`/users/${id}`),
};


export default userApi;
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { IconButton } from "components/01-atoms";
type Action = {
title: string;
icon: ReactElement;
disabled?: boolean;
onClick?: () => void;
};

Expand Down Expand Up @@ -39,7 +40,7 @@ const Component = (props: {
title={action.title}
icon={action.icon}
onClick={action.onClick}
disabled={!individualEnabled}
disabled={action.disabled || !individualEnabled}
/>
))}
<Divider />
Expand All @@ -49,7 +50,7 @@ const Component = (props: {
title={action.title}
icon={action.icon}
onClick={action.onClick}
disabled={!bulkEnabled}
disabled={action.disabled || !bulkEnabled}
/>
))}
</Box>
Expand Down
128 changes: 106 additions & 22 deletions decide/administration/frontend/src/components/pages/users/users.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import React from "react";
import { Delete } from "@mui/icons-material";
import {
AdminPanelSettings,
Delete,
Pause,
PlayArrow,
Verified,
} from "@mui/icons-material";

import { userApi } from "api";
import { userType } from "types";
Expand All @@ -9,43 +15,80 @@ import { NewUserForm, UserTable } from "components/templates/users";

import Page from "../page";

// todo: fetch users from api and set rows to the response
const rows = [
{ id: 1, lastName: "Snow", firstName: "Jon", age: 35 },
{ id: 2, lastName: "Lannister", firstName: "Cersei", age: 42 },
{ id: 3, lastName: "Lannister", firstName: "Jaime", age: 45 },
{ id: 4, lastName: "Stark", firstName: "Arya", age: 16 },
{ id: 5, lastName: "Targaryen", firstName: "Daenerys", age: null },
{ id: 6, lastName: "Melisandre", firstName: null, age: 150 },
{ id: 7, lastName: "Clifford", firstName: "Ferrara", age: 44 },
{ id: 8, lastName: "Frances", firstName: "Rossini", age: 36 },
{ id: 9, lastName: "Roxie", firstName: "Harvey", age: 65 },
];

const UsersPage = () => {
const [users, setUsers] = React.useState(rows);
const [users, setUsers] = React.useState<userType.User[]>([]);
const [selected, setSelected] = React.useState([]);
const [refetch, setRefetch] = React.useState(false);

const refetchUsers = () => {
setRefetch(!refetch);
};

React.useEffect(() => {
userApi.getUsers().then((response) => {
console.log(response);
setUsers(rows);
});
}, []);
userApi
.getUsers()
.then((response) => {
console.log(response);
setUsers(response.data);
})
.catch((error) => {
console.log(error);
});
}, [refetch]);

const idList = React.useMemo(
() => selected.map((user: userType.User) => user.id),
[selected]
);

const selectionState = React.useMemo(() => {
const checkOptions = (active: number) => {
if (active === selected.length) return "true";
else if (active === 0) return "false";
else return "mixed";
};

const activeNumber = selected.filter(
(user: userType.User) => user.is_active
).length;
const staffNumber = selected.filter(
(user: userType.User) => user.is_staff
).length;
const suNumber = selected.filter(
(user: userType.User) => user.is_superuser
).length;

return {
active: checkOptions(activeNumber),
staff: checkOptions(staffNumber),
su: checkOptions(suNumber),
};
}, [selected]);

const handleDelete = () => {
console.log(idList);
userApi.deleteUsers(idList).then((response) => {
console.log(response);
refetchUsers();
});
};

const handleChangeActive = (value: boolean) => {
userApi.updateUsersActive(idList, value).then((response) => {
console.log(response);
refetchUsers();
});
};
const handleChangeRole = (value: boolean, role: "Staff" | "Superuser") => {
userApi.updateUsersRole(idList, value, role).then((response) => {
console.log(response);
refetchUsers();
});
};

return (
<>
<Page title="Users">
<UserTable users={users || rows} setSelected={setSelected} />
<UserTable users={users} setSelected={setSelected} />
</Page>
<ActionBar
selection={selected}
Expand All @@ -63,6 +106,47 @@ const UsersPage = () => {
handleDelete();
},
},
{
icon: selectionState.active === "true" ? <Pause /> : <PlayArrow />,
title:
selectionState.active === "true"
? "Mark as Inactive"
: "Mark as Active",
disabled: selectionState.active === "mixed",
onClick: () => {
console.log("switch active");
selectionState.active === "true"
? handleChangeActive(false)
: handleChangeActive(true);
},
},
{
icon: selectionState.staff === "true" ? <Pause /> : <Verified />,
title:
selectionState.staff === "true" ? "Remove Staff" : "Make Staff",
disabled: selectionState.staff === "mixed",
onClick: () => {
console.log("switch staff");
selectionState.staff === "true"
? handleChangeRole(false, "Staff")
: handleChangeRole(true, "Staff");
},
},
{
icon:
selectionState.su === "true" ? <Pause /> : <AdminPanelSettings />,
title:
selectionState.su === "true"
? "Remove SuperUser"
: "Make SuperUser",
disabled: selectionState.su === "mixed",
onClick: () => {
console.log("switch staff");
selectionState.su === "true"
? handleChangeRole(false, "Superuser")
: handleChangeRole(true, "Superuser");
},
},
]}
/>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const Component = (props: { initialUser?: userType.User }) => {
setError,
formState: { errors },
} = useForm<{ username: string; username2: string }>({
defaultValues: { username: props.initialUser?.firstName || "" },
defaultValues: { username: props.initialUser?.first_name || "" },
});

const [sent, setSent] = React.useState(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,38 @@ import { Table } from "components/02-molecules";

const columns: GridColDef[] = [
{
field: "firstName",
field: "username",
headerName: "Username",
width: 110,
},
{
field: "first_name",
headerName: "First name",
width: 200,
},
{
field: "lastName",
field: "last_name",
headerName: "Last name",
width: 200,
},
{
field: "age",
headerName: "Age",
type: "number",
field: "email",
headerName: "Email",
width: 110,
},
{
field: "is_active",
headerName: "Active",
width: 110,
},
{
field: "is_staff",
headerName: "Staff",
width: 110,
},
{
field: "is_superuser",
headerName: "Superuser",
width: 110,
},
];
Expand Down
11 changes: 7 additions & 4 deletions decide/administration/frontend/src/types/user.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//todo replace with user correct data
export type User = {
id: number;
lastName: string;
firstName?: string | null;
age?: number | null;
email: string;
first_name: string;
last_name: string;
username: string;
is_active: boolean;
is_staff: boolean;
is_superuser: boolean;
};

0 comments on commit 7636790

Please sign in to comment.