Compare commits
4 Commits
feature/sw
...
feature/re
Author | SHA1 | Date | |
---|---|---|---|
59c03d16eb | |||
adbc7d455d | |||
13f9bb13fd | |||
b1dd6a5424 |
@ -9,16 +9,17 @@ import { ModalInitial } from './components/Modal/ModalInitial/ModalInitial'
|
|||||||
import { ModalImportKeys } from './components/Modal/ModalImportKeys/ModalImportKeys'
|
import { ModalImportKeys } from './components/Modal/ModalImportKeys/ModalImportKeys'
|
||||||
import { ModalSignUp } from './components/Modal/ModalSignUp/ModalSignUp'
|
import { ModalSignUp } from './components/Modal/ModalSignUp/ModalSignUp'
|
||||||
import { ModalLogin } from './components/Modal/ModalLogin/ModalLogin'
|
import { ModalLogin } from './components/Modal/ModalLogin/ModalLogin'
|
||||||
|
import { useSearchParams } from 'react-router-dom'
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [render, setRender] = useState(0)
|
const [render, setRender] = useState(0)
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams()
|
||||||
|
|
||||||
const [isConnected, setIsConnected] = useState(false)
|
const [isConnected, setIsConnected] = useState(false)
|
||||||
|
|
||||||
const load = useCallback(async () => {
|
const load = useCallback(async () => {
|
||||||
const keys: DbKey[] = await dbi.listKeys()
|
const keys: DbKey[] = await dbi.listKeys()
|
||||||
// console.log(keys, 'keys')
|
|
||||||
|
|
||||||
dispatch(setKeys({ keys }))
|
dispatch(setKeys({ keys }))
|
||||||
const loadProfiles = async () => {
|
const loadProfiles = async () => {
|
||||||
@ -55,7 +56,6 @@ function App() {
|
|||||||
// rerender
|
// rerender
|
||||||
// setRender((r) => r + 1)
|
// setRender((r) => r + 1)
|
||||||
|
|
||||||
// if (!keys.length) handleOpen(MODAL_PARAMS_KEYS.INITIAL)
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [dispatch])
|
}, [dispatch])
|
||||||
|
|
||||||
@ -80,12 +80,14 @@ function App() {
|
|||||||
// subscribe to service worker updates
|
// subscribe to service worker updates
|
||||||
swicOnReload(() => {
|
swicOnReload(() => {
|
||||||
console.log('reload')
|
console.log('reload')
|
||||||
// FIXME show 'Please reload' badge at page top
|
searchParams.set('reload', 'true')
|
||||||
|
setSearchParams(searchParams)
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AppRoutes />
|
<AppRoutes />
|
||||||
|
|
||||||
<ModalInitial />
|
<ModalInitial />
|
||||||
<ModalImportKeys />
|
<ModalImportKeys />
|
||||||
<ModalSignUp />
|
<ModalSignUp />
|
||||||
|
@ -68,7 +68,6 @@ export const ModalAppDetails = () => {
|
|||||||
if (isEmptyString(url)) return
|
if (isEmptyString(url)) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const u = new URL(url)
|
const u = new URL(url)
|
||||||
|
|
||||||
if (isEmptyString(name)) setDetails((prev) => ({ ...prev, name: u.hostname }))
|
if (isEmptyString(name)) setDetails((prev) => ({ ...prev, name: u.hostname }))
|
||||||
|
@ -73,11 +73,11 @@ export const ModalConfirmConnect = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isModalOpened) {
|
if (isModalOpened) {
|
||||||
if (isPopup) {
|
if (isPopup) {
|
||||||
console.log("waiting for sw")
|
console.log('waiting for sw')
|
||||||
// wait for SW to start
|
// wait for SW to start
|
||||||
swicWaitStarted().then(() => {
|
swicWaitStarted().then(() => {
|
||||||
// give it some time to load the pending reqs etc
|
// give it some time to load the pending reqs etc
|
||||||
console.log("waiting for sw done")
|
console.log('waiting for sw done')
|
||||||
setTimeout(() => setIsLoaded(true), 500)
|
setTimeout(() => setIsLoaded(true), 500)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -123,7 +123,6 @@ export const ModalConfirmConnect = () => {
|
|||||||
const options = { perms, appUrl }
|
const options = { perms, appUrl }
|
||||||
await confirmPending(pendingReqId, true, true, options)
|
await confirmPending(pendingReqId, true, true, options)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await askNotificationPermission()
|
await askNotificationPermission()
|
||||||
const result = await swicCall('enablePush')
|
const result = await swicCall('enablePush')
|
||||||
|
@ -13,7 +13,7 @@ import { DOMAIN } from '@/utils/consts'
|
|||||||
import { fetchNip05 } from '@/utils/helpers/helpers'
|
import { fetchNip05 } from '@/utils/helpers/helpers'
|
||||||
import { Stack, Typography, useTheme } from '@mui/material'
|
import { Stack, Typography, useTheme } from '@mui/material'
|
||||||
import { ChangeEvent, Fragment, useCallback, useEffect, useState } from 'react'
|
import { ChangeEvent, Fragment, useCallback, useEffect, useState } from 'react'
|
||||||
import { useParams, useSearchParams } from 'react-router-dom'
|
import { useParams } from 'react-router-dom'
|
||||||
import { useDebounce } from 'use-debounce'
|
import { useDebounce } from 'use-debounce'
|
||||||
import { StyledSettingContainer } from './styled'
|
import { StyledSettingContainer } from './styled'
|
||||||
import { SectionTitle } from '@/shared/SectionTitle/SectionTitle'
|
import { SectionTitle } from '@/shared/SectionTitle/SectionTitle'
|
||||||
@ -55,7 +55,7 @@ export const ModalEditName = () => {
|
|||||||
setIsAvailable(true)
|
setIsAvailable(true)
|
||||||
setIsChecking(false)
|
setIsChecking(false)
|
||||||
}
|
}
|
||||||
}, [debouncedName])
|
}, [debouncedName, npub])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
checkIsUsernameAvailable()
|
checkIsUsernameAvailable()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Stack, StackProps, styled } from "@mui/material";
|
import { Stack, StackProps, styled } from '@mui/material'
|
||||||
|
|
||||||
export const StyledSettingContainer = styled((props: StackProps) => (
|
export const StyledSettingContainer = styled((props: StackProps) => (
|
||||||
<Stack gap={'0.75rem'} component={'form'} {...props} />
|
<Stack gap={'0.75rem'} component={'form'} {...props} />
|
||||||
@ -7,4 +7,4 @@ export const StyledSettingContainer = styled((props: StackProps) => (
|
|||||||
borderRadius: '1rem',
|
borderRadius: '1rem',
|
||||||
background: theme.palette.background.default,
|
background: theme.palette.background.default,
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
}))
|
}))
|
||||||
|
@ -60,10 +60,8 @@ export const ModalSignUp = () => {
|
|||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
const k: any = await swicCall('generateKey', name)
|
const k: any = await swicCall('generateKey', name)
|
||||||
if (k.name)
|
if (k.name) notify(`Account created for "${k.name}"`, 'success')
|
||||||
notify(`Account created for "${k.name}"`, 'success')
|
else notify(`Failed to assign name "${name}", try again`, 'error')
|
||||||
else
|
|
||||||
notify(`Failed to assign name "${name}", try again`, 'error')
|
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// give frontend time to read the new key first
|
// give frontend time to read the new key first
|
||||||
|
33
src/components/ReloadBadge/ReloadBadge.tsx
Normal file
33
src/components/ReloadBadge/ReloadBadge.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { FC } from 'react'
|
||||||
|
import { Collapse, Stack, Typography } from '@mui/material'
|
||||||
|
import { useSearchParams } from 'react-router-dom'
|
||||||
|
import { StyledAlert, StyledReloadButton } from './styled'
|
||||||
|
|
||||||
|
const ReloadBadgeContent: FC = () => {
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams()
|
||||||
|
|
||||||
|
const handleReload = () => {
|
||||||
|
searchParams.delete('reload')
|
||||||
|
setSearchParams(searchParams)
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Collapse in>
|
||||||
|
<StyledAlert>
|
||||||
|
<Stack direction={'row'} className="content">
|
||||||
|
<Typography flex={1} className="title">
|
||||||
|
New version available, please reload the page!
|
||||||
|
</Typography>
|
||||||
|
<StyledReloadButton onClick={handleReload}>Reload</StyledReloadButton>
|
||||||
|
</Stack>
|
||||||
|
</StyledAlert>
|
||||||
|
</Collapse>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ReloadBadge = () => {
|
||||||
|
const [searchParams] = useSearchParams()
|
||||||
|
const open = searchParams.get('reload') === 'true'
|
||||||
|
|
||||||
|
return <>{open && <ReloadBadgeContent />}</>
|
||||||
|
}
|
50
src/components/ReloadBadge/styled.tsx
Normal file
50
src/components/ReloadBadge/styled.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { AppButtonProps, Button } from '@/shared/Button/Button'
|
||||||
|
import { Alert, AlertProps, styled } from '@mui/material'
|
||||||
|
import RefreshIcon from '@mui/icons-material/Refresh'
|
||||||
|
|
||||||
|
export const StyledAlert = styled((props: AlertProps) => (
|
||||||
|
<Alert {...props} variant="outlined" severity="info" classes={{ message: 'message' }} />
|
||||||
|
))(() => {
|
||||||
|
return {
|
||||||
|
height: 'auto',
|
||||||
|
marginTop: '0.5rem',
|
||||||
|
alignItems: 'center',
|
||||||
|
'& .message': {
|
||||||
|
flex: 1,
|
||||||
|
overflow: 'initial',
|
||||||
|
},
|
||||||
|
'& .content': {
|
||||||
|
width: '100%',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '1rem',
|
||||||
|
},
|
||||||
|
'& .title': {
|
||||||
|
display: '-webkit-box',
|
||||||
|
WebkitLineClamp: 3,
|
||||||
|
WebkitBoxOrient: 'vertical',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
},
|
||||||
|
'@media screen and (max-width: 320px)': {
|
||||||
|
'& .title': {
|
||||||
|
fontSize: '14px',
|
||||||
|
WebkitLineClamp: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const StyledReloadButton = styled((props: AppButtonProps) => <Button startIcon={<RefreshIcon />} {...props} />)(
|
||||||
|
({ theme }) => {
|
||||||
|
const isDarkTheme = theme.palette.mode === 'dark'
|
||||||
|
return {
|
||||||
|
padding: '0.25rem 1rem',
|
||||||
|
'&.button:is(:hover, :active, &)': {
|
||||||
|
background: isDarkTheme ? '#b8e7fb' : '#014361',
|
||||||
|
},
|
||||||
|
'@media screen and (max-width: 320px)': {
|
||||||
|
padding: '0.25rem 0.5rem',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
@ -13,14 +13,8 @@ export const Warning: FC<WarningProps> = ({ hint, message, icon, ...restProps })
|
|||||||
<StyledContainer {...restProps}>
|
<StyledContainer {...restProps}>
|
||||||
{icon && <IconContainer>{icon}</IconContainer>}
|
{icon && <IconContainer>{icon}</IconContainer>}
|
||||||
<Stack flex={1} direction={'column'} gap={'0.2rem'}>
|
<Stack flex={1} direction={'column'} gap={'0.2rem'}>
|
||||||
<Typography noWrap>
|
<Typography noWrap>{message}</Typography>
|
||||||
{message}
|
{hint && <Typography>{hint}</Typography>}
|
||||||
</Typography>
|
|
||||||
{hint && (
|
|
||||||
<Typography>
|
|
||||||
{hint}
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Avatar, Stack, Toolbar, Typography } from '@mui/material'
|
import { Avatar, Stack, Toolbar, Typography, Divider, DividerProps, styled } from '@mui/material'
|
||||||
import { StyledAppBar, StyledAppLogo, StyledAppName, StyledProfileContainer, StyledThemeButton } from './styled'
|
import { StyledAppBar, StyledAppLogo, StyledAppName, StyledProfileContainer, StyledThemeButton } from './styled'
|
||||||
import { Menu } from './components/Menu'
|
import { Menu } from './components/Menu'
|
||||||
import { useNavigate, useParams } from 'react-router-dom'
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
|
||||||
import { ProfileMenu } from './components/ProfileMenu'
|
import { ProfileMenu } from './components/ProfileMenu'
|
||||||
import { useProfile } from '@/hooks/useProfile'
|
import { useProfile } from '@/hooks/useProfile'
|
||||||
import DarkModeIcon from '@mui/icons-material/DarkMode'
|
import DarkModeIcon from '@mui/icons-material/DarkMode'
|
||||||
@ -13,6 +13,8 @@ export const Header = () => {
|
|||||||
const themeMode = useAppSelector((state) => state.ui.themeMode)
|
const themeMode = useAppSelector((state) => state.ui.themeMode)
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
const [searchParams] = useSearchParams()
|
||||||
|
const needReload = searchParams.get('reload') === 'true'
|
||||||
|
|
||||||
const { npub = '' } = useParams<{ npub: string }>()
|
const { npub = '' } = useParams<{ npub: string }>()
|
||||||
const { userName, userAvatar, avatarTitle } = useProfile(npub)
|
const { userName, userAvatar, avatarTitle } = useProfile(npub)
|
||||||
@ -30,7 +32,7 @@ export const Header = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledAppBar position="fixed">
|
<StyledAppBar position={needReload ? 'relative' : 'fixed'}>
|
||||||
<Toolbar sx={{ padding: '12px' }}>
|
<Toolbar sx={{ padding: '12px' }}>
|
||||||
<Stack direction={'row'} justifyContent={'space-between'} alignItems={'center'} width={'100%'}>
|
<Stack direction={'row'} justifyContent={'space-between'} alignItems={'center'} width={'100%'}>
|
||||||
{showProfile && (
|
{showProfile && (
|
||||||
@ -56,6 +58,15 @@ export const Header = () => {
|
|||||||
{showProfile ? <ProfileMenu /> : <Menu />}
|
{showProfile ? <ProfileMenu /> : <Menu />}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
|
<StyledDivider />
|
||||||
</StyledAppBar>
|
</StyledAppBar>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const StyledDivider = styled((props: DividerProps) => <Divider {...props} />)({
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
width: '100%',
|
||||||
|
left: 0,
|
||||||
|
height: '2px',
|
||||||
|
})
|
||||||
|
@ -4,28 +4,21 @@ import { Avatar, ListItemIcon, MenuItem, Typography } from '@mui/material'
|
|||||||
import React, { FC } from 'react'
|
import React, { FC } from 'react'
|
||||||
|
|
||||||
type ListItemProfileProps = {
|
type ListItemProfileProps = {
|
||||||
onClickItem: () => void
|
onClickItem: () => void
|
||||||
} & DbKey
|
} & DbKey
|
||||||
|
|
||||||
export const ListItemProfile: FC<ListItemProfileProps> = ({
|
export const ListItemProfile: FC<ListItemProfileProps> = ({ onClickItem, npub }) => {
|
||||||
onClickItem,
|
const { userName, userAvatar, avatarTitle } = useProfile(npub)
|
||||||
npub,
|
return (
|
||||||
}) => {
|
<MenuItem sx={{ gap: '0.5rem' }} onClick={onClickItem}>
|
||||||
const { userName, userAvatar, avatarTitle } = useProfile(npub)
|
<ListItemIcon>
|
||||||
return (
|
<Avatar src={userAvatar} alt={userName} sx={{ width: 36, height: 36 }}>
|
||||||
<MenuItem sx={{ gap: '0.5rem' }} onClick={onClickItem}>
|
{avatarTitle}
|
||||||
<ListItemIcon>
|
</Avatar>
|
||||||
<Avatar
|
</ListItemIcon>
|
||||||
src={userAvatar}
|
<Typography variant="body2" noWrap>
|
||||||
alt={userName}
|
{userName}
|
||||||
sx={{ width: 36, height: 36 }}
|
</Typography>
|
||||||
>
|
</MenuItem>
|
||||||
{avatarTitle}
|
)
|
||||||
</Avatar>
|
|
||||||
</ListItemIcon>
|
|
||||||
<Typography variant='body2' noWrap>
|
|
||||||
{userName}
|
|
||||||
</Typography>
|
|
||||||
</MenuItem>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import { Outlet } from 'react-router-dom'
|
import { Outlet, useSearchParams } from 'react-router-dom'
|
||||||
import { Header } from './Header/Header'
|
import { Header } from './Header/Header'
|
||||||
import { Container, ContainerProps, Divider, DividerProps, styled } from '@mui/material'
|
import { Container, ContainerProps, styled } from '@mui/material'
|
||||||
|
import { ReloadBadge } from '@/components/ReloadBadge/ReloadBadge'
|
||||||
|
|
||||||
export const Layout: FC = () => {
|
export const Layout: FC = () => {
|
||||||
|
const [searchParams] = useSearchParams()
|
||||||
|
const needReload = searchParams.get('reload') === 'true'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer maxWidth="md">
|
<StyledContainer maxWidth="md" className={needReload ? 'reload' : ''}>
|
||||||
|
<ReloadBadge />
|
||||||
<Header />
|
<Header />
|
||||||
<StyledDivider />
|
|
||||||
<main>
|
<main>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</main>
|
</main>
|
||||||
@ -21,17 +25,11 @@ const StyledContainer = styled((props: ContainerProps) => <Container maxWidth="s
|
|||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
paddingBottom: '1rem',
|
paddingBottom: '1rem',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
'& > main': {
|
'&': {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
maxHeight: '100%',
|
maxHeight: '100%',
|
||||||
|
},
|
||||||
|
'&:not(.reload) > main': {
|
||||||
paddingTop: 'calc(66px + 1rem)',
|
paddingTop: 'calc(66px + 1rem)',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const StyledDivider = styled((props: DividerProps) => <Divider {...props} />)({
|
|
||||||
position: 'absolute',
|
|
||||||
top: '66px',
|
|
||||||
width: '100%',
|
|
||||||
left: 0,
|
|
||||||
height: '2px',
|
|
||||||
})
|
|
||||||
|
@ -48,7 +48,7 @@ interface Pending {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface IAllowCallbackParams {
|
interface IAllowCallbackParams {
|
||||||
backend: NDKNip46Backend
|
backend: Nip46Backend
|
||||||
npub: string
|
npub: string
|
||||||
id: string
|
id: string
|
||||||
method: string
|
method: string
|
||||||
@ -692,7 +692,9 @@ export class NoauthBackend {
|
|||||||
return this.keyInfo(dbKey)
|
return this.keyInfo(dbKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDecision(req: DbPending): DECISION {
|
private getDecision(backend: Nip46Backend, req: DbPending): DECISION {
|
||||||
|
if (!(req.method in backend.handlers)) return DECISION.IGNORE
|
||||||
|
|
||||||
const reqPerm = getReqPerm(req)
|
const reqPerm = getReqPerm(req)
|
||||||
const appPerms = this.perms.filter((p) => p.npub === req.npub && p.appNpub === req.appNpub)
|
const appPerms = this.perms.filter((p) => p.npub === req.npub && p.appNpub === req.appNpub)
|
||||||
|
|
||||||
@ -877,7 +879,7 @@ export class NoauthBackend {
|
|||||||
const otherReqs = self.confirmBuffer.filter((r) => r.req.appNpub === req.appNpub)
|
const otherReqs = self.confirmBuffer.filter((r) => r.req.appNpub === req.appNpub)
|
||||||
console.log('updated perms', this.perms, 'otherReqs', otherReqs, 'connected', connected)
|
console.log('updated perms', this.perms, 'otherReqs', otherReqs, 'connected', connected)
|
||||||
for (const r of otherReqs) {
|
for (const r of otherReqs) {
|
||||||
const dec = this.getDecision(r.req)
|
const dec = this.getDecision(backend, r.req)
|
||||||
if (dec !== DECISION.ASK) {
|
if (dec !== DECISION.ASK) {
|
||||||
r.cb(dec, false)
|
r.cb(dec, false)
|
||||||
}
|
}
|
||||||
@ -886,7 +888,7 @@ export class NoauthBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check perms
|
// check perms
|
||||||
const dec = this.getDecision(req)
|
const dec = this.getDecision(backend, req)
|
||||||
console.log(Date.now(), 'decision', req.id, dec)
|
console.log(Date.now(), 'decision', req.id, dec)
|
||||||
|
|
||||||
// have perm?
|
// have perm?
|
||||||
@ -1173,10 +1175,10 @@ export class NoauthBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async transferName(npub: string, name: string, newNpub: string) {
|
private async transferName(npub: string, name: string, newNpub: string) {
|
||||||
const key = this.enckeys.find(k => k.npub === npub)
|
const key = this.enckeys.find((k) => k.npub === npub)
|
||||||
if (!key) throw new Error("Npub not found")
|
if (!key) throw new Error('Npub not found')
|
||||||
if (!name) throw new Error("Empty name")
|
if (!name) throw new Error('Empty name')
|
||||||
if (key.name !== name) throw new Error("Name changed, please reload")
|
if (key.name !== name) throw new Error('Name changed, please reload')
|
||||||
await this.sendTransferNameToServer(npub, key.name, newNpub)
|
await this.sendTransferNameToServer(npub, key.name, newNpub)
|
||||||
await dbi.editName(npub, '')
|
await dbi.editName(npub, '')
|
||||||
key.name = ''
|
key.name = ''
|
||||||
|
@ -43,7 +43,7 @@ export function isWeakPassphase(passphrase: string): boolean {
|
|||||||
const compl = Math.pow(base, passphrase.length)
|
const compl = Math.pow(base, passphrase.length)
|
||||||
const thresh = Math.pow(11, 14)
|
const thresh = Math.pow(11, 14)
|
||||||
// console.log({ big, small, number, punct, base, compl, thresh });
|
// console.log({ big, small, number, punct, base, compl, thresh });
|
||||||
return compl < thresh;
|
return compl < thresh
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Keys {
|
export class Keys {
|
||||||
|
@ -20,8 +20,8 @@ export async function swicRegister() {
|
|||||||
},
|
},
|
||||||
onUpdate() {
|
onUpdate() {
|
||||||
// tell new SW that it should activate immediately
|
// tell new SW that it should activate immediately
|
||||||
swr?.waiting?.postMessage({type: 'SKIP_WAITING'})
|
swr?.waiting?.postMessage({ type: 'SKIP_WAITING' })
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
navigator.serviceWorker.ready.then(async (r) => {
|
navigator.serviceWorker.ready.then(async (r) => {
|
||||||
@ -33,8 +33,7 @@ export async function swicRegister() {
|
|||||||
console.log('This page is not currently controlled by a service worker.')
|
console.log('This page is not currently controlled by a service worker.')
|
||||||
}
|
}
|
||||||
|
|
||||||
while (queue.length)
|
while (queue.length) await queue.shift()!()
|
||||||
await (queue.shift()!)()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
navigator.serviceWorker.addEventListener('message', (event) => {
|
navigator.serviceWorker.addEventListener('message', (event) => {
|
||||||
@ -43,11 +42,11 @@ export async function swicRegister() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function swicWaitStarted() {
|
export function swicWaitStarted() {
|
||||||
return new Promise<void>(ok => {
|
return new Promise<void>((ok) => {
|
||||||
if (swr && swr.active) ok()
|
if (swr && swr.active) ok()
|
||||||
else queue.push(ok)
|
else queue.push(ok)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMessage(data: any) {
|
function onMessage(data: any) {
|
||||||
const { id, result, error } = data
|
const { id, result, error } = data
|
||||||
@ -78,7 +77,6 @@ export async function swicCall(method: string, ...args: any[]) {
|
|||||||
nextReqId++
|
nextReqId++
|
||||||
|
|
||||||
return new Promise((ok, rej) => {
|
return new Promise((ok, rej) => {
|
||||||
|
|
||||||
const call = async () => {
|
const call = async () => {
|
||||||
if (!swr || !swr.active) {
|
if (!swr || !swr.active) {
|
||||||
rej(new Error('No active service worker'))
|
rej(new Error('No active service worker'))
|
||||||
|
@ -16,12 +16,7 @@ export const BackgroundSigningWarning: FC<BackgroundSigningWarningProps> = ({ is
|
|||||||
Enable background service {isEnabling ? <CircularProgress size={'1.5rem'} /> : null}
|
Enable background service {isEnabling ? <CircularProgress size={'1.5rem'} /> : null}
|
||||||
</Stack>
|
</Stack>
|
||||||
}
|
}
|
||||||
hint={
|
hint={<Typography variant="body2">Please allow notifications for background operation.</Typography>}
|
||||||
<Typography variant='body2'>
|
|
||||||
Please allow notifications
|
|
||||||
for background operation.
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
icon={<AutoModeOutlinedIcon htmlColor="white" />}
|
icon={<AutoModeOutlinedIcon htmlColor="white" />}
|
||||||
onClick={isEnabling ? undefined : onEnableBackSigning}
|
onClick={isEnabling ? undefined : onEnableBackSigning}
|
||||||
/>
|
/>
|
||||||
|
@ -21,7 +21,6 @@ const AppRoutes = () => {
|
|||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Layout />}>
|
<Route path="/" element={<Layout />}>
|
||||||
<Route path="/" element={<Navigate to={'/home'} />} />
|
<Route path="/" element={<Navigate to={'/home'} />} />
|
||||||
{/* <Route path='/welcome' element={<WelcomePage />} /> */}
|
|
||||||
<Route path="/home" element={<HomePage />} />
|
<Route path="/home" element={<HomePage />} />
|
||||||
<Route path="/key/:npub" element={<KeyPage />} />
|
<Route path="/key/:npub" element={<KeyPage />} />
|
||||||
<Route path="/key/:npub/app/:appNpub" element={<AppPage />} />
|
<Route path="/key/:npub/app/:appNpub" element={<AppPage />} />
|
||||||
|
@ -2,16 +2,7 @@ import { combineReducers, configureStore } from '@reduxjs/toolkit'
|
|||||||
import { contentSlice } from './reducers/content.slice'
|
import { contentSlice } from './reducers/content.slice'
|
||||||
import { uiSlice } from './reducers/ui.slice'
|
import { uiSlice } from './reducers/ui.slice'
|
||||||
|
|
||||||
import {
|
import { persistStore, persistReducer } from 'redux-persist'
|
||||||
persistStore,
|
|
||||||
persistReducer,
|
|
||||||
// FLUSH,
|
|
||||||
// REGISTER,
|
|
||||||
// REHYDRATE,
|
|
||||||
// PAUSE,
|
|
||||||
// PERSIST,
|
|
||||||
// PURGE,
|
|
||||||
} from 'redux-persist'
|
|
||||||
import storage from 'redux-persist/lib/storage' // defaults to localStorage for web
|
import storage from 'redux-persist/lib/storage' // defaults to localStorage for web
|
||||||
import memoizeOne from 'memoize-one'
|
import memoizeOne from 'memoize-one'
|
||||||
import isDeepEqual from 'lodash.isequal'
|
import isDeepEqual from 'lodash.isequal'
|
||||||
|
@ -16,7 +16,7 @@ export enum ACTION_TYPE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ACTIONS: { [type: string]: string } = {
|
export const ACTIONS: { [type: string]: string } = {
|
||||||
basic: 'Basic permissions',
|
basic: 'Basic permissions',
|
||||||
get_public_key: 'Get public key',
|
get_public_key: 'Get public key',
|
||||||
sign_event: 'Sign event',
|
sign_event: 'Sign event',
|
||||||
connect: 'Connect',
|
connect: 'Connect',
|
||||||
|
@ -3,7 +3,7 @@ import { format } from 'date-fns'
|
|||||||
export const formatTimestampDate = (timestamp: number) => {
|
export const formatTimestampDate = (timestamp: number) => {
|
||||||
try {
|
try {
|
||||||
const date = new Date(timestamp)
|
const date = new Date(timestamp)
|
||||||
const formattedDate = format(date, "dd-MM-yyyy HH:mm")
|
const formattedDate = format(date, 'dd-MM-yyyy HH:mm')
|
||||||
return formattedDate
|
return formattedDate
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return ''
|
return ''
|
||||||
|
Reference in New Issue
Block a user