Skip to content

Commit

Permalink
adds synonyms moderation front end
Browse files Browse the repository at this point in the history
  • Loading branch information
Courey committed Aug 14, 2024
1 parent d38fcda commit ad5f69a
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 89 deletions.
54 changes: 54 additions & 0 deletions app/routes/circulars._archive._index/PaginationSelectionFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useSubmit } from '@remix-run/react'
import { Select } from '@trussworks/react-uswds'

import CircularPagination from './CircularPagination'

export default function ({
page,
totalPages,
limit,
query,
formId,
}: {
page: number
totalPages: number
limit?: number
query?: string
formId: string
}) {
const submit = useSubmit()
return (
<div className="display-flex flex-row flex-wrap">
<div className="display-flex flex-align-self-center margin-right-2 width-auto">
<div>
<Select
id="limit"
title="Number of results per page"
className="width-auto height-5 padding-y-0 margin-y-0"
name="limit"
defaultValue="100"
form={formId}
onChange={({ target: { form } }) => {
submit(form)
}}
>
<option value="10">10 / page</option>
<option value="20">20 / page</option>
<option value="50">50 / page</option>
<option value="100">100 / page</option>
</Select>
</div>
</div>
<div className="display-flex flex-fill">
{totalPages > 1 && (
<CircularPagination
query={query}
page={page}
limit={limit}
totalPages={totalPages}
/>
)}
</div>
</div>
)
}
52 changes: 9 additions & 43 deletions app/routes/circulars._archive._index/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,7 @@ import {
useSearchParams,
useSubmit,
} from '@remix-run/react'
import {
Alert,
Button,
Icon,
Label,
Select,
TextInput,
} from '@trussworks/react-uswds'
import { Alert, Button, Icon, Label, TextInput } from '@trussworks/react-uswds'
import clamp from 'lodash/clamp'
import { useId, useState } from 'react'

Expand All @@ -40,10 +33,10 @@ import {
putVersion,
search,
} from '../circulars/circulars.server'
import CircularPagination from './CircularPagination'
import CircularsHeader from './CircularsHeader'
import CircularsIndex from './CircularsIndex'
import { DateSelector } from './DateSelectorMenu'
import PaginationSelectionFooter from './PaginationSelectionFooter'
import { SortSelector } from './SortSelectorButton'
import Hint from '~/components/Hint'
import { ToolbarButtonGroup } from '~/components/ToolbarButtonGroup'
Expand Down Expand Up @@ -263,40 +256,13 @@ export default function () {
totalItems={totalItems}
query={query}
/>
<div className="display-flex flex-row flex-wrap">
<div className="display-flex flex-align-self-center margin-right-2 width-auto">
<div>
<Select
id="limit"
title="Number of results per page"
className="width-auto height-5 padding-y-0 margin-y-0"
name="limit"
defaultValue="100"
form={formId}
onChange={({ target: { form } }) => {
submit(form)
}}
>
<option value="10">10 / page</option>
<option value="20">20 / page</option>
<option value="50">50 / page</option>
<option value="100">100 / page</option>
</Select>
</div>
</div>
<div className="display-flex flex-fill">
{totalPages > 1 && (
<CircularPagination
query={query}
page={page}
limit={parseInt(limit)}
totalPages={totalPages}
startDate={startDate}
endDate={endDate}
/>
)}
</div>
</div>
<PaginationSelectionFooter
query={query}
page={page}
limit={parseInt(limit)}
totalPages={totalPages}
formId={formId}
/>
</>
)}
</>
Expand Down
74 changes: 41 additions & 33 deletions app/routes/synonyms.$synonymId.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
getSynonymsByUuid,
putSynonyms,
} from './synonyms/synonyms.server'
import { ToolbarButtonGroup } from '~/components/ToolbarButtonGroup'
import { getFormDataString } from '~/lib/utils'

