frontPanel/src/ui_kit/FloatingSupportChat/FloatingSupportChat.tsx
2025-07-05 03:27:58 +03:00

219 lines
6.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { ReactNode, Ref } from "react";
import { forwardRef, useEffect, useState } from "react";
import {
Badge,
Box,
Dialog,
Fab,
Modal,
Slide,
Typography,
useMediaQuery,
useTheme,
} from "@mui/material";
import CircleDoubleDown from "./QuestionIcon";
import Chat from "./Chat";
import { TransitionProps } from "@mui/material/transitions";
import { useLocation } from "react-router-dom";
import { useTicketStore } from "@root/ticket";
import { useUserStore } from "@root/user";
import { TicketMessage } from "@frontend/kitui";
const animation = {
"@keyframes runningStripe": {
"0%": { left: "10%", backgroundColor: "transparent" },
"10%": { backgroundColor: "#ffffff" },
"50%": { backgroundColor: "#ffffff", transform: "translate(400px, 0)" },
"80%": { backgroundColor: "#ffffff" },
"100%": { backgroundColor: "transparent", boxShadow: "none", left: "100%" },
},
};
const Transition = forwardRef(function Transition(
props: TransitionProps & {
children: ReactNode;
},
ref: Ref<unknown>,
) {
return <Slide direction="up" ref={ref} {...props} />;
});
interface Props {
isChatOpened: boolean;
handleChatClickOpen: () => void;
handleChatClickClose: () => void;
handleChatClickSwitch: () => void;
sendMessage: (a: string) => Promise<boolean>;
sendFile: (a: File | undefined) => Promise<void>;
modalWarningType: string | null;
setModalWarningType: any;
greetingMessage: TicketMessage;
}
export default function FloatingSupportChat({
isChatOpened,
handleChatClickOpen,
handleChatClickClose,
handleChatClickSwitch,
sendMessage,
sendFile,
modalWarningType,
setModalWarningType,
greetingMessage,
}: Props) {
const [monitorType, setMonitorType] = useState<"desktop" | "mobile" | "">("");
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(800));
const location = useLocation();
const locationChat = location.pathname;
const user = useUserStore((state) => state.user?._id);
const { messages } = useTicketStore(
(state) => state[user ? "authData" : "unauthData"],
);
useEffect(() => {
const onResize = () => {
if (document.fullscreenElement) {
setMonitorType(isMobile ? "mobile" : "desktop");
return;
}
setMonitorType("");
};
window.addEventListener("resize", onResize);
return () => {
window.removeEventListener("resize", onResize);
};
}, [isMobile]);
return (
<Box
sx={{
position: "fixed",
right: "20px",
bottom: locationChat !== "/edit" ? "10px" : "100px",
display: "flex",
flexDirection: "column",
gap: "8px",
width: isChatOpened ? "clamp(200px, 100% - 40px, 454px)" : "64px",
zIndex: 10,
}}
>
<Chat
open={isChatOpened && (monitorType === "desktop" || !isMobile)}
sx={{ alignSelf: "start", width: "clamp(200px, 100%, 400px)" }}
sendMessage={sendMessage}
sendFile={sendFile}
greetingMessage={greetingMessage}
/>
<Dialog
fullScreen
open={isChatOpened && (monitorType === "mobile" || isMobile)}
onClose={handleChatClickClose}
TransitionComponent={Transition}
>
<Chat
open={isChatOpened && (monitorType === "mobile" || isMobile)}
onclickArrow={handleChatClickClose}
sendMessage={sendMessage}
sendFile={sendFile}
greetingMessage={greetingMessage}
/>
</Dialog>
<Fab
disableRipple
sx={{
position: "relative",
backgroundColor: "rgba(255, 255, 255, 0.7)",
borderRadius: "50%",
alignSelf: "end",
padding: "0px",
overflow: "hidden",
height: "54px",
width: "54px",
transform: !isMobile ? "scale(1.2)" : null,
"&:hover": {
background: "rgba(255, 255, 255, 0.7)",
},
}}
variant={"extended"}
onClick={() => {
handleChatClickSwitch();
}}
>
{!isChatOpened && (
<Box
sx={{
position: "absolute",
bgcolor: "#FFFFFF",
height: "100px",
width: "25px",
animation: "runningStripe linear 3s infinite",
transform:
" skew(-10deg) rotate(70deg) skewX(20deg) skewY(10deg)",
boxShadow: "0px 3px 12px rgba(126, 42, 234, 0.1)",
opacity: "0.4",
...animation,
}}
/>
)}
<Badge
badgeContent={
messages.filter(({ shown }) => shown?.me !== 1).length || 0
}
sx={{
"& .MuiBadge-badge": {
display: isChatOpened ? "none" : "flex",
color: "#FFFFFF",
background: theme.palette.brightPurple.main,
top: "4px",
right: "4px",
transform: "scale(0.8) translate(50%, -50%)",
},
}}
>
<CircleDoubleDown />
</Badge>
</Fab>
<Modal
open={modalWarningType !== null}
onClose={() => setModalWarningType(null)}
>
<Box
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: isMobile ? 300 : 400,
bgcolor: "background.paper",
borderRadius: 3,
boxShadow: 24,
p: 4,
}}
>
<CurrentModal status={modalWarningType} />
</Box>
</Modal>
</Box>
);
}
const CurrentModal = ({ status }: { status: ["errorType" | "errorSize"] }) => {
switch (status) {
case null:
return null;
case "errorType":
return <Typography>Выбран некорректный тип файла</Typography>;
case "errorSize":
return (
<Typography>Файл слишком большой. Максимальный размер 50 МБ</Typography>
);
default:
return <></>;
}
};