Skip to content

Commit

Permalink
Merge pull request #1265 from concord-consortium/187339065-research-c…
Browse files Browse the repository at this point in the history
…lasses-table

Add sorting to research classes table
  • Loading branch information
pjanik committed Apr 2, 2024
2 parents 3f2b95c + 21e421b commit f3b90e7
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 27 deletions.
12 changes: 6 additions & 6 deletions rails/app/assets/javascripts/react-components.js

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions rails/app/assets/javascripts/react-test-globals.js

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions rails/app/controllers/api/v1/researcher_classes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,13 @@ def classes_query(options, user, scope, ids)

def classes_mapping(classes_query)
classes_query.map do |c|
hash = {}
hash[:label] = c.name # required by JS code, fix it?
hash[:name] = c.name
hash[:teacher_names] = c.teachers.map { |t| "#{t.user.first_name} #{t.user.last_name}" }.join(", ")
hash[:cohort_names] = c.teachers.map { |t| t.cohorts.map(&:name) }.flatten.uniq.join(", ")
hash[:class_url] = materials_portal_clazz_url(c.id, researcher: true)
hash
{
id: c.id,
name: c.name,
teacher_names: c.teachers.map { |t| "#{t.user.first_name} #{t.user.last_name}" }.join(", "),
cohort_names: c.teachers.map { |t| t.cohorts.map(&:name) }.flatten.uniq.join(", "),
class_url: materials_portal_clazz_url(c.id, researcher: true)
}
end
end
end
2 changes: 1 addition & 1 deletion rails/app/policies/admin/project_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,6 @@ def api_show?
end

def research_classes?
update_or_edit? || user.is_project_researcher?(record)
update_or_edit? || user && user.is_project_researcher?(record)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,51 @@
width: 100%;
border: 1px solid #444;

th, td {
padding: 0 5px;
}

th {
background-color: #cdcdcd;
text-align: left;
$bgColor: #cdcdcd;
background-color: $bgColor;

.header {
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;

.sortIcon {
font-size: 0.85em;
position: relative;

&.desc {
margin-top: -7px;
&::after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 50%;
background: $bgColor;
}
}

&.asc {
margin-top: 7px;
&::after {
content: "";
position: absolute;
top: 50%;
left: 0;
right: 0;
bottom: 0;
background: $bgColor;
}
}
}
}
}
tr:nth-child(even) {
background-color: #efefef;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,56 @@ import 'react-day-picker/lib/style.css'
import css from './style.scss'

export default class ResearcherClassesTable extends React.Component {
constructor (props) {
super(props)
this.state = {
sortedClasses: props.classes,
// Default sort by id in descending order - this will show the most recent classes first
sortBy: 'id',
sortDirection: 'desc'
}
}

componentDidMount () {
this.sortClasses()
}

componentDidUpdate (prevProps) {
if (this.props.classes !== prevProps.classes) {
this.sortClasses(this.props.classes)
}
}

sortClasses (classesToSort = this.state.sortedClasses) {
const fieldName = this.state.sortBy
const direction = this.state.sortDirection
this.setState({
sortedClasses: classesToSort.slice().sort((a, b) => {
// Using localeCompare for a more natural sort order
const comparison = a[fieldName].toString().localeCompare(b[fieldName].toString(), 'en', { sensitivity: 'base' })
return direction === 'asc' ? comparison : -comparison
})
})
}

fieldSortIcon (fieldName) {
if (this.state.sortBy === fieldName) {
return this.state.sortDirection === 'asc' ? css.asc : css.desc
}
return ''
}

handleHeaderClick (fieldName) {
const direction = this.state.sortBy === fieldName && this.state.sortDirection === 'asc' ? 'desc' : 'asc'
this.setState({
sortBy: fieldName,
sortDirection: direction
}, () => this.sortClasses())
}

render () {
const { classes } = this.props
if (classes.length === 0) {
const { sortedClasses } = this.state
if (sortedClasses.length === 0) {
return null
}
return (
Expand All @@ -16,15 +63,27 @@ export default class ResearcherClassesTable extends React.Component {
<table>
<thead>
<tr>
<th>Cohort</th>
<th>Teacher</th>
<th>Class</th>
<th onClick={this.handleHeaderClick.bind(this, 'cohort_names')}>
<span className={css.header}>
Cohort <span className={`${css.sortIcon} ${this.fieldSortIcon('cohort_names')} icon-sort`} />
</span>
</th>
<th onClick={this.handleHeaderClick.bind(this, 'teacher_names')}>
<span className={css.header}>
Teacher <span className={`${css.sortIcon} ${this.fieldSortIcon('teacher_names')} icon-sort`} />
</span>
</th>
<th onClick={this.handleHeaderClick.bind(this, 'name')}>
<span className={css.header}>
Class <span className={`${css.sortIcon} ${this.fieldSortIcon('name')} icon-sort`} />
</span>
</th>
<th />
</tr>
</thead>
<tbody>
{
classes.map((c, i) => (
sortedClasses.map((c, i) => (
<tr key={i}>
<td>{c.cohort_names}</td>
<td>{c.teacher_names}</td>
Expand Down

0 comments on commit f3b90e7

Please sign in to comment.