This commit is contained in:
Filipe Medeiros 2021-11-29 01:27:56 +00:00
parent 9fa142841b
commit a78abbd950
23 changed files with 235 additions and 272 deletions

2
.env Normal file
View file

@ -0,0 +1,2 @@
NEXT_PUBLIC_DEFAULT_NANO_NODE_RPC=https://rainstorm.city/api
NEXT_PUBLIC_DEFAULT_NANO_NODE_WS=wss://ws.mynano.ninja/

View file

@ -66,7 +66,7 @@ const BottomMenu: FC<Props> = ({ className }) => {
<div>
<div
className={clsx(
'flex gap-10 items-end',
'flex gap-6 items-end',
leftHanded ? 'flex-row-reverse' : 'flex-row'
)}
>
@ -97,31 +97,12 @@ const BottomMenu: FC<Props> = ({ className }) => {
</button>
)}
<div className="relative h-16">
<div className="flex h-16">
<button
disabled={isWelcoming}
className={clsx(
'bg-purple-500 absolute top-0 px-1 h-16 w-10 rounded-r hover:bg-purple-400 disabled:hover:bg-purple-500 shadow-md disabled:cursor-default',
leftHanded
? 'left-0 -translate-x-2/3 rounded-l'
: 'right-0 translate-x-2/3 rounded-r'
)}
onClick={() => push('/send/qr')}
>
<PaperAirplaneIcon className="h-full text-purple-50 dark:text-gray-900 w-full rotate-[30deg] translate-x-1" />
</button>
<div className="border-purple-500 border-t-2 border-b-2 py-1 px-4 h-16 shadow-lg">
<QrcodeIcon className="h-full text-gray-900 dark:text-purple-100" />
</div>
<button
disabled={isWelcoming}
className={clsx(
'bg-purple-500 absolute top-0 px-1 h-16 w-10 hover:bg-purple-400 disabled:hover:bg-purple-500 shadow-md disabled:cursor-default',
leftHanded
? 'right-0 translate-x-2/3 rounded-r'
: 'left-0 -translate-x-2/3 rounded-l'
'bg-purple-500 px-1 h-16 w-10 hover:bg-purple-400 disabled:hover:bg-purple-500 shadow-md disabled:cursor-default',
leftHanded ? 'rounded-r' : 'rounded-l'
)}
onClick={() => push('/receive/qr')}
>
@ -131,20 +112,18 @@ const BottomMenu: FC<Props> = ({ className }) => {
}
/>
</button>
</div>
<div className="flex flex-col h-16 justify-between">
<div className="border-purple-500 border-t-2 border-b-2 p-1 h-16 shadow-lg">
<QrcodeIcon className="h-full text-gray-900 dark:text-purple-100" />
</div>
<button
disabled={isWelcoming}
className="bg-purple-500 p-1 h-7 rounded hover:bg-purple-400 disabled:hover:bg-purple-500 shadow-md disabled:cursor-default"
className={clsx(
'bg-purple-500 px-1 h-16 w-10 rounded-r hover:bg-purple-400 disabled:hover:bg-purple-500 shadow-md disabled:cursor-default',
leftHanded ? 'rounded-l' : 'rounded-r'
)}
onClick={() => push('/send/qr')}
>
<PaperAirplaneIcon className="h-full text-purple-50 dark:text-gray-900 rotate-[30deg] translate-x-[2px]" />
</button>
<button
disabled={isWelcoming}
className="bg-purple-500 p-1 h-7 rounded hover:bg-purple-400 disabled:hover:bg-purple-500 shadow-lg disabled:cursor-default"
>
<RssIcon className="h-full text-purple-50 dark:text-gray-900" />
<PaperAirplaneIcon className="h-full text-purple-50 dark:text-gray-900 w-full rotate-[30deg] translate-x-1" />
</button>
</div>
</div>

View file

