Advertisement
Nighteclipse

Untitled

Jul 2nd, 2021 (edited)
1,736
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import React, { useEffect, useState } from 'react';
  2. import './App.css';
  3.  
  4. const headers = [
  5.   { key: 'firstName', value: 'First Name' },
  6.   { key: 'lastName', value: 'Last Name' },
  7.   { key: 'street', value: 'Street Address' },
  8.   { key: 'city', value: 'City' },
  9.   { key: 'state', value: 'State' },
  10.   { key: 'country', value: 'Country' },
  11.   { key: 'postcode', value: 'Postal Code' },
  12.   { key: 'latitude', value: 'Latitude' },
  13.   { key: 'longitude', value: 'Longitude' }
  14. ]
  15.  
  16. function App() {
  17.   const [isLoading, setIsLoading] = useState(true)
  18.   const [errorLoading, setErrorLoading] = useState(false)
  19.   const [data, setData] = useState<any[]>([])
  20.   const [sortedData, setSortedData] = useState<any[]>([])
  21.   const [sorting, setSorting] = useState(0)
  22.   const [searchValue, setSearchValue] = useState('')
  23.  
  24.   useEffect(() => {
  25.     fetch('https://randomuser.me/api/?results=20')
  26.       .then((response) => response.json())
  27.       .then((data) => data.results)
  28.       .then((data: any[]) => {
  29.         const filtered: any[] = data.map((obj) => {
  30.           const { street, coordinates, timezone, ...rest } = obj.location
  31.           return ({
  32.             firstName: obj.name.first,
  33.             lastName: obj.name.last,
  34.             street: `${street.number} ${street.name}`,
  35.             latitude: coordinates.latitude,
  36.             longitude: coordinates.longitude,
  37.             ...rest
  38.           })
  39.         })
  40.         setData(filtered)
  41.         setSortedData(filtered)
  42.         setIsLoading(false)
  43.       })
  44.       .catch((err) => {
  45.         setIsLoading(false)
  46.         setErrorLoading(true)
  47.         console.error(err)
  48.       })
  49.   }, [])
  50.  
  51.   // Sets the sortedData anytime sorting or searchValue change
  52.   useEffect(() => {
  53.     const index = Math.abs(sorting) - 1        
  54.     let newData = [...data]
  55.     if (index >= 0) {
  56.       const key = headers[index].key
  57.       newData = newData.sort((a, b) => a[key] === b[key] ? 0 : a[key] > b[key] ? 1 : -1)
  58.       if (sorting < 0) newData.reverse()
  59.     }
  60.     setSortedData(newData.filter((value) => {
  61.       return Object.values(value).some((element) => `${element}`.toLowerCase().includes(searchValue.toLowerCase()))
  62.     }))
  63.     // eslint-disable-next-line
  64.   }, [sorting, searchValue])
  65.  
  66.   if (isLoading)
  67.     return <div className="App">Loading...</div>
  68.  
  69.   if (errorLoading)
  70.     return <div className="App">Error: Could not fetch data!</div>
  71.  
  72.   return (
  73.     <div className="App">
  74.       <input value={searchValue} onChange={(e) => {
  75.         setSearchValue(e.target.value)
  76.       }} />
  77.       <table>
  78.         <thead>
  79.           <tr>
  80.             {headers.map((header, headerIdx) => (
  81.               <th
  82.                 style={{ userSelect: 'none', cursor: 'pointer' }}
  83.                 key={headerIdx}
  84.                 onClick={() => {
  85.                   setSorting(sorting < 0 ? 0 : (sorting >= 0 && ++headerIdx !== sorting) ? headerIdx : -headerIdx)
  86.                 }}
  87.               >{header.value}</th>
  88.             ))}
  89.           </tr>
  90.         </thead>
  91.         <tbody>
  92.           {sortedData.map((data, dataIdx) => (
  93.             <tr key={dataIdx}>
  94.               {headers.map((header, headerIdx) => <td key={headerIdx}>{data[header.key]}</td>)}
  95.             </tr>
  96.           ))}
  97.         </tbody>
  98.       </table>
  99.     </div>
  100.   );
  101. }
  102.  
  103. export default App;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement