Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Date selector cleanup #1856

Merged
merged 10 commits into from
Jan 30, 2024
233 changes: 128 additions & 105 deletions app/routes/_gcn.circulars._archive._index/DateSelectorMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
import { useSearchParams, useSubmit } from '@remix-run/react'
import { useSubmit } from '@remix-run/react'
import {
Button,
ButtonGroup,
Expand All @@ -16,7 +16,8 @@ import {
Icon,
Radio,
} from '@trussworks/react-uswds'
import { useState } from 'react'
import classNames from 'classnames'
import { type ChangeEvent, useRef, useState } from 'react'

import DetailsDropdownContent from '~/components/DetailsDropdownContent'

Expand Down Expand Up @@ -68,133 +69,155 @@ function DateSelectorButton({
}

export function DateSelector({
startDate,
endDate,
form,
defaultStartDate,
defaultEndDate,
}: {
startDate?: string
endDate?: string
form?: string
defaultStartDate?: string
defaultEndDate?: string
}) {
const [searchParams] = useSearchParams()

const [inputDateGte, setInputDateGte] = useState(startDate)
const [inputDateLte, setInputDateLte] = useState(endDate)
const [showContent, setShowContent] = useState(false)
const [showDateRange, setShowDateRange] = useState(false)

const defaultShowDateRange = Boolean(
(defaultStartDate && !dateSelectorLabels[defaultStartDate]) ||
defaultEndDate
)
const [showDateRange, setShowDateRange] = useState(defaultShowDateRange)
const startDateInputRef = useRef<HTMLInputElement>(null)
const endDateInputRef = useRef<HTMLInputElement>(null)
const submit = useSubmit()

function setFuzzyTime(startDate?: string) {
setShowDateRange(false)
setInputDateGte(startDate)
setInputDateLte('')
function setStartDate(value: string) {
if (startDateInputRef.current) startDateInputRef.current.value = value
}

function setEndDate(value: string) {
if (endDateInputRef.current) endDateInputRef.current.value = value
}

function setDateRange() {
function radioOnChange({ target: { value } }: ChangeEvent<HTMLInputElement>) {
setShowDateRange(false)
lpsinger marked this conversation as resolved.
Show resolved Hide resolved
setStartDate(value)
setEndDate('')
setShowContent(false)
if (inputDateGte) searchParams.set('startDate', inputDateGte)
else searchParams.delete('startDate')
if (inputDateLte) searchParams.set('endDate', inputDateLte)
else searchParams.delete('endDate')
submit(searchParams, {
method: 'get',
action: '/circulars',
})
const form = startDateInputRef.current?.form
if (form) submit(form)
}

return (
<>
<input
type="hidden"
name="startDate"
form={form}
ref={startDateInputRef}
defaultValue={defaultStartDate}
/>
<input
type="hidden"
name="endDate"
form={form}
ref={endDateInputRef}
defaultValue={defaultEndDate}
/>
<DateSelectorButton
startDate={startDate}
endDate={endDate}
startDate={defaultStartDate}
endDate={defaultEndDate}
onClick={() => {
setShowContent((shown) => !shown)
setShowDateRange(false)
}}
expanded={showContent}
/>
{showContent && (
<DetailsDropdownContent className="maxw-card-xlg">
<CardBody>
<Grid row>
<Grid col={4} key="radio-alltime">
<Radio
id="radio-alltime"
name="radio-date"
value=""
label="All Time"
defaultChecked={true}
onChange={(e) => {
setInputDateGte(e.target.value)
}}
/>
</Grid>
{Object.entries(dateSelectorLabels).map(([value, label]) => (
<Grid col={4} key={`radio-${value}`}>
<Radio
id={`radio-${value}`}
name="radio-date"
value={value}
label={label}
checked={value === inputDateGte}
onChange={() => {
setFuzzyTime(value)
}}
/>
</Grid>
))}
<Grid col={4}>
<DetailsDropdownContent
className={classNames('maxw-card-xlg', {
'display-none': !showContent,
})}
>
<CardBody>
<Grid row>
<Grid col={4} key="radio-alltime">
<Radio
form=""
id="radio-alltime"
name="radio-date"
value=""
label="All Time"
defaultChecked={!defaultStartDate && !defaultEndDate}
onChange={radioOnChange}
/>
</Grid>
{Object.entries(dateSelectorLabels).map(([value, label]) => (
<Grid col={4} key={`radio-${value}`}>
<Radio
id="radio-custom"
form=""
id={`radio-${value}`}
name="radio-date"
value="custom"
label="Custom Range..."
checked={showDateRange}
onChange={(e) => {
setShowDateRange(e.target.checked)
}}
value={value}
label={label}
defaultChecked={value === defaultStartDate}
onChange={radioOnChange}
/>
</Grid>
</Grid>
{showDateRange && (
<DateRangePicker
startDateHint="dd/mm/yyyy"
startDateLabel="Start Date"
className="margin-bottom-2"
startDatePickerProps={{
id: 'event-date-start',
name: 'event-date-start',
defaultValue: 'startDate',
onChange: (value) => {
setInputDateGte(value)
},
}}
endDateHint="dd/mm/yyyy"
endDateLabel="End Date"
endDatePickerProps={{
id: 'event-date-end',
name: 'event-date-end',
defaultValue: 'endDate',
onChange: (value) => {
setInputDateLte(value)
},
))}
<Grid col={4}>
<Radio
form=""
id="radio-custom"
name="radio-date"
value="custom"
label="Custom Range..."
defaultChecked={defaultShowDateRange}
onChange={({ target: { checked } }) => {
setShowDateRange(checked)
}}
/>
)}

<CardFooter>
<Button
type="button"
form="searchForm"
onClick={() => {
setDateRange()
}}
>
<Icon.CalendarToday /> Submit
</Button>
</CardFooter>
</CardBody>
</DetailsDropdownContent>
)}
</Grid>
</Grid>
{showDateRange && (
<DateRangePicker
startDateHint="YYYY-MM-DD"
startDateLabel="Start Date"
className="margin-bottom-2"
startDatePickerProps={{
form: '',
id: 'event-date-start',
name: 'event-date-start',
dateFormat: 'YYYY-MM-DD',
defaultValue: defaultStartDate,
onChange: (value) => {
setStartDate(value ?? '')
},
}}
endDateHint="YYYY-MM-DD"
endDateLabel="End Date"
endDatePickerProps={{
form: '',
id: 'event-date-end',
name: 'event-date-end',
dateFormat: 'YYYY-MM-DD',
defaultValue: defaultEndDate,
onChange: (value) => {
setEndDate(value ?? '')
},
}}
/>
)}
</CardBody>
{showDateRange && (
<CardFooter>
<Button
type="button"
onClick={() => {
setShowContent(false)
const form = startDateInputRef.current?.form
if (form) submit(form)
}}
>
Submit
</Button>
</CardFooter>
)}
</DetailsDropdownContent>
</>
)
}
15 changes: 8 additions & 7 deletions app/routes/_gcn.circulars._archive._index/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
TextInput,
} from '@trussworks/react-uswds'
import clamp from 'lodash/clamp'
import { useState } from 'react'
import { useId, useState } from 'react'

import { getUser } from '../_gcn._auth/user.server'
import {
Expand All @@ -39,7 +39,6 @@ import CircularsIndex from './CircularsIndex'
import { DateSelector } from './DateSelectorMenu'
import Hint from '~/components/Hint'
import { getFormDataString } from '~/lib/utils'
import { useFeature } from '~/root'

import searchImg from 'nasawds/src/img/usa-icons-bg/search--white.svg'

Expand Down Expand Up @@ -92,7 +91,6 @@ export async function action({ request }: ActionFunctionArgs) {
export default function () {
const newItem = useActionData<typeof action>()
const { items, page, totalPages, totalItems } = useLoaderData<typeof loader>()
const featureCircularsFilterByDate = useFeature('CIRCULARS_FILTER_BY_DATE')

// Concatenate items from the action and loader functions
const allItems = [...(newItem ? [newItem] : []), ...(items || [])]
Expand All @@ -114,6 +112,7 @@ export default function () {
const [inputQuery, setInputQuery] = useState(query)
const clean = inputQuery === query

const formId = useId()
const submit = useSubmit()

return (
Expand All @@ -123,7 +122,7 @@ export default function () {
<Form
className="display-inline-block usa-search usa-search--small"
role="search"
id="searchForm"
id={formId}
>
<Label srOnly={true} htmlFor="query">
Search
Expand All @@ -149,9 +148,11 @@ export default function () {
/>
</Button>
</Form>
{featureCircularsFilterByDate && (
<DateSelector startDate={startDate} endDate={endDate} />
)}
<DateSelector
form={formId}
defaultStartDate={startDate}
defaultEndDate={endDate}
/>
<Link to={`/circulars/new${searchString}`}>
<Button
type="button"
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"@remix-run/css-bundle": "^2.5.1",
"@remix-run/node": "^2.5.1",
"@remix-run/react": "^2.5.1",
"@trussworks/react-uswds": "^6.2.0",
"@trussworks/react-uswds": "github:lpsinger/react-uswds#dateFormat",
"aws-lambda-ses-forwarder": "github:lpsinger/aws-lambda-ses-forwarder#aws-sdk-v3",
"classnames": "^2.5.1",
"color-convert": "^2.0.1",
Expand Down