├── .env.sample
├── .eslintrc.js
├── .gitignore
├── Layout
├── Footer
│ ├── FooterAccount
│ │ └── index.js
│ ├── FooterContact
│ │ └── index.js
│ ├── FooterMenu
│ │ └── index.js
│ ├── FooterMenuItem
│ │ └── index.js
│ ├── FooterTerm
│ │ └── index.js
│ └── index.js
├── TopAppBar
│ ├── ConnectWallet
│ │ └── index.js
│ ├── NavBarMenu
│ │ └── index.js
│ ├── NavDropMenu
│ │ └── index.js
│ ├── ThemeButton
│ │ └── index.js
│ └── index.js
└── index.js
├── README.md
├── actions
├── auth.js
├── loading.js
├── popUp.js
└── types.js
├── components
├── Icons
│ ├── DefaultImageIcon
│ │ └── index.js
│ ├── DiscordIcon
│ │ └── index.js
│ ├── GreyEyeCloseIcon
│ │ └── index.js
│ ├── GreyEyeIcon
│ │ └── index.js
│ ├── MaximizeIcon
│ │ └── index.js
│ ├── TelegramIcon
│ │ └── index.js
│ └── TwitterIcon
│ │ └── index.js
├── Logo
│ └── index.js
├── MagicDialog
│ └── index.js
├── MagicLoading
│ ├── LoadingSpinner
│ │ └── index.js
│ └── index.js
└── UI
│ ├── Buttons
│ ├── ButtonLink
│ │ └── index.js
│ ├── ContainedButton
│ │ └── index.js
│ ├── LinkButton
│ │ └── index.js
│ └── OutlinedButton
│ │ └── index.js
│ ├── MagicCheckbox
│ └── index.js
│ ├── MagicMultiSelect
│ └── index.js
│ ├── MagicSelect
│ └── index.js
│ └── TextFields
│ ├── AccountTextField
│ └── index.js
│ ├── MagicTextField
│ └── index.js
│ └── TextMaskCustom
│ └── index.js
├── config
└── index.js
├── containers
├── Auth
│ ├── Shared
│ │ └── AuthWrapper
│ │ │ └── index.js
│ ├── SignIn
│ │ └── index.js
│ └── SignUp
│ │ └── index.js
├── CreateNFT
│ ├── CreateForm
│ │ └── index.js
│ ├── PreviewCard
│ │ └── index.js
│ ├── UploadMedia
│ │ └── index.js
│ └── index.js
├── FAQ
│ └── index.js
├── Home
│ ├── CreatorAndCollector
│ │ └── index.js
│ ├── HomeHeader
│ │ └── index.js
│ ├── HomeJourney
│ │ └── index.js
│ ├── UserFeedback
│ │ ├── FeedbackCard
│ │ │ └── index.js
│ │ └── index.js
│ └── index.js
├── Marketplace
│ └── index.js
├── MyAccount
│ ├── EditAccount
│ │ └── index.js
│ ├── MyBalance
│ │ └── index.js
│ └── index.js
├── MyNFTs
│ ├── MyAskOrders
│ │ ├── OrderItem
│ │ │ └── index.js
│ │ └── index.js
│ ├── MyAssets
│ │ ├── AssetItem
│ │ │ └── index.js
│ │ └── index.js
│ ├── MyBidOrders
│ │ ├── BidItem
│ │ │ └── index.js
│ │ └── index.js
│ ├── Shared
│ │ ├── TabPanel
│ │ │ └── index.js
│ │ └── VerticalTabs
│ │ │ └── index.js
│ └── index.js
├── NFTDetail
│ ├── AssetBids
│ │ └── index.js
│ ├── HistoricalPrices
│ │ └── index.js
│ ├── NFTInformation
│ │ ├── InformationContent
│ │ │ └── index.js
│ │ └── index.js
│ ├── SellerNFTs
│ │ └── index.js
│ └── index.js
├── PrivacyPolicy
│ └── index.js
├── TermsOfService
│ └── index.js
└── TransactionHistory
│ ├── TransactionItem
│ └── index.js
│ └── index.js
├── contexts
└── ui-context.js
├── jsconfig.json
├── next.config.js
├── package.json
├── pages
├── _app.js
├── _document.js
├── auth
│ ├── sign-in.js
│ └── sign-up.js
├── create-nft.js
├── faq.js
├── index.js
├── marketplace.js
├── my-account.js
├── my-nfts.js
├── nft-details
│ └── [goods].js
├── privacy-policy.js
├── terms-of-service.js
└── transaction-history.js
├── parts
├── BidNFTDialog
│ └── index.js
├── CancelNFTOrderDialog
│ └── index.js
├── DeleteNFTDialog
│ └── index.js
├── HeaderMeta
│ └── index.js
├── ImageWall
│ └── index.js
├── MagicConfirmDialog
│ └── index.js
├── NFTCarousel
│ ├── NFTCarouselItem
│ │ └── index.js
│ └── index.js
├── NFTList
│ ├── NFTCard
│ │ └── index.js
│ └── index.js
├── NoData
│ └── index.js
├── ProductContent
│ └── index.js
├── PurchaseNFTDialog
│ └── index.js
├── SearchInput
│ └── index.js
├── SellAssetDialog
│ └── index.js
├── SendAssetDialog
│ └── index.js
└── Table
│ └── TableContainer
│ └── index.js
├── public
├── android-chrome-144x144.png
├── android-chrome-192x192.png
├── android-chrome-256x256.png
├── android-chrome-36x36.png
├── android-chrome-384x384.png
├── android-chrome-48x48.png
├── android-chrome-512x512.png
├── android-chrome-72x72.png
├── android-chrome-96x96.png
├── apple-touch-icon-114x114-precomposed.png
├── apple-touch-icon-114x114.png
├── apple-touch-icon-120x120-precomposed.png
├── apple-touch-icon-120x120.png
├── apple-touch-icon-144x144-precomposed.png
├── apple-touch-icon-144x144.png
├── apple-touch-icon-152x152-precomposed.png
├── apple-touch-icon-152x152.png
├── apple-touch-icon-180x180-precomposed.png
├── apple-touch-icon-180x180.png
├── apple-touch-icon-57x57-precomposed.png
├── apple-touch-icon-57x57.png
├── apple-touch-icon-60x60-precomposed.png
├── apple-touch-icon-60x60.png
├── apple-touch-icon-72x72-precomposed.png
├── apple-touch-icon-72x72.png
├── apple-touch-icon-76x76-precomposed.png
├── apple-touch-icon-76x76.png
├── apple-touch-icon-precomposed.png
├── apple-touch-icon.png
├── assets
│ ├── fonts
│ │ ├── CRC-BOLD.woff
│ │ └── CRC-LIGHT.woff
│ ├── images
│ │ ├── background
│ │ │ ├── auth.jpg
│ │ │ ├── footer.jpg
│ │ │ ├── header.jpg
│ │ │ └── home-header.jpg
│ │ ├── banner.png
│ │ ├── black-logo.png
│ │ ├── home-logo.png
│ │ ├── icon
│ │ │ └── image-placeholder.jpg
│ │ └── white-logo.png
│ ├── js
│ │ └── europa-jupiter.js
│ └── lotties
│ │ └── green-progress.json
├── browserconfig.xml
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon.ico
├── mstile-144x144.png
├── mstile-150x150.png
├── mstile-310x150.png
├── mstile-310x310.png
├── safari-pinned-tab.svg
└── site.webmanifest
├── reducers
├── authReducer.js
├── index.js
├── loadingReducer.js
└── popUpReducer.js
├── services
├── api-cloudinary.js
├── api-jupiter.js
├── axios.js
└── europa.js
├── store.js
├── styles
├── global.js
├── theme.js
└── use-styles.js
├── utils
├── constants
│ ├── common.js
│ ├── contact.js
│ ├── file-types.js
│ ├── footer-menu.js
│ ├── image-paths.js
│ ├── links.js
│ ├── messages.js
│ ├── order-type.js
│ ├── routes.js
│ ├── social.js
│ ├── text-masks.js
│ ├── top-bar-menu.js
│ ├── validations.js
│ └── words.js
├── helpers
│ ├── delay.js
│ ├── generatePassphrase.js
│ ├── getEllipsis.js
│ ├── getJSONParse.js
│ ├── getTimestamp.js
│ ├── scrollToTop.js
│ ├── signTransaction.js
│ ├── time.js
│ ├── toFixedIfNecessary.js
│ └── utility.js
├── hocs
│ ├── InitProvider
│ │ └── index.js
│ ├── PopUpProvider
│ │ └── index.js
│ └── ThemeProvider
│ │ └── index.js
└── hooks
│ ├── useAuth.js
│ ├── useLoading.js
│ ├── useMenu.js
│ └── usePopUp.js
└── yarn.lock
/.env.sample:
--------------------------------------------------------------------------------
1 | VERSION='1.0-rc'
2 | APPNAME='Leda'
3 |
4 | NETWORK=mainnet
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /**
2 | * TODO: Warning: React version not specified in eslint-plugin-react settings. See https://github.com/yannickcr/eslint-plugin-react#configuration
3 | * TODO: update with the standard linting settings
4 | * By great.dolphin.ls
5 | */
6 |
7 | module.exports = {
8 | 'parser': 'babel-eslint',
9 | 'parserOptions': {
10 | 'ecmaVersion': 2018,
11 | 'sourceType': 'module'
12 | },
13 | 'env': {
14 | 'es6': true
15 | },
16 | 'extends': [
17 | 'plugin:react/recommended',
18 | 'plugin:react-hooks/recommended'
19 | ],
20 | 'rules': {
21 | 'react/display-name': 0,
22 | 'no-unused-vars': 'warn',
23 | 'react/no-unknown-property': 0,
24 | 'react/prop-types': 0,
25 | 'react/react-in-jsx-scope': 0
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env
29 | .env.local
30 | .env.development.local
31 | .env.test.local
32 | .env.production.local
33 |
34 | # vercel
35 | .vercel
36 |
--------------------------------------------------------------------------------
/Layout/Footer/FooterAccount/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { useSelector } from 'react-redux'
4 | import { makeStyles } from '@material-ui/core/styles'
5 | import {
6 | Grid,
7 | Typography
8 | } from '@material-ui/core'
9 |
10 | import FooterMenuItem from '../FooterMenuItem'
11 | import LINKS from 'utils/constants/links'
12 |
13 | const useStyles = makeStyles(theme => ({
14 | root: {
15 | margin: theme.spacing(0.5, 0)
16 | },
17 | title: {
18 | fontWeight: 'bold',
19 | color: theme.palette.background.default,
20 | marginBottom: theme.spacing(1)
21 | }
22 | }));
23 |
24 | const FooterAccount = () => {
25 | const classes = useStyles();
26 | const { accountRS = '' } = useSelector(state => state.auth);
27 |
28 | return (
29 |
30 |
34 | ACCOUNT
35 |
36 |
37 | {accountRS
38 | ? (
39 | <>
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | >
53 | ) : (
54 | <>
55 |
56 |
57 |
58 |
59 |
60 |
61 | >
62 | )
63 | }
64 |
65 |
66 | );
67 | };
68 |
69 | export default memo(FooterAccount);
--------------------------------------------------------------------------------
/Layout/Footer/FooterContact/index.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react'
2 | import { makeStyles } from '@material-ui/core/styles'
3 |
4 | import Logo from 'components/Logo'
5 | import TelegramIcon from 'components/Icons/TelegramIcon'
6 | import TwitterIcon from 'components/Icons/TwitterIcon'
7 | import DiscordIcon from 'components/Icons/DiscordIcon'
8 | import LinkButton from 'components/UI/Buttons/LinkButton'
9 | import { SUPPORT_EMAIL } from 'utils/constants/contact'
10 |
11 | const useStyles = makeStyles((theme) => ({
12 | root: {
13 | display: 'flex',
14 | flexDirection: 'column',
15 | marginBottom: theme.spacing(2),
16 | },
17 | email: {
18 | fontSize: 18,
19 | fontWeight: 600,
20 | marginTop: theme.spacing(1.5),
21 | color: theme.palette.background.default,
22 | textDecoration: 'unset',
23 | },
24 | socialContainer: {
25 | margin: theme.spacing(2.5, 0)
26 | },
27 | socialIcon: {
28 | marginRight: theme.spacing(2)
29 | }
30 | }));
31 |
32 | const FooterContact = () => {
33 | const classes = useStyles();
34 |
35 | return (
36 |
37 |
38 |
43 | {SUPPORT_EMAIL}
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | );
52 | };
53 |
54 | export default memo(FooterContact);
55 |
--------------------------------------------------------------------------------
/Layout/Footer/FooterMenu/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import {
5 | Grid,
6 | Typography
7 | } from '@material-ui/core'
8 |
9 | import FooterMenuItem from '../FooterMenuItem'
10 | import FOOTER_MENU from 'utils/constants/footer-menu'
11 |
12 | const useStyles = makeStyles(theme => ({
13 | root: {
14 | margin: theme.spacing(0.5, 0)
15 | },
16 | title: {
17 | fontWeight: 'bold',
18 | color: theme.palette.background.default,
19 | marginBottom: theme.spacing(1)
20 | }
21 | }));
22 |
23 | const FooterMenu = () => {
24 | const classes = useStyles();
25 |
26 | return (
27 |
28 |
32 | MENU
33 |
34 |
35 | {
36 | FOOTER_MENU.map((menuItem) => (
37 |
38 |
39 |
40 | ))
41 | }
42 |
43 |
44 | );
45 | };
46 |
47 | export default memo(FooterMenu);
48 |
--------------------------------------------------------------------------------
/Layout/Footer/FooterMenuItem/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useCallback } from 'react'
3 | import Typography from '@material-ui/core/Typography'
4 | import { makeStyles } from '@material-ui/core/styles'
5 |
6 | import useMenu from 'utils/hooks/useMenu'
7 |
8 | const useStyles = makeStyles(theme => ({
9 | item: {
10 | cursor: 'pointer',
11 | color: theme.palette.background.default,
12 | margin: theme.spacing(0.5, 0),
13 | '&:hover': {
14 | textDecoration: 'underline'
15 | }
16 | }
17 | }));
18 |
19 | const FooterMenuItem = ({
20 | menu
21 | }) => {
22 | const classes = useStyles();
23 | const { onMenuHandler } = useMenu();
24 |
25 | const onNavHandler = useCallback(() => {
26 | onMenuHandler(menu)
27 | }, [menu, onMenuHandler]);
28 |
29 | return (
30 |
35 | {menu.TITLE}
36 |
37 | );
38 | };
39 |
40 | export default memo(FooterMenuItem);
41 |
--------------------------------------------------------------------------------
/Layout/Footer/FooterTerm/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import {
5 | Grid,
6 | Typography
7 | } from '@material-ui/core'
8 |
9 | import FooterMenuItem from '../FooterMenuItem'
10 | import LINKS from 'utils/constants/links'
11 |
12 | const useStyles = makeStyles(theme => ({
13 | root: {
14 | margin: theme.spacing(0.5, 0)
15 | },
16 | title: {
17 | fontWeight: 'bold',
18 | color: theme.palette.background.default,
19 | marginBottom: theme.spacing(1)
20 | }
21 | }));
22 |
23 | const FooterTerm = () => {
24 | const classes = useStyles();
25 |
26 | return (
27 |
28 |
32 | TERMS
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | );
44 | };
45 |
46 | export default memo(FooterTerm);
--------------------------------------------------------------------------------
/Layout/Footer/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import Grid from '@material-ui/core/Grid'
4 | import { makeStyles } from '@material-ui/core/styles'
5 | import clsx from 'clsx'
6 |
7 | import FooterMenu from './FooterMenu'
8 | import FooterAccount from './FooterAccount'
9 | import FooterContact from './FooterContact'
10 | import FooterTerm from './FooterTerm'
11 | import { FOOTER_BACKGROUND_IMAGE_PATH } from 'utils/constants/image-paths'
12 | import { useCommonStyles } from 'styles/use-styles'
13 |
14 | const useStyles = makeStyles(theme => ({
15 | root: {
16 | display: 'flex',
17 | flexDirection: 'row',
18 | justifyContent: 'center',
19 | width: '100%',
20 | backgroundImage: `url(${FOOTER_BACKGROUND_IMAGE_PATH})`,
21 | backgroundRepeat: 'no-repeat',
22 | backgroundSize: 'cover',
23 | backgroundPosition: 'center',
24 | },
25 | container: {
26 | display: 'flex',
27 | flexDirection: 'row',
28 | justifyContent: 'space-between',
29 | color: theme.custom.palette.blue,
30 | paddingTop: theme.spacing(6),
31 | paddingBottom: theme.spacing(6),
32 | [theme.breakpoints.down('sm')]: {
33 | flexDirection: 'column',
34 | }
35 | }
36 | }));
37 |
38 | const Footer = () => {
39 | const classes = useStyles();
40 | const commonClasses = useCommonStyles();
41 |
42 | return (
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | );
68 | };
69 |
70 | export default memo(Footer);
71 |
--------------------------------------------------------------------------------
/Layout/TopAppBar/ConnectWallet/index.js:
--------------------------------------------------------------------------------
1 | import { memo, useState } from 'react'
2 | import { Typography } from '@material-ui/core'
3 | import { makeStyles } from '@material-ui/core/styles'
4 |
5 | import * as europaAPI from 'services/europa'
6 | import * as jupiterAPI from 'services/api-jupiter'
7 | import ContainedButton from 'components/UI/Buttons/ContainedButton'
8 | import useAuth from 'utils/hooks/useAuth'
9 | import usePopUp from 'utils/hooks/usePopUp'
10 | import MESSAGES from 'utils/constants/messages'
11 |
12 | const useStyles = makeStyles((theme) => ({
13 | account: {
14 | fontWeight: 'bold',
15 | cursor: 'pointer',
16 | padding: theme.spacing(0, 1),
17 | color: theme.custom.palette.green,
18 | border: `2px dashed ${theme.custom.palette.green}`,
19 | },
20 | connect: {
21 | margin: theme.spacing(0, 1)
22 | }
23 | }));
24 |
25 | const ConnectWallet = () => {
26 | const classes = useStyles()
27 | const { accountRS, logOutHandler, setLoginToken } = useAuth();
28 | const { setPopUp } = usePopUp();
29 |
30 | const [loading, setLoading] = useState(false);
31 |
32 | const walletHandler = async () => {
33 | if (!!accountRS) {
34 | logOutHandler()
35 | return
36 | }
37 |
38 | setLoading(true);
39 | try {
40 | const accountRS = await europaAPI.connectWallet()
41 | const response = await jupiterAPI.getAccountByAccountID(accountRS);
42 | if (!response?.accountRS) {
43 | setPopUp({ text: MESSAGES.CONNECT_WALLET_ERROR })
44 | setLoading(false);
45 | return;
46 | }
47 |
48 | setLoginToken({
49 | accountRS: response.accountRS,
50 | user: response,
51 | isWallet: true
52 | });
53 | } catch (error) {
54 | console.log(error)
55 | setPopUp({ text: MESSAGES.CONNECT_WALLET_ERROR })
56 | }
57 | setLoading(false);
58 | }
59 |
60 | return (
61 | !!accountRS
62 | ? (
63 |
68 | {accountRS || ''}
69 |
70 | ) : (
71 |
76 | Connect
77 |
78 | )
79 | );
80 | };
81 |
82 | export default memo(ConnectWallet);
83 |
--------------------------------------------------------------------------------
/Layout/TopAppBar/NavBarMenu/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useCallback } from 'react'
3 | import { useRouter } from 'next/router'
4 | import {
5 | Button,
6 | Hidden
7 | } from '@material-ui/core'
8 | import { makeStyles } from '@material-ui/core/styles'
9 | import clsx from 'clsx';
10 |
11 | import ContainedButton from 'components/UI/Buttons/ContainedButton'
12 | import OutlinedButton from 'components/UI/Buttons/OutlinedButton'
13 | import useMenu from 'utils/hooks/useMenu'
14 | import LINKS from 'utils/constants/links'
15 |
16 | const useStyles = makeStyles((theme) => ({
17 | root: {
18 | display: 'flex',
19 | flexDirection: 'row',
20 | alignItems: 'center'
21 | },
22 | item: {
23 | fontSize: 15,
24 | fontWeight: 'bold',
25 | color: theme.palette.text.primary
26 | },
27 | login: {
28 | margin: theme.spacing(0, 1)
29 | },
30 | selected: {
31 | color: theme.palette.primary.main
32 | }
33 | }));
34 |
35 | const NavBarMenu = () => {
36 | const classes = useStyles();
37 | const router = useRouter()
38 | const { PROFILE_MENU_LINKS, onMenuHandler } = useMenu();
39 |
40 | const onNavHandler = useCallback((item) => () => {
41 | onMenuHandler(item)
42 | }, [onMenuHandler])
43 |
44 | return (
45 |
46 |
47 | {
48 | PROFILE_MENU_LINKS.map((item, index) => {
49 | if (item.HREF === LINKS.SIGN_UP.HREF) {
50 | return (
51 |
56 | {item.TITLE}
57 |
58 | )
59 | }
60 |
61 | if (item.HREF === LINKS.SIGN_IN.HREF || item.HREF === LINKS.SIGN_OUT.HREF) {
62 | return (
63 |
68 | {item.TITLE}
69 |
70 | )
71 | }
72 |
73 | return (
74 |
79 | {item.TITLE}
80 |
81 | )
82 | })
83 | }
84 |
85 |
86 | );
87 | };
88 |
89 | export default memo(NavBarMenu);
--------------------------------------------------------------------------------
/Layout/TopAppBar/NavDropMenu/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useCallback, useState } from 'react'
3 | import {
4 | Menu,
5 | MenuItem,
6 | Hidden,
7 | IconButton
8 | } from '@material-ui/core'
9 | import { makeStyles } from '@material-ui/core/styles'
10 | import MenuIcon from '@material-ui/icons/Menu'
11 |
12 | import useMenu from 'utils/hooks/useMenu'
13 |
14 | const useStyles = makeStyles((theme) => ({
15 | paper: {
16 | minWidth: 120,
17 | marginTop: theme.spacing(2),
18 | backgroundColor: theme.palette.background.default,
19 | border: `1px solid ${theme.custom.palette.border}`,
20 | padding: theme.spacing(1)
21 | },
22 | menu: {
23 | width: 30,
24 | height: 30,
25 | color: theme.palette.text.primary,
26 | },
27 | item: {
28 | borderRadius: 4,
29 | color: theme.palette.text.primary,
30 | }
31 | }));
32 |
33 | const NavDropMenu = () => {
34 | const classes = useStyles();
35 |
36 | const { PROFILE_MENU_LINKS, onMenuHandler } = useMenu();
37 | const [anchorEl, setAnchorEl] = useState(null);
38 |
39 | const handleClick = useCallback(event => {
40 | setAnchorEl(event.currentTarget);
41 | }, [setAnchorEl]);
42 |
43 | const handleClose = useCallback(() => {
44 | setAnchorEl(null);
45 | }, [setAnchorEl]);
46 |
47 | const itemHandler = useCallback((item) => () => {
48 | onMenuHandler(item)
49 | }, [onMenuHandler]);
50 |
51 | return (
52 | <>
53 |
54 |
59 |
60 |
61 |
95 |
96 | >
97 | );
98 | };
99 |
100 | export default memo(NavDropMenu);
--------------------------------------------------------------------------------
/Layout/TopAppBar/ThemeButton/index.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react';
2 | import { Switch } from '@material-ui/core';
3 | import { makeStyles } from '@material-ui/core/styles';
4 |
5 | import { useDarkMode } from 'contexts/ui-context';
6 |
7 | const useStyles = makeStyles((theme) => ({
8 | root: {
9 | width: 40,
10 | height: 22,
11 | padding: 0,
12 | margin: theme.spacing(1),
13 | },
14 | switchBase: {
15 | padding: 2,
16 | '&$checked': {
17 | transform: 'translateX(18px)',
18 | color: theme.custom.palette.white,
19 | '& + $track': {
20 | backgroundColor: theme.custom.palette.green,
21 | opacity: 1,
22 | border: 'none',
23 | },
24 | },
25 | '&$focusVisible $thumb': {
26 | color: theme.custom.palette.green,
27 | border: `6px solid ${theme.custom.palette.border}`,
28 | },
29 | },
30 | thumb: {
31 | width: 17,
32 | height: 17,
33 | },
34 | track: {
35 | borderRadius: 20,
36 | backgroundColor: theme.palette.background.default,
37 | opacity: 1,
38 | transition: theme.transitions.create(['background-color', 'border']),
39 | '&:before, &:after': {
40 | content: '""',
41 | position: 'absolute',
42 | top: '50%',
43 | transform: 'translateY(-50%)',
44 | width: 16,
45 | height: 16,
46 | },
47 | '&:before': {
48 | background: `url('data:image/svg+xml;utf8, ') center center no-repeat`,
51 | left: 20,
52 | },
53 | '&:after': {
54 | background: `url('data:image/svg+xml;utf8, ') center center no-repeat`,
55 | right: 20,
56 | },
57 | },
58 | checked: {},
59 | focusVisible: {},
60 | }));
61 |
62 | const ThemeButton = () => {
63 | const classes = useStyles();
64 | const { darkMode, setDarkMode } = useDarkMode();
65 |
66 | const themeHandler = () => {
67 | setDarkMode(prev => !prev)
68 | };
69 |
70 | return (
71 |
84 | );
85 | };
86 |
87 | export default memo(ThemeButton);
88 |
--------------------------------------------------------------------------------
/Layout/TopAppBar/index.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react'
2 | import { AppBar, Toolbar } from '@material-ui/core'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import clsx from 'clsx'
5 |
6 | import Logo from 'components/Logo'
7 | import NavBarMenu from './NavBarMenu'
8 | import NavDropMenu from './NavDropMenu'
9 | import ConnectWallet from './ConnectWallet'
10 | // import ThemeButton from './ThemeButton'
11 | import { useCommonStyles } from 'styles/use-styles'
12 |
13 | const useStyles = makeStyles((theme) => ({
14 | appBar: {
15 | display: 'flex',
16 | flexDirection: 'row',
17 | justifyContent: 'center',
18 | boxShadow: 'none',
19 | width: '100%',
20 | height: theme.custom.layout.topAppBarHeight,
21 | backgroundColor: theme.palette.background.default
22 | },
23 | toolBar: {
24 | display: 'flex',
25 | justifyContent: 'space-between',
26 | },
27 | container: {
28 | display: 'flex',
29 | alignItems: 'center',
30 | }
31 | }));
32 |
33 | const TopAppBar = () => {
34 | const classes = useStyles();
35 | const commonClasses = useCommonStyles();
36 |
37 | return (
38 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | {/* */}
49 |
50 |
51 |
52 | );
53 | };
54 |
55 | export default memo(TopAppBar);
56 |
--------------------------------------------------------------------------------
/Layout/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { useSelector } from 'react-redux'
4 | import { makeStyles } from '@material-ui/core/styles'
5 |
6 | import MagicLoading from 'components/MagicLoading'
7 | import TopAppBar from './TopAppBar'
8 | import Footer from './Footer'
9 |
10 | const useStyles = makeStyles(() => ({
11 | root: {
12 | display: 'flex',
13 | flexDirection: 'column',
14 | minHeight: '100vh',
15 | position: 'relative'
16 | },
17 | container: {
18 | flex: '1 0 auto'
19 | },
20 | }));
21 |
22 | const Layout = ({
23 | isFooter = true,
24 | children
25 | }) => {
26 | const classes = useStyles();
27 | const { loadingStatus } = useSelector(state => state.loading);
28 |
29 | return (
30 |
31 | {loadingStatus && }
32 |
33 |
34 | {children}
35 |
36 | {isFooter && }
37 |
38 | );
39 | };
40 |
41 | export default memo(Layout);
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
Leda - Jupiter NFT Market 🎣
3 |
4 |
Allows you to sell and buy Jupiter NFT Token
5 |
6 |
7 | ---
8 |
9 | ## Summary
10 |
11 | This project is the frontend project for Leda and a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
12 |
13 | ### Local http://localhost:3000
14 | ### Development https://jupiter-frontend.vercel.app/
15 |
16 | ---
17 |
18 | ## Installation
19 |
20 | ```bash
21 | yarn install
22 | yarn dev
23 | yarn build
24 | yarn start
25 | yarn deploy:vercel
26 | ```
27 | ---
28 | ## Development stacks
29 |
30 | - React.js(NEXT.js) + Material-UI
31 | ---
32 |
33 | ## Pages
34 |
35 | ### Home Page
36 |
37 | - /home
38 | ### Marketplace Page
39 |
40 | - /marketplace
41 |
42 | ### Create NFT Page
43 |
44 | - /create-collect
45 | ---
46 | ## Contributors ✨
47 |
48 |
49 |
50 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/actions/auth.js:
--------------------------------------------------------------------------------
1 |
2 | import Router from 'next/router'
3 |
4 | import LINKS from 'utils/constants/links'
5 | import * as TYPES from './types'
6 |
7 | const setUserToken = ({ accountRS, user, isWallet = false }) => dispatch => {
8 | dispatch(setAccountRS(accountRS));
9 | dispatch(setCurrentUser(user));
10 | dispatch(setIsWallet(isWallet));
11 | Router.push(LINKS.MARKETPLACE.HREF);
12 | };
13 |
14 | const setAccountRS = accountRS => {
15 | localStorage.setItem('accountRS', accountRS);
16 | return {
17 | type: TYPES.SET_ACCOUNT_RS,
18 | payload: accountRS
19 | };
20 | };
21 |
22 | const setCurrentUser = currentUser => {
23 | localStorage.setItem('currentUser', JSON.stringify(currentUser));
24 | return {
25 | type: TYPES.SET_CURRENT_USER,
26 | payload: currentUser
27 | };
28 | };
29 |
30 | const setIsWallet = isWallet => {
31 | localStorage.setItem('isWallet', isWallet);
32 | return {
33 | type: TYPES.SET_IS_WALLET,
34 | payload: isWallet
35 | };
36 | };
37 |
38 | const logoutUser = () => dispatch => {
39 | localStorage.clear();
40 | dispatch(setAccountRS(''));
41 | dispatch(setCurrentUser({}));
42 | dispatch(setIsWallet(false));
43 | Router.push(LINKS.HOME.HREF);
44 | };
45 |
46 | export {
47 | setUserToken,
48 | setAccountRS,
49 | setCurrentUser,
50 | setIsWallet,
51 | logoutUser
52 | }
--------------------------------------------------------------------------------
/actions/loading.js:
--------------------------------------------------------------------------------
1 |
2 | import * as TYPES from './types'
3 |
4 | const setLoadingStatus = loadingStatus => dispatch => {
5 | dispatch({
6 | type: TYPES.SET_LOADING_STATUS,
7 | payload: loadingStatus
8 | });
9 | };
10 |
11 | export default setLoadingStatus;
--------------------------------------------------------------------------------
/actions/popUp.js:
--------------------------------------------------------------------------------
1 | import * as TYPES from './types'
2 |
3 | const setPopUpInfo = (data) => (dispatch) => {
4 | dispatch({
5 | type: TYPES.SET_POP_UP_INFO,
6 | payload: data
7 | })
8 | }
9 |
10 | const openPopUp = () => (dispatch) => {
11 | dispatch({ type: TYPES.OPEN_POP_UP })
12 | }
13 |
14 | const closePopUp = () => (dispatch) => {
15 | dispatch({ type: TYPES.CLOSE_POP_UP })
16 | }
17 |
18 | export {
19 | setPopUpInfo,
20 | openPopUp,
21 | closePopUp
22 | }
23 |
--------------------------------------------------------------------------------
/actions/types.js:
--------------------------------------------------------------------------------
1 |
2 | const SET_LOADING_STATUS = 'SET_LOADING_STATUS'
3 | const SET_CURRENT_USER = 'SET_CURRENT_USER'
4 | const SET_ACCOUNT_RS = 'SET_ACCOUNT_RS'
5 | const SET_IS_WALLET = 'SET_IS_WALLET'
6 |
7 | // PopUp
8 | const SET_POP_UP_INFO = 'SET_POP_UP_INFO'
9 | const OPEN_POP_UP = 'OPEN_POP_UP'
10 | const CLOSE_POP_UP = 'CLOSE_POP_UP'
11 |
12 | export {
13 | SET_LOADING_STATUS,
14 | SET_CURRENT_USER,
15 | SET_ACCOUNT_RS,
16 | SET_IS_WALLET,
17 | SET_POP_UP_INFO,
18 | OPEN_POP_UP,
19 | CLOSE_POP_UP
20 | };
21 |
--------------------------------------------------------------------------------
/components/Icons/DefaultImageIcon/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import SvgIcon from '@material-ui/core/SvgIcon'
5 | import clsx from 'clsx'
6 |
7 | const useStyles = makeStyles(() => ({
8 | root: {
9 | width: 131,
10 | height: 65
11 | }
12 | }));
13 |
14 | const DefaultImageIcon = ({
15 | className,
16 | viewBox,
17 | ...rest
18 | }) => {
19 | const classes = useStyles();
20 |
21 | return (
22 |
23 |
24 |
25 |
29 |
32 |
33 |
34 |
35 | )
36 | }
37 |
38 | export default memo(DefaultImageIcon);
39 |
--------------------------------------------------------------------------------
/components/Icons/DiscordIcon/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import Link from 'next/link'
4 | import SvgIcon from '@material-ui/core/SvgIcon'
5 | import { makeStyles } from '@material-ui/core/styles'
6 | import clsx from 'clsx'
7 |
8 | import SOCIALS from 'utils/constants/social'
9 |
10 | const useStyles = makeStyles(() => ({
11 | root: {
12 | width: 24,
13 | height: 24
14 | }
15 | }));
16 |
17 | const DiscordIcon = ({
18 | className,
19 | viewBox,
20 | ...rest
21 | }) => {
22 | const classes = useStyles();
23 |
24 | return (
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | )
33 | }
34 |
35 | export default memo(DiscordIcon);
--------------------------------------------------------------------------------
/components/Icons/GreyEyeCloseIcon/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import SvgIcon from '@material-ui/core/SvgIcon'
5 | import clsx from 'clsx'
6 |
7 | const useStyles = makeStyles(theme => ({
8 | root: {
9 | width: theme.spacing(3)
10 | }
11 | }));
12 |
13 | const GreyEyeCloseIcon = ({
14 | className,
15 | viewBox,
16 | ...rest
17 | }) => {
18 | const classes = useStyles();
19 |
20 | return (
21 |
22 |
23 |
32 |
33 |
34 | )
35 | }
36 |
37 | export default memo(GreyEyeCloseIcon);
38 |
--------------------------------------------------------------------------------
/components/Icons/GreyEyeIcon/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import SvgIcon from '@material-ui/core/SvgIcon'
5 | import clsx from 'clsx'
6 |
7 | const useStyles = makeStyles(theme => ({
8 | root: {
9 | width: theme.spacing(3),
10 | }
11 | }));
12 |
13 | const GreyEyeIcon = ({
14 | className,
15 | viewBox,
16 | ...rest
17 | }) => {
18 | const classes = useStyles();
19 |
20 | return (
21 |
22 |
23 |
24 |
27 |
28 |
29 |
32 |
33 |
34 |
35 | )
36 | }
37 |
38 | export default memo(GreyEyeIcon);
39 |
--------------------------------------------------------------------------------
/components/Icons/MaximizeIcon/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import {
5 | IconButton,
6 | SvgIcon
7 | } from '@material-ui/core'
8 | import clsx from 'clsx'
9 |
10 | const useStyles = makeStyles(theme => ({
11 | root: {
12 | width: 45,
13 | height: 45,
14 | border: `1px solid ${theme.palette.text.secondary}`,
15 | },
16 | svg: {
17 | width: theme.spacing(2.5),
18 | }
19 | }));
20 |
21 | const MaximizeIcon = ({
22 | className,
23 | viewBox,
24 | ...rest
25 | }) => {
26 | const classes = useStyles();
27 |
28 | return (
29 |
35 |
36 |
37 |
38 |
39 | )
40 | }
41 |
42 | export default memo(MaximizeIcon);
43 |
--------------------------------------------------------------------------------
/components/Icons/TelegramIcon/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import Link from 'next/link'
4 | import SvgIcon from '@material-ui/core/SvgIcon'
5 | import { makeStyles } from '@material-ui/core/styles'
6 | import clsx from 'clsx'
7 |
8 | import SOCIALS from 'utils/constants/social'
9 |
10 | const useStyles = makeStyles(() => ({
11 | root: {
12 | width: 24,
13 | height: 24
14 | }
15 | }));
16 |
17 | const TelegramIcon = ({
18 | className,
19 | viewBox,
20 | ...rest
21 | }) => {
22 | const classes = useStyles();
23 |
24 | return (
25 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | )
34 | }
35 |
36 | export default memo(TelegramIcon);
37 |
--------------------------------------------------------------------------------
/components/Icons/TwitterIcon/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import Link from 'next/link'
4 | import { makeStyles } from '@material-ui/core/styles'
5 | import SvgIcon from '@material-ui/core/SvgIcon'
6 | import clsx from 'clsx'
7 |
8 | import SOCIALS from 'utils/constants/social'
9 |
10 | const useStyles = makeStyles(() => ({
11 | root: {
12 | width: 24,
13 | height: 24
14 | }
15 | }));
16 |
17 | const TwitterIcon = ({
18 | className,
19 | viewBox,
20 | ...rest
21 | }) => {
22 | const classes = useStyles();
23 |
24 | return (
25 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | )
34 | }
35 |
36 | export default memo(TwitterIcon);
--------------------------------------------------------------------------------
/components/Logo/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import Link from 'next/link'
4 | import { makeStyles } from '@material-ui/core/styles'
5 |
6 | import LINKS from 'utils/constants/links'
7 | import {
8 | WHITE_LOGO_IMAGE_PATH,
9 | BLACK_LOGO_IMAGE_PATH
10 | } from 'utils/constants/image-paths'
11 |
12 | const useStyles = makeStyles(() => ({
13 | picture: {
14 | display: 'flex',
15 | },
16 | img: {
17 | width: 120,
18 | height: 40,
19 | objectFit: 'contain'
20 | },
21 | }));
22 |
23 | const Logo = ({
24 | isWhite = false,
25 | className,
26 | ...rest
27 | }) => {
28 | const classes = useStyles();
29 |
30 | const LOGO_IMAGE_PATH = isWhite ? WHITE_LOGO_IMAGE_PATH : BLACK_LOGO_IMAGE_PATH;
31 |
32 | return (
33 |
34 |
35 |
36 |
37 |
41 |
42 |
43 |
44 | )
45 | }
46 |
47 | export default memo(Logo);
48 |
--------------------------------------------------------------------------------
/components/MagicDialog/index.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react'
2 | import { makeStyles } from '@material-ui/core/styles'
3 | import {
4 | IconButton,
5 | Typography,
6 | Dialog,
7 | DialogTitle,
8 | DialogContent,
9 | DialogActions
10 | } from '@material-ui/core'
11 | import CloseIcon from '@material-ui/icons/Close'
12 |
13 | import ContainedButton from 'components/UI/Buttons/ContainedButton'
14 |
15 | const useStyles = makeStyles((theme) => ({
16 | paper: {
17 | minWidth: 700,
18 | borderRadius: 10,
19 | backgroundColor: theme.palette.background.default,
20 | [theme.breakpoints.down('sm')]: {
21 | minWidth: 'unset'
22 | },
23 | },
24 | dialogTitle: {
25 | display: 'flex',
26 | alignItems: 'center',
27 | justifyContent: 'center',
28 | height: 68,
29 | lineHeight: 'initial',
30 | padding: theme.spacing(0, 6),
31 | background: `linear-gradient(90deg, ${theme.custom.palette.darkGreen}, ${theme.custom.palette.black})`
32 | },
33 | title: {
34 | fontWeight: 'bold',
35 | textTransform: 'uppercase',
36 | color: theme.custom.palette.white
37 | },
38 | closeIcon: {
39 | position: 'absolute',
40 | top: theme.spacing(1.5),
41 | right: theme.spacing(2),
42 | color: theme.custom.palette.white
43 | },
44 | dialogContent: {
45 | width: '100%',
46 | minWidth: 600,
47 | minHeight: 130,
48 | padding: theme.spacing(4, 2),
49 | [theme.breakpoints.down('sm')]: {
50 | minWidth: 520
51 | },
52 | [theme.breakpoints.down('xs')]: {
53 | minWidth: 'unset',
54 | padding: theme.spacing(2, 1)
55 | }
56 | },
57 | dialogActions: {
58 | display: 'flex',
59 | justifyContent: 'center',
60 | padding: theme.spacing(0, 2, 3),
61 | [theme.breakpoints.down('xs')]: {
62 | padding: theme.spacing(0, 1.5, 1),
63 | flexDirection: 'column'
64 | }
65 | },
66 | button: {
67 | margin: theme.spacing(0, 1),
68 | [theme.breakpoints.down('xs')]: {
69 | margin: theme.spacing(1, 0),
70 | }
71 | }
72 | }));
73 |
74 | const MagicDialog = ({
75 | open,
76 | title,
77 | cancelLabel,
78 | confirmLabel,
79 | onCancel,
80 | onConfirm,
81 | onClose,
82 | confirmDisable = false,
83 | children
84 | }) => {
85 | const classes = useStyles();
86 |
87 | return (
88 |
96 |
102 |
106 | {title}
107 |
108 |
114 |
115 |
116 |
117 |
118 | {children}
119 |
120 | {
121 | (!!cancelLabel || !!confirmLabel) &&
122 |
126 | {
127 | !!cancelLabel &&
128 |
133 | {cancelLabel}
134 |
135 | }
136 | {
137 | !!confirmLabel &&
138 |
143 | {confirmLabel}
144 |
145 | }
146 |
147 | }
148 |
149 | );
150 | }
151 |
152 | export default memo(MagicDialog)
--------------------------------------------------------------------------------
/components/MagicLoading/LoadingSpinner/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import ReactLottie from 'react-lottie'
4 |
5 | const defaultOptions = {
6 | loop: true,
7 | autoplay: true,
8 | animationData: require('public/assets/lotties/green-progress.json'),
9 | rendererSettings: {
10 | preserveAspectRatio: 'xMidYMid slice'
11 | },
12 | };
13 |
14 | const LoadingSpinner = ({ loading, size = 100 || size, ...rest }) => {
15 | if (!loading)
16 | return null;
17 | return (
18 |
25 | );
26 | };
27 |
28 | export default memo(LoadingSpinner);
--------------------------------------------------------------------------------
/components/MagicLoading/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 |
5 | import LoadingSpinner from './LoadingSpinner'
6 |
7 | const useStyles = makeStyles(() => ({
8 | root: props => ({
9 | position: 'absolute',
10 | zIndex: 5,
11 | display: 'flex',
12 | justifyContent: 'center',
13 | alignItems: 'center',
14 | width: '100%',
15 | height: props.height ? props.height : '100%',
16 | })
17 | }));
18 |
19 | const MagicLoading = ({
20 | loading,
21 | height,
22 | size = 100
23 | }) => {
24 | const classes = useStyles({ height });
25 |
26 | return (
27 |
28 |
31 |
32 | );
33 | };
34 |
35 | export default memo(MagicLoading);
--------------------------------------------------------------------------------
/components/UI/Buttons/ButtonLink/index.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { memo } from 'react'
3 | import Link from 'next/link'
4 |
5 | const ButtonLink = React.forwardRef(({
6 | className,
7 | href,
8 | hrefAs,
9 | children,
10 | prefetch
11 | }, ref) => (
12 |
17 |
18 | {children}
19 |
20 |
21 | ));
22 |
23 | export default memo(ButtonLink);
24 |
--------------------------------------------------------------------------------
/components/UI/Buttons/ContainedButton/index.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import Button from '@material-ui/core/Button'
5 | import clsx from 'clsx'
6 |
7 | import ButtonLink from 'components/UI/Buttons/ButtonLink'
8 |
9 | const useStyles = makeStyles(theme => ({
10 | root: {
11 | fontSize: 15,
12 | fontWeight: 'bold',
13 | boxShadow: 'none',
14 | padding: theme.spacing(0.25, 1.5, 0),
15 | borderRadius: 2,
16 | border: `1px solid ${theme.palette.primary.main}`,
17 | '&:hover': {
18 | color: theme.palette.primary.main
19 | }
20 | },
21 | icon: {
22 | display: 'flex',
23 | marginRight: theme.spacing(1.5)
24 | },
25 | disabled: {
26 | opacity: 0.6,
27 | color: `${theme.palette.primary.main} !important`,
28 | }
29 | }));
30 |
31 | const ContainedButton = React.forwardRef(({
32 | className,
33 | classes: propClasses = {},
34 | color = 'primary',
35 | href,
36 | loading,
37 | disabled,
38 | icon,
39 | children,
40 | ...rest
41 | }, ref) => {
42 | const classes = useStyles();
43 |
44 | return (
45 |
59 | {
60 | !!icon &&
61 |
62 | {icon}
63 |
64 | }
65 | {children}
66 |
67 | );
68 | });
69 |
70 | export default memo(ContainedButton);
71 |
--------------------------------------------------------------------------------
/components/UI/Buttons/LinkButton/index.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { memo } from 'react'
3 | import Link from 'next/link'
4 | import { makeStyles } from '@material-ui/core/styles'
5 | import Typography from '@material-ui/core/Typography'
6 | import clsx from 'clsx'
7 |
8 | const useStyles = makeStyles(theme => ({
9 | root: {
10 | cursor: 'pointer',
11 | fontSize: 14,
12 | fontWeight: 600,
13 | textDecoration: 'unset',
14 | color: theme.palette.primary.main,
15 | '&:hover': {
16 | textDecoration: 'underline',
17 | }
18 | }
19 | }));
20 |
21 | const LinkButton = ({
22 | className,
23 | href,
24 | as,
25 | target = '',
26 | onClick = () => { },
27 | children
28 | }) => {
29 | const classes = useStyles();
30 |
31 | return href
32 | ? (
33 |
37 |
41 | {children}
42 |
43 |
44 | ) : (
45 |
49 | {children}
50 |
51 | )
52 | };
53 |
54 | export default memo(LinkButton);
--------------------------------------------------------------------------------
/components/UI/Buttons/OutlinedButton/index.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import Button from '@material-ui/core/Button'
5 | import clsx from 'clsx'
6 |
7 | import ButtonLink from 'components/UI/Buttons/ButtonLink'
8 |
9 | const useStyles = makeStyles(theme => ({
10 | root: {
11 | fontSize: 15,
12 | fontWeight: 'bold',
13 | padding: theme.spacing(0.25, 1.5, 0),
14 | borderRadius: 2,
15 | border: `1px solid ${theme.palette.primary.main}`
16 | },
17 | icon: {
18 | display: 'flex',
19 | marginRight: theme.spacing(1.5)
20 | },
21 | disabled: {
22 | opacity: 0.6,
23 | color: `${theme.palette.primary.main} !important`,
24 | border: `2px solid ${theme.palette.primary.main} !important`,
25 | }
26 | }));
27 |
28 | const OutlinedButton = React.forwardRef(({
29 | className,
30 | classes: propClasses = {},
31 | color = 'primary',
32 | href,
33 | loading,
34 | disabled,
35 | icon,
36 | children,
37 | ...rest
38 | }, ref) => {
39 | const classes = useStyles();
40 |
41 | return (
42 |
56 | {
57 | !!icon &&
58 |
59 | {icon}
60 |
61 | }
62 | {children}
63 |
64 | );
65 | });
66 |
67 | export default memo(OutlinedButton);
68 |
--------------------------------------------------------------------------------
/components/UI/MagicCheckbox/index.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import Checkbox from '@material-ui/core/Checkbox'
5 | import clsx from 'clsx'
6 |
7 | const useStyles = makeStyles(theme => ({
8 | checkbox: {
9 | padding: 0,
10 | marginRight: theme.spacing(0.75),
11 | color: theme.custom.palette.green,
12 | '&$checked': {
13 | color: theme.custom.palette.green,
14 | },
15 | }
16 | }));
17 |
18 | const MagicCheckbox = React.forwardRef(({
19 | className,
20 | ...rest
21 | }, ref) => {
22 | const classes = useStyles();
23 |
24 | return (
25 |
34 | );
35 | });
36 |
37 | export default memo(MagicCheckbox);
38 |
--------------------------------------------------------------------------------
/components/UI/MagicMultiSelect/index.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import {
5 | Select,
6 | MenuItem
7 | } from '@material-ui/core'
8 |
9 | import MagicTextField from 'components/UI/TextFields/MagicTextField'
10 |
11 | const useStyles = makeStyles(theme => ({
12 | menuPaper: {
13 | backgroundColor: theme.palette.background.primary
14 | },
15 | icon: {
16 | borderRadius: 6,
17 | marginRight: theme.spacing(1),
18 | color: theme.palette.text.primary
19 | },
20 | placeholder: {
21 | color: theme.custom.palette.lightBlack,
22 | }
23 | }));
24 |
25 | const MagicMultiSelect = React.forwardRef(({
26 | items = [],
27 | placeholder,
28 | label,
29 | ...rest
30 | }, ref) => {
31 |
32 | const classes = useStyles();
33 |
34 | return (
35 | }
41 | displayEmpty
42 | classes={{
43 | icon: classes.icon
44 | }}
45 | MenuProps={{
46 | classes: {
47 | paper: classes.menuPaper
48 | }
49 | }}
50 | placeholder={placeholder}
51 | {...rest}
52 | >
53 | {
54 | placeholder &&
55 |
60 | {placeholder}
61 |
62 | }
63 | {
64 | items.map((item, index) => (
65 |
69 | {item}
70 |
71 | ))
72 | }
73 |
74 | );
75 | });
76 |
77 | export default memo(MagicMultiSelect);
--------------------------------------------------------------------------------
/components/UI/MagicSelect/index.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import {
5 | Select,
6 | MenuItem
7 | } from '@material-ui/core'
8 |
9 | import MagicTextField from 'components/UI/TextFields/MagicTextField'
10 |
11 | const useStyles = makeStyles(theme => ({
12 | menuPaper: {
13 | backgroundColor: theme.palette.background.primary
14 | },
15 | icon: {
16 | borderRadius: 6,
17 | marginRight: theme.spacing(1),
18 | color: theme.palette.text.primary
19 | },
20 | placeholder: {
21 | color: theme.custom.palette.lightBlack,
22 | }
23 | }));
24 |
25 | const MagicSelect = React.forwardRef(({
26 | items,
27 | placeholder,
28 | label,
29 | ...rest
30 | }, ref) => {
31 |
32 | const classes = useStyles();
33 |
34 | return (
35 | }
39 | displayEmpty
40 | classes={{
41 | icon: classes.icon
42 | }}
43 | MenuProps={{
44 | classes: {
45 | paper: classes.menuPaper
46 | }
47 | }}
48 | placeholder={placeholder}
49 | {...rest}
50 | >
51 | {
52 | placeholder &&
53 |
58 | {placeholder}
59 |
60 | }
61 | {
62 | items.map((item, index) => (
63 |
67 | {item.LABEL}
68 |
69 | ))
70 | }
71 |
72 | );
73 | });
74 |
75 | export default memo(MagicSelect);
--------------------------------------------------------------------------------
/components/UI/TextFields/AccountTextField/index.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { memo, useCallback, useMemo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import {
5 | Typography,
6 | TextField
7 | } from '@material-ui/core'
8 | import clsx from 'clsx'
9 |
10 | import TextMaskCustom from 'components/UI/TextFields/TextMaskCustom'
11 | import { isEmpty } from 'utils/helpers/utility'
12 |
13 | const useStyles = makeStyles(theme => ({
14 | root: {
15 | width: '100%'
16 | },
17 | textField: {
18 | width: '100%',
19 |
20 | },
21 | inputRoot: {
22 | '&:hover:before': {
23 | border: '0 !important'
24 | },
25 | '&::after': {
26 | border: '0 !important'
27 | },
28 | '&::before': {
29 | border: '0 !important'
30 | }
31 | },
32 | input: {
33 | width: '100%',
34 | fontSize: 18,
35 | padding: theme.spacing(1.5),
36 | border: `1px solid ${theme.custom.palette.border}`,
37 | borderRadius: 2,
38 | backgroundColor: theme.palette.background.primary,
39 | color: theme.custom.palette.lightBlack
40 | },
41 | errorInput: {
42 | border: `1px solid ${theme.palette.danger.main}`
43 | },
44 | labelContainer: {
45 | display: 'flex',
46 | justifyContent: 'space-between',
47 | alignItems: 'center',
48 | padding: theme.spacing(0, 1.5, 1)
49 | },
50 | optional: {
51 | fontStyle: 'italic'
52 | },
53 | error: {
54 | padding: theme.spacing(1, 1.5, 0)
55 | },
56 | }));
57 |
58 | const AccountTextField = React.forwardRef(({
59 | error,
60 | mask,
61 | label,
62 | isOption = false,
63 | placeholder,
64 | className,
65 | onChange,
66 | endAdornment,
67 | ...rest
68 | }, ref) => {
69 |
70 | const classes = useStyles();
71 |
72 | const inputComponent = useMemo(() => {
73 | if (!isEmpty(mask)) {
74 | return {
75 | inputComponent: TextMaskCustom
76 | }
77 | }
78 | }, [mask]);
79 |
80 | const inputHandler = useCallback((e) => {
81 | onChange(e.target.value.toUpperCase())
82 | }, [onChange])
83 |
84 | return (
85 |
86 | {
87 | !!label &&
88 |
89 |
90 | {label}
91 |
92 |
93 | {
94 | isOption &&
95 |
100 | (Optional)
101 |
102 | }
103 |
104 | }
105 |
106 |
126 |
127 | {
128 | !!error &&
129 |
134 | {error}
135 |
136 | }
137 |
138 | );
139 | });
140 |
141 | export default memo(AccountTextField);
--------------------------------------------------------------------------------
/components/UI/TextFields/MagicTextField/index.js:
--------------------------------------------------------------------------------
1 |
2 | import React, { memo, useCallback, useState } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import {
5 | Typography,
6 | OutlinedInput
7 | } from '@material-ui/core'
8 | import clsx from 'clsx'
9 |
10 | import GreyEyeIcon from 'components/Icons/GreyEyeIcon'
11 | import GreyEyeCloseIcon from 'components/Icons/GreyEyeCloseIcon'
12 |
13 | const useStyles = makeStyles(theme => ({
14 | root: {
15 | width: '100%'
16 | },
17 | textField: {
18 | width: '100%',
19 | border: `1px solid ${theme.custom.palette.border}`,
20 | borderRadius: 2,
21 | backgroundColor: theme.palette.background.default,
22 | },
23 | input: {
24 | fontSize: 16,
25 | fontFamily: 'roboto, sans-serif',
26 | lineHeight: 'normal',
27 | padding: theme.spacing(1),
28 | color: theme.custom.palette.lightBlack,
29 | '&:focus': {
30 | backgroundColor: 'unset'
31 | },
32 | '&::placeholder': {
33 | lineHeight: 'normal',
34 | color: theme.palette.text.secondary
35 | },
36 | '&:-ms-input-placeholder': {
37 | lineHeight: 'normal',
38 | color: theme.palette.text.secondary
39 | },
40 | '&::-ms-input-placeholder': {
41 | lineHeight: 'normal',
42 | color: theme.palette.text.secondary
43 | }
44 | },
45 | multiline: {
46 | padding: 0
47 | },
48 | notchedOutline: {
49 | border: 'none'
50 | },
51 | errorInput: {
52 | border: `1px solid ${theme.palette.danger.main}`
53 | },
54 | labelContainer: {
55 | display: 'flex',
56 | justifyContent: 'space-between',
57 | alignItems: 'center',
58 | padding: theme.spacing(0, 1, 0.5)
59 | },
60 | optional: {
61 | fontStyle: 'italic'
62 | },
63 | error: {
64 | padding: theme.spacing(1, 1, 0)
65 | },
66 | eyeIcon: {
67 | cursor: 'pointer'
68 | }
69 | }));
70 |
71 | const MagicTextField = React.forwardRef(({
72 | label,
73 | type = 'text',
74 | error,
75 | isOption = false,
76 | className,
77 | ...rest
78 | }, ref) => {
79 |
80 | const classes = useStyles();
81 | const [showPassword, setShowPassword] = useState(false);
82 |
83 | const eyeIconHandler = useCallback(() => {
84 | setShowPassword(prev => !prev)
85 | }, [setShowPassword])
86 |
87 | return (
88 |
89 | {
90 | !!label &&
91 |
92 |
93 | {label}
94 |
95 |
96 | {
97 | isOption &&
98 |
103 | (Optional)
104 |
105 | }
106 |
107 | }
108 |
109 |
122 | ) : (
123 |
127 | )
128 | )
129 | }
130 | className={clsx(
131 | 'form-control form-control-lg',
132 | classes.textField
133 | )}
134 | classes={{
135 | input: classes.input,
136 | multiline: classes.multiline,
137 | error: classes.errorInput,
138 | notchedOutline: classes.notchedOutline
139 | }}
140 | {...rest}
141 | />
142 | {
143 | !!error &&
144 |
149 | {error}
150 |
151 | }
152 |
153 | );
154 | });
155 |
156 | export default memo(MagicTextField);
--------------------------------------------------------------------------------
/components/UI/TextFields/TextMaskCustom/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import MaskedInput from 'react-text-mask'
4 |
5 | const TextMaskCustom = ({
6 | inputRef,
7 | ...rest
8 | }) => {
9 | return (
10 | {
13 | inputRef(ref ? ref.inputElement : null);
14 | }}
15 | guide={false}
16 | placeholderChar={'\u005F'}
17 | showMask
18 | />
19 | )
20 | };
21 |
22 | export default memo(TextMaskCustom);
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | const IS_MAINNET = process.env.NETWORK === 'mainnet'
2 |
3 | const PROXY_URL = process.env.NODE_ENV === 'production'
4 | ? 'https://leda.gojupiter.tech/'
5 | : 'http://localhost:8000'
6 |
7 | const JUPITER_URL = 'https://nodes.jup.io'
8 |
9 | const STATS_URL = 'https://stats.jup.io'
10 |
11 | const ERC_CHAIN_ID = IS_MAINNET ? 1 : 4;
12 |
13 | export {
14 | PROXY_URL,
15 | JUPITER_URL,
16 | STATS_URL,
17 | ERC_CHAIN_ID
18 | }
--------------------------------------------------------------------------------
/containers/Auth/Shared/AuthWrapper/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import Paper from '@material-ui/core/Paper'
4 | import Typography from '@material-ui/core/Typography'
5 | import { makeStyles } from '@material-ui/core/styles'
6 |
7 | import Logo from 'components/Logo'
8 | import { AUTH_BACKGROUND_IMAGE_PATH } from 'utils/constants/image-paths'
9 |
10 | const useStyles = makeStyles((theme) => ({
11 | root: {
12 | display: 'flex',
13 | alignItems: 'center',
14 | justifyContent: 'center',
15 | minHeight: `calc(100vh - ${theme.custom.layout.topAppBarHeight}px)`,
16 | backgroundImage: `url(${AUTH_BACKGROUND_IMAGE_PATH})`,
17 | backgroundRepeat: 'no-repeat',
18 | backgroundSize: 'cover',
19 | backgroundPosition: 'center',
20 | },
21 | container: {
22 | display: 'flex',
23 | flexDirection: 'column',
24 | alignItems: 'center',
25 | width: '100%',
26 | maxWidth: 544,
27 | borderRadius: 2,
28 | margin: theme.spacing(3),
29 | padding: theme.spacing(4, 8),
30 | [theme.breakpoints.down('xs')]: {
31 | padding: theme.spacing(4, 2)
32 | }
33 | },
34 | logo: {
35 | marginBottom: theme.spacing(2)
36 | },
37 | welcome: {
38 | fontWeight: 'bold',
39 | marginBottom: theme.spacing(4)
40 | }
41 | }));
42 |
43 | const authPageStyles = makeStyles(theme => ({
44 | form: {
45 | display: 'flex',
46 | flexDirection: 'column',
47 | alignItems: 'center',
48 | width: '100%'
49 | },
50 | input: {
51 | marginBottom: theme.spacing(2.5)
52 | },
53 | button: {
54 | margin: theme.spacing(2.5)
55 | }
56 | }));
57 |
58 | const AuthWrapper = ({
59 | children
60 | }) => {
61 | const classes = useStyles()
62 |
63 | return (
64 |
65 |
66 |
67 |
73 | Welcome to Leda!
74 |
75 | {children}
76 |
77 |
78 | )
79 | }
80 |
81 | export { authPageStyles };
82 | export default memo(AuthWrapper);
--------------------------------------------------------------------------------
/containers/Auth/SignIn/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useCallback } from 'react'
3 | import { useDispatch } from 'react-redux'
4 | import { useRouter } from 'next/router'
5 | import Typography from '@material-ui/core/Typography'
6 | import { makeStyles } from '@material-ui/core/styles'
7 | import { useForm, Controller } from 'react-hook-form'
8 | import { yupResolver } from '@hookform/resolvers/yup'
9 | import * as yup from 'yup'
10 |
11 | import * as jupiterAPI from 'services/api-jupiter'
12 | import { setUserToken } from 'actions/auth'
13 | import ContainedButton from 'components/UI/Buttons/ContainedButton'
14 | import LinkButton from 'components/UI/Buttons/LinkButton'
15 | import AccountTextField from 'components/UI/TextFields/AccountTextField'
16 | import AuthWrapper, { authPageStyles } from '../Shared/AuthWrapper'
17 | import useLoading from 'utils/hooks/useLoading'
18 | import usePopUp from 'utils/hooks/usePopUp'
19 | import LINKS from 'utils/constants/links'
20 | import { ACCOUNT_VALID } from 'utils/constants/validations'
21 | import MESSAGES from 'utils/constants/messages'
22 | import TEXT_MASKS from 'utils/constants/text-masks'
23 |
24 | const useStyles = makeStyles((theme) => ({
25 | footer: {
26 | display: 'flex'
27 | },
28 | signup: {
29 | paddingLeft: theme.spacing(1)
30 | }
31 | }));
32 |
33 | const schema = yup.object().shape({
34 | account: ACCOUNT_VALID
35 | });
36 |
37 | const SignIn = () => {
38 | const dispatch = useDispatch();
39 | const classes = useStyles();
40 | const authClasses = authPageStyles();
41 | const router = useRouter();
42 | const { setPopUp } = usePopUp();
43 | const { changeLoadingStatus } = useLoading();
44 |
45 | const { control, handleSubmit, errors } = useForm({
46 | resolver: yupResolver(schema)
47 | });
48 |
49 | const onSubmit = useCallback(async (data) => {
50 | changeLoadingStatus(true)
51 | try {
52 | const response = await jupiterAPI.getAccountByAccountID(data.account);
53 | if (!response?.accountRS) {
54 | setPopUp({ text: MESSAGES.AUTH_ERROR })
55 | changeLoadingStatus(false);
56 | return;
57 | }
58 |
59 | dispatch(setUserToken({
60 | accountRS: response.accountRS,
61 | user: response
62 | }));
63 | setPopUp({ text: MESSAGES.SIGN_IN_SUCCESS })
64 | router.push(LINKS.MARKETPLACE.HREF)
65 | } catch (error) {
66 | console.log(error)
67 | }
68 | changeLoadingStatus(false)
69 | }, [router, dispatch, setPopUp, changeLoadingStatus]);
70 |
71 | return (
72 |
73 |
109 |
110 | )
111 | }
112 |
113 | export default memo(SignIn)
--------------------------------------------------------------------------------
/containers/CreateNFT/PreviewCard/index.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react'
2 | import { makeStyles } from '@material-ui/core/styles'
3 |
4 | import DefaultImageIcon from 'components/Icons/DefaultImageIcon'
5 | import { FILE_TYPES } from 'utils/constants/file-types'
6 | import { IMAGE_PLACEHOLDER_IMAGE_PATH } from 'utils/constants/image-paths'
7 |
8 | const useStyles = makeStyles((theme) => ({
9 | root: {
10 | height: 220,
11 | padding: theme.spacing(1),
12 | borderRadius: 2,
13 | border: `1px solid ${theme.custom.palette.border}`,
14 | },
15 | defaultImage: {
16 | display: 'flex',
17 | flexDirection: 'column',
18 | justifyContent: 'center',
19 | alignItems: 'center',
20 | height: '100%',
21 | backgroundColor: theme.custom.palette.grey
22 | },
23 | image: {
24 | height: '100%',
25 | width: '100%',
26 | objectFit: 'contain'
27 | },
28 | }));
29 |
30 | const PreviewCard = ({
31 | type,
32 | fileBuffer
33 | }) => {
34 | const classes = useStyles();
35 |
36 | return (
37 |
38 | {!!fileBuffer
39 | ? (
40 | type === FILE_TYPES.IMAGE.VALUE
41 | ? (
42 |
47 | ) : (
48 |
49 |
50 |
51 | )
52 | ) : (
53 |
54 |
55 |
56 | )
57 | }
58 |
59 | );
60 | }
61 |
62 | export default memo(PreviewCard)
--------------------------------------------------------------------------------
/containers/CreateNFT/UploadMedia/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useCallback } from 'react'
3 | import { useDropzone } from 'react-dropzone'
4 | import { makeStyles } from '@material-ui/core/styles'
5 | import { Typography } from '@material-ui/core'
6 |
7 | import ContainedButton from 'components/UI/Buttons/ContainedButton'
8 | import { MAX_UPLOAD_SIZE } from 'utils/constants/common'
9 | import usePopUp from 'utils/hooks/usePopUp'
10 | import MESSAGES from 'utils/constants/messages'
11 |
12 | const useStyles = makeStyles((theme) => ({
13 | root: {
14 | height: '100%',
15 | padding: theme.spacing(1),
16 | borderRadius: 2,
17 | border: `1px solid ${theme.custom.palette.border}`,
18 | },
19 | container: {
20 | display: 'flex',
21 | flexDirection: 'column',
22 | justifyContent: 'space-evenly',
23 | alignItems: 'center',
24 | height: '100%',
25 | padding: theme.spacing(3),
26 | backgroundColor: theme.custom.palette.grey
27 | },
28 | }));
29 |
30 | const UploadMedia = ({
31 | type,
32 | setFileBuffer
33 | }) => {
34 | const classes = useStyles();
35 | const { setPopUp } = usePopUp();
36 |
37 | const onDrop = useCallback(async (acceptedFiles) => {
38 | if (!Array.isArray(acceptedFiles) || acceptedFiles.length <= 0) {
39 | setPopUp({ text: MESSAGES.MAX_UPLOAD_ERROR })
40 | return;
41 | }
42 |
43 | const file = acceptedFiles[0];
44 | const reader = new FileReader();
45 | reader.addEventListener('load', () => {
46 | setFileBuffer(reader.result);
47 | });
48 | reader.readAsDataURL(file);
49 | }, [setPopUp, setFileBuffer]);
50 |
51 | const { getRootProps, getInputProps } = useDropzone({
52 | onDrop,
53 | accept: type.ACCEPT,
54 | maxSize: MAX_UPLOAD_SIZE
55 | })
56 |
57 | return (
58 |
59 |
60 |
61 |
66 | {type.PLACEHOLDER}
67 |
68 |
69 | Choose file
70 |
71 |
72 |
73 | );
74 | }
75 |
76 | export default memo(UploadMedia)
--------------------------------------------------------------------------------
/containers/CreateNFT/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import { Typography } from '@material-ui/core'
5 |
6 | import ImageWall from 'parts/ImageWall'
7 | import CreateForm from './CreateForm'
8 |
9 | const useStyles = makeStyles((theme) => ({
10 | root: {
11 | display: 'flex',
12 | flexDirection: 'column',
13 | alignItems: 'center',
14 | width: '100%',
15 | backgroundColor: theme.palette.background.default
16 | },
17 | container: {
18 | display: 'flex',
19 | flexDirection: 'column',
20 | alignItems: 'center',
21 | width: '100%',
22 | maxWidth: 610,
23 | padding: theme.spacing(0, 2, 10),
24 | },
25 | header: {
26 | fontSize: 18,
27 | marginBottom: theme.spacing(3)
28 | },
29 | }));
30 |
31 | const CreateNFT = () => {
32 | const classes = useStyles();
33 |
34 | return (
35 |
36 |
37 |
38 |
43 | Please select your file type, upload your file and add a title for your NFT.
44 |
45 | If you{"'"}d like to attach additional info you can enter this in the
46 | description box (sub-title, your name, inspiration, whether it is part of a
47 | series or a limited edition number, etc).
48 |
49 |
50 |
51 |
52 | )
53 | }
54 |
55 | export default memo(CreateNFT)
--------------------------------------------------------------------------------
/containers/Home/CreatorAndCollector/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import {
5 | Grid,
6 | Typography
7 | } from '@material-ui/core'
8 | import CodeIcon from '@material-ui/icons/Code'
9 | import BoltIcon from '@material-ui/icons/OfflineBolt'
10 | import HeadPhoneIcon from '@material-ui/icons/Headset'
11 | import CheckIcon from '@material-ui/icons/Check'
12 | import BarIcon from '@material-ui/icons/ViewWeek'
13 | import UnLockIcon from '@material-ui/icons/LockOpen'
14 | import ShowChartIcon from '@material-ui/icons/ShowChart'
15 | import HomeIcon from '@material-ui/icons/DonutSmall'
16 |
17 | const useStyles = makeStyles(theme => ({
18 | root: {
19 | display: 'flex',
20 | justifyContent: 'center',
21 | width: '100%',
22 | margin: theme.spacing(8, 3)
23 | },
24 | container: {
25 | display: 'flex',
26 | flexDirection: 'column',
27 | alignItems: 'center',
28 | maxWidth: 1020,
29 | width: '100%'
30 | },
31 | title: {
32 | fontSize: 40,
33 | fontWeight: 'bold',
34 | textAlign: 'center',
35 | marginBottom: theme.spacing(8),
36 | maxWidth: 380,
37 | [theme.breakpoints.down('sm')]: {
38 | fontSize: 32,
39 | marginBottom: theme.spacing(5),
40 | },
41 | },
42 | list: {
43 | width: '100%',
44 | padding: theme.spacing(2)
45 | },
46 | item: {
47 | display: 'flex',
48 | flexDirection: 'column',
49 | alignItems: 'center',
50 | justifyContent: 'center'
51 | },
52 | iconContainer: {
53 | position: 'relative',
54 | display: 'flex',
55 | alignItems: 'center',
56 | justifyContent: 'center',
57 | margin: theme.spacing(2)
58 | },
59 | square: {
60 | position: 'absolute',
61 | width: 60,
62 | height: 60,
63 | borderRadius: 15,
64 | opacity: 0.2,
65 | },
66 | text: {
67 | fontSize: 32,
68 | fontWeight: 'bold',
69 | [theme.breakpoints.down('sm')]: {
70 | fontSize: 22,
71 | },
72 | }
73 | }));
74 |
75 | const CreatorAndCollector = () => {
76 | const classes = useStyles();
77 |
78 | return (
79 |
80 |
81 |
82 | Categories and Tags
83 |
84 |
85 | {
86 | CREATORS.map((item, index) => (
87 |
88 |
92 |
93 | {item.title}
94 |
95 |
96 | {item.description}
97 |
98 |
99 | ))
100 | }
101 |
102 |
103 |
104 | );
105 | };
106 |
107 | export default memo(CreatorAndCollector);
108 |
109 | const CREATORS = [
110 | {
111 | title: 'No code',
112 | description: 'Required',
113 | color: '#5dc1a3',
114 | icon: CodeIcon
115 | },
116 | {
117 | title: 'Community',
118 | description: 'Driven',
119 | color: '#7672f6',
120 | icon: BoltIcon
121 | },
122 | {
123 | title: 'Flexible',
124 | description: 'Royalties',
125 | color: '#ec5f67',
126 | icon: HeadPhoneIcon
127 | },
128 | {
129 | title: 'Verified',
130 | description: 'Creators',
131 | color: '#f3be42',
132 | icon: CheckIcon
133 | },
134 | {
135 | title: 'Multiple',
136 | description: 'Minting',
137 | color: '#ef8532',
138 | icon: BarIcon
139 | },
140 | {
141 | title: 'Unlockable',
142 | description: 'Items',
143 | color: '#4ca9ef',
144 | icon: UnLockIcon
145 | },
146 | {
147 | title: 'Auction',
148 | description: 'Functions',
149 | color: '#bd00ff',
150 | icon: ShowChartIcon
151 | },
152 | {
153 | title: 'Leda',
154 | description: 'Rewards',
155 | color: '#0066ff',
156 | icon: HomeIcon
157 | },
158 | ]
--------------------------------------------------------------------------------
/containers/Home/HomeHeader/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 |
5 | import {
6 | HOME_LOGO_IMAGE_PATH,
7 | HOME_HEADER_BACKGROUND_IMAGE_PATH
8 | } from 'utils/constants/image-paths'
9 |
10 | const useStyles = makeStyles(theme => ({
11 | root: {
12 | display: 'flex',
13 | justifyContent: 'center',
14 | width: '100%',
15 | padding: theme.spacing(15, 3),
16 | minHeight: 790,
17 | backgroundImage: `url(${HOME_HEADER_BACKGROUND_IMAGE_PATH})`,
18 | backgroundRepeat: 'no-repeat',
19 | backgroundSize: 'cover',
20 | backgroundPosition: 'center',
21 | [theme.breakpoints.down('sm')]: {
22 | minHeight: 'unset',
23 | },
24 | },
25 | container: {
26 | width: '100%',
27 | maxWidth: 760,
28 | },
29 | picture: {
30 | display: 'flex',
31 | },
32 | img: {
33 | width: '100%',
34 | objectFit: 'contain'
35 | },
36 | }));
37 |
38 | const HomeHeader = () => {
39 | const classes = useStyles();
40 | return (
41 |
42 |
43 |
44 |
45 |
49 |
50 |
51 |
52 | );
53 | };
54 |
55 | export default memo(HomeHeader);
--------------------------------------------------------------------------------
/containers/Home/HomeJourney/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import { Typography } from '@material-ui/core'
5 |
6 | const useStyles = makeStyles(theme => ({
7 | root: {
8 | display: 'flex',
9 | justifyContent: 'center',
10 | alignItems: 'center',
11 | width: '100%',
12 | padding: theme.spacing(10, 0)
13 | },
14 | container: {
15 | display: 'flex',
16 | flexDirection: 'column',
17 | alignItems: 'center',
18 | width: '100%',
19 | maxWidth: 1020,
20 | padding: theme.spacing(3),
21 | },
22 | title: {
23 | fontSize: 40,
24 | fontWeight: 'bold',
25 | fontFamily: 'CRC-LIGHT',
26 | textAlign: 'center',
27 | marginBottom: theme.spacing(4),
28 | [theme.breakpoints.down('sm')]: {
29 | fontSize: 32,
30 | },
31 | },
32 | description: {
33 | fontSize: 18,
34 | marginBottom: theme.spacing(4),
35 | }
36 | }));
37 |
38 | const HomeJourney = () => {
39 | const classes = useStyles();
40 |
41 | return (
42 |
43 |
44 |
48 | WHAT IS LEDA?
49 |
50 |
51 | Leda is an NFT marketplace, that uses the Jupiter blockchain. A Non-Fungible
52 | Token (NFT) (or called Singleton Asset Token on Jupiter) is a unit of data
53 | stored on a blockchain that certifies a digital asset to be unique and
54 | therefore not interchangeable.
55 |
56 |
57 | NFTs can be used to represent items such as photos, videos, audios, in-game
58 | items, and any other type of digital file. As an artist, by tokenizing your
59 | work, you ensure that it is unique and that the ownership is provably yours.
60 |
61 |
62 | Start your NFT journey with Leda!
63 |
64 |
65 | No code knowledge required. Easily upload your content and create your NFT
66 | with a few clicks.
67 |
68 |
69 |
70 | );
71 | };
72 |
73 | export default memo(HomeJourney);
--------------------------------------------------------------------------------
/containers/Home/UserFeedback/FeedbackCard/index.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react';
2 | import {
3 | Card,
4 | CardHeader,
5 | CardContent,
6 | CardActionArea,
7 | Avatar,
8 | Typography,
9 | } from '@material-ui/core'
10 | import { makeStyles } from '@material-ui/core/styles'
11 |
12 | const useStyles = makeStyles((theme) => ({
13 | card: {
14 | margin: theme.spacing(1.5),
15 | borderRadius: 10,
16 | },
17 | content: {
18 | height: 205
19 | },
20 | description: {
21 | fontSize: 18
22 | },
23 | action: {
24 | display: 'flex',
25 | flexDirection: 'column',
26 | alignItems: 'flex-start',
27 | padding: theme.spacing(2)
28 | },
29 | name: {
30 | fontWeight: 'bold'
31 | }
32 | }));
33 |
34 | const FeedbackCard = ({
35 | item
36 | }) => {
37 | const classes = useStyles();
38 |
39 | return (
40 |
41 |
44 | }
45 | />
46 |
47 |
52 | {item.description}
53 |
54 |
55 |
56 |
61 | {item.name}
62 |
63 |
67 | {item.subName}
68 |
69 |
70 |
71 | );
72 | }
73 |
74 | export default memo(FeedbackCard)
--------------------------------------------------------------------------------
/containers/Home/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 |
5 | import HomeHeader from './HomeHeader'
6 | // import CreatorAndCollector from './CreatorAndCollector'
7 | // import UserFeedback from './UserFeedback'
8 | import NFTCarousel from 'parts/NFTCarousel'
9 | import HomeJourney from './HomeJourney'
10 |
11 | const useStyles = makeStyles((theme) => ({
12 | root: {
13 | display: 'flex',
14 | flexDirection: 'column',
15 | alignItems: 'center',
16 | width: '100%',
17 | backgroundColor: theme.palette.background.default,
18 | marginBottom: theme.spacing(15)
19 | }
20 | }));
21 |
22 | const Home = () => {
23 | const classes = useStyles();
24 |
25 | return (
26 |
27 |
28 |
29 | {/* */}
30 | {/* */}
31 |
32 |
33 | )
34 | }
35 |
36 | export default memo(Home)
--------------------------------------------------------------------------------
/containers/Marketplace/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useState, useEffect, useCallback } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import Router, { useRouter } from 'next/router'
5 |
6 | import * as jupiterAPI from 'services/api-jupiter'
7 | import ImageWall from 'parts/ImageWall'
8 | import SearchInput from 'parts/SearchInput'
9 | import NFTList from 'parts/NFTList'
10 | import LINKS from 'utils/constants/links'
11 |
12 | const useStyles = makeStyles((theme) => ({
13 | root: {
14 | display: 'flex',
15 | flexDirection: 'column',
16 | alignItems: 'center'
17 | },
18 | container: {
19 | width: '100%',
20 | maxWidth: theme.custom.layout.maxMarketPlaceWidth,
21 | padding: theme.spacing(2),
22 | },
23 | filterContainer: {
24 | display: 'flex',
25 | flexDirection: 'column',
26 | alignItems: 'flex-end',
27 | marginBottom: theme.spacing(2)
28 | },
29 | }));
30 |
31 | const PAGE_COUNT = 8;
32 |
33 | const Marketplace = () => {
34 | const classes = useStyles();
35 | const router = useRouter();
36 |
37 | const [goods, setGoods] = useState([]);
38 | const [first, setFirst] = useState(0);
39 | const [isLast, setIsLast] = useState(false);
40 | const [search, setSearch] = useState(router.query.search);
41 |
42 | useEffect(() => {
43 | getAllOpenAskOrders();
44 | // eslint-disable-next-line react-hooks/exhaustive-deps
45 | }, [search]);
46 |
47 | const getAllOpenAskOrders = useCallback(async () => {
48 | try {
49 | if (!isLast) {
50 | const params = {
51 | first,
52 | last: first + PAGE_COUNT - 1,
53 | query: search
54 | }
55 |
56 | const { openOrders = [] } = await jupiterAPI.searchAllOpenAskOrders(params);
57 | if (first === 0) {
58 | setGoods(openOrders);
59 | } else {
60 | setGoods((prev) => [...prev, ...openOrders]);
61 | }
62 |
63 | setFirst((prev) => prev + openOrders.length);
64 | setIsLast(openOrders.length < PAGE_COUNT);
65 | }
66 | } catch (error) {
67 | console.log(error)
68 | }
69 | }, [search, isLast, first, setGoods, setFirst, setIsLast])
70 |
71 | const searchHandler = useCallback(async (value) => {
72 | if (search !== value) {
73 | setGoods([]);
74 | setFirst(0)
75 | setIsLast(false)
76 | setSearch(value);
77 | Router.replace({
78 | pathname: LINKS.MARKETPLACE.HREF,
79 | query: {
80 | search: value
81 | }
82 | });
83 | }
84 | }, [search, setSearch, setGoods, setFirst, setIsLast])
85 |
86 | return (
87 |
100 | )
101 | }
102 |
103 | export default memo(Marketplace);
--------------------------------------------------------------------------------
/containers/MyAccount/MyBalance/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { useSelector } from 'react-redux'
4 | import { makeStyles } from '@material-ui/core/styles'
5 | import { Typography } from '@material-ui/core'
6 |
7 | import { NQT_WEIGHT } from 'utils/constants/common'
8 |
9 | const useStyles = makeStyles((theme) => ({
10 | root: {
11 | display: 'flex',
12 | flexDirection: 'column',
13 | alignItems: 'center'
14 | },
15 | title: {
16 | fontSize: 24,
17 | marginBottom: theme.spacing(1),
18 | [theme.breakpoints.down('sm')]: {
19 | fontSize: 20,
20 | },
21 | },
22 | balance: {
23 | fontSize: 30,
24 | color: theme.palette.primary.main,
25 | marginBottom: theme.spacing(5),
26 | [theme.breakpoints.down('sm')]: {
27 | fontSize: 24,
28 | },
29 | },
30 | }));
31 |
32 | const MyBalance = () => {
33 | const classes = useStyles();
34 | const { currentUser, accountRS } = useSelector(state => state.auth);
35 |
36 | return (
37 |
38 |
42 | JUP ADDRESS
43 |
44 |
49 | {accountRS}
50 |
51 |
55 | BALANCE
56 |
57 |
62 | {parseInt(currentUser?.balanceNQT || 0, 10) / NQT_WEIGHT} JUP
63 |
64 |
65 | )
66 | }
67 |
68 |
69 | export default memo(MyBalance)
--------------------------------------------------------------------------------
/containers/MyAccount/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import clsx from 'clsx'
5 |
6 | import ImageWall from 'parts/ImageWall'
7 | import MyBalance from './MyBalance'
8 | import EditAccount from './EditAccount'
9 | import { useCommonStyles } from 'styles/use-styles'
10 |
11 | const useStyles = makeStyles((theme) => ({
12 | root: {
13 | display: 'flex',
14 | flexDirection: 'column',
15 | alignItems: 'center'
16 | },
17 | container: {
18 | display: 'flex',
19 | flexDirection: 'column',
20 | alignItems: 'center',
21 | maxWidth: theme.custom.layout.maxDesktopWidth,
22 | margin: theme.spacing(7, 0, 13),
23 | [theme.breakpoints.down('xs')]: {
24 | margin: theme.spacing(2.5, 0)
25 | }
26 | },
27 | }));
28 |
29 | const MyAccount = () => {
30 | const classes = useStyles();
31 | const commonClasses = useCommonStyles();
32 |
33 | return (
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | )
42 | }
43 |
44 | export default memo(MyAccount)
--------------------------------------------------------------------------------
/containers/MyNFTs/MyAskOrders/OrderItem/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useMemo } from 'react'
3 | import { Typography } from '@material-ui/core'
4 | import { makeStyles } from '@material-ui/core/styles'
5 |
6 | import ContainedButton from 'components/UI/Buttons/ContainedButton'
7 | import ProductContent from 'parts/ProductContent'
8 | import getJSONParse from 'utils/helpers/getJSONParse'
9 | import { NQT_WEIGHT } from 'utils/constants/common'
10 |
11 | const useStyles = makeStyles((theme) => ({
12 | itemContainer: {
13 | display: 'flex',
14 | width: '100%',
15 | marginBottom: theme.spacing(3),
16 | [theme.breakpoints.down('xs')]: {
17 | flexDirection: 'column'
18 | },
19 | },
20 | imageContainer: {
21 | display: 'flex',
22 | justifyContent: 'center',
23 | cursor: 'pointer',
24 | padding: theme.spacing(1),
25 | borderRadius: 2,
26 | border: `1px solid ${theme.custom.palette.border}`,
27 | backgroundColor: theme.palette.background.default,
28 | marginRight: theme.spacing(2),
29 | [theme.breakpoints.down('xs')]: {
30 | marginBottom: theme.spacing(1),
31 | },
32 | },
33 | image: {
34 | width: 90,
35 | height: 90,
36 | objectFit: 'cover',
37 | },
38 | content: {
39 | display: 'flex',
40 | flexDirection: 'column',
41 | justifyContent: 'space-between',
42 | alignItems: 'flex-start',
43 | },
44 | name: {
45 | fontSize: 16,
46 | fontWeight: 'bold',
47 | marginBottom: theme.spacing(1)
48 | },
49 | delete: {
50 | backgroundColor: theme.custom.palette.red,
51 | },
52 | rowContainer: {
53 | display: 'flex',
54 | alignItems: 'center',
55 | marginBottom: theme.spacing(1)
56 | },
57 | label: {
58 | fontSize: 14,
59 | fontWeight: 'bold',
60 | textTransform: 'uppercase',
61 | width: 60
62 | },
63 | value: {
64 | fontWeight: 'bold',
65 | fontSize: 14,
66 | }
67 | }));
68 |
69 | const OrderItem = ({
70 | item,
71 | onDetail,
72 | onDelete
73 | }) => {
74 | const classes = useStyles();
75 |
76 | const info = useMemo(() => getJSONParse(item?.message), [item]);
77 |
78 | return (
79 |
80 |
onDetail(item)}>
81 |
85 |
86 |
87 |
88 |
92 | {item.description}
93 |
94 |
95 |
99 | PRICE
100 |
101 |
105 | {item?.priceNQT / NQT_WEIGHT || 0} JUP
106 |
107 |
108 |
109 |
onDelete(item)}
112 | >
113 | Cancel
114 |
115 |
116 |
117 | )
118 | }
119 |
120 | export default memo(OrderItem)
--------------------------------------------------------------------------------
/containers/MyNFTs/MyAskOrders/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useState, useEffect, useCallback } from 'react'
3 | import { useRouter } from 'next/router'
4 | import { useSelector } from 'react-redux'
5 | import { makeStyles } from '@material-ui/core/styles'
6 | import { IconButton } from '@material-ui/core'
7 | import ExpandMoreIcon from '@material-ui/icons/ExpandMore'
8 |
9 | import * as jupiterAPI from 'services/api-jupiter'
10 | import NoData from 'parts/NoData'
11 | import CancelNFTOrderDialog from 'parts/CancelNFTOrderDialog'
12 | import TabPanel from '../Shared/TabPanel'
13 | import OrderItem from './OrderItem'
14 | import { isEmpty } from 'utils/helpers/utility'
15 | import usePopUp from 'utils/hooks/usePopUp'
16 | import MESSAGES from 'utils/constants/messages'
17 | import LINKS from 'utils/constants/links'
18 |
19 | const useStyles = makeStyles(() => ({
20 | container: {
21 | display: 'flex',
22 | flexDirection: 'column',
23 | alignItems: 'center',
24 | },
25 | moreIcon: {
26 | fontSize: 50
27 | }
28 | }));
29 |
30 | const PAGE_COUNT = 5;
31 | const MyAskOrders = ({
32 | index,
33 | value
34 | }) => {
35 | const classes = useStyles();
36 | const { setPopUp } = usePopUp();
37 | const router = useRouter();
38 |
39 | const { currentUser } = useSelector(state => state.auth);
40 | const [assets, setAssets] = useState([])
41 | const [first, setFirst] = useState(0);
42 | const [isLast, setIsLast] = useState(false)
43 | const [openModal, setOpenModal] = useState(false);
44 | const [selectedItem, setSelectedItem] = useState(false);
45 |
46 | useEffect(() => {
47 | if (!isEmpty(currentUser)) {
48 | getAccountCurrentAskOrders();
49 | }
50 | // eslint-disable-next-line react-hooks/exhaustive-deps
51 | }, [currentUser])
52 |
53 | const getAccountCurrentAskOrders = useCallback(async () => {
54 | if (!isLast) {
55 | const params = {
56 | first,
57 | last: first + PAGE_COUNT - 1,
58 | account: currentUser.account
59 | }
60 |
61 | const response = await jupiterAPI.getAccountCurrentAskOrders(params);
62 | if (response?.errorCode) {
63 | setPopUp({ text: MESSAGES.GET_NFT_ERROR })
64 | return;
65 | }
66 |
67 | const { askOrders = [] } = response;
68 | setAssets((prev) => [...prev, ...askOrders]);
69 | setFirst((prev) => prev + askOrders.length);
70 | setIsLast(askOrders.length < PAGE_COUNT);
71 | }
72 | }, [isLast, first, currentUser, setAssets, setFirst, setIsLast, setPopUp])
73 |
74 | const deleteHandler = useCallback((item) => {
75 | setSelectedItem(item)
76 | setOpenModal(true)
77 | }, [setOpenModal, setSelectedItem])
78 |
79 | const detailNFTHandler = useCallback((item) => {
80 | router.push(
81 | LINKS.NFT_DETAIL.HREF,
82 | LINKS.NFT_DETAIL.HREF.replace('[goods]', item.asset)
83 | )
84 | }, [router])
85 |
86 | return (
87 |
88 | {isEmpty(assets)
89 | ? (
90 |
91 | ) : (
92 |
93 | {assets.map((item, index) => (
94 |
100 | ))}
101 | {
102 | !isLast &&
103 |
104 |
105 |
106 | }
107 |
108 | )
109 | }
110 | {
111 | openModal &&
112 |
117 | }
118 |
119 | )
120 | }
121 |
122 | export default memo(MyAskOrders)
--------------------------------------------------------------------------------
/containers/MyNFTs/MyAssets/AssetItem/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useMemo } from 'react'
3 | import { Grid, Typography } from '@material-ui/core'
4 | import { makeStyles } from '@material-ui/core/styles'
5 |
6 | import ContainedButton from 'components/UI/Buttons/ContainedButton'
7 | import OutlinedButton from 'components/UI/Buttons/OutlinedButton'
8 | import ProductContent from 'parts/ProductContent'
9 | import getJSONParse from 'utils/helpers/getJSONParse'
10 |
11 | const useStyles = makeStyles((theme) => ({
12 | itemContainer: {
13 | display: 'flex',
14 | width: '100%',
15 | marginBottom: theme.spacing(3),
16 | [theme.breakpoints.down('xs')]: {
17 | flexDirection: 'column'
18 | },
19 | },
20 | imageContainer: {
21 | display: 'flex',
22 | justifyContent: 'center',
23 | cursor: 'pointer',
24 | padding: theme.spacing(1),
25 | borderRadius: 2,
26 | border: `1px solid ${theme.custom.palette.border}`,
27 | backgroundColor: theme.palette.background.default,
28 | marginRight: theme.spacing(2),
29 | [theme.breakpoints.down('xs')]: {
30 | marginBottom: theme.spacing(1),
31 | },
32 | },
33 | image: {
34 | width: 90,
35 | height: 90,
36 | objectFit: 'cover',
37 | },
38 | content: {
39 | display: 'flex',
40 | flexDirection: 'column',
41 | justifyContent: 'space-between',
42 | alignItems: 'flex-start',
43 | },
44 | name: {
45 | fontSize: 16,
46 | fontWeight: 'bold',
47 | marginBottom: theme.spacing(1)
48 | },
49 | delete: {
50 | borderColor: theme.custom.palette.red,
51 | backgroundColor: theme.custom.palette.red,
52 | },
53 | }));
54 |
55 | const AssetItem = ({
56 | item,
57 | onDetail,
58 | onSell,
59 | onSend,
60 | onDelete
61 | }) => {
62 | const classes = useStyles();
63 |
64 | const info = useMemo(() => getJSONParse(item?.message), [item]);
65 |
66 | return (
67 |
68 |
onDetail(item)}>
69 |
73 |
74 |
75 |
79 | {item.description}
80 |
81 | {
82 | item.unconfirmedQuantityQNT > 0 &&
83 |
84 |
85 | onSell(item)}>
86 | Sell
87 |
88 |
89 |
90 | onSend(item)}>
91 | Transfer
92 |
93 |
94 |
95 | onDelete(item)}
98 | >
99 | Delete
100 |
101 |
102 |
103 | }
104 |
105 |
106 | )
107 | }
108 |
109 | export default memo(AssetItem)
--------------------------------------------------------------------------------
/containers/MyNFTs/MyBidOrders/BidItem/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useMemo } from 'react'
3 | import { Typography } from '@material-ui/core'
4 | import { makeStyles } from '@material-ui/core/styles'
5 |
6 | import ContainedButton from 'components/UI/Buttons/ContainedButton'
7 | import ProductContent from 'parts/ProductContent'
8 | import getJSONParse from 'utils/helpers/getJSONParse'
9 | import { NQT_WEIGHT } from 'utils/constants/common'
10 |
11 | const useStyles = makeStyles((theme) => ({
12 | itemContainer: {
13 | display: 'flex',
14 | width: '100%',
15 | marginBottom: theme.spacing(3),
16 | [theme.breakpoints.down('xs')]: {
17 | flexDirection: 'column'
18 | },
19 | },
20 | imageContainer: {
21 | display: 'flex',
22 | justifyContent: 'center',
23 | cursor: 'pointer',
24 | padding: theme.spacing(1),
25 | borderRadius: 2,
26 | border: `1px solid ${theme.custom.palette.border}`,
27 | backgroundColor: theme.palette.background.default,
28 | marginRight: theme.spacing(2),
29 | [theme.breakpoints.down('xs')]: {
30 | marginBottom: theme.spacing(1),
31 | },
32 | },
33 | image: {
34 | width: 90,
35 | height: 90,
36 | objectFit: 'cover',
37 | },
38 | content: {
39 | display: 'flex',
40 | flexDirection: 'column',
41 | justifyContent: 'space-between',
42 | alignItems: 'flex-start',
43 | },
44 | name: {
45 | fontSize: 16,
46 | fontWeight: 'bold',
47 | marginBottom: theme.spacing(1)
48 | },
49 | delete: {
50 | backgroundColor: theme.custom.palette.red,
51 | },
52 | rowContainer: {
53 | display: 'flex',
54 | alignItems: 'center',
55 | marginBottom: theme.spacing(1)
56 | },
57 | label: {
58 | fontSize: 14,
59 | fontWeight: 'bold',
60 | textTransform: 'uppercase',
61 | width: 60
62 | },
63 | value: {
64 | fontWeight: 'bold',
65 | fontSize: 14,
66 | }
67 | }));
68 |
69 | const BidItem = ({
70 | item,
71 | onDetail,
72 | onDelete
73 | }) => {
74 | const classes = useStyles();
75 |
76 | const info = useMemo(() => getJSONParse(item?.message), [item]);
77 |
78 | return (
79 |
80 |
onDetail(item)}>
81 |
85 |
86 |
87 |
88 |
92 | {item.description}
93 |
94 |
95 |
99 | PRICE
100 |
101 |
105 | {item?.priceNQT / NQT_WEIGHT || 0} JUP
106 |
107 |
108 |
109 |
onDelete(item)}
112 | >
113 | Cancel
114 |
115 |
116 |
117 | )
118 | }
119 |
120 | export default memo(BidItem)
--------------------------------------------------------------------------------
/containers/MyNFTs/MyBidOrders/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useState, useEffect, useCallback } from 'react'
3 | import { useRouter } from 'next/router'
4 | import { useSelector } from 'react-redux'
5 | import { makeStyles } from '@material-ui/core/styles'
6 | import { IconButton } from '@material-ui/core'
7 | import ExpandMoreIcon from '@material-ui/icons/ExpandMore'
8 |
9 | import * as jupiterAPI from 'services/api-jupiter'
10 | import NoData from 'parts/NoData'
11 | import CancelNFTOrderDialog from 'parts/CancelNFTOrderDialog'
12 | import TabPanel from '../Shared/TabPanel'
13 | import BidItem from './BidItem'
14 | import { isEmpty } from 'utils/helpers/utility'
15 | import usePopUp from 'utils/hooks/usePopUp'
16 | import MESSAGES from 'utils/constants/messages'
17 | import LINKS from 'utils/constants/links'
18 |
19 | const useStyles = makeStyles(() => ({
20 | container: {
21 | display: 'flex',
22 | flexDirection: 'column',
23 | alignItems: 'center',
24 | },
25 | moreIcon: {
26 | fontSize: 50
27 | }
28 | }));
29 |
30 | const PAGE_COUNT = 5;
31 | const MyBidOrders = ({
32 | index,
33 | value
34 | }) => {
35 | const classes = useStyles();
36 | const { setPopUp } = usePopUp();
37 | const router = useRouter();
38 |
39 | const { currentUser } = useSelector(state => state.auth);
40 | const [assets, setAssets] = useState([])
41 | const [first, setFirst] = useState(0);
42 | const [isLast, setIsLast] = useState(false)
43 | const [openModal, setOpenModal] = useState(false);
44 | const [selectedItem, setSelectedItem] = useState(false);
45 |
46 | useEffect(() => {
47 | if (!isEmpty(currentUser)) {
48 | getAccountCurrentBidOrders();
49 | }
50 | // eslint-disable-next-line react-hooks/exhaustive-deps
51 | }, [currentUser])
52 |
53 | const getAccountCurrentBidOrders = useCallback(async () => {
54 | if (!isLast) {
55 | const params = {
56 | first,
57 | last: first + PAGE_COUNT - 1,
58 | account: currentUser.account
59 | }
60 |
61 | const response = await jupiterAPI.getAccountCurrentBidOrders(params);
62 | if (response?.errorCode) {
63 | setPopUp({ text: MESSAGES.GET_NFT_ERROR })
64 | return;
65 | }
66 |
67 | const { bidOrders = [] } = response;
68 | setAssets((prev) => [...prev, ...bidOrders]);
69 | setFirst((prev) => prev + bidOrders.length);
70 | setIsLast(bidOrders.length < PAGE_COUNT);
71 | }
72 | }, [isLast, first, currentUser, setAssets, setFirst, setIsLast, setPopUp])
73 |
74 | const deleteHandler = useCallback((item) => {
75 | setSelectedItem(item)
76 | setOpenModal(true)
77 | }, [setOpenModal, setSelectedItem])
78 |
79 | const detailNFTHandler = useCallback((item) => {
80 | router.push(
81 | LINKS.NFT_DETAIL.HREF,
82 | LINKS.NFT_DETAIL.HREF.replace('[goods]', item.asset)
83 | )
84 | }, [router])
85 |
86 | return (
87 |
88 | {isEmpty(assets)
89 | ? (
90 |
91 | ) : (
92 |
93 | {assets.map((item, index) => (
94 |
100 | ))}
101 | {
102 | !isLast &&
103 |
104 |
105 |
106 | }
107 |
108 | )
109 | }
110 | {
111 | openModal &&
112 |
117 | }
118 |
119 | )
120 | }
121 |
122 | export default memo(MyBidOrders)
--------------------------------------------------------------------------------
/containers/MyNFTs/Shared/TabPanel/index.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react'
2 | import { Box } from '@material-ui/core'
3 | import { makeStyles } from '@material-ui/core/styles'
4 |
5 | const useStyles = makeStyles(() => ({
6 | tabPanel: {
7 | width: '100%'
8 | },
9 | }));
10 |
11 | const TabPanel = ({
12 | children,
13 | value,
14 | index,
15 | ...rest
16 | }) => {
17 | const classes = useStyles();
18 |
19 | return (
20 |
28 | {value === index && (
29 |
30 | {children}
31 |
32 | )}
33 |
34 | )
35 | };
36 |
37 | export default memo(TabPanel)
--------------------------------------------------------------------------------
/containers/MyNFTs/Shared/VerticalTabs/index.js:
--------------------------------------------------------------------------------
1 | import { memo, useCallback } from 'react'
2 | import { makeStyles } from '@material-ui/core/styles'
3 | import { Tab, Tabs } from '@material-ui/core'
4 |
5 | function a11yProps(index) {
6 | return {
7 | id: `vertical-tab-${index}`,
8 | 'aria-controls': `vertical-tabpanel-${index}`,
9 | };
10 | }
11 |
12 | const useStyles = makeStyles((theme) => ({
13 | tabs: {
14 | maxWidth: 180,
15 | width: '100%',
16 | borderRight: `2px solid ${theme.palette.divider}`,
17 | [theme.breakpoints.down('xs')]: {
18 | maxWidth: 80,
19 | },
20 | },
21 | tab: {
22 | fontSize: 18,
23 | fontWeight: 'bold',
24 | textDecoration: 'underline',
25 | textAlign: 'right',
26 | color: theme.palette.text.primary,
27 | padding: theme.spacing(0.5, 1, 0.5, 0),
28 | minHeight: 'unset',
29 | [theme.breakpoints.down('xs')]: {
30 | fontSize: 14,
31 | },
32 | },
33 | selected: {
34 | color: theme.palette.primary.main,
35 | },
36 | wrapper: {
37 | alignItems: 'flex-end'
38 | },
39 | indicator: {
40 | backgroundColor: 'unset',
41 | }
42 | }));
43 |
44 | const VerticalTabs = ({
45 | tabs,
46 | value,
47 | setValue
48 | }) => {
49 | const classes = useStyles();
50 |
51 | const handleChange = useCallback((event, newValue) => {
52 | setValue(newValue);
53 | }, [setValue]);
54 |
55 | return (
56 |
67 | {
68 | tabs.map((item, index) => (
69 |
79 | ))
80 | }
81 |
82 | );
83 | }
84 |
85 | export default memo(VerticalTabs)
86 |
--------------------------------------------------------------------------------
/containers/MyNFTs/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useEffect, useState } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import clsx from 'clsx'
5 | import Router, { useRouter } from 'next/router'
6 |
7 | import ImageWall from 'parts/ImageWall'
8 | import { useCommonStyles } from 'styles/use-styles'
9 | import VerticalTabs from './Shared/VerticalTabs'
10 | import MyAssets from './MyAssets'
11 | import MyAskOrders from './MyAskOrders'
12 | import MyBidOrders from './MyBidOrders'
13 | import LINKS from 'utils/constants/links'
14 |
15 | const useStyles = makeStyles((theme) => ({
16 | root: {
17 | display: 'flex',
18 | flexDirection: 'column',
19 | alignItems: 'center'
20 | },
21 | container: {
22 | flexGrow: 1,
23 | display: 'flex',
24 | height: '100%',
25 | width: '100%',
26 | maxWidth: 720,
27 | padding: theme.spacing(0, 2),
28 | marginBottom: theme.spacing(10)
29 | },
30 | }));
31 |
32 | const TABS = [
33 | 'MY NFTS',
34 | 'MY SELL ORDERS',
35 | 'MY BUY ORDERS',
36 | ]
37 |
38 | const MyNFTs = () => {
39 | const classes = useStyles();
40 | const commonClasses = useCommonStyles();
41 | const router = useRouter();
42 |
43 | const [selectedTab, setSelectedTab] = useState(() => {
44 | const findIndex = TABS.findIndex((tab) => tab === router.query.tab)
45 | return findIndex < 0 ? 0 : findIndex
46 | });
47 |
48 | useEffect(() => {
49 | const tabValue = TABS[selectedTab]
50 | Router.replace({
51 | pathname: LINKS.MY_NFTS.HREF,
52 | query: {
53 | tab: tabValue
54 | }
55 | });
56 | }, [selectedTab])
57 |
58 | return (
59 |
60 |
61 |
62 |
67 |
71 |
75 |
79 |
80 |
81 | )
82 | }
83 |
84 | export default memo(MyNFTs)
--------------------------------------------------------------------------------
/containers/NFTDetail/HistoricalPrices/index.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react'
2 | import { makeStyles } from '@material-ui/core/styles'
3 | import {
4 | Typography,
5 | TableCell,
6 | TableRow,
7 | } from '@material-ui/core'
8 |
9 | import TableContainer from 'parts/Table/TableContainer'
10 | import { isEmpty } from 'utils/helpers/utility'
11 | import { NQT_WEIGHT } from 'utils/constants/common'
12 |
13 | const useStyles = makeStyles((theme) => ({
14 | root: {
15 | overflowX: 'inherit',
16 | marginBottom: theme.spacing(1)
17 | },
18 | title: {
19 | fontWeight: 'bold',
20 | textTransform: 'uppercase',
21 | },
22 | cell: {
23 | border: 'unset',
24 | padding: theme.spacing(1, 0)
25 | },
26 | }));
27 |
28 | const columns = [
29 | { id: 'seller', label: 'Seller', minWidth: 150 },
30 | { id: 'buyer', label: 'Buyer', minWidth: 150 },
31 | { id: 'price', label: 'Price', minWidth: 60 },
32 | ];
33 |
34 | const HistoricalPrices = ({
35 | trades
36 | }) => {
37 | const classes = useStyles();
38 |
39 | return (
40 |
41 |
42 | Historical Prices
43 |
44 | {isEmpty(trades)
45 | ? (
46 |
47 | No Transaction Histories
48 |
49 | ) : (
50 |
51 | {trades.map((trade, index) => (
52 |
53 |
54 |
55 | {trade.sellerRS}
56 |
57 |
58 |
59 |
60 | {trade.buyerRS}
61 |
62 |
63 |
64 | {trade.priceNQT / NQT_WEIGHT} JUP
65 |
66 |
67 | ))}
68 |
69 | )}
70 |
71 | )
72 | }
73 |
74 | export default memo(HistoricalPrices)
--------------------------------------------------------------------------------
/containers/NFTDetail/NFTInformation/InformationContent/index.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react'
2 | import { makeStyles } from '@material-ui/core/styles'
3 | import { Typography } from '@material-ui/core'
4 |
5 | import { NQT_WEIGHT } from 'utils/constants/common'
6 | import { getDateFromTimestamp } from 'utils/helpers/getTimestamp'
7 |
8 | const useStyles = makeStyles((theme) => ({
9 | name: {
10 | fontSize: 30,
11 | fontWeight: 'bold',
12 | marginBottom: theme.spacing(1)
13 | },
14 | description: {
15 | fontSize: 16,
16 | marginBottom: theme.spacing(2)
17 | },
18 | container: {
19 | marginBottom: theme.spacing(2)
20 | },
21 | label: {
22 | fontSize: 16,
23 | fontWeight: 'bold'
24 | },
25 | accountName: {
26 | fontSize: 14,
27 | },
28 | accountDescription: {
29 | fontSize: 14,
30 | },
31 | accountRS: {
32 | fontSize: 14,
33 | fontWeight: 'bold',
34 | },
35 | price: {
36 | fontSize: 14,
37 | },
38 | }));
39 |
40 | const InformationContent = ({
41 | good,
42 | sellerAccount,
43 | creatorAccount,
44 | assetInfo
45 | }) => {
46 | const classes = useStyles();
47 |
48 | return (
49 | <>
50 |
55 | {good.description}
56 |
57 |
62 | {assetInfo.description}
63 |
64 |
65 |
66 |
70 | CREATOR INFO
71 |
72 |
76 | {creatorAccount.accountRS}
77 |
78 |
82 | {creatorAccount.name || 'No Name'}
83 |
84 | {creatorAccount?.description &&
85 |
89 | {creatorAccount.description}
90 |
91 | }
92 |
96 | {`DATE OF CREATION: ${getDateFromTimestamp(good.timestamp)}`}
97 |
98 |
99 |
100 |
101 |
105 | SELLER INFO
106 |
107 |
111 | {sellerAccount.accountRS}
112 |
113 |
117 | {sellerAccount.name || 'No Name'}
118 |
119 | {sellerAccount?.description &&
120 |
124 | {sellerAccount.description}
125 |
126 | }
127 |
128 |
129 |
130 |
134 | PRICE
135 |
136 |
140 | {!good.priceNQT
141 | ? 'No Price'
142 | : `${good.priceNQT / NQT_WEIGHT} JUP`
143 | }
144 |
145 |
146 | >
147 | )
148 | }
149 |
150 | export default memo(InformationContent)
--------------------------------------------------------------------------------
/containers/NFTDetail/NFTInformation/index.js:
--------------------------------------------------------------------------------
1 | import { memo, useState, useCallback } from 'react'
2 | import { makeStyles } from '@material-ui/core/styles'
3 | import { useRouter } from 'next/router'
4 | import { useSelector } from 'react-redux'
5 |
6 | import ContainedButton from 'components/UI/Buttons/ContainedButton'
7 | import CancelNFTOrderDialog from 'parts/CancelNFTOrderDialog'
8 | import PurchaseNFTDialog from 'parts/PurchaseNFTDialog'
9 | import InformationContent from './InformationContent'
10 | import usePopUp from 'utils/hooks/usePopUp'
11 | import MESSAGES from 'utils/constants/messages'
12 | import LINKS from 'utils/constants/links'
13 | import { isEmpty } from 'utils/helpers/utility'
14 |
15 | const useStyles = makeStyles((theme) => ({
16 | root: {
17 | marginBottom: theme.spacing(2),
18 | },
19 | delete: {
20 | backgroundColor: theme.custom.palette.red
21 | }
22 | }));
23 |
24 | const NFTInformation = ({
25 | isMine,
26 | good,
27 | order,
28 | sellerAccount,
29 | creatorAccount,
30 | assetInfo
31 | }) => {
32 | const classes = useStyles();
33 | const router = useRouter();
34 | const { setPopUp } = usePopUp();
35 |
36 | const { accountRS } = useSelector(state => state.auth);
37 | const [openDeleteModal, setOpenDeleteModal] = useState(false);
38 | const [openPurchaseModal, setOpenPurchaseModal] = useState(false);
39 |
40 | const purchaseHandler = useCallback(() => {
41 | if (!accountRS) {
42 | setPopUp({ text: MESSAGES.AUTH_REQUIRED })
43 | router.push(LINKS.SIGN_IN.HREF)
44 | return;
45 | }
46 |
47 | setOpenPurchaseModal(true)
48 | }, [accountRS, router, setPopUp, setOpenPurchaseModal])
49 |
50 | return (
51 |
52 |
58 | {!isEmpty(order) &&
59 | (isMine
60 | ? (
61 |
setOpenDeleteModal(true)}
64 | >
65 | Delete
66 |
67 | ) : (
68 |
69 | Buy Now
70 |
71 | ))
72 | }
73 |
74 | {openPurchaseModal &&
75 |
80 | }
81 | {openDeleteModal &&
82 |
87 | }
88 |
89 | )
90 | }
91 |
92 | export default memo(NFTInformation)
--------------------------------------------------------------------------------
/containers/NFTDetail/SellerNFTs/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useState, useCallback } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import { Typography } from '@material-ui/core'
5 |
6 | import * as jupiterAPI from 'services/api-jupiter'
7 | import NFTList from 'parts/NFTList'
8 |
9 | const useStyles = makeStyles((theme) => ({
10 | container: {
11 | width: '100%',
12 | maxWidth: theme.custom.layout.maxMarketPlaceWidth,
13 | padding: theme.spacing(4, 3)
14 | },
15 | title: {
16 | fontSize: 28,
17 | }
18 | }));
19 |
20 | const PAGE_COUNT = 8;
21 |
22 | const SellerNFTs = ({
23 | account
24 | }) => {
25 | const classes = useStyles();
26 |
27 | const [goods, setGoods] = useState([]);
28 | const [first, setFirst] = useState(0);
29 | const [isLast, setIsLast] = useState(false);
30 |
31 | const getAccountCurrentAskOrders = useCallback(async () => {
32 | try {
33 | if (!isLast) {
34 | const params = {
35 | first,
36 | last: first + PAGE_COUNT - 1,
37 | account
38 | }
39 |
40 | const { askOrders = [] } = await jupiterAPI.getAccountCurrentAskOrders(params);
41 |
42 | setGoods((prev) => [...prev, ...askOrders]);
43 | setFirst((prev) => prev + askOrders.length);
44 | setIsLast(askOrders.length < PAGE_COUNT);
45 | }
46 | } catch (error) {
47 | console.log(error)
48 | }
49 | }, [account, isLast, first, setGoods, setFirst, setIsLast])
50 |
51 | return (
52 |
53 |
54 | MORE NFTS FROM THIS SELLER
55 |
56 |
61 |
62 | )
63 | }
64 |
65 | export default memo(SellerNFTs);
--------------------------------------------------------------------------------
/containers/TransactionHistory/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useEffect, useCallback, useState } from 'react'
3 | import { useRouter } from 'next/router'
4 | import { makeStyles } from '@material-ui/core/styles'
5 | import { IconButton } from '@material-ui/core'
6 | import ExpandMoreIcon from '@material-ui/icons/ExpandMore'
7 | import clsx from 'clsx'
8 |
9 | import * as jupiterAPI from 'services/api-jupiter'
10 | import ImageWall from 'parts/ImageWall'
11 | import TransactionItem from './TransactionItem'
12 | import { useCommonStyles } from 'styles/use-styles'
13 | import LINKS from 'utils/constants/links'
14 |
15 | const useStyles = makeStyles((theme) => ({
16 | root: {
17 | display: 'flex',
18 | flexDirection: 'column',
19 | alignItems: 'center'
20 | },
21 | container: {
22 | display: 'flex',
23 | flexDirection: 'column',
24 | height: '100%',
25 | width: '100%',
26 | maxWidth: 560,
27 | marginBottom: theme.spacing(10),
28 | },
29 | moreIcon: {
30 | fontSize: 50
31 | }
32 | }));
33 |
34 | const PAGE_COUNT = 8;
35 |
36 | const TransactionHistory = () => {
37 | const classes = useStyles();
38 | const router = useRouter();
39 | const commonClasses = useCommonStyles();
40 |
41 | const [trades, setTrades] = useState([])
42 | const [first, setFirst] = useState(0)
43 | const [isLast, setIsLast] = useState(false)
44 |
45 | useEffect(() => {
46 | searchAllTrades();
47 | // eslint-disable-next-line react-hooks/exhaustive-deps
48 | }, [])
49 |
50 | const searchAllTrades = useCallback(async () => {
51 | if (!isLast) {
52 | const params = {
53 | first,
54 | last: first + PAGE_COUNT - 1,
55 | }
56 |
57 | const response = await jupiterAPI.searchAllTrades(params);
58 | const { trades = [] } = response;
59 | setTrades((prev) => [...prev, ...trades]);
60 | setFirst((prev) => prev + trades.length);
61 | setIsLast(trades.length < PAGE_COUNT);
62 | }
63 | }, [isLast, first, setTrades, setFirst, setIsLast]);
64 |
65 | const detailNFTHandler = useCallback((item) => {
66 | console.log(item)
67 | router.push(
68 | LINKS.NFT_DETAIL.HREF,
69 | LINKS.NFT_DETAIL.HREF.replace('[goods]', item.asset)
70 | )
71 | }, [router])
72 |
73 | return (
74 |
75 |
76 |
77 | {
78 | trades.map((item, index) => (
79 |
84 | ))
85 | }
86 | {
87 | !isLast &&
88 |
89 |
90 |
91 | }
92 |
93 |
94 | )
95 | }
96 |
97 | export default memo(TransactionHistory)
--------------------------------------------------------------------------------
/contexts/ui-context.js:
--------------------------------------------------------------------------------
1 | import { createContext, useState, useContext } from 'react'
2 |
3 | const DarkModeContext = createContext()
4 |
5 | function DarkModeProvider({ children }) {
6 | const [darkMode, setDarkMode] = useState(false)
7 | const value = { darkMode, setDarkMode };
8 |
9 | return (
10 |
11 | {children}
12 |
13 | )
14 | }
15 |
16 | function useDarkMode() {
17 | const context = useContext(DarkModeContext)
18 | if (context === undefined) {
19 | throw new Error('useDarkMode must be used within a DarkModeProvider')
20 | }
21 | return context
22 | }
23 |
24 | export { DarkModeProvider, useDarkMode }
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "*": ["*", "/*"]
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | env: {
4 | NETWORK: process.env.NETWORK,
5 | EUROPA_ID: process.env.EUROPA_ID,
6 | },
7 | images: {
8 | domains: [
9 | 'res.cloudinary.com'
10 | ],
11 | },
12 | webpack: (config, { dev }) => {
13 | if (dev) {
14 | config.module.rules.push({
15 | test: /\.(j|t)sx?$/,
16 | exclude: /node_modules/,
17 | loader: 'eslint-loader'
18 | });
19 | }
20 |
21 | config.module.rules.push({
22 | test: /\.svg$/,
23 | use: ['@svgr/webpack']
24 | });
25 |
26 | return config;
27 | }
28 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Leda",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "deploy:vercel": "vercel --prod"
10 | },
11 | "dependencies": {
12 | "@hookform/resolvers": "1.0.0",
13 | "@iarna/word-count": "^1.1.2",
14 | "@material-ui/core": "^4.11.2",
15 | "@material-ui/icons": "^4.11.2",
16 | "axios": "^0.21.1",
17 | "clsx": "^1.1.1",
18 | "next": "10.0.4",
19 | "react": "17.0.1",
20 | "react-alice-carousel": "^2.4.0",
21 | "react-div-100vh": "^0.5.6",
22 | "react-dom": "17.0.1",
23 | "react-dropzone": "^11.3.1",
24 | "react-hook-form": "^6.14.0",
25 | "react-infinite-scroll-component": "^6.0.0",
26 | "react-lottie": "^1.2.3",
27 | "react-redux": "^7.2.2",
28 | "react-text-mask": "^5.4.3",
29 | "redux": "^4.0.5",
30 | "redux-thunk": "^2.3.0",
31 | "yup": "^0.32.8"
32 | },
33 | "devDependencies": {
34 | "@svgr/webpack": "^5.5.0",
35 | "babel-eslint": "^10.1.0",
36 | "eslint": "^7.17.0",
37 | "eslint-loader": "^4.0.2",
38 | "eslint-plugin-react": "^7.22.0",
39 | "eslint-plugin-react-hooks": "^4.2.0",
40 | "pm2": "^4.5.1",
41 | "redux-devtools-extension": "^2.13.8",
42 | "redux-logger": "^3.0.6"
43 | }
44 | }
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 |
2 | import Head from 'next/head'
3 | import { Provider } from 'react-redux'
4 | import CssBaseline from '@material-ui/core/CssBaseline'
5 |
6 | import store from 'store'
7 | import { DarkModeProvider } from 'contexts/ui-context'
8 | import InitProvider from 'utils/hocs/InitProvider'
9 | import PopUpProvider from 'utils/hocs/PopUpProvider'
10 | import ThemeProvider from 'utils/hocs/ThemeProvider'
11 | import * as COMMON_CONSTANTS from 'utils/constants/common'
12 |
13 | function MyApp({ Component, pageProps }) {
14 | return (
15 | <>
16 |
17 | {COMMON_CONSTANTS.TITLE}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | {/* Open Graph / Facebook */}
26 |
27 |
28 |
29 |
30 | {/* Twitter */}
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | >
47 | )
48 | }
49 |
50 | MyApp.getInitialProps = async ({ Component, ctx }) => {
51 | const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {};
52 | return { pageProps };
53 | };
54 |
55 | export default MyApp
56 |
--------------------------------------------------------------------------------
/pages/_document.js:
--------------------------------------------------------------------------------
1 |
2 | import { Fragment } from 'react'
3 | import Document, { Html, Head, Main, NextScript } from 'next/document'
4 | import { ServerStyleSheets } from '@material-ui/core/styles'
5 |
6 | import globalStyles from 'styles/global'
7 |
8 | class MyDocument extends Document {
9 | static async getInitialProps(ctx) {
10 | const sheets = new ServerStyleSheets();
11 | const originalRenderPage = ctx.renderPage;
12 |
13 | ctx.renderPage = () => originalRenderPage({
14 | enhanceApp: App => props => sheets.collect( )
15 | });
16 |
17 | const initialProps = await Document.getInitialProps(ctx);
18 |
19 | return {
20 | ...initialProps,
21 | styles: [
22 |
23 | {initialProps.styles}
24 | {sheets.getStyleElement()}
25 |
26 | ]
27 | };
28 | }
29 |
30 | render() {
31 | return (
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
44 |
47 |
48 |
49 |
50 |
51 |
54 |
55 |
56 |
57 |
58 | );
59 | }
60 | }
61 |
62 | export default MyDocument;
63 |
--------------------------------------------------------------------------------
/pages/auth/sign-in.js:
--------------------------------------------------------------------------------
1 |
2 | import Layout from 'Layout'
3 | import SignIn from 'containers/Auth/SignIn'
4 | import HeaderMeta from 'parts/HeaderMeta'
5 |
6 | export default function SignInPage() {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
--------------------------------------------------------------------------------
/pages/auth/sign-up.js:
--------------------------------------------------------------------------------
1 |
2 | import Layout from 'Layout'
3 | import SignUp from 'containers/Auth/SignUp'
4 | import HeaderMeta from 'parts/HeaderMeta'
5 |
6 | export default function SignUpPage() {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
--------------------------------------------------------------------------------
/pages/create-nft.js:
--------------------------------------------------------------------------------
1 |
2 | import CreateNFT from 'containers/CreateNFT'
3 | import Layout from 'Layout'
4 | import HeaderMeta from 'parts/HeaderMeta'
5 |
6 | export default function HomePage() {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
--------------------------------------------------------------------------------
/pages/faq.js:
--------------------------------------------------------------------------------
1 |
2 | import Layout from 'Layout'
3 | import FAQ from 'containers/FAQ'
4 | import HeaderMeta from 'parts/HeaderMeta'
5 |
6 | export default function MyNFTsPage() {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 |
2 | import Home from 'containers/Home'
3 | import Layout from 'Layout'
4 | import HeaderMeta from 'parts/HeaderMeta'
5 |
6 | export default function HomePage() {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
--------------------------------------------------------------------------------
/pages/marketplace.js:
--------------------------------------------------------------------------------
1 |
2 | import Marketplace from 'containers/Marketplace'
3 | import Layout from 'Layout'
4 | import HeaderMeta from 'parts/HeaderMeta'
5 |
6 | export default function HomePage() {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
--------------------------------------------------------------------------------
/pages/my-account.js:
--------------------------------------------------------------------------------
1 |
2 | import Layout from 'Layout'
3 | import MyAccount from 'containers/MyAccount'
4 | import HeaderMeta from 'parts/HeaderMeta'
5 |
6 | export default function MyAccountPage() {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/pages/my-nfts.js:
--------------------------------------------------------------------------------
1 |
2 | import Layout from 'Layout'
3 | import MyNFTs from 'containers/MyNFTs'
4 | import HeaderMeta from 'parts/HeaderMeta'
5 |
6 | export default function MyNFTsPage() {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/pages/nft-details/[goods].js:
--------------------------------------------------------------------------------
1 |
2 | import NFTDetail from 'containers/NFTDetail'
3 | import Layout from 'Layout'
4 | import * as jupiterAPI from 'services/api-jupiter'
5 | import { isEmpty } from 'utils/helpers/utility'
6 |
7 | export default function NFTDetailPage(props) {
8 | return (
9 |
10 |
11 |
12 | )
13 | }
14 |
15 | NFTDetailPage.getInitialProps = async ({ query }) => {
16 | try {
17 | const [
18 | transactionResponse,
19 | assetAccountsResponse,
20 | askOrdersResponse
21 | ] = await Promise.all([
22 | jupiterAPI.getTransaction(query.goods),
23 | jupiterAPI.getAssetAccounts(query.goods),
24 | jupiterAPI.getAskOrders(query.goods),
25 | ]);
26 | const { senderRS, attachment = {}, timestamp } = transactionResponse
27 | const { accountAssets = [] } = assetAccountsResponse
28 | const { askOrders = [] } = askOrdersResponse
29 |
30 | let good = {
31 | ...attachment,
32 | asset: query.goods,
33 | creatorRS: senderRS,
34 | accountRS: accountAssets[0].accountRS,
35 | priceNQT: 0,
36 | timestamp
37 | }
38 |
39 | let askOrder = {}
40 | if (!isEmpty(askOrders)) {
41 | askOrder = askOrders[0]
42 | const { priceNQT, order, type } = askOrder;
43 | good = {
44 | ...good,
45 | order,
46 | type,
47 | priceNQT
48 | }
49 | }
50 |
51 | return {
52 | good,
53 | order: askOrder,
54 | }
55 | } catch (error) {
56 | console.log(error)
57 | }
58 | }
--------------------------------------------------------------------------------
/pages/privacy-policy.js:
--------------------------------------------------------------------------------
1 |
2 | import Layout from 'Layout'
3 | import PrivacyPolicy from 'containers/PrivacyPolicy'
4 | import HeaderMeta from 'parts/HeaderMeta'
5 |
6 | export default function PrivacyPolicyPage() {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/pages/terms-of-service.js:
--------------------------------------------------------------------------------
1 |
2 | import Layout from 'Layout'
3 | import TermsOfService from 'containers/TermsOfService'
4 | import HeaderMeta from 'parts/HeaderMeta'
5 |
6 | export default function TermsOfServicePage() {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/pages/transaction-history.js:
--------------------------------------------------------------------------------
1 |
2 | import TransactionHistory from 'containers/TransactionHistory'
3 | import Layout from 'Layout'
4 | import HeaderMeta from 'parts/HeaderMeta'
5 |
6 | export default function TransactionHistoryPage() {
7 | return (
8 |
9 |
10 |
11 |
12 | )
13 | }
--------------------------------------------------------------------------------
/parts/HeaderMeta/index.js:
--------------------------------------------------------------------------------
1 |
2 | import Head from 'next/head'
3 |
4 | import * as COMMON_CONSTANTS from 'utils/constants/common'
5 | import { BANNER_IMAGE_PATH } from 'utils/constants/image-paths'
6 |
7 | const HeaderMeta = () => {
8 | return (
9 |
10 | {/* Open Graph / Facebook */}
11 |
12 |
13 |
14 |
15 |
16 | {/* Twitter */}
17 |
18 |
19 |
20 |
21 |
22 | )
23 | }
24 |
25 | export default HeaderMeta
26 |
--------------------------------------------------------------------------------
/parts/ImageWall/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import Typography from '@material-ui/core/Typography'
5 | import clsx from 'clsx'
6 |
7 | import { HEADER_BACKGROUND_IMAGE_PATH } from 'utils/constants/image-paths'
8 | import { useCommonStyles } from 'styles/use-styles'
9 |
10 | const useStyles = makeStyles(theme => ({
11 | root: {
12 | display: 'flex',
13 | alignItems: 'center',
14 | flexDirection: 'column',
15 | width: '100%',
16 | minHeight: 450,
17 | backgroundImage: `url(${HEADER_BACKGROUND_IMAGE_PATH})`,
18 | backgroundRepeat: 'no-repeat',
19 | backgroundPositionX: 'right',
20 | backgroundPositionY: 'bottom',
21 | backgroundSize: 'cover',
22 | marginBottom: -210
23 | },
24 | header: {
25 | fontSize: 80,
26 | fontFamily: 'CRC-LIGHT',
27 | textTransform: 'uppercase',
28 | marginTop: theme.spacing(10),
29 | marginBottom: theme.spacing(2),
30 | [theme.breakpoints.down('sm')]: {
31 | fontSize: 30,
32 | },
33 | }
34 | }));
35 |
36 | const ImageWall = ({
37 | header,
38 | description,
39 | className,
40 | classes: propsClasses = {
41 | header: {}
42 | }
43 | }) => {
44 | const classes = useStyles();
45 | const commonClasses = useCommonStyles();
46 |
47 | return (
48 |
49 |
50 |
56 | {header}
57 |
58 |
63 | {description}
64 |
65 |
66 |
67 | );
68 | };
69 |
70 | export default memo(ImageWall);
71 |
--------------------------------------------------------------------------------
/parts/MagicConfirmDialog/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { Typography } from '@material-ui/core'
4 |
5 | import MagicDialog from 'components/MagicDialog'
6 |
7 | const MagicConfirmDialog = ({
8 | text = 'Are you sure to proceed this operation?',
9 | ...rest
10 | }) => {
11 | return (
12 |
13 |
14 | {text}
15 |
16 |
17 | );
18 | }
19 |
20 | export default memo(MagicConfirmDialog)
--------------------------------------------------------------------------------
/parts/NFTCarousel/NFTCarouselItem/index.js:
--------------------------------------------------------------------------------
1 | import { memo, useMemo } from 'react'
2 | import { Typography } from '@material-ui/core'
3 | import { makeStyles } from '@material-ui/core/styles'
4 |
5 | import ProductContent from 'parts/ProductContent'
6 | import getJSONParse from 'utils/helpers/getJSONParse'
7 |
8 | const useStyles = makeStyles((theme) => ({
9 | container: {
10 | height: 420,
11 | margin: theme.spacing(2),
12 | },
13 | imageContainer: {
14 | width: '100%',
15 | padding: theme.spacing(1),
16 | borderRadius: 2,
17 | border: `1px solid ${theme.custom.palette.border}`,
18 | backgroundColor: theme.palette.background.default,
19 | marginBottom: theme.spacing(1)
20 | },
21 | image: {
22 | height: 320,
23 | width: '100%',
24 | objectFit: 'contain',
25 | },
26 | content: {
27 | display: 'flex',
28 | flexDirection: 'column',
29 | justifyContent: 'center',
30 | alignItems: 'center',
31 | width: '100%',
32 | padding: theme.spacing(1, 0)
33 | },
34 | title: {
35 | fontSize: 18,
36 | fontWeight: 'bold',
37 | lineHeight: 1,
38 | marginBottom: theme.spacing(1),
39 | },
40 | description: {
41 | lineHeight: 1,
42 | fontSize: 14,
43 | }
44 | }));
45 |
46 | const NFTCarouselItem = ({
47 | item,
48 | onDetail
49 | }) => {
50 | const classes = useStyles();
51 |
52 | const info = useMemo(() => getJSONParse(item?.message), [item]);
53 |
54 | return (
55 | onDetail(item)}>
56 |
62 |
63 |
64 | {item.description}
65 |
66 |
67 | {item.accountRS}
68 |
69 |
70 |
71 | );
72 | };
73 |
74 | export default memo(NFTCarouselItem);
--------------------------------------------------------------------------------
/parts/NFTCarousel/index.js:
--------------------------------------------------------------------------------
1 | import { memo, useEffect, useState, useCallback } from 'react'
2 | import { useRouter } from 'next/router'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import { Typography } from '@material-ui/core'
5 | import AliceCarousel from 'react-alice-carousel'
6 | import 'react-alice-carousel/lib/alice-carousel.css'
7 |
8 | import * as jupiterAPI from 'services/api-jupiter'
9 | import NFTCarouselItem from './NFTCarouselItem'
10 | import { isEmpty } from 'utils/helpers/utility'
11 | import LINKS from 'utils/constants/links'
12 |
13 | const useStyles = makeStyles((theme) => ({
14 | carousel: {
15 | width: '100%',
16 | },
17 | title: {
18 | fontSize: 40,
19 | fontWeight: 'bold',
20 | fontFamily: 'CRC-LIGHT',
21 | textAlign: 'center',
22 | padding: theme.spacing(0, 2),
23 | margin: theme.spacing(16, 0, 8),
24 | [theme.breakpoints.down('sm')]: {
25 | fontSize: 32,
26 | margin: theme.spacing(5, 0),
27 | },
28 | }
29 | }));
30 |
31 | const responsive = {
32 | 480: { items: 1 },
33 | 680: { items: 2 },
34 | 960: { items: 4 },
35 | 1280: { items: 5 },
36 | 1480: { items: 6 },
37 | 1800: { items: 7 }
38 | }
39 |
40 | const NFTCarousel = () => {
41 | const classes = useStyles();
42 | const router = useRouter();
43 |
44 | const [openOrders, setOpenOrders] = useState([]);
45 |
46 | useEffect(() => {
47 | searchAllOpenAskOrders()
48 | }, [])
49 |
50 | const searchAllOpenAskOrders = async () => {
51 | try {
52 | const params = {
53 | first: 0,
54 | last: 7
55 | }
56 | const { openOrders = [] } = await jupiterAPI.searchAllOpenAskOrders(params);
57 | setOpenOrders(openOrders)
58 | } catch (error) {
59 | console.log(error)
60 | }
61 | }
62 |
63 | const detailNFTHandler = useCallback((item) => {
64 | router.push(
65 | LINKS.NFT_DETAIL.HREF,
66 | LINKS.NFT_DETAIL.HREF.replace('[goods]', item.asset)
67 | )
68 | }, [router])
69 |
70 | return (
71 | !isEmpty(openOrders) &&
72 | <>
73 |
74 | NEW NFT SUBMISSIONS
75 |
76 |
86 | {
87 | openOrders.map((item, index) =>
88 |
93 | )
94 | }
95 |
96 | >
97 | );
98 | };
99 |
100 | export default memo(NFTCarousel);
--------------------------------------------------------------------------------
/parts/NFTList/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useState, useEffect, useRef, useCallback } from 'react'
3 | import { Typography } from '@material-ui/core'
4 | import { makeStyles } from '@material-ui/core/styles'
5 | import InfiniteScroll from 'react-infinite-scroll-component'
6 | import { use100vh } from 'react-div-100vh'
7 |
8 | import NoData from 'parts/NoData'
9 | import PurchaseNFTDialog from 'parts/PurchaseNFTDialog'
10 | import BidNFTDialog from 'parts/BidNFTDialog'
11 | import NFTCard from './NFTCard'
12 | import { isEmpty } from 'utils/helpers/utility'
13 |
14 | const useStyles = makeStyles((theme) => ({
15 | scroll: {
16 | display: 'flex',
17 | flexDirection: 'column',
18 | alignItems: 'center',
19 | overflow: 'hidden !important',
20 | overflowAnchor: 'none',
21 | padding: theme.spacing(2, 0)
22 | },
23 | list: {
24 | display: 'grid',
25 | gridTemplateColumns: '1fr 1fr 1fr 1fr',
26 | gridGap: theme.spacing(7, 5),
27 | width: '100%',
28 | maxWidth: theme.custom.layout.maxMarketPlaceWidth,
29 | [theme.breakpoints.down('md')]: {
30 | gridTemplateColumns: '1fr 1fr 1fr',
31 | },
32 | [theme.breakpoints.down('sm')]: {
33 | gridTemplateColumns: '1fr 1fr',
34 | },
35 | [theme.breakpoints.down('xs')]: {
36 | gridTemplateColumns: '1fr',
37 | },
38 | },
39 | loading: {
40 | fontWeight: 'bold',
41 | margin: theme.spacing(2, 0)
42 | }
43 | }));
44 |
45 | const NFTList = ({
46 | goods,
47 | isLast,
48 | loadMore
49 | }) => {
50 | const classes = useStyles();
51 | const scrollRef = useRef(null);
52 | const deviceHeight = use100vh();
53 |
54 | const [selectedGood, setSelectedGood] = useState({});
55 | const [openPurchaseModal, setOpenPurchaseModal] = useState(false);
56 | const [openBidModal, setOpenBidModal] = useState(false);
57 |
58 | useEffect(() => {
59 | if (!isLast && scrollRef?.current?.scrollHeight < deviceHeight) {
60 | loadMore()
61 | }
62 | // eslint-disable-next-line react-hooks/exhaustive-deps
63 | }, []);
64 |
65 | const purchaseHandler = useCallback((item) => {
66 | setSelectedGood(item)
67 | setOpenPurchaseModal(true)
68 | }, [setSelectedGood, setOpenPurchaseModal])
69 |
70 | const bidHandler = useCallback((item) => {
71 | setSelectedGood(item)
72 | setOpenBidModal(true)
73 | }, [setSelectedGood, setOpenBidModal])
74 |
75 | return (
76 | isLast && isEmpty(goods)
77 | ? (
78 |
79 | ) : (
80 | <>
81 |
90 | Loading more
91 |
92 | }
93 | next={loadMore}
94 | className={classes.scroll}
95 | >
96 |
97 | {goods.map((item, index) => (
98 |
104 | ))}
105 |
106 |
107 | {openPurchaseModal &&
108 |
113 | }
114 | {openBidModal &&
115 |
120 | }
121 | >
122 | )
123 | )
124 | }
125 |
126 | export default memo(NFTList);
--------------------------------------------------------------------------------
/parts/NoData/index.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react'
2 | import { Typography } from '@material-ui/core'
3 | import { makeStyles } from '@material-ui/core/styles'
4 |
5 | const useStyles = makeStyles(() => ({
6 | root: {
7 | display: 'flex',
8 | justifyContent: 'center',
9 | alignItems: 'center',
10 | width: '100%',
11 | minHeight: 200
12 | },
13 | label: {
14 | fontWeight: 'bold'
15 | }
16 | }));
17 |
18 | const NoData = () => {
19 | const classes = useStyles();
20 |
21 | return (
22 |
23 |
29 | No Data
30 |
31 |
32 | )
33 | }
34 |
35 | export default memo(NoData)
--------------------------------------------------------------------------------
/parts/ProductContent/index.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react'
2 |
3 | import { IMAGE_PLACEHOLDER_IMAGE_PATH } from 'utils/constants/image-paths'
4 | import { FILE_TYPES } from 'utils/constants/file-types'
5 |
6 | const ProductContent = ({
7 | info,
8 | className
9 | }) => {
10 |
11 | return info?.type === FILE_TYPES.VIDEO.VALUE
12 | ? (
13 |
14 |
15 |
16 | ) : (
17 |
22 | )
23 | };
24 |
25 | export default memo(ProductContent);
--------------------------------------------------------------------------------
/parts/SearchInput/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useState, useCallback } from 'react'
3 | import { makeStyles } from '@material-ui/core/styles'
4 | import { OutlinedInput, Button } from '@material-ui/core'
5 | import CloseIcon from '@material-ui/icons/Close'
6 | import SearchIcon from '@material-ui/icons/Search'
7 |
8 | const useStyles = makeStyles((theme) => ({
9 | searchContainer: {
10 | display: 'flex',
11 | alignItems: 'center',
12 | },
13 | textField: {
14 | border: `1px solid ${theme.palette.background.primary}`,
15 | borderRight: 0,
16 | borderRadius: 2,
17 | borderTopRightRadius: 0,
18 | borderBottomRightRadius: 0,
19 | width: 320,
20 | backgroundColor: theme.palette.background.default,
21 | '& input': {
22 | padding: theme.spacing(1),
23 | '&::placeholder': {
24 | opacity: 1,
25 | fontStyle: 'italic'
26 | },
27 | '&:-ms-input-placeholder': {
28 | opacity: 1,
29 | fontStyle: 'italic'
30 | },
31 | '&::-ms-input-placeholder': {
32 | opacity: 1,
33 | fontStyle: 'italic'
34 | },
35 | },
36 | [theme.breakpoints.down('sm')]: {
37 | width: '100%',
38 | },
39 | },
40 | adornedEnd: {
41 | paddingRight: theme.spacing(1)
42 | },
43 | closeIcon: {
44 | fontSize: 18,
45 | cursor: 'pointer'
46 | },
47 | button: {
48 | height: 35,
49 | minWidth: 35,
50 | padding: 0,
51 | color: theme.palette.primary.main,
52 | backgroundColor: theme.palette.background.primary,
53 | borderRadius: 2,
54 | borderTopLeftRadius: 0,
55 | borderBottomLeftRadius: 0,
56 | }
57 | }));
58 |
59 | const SearchInput = ({
60 | search,
61 | onSearch
62 | }) => {
63 | const classes = useStyles();
64 | const [query, setQuery] = useState(search);
65 |
66 | const searchHandler = useCallback(() => {
67 | onSearch(query)
68 | }, [query, onSearch]);
69 |
70 | const closeHandler = useCallback(() => {
71 | setQuery('')
72 | onSearch('')
73 | }, [setQuery, onSearch]);
74 |
75 | return (
76 |
77 |
87 | }
88 | placeholder='Search in titles'
89 | value={query}
90 | onChange={event => setQuery(event.target.value)}
91 | />
92 |
97 |
98 |
99 |
100 | )
101 | }
102 |
103 | export default memo(SearchInput);
--------------------------------------------------------------------------------
/parts/Table/TableContainer/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import {
4 | Table,
5 | TableBody,
6 | TableCell,
7 | TableHead,
8 | TableRow,
9 | } from '@material-ui/core'
10 | import { makeStyles } from '@material-ui/core/styles'
11 |
12 | const useStyles = makeStyles((theme) => ({
13 | cell: {
14 | fontWeight: 'bold',
15 | textTransform: 'uppercase',
16 | border: 'unset',
17 | padding: theme.spacing(1, 0)
18 | },
19 | }));
20 |
21 | const TableContainer = ({
22 | columns,
23 | className,
24 | children
25 | }) => {
26 | const classes = useStyles();
27 |
28 | return (
29 |
30 |
31 |
32 | {columns.map(column => (
33 |
39 | {column.label}
40 |
41 | ))}
42 |
43 |
44 |
45 | {children}
46 |
47 |
48 |
49 | )
50 | }
51 |
52 | export default memo(TableContainer)
--------------------------------------------------------------------------------
/public/android-chrome-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/android-chrome-144x144.png
--------------------------------------------------------------------------------
/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/android-chrome-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/android-chrome-256x256.png
--------------------------------------------------------------------------------
/public/android-chrome-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/android-chrome-36x36.png
--------------------------------------------------------------------------------
/public/android-chrome-384x384.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/android-chrome-384x384.png
--------------------------------------------------------------------------------
/public/android-chrome-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/android-chrome-48x48.png
--------------------------------------------------------------------------------
/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/public/android-chrome-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/android-chrome-72x72.png
--------------------------------------------------------------------------------
/public/android-chrome-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/android-chrome-96x96.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-114x114-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-114x114-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-114x114.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-120x120-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-120x120-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-144x144-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-144x144-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-144x144.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-152x152-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-152x152-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-180x180-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-180x180-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-57x57-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-57x57-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-57x57.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-60x60-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-60x60-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-72x72-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-72x72-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-72x72.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-76x76-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-76x76-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/assets/fonts/CRC-BOLD.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/assets/fonts/CRC-BOLD.woff
--------------------------------------------------------------------------------
/public/assets/fonts/CRC-LIGHT.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/assets/fonts/CRC-LIGHT.woff
--------------------------------------------------------------------------------
/public/assets/images/background/auth.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/assets/images/background/auth.jpg
--------------------------------------------------------------------------------
/public/assets/images/background/footer.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/assets/images/background/footer.jpg
--------------------------------------------------------------------------------
/public/assets/images/background/header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/assets/images/background/header.jpg
--------------------------------------------------------------------------------
/public/assets/images/background/home-header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/assets/images/background/home-header.jpg
--------------------------------------------------------------------------------
/public/assets/images/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/assets/images/banner.png
--------------------------------------------------------------------------------
/public/assets/images/black-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/assets/images/black-logo.png
--------------------------------------------------------------------------------
/public/assets/images/home-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/assets/images/home-logo.png
--------------------------------------------------------------------------------
/public/assets/images/icon/image-placeholder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/assets/images/icon/image-placeholder.jpg
--------------------------------------------------------------------------------
/public/assets/images/white-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/assets/images/white-logo.png
--------------------------------------------------------------------------------
/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | #da532c
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/favicon-32x32.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/favicon.ico
--------------------------------------------------------------------------------
/public/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/mstile-144x144.png
--------------------------------------------------------------------------------
/public/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/mstile-150x150.png
--------------------------------------------------------------------------------
/public/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/mstile-310x150.png
--------------------------------------------------------------------------------
/public/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jupiter-project/marketplace/03e186f32fdf04022d73cac47be5387840d74baf/public/mstile-310x310.png
--------------------------------------------------------------------------------
/public/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 | Created by potrace 1.14, written by Peter Selinger 2001-2017
9 |
10 |
12 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/public/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "",
3 | "short_name": "",
4 | "icons": [
5 | {
6 | "src": "/android-chrome-36x36.png",
7 | "sizes": "36x36",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/android-chrome-48x48.png",
12 | "sizes": "48x48",
13 | "type": "image/png"
14 | },
15 | {
16 | "src": "/android-chrome-72x72.png",
17 | "sizes": "72x72",
18 | "type": "image/png"
19 | },
20 | {
21 | "src": "/android-chrome-96x96.png",
22 | "sizes": "96x96",
23 | "type": "image/png"
24 | },
25 | {
26 | "src": "/android-chrome-144x144.png",
27 | "sizes": "144x144",
28 | "type": "image/png"
29 | },
30 | {
31 | "src": "/android-chrome-192x192.png",
32 | "sizes": "192x192",
33 | "type": "image/png"
34 | },
35 | {
36 | "src": "/android-chrome-256x256.png",
37 | "sizes": "256x256",
38 | "type": "image/png"
39 | },
40 | {
41 | "src": "/android-chrome-384x384.png",
42 | "sizes": "384x384",
43 | "type": "image/png"
44 | },
45 | {
46 | "src": "/android-chrome-512x512.png",
47 | "sizes": "512x512",
48 | "type": "image/png"
49 | }
50 | ],
51 | "theme_color": "#ffffff",
52 | "background_color": "#ffffff",
53 | "display": "standalone"
54 | }
55 |
--------------------------------------------------------------------------------
/reducers/authReducer.js:
--------------------------------------------------------------------------------
1 |
2 | import * as TYPES from 'actions/types'
3 |
4 | const initialState = {
5 | accountRS: '',
6 | currentUser: {},
7 | isWallet: false
8 | };
9 |
10 | export default function authReducer(state = initialState, action) {
11 | switch (action.type) {
12 | case TYPES.SET_ACCOUNT_RS:
13 | return {
14 | ...state,
15 | accountRS: action.payload
16 | };
17 | case TYPES.SET_CURRENT_USER:
18 | return {
19 | ...state,
20 | currentUser: action.payload
21 | };
22 | case TYPES.SET_IS_WALLET:
23 | return {
24 | ...state,
25 | isWallet: action.payload
26 | };
27 | default:
28 | return state;
29 | }
30 | }
--------------------------------------------------------------------------------
/reducers/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { combineReducers } from 'redux'
3 |
4 | import loadingReducer from 'reducers/loadingReducer'
5 | import authReducer from 'reducers/authReducer'
6 | import popUpReducer from 'reducers/popUpReducer'
7 |
8 | export default combineReducers({
9 | loading: loadingReducer,
10 | auth: authReducer,
11 | popUp: popUpReducer,
12 | });
--------------------------------------------------------------------------------
/reducers/loadingReducer.js:
--------------------------------------------------------------------------------
1 |
2 | import * as TYPES from 'actions/types'
3 |
4 | const initialState = {
5 | loadingStatus: false
6 | };
7 |
8 | export default function loadingReducer(state = initialState, action) {
9 | switch (action.type) {
10 | case TYPES.SET_LOADING_STATUS:
11 | return {
12 | ...state,
13 | loadingStatus: action.payload
14 | };
15 | default:
16 | return state;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/reducers/popUpReducer.js:
--------------------------------------------------------------------------------
1 |
2 | import * as TYPES from 'actions/types'
3 |
4 | const initialState = {
5 | open: false,
6 | title: 'Alert',
7 | text: '',
8 | cancelLabel: 'Ok'
9 | };
10 |
11 | export default function popUpReducer(state = initialState, action) {
12 | switch (action.type) {
13 | case TYPES.SET_POP_UP_INFO:
14 | return {
15 | ...state,
16 | open: true,
17 | ...action.payload,
18 | };
19 | case TYPES.OPEN_POP_UP:
20 | return { ...state, open: true };
21 | case TYPES.CLOSE_POP_UP:
22 | return initialState;
23 | default:
24 | return state;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/services/api-cloudinary.js:
--------------------------------------------------------------------------------
1 | import axios from 'services/axios'
2 |
3 | const uploadFileCloudinary = async (params) => {
4 | return await axios.post('/api/cloudinary/upload', params);
5 | };
6 |
7 | export {
8 | uploadFileCloudinary,
9 | };
--------------------------------------------------------------------------------
/services/axios.js:
--------------------------------------------------------------------------------
1 |
2 | import axios from 'axios'
3 |
4 | import { PROXY_URL } from 'config'
5 |
6 | const apiAxios = axios.create({
7 | baseURL: PROXY_URL,
8 | headers: {
9 | 'Content-Type': 'application/json; charset=utf-8'
10 | }
11 | })
12 |
13 | apiAxios.interceptors.response.use((response) => {
14 | return response.data;
15 | });
16 |
17 | export default apiAxios;
--------------------------------------------------------------------------------
/services/europa.js:
--------------------------------------------------------------------------------
1 |
2 | const connectWallet = () => {
3 | return new Promise((resolve) => {
4 | chrome.runtime.sendMessage(
5 | process.env.EUROPA_ID,
6 | { type: "CONNECT_WALLET" },
7 | (response) => {
8 | resolve(response)
9 | }
10 | )
11 | })
12 | };
13 |
14 | const getPassphrase = () => {
15 | return new Promise((resolve) => {
16 | chrome.runtime.sendMessage(
17 | process.env.EUROPA_ID,
18 | { type: "GET_PASSPHRASE" },
19 | (response) => {
20 | resolve(response)
21 | }
22 | )
23 | })
24 | };
25 |
26 | export {
27 | connectWallet,
28 | getPassphrase,
29 | };
--------------------------------------------------------------------------------
/store.js:
--------------------------------------------------------------------------------
1 |
2 | import { createStore, applyMiddleware } from 'redux'
3 | import thunkMiddleware from 'redux-thunk'
4 |
5 | import reducers from 'reducers'
6 |
7 | const bindMiddleWares = middleWares => {
8 | if (process.env.NODE_ENV !== 'production') {
9 | const { composeWithDevTools } = require('redux-devtools-extension');
10 | const { logger } = require(`redux-logger`);
11 | middleWares.push(logger);
12 |
13 | return composeWithDevTools(applyMiddleware(...middleWares));
14 | }
15 | return applyMiddleware(...middleWares);
16 | };
17 |
18 | export default createStore(reducers, bindMiddleWares([thunkMiddleware]))
--------------------------------------------------------------------------------
/styles/global.js:
--------------------------------------------------------------------------------
1 |
2 | import css from 'styled-jsx/css'
3 |
4 | export default css.global`
5 | html,
6 | body {
7 | min-height: 100vh;
8 | scroll-behavior: smooth;
9 | padding: 0 !important;
10 | }
11 | `;
12 |
--------------------------------------------------------------------------------
/styles/theme.js:
--------------------------------------------------------------------------------
1 |
2 | import {
3 | createMuiTheme,
4 | responsiveFontSizes
5 | } from '@material-ui/core/styles'
6 |
7 | const MuiCssBaseline = {
8 | '@global': {
9 | '@font-face': [{
10 | fontFamily: 'CRC-BOLD',
11 | fontStyle: 'normal',
12 | fontDisplay: 'swap',
13 | fontWeight: 400,
14 | src: `
15 | local('CRC-BOLD'),
16 | url('/assets/fonts/CRC-BOLD.woff') format('woff')`
17 | },
18 | {
19 | fontFamily: 'CRC-LIGHT',
20 | fontStyle: 'normal',
21 | fontDisplay: 'swap',
22 | fontWeight: 400,
23 | src: `
24 | local('CRC-LIGHT'),
25 | url('/assets/fonts/CRC-LIGHT.woff') format('woff')`
26 | }],
27 | }
28 | }
29 |
30 | const layout = {
31 | topAppBarHeight: 60,
32 | maxDesktopWidth: 1110,
33 | maxMarketPlaceWidth: 1366
34 | }
35 |
36 | const lightTheme = responsiveFontSizes(createMuiTheme({
37 | typography: {
38 | fontFamily: 'CRC-BOLD, CRC-LIGHT',
39 | },
40 | overrides: {
41 | MuiCssBaseline,
42 | MuiCard: {
43 | root: {
44 | borderRadius: 10,
45 | boxShadow: '0 2px 12px 0 #bdbdbd',
46 | }
47 | },
48 | },
49 | palette: {
50 | primary: {
51 | light: '#4791db',
52 | main: '#2B9938',
53 | dark: '#ecebed',
54 | contrastText: '#ffffff'
55 | },
56 | secondary: {
57 | light: '#555e6c',
58 | main: '#0066ff',
59 | dark: '#1e2532',
60 | contrastText: '#ffffff'
61 | },
62 | danger: {
63 | light: '#c944dd',
64 | main: '#eb196e',
65 | dark: '#b20000',
66 | contrastText: '#ffffff'
67 | },
68 | background: {
69 | default: '#ffffff',
70 | primary: '#ecebed',
71 | secondary: '#343a40'
72 | },
73 | text: {
74 | primary: '#4e4e4f',
75 | secondary: '#a2a1b2'
76 | },
77 | },
78 | custom: {
79 | palette: {
80 | grey: '#e6e6e6',
81 | orange: '#d36738',
82 | white: '#ffffff',
83 | red: '#8d161e',
84 | green: '#2B9938',
85 | darkGreen: '#073920',
86 | blue: '#4595e6',
87 | black: '#000000',
88 | border: '#999999'
89 | },
90 | layout,
91 | }
92 | }));
93 |
94 | const darkTheme = responsiveFontSizes(createMuiTheme({
95 | typography: {
96 | fontFamily: 'CRC-BOLD, CRC-LIGHT',
97 | },
98 | overrides: {
99 | MuiCssBaseline,
100 | MuiCard: {
101 | root: {
102 | borderRadius: 10,
103 | boxShadow: '0 2px 12px 0 #bdbdbd',
104 | }
105 | },
106 | },
107 | palette: {
108 | primary: {
109 | light: '#4791db',
110 | main: '#2B9938',
111 | dark: '#ecebed',
112 | contrastText: '#ffffff'
113 | },
114 | secondary: {
115 | light: '#555e6c',
116 | main: '#0066ff',
117 | dark: '#1e2532',
118 | contrastText: '#ffffff'
119 | },
120 | danger: {
121 | light: '#c944dd',
122 | main: '#eb196e',
123 | dark: '#b20000',
124 | contrastText: '#ffffff'
125 | },
126 | background: {
127 | default: '#4e4e4f',
128 | primary: '#a2a1b2',
129 | secondary: '#343a40'
130 | },
131 | text: {
132 | primary: '#ffffff',
133 | secondary: '#ecebed',
134 | },
135 | },
136 | custom: {
137 | palette: {
138 | grey: '#e6e6e6',
139 | orange: '#d36738',
140 | white: '#ffffff',
141 | red: '#8d161e',
142 | green: '#2B9938',
143 | darkGreen: '#073920',
144 | blue: '#4595e6',
145 | black: '#000000',
146 | border: '#999999'
147 | },
148 | layout,
149 | }
150 | }));
151 |
152 | export { lightTheme, darkTheme };
153 |
--------------------------------------------------------------------------------
/styles/use-styles.js:
--------------------------------------------------------------------------------
1 |
2 | import { makeStyles } from '@material-ui/core/styles'
3 |
4 | const useCommonStyles = makeStyles(theme => ({
5 | containerWidth: {
6 | width: '100%',
7 | paddingLeft: theme.spacing(4),
8 | paddingRight: theme.spacing(4),
9 | [theme.breakpoints.down('sm')]: {
10 | maxWidth: '100%',
11 | paddingLeft: theme.spacing(3),
12 | paddingRight: theme.spacing(3)
13 | }
14 | },
15 | breakWords: {
16 | overflow: 'hidden',
17 | display: '-webkit-box',
18 | WebkitBoxOrient: 'vertical',
19 | textOverflow: 'ellipsis',
20 | overflowWrap: 'break-word',
21 | }
22 | }));
23 |
24 | export {
25 | useCommonStyles
26 | };
27 |
--------------------------------------------------------------------------------
/utils/constants/common.js:
--------------------------------------------------------------------------------
1 |
2 | const TITLE = 'Leda - Jupiter based NFT marketplace'
3 | const SITE_URL = 'https://leda.jup.io'
4 | const DESCRIPTION = 'Buy, sell and collect blockchain-secured digital items'
5 |
6 | const PLACE_FILLER_URL = 'https://gojupiter.tech/placefiller'
7 | const UNISWAP_URL = 'https://app.uniswap.org/#/swap?inputCurrency=ETH&outputCurrency=0x4b1e80cac91e2216eeb63e29b957eb91ae9c2be8'
8 | const PANCAKESWAP_URL = 'https://exchange.pancakeswap.finance/#/swap?inputCurrency=0x0231f91e02DebD20345Ae8AB7D71A41f8E140cE7'
9 | const GATE_WAY_BLOG_URL = 'https://blog.gojupiter.tech/gateway-procedures-update-7c6f29e422a'
10 | const JUP_WALLET_URL = 'https://jpr.gojupiter.tech'
11 | const JUP_SUPPORT_URL = 'https://gojupiter.tech/support'
12 |
13 | const NQT_WEIGHT = 100000000;
14 | const MAX_UPLOAD_SIZE = 20971520;
15 |
16 | export {
17 | TITLE,
18 | SITE_URL,
19 | DESCRIPTION,
20 | PLACE_FILLER_URL,
21 | UNISWAP_URL,
22 | PANCAKESWAP_URL,
23 | GATE_WAY_BLOG_URL,
24 | JUP_WALLET_URL,
25 | JUP_SUPPORT_URL,
26 | NQT_WEIGHT,
27 | MAX_UPLOAD_SIZE
28 | }
29 |
--------------------------------------------------------------------------------
/utils/constants/contact.js:
--------------------------------------------------------------------------------
1 | const SUPPORT_EMAIL = 'info@gojupiter.tech';
2 | const SITE_URL = 'https://leda.jup.io';
3 |
4 | export {
5 | SUPPORT_EMAIL,
6 | SITE_URL
7 | };
8 |
--------------------------------------------------------------------------------
/utils/constants/file-types.js:
--------------------------------------------------------------------------------
1 |
2 | const FILE_TYPES = Object.freeze({
3 | IMAGE: {
4 | LABEL: 'Image',
5 | VALUE: 'IMAGE',
6 | ACCEPT: 'image/*',
7 | PLACEHOLDER: 'PNG, JPEG, GIF, WEBP. Max 20MB.',
8 | },
9 | VIDEO: {
10 | LABEL: 'Video',
11 | VALUE: 'VIDEO',
12 | ACCEPT: 'video/*',
13 | PLACEHOLDER: 'MP4, AVI, MPEG. Max 20MB.'
14 | },
15 | })
16 |
17 | const FILE_TYPES_ARRAY = [
18 | FILE_TYPES.IMAGE,
19 | FILE_TYPES.VIDEO,
20 | ]
21 |
22 | export {
23 | FILE_TYPES,
24 | FILE_TYPES_ARRAY
25 | };
26 |
--------------------------------------------------------------------------------
/utils/constants/footer-menu.js:
--------------------------------------------------------------------------------
1 |
2 | import LINKS from 'utils/constants/links';
3 |
4 | const FOOTER_MENU = [
5 | {
6 | HREF: LINKS.HOME.HREF,
7 | TITLE: LINKS.HOME.TITLE
8 | },
9 | {
10 | HREF: LINKS.MARKETPLACE.HREF,
11 | TITLE: LINKS.MARKETPLACE.TITLE
12 | },
13 | {
14 | TITLE: LINKS.TRANSACTION_HISTORY.TITLE,
15 | HREF: LINKS.TRANSACTION_HISTORY.HREF,
16 | },
17 | {
18 | TITLE: LINKS.FAQ.TITLE,
19 | HREF: LINKS.FAQ.HREF,
20 | },
21 | ]
22 |
23 | export default FOOTER_MENU
--------------------------------------------------------------------------------
/utils/constants/image-paths.js:
--------------------------------------------------------------------------------
1 |
2 | const WHITE_LOGO_IMAGE_PATH = '/assets/images/white-logo.png';
3 | const BLACK_LOGO_IMAGE_PATH = '/assets/images/black-logo.png';
4 | const HOME_LOGO_IMAGE_PATH = '/assets/images/home-logo.png';
5 | const BANNER_IMAGE_PATH = 'https://res.cloudinary.com/leda/image/upload/v1633019916/avyfba0kefc4xspk6m5h.png';
6 | const AUTH_BACKGROUND_IMAGE_PATH = '/assets/images/background/auth.jpg';
7 | const HEADER_BACKGROUND_IMAGE_PATH = '/assets/images/background/header.jpg';
8 | const FOOTER_BACKGROUND_IMAGE_PATH = '/assets/images/background/footer.jpg';
9 | const HOME_HEADER_BACKGROUND_IMAGE_PATH = '/assets/images/background/home-header.jpg';
10 | const IMAGE_PLACEHOLDER_IMAGE_PATH = '/assets/images/icon/image-placeholder.jpg';
11 |
12 | export {
13 | WHITE_LOGO_IMAGE_PATH,
14 | BLACK_LOGO_IMAGE_PATH,
15 | HOME_LOGO_IMAGE_PATH,
16 | BANNER_IMAGE_PATH,
17 | AUTH_BACKGROUND_IMAGE_PATH,
18 | HEADER_BACKGROUND_IMAGE_PATH,
19 | FOOTER_BACKGROUND_IMAGE_PATH,
20 | IMAGE_PLACEHOLDER_IMAGE_PATH,
21 | HOME_HEADER_BACKGROUND_IMAGE_PATH
22 | };
--------------------------------------------------------------------------------
/utils/constants/links.js:
--------------------------------------------------------------------------------
1 |
2 | const LINKS = Object.freeze({
3 | SIGN_IN: {
4 | TITLE: 'Log In',
5 | HREF: '/auth/sign-in',
6 | },
7 | SIGN_UP: {
8 | TITLE: 'Sign Up',
9 | HREF: '/auth/sign-up'
10 | },
11 | SIGN_OUT: {
12 | TITLE: 'Log Out',
13 | HREF: '/auth/sign-out',
14 | },
15 | HOME: {
16 | TITLE: 'Home',
17 | HREF: '/'
18 | },
19 | MARKETPLACE: {
20 | TITLE: 'Marketplace',
21 | HREF: '/marketplace'
22 | },
23 | NFT_DETAIL: {
24 | TITLE: 'NFT details',
25 | HREF: '/nft-details/[goods]'
26 | },
27 | CREATE_NFT: {
28 | TITLE: 'Create NFT',
29 | HREF: '/create-nft'
30 | },
31 | TRANSACTION_HISTORY: {
32 | TITLE: 'Transactions',
33 | HREF: '/transaction-history'
34 | },
35 | MY_ACCOUNT: {
36 | TITLE: 'My Account',
37 | HREF: '/my-account'
38 | },
39 | MY_NFTS: {
40 | TITLE: 'My NFTs',
41 | HREF: '/my-nfts'
42 | },
43 | FAQ: {
44 | TITLE: 'FAQ',
45 | HREF: '/faq',
46 | },
47 | TERMS_OF_SERVICE: {
48 | TITLE: 'Terms Of Service',
49 | HREF: '/terms-of-service',
50 | },
51 | PRIVACY_POLICY: {
52 | TITLE: 'Privacy Policy',
53 | HREF: '/privacy-policy',
54 | },
55 | });
56 |
57 | export default LINKS;
--------------------------------------------------------------------------------
/utils/constants/messages.js:
--------------------------------------------------------------------------------
1 |
2 | const MESSAGES = Object.freeze({
3 | CONNECT_NO_ETHEREUM_PROVIDER_ERROR: 'No Ethereum browser extension detected, install MetaMask on desktop or visit from a dApp browser on mobile.',
4 | CONNECT_UNSUPPORTED_CHAIN_ID_ERROR: 'You\'re connected to an unsupported network.',
5 | CONNECT_ACCESS_BINANCE_ERROR: 'Please authorize this website to access your Binance Smart Chain account.',
6 | CONNECT_UNKNOWN_ERROR: 'An unknown error occurred. Check the console for more details.',
7 | SIGN_IN_SUCCESS: 'Welcome to Leda. You’ve successfully logged in.',
8 | SIGN_UP_SUCCESS: 'Welcome to Leda. You have registered successfully. To be able to buy or create NFTs you will have to fund your JUP address.',
9 | AUTH_ERROR: 'Incorrect JUP address, please try again. ',
10 | AUTH_REQUIRED: 'Please log in first.',
11 | TERMS_PRIVACY_CHECK: 'Please check the Terms of Service and Privacy Policy box.',
12 | MAX_UPLOAD_ERROR: 'There was a problem uploading your file. Please make sure it is a supported file type of less than 20 MB.',
13 | SET_ACCOUNT_ERROR: 'There was a problem updating your account info. Either your JUP balance is insufficient or you’ve entered an incorrect passphrase.',
14 | SET_ACCOUNT_SUCCESS: 'Your updated account info has been submitted to the blockchain and will be confirmed in ~60 seconds.',
15 | IMAGE_NOT_FOUND: 'Please upload your file first.',
16 | CREATE_NFT_SUCCESS: 'Your NFT has been created.Your NFT creation is successfully submitted to the blockchain. After ~60 seconds it will appear in your MY NFTS tab. From there, you can put it for sale on the marketplace.',
17 | CREATE_NFT_ERROR: 'There was a problem creating your NFT. Either your JUP balance is insufficient or you’ve entered an incorrect passphrase.',
18 | GET_NFT_ERROR: 'This NFT does not exist, please check your url.',
19 | PURCHASE_NFT_SUCCESS: 'Your buy order has been submitted to the blockchain and will be confirmed in ~60 seconds.',
20 | PURCHASE_NFT_ERROR: 'You don\'t have enough JUP to buy this NFT, please fund your account.',
21 | BID_NFT_SUCCESS: 'Your bid has been submitted to the blockchain and will be confirmed in ~60 seconds.',
22 | BID_NFT_ERROR: 'You don\'t have enough JUP to place this bid, please lower your bid price or fund your account.',
23 | CANCEL_NFT_ORDER_SUCCESS: 'Your order cancellation has been submitted to the blockchain and will be confirmed in ~60 seconds.',
24 | CANCEL_NFT_ORDER_ERROR: 'Incorrect passphrase, please try again.',
25 | DELETE_NFT_SUCCESS: 'Your NFT delete has been submitted to the blockchain and will be confirmed in ~60 seconds.',
26 | DELETE_NFT_ERROR: 'Incorrect passphrase, please try again.',
27 | PLACE_ASK_ORDER_SUCCESS: 'Your sell order has been submitted to the blockchain and will be confirmed in ~60 seconds.',
28 | PLACE_ASK_ORDER_ERROR: 'Incorrect passphrase, please try again.',
29 | SEND_ASSET_SUCCESS: 'Your sent order has been submitted to the blockchain and will be confirmed in ~60 seconds.',
30 | SEND_ASSET_ERROR: 'Incorrect passphrase, please try again.',
31 | CONNECT_WALLET_ERROR: 'There is an error in connecting Europa. Please check your extension.'
32 | });
33 |
34 | export default MESSAGES;
--------------------------------------------------------------------------------
/utils/constants/order-type.js:
--------------------------------------------------------------------------------
1 |
2 | const ORDER_TYPE = Object.freeze({
3 | ASK: 'ask',
4 | BID: 'bid',
5 | })
6 |
7 | export default ORDER_TYPE;
8 |
--------------------------------------------------------------------------------
/utils/constants/routes.js:
--------------------------------------------------------------------------------
1 | import LINKS from 'utils/constants/links'
2 |
3 | const PAGE_ROUTES = [
4 | LINKS.MY_ACCOUNT.HREF,
5 | LINKS.CREATE_NFT.HREF,
6 | LINKS.MY_NFTS.HREF,
7 | ];
8 |
9 | export {
10 | PAGE_ROUTES
11 | };
12 |
--------------------------------------------------------------------------------
/utils/constants/social.js:
--------------------------------------------------------------------------------
1 |
2 | const SOCIALS = Object.freeze({
3 | TELEGRAM: {
4 | HREF: 'https://t.me/jupiterproject',
5 | LABEL: 'telegram link'
6 | },
7 | TWITTER: {
8 | HREF: 'https://twitter.com/jup_project',
9 | LABEL: 'twitter link'
10 | },
11 | DISCORD: {
12 | HREF: 'https://discord.gg/jUgED8K',
13 | LABEL: 'discord link'
14 | },
15 | })
16 |
17 | export default SOCIALS;
18 |
--------------------------------------------------------------------------------
/utils/constants/text-masks.js:
--------------------------------------------------------------------------------
1 |
2 | const TEXT_MASKS = Object.freeze({
3 | ACCOUNT: [/\b[a-zA-Z]/, /\b[a-zA-Z]/, /\b[a-zA-Z]/, '-', /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/, '-', /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/, '-', /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/, '-', /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/, /\b[a-zA-Z0-9]/],
4 | })
5 |
6 | export default TEXT_MASKS;
--------------------------------------------------------------------------------
/utils/constants/top-bar-menu.js:
--------------------------------------------------------------------------------
1 |
2 | import LINKS from 'utils/constants/links'
3 |
4 | const SIGN_IN_MENU_LINKS = [
5 | {
6 | TITLE: LINKS.MARKETPLACE.TITLE,
7 | HREF: LINKS.MARKETPLACE.HREF,
8 | },
9 | {
10 | TITLE: LINKS.TRANSACTION_HISTORY.TITLE,
11 | HREF: LINKS.TRANSACTION_HISTORY.HREF,
12 | },
13 | {
14 | TITLE: LINKS.CREATE_NFT.TITLE,
15 | HREF: LINKS.CREATE_NFT.HREF,
16 | },
17 | {
18 | TITLE: LINKS.MY_NFTS.TITLE,
19 | HREF: LINKS.MY_NFTS.HREF,
20 | },
21 | {
22 | TITLE: LINKS.MY_ACCOUNT.TITLE,
23 | HREF: LINKS.MY_ACCOUNT.HREF,
24 | },
25 | {
26 | TITLE: LINKS.FAQ.TITLE,
27 | HREF: LINKS.FAQ.HREF,
28 | },
29 | // {
30 | // TITLE: LINKS.SIGN_OUT.TITLE,
31 | // HREF: LINKS.SIGN_OUT.HREF,
32 | // }
33 | ]
34 |
35 | const SIGN_OFF_MENU_LINKS = [
36 | {
37 | TITLE: LINKS.MARKETPLACE.TITLE,
38 | HREF: LINKS.MARKETPLACE.HREF,
39 | },
40 | {
41 | TITLE: LINKS.TRANSACTION_HISTORY.TITLE,
42 | HREF: LINKS.TRANSACTION_HISTORY.HREF,
43 | },
44 | {
45 | TITLE: LINKS.FAQ.TITLE,
46 | HREF: LINKS.FAQ.HREF,
47 | },
48 | {
49 | TITLE: LINKS.SIGN_UP.TITLE,
50 | HREF: LINKS.SIGN_UP.HREF,
51 | },
52 | {
53 | TITLE: LINKS.SIGN_IN.TITLE,
54 | HREF: LINKS.SIGN_IN.HREF,
55 | },
56 | ]
57 |
58 | export {
59 | SIGN_IN_MENU_LINKS,
60 | SIGN_OFF_MENU_LINKS
61 | }
--------------------------------------------------------------------------------
/utils/constants/validations.js:
--------------------------------------------------------------------------------
1 |
2 | import * as yup from 'yup'
3 | import wordCount from '@iarna/word-count'
4 |
5 | const TITLE_VALID = yup.string()
6 | .test('title', "# can't be used", value => !value.includes('#'))
7 | .required('Please enter a title.');
8 |
9 | const STRING_VALID = yup.string()
10 | .required('Please input field.');
11 |
12 | const ACCOUNT_NAME_VALID = yup.string()
13 | .test('name', "# can't be used", value => !value.includes('#'))
14 | .max(100, 'Name length should be less than 1000.')
15 | .required('Please enter a name.')
16 |
17 | const ACCOUNT_DESCRIPTION_VALID = yup.string()
18 | .test('description', "# can't be used", value => !value.includes('#'))
19 | .max(1000, 'Description length should be less than 1000.')
20 | .required('Please enter a description.')
21 |
22 | const NFT_DESCRIPTION_VALID = yup.string()
23 | .test('description', "# can't be used", value => !value.includes('#'))
24 | .max(800, 'Description length should be less than 800.')
25 | .required('Please enter a description.')
26 |
27 | const ACCOUNT_VALID = yup.string()
28 | .test('description', "# can't be used", value => !value.includes('#'))
29 | .length(24, 'Account length should be 24.')
30 | .required('Please enter a description.')
31 |
32 | const PASSPHRASE_VALID = yup.string()
33 | .required('Please enter your passphrase.')
34 | .test('passphrase',
35 | 'Passphrase should be 12 words.',
36 | value => wordCount(value) === 12);
37 |
38 | const PRICE_VALID = yup.number()
39 | .typeError('Please enter valid number')
40 | .test('price',
41 | 'Price should be more than 0.',
42 | value => value > 0)
43 | .test('price',
44 | 'Incorrect price, maximal 8 decimals allowed.',
45 | value => ((value).toString().split('.')[1] || []).length <= 8)
46 | .required('Please input field.');
47 |
48 | export {
49 | TITLE_VALID,
50 | STRING_VALID,
51 | ACCOUNT_NAME_VALID,
52 | ACCOUNT_VALID,
53 | PASSPHRASE_VALID,
54 | PRICE_VALID,
55 | ACCOUNT_DESCRIPTION_VALID,
56 | NFT_DESCRIPTION_VALID
57 | };
--------------------------------------------------------------------------------
/utils/helpers/delay.js:
--------------------------------------------------------------------------------
1 |
2 | const delay = ms => new Promise(res => setTimeout(res, ms));
3 |
4 | export default delay;
5 |
--------------------------------------------------------------------------------
/utils/helpers/generatePassphrase.js:
--------------------------------------------------------------------------------
1 | /*
2 | * By using this function, we can generate a list of 12 random words from words array.
3 | * This list of 12 random words will be used generate an jupiter account
4 | * By great.dolphin.ls
5 | */
6 |
7 | import WORDS from 'utils/constants/words';
8 |
9 | const PASSPHRASE_LENGTH = 12;
10 | const generatePassphrase = () => {
11 | const phraseArray = [];
12 |
13 | for (let i = 0; i < PASSPHRASE_LENGTH; i++) {
14 | phraseArray.push(WORDS[Math.floor(Math.random() * WORDS.length)]);
15 | }
16 |
17 | const passphrase = phraseArray.join(' ');
18 | return passphrase;
19 | }
20 |
21 | export default generatePassphrase;
--------------------------------------------------------------------------------
/utils/helpers/getEllipsis.js:
--------------------------------------------------------------------------------
1 | const getEllipsis = (str, first = 6, last = -4) => {
2 | return `${str.slice(0, first)}...${str.slice(last)}`;
3 | };
4 |
5 | export default getEllipsis
--------------------------------------------------------------------------------
/utils/helpers/getJSONParse.js:
--------------------------------------------------------------------------------
1 | const getJSONParse = data => {
2 | let jsonData = {}
3 | try {
4 | jsonData = JSON.parse(data)
5 | } catch {
6 | jsonData = {}
7 | }
8 | return jsonData
9 | }
10 |
11 | export default getJSONParse;
12 |
13 |
--------------------------------------------------------------------------------
/utils/helpers/getTimestamp.js:
--------------------------------------------------------------------------------
1 |
2 | const GENESIS_TIMESTAMP = Math.round(new Date('2017-10-21 23:19:28') / 1000);
3 |
4 | const getTimestamp = (date) => {
5 | return Math.round(date / 1000) - GENESIS_TIMESTAMP;
6 | }
7 |
8 | const getDateFromTimestamp = (timestamp) =>
9 | new Date((GENESIS_TIMESTAMP + timestamp) * 1000).toLocaleDateString('en-US', {
10 | year: 'numeric',
11 | month: 'short',
12 | day: 'numeric',
13 | hour: 'numeric',
14 | minute: 'numeric',
15 | hour12: true
16 | })
17 |
18 | export {
19 | getTimestamp,
20 | getDateFromTimestamp
21 | }
--------------------------------------------------------------------------------
/utils/helpers/scrollToTop.js:
--------------------------------------------------------------------------------
1 |
2 | const scrollToTop = () => {
3 | window.scroll({
4 | left: 0,
5 | top: 0,
6 | behavior: 'smooth'
7 | });
8 | }
9 | export default scrollToTop
--------------------------------------------------------------------------------
/utils/helpers/signTransaction.js:
--------------------------------------------------------------------------------
1 |
2 | const signTransaction = (unsignedTransactionBytes, passphrase) => {
3 | const sigPos = 192;
4 | const sigLen = 128;
5 | const signature = window.NRS.signBytes(unsignedTransactionBytes, window.converters.stringToHexString(passphrase));
6 | const transactionBytes = unsignedTransactionBytes.substr(0, sigPos) + signature + unsignedTransactionBytes.substr(sigPos + sigLen);
7 |
8 | return transactionBytes
9 | }
10 |
11 | export default signTransaction
--------------------------------------------------------------------------------
/utils/helpers/time.js:
--------------------------------------------------------------------------------
1 |
2 | const getTime = (date) =>
3 | new Date(date).toTimeString().split(' ')[0]
4 |
5 | export {
6 | getTime
7 | }
--------------------------------------------------------------------------------
/utils/helpers/toFixedIfNecessary.js:
--------------------------------------------------------------------------------
1 | const toFixedIfNecessary = (value) => {
2 | const decimalPrecision = 18
3 | let output = parseFloat(value).toFixed(decimalPrecision);
4 | output = output.replace(/\.?0+$/, "");
5 | return output;
6 | }
7 |
8 | export default toFixedIfNecessary
--------------------------------------------------------------------------------
/utils/helpers/utility.js:
--------------------------------------------------------------------------------
1 |
2 | const isServer = () => typeof window === 'undefined';
3 |
4 | const isEmpty = value => {
5 | return (
6 | value === undefined ||
7 | value === null ||
8 | (typeof value === 'object' && Object.keys(value).length === 0) ||
9 | (typeof value === 'string' && value.trim().length === 0)
10 | );
11 | };
12 |
13 | export {
14 | isServer,
15 | isEmpty
16 | }
--------------------------------------------------------------------------------
/utils/hocs/InitProvider/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo, useEffect } from 'react'
3 | import { useDispatch } from 'react-redux'
4 | import { useRouter } from 'next/router'
5 |
6 | import {
7 | setAccountRS,
8 | setCurrentUser,
9 | setIsWallet,
10 | } from 'actions/auth'
11 | import scrollToTop from 'utils/helpers/scrollToTop'
12 | import { PAGE_ROUTES } from 'utils/constants/routes'
13 | import LINKS from 'utils/constants/links'
14 | import { isServer } from 'utils/helpers/utility'
15 |
16 | const InitProvider = () => {
17 | const dispatch = useDispatch();
18 | const router = useRouter();
19 |
20 | useEffect(() => {
21 | const accountRS = isServer() ? '' : localStorage.accountRS;
22 | const currentUser = isServer() ? null : localStorage.currentUser;
23 | const isWallet = isServer() ? null : localStorage.isWallet;
24 |
25 | if (!!accountRS) {
26 | dispatch(setAccountRS(accountRS))
27 | }
28 |
29 | if (!!currentUser) {
30 | dispatch(setCurrentUser(JSON.parse(currentUser)))
31 | }
32 |
33 | if (!!isWallet) {
34 | dispatch(setIsWallet(isWallet === 'true'))
35 | }
36 | }, [dispatch])
37 |
38 | useEffect(() => {
39 | const accountRS = isServer() ? '' : localStorage.accountRS;
40 |
41 | if (!accountRS) {
42 | if (PAGE_ROUTES.includes(router.pathname)) {
43 | router.push(LINKS.HOME.HREF)
44 | }
45 | }
46 |
47 | scrollToTop()
48 | // eslint-disable-next-line react-hooks/exhaustive-deps
49 | }, [router])
50 |
51 | return
52 | };
53 |
54 | export default memo(InitProvider);
--------------------------------------------------------------------------------
/utils/hocs/PopUpProvider/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 |
4 | import MagicConfirmDialog from 'parts/MagicConfirmDialog'
5 | import usePopUp from 'utils/hooks/usePopUp'
6 |
7 | const PopUpProvider = () => {
8 | const { popUpInfo, closePopUpHandler } = usePopUp();
9 |
10 | return (
11 |
19 | )
20 | };
21 |
22 | export default memo(PopUpProvider);
23 |
--------------------------------------------------------------------------------
/utils/hocs/ThemeProvider/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { memo } from 'react'
3 | import { ThemeProvider as MuiThemeProvider } from '@material-ui/core/styles'
4 |
5 | import { useDarkMode } from 'contexts/ui-context'
6 | import { lightTheme, darkTheme } from 'styles/theme'
7 |
8 | const ThemeProvider = ({
9 | children
10 | }) => {
11 | const { darkMode } = useDarkMode();
12 | const theme = darkMode ? darkTheme : lightTheme;
13 |
14 | return (
15 |
16 | {children}
17 |
18 | );
19 | };
20 |
21 | export default memo(ThemeProvider);
22 |
--------------------------------------------------------------------------------
/utils/hooks/useAuth.js:
--------------------------------------------------------------------------------
1 |
2 | import { useCallback } from 'react'
3 | import { useSelector, useDispatch } from 'react-redux'
4 |
5 | import { logoutUser, setUserToken } from 'actions/auth'
6 |
7 | const useAuth = () => {
8 | const dispatch = useDispatch();
9 | const { accountRS = '', isWallet } = useSelector(state => state.auth);
10 |
11 | const logOutHandler = useCallback(() => {
12 | dispatch(logoutUser());
13 | }, [dispatch]);
14 |
15 | const setLoginToken = useCallback(({ accountRS, user, isWallet = false }) => {
16 | dispatch(setUserToken({ accountRS, user, isWallet }));
17 | }, [dispatch]);
18 |
19 | return {
20 | isLoggedIn: !!accountRS,
21 | accountRS,
22 | isWallet,
23 | logOutHandler,
24 | setLoginToken
25 | }
26 | };
27 |
28 | export default useAuth;
--------------------------------------------------------------------------------
/utils/hooks/useLoading.js:
--------------------------------------------------------------------------------
1 |
2 | import { useCallback } from 'react'
3 | import { useDispatch } from 'react-redux'
4 |
5 | import setLoadingStatus from 'actions/loading'
6 |
7 | const useLoading = () => {
8 | const dispatch = useDispatch();
9 |
10 | const changeLoadingStatus = useCallback((loading) => {
11 | dispatch(setLoadingStatus(loading))
12 | }, [dispatch])
13 |
14 | return {
15 | changeLoadingStatus
16 | }
17 | };
18 |
19 | export default useLoading;
--------------------------------------------------------------------------------
/utils/hooks/useMenu.js:
--------------------------------------------------------------------------------
1 |
2 | import { useCallback, useMemo } from 'react'
3 | import { useRouter } from 'next/router'
4 |
5 | import useAuth from 'utils/hooks/useAuth'
6 | import {
7 | SIGN_IN_MENU_LINKS,
8 | SIGN_OFF_MENU_LINKS
9 | } from 'utils/constants/top-bar-menu'
10 | import LINKS from 'utils/constants/links'
11 |
12 | const useMenu = () => {
13 | const router = useRouter();
14 | const { isLoggedIn, logOutHandler } = useAuth();
15 |
16 | const PROFILE_MENU_LINKS = useMemo(() =>
17 | isLoggedIn
18 | ? SIGN_IN_MENU_LINKS
19 | : SIGN_OFF_MENU_LINKS
20 | , [isLoggedIn]);
21 |
22 | const onMenuHandler = useCallback((item) => {
23 | switch (item.TITLE) {
24 | case LINKS.SIGN_OUT.TITLE:
25 | logOutHandler();
26 | return;
27 | default:
28 | if (router.pathname !== item.HREF) {
29 | router.push(item.HREF);
30 | }
31 | }
32 | }, [logOutHandler, router]);
33 |
34 | return {
35 | PROFILE_MENU_LINKS,
36 | onMenuHandler
37 | }
38 | };
39 |
40 | export default useMenu;
--------------------------------------------------------------------------------
/utils/hooks/usePopUp.js:
--------------------------------------------------------------------------------
1 | import { useCallback } from 'react'
2 | import { useDispatch, useSelector } from 'react-redux'
3 |
4 | import {
5 | setPopUpInfo,
6 | openPopUp,
7 | closePopUp
8 | } from 'actions/popUp'
9 |
10 | const usePopUp = () => {
11 | const dispatch = useDispatch()
12 | const popUpInfo = useSelector(state => state.popUp)
13 |
14 | const setPopUp = useCallback((data) => {
15 | dispatch(setPopUpInfo(data))
16 | }, [dispatch])
17 |
18 | const openPopUpHandler = useCallback(() => {
19 | dispatch(openPopUp())
20 | }, [dispatch])
21 |
22 | const closePopUpHandler = useCallback(() => {
23 | dispatch(closePopUp())
24 | }, [dispatch])
25 |
26 | return {
27 | popUpInfo,
28 | setPopUp,
29 | openPopUpHandler,
30 | closePopUpHandler
31 | }
32 | }
33 |
34 | export default usePopUp
35 |
--------------------------------------------------------------------------------