chore: 🔧 add more currencies

This commit is contained in:
AP 2020-06-23 07:21:54 +02:00
parent b33242e7cd
commit dddf895f04
12 changed files with 188 additions and 78 deletions

View File

@ -136,8 +136,8 @@ BASE_PATH = '[Base path where you want to have thunderhub running i.e. '/btcpay'
# -----------
# Interface Configs
# -----------
THEME = 'dark' | 'light'; // Default: 'dark'
CURRENCY = 'sat' | 'btc' | 'eur' | 'usd'; // Default: 'sat'
THEME = 'dark' | 'light' // Default: 'dark'
CURRENCY = 'sat' | 'btc' | 'fiat' // Default: 'sat'
# -----------
# Privacy Configs

5
package-lock.json generated
View File

@ -18456,6 +18456,11 @@
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
},
"lodash.omit": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz",
"integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA="
},
"lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",

View File

@ -63,6 +63,7 @@
"lodash.debounce": "^4.0.8",
"lodash.groupby": "^4.6.0",
"lodash.merge": "^4.6.2",
"lodash.omit": "^4.5.0",
"next": "^9.4.4",
"numeral": "^2.0.6",
"qrcode.react": "^1.0.0",

View File

@ -56,14 +56,14 @@ const App = ({ Component, pageProps, initialConfig }) => (
App.getInitialProps = async props => {
const cookies = parseCookies(props.ctx.req);
if (!cookies?.config) {
return { initialConfig: {} };
if (!cookies?.theme) {
return { initialConfig: 'dark' };
}
try {
const initialConfig = JSON.parse(cookies.config);
const initialConfig = cookies.theme || 'dark';
return { initialConfig };
} catch (error) {
return { initialConfig: {} };
return { initialConfig: 'dark' };
}
};

View File

@ -20,7 +20,7 @@ export const AnimatedNumber = ({ amount = 0 }: AnimatedProps) => {
value: amount,
});
const { currency, displayValues } = useConfigState();
const { prices, dontShow } = usePriceState();
const { fiat, prices, dontShow } = usePriceState();
if (!displayValues) {
return <>-</>;
@ -32,8 +32,8 @@ export const AnimatedNumber = ({ amount = 0 }: AnimatedProps) => {
currency: currency !== 'btc' && currency !== 'sat' ? 'sat' : currency,
};
if (prices && !dontShow) {
const current: { last: number; symbol: string } = prices[currency] ?? {
if (currency === 'fiat' && prices && !dontShow) {
const current: { last: number; symbol: string } = prices[fiat] ?? {
last: 0,
symbol: '',
};

View File

@ -19,6 +19,8 @@ const generalCSS = css`
padding: 20px;
border-radius: 5px;
outline: none;
max-height: 80%;
overflow-y: auto;
@media (${mediaWidths.mobile}) {
top: 100%;
@ -27,7 +29,6 @@ const generalCSS = css`
width: 100%;
min-width: 325px;
max-height: 100%;
overflow-y: auto;
}
`;

View File

@ -19,7 +19,7 @@ export const Price = ({
override?: string;
}): JSX.Element => {
const { currency, displayValues } = useConfigState();
const { prices, dontShow } = usePriceState();
const { fiat, prices, dontShow } = usePriceState();
if (!displayValues) {
return <>-</>;
@ -31,8 +31,8 @@ export const Price = ({
currency: currency !== 'btc' && currency !== 'sat' ? 'sat' : currency,
};
if (prices && !dontShow) {
const current: { last: number; symbol: string } = prices[currency] ?? {
if (currency === 'fiat' && prices && !dontShow) {
const current: { last: number; symbol: string } = prices[fiat] ?? {
last: 0,
symbol: '',
};
@ -57,11 +57,12 @@ export const getPrice = (
currency: string,
displayValues: boolean,
priceContext: {
fiat: string;
dontShow: boolean;
prices?: { [key: string]: { last: number; symbol: string } };
}
) => ({ amount, breakNumber = false, override }: GetPriceProps): string => {
const { prices, dontShow } = priceContext;
const { prices, dontShow, fiat } = priceContext;
if (!displayValues) {
return '-';
@ -73,8 +74,8 @@ export const getPrice = (
currency: currency !== 'btc' && currency !== 'sat' ? 'sat' : currency,
};
if (prices && !dontShow) {
const current: { last: number; symbol: string } = prices[currency] ?? {
if (currency === 'fiat' && prices && !dontShow) {
const current: { last: number; symbol: string } = prices[fiat] ?? {
last: 0,
symbol: '',
};

View File

@ -1,9 +1,10 @@
import React, { createContext, useContext, useReducer, useEffect } from 'react';
import getConfig from 'next/config';
import Cookies from 'js-cookie';
import omit from 'lodash.omit';
const themeTypes = ['dark', 'light'];
const currencyTypes = ['sat', 'btc', 'EUR', 'USD'];
const currencyTypes = ['sat', 'btc', 'fiat'];
export type channelBarStyleTypes = 'normal' | 'compact' | 'ultracompact';
export type channelBarTypeTypes = 'balance' | 'fees' | 'size' | 'proportional';
@ -29,27 +30,29 @@ type State = {
};
type ConfigInitProps = {
initialConfig: State;
initialConfig: string;
};
type ActionType = {
type: 'change';
currency?: string;
theme?: string;
sidebar?: boolean;
multiNodeInfo?: boolean;
fetchFees?: boolean;
fetchPrices?: boolean;
displayValues?: boolean;
hideFee?: boolean;
hideNonVerified?: boolean;
maxFee?: number;
chatPollingSpeed?: number;
channelBarStyle?: channelBarStyleTypes;
channelBarType?: channelBarTypeTypes;
channelSort?: channelSortTypes;
sortDirection?: sortDirectionTypes;
};
type ActionType =
| {
type: 'change' | 'initChange';
currency?: string;
theme?: string;
sidebar?: boolean;
multiNodeInfo?: boolean;
fetchFees?: boolean;
fetchPrices?: boolean;
displayValues?: boolean;
hideFee?: boolean;
hideNonVerified?: boolean;
maxFee?: number;
chatPollingSpeed?: number;
channelBarStyle?: channelBarStyleTypes;
channelBarType?: channelBarTypeTypes;
channelSort?: channelSortTypes;
sortDirection?: sortDirectionTypes;
}
| { type: 'themeChange'; theme: string };
type Dispatch = (action: ActionType) => void;
@ -85,11 +88,27 @@ const initialState: State = {
const stateReducer = (state: State, action: ActionType): State => {
const { type, ...settings } = action;
switch (type) {
case 'change':
case 'initChange': {
return {
...state,
...settings,
};
}
case 'change': {
const newState = {
...state,
...settings,
};
localStorage.setItem('config', JSON.stringify(omit(newState, 'theme')));
return newState;
}
case 'themeChange': {
Cookies.set('theme', action.theme, { expires: 365, sameSite: 'strict' });
return {
...state,
theme: action.theme,
};
}
default:
return state;
}
@ -101,12 +120,13 @@ const ConfigProvider: React.FC<ConfigInitProps> = ({
}) => {
const [state, dispatch] = useReducer(stateReducer, {
...initialState,
...initialConfig,
theme: themeTypes.indexOf(initialConfig) > -1 ? initialConfig : 'dark',
});
useEffect(() => {
Cookies.set('config', state, { expires: 365, sameSite: 'strict' });
}, [state]);
const savedConfig = JSON.parse(localStorage.getItem('config') || '{}');
dispatch({ type: 'initChange', ...savedConfig });
}, []);
return (
<DispatchContext.Provider value={dispatch}>

View File

@ -1,4 +1,4 @@
import React, { createContext, useContext, useReducer } from 'react';
import React, { createContext, useContext, useReducer, useEffect } from 'react';
type PriceProps = {
last: number;
@ -7,6 +7,7 @@ type PriceProps = {
type State = {
dontShow: boolean;
fiat: string;
prices?: { [key: string]: PriceProps };
};
@ -19,6 +20,10 @@ type ActionType =
type: 'fetched';
state: ChangeState;
}
| {
type: 'change' | 'initChange';
fiat: string;
}
| {
type: 'dontShow';
};
@ -29,6 +34,7 @@ export const StateContext = createContext<State | undefined>(undefined);
export const DispatchContext = createContext<Dispatch | undefined>(undefined);
const initialState: State = {
fiat: 'EUR',
dontShow: true,
prices: { EUR: { last: 0, symbol: '€' } },
};
@ -38,7 +44,14 @@ const stateReducer = (state: State, action: ActionType): State => {
case 'dontShow':
return { ...initialState, dontShow: true };
case 'fetched':
return { ...initialState, ...action.state, dontShow: false };
return { ...state, ...action.state, dontShow: false };
case 'change': {
localStorage.setItem('fiat', action.fiat);
return { ...state, fiat: action.fiat };
}
case 'initChange': {
return { ...state, fiat: action.fiat };
}
default:
return state;
}
@ -47,6 +60,11 @@ const stateReducer = (state: State, action: ActionType): State => {
const PriceProvider = ({ children }) => {
const [state, dispatch] = useReducer(stateReducer, initialState);
useEffect(() => {
const fiat = localStorage.getItem('fiat') || 'EUR';
dispatch({ type: 'initChange', fiat });
}, []);
return (
<DispatchContext.Provider value={dispatch}>
<StateContext.Provider value={state}>{children}</StateContext.Provider>

View File

@ -110,6 +110,7 @@ export const NodeInfo = ({ isOpen, isBurger }: NodeInfoProps) => {
</SingleLine>
<SingleLine>
<Zap
size={18}
color={channelPending === 0 ? '#FFD300' : '#652EC7'}
fill={channelPending === 0 ? '#FFD300' : '#652EC7'}
/>

View File

@ -112,7 +112,7 @@ export const SideSettings = ({ isBurger }: SideSettingsProps) => {
currency:
sidebar || isBurger ? value : getNextValue(correctArray, value),
});
type === 'theme' && dispatch({ type: 'change', theme: value });
type === 'theme' && dispatch({ type: 'themeChange', theme: value });
}}
>
{type === 'currency' && <Symbol>{text}</Symbol>}
@ -146,8 +146,7 @@ export const SideSettings = ({ isBurger }: SideSettingsProps) => {
<IconRow>
{renderIcon('currency', 'sat', 'S')}
{renderIcon('currency', 'btc', 'â‚¿')}
{!dontShow && renderIcon('currency', 'EUR', '€')}
{!dontShow && renderIcon('currency', 'USD', '$')}
{!dontShow && renderIcon('currency', 'fiat', 'F')}
</IconRow>
<IconRow>
{renderIcon('theme', 'light', '', false, Sun)}
@ -163,8 +162,7 @@ export const SideSettings = ({ isBurger }: SideSettingsProps) => {
<IconRow>
{renderIcon('currency', 'sat', 'S')}
{renderIcon('currency', 'btc', 'â‚¿')}
{!dontShow && renderIcon('currency', 'EUR', '€')}
{!dontShow && renderIcon('currency', 'USD', '$')}
{!dontShow && renderIcon('currency', 'fiat', 'F')}
</IconRow>
<IconRow>
{renderIcon('theme', 'light', '', false, Sun)}

View File

@ -1,24 +1,32 @@
import React from 'react';
import React, { useState } from 'react';
import { useAccountState, CLIENT_ACCOUNT } from 'src/context/AccountContext';
import { ColorButton } from 'src/components/buttons/colorButton/ColorButton';
import Modal from 'src/components/modal/ReactModal';
import numeral from 'numeral';
import { themeColors } from 'src/styles/Themes';
import {
CardWithTitle,
SubTitle,
Card,
Sub4Title,
SingleLine,
SubCard,
DarkSubTitle,
} from '../../components/generic/Styled';
import { SettingsLine } from '../../../pages/settings';
import { useConfigState, useConfigDispatch } from '../../context/ConfigContext';
import {
MultiButton,
SingleButton,
} from '../../components/buttons/multiButton/MultiButton';
import { usePriceState } from '../../context/PriceContext';
import { usePriceState, usePriceDispatch } from '../../context/PriceContext';
export const InterfaceSettings = () => {
const { dontShow } = usePriceState();
const [changeFiat, changeFiatSet] = useState(false);
const { fiat, prices, dontShow } = usePriceState();
const { theme, currency, multiNodeInfo } = useConfigState();
const dispatch = useConfigDispatch();
const priceDispatch = usePriceDispatch();
const { accounts } = useAccountState();
@ -36,7 +44,7 @@ export const InterfaceSettings = () => {
selected={current === value}
onClick={() => {
localStorage.setItem(type, value);
type === 'theme' && dispatch({ type: 'change', theme: value });
type === 'theme' && dispatch({ type: 'themeChange', theme: value });
type === 'currency' && dispatch({ type: 'change', currency: value });
type === 'nodeInfo' &&
dispatch({
@ -49,36 +57,93 @@ export const InterfaceSettings = () => {
</SingleButton>
);
const handleFiatClick = (fiatCurrency: string) => {
changeFiatSet(false);
priceDispatch({ type: 'change', fiat: fiatCurrency });
};
const renderFiat = () => {
const cards = [];
for (const key in prices) {
if (Object.prototype.hasOwnProperty.call(prices, key)) {
const element = prices[key];
if (!element || !element.last || !element.symbol) return;
const isCurrent = fiat === key;
cards.push(
<SubCard color={isCurrent ? themeColors.blue2 : undefined} key={key}>
<SingleLine>
{key}
<DarkSubTitle>{`${element.symbol} ${numeral(element.last).format(
'0,0'
)}`}</DarkSubTitle>
<ColorButton
onClick={() => handleFiatClick(key)}
disabled={isCurrent}
arrow={true}
>
Select
</ColorButton>
</SingleLine>
</SubCard>
);
}
}
return cards;
};
return (
<CardWithTitle>
<SubTitle>Interface</SubTitle>
<Card>
<SettingsLine>
<Sub4Title>Theme:</Sub4Title>
<MultiButton>
{renderButton('Light', 'light', 'theme', theme)}
{renderButton('Dark', 'dark', 'theme', theme)}
</MultiButton>
</SettingsLine>
{viewOnlyAccounts.length > 1 && (
<>
<CardWithTitle>
<SubTitle>Interface</SubTitle>
<Card>
<SettingsLine>
<Sub4Title>Show all accounts on homepage:</Sub4Title>
<Sub4Title>Theme</Sub4Title>
<MultiButton>
{renderButton('Yes', 'true', 'nodeInfo', `${multiNodeInfo}`)}
{renderButton('No', 'false', 'nodeInfo', `${multiNodeInfo}`)}
{renderButton('Light', 'light', 'theme', theme)}
{renderButton('Dark', 'dark', 'theme', theme)}
</MultiButton>
</SettingsLine>
)}
<SettingsLine>
<Sub4Title>Currency:</Sub4Title>
<MultiButton margin={'0 0 0 16px'}>
{renderButton('Satoshis', 'sat', 'currency', currency)}
{renderButton('Bitcoin', 'btc', 'currency', currency)}
{!dontShow && renderButton('Euro', 'EUR', 'currency', currency)}
{!dontShow && renderButton('USD', 'USD', 'currency', currency)}
</MultiButton>
</SettingsLine>
</Card>
</CardWithTitle>
{viewOnlyAccounts.length > 1 && (
<SettingsLine>
<Sub4Title>Show all accounts on homepage</Sub4Title>
<MultiButton>
{renderButton('Yes', 'true', 'nodeInfo', `${multiNodeInfo}`)}
{renderButton('No', 'false', 'nodeInfo', `${multiNodeInfo}`)}
</MultiButton>
</SettingsLine>
)}
<SettingsLine>
<Sub4Title>Currency</Sub4Title>
<MultiButton margin={'0 0 0 16px'}>
{renderButton('Satoshis', 'sat', 'currency', currency)}
{renderButton('Bitcoin', 'btc', 'currency', currency)}
{!dontShow && renderButton('Fiat', 'fiat', 'currency', currency)}
</MultiButton>
</SettingsLine>
{currency === 'fiat' && !dontShow && (
<SettingsLine>
<SingleLine>
<Sub4Title>Fiat</Sub4Title>
<DarkSubTitle
withMargin={'0 0 0 8px'}
>{`(${fiat})`}</DarkSubTitle>
</SingleLine>
<ColorButton onClick={() => changeFiatSet(true)} arrow={true}>
Change
</ColorButton>
</SettingsLine>
)}
</Card>
</CardWithTitle>
<Modal
isOpen={changeFiat}
closeCallback={() => {
changeFiatSet(false);
}}
>
{renderFiat()}
</Modal>
</>
);
};