Assign name on login, change confirm modals, change push warning, reject reqs before connect
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { useModalSearchParams } from '@/hooks/useModalSearchParams'
|
import { useModalSearchParams } from '@/hooks/useModalSearchParams'
|
||||||
import { Modal } from '@/shared/Modal/Modal'
|
import { Modal } from '@/shared/Modal/Modal'
|
||||||
import { MODAL_PARAMS_KEYS } from '@/types/modal'
|
import { MODAL_PARAMS_KEYS } from '@/types/modal'
|
||||||
import { call, getShortenNpub } from '@/utils/helpers/helpers'
|
import { call, getAppIconTitle, getShortenNpub } from '@/utils/helpers/helpers'
|
||||||
import { Avatar, Box, Stack, Typography } from '@mui/material'
|
import { Avatar, Box, Stack, Typography } from '@mui/material'
|
||||||
import { useParams, useSearchParams } from 'react-router-dom'
|
import { useParams, useSearchParams } from 'react-router-dom'
|
||||||
import { useAppSelector } from '@/store/hooks/redux'
|
import { useAppSelector } from '@/store/hooks/redux'
|
||||||
@@ -29,19 +29,20 @@ export const ModalConfirmConnect = () => {
|
|||||||
const triggerApp = apps.find((app) => app.appNpub === appNpub)
|
const triggerApp = apps.find((app) => app.appNpub === appNpub)
|
||||||
const { name, icon = '' } = triggerApp || {}
|
const { name, icon = '' } = triggerApp || {}
|
||||||
const appName = name || getShortenNpub(appNpub)
|
const appName = name || getShortenNpub(appNpub)
|
||||||
|
const appAvatarTitle = getAppIconTitle(name, appNpub)
|
||||||
|
|
||||||
const handleActionTypeChange = (_: any, value: ACTION_TYPE | null) => {
|
const handleActionTypeChange = (_: any, value: ACTION_TYPE | null) => {
|
||||||
if (!value) return undefined
|
if (!value) return undefined
|
||||||
return setSelectedActionType(value)
|
return setSelectedActionType(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCloseModal = createHandleCloseReplace(MODAL_PARAMS_KEYS.CONFIRM_CONNECT, {
|
// const handleCloseModal = createHandleCloseReplace(MODAL_PARAMS_KEYS.CONFIRM_CONNECT, {
|
||||||
onClose: async (sp) => {
|
// onClose: async (sp) => {
|
||||||
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(MODAL_PARAMS_KEYS.CONFIRM_CONNECT, {
|
const closeModalAfterRequest = createHandleCloseReplace(MODAL_PARAMS_KEYS.CONFIRM_CONNECT, {
|
||||||
onClose: (sp) => {
|
onClose: (sp) => {
|
||||||
sp.delete('appNpub')
|
sp.delete('appNpub')
|
||||||
@@ -79,23 +80,27 @@ export const ModalConfirmConnect = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal open={isModalOpened} withCloseButton={!isPopup} onClose={!isPopup ? handleCloseModal : undefined}>
|
<Modal title='Connection request' open={isModalOpened} withCloseButton={false}
|
||||||
|
// withCloseButton={!isPopup} onClose={!isPopup ? handleCloseModal : undefined}
|
||||||
|
>
|
||||||
<Stack gap={'1rem'} paddingTop={'1rem'}>
|
<Stack gap={'1rem'} paddingTop={'1rem'}>
|
||||||
<Stack direction={'row'} gap={'1rem'} alignItems={'center'} marginBottom={'1rem'}>
|
<Stack direction={'row'} gap={'1rem'} alignItems={'center'} marginBottom={'1rem'}>
|
||||||
<Avatar
|
<Avatar
|
||||||
variant="square"
|
variant="rounded"
|
||||||
sx={{
|
sx={{
|
||||||
width: 56,
|
width: 56,
|
||||||
height: 56,
|
height: 56,
|
||||||
}}
|
}}
|
||||||
src={icon}
|
src={icon}
|
||||||
/>
|
>
|
||||||
|
{appAvatarTitle}
|
||||||
|
</Avatar>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="h5" fontWeight={600}>
|
<Typography variant="h5" fontWeight={600}>
|
||||||
{appName}
|
{appName}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color={'GrayText'}>
|
<Typography variant="body2" color={'GrayText'}>
|
||||||
Would like to connect to your account
|
New app would like to connect
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -103,7 +108,7 @@ export const ModalConfirmConnect = () => {
|
|||||||
<ActionToggleButton
|
<ActionToggleButton
|
||||||
value={ACTION_TYPE.BASIC}
|
value={ACTION_TYPE.BASIC}
|
||||||
title="Basic permissions"
|
title="Basic permissions"
|
||||||
description="Read your public key, sign notes and reactions"
|
description="Read your public key, sign notes, reactions, zaps, etc"
|
||||||
// hasinfo
|
// hasinfo
|
||||||
/>
|
/>
|
||||||
{/* <ActionToggleButton
|
{/* <ActionToggleButton
|
||||||
@@ -115,7 +120,7 @@ export const ModalConfirmConnect = () => {
|
|||||||
<ActionToggleButton
|
<ActionToggleButton
|
||||||
value={ACTION_TYPE.CUSTOM}
|
value={ACTION_TYPE.CUSTOM}
|
||||||
title="On demand"
|
title="On demand"
|
||||||
description="Assign permissions when the app asks for them"
|
description="Confirm permissions when the app asks for them"
|
||||||
/>
|
/>
|
||||||
</StyledToggleButtonsGroup>
|
</StyledToggleButtonsGroup>
|
||||||
<Stack direction={'row'} gap={'1rem'}>
|
<Stack direction={'row'} gap={'1rem'}>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useModalSearchParams } from '@/hooks/useModalSearchParams'
|
import { useModalSearchParams } from '@/hooks/useModalSearchParams'
|
||||||
import { Modal } from '@/shared/Modal/Modal'
|
import { Modal } from '@/shared/Modal/Modal'
|
||||||
import { MODAL_PARAMS_KEYS } from '@/types/modal'
|
import { MODAL_PARAMS_KEYS } from '@/types/modal'
|
||||||
import { call, getShortenNpub, getSignReqKind } from '@/utils/helpers/helpers'
|
import { call, getAppIconTitle, getShortenNpub, getSignReqKind } from '@/utils/helpers/helpers'
|
||||||
import { Avatar, Box, List, ListItem, ListItemIcon, ListItemText, Stack, Typography } from '@mui/material'
|
import { Avatar, Box, List, ListItem, ListItemIcon, ListItemText, Stack, Typography } from '@mui/material'
|
||||||
import { useParams, useSearchParams } from 'react-router-dom'
|
import { useParams, useSearchParams } from 'react-router-dom'
|
||||||
import { useAppSelector } from '@/store/hooks/redux'
|
import { useAppSelector } from '@/store/hooks/redux'
|
||||||
@@ -57,6 +57,7 @@ export const ModalConfirmEvent: FC<ModalConfirmEventProps> = ({ confirmEventReqs
|
|||||||
const triggerApp = apps.find((app) => app.appNpub === appNpub)
|
const triggerApp = apps.find((app) => app.appNpub === appNpub)
|
||||||
const { name, icon = '' } = triggerApp || {}
|
const { name, icon = '' } = triggerApp || {}
|
||||||
const appName = name || getShortenNpub(appNpub)
|
const appName = name || getShortenNpub(appNpub)
|
||||||
|
const appAvatarTitle = getAppIconTitle(name, appNpub)
|
||||||
|
|
||||||
const handleActionTypeChange = (_: any, value: ACTION_TYPE | null) => {
|
const handleActionTypeChange = (_: any, value: ACTION_TYPE | null) => {
|
||||||
if (!value) return undefined
|
if (!value) return undefined
|
||||||
@@ -118,7 +119,9 @@ export const ModalConfirmEvent: FC<ModalConfirmEventProps> = ({ confirmEventReqs
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal open={isModalOpened} withCloseButton={!isPopup} onClose={!isPopup ? handleCloseModal : undefined}>
|
<Modal title='Permission request' open={isModalOpened} withCloseButton={false}
|
||||||
|
// withCloseButton={!isPopup} onClose={!isPopup ? handleCloseModal : undefined}
|
||||||
|
>
|
||||||
<Stack gap={'1rem'} paddingTop={'1rem'}>
|
<Stack gap={'1rem'} paddingTop={'1rem'}>
|
||||||
<Stack direction={'row'} gap={'1rem'} alignItems={'center'} marginBottom={'1rem'}>
|
<Stack direction={'row'} gap={'1rem'} alignItems={'center'} marginBottom={'1rem'}>
|
||||||
<Avatar
|
<Avatar
|
||||||
@@ -129,13 +132,15 @@ export const ModalConfirmEvent: FC<ModalConfirmEventProps> = ({ confirmEventReqs
|
|||||||
borderRadius: '12px',
|
borderRadius: '12px',
|
||||||
}}
|
}}
|
||||||
src={icon}
|
src={icon}
|
||||||
/>
|
>
|
||||||
|
{appAvatarTitle}
|
||||||
|
</Avatar>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="h5" fontWeight={600}>
|
<Typography variant="h5" fontWeight={600}>
|
||||||
{appName}
|
{appName}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" color={'GrayText'}>
|
<Typography variant="body2" color={'GrayText'}>
|
||||||
Would like your permission to
|
App wants to perform these actions
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,19 +1,27 @@
|
|||||||
import React, { FC, ReactNode } from 'react'
|
import { FC, ReactNode } from 'react'
|
||||||
import { IconContainer, StyledContainer } from './styled'
|
import { IconContainer, StyledContainer } from './styled'
|
||||||
import { BoxProps, Typography } from '@mui/material'
|
import { BoxProps, Stack, Typography } from '@mui/material'
|
||||||
|
|
||||||
type WarningProps = {
|
type WarningProps = {
|
||||||
message: string | ReactNode
|
message?: string | ReactNode
|
||||||
Icon?: ReactNode
|
hint?: string | ReactNode
|
||||||
|
icon?: ReactNode
|
||||||
} & BoxProps
|
} & BoxProps
|
||||||
|
|
||||||
export const Warning: FC<WarningProps> = ({ message, Icon, ...restProps }) => {
|
export const Warning: FC<WarningProps> = ({ hint, message, icon, ...restProps }) => {
|
||||||
return (
|
return (
|
||||||
<StyledContainer {...restProps}>
|
<StyledContainer {...restProps}>
|
||||||
{Icon && <IconContainer>{Icon}</IconContainer>}
|
{icon && <IconContainer>{icon}</IconContainer>}
|
||||||
<Typography flex={1} noWrap>
|
<Stack flex={1} direction={'column'} gap={'0.2rem'}>
|
||||||
|
<Typography noWrap>
|
||||||
{message}
|
{message}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{hint && (
|
||||||
|
<Typography>
|
||||||
|
{hint}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const IconContainer = styled((props: BoxProps) => <Box {...props} />)(()
|
|||||||
width: '40px',
|
width: '40px',
|
||||||
height: '40px',
|
height: '40px',
|
||||||
borderRadius: '50%',
|
borderRadius: '50%',
|
||||||
background: 'blue',
|
background: 'grey',
|
||||||
display: 'grid',
|
display: 'grid',
|
||||||
placeItems: 'center',
|
placeItems: 'center',
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import NDK, {
|
|||||||
NDKPrivateKeySigner,
|
NDKPrivateKeySigner,
|
||||||
NDKSigner,
|
NDKSigner,
|
||||||
} from '@nostr-dev-kit/ndk'
|
} from '@nostr-dev-kit/ndk'
|
||||||
import { NOAUTHD_URL, WEB_PUSH_PUBKEY, NIP46_RELAYS, MIN_POW, MAX_POW, KIND_RPC } from '../utils/consts'
|
import { NOAUTHD_URL, WEB_PUSH_PUBKEY, NIP46_RELAYS, MIN_POW, MAX_POW, KIND_RPC, DOMAIN } from '../utils/consts'
|
||||||
import { Nip04 } from './nip04'
|
import { Nip04 } from './nip04'
|
||||||
import { getReqPerm, getShortenNpub, isPackagePerm } from '@/utils/helpers/helpers'
|
import { fetchNip05, getReqPerm, getShortenNpub, isPackagePerm } from '@/utils/helpers/helpers'
|
||||||
import { NostrPowEvent, minePow } from './pow'
|
import { NostrPowEvent, minePow } from './pow'
|
||||||
//import { PrivateKeySigner } from './signer'
|
//import { PrivateKeySigner } from './signer'
|
||||||
|
|
||||||
@@ -225,7 +225,7 @@ export class NoauthBackend {
|
|||||||
|
|
||||||
public setNotifCallback(cb: () => void) {
|
public setNotifCallback(cb: () => void) {
|
||||||
if (this.notifCallback) {
|
if (this.notifCallback) {
|
||||||
this.notify()
|
// this.notify()
|
||||||
}
|
}
|
||||||
this.notifCallback = cb
|
this.notifCallback = cb
|
||||||
}
|
}
|
||||||
@@ -246,6 +246,13 @@ export class NoauthBackend {
|
|||||||
return Buffer.from(await this.swg.crypto.subtle.digest('SHA-256', Buffer.from(s))).toString('hex')
|
return Buffer.from(await this.swg.crypto.subtle.digest('SHA-256', Buffer.from(s))).toString('hex')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async fetchNpubName(npub: string) {
|
||||||
|
const url = `${NOAUTHD_URL}/name?npub=${npub}`
|
||||||
|
const r = await fetch(url)
|
||||||
|
const d = await r.json()
|
||||||
|
return d?.names?.length ? d.names[0] as string : ''
|
||||||
|
}
|
||||||
|
|
||||||
private async sendPost({ url, method, headers, body }: { url: string; method: string; headers: any; body: string }) {
|
private async sendPost({ url, method, headers, body }: { url: string; method: string; headers: any; body: string }) {
|
||||||
const r = await fetch(url, {
|
const r = await fetch(url, {
|
||||||
method,
|
method,
|
||||||
@@ -559,6 +566,12 @@ export class NoauthBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const appNpub = nip19.npubEncode(remotePubkey)
|
const appNpub = nip19.npubEncode(remotePubkey)
|
||||||
|
const connected = !!this.apps.find(a => a.appNpub === appNpub)
|
||||||
|
if (!connected && method !== 'connect') {
|
||||||
|
console.log('ignoring request before connect', method, id, appNpub, npub)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
const req: DbPending = {
|
const req: DbPending = {
|
||||||
id,
|
id,
|
||||||
npub,
|
npub,
|
||||||
@@ -574,12 +587,13 @@ export class NoauthBackend {
|
|||||||
const onAllow = async (manual: boolean, allow: boolean, remember: boolean, options?: any) => {
|
const onAllow = async (manual: boolean, allow: boolean, remember: boolean, options?: any) => {
|
||||||
// confirm
|
// confirm
|
||||||
console.log(Date.now(), allow ? 'allowed' : 'disallowed', npub, method, options, params)
|
console.log(Date.now(), allow ? 'allowed' : 'disallowed', npub, method, options, params)
|
||||||
|
|
||||||
if (manual) {
|
if (manual) {
|
||||||
await dbi.confirmPending(id, allow)
|
await dbi.confirmPending(id, allow)
|
||||||
|
|
||||||
if (!(method === 'connect' && !allow)) {
|
// add app on 'allow connect'
|
||||||
// only add app if it's not 'disallow connect'
|
if (method === 'connect' && allow) {
|
||||||
if (!(await dbi.getApp(req.appNpub))) {
|
// if (!(await dbi.getApp(req.appNpub))) {
|
||||||
await dbi.addApp({
|
await dbi.addApp({
|
||||||
appNpub: req.appNpub,
|
appNpub: req.appNpub,
|
||||||
npub: req.npub,
|
npub: req.npub,
|
||||||
@@ -592,7 +606,6 @@ export class NoauthBackend {
|
|||||||
// reload
|
// reload
|
||||||
self.apps = await dbi.listApps()
|
self.apps = await dbi.listApps()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// just send to db w/o waiting for it
|
// just send to db w/o waiting for it
|
||||||
dbi.addConfirmed({
|
dbi.addConfirmed({
|
||||||
@@ -612,7 +625,8 @@ export class NoauthBackend {
|
|||||||
let newPerms = [getReqPerm(req)]
|
let newPerms = [getReqPerm(req)]
|
||||||
if (allow && options && options.perms) newPerms = options.perms
|
if (allow && options && options.perms) newPerms = options.perms
|
||||||
|
|
||||||
for (const p of newPerms)
|
// write new perms confirmed by user
|
||||||
|
for (const p of newPerms) {
|
||||||
await dbi.addPerm({
|
await dbi.addPerm({
|
||||||
id: req.id,
|
id: req.id,
|
||||||
npub: req.npub,
|
npub: req.npub,
|
||||||
@@ -621,13 +635,17 @@ export class NoauthBackend {
|
|||||||
value: allow ? '1' : '0',
|
value: allow ? '1' : '0',
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// reload
|
||||||
this.perms = await dbi.listPerms()
|
this.perms = await dbi.listPerms()
|
||||||
|
|
||||||
|
// confirm pending requests that might now have
|
||||||
|
// the proper perms
|
||||||
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)
|
console.log('updated perms', this.perms, 'otherReqs', otherReqs, 'connected', connected)
|
||||||
for (const r of otherReqs) {
|
for (const r of otherReqs) {
|
||||||
const perm = this.getPerm(r.req)
|
let perm = this.getPerm(r.req)
|
||||||
if (perm) {
|
if (perm) {
|
||||||
r.cb(perm === '1', false)
|
r.cb(perm === '1', false)
|
||||||
}
|
}
|
||||||
@@ -675,7 +693,7 @@ export class NoauthBackend {
|
|||||||
backend.rpc.sendResponse(id, remotePubkey, 'auth_url', KIND_RPC, authUrl)
|
backend.rpc.sendResponse(id, remotePubkey, 'auth_url', KIND_RPC, authUrl)
|
||||||
|
|
||||||
// show notifs
|
// show notifs
|
||||||
this.notify()
|
// this.notify()
|
||||||
|
|
||||||
// notify main thread to ask for user concent
|
// notify main thread to ask for user concent
|
||||||
this.updateUI()
|
this.updateUI()
|
||||||
@@ -793,7 +811,7 @@ export class NoauthBackend {
|
|||||||
await this.sendKeyToServer(npub, enckey, pwh)
|
await this.sendKeyToServer(npub, enckey, pwh)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async fetchKey(npub: string, passphrase: string, name: string) {
|
private async fetchKey(npub: string, passphrase: string, nip05: string) {
|
||||||
const { type, data: pubkey } = nip19.decode(npub)
|
const { type, data: pubkey } = nip19.decode(npub)
|
||||||
if (type !== 'npub') throw new Error(`Invalid npub ${npub}`)
|
if (type !== 'npub') throw new Error(`Invalid npub ${npub}`)
|
||||||
const { pwh } = await this.keysModule.generatePassKey(pubkey, passphrase)
|
const { pwh } = await this.keysModule.generatePassKey(pubkey, passphrase)
|
||||||
@@ -803,13 +821,50 @@ export class NoauthBackend {
|
|||||||
const key = this.enckeys.find((k) => k.npub === npub)
|
const key = this.enckeys.find((k) => k.npub === npub)
|
||||||
if (key) return this.keyInfo(key)
|
if (key) return this.keyInfo(key)
|
||||||
|
|
||||||
|
let name = ''
|
||||||
|
let existingName = true
|
||||||
|
// check name - user might have provided external nip05,
|
||||||
|
// or just his npub - we must fetch their name from our
|
||||||
|
// server, and if not exists - try to assign one
|
||||||
|
const npubName = await this.fetchNpubName(npub)
|
||||||
|
if (npubName) {
|
||||||
|
// already have name for this npub
|
||||||
|
console.log("existing npub name", npub, npubName)
|
||||||
|
name = npubName
|
||||||
|
} else if (nip05.includes('@')) {
|
||||||
|
// no name for them?
|
||||||
|
const [nip05name, domain] = nip05.split('@')
|
||||||
|
if (domain === DOMAIN) {
|
||||||
|
// wtf? how did we learn their npub if
|
||||||
|
// it's the name on our server but we can't fetch it?
|
||||||
|
console.log("existing name", nip05name)
|
||||||
|
name = nip05name
|
||||||
|
} else {
|
||||||
|
// try to take same name on our domain
|
||||||
|
existingName = false
|
||||||
|
name = nip05name
|
||||||
|
let takenName = await fetchNip05(`${name}@${DOMAIN}`)
|
||||||
|
if (takenName) {
|
||||||
|
// already taken? try name_domain as name
|
||||||
|
name = `${nip05name}_${domain}`
|
||||||
|
takenName = await fetchNip05(`${name}@${DOMAIN}`)
|
||||||
|
}
|
||||||
|
if (takenName) {
|
||||||
|
console.log("All names taken, leave without a name?")
|
||||||
|
name = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("fetch", { name, existingName })
|
||||||
|
|
||||||
// add new key
|
// add new key
|
||||||
const nsec = await this.keysModule.decryptKeyPass({
|
const nsec = await this.keysModule.decryptKeyPass({
|
||||||
pubkey,
|
pubkey,
|
||||||
enckey,
|
enckey,
|
||||||
passphrase,
|
passphrase,
|
||||||
})
|
})
|
||||||
const k = await this.addKey({ name, nsec, existingName: true })
|
const k = await this.addKey({ name, nsec, existingName })
|
||||||
this.updateUI()
|
this.updateUI()
|
||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import { Warning } from '@/components/Warning/Warning'
|
import { Warning } from '@/components/Warning/Warning'
|
||||||
import { CircularProgress, Stack } from '@mui/material'
|
import { CircularProgress, Stack, Typography } from '@mui/material'
|
||||||
import GppMaybeIcon from '@mui/icons-material/GppMaybe'
|
import AutoModeOutlinedIcon from '@mui/icons-material/AutoModeOutlined'
|
||||||
|
|
||||||
type BackgroundSigningWarningProps = {
|
type BackgroundSigningWarningProps = {
|
||||||
isEnabling: boolean
|
isEnabling: boolean
|
||||||
@@ -13,10 +13,16 @@ export const BackgroundSigningWarning: FC<BackgroundSigningWarningProps> = ({ is
|
|||||||
<Warning
|
<Warning
|
||||||
message={
|
message={
|
||||||
<Stack direction={'row'} alignItems={'center'} gap={'1rem'}>
|
<Stack direction={'row'} alignItems={'center'} gap={'1rem'}>
|
||||||
Please enable push notifications {isEnabling ? <CircularProgress size={'1.5rem'} /> : null}
|
Enable background service {isEnabling ? <CircularProgress size={'1.5rem'} /> : null}
|
||||||
</Stack>
|
</Stack>
|
||||||
}
|
}
|
||||||
Icon={<GppMaybeIcon htmlColor="white" />}
|
hint={
|
||||||
|
<Typography variant='body2'>
|
||||||
|
Please allow notifications
|
||||||
|
for background operation.
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
icon={<AutoModeOutlinedIcon htmlColor="white" />}
|
||||||
onClick={isEnabling ? undefined : onEnableBackSigning}
|
onClick={isEnabling ? undefined : onEnableBackSigning}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const useBackgroundSigning = () => {
|
|||||||
await askNotificationPermission()
|
await askNotificationPermission()
|
||||||
const result = await swicCall('enablePush')
|
const result = await swicCall('enablePush')
|
||||||
if (!result) throw new Error('Failed to activate the push subscription')
|
if (!result) throw new Error('Failed to activate the push subscription')
|
||||||
notify('Push notifications enabled!', 'success')
|
notify('Background service enabled!', 'success')
|
||||||
setShowWarning(false)
|
setShowWarning(false)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
notify(`Failed to enable push subscription: ${error}`, 'error')
|
notify(`Failed to enable push subscription: ${error}`, 'error')
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ export const getShortenNpub = (npub = '') => {
|
|||||||
return npub.substring(0, 10) + '...' + npub.slice(-4)
|
return npub.substring(0, 10) + '...' + npub.slice(-4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getAppIconTitle = (name: string | undefined, appNpub: string) => {
|
||||||
|
return name
|
||||||
|
? name[0].toLocaleUpperCase()
|
||||||
|
: appNpub.substring(4, 7);
|
||||||
|
}
|
||||||
|
|
||||||
export const getProfileUsername = (profile: MetaEvent | null, npub: string) => {
|
export const getProfileUsername = (profile: MetaEvent | null, npub: string) => {
|
||||||
return profile?.info?.name || profile?.info?.display_name || getShortenNpub(npub)
|
return profile?.info?.name || profile?.info?.display_name || getShortenNpub(npub)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user