167 lines
4.3 KiB
TypeScript
167 lines
4.3 KiB
TypeScript
"use client"
|
||
|
||
import type { components } from "@shared/api/__generated__/openapi.types"
|
||
import type { JSX } from "react"
|
||
|
||
import { PlusIcon } from "lucide-react"
|
||
import { FunctionComponent, useState } from "react"
|
||
|
||
import { useRouter } from "next/navigation"
|
||
|
||
import { ProjectCard } from "@entities/ProjectCard"
|
||
import { useBreadcrumbs } from "@shared/context/BreadcrumbsContext"
|
||
import {
|
||
CreateProjectModal,
|
||
DeleteProjectModal,
|
||
EditProjectModal,
|
||
RenameProjectModal,
|
||
} from "@features/project"
|
||
import api from "@shared/api"
|
||
import { useDebounce } from "@shared/hooks/useDebounce"
|
||
import { Button } from "@shared/ui"
|
||
import { ProjectCardSkeleton } from "@shared/ui/Skeleton"
|
||
import {
|
||
ProjectsHeader,
|
||
type ProjectStatusEnum,
|
||
} from "@widgets/Projects/ProjectsHeader"
|
||
|
||
import { IProjectsPageProps } from "./ProjectsPage.d"
|
||
import styles from "./ProjectsPage.module.scss"
|
||
|
||
type ProjectRead = components["schemas"]["ProjectRead"]
|
||
|
||
export const ProjectsPage: FunctionComponent<
|
||
IProjectsPageProps
|
||
> = (): JSX.Element => {
|
||
useBreadcrumbs([{ label: "Проекты", href: "/projects" }])
|
||
const router = useRouter()
|
||
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false)
|
||
const [editProject, setEditProject] = useState<ProjectRead | null>(null)
|
||
const [renameProject, setRenameProject] = useState<ProjectRead | null>(null)
|
||
const [deleteProject, setDeleteProject] = useState<ProjectRead | null>(null)
|
||
|
||
const [search, setSearch] = useState("")
|
||
const [statusFilter, setStatusFilter] = useState<ProjectStatusEnum>("")
|
||
const debouncedSearch = useDebounce(search, 300)
|
||
|
||
const {
|
||
data: projects,
|
||
isLoading: projectsLoading,
|
||
refetch: refetchProjects,
|
||
} = api.useQuery("get", "/api/projects/", {
|
||
params: {
|
||
query: {
|
||
search: debouncedSearch || undefined,
|
||
status: statusFilter || undefined,
|
||
},
|
||
},
|
||
})
|
||
|
||
return (
|
||
<div className={styles.root} data-testid="ProjectsPage">
|
||
<div className={styles.header}>
|
||
<div className={styles.titles}>
|
||
<h1 className={styles.title}>Мои проекты</h1>
|
||
<h4 className={styles.subtitle}>
|
||
Управляйте своими последними проектами
|
||
</h4>
|
||
</div>
|
||
<div>
|
||
<Button
|
||
variant="primary"
|
||
size="lg"
|
||
onClick={() => setIsCreateModalOpen(true)}
|
||
>
|
||
<PlusIcon /> Создать проект
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
|
||
<CreateProjectModal
|
||
open={isCreateModalOpen}
|
||
onOpenChange={setIsCreateModalOpen}
|
||
onCreated={async () => {
|
||
await refetchProjects()
|
||
}}
|
||
/>
|
||
|
||
{editProject && (
|
||
<EditProjectModal
|
||
open
|
||
onOpenChange={(open) => {
|
||
if (!open) setEditProject(null)
|
||
}}
|
||
project={editProject}
|
||
onUpdated={async () => {
|
||
await refetchProjects()
|
||
}}
|
||
/>
|
||
)}
|
||
|
||
{renameProject && (
|
||
<RenameProjectModal
|
||
open
|
||
onOpenChange={(open) => {
|
||
if (!open) setRenameProject(null)
|
||
}}
|
||
project={renameProject}
|
||
onRenamed={async () => {
|
||
await refetchProjects()
|
||
}}
|
||
/>
|
||
)}
|
||
|
||
{deleteProject && (
|
||
<DeleteProjectModal
|
||
open
|
||
onOpenChange={(open) => {
|
||
if (!open) setDeleteProject(null)
|
||
}}
|
||
project={deleteProject}
|
||
onDeleted={async () => {
|
||
await refetchProjects()
|
||
}}
|
||
/>
|
||
)}
|
||
|
||
<ProjectsHeader
|
||
search={search}
|
||
onSearchChange={setSearch}
|
||
statusFilter={statusFilter}
|
||
onStatusFilterChange={setStatusFilter}
|
||
/>
|
||
|
||
<div className={styles.projectList}>
|
||
{projectsLoading
|
||
? Array.from({ length: 6 }).map((_, i) => (
|
||
<ProjectCardSkeleton key={i} />
|
||
))
|
||
: projects?.map((project) => (
|
||
<ProjectCard
|
||
key={project.id}
|
||
project={project}
|
||
progress={project.status === "PROCESSING" ? 45 : 0}
|
||
currentAction={
|
||
project.status === "PROCESSING" ? "Рендеринг" : undefined
|
||
}
|
||
onClick={() => router.push(`/projects/${project.id}`)}
|
||
onEdit={() => setEditProject(project)}
|
||
onRename={() => setRenameProject(project)}
|
||
onDelete={() => setDeleteProject(project)}
|
||
/>
|
||
))}
|
||
</div>
|
||
|
||
{!projectsLoading && projects?.length === 0 && (
|
||
<div className={styles.empty}>
|
||
<p className={styles.emptyText}>
|
||
{search || statusFilter
|
||
? "Проекты не найдены"
|
||
: "У вас пока нет проектов"}
|
||
</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|