diff --git a/frontend/components/ClubEditPage/EventsCard.tsx b/frontend/components/ClubEditPage/EventsCard.tsx
index e0acc1feb..b8fbaf946 100644
--- a/frontend/components/ClubEditPage/EventsCard.tsx
+++ b/frontend/components/ClubEditPage/EventsCard.tsx
@@ -1,7 +1,6 @@
import { Field } from 'formik'
import moment from 'moment'
import React, { ReactElement, useState } from 'react'
-import CreatableSelect from 'react-select/creatable'
import TimeAgo from 'react-timeago'
import styled from 'styled-components'
@@ -297,7 +296,22 @@ const eventTableFields = [
{
name: 'is_ics_event',
label: 'ICS',
- converter: (a: boolean): ReactElement => ,
+ converter: (a: boolean): ReactElement => (
+
+ ),
+ },
+]
+
+const eventTableFilter = [
+ {
+ label: 'Types',
+ options: EVENT_TYPES.map((obj) => {
+ return { key: obj.value, label: obj.label }
+ }),
+ filterFunction: (selection, object) => object.type === selection,
},
]
@@ -343,12 +357,6 @@ const eventFields = (
placeholder="Type your event description here!"
as={RichTextField}
/>
-
>
)
@@ -415,6 +423,7 @@ export default function EventsCard({ club }: EventsCardProps): ReactElement {
fields={eventFields}
fileFields={['image']}
tableFields={eventTableFields}
+ filterOptions={eventTableFilter}
noun="Event"
currentTitle={(obj) => (obj != null ? obj.name : 'Deleted Event')}
onChange={(obj) => {
diff --git a/frontend/components/ClubEditPage/MembersCard.tsx b/frontend/components/ClubEditPage/MembersCard.tsx
index 74d1585e8..a50937225 100644
--- a/frontend/components/ClubEditPage/MembersCard.tsx
+++ b/frontend/components/ClubEditPage/MembersCard.tsx
@@ -95,7 +95,16 @@ export default function MembersCard({ club }: MembersCardProps): ReactElement {
],
filterFunction: (selection, object) => object.role === selection,
},
+ {
+ label: 'Active',
+ options: [
+ { key: true, label: 'Active' },
+ { key: false, label: 'Inactive' },
+ ],
+ filterFunction: (selection, object) => object.active === selection,
+ },
]}
+ searchableColumns={['name', 'email']}
currentTitle={(obj) =>
obj != null ? `${obj.name} (${obj.email})` : 'Kicked Member'
}
diff --git a/frontend/components/ModelForm.tsx b/frontend/components/ModelForm.tsx
index f76248bff..80c9ee12a 100644
--- a/frontend/components/ModelForm.tsx
+++ b/frontend/components/ModelForm.tsx
@@ -74,6 +74,7 @@ type ModelFormProps = {
fields: any
tableFields?: TableField[]
filterOptions?: FilterOption[]
+ searchableColumns?: string[]
currentTitle?: (object: ModelObject) => ReactElement | string
noun?: string
deleteVerb?: string
@@ -111,6 +112,7 @@ export const doFormikInitialValueFixes = (currentObject: {
type ModelTableProps = {
tableFields: TableField[]
filterOptions?: FilterOption[]
+ searchableColumns?: string[]
objects: ModelObject[]
allowEditing?: boolean
allowDeletion?: boolean
@@ -130,6 +132,7 @@ type ModelTableProps = {
export const ModelTable = ({
tableFields,
filterOptions,
+ searchableColumns,
objects,
allowEditing = false,
allowDeletion = false,
@@ -150,16 +153,16 @@ export const ModelTable = ({
})),
[tableFields],
)
-
tableFields = tableFields.map((column, index) => {
if (column.converter) {
const renderFunction = column.converter
return {
...column,
- render: (id, _) => {
- const obj = objects?.[id]
+ render: (id) => {
+ const obj =
+ objects?.filter((item) => item.id === id)[0] || objects?.[id]
const value = obj?.[column.name]
- return obj && value ? renderFunction(value, obj) : 'N/A'
+ return obj && value !== null ? renderFunction(value, obj) : 'None'
},
}
} else return column
@@ -215,7 +218,9 @@ export const ModelTable = ({
field.name)
+ }
filterOptions={filterOptions || []}
draggable={draggable}
onDragEnd={onDragEnd}
@@ -255,6 +260,7 @@ export const ModelForm = (props: ModelFormProps): ReactElement => {
fields,
tableFields,
filterOptions,
+ searchableColumns,
onUpdate,
currentTitle,
noun = 'Object',
@@ -464,6 +470,7 @@ export const ModelForm = (props: ModelFormProps): ReactElement => {
noun={noun}
tableFields={tableFields}
filterOptions={filterOptions}
+ searchableColumns={searchableColumns}
objects={objects}
allowDeletion={allowDeletion}
confirmDeletion={confirmDeletion}
diff --git a/frontend/components/PaginatedClubDisplay.tsx b/frontend/components/PaginatedClubDisplay.tsx
index d65bb35a5..db61b9519 100644
--- a/frontend/components/PaginatedClubDisplay.tsx
+++ b/frontend/components/PaginatedClubDisplay.tsx
@@ -101,7 +101,7 @@ const PaginatedClubDisplay = ({
/>
)}
{isLoading && }
- {clubs && clubs.length <= 0 && (
+ {(clubs == null || clubs.length <= 0) && (
('')
const [tableData, setTableData] = useState([])
const [selectedFilter, setSelectedFilter] = useState({})
+ const [sortedColumn, setSortedColumn] = useState(null)
useEffect(() => {
const searchedData = data.filter((item) => {
if (!searchQuery || searchQuery.length < 3) {
return true
}
return searchableColumns.some((searchId) => {
- const strings = item[searchId].split(' ')
- return strings.some((string) =>
- string.toLowerCase().startsWith(searchQuery.toLowerCase()),
- )
+ if (typeof item[searchId] === 'string') {
+ const strings = item[searchId].split(' ')
+ return strings.some((string) =>
+ string.toLowerCase().startsWith(searchQuery.toLowerCase()),
+ )
+ }
+ return false
})
})
const filteredData = searchedData.filter((item) => {
@@ -216,6 +224,18 @@ const Table = ({
setSearchQuery(e.target.value)
}
+ const handleColumnsSort = (target) => {
+ if (sortedColumn && sortedColumn.name === target) {
+ if (sortedColumn.status === 'asc') {
+ setSortedColumn({ name: target, status: 'desc' })
+ } else {
+ setSortedColumn(null)
+ }
+ } else {
+ setSortedColumn({ name: target, status: 'asc' })
+ }
+ }
+
const components = {
IndicatorSeparator: () => null,
}
@@ -225,7 +245,6 @@ const Table = ({
newFilters[newFilter.label] = newFilter.value
setSelectedFilter(newFilters)
}
-
if (data.length <= 0) {
return <>>
} else if (setInitialPage != null) {
@@ -233,8 +252,8 @@ const Table = ({
}
return (
-
-
+
+
-
-
- {filterOptions &&
- filterOptions.map((filterOption) => (
-
-
- ))}
-
+
+ {filterOptions &&
+ filterOptions.map((filterOption) => (
+
+
+ ))}
- {tableData.length > 0 ? (
+ {headerGroups.length > 0 ? (
{headerGroups.map((headerGroup) => (
{headerGroup.headers.map((column) => (
- {titleize(column.render('Header'))}
-
- {column.isSorted ? (
- column.isSortedDesc ? (
-
+ handleColumnsSort(column.Header)}>
+ {titleize(column.render('Header'))}
+
+ {column.isSorted ? (
+ column.isSortedDesc ? (
+
+ ) : (
+
+ )
+ ) : sortedColumn === null ? (
+
) : (
-
- )
- ) : (
- ''
- )}
-
+ ''
+ )}
+
+
|
))}
@@ -334,8 +352,12 @@ const Table = ({
return (
{column.render
- ? column.render(row.original.id, row.id)
- : row.original[column.name]}
+ ? column.render(row.original.id) || (
+ None
+ )
+ : row.original[column.name] || (
+ None
+ )}
|
)
})}
@@ -412,23 +434,25 @@ const Table = ({
)}
) : (
-
No matches were found. Please change your filters.
+
Nothing to Show.
)}
{pageOptions.length > 1 && (
-
+
)}
diff --git a/frontend/public/static/img/icons/group-arrows.svg b/frontend/public/static/img/icons/group-arrows.svg
new file mode 100644
index 000000000..e4bc620eb
--- /dev/null
+++ b/frontend/public/static/img/icons/group-arrows.svg
@@ -0,0 +1,4 @@
+
diff --git a/frontend/public/static/img/icons/triangle-down.svg b/frontend/public/static/img/icons/triangle-down.svg
new file mode 100644
index 000000000..80b1ebda1
--- /dev/null
+++ b/frontend/public/static/img/icons/triangle-down.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/public/static/img/icons/triangle-up.svg b/frontend/public/static/img/icons/triangle-up.svg
new file mode 100644
index 000000000..11f444267
--- /dev/null
+++ b/frontend/public/static/img/icons/triangle-up.svg
@@ -0,0 +1,3 @@
+