Add functional changes for the replacement

This commit is contained in:
Aarni Halinen
2022-07-22 01:49:20 +03:00
parent 653ec8a7a5
commit 9c6e771b1c
2 changed files with 95 additions and 57 deletions
@@ -1,6 +1,6 @@
import React, { ReactNode } from "react";
import React, { ReactNode, useRef } from "react";
import { useDrag, useDrop } from "react-dnd";
import styled from "styled-components";
import { Draggable } from "react-beautiful-dnd";
import colors from "@theme/colors";
import { SignupFormQuestion } from "@models/Signup";
import { Lang } from "../../../i18n";
@@ -8,7 +8,64 @@ import OptionsWidget from "./OptionsWidget";
import TypeWidget from "./TypeWidget";
import QuestionElement from "./Question";
const WidgetRow = styled.div`
const type = "Draggable";
const Draggable = ({
id, index, handleDrag, children,
}) => {
const ref = useRef(null); // Initialize the reference
// useDrop hook is responsible for handling whether any item gets hovered or dropped on the element
const [, drop] = useDrop({
// accept receives a definition of what must be the type of the dragged item to be droppable
accept: type,
// This method is called when we hover over an element while dragging
hover(item: any) { // item is the dragged element
if (!ref.current) {
return;
}
const dragIndex = item.index;
// current element where the dragged element is hovered on
const hoverIndex = index;
// If the dragged element is hovered in the same place, then do nothing
if (dragIndex === hoverIndex) {
return;
}
// If it is dragged around other elements, then move the image and set the state with position changes
handleDrag(dragIndex, hoverIndex);
/*
Update the index for dragged item directly to avoid flickering
when the image was half dragged into the next
*/
// eslint-disable-next-line no-param-reassign
item.index = hoverIndex;
},
});
// useDrag will be responsible for making an element draggable. It also expose, isDragging method to add any styles while dragging
const [{ isDragging }, drag] = useDrag(() => ({
// what type of item this to determine if a drop target accepts it
type,
// data of the item to be available to the drop methods
item: { id, index },
// method to collect additional data for drop handling like whether is currently being dragged
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
}));
/*
Initialize drag and drop into the element using its reference.
Here we initialize both drag and drop on the same element (i.e., Image component)
*/
drag(drop(ref));
return (
<div ref={ref}>{children}</div>
);
};
const WidgetRow = styled(Draggable)`
margin-bottom: 1rem;
display: flex;
flex-flow: column nowrap;
@@ -18,8 +75,6 @@ const WidgetRow = styled.div`
interface QuestionListProps {
questions: SignupFormQuestion[];
innerRef: React.Ref<HTMLDivElement>;
placeholder: ReactNode;
onChange: (value: SignupFormQuestion[]) => void;
}
@@ -45,6 +100,14 @@ class QuestionList extends React.Component<QuestionListProps> {
onChange(newQuestions);
};
handleDrag = (questions: SignupFormQuestion[]) => (srcIndex, dstIndex) => {
const { onChange } = this.props;
const srcCopy = { ...questions[srcIndex] };
questions.splice(srcIndex, 1);
questions.splice(dstIndex, 0, srcCopy);
onChange(questions);
};
renderQuestions(): JSX.Element[] {
const { questions, onChange } = this.props;
return questions.map((q, index) => {
@@ -54,35 +117,31 @@ class QuestionList extends React.Component<QuestionListProps> {
const optionsWidget = <OptionsWidget inputProps={dataProps} onChange={onChange} />;
const typeSelectWidget = <TypeWidget inputProps={dataProps} onChange={onChange} />;
return (
<Draggable draggableId={q.id} key={q.id} index={index}>
{(provided) => (
<WidgetRow
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
<QuestionElement
onClick={this.handleElementRemove(questions, index)}
>
<input type="text" value={q.title_fi} onChange={this.handleNameInputChange(questions, index, "fi")} />
<input type="text" value={q.title_en} onChange={this.handleNameInputChange(questions, index, "en")} />
{typeSelectWidget}
{optionsWidget}
</QuestionElement>
</WidgetRow>
)}
</Draggable>
<WidgetRow
key={q.id}
id={q.id}
index={index}
handleDrag={this.handleDrag(questions)}
>
<QuestionElement
onClick={this.handleElementRemove(questions, index)}
>
<input type="text" value={q.title_fi} onChange={this.handleNameInputChange(questions, index, "fi")} />
<input type="text" value={q.title_en} onChange={this.handleNameInputChange(questions, index, "en")} />
{typeSelectWidget}
{optionsWidget}
</QuestionElement>
</WidgetRow>
);
});
}
render(): JSX.Element {
const { placeholder, innerRef } = this.props;
return (
<div ref={innerRef} data-e2e="admin-signup-question">
<div data-e2e="admin-signup-question">
{this.renderQuestions()}
{placeholder}
</div>
);
}
@@ -1,7 +1,8 @@
import React from "react";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import styled from "styled-components";
import shortid from "shortid";
import { DragDropContext, Droppable } from "react-beautiful-dnd";
import colors from "@theme/colors";
import AddIcon from "@components/AddIcon";
import { SignupFormQuestion } from "@models/Signup";
@@ -34,12 +35,9 @@ const AddQuestionButton = styled.button`
interface SignupQuestionsWidgetProps {
value: string;
onChange: (value: string) => void;
onFocus: () => void;
required: boolean;
disabled: boolean;
}
const SignupQuestionsWidget: React.FC<SignupQuestionsWidgetProps> = ({ value, onFocus, onChange }) => {
const SignupQuestionsWidget: React.FC<SignupQuestionsWidgetProps> = ({ value, onChange }) => {
const onValueChange = (questions: SignupFormQuestion[]) => {
const newValue = JSON.stringify(questions);
onChange(newValue);
@@ -62,35 +60,16 @@ const SignupQuestionsWidget: React.FC<SignupQuestionsWidgetProps> = ({ value, on
onValueChange(newQuestions);
};
const handleDragEnd = (questions: SignupFormQuestion[]) => (result) => {
const srcIndex = result.source.index;
const dstIndex = result.destination.index;
const srcCopy = { ...questions[srcIndex] };
questions.splice(srcIndex, 1);
questions.splice(dstIndex, 0, srcCopy);
onValueChange(questions);
};
const questions: SignupFormQuestion[] = JSON.parse(value);
return (
<Widget>
<DragDropContext
onDragEnd={handleDragEnd(questions)}
onDragStart={onFocus}
>
<Droppable droppableId="questions">
{(provided) => (
<QuestionList
{...provided.droppableProps}
innerRef={provided.innerRef}
questions={questions}
onChange={onValueChange}
placeholder={provided.placeholder}
/>
)}
</Droppable>
</DragDropContext>
<DndProvider backend={HTML5Backend}>
<QuestionList
questions={questions}
onChange={onValueChange}
/>
</DndProvider>
<AddQuestionButton type="button" onClick={handleNewRowClick(questions)} data-e2e="admin-signup-new-question">
<AddIcon />
New Question