Compare commits

...

14 Commits

Author SHA1 Message Date
84c374bb2c chore(git): merge pull request #198 from 196-ext-login-infinite-loading into staging
All checks were successful
Release to Staging / build_and_release (push) Successful in 1m18s
Reviewed-on: #198
Reviewed-by: eugene <eugene@nostrdev.com>
2024-09-16 12:27:43 +00:00
a53914b59d Merge branch 'staging' into 196-ext-login-infinite-loading
All checks were successful
Open PR on Staging / audit_and_check (pull_request) Successful in 35s
2024-09-16 12:19:09 +00:00
b
5a2a0ad9c4 Merge branch 'staging' into 196-ext-login-infinite-loading
All checks were successful
Open PR on Staging / audit_and_check (pull_request) Successful in 33s
2024-09-16 11:45:22 +00:00
8b4f1a8973 fix(online-detection): use relative url
All checks were successful
Open PR on Staging / audit_and_check (pull_request) Successful in 35s
2024-09-16 11:00:16 +02:00
79ef9eb8d6 fix: url
All checks were successful
Open PR on Staging / audit_and_check (pull_request) Successful in 34s
2024-09-13 17:47:55 +02:00
ba24e7417d refactor: log timeout error only, no toast
All checks were successful
Open PR on Staging / audit_and_check (pull_request) Successful in 34s
2024-09-13 11:14:10 +02:00
ea7e3a0964 refactor: update url for online status 2024-09-13 11:06:06 +02:00
2e58b58a6a refactor: move publish button to the bottom
All checks were successful
Open PR on Staging / audit_and_check (pull_request) Successful in 33s
2024-09-12 13:30:59 +02:00
17c1700554 fix(login): use const and make sure to clear timeout always
All checks were successful
Open PR on Staging / audit_and_check (pull_request) Successful in 34s
2024-09-12 13:24:05 +02:00
9191336722 refactor(login): update the delay message and increase timers 2024-09-12 12:17:58 +02:00
7c80643aba fix(login): extension login infinite loading
All checks were successful
Open PR on Staging / audit_and_check (pull_request) Successful in 34s
Fixes #196
2024-09-11 16:44:45 +02:00
9c545a477c fix(errors): add custom timeout error 2024-09-11 16:33:53 +02:00
4d1e672268 feat(loading-spinner): add children support for default variant 2024-09-11 16:33:13 +02:00
4bc5882ab6 fix(loading): make sure the default spinner is absolute relative to root always 2024-09-11 13:27:50 +02:00
6 changed files with 98 additions and 31 deletions

View File

