Changeset View
Changeset View
Standalone View
Standalone View
web/cashtab/src/components/App.js
import React, { useState } from 'react'; | import React, { useState } from 'react'; | ||||
import 'antd/dist/antd.less'; | import 'antd/dist/antd.less'; | ||||
import { Spin } from 'antd'; | import { Spin } from 'antd'; | ||||
import { | import { | ||||
CashLoadingIcon, | CashLoadingIcon, | ||||
HomeIcon, | HomeIcon, | ||||
SendIcon, | SendIcon, | ||||
ReceiveIcon, | ReceiveIcon, | ||||
SettingsIcon, | SettingsIcon, | ||||
} from '@components/Common/CustomIcons'; | } from 'components/Common/CustomIcons'; | ||||
import '../index.css'; | import '../index.css'; | ||||
import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'; | import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'; | ||||
import { theme } from '@assets/styles/theme'; | import { theme } from 'assets/styles/theme'; | ||||
import Home from '@components/Home/Home'; | import Home from 'components/Home/Home'; | ||||
import Receive from '@components/Receive/Receive'; | import Receive from 'components/Receive/Receive'; | ||||
import Tokens from '@components/Tokens/Tokens'; | import Tokens from 'components/Tokens/Tokens'; | ||||
import Send from '@components/Send/Send'; | import Send from 'components/Send/Send'; | ||||
import SendToken from '@components/Send/SendToken'; | import SendToken from 'components/Send/SendToken'; | ||||
import Configure from '@components/Configure/Configure'; | import Configure from 'components/Configure/Configure'; | ||||
import NotFound from '@components/NotFound'; | import NotFound from 'components/NotFound'; | ||||
import CashTab from '@assets/cashtab_xec.png'; | import CashTab from 'assets/cashtab_xec.png'; | ||||
import './App.css'; | import './App.css'; | ||||
import { WalletContext } from '@utils/context'; | import { WalletContext } from 'utils/context'; | ||||
import { isValidStoredWallet } from '@utils/cashMethods'; | import { isValidStoredWallet } from 'utils/cashMethods'; | ||||
import { | import { | ||||
Route, | Route, | ||||
Redirect, | Redirect, | ||||
Switch, | Switch, | ||||
useLocation, | useLocation, | ||||
useHistory, | useHistory, | ||||
} from 'react-router-dom'; | } from 'react-router-dom'; | ||||
// Easter egg imports not used in extension/src/components/App.js | // Extension-only import used for open in new tab link | ||||
import TabCash from '@assets/tabcash.png'; | import PopOut from 'assets/popout.svg'; | ||||
import { checkForTokenById } from '@utils/tokenMethods.js'; | |||||
// Biometric security import not used in extension/src/components/App.js | |||||
import ProtectableComponentWrapper from './Authentication/ProtectableComponentWrapper'; | |||||
const GlobalStyle = createGlobalStyle` | const GlobalStyle = createGlobalStyle` | ||||
*::placeholder { | *::placeholder { | ||||
color: ${props => props.theme.forms.placeholder} !important; | color: ${props => props.theme.forms.placeholder} !important; | ||||
} | } | ||||
*::selection { | *::selection { | ||||
background: ${props => props.theme.eCashBlue} !important; | background: ${props => props.theme.eCashBlue} !important; | ||||
} | } | ||||
.ant-modal-content, .ant-modal-header, .ant-modal-title { | .ant-modal-content, .ant-modal-header, .ant-modal-title { | ||||
background-color: ${props => props.theme.modal.background} !important; | background-color: ${props => props.theme.modal.background} !important; | ||||
color: ${props => props.theme.modal.color} !important; | color: ${props => props.theme.modal.color} !important; | ||||
} | } | ||||
.ant-modal-content svg { | .ant-modal-content svg { | ||||
fill: ${props => props.theme.modal.color}; | fill: ${props => props.theme.modal.color}; | ||||
} | } | ||||
.ant-modal-footer button { | .ant-modal-footer button { | ||||
background-color: ${props => | background-color: ${props => | ||||
props.theme.modal.buttonBackground} !important; | props.theme.modal.buttonBackground} !important; | ||||
color: ${props => props.theme.modal.color} !important; | color: ${props => props.theme.modal.color} !important; | ||||
border-color: ${props => props.theme.modal.border} !important; | border-color: ${props => props.theme.modal.border} !important; | ||||
:hover { | :hover { | ||||
background-color: ${props => props.theme.eCashBlue} !important; | background-color: ${props => props.theme.eCashBlue} !important; | ||||
} | } | ||||
} | } | ||||
.ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button, .ant-modal > button, .ant-modal-confirm-btns > button, .ant-modal-footer > button, #cropControlsConfirm { | .ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button, .ant-modal > button, .ant-modal-confirm-btns > button, .ant-modal-footer > button, #cropControlsConfirm{ | ||||
border-radius: 3px; | border-radius: 3px; | ||||
border-radius: 3px; | |||||
background-color: ${props => | background-color: ${props => | ||||
props.theme.modal.buttonBackground} !important; | props.theme.modal.buttonBackground} !important; | ||||
color: ${props => props.theme.modal.color} !important; | color: ${props => props.theme.modal.color} !important; | ||||
border-color: ${props => props.theme.modal.border} !important; | border-color: ${props => props.theme.modal.border} !important; | ||||
:hover { | :hover { | ||||
background-color: ${props => props.theme.eCashBlue} !important; | background-color: ${props => props.theme.eCashBlue} !important; | ||||
} | } | ||||
text-shadow: none !important; | text-shadow: none !important; | ||||
text-shadow: none !important; | |||||
} | } | ||||
.ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button:hover,.ant-modal-confirm-btns > button:hover, .ant-modal-footer > button:hover, #cropControlsConfirm:hover { | .ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button:hover,.ant-modal-confirm-btns > button:hover, .ant-modal-footer > button:hover, #cropControlsConfirm:hover { | ||||
color: ${props => props.theme.contrast}; | color: ${props => props.theme.contrast}; | ||||
transition: all 0.3s; | transition: all 0.3s; | ||||
background-color: ${props => props.theme.eCashBlue}; | background-color: ${props => props.theme.eCashBlue}; | ||||
border-color: ${props => props.theme.eCashBlue}; | border-color: ${props => props.theme.eCashBlue}; | ||||
} | } | ||||
.selectedCurrencyOption, .ant-select-dropdown { | .selectedCurrencyOption, .ant-select-dropdown { | ||||
text-align: left; | text-align: left; | ||||
color: ${props => props.theme.contrast} !important; | color: ${props => props.theme.contrast} !important; | ||||
background-color: ${props => | background-color: ${props => | ||||
props.theme.collapses.expandedBackground} !important; | props.theme.collapses.expandedBackground} !important; | ||||
} | } | ||||
Show All 16 Lines | const GlobalStyle = createGlobalStyle` | ||||
} | } | ||||
.ant-slider-rail { | .ant-slider-rail { | ||||
background-color: ${props => props.theme.forms.border} !important; | background-color: ${props => props.theme.forms.border} !important; | ||||
} | } | ||||
.ant-slider-track { | .ant-slider-track { | ||||
background-color: ${props => props.theme.eCashBlue} !important; | background-color: ${props => props.theme.eCashBlue} !important; | ||||
} | } | ||||
.ant-descriptions-bordered .ant-descriptions-row { | .ant-descriptions-bordered .ant-descriptions-row { | ||||
background: ${props => props.theme.contrast}; | background: ${props => props.theme.contrast}; | ||||
} | } | ||||
.ant-modal-confirm-content, .ant-modal-confirm-title { | .ant-modal-confirm-content, .ant-modal-confirm-title { | ||||
color: ${props => props.theme.contrast} !important; | color: ${props => props.theme.contrast} !important; | ||||
} | } | ||||
`; | `; | ||||
const CustomApp = styled.div` | const CustomApp = styled.div` | ||||
text-align: center; | text-align: center; | ||||
font-family: 'Gilroy', sans-serif; | |||||
font-family: 'Poppins', sans-serif; | font-family: 'Poppins', sans-serif; | ||||
background-color: ${props => props.theme.backgroundColor}; | background-color: ${props => props.theme.backgroundColor}; | ||||
background-size: 100px 171px; | background-size: 100px 171px; | ||||
background-image: ${props => props.theme.backgroundImage}; | background-image: ${props => props.theme.backgroundImage}; | ||||
background-attachment: fixed; | background-attachment: fixed; | ||||
`; | `; | ||||
const Footer = styled.div` | const Footer = styled.div` | ||||
Show All 26 Lines | export const NavButton = styled.button` | ||||
font-size: 10px; | font-size: 10px; | ||||
svg { | svg { | ||||
fill: ${props => props.theme.contrast}; | fill: ${props => props.theme.contrast}; | ||||
width: 26px; | width: 26px; | ||||
height: auto; | height: auto; | ||||
} | } | ||||
${({ active, ...props }) => | ${({ active, ...props }) => | ||||
active && | active && | ||||
` | ` | ||||
color: ${props.theme.navActive}; | color: ${props.theme.navActive}; | ||||
svg { | svg { | ||||
fill: ${props.theme.navActive}; | fill: ${props.theme.navActive}; | ||||
} | } | ||||
`} | `} | ||||
`; | `; | ||||
export const WalletBody = styled.div` | export const WalletBody = styled.div` | ||||
display: flex; | display: flex; | ||||
align-items: center; | align-items: center; | ||||
justify-content: center; | justify-content: center; | ||||
width: 100%; | width: 100%; | ||||
Show All 15 Lines | @media (max-width: 768px) { | ||||
-moz-box-shadow: none; | -moz-box-shadow: none; | ||||
box-shadow: none; | box-shadow: none; | ||||
} | } | ||||
`; | `; | ||||
export const HeaderCtn = styled.div` | export const HeaderCtn = styled.div` | ||||
display: flex; | display: flex; | ||||
align-items: center; | align-items: center; | ||||
justify-content: center; | justify-content: space-between; | ||||
width: 100%; | width: 100%; | ||||
padding: 15px 0; | padding: 15px; | ||||
`; | `; | ||||
export const CashTabLogo = styled.img` | export const CashTabLogo = styled.img` | ||||
width: 120px; | width: 120px; | ||||
@media (max-width: 768px) { | @media (max-width: 768px) { | ||||
width: 110px; | width: 110px; | ||||
} | } | ||||
`; | `; | ||||
// AbcLogo styled component not included in extension, replaced by open in new tab link | // Extension only styled components | ||||
export const AbcLogo = styled.img` | const OpenInTabBtn = styled.button` | ||||
width: 150px; | background: none; | ||||
@media (max-width: 768px) { | border: none; | ||||
width: 120px; | |||||
} | |||||
`; | `; | ||||
// Easter egg styled component not used in extension/src/components/App.js | const ExtTabImg = styled.img` | ||||
export const EasterEgg = styled.img` | max-width: 20px; | ||||
position: fixed; | |||||
bottom: -195px; | |||||
margin: 0; | |||||
right: 10%; | |||||
transition-property: bottom; | |||||
transition-duration: 1.5s; | |||||
transition-timing-function: ease-out; | |||||
:hover { | |||||
bottom: 0; | |||||
} | |||||
@media screen and (max-width: 1250px) { | |||||
display: none; | |||||
} | |||||
`; | `; | ||||
const App = () => { | const App = () => { | ||||
const ContextValue = React.useContext(WalletContext); | const ContextValue = React.useContext(WalletContext); | ||||
const { wallet, loading } = ContextValue; | const { wallet, loading } = ContextValue; | ||||
const [loadingUtxosAfterSend, setLoadingUtxosAfterSend] = useState(false); | const [loadingUtxosAfterSend, setLoadingUtxosAfterSend] = useState(false); | ||||
// If wallet is unmigrated, do not show page until it has migrated | // If wallet is unmigrated, do not show page until it has migrated | ||||
// An invalid wallet will be validated/populated after the next API call, ETA 10s | // An invalid wallet will be validated/populated after the next API call, ETA 10s | ||||
const validWallet = isValidStoredWallet(wallet); | const validWallet = isValidStoredWallet(wallet); | ||||
const location = useLocation(); | const location = useLocation(); | ||||
const history = useHistory(); | const history = useHistory(); | ||||
const selectedKey = | const selectedKey = | ||||
location && location.pathname ? location.pathname.substr(1) : ''; | location && location.pathname ? location.pathname.substr(1) : ''; | ||||
// openInTab is an extension-only method | |||||
// Easter egg boolean not used in extension/src/components/App.js | const openInTab = () => { | ||||
const hasTab = validWallet | window.open(`index.html#/${selectedKey}`); | ||||
? checkForTokenById( | }; | ||||
wallet.state.tokens, | |||||
'50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e', | |||||
) | |||||
: false; | |||||
return ( | return ( | ||||
<ThemeProvider theme={theme}> | <ThemeProvider theme={theme}> | ||||
<GlobalStyle /> | <GlobalStyle /> | ||||
<Spin | <Spin | ||||
spinning={ | spinning={ | ||||
loading || loadingUtxosAfterSend || (wallet && !validWallet) | loading || loadingUtxosAfterSend || (wallet && !validWallet) | ||||
} | } | ||||
indicator={CashLoadingIcon} | indicator={CashLoadingIcon} | ||||
> | > | ||||
<CustomApp> | <CustomApp> | ||||
<WalletBody> | <WalletBody> | ||||
<WalletCtn> | <WalletCtn> | ||||
<HeaderCtn> | <HeaderCtn> | ||||
<CashTabLogo src={CashTab} alt="cashtab" /> | <CashTabLogo src={CashTab} alt="cashtab" /> | ||||
{/*Begin component not included in extension as desktop only*/} | {/*Begin extension-only components*/} | ||||
{hasTab && ( | <OpenInTabBtn | ||||
<EasterEgg src={TabCash} alt="tabcash" /> | data-tip="Open in tab" | ||||
)} | onClick={() => openInTab()} | ||||
{/*End component not included in extension as desktop only*/} | > | ||||
<ExtTabImg src={PopOut} alt="Open in tab" /> | |||||
</OpenInTabBtn> | |||||
{/*End extension-only components*/} | |||||
</HeaderCtn> | </HeaderCtn> | ||||
<ProtectableComponentWrapper> | {/*Note that the extension does not support biometric security*/} | ||||
{/*Hence <ProtectableComponentWrapper> is not pulled in*/} | |||||
<Switch> | <Switch> | ||||
<Route path="/wallet"> | <Route path="/wallet"> | ||||
<Home /> | <Home /> | ||||
</Route> | </Route> | ||||
<Route path="/receive"> | <Route path="/receive"> | ||||
<Receive | <Receive | ||||
passLoadingStatus={ | passLoadingStatus={ | ||||
setLoadingUtxosAfterSend | setLoadingUtxosAfterSend | ||||
} | } | ||||
/> | /> | ||||
</Route> | </Route> | ||||
<Route path="/tokens"> | <Route path="/tokens"> | ||||
<Tokens | <Tokens | ||||
passLoadingStatus={ | passLoadingStatus={ | ||||
setLoadingUtxosAfterSend | setLoadingUtxosAfterSend | ||||
} | } | ||||
/> | /> | ||||
</Route> | </Route> | ||||
<Route path="/send"> | <Route path="/send"> | ||||
<Send | <Send | ||||
passLoadingStatus={ | passLoadingStatus={ | ||||
setLoadingUtxosAfterSend | setLoadingUtxosAfterSend | ||||
} | } | ||||
/> | /> | ||||
</Route> | </Route> | ||||
<Route | <Route | ||||
path="/send-token/:tokenId" | path="/send-token/:tokenId" | ||||
render={props => ( | render={props => ( | ||||
<SendToken | <SendToken | ||||
tokenId={ | tokenId={props.match.params.tokenId} | ||||
props.match.params.tokenId | |||||
} | |||||
passLoadingStatus={ | passLoadingStatus={ | ||||
setLoadingUtxosAfterSend | setLoadingUtxosAfterSend | ||||
} | } | ||||
/> | /> | ||||
)} | )} | ||||
/> | /> | ||||
<Route path="/configure"> | <Route path="/configure"> | ||||
<Configure /> | <Configure /> | ||||
</Route> | </Route> | ||||
<Redirect exact from="/" to="/wallet" /> | <Redirect exact from="/" to="/wallet" /> | ||||
<Route component={NotFound} /> | <Route component={NotFound} /> | ||||
</Switch> | </Switch> | ||||
</ProtectableComponentWrapper> | |||||
</WalletCtn> | </WalletCtn> | ||||
{wallet ? ( | {wallet ? ( | ||||
<Footer> | <Footer> | ||||
<NavButton | <NavButton | ||||
active={selectedKey === 'wallet'} | active={selectedKey === 'wallet'} | ||||
onClick={() => history.push('/wallet')} | onClick={() => history.push('/wallet')} | ||||
> | > | ||||
<HomeIcon /> | <HomeIcon /> | ||||
Show All 34 Lines |