feat(design): home page new design and functionality #135

Merged
enes merged 24 commits from issue-121 into staging 2024-08-14 08:44:09 +00:00
12 changed files with 69 additions and 50 deletions
Showing only changes of commit 6652c6519e - Show all commits

View File

@ -7,7 +7,7 @@
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "tsc && vite build", "build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 29", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 25",
"lint:fix": "eslint . --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "lint:fix": "eslint . --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"lint:staged": "eslint --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "lint:staged": "eslint --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"formatter:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"", "formatter:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",

View File

@ -12,7 +12,8 @@ import {
getAuthToken, getAuthToken,
getVisitedLink, getVisitedLink,
saveAuthToken, saveAuthToken,
compareObjects compareObjects,
unixNow
} from '../utils' } from '../utils'
import { appPrivateRoutes } from '../routes' import { appPrivateRoutes } from '../routes'
import { SignedEvent } from '../types' import { SignedEvent } from '../types'
@ -54,7 +55,7 @@ export class AuthController {
}) })
// Nostr uses unix timestamps // Nostr uses unix timestamps
const timestamp = Math.floor(Date.now() / 1000) const timestamp = unixNow()
const { hostname } = window.location const { hostname } = window.location
const authEvent: EventTemplate = { const authEvent: EventTemplate = {

View File

@ -12,7 +12,7 @@ import {
import { NostrJoiningBlock, ProfileMetadata, RelaySet } from '../types' import { NostrJoiningBlock, ProfileMetadata, RelaySet } from '../types'
import { NostrController } from '.' import { NostrController } from '.'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { queryNip05 } from '../utils' import { queryNip05, unixNow } from '../utils'
import NDK, { NDKEvent, NDKSubscription } from '@nostr-dev-kit/ndk' import NDK, { NDKEvent, NDKSubscription } from '@nostr-dev-kit/ndk'
import { EventEmitter } from 'tseep' import { EventEmitter } from 'tseep'
import { localCache } from '../services' import { localCache } from '../services'
@ -194,7 +194,7 @@ export class MetadataController extends EventEmitter {
let signedMetadataEvent = event let signedMetadataEvent = event
if (event.sig.length < 1) { if (event.sig.length < 1) {
const timestamp = Math.floor(Date.now() / 1000) const timestamp = unixNow()
// Metadata event to publish to the wss://purplepag.es relay // Metadata event to publish to the wss://purplepag.es relay
const newMetadataEvent: Event = { const newMetadataEvent: Event = {
@ -265,7 +265,7 @@ export class MetadataController extends EventEmitter {
// initialize job request // initialize job request
const jobEventTemplate: EventTemplate = { const jobEventTemplate: EventTemplate = {
content: '', content: '',
created_at: Math.round(Date.now() / 1000), created_at: unixNow(),
kind: 68001, kind: 68001,
tags: [ tags: [
['i', `${created_at * 1000}`], ['i', `${created_at * 1000}`],

View File

@ -42,6 +42,7 @@ import {
import { import {
compareObjects, compareObjects,
getNsecBunkerDelegatedKey, getNsecBunkerDelegatedKey,
unixNow,
verifySignedEvent verifySignedEvent
} from '../utils' } from '../utils'
import { getDefaultRelayMap } from '../utils/relays.ts' import { getDefaultRelayMap } from '../utils/relays.ts'
@ -244,7 +245,7 @@ export class NostrController extends EventEmitter {
if (!firstSuccessfulPublish) { if (!firstSuccessfulPublish) {
// If no publish was successful, collect the reasons for failures // If no publish was successful, collect the reasons for failures
const failedPublishes: any[] = [] const failedPublishes: unknown[] = []
const fallbackRejectionReason = const fallbackRejectionReason =
'Attempt to publish an event has been rejected with unknown reason.' 'Attempt to publish an event has been rejected with unknown reason.'
@ -504,7 +505,9 @@ export class NostrController extends EventEmitter {
} else if (loginMethod === LoginMethods.extension) { } else if (loginMethod === LoginMethods.extension) {
const nostr = this.getNostrObject() const nostr = this.getNostrObject()
return (await nostr.signEvent(event as NostrEvent).catch((err: any) => { return (await nostr
.signEvent(event as NostrEvent)
.catch((err: unknown) => {
console.log('Error while signing event: ', err) console.log('Error while signing event: ', err)
throw err throw err
@ -625,8 +628,12 @@ export class NostrController extends EventEmitter {
*/ */
capturePublicKey = async (): Promise<string> => { capturePublicKey = async (): Promise<string> => {
const nostr = this.getNostrObject() const nostr = this.getNostrObject()
const pubKey = await nostr.getPublicKey().catch((err: any) => { const pubKey = await nostr.getPublicKey().catch((err: unknown) => {
if (err instanceof Error) {
return Promise.reject(err.message) return Promise.reject(err.message)
} else {
return Promise.reject(JSON.stringify(err))
}
}) })
if (!pubKey) { if (!pubKey) {
@ -708,7 +715,7 @@ export class NostrController extends EventEmitter {
npub: string, npub: string,
extraRelaysToPublish?: string[] extraRelaysToPublish?: string[]
): Promise<string> => { ): Promise<string> => {
const timestamp = Math.floor(Date.now() / 1000) const timestamp = unixNow()
const relayURIs = Object.keys(relayMap) const relayURIs = Object.keys(relayMap)
// More info about this kind of event available https://github.com/nostr-protocol/nips/blob/master/65.md // More info about this kind of event available https://github.com/nostr-protocol/nips/blob/master/65.md
@ -810,7 +817,7 @@ export class NostrController extends EventEmitter {
// initialize job request // initialize job request
const jobEventTemplate: EventTemplate = { const jobEventTemplate: EventTemplate = {
content: '', content: '',
created_at: Math.round(Date.now() / 1000), created_at: unixNow(),
kind: 68001, kind: 68001,
tags: [ tags: [
['i', `${JSON.stringify(relayURIs)}`], ['i', `${JSON.stringify(relayURIs)}`],

View File

@ -2,6 +2,7 @@ import { useEffect, useState } from 'react'
import { CreateSignatureEventContent, Meta } from '../types' import { CreateSignatureEventContent, Meta } from '../types'
import { Mark } from '../types/mark' import { Mark } from '../types/mark'
import { import {
fromUnixTimestamp,
parseCreateSignatureEvent, parseCreateSignatureEvent,
parseCreateSignatureEventContent, parseCreateSignatureEventContent,
SigitMetaParseError, SigitMetaParseError,
@ -68,7 +69,7 @@ export const useSigitMeta = (meta: Meta): FlatMeta => {
setKind(kind) setKind(kind)
setTags(tags) setTags(tags)
// created_at in nostr events are stored in seconds // created_at in nostr events are stored in seconds
Review

created_at * 1000 should be made into a utility function and used in other similar places (there is at least one that I could find).

Similarly, there is a reverse action, created_at / 1000, which should also be a utility.

`created_at * 1000` should be made into a utility function and used in other similar places (there is at least one that I could find). Similarly, there is a reverse action, `created_at / 1000`, which should also be a utility.
setCreatedAt(created_at * 1000) setCreatedAt(fromUnixTimestamp(created_at))
setPubkey(pubkey) setPubkey(pubkey)
setId(id) setId(id)
setSig(sig) setSig(sig)

View File

@ -50,7 +50,7 @@ import {
getHash, getHash,
hexToNpub, hexToNpub,
isOnline, isOnline,
now, unixNow,
npubToHex, npubToHex,
queryNip05, queryNip05,
sendNotification, sendNotification,
@ -407,7 +407,6 @@ export const CreatePage = () => {
encryptionKey: string encryptionKey: string
): Promise<File | null> => { ): Promise<File | null> => {
// Get the current timestamp in seconds // Get the current timestamp in seconds
const unixNow = now()
const blob = new Blob([encryptedArrayBuffer]) const blob = new Blob([encryptedArrayBuffer])
// Create a File object with the Blob data // Create a File object with the Blob data
const file = new File([blob], `compressed.sigit`, { const file = new File([blob], `compressed.sigit`, {
@ -455,10 +454,9 @@ export const CreatePage = () => {
const uploadFile = async ( const uploadFile = async (
arrayBuffer: ArrayBuffer arrayBuffer: ArrayBuffer
): Promise<string | null> => { ): Promise<string | null> => {
const unixNow = now()
const blob = new Blob([arrayBuffer]) const blob = new Blob([arrayBuffer])
// Create a File object with the Blob data // Create a File object with the Blob data
const file = new File([blob], `compressed-${unixNow}.sigit`, { const file = new File([blob], `compressed-${unixNow()}.sigit`, {
type: 'application/sigit' type: 'application/sigit'
}) })
@ -485,7 +483,7 @@ export const CreatePage = () => {
return return
} }
saveAs(finalZipFile, `request-${now()}.sigit.zip`) saveAs(finalZipFile, `request-${unixNow()}.sigit.zip`)
setIsLoading(false) setIsLoading(false)
} }
@ -615,7 +613,7 @@ export const CreatePage = () => {
const meta: Meta = { const meta: Meta = {
createSignature, createSignature,
keys, keys,
modifiedAt: now(), modifiedAt: unixNow(),
docSignatures: {} docSignatures: {}
} }
@ -654,7 +652,7 @@ export const CreatePage = () => {
const meta: Meta = { const meta: Meta = {
createSignature, createSignature,
modifiedAt: now(), modifiedAt: unixNow(),
docSignatures: {} docSignatures: {}
} }

View File

@ -26,7 +26,7 @@ import { setMetadataEvent } from '../../../store/actions'
import { LoadingSpinner } from '../../../components/LoadingSpinner' import { LoadingSpinner } from '../../../components/LoadingSpinner'
import { LoginMethods } from '../../../store/auth/types' import { LoginMethods } from '../../../store/auth/types'
import { SmartToy } from '@mui/icons-material' import { SmartToy } from '@mui/icons-material'
import { getRoboHashPicture } from '../../../utils' import { getRoboHashPicture, unixNow } from '../../../utils'
import { Container } from '../../../components/Container' import { Container } from '../../../components/Container'
export const ProfileSettingsPage = () => { export const ProfileSettingsPage = () => {
@ -197,7 +197,7 @@ export const ProfileSettingsPage = () => {
// Relay will reject if created_at is too late // Relay will reject if created_at is too late
const updatedMetadataState: UnsignedEvent = { const updatedMetadataState: UnsignedEvent = {
content: content, content: content,
created_at: Math.round(Date.now() / 1000), created_at: unixNow(),
kind: kinds.Metadata, kind: kinds.Metadata,
pubkey: pubkey!, pubkey: pubkey!,
tags: metadataState?.tags || [] tags: metadataState?.tags || []

View File

@ -26,7 +26,7 @@ import {
hexToNpub, hexToNpub,
isOnline, isOnline,
loadZip, loadZip,
now, unixNow,
npubToHex, npubToHex,
parseJson, parseJson,
readContentOfZipEntry, readContentOfZipEntry,
@ -554,7 +554,7 @@ export const SignPage = () => {
...metaCopy.docSignatures, ...metaCopy.docSignatures,
[hexToNpub(signedEvent.pubkey)]: JSON.stringify(signedEvent, null, 2) [hexToNpub(signedEvent.pubkey)]: JSON.stringify(signedEvent, null, 2)
} }
metaCopy.modifiedAt = now() metaCopy.modifiedAt = unixNow()
return metaCopy return metaCopy
} }
@ -564,7 +564,6 @@ export const SignPage = () => {
encryptionKey: string encryptionKey: string
): Promise<File | null> => { ): Promise<File | null> => {
// Get the current timestamp in seconds // Get the current timestamp in seconds
const unixNow = now()
const blob = new Blob([encryptedArrayBuffer]) const blob = new Blob([encryptedArrayBuffer])
// Create a File object with the Blob data // Create a File object with the Blob data
const file = new File([blob], `compressed.sigit`, { const file = new File([blob], `compressed.sigit`, {
@ -614,7 +613,7 @@ export const SignPage = () => {
if (!arraybuffer) return null if (!arraybuffer) return null
return new File([new Blob([arraybuffer])], `${unixNow}.sigit.zip`, { return new File([new Blob([arraybuffer])], `${unixNow()}.sigit.zip`, {
type: 'application/zip' type: 'application/zip'
}) })
} }
@ -758,8 +757,7 @@ export const SignPage = () => {
if (!arrayBuffer) return if (!arrayBuffer) return
const blob = new Blob([arrayBuffer]) const blob = new Blob([arrayBuffer])
const unixNow = now() saveAs(blob, `exported-${unixNow()}.sigit.zip`)
saveAs(blob, `exported-${unixNow}.sigit.zip`)
setIsLoading(false) setIsLoading(false)
@ -804,8 +802,7 @@ export const SignPage = () => {
const finalZipFile = await createFinalZipFile(encryptedArrayBuffer, key) const finalZipFile = await createFinalZipFile(encryptedArrayBuffer, key)
if (!finalZipFile) return if (!finalZipFile) return
const unixNow = now() saveAs(finalZipFile, `exported-${unixNow()}.sigit.zip`)
saveAs(finalZipFile, `exported-${unixNow}.sigit.zip`)
} }
/** /**

View File

@ -28,7 +28,7 @@ import {
extractZipUrlAndEncryptionKey, extractZipUrlAndEncryptionKey,
getHash, getHash,
hexToNpub, hexToNpub,
now, unixNow,
npubToHex, npubToHex,
parseJson, parseJson,
readContentOfZipEntry, readContentOfZipEntry,
@ -239,7 +239,7 @@ export const VerifyPage = () => {
} }
}) })
} }
}, [submittedBy, signers, viewers]) }, [submittedBy, signers, viewers, metadata])
const handleVerify = async () => { const handleVerify = async () => {
if (!selectedFile) return if (!selectedFile) return
@ -445,7 +445,7 @@ export const VerifyPage = () => {
if (!arrayBuffer) return if (!arrayBuffer) return
const blob = new Blob([arrayBuffer]) const blob = new Blob([arrayBuffer])
saveAs(blob, `exported-${now()}.sigit.zip`) saveAs(blob, `exported-${unixNow()}.sigit.zip`)
setIsLoading(false) setIsLoading(false)
} }

View File

@ -1,5 +1,5 @@
import { CreateSignatureEventContent, Meta } from '../types' import { CreateSignatureEventContent, Meta } from '../types'
import { parseJson } from '.' import { fromUnixTimestamp, parseJson } from '.'
import { Event } from 'nostr-tools' import { Event } from 'nostr-tools'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
@ -140,7 +140,7 @@ export const extractSigitCardDisplayInfo = async (meta: Meta) => {
) )
// created_at in nostr events are stored in seconds // created_at in nostr events are stored in seconds
sigitInfo.createdAt = createSignatureEvent.created_at * 1000 sigitInfo.createdAt = fromUnixTimestamp(createSignatureEvent.created_at)
const createSignatureContent = await parseCreateSignatureEventContent( const createSignatureContent = await parseCreateSignatureEventContent(
createSignatureEvent.content createSignatureEvent.content

View File

@ -13,7 +13,7 @@ import { NostrController } from '../controllers'
import { AuthState } from '../store/auth/types' import { AuthState } from '../store/auth/types'
import store from '../store/store' import store from '../store/store'
import { CreateSignatureEventContent, Meta } from '../types' import { CreateSignatureEventContent, Meta } from '../types'
import { hexToNpub, now } from './nostr' import { hexToNpub, unixNow } from './nostr'
import { parseJson } from './string' import { parseJson } from './string'
import { hexToBytes } from '@noble/hashes/utils' import { hexToBytes } from '@noble/hashes/utils'
@ -28,10 +28,10 @@ export const uploadToFileStorage = async (file: File) => {
const event: EventTemplate = { const event: EventTemplate = {
kind: 24242, kind: 24242,
content: 'Authorize Upload', content: 'Authorize Upload',
created_at: Math.floor(Date.now() / 1000), created_at: unixNow(),
tags: [ tags: [
['t', 'upload'], ['t', 'upload'],
['expiration', String(now() + 60 * 5)], // Set expiration time to 5 minutes from now ['expiration', String(unixNow() + 60 * 5)], // Set expiration time to 5 minutes from now
['name', file.name], ['name', file.name],
['size', String(file.size)] ['size', String(file.size)]
] ]
@ -78,7 +78,7 @@ export const signEventForMetaFile = async (
const event: EventTemplate = { const event: EventTemplate = {
kind: 27235, // Event type for meta file kind: 27235, // Event type for meta file
content: content, // content for event content: content, // content for event
created_at: Math.floor(Date.now() / 1000), // Current timestamp created_at: unixNow(), // Current timestamp
tags: [['-']] // For understanding why "-" tag is used here see: https://github.com/nostr-protocol/nips/blob/protected-events-tag/70.md tags: [['-']] // For understanding why "-" tag is used here see: https://github.com/nostr-protocol/nips/blob/protected-events-tag/70.md
} }

View File

@ -211,7 +211,22 @@ export const getRoboHashPicture = (
return `https://robohash.org/${npub}.png?set=set${set}` return `https://robohash.org/${npub}.png?set=set${set}`
} }
export const now = () => Math.round(Date.now() / 1000) export const unixNow = () => Math.round(Date.now() / 1000)
export const toUnixTimestamp = (date: number | Date) => {
let time
if (typeof date === 'number') {
time = Math.round(date / 1000)
} else if (date instanceof Date) {
time = Math.round(date.getTime() / 1000)
} else {
throw Error('Unsupported type when converting to unix timestamp')
}
return time
}
export const fromUnixTimestamp = (unix: number) => {
return unix * 1000
}
/** /**
* Generate nip44 conversation key * Generate nip44 conversation key
@ -288,7 +303,7 @@ export const createWrap = (unsignedEvent: UnsignedEvent, receiver: string) => {
kind: 1059, // Event kind kind: 1059, // Event kind
content, // Encrypted content content, // Encrypted content
pubkey, // Public key of the creator pubkey, // Public key of the creator
created_at: now(), // Current timestamp created_at: unixNow(), // Current timestamp
tags: [ tags: [
// Tags including receiver and nonce // Tags including receiver and nonce
['p', receiver], ['p', receiver],
@ -542,7 +557,7 @@ export const updateUsersAppData = async (meta: Meta) => {
const updatedEvent: UnsignedEvent = { const updatedEvent: UnsignedEvent = {
kind: kinds.Application, kind: kinds.Application,
pubkey: usersPubkey!, pubkey: usersPubkey!,
created_at: now(), created_at: unixNow(),
tags: [['d', hash]], tags: [['d', hash]],
content: encryptedContent content: encryptedContent
} }
@ -608,10 +623,10 @@ const deleteBlossomFile = async (url: string, privateKey: string) => {
const event: EventTemplate = { const event: EventTemplate = {
kind: 24242, kind: 24242,
content: 'Authorize Upload', content: 'Authorize Upload',
created_at: now(), created_at: unixNow(),
tags: [ tags: [
['t', 'delete'], ['t', 'delete'],
['expiration', String(now() + 60 * 5)], // Set expiration time to 5 minutes from now ['expiration', String(unixNow() + 60 * 5)], // Set expiration time to 5 minutes from now
['x', hash] ['x', hash]
] ]
} }
@ -667,10 +682,10 @@ const uploadUserAppDataToBlossom = async (
const event: EventTemplate = { const event: EventTemplate = {
kind: 24242, kind: 24242,
content: 'Authorize Upload', content: 'Authorize Upload',
created_at: now(), created_at: unixNow(),
tags: [ tags: [
['t', 'upload'], ['t', 'upload'],
['expiration', String(now() + 60 * 5)], // Set expiration time to 5 minutes from now ['expiration', String(unixNow() + 60 * 5)], // Set expiration time to 5 minutes from now
['name', file.name], ['name', file.name],
['size', String(file.size)] ['size', String(file.size)]
] ]
@ -875,7 +890,7 @@ export const sendNotification = async (receiver: string, meta: Meta) => {
pubkey: usersPubkey, pubkey: usersPubkey,
content: JSON.stringify(meta), content: JSON.stringify(meta),
tags: [], tags: [],
created_at: now() created_at: unixNow()
} }
// Wrap the unsigned event with the receiver's information // Wrap the unsigned event with the receiver's information