Changeset View
Changeset View
Standalone View
Standalone View
cashtab/src/components/Configure/Configure.tsx
| // Copyright (c) 2024 The Bitcoin developers | // Copyright (c) 2024 The Bitcoin developers | ||||
| // Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
| // file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
| import React, { useContext } from 'react'; | import React, { useContext } from 'react'; | ||||
| import styled from 'styled-components'; | import styled from 'styled-components'; | ||||
| import { Link } from 'react-router'; | |||||
| import { WalletContext, isWalletContextLoaded } from 'wallet/context'; | import { WalletContext, isWalletContextLoaded } from 'wallet/context'; | ||||
| import { | import { | ||||
| DollarIcon, | |||||
| SettingsIcon, | |||||
| ThemedXIcon, | ThemedXIcon, | ||||
| ThemedFacebookIcon, | ThemedFacebookIcon, | ||||
| SocialContainer, | SocialContainer, | ||||
| SocialLink, | SocialLink, | ||||
| GithubIcon, | GithubIcon, | ||||
| } from 'components/Common/CustomIcons'; | } from 'components/Common/CustomIcons'; | ||||
| import TokenIcon from 'components/Etokens/TokenIcon'; | import TokenIcon from 'components/Etokens/TokenIcon'; | ||||
| import appConfig from 'config/app'; | import appConfig from 'config/app'; | ||||
| import { hasEnoughToken } from 'wallet'; | import { hasEnoughToken } from 'wallet'; | ||||
| import { CurrencySelect } from 'components/Common/Inputs'; | import { CurrencySelect } from 'components/Common/Inputs'; | ||||
| import Switch from 'components/Common/Switch'; | import SegmentedControl from 'components/Common/SegmentedControl'; | ||||
| import { PageHeader } from 'components/Common/Atoms'; | import { ReactComponent as BackIconSvg } from 'assets/back.svg'; | ||||
| import { ReactComponent as RightIconSvg } from 'assets/right.svg'; | |||||
| const VersionContainer = styled.div` | const VersionContainer = styled.div` | ||||
| color: ${props => props.theme.primaryText}; | color: ${props => props.theme.primaryText}; | ||||
| font-size: var(--text-sm); | |||||
| margin-top: 60px; | |||||
| text-align: right; | |||||
| border-bottom: 1px solid ${props => props.theme.border}; | |||||
| padding-bottom: 20px; | |||||
| margin-bottom: 40px; | |||||
| `; | `; | ||||
| const ConfigIconWrapper = styled.div` | export const StyledConfigure = styled.div` | ||||
| svg { | margin-top: 20px; | ||||
| height: 42px; | padding: 0 20px; | ||||
| width: 42px; | @media (max-width: 768px) { | ||||
| fill: ${props => props.theme.accent}; | padding: 0 14px; | ||||
| } | } | ||||
| `; | `; | ||||
| const StyledConfigure = styled.div` | |||||
| margin: 12px 0; | export const SettingsPageHeaderLink = styled(Link)` | ||||
| background: ${props => props.theme.primaryBackground}; | display: flex; | ||||
| padding: 20px; | align-items: center; | ||||
| border-radius: 10px; | gap: 8px; | ||||
| @media (max-width: 768px) { | margin-bottom: 16px; | ||||
| border-radius: 0; | padding-bottom: 16px; | ||||
| margin: 0; | border-bottom: 1px solid ${props => props.theme.border}; | ||||
| color: ${props => props.theme.primaryText}; | |||||
| text-decoration: none; | |||||
| font-size: var(--text-2xl); | |||||
| font-weight: 700; | |||||
| :hover { | |||||
| color: ${props => props.theme.accent}; | |||||
| } | } | ||||
| h2 { | `; | ||||
| margin-bottom: 30px; | |||||
| export const BackIcon = styled(BackIconSvg)` | |||||
| width: 18px; | |||||
| height: 18px; | |||||
| flex-shrink: 0; | |||||
| path { | |||||
| fill: currentColor; | |||||
| } | } | ||||
| `; | `; | ||||
| const HeadlineAndIcon = styled.div` | const RightIcon = styled(RightIconSvg)` | ||||
| width: 16px; | |||||
| height: 16px; | |||||
| flex-shrink: 0; | |||||
| path { | |||||
| fill: currentColor; | |||||
| } | |||||
| `; | |||||
| const SettingsList = styled.div` | |||||
| display: flex; | display: flex; | ||||
| align-items: center; | flex-direction: column; | ||||
| justify-content: center; | gap: 0; | ||||
| gap: 6px; | |||||
| margin: 12px 0; | |||||
| `; | `; | ||||
| const Headline = styled.div` | |||||
| font-size: var(--text-xl); | const SettingsRow = styled.div` | ||||
| line-height: var(--text-xl--line-height); | display: flex; | ||||
| align-items: center; | |||||
| justify-content: space-between; | |||||
| padding: 14px 0; | |||||
| color: ${props => props.theme.primaryText}; | color: ${props => props.theme.primaryText}; | ||||
| font-weight: bold; | :last-child { | ||||
| border-bottom: none; | |||||
| } | |||||
| `; | `; | ||||
| const StyledSpacer = styled.div` | const SettingsRowLabel = styled.span` | ||||
| height: 1px; | font-size: var(--text-base); | ||||
| width: 100%; | line-height: var(--text-base--line-height); | ||||
| background-color: ${props => props.theme.border}; | `; | ||||
| margin: 60px 0 50px; | |||||
| const SettingsRowControl = styled.div` | |||||
| display: flex; | |||||
| align-items: center; | |||||
| `; | `; | ||||
| const SettingsLabel = styled.div` | const SettingsLinkRow = styled(Link)` | ||||
| text-align: left; | |||||
| display: flex; | display: flex; | ||||
| gap: 9px; | align-items: center; | ||||
| justify-content: space-between; | |||||
| padding: 14px 0; | |||||
| color: ${props => props.theme.primaryText}; | color: ${props => props.theme.primaryText}; | ||||
| text-decoration: none; | |||||
| font-size: var(--text-base); | |||||
| :hover { | |||||
| color: ${props => props.theme.accent}; | |||||
| span { | |||||
| color: ${props => props.theme.accent}; | |||||
| } | |||||
| } | |||||
| `; | `; | ||||
| const Switches = styled.div` | const SettingsLinkChevron = styled.span` | ||||
| flex-direction: column; | |||||
| display: flex; | display: flex; | ||||
| gap: 12px; | align-items: center; | ||||
| color: ${props => props.theme.primaryText}; | |||||
| `; | `; | ||||
| const GeneralSettingsItem = styled.div` | |||||
| const StyledSpacer = styled.div` | |||||
| height: 1px; | |||||
| width: 100%; | |||||
| background-color: ${props => props.theme.border}; | |||||
| margin: 40px 0 24px; | |||||
| `; | |||||
| const HeadlineAndIcon = styled.div` | |||||
| display: flex; | display: flex; | ||||
| align-items: center; | align-items: center; | ||||
| justify-content: center; | justify-content: center; | ||||
| gap: 12px; | gap: 6px; | ||||
| margin: 12px 0; | |||||
| `; | |||||
| const Headline = styled.div` | |||||
| font-size: var(--text-xl); | |||||
| line-height: var(--text-xl--line-height); | |||||
| color: ${props => props.theme.primaryText}; | |||||
| font-weight: bold; | |||||
| `; | `; | ||||
| const Configure: React.FC = () => { | const Configure: React.FC = () => { | ||||
| const ContextValue = useContext(WalletContext); | const ContextValue = useContext(WalletContext); | ||||
| if (!isWalletContextLoaded(ContextValue)) { | if (!isWalletContextLoaded(ContextValue)) { | ||||
| // Confirm we have all context required to load the page | // Confirm we have all context required to load the page | ||||
| return null; | return null; | ||||
| } | } | ||||
| const { updateCashtabState, cashtabState } = ContextValue; | const { updateCashtabState, cashtabState } = ContextValue; | ||||
| const { settings, tokens } = cashtabState; | const { settings, tokens } = cashtabState; | ||||
| const handleSendModalToggle = (e: React.ChangeEvent<HTMLInputElement>) => { | |||||
| updateCashtabState({ | |||||
| settings: { | |||||
| ...settings, | |||||
| sendModal: e.target.checked, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| return ( | return ( | ||||
| <StyledConfigure title="Settings"> | <StyledConfigure title="Settings"> | ||||
| <PageHeader> | <SettingsPageHeaderLink to="/" aria-label="Back to home"> | ||||
| Settings <SettingsIcon /> | <BackIcon aria-hidden="true" /> | ||||
| </PageHeader> | Settings | ||||
| <HeadlineAndIcon> | </SettingsPageHeaderLink> | ||||
| <ConfigIconWrapper> | |||||
| <DollarIcon /> | <SettingsList> | ||||
| </ConfigIconWrapper>{' '} | <SettingsLinkRow to="/wallets"> | ||||
| <Headline>Fiat Currency</Headline> | <SettingsRowLabel>Wallets</SettingsRowLabel> | ||||
| </HeadlineAndIcon> | <SettingsLinkChevron aria-hidden="true"> | ||||
| <RightIcon /> | |||||
| </SettingsLinkChevron> | |||||
| </SettingsLinkRow> | |||||
| <SettingsLinkRow to="/backup"> | |||||
| <SettingsRowLabel>Wallet Backup</SettingsRowLabel> | |||||
| <SettingsLinkChevron aria-hidden="true"> | |||||
| <RightIcon /> | |||||
| </SettingsLinkChevron> | |||||
| </SettingsLinkRow> | |||||
| <SettingsRow> | |||||
| <SettingsRowLabel>Display Currency</SettingsRowLabel> | |||||
| <SettingsRowControl> | |||||
| <CurrencySelect | <CurrencySelect | ||||
| name="configure-fiat-select" | name="configure-fiat-select" | ||||
| value={cashtabState.settings.fiatCurrency} | value={cashtabState.settings.fiatCurrency} | ||||
| handleSelect={e => { | handleSelect={e => { | ||||
| updateCashtabState({ | updateCashtabState({ | ||||
| settings: { | settings: { | ||||
| ...settings, | ...settings, | ||||
| fiatCurrency: e.target.value, | fiatCurrency: e.target.value, | ||||
| }, | }, | ||||
| }); | }); | ||||
| }} | }} | ||||
| /> | /> | ||||
| <StyledSpacer /> | </SettingsRowControl> | ||||
| <HeadlineAndIcon> | </SettingsRow> | ||||
| <ConfigIconWrapper> | <SettingsRow> | ||||
| <SettingsIcon /> | <SettingsRowLabel>Send Confirmations</SettingsRowLabel> | ||||
| </ConfigIconWrapper>{' '} | <SettingsRowControl> | ||||
| <Headline>General Settings</Headline> | <SegmentedControl | ||||
| </HeadlineAndIcon> | name="Send Confirmations" | ||||
| <Switches> | options={[ | ||||
| <GeneralSettingsItem> | { value: 'on', label: 'On' }, | ||||
| <Switch | { value: 'off', label: 'Off' }, | ||||
| name="Toggle Send Confirmations" | ]} | ||||
| checked={settings.sendModal} | value={settings.sendModal ? 'on' : 'off'} | ||||
| handleToggle={handleSendModalToggle} | onChange={v => | ||||
| updateCashtabState({ | |||||
| settings: { | |||||
| ...settings, | |||||
| sendModal: v === 'on', | |||||
| }, | |||||
| }) | |||||
| } | |||||
| /> | /> | ||||
| <SettingsLabel>Send Confirmations</SettingsLabel> | </SettingsRowControl> | ||||
| </GeneralSettingsItem> | </SettingsRow> | ||||
| </Switches> | </SettingsList> | ||||
| {(hasEnoughToken( | {(hasEnoughToken( | ||||
| tokens, | tokens, | ||||
| appConfig.vipTokens.grumpy.tokenId, | appConfig.vipTokens.grumpy.tokenId, | ||||
| appConfig.vipTokens.grumpy.vipBalance, | appConfig.vipTokens.grumpy.vipBalance, | ||||
| ) || | ) || | ||||
| hasEnoughToken( | hasEnoughToken( | ||||
| tokens, | tokens, | ||||
| Show All 24 Lines | return ( | ||||
| tokenId={appConfig.vipTokens.cachet.tokenId} | tokenId={appConfig.vipTokens.cachet.tokenId} | ||||
| /> | /> | ||||
| )} | )} | ||||
| <Headline>Cashtab VIP 🏆</Headline> | <Headline>Cashtab VIP 🏆</Headline> | ||||
| </HeadlineAndIcon> | </HeadlineAndIcon> | ||||
| </> | </> | ||||
| )} | )} | ||||
| <StyledSpacer /> | {typeof import.meta.env.VITE_VERSION === 'string' && ( | ||||
| <VersionContainer> | |||||
| v{import.meta.env.VITE_VERSION} | |||||
| </VersionContainer> | |||||
| )} | |||||
| <SocialContainer> | <SocialContainer> | ||||
| <SocialLink | <SocialLink | ||||
| href="https://x.com/cashtabwallet" | href="https://x.com/cashtabwallet" | ||||
| target="_blank" | target="_blank" | ||||
| rel="noreferrer" | rel="noreferrer" | ||||
| > | > | ||||
| <ThemedXIcon /> | <ThemedXIcon /> | ||||
| </SocialLink>{' '} | </SocialLink>{' '} | ||||
| <SocialLink | <SocialLink | ||||
| href="https://www.facebook.com/Cashtab" | href="https://www.facebook.com/Cashtab" | ||||
| target="_blank" | target="_blank" | ||||
| rel="noreferrer" | rel="noreferrer" | ||||
| > | > | ||||
| <ThemedFacebookIcon /> | <ThemedFacebookIcon /> | ||||
| </SocialLink> | </SocialLink> | ||||
| <SocialLink | <SocialLink | ||||
| href="https://github.com/Bitcoin-ABC/bitcoin-abc/tree/master/cashtab" | href="https://github.com/Bitcoin-ABC/bitcoin-abc/tree/master/cashtab" | ||||
| target="_blank" | target="_blank" | ||||
| rel="noreferrer" | rel="noreferrer" | ||||
| > | > | ||||
| <GithubIcon /> | <GithubIcon /> | ||||
| </SocialLink> | </SocialLink> | ||||
| </SocialContainer> | </SocialContainer> | ||||
| {typeof import.meta.env.VITE_VERSION === 'string' && ( | |||||
| <> | |||||
| <StyledSpacer /> | |||||
| <VersionContainer> | |||||
| v{import.meta.env.VITE_VERSION} | |||||
| </VersionContainer> | |||||
| </> | |||||
| )} | |||||
| </StyledConfigure> | </StyledConfigure> | ||||
| ); | ); | ||||
| }; | }; | ||||
| export default Configure; | export default Configure; | ||||