diff --git a/src/AppV2.js b/src/AppV2.js
index db5a9963..c45525f1 100644
--- a/src/AppV2.js
+++ b/src/AppV2.js
@@ -34,6 +34,7 @@ const ApplicationDetail = lazy(() =>
import('v2/components/Applications/Detail'),
);
const Favorites = lazy(() => import('v2/components/Favorites'));
+const AccountDetail = lazy(() => import('v2/components/Account/Detail'));
const useStyles = makeStyles(() => {
return {
@@ -132,6 +133,7 @@ const App = () => {
component={ApplicationDetail}
/>
+
diff --git a/src/v2/components/Account/Detail/Chart/index.jsx b/src/v2/components/Account/Detail/Chart/index.jsx
new file mode 100644
index 00000000..2006e3ae
--- /dev/null
+++ b/src/v2/components/Account/Detail/Chart/index.jsx
@@ -0,0 +1,94 @@
+// @flow
+import {get, maxBy, minBy, map} from 'lodash/fp';
+import React, {useState} from 'react';
+import cn from 'classnames';
+import {ResponsiveLine} from '@nivo/line';
+import OverviewStore from 'v2/stores/networkOverview';
+
+import HelpLink from 'v2/components/HelpLink';
+import useStyles from './styles';
+
+type Point = {
+ data: {
+ x: string,
+ y: number,
+ date: string,
+ },
+};
+
+const Tooltip = ({point: {data}}: {point: Point}) => {
+ const classes = useStyles();
+ if (!data) return null;
+ return (
+
+
+
AVG TPS:{data.y}
+
{data.date}
+
+ );
+};
+
+const Chart = props => {
+ const [range, setRange] = useState('24h');
+ const classes = useStyles();
+ const {txnChartData} = OverviewStore;
+ const data = [
+ {
+ id: 'txn',
+ data: txnChartData,
+ },
+ ];
+
+ const min = get('y')(minBy('y')(txnChartData));
+ const max = get('y')(maxBy('y')(txnChartData));
+
+ const rangeBtns = ['24h', '1m', '6m', '1y', 'all'];
+
+ const lineProperties = {
+ animate: true,
+ useMesh: true,
+ layers: ['lines', 'mesh'],
+ enableSlices: false,
+ yScale: {
+ type: 'linear',
+ stacked: false,
+ min,
+ max,
+ },
+ xScale: {
+ type: 'time',
+ format: '%Y%m%dT%H:%M',
+ precision: 'minute',
+ },
+ colors: ['#00FFAD'],
+ curve: 'monotoneX',
+ data,
+ };
+
+ const switchRange = val => () => setRange(val);
+
+ const renderRangeBtn = val => (
+
+ );
+
+ return (
+
+
+
+ Balance
+
+
{map(renderRangeBtn)(rangeBtns)}
+
+
+
+
+
+ );
+};
+
+export default Chart;
diff --git a/src/v2/components/Account/Detail/Chart/styles.js b/src/v2/components/Account/Detail/Chart/styles.js
new file mode 100644
index 00000000..59e6d059
--- /dev/null
+++ b/src/v2/components/Account/Detail/Chart/styles.js
@@ -0,0 +1,64 @@
+import {makeStyles} from '@material-ui/core';
+import getColor from 'v2/utils/getColor';
+
+export default makeStyles(theme => ({
+ card: {
+ backgroundColor: getColor('grey2')(theme),
+ },
+ graph: {
+ textAlign: 'center',
+ height: 220,
+ padding: '20px 40px',
+ },
+ tooltip: {
+ backgroundColor: '#fff',
+ padding: 13,
+ color: getColor('dark')(theme),
+ textAlign: 'center',
+ },
+ tooltipDot: {
+ position: 'absolute',
+ width: 14,
+ height: 14,
+ background: getColor('main')(theme),
+ borderRadius: '50%',
+ border: `3px solid ${getColor('grey2')(theme)}`,
+ bottom: -20,
+ left: '50%',
+ marginLeft: -7,
+ },
+ tooltipDate: {
+ fontSize: 12,
+ color: getColor('grey3')(theme),
+ },
+ tooltipTitle: {
+ textTransform: 'uppercase',
+ },
+ rangeBtn: {
+ textTransform: 'uppercase',
+ color: getColor('grey4')(theme),
+ width: 44,
+ marginLeft: 4,
+ backgroundColor: 'transparent',
+ border: 'none',
+ outline: 'none',
+ cursor: 'pointer',
+ fontFamily: 'Exo, sans-serif',
+ letterSpacing: 2.5,
+ },
+ rangeActive: {
+ color: getColor('main')(theme),
+ fontWeight: 'bold',
+ },
+ header: {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ padding: '20px 35px',
+ marginBottom: 30,
+ },
+ title: {
+ textTransform: 'uppercase',
+ fontSize: 18,
+ },
+}));
diff --git a/src/v2/components/Account/Detail/Code/index.jsx b/src/v2/components/Account/Detail/Code/index.jsx
new file mode 100644
index 00000000..446cef51
--- /dev/null
+++ b/src/v2/components/Account/Detail/Code/index.jsx
@@ -0,0 +1,29 @@
+// @flow
+import React from 'react';
+import HelpLink from 'v2/components/HelpLink';
+import CopyBtn from 'v2/components/UI/CopyBtn';
+import {observer} from 'mobx-react-lite';
+import YAML from 'yaml';
+
+import useStyles from './styles';
+
+const AccountCode = ({accountView}: {accountView: Object}) => {
+ const classes = useStyles();
+ const applicationCode = YAML.stringify(accountView);
+
+ return (
+
+
+
+
+
+
+
+ {applicationCode}
+
+
+
+ );
+};
+
+export default observer(AccountCode);
diff --git a/src/v2/components/Account/Detail/Code/styles.js b/src/v2/components/Account/Detail/Code/styles.js
new file mode 100644
index 00000000..e7e5dad9
--- /dev/null
+++ b/src/v2/components/Account/Detail/Code/styles.js
@@ -0,0 +1,28 @@
+import {makeStyles} from '@material-ui/core';
+import getColor from 'v2/utils/getColor';
+
+export default makeStyles(theme => ({
+ header: {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'flex-end',
+ marginBottom: 17,
+ '& a': {
+ marginLeft: 15,
+ },
+ },
+ code: {
+ maxHeight: 456,
+ overflowY: 'auto',
+ backgroundColor: getColor('grey')(theme),
+ padding: 39,
+ color: getColor('white')(theme),
+ '& code': {
+ whiteSpace: 'pre-wrap',
+ letterSpacing: 2,
+ fontSize: 15,
+ lineHeight: '100%',
+ display: 'block',
+ },
+ },
+}));
diff --git a/src/v2/components/Account/Detail/Transactions/index.jsx b/src/v2/components/Account/Detail/Transactions/index.jsx
new file mode 100644
index 00000000..0be62288
--- /dev/null
+++ b/src/v2/components/Account/Detail/Transactions/index.jsx
@@ -0,0 +1,91 @@
+// @flow
+import React from 'react';
+import {observer} from 'mobx-react-lite';
+import {TableCell, TableRow} from '@material-ui/core';
+import Table from 'v2/components/UI/Table';
+import TypeLabel from 'v2/components/UI/TypeLabel';
+
+import useStyles from './styles';
+
+const fields = [
+ {
+ id: 'hash',
+ label: 'Hash',
+ text: '',
+ term: '',
+ },
+ {
+ id: 'block',
+ label: 'Block',
+ text: '',
+ term: '',
+ },
+ {
+ id: 'time',
+ label: 'Time',
+ text: '',
+ term: '',
+ },
+ {
+ id: 'application_id',
+ label: 'Application Id',
+ text: '',
+ term: '',
+ },
+ {
+ id: 'type',
+ label: 'Type',
+ text: '',
+ term: '',
+ },
+ {
+ id: 'confirmations',
+ label: 'Confirmations',
+ text: '',
+ term: '',
+ },
+];
+
+const demoData = [
+ {
+ hash: '5CpdpKwKUBJgD4Bdase123as12asd21312',
+ block: '7887219',
+ time: '55 sec ago',
+ timeType: 'in',
+ application_id: '5CpdpKwKUBJgD4Bdase123as12asd21312',
+ type: 'other',
+ confirmations: 5,
+ },
+];
+
+const Transactions = ({transactions}: {transactions: Array}) => {
+ const classes = useStyles();
+ const renderRow = transaction => {
+ return (
+
+ {transaction.hash}
+ {transaction.block}
+
+ {transaction.time}
+ {transaction.timeType}
+
+ {transaction.application_id}
+
+
+
+ {transaction.confirmations}
+
+ );
+ };
+
+ return (
+
+ );
+};
+
+export default observer(Transactions);
diff --git a/src/v2/components/Account/Detail/Transactions/styles.js b/src/v2/components/Account/Detail/Transactions/styles.js
new file mode 100644
index 00000000..e46793be
--- /dev/null
+++ b/src/v2/components/Account/Detail/Transactions/styles.js
@@ -0,0 +1,14 @@
+import {makeStyles} from '@material-ui/core';
+import getColor from 'v2/utils/getColor';
+
+export default makeStyles(theme => ({
+ timeType: {
+ display: 'inline-block',
+ backgroundColor: getColor('grey3')(theme),
+ textTransform: 'uppercase',
+ borderRadius: 2,
+ color: getColor('dark')(theme),
+ padding: '2px 10px',
+ marginLeft: 20,
+ },
+}));
diff --git a/src/v2/components/Account/Detail/index.jsx b/src/v2/components/Account/Detail/index.jsx
new file mode 100644
index 00000000..471a7e83
--- /dev/null
+++ b/src/v2/components/Account/Detail/index.jsx
@@ -0,0 +1,120 @@
+// @flow
+import {observer} from 'mobx-react-lite';
+import {Container, IconButton, Tabs, useTheme} from '@material-ui/core';
+import useMediaQuery from '@material-ui/core/useMediaQuery/useMediaQuery';
+import {map, eq} from 'lodash/fp';
+import React, {useState} from 'react';
+import {Match} from 'react-router-dom';
+import {ReactComponent as StarIcon} from 'v2/assets/icons/star.svg';
+import SectionHeader from 'v2/components/UI/SectionHeader';
+import HelpLink from 'v2/components/HelpLink';
+import QRPopup from 'v2/components/QRPopup';
+import CopyBtn from 'v2/components/UI/CopyBtn';
+import Loader from 'v2/components/UI/Loader';
+import ApplicationDetailStore from 'v2/stores/applications/detail';
+import {LAMPORT_SOL_RATIO} from 'v2/constants';
+import TabNav from 'v2/components/UI/TabNav';
+import Chart from './Chart';
+
+import Transactions from './Transactions';
+import AccountCode from './Code';
+import useStyles from './styles';
+
+const AccountDetail = ({match}: {match: Match}) => {
+ const classes = useStyles();
+ const {
+ isLoading,
+ applicationId,
+ accountInfo,
+ applicationView,
+ } = ApplicationDetailStore;
+
+ if (applicationId !== match.params.id) {
+ ApplicationDetailStore.init({applicationId: match.params.id});
+ }
+
+ const [tab, setTab] = useState(0);
+ const theme = useTheme();
+ const verticalTable = useMediaQuery(theme.breakpoints.down('xs'));
+
+ if (isLoading) {
+ return ;
+ }
+
+ const handleTabChange = (event, tab) => setTab(tab);
+
+ const specs = [
+ {
+ label: 'Balance',
+ hint: '',
+ value: `${(accountInfo.lamports * LAMPORT_SOL_RATIO).toFixed(8)} SOL`,
+ },
+ {
+ label: 'Transactions',
+ hint: '',
+ value: 'TODO',
+ },
+ {
+ label: 'Nickname',
+ hint: '',
+ value: accountInfo.data,
+ },
+ {
+ label: 'Token',
+ hint: '',
+ value: 'TODO',
+ },
+ ];
+
+ const renderSpec = ({label, value}: {label: string, value: string}) => (
+
+
+ {label}
+
+
+
+ {typeof value === 'function' ? value() : value}
+
+
+ );
+
+ const tabNav = ['transaction', 'analytics', 'code/source'];
+
+ const renderTabNav = label => ;
+ const url = window.location.href;
+
+ return (
+
+
+
+
+ {applicationId}
+
+
+
+
+
+
+
+
+
+ {map(renderTabNav)(tabNav)}
+
+ {eq(0, tab) &&
}
+ {eq(1, tab) &&
}
+ {eq(2, tab) &&
}
+
+
+ );
+};
+
+export default observer(AccountDetail);
diff --git a/src/v2/components/Account/Detail/styles.js b/src/v2/components/Account/Detail/styles.js
new file mode 100644
index 00000000..bf433b71
--- /dev/null
+++ b/src/v2/components/Account/Detail/styles.js
@@ -0,0 +1,96 @@
+import {makeStyles} from '@material-ui/core';
+import getColor from 'v2/utils/getColor';
+
+export default makeStyles(theme => ({
+ applicationTitle: {
+ display: 'flex',
+ alignItems: 'center',
+ marginLeft: 100,
+ marginRight: 'auto',
+ overflow: 'hidden',
+ '& div': {
+ marginLeft: 15,
+ display: 'flex',
+ alignItems: 'center',
+ },
+ '& span': {
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ },
+ [theme.breakpoints.down('md')]: {
+ flexWrap: 'wrap',
+ marginLeft: 0,
+ },
+ },
+ types: {
+ '& > div:not(:last-child)': {
+ marginRight: 8,
+ },
+ },
+ spec: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ padding: 0,
+ [theme.breakpoints.down('xs')]: {
+ flexDirection: 'column',
+ },
+ '& li': {
+ width: '50%',
+ display: 'flex',
+ marginBottom: 48,
+ [theme.breakpoints.down('sm')]: {
+ marginBottom: 32,
+ flexDirection: 'column',
+ },
+ [theme.breakpoints.down('xs')]: {
+ width: '100%',
+ },
+ '&:nth-child(odd)': {
+ width: 'calc(50% - 80px)',
+ marginRight: 80,
+ [theme.breakpoints.down('xs')]: {
+ width: '100%',
+ marginRight: 0,
+ },
+ },
+ },
+ },
+ label: {
+ textTransform: 'uppercase',
+ fontSize: 15,
+ fontWeight: 'bold',
+ letterSpacing: 2,
+ width: 150,
+ flexShrink: 0,
+ marginRight: 40,
+ color: getColor('grey4')(theme),
+ display: 'flex',
+ alignItems: 'center',
+ [theme.breakpoints.down('md')]: {
+ marginRight: 20,
+ },
+ [theme.breakpoints.down('sm')]: {
+ width: '100%',
+ marginRight: 0,
+ },
+ },
+ value: {
+ fontSize: 15,
+ lineHeight: '29px',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ '& a': {
+ color: getColor('main')(theme),
+ textDecoration: 'none',
+ '&:hover': {
+ textDecoration: 'underline',
+ },
+ },
+ },
+ tabs: {
+ marginBottom: 50,
+ },
+ indicator: {
+ display: 'none',
+ },
+}));
diff --git a/src/v2/components/HelpLink/styles.js b/src/v2/components/HelpLink/styles.js
index 39ac2f35..c3c5a288 100644
--- a/src/v2/components/HelpLink/styles.js
+++ b/src/v2/components/HelpLink/styles.js
@@ -16,6 +16,7 @@ export default makeStyles(theme => ({
transition: '.15s ease-in-out',
marginLeft: 5,
marginTop: -2,
+ verticalAlign: 'middle',
'&:hover': {
color: getColor('main')(theme),
borderColor: getColor('main')(theme),
diff --git a/src/v2/components/Transactions/Detail/Application/index.jsx b/src/v2/components/Transactions/Detail/Application/index.jsx
index aa0c71bb..5555b7e3 100644
--- a/src/v2/components/Transactions/Detail/Application/index.jsx
+++ b/src/v2/components/Transactions/Detail/Application/index.jsx
@@ -2,6 +2,7 @@
import React from 'react';
import _ from 'lodash';
import {Grid} from '@material-ui/core';
+import {Link} from 'react-router-dom';
import Label from 'v2/components/UI/Label';
import Avatar from 'v2/components/UI/Avatar';
import TypeLabel from 'v2/components/UI/TypeLabel';
@@ -18,8 +19,10 @@ const Application = ({id, accounts}: TApplication) => {
const renderAccount = (account, i) => (
-
-
{account}
+
+
+
{account}
+
);
return (
diff --git a/src/v2/components/Transactions/Detail/Application/styles.js b/src/v2/components/Transactions/Detail/Application/styles.js
index 499118f2..fc3c2447 100644
--- a/src/v2/components/Transactions/Detail/Application/styles.js
+++ b/src/v2/components/Transactions/Detail/Application/styles.js
@@ -12,15 +12,20 @@ export default makeStyles(theme => ({
alignItems: 'center',
justifyContent: 'flex-end',
marginBottom: 40,
- '& > div:first-child': {
- marginRight: 25,
+ [theme.breakpoints.down('xs')]: {
+ flexDirection: 'column',
+ alignItems: 'flex-start',
},
+ },
+ accountLink: {
+ display: 'flex',
+ textDecoration: 'none',
+ marginLeft: 25,
'& > div:nth-child(2)': {
[theme.breakpoints.down('xs')]: {
display: 'none',
},
},
-
'& > div:last-child': {
marginLeft: 25,
[theme.breakpoints.down('xs')]: {
@@ -30,6 +35,7 @@ export default makeStyles(theme => ({
[theme.breakpoints.down('xs')]: {
flexDirection: 'column',
alignItems: 'flex-start',
+ marginLeft: 0,
},
},
address: {