This commit is contained in:
2025-07-07 11:12:02 +05:00
parent 2e5790d246
commit 1a8c25f092
11 changed files with 152 additions and 35 deletions
+58 -10
View File
@@ -15,6 +15,7 @@ import SpinIcon from "../icons/SpinIcon";
import useModalStore from "../../stores/useModalStore";
import CreateSessionModal from "./CreateSessionModal";
import SessionModal from "./SessionModal";
import SessionCommentItem from "../SessionCommentItem";
function ClientModal({ client }: { client: Client }) {
const queryClient = useQueryClient();
@@ -41,7 +42,7 @@ function ClientModal({ client }: { client: Client }) {
<div className="flex justify-center items-center py-[1.806vw] border-b border-[#D6D6D6]">
<p className="title-s font-medium">{client.name}</p>
</div>
<div className="flex bg-[#F0F0F0] h-[calc(100vh-8.861vw)] rounded-b-[2.222vw]">
<div className="flex bg-[#F0F0F0] h-[calc(100vh-8.861vw)] rounded-b-[2.222vw] overflow-hidden">
<div className="flex flex-col gap-[1.111vw] p-[1.111vw] flex-1 overflow-y-auto [scrollbar-width:thin]">
<div className="flex flex-col gap-[1.111vw] rounded-[1.667vw] bg-white p-[1.111vw]">
<div className="flex flex-col gap-[0.278vw]">
@@ -123,8 +124,12 @@ function ClientModal({ client }: { client: Client }) {
</p>
</div>
<div className="flex gap-[0.556vw]">
<div className="size-[2.222vw] rounded-full bg-[#F0F0F0] bg-[url(/images/mock_manager_photo_c.png)] bg-cover bg-no-repeat bg-center" />
<div className="size-[2.222vw] rounded-full bg-[#F0F0F0] bg-[url(/images/mock_manager_photo_1_c.png)] bg-cover bg-no-repeat bg-center" />
{client.managers.map((manager) => (
<div
key={manager.id}
className="size-[2.222vw] rounded-full bg-[#F0F0F0] bg-[url(/images/mock_manager_photo_c.png)] bg-cover bg-no-repeat bg-center"
/>
))}
</div>
<div>
<button className="button-m text-[#7B60F3] font-medium flex items-center gap-[0.278vw]">
@@ -152,9 +157,7 @@ function ClientModal({ client }: { client: Client }) {
<div
key={session.id}
className="p-[0.278vw] border-b border-[#F6F6F6] cursor-pointer"
onClick={() => {
setModal(<SessionModal session={session} />);
}}
onClick={() => setModal(<SessionModal session={session} />)}
>
<div className="p-[0.833vw] flex justify-between items-center">
<div className="flex gap-[0.556vw] items-center">
@@ -166,9 +169,13 @@ function ClientModal({ client }: { client: Client }) {
<p className="caption-s text-[#BDBDBD] font-medium">
{isToday(new Date(session.updatedAt))
? "Сегодня"
: format(new Date(session.updatedAt), "d MMMM", {
locale: ru,
})}
: format(
new Date(session.updatedAt),
"dd.MM.yyyy",
{
locale: ru,
}
)}
</p>
</div>
</div>
@@ -196,7 +203,48 @@ function ClientModal({ client }: { client: Client }) {
</Button>
</div>
</div>
<div className="flex-1"></div>
<div className="flex-1 overflow-auto px-[1.111vw] py-[1.667vw] [scrollbar-width:thin] flex flex-col-reverse">
{client.sessions
.filter((session) => session.comments.length)
.map((session) => (
<div key={session.id} className="space-y-[1.111vw]">
<p className="text-center text-[#BDBDBD] caption-s font-medium">
{isToday(new Date(session.createdAt))
? "Сегодня"
: format(new Date(session.createdAt), "dd MMMM", {
locale: ru,
})}
</p>
<div className="space-y-[0.833vw]">
{session.comments.map((comment) => (
<SessionCommentItem
key={comment.id}
comment={comment}
session={session}
/>
))}
</div>
</div>
))}
{(client.sessions.length === 0 ||
client.sessions.filter((session) => session.comments.length)
.length === 0) && (
<div className="flex flex-col items-center gap-[1.111vw] w-[18.333vw] m-auto">
<div className="w-[13.889vw]">
<img src="/images/empty_ghost.png" alt="" />
</div>
<div className="space-y-[0.556vw]">
<p className="text-center title-m font-medium">
Пока что пусто
</p>
<p className="caption-s text-[#BDBDBD] font-medium text-center">
Здесь отображаются все комментарии по сеансам с текущим
клиентом
</p>
</div>
</div>
)}
</div>
</div>
</div>
);
+4 -4
View File
@@ -46,7 +46,7 @@ export default function CreateSessionModal({ targetServerId, client }: Props) {
useEffect(() => {
setSelectedApp(
selectedServer?.sessions?.[0]?.app ||
selectedServer?.apps?.[0].app ||
selectedServer?.appsToServers?.[0].app ||
null
);
}, [selectedServer]);
@@ -244,15 +244,15 @@ export default function CreateSessionModal({ targetServerId, client }: Props) {
<div className="flex flex-col gap-y-[0.833vw]">
<p className="title-s font-medium">Выберите параметры сеанса</p>
{selectedServer &&
selectedServer?.apps &&
selectedServer?.apps?.length > 0 && (
selectedServer?.appsToServers &&
selectedServer?.appsToServers?.length > 0 && (
<ProjectSelector
activeProject={
selectedServer?.sessions?.[0]?.status === "started"
? selectedApp
: null
}
projects={selectedServer?.apps.map(({ app }) => app)}
projects={selectedServer?.appsToServers.map(({ app }) => app)}
selectedProject={selectedApp}
setSelectedProject={setSelectedApp}
/>
+22 -8
View File
@@ -1,28 +1,42 @@
import { useMutation } from "@tanstack/react-query";
import { useQueryClient } from "@tanstack/react-query";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import useModalStore from "../../stores/useModalStore";
import { Session } from "../../types/Session";
import Button from "../Button";
import CurrentSessionModal from "./CurrentSessionModal";
import api from "../../utils/api";
import SpinIcon from "../icons/SpinIcon";
import SessionModal from "./SessionModal";
import { Server } from "../../types/Server";
function EndSessionModal({ session }: { session: Session }) {
const queryClient = useQueryClient();
const { setModal } = useModalStore();
const { setModal, setPosition } = useModalStore();
const { mutate: endSession, isPending } = useMutation({
mutationKey: ["sessions", session.id],
mutationFn: () =>
api.put(`sessions/${session.id}`, { json: { status: "ending" } }),
api
.put(`sessions/${session.id}`, { json: { status: "ending" } })
.json<Session>(),
onMutate: () => {
queryClient.invalidateQueries({ queryKey: ["sessions"] });
queryClient.invalidateQueries({ queryKey: ["last-started"] });
queryClient.invalidateQueries({ queryKey: ["servers"] });
// queryClient.invalidateQueries({ queryKey: ["sessions"] });
// queryClient.invalidateQueries({ queryKey: ["last-started"] });
// queryClient.invalidateQueries({ queryKey: ["servers"] });
setModal(null);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["servers"] });
queryClient.invalidateQueries({ queryKey: ["last-sessions"] });
setModal(null);
queryClient.invalidateQueries({ queryKey: ["sessions"] });
const servers = queryClient.getQueryData<Server[]>(["servers"]);
const updatedSession = servers
?.find((s) => s.id === session.serverId)
?.sessions?.find((s) => s.id === session.id);
if (updatedSession) {
setPosition("right");
setModal(<SessionModal session={updatedSession} />);
}
},
});
+5 -5
View File
@@ -15,8 +15,8 @@ import DownloadIcon from "../icons/DownloadIcon";
import ShareIcon from "../icons/ShareIcon";
function SessionModal({ session }: { session: Session }) {
const { data } = useQuery({
queryKey: ["file-list"],
const { data: files } = useQuery({
queryKey: ["file-list", session.id],
queryFn: () =>
api
.get("files", {
@@ -122,13 +122,13 @@ function SessionModal({ session }: { session: Session }) {
</span>
</Button>
</div>
{data && (
{files && (
<div className="flex flex-col gap-[1.111vw] bg-white rounded-[1.667vw] p-[1.111vw]">
<h3 className="title-s flex items-center font-medium gap-[0.556vw]">
<span>Документы по сеансу</span>
<Badge count={data?.length} />
<Badge count={files?.length} />
</h3>
<SessionFiles files={data} session={session} />
<SessionFiles files={files} session={session} />
<div className="flex w-full gap-[0.556vw]">
<Button variant="primary" size="large" className="w-full">
<span className="size-[1.111vw] text-[#7B60F3]">