mirror of
https://github.com/kremalicious/blowfish.git
synced 2024-11-22 17:50:11 +01:00
refactor, add global error state
This commit is contained in:
parent
2efee0ec73
commit
33532c33d3
1
.env.example
Normal file
1
.env.example
Normal file
@ -0,0 +1 @@
|
|||||||
|
ETHERSCAN_API_KEY=
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ dist
|
|||||||
coverage
|
coverage
|
||||||
.next
|
.next
|
||||||
out
|
out
|
||||||
|
.env
|
@ -53,6 +53,7 @@
|
|||||||
"babel-jest": "^25.1.0",
|
"babel-jest": "^25.1.0",
|
||||||
"copy": "^0.3.2",
|
"copy": "^0.3.2",
|
||||||
"cross-env": "^7.0.0",
|
"cross-env": "^7.0.0",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
"electron": "^8.0.1",
|
"electron": "^8.0.1",
|
||||||
"electron-builder": "^22.3.2",
|
"electron-builder": "^22.3.2",
|
||||||
"electron-devtools-installer": "^2.2.4",
|
"electron-devtools-installer": "^2.2.4",
|
||||||
|
@ -2,8 +2,6 @@ import React from 'react'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import posed, { PoseGroup } from 'react-pose'
|
import posed, { PoseGroup } from 'react-pose'
|
||||||
import shortid from 'shortid'
|
import shortid from 'shortid'
|
||||||
import AppProvider from './store/AppProvider'
|
|
||||||
import PriceProvider from './store/PriceProvider'
|
|
||||||
import { defaultAnimation } from './components/Animations'
|
import { defaultAnimation } from './components/Animations'
|
||||||
import Titlebar from './components/Titlebar'
|
import Titlebar from './components/Titlebar'
|
||||||
import styles from './Layout.module.css'
|
import styles from './Layout.module.css'
|
||||||
@ -12,16 +10,14 @@ const Animation = posed.div(defaultAnimation)
|
|||||||
|
|
||||||
export default function Layout({ children }) {
|
export default function Layout({ children }) {
|
||||||
return (
|
return (
|
||||||
<PriceProvider>
|
<>
|
||||||
<AppProvider>
|
|
||||||
{process.platform === 'darwin' && <Titlebar />}
|
{process.platform === 'darwin' && <Titlebar />}
|
||||||
<div className={styles.app}>
|
<div className={styles.app}>
|
||||||
<PoseGroup animateOnMount>
|
<PoseGroup animateOnMount>
|
||||||
<Animation key={shortid.generate()}>{children}</Animation>
|
<Animation key={shortid.generate()}>{children}</Animation>
|
||||||
</PoseGroup>
|
</PoseGroup>
|
||||||
</div>
|
</div>
|
||||||
</AppProvider>
|
</>
|
||||||
</PriceProvider>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// eslint-disable-next-line no-unused-vars
|
require('dotenv').config()
|
||||||
const withSvgr = (nextConfig = {}, nextComposePlugins = {}) => {
|
|
||||||
|
const withSvgr = (nextConfig = {}) => {
|
||||||
return Object.assign({}, nextConfig, {
|
return Object.assign({}, nextConfig, {
|
||||||
webpack(config, options) {
|
webpack(config, options) {
|
||||||
config.module.rules.push({
|
config.module.rules.push({
|
||||||
@ -23,10 +24,19 @@ const withSvgr = (nextConfig = {}, nextComposePlugins = {}) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = withSvgr({
|
const withElectron = (nextConfig = {}) => {
|
||||||
|
return Object.assign({}, nextConfig, {
|
||||||
webpack: config => {
|
webpack: config => {
|
||||||
config.target = 'electron-renderer'
|
config.target = 'electron-renderer'
|
||||||
return config
|
return config
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = withSvgr(
|
||||||
|
withElectron({
|
||||||
|
env: {
|
||||||
|
ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY
|
||||||
},
|
},
|
||||||
exportPathMap() {
|
exportPathMap() {
|
||||||
return {
|
return {
|
||||||
@ -34,4 +44,5 @@ module.exports = withSvgr({
|
|||||||
'/preferences': { page: '/preferences' }
|
'/preferences': { page: '/preferences' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
)
|
||||||
|
@ -2,6 +2,8 @@ import React, { useEffect } from 'react'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import Router from 'next/router'
|
import Router from 'next/router'
|
||||||
// import { ipcRenderer } from 'electron'
|
// import { ipcRenderer } from 'electron'
|
||||||
|
import AppProvider from '../store/AppProvider'
|
||||||
|
import PriceProvider from '../store/PriceProvider'
|
||||||
import Layout from '../Layout'
|
import Layout from '../Layout'
|
||||||
|
|
||||||
import '../global.css'
|
import '../global.css'
|
||||||
@ -14,9 +16,13 @@ export default function App({ Component, pageProps }) {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<PriceProvider>
|
||||||
|
<AppProvider>
|
||||||
<Layout>
|
<Layout>
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
</Layout>
|
</Layout>
|
||||||
|
</AppProvider>
|
||||||
|
</PriceProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import IconCog from '../images/cog.svg'
|
|||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const { isLoading, needsConfig } = useContext(AppContext)
|
const { isLoading, error, needsConfig } = useContext(AppContext)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -24,6 +24,8 @@ export default function Home() {
|
|||||||
|
|
||||||
{needsConfig ? (
|
{needsConfig ? (
|
||||||
<Welcome />
|
<Welcome />
|
||||||
|
) : error ? (
|
||||||
|
<div className={styles.error}>{error}</div>
|
||||||
) : isLoading ? (
|
) : isLoading ? (
|
||||||
<Spinner />
|
<Spinner />
|
||||||
) : (
|
) : (
|
||||||
|
@ -32,3 +32,8 @@
|
|||||||
justify-items: start;
|
justify-items: start;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: lightcoral;
|
||||||
|
}
|
||||||
|
@ -10,7 +10,7 @@ import { refreshInterval, conversions, oceanTokenContract } from '../../config'
|
|||||||
|
|
||||||
async function getBalance(account) {
|
async function getBalance(account) {
|
||||||
const json = await fetchData(
|
const json = await fetchData(
|
||||||
`https://api.etherscan.io/api?module=account&action=tokenbalance&contractaddress=${oceanTokenContract}&address=${account}&tag=latest`
|
`https://api.etherscan.io/api?module=account&action=tokenbalance&contractaddress=${oceanTokenContract}&address=${account}&tag=latest&apikey=${process.env.ETHERSCAN_API_KEY}`
|
||||||
)
|
)
|
||||||
|
|
||||||
const balance = unit.fromWei(`${json.result}`, 'ether')
|
const balance = unit.fromWei(`${json.result}`, 'ether')
|
||||||
@ -24,18 +24,26 @@ export default function AppProvider({ children }) {
|
|||||||
const [needsConfig, setNeedsConfig] = useState(false)
|
const [needsConfig, setNeedsConfig] = useState(false)
|
||||||
const [currency, setCurrency] = useState('ocean')
|
const [currency, setCurrency] = useState('ocean')
|
||||||
const [accentColor, setAccentColor] = useState('#f6388a')
|
const [accentColor, setAccentColor] = useState('#f6388a')
|
||||||
|
const [error, setError] = useState()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// listener for accent color
|
// listener for accent color
|
||||||
|
if (process.env.NODE_ENV !== 'test') {
|
||||||
global.ipcRenderer.on('accent-color', (evt, accentColor) => {
|
global.ipcRenderer.on('accent-color', (evt, accentColor) => {
|
||||||
setAccentColor(accentColor)
|
setAccentColor(accentColor)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function init() {
|
async function init() {
|
||||||
|
try {
|
||||||
await setBalances()
|
await setBalances()
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error.message)
|
||||||
|
setError(error.message)
|
||||||
|
}
|
||||||
|
|
||||||
// listener for touchbar
|
// listener for touchbar
|
||||||
global.ipcRenderer.on('setCurrency', (evt, currency) =>
|
global.ipcRenderer.on('setCurrency', (evt, currency) =>
|
||||||
@ -96,9 +104,9 @@ export default function AppProvider({ children }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toggleCurrencies(currency) {
|
function toggleCurrencies(currency) {
|
||||||
|
setCurrency(currency)
|
||||||
const pricesNew = Array.from(prices)
|
const pricesNew = Array.from(prices)
|
||||||
global.ipcRenderer.send('currency-updated', pricesNew, currency)
|
global.ipcRenderer.send('currency-updated', pricesNew, currency)
|
||||||
setCurrency(currency)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const context = {
|
const context = {
|
||||||
@ -107,8 +115,9 @@ export default function AppProvider({ children }) {
|
|||||||
currency,
|
currency,
|
||||||
needsConfig,
|
needsConfig,
|
||||||
accentColor,
|
accentColor,
|
||||||
toggleCurrencies: currency => toggleCurrencies(currency),
|
error,
|
||||||
setBalances: () => setBalances()
|
toggleCurrencies,
|
||||||
|
setBalances
|
||||||
}
|
}
|
||||||
|
|
||||||
return <AppContext.Provider value={context}>{children}</AppContext.Provider>
|
return <AppContext.Provider value={context}>{children}</AppContext.Provider>
|
||||||
|
@ -41,10 +41,14 @@ export default function PriceProvider({ children }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function init() {
|
async function init() {
|
||||||
|
try {
|
||||||
const { newPrices, newPriceChanges } = await fetchAndSetPrices()
|
const { newPrices, newPriceChanges } = await fetchAndSetPrices()
|
||||||
setPrices(newPrices)
|
setPrices(newPrices)
|
||||||
setPriceChanges(newPriceChanges)
|
setPriceChanges(newPriceChanges)
|
||||||
global.ipcRenderer.send('prices-updated', Array.from(newPrices)) // convert Map to array, ipc messages seem to kill it
|
global.ipcRenderer.send('prices-updated', Array.from(newPrices)) // convert Map to array, ipc messages seem to kill it
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error.message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init()
|
init()
|
||||||
|
22
tests/Providers.test.jsx
Normal file
22
tests/Providers.test.jsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { render, waitForElement } from '@testing-library/react'
|
||||||
|
import AppProvider from '../src/renderer/store/AppProvider'
|
||||||
|
import PriceProvider from '../src/renderer/store/PriceProvider'
|
||||||
|
import { PriceContext } from '../src/renderer/store/createContext'
|
||||||
|
import { priceContext } from './__fixtures__/context'
|
||||||
|
|
||||||
|
describe('Providers', () => {
|
||||||
|
it('PriceProvider', async () => {
|
||||||
|
const { getByText } = render(<PriceProvider>Hello</PriceProvider>)
|
||||||
|
await waitForElement(() => getByText('Hello'))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('AppProvider', async () => {
|
||||||
|
const { getByText } = render(
|
||||||
|
<PriceContext.Provider value={priceContext}>
|
||||||
|
<AppProvider>Hello</AppProvider>
|
||||||
|
</PriceContext.Provider>
|
||||||
|
)
|
||||||
|
await waitForElement(() => getByText('Hello'))
|
||||||
|
})
|
||||||
|
})
|
@ -1,10 +0,0 @@
|
|||||||
const global = {
|
|
||||||
ipcRenderer: {
|
|
||||||
on: () => jest.fn()
|
|
||||||
},
|
|
||||||
store: {
|
|
||||||
has: () => jest.fn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = global
|
|
Loading…
Reference in New Issue
Block a user