diff --git a/src/components/AppBar/AppBar.tsx b/src/components/AppBar/AppBar.tsx
index b392d9a..78f4f01 100644
--- a/src/components/AppBar/AppBar.tsx
+++ b/src/components/AppBar/AppBar.tsx
@@ -10,24 +10,17 @@ import {
import { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
-import {
- setAuthState,
- setMetadataEvent,
- userLogOutAction
-} from '../../store/actions'
+import { setAuthState, setMetadataEvent } from '../../store/actions'
import { State } from '../../store/rootReducer'
import { Dispatch } from '../../store/store'
import Username from '../username'
import { Link, useNavigate } from 'react-router-dom'
import { MetadataController, NostrController } from '../../controllers'
-import {
- appPublicRoutes,
- appPrivateRoutes,
- getProfileRoute
-} from '../../routes'
+import { appPublicRoutes, getProfileRoute } from '../../routes'
import {
clearAuthToken,
+ clearState,
saveNsecBunkerDelegatedKey,
shorten
} from '../../utils'
@@ -99,8 +92,7 @@ export const AppBar = () => {
// clear authToken saved in local storage
clearAuthToken()
-
- dispatch(userLogOutAction())
+ clearState()
// update nsecBunker delegated key after logout
const nostrController = NostrController.getInstance()
@@ -168,16 +160,6 @@ export const AppBar = () => {
>
Profile
-
{
if (res.status === 'rejected') {
failedPublishes.push({
relay: relays[index],
- error: res.reason
- ? res.reason.message || fallbackRejectionReason
- : fallbackRejectionReason
+ error: res.reason.message
})
}
})
@@ -402,359 +374,4 @@ export class NostrController extends EventEmitter {
generateDelegatedKey = (): string => {
return NDKPrivateKeySigner.generate().privateKey!
}
-
- /**
- * Provides relay map.
- * @param npub - user's npub
- * @returns - promise that resolves into relay map and a timestamp when it has been updated.
- */
- getRelayMap = async (
- npub: string
- ): Promise<{ map: RelayMap; mapUpdated: number }> => {
- const mostPopularRelays = await this.getMostPopularRelays()
-
- const pool = new SimplePool()
-
- // More info about this kind of event available https://github.com/nostr-protocol/nips/blob/master/65.md
- const eventFilter: Filter = {
- kinds: [kinds.RelayList],
- authors: [npub]
- }
-
- const event = await pool
- .get(mostPopularRelays, eventFilter)
- .catch((err) => {
- return Promise.reject(err)
- })
-
- if (event) {
- // Handle founded 10002 event
- const relaysMap: RelayMap = {}
-
- // 'r' stands for 'relay'
- const relayTags = event.tags.filter((tag) => tag[0] === 'r')
-
- relayTags.forEach((tag) => {
- const uri = tag[1]
- const relayType = tag[2]
-
- // if 3rd element of relay tag is undefined, relay is WRITE and READ
- relaysMap[uri] = {
- write: relayType ? relayType === 'write' : true,
- read: relayType ? relayType === 'read' : true
- }
- })
-
- this.getRelayInfo(Object.keys(relaysMap))
-
- this.connectToRelays(Object.keys(relaysMap))
-
- return Promise.resolve({ map: relaysMap, mapUpdated: event.created_at })
- } else {
- return Promise.reject('User relays were not found.')
- }
- }
-
- /**
- * Publishes relay map.
- * @param relayMap - relay map.
- * @param npub - user's npub.
- * @param extraRelaysToPublish - optional relays to publish relay map.
- * @returns - promise that resolves into a string representing publishing result.
- */
- publishRelayMap = async (
- relayMap: RelayMap,
- npub: string,
- extraRelaysToPublish?: string[]
- ): Promise => {
- const timestamp = Math.floor(Date.now() / 1000)
- const relayURIs = Object.keys(relayMap)
-
- // More info about this kind of event available https://github.com/nostr-protocol/nips/blob/master/65.md
- const tags: string[][] = relayURIs.map((relayURI) =>
- [
- 'r',
- relayURI,
- relayMap[relayURI].read && relayMap[relayURI].write
- ? ''
- : relayMap[relayURI].write
- ? 'write'
- : 'read'
- ].filter((value) => value !== '')
- )
-
- const newRelayMapEvent: UnsignedEvent = {
- kind: kinds.RelayList,
- tags,
- content: '',
- pubkey: npub,
- created_at: timestamp
- }
-
- const signedEvent = await this.signEvent(newRelayMapEvent)
-
- let relaysToPublish = relayURIs
-
- // Add extra relays if provided
- if (extraRelaysToPublish) {
- relaysToPublish = [...relaysToPublish, ...extraRelaysToPublish]
- }
-
- // If relay map is empty, use most popular relay URIs
- if (!relaysToPublish.length) {
- relaysToPublish = await this.getMostPopularRelays()
- }
-
- const publishResult = await this.publishEvent(signedEvent, relaysToPublish)
-
- if (publishResult && publishResult.length) {
- return Promise.resolve(
- `Relay Map published on: ${publishResult.join('\n')}`
- )
- }
-
- return Promise.reject('Publishing updated relay map was unsuccessful.')
- }
-
- /**
- * Provides most popular relays.
- * @param numberOfTopRelays - number representing how many most popular relays to provide
- * @returns - promise that resolves into an array of most popular relays
- */
- getMostPopularRelays = async (
- numberOfTopRelays: number = 30
- ): Promise => {
- const mostPopularRelaysState = store.getState().relays?.mostPopular
-
- // return most popular relays from app state if present
- if (mostPopularRelaysState) return mostPopularRelaysState
-
- // relays in env
- const { VITE_MOST_POPULAR_RELAYS } = import.meta.env
- const hardcodedPopularRelays = (VITE_MOST_POPULAR_RELAYS || '').split(' ')
- const url = `https://stats.nostr.band/stats_api?method=stats`
-
- const response = await axios.get(url).catch(() => undefined)
-
- if (!response) {
- return hardcodedPopularRelays //return hardcoded relay list
- }
-
- const data = response.data
-
- if (!data) {
- return hardcodedPopularRelays //return hardcoded relay list
- }
-
- const apiTopRelays = data.relay_stats.user_picks.read_relays
- .slice(0, numberOfTopRelays)
- .map((relay: ReadRelay) => relay.d)
-
- if (!apiTopRelays.length) {
- return Promise.reject(`Couldn't fetch popular relays.`)
- }
-
- if (store.getState().auth?.loggedIn) {
- store.dispatch(setMostPopularRelaysAction(apiTopRelays))
- }
-
- return apiTopRelays
- }
-
- /**
- * Sets information about relays into relays.info app state.
- * @param relayURIs - relay URIs to get information about
- */
- getRelayInfo = async (relayURIs: string[]) => {
- // initialize job request
- const jobEventTemplate: EventTemplate = {
- content: '',
- created_at: Math.round(Date.now() / 1000),
- kind: 68001,
- tags: [
- ['i', `${JSON.stringify(relayURIs)}`],
- ['j', 'relay-info']
- ]
- }
-
- // sign job request event
- const jobSignedEvent = await this.signEvent(jobEventTemplate)
-
- const relays = [
- 'wss://relay.damus.io',
- 'wss://relay.primal.net',
- 'wss://relayable.org'
- ]
-
- // publish job request
- await this.publishEvent(jobSignedEvent, relays)
-
- console.log('jobSignedEvent :>> ', jobSignedEvent)
-
- const subscribeWithTimeout = (
- subscription: NDKSubscription,
- timeoutMs: number
- ): Promise => {
- return new Promise((resolve, reject) => {
- const eventHandler = (event: NDKEvent) => {
- subscription.stop()
- resolve(event.content)
- }
-
- subscription.on('event', eventHandler)
-
- // Set up a timeout to stop the subscription after a specified time
- const timeout = setTimeout(() => {
- subscription.stop() // Stop the subscription
- reject(new Error('Subscription timed out')) // Reject the promise with a timeout error
- }, timeoutMs)
-
- // Handle subscription close event
- subscription.on('close', () => clearTimeout(timeout))
- })
- }
-
- const dvmNDK = new NDK({
- explicitRelayUrls: relays
- })
-
- await dvmNDK.connect(2000)
-
- // filter for getting DVM job's result
- const sub = dvmNDK.subscribe({
- kinds: [68002 as number],
- '#e': [jobSignedEvent.id],
- '#p': [jobSignedEvent.pubkey]
- })
-
- // asynchronously get block number from dvm job with 20 seconds timeout
- const dvmJobResult = await subscribeWithTimeout(sub, 20000)
-
- if (!dvmJobResult) {
- return Promise.reject(`Relay(s) information wasn't received`)
- }
-
- let relaysInfo: RelayInfoObject
-
- try {
- relaysInfo = JSON.parse(dvmJobResult)
- } catch (error) {
- return Promise.reject(`Invalid relay(s) information.`)
- }
-
- if (
- relaysInfo &&
- !compareObjects(store.getState().relays?.info, relaysInfo)
- ) {
- store.dispatch(setRelayInfoAction(relaysInfo))
- }
- }
-
- /**
- * Establishes connection to relays.
- * @param relayURIs - an array of relay URIs
- * @returns - promise that resolves into an array of connections
- */
- connectToRelays = async (relayURIs: string[]) => {
- // Copy of relay connection status
- const relayConnectionsStatus: RelayConnectionStatus = JSON.parse(
- JSON.stringify(store.getState().relays?.connectionStatus || {})
- )
-
- const connectedRelayURLs = this.connectedRelays
- ? this.connectedRelays.map((relay) => relay.url)
- : []
-
- // Check if connections already established
- if (compareObjects(connectedRelayURLs, relayURIs)) {
- return
- }
-
- const connections = relayURIs
- .filter((relayURI) => !connectedRelayURLs.includes(relayURI))
- .map((relayURI) =>
- Relay.connect(relayURI)
- .then((relay) => {
- // put connection status into relayConnectionsStatus object
- relayConnectionsStatus[relayURI] = relay.connected
- ? RelayConnectionState.Connected
- : RelayConnectionState.NotConnected
-
- return relay
- })
- .catch(() => {
- relayConnectionsStatus[relayURI] = RelayConnectionState.NotConnected
- })
- )
-
- const connected = await Promise.all(connections)
-
- // put connected relays into connectedRelays private property, so it can be closed later
- this.connectedRelays = connected.filter(
- (relay) => relay instanceof Relay && relay.connected
- ) as Relay[]
-
- if (Object.keys(relayConnectionsStatus)) {
- if (
- !compareObjects(
- store.getState().relays?.connectionStatus,
- relayConnectionsStatus
- )
- ) {
- store.dispatch(setRelayConnectionStatusAction(relayConnectionsStatus))
- }
- }
-
- return Promise.resolve(relayConnectionsStatus)
- }
-
- /**
- * Disconnects from relays.
- * @param relayURIs - array of relay URIs to disconnect from
- */
- disconnectFromRelays = async (relayURIs: string[]) => {
- const connectedRelayURLs = this.connectedRelays
- ? this.connectedRelays.map((relay) => relay.url)
- : []
-
- relayURIs
- .filter((relayURI) => connectedRelayURLs.includes(relayURI))
- .forEach((relayURI) => {
- if (this.connectedRelays) {
- const relay = this.connectedRelays.find(
- (relay) => relay.url === relayURI
- )
-
- if (relay) {
- // close relay connection
- relay.close()
-
- // remove relay from connectedRelays property
- this.connectedRelays = this.connectedRelays.filter(
- (relay) => relay.url !== relayURI
- )
- }
- }
- })
-
- if (store.getState().relays?.connectionStatus) {
- const connectionStatus = JSON.parse(
- JSON.stringify(store.getState().relays?.connectionStatus)
- )
-
- relayURIs.forEach((relay) => {
- delete connectionStatus[relay]
- })
-
- if (
- !compareObjects(
- store.getState().relays?.connectionStatus,
- connectionStatus
- )
- ) {
- // Update app state
- store.dispatch(setRelayConnectionStatusAction(connectionStatus))
- }
- }
- }
}
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
deleted file mode 100644
index 16c8633..0000000
--- a/src/hooks/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './store'
diff --git a/src/hooks/store.ts b/src/hooks/store.ts
deleted file mode 100644
index f3e9b21..0000000
--- a/src/hooks/store.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { useDispatch, useSelector } from 'react-redux'
-import type { Dispatch, RootState } from '../store/store'
-
-// Use instead of plain `useDispatch` and `useSelector`
-export const useAppDispatch = useDispatch.withTypes()
-export const useAppSelector = useSelector.withTypes()
diff --git a/src/main.tsx b/src/main.tsx
index 135d197..d586217 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -15,8 +15,7 @@ store.subscribe(
saveState({
auth: store.getState().auth,
metadata: store.getState().metadata,
- userRobotImage: store.getState().userRobotImage,
- relays: store.getState().relays
+ userRobotImage: store.getState().userRobotImage
})
}, 1000)
)
diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx
index cd3d606..8c2f702 100644
--- a/src/pages/login/index.tsx
+++ b/src/pages/login/index.tsx
@@ -80,7 +80,7 @@ export const Login = () => {
setLoadingSpinnerDesc('Authenticating and finding metadata')
const redirectPath =
- await authController.authAndGetMetadataAndRelaysMap(pubkey)
+ await authController.authenticateAndFindMetadata(pubkey)
navigateAfterLogin(redirectPath)
})
@@ -134,7 +134,7 @@ export const Login = () => {
setLoadingSpinnerDesc('Authenticating and finding metadata')
const redirectPath = await authController
- .authAndGetMetadataAndRelaysMap(publickey)
+ .authenticateAndFindMetadata(publickey)
.catch((err) => {
toast.error('Error occurred in authentication: ' + err)
return null
@@ -229,7 +229,7 @@ export const Login = () => {
setLoadingSpinnerDesc('Authenticating and finding metadata')
const redirectPath = await authController
- .authAndGetMetadataAndRelaysMap(pubkey!)
+ .authenticateAndFindMetadata(pubkey!)
.catch((err) => {
toast.error('Error occurred in authentication: ' + err)
return null
@@ -289,7 +289,7 @@ export const Login = () => {
setLoadingSpinnerDesc('Authenticating and finding metadata')
const redirectPath = await authController
- .authAndGetMetadataAndRelaysMap(pubkey!)
+ .authenticateAndFindMetadata(pubkey!)
.catch((err) => {
toast.error('Error occurred in authentication: ' + err)
return null
diff --git a/src/pages/relays/index.tsx b/src/pages/relays/index.tsx
deleted file mode 100644
index 010d24d..0000000
--- a/src/pages/relays/index.tsx
+++ /dev/null
@@ -1,512 +0,0 @@
-import { useEffect, useState } from 'react'
-import { Box, List, ListItem, TextField } from '@mui/material'
-import RouterIcon from '@mui/icons-material/Router'
-import styles from './style.module.scss'
-import Switch from '@mui/material/Switch'
-import ListItemText from '@mui/material/ListItemText'
-import Divider from '@mui/material/Divider'
-import { NostrController } from '../../controllers'
-import {
- RelayMap,
- RelayInfoObject,
- RelayFee,
- RelayConnectionState
-} from '../../types'
-import LogoutIcon from '@mui/icons-material/Logout'
-import { useAppSelector, useAppDispatch } from '../../hooks'
-import {
- compareObjects,
- shorten,
- hexToNpub,
- capitalizeFirstLetter
-} from '../../utils'
-import {
- setRelayMapAction,
- setRelayMapUpdatedAction
-} from '../../store/actions'
-import { toast } from 'react-toastify'
-import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'
-import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'
-import ContentCopyIcon from '@mui/icons-material/ContentCopy'
-import ElectricBoltIcon from '@mui/icons-material/ElectricBolt'
-import { Tooltip } from '@mui/material'
-import InputAdornment from '@mui/material/InputAdornment'
-import Button from '@mui/material/Button'
-
-export const RelaysPage = () => {
- const nostrController = NostrController.getInstance()
-
- const relaysState = useAppSelector((state) => state.relays)
- const usersPubkey = useAppSelector((state) => state.auth?.usersPubkey)
-
- const dispatch = useAppDispatch()
-
- const [newRelayURI, setNewRelayURI] = useState()
- const [newRelayURIerror, setNewRelayURIerror] = useState()
- const [relayMap, setRelayMap] = useState(
- relaysState?.map
- )
- const [relaysInfo, setRelaysInfo] = useState(
- relaysState?.info
- )
- const [displayRelaysInfo, setDisplayRelaysInfo] = useState([])
- const [relaysConnectionStatus, setRelaysConnectionStatus] = useState(
- relaysState?.connectionStatus
- )
-
- const webSocketPrefix = 'wss://'
-
- // Update relay connection status
- useEffect(() => {
- if (
- !compareObjects(relaysConnectionStatus, relaysState?.connectionStatus)
- ) {
- setRelaysConnectionStatus(relaysState?.connectionStatus)
- }
- }, [relaysConnectionStatus, relaysState?.connectionStatus])
-
- useEffect(() => {
- if (!compareObjects(relaysInfo, relaysState?.info)) {
- setRelaysInfo(relaysState?.info)
- }
- }, [relaysInfo, relaysState?.info])
-
- useEffect(() => {
- let isMounted = false
-
- const fetchData = async () => {
- if (usersPubkey) {
- isMounted = true
-
- // call async func to fetch relay map
- const newRelayMap = await nostrController.getRelayMap(usersPubkey)
-
- // handle fetched relay map
- if (isMounted) {
- if (
- !relaysState?.mapUpdated ||
- newRelayMap.mapUpdated > relaysState?.mapUpdated
- ) {
- if (
- !relaysState?.map ||
- !compareObjects(relaysState.map, newRelayMap)
- ) {
- setRelayMap(newRelayMap.map)
-
- dispatch(setRelayMapAction(newRelayMap.map))
- } else {
- // Update relay map updated timestamp
- dispatch(setRelayMapUpdatedAction())
- }
- }
- }
- }
- }
-
- // Publishing relay map can take some time.
- // This is why data fetch should happen only if relay map was received more than 5 minutes ago.
- if (
- usersPubkey &&
- (!relaysState?.mapUpdated ||
- Date.now() - relaysState?.mapUpdated > 5 * 60 * 1000) // 5 minutes
- ) {
- fetchData()
-
- // Update relay connection status
- if (relaysConnectionStatus) {
- const notConnectedRelays = Object.keys(relaysConnectionStatus).filter(
- (key) =>
- relaysConnectionStatus[key] === RelayConnectionState.NotConnected
- )
-
- if (notConnectedRelays.length) {
- nostrController.connectToRelays(notConnectedRelays)
- }
- }
- }
-
- // cleanup func
- return () => {
- isMounted = false
- }
- }, [
- dispatch,
- usersPubkey,
- relaysState?.map,
- relaysState?.mapUpdated,
- nostrController,
- relaysConnectionStatus
- ])
-
- useEffect(() => {
- // Display notification if an empty relay map has been received
- if (relayMap && Object.keys(relayMap).length === 0) {
- relayRequirementWarning()
- }
- }, [relayMap])
-
- const relayRequirementWarning = () =>
- toast.warning('At least one write relay is needed for SIGit to work.')
-
- const handleLeaveRelay = async (relay: string) => {
- if (relayMap) {
- const relaysInMap = Object.keys(relayMap).length
- const writeRelays = Object.keys(relayMap).filter(
- (key) => relayMap[key].write
- )
-
- // Check if at least one write relay is present in relay map
- if (
- relaysInMap <= 1 ||
- (writeRelays.length === 1 && writeRelays.includes(relay))
- ) {
- relayRequirementWarning()
- } else {
- const relayMapCopy = JSON.parse(JSON.stringify(relayMap))
- // Remove relay from relay map
- delete relayMapCopy[relay]
-
- if (usersPubkey) {
- // Publish updated relay map.
- const relayMapPublishingRes = await nostrController
- .publishRelayMap(relayMapCopy, usersPubkey, [relay])
- .catch((err) => handlePublishRelayMapError(err))
-
- if (relayMapPublishingRes) {
- toast.success(relayMapPublishingRes)
-
- setRelayMap(relayMapCopy)
-
- dispatch(setRelayMapAction(relayMapCopy))
- }
- }
-
- nostrController.disconnectFromRelays([relay])
- }
- }
- }
-
- const handlePublishRelayMapError = (err: any) => {
- const errorPrefix = 'Error while publishing Relay Map'
-
- if (Array.isArray(err)) {
- err.forEach((errorObj: { relay: string; error: string }) => {
- toast.error(
- `${errorPrefix} to ${errorObj.relay}. Error: ${errorObj.error || 'Unknown'}`
- )
- })
- } else {
- toast.error(`${errorPrefix}. Error: ${err.message || 'Unknown'}`)
- }
- }
-
- const handleRelayWriteChange = async (
- relay: string,
- event: React.ChangeEvent
- ) => {
- if (relayMap && relayMap[relay]) {
- if (
- !event.target.checked &&
- Object.keys(relayMap).filter((relay) => relayMap[relay].write)
- .length === 1
- ) {
- relayRequirementWarning()
- } else {
- const relayMapCopy = JSON.parse(JSON.stringify(relayMap))
- relayMapCopy[relay].write = event.target.checked
-
- if (usersPubkey) {
- // Publish updated relay map
- const relayMapPublishingRes = await nostrController
- .publishRelayMap(relayMapCopy, usersPubkey)
- .catch((err) => handlePublishRelayMapError(err))
-
- if (relayMapPublishingRes) {
- toast.success(relayMapPublishingRes)
-
- setRelayMap(relayMapCopy)
-
- dispatch(setRelayMapAction(relayMapCopy))
- }
- }
- }
- }
- }
-
- const handleAddNewRelay = async () => {
- const relayURI = `${webSocketPrefix}${newRelayURI?.trim().replace(webSocketPrefix, '')}`
-
- // Check if new relay URI is a valid string
- if (
- relayURI &&
- !/^wss:\/\/[-a-zA-Z0-9@:%._\\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}/.test(
- relayURI
- )
- ) {
- if (relayURI !== webSocketPrefix) {
- setNewRelayURIerror(
- 'New relay URI is not valid. Example of valid relay URI: wss://sigit.relay.io'
- )
- }
- } else if (relayURI && usersPubkey) {
- const connectionStatus = await nostrController.connectToRelays([relayURI])
-
- if (
- connectionStatus &&
- connectionStatus[relayURI] &&
- connectionStatus[relayURI] === RelayConnectionState.Connected
- ) {
- const relayMapCopy = JSON.parse(JSON.stringify(relayMap))
-
- relayMapCopy[relayURI] = { write: true, read: true }
-
- // Publish updated relay map
- const relayMapPublishingRes = await nostrController
- .publishRelayMap(relayMapCopy, usersPubkey)
- .catch((err) => handlePublishRelayMapError(err))
-
- if (relayMapPublishingRes) {
- setRelayMap(relayMapCopy)
- setNewRelayURI('')
-
- dispatch(setRelayMapAction(relayMapCopy))
-
- nostrController.getRelayInfo([relayURI])
-
- toast.success(relayMapPublishingRes)
- }
-
- setNewRelayURIerror(undefined)
- } else {
- toast.error(`Relay '${relayURI}' wasn't added.`)
-
- setNewRelayURIerror(`Connection to '${relayURI}' was unsuccessful.`)
- }
- }
- }
-
- // Handle relay open and close state
- const handleRelayInfo = (relay: string) => {
- if (relaysInfo) {
- const info = relaysInfo[relay]
-
- if (info) {
- let displayRelaysInfoCopy: string[] = JSON.parse(
- JSON.stringify(displayRelaysInfo)
- )
-
- if (displayRelaysInfoCopy.includes(relay)) {
- displayRelaysInfoCopy = displayRelaysInfoCopy.filter(
- (rel) => rel !== relay
- )
- } else {
- displayRelaysInfoCopy.push(relay)
- }
-
- setDisplayRelaysInfo(displayRelaysInfoCopy)
- }
- }
- }
-
- return (
-
-
- setNewRelayURI(e.target.value)}
- helperText={newRelayURIerror}
- error={!!newRelayURIerror}
- InputProps={{
- startAdornment: (
-
- {webSocketPrefix}
-
- )
- }}
- className={styles.relayURItextfield}
- />
-
-
-
-
- YOUR RELAYS
-
- {relayMap && (
-
- {Object.keys(relayMap).map((relay, i) => (
-
-
-
-
- {relaysInfo &&
- relaysInfo[relay] &&
- relaysInfo[relay].limitation &&
- relaysInfo[relay].limitation?.payment_required && (
-
- handleRelayInfo(relay)}
- />
-
- )}
-
-
-
- handleLeaveRelay(relay)}
- >
-
- Leave
-
-
-
-
- handleRelayInfo(relay)}
- className={styles.showInfo}
- >
- Show info{' '}
- {displayRelaysInfo.includes(relay) ? (
-
- ) : (
-
- )}
-
- ) : (
- ''
- )
- }
- />
- handleRelayWriteChange(relay, event)}
- />
-
- {displayRelaysInfo.includes(relay) && (
- <>
-
-
-
- {relaysInfo &&
- relaysInfo[relay] &&
- Object.keys(relaysInfo[relay]).map((key: string) => {
- const infoTitle = capitalizeFirstLetter(
- key.replace('_', ' ')
- )
- let infoValue = (relaysInfo[relay] as any)[key]
-
- switch (key) {
- case 'pubkey':
- infoValue = shorten(hexToNpub(infoValue), 15)
-
- break
-
- case 'limitation':
- infoValue = (
-
- {Object.keys(infoValue).map((valueKey) => (
- -
-
- {capitalizeFirstLetter(
- valueKey.split('_').join(' ')
- )}
- :
- {' '}
- {`${infoValue[valueKey]}`}
-
- ))}
-
- )
-
- break
-
- case 'fees':
- infoValue = (
-
- {Object.keys(infoValue).map((valueKey) => (
- -
-
- {capitalizeFirstLetter(
- valueKey.split('_').join(' ')
- )}
- :
- {' '}
- {`${infoValue[valueKey].map((fee: RelayFee) => `${fee.amount} ${fee.unit}`)}`}
-
- ))}
-
- )
- break
- default:
- break
- }
-
- if (Array.isArray(infoValue)) {
- infoValue = infoValue.join(', ')
- }
-
- return (
-
-
- {infoTitle}:
- {' '}
- {infoValue}
- {key === 'pubkey' ? (
- {
- navigator.clipboard.writeText(
- hexToNpub(
- (relaysInfo[relay] as any)[key]
- )
- )
-
- toast.success('Copied to clipboard', {
- autoClose: 1000,
- hideProgressBar: true
- })
- }}
- />
- ) : null}
-
- )
- })}
-
-
- >
- )}
-
-
- ))}
-
- )}
-
- )
-}
diff --git a/src/pages/relays/style.module.scss b/src/pages/relays/style.module.scss
deleted file mode 100644
index 6fcb8b7..0000000
--- a/src/pages/relays/style.module.scss
+++ /dev/null
@@ -1,106 +0,0 @@
-@import '../../colors.scss';
-
-.container {
- margin-top: 25px;
-
- .relayURItextfield {
- width: 100%;
- }
-
- .relayAddContainer {
- display: flex;
- flex-direction: row;
- gap: 10px;
- width: 100%;
- }
-
- .sectionIcon {
- font-size: 30px;
- }
-
- .sectionTitle {
- margin-top: 35px;
- margin-bottom: 10px;
- display: flex;
- flex-direction: row;
- gap: 5px;
- font-size: 1.5rem;
- line-height: 2rem;
- font-weight: 600;
- }
-
- .relaysContainer {
- display: flex;
- flex-direction: column;
- gap: 15px;
- }
-
- .relay {
- border: 1px solid rgba(0, 0, 0, 0.12);
- border-radius: 4px;
-
- .relayDivider {
- margin-left: 10px;
- margin-right: 10px;
- }
-
- .leaveRelayContainer {
- display: flex;
- flex-direction: row;
- gap: 10px;
- cursor: pointer;
- }
-
- .showInfo {
- cursor: pointer;
- }
-
- .showInfoIcon {
- margin-right: 3px;
- margin-bottom: auto;
- vertical-align: middle;
- }
-
- .relayInfoContainer {
- display: flex;
- flex-direction: column;
- gap: 5px;
- text-wrap: wrap;
- }
-
- .relayInfoTitle {
- font-weight: 600;
- }
-
- .relayInfoSubTitle {
- font-weight: 500;
- }
-
- .copyItem {
- margin-left: 10px;
- color: #34495e;
- vertical-align: bottom;
- cursor: pointer;
- }
-
- .connectionStatus {
- border-radius: 9999px;
- width: 10px;
- height: 10px;
- margin-right: 5px;
- margin-top: 2px;
- }
-
- .connectionStatusConnected {
- background-color: $review-feedback-correct;
- }
-
- .connectionStatusNotConnected {
- background-color: $review-feedback-incorrect;
- }
-
- .connectionStatusUnknown {
- background-color: $input-text-color;
- }
- }
-}
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index 4753835..a88732f 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -6,15 +6,14 @@ import { ProfilePage } from '../pages/profile'
import { hexToNpub } from '../utils'
import { SignPage } from '../pages/sign'
import { VerifyPage } from '../pages/verify'
-import { RelaysPage } from '../pages/relays'
+import { ProfileSettingsPage } from '../pages/settings/profile'
export const appPrivateRoutes = {
homePage: '/',
create: '/create',
sign: '/sign',
verify: '/verify',
- profileSettings: '/settings/profile/:npub',
- relays: '/relays'
+ profileSettings: '/settings/profile/:npub'
}
export const appPublicRoutes = {
@@ -66,10 +65,6 @@ export const privateRoutes = [
},
{
path: appPrivateRoutes.profileSettings,
- element:
- },
- {
- path: appPrivateRoutes.relays,
- element:
+ element:
}
]
diff --git a/src/store/actionTypes.ts b/src/store/actionTypes.ts
index 18b4063..6e0cc66 100644
--- a/src/store/actionTypes.ts
+++ b/src/store/actionTypes.ts
@@ -1,7 +1,5 @@
export const RESTORE_STATE = 'RESTORE_STATE'
-export const USER_LOGOUT = 'USER_LOGOUT'
-
export const SET_AUTH_STATE = 'SET_AUTH_STATE'
export const UPDATE_LOGIN_METHOD = 'UPDATE_LOGIN_METHOD'
export const UPDATE_KEYPAIR = 'UPDATE_KEYPAIR'
@@ -11,9 +9,3 @@ export const UPDATE_NSECBUNKER_RELAYS = 'UPDATE_NSECBUNKER_RELAYS'
export const SET_METADATA_EVENT = 'SET_METADATA_EVENT'
export const SET_USER_ROBOT_IMAGE = 'SET_USER_ROBOT_IMAGE'
-
-export const SET_RELAY_MAP = 'SET_RELAY_MAP'
-export const SET_RELAY_INFO = 'SET_RELAY_INFO'
-export const SET_RELAY_MAP_UPDATED = 'SET_RELAY_MAP_UPDATED'
-export const SET_MOST_POPULAR_RELAYS = 'SET_MOST_POPULAR_RELAYS'
-export const SET_RELAY_CONNECTION_STATUS = 'SET_RELAY_CONNECTION_STATUS'
diff --git a/src/store/actions.ts b/src/store/actions.ts
index a101199..3bf716b 100644
--- a/src/store/actions.ts
+++ b/src/store/actions.ts
@@ -3,7 +3,6 @@ import { State } from './rootReducer'
export * from './auth/action'
export * from './metadata/action'
-export * from './relays/action'
export const restoreState = (payload: State) => {
return {
@@ -16,9 +15,3 @@ export interface RestoreState {
type: typeof ActionTypes.RESTORE_STATE
payload: State
}
-
-export const userLogOutAction = () => {
- return {
- type: ActionTypes.USER_LOGOUT
- }
-}
diff --git a/src/store/relays/action.ts b/src/store/relays/action.ts
deleted file mode 100644
index 6f95840..0000000
--- a/src/store/relays/action.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import * as ActionTypes from '../actionTypes'
-import {
- SetRelayMapAction,
- SetMostPopularRelaysAction,
- SetRelayInfoAction,
- SetRelayConnectionStatusAction,
- SetRelayMapUpdatedAction
-} from './types'
-import { RelayMap, RelayInfoObject, RelayConnectionStatus } from '../../types'
-
-export const setRelayMapAction = (payload: RelayMap): SetRelayMapAction => ({
- type: ActionTypes.SET_RELAY_MAP,
- payload
-})
-
-export const setRelayInfoAction = (
- payload: RelayInfoObject
-): SetRelayInfoAction => ({
- type: ActionTypes.SET_RELAY_INFO,
- payload
-})
-
-export const setMostPopularRelaysAction = (
- payload: string[]
-): SetMostPopularRelaysAction => ({
- type: ActionTypes.SET_MOST_POPULAR_RELAYS,
- payload
-})
-
-export const setRelayConnectionStatusAction = (
- payload: RelayConnectionStatus
-): SetRelayConnectionStatusAction => ({
- type: ActionTypes.SET_RELAY_CONNECTION_STATUS,
- payload
-})
-
-export const setRelayMapUpdatedAction = (): SetRelayMapUpdatedAction => ({
- type: ActionTypes.SET_RELAY_MAP_UPDATED
-})
diff --git a/src/store/relays/reducer.ts b/src/store/relays/reducer.ts
deleted file mode 100644
index b4b9854..0000000
--- a/src/store/relays/reducer.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import * as ActionTypes from '../actionTypes'
-import { RelaysDispatchTypes, RelaysState } from './types'
-
-const initialState: RelaysState = {
- map: undefined,
- mapUpdated: undefined,
- mostPopular: undefined,
- info: undefined,
- connectionStatus: undefined
-}
-
-const reducer = (
- state = initialState,
- action: RelaysDispatchTypes
-): RelaysState | null => {
- switch (action.type) {
- case ActionTypes.SET_RELAY_MAP:
- return { ...state, map: action.payload, mapUpdated: Date.now() }
-
- case ActionTypes.SET_RELAY_MAP_UPDATED:
- return { ...state, mapUpdated: Date.now() }
-
- case ActionTypes.SET_RELAY_INFO:
- return {
- ...state,
- info: { ...state.info, ...action.payload }
- }
-
- case ActionTypes.SET_RELAY_CONNECTION_STATUS:
- return {
- ...state,
- connectionStatus: action.payload
- }
-
- case ActionTypes.SET_MOST_POPULAR_RELAYS:
- return { ...state, mostPopular: action.payload }
-
- case ActionTypes.RESTORE_STATE:
- return action.payload.relays
-
- default:
- return state
- }
-}
-
-export default reducer
diff --git a/src/store/relays/types.ts b/src/store/relays/types.ts
deleted file mode 100644
index e1c4da8..0000000
--- a/src/store/relays/types.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import * as ActionTypes from '../actionTypes'
-import { RestoreState } from '../actions'
-import { RelayMap, RelayInfoObject, RelayConnectionStatus } from '../../types'
-
-export type RelaysState = {
- map?: RelayMap
- mapUpdated?: number
- mostPopular?: string[]
- info?: RelayInfoObject
- connectionStatus?: RelayConnectionStatus
-}
-
-export interface SetRelayMapAction {
- type: typeof ActionTypes.SET_RELAY_MAP
- payload: RelayMap
-}
-
-export interface SetMostPopularRelaysAction {
- type: typeof ActionTypes.SET_MOST_POPULAR_RELAYS
- payload: string[]
-}
-
-export interface SetRelayInfoAction {
- type: typeof ActionTypes.SET_RELAY_INFO
- payload: RelayInfoObject
-}
-
-export interface SetRelayConnectionStatusAction {
- type: typeof ActionTypes.SET_RELAY_CONNECTION_STATUS
- payload: RelayConnectionStatus
-}
-
-export interface SetRelayMapUpdatedAction {
- type: typeof ActionTypes.SET_RELAY_MAP_UPDATED
-}
-
-export type RelaysDispatchTypes =
- | SetRelayMapAction
- | SetRelayInfoAction
- | SetRelayMapUpdatedAction
- | SetMostPopularRelaysAction
- | SetRelayConnectionStatusAction
- | RestoreState
diff --git a/src/store/rootReducer.ts b/src/store/rootReducer.ts
index 517291c..03c9b5c 100644
--- a/src/store/rootReducer.ts
+++ b/src/store/rootReducer.ts
@@ -4,31 +4,15 @@ import authReducer from './auth/reducer'
import { AuthState } from './auth/types'
import metadataReducer from './metadata/reducer'
import userRobotImageReducer from './userRobotImage/reducer'
-import { RelaysState } from './relays/types'
-import relaysReducer from './relays/reducer'
-import * as ActionTypes from './actionTypes'
export interface State {
auth: AuthState
metadata?: Event
userRobotImage?: string
- relays: RelaysState
}
-export const appReducer = combineReducers({
+export default combineReducers({
auth: authReducer,
metadata: metadataReducer,
- userRobotImage: userRobotImageReducer,
- relays: relaysReducer
+ userRobotImage: userRobotImageReducer
})
-
-// FIXME: define types
-export default (state: any, action: any) => {
- switch (action.type) {
- case ActionTypes.USER_LOGOUT:
- return appReducer(undefined, action)
-
- default:
- return appReducer(state, action)
- }
-}
diff --git a/src/store/store.ts b/src/store/store.ts
index ab20121..20d9b66 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -1,11 +1,8 @@
import { configureStore } from '@reduxjs/toolkit'
import rootReducer from './rootReducer'
-const store = configureStore({
- reducer: rootReducer
-})
+const store = configureStore({ reducer: rootReducer })
export default store
export type Dispatch = typeof store.dispatch
-export type RootState = ReturnType
diff --git a/src/types/index.ts b/src/types/index.ts
index 9397745..ef2283f 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -2,4 +2,3 @@ export * from './core'
export * from './nostr'
export * from './profile'
export * from './zip'
-export * from './relay'
diff --git a/src/types/nostr.ts b/src/types/nostr.ts
index a7d6f0c..67572d8 100644
--- a/src/types/nostr.ts
+++ b/src/types/nostr.ts
@@ -8,6 +8,11 @@ export interface SignedEvent {
sig: string
}
+export interface RelaySet {
+ read: string[]
+ write: string[]
+}
+
export interface NostrJoiningBlock {
block: number
encodedEventPointer: string
diff --git a/src/types/relay.ts b/src/types/relay.ts
deleted file mode 100644
index ee426f2..0000000
--- a/src/types/relay.ts
+++ /dev/null
@@ -1,232 +0,0 @@
-export interface RelaySet {
- read: string[]
- write: string[]
-}
-
-export type RelayMap = {
- [key: string]: {
- read: boolean
- write: boolean
- }
-}
-
-export interface RelayStats {
- relays: number
- pubKeys: number
- users: number
- trusted_users: number
- events: number
- posts: number
- zaps: number
- zap_amount: number
- daily: Daily
- daily_totals: DailyTotals
- relay_stats: RelayStats
-}
-
-export interface RelayStats {
- user_picks: UserPicks
- written: Written
-}
-
-export interface Written {
- last_week: LastWeek[]
-}
-
-export interface LastWeek {
- d: string
- p: number
- ps: number
- e: number
- es: number
-}
-
-export interface UserPicks {
- read_relays: ReadRelay[]
- write_relays: ReadRelay[]
-}
-
-export interface ReadRelay {
- d: string
- r: number
- w: number
- rs: number
- ws: number
-}
-
-export interface DailyTotals {
- datasets: Datasets2
-}
-
-export interface Datasets2 {
- kind_0: Kind0[]
- kind_1: Kind0[]
- kind_2: Kind0[]
- kind_3: Kind0[]
- kind_5: Kind0[]
- kind_6: Kind0[]
- kind_7: Kind0[]
- kind_1984: Kind0[]
- kind_9735: Kind0[]
- kind_1063: Kind0[]
- kind_6969: Kind0[]
- kind_9802: Kind0[]
- kind_30000: Kind0[]
- kind_30001: Kind0[]
- kind_30008: Kind0[]
- kind_30009: Kind0[]
- kind_30017: Kind0[]
- kind_30018: Kind0[]
- kind_30023: Kind0[]
- kind_31337: Kind0[]
- totals: Kind0[]
- new_profiles: Kind0[]
- new_pubkeys: Kind0[]
- new_contact_lists: Kind0[]
- new_ln: Kind0[]
- new_users: Kind0[]
- total_zap_amount: Kind0[]
- zappers: Kind0[]
- zapped_pubkeys: Kind0[]
- zapped_events: Kind0[]
- zap_providers: Kind0[]
-}
-
-export interface Daily {
- datasets: Datasets
-}
-
-export interface Datasets {
- kind_0: Kind0[]
- kind_1: Kind0[]
- kind_2: Kind0[]
- kind_3: Kind0[]
- kind_5: Kind0[]
- kind_6: Kind0[]
- kind_7: Kind0[]
- kind_1984: Kind0[]
- kind_9735: Kind0[]
- kind_1063: Kind0[]
- kind_6969: Kind0[]
- kind_9802: Kind0[]
- kind_30000: Kind0[]
- kind_30001: Kind0[]
- kind_30008: Kind0[]
- kind_30009: Kind0[]
- kind_30017: Kind0[]
- kind_30018: Kind0[]
- kind_30023: Kind0[]
- kind_31337: Kind0[]
- totals: Kind0[]
- new_profiles: Kind0[]
- new_pubkeys: Kind0[]
- new_contact_lists: Kind0[]
- new_ln: Kind0[]
- new_users: Kind0[]
- max_zap_amount: Kind0[]
- avg_zap_amount: Kind0[]
- total_zap_amount: Kind0[]
- active_pubkeys: Kind0[]
- active_pubkeys_total: Kind0[]
- active_pubkeys_week: Kind0[]
- active_pubkeys_total_week: Kind0[]
- active_relays: Kind0[]
- zappers: Kind0[]
- zapped_pubkeys: Kind0[]
- zapped_events: Kind0[]
- zap_providers: Kind0[]
- retention: Retention
-}
-
-export interface Retention {
- all: All[]
- tr: All[]
- bio: All[]
- all_curves: Allcurve[]
- tr_curves: Allcurve[]
- bio_curves: Allcurve[]
-}
-
-export interface Allcurve {
- day: number
- '2023-02': number
- '2023-03': number
- '2023-04': number
- '2023-05': number
- '2023-06': number
- '2023-07': number
-}
-
-export interface All {
- d: string
- signups: number
- retained: number
- retd_posts: number
- retd_replies: number
- retd_reposts: number
- retd_likes: number
- retd_liked: number
- retd_liked_pubkeys: number
- retd_replied: number
- retd_replied_pubkeys: number
- retd_zaps_received: number
- retd_zaps_received_msats: number
- retd_zaps_sent: number
- retd_zaps_sent_msats: number
- retd_following: number
- retd_followers: number
- lost_posts: number
- lost_replies: number
- lost_reposts: number
- lost_likes: number
- lost_liked: number
- lost_liked_pubkeys: number
- lost_replied: number
- lost_replied_pubkeys: number
- lost_zaps_received: number
- lost_zaps_received_msats: number
- lost_zaps_sent: number
- lost_zaps_sent_msats: number
- lost_following: number
- lost_followers: number
-}
-
-export interface Kind0 {
- d: string
- c: number
-}
-
-export interface RelayFee {
- amount: number
- unit: string
-}
-
-export interface RelayInfo {
- name: string
- description: string
- pubkey: string
- contact: string
- supported_nips: number[]
- software: string
- version: string
- limitation?: { [key: string]: number | boolean }
- fees?: { [key: string]: RelayFee[] }
-}
-
-export interface RelayInfoObject {
- [key: string]: RelayInfo
-}
-
-export interface RelayInfoItem {
- uri: string
- info: RelayInfo
-}
-
-export enum RelayConnectionState {
- Connected = 'Connected',
- NotConnected = 'Failed to connect'
-}
-
-export interface RelayConnectionStatus {
- [key: string]: RelayConnectionState
-}
diff --git a/src/utils/index.ts b/src/utils/index.ts
index d2f5ec1..156c643 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -5,4 +5,3 @@ export * from './misc'
export * from './nostr'
export * from './string'
export * from './zip'
-export * from './utils'
diff --git a/src/utils/string.ts b/src/utils/string.ts
index 09a9313..97e86ea 100644
--- a/src/utils/string.ts
+++ b/src/utils/string.ts
@@ -85,11 +85,3 @@ export const parseJson = (content: string): Promise => {
}
})
}
-
-/**
- * Capitalizes the first character in the string
- * @param str string to modify
- * @returns modified string
- */
-export const capitalizeFirstLetter = (str: string) =>
- str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
deleted file mode 100644
index a436fae..0000000
--- a/src/utils/utils.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export const compareObjects = (
- obj1: object | null | undefined,
- obj2: object | null | undefined
-): boolean => {
- if (Array.isArray(obj1) && Array.isArray(obj2)) {
- const obj1Copy = [...obj1].sort()
- const obj2Copy = [...obj2].sort()
-
- return JSON.stringify(obj1Copy) === JSON.stringify(obj2Copy)
- }
-
- return JSON.stringify(obj1) === JSON.stringify(obj2)
-}