github.com/grafviktor/keep-my-secret@v0.9.10-0.20230908165355-19f35cce90e5/website/src/components/App/index.jsx (about)

     1  import get from 'lodash/get'
     2  import {useMemo, useState, useEffect} from 'react'
     3  import Navigation from '../Navigation'
     4  import Error from '../Error'
     5  import Login from '../Login'
     6  import Register from '../Register'
     7  import Home from '../Home'
     8  import PaymentCard from '../Home/PaymentCard'
     9  import File from '../Home/File'
    10  import Note from '../Home/Note'
    11  import Password from '../Home/Password'
    12  import ApplicationContext from '../../context'
    13  import {isTokenExpired} from '../../utils'
    14  import createAPI from '../../api'
    15  
    16  import './style.css'
    17  
    18  const viewToComponentMap = {
    19    login    : Login,
    20    register : Register,
    21    home     : Home,
    22    card     : PaymentCard,
    23    file     : File,
    24    note     : Note,
    25    pass     : Password,
    26  }
    27  
    28  export default () => {
    29    const [alertMessage, setAlertMessage] = useState('')
    30    const [accessToken, setAccessToken] = useState('')
    31    const isLoggedIn = () => !isTokenExpired(accessToken)
    32    const [view, navigateTo] = useState('login')
    33    const [refreshTokenIngervalID, setRefreshTokenIntervalID] = useState(null)
    34    const [loggedIn, setLoggedIn] = useState(false)
    35    const [secret, setSecret] = useState(null)
    36    const [secrets, setSecrets] = useState({})
    37    const [appBusy, setAppBusy] = useState(false)
    38  
    39    const api = createAPI({setAppBusy, navigateTo})
    40  
    41    const getVersion = () => api.getVersion()
    42  
    43    // eslint-disable-next-line no-shadow
    44    const createSecret = async (secret) => api.createSecret(accessToken, secret)
    45  
    46    // eslint-disable-next-line no-shadow
    47    const updateSecret = (secret, id) => api.updateSecret(accessToken, id, secret)
    48  
    49    const deleteSecret = (id) => api.deleteSecret(accessToken, id)
    50  
    51    const getSecretFile = async (id) => {
    52      const response = await api.getSecretFile(accessToken, id)
    53      const url = window.URL.createObjectURL(new Blob([response.data]))
    54      const link = document.createElement('a')
    55      const contentDispositionHeader = get(response, 'headers.content-disposition', '')
    56      const match = contentDispositionHeader.match(/.*filename=([^"]+)/)
    57  
    58      if (match) {
    59        link.href = url
    60        link.setAttribute('download', match[1])
    61        document.body.appendChild(link)
    62        link.click()
    63      }
    64    }
    65  
    66    const fetchSecrets = () => api.fetchSecrets(accessToken)
    67  
    68    useEffect(() => {
    69      if (!loggedIn) {
    70        navigateTo('login')
    71      }
    72    }, [loggedIn])
    73  
    74    useEffect(() => {
    75      if (isTokenExpired(accessToken)) {
    76        setLoggedIn(false)
    77      } else {
    78        setLoggedIn(true)
    79      }
    80    }, [accessToken])
    81  
    82    useEffect(() => {
    83      if (!isTokenExpired(accessToken)) {
    84        setRefreshTokenIntervalID(setInterval(async () => {
    85          try {
    86            await api.refreshToken()
    87          } catch (error) {
    88            console.warn('Warning: unable to get refreshed token')
    89          }
    90        }, 1000 * 60))
    91      } else {
    92        clearInterval(refreshTokenIngervalID)
    93      }
    94    }, [accessToken])
    95  
    96    const contextValue = useMemo(() => ({
    97      // verbs
    98      setSecret,
    99      getVersion,
   100      isLoggedIn,
   101      navigateTo,
   102      setSecrets,
   103      createSecret,
   104      updateSecret,
   105      fetchSecrets,
   106      deleteSecret,
   107      getSecretFile,
   108      setAccessToken,
   109      setAlertMessage,
   110  
   111      // and nouns
   112      api,
   113      secret,
   114      secrets,
   115      loggedIn,
   116    }))
   117  
   118    const ActiveComponent = viewToComponentMap[view] || Login
   119  
   120    return (
   121      <div className="application">
   122        <ApplicationContext.Provider value={contextValue}>
   123          <Navigation loggedIn={loggedIn} />
   124          <Error message={alertMessage} view={view} />
   125          <ActiveComponent loggedIn={loggedIn} appBusy={appBusy} />
   126        </ApplicationContext.Provider>
   127      </div>
   128    )
   129  }