react-vite-demo

react and vite demo

git clone https://9o.is/git/react-vite-demo.git

EventsPage.tsx

(2339B)


      1 import { Checkbox, ComboBox, Select, Progress, Alert, Form, FormDataMap, Button } from '../../headless'
      2 import { useNumberFormatter } from '../../hooks'
      3 import { useSHEvents } from './useSHEvents'
      4 import { FilteredSHEventsInput, useFilteredSHEvents } from './useFilteredSHEvents'
      5 import { invariant, isSortType, SORT_TYPES } from '../../../lib'
      6 import { useMemo } from 'react'
      7   
      8 export function EventsPage() {
      9     const { events: loadedEvents, error, loading } = useSHEvents('node-a')
     10     const { events, filterSHEvents } = useFilteredSHEvents(loadedEvents)
     11     const priceFormatter = useNumberFormatter({ 
     12       style: 'currency', 
     13       currency: 'USD',
     14       maximumFractionDigits: 0 
     15     })
     16   
     17     const cities = useMemo(() => 
     18       [...new Set(loadedEvents.map(({ city }) => city))], [loadedEvents])
     19   
     20     return (
     21       <>
     22         <Alert error={error} />
     23         <Form aria-label='Filter Events' onSubmit={filterSHEvents} validator={validator}>
     24           <ComboBox label="City" name="city" options={cities} />
     25           <Select label="Sort by price" name="priceSort" options={SORT_TYPES} />
     26           <Checkbox label="Find Cheapest" name="cheapest" />
     27           <Button type="submit" disabled={loading}>Search</Button>
     28           <Form.Error>{(error) => error}</Form.Error>
     29         </Form>
     30         <Progress loading={loading}>
     31           <Progress.Bar>
     32             <Progress.Label>Loading events...</Progress.Label>
     33           </Progress.Bar>
     34           <Progress.Content>
     35             <ul>
     36               {events.map(({ id, city, price }) => (
     37                 <li key={id}>
     38                   <div>City: {city}</div>
     39                   <div>Price: {priceFormatter.format(price)}</div>
     40                 </li>
     41               ))}
     42             </ul>
     43           </Progress.Content>
     44         </Progress>
     45       </>
     46     )
     47 }
     48 
     49 
     50 function validator ({ city, priceSort, cheapest }: FormDataMap): FilteredSHEventsInput {
     51   invariant(
     52     typeof city === 'string' && city.length < 255, 
     53     "City is invalid"
     54   )
     55   
     56   invariant(
     57     cheapest === undefined || cheapest === 'on', 
     58     "Find cheapest input is invalid"
     59   )
     60   
     61   invariant(
     62     priceSort === '' || (typeof priceSort === 'string' && isSortType(priceSort)),
     63     "Sort by price is invalid"
     64   )
     65 
     66   return { 
     67     city, 
     68     priceSort: priceSort || undefined, 
     69     cheapest: cheapest === 'on', 
     70   }
     71 }