fix: Questions drag&drop

This commit is contained in:
IlyaDoronin 2023-08-08 14:01:37 +03:00
parent 2bb8eb20c3
commit 64ec511f21
5 changed files with 144 additions and 102 deletions

@ -1,23 +1,30 @@
import { Draggable } from "react-beautiful-dnd"; import { Draggable } from "react-beautiful-dnd";
import { ListItem } from "@mui/material"; import { ListItem } from "@mui/material";
import type { ReactNode } from "react"; import QuestionsPageCard from "../QuestionPageCard";
type DraggableListItemProps = { type DraggableListItemProps = {
item: ReactNode;
index: number; index: number;
onDelete: () => void;
}; };
export const DraggableListItem = ({ item, index }: DraggableListItemProps) => ( export const DraggableListItem = ({
index,
onDelete,
}: DraggableListItemProps) => (
<Draggable draggableId={String(index)} index={index}> <Draggable draggableId={String(index)} index={index}>
{(provided, snapshot) => ( {(provided, snapshot) => (
<ListItem <ListItem
ref={provided.innerRef} ref={provided.innerRef}
{...provided.draggableProps} {...provided.draggableProps}
{...provided.dragHandleProps}
sx={{ padding: 0 }} sx={{ padding: 0 }}
> >
{item} <QuestionsPageCard
key={index}
totalIndex={index}
DeleteClick={onDelete}
draggableProps={provided.dragHandleProps}
/>
</ListItem> </ListItem>
)} )}
</Draggable> </Draggable>

@ -7,11 +7,15 @@ import { DraggableListItem } from "./DraggableListItem";
import { reorder } from "./helper"; import { reorder } from "./helper";
import type { ReactNode } from "react";
import type { DropResult } from "react-beautiful-dnd"; import type { DropResult } from "react-beautiful-dnd";
import type { Quizes } from "../../../stores/quizes";
export type ExtendedQuizes = Quizes & {
onDelete: () => void;
};
type DraggableListProps = { type DraggableListProps = {
items: ReactNode[]; items: ExtendedQuizes[];
}; };
export const DraggableList = ({ items }: DraggableListProps) => { export const DraggableList = ({ items }: DraggableListProps) => {
@ -34,8 +38,12 @@ export const DraggableList = ({ items }: DraggableListProps) => {
<StrictModeDroppable droppableId="droppable-list"> <StrictModeDroppable droppableId="droppable-list">
{(provided) => ( {(provided) => (
<Box ref={provided.innerRef} {...provided.droppableProps}> <Box ref={provided.innerRef} {...provided.droppableProps}>
{listItems.map((item, index) => ( {listItems.map(({ onDelete }, index) => (
<DraggableListItem key={index} item={item} index={index} /> <DraggableListItem
key={index}
index={index}
onDelete={onDelete}
/>
))} ))}
{provided.placeholder} {provided.placeholder}
</Box> </Box>

@ -1,100 +1,127 @@
import {Box, Checkbox, FormControlLabel, IconButton, Paper, useTheme} from "@mui/material"; import {
Box,
Checkbox,
FormControlLabel,
IconButton,
Paper,
useTheme,
} from "@mui/material";
import CustomTextField from "@ui_kit/CustomTextField"; import CustomTextField from "@ui_kit/CustomTextField";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ExpandLessIcon from '@mui/icons-material/ExpandLess'; import ExpandLessIcon from "@mui/icons-material/ExpandLess";
import OneIcon from "@icons/questionsPage/OneIcon"; import OneIcon from "@icons/questionsPage/OneIcon";
import PointsIcon from "@icons/questionsPage/PointsIcon"; import PointsIcon from "@icons/questionsPage/PointsIcon";
import TypeQuestions from "./TypeQuestions"; import TypeQuestions from "./TypeQuestions";
import SwitchQuestionsPage from "./SwitchQuestionsPage"; import SwitchQuestionsPage from "./SwitchQuestionsPage";
import React, {useState} from "react"; import React, { useState } from "react";
import DeleteIcon from "@icons/questionsPage/deleteIcon"; import DeleteIcon from "@icons/questionsPage/deleteIcon";
import {useParams} from "react-router-dom"; import { useParams } from "react-router-dom";
import {questionStore} from "@root/questions"; import { questionStore } from "@root/questions";
import CopyIcon from "@icons/questionsPage/CopyIcon"; import CopyIcon from "@icons/questionsPage/CopyIcon";
import CrossedEyeIcon from "@icons/CrossedEyeIcon"; import CrossedEyeIcon from "@icons/CrossedEyeIcon";
import HideIcon from "@icons/questionsPage/hideIcon"; import HideIcon from "@icons/questionsPage/hideIcon";
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
interface Props { interface Props {
DeleteClick: () => void; DeleteClick: () => void;
totalIndex: number totalIndex: number;
draggableProps: DraggableProvidedDragHandleProps | null | undefined;
} }
export default function QuestionsPageCard({totalIndex, DeleteClick}: Props) { export default function QuestionsPageCard({
totalIndex,
DeleteClick,
draggableProps,
}: Props) {
function onDragStart(event: any) {
event.dataTransfer.setData("text", event.target.id);
}
function onDragStart(event: any) { const theme = useTheme();
event const params = Number(useParams().quizId);
.dataTransfer const { listQuestions, updateQuestionsList, createQuestion, removeQuestion } =
.setData('text', event.target.id); questionStore();
} const [isExpanded, setIsExpanded] = useState<boolean>(false);
const switchState = listQuestions[params][totalIndex].type;
return (
const theme = useTheme(); <Paper
const params = Number(useParams().quizId); id={String(totalIndex)}
const {listQuestions, updateQuestionsList, createQuestion, removeQuestion} = questionStore() sx={{
const [isExpanded, setIsExpanded] = useState<boolean>(false); maxWidth: "796px",
const switchState = listQuestions[params][totalIndex].type width: "100%",
return ( borderRadius: "12px",
<Paper marginBottom: "20px",
draggable="true" backgroundColor: isExpanded ? "white" : "#333647",
id={String(totalIndex)} }}
sx={{ onDragStart={onDragStart}
maxWidth: "796px", >
width: "100%", <Box
borderRadius: "12px", sx={{
marginBottom: "20px", width: "100%",
backgroundColor: isExpanded ? "white" : "#333647" maxWidth: "760px",
}} display: "flex",
onDragStart={onDragStart} alignItems: "center",
> gap: "10px",
<Box padding: "20px",
sx={{ width: "100%", maxWidth: "760px", display: "flex", alignItems: "center", gap: "10px", padding: "20px" }} }}
> >
<CustomTextField placeholder="Заголовок вопроса" text={""} <CustomTextField
onChange={e => {updateQuestionsList(params, totalIndex, {title: e.target.value}) placeholder="Заголовок вопроса"
console.log(listQuestions[params][totalIndex].title) text={""}
} onChange={(e) => {
}/> updateQuestionsList(params, totalIndex, { title: e.target.value });
<IconButton onClick={() => setIsExpanded((prev) => !prev)}> console.log(listQuestions[params][totalIndex].title);
{" "} }}
{isExpanded ? />
<ExpandMoreIcon /> <IconButton onClick={() => setIsExpanded((prev) => !prev)}>
:<ExpandLessIcon fill="#7E2AEA"/> {" "}
} {isExpanded ? <ExpandMoreIcon /> : <ExpandLessIcon fill="#7E2AEA" />}
</IconButton> </IconButton>
<Box sx={{display: "flex"}}> <Box sx={{ display: "flex" }}>
<FormControlLabel <FormControlLabel
control={ control={
<Checkbox <Checkbox icon={<HideIcon />} checkedIcon={<CrossedEyeIcon />} />
icon={<HideIcon/>}
checkedIcon={<CrossedEyeIcon />}
/>}
label={""}
sx={{
color: theme.palette.grey2.main,
ml: "-9px",
mr: 0,
userSelect: "none",
}}
/>
<IconButton><CopyIcon/></IconButton>
<IconButton sx={{ borderRadius: "6px", padding: "2px" }} onClick={DeleteClick}>
<DeleteIcon />
</IconButton>
</Box>
<OneIcon />
<PointsIcon />
</Box>
{isExpanded && (
<Box sx={{display: "flex", flexDirection: "column", padding: 0, borderRadius: "12px"}}>
{switchState.length === 0 ?
<TypeQuestions totalIndex={totalIndex}/>
:
<SwitchQuestionsPage totalIndex={totalIndex}/>}
</Box>)
} }
</Paper> label={""}
sx={{
) color: theme.palette.grey2.main,
} ml: "-9px",
mr: 0,
userSelect: "none",
}}
/>
<IconButton>
<CopyIcon />
</IconButton>
<IconButton
sx={{ borderRadius: "6px", padding: "2px" }}
onClick={DeleteClick}
>
<DeleteIcon />
</IconButton>
</Box>
<OneIcon />
<Box {...draggableProps}>
<PointsIcon />
</Box>
</Box>
{isExpanded && (
<Box
sx={{
display: "flex",
flexDirection: "column",
padding: 0,
borderRadius: "12px",
}}
>
{switchState.length === 0 ? (
<TypeQuestions totalIndex={totalIndex} />
) : (
<SwitchQuestionsPage totalIndex={totalIndex} />
)}
</Box>
)}
</Paper>
);
}

@ -12,12 +12,13 @@ import AddPlus from "../../assets/icons/questionsPage/addPlus";
import ArrowLeft from "../../assets/icons/questionsPage/arrowLeft"; import ArrowLeft from "../../assets/icons/questionsPage/arrowLeft";
import { quizStore } from "@root/quizes"; import { quizStore } from "@root/quizes";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import QuestionsPageCard from "./QuestionPageCard";
import { questionStore } from "@root/questions"; import { questionStore } from "@root/questions";
// import { DraggableList } from "./DraggableList"; // import { DraggableList } from "./DraggableList";
import QuizCard from "../createQuize/QuizCard"; import QuizCard from "../createQuize/QuizCard";
import { DraggableList } from "./DraggableList"; import { DraggableList } from "./DraggableList";
import type { ExtendedQuizes } from "./DraggableList";
export default function QuestionsPage() { export default function QuestionsPage() {
const { listQuizes, updateQuizesList } = quizStore(); const { listQuizes, updateQuizesList } = quizStore();
const params = Number(useParams().quizId); const params = Number(useParams().quizId);
@ -59,13 +60,12 @@ export default function QuestionsPage() {
</Link> </Link>
</Box> </Box>
<DraggableList <DraggableList
items={Object.values(listQuestions[params]).map((_, index) => ( items={Object.values(listQuestions[params] as ExtendedQuizes[]).map(
<QuestionsPageCard (item, index) => ({
key={index} ...item,
totalIndex={index} onDelete: () => removeQuestion(params, index),
DeleteClick={() => removeQuestion(params, index)} })
/> )}
))}
/> />
<Box <Box
sx={{ sx={{

@ -8,7 +8,7 @@ interface QuizStore {
createBlank: () => void; createBlank: () => void;
} }
interface Quizes { export interface Quizes {
id: number, id: number,
qid: string, qid: string,
deleted: boolean, deleted: boolean,