Merge branch 'support-chat-logic' into 'vis-fix'
feat: support chat logic See merge request frontend/squiz!178
This commit is contained in:
commit
5bbbfab6ca
@ -1,6 +1,5 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
|
||||
import CustomNumberField from "@ui_kit/CustomNumberField";
|
||||
|
||||
@ -27,40 +26,8 @@ export default function SliderOptions({
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||
const [switchState, setSwitchState] = useState("setting");
|
||||
const [stepError, setStepError] = useState("");
|
||||
const [startError, setStartError] = useState<boolean>(false);
|
||||
const [minError, setMinError] = useState<boolean>(false);
|
||||
const [maxError, setMaxError] = useState<boolean>(false);
|
||||
const startValueDebounce = useDebouncedCallback((value) => {
|
||||
updateQuestion(question.id, (question) => {
|
||||
if (question.type !== "number") return;
|
||||
|
||||
question.content.start = value;
|
||||
});
|
||||
}, 2000);
|
||||
|
||||
useEffect(() => {
|
||||
const min = Number(question.content.range.split("—")[0]);
|
||||
const max = Number(question.content.range.split("—")[1]);
|
||||
const start = Number(question.content.start);
|
||||
|
||||
if (start < min) {
|
||||
setStartError(true);
|
||||
startValueDebounce(min);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (start > max && min < max) {
|
||||
setStartError(true);
|
||||
startValueDebounce(max);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (start >= min && start <= max) {
|
||||
setStartError(false);
|
||||
}
|
||||
}, [question.content.range, question.content.start]);
|
||||
|
||||
useEffect(() => {
|
||||
const min = Number(question.content.range.split("—")[0]);
|
||||
@ -211,7 +178,6 @@ export default function SliderOptions({
|
||||
sx={{ maxWidth: "310px", width: "100%" }}
|
||||
placeholder={"50"}
|
||||
value={String(question.content.start)}
|
||||
emptyError={startError}
|
||||
onChange={({ target }) => {
|
||||
updateQuestion(question.id, (question) => {
|
||||
if (question.type !== "number") return;
|
||||
|
@ -33,15 +33,16 @@ import {
|
||||
useEventListener,
|
||||
createTicket,
|
||||
} from "@frontend/kitui";
|
||||
import { sendTicketMessage } from "../../api/ticket";
|
||||
import { sendTicketMessage, shownMessage } from "../../api/ticket";
|
||||
import ArrowLeft from "@icons/questionsPage/arrowLeft";
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
sx?: SxProps<Theme>;
|
||||
onclickArrow?: () => void;
|
||||
}
|
||||
|
||||
export default function Chat({ sx, onclickArrow }: Props) {
|
||||
export default function Chat({ open = false, sx, onclickArrow }: Props) {
|
||||
const theme = useTheme();
|
||||
const upMd = useMediaQuery(theme.breakpoints.up("md"));
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(800));
|
||||
@ -129,6 +130,16 @@ export default function Chat({ sx, onclickArrow }: Props) {
|
||||
[lastMessageId],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
const newMessages = messages.filter(({ shown }) => shown.me !== 1);
|
||||
|
||||
newMessages.map(async ({ id }) => {
|
||||
await shownMessage(id);
|
||||
});
|
||||
}
|
||||
}, [open, messages]);
|
||||
|
||||
async function handleSendMessage() {
|
||||
if (!messageField || isMessageSending) return;
|
||||
|
||||
@ -194,137 +205,143 @@ export default function Chat({ sx, onclickArrow }: Props) {
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: isMobile ? "100%" : "clamp(250px, calc(100vh - 90px), 600px)",
|
||||
backgroundColor: "#944FEE",
|
||||
borderRadius: "8px",
|
||||
...sx,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "9px",
|
||||
pl: "22px",
|
||||
pt: "12px",
|
||||
pb: "20px",
|
||||
filter: "drop-shadow(0px 3px 12px rgba(37, 39, 52, 0.3))",
|
||||
}}
|
||||
>
|
||||
{isMobile && (
|
||||
<IconButton onClick={onclickArrow}>
|
||||
<ArrowLeft color="white" />
|
||||
</IconButton>
|
||||
)}
|
||||
<UserCircleIcon />
|
||||
<>
|
||||
{open && (
|
||||
<Box
|
||||
sx={{
|
||||
mt: "5px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "3px",
|
||||
color: theme.palette.common.white,
|
||||
height: isMobile
|
||||
? "100%"
|
||||
: "clamp(250px, calc(100vh - 90px), 600px)",
|
||||
backgroundColor: "#944FEE",
|
||||
borderRadius: "8px",
|
||||
...sx,
|
||||
}}
|
||||
>
|
||||
<Typography>Мария</Typography>
|
||||
<Typography
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
lineHeight: "19px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "9px",
|
||||
pl: "22px",
|
||||
pt: "12px",
|
||||
pb: "20px",
|
||||
filter: "drop-shadow(0px 3px 12px rgba(37, 39, 52, 0.3))",
|
||||
}}
|
||||
>
|
||||
онлайн-консультант
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
backgroundColor: "white",
|
||||
borderRadius: "8px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
ref={chatBoxRef}
|
||||
sx={{
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
flexBasis: 0,
|
||||
flexDirection: "column",
|
||||
gap: upMd ? "20px" : "16px",
|
||||
px: upMd ? "20px" : "5px",
|
||||
py: upMd ? "20px" : "13px",
|
||||
overflowY: "auto",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
{sessionData &&
|
||||
messages.map((message) => (
|
||||
<ChatMessage
|
||||
unAuthenticated
|
||||
key={message.id}
|
||||
text={message.message}
|
||||
createdAt={message.created_at}
|
||||
isSelf={sessionData.sessionId === message.user_id}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
<FormControl fullWidth sx={{ borderTop: "1px solid black" }}>
|
||||
<InputBase
|
||||
value={messageField}
|
||||
fullWidth
|
||||
placeholder="Введите сообщение..."
|
||||
id="message"
|
||||
multiline
|
||||
onKeyDown={handleTextfieldKeyPress}
|
||||
{isMobile && (
|
||||
<IconButton onClick={onclickArrow}>
|
||||
<ArrowLeft color="white" />
|
||||
</IconButton>
|
||||
)}
|
||||
<UserCircleIcon />
|
||||
<Box
|
||||
sx={{
|
||||
mt: "5px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "3px",
|
||||
color: theme.palette.common.white,
|
||||
}}
|
||||
>
|
||||
<Typography>Мария</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
lineHeight: "19px",
|
||||
}}
|
||||
>
|
||||
онлайн-консультант
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
p: 0,
|
||||
flexGrow: 1,
|
||||
backgroundColor: "white",
|
||||
borderRadius: "8px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
inputProps={{
|
||||
sx: {
|
||||
fontWeight: 400,
|
||||
fontSize: "16px",
|
||||
lineHeight: "19px",
|
||||
pt: upMd ? "30px" : "28px",
|
||||
pb: upMd ? "30px" : "24px",
|
||||
px: "19px",
|
||||
maxHeight: "calc(19px * 5)",
|
||||
color: "black",
|
||||
},
|
||||
}}
|
||||
onChange={(e) => setMessageField(e.target.value)}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<IconButton
|
||||
disabled={isMessageSending}
|
||||
onClick={handleSendMessage}
|
||||
sx={{
|
||||
height: "53px",
|
||||
width: "53px",
|
||||
mr: "13px",
|
||||
p: 0,
|
||||
opacity: isMessageSending ? 0.3 : 1,
|
||||
}}
|
||||
>
|
||||
<SendIcon
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
ref={chatBoxRef}
|
||||
sx={{
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
flexBasis: 0,
|
||||
flexDirection: "column",
|
||||
gap: upMd ? "20px" : "16px",
|
||||
px: upMd ? "20px" : "5px",
|
||||
py: upMd ? "20px" : "13px",
|
||||
overflowY: "auto",
|
||||
flexGrow: 1,
|
||||
}}
|
||||
>
|
||||
{sessionData &&
|
||||
messages.map((message) => (
|
||||
<ChatMessage
|
||||
unAuthenticated
|
||||
key={message.id}
|
||||
text={message.message}
|
||||
createdAt={message.created_at}
|
||||
isSelf={sessionData.sessionId === message.user_id}
|
||||
/>
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
<FormControl fullWidth sx={{ borderTop: "1px solid black" }}>
|
||||
<InputBase
|
||||
value={messageField}
|
||||
fullWidth
|
||||
placeholder="Введите сообщение..."
|
||||
id="message"
|
||||
multiline
|
||||
onKeyDown={handleTextfieldKeyPress}
|
||||
sx={{
|
||||
width: "100%",
|
||||
p: 0,
|
||||
}}
|
||||
inputProps={{
|
||||
sx: {
|
||||
fontWeight: 400,
|
||||
fontSize: "16px",
|
||||
lineHeight: "19px",
|
||||
pt: upMd ? "30px" : "28px",
|
||||
pb: upMd ? "30px" : "24px",
|
||||
px: "19px",
|
||||
maxHeight: "calc(19px * 5)",
|
||||
color: "black",
|
||||
},
|
||||
}}
|
||||
onChange={(e) => setMessageField(e.target.value)}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<IconButton
|
||||
disabled={isMessageSending}
|
||||
onClick={handleSendMessage}
|
||||
sx={{
|
||||
height: "53px",
|
||||
width: "53px",
|
||||
mr: "13px",
|
||||
p: 0,
|
||||
opacity: isMessageSending ? 0.3 : 1,
|
||||
}}
|
||||
>
|
||||
<SendIcon
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
/>
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
useMediaQuery,
|
||||
Slide,
|
||||
Dialog,
|
||||
Badge,
|
||||
} from "@mui/material";
|
||||
import { ReactNode, useState } from "react";
|
||||
import CircleDoubleDown from "./QuestionIcon";
|
||||
@ -12,6 +13,7 @@ import * as React from "react";
|
||||
import Chat from "./Chat";
|
||||
import { TransitionProps } from "@mui/material/transitions";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useUnauthTicketStore } from "@root/unauthTicket";
|
||||
|
||||
const animation = {
|
||||
"@keyframes runningStripe": {
|
||||
@ -39,6 +41,7 @@ export default function FloatingSupportChat() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const location = useLocation();
|
||||
const locationChat = location.pathname;
|
||||
const { messages } = useUnauthTicketStore((state) => state);
|
||||
|
||||
const handleClickOpen = () => {
|
||||
setOpen(true);
|
||||
@ -60,9 +63,10 @@ export default function FloatingSupportChat() {
|
||||
zIndex: 10,
|
||||
}}
|
||||
>
|
||||
{isChatOpened && (
|
||||
<Chat sx={{ alignSelf: "start", width: "clamp(200px, 100%, 400px)" }} />
|
||||
)}
|
||||
<Chat
|
||||
open={isChatOpened}
|
||||
sx={{ alignSelf: "start", width: "clamp(200px, 100%, 400px)" }}
|
||||
/>
|
||||
<Dialog
|
||||
fullScreen
|
||||
open={open}
|
||||
@ -112,7 +116,21 @@ export default function FloatingSupportChat() {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<CircleDoubleDown />
|
||||
<Badge
|
||||
badgeContent={messages.filter(({ shown }) => shown.me !== 1).length}
|
||||
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 isUp={isChatOpened} />
|
||||
</Badge>
|
||||
</Fab>
|
||||
</Box>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user