diff --git a/public/images/smile-ghost.png b/public/images/smile-ghost.png new file mode 100644 index 0000000..ce23bb8 Binary files /dev/null and b/public/images/smile-ghost.png differ diff --git a/src/components/ClientCard.tsx b/src/components/ClientCard.tsx new file mode 100644 index 0000000..59046fc --- /dev/null +++ b/src/components/ClientCard.tsx @@ -0,0 +1,28 @@ +import { IUser } from "../types/IUser"; +import ChevronRightIcon from "./icons/ChevronRightIcon"; +import NewButton from "./NewButton"; + +function ClientCard({ client }: { client: IUser }) { + return ( + <> + +
+

Клиент

+

{client.name}

+
+
+ {!client.email && ( +

+ Добавьте email +

+ )} + + + +
+
+ + ); +} + +export default ClientCard; diff --git a/src/components/CurrentSessionCard.tsx b/src/components/CurrentSessionCard.tsx index 91401e1..b0c8929 100644 --- a/src/components/CurrentSessionCard.tsx +++ b/src/components/CurrentSessionCard.tsx @@ -28,6 +28,9 @@ function CurrentSessionCard({ queryClient.invalidateQueries({ queryKey: ["last-started"] }); queryClient.invalidateQueries({ queryKey: ["servers"] }); }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["last-sessions"] }); + }, }); return ( diff --git a/src/components/DesktopCard.tsx b/src/components/DesktopCard.tsx index 8ff993b..028d5e1 100644 --- a/src/components/DesktopCard.tsx +++ b/src/components/DesktopCard.tsx @@ -84,7 +84,7 @@ export default function DesktopCard({ server }: IDesktopCardProps) { ) : server.status === "offline" ? ( - + diff --git a/src/components/SessionCard.tsx b/src/components/SessionCard.tsx index db1f79f..26d3e3c 100644 --- a/src/components/SessionCard.tsx +++ b/src/components/SessionCard.tsx @@ -1,8 +1,17 @@ +import useModalStore from "../stores/useModalStore"; import { ISession } from "../types/ISession"; +import SessionModal from "./modals/SessionModal"; function SessionCard({ session }: { session: ISession }) { + const { setModal, setPosition } = useModalStore(); return ( -
+
{ + setModal(); + setPosition("right"); + }} + >
diff --git a/src/components/icons/DownloadIcon.tsx b/src/components/icons/DownloadIcon.tsx new file mode 100644 index 0000000..fff22ac --- /dev/null +++ b/src/components/icons/DownloadIcon.tsx @@ -0,0 +1,15 @@ +function DownloadIcon() { + return ( + + + + ); +} + +export default DownloadIcon; diff --git a/src/components/icons/MagicIcon.tsx b/src/components/icons/MagicIcon.tsx new file mode 100644 index 0000000..654f352 --- /dev/null +++ b/src/components/icons/MagicIcon.tsx @@ -0,0 +1,12 @@ +function MagicIcon() { + return ( + + + + ); +} + +export default MagicIcon; diff --git a/src/components/icons/ShareIcon.tsx b/src/components/icons/ShareIcon.tsx new file mode 100644 index 0000000..4ee68a6 --- /dev/null +++ b/src/components/icons/ShareIcon.tsx @@ -0,0 +1,15 @@ +function ShareIcon() { + return ( + + + + ); +} + +export default ShareIcon; diff --git a/src/components/modals/CreateSessionModal.tsx b/src/components/modals/CreateSessionModal.tsx index 6f0a9b8..b644e50 100644 --- a/src/components/modals/CreateSessionModal.tsx +++ b/src/components/modals/CreateSessionModal.tsx @@ -144,7 +144,7 @@ export default function CreateSessionModal({ targetServerId }: Props) { return (
diff --git a/src/components/modals/CurrentSessionModal.tsx b/src/components/modals/CurrentSessionModal.tsx index 1d83d0a..6d36050 100644 --- a/src/components/modals/CurrentSessionModal.tsx +++ b/src/components/modals/CurrentSessionModal.tsx @@ -18,7 +18,15 @@ function CurrentSessionModal({ session }: { session: ISession }) { api.put(`sessions/${session.id}`, { json: { status: "ending" }, }), - onMutate: () => queryClient.invalidateQueries({ queryKey: ["sessions"] }), + onMutate: () => + queryClient.invalidateQueries({ + queryKey: ["sessions"], + }), + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: ["last-sessions"], + }); + }, }); const [now, setNow] = useState(Date.now()); diff --git a/src/components/modals/SessionModal.tsx b/src/components/modals/SessionModal.tsx new file mode 100644 index 0000000..2fd9999 --- /dev/null +++ b/src/components/modals/SessionModal.tsx @@ -0,0 +1,150 @@ +import { ISession } from "../../types/ISession"; +import { format } from "date-fns"; +import { ru } from "date-fns/locale"; +import getIntervalDuration from "../../utils/interval-duration"; +import MagicIcon from "../icons/MagicIcon"; +import NewButton from "../NewButton"; +import ChevronRightIcon from "../icons/ChevronRightIcon"; +import Badge from "../Badge"; +import ClientCard from "../ClientCard"; +import DownloadIcon from "../icons/DownloadIcon"; +import ShareIcon from "../icons/ShareIcon"; + +function SessionModal({ session }: { session: ISession }) { + console.log(session); + return ( +
+
+
+

{format(session.createdAt, "dd MMMM yyyy", { locale: ru })}

+

, {format(session.createdAt, "HH:mm")}

+
+
+
+
+
+
+
+

{session.owner.fullname}

+

+ Продолжительность:{" "} + {getIntervalDuration(session.createdAt, session.updatedAt)} +

+
+
+
+

Информация о сеансе

+
+

+ + Сценарии: + + Добавить в бэкенд +

+

+ + Интерактивный стол: + + + {session.server.name} + +

+

+ + Продолжительность сеанса: + + + {getIntervalDuration(session.createdAt, session.updatedAt)} + +

+

+ + Проект: + + + {session.app.name} + +

+
+ +
+
+

+ Речевая  + + аналитика  + + + + +

+
+

+ + Эффективность встречи: + + + Высокая + +

+

+ + Бюджет клиента: + + 8 500 000 ₽ +

+
+
+ Клиент проявил высокий интерес к объекту, особенно к варианту с + улучшенной отделкой. Основной вопрос для принятия решения — + согласование с семьей и выбор этажа. Необходимо подготовить + предварительный договор к следующей встрече. +
+ + Весь отчёт по встречи + +
+
+

+ Документы по сеансу +

+
+ + + + + Скачать архивом + + + + + + +
+
+
+
+
+ {session.comments.length > 0 ? ( +
Комменты
+ ) : ( +
+ ghost +
+

Оставьте заметку

+

+ {`В дальнейшем это поможет быстро найти + клиента и не запутаться.`} +

+
+
+ )} +
+
+
+
+
+ ); +} + +export default SessionModal; diff --git a/src/pages/DashboardPage.tsx b/src/pages/DashboardPage.tsx index 70f2d5e..fa1316c 100644 --- a/src/pages/DashboardPage.tsx +++ b/src/pages/DashboardPage.tsx @@ -8,6 +8,7 @@ import { ISession } from "../types/ISession"; import SessionCard from "../components/SessionCard"; import NewButton from "../components/NewButton"; import ChevronRightIcon from "../components/icons/ChevronRightIcon"; +import { useEffect } from "react"; function DashboardPage() { const { data: me } = useQuery({ @@ -23,7 +24,7 @@ function DashboardPage() { }); const { data: sessions } = useQuery({ - queryKey: ["sessions", { limit: 5 }], + queryKey: ["last-sessions"], queryFn: () => api.get("sessions", { searchParams: { limit: 5 } }).json(), enabled: !!me, @@ -42,6 +43,10 @@ function DashboardPage() { // } // } + useEffect(() => { + console.log(sessions); + }, [sessions]); + return (
@@ -63,7 +68,10 @@ function DashboardPage() {
{sessions - ?.filter((session) => session.status === "ended") + ?.filter( + (session) => + session.status === "ended" || session.status === "ending" + ) .map((session) => ( ))} diff --git a/src/types/IComments.ts b/src/types/IComments.ts new file mode 100644 index 0000000..f1f625a --- /dev/null +++ b/src/types/IComments.ts @@ -0,0 +1,8 @@ +export interface IComment { + id: string; + text: string; + createdAt: Date; + updatedAt: Date; + ownerId: string; + sessionId: string; +} diff --git a/src/types/ISession.ts b/src/types/ISession.ts index 7461e3b..b974465 100644 --- a/src/types/ISession.ts +++ b/src/types/ISession.ts @@ -1,4 +1,5 @@ import { IApp } from "./IApp"; +import { IComment } from "./IComments"; import { IOwner } from "./IOwner"; import { IServer } from "./IServer"; import { IUser } from "./IUser"; @@ -9,10 +10,12 @@ export interface ISession { serverId: string; clientId: string; companyId: string; + comments: IComment[]; status: "starting" | "started" | "restarted" | "ending" | "ended"; server: IServer; client: IUser; app: IApp; owner: IOwner; createdAt: Date; + updatedAt: Date; } diff --git a/src/utils/interval-duration.tsx b/src/utils/interval-duration.tsx new file mode 100644 index 0000000..49861df --- /dev/null +++ b/src/utils/interval-duration.tsx @@ -0,0 +1,14 @@ +import { intervalToDuration } from "date-fns"; + +function getIntervalDuration(start: Date, end: Date) { + const duration = intervalToDuration({ + start: start, + end: end, + }); + const hours = (duration.hours || 0).toString().padStart(2, "0"); + const minutes = (duration.minutes || 0).toString().padStart(2, "0"); + const seconds = (duration.seconds || 0).toString().padStart(2, "0"); + return `${hours}:${minutes}:${seconds}`; +} + +export default getIntervalDuration;