From bc1484d11db0b02d5472a4a4ce3a12f1cde43ba4 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Tue, 17 Nov 2020 10:36:33 -0500 Subject: [PATCH 01/12] Stop auto population of text on menu item hover --- src/components/QueueSelector/QueueSelector.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index f4d8c4a..12ad57a 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -34,7 +34,6 @@ export default function QueueSelector({ queues, selectedQueues, setSelectedQueue )} getOptionSelected={ (option, value) => option.name === value.name } disableCloseOnSelect - autoComplete disableListWrap openOnFocus fullWidth From 68ec4382a5fbc006e133e09b6dbc73765d3e86bd Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Tue, 17 Nov 2020 10:44:40 -0500 Subject: [PATCH 02/12] Disable open on focus --- src/components/QueueSelector/QueueSelector.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index 12ad57a..2fe2050 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -35,7 +35,6 @@ export default function QueueSelector({ queues, selectedQueues, setSelectedQueue getOptionSelected={ (option, value) => option.name === value.name } disableCloseOnSelect disableListWrap - openOnFocus fullWidth multiple /> From 9979aa81eafef15a57d0431ee2e87a9721b21898 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Tue, 17 Nov 2020 10:45:21 -0500 Subject: [PATCH 03/12] Update placeholder text --- src/components/QueueSelector/QueueSelector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index 2fe2050..a57b69a 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -16,7 +16,7 @@ export default function QueueSelector({ queues, selectedQueues, setSelectedQueue return( ); }} From c216a179b625b8c24dfcffafbca6c141825f0d32 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Tue, 17 Nov 2020 12:44:27 -0500 Subject: [PATCH 04/12] Add label via start adornment w/ workaround --- src/components/QueueSelector/QueueSelector.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index a57b69a..c17c7c9 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -1,6 +1,6 @@ import React from "react"; import PropTypes from "prop-types"; -import { TextField, Checkbox} from "@material-ui/core"; +import { TextField, Checkbox, InputAdornment } from "@material-ui/core"; import { Autocomplete } from "@material-ui/lab"; import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'; import CheckBoxIcon from '@material-ui/icons/CheckBox'; @@ -17,6 +17,20 @@ export default function QueueSelector({ queues, selectedQueues, setSelectedQueue + + Active Queues: + + {params.InputProps.startAdornment} + + ), + }} /> ); }} From 172480b73cbc8047c465e89e2162a01a60ceec54 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Tue, 17 Nov 2020 15:06:15 -0500 Subject: [PATCH 05/12] Refactor handler functions --- src/components/QueueSelector/QueueSelector.js | 76 ++++++++++--------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index c17c7c9..01a605b 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -6,46 +6,50 @@ import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'; import CheckBoxIcon from '@material-ui/icons/CheckBox'; export default function QueueSelector({ queues, selectedQueues, setSelectedQueues }) { + + const handleChange = (event, newValue) => { + setSelectedQueues(newValue) + }; + + const optionRenderer = (option, { selected }) => ( + <> + } + checkedIcon={} + style={{ marginRight: 8 }} + checked={selected} + /> + {`${option.name} (${option.number_of_items})`} + + ); + return( ( + + + Active Queues: + + {params.InputProps.startAdornment} + + ), + }} + /> + )} + options={queues} - onChange={(event, newValue) => { - setSelectedQueues(newValue) - }} - renderInput={(params) => { - return( - - - Active Queues: - - {params.InputProps.startAdornment} - - ), - }} - /> - ); - }} + onChange={handleChange} getOptionLabel={(option) => `${option.name} (${option.number_of_items})`} - renderOption={(option, { selected }) => ( - <> - } - checkedIcon={} - style={{ marginRight: 8 }} - checked={selected} - /> - {`${option.name} (${option.number_of_items})`} - - )} + renderOption={optionRenderer} getOptionSelected={ (option, value) => option.name === value.name } disableCloseOnSelect disableListWrap From 983e85218982ead686f430f602d47943682c4cee Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Tue, 17 Nov 2020 15:17:44 -0500 Subject: [PATCH 06/12] Add visual spacing and use small outlined styling --- src/components/QueueSelector/QueueSelector.js | 70 ++++++++++--------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index 01a605b..fb0f6bf 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -1,12 +1,14 @@ import React from "react"; import PropTypes from "prop-types"; -import { TextField, Checkbox, InputAdornment } from "@material-ui/core"; +import { TextField, Checkbox, InputAdornment, Box, useTheme } from "@material-ui/core"; import { Autocomplete } from "@material-ui/lab"; import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'; import CheckBoxIcon from '@material-ui/icons/CheckBox'; export default function QueueSelector({ queues, selectedQueues, setSelectedQueues }) { + const theme = useTheme(); + const handleChange = (event, newValue) => { setSelectedQueues(newValue) }; @@ -24,38 +26,42 @@ export default function QueueSelector({ queues, selectedQueues, setSelectedQueue ); return( - ( - - - Active Queues: - - {params.InputProps.startAdornment} - - ), - }} - /> - )} + + ( + + + Active Queues: + + {params.InputProps.startAdornment} + + ), + }} + /> + )} - options={queues} - onChange={handleChange} - getOptionLabel={(option) => `${option.name} (${option.number_of_items})`} - renderOption={optionRenderer} - getOptionSelected={ (option, value) => option.name === value.name } - disableCloseOnSelect - disableListWrap - fullWidth - multiple - /> + options={queues} + onChange={handleChange} + getOptionLabel={(option) => `${option.name} (${option.number_of_items})`} + renderOption={optionRenderer} + getOptionSelected={ (option, value) => option.name === value.name } + disableCloseOnSelect + disableListWrap + fullWidth + multiple + size="small" + /> + ); }; From 18e05652a4fc03d8d0d1e7cd3b73431cfb7790fd Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 19 Nov 2020 10:36:21 -0500 Subject: [PATCH 07/12] Auto highlight first matching queue --- src/components/QueueSelector/QueueSelector.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index fb0f6bf..3866559 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -60,6 +60,7 @@ export default function QueueSelector({ queues, selectedQueues, setSelectedQueue fullWidth multiple size="small" + autoHighlight /> ); From 1743ecb6b668d6178a74605ba967eea383e0a78c Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 19 Nov 2020 14:55:19 -0500 Subject: [PATCH 08/12] Consolidate queue count fetch and add visual loading state --- src/components/AppView/AppView.js | 21 +------ src/components/QueueSelector/QueueSelector.js | 57 +++++++++++++++---- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/components/AppView/AppView.js b/src/components/AppView/AppView.js index a00abbe..9c630fc 100644 --- a/src/components/AppView/AppView.js +++ b/src/components/AppView/AppView.js @@ -16,7 +16,6 @@ export default function AppView({ setDarkMode }){ const [queues, setQueues] = useState([]); const [items, setItems] = useState([]); const [selectedQueues, setSelectedQueues] = useState([]); - const [queueCounts, setQueueCounts] = useState([]); const access_token = useToken(); @@ -55,24 +54,6 @@ export default function AppView({ setDarkMode }){ setItems(tempItems); }, [queues]); - useEffect( _ => { - async function getQueueCounts(){ - if (access_token === null){ - return - } - - let myHeaders = new Headers(); - myHeaders.append("Authorization", `Bearer ${access_token}`); - let requestOptions = { headers: myHeaders }; - - const apiResponse = await fetch(`/api/get_queues`, requestOptions); - const queueCountJson = await apiResponse.json(); - setQueueCounts(queueCountJson); - }; - getQueueCounts(); - return _ => setQueueCounts([]); - }, [selectedQueues, access_token]); - const theme = useTheme(); const transitionWidth = theme.transitions.create(["width"], { duration: theme.transitions.duration.enteringScreen, @@ -111,7 +92,7 @@ export default function AppView({ setDarkMode }){ - + diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index 3866559..ae66b44 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -1,11 +1,44 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import PropTypes from "prop-types"; import { TextField, Checkbox, InputAdornment, Box, useTheme } from "@material-ui/core"; import { Autocomplete } from "@material-ui/lab"; import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'; import CheckBoxIcon from '@material-ui/icons/CheckBox'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import { useToken } from "../AuthProvider/"; -export default function QueueSelector({ queues, selectedQueues, setSelectedQueues }) { +export default function QueueSelector({ selectedQueues, setSelectedQueues }) { + const [open, setOpen] = useState(false); + const [queues, setQueues] = useState([]); + const access_token = useToken(); + const loading = open && queues.length === 0; + + useEffect( _ => { + const getQueueCounts = async _ => { + if (access_token === null){ + return undefined + } + + let myHeaders = new Headers(); + myHeaders.append("Authorization", `Bearer ${access_token}`); + let requestOptions = { headers: myHeaders }; + + const apiResponse = await fetch(`/api/get_queues`, requestOptions); + const queueCountJson = await apiResponse.json(); + setQueues(queueCountJson); + }; + + if (loading) { + getQueueCounts(); + } + + }, [loading, access_token]); + + useEffect(() => { + if (!open) { + setQueues([]); + } + }, [open]); const theme = useTheme(); @@ -46,20 +79,30 @@ export default function QueueSelector({ queues, selectedQueues, setSelectedQueue {params.InputProps.startAdornment} ), + endAdornment: ( + <> + {loading ? : null} + {params.InputProps.endAdornment} + + ) }} /> )} - + options={queues} onChange={handleChange} getOptionLabel={(option) => `${option.name} (${option.number_of_items})`} renderOption={optionRenderer} getOptionSelected={ (option, value) => option.name === value.name } + size="small" + open={open} + onOpen={_ => setOpen(true)} + onClose={_ => setOpen(false)} + loading={true} disableCloseOnSelect disableListWrap fullWidth multiple - size="small" autoHighlight /> @@ -67,14 +110,8 @@ export default function QueueSelector({ queues, selectedQueues, setSelectedQueue }; QueueSelector.propTypes = { - /** An array of objects with keys of name and number of items for each queue. */ - "queues": PropTypes.array, /** State variable to manage selected queues. */ "selectedQueues": PropTypes.array.isRequired, /** Function to update state variable that manages selected queues. */ "setSelectedQueues": PropTypes.func.isRequired -}; - -QueueSelector.defaultProps = { - "queues": [] }; \ No newline at end of file From cd85eee3a72a915a6a87083fbca9a0af040bc1e7 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Thu, 19 Nov 2020 14:58:30 -0500 Subject: [PATCH 09/12] Autofocus QueueSelector --- src/components/QueueSelector/QueueSelector.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index ae66b44..8c912ba 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -66,6 +66,7 @@ export default function QueueSelector({ selectedQueues, setSelectedQueues }) { {...params} variant="outlined" placeholder={selectedQueues.length === 0 ? "Click or type to select queues." : ""} + autoFocus // The MUI Autocomplete component uses the InputProps.startAdornment to store chips fpr multi-selection. // Using InputProps.startAdornment directly will override those chips. Code below is a workaround. // See: https://github.com/mui-org/material-ui/issues/19479 From 2de2d344fcc97bd85d92b5fb1fa59a7ffb7ffc40 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Fri, 20 Nov 2020 11:07:24 -0500 Subject: [PATCH 10/12] Refactor queues to queueCounts --- src/components/QueueSelector/QueueSelector.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index 8c912ba..5d8d45f 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -9,9 +9,9 @@ import { useToken } from "../AuthProvider/"; export default function QueueSelector({ selectedQueues, setSelectedQueues }) { const [open, setOpen] = useState(false); - const [queues, setQueues] = useState([]); + const [queueCounts, setQueueCounts] = useState([]); const access_token = useToken(); - const loading = open && queues.length === 0; + const loading = open && queueCounts.length === 0; useEffect( _ => { const getQueueCounts = async _ => { @@ -25,7 +25,7 @@ export default function QueueSelector({ selectedQueues, setSelectedQueues }) { const apiResponse = await fetch(`/api/get_queues`, requestOptions); const queueCountJson = await apiResponse.json(); - setQueues(queueCountJson); + setQueueCounts(queueCountJson); }; if (loading) { @@ -36,9 +36,9 @@ export default function QueueSelector({ selectedQueues, setSelectedQueues }) { useEffect(() => { if (!open) { - setQueues([]); + setQueueCounts([]); } - }, [open]); + }, [open]); const theme = useTheme(); @@ -90,7 +90,7 @@ export default function QueueSelector({ selectedQueues, setSelectedQueues }) { /> )} - options={queues} + options={queueCounts} onChange={handleChange} getOptionLabel={(option) => `${option.name} (${option.number_of_items})`} renderOption={optionRenderer} From e7bc28118ef3e0650700c1e051299aa99eeea8a0 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Fri, 20 Nov 2020 11:07:38 -0500 Subject: [PATCH 11/12] Add controlled values --- src/components/QueueSelector/QueueSelector.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index 5d8d45f..1c119f6 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -91,6 +91,7 @@ export default function QueueSelector({ selectedQueues, setSelectedQueues }) { )} options={queueCounts} + value={selectedQueues} onChange={handleChange} getOptionLabel={(option) => `${option.name} (${option.number_of_items})`} renderOption={optionRenderer} From f8fa0922d974f885c58116907004d6370b3760a7 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Fri, 20 Nov 2020 11:48:23 -0500 Subject: [PATCH 12/12] Raise QueueSelector open state and optimize API calls --- src/components/AppView/AppView.js | 16 +++++++++++++--- src/components/QueueSelector/QueueSelector.js | 11 ++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/components/AppView/AppView.js b/src/components/AppView/AppView.js index 9c630fc..9ba85ef 100644 --- a/src/components/AppView/AppView.js +++ b/src/components/AppView/AppView.js @@ -16,13 +16,18 @@ export default function AppView({ setDarkMode }){ const [queues, setQueues] = useState([]); const [items, setItems] = useState([]); const [selectedQueues, setSelectedQueues] = useState([]); + const [queueSelectorOpen, setQueueSelectorOpen] = useState(false); const access_token = useToken(); useEffect( _ => { async function getQueues(){ if (access_token === null){ - return + return undefined + } + + if (queueSelectorOpen){ + return undefined } if (selectedQueues.length > 0){ @@ -44,7 +49,7 @@ export default function AppView({ setDarkMode }){ } } getQueues(); - }, [selectedQueues, access_token]); + }, [selectedQueues, access_token, queueSelectorOpen]); useEffect( _ => { let tempItems = []; @@ -92,7 +97,12 @@ export default function AppView({ setDarkMode }){ - + diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index 1c119f6..4395d02 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -7,8 +7,9 @@ import CheckBoxIcon from '@material-ui/icons/CheckBox'; import CircularProgress from '@material-ui/core/CircularProgress'; import { useToken } from "../AuthProvider/"; -export default function QueueSelector({ selectedQueues, setSelectedQueues }) { - const [open, setOpen] = useState(false); +export default function QueueSelector({ queueSelectorOpen, setQueueSelectorOpen, selectedQueues, setSelectedQueues }) { + const open = queueSelectorOpen; + const setOpen = setQueueSelectorOpen; const [queueCounts, setQueueCounts] = useState([]); const access_token = useToken(); const loading = open && queueCounts.length === 0; @@ -112,8 +113,12 @@ export default function QueueSelector({ selectedQueues, setSelectedQueues }) { }; QueueSelector.propTypes = { + /** State variable to manage open status. */ + "queueSelectorOpen": PropTypes.bool.isRequired, + /** Function to update state variable that manages open status. */ + "setQueueSelectorOpen": PropTypes.func.isRequired, /** State variable to manage selected queues. */ "selectedQueues": PropTypes.array.isRequired, /** Function to update state variable that manages selected queues. */ - "setSelectedQueues": PropTypes.func.isRequired + "setSelectedQueues": PropTypes.func.isRequired, }; \ No newline at end of file