191 lines
5.8 KiB
TypeScript
191 lines
5.8 KiB
TypeScript
/* eslint-disable react-hooks/exhaustive-deps */
|
||
import { useEffect, useState } from "react";
|
||
import api from "../utils/api";
|
||
import IError from "../types/IError";
|
||
import Button from "../components/Button";
|
||
import useModalStore from "../stores/useModalStore";
|
||
import ModalContainer from "../components/ModalContainer";
|
||
import { useNavigate, useParams } from "react-router-dom";
|
||
import IBuild from "../types/IBuild";
|
||
import CreateBuildModal from "../components/modals/CreateBuildModal";
|
||
import IUser from "../types/IUser";
|
||
import CreateUserModal from "../components/modals/CreateUserModal";
|
||
import { Transition } from "react-transition-group";
|
||
import SpinnerIcon from "../components/icons/SpinnerIcon";
|
||
import MoreIcon from "../components/icons/MoreIcon";
|
||
import EditUserModal from "../components/modals/EditUserModal";
|
||
|
||
function AdminCompanyPage() {
|
||
const { companyId } = useParams();
|
||
const [builds, setBuilds] = useState<IBuild[]>();
|
||
const [users, setUsers] = useState<IUser[]>();
|
||
const { setModal } = useModalStore();
|
||
const navigate = useNavigate();
|
||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||
|
||
async function getBuilds() {
|
||
if (!companyId) return;
|
||
|
||
try {
|
||
const result: IBuild[] | IError = await api
|
||
.get(`admin/builds?companyId=${companyId}`)
|
||
.json();
|
||
|
||
if ("error" in result) {
|
||
alert(result.error);
|
||
return;
|
||
}
|
||
|
||
setBuilds(result);
|
||
} catch (error) {
|
||
alert((error as Error).message);
|
||
}
|
||
}
|
||
|
||
async function getUsers() {
|
||
if (!companyId) return;
|
||
|
||
try {
|
||
const result: IUser[] | IError = await api
|
||
.get(`admin/users?companyId=${companyId}`)
|
||
.json();
|
||
|
||
if ("error" in result) {
|
||
alert(result.error);
|
||
return;
|
||
}
|
||
|
||
setUsers(result);
|
||
} catch (error) {
|
||
alert((error as Error).message);
|
||
}
|
||
}
|
||
|
||
useEffect(() => {
|
||
getBuilds();
|
||
getUsers();
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
if (!users || !builds) {
|
||
return;
|
||
}
|
||
|
||
setIsLoading(false);
|
||
}, [users, builds]);
|
||
|
||
return (
|
||
<div className="flex flex-col min-h-screen gap-8 p-8 bg-gray-100">
|
||
<div className="flex gap-8">
|
||
<Button
|
||
variant="secondary"
|
||
size="medium"
|
||
className="border border-gray-300"
|
||
onClick={() => navigate("..")}
|
||
>
|
||
Назад
|
||
</Button>
|
||
</div>
|
||
<div className="space-y-4">
|
||
<div className="flex items-center gap-4">
|
||
<p className="text-xl font-semibold">Жилые комплексы</p>
|
||
<Button
|
||
onClick={() =>
|
||
companyId && setModal(<CreateBuildModal companyId={companyId} />)
|
||
}
|
||
>
|
||
Добавить ЖК
|
||
</Button>
|
||
</div>
|
||
<div className="grid grid-cols-4 gap-4 pb-8 border-b border-gray-300">
|
||
{builds &&
|
||
builds.map((build) => (
|
||
<div className="relative overflow-hidden bg-white rounded-xl">
|
||
<img
|
||
src=""
|
||
alt=""
|
||
className="object-cover bg-gray-400 aspect-video"
|
||
/>
|
||
<div className="absolute text-left text-white bottom-4 left-6">
|
||
<p className="text-xl font-semibold">{build.name}</p>
|
||
<p className="">
|
||
Сборка приложения:{" "}
|
||
<span className="font-semibold">{build.build}</span>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
<div className="pb-8 space-y-4 border-b border-gray-300">
|
||
<div className="flex items-center gap-4">
|
||
<p className="text-xl font-semibold">Пользователи</p>
|
||
<Button
|
||
onClick={() =>
|
||
companyId && setModal(<CreateUserModal companyId={companyId} />)
|
||
}
|
||
>
|
||
Добавить пользователя
|
||
</Button>
|
||
</div>
|
||
<div className="grid grid-cols-5 gap-4">
|
||
{users &&
|
||
users.map((user) => (
|
||
<div
|
||
key={user.id}
|
||
className="flex items-start justify-between gap-4 p-4 rounded-lg shadow"
|
||
>
|
||
<div className="flex gap-4">
|
||
<img
|
||
src={user.avatar || "/images/no-avatar.png"}
|
||
alt=""
|
||
className="w-8 h-8 bg-gray-500 rounded-full"
|
||
/>
|
||
|
||
<div className="text-sm">
|
||
<p>{user.name}</p>
|
||
<p>{user.username}</p>
|
||
<p>Роль: {user.role}</p>
|
||
<p>
|
||
Связанные ЖК:{" "}
|
||
{builds
|
||
?.filter((build) => user.buildIds?.includes(build.id))
|
||
.map((build) => build.name)
|
||
.join(", ") || "Нет связанных сборок"}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<Button
|
||
variant="secondary"
|
||
icon={<MoreIcon className="w-5 h-5" />}
|
||
onlyIcon
|
||
onClick={() =>
|
||
companyId &&
|
||
setModal(
|
||
<EditUserModal companyId={companyId} userId={user.id} />
|
||
)
|
||
}
|
||
/>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<ModalContainer />
|
||
|
||
<Transition in={isLoading} timeout={150} mountOnEnter unmountOnExit>
|
||
{(state) => (
|
||
<div
|
||
className={`fixed top-0 left-0 w-full h-full flex items-center justify-center bg-black bg-opacity-50 transition-all ${state}`}
|
||
>
|
||
<SpinnerIcon />
|
||
</div>
|
||
)}
|
||
</Transition>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default AdminCompanyPage;
|