Skip to content

Commit

Permalink
Merge pull request #188 from Cryptonomic/feat/136-modal-entity-view
Browse files Browse the repository at this point in the history
implemented the entity view modal
  • Loading branch information
anonymoussprocket authored May 10, 2019
2 parents 28ce8f2 + eab6e60 commit ac06721
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 19 deletions.
54 changes: 45 additions & 9 deletions src/components/CustomTableRow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ const ClipboardWrapper = styled(Clipboard)`
cursor: pointer;
`;

const LinkDiv = styled.div`
color: #56c2d9;
cursor: pointer;
text-decoration: underline;
`;

const DefaultAttributeNames = [
'predecessor',
'hash',
Expand All @@ -69,21 +75,51 @@ const DefaultAttributeNames = [
'operations_hash',
'signature'
];

const PrimaryKeyList = {
blocks: ['hash', 'level'],
accounts: ['account_id'],
operations: ['operation_group_hash']
};

interface Props {
item: any;
selectedColumns: any[];
network: string;
platform: string;
selectedEntity: string,
onClickPrimaryKey: (key, value) => void;
}

const formatValueForPrimary = (entity, name, shortValue, value, onClickPrimaryKey) => {
if (PrimaryKeyList[entity].includes(name)) {
return <LinkDiv onClick={() => onClickPrimaryKey(name, value)}>{shortValue}</LinkDiv>;
} else if (entity === 'accounts' && name === 'manager') { // TODO: resolve via metadata
return <LinkDiv onClick={() => onClickPrimaryKey('account_id', value)}>{shortValue}</LinkDiv>;
} else if (entity === 'blocks' && name === 'predecessor') { // TODO: resolve via metadata
return <LinkDiv onClick={() => onClickPrimaryKey('hash', value)}>{shortValue}</LinkDiv>;
}
return shortValue;
}

export const formatValueForDisplay = (platform: string, network: string, value: any, attribute: AttributeDefinition) => {
const { name, entity, dataFormat, dataType} = attribute;
if (dataType === 'DateTime') {
const formatValueForDisplay = (
platform: string,
network: string,
entity: string,
value: any,
attribute: AttributeDefinition,
onClickPrimaryKey: (key, value) => void
) => {
const { name, dataFormat, dataType} = attribute;
if (dataType === 'Boolean') {
const svalue = value.toString();
return svalue.charAt(0).toUpperCase() + svalue.slice(1);
} else if (dataType === 'DateTime') {
if (!dataFormat) {
return value;
}
return (
<Moment parse={dataFormat}>
<Moment format={dataFormat}>
{value}
</Moment>
)
Expand All @@ -93,7 +129,7 @@ export const formatValueForDisplay = (platform: string, network: string, value:
<React.Fragment>
<StyledCircle1 newcolor={`#${colors.substring(0, 6)}`} />
<StyledCircle2 newcolor={`#${colors.slice(-6)}`} />
{getShortColumn(value)}
{formatValueForPrimary(entity, name, getShortColumn(value), value, onClickPrimaryKey)}
<ClipboardWrapper data-clipboard-text={value}>
<CopyIcon />
</ClipboardWrapper>
Expand All @@ -102,26 +138,26 @@ export const formatValueForDisplay = (platform: string, network: string, value:
} else if (DefaultAttributeNames.includes(name)) {
return (
<React.Fragment>
{getShortColumn(value)}
{formatValueForPrimary(entity, name, getShortColumn(value), value, onClickPrimaryKey)}
<ClipboardWrapper data-clipboard-text={value}>
<CopyIcon />
</ClipboardWrapper>
</React.Fragment>
);
} else {
return value;
return formatValueForPrimary(entity, name, value, value, onClickPrimaryKey);
}
};

const CustomTableRow: React.StatelessComponent<Props> = props => {
const { selectedColumns, item, network, platform } = props;
const { selectedColumns, item, network, platform, selectedEntity, onClickPrimaryKey } = props;
return (
<TableRowWrapper>
{selectedColumns.map((column, index) => {
return (
<StyledCell key={index}>
<SpanContainer>
{formatValueForDisplay(platform, network, item[column.name], column)}
{formatValueForDisplay(platform, network, selectedEntity, item[column.name], column, onClickPrimaryKey)}
</SpanContainer>
</StyledCell>
);
Expand Down
175 changes: 175 additions & 0 deletions src/components/EntityModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import * as React from 'react';
import styled from 'styled-components';
import Modal from '@material-ui/core/Modal';
import CircularProgress from '@material-ui/core/CircularProgress';
import Moment from 'react-moment';
import 'moment-timezone';
import ArronaxIcon from '../ArronaxIcon';

const ModalWrapper = styled(Modal)``;

const ScrollContainer = styled.div`
width: 100%;
height: 100%;
overflow-y: auto;
padding: 77px 0;
`;

const ModalContainer = styled.div`
background-color: #ffffff;
outline: none;
position: relative;
padding: 27px 30px 30px 30px;
margin: 0 auto;
width: 798px;
min-height: 100%;
`;

const ListContainer = styled.div`
width: 100%;
`;

const CloseIcon = styled(ArronaxIcon)`
cursor: pointer;
position: absolute;
top: 30px;
right: 30px;
`;

const ModalTitle = styled.div`
padding: 0 0 19px 0;
font-size: 24px;
line-height: 28px;
font-weight: 400;
color: #9b9b9b;
`;

const RowContainer = styled.div`
display: flex;
padding: 15px 0;
font-size: 16px;
line-height: 19px;
border-bottom: 1px solid #dcdcdc;
letter-spacing: 0.23px;
color: rgb(74, 74, 74);
`;

const TitleTxt = styled.div`
width: 198px;
font-weight: 400;
`;

const ContentTxt = styled.div`
font-weight: 300;
word-break: break-word;
flex: 1;
`;

const LoadingContainer = styled.div`
position: absolute;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.3);
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
`;

export const ButtonContainer = styled.div`
display: flex;
padding: 15px;
justify-content: flex-end;
`;

export const CloseButton = styled.div`
color: #56c2d9;
font-size: 20px;
font-weight: 700;
cursor: pointer;
display: flex;
align-items: center;
`;

const TITLE = {
blocks: 'Block',
opperations: 'Operation',
accounts: 'Account'
};

type Props = {
selectedEntity: string,
open: boolean,
item: any;
attributes: any[];
isLoading: boolean,
onClose: () => void
};

class EntityModal extends React.Component<Props, {}> {

onClickModal = (event) => {
event.stopPropagation();
}
render() {
const {
selectedEntity,
open,
item,
attributes,
isLoading,
onClose,
} = this.props;
return (
<ModalWrapper
open={open}
>
<ScrollContainer onClick={onClose}>
<ModalContainer onClick={(event) => this.onClickModal(event)}>
<CloseIcon onClick={onClose} size="19px" color="#9b9b9b" iconName="icon-close" />
<ModalTitle>{TITLE[selectedEntity]} Details</ModalTitle>
{!isLoading && (
<ListContainer>
{attributes.map((column, index) => {
const { displayName, dataType, dataFormat, name } = column;
let value = item[name];
if (!value) {
return null;
}
if (dataType === 'DateTime' && dataFormat) {
value = (
<Moment format={dataFormat}>
{value}
</Moment>
);
}
return (
<RowContainer key={index}>
<TitleTxt>{displayName}</TitleTxt>
<ContentTxt>{value}</ContentTxt>
</RowContainer>
);
})}
<ButtonContainer>
<CloseButton onClick={onClose}>
Close
</CloseButton>
</ButtonContainer>
</ListContainer>
)}
{isLoading && (
<LoadingContainer>
<CircularProgress />
</LoadingContainer>
)}
</ModalContainer>
</ScrollContainer>

</ModalWrapper>
);
}
};

export default EntityModal;
6 changes: 3 additions & 3 deletions src/containers/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ const MainContainer = styled.div`
`;

const LoadingContainer = styled.div`
position: absolute;
position: fixed;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.3);
top: 0;
left: 0;
width: 100%;
height: 100%;
height: 100vh;
z-index: 100;
`;

Expand Down Expand Up @@ -306,7 +306,7 @@ class Arronax extends React.Component<Props, States> {
onClose={this.onCloseFilter}
/>
<TabContainer component="div">
{items.length > 0 && <CustomTable items={items} onExportCsv={this.onExportCsv} /> }
{items.length > 0 && <CustomTable isLoading={isLoading} items={items} onExportCsv={this.onExportCsv} /> }
{items.length === 0 && (
<NoResultContainer>
<OctopusImg src={octopusSrc} />
Expand Down
Loading

0 comments on commit ac06721

Please sign in to comment.