Merge branch 'refactoring-applications-page' into dev
This commit is contained in:
commit
30e97416fa
@ -1,7 +1,36 @@
|
||||
import { makeRequest } from "@frontend/kitui";
|
||||
import { RawResult } from "@model/result/result";
|
||||
|
||||
async function getResultList(quizId, page: number, body: any) {
|
||||
return makeRequest<unknown, unknown>({
|
||||
interface IResultListBody {
|
||||
to: number;
|
||||
from: string;
|
||||
new: boolean;
|
||||
page: number;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
export interface IAnswerResult {
|
||||
Browser: string;
|
||||
CreatedAt: string;
|
||||
Deleted: boolean;
|
||||
Device: string;
|
||||
DeviceType: string;
|
||||
Email: string;
|
||||
Fingerprint: string;
|
||||
IP: string;
|
||||
Id: number;
|
||||
OS: string;
|
||||
QuizId: number;
|
||||
Result: boolean;
|
||||
Session: string;
|
||||
Start: boolean;
|
||||
content: string;
|
||||
new: boolean;
|
||||
question_id: number;
|
||||
}
|
||||
|
||||
async function getResultList(quizId: number, page: number, body: any) {
|
||||
return makeRequest<IResultListBody, RawResult>({
|
||||
url: process.env.REACT_APP_DOMAIN + `/squiz/results/getResults/${quizId}`,
|
||||
method: "POST",
|
||||
body: { page: page, limit: 10, ...body },
|
||||
@ -31,7 +60,7 @@ function deleteResult(resultId: number) {
|
||||
// }
|
||||
// };
|
||||
|
||||
function obsolescenceResult(idResultArray: string[]) {
|
||||
function obsolescenceResult(idResultArray: number[]) {
|
||||
return makeRequest<unknown, unknown>({
|
||||
url: process.env.REACT_APP_DOMAIN + `/squiz/result/seen`,
|
||||
body: {
|
||||
@ -42,7 +71,7 @@ function obsolescenceResult(idResultArray: string[]) {
|
||||
}
|
||||
|
||||
function getAnswerResultList(resultId: number) {
|
||||
return makeRequest<unknown, unknown>({
|
||||
return makeRequest<unknown, IAnswerResult[]>({
|
||||
url: process.env.REACT_APP_DOMAIN + `/squiz/result/${resultId}`,
|
||||
method: "GET",
|
||||
});
|
||||
|
@ -1,11 +1,13 @@
|
||||
export interface RawResult {
|
||||
total_count: number;
|
||||
results: {
|
||||
results: RawResultItem[];
|
||||
}
|
||||
|
||||
export interface RawResultItem {
|
||||
content: string;
|
||||
id: number;
|
||||
new: boolean;
|
||||
created_at: string;
|
||||
};
|
||||
}
|
||||
export interface ResultContent {
|
||||
name?: string;
|
||||
@ -35,12 +37,11 @@ export const defaultResultContent: ResultContent = {
|
||||
messenger: "",
|
||||
};
|
||||
|
||||
export function rawResultToResult(rawResult): RawResult {
|
||||
export function rawResultToResult(rawResult: RawResultItem) {
|
||||
let content = defaultResultContent;
|
||||
|
||||
try {
|
||||
content = JSON.parse(rawResult.content);
|
||||
console.log("Content", content);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"Cannot parse result from string, using default config",
|
||||
|
71
src/pages/QuizAnswersPage/AnswerList.tsx
Normal file
71
src/pages/QuizAnswersPage/AnswerList.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import { FC } from "react";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { DateDefinition, TimeDefinition } from "./helper";
|
||||
import { CardAnswer } from "./CardAnswer";
|
||||
import { Result } from "@root/results/store";
|
||||
|
||||
interface AnswerListProps {
|
||||
isTablet: boolean;
|
||||
results: Result[] | [];
|
||||
setPrePaymentModalOpen: (value: boolean) => void;
|
||||
}
|
||||
export const AnswerList: FC<AnswerListProps> = ({
|
||||
isTablet,
|
||||
results,
|
||||
setPrePaymentModalOpen,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
{!isTablet && (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
mb: "15px",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ fontSize: "18px", color: "#9A9AAF", mr: "40px" }}>
|
||||
№ заявки
|
||||
</Typography>
|
||||
<Typography sx={{ fontSize: "18px", color: "#9A9AAF" }}>
|
||||
Дата
|
||||
</Typography>
|
||||
<Typography sx={{ fontSize: "18px", color: "#9A9AAF", ml: "288px" }}>
|
||||
Контакты
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "flex-start",
|
||||
flexDirection: isTablet ? "-moz-initial" : "column",
|
||||
flexWrap: isTablet ? "wrap" : "nowrap",
|
||||
gap: "20px",
|
||||
}}
|
||||
>
|
||||
{results &&
|
||||
results.map((result) => {
|
||||
const dayResult = DateDefinition(result.created_at);
|
||||
const timeResult = TimeDefinition(result.created_at);
|
||||
return (
|
||||
<CardAnswer
|
||||
key={result.id}
|
||||
name={result.content.name}
|
||||
email={result.content.email}
|
||||
phone={result.content.phone}
|
||||
address={result.content.address}
|
||||
isNew={result.new}
|
||||
idResult={result.id}
|
||||
dayResult={dayResult}
|
||||
timeResult={timeResult}
|
||||
openPrePaymentModal={() => setPrePaymentModalOpen(true)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,25 +1,20 @@
|
||||
import { ArrowDownIcon } from "@icons/questionsPage/ArrowDownIcon";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
IconButton,
|
||||
Link,
|
||||
Modal,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { FC, useState } from "react";
|
||||
import { FC, MouseEvent, useState } from "react";
|
||||
import { ContactIcon } from "./icons/ContactIcon";
|
||||
import { MessageIcon } from "./icons/MessageIcon";
|
||||
import { PhoneIcon } from "./icons/PhoneIcon";
|
||||
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
||||
|
||||
import homeImg from "./images/home.png";
|
||||
import videoFrame from "./images/videoFrame.png";
|
||||
import { EyeIcon } from "./icons/EyeIcon";
|
||||
import { deleteResult, obsolescenceResult } from "@root/results/actions";
|
||||
import { resultApi } from "@api/result";
|
||||
import { IAnswerResult, resultApi } from "@api/result";
|
||||
import { useQuizStore } from "@root/quizes/store";
|
||||
import { useQuestionsStore } from "@root/questions/store";
|
||||
import AddressIcon from "@icons/ContactFormIcon/AddressIcon";
|
||||
@ -27,21 +22,19 @@ import AddressIcon from "@icons/ContactFormIcon/AddressIcon";
|
||||
import type { AxiosError } from "axios";
|
||||
import { DeleteModal } from "./DeleteModal";
|
||||
|
||||
interface Props {
|
||||
interface CardAnswerProps {
|
||||
isNew: boolean;
|
||||
idResult: string;
|
||||
onClick: () => void;
|
||||
idResult: number;
|
||||
dayResult: string;
|
||||
timeResult: string;
|
||||
name?: string;
|
||||
phone?: string;
|
||||
email?: string;
|
||||
address?: string;
|
||||
onLossNew?: (id: string) => void;
|
||||
openPrePaymentModal: () => void;
|
||||
}
|
||||
|
||||
export const CardAnswer = ({
|
||||
export const CardAnswer: FC<CardAnswerProps> = ({
|
||||
name,
|
||||
phone,
|
||||
email,
|
||||
@ -50,35 +43,29 @@ export const CardAnswer = ({
|
||||
idResult,
|
||||
timeResult,
|
||||
dayResult,
|
||||
onLossNew,
|
||||
openPrePaymentModal,
|
||||
}: Props) => {
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
const [openDelete, setOpenDelete] = useState<boolean>(false);
|
||||
const theme = useTheme();
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||
const [resultsAnswer, setResultsAnswer] = useState([]);
|
||||
const [resultQuiz, setResultQuiz] = useState([]);
|
||||
const [resultsAnswer, setResultsAnswer] = useState<IAnswerResult[]>([]);
|
||||
const [questionsResultState, setQuestionsResultState] = useState([]);
|
||||
const { editQuizId } = useQuizStore();
|
||||
const { questions } = useQuestionsStore();
|
||||
|
||||
const openResults = async () => {
|
||||
setIsOpen(!isOpen);
|
||||
if (!isOpen) {
|
||||
try {
|
||||
let resAnswer = await resultApi.getAnswerList(Number(idResult));
|
||||
|
||||
let resAnswerOnly = resAnswer.filter((res) => res.Result !== true);
|
||||
let resQuiz = resAnswer.filter((res) => res.Result === true);
|
||||
setResultQuiz(resQuiz);
|
||||
const resAnswer = await resultApi.getAnswerList(idResult);
|
||||
const resAnswerOnly = resAnswer.filter((res) => res.Result !== true);
|
||||
const resQuiz = resAnswer.filter((res) => res.Result === true);
|
||||
setResultsAnswer(resAnswerOnly);
|
||||
let idResults = resQuiz[0].question_id;
|
||||
let questionsResult = questions.filter(
|
||||
const idResults = resQuiz[0].question_id;
|
||||
const questionsResult = questions.filter(
|
||||
(q) => q.backendId === idResults,
|
||||
);
|
||||
setQuestionsResultState(questionsResult);
|
||||
console.log("тут хранятся ответы", resAnswerOnly);
|
||||
} catch (nativeError) {
|
||||
const error = nativeError as AxiosError;
|
||||
|
||||
@ -89,11 +76,19 @@ export const CardAnswer = ({
|
||||
}
|
||||
};
|
||||
|
||||
const onClickDelete = (e: MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
setOpenDelete(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
onClick={() => {
|
||||
if (editQuizId !== null) {
|
||||
obsolescenceResult(idResult, editQuizId);
|
||||
openResults();
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
borderRadius: "12px",
|
||||
@ -182,7 +177,9 @@ export const CardAnswer = ({
|
||||
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: "10px" }}>
|
||||
{name && (
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "13px" }}>
|
||||
<Box
|
||||
sx={{ display: "flex", alignItems: "center", gap: "13px" }}
|
||||
>
|
||||
<ContactIcon />
|
||||
<Typography sx={{ fontSize: "18px", color: "#4D4D4D" }}>
|
||||
{name}
|
||||
@ -190,7 +187,9 @@ export const CardAnswer = ({
|
||||
</Box>
|
||||
)}
|
||||
{email && (
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "13px" }}>
|
||||
<Box
|
||||
sx={{ display: "flex", alignItems: "center", gap: "13px" }}
|
||||
>
|
||||
<MessageIcon />
|
||||
<Typography sx={{ fontSize: "18px", color: "#4D4D4D" }}>
|
||||
{email}
|
||||
@ -198,7 +197,9 @@ export const CardAnswer = ({
|
||||
</Box>
|
||||
)}
|
||||
{phone && (
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "13px" }}>
|
||||
<Box
|
||||
sx={{ display: "flex", alignItems: "center", gap: "13px" }}
|
||||
>
|
||||
<PhoneIcon />
|
||||
<Typography sx={{ fontSize: "18px", color: "#4D4D4D" }}>
|
||||
{phone}
|
||||
@ -206,7 +207,9 @@ export const CardAnswer = ({
|
||||
</Box>
|
||||
)}
|
||||
{address && (
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "13px" }}>
|
||||
<Box
|
||||
sx={{ display: "flex", alignItems: "center", gap: "13px" }}
|
||||
>
|
||||
<AddressIcon color={"#9A9AAF"} />
|
||||
<Typography sx={{ fontSize: "18px", color: "#4D4D4D" }}>
|
||||
{address}
|
||||
@ -263,24 +266,16 @@ export const CardAnswer = ({
|
||||
Новая
|
||||
</Typography>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<IconButton onClick={() => setOpenDelete(true)}>
|
||||
<IconButton onClick={onClickDelete}>
|
||||
<DeleteIcon color="#4D4D4D" fontSize="34px" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</>
|
||||
) : (
|
||||
<IconButton onClick={() => setOpenDelete(true)}>
|
||||
<IconButton onClick={onClickDelete}>
|
||||
<DeleteIcon color="#4D4D4D" fontSize="34px" />
|
||||
</IconButton>
|
||||
)}
|
||||
<DeleteModal
|
||||
openDelete={openDelete}
|
||||
handleClose={() => setOpenDelete(false)}
|
||||
onClick={() => {
|
||||
deleteResult(Number(idResult));
|
||||
setOpenDelete(false);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@ -339,7 +334,12 @@ export const CardAnswer = ({
|
||||
}
|
||||
return (
|
||||
<Box
|
||||
sx={{ display: "flex", alignItems: "center", gap: "13px" }}
|
||||
key={answer.id}
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "13px",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ fontSize: "18px", color: "#9A9AAF" }}>
|
||||
{id + 1}. {titleQuestion}.
|
||||
@ -414,9 +414,9 @@ export const CardAnswer = ({
|
||||
</Typography>
|
||||
</Box>
|
||||
{questionsResultState.map((res) => {
|
||||
console.log(questionsResultState, "что за результат тут");
|
||||
return (
|
||||
<Box
|
||||
key={res.id}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
@ -433,7 +433,9 @@ export const CardAnswer = ({
|
||||
>
|
||||
{res.description}
|
||||
</Typography>
|
||||
<Typography sx={{ fontSize: "18px", wordBreak: "break-word" }}>
|
||||
<Typography
|
||||
sx={{ fontSize: "18px", wordBreak: "break-word" }}
|
||||
>
|
||||
{res.title}
|
||||
</Typography>
|
||||
{res.content.useImage &&
|
||||
@ -459,5 +461,14 @@ export const CardAnswer = ({
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
<DeleteModal
|
||||
openDelete={openDelete}
|
||||
handleClose={() => setOpenDelete(false)}
|
||||
onClick={() => {
|
||||
deleteResult(Number(idResult));
|
||||
setOpenDelete(false);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,37 +1,22 @@
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
useTheme,
|
||||
useMediaQuery,
|
||||
Skeleton,
|
||||
} from "@mui/material";
|
||||
import { Box, Skeleton, useMediaQuery, useTheme } from "@mui/material";
|
||||
import HeaderFull from "@ui_kit/Header/HeaderFull";
|
||||
import SectionWrapper from "@ui_kit/SectionWrapper";
|
||||
import { FC, useEffect, useState } from "react";
|
||||
import { CardAnswer } from "./CardAnswer";
|
||||
import { ChangeEvent, FC, useEffect, useState } from "react";
|
||||
import { PrePaymentModal } from "./PrePaymentModal";
|
||||
import { FilterModal } from "@ui_kit/Modal/FilterModal/FilterModal";
|
||||
|
||||
import { resultApi } from "@api/result";
|
||||
import { useResultStore } from "@root/results/store";
|
||||
import { ExportResults, setResults } from "@root/results/actions";
|
||||
|
||||
import { quizApi } from "@api/quiz";
|
||||
import { setQuizes } from "@root/quizes/actions";
|
||||
import { setResults } from "@root/results/actions";
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import { useQuizStore } from "@root/quizes/store";
|
||||
import { questionApi } from "@api/question";
|
||||
import { setQuestions } from "@root/questions/actions";
|
||||
import { useUserStore } from "@root/user";
|
||||
|
||||
import CustomPagination from "@ui_kit/CustomPagination";
|
||||
import SettingResults from "./SettingResults";
|
||||
import { DateDefinition, parseFilters, TimeDefinition } from "./helper";
|
||||
|
||||
const itemsCities = [
|
||||
{ label: "Муром (1)", value: "option1" },
|
||||
{ label: "Москва (1)", value: "option2" },
|
||||
];
|
||||
import { parseFilters } from "./helper";
|
||||
import { QuizSettingsMenu } from "./QuizSettingsMenu";
|
||||
import { AnswerList } from "./AnswerList";
|
||||
import { useGetData } from "./useGetData";
|
||||
|
||||
const itemsTime = [
|
||||
"За всё время",
|
||||
@ -50,8 +35,6 @@ export const QuizAnswersPage: FC = () => {
|
||||
|
||||
const [filterModalOpen, setFilterModalOpen] = useState<boolean>(false);
|
||||
const [page, setPage] = useState(1);
|
||||
const [exportContactsModalOpen, setExportContactsModalOpen] =
|
||||
useState<boolean>(false);
|
||||
const [filterNew, setFilterNew] = useState<string>("Все заявки");
|
||||
const [filterDate, setFilterDate] = useState<string>("За всё время");
|
||||
const [prePaymentModalOpen, setPrePaymentModalOpen] =
|
||||
@ -68,14 +51,13 @@ export const QuizAnswersPage: FC = () => {
|
||||
const quiz = useCurrentQuiz();
|
||||
const { editQuizId } = useQuizStore();
|
||||
const { results, total_count } = useResultStore();
|
||||
const countPagination =
|
||||
typeof total_count === "number" ? Math.ceil(total_count / 10) : 0;
|
||||
useGetData(filterNew, filterDate);
|
||||
|
||||
console.log("Перерендер компонента ", results);
|
||||
|
||||
const countPagination = Math.ceil(total_count / 10);
|
||||
// const {idResultArray, addIdResult, clearIdResultArray} = useObsolescenceIdResult()
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, [filterNew, filterDate]);
|
||||
return setResults([]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!userAccount) {
|
||||
@ -94,31 +76,20 @@ export const QuizAnswersPage: FC = () => {
|
||||
setPrePaymentModalOpen(false);
|
||||
}, [userAccount]);
|
||||
|
||||
const getData = async () => {
|
||||
if (editQuizId !== null) {
|
||||
const quizes = await quizApi.getList();
|
||||
setQuizes(quizes);
|
||||
|
||||
const questions = await questionApi.getList({ quiz_id: editQuizId });
|
||||
setQuestions(questions);
|
||||
|
||||
const result = await resultApi.getList(
|
||||
editQuizId,
|
||||
0,
|
||||
parseFilters(filterNew, filterDate),
|
||||
);
|
||||
setResults(result);
|
||||
}
|
||||
};
|
||||
|
||||
const PaginationHC = async (e, value) => {
|
||||
const PaginationHC = async (e: ChangeEvent<unknown>, value: number) => {
|
||||
setPage(value);
|
||||
try {
|
||||
if (editQuizId !== null) {
|
||||
const result = await resultApi.getList(
|
||||
editQuizId,
|
||||
value - 1,
|
||||
parseFilters(filterNew, filterDate),
|
||||
);
|
||||
setResults(result);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("An error occurred while receiving data: ", error);
|
||||
}
|
||||
};
|
||||
|
||||
if (quiz === undefined)
|
||||
@ -133,137 +104,34 @@ export const QuizAnswersPage: FC = () => {
|
||||
sx={{ padding: isMobile ? "115px 16px" : "115px 20px 20px" }}
|
||||
maxWidth="lg"
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "36px",
|
||||
fontWeight: "500",
|
||||
mb: "50px",
|
||||
|
||||
lineHeight: "normal",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{quiz.name}
|
||||
</Typography>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: isTablet ? "flex" : "-moz-initial",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "8px" }}>
|
||||
<Typography sx={{ fontSize: "18px", color: "#4D4D4D" }}>
|
||||
Ответы на квиз
|
||||
</Typography>
|
||||
<Typography sx={{ fontSize: "18px", color: "#9A9AAF" }}>
|
||||
({total_count})
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
mt: "20px",
|
||||
mb: "31px",
|
||||
gap: "30px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
width: isTablet ? "auto" : "100%",
|
||||
}}
|
||||
>
|
||||
<SettingResults
|
||||
onclickExport={() =>
|
||||
ExportResults(
|
||||
filterNew,
|
||||
filterDate,
|
||||
() => setPrePaymentModalOpen(true),
|
||||
editQuizId,
|
||||
)
|
||||
}
|
||||
onclickUpdate={async () => {
|
||||
const result = await resultApi.getList(
|
||||
editQuizId,
|
||||
page - 1,
|
||||
parseFilters(filterNew, filterDate),
|
||||
);
|
||||
setResults(result);
|
||||
}}
|
||||
onclickFilterTablet={() => setFilterModalOpen(true)}
|
||||
onclickResetFilers={() => {
|
||||
setFilterNew("Все заявки");
|
||||
setFilterDate("За всё время");
|
||||
}}
|
||||
<QuizSettingsMenu
|
||||
quiz={quiz}
|
||||
total_count={total_count}
|
||||
isTablet={isTablet}
|
||||
filterNew={filterNew}
|
||||
filterDate={filterDate}
|
||||
setPrePaymentModalOpen={setPrePaymentModalOpen}
|
||||
editQuizId={editQuizId}
|
||||
page={page}
|
||||
setFilterModalOpen={setFilterModalOpen}
|
||||
setFilterNew={setFilterNew}
|
||||
setFilterDate={setFilterDate}
|
||||
filterNewHC={filterNewHC}
|
||||
filterDateHC={filterDateHC}
|
||||
itemsTime={itemsTime}
|
||||
itemsNews={itemsNews}
|
||||
filterDate={filterDate}
|
||||
filterNew={filterNew}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<CustomPagination
|
||||
countPagination={countPagination}
|
||||
page={page}
|
||||
onChange={PaginationHC}
|
||||
/>
|
||||
|
||||
{!isTablet && (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
mb: "15px",
|
||||
}}
|
||||
>
|
||||
<Typography sx={{ fontSize: "18px", color: "#9A9AAF", mr: "40px" }}>
|
||||
№ заявки
|
||||
</Typography>
|
||||
<Typography sx={{ fontSize: "18px", color: "#9A9AAF" }}>
|
||||
Дата
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{ fontSize: "18px", color: "#9A9AAF", ml: "288px" }}
|
||||
>
|
||||
Контакты
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "flex-start",
|
||||
flexDirection: isTablet ? "-moz-initial" : "column",
|
||||
flexWrap: isTablet ? "wrap" : "nowrap",
|
||||
gap: "20px",
|
||||
}}
|
||||
>
|
||||
{results.map((result) => {
|
||||
const dataResult = new Date(result.created_at);
|
||||
let dayResult = DateDefinition(result.created_at);
|
||||
let timeResult = TimeDefinition(result.created_at);
|
||||
return (
|
||||
<CardAnswer
|
||||
name={result.content.name}
|
||||
email={result.content.email}
|
||||
phone={result.content.phone}
|
||||
address={result.content.address}
|
||||
isNew={result.new}
|
||||
idResult={result.id}
|
||||
dayResult={dayResult}
|
||||
timeResult={timeResult}
|
||||
openPrePaymentModal={() => setPrePaymentModalOpen(true)}
|
||||
<AnswerList
|
||||
isTablet={isTablet}
|
||||
results={results}
|
||||
setPrePaymentModalOpen={setPrePaymentModalOpen}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</SectionWrapper>
|
||||
|
||||
<FilterModal
|
||||
open={filterModalOpen}
|
||||
handleClose={() => setFilterModalOpen(false)}
|
||||
|
127
src/pages/QuizAnswersPage/QuizSettingsMenu.tsx
Normal file
127
src/pages/QuizAnswersPage/QuizSettingsMenu.tsx
Normal file
@ -0,0 +1,127 @@
|
||||
import SettingResults from "./SettingResults";
|
||||
import { ExportResults, setResults } from "@root/results/actions";
|
||||
import { resultApi } from "@api/result";
|
||||
import { parseFilters } from "./helper";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { FC } from "react";
|
||||
import { Quiz } from "@model/quiz/quiz";
|
||||
|
||||
interface QuizSettingsMenuProps {
|
||||
quiz: Quiz;
|
||||
total_count: number;
|
||||
isTablet: boolean;
|
||||
filterNew: string;
|
||||
filterDate: string;
|
||||
setPrePaymentModalOpen: (value: boolean) => void;
|
||||
editQuizId: number | null;
|
||||
page: number;
|
||||
setFilterModalOpen: (value: boolean) => void;
|
||||
setFilterNew: (value: string) => void;
|
||||
setFilterDate: (value: string) => void;
|
||||
filterNewHC: (value: string) => void;
|
||||
filterDateHC: (value: string) => void;
|
||||
itemsTime: string[];
|
||||
itemsNews: string[];
|
||||
}
|
||||
|
||||
export const QuizSettingsMenu: FC<QuizSettingsMenuProps> = ({
|
||||
quiz,
|
||||
total_count,
|
||||
isTablet,
|
||||
filterNew,
|
||||
filterDate,
|
||||
setPrePaymentModalOpen,
|
||||
editQuizId,
|
||||
page,
|
||||
setFilterModalOpen,
|
||||
setFilterNew,
|
||||
setFilterDate,
|
||||
filterNewHC,
|
||||
filterDateHC,
|
||||
itemsTime,
|
||||
itemsNews,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "36px",
|
||||
fontWeight: "500",
|
||||
mb: "50px",
|
||||
|
||||
lineHeight: "normal",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{quiz.name}
|
||||
</Typography>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: isTablet ? "flex" : "-moz-initial",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "8px" }}>
|
||||
<Typography sx={{ fontSize: "18px", color: "#4D4D4D" }}>
|
||||
Ответы на квиз
|
||||
</Typography>
|
||||
<Typography sx={{ fontSize: "18px", color: "#9A9AAF" }}>
|
||||
({total_count})
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
mt: "20px",
|
||||
mb: "31px",
|
||||
gap: "30px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
width: isTablet ? "auto" : "100%",
|
||||
}}
|
||||
>
|
||||
<SettingResults
|
||||
onclickExport={() => {
|
||||
if (editQuizId !== null) {
|
||||
ExportResults(
|
||||
filterNew,
|
||||
filterDate,
|
||||
() => setPrePaymentModalOpen(true),
|
||||
editQuizId,
|
||||
);
|
||||
} else {
|
||||
console.error("editQuizId is null");
|
||||
}
|
||||
}}
|
||||
onclickUpdate={async () => {
|
||||
if (editQuizId !== null) {
|
||||
const result = await resultApi.getList(
|
||||
editQuizId,
|
||||
page - 1,
|
||||
parseFilters(filterNew, filterDate),
|
||||
);
|
||||
setResults(result);
|
||||
} else {
|
||||
console.error("editQuizId is null");
|
||||
}
|
||||
}}
|
||||
onclickFilterTablet={() => setFilterModalOpen(true)}
|
||||
onclickResetFilers={() => {
|
||||
setFilterNew("Все заявки");
|
||||
setFilterDate("За всё время");
|
||||
}}
|
||||
filterNewHC={filterNewHC}
|
||||
filterDateHC={filterDateHC}
|
||||
itemsTime={itemsTime}
|
||||
itemsNews={itemsNews}
|
||||
filterDate={filterDate}
|
||||
filterNew={filterNew}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
@ -37,7 +37,6 @@ export default function SettingResults({
|
||||
}: Props) {
|
||||
const theme = useTheme();
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
||||
|
@ -9,8 +9,6 @@ export const parseFilters = (filterNew: string, filterDate: string) => {
|
||||
|
||||
if (filterNew === "Новые") filters.new = true;
|
||||
if (filterDate.length !== 0 && filterDate !== "За всё время") {
|
||||
console.log(filterDate);
|
||||
|
||||
filters.to = new Date();
|
||||
|
||||
let resetedCurrentTime = Number(resetTime());
|
||||
|
@ -1,16 +0,0 @@
|
||||
export const EyeIcon = () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="30"
|
||||
height="30"
|
||||
viewBox="0 0 30 30"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M3.26743 16.0459C2.91085 15.3939 2.91086 14.6059 3.26744 13.9539C5.53334 9.8107 9.93781 7 15 7C20.0622 7 24.4667 9.81079 26.7326 13.9541C27.0891 14.6061 27.0891 15.3941 26.7326 16.0461C24.4667 20.1893 20.0622 23 15 23C9.93782 23 5.53329 20.1892 3.26743 16.0459Z"
|
||||
stroke="#4D4D4D"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
<circle cx="15" cy="15" r="4" stroke="#4D4D4D" strokeWidth="1.5" />
|
||||
</svg>
|
||||
);
|
Binary file not shown.
Before Width: | Height: | Size: 42 KiB |
Binary file not shown.
Before Width: | Height: | Size: 64 KiB |
41
src/pages/QuizAnswersPage/useGetData.ts
Normal file
41
src/pages/QuizAnswersPage/useGetData.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { useEffect } from "react";
|
||||
import { useQuizStore } from "@root/quizes/store";
|
||||
import { quizApi } from "@api/quiz";
|
||||
import { setQuizes } from "@root/quizes/actions";
|
||||
import { questionApi } from "@api/question";
|
||||
import { setQuestions } from "@root/questions/actions";
|
||||
import { resultApi } from "@api/result";
|
||||
import { parseFilters } from "./helper";
|
||||
import { setResults } from "@root/results/actions";
|
||||
|
||||
export const useGetData = (filterNew: string, filterDate: string): void => {
|
||||
const { editQuizId } = useQuizStore();
|
||||
|
||||
useEffect(() => {
|
||||
const getData = async (): Promise<void> => {
|
||||
try {
|
||||
if (editQuizId !== null) {
|
||||
const quizes = await quizApi.getList();
|
||||
setQuizes(quizes);
|
||||
|
||||
const questions = await questionApi.getList({ quiz_id: editQuizId });
|
||||
setQuestions(questions);
|
||||
|
||||
const result = await resultApi.getList(
|
||||
editQuizId,
|
||||
0,
|
||||
parseFilters(filterNew, filterDate),
|
||||
);
|
||||
if (result.total_count === 0) {
|
||||
console.log("No results found");
|
||||
}
|
||||
setResults(result);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("An error occurred while receiving data: ", error);
|
||||
}
|
||||
};
|
||||
|
||||
getData();
|
||||
}, [editQuizId, filterNew, filterDate, setResults]);
|
||||
};
|
@ -5,7 +5,6 @@ import { RequestQueue } from "@utils/requestQueue";
|
||||
import { resultApi } from "@api/result";
|
||||
import { devlog, getMessageFromFetchError } from "@frontend/kitui";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
import { useQuizStore } from "@root/quizes/store";
|
||||
import { AxiosError } from "axios";
|
||||
import { parseFilters } from "../../pages/QuizAnswersPage/helper";
|
||||
|
||||
@ -13,7 +12,7 @@ const REQUEST_DEBOUNCE = 200;
|
||||
const requestQueue = new RequestQueue();
|
||||
let requestTimeoutId: ReturnType<typeof setTimeout>;
|
||||
|
||||
export const setResults = (results: RawResult[] | null) =>
|
||||
export const setResults = (results: RawResult | []) =>
|
||||
setProducedState(
|
||||
(state) => {
|
||||
state.results = Object.values(results)[1]?.map(rawResultToResult) ?? [];
|
||||
@ -22,11 +21,10 @@ export const setResults = (results: RawResult[] | null) =>
|
||||
{
|
||||
type: "setResults",
|
||||
results,
|
||||
// total_count
|
||||
},
|
||||
);
|
||||
|
||||
const removeResult = (resultId: string) =>
|
||||
const removeResult = (resultId: number) =>
|
||||
setProducedState((state) => {
|
||||
const index = state.results.findIndex((r) => r.id === resultId);
|
||||
if (index === -1) return;
|
||||
@ -53,9 +51,9 @@ export const deleteResult = async (resultId: number) =>
|
||||
});
|
||||
|
||||
export const obsolescenceResult = async (
|
||||
resultId: string,
|
||||
resultId: number,
|
||||
editQuizId: number,
|
||||
) =>
|
||||
) => {
|
||||
requestQueue.enqueue(
|
||||
`obsolescenceResult-${resultId}-${editQuizId}`,
|
||||
async () => {
|
||||
@ -65,7 +63,7 @@ export const obsolescenceResult = async (
|
||||
if (!result) return;
|
||||
if (result.new === false) return;
|
||||
let lossDebouncer: null | ReturnType<typeof setTimeout> = null;
|
||||
let lossId: string[] = [] as string[];
|
||||
let lossId: number[] = [];
|
||||
if (!lossId.includes(resultId)) lossId.push(resultId);
|
||||
if (typeof lossDebouncer === "number") clearTimeout(lossDebouncer);
|
||||
lossDebouncer = setTimeout(async () => {
|
||||
@ -85,12 +83,13 @@ export const obsolescenceResult = async (
|
||||
setResults(resultList);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const ExportResults = async (
|
||||
filterNew: string,
|
||||
filterDate: string,
|
||||
openPrePaymentModal: () => void,
|
||||
editQuizId: number | null,
|
||||
editQuizId: number,
|
||||
) => {
|
||||
try {
|
||||
const data = await resultApi.export(
|
||||
@ -101,7 +100,7 @@ export const ExportResults = async (
|
||||
|
||||
const blob = data;
|
||||
const link = document.createElement("a");
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
link.href = window.URL.createObjectURL(blob as Blob);
|
||||
link.download = `report_${new Date().getTime()}.xlsx`;
|
||||
link.click();
|
||||
} catch (nativeError) {
|
||||
|
@ -1,18 +1,17 @@
|
||||
import { create } from "zustand";
|
||||
import { devtools, persist } from "zustand/middleware";
|
||||
import { ResultContent } from "@model/result/result";
|
||||
|
||||
export type ResultStore = {
|
||||
results: [
|
||||
{
|
||||
results: {
|
||||
content: string;
|
||||
results: Result[];
|
||||
total_count: number;
|
||||
};
|
||||
|
||||
export type Result = {
|
||||
content: ResultContent;
|
||||
id: number;
|
||||
new: boolean;
|
||||
created_at: string;
|
||||
};
|
||||
},
|
||||
];
|
||||
total_count: number;
|
||||
};
|
||||
|
||||
const initialState: ResultStore = {
|
||||
@ -40,7 +39,6 @@ export const useObsolescenceIdResult = create()(
|
||||
idResultArray: [],
|
||||
addIdResult: (idResult: number) => {
|
||||
const state = get()["idResultArray"] || [];
|
||||
console.log(state);
|
||||
const newState = [...state, idResult];
|
||||
set({ idResultArray: newState });
|
||||
},
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { Pagination } from "@mui/material";
|
||||
import { ChangeEvent } from "react";
|
||||
|
||||
interface Props {
|
||||
countPagination: number;
|
||||
page: number;
|
||||
onChange: (e: ChangeEvent, value: number) => void;
|
||||
onChange: (e: ChangeEvent<unknown>, value: number) => void;
|
||||
}
|
||||
|
||||
export default function CustomPagination({
|
||||
|
Loading…
Reference in New Issue
Block a user