export async function loader({ params: { synonymId } }: LoaderFunctionArgs) {
Expand Down Expand Up @@ -52,7 +53,7 @@ export async function action({
return null
} else if (intent === 'delete') {
await deleteSynonyms(synonymId)
return redirect('/synonyms')
return redirect('/synonyms/moderation')
} else {
throw new Response('Unknown intent.', {
status: 400,
Expand All @@ -69,47 +70,54 @@ export default function () {

return (
<>
<ButtonGroup>
<h1>Synonym Group</h1>
<ButtonGroup className="margin-bottom-2">
<Link to="/synonyms" className="usa-button">
<div className="display-inline">
<Icon.ArrowBack
role="presentation"
className="position-relative"
/>
</div>
</Link>
<Form method="POST">
<input type="hidden" name="intent" value="delete" />
<Button type="submit">
<Icon.Delete
role="presentation"
className="bottom-aligned margin-right-05"
/>
</Button>
</Form>
</ButtonGroup>
</ButtonGroup>
<ToolbarButtonGroup className="flex-wrap">
<Link
to="/synonyms/moderation"
className="usa-button flex-align-stretch"
>
<div className="position-relative">
<Icon.ArrowBack
role="presentation"
className="position-absolute top-0 left-0"
/>
</div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Back
</Link>
<Form method="POST">
<input type="hidden" name="intent" value="delete" />
<Button type="submit" outline>
<Icon.Delete
role="presentation"
className="bottom-aligned margin-right-05"
/>{' '}
Delete
</Button>
</Form>
</ToolbarButtonGroup>
<h1>Synonym Group</h1>
<p>
Synonym groupings are limited to 25 synonymous event identifiers. If you
are adding an event identifier that is already part of a group, it will
be removed from the previous association and added to this group.
If you are adding an event identifier that is already part of a group,
it will be removed from the previous association and added to this
group.
</p>
<Form>
<FormGroup>
<ButtonGroup>
<ToolbarButtonGroup className="bg-white z-300">
<Form>
<ToolbarButtonGroup className="height-auto">
<input
placeholder="event id"
className="margin-right-1 height-full"
value={newSynonym}
key="synonym"
id="synonymInput"
name="synonym"
type="text"
onChange={(e) => {
setNewSynonym(e.currentTarget.value)
}}
/>
<Button
type="button"
onClick={(e) => {
onClick={() => {
if (!newSynonym) return
setDeleteSynonyms(
deleteSynonyms.filter(function (item) {
Expand All @@ -133,9 +141,9 @@ export default function () {
>
<Icon.Add role="presentation" /> Add
</Button>
</ButtonGroup>
</FormGroup>
</Form>
</ToolbarButtonGroup>
</Form>
</ToolbarButtonGroup>
<Form
method="POST"
onSubmit={() => {
Expand Down
121 changes: 121 additions & 0 deletions app/routes/synonyms._moderation._index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import type { LoaderFunctionArgs } from '@remix-run/node'
import {
Form,
Link,
useLoaderData,
useSearchParams,
useSubmit,
} from '@remix-run/react'
import {
Button,
Grid,
GridContainer,
Icon,
Label,
TextInput,
} from '@trussworks/react-uswds'
import { useId, useState } from 'react'

import PaginationSelectionFooter from './circulars._archive._index/PaginationSelectionFooter'
import type { SynonymGroup } from './synonyms/synonyms.lib'
import { searchSynonymsByEventId } from './synonyms/synonyms.server'
import { ToolbarButtonGroup } from '~/components/ToolbarButtonGroup'

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

export async function loader({ request: { url } }: LoaderFunctionArgs) {
const { searchParams } = new URL(url)
const query = searchParams.get('query') || undefined
const limit = parseInt(searchParams.get('limit') || '100')
const page = parseInt(searchParams.get('page') || '1')
const synonyms = searchSynonymsByEventId({ page, eventId: query, limit })
return synonyms
}

function SynonymList({ synonyms }: { synonyms: SynonymGroup[] }) {
return (
<>
<ul>
{synonyms.map((synonym) => {
return (
<li key={synonym.synonymId}>
<Link to={`/synonyms/${synonym.synonymId}`}>
{' '}
{synonym.eventIds.join(', ')}
</Link>
</li>
)
})}
</ul>
</>
)
}
export default function () {
const { synonyms, page, totalPages } = useLoaderData<typeof loader>()
const submit = useSubmit()
const formId = useId()
const [searchParams] = useSearchParams()
const limit = searchParams.get('limit') || '100'
const query = searchParams.get('query') || ''

let searchString = searchParams.toString()
if (searchString) searchString = `?${searchString}`

const [inputQuery, setInputQuery] = useState('')

return (
<>
<h1>Synonym Group Moderation</h1>
<GridContainer>
<Grid row>
<ToolbarButtonGroup className="position-sticky top-0 bg-white margin-bottom-1 padding-top-1 z-300">
<Form
preventScrollReset
className="display-inline-block usa-search usa-search--small"
role="search"
id={formId}
>
<Label srOnly htmlFor="query">
Search
</Label>
<TextInput
autoFocus
className="minw-15"
id="query"
name="query"
type="search"
defaultValue={inputQuery}
placeholder="Search"
aria-describedby="searchHint"
onChange={({ target: { form, value } }) => {
setInputQuery(value)
if (!value) submit(form, { preventScrollReset: true })
}}
/>
<Button type="submit">
<img
src={searchImg}
className="usa-search__submit-icon"
alt="Search"
/>
</Button>
</Form>
<Link to="/synonyms/new">
<Button type="button" className="padding-y-1">
<Icon.Edit role="presentation" /> New
</Button>
</Link>
</ToolbarButtonGroup>
</Grid>
</GridContainer>
<SynonymList synonyms={synonyms} />
<PaginationSelectionFooter
query={query}
page={page}
totalPages={totalPages}
limit={parseInt(limit)}
formId={formId}
/>
</>
)
}
Loading

0 comments on commit ad5f69a

Please sign in to comment.