refactor: migrate to dndkit for drag list

This commit is contained in:
Markus
2026-08-18 15:07:28 +03:00
parent b25da72aee
commit 1bdb6f51ef
8 changed files with 1183 additions and 625 deletions
+1087 -577
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -19,6 +19,8 @@
"format:check": "oxfmt --check" "format:check": "oxfmt --check"
}, },
"dependencies": { "dependencies": {
"@dnd-kit/helpers": "^0.2.4",
"@dnd-kit/react": "^0.2.4",
"@emotion/react": "^11.14.0", "@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1", "@emotion/styled": "^11.14.1",
"@mui/icons-material": "^9.2.0", "@mui/icons-material": "^9.2.0",
@@ -31,7 +33,6 @@
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^19.2.8", "react": "^19.2.8",
"react-dom": "^19.2.8", "react-dom": "^19.2.8",
"react-drag-list": "^1.1.0",
"react-markdown": "^10.1.0", "react-markdown": "^10.1.0",
"react-redux": "^9.3.0", "react-redux": "^9.3.0",
"react-router-dom": "^7.18.2", "react-router-dom": "^7.18.2",
@@ -2,7 +2,6 @@ import { withRouter } from '../utils/withRouter'
import React from 'react' import React from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import ReactDragList from 'react-drag-list'
import registrationActions from '../reducers/actions/registrationActions' import registrationActions from '../reducers/actions/registrationActions'
import { setError } from '../reducers/actions/notificationActions' import { setError } from '../reducers/actions/notificationActions'
@@ -11,8 +10,8 @@ import peerReviewService from '../services/peerReview'
import Typography from '@mui/material/Typography' import Typography from '@mui/material/Typography'
import { Input, Card, CardContent, Select, MenuItem } from '@mui/material' import { Input, Card, CardContent, Select, MenuItem } from '@mui/material'
import TopicDialog from './TopicDialog'
import CourseMaterial from './common/CourseMaterial' import CourseMaterial from './common/CourseMaterial'
import SortableTopicList from './SortableTopicList'
import { formatDate, extractCallingName } from '../utils/functions' import { formatDate, extractCallingName } from '../utils/functions'
@@ -125,26 +124,8 @@ const PreferredTopics = ({ topics }) => {
return ( return (
<div> <div>
<h2>Preferred Topics</h2> <h2>Preferred Topics</h2>
<div className="dragndrop-container"> <div className="dragndrop-container" style={{ flexDirection: 'column' }}>
<div className="dragndrop-indexes-container"> <SortableTopicList topics={topics} isReadOnly={true} />
{topics.map((topic, index) => {
return (
<Card key={index} className="dragndrop-index">
{index + 1}
</Card>
)
})}
</div>
<ReactDragList
className="dragndrop-list"
handles={false}
dataSource={topics}
rowKey="id"
row={(topic) => {
return <TopicDialog topic={topic} key={topic.content.title} />
}}
disabled
/>
</div> </div>
</div> </div>
) )
@@ -27,10 +27,6 @@
flex-direction: row; flex-direction: row;
} }
.dragndrop-list {
flex: 99;
}
.dragndrop-indexes-container { .dragndrop-indexes-container {
flex: 1; flex: 1;
height: 80px; height: 80px;
+2 -17
View File
@@ -2,7 +2,6 @@ import { withRouter } from '../utils/withRouter'
import React from 'react' import React from 'react'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import ReactDragList from 'react-drag-list'
// MUI // MUI
import Card from '@mui/material/Card' import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent' import CardContent from '@mui/material/CardContent'
@@ -19,7 +18,6 @@ import configurationService from '../services/configuration'
// components // components
import LoadingSpinner from './common/LoadingSpinner' import LoadingSpinner from './common/LoadingSpinner'
import CourseMaterial from './common/CourseMaterial' import CourseMaterial from './common/CourseMaterial'
import TopicDialog from './TopicDialog'
import UserDetails from './UserDetails' import UserDetails from './UserDetails'
import './RegistrationPage.css' import './RegistrationPage.css'
// Actions // Actions
@@ -27,6 +25,7 @@ import registrationPageActions from '../reducers/actions/registrationPageActions
import * as notificationActions from '../reducers/actions/notificationActions' import * as notificationActions from '../reducers/actions/notificationActions'
import registrationActions from '../reducers/actions/registrationActions' import registrationActions from '../reducers/actions/registrationActions'
import registrationmanagementActions from '../reducers/actions/registrationManagementActions' import registrationmanagementActions from '../reducers/actions/registrationManagementActions'
import SortableTopicList from './SortableTopicList'
const Prerequisites = ({ checkbox1, checkbox2, checkbox3, onToggle1, onToggle2, onToggle3 }) => { const Prerequisites = ({ checkbox1, checkbox2, checkbox3, onToggle1, onToggle2, onToggle3 }) => {
return ( return (
@@ -306,12 +305,6 @@ class RegistrationPage extends React.Component {
</Card> </Card>
)) ))
const indexes = this.props.topics.map((item, idx) => (
<Card key={idx} className="dragndrop-index">
{idx + 1}
</Card>
))
return ( return (
<div> <div>
<div <div
@@ -455,15 +448,7 @@ class RegistrationPage extends React.Component {
dragging and dropping, click to expand details dragging and dropping, click to expand details
</div> </div>
<div className="dragndrop-container"> <div className="dragndrop-container">
<div className="dragndrop-indexes-container">{indexes}</div> <SortableTopicList topics={this.props.topics} onUpdate={this.handleUpdate} />
<ReactDragList
className="dragndrop-list"
handles={false}
dataSource={this.props.topics}
onUpdate={this.handleUpdate}
rowKey="id"
row={(topic) => <TopicDialog topic={topic} key={topic.content.title} />}
/>
</div> </div>
</> </>
)} )}
@@ -0,0 +1,65 @@
import { DragDropProvider } from '@dnd-kit/react'
import { useSortable } from '@dnd-kit/react/sortable'
import { move } from '@dnd-kit/helpers'
import Card from '@mui/material/Card'
import TopicDialog from './TopicDialog'
const SortableTopicItem = ({ topic, index, isReadOnly }) => {
const { ref, isDragging } = useSortable({
id: topic.id,
index,
disabled: isReadOnly,
})
const style = {
opacity: isDragging ? 0.4 : 1,
display: 'flex',
alignItems: 'stretch',
marginBottom: '8px',
}
return (
<div
ref={isReadOnly ? null : ref}
style={{ ...style, cursor: isReadOnly ? 'default' : 'grab' }}
>
<Card
className="dragndrop-index"
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
minWidth: '40px',
maxHeight: 'none',
padding: 0,
}}
>
{index + 1}
</Card>
<div style={{ flex: 1, minWidth: 0 }}>
<TopicDialog topic={topic} showDragIcon={!isReadOnly} />
</div>
</div>
)
}
const SortableTopicList = ({ topics, onUpdate, isReadOnly }) => {
const handleDragEnd = (event) => {
if (!event.canceled && onUpdate) {
const newTopics = move(topics, event)
onUpdate(null, newTopics)
}
}
return (
<DragDropProvider onDragEnd={handleDragEnd}>
<div className="dragndrop-list">
{topics.map((topic, index) => (
<SortableTopicItem key={topic.id} topic={topic} index={index} isReadOnly={isReadOnly} />
))}
</div>
</DragDropProvider>
)
}
export default SortableTopicList
+24 -2
View File
@@ -7,6 +7,7 @@ import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent' import CardContent from '@mui/material/CardContent'
import Topic from './Topic' import Topic from './Topic'
import Typography from '@mui/material/Typography' import Typography from '@mui/material/Typography'
import DragIndicatorIcon from '@mui/icons-material/DragIndicator'
class TopicDialog extends React.Component { class TopicDialog extends React.Component {
constructor(props) { constructor(props) {
@@ -37,8 +38,29 @@ class TopicDialog extends React.Component {
: 'Software is published under an open source license' : 'Software is published under an open source license'
return ( return (
<Card style={{ margin: '2px', height: '78px' }}> <Card style={{ margin: '2px', minHeight: '78px' }}>
<CardContent style={{ padding, display: 'flex', flexDirection: 'row' }}> <CardContent
style={{
padding,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
}}
>
{this.props.showDragIcon && (
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginRight: '12px',
color: '#888',
flexShrink: 0,
}}
>
<DragIndicatorIcon />
</div>
)}
<div style={{ flex: 4 }}> <div style={{ flex: 4 }}>
<Typography style={{ flex: 1, fontWeight: 'bold' }}> <Typography style={{ flex: 1, fontWeight: 'bold' }}>
{this.props.topic.content.title} {this.props.topic.content.title}
-2
View File
@@ -6,8 +6,6 @@
"packages": { "packages": {
"": { "": {
"name": "ohtuilmo", "name": "ohtuilmo",
"version": "1.0.0",
"license": "ISC",
"devDependencies": { "devDependencies": {
"husky": "^9.1.7", "husky": "^9.1.7",
"lint-staged": "^17.3.0" "lint-staged": "^17.3.0"