Skip to content

Commit a0d484a

Browse files
authored
Merge pull request #1120 from isaacphysics/hotfix/gameboard-builder-drag-fix
Fix dragging rows on the gameboard builder
2 parents 223143f + 9291830 commit a0d484a

File tree

5 files changed

+101
-84
lines changed

5 files changed

+101
-84
lines changed

src/app/components/elements/GameboardBuilderRow.tsx

Lines changed: 58 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -61,67 +61,71 @@ const GameboardBuilderRow = (
6161
const isSelected = question.id !== undefined && currentQuestions.selectedQuestions.has(question.id);
6262

6363
return filteredAudienceViews.map((view, i, arr) => <tr
64-
key={`${question.id} ${i}`} ref={provided && provided.innerRef}
65-
className={classnames({selected: isSelected})}
66-
{...(provided && provided.draggableProps)} {...(provided && provided.dragHandleProps)}
64+
key={`${question.id} ${i}`} className={classnames({selected: isSelected})}
6765
>
6866
{i === 0 && <>
6967
<td rowSpan={arr.length} className="w-5 text-center align-middle">
70-
<RS.Input
71-
type="checkbox"
72-
id={`${provided ? "gameboard-builder" : "question-search-modal"}-include-${question.id}`}
73-
aria-label={!isSelected ? "Select question" : "Deselect question"}
74-
title={!isSelected ? "Select question" : "Deselect question"}
75-
color="secondary"
76-
className={!provided ? "isaac-checkbox mt-1" : undefined}
77-
checked={isSelected}
78-
onChange={() => {
79-
if (question.id) {
80-
const newSelectedQuestions = new Map(currentQuestions.selectedQuestions);
81-
const newQuestionOrder = [...currentQuestions.questionOrder];
82-
if (newSelectedQuestions.has(question.id)) {
83-
newSelectedQuestions.delete(question.id);
84-
newQuestionOrder.splice(newQuestionOrder.indexOf(question.id), 1);
85-
} else {
86-
newSelectedQuestions.set(question.id, {...question, creationContext});
87-
newQuestionOrder.push(question.id);
68+
<div className="d-flex justify-content-center">
69+
<RS.Input
70+
type="checkbox"
71+
id={`${provided ? "gameboard-builder" : "question-search-modal"}-include-${question.id}`}
72+
aria-label={!isSelected ? "Select question" : "Deselect question"}
73+
title={!isSelected ? "Select question" : "Deselect question"}
74+
color="secondary"
75+
className={!provided ? "isaac-checkbox mt-1" : undefined}
76+
checked={isSelected}
77+
onChange={() => {
78+
if (question.id) {
79+
const newSelectedQuestions = new Map(currentQuestions.selectedQuestions);
80+
const newQuestionOrder = [...currentQuestions.questionOrder];
81+
if (newSelectedQuestions.has(question.id)) {
82+
newSelectedQuestions.delete(question.id);
83+
newQuestionOrder.splice(newQuestionOrder.indexOf(question.id), 1);
84+
} else {
85+
newSelectedQuestions.set(question.id, {...question, creationContext});
86+
newQuestionOrder.push(question.id);
87+
}
88+
currentQuestions.setSelectedQuestions(newSelectedQuestions);
89+
currentQuestions.setQuestionOrder(newQuestionOrder);
90+
if (provided) {
91+
undoStack.push({questionOrder: currentQuestions.questionOrder, selectedQuestions: currentQuestions.selectedQuestions});
92+
redoStack.clear();
93+
}
8894
}
89-
currentQuestions.setSelectedQuestions(newSelectedQuestions);
90-
currentQuestions.setQuestionOrder(newQuestionOrder);
91-
if (provided) {
92-
undoStack.push({questionOrder: currentQuestions.questionOrder, selectedQuestions: currentQuestions.selectedQuestions});
93-
redoStack.clear();
94-
}
95-
}
96-
}}
97-
/>
95+
}}
96+
/>
97+
</div>
9898
</td>
9999
<td rowSpan={arr.length} className={classNames(cellClasses, siteSpecific("w-40", "w-30"))}>
100-
{provided && <img src="/assets/common/icons/drag_indicator.svg" alt="Drag to reorder" className="me-1 grab-cursor" />}
101100
<div className="d-flex">
102-
<a className="me-2 text-wrap" href={`/questions/${question.id}`} target="_blank" rel="noopener noreferrer" title="Preview question in new tab">
103-
{generateQuestionTitle(question)}
104-
</a>
105-
<input
106-
type="image" src="/assets/common/icons/new-tab.svg" alt="Preview question" title="Preview question in modal"
107-
className="pointer-cursor align-middle new-tab" onClick={() => question.id && openQuestionModal(question.id)}
108-
/>
109-
<Spacer />
110-
{isPhy && <div className="d-flex flex-column justify-self-end">
111-
{question.supersededBy && <a
112-
className="superseded-tag ms-1 ms-sm-3 my-1 align-self-end"
113-
href={`/questions/${question.supersededBy}`}
114-
onClick={(e) => e.stopPropagation()}
115-
>SUPERSEDED</a>}
116-
{question.tags?.includes("nofilter") && <span
117-
className="superseded-tag ms-1 ms-sm-3 my-1 align-self-end"
118-
>NO-FILTER</span>}
119-
</div>}
120-
</div>
101+
{provided && <img src="/assets/common/icons/drag_indicator.svg" alt="Drag to reorder" className="me-1 grab-cursor" />}
102+
<div>
103+
<div className="d-flex">
104+
<a className="me-2 text-wrap" href={`/questions/${question.id}`} target="_blank" rel="noopener noreferrer" title="Preview question in new tab">
105+
{generateQuestionTitle(question)}
106+
</a>
107+
<input
108+
type="image" src="/assets/common/icons/new-tab.svg" alt="Preview question" title="Preview question in modal"
109+
className="pointer-cursor align-middle new-tab" onClick={() => question.id && openQuestionModal(question.id)}
110+
/>
111+
<Spacer />
112+
{isPhy && <div className="d-flex flex-column justify-self-end">
113+
{question.supersededBy && <a
114+
className="superseded-tag ms-1 ms-sm-3 my-1 align-self-end"
115+
href={`/questions/${question.supersededBy}`}
116+
onClick={(e) => e.stopPropagation()}
117+
>SUPERSEDED</a>}
118+
{question.tags?.includes("nofilter") && <span
119+
className="superseded-tag ms-1 ms-sm-3 my-1 align-self-end"
120+
>NO-FILTER</span>}
121+
</div>}
122+
</div>
121123

122-
{question.subtitle && <>
123-
<span className="small text-muted d-none d-sm-block">{question.subtitle}</span>
124-
</>}
124+
{question.subtitle && <>
125+
<span className="small text-muted d-none d-sm-block">{question.subtitle}</span>
126+
</>}
127+
</div>
128+
</div>
125129
</td>
126130
<td rowSpan={arr.length} className={classNames(cellClasses, siteSpecific("w-25", "w-20"))}>
127131
{topicTag()}
@@ -142,4 +146,5 @@ const GameboardBuilderRow = (
142146
</td>}
143147
</tr>);
144148
};
149+
145150
export default GameboardBuilderRow;

src/app/components/pages/GameboardBuilder.tsx

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -281,48 +281,53 @@ const GameboardBuilder = ({user}: {user: RegisteredUserDTO}) => {
281281

282282
<div className="my-4 responsive">
283283
<DragDropContext onDragEnd={reorder}>
284-
<Table bordered className="m-0">
285-
<thead>
286-
<tr>
287-
<th className="w-5"/>
288-
<th className={siteSpecific("w-40", "w-30")}>Question title</th>
289-
<th className={siteSpecific("w-25", "w-20")}>Topic</th>
290-
<th className="w-15">Stage</th>
291-
<th className="w-15">Difficulty</th>
292-
{isAda && <th className="w-15">Exam boards</th>}
293-
</tr>
294-
</thead>
295-
<Droppable droppableId="droppable">
296-
{(provided) => {
297-
return (
298-
<tbody ref={provided.innerRef}>
284+
<Droppable droppableId="droppable">
285+
{(providedDrop) => {
286+
return (
287+
<Table bordered className="m-0" innerRef={providedDrop.innerRef}>
288+
<thead>
289+
<tr>
290+
<th className="w-5"/>
291+
<th className={siteSpecific("w-40", "w-30")}>Question title</th>
292+
<th className={siteSpecific("w-25", "w-20")}>Topic</th>
293+
<th className="w-15">Stage</th>
294+
<th className="w-15">Difficulty</th>
295+
{isAda && <th className="w-15">Exam boards</th>}
296+
</tr>
297+
</thead>
299298
{questionOrder.map((questionId, index: number) => {
300299
const question = selectedQuestions.get(questionId);
301-
return question && question.id &&
302-
<Draggable key={question.id} draggableId={question.id} index={index}>
303-
{(provided, snapshot) => (
300+
return question && question.id && <Draggable key={question.id} draggableId={question.id} index={index}>
301+
{(providedDrag, snapshot) => {
302+
return <tbody ref={providedDrag && providedDrag.innerRef}
303+
className={classNames({"table-row-dragging" : snapshot.isDragging})}
304+
{...(providedDrag && providedDrag.draggableProps)} {...(providedDrag && providedDrag.dragHandleProps)}
305+
>
304306
<GameboardBuilderRow
305-
provided={provided}
307+
provided={providedDrag}
306308
snapshot={snapshot}
307309
key={`gameboard-builder-row-${question.id}`}
308310
question={question}
309311
currentQuestions={currentQuestions}
310312
undoStack={undoStack}
311313
redoStack={redoStack}
312314
creationContext={question.creationContext}
313-
/>)}
314-
</Draggable>;
315+
/>
316+
</tbody>;
317+
}}
318+
</Draggable>;
315319
})}
316-
{provided.placeholder}
317-
{selectedQuestions?.size === 0 && <tr>
318-
<td colSpan={20}>
319-
</td>
320-
</tr>}
320+
<tbody >
321+
{providedDrop.placeholder}
322+
{selectedQuestions?.size === 0 && <tr>
323+
<td colSpan={20}>
324+
</td>
325+
</tr>}
321326
</tbody>
322-
);
323-
}}
324-
</Droppable>
325-
</Table>
327+
</Table>
328+
);
329+
}}
330+
</Droppable>
326331
</DragDropContext>
327332
</div>
328333

src/scss/common/table.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.table-row-dragging {
2+
display: table;
3+
}

src/scss/cs/table.scss

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@import "../common/table";
2+
13
.table {
24
text-align: left;
35
th {
@@ -41,4 +43,4 @@
4143

4244
.long-titled-col {
4345
min-width: 140px;
44-
}
46+
}

src/scss/phy/table.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@import "../common/table";
2+
13
.table:not(.table-borderless) thead th {
24
vertical-align: bottom;
35
border-bottom: 2px solid $border-color;

0 commit comments

Comments
 (0)