From ce280ca23d41dbfaccfc52b64d1a5b72b6164cdc Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Wed, 25 Nov 2020 21:51:43 -0500 Subject: [PATCH 1/4] Add csrf ass cookie dependency to reduce renders --- src/components/AuthProvider/AuthProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AuthProvider/AuthProvider.js b/src/components/AuthProvider/AuthProvider.js index 6643208..ae0effe 100644 --- a/src/components/AuthProvider/AuthProvider.js +++ b/src/components/AuthProvider/AuthProvider.js @@ -21,7 +21,7 @@ export default function AuthProvider({ children }) { const [loggedIn, setLoggedIn] = useState( false ); const [token, setToken] = useState( null ); - const [cookies] = useCookies(); + const [cookies] = useCookies(["csrf_refresh_token"]); async function tryRefresh(csrf_refresh_token){ if (csrf_refresh_token === undefined){ From 1e06378320adbc0f41d8e5b2649434cb2de63749 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Fri, 27 Nov 2020 17:55:56 -0500 Subject: [PATCH 2/4] Add clarifying comments --- src/components/QueueSelector/QueueSelector.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index 4395d02..b836b2c 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -14,6 +14,7 @@ export default function QueueSelector({ queueSelectorOpen, setQueueSelectorOpen, const access_token = useToken(); const loading = open && queueCounts.length === 0; + // Get queue counts if QueueSelector is open useEffect( _ => { const getQueueCounts = async _ => { if (access_token === null){ @@ -35,6 +36,7 @@ export default function QueueSelector({ queueSelectorOpen, setQueueSelectorOpen, }, [loading, access_token]); + // Delete queue counts if QueueSelector is closed useEffect(() => { if (!open) { setQueueCounts([]); @@ -47,6 +49,8 @@ export default function QueueSelector({ queueSelectorOpen, setQueueSelectorOpen, setSelectedQueues(newValue) }; + // Function to render checkboxes in dropdown + // See `renderOptions` prop at https://material-ui.com/api/autocomplete/#props const optionRenderer = (option, { selected }) => ( <> ( From 77c40a4e62a20e17d3538031ff6f5f149e68ca70 Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Mon, 30 Nov 2020 20:56:46 -0500 Subject: [PATCH 3/4] Add support for storing active queues across page reloads --- src/components/QueueSelector/QueueSelector.js | 105 +++++++++++++----- 1 file changed, 76 insertions(+), 29 deletions(-) diff --git a/src/components/QueueSelector/QueueSelector.js b/src/components/QueueSelector/QueueSelector.js index b836b2c..aa1a816 100644 --- a/src/components/QueueSelector/QueueSelector.js +++ b/src/components/QueueSelector/QueueSelector.js @@ -5,35 +5,73 @@ 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 { useCookies } from "react-cookie"; import { useToken } from "../AuthProvider/"; -export default function QueueSelector({ queueSelectorOpen, setQueueSelectorOpen, selectedQueues, setSelectedQueues }) { - const open = queueSelectorOpen; - const setOpen = setQueueSelectorOpen; +/** + * Get queue names and number of items. + * @param {String} access_token A valid API access token. + * @returns Array of objects containing queue names and item counts. + */ +const getQueueCounts = async (access_token) => { + 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(); + + return queueCountJson; +}; + +export default function QueueSelector({ open, setOpen, value, setValue }) { const [queueCounts, setQueueCounts] = useState([]); + const [isFirstRender, setIsFirstRender] = useState(true); const access_token = useToken(); const loading = open && queueCounts.length === 0; - // Get queue counts if QueueSelector is open + const [cookies, setCookie] = useCookies(["active-queues"]); + const activeQueues = cookies['active-queues'] !== undefined ? cookies['active-queues'].split(',') : []; + + const theme = useTheme(); + + // Prepopulate Active Queues from Cookies 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(); - setQueueCounts(queueCountJson); - }; + if (access_token === null){ + return undefined; + } - if (loading) { - getQueueCounts(); + if (isFirstRender) { + ( async _ => { + // Get queue counts + let queueCountsJson = await getQueueCounts(access_token); + + // Find queue count info for queue names in active queues + let activeQueuesInfo = activeQueues.map((queueName) => ( + queueCountsJson.find( ({ name }) => queueName === name ) + )); + + // Filter undefined values + activeQueuesInfo = activeQueuesInfo.filter( (entry) => entry !== undefined); + + setValue(activeQueuesInfo); + setIsFirstRender(false); + })(); } + }, []); + // Get queue counts if QueueSelector is open + useEffect( _ => { + (async _ => { + if (loading) { + let queueCountsJson = await getQueueCounts(access_token); + setQueueCounts(queueCountsJson); + } + })() }, [loading, access_token]); // Delete queue counts if QueueSelector is closed @@ -43,10 +81,20 @@ export default function QueueSelector({ queueSelectorOpen, setQueueSelectorOpen, } }, [open]); - const theme = useTheme(); - const handleChange = (event, newValue) => { - setSelectedQueues(newValue) + setValue(newValue) + + // Set active-queues cookie to csv of selected queue names + const activeQueueOptions = { + path: "/", + expires: (_ => { + let expiration_date = new Date(); + expiration_date.setDate(expiration_date.getDate() + 365); + return expiration_date; + })() + }; + const activeQueues = newValue.map( (value) => value.name).join(','); + setCookie("active-queues", activeQueues, activeQueueOptions); }; // Function to render checkboxes in dropdown @@ -71,7 +119,7 @@ export default function QueueSelector({ queueSelectorOpen, setQueueSelectorOpen, )} - options={queueCounts} - value={selectedQueues} + value={value} onChange={handleChange} getOptionLabel={(option) => `${option.name} (${option.number_of_items})`} renderOption={optionRenderer} @@ -119,11 +166,11 @@ export default function QueueSelector({ queueSelectorOpen, setQueueSelectorOpen, QueueSelector.propTypes = { /** State variable to manage open status. */ - "queueSelectorOpen": PropTypes.bool.isRequired, + "open": PropTypes.bool.isRequired, /** Function to update state variable that manages open status. */ - "setQueueSelectorOpen": PropTypes.func.isRequired, + "setOpen": PropTypes.func.isRequired, /** State variable to manage selected queues. */ - "selectedQueues": PropTypes.array.isRequired, + "value": PropTypes.array.isRequired, /** Function to update state variable that manages selected queues. */ - "setSelectedQueues": PropTypes.func.isRequired, + "setValue": PropTypes.func.isRequired, }; \ No newline at end of file From 1c8dedcd1ad422b0fbccd5f9d4fa907b8d4f156f Mon Sep 17 00:00:00 2001 From: Justin Campbell Date: Mon, 30 Nov 2020 20:56:59 -0500 Subject: [PATCH 4/4] Update QueueSelector props --- src/components/AppView/AppView.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/AppView/AppView.js b/src/components/AppView/AppView.js index 9ba85ef..75c7c60 100644 --- a/src/components/AppView/AppView.js +++ b/src/components/AppView/AppView.js @@ -98,10 +98,10 @@ export default function AppView({ setDarkMode }){