team initial commit

This commit is contained in:
Alex Holliday
2026-02-08 16:14:35 +00:00
parent 2e3b32462f
commit 9ca79ea793
6 changed files with 180 additions and 10 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ export const TabPassword = () => {
const { resolver, defaults } = usePasswordForm();
const { patch, loading } = usePatch<FormData, void>();
const { control, handleSubmit, reset, setError } = useForm<PasswordFormData>({
const { control, handleSubmit, reset } = useForm<PasswordFormData>({
resolver,
defaultValues: defaults,
});
+28 -2
View File
@@ -1,5 +1,31 @@
import { Box } from "@mui/material";
import { Stack } from "@mui/material";
import { useTheme } from "@mui/material";
import { useState, useMemo } from "react";
import { HeaderTeamControls } from "./components/HeaderTeamControls";
import { TeamTable } from "./components/TeamTable";
import { useGet } from "@/Hooks/UseApi";
import type { User, UserRole } from "@/Types/User";
export const TabTeam = () => {
return <Box>{/* TODO: Implement TabTeam */}</Box>;
const theme = useTheme();
const [filter, setFilter] = useState<UserRole | "">("");
const { data: users } = useGet<User[]>("/auth/users");
const filteredUsers = useMemo(() => {
if (!users) return [];
if (!filter) return users;
return users.filter((u) => u.role.includes(filter));
}, [users, filter]);
return (
<Stack gap={theme.spacing(8)}>
<HeaderTeamControls
filter={filter}
onFilterChange={setFilter}
/>
<TeamTable users={filteredUsers} />
</Stack>
);
};
@@ -0,0 +1,74 @@
import Stack from "@mui/material/Stack";
import MenuItem from "@mui/material/MenuItem";
import { Button, Select } from "@/Components/v2/inputs";
import { Icon } from "@/Components/v2/design-elements";
import { UserPlus, Mail } from "lucide-react";
import { UserRoles } from "@/Types/User";
import { useTheme } from "@mui/material/styles";
import type { UserRole } from "@/Types/User";
import { useTranslation } from "react-i18next";
import { useIsAdmin, useIsSuperAdmin } from "@/Hooks/useIsAdmin";
interface HeaderTeamControlsProps {
filter: UserRole | "";
onFilterChange: (value: UserRole | "") => void;
}
export const HeaderTeamControls = ({
filter,
onFilterChange,
}: HeaderTeamControlsProps) => {
const theme = useTheme();
const { t } = useTranslation();
const isAdmin = useIsAdmin();
const isSuperAdmin = useIsSuperAdmin();
const handleFilterChange = (event: { target: { value: unknown } }) => {
onFilterChange(event.target.value as UserRole | "");
};
return (
<Stack
direction="row"
alignItems="center"
justifyContent="flex-end"
gap={theme.spacing(4)}
>
<Select
value={filter}
onChange={handleFilterChange}
placeholder={t("pages.account.team.filter.placeholder")}
sx={{ minWidth: 150 }}
>
<MenuItem value="">{t("pages.account.team.filter.all")}</MenuItem>
{UserRoles.map((role) => (
<MenuItem
key={role}
value={role}
>
{t(`common.auth.roles.${role}`)}
</MenuItem>
))}
</Select>
{isAdmin && (
<Button
variant="contained"
color="primary"
startIcon={<Icon icon={Mail} />}
>
{t("pages.account.team.inviteMember")}
</Button>
)}
{isSuperAdmin && (
<Button
variant="contained"
color="primary"
startIcon={<Icon icon={UserPlus} />}
>
{t("pages.account.team.addMember")}
</Button>
)}
</Stack>
);
};
@@ -15,13 +15,6 @@ import { useGetInviteToken } from "../../../Hooks/inviteHooks.js";
import { useNavigate } from "react-router-dom";
import { useIsSuperAdmin } from "@/Hooks/useIsAdmin.js";
import AddMemberMenu from "./AddMemberMenu/index.jsx";
/**
* TeamPanel component manages the organization and team members,
* providing functionalities like renaming the organization, managing team members,
* and inviting new members.
*
* @returns {JSX.Element}
*/
const TeamPanel = () => {
const theme = useTheme();
@@ -0,0 +1,53 @@
import Typography from "@mui/material/Typography";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { Table } from "@/Components/v2/design-elements";
import type { Header } from "@/Components/v2/design-elements/Table";
import { useIsSuperAdmin } from "@/Hooks/useIsAdmin";
import type { User } from "@/Types/User";
interface TeamTableProps {
users: User[];
}
export const TeamTable = ({ users }: TeamTableProps) => {
const { t } = useTranslation();
const navigate = useNavigate();
const isSuperAdmin = useIsSuperAdmin();
const headers: Header<User>[] = [
{
id: "name",
content: t("common.table.headers.name"),
render: (row) => <Typography>{`${row.firstName} ${row.lastName}`}</Typography>,
},
{
id: "email",
content: t("pages.account.team.table.headers.email"),
render: (row) => <Typography>{row.email}</Typography>,
},
{
id: "role",
content: t("pages.account.team.table.headers.role"),
render: (row) => (
<Typography>
{row.role.map((r) => t(`common.auth.roles.${r}`)).join(", ")}
</Typography>
),
},
];
const handleRowClick = (row: User) => {
if (isSuperAdmin) {
navigate(`/account/team/${row.id}`);
}
};
return (
<Table
headers={headers}
data={users}
onRowClick={isSuperAdmin ? handleRowClick : undefined}
/>
);
};
+24
View File
@@ -176,6 +176,14 @@
"ClickUpload": "Click to upload",
"close": "Close",
"common": {
"auth": {
"roles": {
"admin": "Admin",
"demo": "Demo",
"superadmin": "Super admin",
"user": "User"
}
},
"alerts": {
"pageSpeedApiKey": {
"content": "Warning: You haven't added a Google PageSpeed API key yet. Visit <settingsLink>Settings</settingsLink> to add one. Without it, the PageSpeed monitor won't function."
@@ -549,6 +557,22 @@
"title": "Delete account",
"description": "This action is permanent and cannot be undone"
}
},
"team": {
"addMember": "Add member",
"inviteMember": "Invite member",
"filter": {
"placeholder": "Filter by role",
"all": "All roles",
"admin": "Admin",
"member": "Member"
},
"table": {
"headers": {
"email": "Email",
"role": "Role"
}
}
}
},
"auth": {