feat: add ghost image and enhance CreateSessionModal with session existence check and improved server handling

This commit is contained in:
2025-06-05 13:31:21 +05:00
parent fbbfcd6b42
commit 4091626bc8
5 changed files with 96 additions and 23 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

+1 -4
View File
@@ -1,4 +1,3 @@
import { useQueryClient } from "@tanstack/react-query";
import { IServer } from "../types/IServer";
import useModalStore from "../stores/useModalStore";
import CreateSessionModal from "./modals/CreateSessionModal";
@@ -17,8 +16,6 @@ interface IDesktopCardProps {
export default function DesktopCard({ server }: IDesktopCardProps) {
const { setModal, setPosition } = useModalStore();
const queryClient = useQueryClient();
const servers = queryClient.getQueryData<IServer[]>(["servers"]);
// const { mutate: createSession } = useMutation({
// mutationFn: () =>
@@ -34,7 +31,7 @@ export default function DesktopCard({ server }: IDesktopCardProps) {
async function handleClickCreateSession() {
setPosition("right");
setModal(<CreateSessionModal servers={servers} targetServer={server} />);
setModal(<CreateSessionModal targetServerId={server.id} />);
}
return (
+19
View File
@@ -5,6 +5,10 @@ import api from "../utils/api";
import CurrentSessionCard from "./CurrentSessionCard";
import { ISession } from "../types/ISession";
import { AnimatePresence } from "motion/react";
import NewButton from "./NewButton";
import PlusIcon from "./icons/PlusIcon";
import useModalStore from "../stores/useModalStore";
import CreateSessionModal from "./modals/CreateSessionModal";
function Layout() {
const { data: currentStartedSessions } = useQuery({
@@ -18,6 +22,8 @@ function Layout() {
refetchInterval: 1000,
});
const { setModal, setPosition } = useModalStore();
return (
<div className="flex gap-[1.667vw] overflow-hidden">
<div className="flex-1"></div>
@@ -35,6 +41,19 @@ function Layout() {
/>
))}
</AnimatePresence>
<NewButton
variant="cta"
className="w-[18.889vw]"
onClick={() => {
setPosition("right");
setModal(<CreateSessionModal targetServerId={null} />);
}}
>
<span className="w-[1.111vw] h-[1.111vw] flex items-center justify-center">
<PlusIcon />
</span>
Создать сеанс
</NewButton>
</div>
</div>
);
-1
View File
@@ -13,7 +13,6 @@ function TableSelector({
selectedTable,
onSelect,
}: TableSelectorProps) {
console.log(tables);
return (
<div className="flex gap-[0.556vw] overflow-x-auto -mx-[1.111vw] pl-[1.111vw] [scrollbar-width:none]">
{tables.map((table) => (
+76 -18
View File
@@ -10,27 +10,34 @@ import NewInput from "../NewInput.tsx";
import StartSessionIcon from "../icons/StartSessionIcon.tsx";
import NewButton from "../NewButton.tsx";
import ProjectSelector from "../ProjectSelector.tsx";
import { useQueryClient, useMutation } from "@tanstack/react-query";
import { useQueryClient, useMutation, useQuery } from "@tanstack/react-query";
interface Props {
servers: IServer[] | undefined;
targetServer: IServer | null;
targetServerId: string | null;
}
export default function CreateSessionModal({
servers,
targetServer = null,
}: Props) {
export default function CreateSessionModal({ targetServerId }: Props) {
const { setModal } = useModalStore();
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [email, setEmail] = useState("");
const [isSessionExists, setIsSessionExists] = useState(false);
const queryClient = useQueryClient();
const { data: servers } = useQuery({
queryKey: ["servers"],
queryFn: () => api.get("servers?withLastSession=true").json<IServer[]>(),
});
const targetServer = targetServerId
? servers?.find((server) => server.id === targetServerId) || null
: null;
const [selectedServer, setSelectedServer] = useState<IServer | null>(
targetServer
);
const [selectedApp, setSelectedApp] = useState<IApp | null>(null);
const queryClient = useQueryClient();
const { mutate: createClient } = useMutation({
mutationFn: () => {
return api
@@ -65,26 +72,61 @@ export default function CreateSessionModal({
},
});
const { mutate: endSession } = useMutation({
mutationKey: ["sessions", selectedServer?.sessions?.[0]?.id],
mutationFn: () =>
api.put(`sessions/${selectedServer?.sessions?.[0]?.id}`, {
json: { status: "ending" },
}),
onMutate: () => queryClient.invalidateQueries({ queryKey: ["sessions"] }),
});
async function handleClickCreateSession(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
if (!name || !phone || !selectedServer || !selectedApp) return;
createClient(undefined, {
onSuccess: (client) => {
createSession(client.id);
},
onError: (error) => {
console.log(error);
},
});
if (
selectedServer?.sessions?.[0]?.status === "started" &&
!isSessionExists
) {
setIsSessionExists(true);
return;
}
if (isSessionExists) {
endSession(undefined, {
onSuccess: () => {
createClient(undefined, {
onSuccess: (client) => {
createSession(client.id);
},
onError: (error) => {
console.log(error);
},
});
},
onError: (error) => {
console.log("Ошибка при завершении сессии:", error);
},
});
} else {
createClient(undefined, {
onSuccess: (client) => {
createSession(client.id);
},
onError: (error) => {
console.log(error);
},
});
}
}
const ref = useRef<HTMLFormElement>(null);
return (
<form
className="rounded-[2.222vw] w-[25vw] min-h-[calc(100dvh-2.222vw)] bg-[#F0F0F0] flex flex-col overflow-hidden"
className="relative rounded-[2.222vw] w-[25vw] min-h-[calc(100dvh-2.222vw)] bg-[#F0F0F0] flex flex-col overflow-hidden"
onSubmit={handleClickCreateSession}
ref={ref}
>
@@ -131,6 +173,22 @@ export default function CreateSessionModal({
/>
)}
</div>
{isSessionExists && (
<div className="absolute inset-0 top-[11.806vw] bg-[#FFFFFF] flex flex-col gap-[1.111vw] items-center justify-center h-[31.458vw]">
<img
src="/images/ghost.png"
alt="ghost error"
className="w-[13.889vw] h-[11.806vw]"
/>
<div className="flex flex-col gap-[0.556vw] items-center">
<h3 className="title-m font-medium">Есть текущий сеанс</h3>
<p className="caption-s text-[#BDBDBD] text-center whitespace-pre-line">
{`На выбранном столе есть текущий сеанс.
При запуске нового текущий будет завершен.`}
</p>
</div>
</div>
)}
<NewButton
type="submit"
disabled={