sigit.io/src/layouts/Main.tsx
enes c3a39157ff
All checks were successful
Release to Staging / build_and_release (push) Successful in 1m14s
fix(verify-page): remove mark border in production, enable dev flag for css classes
Hotfix
2024-08-20 15:47:51 +02:00

167 lines
4.8 KiB
TypeScript

import { Event, kinds } from 'nostr-tools'
import { useEffect, useRef, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Outlet } from 'react-router-dom'
import { AppBar } from '../components/AppBar/AppBar'
import { LoadingSpinner } from '../components/LoadingSpinner'
import { MetadataController, NostrController } from '../controllers'
import {
restoreState,
setAuthState,
setMetadataEvent,
updateUserAppData
} from '../store/actions'
import { LoginMethods } from '../store/auth/types'
import { State } from '../store/rootReducer'
import { Dispatch } from '../store/store'
import { setUserRobotImage } from '../store/userRobotImage/action'
import {
clearAuthToken,
clearState,
getRoboHashPicture,
getUsersAppData,
loadState,
saveNsecBunkerDelegatedKey,
subscribeForSigits
} from '../utils'
import { useAppSelector } from '../hooks'
import styles from './style.module.scss'
import { Footer } from '../components/Footer/Footer'
export const MainLayout = () => {
const dispatch: Dispatch = useDispatch()
const [isLoading, setIsLoading] = useState(true)
const [loadingSpinnerDesc, setLoadingSpinnerDesc] = useState(`Loading App`)
const authState = useSelector((state: State) => state.auth)
const usersAppData = useAppSelector((state) => state.userAppData)
// Ref to track if `subscribeForSigits` has been called
const hasSubscribed = useRef(false)
useEffect(() => {
const metadataController = new MetadataController()
const logout = () => {
dispatch(
setAuthState({
keyPair: undefined,
loggedIn: false,
usersPubkey: undefined,
loginMethod: undefined,
nsecBunkerPubkey: undefined
})
)
dispatch(setMetadataEvent(metadataController.getEmptyMetadataEvent()))
// clear authToken saved in local storage
clearAuthToken()
clearState()
// update nsecBunker delegated key
const newDelegatedKey =
NostrController.getInstance().generateDelegatedKey()
saveNsecBunkerDelegatedKey(newDelegatedKey)
}
const restoredState = loadState()
if (restoredState) {
dispatch(restoreState(restoredState))
const { loggedIn, loginMethod, usersPubkey, nsecBunkerRelays } =
restoredState.auth
if (loggedIn) {
if (!loginMethod || !usersPubkey) return logout()
if (loginMethod === LoginMethods.nsecBunker) {
if (!nsecBunkerRelays) return logout()
const nostrController = NostrController.getInstance()
nostrController.nsecBunkerInit(nsecBunkerRelays).then(() => {
nostrController.createNsecBunkerSigner(usersPubkey)
})
}
const handleMetadataEvent = (event: Event) => {
dispatch(setMetadataEvent(event))
}
metadataController.on(usersPubkey, (kind: number, event: Event) => {
if (kind === kinds.Metadata) {
handleMetadataEvent(event)
}
})
metadataController.findMetadata(usersPubkey).then((metadataEvent) => {
if (metadataEvent) handleMetadataEvent(metadataEvent)
})
} else {
setIsLoading(false)
}
} else {
setIsLoading(false)
}
}, [dispatch])
useEffect(() => {
if (authState.loggedIn && usersAppData) {
const pubkey = authState.usersPubkey || authState.keyPair?.public
if (pubkey && !hasSubscribed.current) {
// Call `subscribeForSigits` only if it hasn't been called before
subscribeForSigits(pubkey)
// Mark `subscribeForSigits` as called
hasSubscribed.current = true
}
}
}, [authState, usersAppData])
/**
* When authState change user logged in / or app reloaded
* we set robohash avatar in the global state based on user npub
* so that avatar will be consistent across the app when kind 0 is empty
*/
useEffect(() => {
if (authState && authState.loggedIn) {
const pubkey = authState.usersPubkey || authState.keyPair?.public
if (pubkey) {
dispatch(setUserRobotImage(getRoboHashPicture(pubkey)))
}
setIsLoading(true)
setLoadingSpinnerDesc(`Loading SIGit history...`)
getUsersAppData()
.then((appData) => {
if (appData) {
dispatch(updateUserAppData(appData))
}
})
.finally(() => setIsLoading(false))
}
}, [authState, dispatch])
if (isLoading) return <LoadingSpinner desc={loadingSpinnerDesc} />
const isDev = import.meta.env.MODE === 'development'
return (
<>
<AppBar />
<main
className={styles.main}
// Add dev debug flag to show special dev css
// (visible marks border on verify)
{...(isDev && {
'data-dev': true
})}
>
<Outlet />
</main>
<Footer />
</>
)
}