frontend: minimal Login
from https://github.com/johannesloetzsch/swlkup/blob/master/frontend/components/Login.tsx
This commit is contained in:
parent
5abc0e7a8b
commit
220dacb949
|
@ -0,0 +1,77 @@
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useLoginQuery } from '../codegen/generates'
|
||||||
|
import create from 'zustand'
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
function jwtDecode(jwt: string) {
|
||||||
|
/* Just parses the payload — Be aware that signature is not checked */
|
||||||
|
return jwt && JSON.parse(atob(jwt.split('.')[1]))
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AuthState {
|
||||||
|
mail: string,
|
||||||
|
password: string,
|
||||||
|
setLogin: (mail: string, password: string) => void
|
||||||
|
jwt: string,
|
||||||
|
setJwt: (jwt: string) => void,
|
||||||
|
logout: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useAuthStore = create<AuthState>(set => ({
|
||||||
|
mail: '',
|
||||||
|
password: '',
|
||||||
|
setLogin: (mail, password) => set( _orig => ({mail, password})),
|
||||||
|
jwt: '',
|
||||||
|
setJwt: jwt => set( _orig => ({jwt}) ),
|
||||||
|
logout: () => { localStorage.removeItem('jwt')
|
||||||
|
set({mail: '', password: '', jwt: ''}) }
|
||||||
|
}))
|
||||||
|
|
||||||
|
export function jwtFromLocalStorage() {
|
||||||
|
return localStorage.getItem('jwt') || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Login() {
|
||||||
|
const {t} = useTranslation()
|
||||||
|
const auth = useAuthStore()
|
||||||
|
|
||||||
|
const { data } = useLoginQuery({auth}, {enabled: Boolean(!auth.jwt && auth.mail && auth.password)})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(auth.jwt) {
|
||||||
|
localStorage.setItem('jwt', auth.jwt)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auth.setJwt(data?.login.jwt || jwtFromLocalStorage())
|
||||||
|
}
|
||||||
|
|
||||||
|
if(jwtDecode(auth.jwt).exp < Date.now()/1000) {
|
||||||
|
console.log('session expired')
|
||||||
|
auth.logout()
|
||||||
|
}
|
||||||
|
}, [auth.jwt, data])
|
||||||
|
|
||||||
|
if(!auth.jwt) {
|
||||||
|
return (
|
||||||
|
<form onSubmit={ (event) => {event.preventDefault()
|
||||||
|
auth.setLogin((document.getElementById('mail') as HTMLInputElement).value,
|
||||||
|
(document.getElementById('password') as HTMLInputElement).value) }}>
|
||||||
|
<label>{ t('Email') }:
|
||||||
|
<input id='mail' name='mail'/>
|
||||||
|
</label>
|
||||||
|
<label>{ t('Password') }:
|
||||||
|
<input id='password' type='password' name='password'/>
|
||||||
|
</label>
|
||||||
|
<input type='submit' value={ t('Login') as string }/>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<form onSubmit={ async (event) => {event.preventDefault()
|
||||||
|
auth.logout()}}
|
||||||
|
style={{width: "100%", textAlign: "right"}}>
|
||||||
|
<input type='submit' value={ t('Logout') as string }/>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +1,22 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Auth, useGetOffersQuery } from "../../codegen/generates"
|
import { useGetOffersQuery } from "../../codegen/generates"
|
||||||
import testAuth from '../util/testAuth.json'
|
|
||||||
import HostOfferLookupTable from "./HostOfferLookupTable"
|
import HostOfferLookupTable from "./HostOfferLookupTable"
|
||||||
import { Box } from "@mui/material"
|
import { Box } from "@mui/material"
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { Login, useAuthStore } from '../Login'
|
||||||
|
|
||||||
type HostLookupWrapperProps = Record<string, never>
|
type HostLookupWrapperProps = Record<string, never>
|
||||||
|
|
||||||
const HostOfferLookupWrapper = ({}: HostLookupWrapperProps) => {
|
const HostOfferLookupWrapper = ({}: HostLookupWrapperProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const auth = useAuthStore()
|
||||||
|
|
||||||
const staleTimeMinutes = 60 // hotfix till table settings by user (columns width, filters, sort options, …) are persisted
|
const staleTimeMinutes = 60 // hotfix till table settings by user (columns width, filters, sort options, …) are persisted
|
||||||
const {data, isFetching, error} = useGetOffersQuery({auth: testAuth as Auth}, {staleTime: staleTimeMinutes * 60 * 1000})
|
const {data, isFetching, error} = useGetOffersQuery({auth}, {staleTime: staleTimeMinutes * 60 * 1000})
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
|
{ !data?.get_offers && <Login/> /** TODO: Show logout, by placing <Login/> in Header at Layout **/ }
|
||||||
|
|
||||||
{ isFetching && <p>{ t('loading…') }</p> }
|
{ isFetching && <p>{ t('loading…') }</p> }
|
||||||
{ error && <p>{ t('An error occurred while trying to get data from the backend.') }</p> }
|
{ error && <p>{ t('An error occurred while trying to get data from the backend.') }</p> }
|
||||||
{ data && !data.get_offers && <p>{ t('Seems like you have no permissions. Please try to login again.') }</p> }
|
{ data && !data.get_offers && <p>{ t('Seems like you have no permissions. Please try to login again.') }</p> }
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"mail": "crewing@example-ngo.com",
|
|
||||||
"password": "Vr(+cFtUG=rsj2:/]*uR"
|
|
||||||
}
|
|
|
@ -32,7 +32,8 @@
|
||||||
"react-collapse-pane": "^2.0.1",
|
"react-collapse-pane": "^2.0.1",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
"react-i18next": "^11.15.5",
|
"react-i18next": "^11.15.5",
|
||||||
"react-query": "^3.34.16"
|
"react-query": "^3.34.16",
|
||||||
|
"zustand": "^3.7.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@graphql-codegen/cli": "^2.3.0",
|
"@graphql-codegen/cli": "^2.3.0",
|
||||||
|
|
|
@ -5617,3 +5617,8 @@ yocto-queue@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||||
|
|
||||||
|
zustand@^3.7.1:
|
||||||
|
version "3.7.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.7.1.tgz#7388f0a7175a6c2fd9a2880b383a4bf6cdf6b7c6"
|
||||||
|
integrity sha512-wHBCZlKj+bg03/hP+Tzv24YhnqqP8MCeN9ECPDXoF01062SIbnfl3j9O0znkDw1lNTY0a8WN3F///a0UhhaEqg==
|
||||||
|
|
Loading…
Reference in New Issue