diff --git a/src/index.tsx b/src/index.tsx
index 3f4aa62..0223de9 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -23,6 +23,7 @@ import DiscountManagement from "@root/pages/dashboard/Content/DiscountManagement
import { PromocodeManagement } from "@root/pages/dashboard/Content/PromocodeManagement";
import { SettingRoles } from "@pages/Setting/SettingRoles";
import Support from "@pages/dashboard/Content/Support/Support";
+import ChatImageNewWindow from "@pages/dashboard/Content/Support/ChatImageNewWindow";
import theme from "./theme";
import "./index.css";
@@ -111,6 +112,7 @@ root.render(
/>
))}
+ } />
} />
diff --git a/src/pages/dashboard/Content/Support/Chat/Chat.tsx b/src/pages/dashboard/Content/Support/Chat/Chat.tsx
index ce6b471..8907b0a 100644
--- a/src/pages/dashboard/Content/Support/Chat/Chat.tsx
+++ b/src/pages/dashboard/Content/Support/Chat/Chat.tsx
@@ -9,8 +9,39 @@ import { TicketMessage } from "@root/model/ticket";
import { sendTicketMessage } from "@root/api/tickets";
import { enqueueSnackbar } from "notistack";
import { useTicketStore } from "@root/stores/tickets";
-import { getMessageFromFetchError, throttle, useEventListener, useSSESubscription, useTicketMessages, useToken } from "@frontend/kitui";
+import { getMessageFromFetchError, makeRequest, throttle, useEventListener, useSSESubscription, useTicketMessages, useToken } from "@frontend/kitui";
+import ChatImage from "./ChatImage";
+import ChatDocument from "./ChatDocument";
+import ChatVideo from "./ChatVideo";
+import ChatMessage from "./ChatMessage";
+import { ACCEPT_SEND_MEDIA_TYPES_MAP, MAX_FILE_SIZE, MAX_PHOTO_SIZE, MAX_VIDEO_SIZE } from "./fileUpload";
+const tooLarge = "Файл слишком большой"
+const checkAcceptableMediaType = (file: File) => {
+ if (file === null) return ""
+
+ const segments = file?.name.split('.');
+ const extension = segments[segments.length - 1];
+ const type = extension.toLowerCase();
+
+ console.log(type)
+ switch (type) {
+ case ACCEPT_SEND_MEDIA_TYPES_MAP.document.find(name => name === type):
+ if (file.size > MAX_FILE_SIZE) return tooLarge
+ return ""
+
+ case ACCEPT_SEND_MEDIA_TYPES_MAP.picture.find(name => name === type):
+ if (file.size > MAX_PHOTO_SIZE) return tooLarge
+ return ""
+
+ case ACCEPT_SEND_MEDIA_TYPES_MAP.video.find(name => name === type):
+ if (file.size > MAX_VIDEO_SIZE) return tooLarge
+ return ""
+
+ default:
+ return "Не удалось отправить файл. Недопустимый тип"
+ }
+ }
export default function Chat() {
const token = useToken();
@@ -26,6 +57,8 @@ export default function Chat() {
const isPreventAutoscroll = useMessageStore(state => state.isPreventAutoscroll);
const fetchState = useMessageStore(state => state.ticketMessagesFetchState);
const lastMessageId = useMessageStore(state => state.lastMessageId);
+ const fileInputRef = useRef(null);
+ const [disableFileButton, setDisableFileButton] = useState(false);
const ticket = tickets.find(ticket => ticket.id === ticketId);
@@ -107,7 +140,47 @@ export default function Chat() {
setMessageField("");
}
- function handleAddAttachment() { }
+ const sendFile = async (file: File) => {
+ if (file === undefined) return true;
+
+ // const isFileTypeAccepted = ACCEPT_SEND_FILE_TYPES_MAP.some(
+ // fileType => file.name.toLowerCase().endsWith(fileType)
+ // );
+ // console.log(file.name.toLowerCase().endsWith(".png"))
+ // if (!isFileTypeAccepted) return setModalWarningType("errorType");
+ let data;
+
+ const ticketId = ticket?.id
+ if (ticketId !== undefined) {
+ try {
+ const body = new FormData();
+
+ body.append(file.name, file);
+ body.append("ticket", ticketId);
+ await makeRequest({
+ url: process.env.REACT_APP_DOMAIN + "/heruvym/sendFiles",
+ body: body,
+ method: "POST",
+ });
+ } catch (error: any) {
+ const errorMessage = getMessageFromFetchError(error);
+ if (errorMessage) enqueueSnackbar(errorMessage);
+ }
+ return true;
+ }
+ };
+ const sendFileHC = async (file: File) => {
+ console.log(file)
+ const check = checkAcceptableMediaType(file)
+ if (check.length > 0) {
+ enqueueSnackbar(check)
+ return
+ }
+ setDisableFileButton(true)
+ await sendFile(file)
+ setDisableFileButton(false)
+ console.log(disableFileButton)
+ };
function handleTextfieldKeyPress(e: KeyboardEvent) {
if (e.key === "Enter" && !e.shiftKey) {
@@ -145,9 +218,66 @@ export default function Chat() {
colorScheme: "dark",
}}
>
- {ticket && messages.map(message =>
-
- )}
+ {ticket &&
+ messages.map((message) => {
+ const isFileVideo = () => {
+ if (message.files) {
+ return (ACCEPT_SEND_MEDIA_TYPES_MAP.video.some((fileType) =>
+ message.files[0].toLowerCase().endsWith(fileType),
+ ))
+ }
+ };
+ const isFileImage = () => {
+ if (message.files) {
+ return (ACCEPT_SEND_MEDIA_TYPES_MAP.picture.some((fileType) =>
+ message.files[0].toLowerCase().endsWith(fileType),
+ ))
+ }
+ };
+ const isFileDocument = () => {
+ if (message.files) {
+ return (ACCEPT_SEND_MEDIA_TYPES_MAP.document.some((fileType) =>
+ message.files[0].toLowerCase().endsWith(fileType),
+ ))
+ }
+ };
+ if (message.files !== null && message.files.length > 0 && isFileImage()) {
+ return
+ }
+ if (message.files !== null && message.files.length > 0 && isFileVideo()) {
+ return
+ }
+ if (message.files !== null && message.files.length > 0 && isFileDocument()) {
+ return
+ }
+ return
+
+ })
+ }
{ticket &&
{
+ console.log(disableFileButton)
+ if (!disableFileButton) fileInputRef.current?.click()
+ }}
sx={{
height: "45px",
width: "45px",
p: 0,
}}
>
+ {
+ if (e.target.files?.[0]) sendFileHC(e.target.files?.[0]);
+ }}
+ style={{ display: "none" }}
+ type="file"
+ />
diff --git a/src/pages/dashboard/Content/Support/Chat/ChatDocument.tsx b/src/pages/dashboard/Content/Support/Chat/ChatDocument.tsx
new file mode 100644
index 0000000..f180a67
--- /dev/null
+++ b/src/pages/dashboard/Content/Support/Chat/ChatDocument.tsx
@@ -0,0 +1,61 @@
+import { Box, Link, Typography, useMediaQuery, useTheme } from "@mui/material";
+import DownloadIcon from '@mui/icons-material/Download';
+
+interface Props {
+ unAuthenticated?: boolean;
+ isSelf: boolean;
+ file: string;
+ createdAt: string;
+}
+
+export default function ChatDocument({
+ unAuthenticated = false,
+ isSelf,
+ file,
+ createdAt,
+}: Props) {
+ const theme = useTheme();
+
+ const date = new Date(createdAt);
+
+ return (
+
+
+ {new Date(createdAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/pages/dashboard/Content/Support/Chat/ChatImage.tsx b/src/pages/dashboard/Content/Support/Chat/ChatImage.tsx
new file mode 100644
index 0000000..8842d48
--- /dev/null
+++ b/src/pages/dashboard/Content/Support/Chat/ChatImage.tsx
@@ -0,0 +1,67 @@
+import {
+ Box,
+ ButtonBase,
+ Link,
+ Typography,
+ useMediaQuery,
+ useTheme,
+} from "@mui/material";
+import { useNavigate } from "react-router-dom";
+
+interface Props {
+ unAuthenticated?: boolean;
+ isSelf: boolean;
+ file: string;
+ createdAt: string;
+}
+
+export default function ChatImage({
+ unAuthenticated = false,
+ isSelf,
+ file,
+ createdAt,
+}: Props) {
+ const theme = useTheme();
+ const upMd = useMediaQuery(theme.breakpoints.up("md"));
+ const navigate = useNavigate();
+
+
+ return (
+
+
+ {new Date(createdAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/pages/dashboard/Content/Support/Chat/ChatMessage.tsx b/src/pages/dashboard/Content/Support/Chat/ChatMessage.tsx
new file mode 100644
index 0000000..0c944a0
--- /dev/null
+++ b/src/pages/dashboard/Content/Support/Chat/ChatMessage.tsx
@@ -0,0 +1,52 @@
+import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
+
+interface Props {
+ unAuthenticated?: boolean;
+ isSelf: boolean;
+ text: string;
+ createdAt: string;
+}
+
+export default function ChatMessage({
+ unAuthenticated = false,
+ isSelf,
+ text,
+ createdAt,
+}: Props) {
+ const theme = useTheme();
+ const upMd = useMediaQuery(theme.breakpoints.up("md"));
+
+
+
+ return (
+
+
+ {new Date(createdAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
+
+
+
+ {text}
+
+
+
+ );
+}
diff --git a/src/pages/dashboard/Content/Support/Chat/ChatVideo.tsx b/src/pages/dashboard/Content/Support/Chat/ChatVideo.tsx
new file mode 100644
index 0000000..5fb281f
--- /dev/null
+++ b/src/pages/dashboard/Content/Support/Chat/ChatVideo.tsx
@@ -0,0 +1,68 @@
+import {
+ Box,
+ ButtonBase,
+ Link,
+ Typography,
+ useMediaQuery,
+ useTheme,
+} from "@mui/material";
+import { useNavigate } from "react-router-dom";
+import { useEffect } from "react";
+
+interface Props {
+ unAuthenticated?: boolean;
+ isSelf: boolean;
+ file: string;
+ createdAt: string;
+}
+
+export default function ChatImage({
+ unAuthenticated = false,
+ isSelf,
+ file,
+ createdAt,
+}: Props) {
+ const theme = useTheme();
+ const upMd = useMediaQuery(theme.breakpoints.up("md"));
+ const navigate = useNavigate();
+
+
+ return (
+
+
+ {new Date(createdAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/pages/dashboard/Content/Support/Chat/fileUpload.ts b/src/pages/dashboard/Content/Support/Chat/fileUpload.ts
new file mode 100644
index 0000000..19410e1
--- /dev/null
+++ b/src/pages/dashboard/Content/Support/Chat/fileUpload.ts
@@ -0,0 +1,9 @@
+export const MAX_FILE_SIZE = 10485760;
+export const MAX_PHOTO_SIZE = 5242880;
+export const MAX_VIDEO_SIZE = 52428800;
+
+export const ACCEPT_SEND_MEDIA_TYPES_MAP = {
+ picture: ["jpg", "png"],
+ video: ["mp4"],
+ document: ["doc", "docx", "pdf", "txt", "xlsx", "csv"],
+ } as const;
\ No newline at end of file
diff --git a/src/pages/dashboard/Content/Support/ChatImageNewWindow.tsx b/src/pages/dashboard/Content/Support/ChatImageNewWindow.tsx
new file mode 100644
index 0000000..3adc7e4
--- /dev/null
+++ b/src/pages/dashboard/Content/Support/ChatImageNewWindow.tsx
@@ -0,0 +1,20 @@
+import { Box } from "@mui/material";
+import { useLocation } from "react-router-dom";
+
+export default function ChatImageNewWindow() {
+ const location = useLocation();
+ console.log(location);
+ const srcImage = location.pathname.split("image/")[1];
+ return (
+ <>
+
+ >
+ );
+}