diff --git a/apiserver/apiserver/api/serializers.py b/apiserver/apiserver/api/serializers.py index 540cf78..13720ee 100644 --- a/apiserver/apiserver/api/serializers.py +++ b/apiserver/apiserver/api/serializers.py @@ -523,6 +523,8 @@ class SimpleStorageSpaceSerializer(serializers.ModelSerializer): class StorageSpaceSerializer(serializers.ModelSerializer): member_id = serializers.SerializerMethodField() member_name = serializers.SerializerMethodField() + member_status = serializers.SerializerMethodField() + member_paused = serializers.SerializerMethodField() class Meta: model = models.StorageSpace @@ -553,6 +555,14 @@ class StorageSpaceSerializer(serializers.ModelSerializer): member = obj.user.member return member.preferred_name + ' ' + member.last_name + def get_member_status(self, obj): + if not obj.user: return None + return obj.user.member.status + + def get_member_paused(self, obj): + if not obj.user: return None + return obj.user.member.paused_date + class TrainingSerializer(serializers.ModelSerializer): attendance_status = serializers.ChoiceField([ diff --git a/webclient/src/Storage.js b/webclient/src/Storage.js index 6e4e22f..1f08d54 100644 --- a/webclient/src/Storage.js +++ b/webclient/src/Storage.js @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'; import { Link, useParams, useHistory } from 'react-router-dom'; import './light.css'; import { MembersDropdown } from './Members.js'; -import { isAdmin, BasicTable, requester, useIsMobile } from './utils.js'; +import { statusColor, isAdmin, BasicTable, requester, useIsMobile } from './utils.js'; import { Button, Checkbox, Container, Form, Grid, Header, Icon, Input, Message, Segment, Table } from 'semantic-ui-react'; export function StorageEditor(props) { @@ -277,6 +277,7 @@ let storageListCache = false; let showEmptyCache = false; let showMemodCache = false; let showServedCache = false; +let showExpiredCache = false; export function StorageList(props) { const { token } = props; @@ -285,6 +286,7 @@ export function StorageList(props) { const [showEmpty, setShowEmpty] = useState(showEmptyCache); const [showMemod, setShowMemod] = useState(showMemodCache); const [showServed, setShowServed] = useState(showServedCache); + const [showExpired, setShowExpired] = useState(showExpiredCache); const [error, setError] = useState(false); const isMobile = useIsMobile(); @@ -310,11 +312,21 @@ export function StorageList(props) { return false; } else if (showServed && !x.memo.toLowerCase().includes('served')) { return false; + } else if (showExpired && !x.member_paused) { + return false; } else { return true; } }; + const sortStorage = (a, b) => { + if (showExpired) { + return a.member_paused !== b.member_paused ? a.member_paused < b.member_paused ? -1 : 1 : 0; + } else { + return a.shelf_id !== b.shelf_id ? a.shelf_id < b.shelf_id ? -1 : 1 : 0; + } + }; + const handleShowEmpty = (e, v) => { setShowEmpty(v.checked); showEmptyCache = v.checked; @@ -330,6 +342,13 @@ export function StorageList(props) { showServedCache = v.checked; }; + const handleShowExpired = (e, v) => { + setShowExpired(v.checked); + showExpiredCache = v.checked; + }; + + const numResults = storageList ? storageList.filter(filterStorage).length : 0; + return (

@@ -363,29 +382,40 @@ export function StorageList(props) { onChange={handleShowServed} checked={showServed} /> + +

{!error ? storageList ? <> -

{storageList.filter(filterStorage).length} results:

+

{numResults} result{numResults === 1 ? '' : 's'}{showExpired && ', ordered by expiry'}:

{!isMobile && Shelf ID Owner + Expired Memo } - {storageList.filter(filterStorage).map(x => + {storageList.filter(filterStorage).sort(sortStorage).map(x => - {isMobile && 'Owner: '}{x.member_name} + {isMobile && 'Owner: '} + {x.member_name && } + {x.member_name} + {isMobile && 'Expired: '}{x.member_paused} {isMobile && 'Memo: '}{x.memo} )}