From f4556839c85bd5422209d5bf7270735ba5e633ce Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 29 Jan 2025 15:29:30 +0100 Subject: [PATCH] feat(1-3281): wraps the new datepicker in a dropdown (#9169) Wraps the datepicker in a popover, making it function largely the same as a dropdown list. The dropdown displays one of: - "current month" if you've selected the current month - " " (e.g. "December 2024") if you've selected a month that isn't the current month - "Last n months" (e.g. "Last 3 months") if you have selected a range Additionally, the range selections have been updated to span the whole row, aligning with the look of generic dropdown lists. ![image](https://github.com/user-attachments/assets/d356aec5-d51b-42fa-9591-60e2b5038a8e) Like with the rest of this file (`PeriodSelector`), the code is rough and not according to Unleash standards. However, I'm prioritizing fast changes so UX can have a look before I clean up the code to switch to using styled components etc later. It's still behind a flag, so I'm not very worried about it. --- .../NetworkTrafficUsage/PeriodSelector.tsx | 232 ++++++++++++------ 1 file changed, 153 insertions(+), 79 deletions(-) diff --git a/frontend/src/component/admin/network/NetworkTrafficUsage/PeriodSelector.tsx b/frontend/src/component/admin/network/NetworkTrafficUsage/PeriodSelector.tsx index 29455d2e2b..b56e421c8c 100644 --- a/frontend/src/component/admin/network/NetworkTrafficUsage/PeriodSelector.tsx +++ b/frontend/src/component/admin/network/NetworkTrafficUsage/PeriodSelector.tsx @@ -1,6 +1,12 @@ -import { styled } from '@mui/material'; +import { styled, Button, Popover, Box, type Theme } from '@mui/material'; +import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; +import ArrowDropUpIcon from '@mui/icons-material/ArrowDropUp'; import type { ChartDataSelection } from 'hooks/api/getters/useInstanceTrafficMetrics/useInstanceTrafficMetrics'; -import type { FC } from 'react'; +import { useRef, useState, type FC } from 'react'; +import { format } from 'date-fns'; + +const dropdownWidth = '15rem'; +const dropdownInlinePadding = (theme: Theme) => theme.spacing(3); export type Period = { key: string; @@ -60,9 +66,8 @@ const getSelectablePeriods = (): Period[] => { }; const Wrapper = styled('article')(({ theme }) => ({ - borderRadius: theme.shape.borderRadiusLarge, - border: `2px solid ${theme.palette.divider}`, - padding: theme.spacing(3), + width: dropdownWidth, + paddingBlock: theme.spacing(2), display: 'flex', flexFlow: 'column', gap: theme.spacing(2), @@ -84,13 +89,17 @@ const Wrapper = styled('article')(({ theme }) => ({ cursor: 'default', color: theme.palette.text.disabled, }, - 'button:hover': { + 'button:hover:not(:disabled)': { backgroundColor: theme.palette.action.hover, }, + 'button:focus': { + outline: `2px solid ${theme.palette.primary.main}`, + }, })); const MonthSelector = styled('article')(({ theme }) => ({ border: 'none', + paddingInline: dropdownInlinePadding(theme), hgroup: { h3: { margin: 0, @@ -116,9 +125,11 @@ const MonthGrid = styled('ul')(({ theme }) => ({ const RangeSelector = styled('article')(({ theme }) => ({ display: 'flex', + width: '100%', flexFlow: 'column', - gap: theme.spacing(0.5), + gap: theme.spacing(0), h4: { + paddingInline: dropdownInlinePadding(theme), fontSize: theme.typography.body2.fontSize, margin: 0, color: theme.palette.text.secondary, @@ -127,31 +138,34 @@ const RangeSelector = styled('article')(({ theme }) => ({ const RangeList = styled('ul')(({ theme }) => ({ listStyle: 'none', + margin: 0, padding: 0, - 'li + li': { - marginTop: theme.spacing(1), + width: '100%', + li: { + width: '100%', }, button: { - marginLeft: `-${theme.spacing(0.5)}`, + width: '100%', + paddingBlock: theme.spacing(1), + textAlign: 'left', + borderRadius: 0, + paddingInline: dropdownInlinePadding(theme), }, })); -type Selection = - | { - type: 'month'; - value: string; - } - | { - type: 'range'; - monthsBack: number; - }; - type Props = { selectedPeriod: ChartDataSelection; setPeriod: (period: ChartDataSelection) => void; }; +const StyledPopover = styled(Popover)(({ theme }) => ({ + '& .MuiPaper-root': { + borderRadius: theme.shape.borderRadiusLarge, + border: `1px solid ${theme.palette.divider}`, + }, +})); + export const PeriodSelector: FC = ({ selectedPeriod, setPeriod }) => { const selectablePeriods = getSelectablePeriods(); @@ -160,65 +174,125 @@ export const PeriodSelector: FC = ({ selectedPeriod, setPeriod }) => { label: `Last ${monthsBack} months`, })); - return ( - - -
-

Select month

-

Last 12 months

-
- - {selectablePeriods.map((period, index) => ( -
  • - -
  • - ))} -
    -
    - -

    Range

    + const [open, setOpen] = useState(false); + const ref = useRef(null); - - {rangeOptions.map((option) => ( -
  • - -
  • - ))} -
    -
    -
    + const selectPeriod = (period: ChartDataSelection) => { + setPeriod(period); + setOpen(false); + }; + + const buttonText = + selectedPeriod.grouping === 'daily' + ? selectedPeriod.month === format(new Date(), 'yyyy-MM') + ? 'Current month' + : new Date(selectedPeriod.month).toLocaleDateString('en-US', { + month: 'long', + year: 'numeric', + }) + : `Last ${selectedPeriod.monthsBack} months`; + + return ( + + + setOpen(false)} + anchorOrigin={{ + vertical: 'bottom', + horizontal: 'center', + }} + transformOrigin={{ + vertical: 'top', + horizontal: 'center', + }} + > + + +
    +

    Select month

    +

    Last 12 months

    +
    + + {selectablePeriods.map((period, index) => ( +
  • + +
  • + ))} +
    +
    + +

    Range

    + + + {rangeOptions.map((option) => ( +
  • + +
  • + ))} +
    +
    +
    {' '} +
    +
    ); };