@ -7,9 +7,7 @@ import type { FC } from 'react'
import { useCurrentAccount } from '../lib/context/accountContext'
import useAccountHistory from '../lib/hooks/useAccountHistory'
import useAccountReceivable from '../lib/hooks/useAccountReceivable'
import useListenToConfirmations from '../lib/hooks/useListenToConfirmations'
import useReceiveNano from '../lib/hooks/useReceiveNano'
import { ConfirmationMessage } from '../lib/types'
import rawToNanoDisplay from '../lib/xno/rawToNanoDisplay'
export interface Props {
@ -17,90 +15,32 @@ export interface Props {
}
const RecentTransactions: FC<Props> = ({ className }) => {
const account = useCurrentAccount()
const { receive } = useReceiveNano()
const {
accountReceivable,
blocksInfo: receivableBlocksInfo,
mutate,
} = useAccountReceivable()
const { accountHistory } = useAccountHistory()
const account = useCurrentAccount()
const { receivableBlocks, receivableBlocksInfo, onBlockReceived } =
useAccountReceivable()
const { data: accountHistory } = useAccountHistory()
const hasReceivable =
accountReceivable !== undefined &&
Object.values(accountReceivable.blocks).some(account => account !== '')
receivableBlocks !== undefined &&
receivableBlocks.blocks[account?.address ?? ''] !== '' &&
receivableBlocksInfo !== undefined
const receivable = Object.entries(
accountReceivable?.blocks[account?.address ?? ''] ?? {}
receivableBlocks?.blocks[account?.address ?? ''] ?? {}
).map(([hash, { amount, source }]) => ({
hash,
amount,
from: source,
}))
const [listenedReceivables, setListenedReceivables] = useState<
ConfirmationMessage[]
>([])
const onConfirmation = useCallback(
(confirmation: ConfirmationMessage) => {
const alreadyHaveConfirmation =
accountHistory?.history !== '' &&
accountHistory?.history.some(
txn => txn.hash === confirmation.message.hash
) &&
receivable.some(txn => txn.hash === confirmation.message.hash)
if (!alreadyHaveConfirmation)
setListenedReceivables(prev => [...prev, confirmation])
},
[accountHistory, receivable]
)
useListenToConfirmations(onConfirmation)
return (
<div className={clsx('flex flex-col gap-6 w-full', className)}>
{hasReceivable && (
<section className="flex flex-col gap-3 w-full items-center">
<h2 className="text-2xl font-semibold text-purple-50">receivable</h2>
<ol className="flex flex-col gap-3 w-full">
{listenedReceivables.map(({ message, time }) => (
<li
key={message.hash}
className="bg-purple-50 shadow rounded px-3 py-3 flex items-center justify-between gap-2 text-black border-r-4 border-blue-500"
>
<button
className="contents"
onClick={() => receive(message.hash, message.amount)}
>
<ClockIcon className="w-6 flex-shrink-0 text-blue-500" />
<div className="overflow-hidden overflow-ellipsis text-left flex-1 whitespace-nowrap">
{Intl.DateTimeFormat([], {
day: '2-digit',
month: '2-digit',
year: '2-digit',
}).format(Number(time) * 1000)}{' '}
- {<span className="text-xs">{message.block.account}</span>}
</div>
<span className="flex-shrink-0 font-medium">
Ӿ{' '}
{rawToNanoDisplay(message.amount) === 'small' ? (
'<0.01'
) : rawToNanoDisplay(message.amount).startsWith('0.') ? (
<>
<span className="text-sm font-semibold">0</span>
{rawToNanoDisplay(message.amount).substring(1)}
</>
) : (
rawToNanoDisplay(message.amount)
)}
</span>
</button>
</li>
))}
{receivable.map(receivable => (
<li
key={receivable.hash}
@ -108,7 +48,10 @@ const RecentTransactions: FC<Props> = ({ className }) => {
>
<button
className="contents"
onClick={() => receive(receivable.hash, receivable.amount)}
onClick={async () => {
await receive(receivable.hash, receivable.amount)
onBlockReceived(receivable.hash)
}}
>
<ClockIcon className="w-6 flex-shrink-0 text-blue-500" />
@ -119,7 +62,7 @@ const RecentTransactions: FC<Props> = ({ className }) => {
year: '2-digit',
}).format(
Number(
receivableBlocksInfo!.blocks[receivable.hash]
receivableBlocksInfo.blocks[receivable.hash]
.local_timestamp
) * 1000
)}{' '}

View file

@ -1,11 +1,11 @@
import {
CogIcon,
DotsHorizontalIcon,
FingerPrintIcon,
HandIcon,
KeyIcon,
LibraryIcon,
MoonIcon,
PlusIcon,
UsersIcon,
} from '@heroicons/react/solid'
import clsx from 'clsx'
@ -59,7 +59,7 @@ const TopMenu: FC<Props> = () => {
)}
onClick={toggleAdvanced}
>
<PlusIcon className="w-full" />
<DotsHorizontalIcon className="w-full" />
</button>
<ul
role="menu"

View file

@ -1,3 +1,4 @@
import { validateWork } from 'nanocurrency'
import {
FC,
createContext,
@ -9,12 +10,7 @@ import {
} from 'react'
import computeWorkAsync from '../computeWorkAsync'
import {
addPrecomputedWork,
consumePrecomputedWork,
getAllAccounts,
putAccount,
} from '../db/accounts'
import { addPrecomputedWork, getAllAccounts, putAccount } from '../db/accounts'
import { AccountInfoCache } from '../types'
import fetchAccountInfo from '../xno/fetchAccountInfo'
@ -37,7 +33,7 @@ const refreshAccountFromNetwork = async (account: AccountInfoCache) => {
'error' in infoResponse ? null : infoResponse.confirmed_representative
const balance =
'error' in infoResponse ? null : infoResponse.confirmed_balance
const freshAccountInfo = {
const freshAccountInfo: AccountInfoCache = {
...account,
frontier,
representative,
@ -66,9 +62,13 @@ export const useAccounts = () => {
*/
export const useAccount = (index?: number) => {
const contextValue = useAccounts()
return index !== undefined
? contextValue.accounts?.[index]
: contextValue.currAccount
return useMemo(
() =>
index !== undefined
? contextValue.accounts?.[index]
: contextValue.currAccount,
[contextValue, index]
)
}
export const useCurrentAccount = () => useAccount()
@ -98,7 +98,13 @@ export const AccountProvider: FC = ({ children }) => {
const accounts: AccountContextValue['accounts'] = {}
accountList.forEach(async account => {
accounts[account.index] = account
if (account.precomputedWork === null) {
if (
account.precomputedWork === null ||
!validateWork({
work: account.precomputedWork,
blockHash: account.frontier ?? account.publicKey,
})
) {
const work = await computeWorkAsync(
account.frontier ?? account.publicKey,
{

View file

@ -8,7 +8,11 @@ import {
} from 'react'
import { getAllPreferences, putPreference } from '../db/preferences'
import { PreferenceName, PreferenceTypes } from '../db/types'
import {
PreferenceName,
PreferenceTypes,
ShowCurrencyPreference,
} from '../db/types'
import useDarkMode from '../hooks/useDarkMode'
export interface PreferenceContextValue {
@ -33,47 +37,49 @@ export const usePreferences = () => {
}
const initialState: PreferenceContextValue['preferences'] = {
darkMode: undefined,
biometricsAuth: undefined,
leftHanded: undefined,
showCurrencyDash: undefined,
darkMode: true,
biometricsAuth: true,
leftHanded: false,
showCurrencyDash: ShowCurrencyPreference.None,
}
export const PreferencesProvider: FC = ({ children }) => {
const [preferences, setPreferences] = useState<PreferenceTypes>(initialState)
useEffect(() => {
const fetchPreferencesFromIdb = async () => {
const preferenceList = await getAllPreferences()
const preferences: PreferenceContextValue['preferences'] = initialState
for (const preference of preferenceList) {
// @ts-expect-error i should type this better but should be fine for now
preferences[preference.name] = preference.value
}
setPreferences(preferences)
}
fetchPreferencesFromIdb()
}, [])
const { setDarkMode, isDarkMode } = useDarkMode()
const setPreference = useCallback(
<P extends PreferenceName>(
name: P,
value: Exclude<PreferenceTypes[P], undefined>
value: Exclude<PreferenceTypes[P], undefined>,
{ skipIdb = false } = { skipIdb: false }
) => {
setPreferences(prev => ({ ...prev, [name]: value }))
putPreference(name, value)
if (!skipIdb) putPreference(name, value)
// ? is there a better way to type this?
if (name === 'darkMode') setDarkMode(value as boolean)
if (name === 'darkMode' && isDarkMode !== value)
setDarkMode(value as boolean)
},
[setDarkMode]
[setDarkMode, isDarkMode]
)
useEffect(() => {
setPreference('darkMode', isDarkMode)
}, [isDarkMode, setPreference])
useEffect(() => {
const fetchPreferencesFromIdb = async () => {
const preferenceList = await getAllPreferences()
// todo i can change this to only change state once but i'm too sleepy now
for (const preference of preferenceList) {
// @ts-expect-error i should type this better but should be fine for now
setPreference(preference.name, preference.value, { skipIdb: true })
}
}
fetchPreferencesFromIdb()
}, [setPreference])
return (
<preferencesContext.Provider value={{ preferences, setPreference }}>
{children}

View file

@ -54,7 +54,7 @@ export const openDb = async (version = 1) => {
autoIncrement: true,
})
db.createObjectStore('preferences', {
keyPath: 'id',
keyPath: 'name',
autoIncrement: true,
})
},

View file

@ -1,30 +1,15 @@
import { useEffect, useState } from 'react'
import useSWR from 'swr'
import { useCurrentAccount } from '../context/accountContext'
import type { AccountHistoryResponse } from '../types'
import fetchAccountHistory from '../xno/fetchAccountHistory'
type ReturnValue =
| {
accountHistory: undefined
loading: true
}
| { accountHistory: AccountHistoryResponse; loading: false }
const useAccountHistory = (): ReturnValue => {
const [accountHistory, setAccountHistory] = useState<
AccountHistoryResponse | undefined
>(undefined)
const useAccountHistory = () => {
const account = useCurrentAccount()
useEffect(() => {
if (account !== undefined)
fetchAccountHistory(account.address).then(setAccountHistory)
}, [account])
const loading = accountHistory === undefined
return { accountHistory, loading } as ReturnValue
return useSWR<AccountHistoryResponse>(
account !== undefined ? `history:${account.address}` : null,
(key: string) => fetchAccountHistory(key.split(':')[1])
)
}
export default useAccountHistory

View file

@ -1,30 +1,15 @@
import { useEffect, useState } from 'react'
import useSWR from 'swr'
import { useCurrentAccount } from '../context/accountContext'
import { AccountInfoResponse } from '../types'
import fetchAccountInfo from '../xno/fetchAccountInfo'
type ReturnValue =
| {
accountInfo: undefined
loading: true
}
| { accountInfo: AccountInfoResponse; loading: false }
const useAccountInfo = (): ReturnValue => {
const [accountInfo, setAccountInfo] = useState<
AccountInfoResponse | undefined
>(undefined)
const useAccountInfo = () => {
const account = useCurrentAccount()
useEffect(() => {
if (account !== undefined)
fetchAccountInfo(account.address).then(setAccountInfo)
}, [account])
const loading = accountInfo === undefined
return { accountInfo, loading } as ReturnValue
return useSWR<AccountInfoResponse>(
account !== undefined ? `info:${account.address}` : null,
(key: string) => fetchAccountInfo(key.split(':')[1])
)
}
export default useAccountInfo

View file

@ -1,66 +1,92 @@
import { useCallback, useEffect, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import useSWR from 'swr'
import { useCurrentAccount } from '../context/accountContext'
import type { AccountReceivableResponse, BlocksInfoResponse } from '../types'
import type {
AccountReceivableResponse,
BlocksInfoResponse,
ConfirmationMessage,
} from '../types'
import fetchAccountReceivable from '../xno/fetchAccountReceivable'
import fetchBlocksInfo from '../xno/fetchBlocksInfo'
import useListenToReceivables from './useListenToReceivables'
type ReturnValue = (
| {
accountReceivable: undefined
blocksInfo: undefined
loading: true
}
| {
accountReceivable: AccountReceivableResponse
blocksInfo: BlocksInfoResponse
loading: false
}
) & {
mutate: (prev: {
accountReceivable: AccountReceivableResponse | undefined
blocksInfo: BlocksInfoResponse | undefined
}) => {
accountReceivable: AccountReceivableResponse | undefined
blocksInfo: BlocksInfoResponse | undefined
}
}
const useAccountReceivable = (): ReturnValue => {
const [accountReceivableWithInfo, setAccountReceivableWithInfo] = useState<{
accountReceivable: AccountReceivableResponse | undefined
blocksInfo: BlocksInfoResponse | undefined
}>({ accountReceivable: undefined, blocksInfo: undefined })
const useAccountReceivable = () => {
const account = useCurrentAccount()
useEffect(() => {
if (account !== undefined) {
const fetchReceivable = async () => {
const receivableBlocks = await fetchAccountReceivable(account.address)
const blocksInfo = await fetchBlocksInfo(
const { data: receivableBlocks, mutate: mutateReceivable } =
useSWR<AccountReceivableResponse>(
account !== undefined ? `receivable:${account.address}` : null,
(key: string) => fetchAccountReceivable(key.split(':')[1])
)
const { data: receivableBlocksInfo } = useSWR<BlocksInfoResponse>(
receivableBlocks !== undefined
? [
Object.values(receivableBlocks.blocks)
.map(blocks => Object.keys(blocks))
.flat()
)
setAccountReceivableWithInfo({
accountReceivable: receivableBlocks,
blocksInfo,
})
}
.join(','),
]
: null,
(key: string) => fetchBlocksInfo(key.split(','))
)
fetchReceivable()
}
}, [account])
const onBlockReceived = useCallback(
(hash: string) => {
mutateReceivable(async current => {
if (current === undefined || account === undefined) return current
const { blocks } = current
const currBlocks = blocks[account.address]
if (currBlocks === '') return current
const newBlocks = { ...currBlocks }
delete newBlocks[hash]
return { blocks: { [account.address]: newBlocks } }
})
},
[mutateReceivable, account]
)
const addReceivable = useCallback(
({
hash,
amount,
source,
}: {
hash: string
amount: string
source: string
}) => {
mutateReceivable(async current => {
if (current === undefined || account === undefined) return current
const { blocks } = current
const currBlocks = blocks[account.address]
if (currBlocks === '') return current
const newBlocks = { ...currBlocks, [hash]: { amount, source } }
return { blocks: { [account.address]: newBlocks } }
})
},
[mutateReceivable, account]
)
const onNewReceivable = useCallback(
(confirmation: ConfirmationMessage) => {
addReceivable({
hash: confirmation.message.hash,
amount: confirmation.message.amount,
source: confirmation.message.account,
})
},
[addReceivable]
)
useListenToReceivables(onNewReceivable)
const loading =
accountReceivableWithInfo.accountReceivable === undefined &&
accountReceivableWithInfo.blocksInfo === undefined
return {
...accountReceivableWithInfo,
loading,
mutate: setAccountReceivableWithInfo,
} as ReturnValue
receivableBlocks,
receivableBlocksInfo,
onBlockReceived,
}
}
export default useAccountReceivable

View file

@ -2,12 +2,13 @@ import { useEffect, useRef } from 'react'
import { useCurrentAccount } from '../context/accountContext'
import type { ConfirmationMessage } from '../types'
import { defaultUrls } from '../xno/constants'
/**
* _please don't forget to memo `onConfirmation`_ :)
* @param onConfirmation the callback to call with the new confirmation
*/
const useListenToConfirmations = (
const useListenToReceivables = (
onConfirmation: (confirmation: ConfirmationMessage) => void
) => {
const account = useCurrentAccount()
@ -15,7 +16,7 @@ const useListenToConfirmations = (
const wsRef = useRef<WebSocket>()
useEffect(() => {
wsRef.current = new WebSocket('wss://socket.nanos.cc/')
wsRef.current = new WebSocket(defaultUrls.ws)
return () => {
if (
wsRef.current?.readyState !== WebSocket.CLOSING &&
@ -44,7 +45,8 @@ const useListenToConfirmations = (
const parsed = JSON.parse(data) as ConfirmationMessage
if (
parsed.topic !== 'confirmation' ||
parsed.message.block.subtype !== 'send'
parsed.message.block.subtype !== 'send' ||
parsed.message.account !== account.address
)
return
onConfirmation(parsed)
@ -61,4 +63,4 @@ const useListenToConfirmations = (
}, [account, onConfirmation])
}
export default useListenToConfirmations
export default useListenToReceivables

View file

@ -4,3 +4,8 @@ export const zeroString =
export const receiveDiff = 'fffffe0000000000'
export const sendDiff = 'fffffff800000000'
export const defaultUrls = {
rpc: process.env.NEXT_PUBLIC_DEFAULT_NANO_NODE_RPC!,
ws: process.env.NEXT_PUBLIC_DEFAULT_NANO_NODE_WS!,
}

View file

@ -1,8 +1,9 @@
import fetcher from '../fetcher'
import { AccountHistoryResponse } from '../types'
import { defaultUrls } from './constants'
const fetchAccountHistory = (address: string, count = 20, head = undefined) =>
fetcher('https://proxy.powernode.cc/proxy', {
fetcher(defaultUrls.rpc, {
method: 'POST',
body: {
action: 'account_history',

View file

@ -1,8 +1,9 @@
import fetcher from '../fetcher'
import { AccountInfoResponse } from '../types'
import { defaultUrls } from './constants'
const fetchAccountInfo = (address: string) =>
fetcher('https://proxy.powernode.cc/proxy', {
fetcher(defaultUrls.rpc, {
method: 'POST',
body: {
action: 'account_info',

View file

@ -1,12 +1,13 @@
import fetcher from '../fetcher'
import type { AccountReceivableResponse } from '../types'
import { defaultUrls } from './constants'
const _fetchAccountReceivable = (
address: string,
count = 20,
version22 = false
) =>
fetcher('https://proxy.powernode.cc/proxy', {
fetcher(defaultUrls.rpc, {
method: 'POST',
body: {
action: version22 ? 'accounts_pending' : 'accounts_receivable',

View file

@ -1,8 +1,9 @@
import fetcher from '../fetcher'
import type { BlocksInfoResponse } from '../types'
import { defaultUrls } from './constants'
const fetchBlocksInfo = (hashes: string[]) =>
fetcher('https://proxy.powernode.cc/proxy', {
fetcher(defaultUrls.rpc, {
method: 'POST',
body: {
action: 'blocks_info',

View file

@ -7,6 +7,7 @@ import decryptSeed from '../decryptSeed'
import fetcher from '../fetcher'
import { ProcessResponse } from '../types'
import accountAtIndex from './accountAtIndex'
import { defaultUrls } from './constants'
const sendNano = async (
blockData: Parameters<typeof block['receive']>[0],
@ -18,18 +19,15 @@ const sendNano = async (
)
const signedBlock = block.receive(blockData, privateKey)
const processResponse = await fetcher<ProcessResponse>(
'https://proxy.powernode.cc/proxy',
{
method: 'POST',
body: {
action: 'process',
json_block: 'true',
subtype: 'receive',
block: signedBlock,
},
}
)
const processResponse = await fetcher<ProcessResponse>(defaultUrls.rpc, {
method: 'POST',
body: {
action: 'process',
json_block: 'true',
subtype: 'receive',
block: signedBlock,
},
})
if ('error' in processResponse) throw new Error()

View file

@ -6,6 +6,7 @@ import decryptSeed from '../decryptSeed'
import fetcher from '../fetcher'
import { ProcessResponse } from '../types'
import accountAtIndex from './accountAtIndex'
import { defaultUrls } from './constants'
const sendNano = async (
blockData: Parameters<typeof block['send']>[0],
@ -17,18 +18,15 @@ const sendNano = async (
)
const signedBlock = block.send(blockData, privateKey)
const processResponse = await fetcher<ProcessResponse>(
'https://proxy.powernode.cc/proxy',
{
method: 'POST',
body: {
action: 'process',
json_block: 'true',
subtype: 'send',
block: signedBlock,
},
}
)
const processResponse = await fetcher<ProcessResponse>(defaultUrls.rpc, {
method: 'POST',
body: {
action: 'process',
json_block: 'true',
subtype: 'send',
block: signedBlock,
},
})
if ('error' in processResponse) throw new Error()

View file

@ -32,7 +32,8 @@
"prettier": "^2.4.1",
"qrcode": "^1.5.0",
"react": "^17.0.2",
"react-dom": "^17.0.2"
"react-dom": "^17.0.2",
"swr": "^1.0.1"
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^3.1.1",

View file

@ -1,8 +1,10 @@
import type { AppProps } from 'next/app'
import { FC } from 'react'
import { SWRConfig } from 'swr'
import Layout from '../components/Layout'
import MemCacheProvider from '../lib/context/memCacheContextProvider'
import fetcher from '../lib/fetcher'
import useProtectedRoutes from '../lib/hooks/useProtectedRoutes'
import useSetupDb from '../lib/hooks/useSetupDb'
import useSetupServiceWorker from '../lib/hooks/useSetupServiceWorker'
@ -10,17 +12,19 @@ import '../styles/global.css'
const MyApp: FC<AppProps> = ({ Component, pageProps }) => {
useSetupServiceWorker()
const ready = useSetupDb(10)
const ready = useSetupDb()
const validatingCredential = useProtectedRoutes(!ready)
if (validatingCredential) return null // todo
return (
<MemCacheProvider>
<Layout>
<Component {...pageProps} />
</Layout>
</MemCacheProvider>
<SWRConfig value={{ fetcher }}>
<MemCacheProvider>
<Layout>
<Component {...pageProps} />
</Layout>
</MemCacheProvider>
</SWRConfig>
)
}

View file

@ -7,10 +7,16 @@ const Done: NextPage = () => {
<div className="flex flex-col h-full justify-start items-center text-center px-4 gap-2 text-purple-50">
<h1 className="text-9xl font-extrabold">3</h1>
<p className="text-3xl">you&apos;re done!</p>
<p className="text-xl">
<p className="text-xl mb-5">
all the buttons are now enabled and you can start using <b>zep</b> and{' '}
<b>nano</b>!
</p>
<button
className="dark:bg-gray-900 dark:text-purple-100 py-2 px-5 rounded text-xl bg-purple-50 font-bold text-gray-900"
onClick={() => push('/dashboard')}
>
go!
</button>
</div>
)
}

View file

@ -2,5 +2,6 @@
"expand target gospel goose oppose acquire genius hurdle trade size huge pact square silk canal bar curve shallow pistol push crowd glory slice news",
"81631b9773ab0f4ff0d61a0ae092ec564acc01912aedbd849c420e10b2c38c7edc2c5494f778d3122a5933261c3a09b17f1b1be33d3b068d3228529a24bf94b3",
"738b5cb3315dd267fc882f1388911162ee9a241c800bf583c07c1bbbc34c64a9c2099e01b5d5e3ab217012717e3ecfbe3f735af431c7e105e1719eeb03476af5",
"75edd150e09bada0f5c68fab14c0b385239cc396ef6600029dea0f7b66be63fa6a7d8ebe30aaff66634f583c4e68067c0de136e27dddc96be76d2ac5bb14ef71"
"75edd150e09bada0f5c68fab14c0b385239cc396ef6600029dea0f7b66be63fa6a7d8ebe30aaff66634f583c4e68067c0de136e27dddc96be76d2ac5bb14ef71",
"b6203f57196d244f7eb6971cef41a4cd4ce961e81ae8046f4f8274a4057cb77b4ef97ad3c25e14b50598c1243fa3253644b44e89c8648fd9c18b3703d36372bb"
]

View file

@ -1627,6 +1627,11 @@ depd@~1.1.2:
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
dequal@2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d"
integrity sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==
des.js@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843"
@ -4671,6 +4676,13 @@ swap-case@^1.1.0:
lower-case "^1.1.1"
upper-case "^1.1.1"
swr@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/swr/-/swr-1.0.1.tgz#15f62846b87ee000e52fa07812bb65eb62d79483"
integrity sha512-EPQAxSjoD4IaM49rpRHK0q+/NzcwoT8c0/Ylu/u3/6mFj/CWnQVjNJ0MV2Iuw/U+EJSd2TX5czdAwKPYZIG0YA==
dependencies:
dequal "2.0.2"
table@^6.0.9, table@^6.7.3:
version "6.7.3"
resolved "https://registry.yarnpkg.com/table/-/table-6.7.3.tgz#255388439715a738391bd2ee4cbca89a4d05a9b7"