Commit 4e580901 authored by jang dong hyeok's avatar jang dong hyeok
Browse files

dnd 시도

parent 0150d3d8
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
"d3-scale": "^4.0.2", "d3-scale": "^4.0.2",
"d3-shape": "^3.2.0", "d3-shape": "^3.2.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^6.3.0" "react-router-dom": "^6.3.0"
} }
......
...@@ -2,12 +2,16 @@ import React from "react"; ...@@ -2,12 +2,16 @@ import React from "react";
import { Outlet } from "react-router-dom"; import { Outlet } from "react-router-dom";
import { AuthProvider } from "./auth/auth.context"; import { AuthProvider } from "./auth/auth.context";
import { Footer, Header } from "./commons"; import { Footer, Header } from "./commons";
import { DndProvider } from "react-dnd/dist/core";
import { HTML5Backend } from "react-dnd-html5-backend";
const App = () => ( const App = () => (
<AuthProvider> <AuthProvider>
<Header /> <Header />
<div style={{ minHeight: "80vh" }}> <div style={{ minHeight: "80vh" }}>
<Outlet /> <DndProvider backend={HTML5Backend}>
<Outlet />
</DndProvider>
</div> </div>
<Footer /> <Footer />
</AuthProvider> </AuthProvider>
......
...@@ -10,6 +10,8 @@ import type { ...@@ -10,6 +10,8 @@ import type {
} from "../types"; } from "../types";
import { SpinnerIcon } from "../icons"; import { SpinnerIcon } from "../icons";
import { surveyApi } from "../apis"; import { surveyApi } from "../apis";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
type SurveyContextType = { type SurveyContextType = {
survey: ICreateSurvey; survey: ICreateSurvey;
...@@ -122,15 +124,17 @@ export const SurveyLayout = () => { ...@@ -122,15 +124,17 @@ export const SurveyLayout = () => {
응답결과 응답결과
</NavLink> </NavLink>
</div> </div>
<Outlet <DndProvider backend={HTML5Backend}>
context={{ <Outlet
survey, context={{
createQuestion, survey,
removeQuestion, createQuestion,
updateQuestion, removeQuestion,
updateTitleComment, updateQuestion,
}} updateTitleComment,
/> }}
/>
</DndProvider>
</div> </div>
); );
}; };
......
...@@ -2,6 +2,9 @@ import React, { useState } from "react"; ...@@ -2,6 +2,9 @@ import React, { useState } from "react";
import { getEnumKeyByEnumValue, QUESTION_TYPES } from "../commons"; import { getEnumKeyByEnumValue, QUESTION_TYPES } from "../commons";
import { getElementByQuestionType } from "../helpers"; import { getElementByQuestionType } from "../helpers";
import { IQuestionProps } from "../types"; import { IQuestionProps } from "../types";
import { useDrag, useDrop } from "react-dnd";
import { SurveyLayout } from "../layouts";
import { surveyApi } from "../apis";
const options = Object.entries(QUESTION_TYPES).map(([type, value]) => ( const options = Object.entries(QUESTION_TYPES).map(([type, value]) => (
<option key={type} value={value}> <option key={type} value={value}>
...@@ -9,6 +12,9 @@ const options = Object.entries(QUESTION_TYPES).map(([type, value]) => ( ...@@ -9,6 +12,9 @@ const options = Object.entries(QUESTION_TYPES).map(([type, value]) => (
</option> </option>
)); ));
export interface DropResult {
name: string;
}
export const Question = ({ export const Question = ({
element, element,
handleQuestion, handleQuestion,
...@@ -16,7 +22,39 @@ export const Question = ({ ...@@ -16,7 +22,39 @@ export const Question = ({
}: IQuestionProps) => { }: IQuestionProps) => {
const [question, setQuestion] = useState(element); const [question, setQuestion] = useState(element);
const isEditing = question.isEditing; const isEditing = question.isEditing;
//
const [{ isDragging }, drag] = useDrag(() => ({
type: SurveyLayout.name,
item: { name: question.type },
end: (item, monitor) => {
const dropResult = monitor.getDropResult<DropResult>();
if (item && dropResult) {
alert(`You dropped ${item.name}`);
}
},
collect: (monitor) => ({
isDragging: monitor.isDragging(),
handlerId: monitor.getHandlerId(),
}),
}));
const [{ canDrop, isOver }, drop] = useDrop(() => ({
accept: SurveyLayout.name,
collect: (monitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
}));
const isActive = canDrop && isOver;
let backgroundColor = "#222";
if (isActive) {
backgroundColor = "darkgreen";
} else if (canDrop) {
backgroundColor = "darkkhaki";
}
//
async function handleEditComplete() { async function handleEditComplete() {
question.content.choices.map((choice) => { question.content.choices.map((choice) => {
if (choice.text.trim() === "") { if (choice.text.trim() === "") {
...@@ -71,82 +109,87 @@ export const Question = ({ ...@@ -71,82 +109,87 @@ export const Question = ({
}; };
return ( return (
<div <div ref={drop} className="flex w-3/5 h-full justify-center">
style={{ borderColor: isEditing ? "red" : "#0A8A8A" }} <div
className="flex flex-col container w-4/5 h-auto border-2 items-center m-3 py-2 rounded-lg" ref={drag}
> style={{ borderColor: isEditing ? "red" : "#0A8A8A" }}
<div className="flex h-16 w-full place-content-center items-center"> className={
<input "flex flex-col container w-full h-auto border-2 items-center m-3 py-2 rounded-lg cursor-move "
type="text" }
name="title" >
id={question._id} <div className="flex h-16 w-full place-content-center items-center">
className="text-xl font-bold border-b-2 w-11/12"
placeholder={"Question Title"}
value={question.title}
onChange={handleChange}
disabled={!isEditing}
></input>
</div>
<div className="flex w-full justify-center">
<input
type="text"
name="comment"
id={question._id}
className="border w-11/12"
placeholder="질문에 대한 설명을 입력해주세요"
value={question.comment}
onChange={handleChange}
disabled={!isEditing}
></input>
</div>
{getElementByQuestionType(question, handleElement, isEditing)}
<div className="flex flex-row place-content-between w-11/12 py-2">
<select
id={question._id}
name="type"
onChange={handleSelect}
disabled={!isEditing}
value={QUESTION_TYPES[question.type]}
className="w-32 h-10 md:w-36 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-themeColor"
>
{options}
</select>
<div className="place-self-end py-2">
<input <input
type="checkbox" type="text"
id="isRequired" name="title"
name="isRequired" id={question._id}
className="text-xl font-bold border-b-2 w-11/12"
placeholder={"Question Title"}
value={question.title}
onChange={handleChange} onChange={handleChange}
disabled={!isEditing} disabled={!isEditing}
checked={question.isRequired} ></input>
/> </div>
<label htmlFor="isRequired" className="px-1"> <div className="flex w-full justify-center">
필수 <input
</label> type="text"
{isEditing ? ( name="comment"
<> id={question._id}
<button type="button" className="px-1" onClick={onCancel}> className="border w-11/12"
취소 placeholder="질문에 대한 설명을 입력해주세요"
</button> value={question.comment}
onChange={handleChange}
disabled={!isEditing}
></input>
</div>
{getElementByQuestionType(question, handleElement, isEditing)}
<div className="flex flex-row place-content-between w-11/12 py-2">
<select
id={question._id}
name="type"
onChange={handleSelect}
disabled={!isEditing}
value={QUESTION_TYPES[question.type]}
className="w-32 h-10 md:w-36 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-themeColor"
>
{options}
</select>
<div className="place-self-end py-2">
<input
type="checkbox"
id="isRequired"
name="isRequired"
onChange={handleChange}
disabled={!isEditing}
checked={question.isRequired}
/>
<label htmlFor="isRequired" className="px-1">
필수
</label>
{isEditing ? (
<>
<button type="button" className="px-1" onClick={onCancel}>
취소
</button>
<button <button
type="button" type="button"
className="px-1" className="px-1"
onClick={handleEditComplete} onClick={handleEditComplete}
> >
확인 확인
</button> </button>
</> </>
) : ( ) : (
<> <>
<button type="button" className="px-1" onClick={onDelete}> <button type="button" className="px-1" onClick={onDelete}>
삭제 삭제
</button> </button>
<button type="button" className="px-1" onClick={onEdit}> <button type="button" className="px-1" onClick={onEdit}>
수정 수정
</button> </button>
</> </>
)} )}
</div>
</div> </div>
</div> </div>
</div> </div>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment