save
This commit is contained in:
parent
14940a4345
commit
9d565ddbde
@ -12,7 +12,6 @@ import { useState } from 'react'
|
|||||||
import { swicCall } from '@/modules/swic'
|
import { swicCall } from '@/modules/swic'
|
||||||
import { ACTION_TYPE } from '@/utils/consts'
|
import { ACTION_TYPE } from '@/utils/consts'
|
||||||
|
|
||||||
|
|
||||||
export const ModalConfirmConnect = () => {
|
export const ModalConfirmConnect = () => {
|
||||||
const { getModalOpened, createHandleCloseReplace } = useModalSearchParams()
|
const { getModalOpened, createHandleCloseReplace } = useModalSearchParams()
|
||||||
const isModalOpened = getModalOpened(MODAL_PARAMS_KEYS.CONFIRM_CONNECT)
|
const isModalOpened = getModalOpened(MODAL_PARAMS_KEYS.CONFIRM_CONNECT)
|
||||||
@ -45,7 +44,7 @@ export const ModalConfirmConnect = () => {
|
|||||||
sp.delete('appNpub')
|
sp.delete('appNpub')
|
||||||
sp.delete('reqId')
|
sp.delete('reqId')
|
||||||
await swicCall('confirm', pendingReqId, false, false)
|
await swicCall('confirm', pendingReqId, false, false)
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
const closeModalAfterRequest = createHandleCloseReplace(
|
const closeModalAfterRequest = createHandleCloseReplace(
|
||||||
@ -55,27 +54,27 @@ export const ModalConfirmConnect = () => {
|
|||||||
sp.delete('appNpub')
|
sp.delete('appNpub')
|
||||||
sp.delete('reqId')
|
sp.delete('reqId')
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
async function confirmPending(
|
async function confirmPending(
|
||||||
id: string,
|
id: string,
|
||||||
allow: boolean,
|
allow: boolean,
|
||||||
remember: boolean,
|
remember: boolean,
|
||||||
options?: any
|
options?: any,
|
||||||
) {
|
) {
|
||||||
call(async () => {
|
call(async () => {
|
||||||
await swicCall('confirm', id, allow, remember, options)
|
await swicCall('confirm', id, allow, remember, options)
|
||||||
console.log('confirmed', id, allow, remember, options)
|
console.log('confirmed', id, allow, remember, options)
|
||||||
closeModalAfterRequest()
|
closeModalAfterRequest()
|
||||||
})
|
})
|
||||||
if (isPopup) window.close();
|
if (isPopup) window.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
const allow = () => {
|
const allow = () => {
|
||||||
const options: any = {};
|
const options: any = {}
|
||||||
if (selectedActionType === ACTION_TYPE.BASIC)
|
if (selectedActionType === ACTION_TYPE.BASIC)
|
||||||
options.perms = [ACTION_TYPE.BASIC];
|
options.perms = [ACTION_TYPE.BASIC]
|
||||||
// else
|
// else
|
||||||
// options.perms = ['connect','get_public_key'];
|
// options.perms = ['connect','get_public_key'];
|
||||||
confirmPending(pendingReqId, true, true, options)
|
confirmPending(pendingReqId, true, true, options)
|
||||||
@ -86,16 +85,16 @@ export const ModalConfirmConnect = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isPopup) {
|
if (isPopup) {
|
||||||
document.addEventListener('visibilitychange', function() {
|
document.addEventListener('visibilitychange', function () {
|
||||||
if (document.visibilityState == 'hidden') {
|
if (document.visibilityState === 'hidden') {
|
||||||
disallow();
|
disallow()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
open={isModalOpened}
|
open={isModalOpened}
|
||||||
withCloseButton={!isPopup}
|
withCloseButton={!isPopup}
|
||||||
onClose={!isPopup ? handleCloseModal : undefined}
|
onClose={!isPopup ? handleCloseModal : undefined}
|
||||||
>
|
>
|
||||||
@ -147,16 +146,10 @@ export const ModalConfirmConnect = () => {
|
|||||||
/>
|
/>
|
||||||
</StyledToggleButtonsGroup>
|
</StyledToggleButtonsGroup>
|
||||||
<Stack direction={'row'} gap={'1rem'}>
|
<Stack direction={'row'} gap={'1rem'}>
|
||||||
<StyledButton
|
<StyledButton onClick={disallow} varianttype='secondary'>
|
||||||
onClick={disallow}
|
|
||||||
varianttype='secondary'
|
|
||||||
>
|
|
||||||
Disallow
|
Disallow
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
<StyledButton
|
<StyledButton fullWidth onClick={allow}>
|
||||||
fullWidth
|
|
||||||
onClick={allow}
|
|
||||||
>
|
|
||||||
{/* Allow {selectedActionType} actions */}
|
{/* Allow {selectedActionType} actions */}
|
||||||
Connect
|
Connect
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
@ -94,10 +94,11 @@ export const ModalConfirmEvent: FC<ModalConfirmEventProps> = ({
|
|||||||
sp.delete('appNpub')
|
sp.delete('appNpub')
|
||||||
sp.delete('reqId')
|
sp.delete('reqId')
|
||||||
selectedPendingRequests.forEach(
|
selectedPendingRequests.forEach(
|
||||||
async (req) => await swicCall('confirm', req.id, false, false),
|
async (req) =>
|
||||||
|
await swicCall('confirm', req.id, false, false),
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
const closeModalAfterRequest = createHandleCloseReplace(
|
const closeModalAfterRequest = createHandleCloseReplace(
|
||||||
@ -106,8 +107,8 @@ export const ModalConfirmEvent: FC<ModalConfirmEventProps> = ({
|
|||||||
onClose: (sp) => {
|
onClose: (sp) => {
|
||||||
sp.delete('appNpub')
|
sp.delete('appNpub')
|
||||||
sp.delete('reqId')
|
sp.delete('reqId')
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
async function confirmPending(allow: boolean) {
|
async function confirmPending(allow: boolean) {
|
||||||
@ -119,7 +120,7 @@ export const ModalConfirmEvent: FC<ModalConfirmEventProps> = ({
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
closeModalAfterRequest()
|
closeModalAfterRequest()
|
||||||
if (isPopup) window.close();
|
if (isPopup) window.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleChangeCheckbox = (reqId: string) => () => {
|
const handleChangeCheckbox = (reqId: string) => () => {
|
||||||
@ -141,8 +142,8 @@ export const ModalConfirmEvent: FC<ModalConfirmEventProps> = ({
|
|||||||
|
|
||||||
if (isPopup) {
|
if (isPopup) {
|
||||||
document.addEventListener('visibilitychange', () => {
|
document.addEventListener('visibilitychange', () => {
|
||||||
if (document.visibilityState == 'hidden') {
|
if (document.visibilityState === 'hidden') {
|
||||||
confirmPending(false);
|
confirmPending(false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,7 @@
|
|||||||
import * as yup from 'yup'
|
import * as yup from 'yup'
|
||||||
|
|
||||||
export const schema = yup.object().shape({
|
export const schema = yup.object().shape({
|
||||||
username: yup
|
username: yup.string().required(),
|
||||||
.string()
|
|
||||||
.test('Domain validation', 'The domain is required!', function (value) {
|
|
||||||
if (!value || !value.trim().length) return false
|
|
||||||
|
|
||||||
const USERNAME_WITH_DOMAIN_REGEXP = new RegExp(
|
|
||||||
/^[\w-.]+@([\w-]+\.)+[\w-]{2,8}$/g,
|
|
||||||
)
|
|
||||||
return USERNAME_WITH_DOMAIN_REGEXP.test(value)
|
|
||||||
})
|
|
||||||
.required(),
|
|
||||||
password: yup.string().required().min(4),
|
password: yup.string().required().min(4),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import { Button } from '@/shared/Button/Button'
|
|||||||
import { CheckmarkIcon } from '@/assets'
|
import { CheckmarkIcon } from '@/assets'
|
||||||
import { swicCall } from '@/modules/swic'
|
import { swicCall } from '@/modules/swic'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { DOMAIN, NOAUTHD_URL } from '@/utils/consts'
|
import { DOMAIN } from '@/utils/consts'
|
||||||
import { fetchNip05 } from '@/utils/helpers/helpers'
|
import { fetchNip05 } from '@/utils/helpers/helpers'
|
||||||
|
|
||||||
export const ModalSignUp = () => {
|
export const ModalSignUp = () => {
|
||||||
@ -36,20 +36,17 @@ export const ModalSignUp = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputHelperText = enteredValue
|
const inputHelperText = enteredValue ? (
|
||||||
? (
|
|
||||||
isAvailable ? (
|
isAvailable ? (
|
||||||
<>
|
<>
|
||||||
<CheckmarkIcon /> Available
|
<CheckmarkIcon /> Available
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>Already taken</>
|
||||||
Already taken
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
"Don't worry, username can be changed later."
|
"Don't worry, username can be changed later."
|
||||||
);
|
)
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
const name = enteredValue.trim()
|
const name = enteredValue.trim()
|
||||||
@ -96,13 +93,13 @@ export const ModalSignUp = () => {
|
|||||||
helperTextProps={{
|
helperTextProps={{
|
||||||
sx: {
|
sx: {
|
||||||
'&.helper_text': {
|
'&.helper_text': {
|
||||||
color: enteredValue && isAvailable
|
color:
|
||||||
? theme.palette.success.main
|
enteredValue && isAvailable
|
||||||
: (enteredValue && !isAvailable
|
? theme.palette.success.main
|
||||||
? theme.palette.error.main
|
: enteredValue && !isAvailable
|
||||||
: theme.palette.textSecondaryDecorate.main
|
? theme.palette.error.main
|
||||||
)
|
: theme.palette
|
||||||
,
|
.textSecondaryDecorate.main,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
40
src/hooks/useProfile.ts
Normal file
40
src/hooks/useProfile.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
|
import { fetchProfile } from '@/modules/nostr'
|
||||||
|
import { MetaEvent } from '@/types/meta-event'
|
||||||
|
import { getProfileUsername, getShortenNpub } from '@/utils/helpers/helpers'
|
||||||
|
import { useAppSelector } from '@/store/hooks/redux'
|
||||||
|
import { selectKeyByNpub } from '@/store'
|
||||||
|
|
||||||
|
const getFirstLetter = (text: string | undefined): string | null => {
|
||||||
|
if (!text || text.trim().length === 0) return null
|
||||||
|
return text.substring(0, 1).toUpperCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useProfile = (npub: string) => {
|
||||||
|
const [profile, setProfile] = useState<MetaEvent | null>(null)
|
||||||
|
const currentKey = useAppSelector((state) => selectKeyByNpub(state, npub))
|
||||||
|
|
||||||
|
const userName = getProfileUsername(profile) || currentKey?.name
|
||||||
|
const userAvatar = profile?.info?.picture || ''
|
||||||
|
const avatarTitle = getFirstLetter(userName)
|
||||||
|
|
||||||
|
const loadProfile = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetchProfile(npub)
|
||||||
|
setProfile(response)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch profile:', error)
|
||||||
|
}
|
||||||
|
}, [npub])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadProfile()
|
||||||
|
}, [loadProfile])
|
||||||
|
|
||||||
|
return {
|
||||||
|
profile,
|
||||||
|
userName: userName || getShortenNpub(npub),
|
||||||
|
userAvatar,
|
||||||
|
avatarTitle,
|
||||||
|
}
|
||||||
|
}
|
@ -2,35 +2,20 @@ import { Avatar, Stack, Toolbar, Typography } from '@mui/material'
|
|||||||
import { AppLogo } from '../../assets'
|
import { AppLogo } from '../../assets'
|
||||||
import { StyledAppBar, StyledAppName } from './styled'
|
import { StyledAppBar, StyledAppName } from './styled'
|
||||||
import { Menu } from './components/Menu'
|
import { Menu } from './components/Menu'
|
||||||
import { useParams } from 'react-router-dom'
|
import { useNavigate, useParams } from 'react-router-dom'
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
|
||||||
import { MetaEvent } from '@/types/meta-event'
|
|
||||||
import { fetchProfile } from '@/modules/nostr'
|
|
||||||
import { ProfileMenu } from './components/ProfileMenu'
|
import { ProfileMenu } from './components/ProfileMenu'
|
||||||
import { getShortenNpub } from '@/utils/helpers/helpers'
|
import { useProfile } from '@/hooks/useProfile'
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
const { npub = '' } = useParams<{ npub: string }>()
|
const { npub = '' } = useParams<{ npub: string }>()
|
||||||
const [profile, setProfile] = useState<MetaEvent | null>(null)
|
const { userName, userAvatar, avatarTitle } = useProfile(npub)
|
||||||
|
const showProfile = Boolean(npub)
|
||||||
|
|
||||||
const load = useCallback(async () => {
|
const navigate = useNavigate()
|
||||||
if (!npub) return setProfile(null)
|
|
||||||
|
|
||||||
try {
|
const handleNavigate = () => {
|
||||||
const response = await fetchProfile(npub)
|
navigate(`/key/${npub}`)
|
||||||
setProfile(response as any)
|
}
|
||||||
} catch (e) {
|
|
||||||
return setProfile(null)
|
|
||||||
}
|
|
||||||
}, [npub])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
load()
|
|
||||||
}, [load])
|
|
||||||
|
|
||||||
const showProfile = Boolean(npub || profile)
|
|
||||||
const userName = profile?.info?.name || getShortenNpub(npub)
|
|
||||||
const userAvatar = profile?.info?.picture || ''
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledAppBar position='fixed'>
|
<StyledAppBar position='fixed'>
|
||||||
@ -41,17 +26,30 @@ export const Header = () => {
|
|||||||
alignItems={'center'}
|
alignItems={'center'}
|
||||||
width={'100%'}
|
width={'100%'}
|
||||||
>
|
>
|
||||||
{showProfile ? (
|
{showProfile && (
|
||||||
<Stack
|
<Stack
|
||||||
gap={'1rem'}
|
gap={'1rem'}
|
||||||
direction={'row'}
|
direction={'row'}
|
||||||
alignItems={'center'}
|
alignItems={'center'}
|
||||||
flex={1}
|
flex={1}
|
||||||
>
|
>
|
||||||
<Avatar src={userAvatar} alt={userName} />
|
<Avatar
|
||||||
<Typography fontWeight={600}>{userName}</Typography>
|
src={userAvatar}
|
||||||
|
alt={userName}
|
||||||
|
onClick={handleNavigate}
|
||||||
|
>
|
||||||
|
{avatarTitle}
|
||||||
|
</Avatar>
|
||||||
|
<Typography
|
||||||
|
fontWeight={600}
|
||||||
|
onClick={handleNavigate}
|
||||||
|
>
|
||||||
|
{userName}
|
||||||
|
</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
) : (
|
)}
|
||||||
|
|
||||||
|
{!showProfile && (
|
||||||
<StyledAppName>
|
<StyledAppName>
|
||||||
<AppLogo />
|
<AppLogo />
|
||||||
<span>Nsec.app</span>
|
<span>Nsec.app</span>
|
||||||
|
31
src/layout/Header/components/ListItemProfile.tsx
Normal file
31
src/layout/Header/components/ListItemProfile.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { useProfile } from '@/hooks/useProfile'
|
||||||
|
import { DbKey } from '@/modules/db'
|
||||||
|
import { Avatar, ListItemIcon, MenuItem, Typography } from '@mui/material'
|
||||||
|
import React, { FC } from 'react'
|
||||||
|
|
||||||
|
type ListItemProfileProps = {
|
||||||
|
onClickItem: () => void
|
||||||
|
} & DbKey
|
||||||
|
|
||||||
|
export const ListItemProfile: FC<ListItemProfileProps> = ({
|
||||||
|
onClickItem,
|
||||||
|
npub,
|
||||||
|
}) => {
|
||||||
|
const { userName, userAvatar, avatarTitle } = useProfile(npub)
|
||||||
|
return (
|
||||||
|
<MenuItem sx={{ gap: '0.5rem' }} onClick={onClickItem}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<Avatar
|
||||||
|
src={userAvatar}
|
||||||
|
alt={userName}
|
||||||
|
sx={{ width: 36, height: 36 }}
|
||||||
|
>
|
||||||
|
{avatarTitle}
|
||||||
|
</Avatar>
|
||||||
|
</ListItemIcon>
|
||||||
|
<Typography variant='body2' noWrap>
|
||||||
|
{userName}
|
||||||
|
</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
)
|
||||||
|
}
|
@ -1,13 +1,7 @@
|
|||||||
import { DbKey } from '@/modules/db'
|
import { DbKey } from '@/modules/db'
|
||||||
import { getShortenNpub } from '@/utils/helpers/helpers'
|
import { Stack } from '@mui/material'
|
||||||
import {
|
import { FC } from 'react'
|
||||||
Avatar,
|
import { ListItemProfile } from './ListItemProfile'
|
||||||
ListItemIcon,
|
|
||||||
MenuItem,
|
|
||||||
Stack,
|
|
||||||
Typography,
|
|
||||||
} from '@mui/material'
|
|
||||||
import React, { FC } from 'react'
|
|
||||||
|
|
||||||
type ListProfilesProps = {
|
type ListProfilesProps = {
|
||||||
keys: DbKey[]
|
keys: DbKey[]
|
||||||
@ -21,26 +15,12 @@ export const ListProfiles: FC<ListProfilesProps> = ({
|
|||||||
return (
|
return (
|
||||||
<Stack maxHeight={'10rem'} overflow={'auto'}>
|
<Stack maxHeight={'10rem'} overflow={'auto'}>
|
||||||
{keys.map((key) => {
|
{keys.map((key) => {
|
||||||
const userName =
|
|
||||||
key?.profile?.info?.name || getShortenNpub(key.npub)
|
|
||||||
const userAvatar = key?.profile?.info?.picture || ''
|
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<ListItemProfile
|
||||||
sx={{ gap: '0.5rem' }}
|
{...key}
|
||||||
onClick={() => onClickItem(key)}
|
|
||||||
key={key.npub}
|
key={key.npub}
|
||||||
>
|
onClickItem={() => onClickItem(key)}
|
||||||
<ListItemIcon>
|
/>
|
||||||
<Avatar
|
|
||||||
src={userAvatar}
|
|
||||||
alt={userName}
|
|
||||||
sx={{ width: 36, height: 36 }}
|
|
||||||
/>
|
|
||||||
</ListItemIcon>
|
|
||||||
<Typography variant='body2' noWrap>
|
|
||||||
{userName}
|
|
||||||
</Typography>
|
|
||||||
</MenuItem>
|
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
@ -8,26 +8,26 @@ import {
|
|||||||
TypographyProps,
|
TypographyProps,
|
||||||
styled,
|
styled,
|
||||||
} from '@mui/material'
|
} from '@mui/material'
|
||||||
import { getShortenNpub } from '../../../utils/helpers/helpers'
|
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { useProfile } from '@/hooks/useProfile'
|
||||||
|
|
||||||
type ItemKeyProps = DbKey
|
type ItemKeyProps = DbKey
|
||||||
|
|
||||||
export const ItemKey: FC<ItemKeyProps> = (props) => {
|
export const ItemKey: FC<ItemKeyProps> = (props) => {
|
||||||
const { npub, profile } = props
|
const { npub } = props
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const { userName, userAvatar, avatarTitle } = useProfile(npub)
|
||||||
|
|
||||||
const handleNavigate = () => {
|
const handleNavigate = () => {
|
||||||
navigate('/key/' + npub)
|
navigate('/key/' + npub)
|
||||||
}
|
}
|
||||||
const { name = '', picture = '' } = profile?.info || {}
|
|
||||||
const userName = name || getShortenNpub(npub)
|
|
||||||
const userAvatar = picture || ''
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledKeyContainer onClick={handleNavigate}>
|
<StyledKeyContainer onClick={handleNavigate}>
|
||||||
<Stack direction={'row'} alignItems={'center'} gap='1rem'>
|
<Stack direction={'row'} alignItems={'center'} gap='1rem'>
|
||||||
<Avatar src={userAvatar} alt={userName} />
|
<Avatar src={userAvatar} alt={userName}>
|
||||||
|
{avatarTitle}
|
||||||
|
</Avatar>
|
||||||
<StyledText variant='body1'>{userName}</StyledText>
|
<StyledText variant='body1'>{userName}</StyledText>
|
||||||
</Stack>
|
</Stack>
|
||||||
</StyledKeyContainer>
|
</StyledKeyContainer>
|
||||||
|
@ -11,7 +11,6 @@ import { ModalSettings } from '@/components/Modal/ModalSettings/ModalSettings'
|
|||||||
import { ModalExplanation } from '@/components/Modal/ModalExplanation/ModalExplanation'
|
import { ModalExplanation } from '@/components/Modal/ModalExplanation/ModalExplanation'
|
||||||
import { ModalConfirmConnect } from '@/components/Modal/ModalConfirmConnect/ModalConfirmConnect'
|
import { ModalConfirmConnect } from '@/components/Modal/ModalConfirmConnect/ModalConfirmConnect'
|
||||||
import { ModalConfirmEvent } from '@/components/Modal/ModalConfirmEvent/ModalConfirmEvent'
|
import { ModalConfirmEvent } from '@/components/Modal/ModalConfirmEvent/ModalConfirmEvent'
|
||||||
import { useProfile } from './hooks/useProfile'
|
|
||||||
import { useBackgroundSigning } from './hooks/useBackgroundSigning'
|
import { useBackgroundSigning } from './hooks/useBackgroundSigning'
|
||||||
import { BackgroundSigningWarning } from './components/BackgroundSigningWarning'
|
import { BackgroundSigningWarning } from './components/BackgroundSigningWarning'
|
||||||
import UserValueSection from './components/UserValueSection'
|
import UserValueSection from './components/UserValueSection'
|
||||||
@ -22,23 +21,23 @@ import { DOMAIN } from '@/utils/consts'
|
|||||||
|
|
||||||
const KeyPage = () => {
|
const KeyPage = () => {
|
||||||
const { npub = '' } = useParams<{ npub: string }>()
|
const { npub = '' } = useParams<{ npub: string }>()
|
||||||
const { keys, apps, pending, perms } = useAppSelector((state) => state.content)
|
const { keys, apps, pending, perms } = useAppSelector(
|
||||||
|
(state) => state.content,
|
||||||
|
)
|
||||||
const isSynced = useLiveQuery(checkNpubSyncQuerier(npub), [npub], false)
|
const isSynced = useLiveQuery(checkNpubSyncQuerier(npub), [npub], false)
|
||||||
|
|
||||||
const { handleOpen } = useModalSearchParams()
|
const { handleOpen } = useModalSearchParams()
|
||||||
|
|
||||||
// const { userNameWithPrefix } = useProfile(npub)
|
|
||||||
const { handleEnableBackground, showWarning, isEnabling } =
|
const { handleEnableBackground, showWarning, isEnabling } =
|
||||||
useBackgroundSigning()
|
useBackgroundSigning()
|
||||||
|
|
||||||
const key = keys.find(k => k.npub === npub)
|
const key = keys.find((k) => k.npub === npub)
|
||||||
|
|
||||||
let username = ''
|
let username = ''
|
||||||
if (key?.name) {
|
if (key?.name) {
|
||||||
if (key.name.includes('@'))
|
if (key.name.includes('@')) username = key.name
|
||||||
username = key.name
|
else username = `${key?.name}@${DOMAIN}`
|
||||||
else
|
}
|
||||||
username = `${key?.name}@${DOMAIN}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const filteredApps = apps.filter((a) => a.npub === npub)
|
const filteredApps = apps.filter((a) => a.npub === npub)
|
||||||
const { prepareEventPendings } = useTriggerConfirmModal(
|
const { prepareEventPendings } = useTriggerConfirmModal(
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react'
|
|
||||||
import { fetchProfile } from '@/modules/nostr'
|
|
||||||
import { MetaEvent } from '@/types/meta-event'
|
|
||||||
import { getProfileUsername } from '@/utils/helpers/helpers'
|
|
||||||
import { DOMAIN } from '@/utils/consts'
|
|
||||||
|
|
||||||
export const useProfile = (npub: string) => {
|
|
||||||
const [profile, setProfile] = useState<MetaEvent | null>(null)
|
|
||||||
|
|
||||||
const userName = getProfileUsername(profile, npub)
|
|
||||||
// FIXME use nip05?
|
|
||||||
const userNameWithPrefix = userName + '@' + DOMAIN
|
|
||||||
|
|
||||||
const loadProfile = useCallback(async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetchProfile(npub)
|
|
||||||
setProfile(response)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to fetch profile:', error)
|
|
||||||
}
|
|
||||||
}, [npub])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
loadProfile()
|
|
||||||
}, [loadProfile])
|
|
||||||
|
|
||||||
return {
|
|
||||||
profile,
|
|
||||||
userNameWithPrefix,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
import { Suspense, lazy } from 'react'
|
import { Suspense, lazy } from 'react'
|
||||||
import { Route, Routes, Navigate } from 'react-router-dom'
|
import { Route, Routes, Navigate } from 'react-router-dom'
|
||||||
import HomePage from '../pages/HomePage/Home.Page'
|
import HomePage from '../pages/HomePage/Home.Page'
|
||||||
import WelcomePage from '../pages/Welcome.Page'
|
|
||||||
import { Layout } from '../layout/Layout'
|
import { Layout } from '../layout/Layout'
|
||||||
import { CircularProgress, Stack } from '@mui/material'
|
import { CircularProgress, Stack } from '@mui/material'
|
||||||
|
|
||||||
|
@ -44,6 +44,10 @@ export type AppDispatch = typeof store.dispatch
|
|||||||
|
|
||||||
export const selectKeys = (state: RootState) => state.content.keys
|
export const selectKeys = (state: RootState) => state.content.keys
|
||||||
|
|
||||||
|
export const selectKeyByNpub = (state: RootState, npub: string) => {
|
||||||
|
return state.content.keys.find((key) => key.npub === npub)
|
||||||
|
}
|
||||||
|
|
||||||
export const selectAppsByNpub = memoizeOne((state: RootState, npub: string) => {
|
export const selectAppsByNpub = memoizeOne((state: RootState, npub: string) => {
|
||||||
return state.content.apps.filter((app) => app.npub === npub)
|
return state.content.apps.filter((app) => app.npub === npub)
|
||||||
}, isDeepEqual)
|
}, isDeepEqual)
|
||||||
|
@ -1,101 +1,100 @@
|
|||||||
import { nip19 } from "nostr-tools";
|
import { nip19 } from 'nostr-tools'
|
||||||
import { ACTION_TYPE, NIP46_RELAYS } from "../consts";
|
import { ACTION_TYPE, NIP46_RELAYS } from '../consts'
|
||||||
import { DbPending } from "@/modules/db";
|
import { DbPending } from '@/modules/db'
|
||||||
import { MetaEvent } from "@/types/meta-event";
|
import { MetaEvent } from '@/types/meta-event'
|
||||||
|
|
||||||
export async function call(cb: () => any) {
|
export async function call(cb: () => any) {
|
||||||
try {
|
try {
|
||||||
return await cb();
|
return await cb()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`Error: ${e}`);
|
console.log(`Error: ${e}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getShortenNpub = (npub = "") => {
|
export const getShortenNpub = (npub = '') => {
|
||||||
return npub.substring(0, 10) + "..." + npub.slice(-4);
|
return npub.substring(0, 10) + '...' + npub.slice(-4)
|
||||||
};
|
}
|
||||||
|
|
||||||
export const getProfileUsername = (profile: MetaEvent | null, npub: string) => {
|
export const getProfileUsername = (profile: MetaEvent | null) => {
|
||||||
return (
|
if (!profile) return null
|
||||||
profile?.info?.name || profile?.info?.display_name || getShortenNpub(npub)
|
return profile?.info?.name || profile?.info?.display_name
|
||||||
);
|
}
|
||||||
};
|
|
||||||
|
|
||||||
export const getBunkerLink = (npub = "") => {
|
export const getBunkerLink = (npub = '') => {
|
||||||
if (!npub) return "";
|
if (!npub) return ''
|
||||||
const { data: pubkey } = nip19.decode(npub);
|
const { data: pubkey } = nip19.decode(npub)
|
||||||
return `bunker://${pubkey}?relay=${NIP46_RELAYS[0]}`;
|
return `bunker://${pubkey}?relay=${NIP46_RELAYS[0]}`
|
||||||
};
|
}
|
||||||
|
|
||||||
export async function askNotificationPermission() {
|
export async function askNotificationPermission() {
|
||||||
return new Promise<void>((ok, rej) => {
|
return new Promise<void>((ok, rej) => {
|
||||||
// Let's check if the browser supports notifications
|
// Let's check if the browser supports notifications
|
||||||
if (!("Notification" in window)) {
|
if (!('Notification' in window)) {
|
||||||
rej("This browser does not support notifications.");
|
rej('This browser does not support notifications.')
|
||||||
} else {
|
} else {
|
||||||
Notification.requestPermission().then(() => {
|
Notification.requestPermission().then(() => {
|
||||||
if (Notification.permission === "granted") ok();
|
if (Notification.permission === 'granted') ok()
|
||||||
else rej();
|
else rej()
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSignReqKind(req: DbPending): number | undefined {
|
export function getSignReqKind(req: DbPending): number | undefined {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(JSON.parse(req.params)[0]);
|
const data = JSON.parse(JSON.parse(req.params)[0])
|
||||||
return data.kind;
|
return data.kind
|
||||||
} catch {}
|
} catch {}
|
||||||
return undefined;
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getReqPerm(req: DbPending): string {
|
export function getReqPerm(req: DbPending): string {
|
||||||
if (req.method === "sign_event") {
|
if (req.method === 'sign_event') {
|
||||||
const kind = getSignReqKind(req);
|
const kind = getSignReqKind(req)
|
||||||
if (kind !== undefined) return `${req.method}:${kind}`;
|
if (kind !== undefined) return `${req.method}:${kind}`
|
||||||
}
|
}
|
||||||
return req.method;
|
return req.method
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isPackagePerm(perm: string, reqPerm: string) {
|
export function isPackagePerm(perm: string, reqPerm: string) {
|
||||||
if (perm === ACTION_TYPE.BASIC) {
|
if (perm === ACTION_TYPE.BASIC) {
|
||||||
switch (reqPerm) {
|
switch (reqPerm) {
|
||||||
case "connect":
|
case 'connect':
|
||||||
case "get_public_key":
|
case 'get_public_key':
|
||||||
case "nip04_decrypt":
|
case 'nip04_decrypt':
|
||||||
case "nip04_encrypt":
|
case 'nip04_encrypt':
|
||||||
case "sign_event:0":
|
case 'sign_event:0':
|
||||||
case "sign_event:1":
|
case 'sign_event:1':
|
||||||
case "sign_event:3":
|
case 'sign_event:3':
|
||||||
case "sign_event:6":
|
case 'sign_event:6':
|
||||||
case "sign_event:7":
|
case 'sign_event:7':
|
||||||
case "sign_event:9734":
|
case 'sign_event:9734':
|
||||||
case "sign_event:10002":
|
case 'sign_event:10002':
|
||||||
case "sign_event:30023":
|
case 'sign_event:30023':
|
||||||
case "sign_event:10000":
|
case 'sign_event:10000':
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchNip05(value: string, origin?: string) {
|
export async function fetchNip05(value: string, origin?: string) {
|
||||||
try {
|
try {
|
||||||
const [username, domain] = value.split("@");
|
const [username, domain] = value.split('@')
|
||||||
if (!origin) origin = `https://${domain}`
|
if (!origin) origin = `https://${domain}`
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${origin}/.well-known/nostr.json?name=${username}`
|
`${origin}/.well-known/nostr.json?name=${username}`,
|
||||||
);
|
)
|
||||||
const getNpub: {
|
const getNpub: {
|
||||||
names: {
|
names: {
|
||||||
[name: string]: string;
|
[name: string]: string
|
||||||
};
|
}
|
||||||
} = await response.json();
|
} = await response.json()
|
||||||
|
|
||||||
const pubkey = getNpub.names[username];
|
const pubkey = getNpub.names[username]
|
||||||
return nip19.npubEncode(pubkey);
|
return nip19.npubEncode(pubkey)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Failed to fetch nip05", value, "error: " + e);
|
console.log('Failed to fetch nip05', value, 'error: ' + e)
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user