Skip to content

Commit

Permalink
Merge pull request #469 from Cryptonomic/add_NFTs
Browse files Browse the repository at this point in the history
Add NFTs
  • Loading branch information
anonymoussprocket authored Apr 21, 2022
2 parents 108c4b9 + 6602d14 commit b7b64ed
Show file tree
Hide file tree
Showing 23 changed files with 1,043 additions and 76 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@
"webpack-merge": "4.2.2"
},
"dependencies": {
"@airgap/beacon-sdk": "2.3.10",
"@airgap/beacon-sdk": "2.3.12",
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@mui/icons-material": "^5.0.1",
Expand Down
Binary file added resources/contracts/pxl-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions resources/trash-can.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/components/AddressBlock/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import BeaconPermission from '../../featureModals/Beacon/BeaconPermission';
import BeaconInfo from '../../featureModals/Beacon/BeaconInfo';
import BeaconDisabled from '../../featureModals/Beacon/BeaconDisabled';
import PlentyHarvestModal from '../../contracts/Plenty/components/HarvestModal';
import NFTAddModal from '../../contracts/NFT/components/NFTAddModal';
import KolibriHarvestModal from '../../contracts/KolibriToken/components/HarvestModal';
import { setModalOpen, clearModal } from '../../reduxContent/modal/actions';
import { changeAccountThunk } from '../../reduxContent/app/thunks';
Expand Down Expand Up @@ -294,6 +295,7 @@ function AddressBlock(props: Props) {
const isBeaconDisabledModalOpen = isModalOpen && activeModal === 'beaconDisable';
const isDelegateModalOpen = isModalOpen && activeModal === 'delegate_contract';
const isPlentyHarvestModalOpen = isModalOpen && activeModal === 'PlentyHarvest';
const isNFTAddModalOpen = isModalOpen && activeModal === 'NFTAdd';
const isKolibriHarvestModalOpen = isModalOpen && activeModal === 'KolibriHarvest';

return (
Expand Down Expand Up @@ -483,6 +485,7 @@ function AddressBlock(props: Props) {
)}

{isPlentyHarvestModalOpen && <PlentyHarvestModal open={isPlentyHarvestModalOpen} onClose={() => setIsModalOpen(false, 'PlentyHarvest')} />}
{isNFTAddModalOpen && <NFTAddModal open={isNFTAddModalOpen} onClose={() => setIsModalOpen(false, 'NFTAdd')} />}
{isKolibriHarvestModalOpen && <KolibriHarvestModal open={isKolibriHarvestModalOpen} onClose={() => setIsModalOpen(false, 'KolibriHarvest')} />}

{isDelegateModalOpen && (
Expand Down
7 changes: 5 additions & 2 deletions src/components/InputAddress/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ interface Props {
onChange: (val: string) => void;
tooltip?: boolean;
address?: string;
operationType: 'send' | 'delegate' | 'invoke' | 'send_babylon' | 'tz1'; // TODO: enum
operationType: 'send' | 'delegate' | 'invoke' | 'send_babylon' | 'tz1' | 'addNFT'; // TODO: enum
onIssue?: (error: boolean) => void;
onAddressType?: (type: AddressType) => void;
}
Expand Down Expand Up @@ -114,6 +114,9 @@ function InputAddress(props: Props) {
} else if (operationType === 'tz1') {
firstCharactersRegEx = /^(tz1|edpk)/;
regErrorTxt = t('components.inputAddress.errors.verify_tz1');
} else if (operationType === 'addNFT') {
firstCharactersRegEx = /^(KT1)/;
regErrorTxt = t('components.nftGallery.errors.invalid_address');
}

return { firstCharactersRegEx, regErrorTxt };
Expand Down Expand Up @@ -147,7 +150,7 @@ function InputAddress(props: Props) {
errorState = false;
} else {
addressType = getAddressType(addressText, account[0].script);
if (addressType === AddressType.Smart && operationType !== 'invoke') {
if (addressType === AddressType.Smart && operationType !== ('invoke' && 'addNFT')) {
newError = t('components.inputAddress.errors.use_interact');
errorState = true;
}
Expand Down
75 changes: 75 additions & 0 deletions src/components/ManageNFTsModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';

import CloseIcon from '@mui/icons-material/Close';

import { CloseButton, ModalHeader, StyledModalBox, StyledDivider, FooterCon, FooterText } from './style';
import { ModalWrapper } from '../../contracts/components/style';

import TableComponent from '../Table';
import { AddButton, AddIcon } from '../../contracts/NFT/components/NFTGallery/style';

import { getLocalData, setLocalData } from '../../utils/localData';
import { setModalOpen } from '../../reduxContent/modal/actions';

export const ManageNFTsModal = ({ open, onClose, tokens }) => {
const { t } = useTranslation();
const dispatch = useDispatch();

const localTokens = getLocalData('token');

const sortedTokens = tokens.sort((a, b) => b.balance - a.balance || a.displayName.localeCompare(b.displayName));
let customSortedTokens = [];
if (localTokens !== undefined) {
customSortedTokens = localTokens.sort((a, b) => b.balance - a.balance || a.displayName.localeCompare(b.displayName));
}

function findIndexWithProps(array, attr, value) {
for (let i = 0; i < array.length; i += 1) {
if (array[i][attr] === value) {
return i;
}
}
return -1;
}
const deleteToken = (item) => {
const index = findIndexWithProps(localTokens, 'mapid', item.mapid);
localTokens.splice(index, 1);
setLocalData('token', localTokens);
};

return (
<ModalWrapper open={open} onClose={onClose} aria-labelledby="Tokens" aria-describedby="Manage token collections">
<StyledModalBox>
<ModalHeader>{t('components.manageNFTsModal.modal_title')}</ModalHeader>
<TableComponent
tableData={customSortedTokens}
headerOne="Custom Added NFTs"
headerTwo="Quantity"
headerThree="Remove"
icon={true}
deleteToken={(token) => deleteToken(token)}
/>
<TableComponent tableData={sortedTokens} headerOne="Other NFTs" headerTwo="Quantity" headerThree="" />
<CloseButton onClick={onClose}>
<CloseIcon />
</CloseButton>
<StyledDivider />
<FooterCon>
<FooterText>Don’t see your NFTs?</FooterText>
<AddButton
startIcon={<AddIcon />}
onClick={() => {
onClose();
dispatch(setModalOpen(true, 'NFTAdd'));
}}
disableRipple={true}
>
Add NFT
</AddButton>
</FooterCon>
</StyledModalBox>
</ModalWrapper>
);
};
82 changes: 82 additions & 0 deletions src/components/ManageNFTsModal/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import styled from 'styled-components';
import IconButton from '@mui/material/IconButton';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Divider from '@mui/material/Divider';

import { ModalBox } from '../../contracts/components/style';

export const styledTable = styled(Table)`
background: 'red;
`;

export const StyledModalBox = styled(ModalBox)`
position: relative;
overflow: auto;
width: 570px;
min-height: 560px;
max-height: calc(100vh - 80px);
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: ${({ theme: { colors } }) => colors.gray2};
}
&::-webkit-scrollbar-thumb {
background: ${({ theme: { colors } }) => colors.accent};
border-radius: 4px;
}
`;

export const ModalHeader = styled.h2`
background: ${({ theme: { colors } }) => colors.accent};
font-size: 16px;
font-weight: 400;
color: ${({ theme: { colors } }) => colors.white};
margin: 0;
padding: 15px 0 13px 16px;
`;

export const CloseButton = styled(IconButton)`
&&& {
color: ${({ theme: { colors } }) => colors.white};
position: absolute;
top: 5px;
right: 5px;
z-index: 1301;
cursor: pointer !important;
span,
svg,
path {
cursor: pointer !important;
}
:hover {
opacity: 0.7;
}
@media all and (min-width: 768px) {
display: block;
}
}
`;
export const StyledDivider = styled(Divider)`
border: 1px solid #e0e0e0;
`;
export const FooterCon = styled.div`
padding: 16px 0 16px 23px;
`;
export const FooterText = styled.p`
color: ${({ theme: { colors } }) => colors.gray3};
margin: 0;
padding-bottom: 8px;
font-weight: 500;
font-size: 16px;
line-height: 16px;
`;
53 changes: 53 additions & 0 deletions src/components/Table/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';

import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Button from '@mui/material/Button';

import TezosAddress from '../TezosAddress';

import trashCan from '../../../resources/trash-can.svg';

import { StyledTableContainer, StyledTableHeadCell, StyledTableCell, StyledTableCellRight, StyledTableHeadCellRight, TokenTitle } from './style';
import { useSelector } from 'react-redux';

const TableComponent = (props) => {
const { headerOne, headerTwo, headerThree, tableData, icon, deleteToken } = props;

return (
<StyledTableContainer>
<Table>
<TableHead>
<TableRow>
<StyledTableHeadCell>{headerOne}</StyledTableHeadCell>
<StyledTableHeadCellRight> {headerTwo} </StyledTableHeadCellRight>
<StyledTableHeadCellRight> {headerThree} </StyledTableHeadCellRight>
</TableRow>
</TableHead>
<TableBody>
{tableData !== undefined &&
tableData.map((data, index) => (
<TableRow key={`token-item-${index}`}>
<StyledTableCell>
<TokenTitle> {data.displayName} </TokenTitle>
<TezosAddress address={data.address} text={data.address} weight={300} color="gray18" size="14px" shorten={true} />
</StyledTableCell>
<StyledTableCellRight />
<StyledTableCellRight>
{icon && (
<Button disableRipple={true} onClick={() => deleteToken(data)}>
<img src={trashCan} alt="trash-can" />
</Button>
)}
</StyledTableCellRight>
</TableRow>
))}
</TableBody>
</Table>
</StyledTableContainer>
);
};

export default TableComponent;
41 changes: 41 additions & 0 deletions src/components/Table/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import styled from 'styled-components';

import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';

export const StyledTableContainer = styled(TableContainer)`
margin-bottom: 40px;
padding-top: 27px;
`;
export const StyledTableHeadCell = styled(TableCell)`
height: 16px;
font-size: 16px;
font-weight: 400;
color: ${({ theme: { colors } }) => colors.gray3} !important;
border: 0 !important;
min-width: 230px;
padding: 0 16px !important;
`;
export const StyledTableHeadCellRight = styled(TableCell)`
height: 16px;
font-size: 16px;
font-weight: 400;
color: ${({ theme: { colors } }) => colors.gray3} !important;
border: 0 !important;
min-width: 148px;
padding: 0 16px !important;
text-align: right !important;
`;
export const StyledTableCell = styled(TableCell)`
border: 0 !important;
`;
export const StyledTableCellRight = styled(TableCell)`
border: 0 !important;
text-align: right !important;
`;

export const TokenTitle = styled.p`
font-weight: 400;
font-size: 16px;
line-height: 16px;
`;
Loading

0 comments on commit b7b64ed

Please sign in to comment.