@ -1,12 +1,14 @@
import { createPortal } from 'react-dom'
import styles from './style.module.scss'
import { PropsWithChildren } from 'react'
interface Props {
desc?: string
variant?: 'small' | 'default'
}
export const LoadingSpinner = (props: Props) => {
const { desc, variant = 'default' } = props
export const LoadingSpinner = (props: PropsWithChildren<Props>) => {
const { desc, children, variant = 'default' } = props
switch (variant) {
case 'small':
@ -20,16 +22,22 @@ export const LoadingSpinner = (props: Props) => {
)
default:
return (
return createPortal(
<div className={styles.loadingSpinnerOverlay}>
<div
className={styles.loadingSpinnerContainer}
data-variant={variant}
>
<div className={styles.loadingSpinner}></div>
{desc && <p className={styles.loadingSpinnerDesc}>{desc}</p>}
{desc && (
<div className={styles.loadingSpinnerDesc}>
{desc}
{children}
</div>
)}
</div>
</div>
</div>,
document.getElementById('root')!
)
}
}

View File

@ -42,11 +42,15 @@
width: 100%;
padding: 15px;
border-top: solid 1px rgba(0, 0, 0, 0.1);
text-align: center;
color: rgba(0, 0, 0, 0.5);
font-size: 16px;
font-weight: 400;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
}
@keyframes spin {

View File

@ -957,9 +957,6 @@ export const CreatePage = () => {
<FontAwesomeIcon icon={faPlus} />
</Button>
</div>
<Button onClick={handleCreate} variant="contained">
Publish
</Button>
<div className={`${styles.paperGroup} ${styles.toolbox}`}>
{toolbox.map((drawTool: DrawTool, index: number) => {
@ -986,6 +983,10 @@ export const CreatePage = () => {
})}
</div>
<Button onClick={handleCreate} variant="contained">
Publish
</Button>
{!!error && (
<FormHelperText error={!!error}>{error}</FormHelperText>
)}

View File

@ -18,12 +18,16 @@ import {
} from '../../store/actions'
import { LoginMethods } from '../../store/auth/types'
import { Dispatch } from '../../store/store'
import { npubToHex, queryNip05 } from '../../utils'
import { npubToHex, queryNip05, timeout } from '../../utils'
import { hexToBytes } from '@noble/hashes/utils'
import { NIP05_REGEX } from '../../constants'
import styles from './styles.module.scss'
import { TimeoutError } from '../../types/errors/TimeoutError'
const EXTENSION_LOGIN_DELAY_SECONDS = 5
const EXTENSION_LOGIN_TIMEOUT_SECONDS = EXTENSION_LOGIN_DELAY_SECONDS + 55
export const Nostr = () => {
const [searchParams] = useSearchParams()
@ -36,6 +40,7 @@ export const Nostr = () => {
const [isLoading, setIsLoading] = useState(false)
const [loadingSpinnerDesc, setLoadingSpinnerDesc] = useState('')
const [isExtensionSlow, setIsExtensionSlow] = useState(false)
const [inputValue, setInputValue] = useState('')
const [authUrl, setAuthUrl] = useState<string>()
@ -72,27 +77,43 @@ export const Nostr = () => {
}
const loginWithExtension = async () => {
setIsLoading(true)
setLoadingSpinnerDesc('Capturing pubkey from nostr extension')
let waitTimeout: number | undefined
try {
// Wait EXTENSION_LOGIN_DELAY_SECONDS before showing extension delay message
waitTimeout = window.setTimeout(() => {
setIsExtensionSlow(true)
}, EXTENSION_LOGIN_DELAY_SECONDS * 1000)
nostrController
.capturePublicKey()
.then(async (pubkey) => {
dispatch(updateLoginMethod(LoginMethods.extension))
setIsLoading(true)
setLoadingSpinnerDesc('Capturing pubkey from nostr extension')
setLoadingSpinnerDesc('Authenticating and finding metadata')
const redirectPath =
await authController.authAndGetMetadataAndRelaysMap(pubkey)
const pubkey = await nostrController.capturePublicKey()
dispatch(updateLoginMethod(LoginMethods.extension))
if (redirectPath) navigateAfterLogin(redirectPath)
})
.catch((err) => {
toast.error('Error capturing public key from nostr extension: ' + err)
})
.finally(() => {
setIsLoading(false)
setLoadingSpinnerDesc('')
})
setLoadingSpinnerDesc('Authenticating and finding metadata')
const redirectPath = await Promise.race([
authController.authAndGetMetadataAndRelaysMap(pubkey),
timeout(EXTENSION_LOGIN_TIMEOUT_SECONDS * 1000)
])
if (redirectPath) {
navigateAfterLogin(redirectPath)
}
} catch (error) {
if (error instanceof TimeoutError) {
// Just log the error, no toast, user has already been notified with the loading screen
console.error("Extension didn't respond in time")
} else {
toast.error('Error capturing public key from nostr extension: ' + error)
}
} finally {
// Clear the wait timeout so we don't change the state unnecessarily
window.clearTimeout(waitTimeout)
setIsLoading(false)
setLoadingSpinnerDesc('')
setIsExtensionSlow(false)
}
}
/**
@ -354,7 +375,33 @@ export const Nostr = () => {
return (
<>
{isLoading && <LoadingSpinner desc={loadingSpinnerDesc} />}
{isLoading && (
<LoadingSpinner desc={loadingSpinnerDesc}>
{isExtensionSlow && (
<>
<p>
Your nostr extension is not responding. Check these
alternatives:{' '}
<a href="https://github.com/aljazceru/awesome-nostr?tab=readme-ov-file#nip-07-browser-extensions">
https://github.com/aljazceru/awesome-nostr
</a>
</p>
<br />
<Button
fullWidth
variant="contained"
onClick={() => {
setLoadingSpinnerDesc('')
setIsLoading(false)
setIsExtensionSlow(false)
}}
>
Close
</Button>
</>
)}
</LoadingSpinner>
)}
{isNostrExtensionAvailable && (
<>

View File

@ -0,0 +1,6 @@
export class TimeoutError extends Error {
constructor() {
super('Timeout')
this.name = this.constructor.name
}
}

View File

@ -1,3 +1,4 @@
import { TimeoutError } from '../types/errors/TimeoutError.ts'
import { CurrentUserFile } from '../types/file.ts'
import { SigitFile } from './file.ts'
@ -34,7 +35,7 @@ export const isOnline = async () => {
try {
// Define a URL to check the online status
const url = 'https://www.google.com'
const url = document.location.pathname + '?v=' + new Date().getTime()
// Make a HEAD request to the URL with 'no-cors' mode
// This mode is used to handle opaque responses which do not expose their content
@ -63,7 +64,7 @@ export const timeout = (ms: number = 60000) => {
// Set a timeout using setTimeout
setTimeout(() => {
// Reject the promise with an Error indicating a timeout
reject(new Error('Timeout'))
reject(new TimeoutError())
}, ms) // Timeout duration in milliseconds
})
}