diff --git a/frontend/src/components/BottomBar.js b/frontend/src/components/BottomBar.js index d715e327..8220411d 100644 --- a/frontend/src/components/BottomBar.js +++ b/frontend/src/components/BottomBar.js @@ -1,8 +1,7 @@ import React, { Component } from 'react' import { withTranslation } from "react-i18next"; -import {FormControlLabel, Link, Switch, CircularProgress, Badge, Tooltip, TextField, ListItemAvatar, Button, Avatar,Paper, Grid, IconButton, Typography, Select, MenuItem, List, ListItemText, ListItem, ListItemIcon, ListItemButton, Divider, Dialog, DialogContent} from "@mui/material"; +import { Badge, Tooltip, ListItemAvatar, Avatar,Paper, Grid, IconButton, Select, MenuItem, ListItemText, ListItem, ListItemIcon, ListItemButton } from "@mui/material"; import MediaQuery from 'react-responsive' -import { Link as LinkRouter } from 'react-router-dom' // Icons import SettingsIcon from '@mui/icons-material/Settings'; @@ -12,26 +11,15 @@ import SellIcon from '@mui/icons-material/Sell'; import SmartToyIcon from '@mui/icons-material/SmartToy'; import PercentIcon from '@mui/icons-material/Percent'; import PriceChangeIcon from '@mui/icons-material/PriceChange'; -import BoltIcon from '@mui/icons-material/Bolt'; -import GitHubIcon from '@mui/icons-material/GitHub'; -import EqualizerIcon from '@mui/icons-material/Equalizer'; -import PublicIcon from '@mui/icons-material/Public'; -import NumbersIcon from '@mui/icons-material/Numbers'; -import PasswordIcon from '@mui/icons-material/Password'; -import ContentCopy from "@mui/icons-material/ContentCopy"; -import DnsIcon from '@mui/icons-material/Dns'; -import WebIcon from '@mui/icons-material/Web'; -import BookIcon from '@mui/icons-material/Book'; -import PersonAddAltIcon from '@mui/icons-material/PersonAddAlt'; -import EmojiEventsIcon from '@mui/icons-material/EmojiEvents'; -import FavoriteIcon from '@mui/icons-material/Favorite'; -import { AmbossIcon , BitcoinSignIcon} from "./Icons"; - -import { CommunityDialog } from './Dialogs'; +import { + CommunityDialog, + ExchangeSummaryDialog, + ProfileDialog, + StatsDialog, +} from './Dialogs'; import { getCookie } from "../utils/cookies"; -import { pn } from "../utils/prettyNumbers"; class BottomBar extends Component { constructor(props) { @@ -73,7 +61,7 @@ class BottomBar extends Component { this.setState(null) fetch('/api/info/') .then((response) => response.json()) - .then((data) => this.setState(data) + .then((data) => this.setState(data) & this.setState({active_order_id: data.active_order_id ? data.active_order_id : null, last_order_id: data.last_order_id ? data.last_order_id : null}) & this.props.setAppState({nickname:data.nickname, loading:false})); @@ -87,105 +75,6 @@ class BottomBar extends Component { this.setState({openStatsForNerds: false}); }; - StatsDialog =() =>{ - const { t } = this.props; - return( - - - {t("Stats For Nerds")} - - - - - - - - - {this.state.network == 'testnet'? - - - - {this.state.node_id.slice(0, 12)+"... (1ML)"} - - - - : - - - - {this.state.node_id.slice(0, 12)+"... (AMBOSS)"} - - - - } - - - - - - {this.state.alternative_site.slice(0, 12)+"...onion"} - - - - - - - - - {this.state.robosats_running_commit_hash.slice(0, 12)+"..."} - - - - - - - - -
- {pn(this.state.last_day_volume)} - -
-
-
- - - - - -
- {pn(this.state.lifetime_volume)} - -
-
-
- - - - - - {t("Made with")+" "} - - {" "+t("and")+" "} - - } - secondary={t("... somewhere on Earth!")}/> - -
- -
-
- ) - } - handleClickOpenCommunity = () => { this.setState({openCommuniy: true}); }; @@ -201,7 +90,7 @@ class BottomBar extends Component { this.setState({openProfile: false}); }; - handleSubmitInvoiceClicked=()=>{ + handleSubmitInvoiceClicked=(e, rewardInvoice)=>{ this.setState({ badInvoice:false, showRewardsSpinner: true, @@ -211,7 +100,7 @@ class BottomBar extends Component { method: 'POST', headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken'),}, body: JSON.stringify({ - 'invoice': this.state.rewardInvoice, + 'invoice': rewardInvoice, }), }; fetch('/api/reward/', requestOptions) @@ -223,6 +112,7 @@ class BottomBar extends Component { withdrawn: data.successful_withdrawal ? true : false, showRewardsSpinner: false, })); + e.preventDefault(); } getHost(){ @@ -230,186 +120,6 @@ class BottomBar extends Component { return url.split('/')[2] } - dialogProfile =() =>{ - const { t } = this.props; - return( - - - {t("Your Profile")} - - - - - - {this.props.nickname ? - - : ""} - - - - - - - - - - {this.state.active_order_id ? - - - - - - - - - : - - this.state.last_order_id ? - - - - - - - : - - - - - - } - - - - - - - {getCookie("robot_token") ? - - (navigator.clipboard.writeText(getCookie("robot_token")) & this.props.setAppState({copiedToken:true}))}> - - - , - }} - /> - : - t("Cannot remember")} - - - - - - - this.setState({showRewards: !this.state.showRewards})}/>} - label={t("Rewards and compensations")} - /> - - -
- - - - - - - navigator.clipboard.writeText('http://'+this.getHost()+'/ref/'+this.state.referral_code)}> - - - , - }} - /> - - - - - - - - {!this.state.openClaimRewards ? - - - - {this.state.earned_rewards+" Sats"} - - - - - - - : -
- - - { - this.setState({ rewardInvoice: e.target.value }); - }} - /> - - - - - -
- } -
- - {this.state.showRewardsSpinner? -
- -
- :""} - - {this.state.withdrawn? -
- {t("There it goes, thank you!🥇")} -
- :""} - -
-
-
- -
- ) - } - bottomBarDesktop =()=>{ const { t } = this.props; var hasRewards = this.state.earned_rewards > 0 ? true: false; @@ -417,16 +127,13 @@ bottomBarDesktop =()=>{ return( - {this.StatsDialog()} - {this.dialogProfile()} - {this.exchangeSummaryDialog()}
- @@ -576,122 +283,17 @@ bottomBarDesktop =()=>{ this.setState({openExchangeSummary: false}); }; - exchangeSummaryDialog =() =>{ - const { t } = this.props; - return( - - - {t("Exchange Summary")} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {(this.state.maker_fee*100).toFixed(3)}% - - - - - {(this.state.taker_fee*100).toFixed(3)}% - - - - - - - - - ) - } - bottomBarPhone =()=>{ const { t } = this.props; var hasRewards = this.state.earned_rewards > 0 ? true: false; var hasOrder = this.state.active_order_id > 0 & !this.state.profileShown & this.props.avatarLoaded ? true : false; return( - {this.StatsDialog()} - {this.exchangeSummaryDialog()} - {this.dialogProfile()}
- @@ -787,6 +389,49 @@ bottomBarPhone =()=>{ isOpen={this.state.openCommuniy} handleClickCloseCommunity={this.handleClickCloseCommunity} /> + + + + + + + {this.bottomBarDesktop()} diff --git a/frontend/src/components/Dialogs/ExchangeSummary.tsx b/frontend/src/components/Dialogs/ExchangeSummary.tsx new file mode 100644 index 00000000..3b759ec9 --- /dev/null +++ b/frontend/src/components/Dialogs/ExchangeSummary.tsx @@ -0,0 +1,169 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; + +import { + Dialog, + DialogContent, + Divider, + Grid, + List, + ListItemText, + ListItem, + ListItemIcon, + Typography, +} from "@mui/material"; + +import InventoryIcon from '@mui/icons-material/Inventory'; +import SellIcon from '@mui/icons-material/Sell'; +import SmartToyIcon from '@mui/icons-material/SmartToy'; +import PercentIcon from '@mui/icons-material/Percent'; +import PriceChangeIcon from '@mui/icons-material/PriceChange'; +import BookIcon from '@mui/icons-material/Book'; + +import { pn } from "../../utils/prettyNumbers"; + +type Props = { + isOpen: boolean; + handleClickCloseExchangeSummary: () => void; + numPublicBuyOrders: number; + numPublicSellOrders: number; + bookLiquidity: number; + activeRobotsToday: number; + lastDayNonkycBtcPremium: number; + makerFee: number; + takerFee: number; +} + +const ExchangeSummaryDialog = ({ + isOpen, + handleClickCloseExchangeSummary, + numPublicBuyOrders, + numPublicSellOrders, + bookLiquidity, + activeRobotsToday, + lastDayNonkycBtcPremium, + makerFee, + takerFee, +}: Props): JSX.Element => { + const { t } = useTranslation(); + + return ( + + + {t("Exchange Summary")} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {(makerFee * 100).toFixed(3)}% + + + + + + {(takerFee * 100).toFixed(3)}% + + + + + + + + ); +}; + +export default ExchangeSummaryDialog; diff --git a/frontend/src/components/Dialogs/Profile.tsx b/frontend/src/components/Dialogs/Profile.tsx new file mode 100644 index 00000000..27815e91 --- /dev/null +++ b/frontend/src/components/Dialogs/Profile.tsx @@ -0,0 +1,329 @@ +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Link as LinkRouter } from "react-router-dom"; + +import { + Avatar, + Badge, + Button, + CircularProgress, + Dialog, + DialogContent, + Divider, + FormControlLabel, + Grid, + IconButton, + List, + ListItemAvatar, + ListItemButton, + ListItemText, + ListItem, + ListItemIcon, + Switch, + TextField, + Tooltip, + Typography, +} from "@mui/material"; + +import BoltIcon from "@mui/icons-material/Bolt"; +import NumbersIcon from "@mui/icons-material/Numbers"; +import PasswordIcon from "@mui/icons-material/Password"; +import ContentCopy from "@mui/icons-material/ContentCopy"; +import PersonAddAltIcon from "@mui/icons-material/PersonAddAlt"; +import EmojiEventsIcon from "@mui/icons-material/EmojiEvents"; + +import { getCookie } from "../../utils/cookies"; + +type Props = { + isOpen: boolean; + handleClickCloseProfile: () => void; + nickname: string; + activeOrderId: string | number; + lastOrderId: string | number; + referralCode: string; + handleSubmitInvoiceClicked: (e:any, invoice: string) => void; + host: string; + showRewardsSpinner: boolean; + withdrawn: boolean; + badInvoice: boolean | string; + earnedRewards: number; + setAppState: (state: any) => void; // TODO: move to a ContextProvider +} + +const ProfileDialog = ({ + isOpen, + handleClickCloseProfile, + nickname, + activeOrderId, + lastOrderId, + referralCode, + handleSubmitInvoiceClicked, + host, + showRewardsSpinner, + withdrawn, + badInvoice, + earnedRewards, + setAppState, +}: Props): JSX.Element => { + const { t } = useTranslation(); + + const [rewardInvoice, setRewardInvoice] = useState(""); + const [showRewards, setShowRewards] = useState(false); + const [openClaimRewards, setOpenClaimRewards] = useState(false); + + const copyTokenHandler = () => { + const robotToken = getCookie("robot_token"); + + if (robotToken) { + navigator.clipboard.writeText(robotToken); + setAppState({copiedToken:true}); + } + }; + + const copyReferralCodeHandler = () => { + navigator.clipboard.writeText(`http://${host}/ref/${referralCode}`); + }; + + return ( + + + {t("Your Profile")} + + + + + + + + {nickname ? ( +
+
+ + + {nickname} + + +
+
+ ) + : null} +
+
+ + + + +
+ + + + {activeOrderId ? ( + + + + + + + + + ) : + lastOrderId ? ( + + + + + + + ) : ( + + + + + + + ) + } + + + + + + + + {getCookie("robot_token") ? ( + + + + +
, + }} + /> + ) : + t("Cannot remember") + } + + + + + + + + setShowRewards(!showRewards)} + /> + } + /> + + + + {showRewards && ( + <> + + + + + + + + + + + , + }} + /> + + + + + + + + + {!openClaimRewards ? ( + + + + {`${earnedRewards} Sats`} + + + + + + + + ) : ( +
+ + + { + setRewardInvoice(e.target.value); + }} + /> + + + + + + +
+ )} +
+ + {showRewardsSpinner && ( +
+ +
+ )} + + {withdrawn && ( +
+ + {t("There it goes, thank you!🥇")} + +
+ )} + + )} + + + + ); +}; + +export default ProfileDialog; diff --git a/frontend/src/components/Dialogs/Stats.tsx b/frontend/src/components/Dialogs/Stats.tsx new file mode 100644 index 00000000..9f77ddf9 --- /dev/null +++ b/frontend/src/components/Dialogs/Stats.tsx @@ -0,0 +1,196 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; + +import { + Dialog, + DialogContent, + Divider, + Link, + List, + ListItemText, + ListItem, + ListItemIcon, + Typography, +} from "@mui/material"; + +import BoltIcon from "@mui/icons-material/Bolt"; +import PublicIcon from "@mui/icons-material/Public"; +import DnsIcon from "@mui/icons-material/Dns"; +import WebIcon from "@mui/icons-material/Web"; +import FavoriteIcon from "@mui/icons-material/Favorite"; +import GitHubIcon from "@mui/icons-material/GitHub"; +import EqualizerIcon from "@mui/icons-material/Equalizer"; + +import { AmbossIcon, BitcoinSignIcon } from "../Icons"; + +import { pn } from "../../utils/prettyNumbers"; + +type Props = { + isOpen: boolean; + handleClickCloseStatsForNerds: () => void; + lndVersion: string; + network: string; + nodeAlias: string; + nodeId: string; + alternativeName: string; + alternativeSite: string; + robosatsRunningCommitHash: string; + lastDayVolume: number; + lifetimeVolume: number; +} + +const StatsDialog = ({ + isOpen, + handleClickCloseStatsForNerds, + lndVersion, + network, + nodeAlias, + nodeId, + alternativeName, + alternativeSite, + robosatsRunningCommitHash, + lastDayVolume, + lifetimeVolume, +}: Props): JSX.Element => { + const { t } = useTranslation(); + + return ( + + + {t("Stats For Nerds")} + + + + + + + + + + + + + + {network === "testnet" ? ( + + + + + + + {`${nodeId.slice(0, 12)}... (1ML)`} + + + + ) : ( + + + + + + + {`${nodeId.slice(0, 12)}... (AMBOSS)`} + + + + )} + + + + + + + + + + {`${alternativeSite.slice(0, 12)}...onion`} + + + + + + + + + + + + + {`${robosatsRunningCommitHash.slice(0, 12)}...`} + + + + + + + + + + + +
+ {pn(lastDayVolume)} + +
+
+
+ + + + + + + + +
+ {pn(lifetimeVolume)} + +
+
+
+ + + + + + + + {`${t("Made with")} `} + + {` ${t("and")} `} + +
+ } + secondary={t("... somewhere on Earth!")} + /> + + + + + ); +}; + +export default StatsDialog; diff --git a/frontend/src/components/Dialogs/index.ts b/frontend/src/components/Dialogs/index.ts index 518f5c9e..b7177726 100644 --- a/frontend/src/components/Dialogs/index.ts +++ b/frontend/src/components/Dialogs/index.ts @@ -3,4 +3,7 @@ export { default as InfoDialog } from "./Info"; export { default as LearnDialog } from "./Learn"; export { default as NoRobotDialog } from "./NoRobot"; export { default as StoreTokenDialog } from "./StoreToken"; +export { default as ExchangeSummaryDialog } from "./ExchangeSummary"; +export { default as ProfileDialog } from "./Profile"; +export { default as StatsDialog } from "./Stats";