├── .env.local.example
├── .gitignore
├── .storybook
├── main.js
└── preview.js
├── .vscode
└── settings.json
├── README.md
├── TODO
├── components
├── airdropBanner
│ ├── airdrop.module.css
│ └── index.tsx
├── anchor
│ └── index.tsx
├── artistCard
│ └── ArtistCard.tsx
├── button
│ └── index.tsx
├── button2
│ └── index.tsx
├── button3
│ └── index.tsx
├── button4
│ └── index.tsx
├── buyOutCard
│ └── index.tsx
├── chainWarning
│ └── index.tsx
├── dropdown
│ └── index.tsx
├── footer
│ └── index.tsx
├── fraktalButton
│ └── index.tsx
├── fraktionOwners
│ └── index.tsx
├── fraktionsDetail
│ └── index.tsx
├── fraktionsList
│ └── index.tsx
├── header
│ └── index.tsx
├── icon
│ ├── DiscordIcon.tsx
│ ├── InstagramIcon.tsx
│ ├── MediumIcon.tsx
│ ├── TwitterIcon.tsx
│ └── YoutubeIcon.tsx
├── infiniteScrollNft
│ └── index.tsx
├── layout
│ └── index.tsx
├── limitedInput
│ └── index.tsx
├── listCard
│ └── index.tsx
├── listCardAuction
│ └── index.tsx
├── load-screens
│ ├── index.tsx
│ └── loaders.module.css
├── media
│ └── index.tsx
├── modal
│ └── index.tsx
├── newNFTHeader
│ └── index.tsx
├── nft-auction-item
│ └── index.tsx
├── nft-importcard-opensea
│ └── index.tsx
├── nft-item-manager
│ └── index.tsx
├── nft-item-opensea
│ └── index.tsx
├── nft-item
│ └── index.tsx
├── nftCard
│ └── index.tsx
├── offerDetail
│ └── index.tsx
├── pagination
│ └── index.tsx
├── rescueCard
│ └── index.tsx
├── revenuesDetail
│ └── index.tsx
├── revenuesList
│ └── index.tsx
├── search
│ ├── index.tsx
│ └── styles.css
├── tabsCard
│ ├── index.tsx
│ └── tabsCard.module.css
├── useENSAddress.ts
├── userOwnership
│ └── index.tsx
└── verifyNFT
│ └── index.tsx
├── constants
└── routes.ts
├── contexts
├── NFTIsMintingContext.tsx
├── Web3Context.tsx
├── dataContext.tsx
└── userContext.tsx
├── default.js
├── hooks
├── externalContractLoader.js
├── useLoadingScreen.ts
└── useMarketplace.ts
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── pages
├── 404.tsx
├── _app.tsx
├── api
│ └── hello.ts
├── artist
│ ├── [...slug].tsx
│ └── artist.module.css
├── artists.tsx
├── claim-bonus.tsx
├── claim.tsx
├── explore.tsx
├── import-nft.tsx
├── import-nft
│ └── [...slug].tsx
├── import-nfts.tsx
├── index.tsx
├── list-nft.tsx
├── mint-nft.tsx
├── mintPage.tsx
├── my-nfts.tsx
├── nft
│ └── [id]
│ │ ├── auction.module.css
│ │ ├── auction.tsx
│ │ ├── closed.module.css
│ │ ├── closed.tsx
│ │ ├── details.tsx
│ │ ├── fix-price-sale.tsx
│ │ ├── list-item.tsx
│ │ ├── manage.module.css
│ │ └── manage.tsx
└── rewards.tsx
├── public
├── close.svg
├── doge.svg
├── eth.png
├── eth.svg
├── favicon.ico
├── filler-image-1.png
├── filler-image-2.png
├── footer
│ ├── discord.svg
│ ├── icons8-discord.svg
│ ├── icons8-instagram.svg
│ ├── icons8-medium.svg
│ ├── icons8-twitter.svg
│ ├── medium.svg
│ └── twitter.svg
├── fraktal-full-logo.png
├── images
│ ├── 404_OhFrak.png
│ └── Logo.png
├── info.svg
├── logo-wide.svg
├── logo.svg
├── nft-loading-card.svg
├── outlinedClose.png
├── sample-item.png
├── search.svg
├── timer.png
└── trash.svg
├── redux
├── actions
│ └── contractActions.ts
├── reducers
│ ├── index.ts
│ └── loadingScreenReducer.ts
└── store.ts
├── stories
├── Button.stories.tsx
├── Button.tsx
├── Header.stories.tsx
├── Header.tsx
├── Introduction.stories.mdx
├── NFTDetailRevenue.stories.tsx
├── NFTDetails.tsx
├── Page.stories.tsx
├── Page.tsx
├── assets
│ ├── code-brackets.svg
│ ├── colors.svg
│ ├── comments.svg
│ ├── direction.svg
│ ├── flow.svg
│ ├── plugin.svg
│ ├── repo.svg
│ └── stackalt.svg
├── button.css
├── header.css
└── page.css
├── styles
├── artists.module.css
├── fonts.css
├── globals.css
├── landing.module.css
├── mint-nft.module.css
├── my-nfts.module.css
└── rewards.module.css
├── testnetfraktalauction
├── .gitignore
├── abis
│ ├── Contract.json
│ └── Factory.json
├── build
│ ├── Contract
│ │ ├── Contract.wasm
│ │ └── abis
│ │ │ └── Contract.json
│ ├── Factory
│ │ └── abis
│ │ │ └── Factory.json
│ ├── schema.graphql
│ ├── subgraph.yaml
│ └── templates
│ │ └── Factory
│ │ └── Factory.wasm
├── generated
│ ├── Contract
│ │ └── Contract.ts
│ ├── schema.ts
│ ├── templates.ts
│ └── templates
│ │ └── Factory
│ │ └── Factory.ts
├── package.json
├── schema.graphql
├── src
│ ├── mapping.ts
│ └── mappings
│ │ └── factory.ts
├── subgraph.yaml
├── tsconfig.json
└── yarn.lock
├── tsconfig.json
├── types.ts
├── types
└── workflow.ts
├── utils
├── alchemy.ts
├── constants.ts
├── contractCalls.ts
├── format.ts
├── graphQueries.js
├── helpers.ts
├── math.ts
├── merkleTreeProofs.json
├── merkleTreeProofsV2.json
├── nftHelpers.js
├── openSeaAPI.ts
├── pinataPinner.js
├── proofsGetter.js
├── search.ts
└── stores
│ ├── ensStore.ts
│ └── queries
│ └── getQueryENSForETHAddress.ts
└── yarn.lock
/.env.local.example:
--------------------------------------------------------------------------------
1 | NEXT_PUBLIC_INFURA_ID=""
2 | NEXT_PUBLIC_INFURA_PROJECT_ID=""
3 | NEXT_PUBLIC_INFURA_PROJECT_SECRET=""
4 | NEXT_PUBLIC_RINKEBY_MARKET_CONTRACT=""
5 | NEXT_PUBLIC_RINKEBY_FACTORY_CONTRACT=""
6 | NEXT_PUBLIC_GRAPHQL_URL=""
7 | NEXT_PUBLIC_NETWORK_CHAIN_ID=4
8 | NEXT_PUBLIC_PINATA_API_KEY=""
9 | NEXT_PUBLIC_PINATA_API_SECRET=""
10 | NEXT_PUBLIC_ALCHEMY_API_KEY=
--------------------------------------------------------------------------------
/.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 | .idea
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env
30 | .env.local
31 | .env.development.local
32 | .env.test.local
33 | .env.production.local
34 |
35 | # vercel
36 | .vercel
37 |
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "stories": [
3 | "../stories/**/*.stories.mdx",
4 | "../stories/**/*.stories.@(js|jsx|ts|tsx)"
5 | ],
6 | "addons": [
7 | "@storybook/addon-links",
8 | "@storybook/addon-essentials"
9 | ]
10 | }
--------------------------------------------------------------------------------
/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | export const parameters = {
2 | actions: { argTypesRegex: "^on[A-Z].*" },
3 | controls: {
4 | matchers: {
5 | color: /(background|color)$/i,
6 | date: /Date$/,
7 | },
8 | },
9 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "prettier.arrowParens": "avoid",
3 | "prettier.singleQuote": false,
4 | "prettier.bracketSpacing": true,
5 | "prettier.tabWidth": 2
6 | }
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | ```
12 |
13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14 |
15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
16 |
17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
18 |
19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
20 |
21 | ## Learn More
22 |
23 | To learn more about Next.js, take a look at the following resources:
24 |
25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
27 |
28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
29 |
30 | ## Deploy on Vercel
31 |
32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
33 |
34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
35 |
--------------------------------------------------------------------------------
/TODO:
--------------------------------------------------------------------------------
1 | TODO::
2 | --------------------------------------------------------------------------------
3 |
4 | BUGS:
5 |
6 |
7 |
8 | CONTRACTS:
9 | ------------------------------------------------------------------------------------------------
10 | - User can unlock and keep voting, but result is taken from total locked attribute
11 | - Opensea assets in rinkeby have id > uint256 !! they fail on import (overflow)
12 |
13 | AUDITORY:
14 | ------------------------------------------------------------------------------------------------
15 | REMEMBER CHECK EFFECT INTERACTIONS PATTERN :D
16 | FraktalMarket:
17 | - Replace transfer() for AddressUpgradeable.sendValue() in:
18 | -withdrawAccruedFees()
19 | -rescueEth()
20 | -makeOffer()
21 | -createRevenuePayment()
22 |
23 | - setMajority() does not check max value (10000 = 100%)
24 | - setFee() does not check max value (10000 = 100%)
25 | - setFee() uses >= 0 for a uint16 (never negative)
26 |
27 | FraktalMarket, FraktalNFT, PaymentSplitterUpgradeable > check only externally called functions.
28 | -external> public visibility
29 |
30 | This is just a formal revision of patterns. Not an analysis of the program.
31 |
32 | UI
33 | ------------------------------------------------------------------------------------------------
34 | - Opensea API is veery slow to detect transfers
35 | - There is no tx handler (besides metamask)
36 | - Incorrect networks does not work very well, does not detect network change (add listener)
37 | - Does detect account change.. but is buggy..
38 |
39 | SUBGRAPH
40 | ------------------------------------------------------------------------------------------------
41 |
--------------------------------------------------------------------------------
/components/airdropBanner/airdrop.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | width: 964px;
3 | height: 80px;
4 | background: #FFFFFF;
5 | border: 1px solid #C387FF;
6 | box-sizing: border-box;
7 | box-shadow: 0px 1px 4px rgba(64, 84, 102, 0.04), 0px 4px 12px rgba(64, 84, 102, 0.08);
8 | border-radius: 4px;
9 | }
10 | .container div {
11 |
12 | }
13 | .airdropTitle {
14 | font-style: normal;
15 | font-weight: 600;
16 | font-size: 16px;
17 | line-height: 24px;
18 | }
19 | .subtitle {
20 | font-size:14px;
21 | line-height: 20px;
22 | }
23 | .airdropButton {
24 | font-size: 14px;
25 | width: 160px;
26 | height: 40px;
27 | background: #985CFF;
28 | border-radius: 24px;
29 | align-items: center;
30 | padding: 12px 24px;
31 | }
--------------------------------------------------------------------------------
/components/airdropBanner/index.tsx:
--------------------------------------------------------------------------------
1 | import {Box, Button, Spacer, Flex, Stack, HStack, VStack, Text} from "@chakra-ui/react";
2 | import styles from "./airdrop.module.css";
3 |
4 | /**
5 | * Airdrop Banner
6 | * @param {any} title
7 | * @param {any} subtitle
8 | * @param {any} onClick
9 | * @param {any} buttonText
10 | * @param {any} icon
11 | * @returns {any}
12 | * @constructor
13 | */
14 | const AirdropBanner = ({title, subtitle = '', onClick, buttonText, icon}) => {
15 |
16 | return (
17 |
18 |
19 |
20 | {icon}
21 |
22 |
23 |
24 | {title}
25 |
26 | {subtitle && (
27 |
28 | {subtitle}
29 |
30 | )}
31 |
32 |
33 |
34 | {buttonText}
42 |
43 |
44 |
45 | );
46 | };
47 |
48 | export default AirdropBanner;
--------------------------------------------------------------------------------
/components/anchor/index.tsx:
--------------------------------------------------------------------------------
1 | import NextLink from "next/link";
2 | const Anchor = ({ href, passHref, target, children }) => {
3 | return (
4 |
5 |
6 | {children}
7 |
8 |
9 | )
10 | };
11 | export default Anchor;
--------------------------------------------------------------------------------
/components/artistCard/ArtistCard.tsx:
--------------------------------------------------------------------------------
1 | import { Box } from "@chakra-ui/react";
2 |
3 | export default function ArtistCard(props) {
4 | return (
5 | <>
6 |
22 | >
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/components/button/index.tsx:
--------------------------------------------------------------------------------
1 | import { Button, ButtonProps } from "@chakra-ui/button";
2 | import { forwardRef } from "react";
3 |
4 | const FrakButton = forwardRef<
5 | HTMLButtonElement,
6 | ButtonProps & { isOutlined?: boolean }
7 | >(({ isOutlined, children, ...rest }, ref) => {
8 | return (
9 |
24 | {children}
25 |
26 | );
27 | });
28 |
29 | export default FrakButton;
30 |
--------------------------------------------------------------------------------
/components/button2/index.tsx:
--------------------------------------------------------------------------------
1 | import { Button, ButtonProps } from '@chakra-ui/button';
2 | import { Input, Text } from '@chakra-ui/react';
3 | import { forwardRef } from 'react';
4 |
5 | const FrakButton2 = forwardRef<
6 | HTMLButtonElement,
7 | ButtonProps & {
8 | isReady?: boolean;
9 | setFunction: Function;
10 | inputPlaceholder: string;
11 | currency: string;
12 | }
13 | >(
14 | ({
15 | isReady,
16 | onClick,
17 | setFunction,
18 | inputPlaceholder,
19 | currency,
20 | children,
21 | ...rest
22 | }) => {
23 | return (
24 |
35 |
setFunction(d.target.value)}
37 | placeholder={inputPlaceholder ? inputPlaceholder : null}
38 | _focus={{ outline: 'none' }}
39 | style={{
40 | textAlign: 'right',
41 | color: '#000000',
42 | fontWeight: 500,
43 | fontSize: '20px',
44 | outline: `none`,
45 | border: `none`,
46 | borderRadius: `15px 0px 0px 15px`,
47 | height: `38px`,
48 | minWidth: '20%',
49 | marginRight: `0px`,
50 | }}
51 | />
52 |
53 |
67 | {currency ? currency : null}
68 |
69 |
70 |
97 | {children}
98 |
99 |
100 | );
101 | }
102 | );
103 |
104 | export default FrakButton2;
105 |
--------------------------------------------------------------------------------
/components/button3/index.tsx:
--------------------------------------------------------------------------------
1 | import { Button, ButtonProps } from '@chakra-ui/button';
2 | import { Input, Box, Text } from '@chakra-ui/react';
3 | import { forwardRef } from 'react';
4 |
5 | const FrakButton3 = forwardRef<
6 | HTMLButtonElement,
7 | ButtonProps & {
8 | isReady?: boolean;
9 | setFunction: Function;
10 | inputPlaceholder: string;
11 | }
12 | >(({ isReady, onClick, setFunction, inputPlaceholder, children, ...rest }) => {
13 | return (
14 |
26 |
27 | {inputPlaceholder}
28 |
29 | setFunction(d.target.value)}
34 | placeholder={inputPlaceholder ? inputPlaceholder : null}
35 | style={{
36 | display: 'none',
37 | textAlign: 'right',
38 | color: '#000000',
39 | fontWeight: 500,
40 | fontSize: '24px',
41 | outline: `none`,
42 | border: `1px solid transparent`,
43 | borderRadius: `15px 0px 0px 15px`,
44 | height: `40px`,
45 | marginRight: `134px`,
46 | }}
47 | />
48 |
73 | {children}
74 |
75 |
76 | );
77 | });
78 |
79 | export default FrakButton3;
80 |
--------------------------------------------------------------------------------
/components/button4/index.tsx:
--------------------------------------------------------------------------------
1 | import { Button, ButtonProps } from "@chakra-ui/button";
2 | import { forwardRef } from "react";
3 | const FrakButton4 = forwardRef<
4 | HTMLButtonElement,
5 | ButtonProps & { status?: string }
6 | >(({ status, children, ...rest }, ref) => {
7 | return (
8 |
27 | {children}
28 |
29 | );
30 | });
31 |
32 | export default FrakButton4;
33 |
--------------------------------------------------------------------------------
/components/chainWarning/index.tsx:
--------------------------------------------------------------------------------
1 | import { utils } from "ethers";
2 | import { Flex } from "@chakra-ui/layout";
3 |
4 | import {getNetworkName} from "@/utils/helpers";
5 |
6 | const ChainWarning: React.FC = () => {
7 |
8 | const switchChainOnMetaMask = async (): Promise => {
9 | try {
10 | await window.ethereum.request({
11 | method: "wallet_switchEthereumChain",
12 | params: [
13 | {
14 | chainId: utils.hexValue(parseInt(process.env.NEXT_PUBLIC_NETWORK_CHAIN_ID)),
15 | },
16 | ],
17 | });
18 | return true;
19 | } catch (switchError) {
20 | if (switchError.code === 4902) {
21 | console.error("error 4902");
22 | } else {
23 | console.error("Unable to switch to chain on metamask", switchError);
24 | }
25 | }
26 | return false;
27 | };
28 |
29 | return (
30 |
31 | switchChainOnMetaMask()}
43 | >
44 |
52 | Wrong network!
53 |
54 |
62 | Click here to switch to {getNetworkName(parseInt(process.env.NEXT_PUBLIC_NETWORK_CHAIN_ID))}.
63 |
64 |
65 |
66 | );
67 | };
68 |
69 | export default ChainWarning;
70 |
--------------------------------------------------------------------------------
/components/dropdown/index.tsx:
--------------------------------------------------------------------------------
1 | import { Box, StackProps, Text, VStack } from "@chakra-ui/layout";
2 | import React from "react";
3 |
4 | const Dropdown: React.FC<
5 | StackProps & {
6 | items: string[];
7 | onItemClick: (item: string, index: number) => void;
8 | }
9 | > = ({ items, onItemClick, ...rest }) => {
10 | return (
11 |
20 | {items.map((item, index) => (
21 |
33 | {item}
34 |
35 | ))}
36 |
37 | );
38 | };
39 |
40 | export default Dropdown;
41 |
--------------------------------------------------------------------------------
/components/footer/index.tsx:
--------------------------------------------------------------------------------
1 | import { Image } from "@chakra-ui/image";
2 | import { Text, Link, Container, Box } from "@chakra-ui/layout";
3 | import { Heading, Flex, Icon, List, ListItem } from "@chakra-ui/react";
4 | import TwitterIcon from "../icon/TwitterIcon";
5 | import InstagramIcon from "../icon/InstagramIcon";
6 | import DiscordIcon from "../icon/DiscordIcon";
7 | import MediumIcon from '../icon/MediumIcon';
8 | import YoutubeIcon from '../icon/YoutubeIcon';
9 |
10 | const urlLists = [
11 | {
12 | title: "Resources",
13 | items: [
14 | { text: "Blog", url: "https://blog.fraktal.io/" },
15 | { text: "Docs", url: "https://docs.fraktal.io/" },
16 | { text: "Audit", url: "https://github.com/FraktalNFT/audits" }
17 | ]
18 | },
19 | {
20 | title: "Get Involved",
21 | items: [
22 | { text: "Stake", url: "https://docs.fraktal.io/fraktal-governance-token-frak/staking-frak" },
23 | { text: "DAO", url: "https://dao.fraktal.io/#/" },
24 | { text: "Github", url: "https://github.com/FraktalNFT" },
25 | ]
26 | },
27 | {
28 | title: "Need Help?",
29 | items: [
30 | { text: "How it Works", url: "https://docs.fraktal.io/marketplace/get-started" },
31 | { text: "Tutorials", url: "https://www.youtube.com/channel/UCUpcKyPeUJ2Mhx7OWOSZL6w" },
32 | { text: "Support", url: "https://discord.com/invite/P6fCPvtZtq" }
33 | ]
34 | }
35 | ]
36 |
37 | const socials = [
38 | { url: "https://twitter.com/fraktalnft", icon: TwitterIcon },
39 | { url: "https://www.instagram.com/fraktal.io/", icon: InstagramIcon },
40 | { url: "https://discord.com/invite/P6fCPvtZtq", icon: DiscordIcon },
41 | { url: "https://www.youtube.com/channel/UCUpcKyPeUJ2Mhx7OWOSZL6w", icon: YoutubeIcon },
42 | { url: "https://blog.fraktal.io/", icon: MediumIcon },
43 | ]
44 |
45 | const Footer: React.FC = () => {
46 | return (
47 |
51 |
52 |
53 |
54 |
55 | Fraktal is a community first project, with a mission to to empower
56 | artists to be in full control of their work and have unlimited
57 | creative freedom.
58 |
59 |
60 |
61 |
62 | {socials.map(({url, icon}, idx) => (
63 |
64 |
65 |
66 | ))}
67 |
68 |
69 |
70 | © Fraktal Technologies Ltd.
71 |
72 |
73 |
74 |
75 | {urlLists.map(({title, items}, idx) => (
76 |
77 | {title}
78 |
79 | {items.map(({url, text}, lidx) => (
80 |
81 |
88 | {text}
89 |
90 |
91 | ))}
92 |
93 |
94 | ))}
95 |
96 |
97 | );
98 | };
99 |
100 | export default Footer;
101 |
--------------------------------------------------------------------------------
/components/fraktalButton/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * React
3 | */
4 | import { forwardRef, useState } from 'react';
5 | /**
6 | * ChakraUI
7 | */
8 | import { Button, ButtonProps } from '@chakra-ui/button';
9 |
10 | const FraktalButton = forwardRef<
11 | HTMLButtonElement,
12 | ButtonProps & {
13 | isReady?: boolean;
14 | }
15 | >(
16 | ({
17 | isReady, onClick, children, ...rest
18 | }) => {
19 |
20 | return (
21 | <>
22 |
49 | {children}
50 |
51 | >
52 | );
53 | }
54 | );
55 |
56 | export default FraktalButton;
57 |
--------------------------------------------------------------------------------
/components/fraktionOwners/index.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Box,
3 | Center,
4 | StackProps,
5 | Text,
6 | VStack,
7 | HStack,
8 | Stack,
9 | } from "@chakra-ui/layout";
10 | import React, { forwardRef, useState, useEffect } from "react";
11 | import { createRevenuePayment } from "../../utils/contractCalls";
12 | import RevenuesDetail from "../revenuesDetail";
13 | import FrakButton2 from "../button2";
14 | import { utils } from "ethers";
15 | import { getSubgraphData } from "../../utils/graphQueries";
16 | import {getExplorerUrl} from "@/utils/helpers";
17 |
18 | // if account has fraktions.. display info to list?
19 |
20 | export default function FraktionOwners(props) {
21 | const [internalData, setInternalData] = useState({});
22 | let nftObject = props.nftObject;
23 |
24 | // const [owners, setOwners] = useState([]);
25 |
26 | useEffect(() => {
27 | async function getOwners(id) {
28 | let filteredData = props.data.filter(x=>{return x.owner && x.owner.id && x.amount > 0})
29 | setInternalData(filteredData);
30 | }
31 | if (nftObject.id) {
32 | getOwners(nftObject.id);
33 | }
34 | }, [nftObject, props]);
35 |
36 | return (
37 |
46 |
47 |
56 | NFT Owners
57 |
58 |
59 |
60 |
61 |
69 | Address
70 |
71 |
80 | Ownership
81 |
82 |
83 | {internalData && internalData.length && internalData.map(
84 | (user: object, index: number) => {
85 | let first4 = user.owner.id.substring(0, 6); // (0x + 4 digits)
86 | let last4 = user.owner.id.substring(
87 | user.owner.id.length - 4,
88 | user.owner.id.length
89 | );
90 | let shortAddress = `${first4}...${last4}`;
91 | let ownedAmount = utils.parseUnits(user.amount,"wei");//in fei
92 | let percentOwned = "";
93 | if(ownedAmount < utils.parseEther("1.0")){
94 | percentOwned = "<0.01"
95 | }else{
96 | percentOwned = utils.formatEther(ownedAmount.div(100));
97 | }
98 | // let percentOwned = (parseInt(user.amount) / 10000) * 100;
99 | return (
100 |
109 |
113 |
114 | {shortAddress}
115 |
116 |
117 | {percentOwned}%
118 |
119 | );
120 | }
121 | )}
122 |
123 |
124 |
125 | );
126 | }
127 |
--------------------------------------------------------------------------------
/components/fraktionsList/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * React
3 | */
4 | import React, {useEffect, useState} from "react";
5 |
6 | import FraktionsDetail from '../fraktionsDetail';
7 |
8 | import VerifyNFT from "@/components/verifyNFT";
9 | // if account has fraktions.. display info to list?
10 |
11 | const FraktionsList=(({nftObject, fraktionsListed, tokenAddress, marketAddress, provider}) => {
12 |
13 | return(
14 | <>
15 |
23 |
32 | Fraktions
33 |
34 |
35 | {fraktionsListed && fraktionsListed.length ?
36 |
37 | {fraktionsListed.map(x=>{
38 | return(
39 |
48 | )
49 | })}
50 |
51 | :
52 |
53 | There are no listed Fraktions of this NFT.
54 |
55 | }
56 |
57 | >
58 | )
59 |
60 | })
61 |
62 |
63 | export default FraktionsList;
64 |
--------------------------------------------------------------------------------
/components/header/index.tsx:
--------------------------------------------------------------------------------
1 | import { Box, Flex, HStack, Image, Link } from "@chakra-ui/react";
2 | import NextLink from "next/link";
3 | import FrakButton from "../button";
4 | import { useWeb3Context } from "../../contexts/Web3Context";
5 | import { shortenHash } from "../../utils/helpers";
6 | import { useRouter } from "next/router";
7 | import {ARTISTS, CREATE_NFT, EXPLORE, LANDING, IMPORT_NFTS, REWARDS, CLAIM, CLAIM_BONUS} from "@/constants/routes";
8 |
9 | const Header = () => {
10 | const router = useRouter();
11 | const { connectWeb3, account } = useWeb3Context();
12 |
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
30 |
31 | {router.pathname === EXPLORE ? (
32 |
39 | Explore
40 |
41 | ) : (
42 |
48 | Explore
49 |
50 | )}
51 |
52 |
53 | {router.pathname === CREATE_NFT ||
54 | router.pathname === IMPORT_NFTS ? (
55 |
62 | List NFT
63 |
64 | ) : (
65 |
71 | List NFT
72 |
73 | )}
74 |
75 |
76 | {router.pathname === REWARDS ? (
77 |
84 | Rewards
85 |
86 | ) : (
87 |
93 | Rewards
94 |
95 | )}
96 |
97 |
98 | {/*
106 | How it Works
107 | */}
108 |
109 |
110 | {!account ? (
111 | Connect Wallet
112 | ) : (
113 |
114 |
124 | {shortenHash(account)} | View my NFTs
125 |
126 |
127 | )}
128 |
129 |
130 |
131 | );
132 | };
133 |
134 | export default Header;
135 |
--------------------------------------------------------------------------------
/components/icon/DiscordIcon.tsx:
--------------------------------------------------------------------------------
1 | import { Icon } from '@chakra-ui/react'
2 |
3 | const DiscordIcon: React.FC = (props) => (
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | )
15 |
16 | export default DiscordIcon
--------------------------------------------------------------------------------
/components/icon/MediumIcon.tsx:
--------------------------------------------------------------------------------
1 | import { Icon } from '@chakra-ui/react'
2 |
3 | const MediumIcon: React.FC = (props) => (
4 |
5 |
6 |
7 |
8 |
9 | )
10 |
11 | export default MediumIcon
--------------------------------------------------------------------------------
/components/icon/TwitterIcon.tsx:
--------------------------------------------------------------------------------
1 | import { Icon } from '@chakra-ui/react'
2 |
3 | const TwitterIcon: React.FC = (props) => (
4 |
5 |
7 |
8 |
9 |
10 |
12 |
13 | )
14 |
15 | export default TwitterIcon;
--------------------------------------------------------------------------------
/components/icon/YoutubeIcon.tsx:
--------------------------------------------------------------------------------
1 | import { Icon } from '@chakra-ui/react'
2 |
3 | const YoutubeIcon: React.FC = (props) => (
4 |
5 |
6 |
7 |
8 |
9 |
10 | )
11 |
12 | export default YoutubeIcon
--------------------------------------------------------------------------------
/components/infiniteScrollNft/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * React
3 | */
4 | import { useState, useEffect} from "react";
5 | /**
6 | * Chakra UI
7 | */
8 | import {Box, Grid, Spinner} from "@chakra-ui/react";
9 | /**
10 | * Components
11 | */
12 | import InfiniteScroll from "react-infinite-scroll-component";
13 | import NFTImportCardOS from "@/components/nft-importcard-opensea";
14 |
15 | /**
16 | * InfiniteScrollNft
17 | * @param nftItems
18 | * @constructor
19 | */
20 | const InfiniteScrollNft = ({getData, nftItems, setTokenToImport, hasMore, setImportingNFT}) => {
21 |
22 |
23 | return (
24 | }
29 | scrollThreshold={0.5}
30 | endMessage={Nothing more to show }
31 | >
32 |
39 | {nftItems.map((item, index) => (
40 | {
44 | setTokenToImport(item);
45 | setImportingNFT(true);
46 | }}
47 | />
48 | ))}
49 |
50 |
51 | );
52 | }
53 |
54 | const Loading = () => {
55 | return (
63 |
64 | )
65 | };
66 |
67 | export {Loading};
68 | export default InfiniteScrollNft;
--------------------------------------------------------------------------------
/components/limitedInput/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * React
3 | */
4 | import { forwardRef, useState } from 'react';
5 | /**
6 | * ChakraUI
7 | */
8 | import {
9 | NumberInput,
10 | NumberInputField,
11 | Text
12 | } from '@chakra-ui/react';
13 | import { ButtonProps } from '@chakra-ui/button';
14 | /**
15 | * Components
16 | */
17 | import FraktalButton from "@/components/fraktalButton";
18 |
19 | /**
20 | * LimitedInput Component
21 | */
22 | const LimitedInput = forwardRef<
23 | HTMLButtonElement,
24 | ButtonProps & {
25 | isReady?: boolean;
26 | setFunction: Function;
27 | inputPlaceholder: string;
28 | currency: string;
29 | maxFraktions: string;
30 | }>(
31 | ({
32 | isReady,
33 | onClick,
34 | setFunction,
35 | inputPlaceholder,
36 | currency,
37 | children,
38 | maxFraktions,
39 | ...rest
40 | }) => {
41 |
42 | const [color, setColor] = useState("#000");
43 |
44 | return (
45 |
56 |
{
65 | setFunction(num);
66 | (parseInt(num) > parseInt(maxFraktions)) ? setColor("#ff0000") : setColor("#000");
67 | }}
68 | >
69 |
78 |
79 |
80 |
94 | {currency ? currency : null}
95 |
96 |
97 |
102 | {children}
103 |
104 |
105 | );
106 | }
107 | );
108 |
109 | export default LimitedInput;
110 |
--------------------------------------------------------------------------------
/components/listCard/index.tsx:
--------------------------------------------------------------------------------
1 | import { formatEtherPrice } from '@/utils/format';
2 | import { HStack, VStack } from '@chakra-ui/layout';
3 | import {
4 | NumberInput,
5 | NumberInputField,
6 | NumberInputStepper,
7 | NumberIncrementStepper,
8 | NumberDecrementStepper,
9 | } from '@chakra-ui/react';
10 | import { BigNumber, utils } from 'ethers';
11 |
12 | const ListCard = ({
13 | totalPrice,
14 | setTotalPrice,
15 | totalAmount,
16 | setTotalAmount,
17 | listingProcess,
18 | maxFraktions,
19 | }) => {
20 | const wei = totalPrice > 0 && utils.parseEther(totalPrice.toString());
21 | const fei = totalAmount > 0 && utils.parseEther(totalAmount.toString());
22 | const pricePerFraktion =
23 | totalPrice > 0 && totalAmount > 0
24 | ? wei.mul(utils.parseEther('1.0')).div(fei)
25 | : 0;
26 | return (
27 |
28 |
29 |
38 | TOTAL PRICE
39 |
40 | {
43 | setTotalPrice(e.target.value);
44 | }}
45 | type="number"
46 | style={{
47 | margin: '8px',
48 | border: '2px solid #E0E0E0',
49 | padding: '14.5px 16px',
50 | background: '#FFFFFF',
51 | borderRadius: '16px',
52 | }}
53 | >
54 |
63 | Per Fraktion:{' '}
64 | {pricePerFraktion ? formatEtherPrice(pricePerFraktion) : null} ETH
65 |
66 |
67 |
68 |
77 | TOTAL AMOUNT
78 |
79 | {
88 | setTotalAmount(num);
89 | }}
90 | >
91 |
101 |
102 |
103 |
104 |
105 |
106 |
115 | Of {maxFraktions} Fraktions
116 |
117 |
118 |
119 | );
120 | };
121 |
122 | export default ListCard;
123 |
--------------------------------------------------------------------------------
/components/listCardAuction/index.tsx:
--------------------------------------------------------------------------------
1 | import { formatEtherPrice } from '@/utils/format';
2 | import { HStack, VStack } from '@chakra-ui/layout';
3 | import {
4 | NumberInput,
5 | NumberInputField,
6 | NumberInputStepper,
7 | NumberIncrementStepper,
8 | NumberDecrementStepper,
9 | } from '@chakra-ui/react';
10 | import { utils } from 'ethers';
11 |
12 | const ListCardAuction = ({
13 | totalPrice,
14 | setTotalPrice,
15 | totalAmount,
16 | setTotalAmount,
17 | listingProcess,
18 | maxFraktions,
19 | }) => {
20 | const wei = totalPrice > 0 && utils.parseEther(totalPrice.toString());
21 | const fei = totalAmount > 0 && utils.parseEther(totalAmount.toString());
22 | const pricePerFraktion =
23 | totalPrice > 0 && totalAmount > 0
24 | ? wei.mul(utils.parseEther('1.0')).div(fei)
25 | : 0;
26 | return (
27 |
28 |
29 |
38 | RESERVE PRICE
39 |
40 | {
43 | setTotalPrice(e.target.value);
44 | }}
45 | type="number"
46 | style={{
47 | margin: '8px',
48 | border: '2px solid #E0E0E0',
49 | padding: '14.5px 16px',
50 | background: '#FFFFFF',
51 | borderRadius: '16px',
52 | }}
53 | >
54 |
63 | Per Fraktion:{' '}
64 | {pricePerFraktion ? formatEtherPrice(pricePerFraktion) : null} ETH
65 |
66 |
67 |
68 |
77 | TOTAL AMOUNT
78 |
79 | {
88 | setTotalAmount(num);
89 | }}
90 | >
91 |
101 |
102 |
103 |
104 |
105 |
106 |
115 | Of {maxFraktions} Fraktions
116 |
117 |
118 |
119 | );
120 | };
121 |
122 | export default ListCardAuction;
123 |
--------------------------------------------------------------------------------
/components/load-screens/loaders.module.css:
--------------------------------------------------------------------------------
1 |
2 | .wrapper {
3 | display: flex;
4 | justify-content: center;
5 | align-items: center;
6 | }
7 |
8 | .checkmark {
9 | width: 60px;
10 | height: 60px;
11 | border-radius: 50%;
12 | display: block;
13 | stroke-width: 6;
14 | stroke-linecap: round;
15 | stroke-miterlimit: 10;
16 | margin: 10% auto;
17 | animation: fill .4s ease-in-out .4s forwards, scale .3s ease-in-out .9s both
18 | }
19 |
20 | .crossPathLeft {
21 | transform-origin: 50% 50%;
22 | stroke-dasharray: 48;
23 | stroke-dashoffset: 48;
24 | animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.5s forwards;
25 | }
26 | .crossPathRight {
27 | transform-origin: 50% 50%;
28 | stroke-dasharray: 48;
29 | stroke-dashoffset: 48;
30 | animation: stroke 0.5s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards;
31 | }
32 |
33 | .checkmarkCheck {
34 | transform-origin: 50% 50%;
35 | stroke-dasharray: 48;
36 | stroke-dashoffset: 48;
37 | animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards;
38 | }
39 |
40 | @keyframes stroke {
41 | 100% {
42 | stroke-dashoffset: 0
43 | }
44 | }
45 |
46 | @keyframes scale {
47 |
48 | 0%,
49 | 100% {
50 | transform: none
51 | }
52 |
53 | 50% {
54 | transform: scale3d(1, 1, 1)
55 | }
56 | }
57 |
58 | @keyframes fill {
59 | 100% {
60 | /* box-shadow: inset 0px 0px 0px 30px #7ac142*/
61 | }
62 | }
--------------------------------------------------------------------------------
/components/media/index.tsx:
--------------------------------------------------------------------------------
1 | import React, {useState, useEffect} from "react";
2 | import {Image} from "@chakra-ui/image";
3 | import {Box, Spinner} from "@chakra-ui/react";
4 |
5 | const NFTMedia = ({imageURL, setIsImageLoaded, type, metadata={}}) => {
6 |
7 | const [image, setImage] = useState('https://image.fraktal.io/?height=350&image=' + encodeURIComponent(imageURL));
8 | const [video, setVideo] = useState("");
9 |
10 | async function loadMedia() {
11 | try {
12 | const loadImage = await fetch(imageURL);
13 | if (loadImage.headers.get('content-type') == 'image/gif') {
14 | setImage(imageURL);
15 | }
16 | setIsImageLoaded(true);
17 | } catch (e) {
18 | //TODO - Add Error
19 | }
20 | }
21 |
22 | useEffect(() => {
23 | loadVideo();
24 | if (type == 'details') {
25 | loadMedia();
26 | }
27 | }, []);
28 |
29 | const onImageLoad = (ms: number) => {
30 | setIsImageLoaded(true);
31 | };
32 |
33 | const loadVideo = () => {
34 | if (!imageURL) {
35 | return null;
36 | }
37 | const fileExtension = imageURL.split('.').pop();
38 | if (fileExtension === 'mp4') {
39 | setVideo(imageURL);
40 | return true;
41 | }
42 | if (!metadata.metadata) {
43 | return false;
44 | }
45 | if (metadata.metadata.animation_url) {
46 | if (metadata.metadata.animation_url.startsWith('ipfs://')) {
47 | let hasIpfsProtocol = metadata.metadata.animation_url.split('ipfs://');
48 | setVideo('https://ipfs.io/ipfs/' + hasIpfsProtocol[1]);
49 | } else {
50 | setVideo(metadata.metadata.animation_url);
51 | }
52 | return true;
53 | }
54 | if (metadata.metadata.properties && metadata.metadata.properties.preview_media_file2 && metadata.metadata.properties.preview_media_file2_type.description == 'mp4') {
55 | setVideo(metadata.metadata.properties.preview_media_file2.description);
56 | return true;
57 | }
58 | };
59 |
60 | const isVideo = () => {
61 | if (video === "") {
62 | return false;
63 | }
64 | setIsImageLoaded(true);
65 | return true;
66 | };
67 |
68 | return (
69 | <>
70 | {isVideo() ? (
71 |
72 |
73 |
74 | ) : (
75 | onImageLoad(50)}
88 | />)
89 | }
90 |
91 | >
92 | )
93 | }
94 | export default NFTMedia;
--------------------------------------------------------------------------------
/components/modal/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactModal from "react-modal";
3 | import { Image } from "@chakra-ui/react";
4 |
5 | const customStyles = {
6 | content: {
7 | top: "50%",
8 | left: "50%",
9 | right: "auto",
10 | padding: 0,
11 | bottom: "auto",
12 | marginRight: "-50%",
13 | transform: "translate(-50%, -50%)",
14 | },
15 | };
16 |
17 | interface Props {
18 | open: boolean;
19 | onClose: () => void;
20 | onConfirm?: () => void;
21 | children: React.ReactNode;
22 | }
23 |
24 | typeof window !== "undefined" && ReactModal.setAppElement("#app");
25 |
26 | const Modal: React.FC = ({ open, onClose, children }) => {
27 | return (
28 |
29 |
30 |
38 | {children}
39 |
40 |
41 | );
42 | };
43 |
44 | export default Modal;
45 |
--------------------------------------------------------------------------------
/components/newNFTHeader/index.tsx:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * React
4 | */
5 | import { useEffect, useState } from 'react';
6 | import {useRouter} from "next/router";
7 | import {Box, Link, Text} from "@chakra-ui/react";
8 | import {CREATE_NFT, IMPORT_NFTS} from "@/constants/routes";
9 |
10 | /**
11 | * MyNFTWallet
12 | * @constructor
13 | */
14 | const NewNFTHeader = () => {
15 | const router = useRouter();
16 |
17 | // Show Loading State
18 | useEffect(() => {
19 |
20 | }, []);
21 |
22 | return (
23 | <>
24 |
25 | router.push(CREATE_NFT, null, { scroll: false })}
31 | >
32 | Mint NFT
33 |
34 | router.push(IMPORT_NFTS, null, { scroll: false })}
45 | >
46 | Import NFT
47 |
48 |
49 | >
50 | );
51 | }
52 |
53 | export default NewNFTHeader;
--------------------------------------------------------------------------------
/components/nft-importcard-opensea/index.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@chakra-ui/button";
2 | import { Image } from "@chakra-ui/image";
3 | import { Box, Center, StackProps, Text, VStack } from "@chakra-ui/layout";
4 | import { formatEther } from "@ethersproject/units";
5 | import React, { forwardRef } from "react";
6 | import { FrakCard } from "../../types";
7 | import FrakButton from "../button";
8 | import NextLink from "next/link";
9 | import {useState} from 'react';
10 | import { useWeb3Context } from '../../contexts/Web3Context';
11 | import {approveMarket, importERC721, importERC1155} from '../../utils/contractCalls';
12 | // import { claimNFT } from '../../utils/helpers';
13 |
14 | interface NFTItemProps extends StackProps {
15 | item: FrakCard;
16 | CTAText?: string;
17 | onCollateralRequest?: void;
18 | };
19 |
20 | const NFTImportCardOS = forwardRef(
21 | ({ item, onClick }, ref) => {
22 | return (
23 |
33 |
34 |
35 |
36 |
37 | {item?.name}
38 |
39 |
40 | );
41 | }
42 | );
43 |
44 | export default NFTImportCardOS;
45 |
--------------------------------------------------------------------------------
/components/nft-item-manager/index.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@chakra-ui/button";
2 | import { Image } from "@chakra-ui/image";
3 | import { Box, Center, StackProps, Text, VStack } from "@chakra-ui/layout";
4 | import { formatEther } from "@ethersproject/units";
5 | import React, { forwardRef } from "react";
6 | import { FrakCard } from "../../types";
7 | import FrakButton from "../button";
8 | import NextLink from "next/link";
9 |
10 | interface NFTItemProps extends StackProps {
11 | item: FrakCard;
12 | CTAText?: string;
13 | }
14 |
15 | const NFTItemManager = forwardRef(
16 | ({ item, onClick, CTAText }, ref) => {
17 | return (
18 |
28 |
29 |
30 | {item.countdown && (
31 |
43 | Time Remaining
44 | 11:59:09
45 |
46 | )}
47 |
48 | {item.contributions && (
49 |
56 |
57 | {formatEther(item.contributions).toString()} Contributed
58 |
59 |
60 | )}
61 |
62 |
63 |
64 | {item.name}
65 |
66 |
67 |
68 | Sell
69 |
70 |
71 |
72 |
73 | Manage
74 |
75 |
76 |
77 |
78 | );
79 | }
80 | );
81 |
82 | export default NFTItemManager;
83 |
--------------------------------------------------------------------------------
/components/nft-item-opensea/index.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@chakra-ui/button";
2 | import { Image } from "@chakra-ui/image";
3 | import { Box, Center, StackProps, Text, VStack } from "@chakra-ui/layout";
4 | import { formatEther } from "@ethersproject/units";
5 | import React, { forwardRef } from "react";
6 | import { FrakCard } from "../../types";
7 | import FrakButton from "../button";
8 | import NextLink from "next/link";
9 | import {useState} from 'react';
10 | import { useWeb3Context } from '../../contexts/Web3Context';
11 | import {approveMarket, importERC721, importERC1155} from '../../utils/contractCalls';
12 | import { claimNFT } from '../../utils/helpers';
13 |
14 | interface NFTItemProps extends StackProps {
15 | item: FrakCard;
16 | CTAText?: string;
17 | onCollateralRequest?: void;
18 | }
19 |
20 | const NFTItemOS = forwardRef(
21 | ({ item, onClick, CTAText, onCollateralRequest }, ref) => {
22 |
23 | return (
24 |
37 |
38 |
39 |
40 |
41 |
42 | {item.name}
43 |
44 |
45 | {item.token_schema}
46 |
47 |
52 | {CTAText}
53 |
54 | {item.collateral &&
55 |
56 | onCollateralRequest()}
61 | >
62 | Claim collateral
63 |
64 |
65 | }
66 |
67 |
68 |
69 | );
70 | }
71 | );
72 |
73 | export default NFTItemOS;
74 |
--------------------------------------------------------------------------------
/components/nftCard/index.tsx:
--------------------------------------------------------------------------------
1 | import { Button, ButtonProps } from "@chakra-ui/button";
2 | import { forwardRef } from "react";
3 | import FrakButton3 from "../button3";
4 | import styles from "../../styles/mint-nft.module.css";
5 | import { Box, Input, Textarea } from "@chakra-ui/react";
6 | const NFTCard = ({ setName, setDescription, addFile, file, fileUpload=true, nftName = "" }) => {
7 | function openLocal() {
8 | document.getElementById("imageInput").files = null;
9 | document.getElementById("imageInput").click();
10 | }
11 |
12 | return (
13 |
14 |
24 | NAME
25 |
26 |
setName(e.target.value)}
38 | />
39 | {fileUpload ?
40 | (
41 |
52 | image
53 |
54 |
55 |
openLocal()}
58 | setFunction={() => addFile()}
59 | inputPlaceholder="PNG, JPG or GIF"
60 | >
61 | {file ? "Change File" : "Choose File"}
62 |
63 |
64 |
): null}
65 |
76 | DESCRIPTION (OPTIONAL)
77 |
78 |
91 | );
92 | };
93 |
94 | export default NFTCard;
95 |
--------------------------------------------------------------------------------
/components/pagination/index.tsx:
--------------------------------------------------------------------------------
1 | import { HStack, StackProps, Text } from "@chakra-ui/layout";
2 | import { MouseEventHandler, useState } from "react";
3 | import FrakButton from "../button";
4 |
5 | const Pagination: React.FC<
6 | StackProps & {
7 | pageCount: number;
8 | handlePageClick: (pageNumber: number) => void;
9 | }
10 | > = ({ pageCount, handlePageClick, ...props }) => {
11 | const [currentPage, setCurrentPage] = useState(1);
12 |
13 | const handleClick: MouseEventHandler = e => {
14 | const pageNumber = parseInt((e.target as HTMLButtonElement).textContent);
15 | setCurrentPage(pageNumber);
16 | handlePageClick(pageNumber);
17 | };
18 |
19 | return (
20 |
21 | {Array.from({ length: pageCount })
22 | .slice(0, 3)
23 | .map((_, index) => (
24 |
35 | {index + 1}
36 |
37 | ))}
38 | {pageCount > 5 && (
39 | <>
40 | ...
41 |
51 | {pageCount}
52 |
53 | >
54 | )}
55 |
56 | );
57 | };
58 |
59 | export default Pagination;
60 |
--------------------------------------------------------------------------------
/components/rescueCard/index.tsx:
--------------------------------------------------------------------------------
1 | import { VStack, HStack, Box } from "@chakra-ui/layout";
2 | import React, { useState } from "react";
3 | import { rescueEth } from "../../utils/contractCalls";
4 | import { Text } from "@chakra-ui/react";
5 | import toast from 'react-hot-toast';
6 |
7 | const RescueCard = ({ marketAddress, provider, gains }) => {
8 | // const [isReady, setIsReady] = useState(false);
9 |
10 | async function handleEthRescue() {
11 | toast('Claiming ETH...');
12 | const response = await rescueEth(provider, marketAddress)
13 | if (!response?.error) {
14 | toast.success("ETH Claimed.");
15 | }
16 | if (response?.error) {
17 | toast.error("Transaction failed.");
18 | console.error()
19 | }
20 | }
21 |
22 | return (
23 |
32 |
41 | Marketplace Profits
42 |
43 |
44 | <>
45 | {gains > 0 && (
46 | <>
47 |
48 |
49 |
59 |
60 |
61 |
70 | {gains} ETH
71 |
72 |
73 | await handleEthRescue()}
89 | >
90 | Claim
91 |
92 |
93 | >
94 | )}
95 | {(gains == 0 || gains == null) && (
96 |
97 | Nothing to claim yet.
98 |
99 | )}
100 | >
101 |
102 |
103 | );
104 | };
105 | export default RescueCard;
106 |
--------------------------------------------------------------------------------
/components/search/styles.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/components/search/styles.css
--------------------------------------------------------------------------------
/components/tabsCard/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * CHAKRA UI
3 | */
4 | import {
5 | Box,
6 | Flex,
7 | Grid,
8 | GridItem,
9 | Icon,
10 | Link,
11 | Spacer,
12 | StackDivider,
13 | StackProps,
14 | Tab,
15 | Tabs,
16 | TabList,
17 | TabPanels,
18 | TabPanel,
19 | Text,
20 | Tooltip,
21 | VStack,
22 | } from '@chakra-ui/react';
23 | /**
24 | * Styles
25 | */
26 | import styles from './tabsCard.module.css';
27 | /**
28 | * FRAKTAL Components
29 | */
30 | import FrakButton from '@/components/button';
31 | import FrakButton2 from '@/components/button2';
32 |
33 | /**
34 | * ICONS
35 | */
36 |
37 | import { AiOutlineInfoCircle } from 'react-icons/ai';
38 |
39 | interface TabsCardProps extends StackProps {
40 | height?: string;
41 | }
42 |
43 | /**
44 | * CardTabs
45 | * @returns {any}
46 | * @constructor
47 | */
48 | const TabsCard = ({
49 | title,
50 | secondaryText,
51 | currency,
52 | labelTooltip,
53 | children,
54 | }) => {
55 | return (
56 |
57 | {title && (
58 |
59 |
60 | {title}
61 |
62 | {secondaryText && (
63 |
64 |
65 | {secondaryText}
66 |
67 |
68 | )}
69 |
70 |
71 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | )}
89 | {children}
90 |
91 | );
92 | };
93 | export default TabsCard;
94 |
--------------------------------------------------------------------------------
/components/tabsCard/tabsCard.module.css:
--------------------------------------------------------------------------------
1 | .tabsCard {
2 | border-radius: 4px;
3 | border-width: 1px;
4 | border-color: #E0E0E0;
5 | padding: 5px 0;
6 | height: 454px;
7 | max-width: 300px;
8 | }
9 | .tooltip {
10 | border: 1px solid #E0E0E0;
11 | box-sizing: border-box;
12 | box-shadow: none;
13 | }
14 | .titleCard {
15 | font-family: "Inter";
16 | font-style: normal;
17 | font-weight: 600;
18 | /*font-size: 21px;*/
19 | font-size: 32px;
20 | line-height: 40px;
21 | color: #000000;
22 | }
23 | .tabButtons button {
24 | font-style: normal;
25 | font-weight: 600;
26 | font-size: 16px;
27 | line-height: 35px;
28 | text-align: center;
29 | color: #405466;
30 | width: 150px;
31 | }
32 | .gridCard a {
33 | font-style: normal;
34 | font-weight: normal;
35 | font-size: 14px;
36 | line-height: 20px;
37 | color: #985CFF;
38 | }
--------------------------------------------------------------------------------
/components/useENSAddress.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import { queryENSForETHAddress } from 'utils/stores/ensStore'
3 |
4 | /**
5 | * @param inputAddress is whatever user types. Could be ETH address or ENS address
6 | */
7 | export function useENSAddress(inputAddress: string) {
8 | const [ethAddress, setETHAddress] = useState('0')
9 | const [isLoading, setIsLoading] = useState(true)
10 |
11 | useEffect((): any => {
12 | async function run() {
13 | try {
14 | setETHAddress(await queryENSForETHAddress(inputAddress))
15 | } catch (e) {
16 | setETHAddress('0')
17 | }
18 | }
19 |
20 | setIsLoading(true)
21 | run()
22 |
23 | setIsLoading(false)
24 | }, [inputAddress])
25 |
26 | // First return value says if is valid ENS address or not
27 | return [parseInt(ethAddress, 16) !== 0, ethAddress, isLoading]
28 | }
29 |
--------------------------------------------------------------------------------
/components/verifyNFT/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * React
3 | */
4 | import React, {useEffect, useState} from "react";
5 | /**
6 | * Chakra
7 | *
8 | */
9 | import {
10 | Text,
11 | Icon,
12 | Tooltip,
13 | Modal,
14 | ModalOverlay,
15 | ModalContent,
16 | ModalHeader,
17 | ModalBody,
18 | ModalCloseButton,
19 | } from '@chakra-ui/react';
20 | /**
21 | * Component
22 | */
23 | import FrakButton from '../../components/button4'
24 |
25 | /**
26 | * Icons
27 | */
28 | import { AiOutlineInfoCircle } from 'react-icons/ai';
29 | /**
30 | * Utils
31 | */
32 | import {validateAsset} from "@/utils/openSeaAPI";
33 |
34 | const VerifyNFT =(({nftObject}) => {
35 | const [opeaSeaURL, setOpeaSeaURL] = useState("");
36 | const [openModal, setOpenModal] = useState(false);
37 | const [message, setMessage] = useState("");
38 | const [isValidating, setIsValidating] = useState(false);
39 |
40 | async function validateNFT() {
41 | setIsValidating(true);
42 | let response;
43 | if (nftObject.collateral !== null && nftObject.collateral !== undefined) {
44 | let contract, tokeId;
45 | if (nftObject.collateral.id.includes("-")) {
46 | const native = nftObject.collateral.id.split("-");
47 | contract = native[0];
48 | tokeId = native[1];
49 | } else {
50 | contract = nftObject.collateral.id;
51 | tokeId = 1;
52 | }
53 | response = await validateAsset(contract, tokeId);
54 | }
55 | setIsValidating(false);
56 | if (response === undefined || response.success === false) {
57 | setMessage("NFT was minted on Fraktal");
58 | setOpenModal(true);
59 | } else if (response.permalink !== undefined) {
60 | setOpeaSeaURL(response.permalink);
61 | window.open(response.permalink, '_blank');
62 | }
63 | }
64 |
65 | return(
66 | <>
67 |
73 |
82 |
83 |
86 | validateNFT()
87 | }
88 | >
89 | Verify On Opensea
90 |
91 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | >
111 | );
112 |
113 | });
114 |
115 | const ModalOpenSeaValidation = ({nftObject, opeaSeaURL, openModal, setOpenModal, message}) => {
116 |
117 | const closeModal = () => {
118 | setOpenModal(false);
119 | }
120 |
121 | return (
122 |
123 |
124 |
131 | {nftObject.name}
132 |
133 |
134 | {message}
135 |
136 |
137 |
138 | );
139 | }
140 |
141 | export default VerifyNFT;
--------------------------------------------------------------------------------
/constants/routes.ts:
--------------------------------------------------------------------------------
1 | export const ARTISTS = '/artists';
2 | export const CREATE_NFT = '/list-nft';
3 | export const EXPLORE = '/explore';
4 | //export const IMPORT_NFT = '/import-nft';
5 | export const IMPORT_NFTS = '/import-nft';
6 | export const LANDING = '/';
7 | export const MINT_NFT = '/mint-nft';
8 | export const MY_NFTS = '/my-nfts';
9 | export const REWARDS = '/rewards';
10 | export const NOT_FOUND = '/404';
11 | export const CLAIM = '/claim';
12 | export const CLAIM_BONUS = '/claim-bonus';
13 |
14 |
15 | export const resolveNFTRoute = (nftAddress: string) =>
16 | `/nft/${nftAddress}/details`;
17 |
18 | export const resolveAuctionNFTRoute = (nftAddress: string) =>
19 | `/nft/${nftAddress}/auction`;
20 |
--------------------------------------------------------------------------------
/contexts/NFTIsMintingContext.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from 'react';
2 |
3 | export const NFTIsMintingContext = React.createContext(null);
4 |
5 | export const MintingFC = ({children}) => {
6 | const [isMinting, setIsMinting] = useState(false);
7 | function toggleMinting() {
8 | setIsMinting(!isMinting);
9 | }
10 |
11 | return (
12 |
15 | {children}
16 |
17 | )
18 | }
19 |
20 | export const useMintingContext = () => {
21 | const {
22 | isMinting,
23 | setIsMinting
24 | } = useContext(NFTIsMintingContext)
25 | return {
26 | isMinting,
27 | setIsMinting
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/contexts/dataContext.tsx:
--------------------------------------------------------------------------------
1 | import {createContext, useContext, useEffect, useState} from 'react';
2 |
3 |
--------------------------------------------------------------------------------
/default.js:
--------------------------------------------------------------------------------
1 | export const config = {
2 | pinningService: {
3 | name: 'pinata',
4 | endpoint: 'https://api.pinata.cloud/psa',
5 | key: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySW5mb3JtYXRpb24iOnsiaWQiOiIzNjk4ZDMxOS1hMTM2LTRjZTQtOWU1NC0zNWMwZjBkMjFkMDQiLCJlbWFpbCI6Imx1Y2FzemllZ2VuZnVoc0BnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicGluX3BvbGljeSI6eyJyZWdpb25zIjpbeyJpZCI6Ik5ZQzEiLCJkZXNpcmVkUmVwbGljYXRpb25Db3VudCI6MX1dLCJ2ZXJzaW9uIjoxfSwibWZhX2VuYWJsZWQiOmZhbHNlfSwiYXV0aGVudGljYXRpb25UeXBlIjoic2NvcGVkS2V5Iiwic2NvcGVkS2V5S2V5IjoiYjE0MWJlODFlZTVjYzYyYmYzNjgiLCJzY29wZWRLZXlTZWNyZXQiOiI3MjMyYWRjYzAyYzA3ZTVkMTgyNWZjZDc1MWY5MmIxNDdiMmFjN2U2OThiOTg2ZWQ2NjVkMGM3YWZhNzU4NmNkIiwiaWF0IjoxNjI0Mzk3MDk1fQ.a5sF34V6yBnq-gqi8qTi0HbJUeiEF6e9kSKaztwcf9s'
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/hooks/externalContractLoader.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-dynamic-require */
2 | /* eslint-disable global-require */
3 | import { Contract } from "@ethersproject/contracts";
4 | import { useEffect, useState } from "react";
5 |
6 | /*
7 | when you want to load an existing contract using just the provider, address, and ABI
8 | */
9 |
10 | /*
11 | ~ What it does? ~
12 |
13 | Enables you to load an existing mainnet DAI contract using the provider, address and abi
14 |
15 | ~ How can I use? ~
16 |
17 | const mainnetDAIContract = useExternalContractLoader(mainnetProvider, DAI_ADDRESS, DAI_ABI)
18 |
19 | */
20 | export default function useExternalContractLoader(provider, address, ABI, optionalBytecode) {
21 | const [contract, setContract] = useState();
22 | useEffect(() => {
23 | async function loadContract() {
24 | if (typeof provider !== "undefined" && address && ABI) {
25 | try {
26 | // we need to check to see if this provider has a signer or not
27 | let signer;
28 | const accounts = await provider.listAccounts();
29 | if (accounts && accounts.length > 0) {
30 | signer = provider.getSigner();
31 | } else {
32 | signer = provider;
33 | }
34 |
35 | const customContract = new Contract(address, ABI, signer);
36 | if (optionalBytecode) customContract.bytecode = optionalBytecode;
37 |
38 | setContract(customContract);
39 | } catch (e) {
40 | console.log("ERROR LOADING EXTERNAL CONTRACT AT " + address + " (check provider, address, and ABI)!!", e);
41 | }
42 | }
43 | }
44 | loadContract();
45 | }, [provider, address, ABI, optionalBytecode]);
46 | return contract;
47 | }
48 |
--------------------------------------------------------------------------------
/hooks/useLoadingScreen.ts:
--------------------------------------------------------------------------------
1 | import { useDispatch } from 'react-redux'
2 | import { useCallback } from 'react'
3 | import { closeModal } from '../redux/actions/contractActions'
4 |
5 | export const useLoadingScreenHandler = () => {
6 | const dispatch = useDispatch()
7 |
8 | const closeModalHandler = useCallback(() => {
9 | dispatch(closeModal())
10 | }, [])
11 |
12 | const closeLoadingModalAfterDelay = useCallback(() => {
13 | setTimeout(() => {
14 | closeModalHandler()
15 | }, 2000)
16 | }, [])
17 |
18 | return { closeModal: closeModalHandler, closeLoadingModalAfterDelay }
19 | }
--------------------------------------------------------------------------------
/hooks/useMarketplace.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 |
3 | const useMarketplace = () => {
4 | const [someState, setSomeState] = useState<{ key: string } | null>(null);
5 |
6 | useEffect(() => {
7 | console.log("Printing demo info");
8 | }, []);
9 | }
10 |
11 | export default useMarketplace;
12 |
--------------------------------------------------------------------------------
/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | typescript: {
3 | // !! WARN !!
4 | // Dangerously allow production builds to successfully complete even if
5 | // your project has type errors.
6 | // !! WARN !!
7 | ignoreBuildErrors: true,
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fraktal-frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "storybook": "start-storybook -p 6006",
10 | "build-storybook": "build-storybook"
11 | },
12 | "dependencies": {
13 | "@alch/alchemy-web3": "^1.2.5",
14 | "@apollo/client": "^3.3.21",
15 | "@chakra-ui/core": "^0.8.0",
16 | "@chakra-ui/react": "^1.6.1",
17 | "@emotion/core": "^11.0.0",
18 | "@emotion/react": "^11",
19 | "@emotion/styled": "^11.3.0",
20 | "@walletconnect/web3-provider": "^1.4.1",
21 | "axios": "^0.21.1",
22 | "emotion-theming": "^11.0.0",
23 | "eslint": "^8.3.0",
24 | "ethers": "^5.1.4",
25 | "framer-motion": "4.1.16",
26 | "graphql": "^15.5.1",
27 | "graphql-request": "^3.5.0",
28 | "ipfs-http-client": "^50.1.2",
29 | "moment": "^2.29.1",
30 | "next": "10.2.0",
31 | "next-redux-wrapper": "^7.0.5",
32 | "opensea-js": "^1.1.13",
33 | "react": "17.0.2",
34 | "react-countdown": "^2.3.2",
35 | "react-dom": "17.0.2",
36 | "react-hot-toast": "^2.1.1",
37 | "react-icons": "^4.2.0",
38 | "react-infinite-scroll-component": "^6.1.0",
39 | "react-jss": "^10.6.0",
40 | "react-modal": "^3.13.1",
41 | "react-redux": "^7.2.6",
42 | "react-select-search": "^3.0.9",
43 | "redux": "^4.1.2",
44 | "web3": "^1.3.6",
45 | "web3modal": "^1.9.3"
46 | },
47 | "devDependencies": {
48 | "@babel/core": "^7.16.0",
49 | "@storybook/addon-actions": "^6.3.12",
50 | "@storybook/addon-essentials": "^6.3.12",
51 | "@storybook/addon-links": "^6.3.12",
52 | "@storybook/react": "^6.3.12",
53 | "@types/react": "^17.0.5",
54 | "babel-loader": "^8.2.3",
55 | "typescript": "^4.2.4"
56 | },
57 | "prettier": {
58 | "tabWidth": 2,
59 | "singleQuote": true
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/pages/404.tsx:
--------------------------------------------------------------------------------
1 | import { Box, Text, VStack } from "@chakra-ui/react";
2 | import NextLink from "next/link";
3 | import FrakButton from "../components/button";
4 | import Image from "next/image";
5 | import {EXPLORE} from "@/constants/routes";
6 |
7 | const Custom404: React.FC = () => {
8 | return (
9 |
21 |
22 |
23 |
33 | Something went wrong
34 |
35 |
36 |
37 |
41 | Back to Marketplace
42 |
43 |
44 |
45 |
46 | );
47 | };
48 |
49 | export default Custom404;
50 |
--------------------------------------------------------------------------------
/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Chakra
3 | */
4 | import { ChakraProvider, ComponentStyleConfig, extendTheme, VStack } from "@chakra-ui/react";
5 | /**
6 | * Styles
7 | */
8 | import "../styles/globals.css";
9 | import "../styles/fonts.css";
10 | /**
11 | * Contexts
12 | */
13 | import Web3ContextProvider from "@/contexts/Web3Context"
14 | import { UserContextProviderFC } from "@/contexts/userContext";
15 | import { MintingFC } from "@/contexts/NFTIsMintingContext";
16 | /**
17 | * App Fraktal Components
18 | */
19 | import Layout from "../components/layout";
20 | import Footer from "../components/footer";
21 | /**
22 | * Redux
23 | */
24 | import { Provider } from 'react-redux'
25 | import store from '../redux/store';
26 | /**
27 | * Toaster
28 | */
29 | import { Toaster } from "react-hot-toast";
30 |
31 | const Text: ComponentStyleConfig = {
32 | variants: {
33 | footer: {
34 | color: "grey.500",
35 | fontSize: "1.6rem",
36 | fontWeight: "500",
37 | lineHeight: "4rem"
38 | }
39 | }
40 | }
41 |
42 | const Heading: ComponentStyleConfig = {
43 | variants: {
44 | footer: {
45 | fontSize: 14,
46 | fontWeight: 700,
47 | mb: [18, 18, "40px", "40px"]
48 | }
49 | }
50 | }
51 |
52 | /**
53 | * Theme
54 | */
55 | const customTheme = extendTheme({
56 | colors: {
57 | grey: {
58 | 500: "#666b6d",
59 | },
60 | white: {
61 | 100: "#E0E0E0",
62 | 500: "#F9F9F9",
63 | 900: "#fff",
64 | },
65 | black: {
66 | 500: "#656464",
67 | 900: "#000",
68 | },
69 | red: {
70 | 900: "#FF0000",
71 | },
72 | },
73 | components: {
74 | Heading,
75 | Text,
76 | }
77 | });
78 |
79 | /**
80 | * App Performance Metrics
81 | * @see https://nextjs.org/docs/advanced-features/measuring-performance
82 | */
83 | export function reportWebVitals(metric) {
84 | //console.log(metric);
85 | }
86 |
87 | /**
88 | * My APP
89 | * @param {any} Component
90 | * @param {any} pageProps
91 | * @returns {any}
92 | * @constructor
93 | */
94 | function MyApp({ Component, pageProps }) {
95 | return (
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | );
114 | }
115 |
116 | export default MyApp;
117 |
--------------------------------------------------------------------------------
/pages/api/hello.ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 |
3 | import { NextApiRequest, NextApiResponse } from "next";
4 |
5 | export default (req: NextApiRequest, res: NextApiResponse) => {
6 | res.status(200).json({ name: "John Doe" });
7 | };
8 |
--------------------------------------------------------------------------------
/pages/artist/[...slug].tsx:
--------------------------------------------------------------------------------
1 | import { Grid, Text, VStack, Heading, Spinner, Box } from "@chakra-ui/react";
2 | import Head from "next/head";
3 | import React, { useState, useEffect } from "react";
4 | import styles from "./artist.module.css";
5 | import styles_Search from "../../styles/artists.module.css";
6 | import NFTItem from "../../components/nft-item";
7 | import FrakButton from "../../components/button";
8 | import NextLink from "next/link";
9 | import { shortenHash, getParams } from "../../utils/helpers";
10 | import { getSubgraphData } from "../../utils/graphQueries";
11 | import {createObject } from "../../utils/nftHelpers";
12 | import toast from "react-hot-toast";
13 | import { useRouter } from "next/router";
14 | import { Image } from "@chakra-ui/image";
15 | import { useENSAddress } from 'components/useENSAddress';
16 |
17 |
18 | export default function ArtistView() {
19 | const router = useRouter();
20 | const [artistAddress, setArtistAddres] = useState("");
21 | const [nftItems, setNftItems] = useState([]);
22 | const [loading, setIsLoading] = useState(false);
23 | const [artist_Address, setArtist_Address] = useState("");
24 | const [inputAddress, setInputAddress] = useState("");
25 |
26 | function searchHandle(e){
27 | e.preventDefault();
28 | if(e.target.value !== ""){
29 | const inputVal=e.target.value;
30 | let address_Artist= inputVal;
31 | if(!inputVal.startsWith("0x")){
32 | setInputAddress(e.target.value);
33 | }
34 | setArtist_Address(address_Artist);
35 | }
36 | }
37 | const [isENSAddressValid, ethAddressFromENS] = useENSAddress(inputAddress)
38 |
39 | useEffect(() => {
40 | async function getData() {
41 | const pathname = router.asPath;
42 | const args = pathname.split("/");
43 | const address = args[2];
44 | setIsLoading(true);
45 | toast("Fetching Data");
46 | try {
47 | if (address) {
48 | setArtistAddres(address);
49 | let objects = await getSubgraphData("creator", address);
50 | await Promise.all(
51 | objects.fraktalNfts.map(x => {
52 | return createObject(x);
53 | })
54 | ).then(results => setNftItems(results));
55 | toast.success("Data fetched");
56 | }
57 | } catch (error) {
58 | console.error(error);
59 | toast.error("Fetch failed");
60 | } finally {
61 | setIsLoading(false);
62 | }
63 | }
64 | getData();
65 | }, [router.asPath]);
66 |
67 | return (
68 |
69 |
70 | Fraktal - Artist
71 |
72 |
73 | {artistAddress}
74 | {/*
75 |
80 | {
81 | artist_Address !=="" &&
82 |
86 |
87 |
88 | }
89 |
90 |
*/}
91 |
92 | {!loading && nftItems.length > 0 && (
93 | <>
94 |
101 | {nftItems.map(item => {
102 | return (
103 |
104 |
109 |
110 | );
111 | })}
112 |
113 | >
114 | )}
115 | {!loading && nftItems == null && (
116 |
117 | Whoops, no NFTs are for sale.
118 | Check back later or list your own!
119 |
120 | Mint NFT
121 |
122 |
123 | )}
124 | {loading && (
125 |
133 |
134 |
135 | )}
136 |
137 | );
138 | }
139 |
--------------------------------------------------------------------------------
/pages/artist/artist.module.css:
--------------------------------------------------------------------------------
1 | .header {
2 | font-size: 48px;
3 | line-height: 64px;
4 | font-weight: 600;
5 | text-align: center;
6 | margin-bottom: 40px;
7 | }
8 |
--------------------------------------------------------------------------------
/pages/claim-bonus.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { Box, Grid, HStack, VStack, Text, Spinner, Input, InputGroup,InputLeftAddon, Button,useToast } from "@chakra-ui/react";
3 | import Head from "next/head";
4 | import { useWeb3Context } from "../contexts/Web3Context";
5 | import { useRouter } from "next/router";
6 | import { useENSAddress } from 'components/useENSAddress';
7 | import { claimPartnerAirdrop } from '@/utils/contractCalls';
8 | import { getAddressAirdrop } from '@/utils/graphQueries';
9 | import {getProofs2} from '../utils/proofsGetter'
10 | import Countdown from 'react-countdown';
11 |
12 |
13 | const Completionist = () => ;
14 | const renderer = ({ hours, minutes, seconds, completed }) => {
15 | if (completed) {
16 | // Render a completed state
17 | return ;
18 | } else {
19 | // Render a countdown
20 | return In {hours} hours {minutes} minutes :{seconds} seconds ;
21 | }
22 | };
23 |
24 | export default function ClaimBonus() {
25 | const { account, loading, partnerAirdropAddress, provider } = useWeb3Context();
26 | const [inputAddress, setInputAddress] = useState("");
27 | const [listedAddress, setListedAddress] = useState("");
28 | const [proofs,setProofs] = useState("");
29 | const [checkedEligible, setCheckedEligible] = useState(false);
30 | const [eligible, setEligible] = useState(true);
31 | const toast = useToast()
32 |
33 | useEffect(() => {
34 | setInputAddress(account);
35 | setCheckedEligible(false);
36 | setEligible(true);
37 | // setProofs(getProofs(account));
38 | }, [account]);
39 |
40 | useEffect(() => {
41 | setCheckedEligible(false);
42 | setEligible(true);
43 | // setProofs(getProofs(account));
44 | }, [inputAddress]);
45 |
46 | const claimHandle = async () => {
47 | if(inputAddress == "" ){
48 | toast({
49 | title: `Some input missing`,
50 | status: "error",
51 | isClosable: true,
52 | position: "top",
53 | })
54 | return;
55 | }
56 |
57 | if(checkedEligible && eligible){
58 | const data = getProofs2(inputAddress);
59 | await userClaimAirdrop(data.amount, data.hexProof);
60 | }else{
61 | const data = getProofs2(inputAddress);
62 | console.log(data);
63 | setCheckedEligible(true);
64 | if(data === undefined){
65 | setEligible(false);
66 | toast({
67 | title: `Not eligible to claim...`,
68 | status: "warning",
69 | isClosable: true,
70 | position: "top",
71 | })
72 | }else{
73 | toast({
74 | title: `Eligible to claim ${data.amount} FRAKs. Claim now!`,
75 | status: "success",
76 | isClosable: true,
77 | position: "top",
78 | })
79 |
80 | }
81 |
82 | }
83 |
84 | }
85 |
86 | const onInputAddressChange = (event) => {
87 | setInputAddress(event.target.value);
88 | }
89 |
90 | const userClaimAirdrop = async (_amount,_proof) => {
91 | try{
92 | console.log("Amount :",_amount,_proof);
93 | await claimPartnerAirdrop(_amount,_proof,provider,"0x19B56b1Ea1522509B7Ab260cBC3989D8Dc024837");
94 |
95 | }
96 | catch(error){
97 | toast({
98 | title: error.error.message,
99 | status: "error",
100 | isClosable: true,
101 | position: "top",
102 | });
103 | console.log({error});
104 | }
105 |
106 | }
107 | //1648382400000
108 | return (
109 |
110 |
111 | Fraktal - Bonus Airdrop
112 |
113 |
114 | Bonus Hodler Airdrop 💎🤲 ,
115 | Check if your address eligible for the airdrop
116 |
117 | <>
118 |
119 |
120 |
121 |
122 |
123 |
124 | {checkedEligible?"Claim!":"Check"}
125 |
126 | >
127 |
128 | );
129 | }
130 |
--------------------------------------------------------------------------------
/pages/claim.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { Box, Grid, HStack, VStack, Text, Spinner, Input, InputGroup,InputLeftAddon, Button,useToast } from "@chakra-ui/react";
3 | import Head from "next/head";
4 | import { useWeb3Context } from "../contexts/Web3Context";
5 | import { useRouter } from "next/router";
6 | import { useENSAddress } from 'components/useENSAddress';
7 | import { claimPartnerAirdrop } from '@/utils/contractCalls';
8 | import { getAddressAirdrop } from '@/utils/graphQueries';
9 | import {getProofs} from '../utils/proofsGetter'
10 | import Countdown from 'react-countdown';
11 |
12 |
13 | const Completionist = () => ;
14 | const renderer = ({ hours, minutes, seconds, completed }) => {
15 | if (completed) {
16 | // Render a completed state
17 | return ;
18 | } else {
19 | // Render a countdown
20 | return In {hours} hours {minutes} minutes :{seconds} seconds ;
21 | }
22 | };
23 |
24 | export default function Claim() {
25 | const { account, loading, partnerAirdropAddress, provider } = useWeb3Context();
26 | const [inputAddress, setInputAddress] = useState("");
27 | const [listedAddress, setListedAddress] = useState("");
28 | const [proofs,setProofs] = useState("");
29 | const [checkedEligible, setCheckedEligible] = useState(false);
30 | const [eligible, setEligible] = useState(true);
31 | const toast = useToast()
32 |
33 | useEffect(() => {
34 | setInputAddress(account);
35 | setCheckedEligible(false);
36 | setEligible(true);
37 | // setProofs(getProofs(account));
38 | }, [account]);
39 |
40 | const claimHandle = async () => {
41 | if(inputAddress == "" ){
42 | toast({
43 | title: `Some input missing`,
44 | status: "error",
45 | isClosable: true,
46 | position: "top",
47 | })
48 | return;
49 | }
50 |
51 | if(checkedEligible && eligible){
52 | const data = getProofs(inputAddress);
53 | await userClaimAirdrop(data.amount, data.hexProof);
54 | }else{
55 | const data = getProofs(inputAddress);
56 | console.log(data);
57 | setCheckedEligible(true);
58 | if(data === undefined){
59 | setEligible(false);
60 | toast({
61 | title: `Not eligible to claim...`,
62 | status: "warning",
63 | isClosable: true,
64 | position: "top",
65 | })
66 | }else{
67 | toast({
68 | title: `Eligible to claim ${data.amount} FRAKs. Claim now!`,
69 | status: "success",
70 | isClosable: true,
71 | position: "top",
72 | })
73 |
74 | }
75 |
76 | }
77 |
78 | }
79 |
80 | const onInputAddressChange = (event) => {
81 | setInputAddress(event.target.value);
82 | }
83 |
84 | const userClaimAirdrop = async (_amount,_proof) => {
85 | try{
86 | console.log("Amount :",_amount,_proof);
87 | await claimPartnerAirdrop(_amount,_proof,provider,partnerAirdropAddress);
88 |
89 | }
90 | catch(error){
91 | toast({
92 | title: error.error.message,
93 | status: "error",
94 | isClosable: true,
95 | position: "top",
96 | });
97 | console.log({error});
98 | }
99 |
100 | }
101 | //1648382400000
102 | return (
103 |
104 |
105 | Fraktal - Launch Partner Airdrop
106 |
107 |
108 | Launch Partner + Bonus Airdrop🎉 ,
109 | Check if your address eligible for the airdrop
110 |
111 | <>
112 |
113 |
114 |
115 |
116 |
117 |
118 | {checkedEligible?"Claim!":"Check"}
119 |
120 | >
121 |
122 | );
123 | }
124 |
--------------------------------------------------------------------------------
/pages/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * REACT
3 | */
4 | import {useEffect, useState} from "react";
5 | /**
6 | * NEXT
7 | */
8 | import { useRouter } from "next/router";
9 | /**
10 | * ICONS
11 | */
12 | import { FaCoins } from 'react-icons/fa';
13 | import { GiProfit } from 'react-icons/gi';
14 |
15 | /**
16 | * CHAKRA UI
17 | */
18 | import {
19 | Box,
20 | Container,
21 | List,
22 | ListItem,
23 | ListIcon,
24 | Link,
25 | Grid,
26 | GridItem,
27 | Text
28 | } from '@chakra-ui/react'
29 | /**
30 | * NFT HELPER
31 | */
32 | import { createListed } from "@/utils/nftHelpers";
33 | /**
34 | * API GRAPH QUERY
35 | */
36 | import {getSubgraphData} from "@/utils/graphQueries";
37 | /**
38 | * FRAKTAL Components
39 | */
40 | import NFTItem from "@/components/nft-item";
41 | import FrakButton from "@/components/button"
42 | import Anchor from '@/components/anchor';
43 | /**
44 | * STYLES
45 | */
46 | import styles from "../styles/landing.module.css";
47 | import {CREATE_NFT, EXPLORE, REWARDS} from "@/constants/routes";
48 |
49 | //TODO LandingPage ADD PROPS
50 |
51 | /**
52 | * LandingPage
53 | * @returns {any}
54 | * @constructor
55 | */
56 | const LandingPage = () => {
57 | const [nftData, setNftData] = useState({});
58 | const router = useRouter();
59 |
60 | const getItem = async () => {
61 | //TODO - Get the most popular NFT without listing the items
62 | const data = await getSubgraphData("listed_items", "");
63 | const mostPopular = getMostPopular(data.listItems)[0];
64 | let nftObjects = await createListed(mostPopular);
65 | setNftData(nftObjects);
66 | };
67 |
68 | const getMostPopular = (items) => {
69 | return items.sort((a, b) => (a.fraktal.fraktions.length > b.fraktal.fraktions.length ? -1 : 1));
70 | };
71 |
72 | useEffect(()=>{
73 | getItem();
74 | }, []);
75 |
76 | return(<>
77 |
78 |
79 |
80 | Buy & Sell Fraktions of NFTs
81 |
82 |
83 | {router.push(EXPLORE, null, {scroll: false})}}
85 | px="80px">Explore
86 |
87 |
88 | {router.push(CREATE_NFT, null, {scroll: false})}}
90 | border="2px solid #000"
91 | px="80px"
92 | background="#ffffff"
93 | color="#000">Create
94 |
95 |
96 | Powered by FRAK
97 |
98 | {router.push(REWARDS, null, {scroll: false})}}>
100 |
101 | Earn FRAK from trading to offset gas costs
102 |
103 | {router.push(REWARDS, null, {scroll: false})}}>
105 |
106 | Stake FRAK and earn ETH from transaction fees
107 |
108 |
109 |
110 |
111 |
112 |
113 | {
114 | nftData && (
115 |
118 |
126 |
127 | )
128 | }
129 |
130 |
131 |
132 | >);
133 | };
134 |
135 | export default LandingPage;
136 |
--------------------------------------------------------------------------------
/pages/nft/[id]/auction.module.css:
--------------------------------------------------------------------------------
1 | .goBack {
2 | text-align: center;
3 | color: #985cff;
4 | font-size: 16px;
5 | line-height: 24px;
6 | font-weight: 500;
7 | cursor: pointer;
8 | }
9 |
10 | .header {
11 | margin-top: 8px;
12 | font-size: 48px;
13 | line-height: 64px;
14 | font-weight: 600;
15 | text-align: center;
16 | }
17 | .subheader {
18 | margin-top: 8px;
19 | font-size: 36px;
20 | line-height: 24px;
21 | font-weight: 500;
22 | text-align: center;
23 | color: grey;
24 | }
25 | .NFTCard {
26 | padding: 16px;
27 | border: 1px solid #e0e0e0;
28 | border-radius: 0px 0px 4px 4px;
29 | }
30 |
31 | .cardHeader {
32 | color: #e0e0e0;
33 | font-size: 12px;
34 | line-height: 14px;
35 | font-weight: 600;
36 | letter-spacing: 1px;
37 | }
38 |
39 | .cardText {
40 | margin-top: 4px;
41 | font-size: 16px;
42 | line-height: 24px;
43 | font-weight: 500;
44 | }
45 |
46 | .auctionCard {
47 | display: flex;
48 | padding: 24px;
49 | position: relative;
50 | border: 1px solid #e0e0e0;
51 | border-radius: 4px;
52 | justify-content: center;
53 | }
54 |
55 | .auctionCardHeader {
56 | font-weight: 500;
57 | font-size: 16px;
58 | line-height: 24px;
59 | }
60 |
61 | .auctionCardDetailsContainer {
62 | display: flex;
63 | margin-top: 16px;
64 | justify-content: flex-start;
65 | }
66 |
67 | .auctionCardDetailsNumber {
68 | font-weight: 600;
69 | font-size: 32px;
70 | line-height: 40px;
71 | }
72 |
73 | .auctionCardDetailsText {
74 | margin-top: 4px;
75 | font-size: 16px;
76 | line-height: 24px;
77 | letter-spacing: 0.02em;
78 | }
79 |
80 | .auctionCardDivider {
81 | background-color: #9f66e3;
82 | height: 109px;
83 | width: 1px;
84 | margin-right: 32px;
85 | }
86 |
87 | .contributeContainer {
88 | position: absolute;
89 | bottom: -100px;
90 | left: calc(50% - 160px);
91 | width: 320px;
92 | height: 64px;
93 | display: flex;
94 | justify-content: space-between;
95 | align-items: center;
96 | padding: 8px;
97 | border: 2px solid #e0e0e0;
98 | border-radius: 32px;
99 | background-color: #fff;
100 | }
101 | .contributeContainer1 {
102 | position: absolute;
103 | bottom: -32px;
104 | left: calc(50% - 320px);
105 | width: 320px;
106 | height: 64px;
107 | display: flex;
108 | justify-content: space-between;
109 | align-items: center;
110 | padding: 8px;
111 | border: 2px solid #e0e0e0;
112 | border-radius: 32px;
113 | background-color: #fff;
114 | }
115 | .contributeContainer2 {
116 | position: absolute;
117 | bottom: -32px;
118 | left: calc(100% - 320px);
119 | width: 280px;
120 | height: 64px;
121 | display: flex;
122 | justify-content: space-between;
123 | align-items: center;
124 | padding: 8px;
125 | border: 2px solid #e0e0e0;
126 | border-radius: 32px;
127 | background-color: #fff;
128 | }
129 |
130 | .contributeHeader {
131 | letter-spacing: 1px;
132 | font-size: 12px;
133 | font-weight: 600;
134 | line-height: 14px;
135 | }
136 |
137 | .contributeInput {
138 | margin-top: 5px;
139 | font-size: 20px;
140 | line-height: 20px;
141 | font-weight: 500;
142 | width: 100px;
143 | }
144 |
145 | .contributInput::placeholder {
146 | color: #e0e0e0;
147 | }
148 |
149 | .contributeCTA {
150 | flex-shrink: 0;
151 | background-color: #9f66e3;
152 | border-radius: 24px;
153 | padding: 12px 24px;
154 | color: #fff;
155 | font-weight: 600;
156 | font-size: 16px;
157 | line-height: 24px;
158 | }
159 |
--------------------------------------------------------------------------------
/pages/nft/[id]/closed.module.css:
--------------------------------------------------------------------------------
1 | .goBack {
2 | text-align: center;
3 | color: #985cff;
4 | font-size: 16px;
5 | line-height: 24px;
6 | font-weight: 500;
7 | cursor: pointer;
8 | }
9 |
10 | .header {
11 | margin-top: 8px;
12 | font-size: 48px;
13 | line-height: 64px;
14 | font-weight: 600;
15 | text-align: center;
16 | }
17 |
18 | .NFTCard {
19 | padding: 16px;
20 | border: 1px solid #e0e0e0;
21 | border-radius: 0px 0px 4px 4px;
22 | }
23 |
24 | .cardHeader {
25 | color: #e0e0e0;
26 | font-size: 12px;
27 | line-height: 14px;
28 | font-weight: 600;
29 | letter-spacing: 1px;
30 | }
31 |
32 | .cardText {
33 | margin-top: 4px;
34 | font-size: 16px;
35 | line-height: 24px;
36 | font-weight: 500;
37 | }
38 |
39 | .auctionCard {
40 | display: flex;
41 | padding: 24px 24px 70px 24px;
42 | position: relative;
43 | border: 1px solid #e0e0e0;
44 | border-radius: 4px;
45 | display: flex;
46 | }
47 |
48 | .auctionCardHeader {
49 | font-weight: 500;
50 | font-size: 16px;
51 | line-height: 24px;
52 | }
53 |
54 | .auctionCardDetailsContainer {
55 | display: flex;
56 | margin-top: 16px;
57 | }
58 |
59 | .auctionCardDetailsNumber {
60 | font-weight: 600;
61 | font-size: 32px;
62 | line-height: 40px;
63 | }
64 |
65 | .auctionCardDetailsText {
66 | margin-top: 4px;
67 | font-size: 16px;
68 | line-height: 24px;
69 | letter-spacing: 0.02em;
70 | }
71 |
72 | .auctionCardDivider {
73 | background-color: #9f66e3;
74 | height: 109px;
75 | width: 1px;
76 | margin-right: 32px;
77 | }
78 |
79 | .CTAContainer {
80 | position: absolute;
81 | bottom: -24px;
82 | left: calc(50% - 208px);
83 | width: 416px;
84 | display: flex;
85 | align-items: center;
86 | }
87 |
88 | .contributeContainer {
89 | width: 320px;
90 | height: 64px;
91 | display: flex;
92 | justify-content: space-between;
93 | align-items: center;
94 | padding: 8px;
95 | border: 2px solid #e0e0e0;
96 | border-radius: 32px;
97 | background-color: #fff;
98 | }
99 |
100 | .contributeHeader {
101 | letter-spacing: 1px;
102 | font-size: 12px;
103 | font-weight: 600;
104 | line-height: 14px;
105 | }
106 |
107 | .contributeInput {
108 | margin-top: 5px;
109 | font-size: 20px;
110 | line-height: 20px;
111 | font-weight: 500;
112 | width: 100px;
113 | }
114 |
115 | .contributInput::placeholder {
116 | color: #e0e0e0;
117 | }
118 |
119 | .contributeCTA {
120 | flex-shrink: 0;
121 | cursor: pointer;
122 | background-color: #000;
123 | border-radius: 24px;
124 | padding: 12px 24px;
125 | color: #fff;
126 | font-weight: 600;
127 | font-size: 16px;
128 | line-height: 24px;
129 | }
130 |
131 | .actionCard {
132 | padding: 24px;
133 | width: 100%;
134 | box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.12);
135 | border-radius: 4px;
136 | text-align: center;
137 | font-weight: 500;
138 | }
139 |
--------------------------------------------------------------------------------
/pages/nft/[id]/manage.module.css:
--------------------------------------------------------------------------------
1 | .goBack {
2 | text-align: center;
3 | color: #985cff;
4 | font-size: 16px;
5 | line-height: 24px;
6 | font-weight: 500;
7 | cursor: pointer;
8 | }
9 |
10 | .header {
11 | margin-top: 8px;
12 | font-size: 48px;
13 | line-height: 64px;
14 | font-weight: 600;
15 | text-align: center;
16 | }
17 |
18 | .redeemContainer {
19 | width: 400px;
20 | height: 64px;
21 | display: flex;
22 | justify-content: space-between;
23 | align-items: center;
24 | padding: 8px;
25 | border: 2px solid #e0e0e0;
26 | border-radius: 32px;
27 | background-color: #fff;
28 | }
29 |
30 | .redeemHeader {
31 | letter-spacing: 1px;
32 | font-size: 12px;
33 | font-weight: 600;
34 | line-height: 14px;
35 | }
36 |
37 | .redeemAmount {
38 | margin-top: 5px;
39 | font-size: 20px;
40 | line-height: 20px;
41 | font-weight: 500;
42 | width: 100px;
43 | }
44 |
45 | .redeemCTA {
46 | flex-shrink: 0;
47 | background-color: #e0e0e0;
48 | border-radius: 24px;
49 | text-align: center;
50 | padding: 12px 18px;
51 | width: 140px;
52 | color: #fff;
53 | font-weight: 600;
54 | font-size: 16px;
55 | line-height: 24px;
56 | }
57 |
58 | .content {
59 | margin-top: 48px;
60 | background-color: black;
61 | padding: 64px 64px 96px 64px;
62 | width: 100vw;
63 | display: flex;
64 | justify-content: center;
65 | align-items: center;
66 | position: relative;
67 | z-index: 1;
68 | }
69 |
70 | .CTAsContainer {
71 | width: 400px;
72 | display: flex;
73 | position: absolute;
74 | top: -24px;
75 | left: calc(50% - 200px);
76 | z-index: 2;
77 | }
78 |
79 | .offerContainer {
80 | position: relative;
81 | box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.12);
82 | border-radius: 4px;
83 | padding: 24px;
84 | width: 640px;
85 | }
86 |
87 | .offerText {
88 | position: "relative";
89 | text-align: center;
90 | font-weight: 500;
91 | font-size: 16px;
92 | line-height: 24px;
93 | }
94 |
95 | .offerCTAContainer {
96 | margin-top: 16px;
97 | display: flex;
98 | justify-content: center;
99 | }
100 |
101 | .offerInfo {
102 | width: 599px;
103 | border: 1px solid #e0e0e0;
104 | border-radius: 4px;
105 | position: absolute;
106 | top: -18px;
107 | padding: 8px;
108 | color: #656464;
109 | font-size: 14px;
110 | line-height: 20px;
111 | }
112 |
113 | .claimContainer {
114 | position: absolute;
115 | top: -32px;
116 | left: calc(50% - 160px);
117 | border-radius: 32px;
118 | border: 2px solid #e0e0e0;
119 | padding: 8px;
120 | display: flex;
121 | justify-content: space-between;
122 | background-color: white;
123 | align-items: center;
124 | width: 320px;
125 | }
126 |
--------------------------------------------------------------------------------
/public/close.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/public/eth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/public/eth.png
--------------------------------------------------------------------------------
/public/eth.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/public/favicon.ico
--------------------------------------------------------------------------------
/public/filler-image-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/public/filler-image-1.png
--------------------------------------------------------------------------------
/public/filler-image-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/public/filler-image-2.png
--------------------------------------------------------------------------------
/public/footer/discord.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/public/footer/icons8-discord.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/footer/icons8-medium.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/footer/icons8-twitter.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/footer/medium.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/public/footer/twitter.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/public/fraktal-full-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/public/fraktal-full-logo.png
--------------------------------------------------------------------------------
/public/images/404_OhFrak.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/public/images/404_OhFrak.png
--------------------------------------------------------------------------------
/public/images/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/public/images/Logo.png
--------------------------------------------------------------------------------
/public/info.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/public/outlinedClose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/public/outlinedClose.png
--------------------------------------------------------------------------------
/public/sample-item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/public/sample-item.png
--------------------------------------------------------------------------------
/public/search.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/public/timer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/public/timer.png
--------------------------------------------------------------------------------
/public/trash.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/redux/actions/contractActions.ts:
--------------------------------------------------------------------------------
1 | import { Workflow } from 'types/workflow';
2 |
3 | export const APPROVED_TRANSACTION = 'APPROVED_TRANSACTION';
4 | export const CALL_CONTRACT = 'CALL_CONTRACT';
5 | export const REJECTED_CONTRACT = 'REJECTED_CONTRACT';
6 | export const ADD_AMOUNT = 'ADD_AMOUNT';
7 | export const REMOVE_AMOUNT = 'REMOVE_AMOUNT';
8 |
9 | export const COMPLETED_STATUS = 'COMPLETED';
10 | export const PENDING_STATUS = 'PENDING';
11 | export const REJECTED_STATUS = 'REJECTED';
12 |
13 | export const CLOSE_MODAL = 'CLOSE_MODAL';
14 |
15 | export const APPROVE_TOKEN = 'APPROVE_TOKEN';
16 | export const BUYING_FRAKTIONS = 'BUYING_FRAKTIONS';
17 | export const CLAIMING_BUYOUTS = 'CLAIMING_BUYOUTS';
18 | export const CLAIMING_FRAKTIONS_PROFIT = 'CLAIMING_FRAKTIONS_PROFIT';
19 | export const CLAIMING_REVENUE = 'CLAIMING_REVENUE';
20 | export const CLAIM_DEPOSITED_FRAKTIONS = 'CLAIM_DEPOSITED_FRAKTIONS';
21 | export const CLAIM_CONTRIBUTED_ETH = 'CLAIM_CONTRIBUTED_ETH';
22 | export const DEPOSIT_REVENUE = 'DEPOSIT_REVENUE';
23 | export const IMPORT_NFT = 'IMPORT_NFT';
24 |
25 | export const IMPORT_FRAKTAL = 'IMPORT_FRAKTAL';
26 | export const EXPORT_FRAKTAL = 'EXPORT_FRAKTAL';
27 |
28 | export const MINT_NFT = 'MINT_NFT';
29 | export const LISTING_NFT = 'LISTING_NFT';
30 | export const OFFERING_BUYOUT = 'OFFERING_BUYOUT';
31 | export const VOTING_BUYOUTS = 'VOTING_BUYOUTS';
32 | export const PARTICIPATE_AUCTION = 'PARTICIPATE_AUCTION';
33 |
34 | export const UNLIST_NFT = 'UNLIST_NFT';
35 | export const UNLIST_AUCTION_NFT = 'UNLIST_AUCTION_NFT';
36 | export const REJECT_OFFER = 'REJECT_OFFER';
37 |
38 | export const CLAIM_NFT = 'CLAIM_NFT';
39 |
40 | export type ActionOpts = { workflow?: Workflow, custom?: any };
41 |
42 | export const callContract = (
43 | transactionType,
44 | obj,
45 | opts: ActionOpts = {}
46 | ) => {
47 | return {
48 | obj: obj,
49 | transactionType,
50 | type: CALL_CONTRACT,
51 | ...opts,
52 | };
53 | };
54 |
55 | export const rejectContract = (
56 | transactionType,
57 | obj,
58 | buttonAction?: any,
59 | opts: ActionOpts = {}
60 | ) => {
61 | return {
62 | obj: obj,
63 | transactionType,
64 | buttonAction,
65 | type: REJECTED_CONTRACT,
66 | ...opts,
67 | };
68 | };
69 |
70 | export const approvedTransaction = (
71 | transactionType,
72 | obj,
73 | tokenAddress?: string,
74 | opts: ActionOpts = {}
75 | ) => {
76 | return {
77 | obj: obj,
78 | transactionType,
79 | tokenAddress,
80 | type: APPROVED_TRANSACTION,
81 | ...opts,
82 | };
83 | };
84 |
85 | export const closeModal = () => {
86 | return {
87 | type: CLOSE_MODAL,
88 | };
89 | };
90 |
91 | export const addAmount = (amount) => {
92 | return {
93 | amount,
94 | type: ADD_AMOUNT,
95 | };
96 | };
97 |
98 | export const removeAmount = () => {
99 | return {
100 | type: REMOVE_AMOUNT,
101 | };
102 | };
103 |
--------------------------------------------------------------------------------
/redux/reducers/index.ts:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux'
2 | import loadingScreenReducer from './loadingScreenReducer'
3 |
4 | export default combineReducers({
5 | loadingScreen: loadingScreenReducer
6 | });
--------------------------------------------------------------------------------
/redux/store.ts:
--------------------------------------------------------------------------------
1 | import { createStore, compose } from 'redux';
2 |
3 | import rootReducer from '../redux/reducers/index';
4 |
5 | let composeEnhancers = compose;
6 | if (typeof window !== 'undefined') {
7 | composeEnhancers =
8 | (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
9 | }
10 |
11 | const store = createStore(rootReducer, composeEnhancers());
12 |
13 | export default store;
14 |
--------------------------------------------------------------------------------
/stories/Button.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ComponentStory, ComponentMeta } from '@storybook/react';
3 |
4 | import { Button } from './Button';
5 |
6 | // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
7 | export default {
8 | title: 'Example/Button',
9 | component: Button,
10 | // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
11 | argTypes: {
12 | backgroundColor: { control: 'color' },
13 | },
14 | } as ComponentMeta;
15 |
16 | // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
17 | const Template: ComponentStory = (args) => ;
18 |
19 | export const Primary = Template.bind({});
20 | // More on args: https://storybook.js.org/docs/react/writing-stories/args
21 | Primary.args = {
22 | primary: true,
23 | label: 'Button',
24 | };
25 |
26 | export const Secondary = Template.bind({});
27 | Secondary.args = {
28 | label: 'Button',
29 | };
30 |
31 | export const Large = Template.bind({});
32 | Large.args = {
33 | size: 'large',
34 | label: 'Button',
35 | };
36 |
37 | export const Small = Template.bind({});
38 | Small.args = {
39 | size: 'small',
40 | label: 'Button',
41 | };
42 |
--------------------------------------------------------------------------------
/stories/Button.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './button.css';
3 |
4 | interface ButtonProps {
5 | /**
6 | * Is this the principal call to action on the page?
7 | */
8 | primary?: boolean;
9 | /**
10 | * What background color to use
11 | */
12 | backgroundColor?: string;
13 | /**
14 | * How large should the button be?
15 | */
16 | size?: 'small' | 'medium' | 'large';
17 | /**
18 | * Button contents
19 | */
20 | label: string;
21 | /**
22 | * Optional click handler
23 | */
24 | onClick?: () => void;
25 | }
26 |
27 | /**
28 | * Primary UI component for user interaction
29 | */
30 | export const Button = ({
31 | primary = false,
32 | size = 'medium',
33 | backgroundColor,
34 | label,
35 | ...props
36 | }: ButtonProps) => {
37 | const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
38 | return (
39 |
45 | {label}
46 |
47 | );
48 | };
49 |
--------------------------------------------------------------------------------
/stories/Header.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ComponentStory, ComponentMeta } from '@storybook/react';
3 |
4 | import { Header } from './Header';
5 |
6 | export default {
7 | title: 'Example/Header',
8 | component: Header,
9 | } as ComponentMeta;
10 |
11 | const Template: ComponentStory = (args) => ;
12 |
13 | export const LoggedIn = Template.bind({});
14 | LoggedIn.args = {
15 | user: {},
16 | };
17 |
18 | export const LoggedOut = Template.bind({});
19 | LoggedOut.args = {};
20 |
--------------------------------------------------------------------------------
/stories/Header.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { Button } from './Button';
4 | import './header.css';
5 |
6 | interface HeaderProps {
7 | user?: {};
8 | onLogin: () => void;
9 | onLogout: () => void;
10 | onCreateAccount: () => void;
11 | }
12 |
13 | export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (
14 |
47 | );
48 |
--------------------------------------------------------------------------------
/stories/NFTDetailRevenue.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ComponentStory, ComponentMeta } from "@storybook/react";
3 | import { ChakraProvider, extendTheme, VStack } from "@chakra-ui/react";
4 | import Footer from "../components/footer";
5 | import "../styles/globals.css";
6 | import "../styles/fonts.css";
7 | import Web3ContextProvider from "../contexts/Web3Context";
8 | import Layout from "../components/layout";
9 |
10 | import RevenuesList from "../components/revenuesList";
11 |
12 | const customTheme = extendTheme({
13 | colors: {
14 | white: {
15 | 100: "#E0E0E0",
16 | 500: "#F9F9F9",
17 | 900: "#fff",
18 | },
19 | black: {
20 | 500: "#656464",
21 | 900: "#000",
22 | },
23 | red: {
24 | 900: "#FF0000",
25 | },
26 | },
27 | });
28 |
29 | // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
30 | export default {
31 | title: "Components/NFT Detail Revenue",
32 | component: RevenuesList,
33 | // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
34 | argTypes: {
35 | revenuesCreated: { type: "array" },
36 | tokenAddress: { type: "string" },
37 | },
38 | } as ComponentMeta;
39 |
40 | // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
41 | const Template: ComponentStory = args => (
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | );
53 |
54 | export const Primary = Template.bind({});
55 | // More on args: https://storybook.js.org/docs/react/writing-stories/args
56 | Primary.args = {
57 | revenuesCreated: [
58 | {
59 | buyout: "false",
60 | creator: { id: "0xbc4a2b0b65e39bae9bedad1798b824eaf0a60639" },
61 | id: "0x45bdd2a4ef0e8e4ff35ac81f2ff333a8ee8e9adc",
62 | timestamp: "1635966464",
63 | tokenAddress: "0x7e371bd4bb49c8c1fb1f25e104ccb233885779e8",
64 | value: "1000000000000000",
65 | },
66 | ],
67 | tokenAddress: "0x7e371bd4bb49c8c1fb1f25e104ccb233885779e8",
68 | };
69 |
--------------------------------------------------------------------------------
/stories/NFTDetails.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ComponentStory, ComponentMeta } from "@storybook/react";
3 | import { ChakraProvider, extendTheme, VStack } from "@chakra-ui/react";
4 | import Footer from "../components/footer";
5 | import "../styles/globals.css";
6 | import "../styles/fonts.css";
7 | import Web3ContextProvider from "../contexts/Web3Context";
8 | import Layout from "../components/layout";
9 |
10 | import RevenuesList from "../components/revenuesList";
11 |
12 | const customTheme = extendTheme({
13 | colors: {
14 | white: {
15 | 100: "#E0E0E0",
16 | 500: "#F9F9F9",
17 | 900: "#fff",
18 | },
19 | black: {
20 | 500: "#656464",
21 | 900: "#000",
22 | },
23 | red: {
24 | 900: "#FF0000",
25 | },
26 | },
27 | });
28 |
29 | // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
30 | export default {
31 | title: "Components/NFT Detail Revenue",
32 | component: RevenuesList,
33 | // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
34 | argTypes: {
35 | revenuesCreated: { type: "array" },
36 | tokenAddress: { type: "string" },
37 | },
38 | } as ComponentMeta;
39 |
40 | // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
41 | const Template: ComponentStory = args => (
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | );
53 |
54 | export const Primary = Template.bind({});
55 | // More on args: https://storybook.js.org/docs/react/writing-stories/args
56 | Primary.args = {
57 | revenuesCreated: [
58 | {
59 | buyout: "false",
60 | creator: { id: "0xbc4a2b0b65e39bae9bedad1798b824eaf0a60639" },
61 | id: "0x45bdd2a4ef0e8e4ff35ac81f2ff333a8ee8e9adc",
62 | timestamp: "1635966464",
63 | tokenAddress: "0x7e371bd4bb49c8c1fb1f25e104ccb233885779e8",
64 | value: "1000000000000000",
65 | },
66 | ],
67 | tokenAddress: "0x7e371bd4bb49c8c1fb1f25e104ccb233885779e8",
68 | };
69 |
--------------------------------------------------------------------------------
/stories/Page.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ComponentStory, ComponentMeta } from '@storybook/react';
3 |
4 | import { Page } from './Page';
5 | import * as HeaderStories from './Header.stories';
6 |
7 | export default {
8 | title: 'Example/Page',
9 | component: Page,
10 | } as ComponentMeta;
11 |
12 | const Template: ComponentStory = (args) => ;
13 |
14 | export const LoggedIn = Template.bind({});
15 | LoggedIn.args = {
16 | // More on composing args: https://storybook.js.org/docs/react/writing-stories/args#args-composition
17 | ...HeaderStories.LoggedIn.args,
18 | };
19 |
20 | export const LoggedOut = Template.bind({});
21 | LoggedOut.args = {
22 | ...HeaderStories.LoggedOut.args,
23 | };
24 |
--------------------------------------------------------------------------------
/stories/Page.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { Header } from './Header';
4 | import './page.css';
5 |
6 | interface PageProps {
7 | user?: {};
8 | onLogin: () => void;
9 | onLogout: () => void;
10 | onCreateAccount: () => void;
11 | }
12 |
13 | export const Page = ({ user, onLogin, onLogout, onCreateAccount }: PageProps) => (
14 |
15 |
16 |
17 |
18 | Pages in Storybook
19 |
20 | We recommend building UIs with a{' '}
21 |
22 | component-driven
23 | {' '}
24 | process starting with atomic components and ending with pages.
25 |
26 |
27 | Render pages with mock data. This makes it easy to build and review page states without
28 | needing to navigate to them in your app. Here are some handy patterns for managing page data
29 | in Storybook:
30 |
31 |
32 |
33 | Use a higher-level connected component. Storybook helps you compose such data from the
34 | "args" of child component stories
35 |
36 |
37 | Assemble data in the page component from your services. You can mock these services out
38 | using Storybook.
39 |
40 |
41 |
42 | Get a guided tutorial on component-driven development at{' '}
43 |
44 | Storybook tutorials
45 |
46 | . Read more in the{' '}
47 |
48 | docs
49 |
50 | .
51 |
52 |
53 |
Tip Adjust the width of the canvas with the{' '}
54 |
55 |
56 |
61 |
62 |
63 | Viewports addon in the toolbar
64 |
65 |
66 |
67 | );
68 |
--------------------------------------------------------------------------------
/stories/assets/code-brackets.svg:
--------------------------------------------------------------------------------
1 | illustration/code-brackets
--------------------------------------------------------------------------------
/stories/assets/comments.svg:
--------------------------------------------------------------------------------
1 | illustration/comments
--------------------------------------------------------------------------------
/stories/assets/direction.svg:
--------------------------------------------------------------------------------
1 | illustration/direction
--------------------------------------------------------------------------------
/stories/assets/flow.svg:
--------------------------------------------------------------------------------
1 | illustration/flow
--------------------------------------------------------------------------------
/stories/assets/plugin.svg:
--------------------------------------------------------------------------------
1 | illustration/plugin
--------------------------------------------------------------------------------
/stories/assets/repo.svg:
--------------------------------------------------------------------------------
1 | illustration/repo
--------------------------------------------------------------------------------
/stories/assets/stackalt.svg:
--------------------------------------------------------------------------------
1 | illustration/stackalt
--------------------------------------------------------------------------------
/stories/button.css:
--------------------------------------------------------------------------------
1 | .storybook-button {
2 | font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
3 | font-weight: 700;
4 | border: 0;
5 | border-radius: 3em;
6 | cursor: pointer;
7 | display: inline-block;
8 | line-height: 1;
9 | }
10 | .storybook-button--primary {
11 | color: white;
12 | background-color: #1ea7fd;
13 | }
14 | .storybook-button--secondary {
15 | color: #333;
16 | background-color: transparent;
17 | box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;
18 | }
19 | .storybook-button--small {
20 | font-size: 12px;
21 | padding: 10px 16px;
22 | }
23 | .storybook-button--medium {
24 | font-size: 14px;
25 | padding: 11px 20px;
26 | }
27 | .storybook-button--large {
28 | font-size: 16px;
29 | padding: 12px 24px;
30 | }
31 |
--------------------------------------------------------------------------------
/stories/header.css:
--------------------------------------------------------------------------------
1 | .wrapper {
2 | font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
3 | border-bottom: 1px solid rgba(0, 0, 0, 0.1);
4 | padding: 15px 20px;
5 | display: flex;
6 | align-items: center;
7 | justify-content: space-between;
8 | }
9 |
10 | svg {
11 | display: inline-block;
12 | vertical-align: top;
13 | }
14 |
15 | h1 {
16 | font-weight: 900;
17 | font-size: 20px;
18 | line-height: 1;
19 | margin: 6px 0 6px 10px;
20 | display: inline-block;
21 | vertical-align: top;
22 | }
23 |
24 | button + button {
25 | margin-left: 10px;
26 | }
27 |
--------------------------------------------------------------------------------
/stories/page.css:
--------------------------------------------------------------------------------
1 | section {
2 | font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
3 | font-size: 14px;
4 | line-height: 24px;
5 | padding: 48px 20px;
6 | margin: 0 auto;
7 | max-width: 600px;
8 | color: #333;
9 | }
10 |
11 | h2 {
12 | font-weight: 900;
13 | font-size: 32px;
14 | line-height: 1;
15 | margin: 0 0 4px;
16 | display: inline-block;
17 | vertical-align: top;
18 | }
19 |
20 | p {
21 | margin: 1em 0;
22 | }
23 |
24 | a {
25 | text-decoration: none;
26 | color: #1ea7fd;
27 | }
28 |
29 | ul {
30 | padding-left: 30px;
31 | margin: 1em 0;
32 | }
33 |
34 | li {
35 | margin-bottom: 8px;
36 | }
37 |
38 | .tip {
39 | display: inline-block;
40 | border-radius: 1em;
41 | font-size: 11px;
42 | line-height: 12px;
43 | font-weight: 700;
44 | background: #e7fdd8;
45 | color: #66bf3c;
46 | padding: 4px 12px;
47 | margin-right: 10px;
48 | vertical-align: top;
49 | }
50 |
51 | .tip-wrapper {
52 | font-size: 13px;
53 | line-height: 20px;
54 | margin-top: 40px;
55 | margin-bottom: 40px;
56 | }
57 |
58 | .tip-wrapper svg {
59 | display: inline-block;
60 | height: 12px;
61 | width: 12px;
62 | margin-right: 4px;
63 | vertical-align: top;
64 | margin-top: 3px;
65 | }
66 |
67 | .tip-wrapper svg path {
68 | fill: #1ea7fd;
69 | }
70 |
--------------------------------------------------------------------------------
/styles/artists.module.css:
--------------------------------------------------------------------------------
1 | .searchContainer {
2 | border-radius: 32px;
3 | border: 2px solid #e0e0e0;
4 | display: flex;
5 | align-items: center;
6 | justify-content: space-between;
7 | width: 300px;
8 | padding: 12px 16px 12px 24px;
9 | }
10 |
11 | .searchInput {
12 | margin-right: 16px;
13 | width: 100%;
14 | font-weight: 500;
15 | font-size: 16px;
16 | line-height: 24px;
17 | }
18 |
19 | .searchInput::placeholder {
20 | color: #e0e0e0;
21 | }
22 |
--------------------------------------------------------------------------------
/styles/fonts.css:
--------------------------------------------------------------------------------
1 | .semi-48 {
2 | /* Desk/Semi 48-64 */
3 | font-family: Inter !important;
4 | font-style: normal !important;
5 | font-weight: 600 !important;
6 | font-size: 36px !important;
7 | line-height: 6.4rem !important;
8 | /* identical to box height, or 133% */
9 | }
10 |
11 | .semi-32 {
12 | /* Desk/Semi 32–40 */
13 | font-family: Inter !important;
14 | font-style: normal !important;
15 | font-weight: 600 !important;
16 | font-size: 32px !important;
17 | line-height: 4rem !important;
18 | /* identical to box height, or 125% */
19 | }
20 |
21 | .semi-21 {
22 | /* Desk/Regular 21–32 */
23 | font-family: Inter !important;
24 | font-style: normal !important;
25 | font-weight: normal !important;
26 | font-size: 2.1rem !important;
27 | line-height: 3.2rem !important;
28 | /* identical to box height, or 152% */
29 | }
30 |
31 | .medium-16 {
32 | /* Desk/Medium 16-24 */
33 | font-family: Inter !important;
34 | font-style: normal !important;
35 | font-weight: 500 !important;
36 | font-size: 1.6rem !important;
37 | line-height: 2.4rem !important;
38 | /* identical to box height, or 150% */
39 | }
40 |
41 | .regular-16 {
42 | /* Desk/Regular 16–24 */
43 | font-family: Inter !important;
44 | font-style: normal !important;
45 | font-weight: normal !important;
46 | font-size: 1.6rem !important;
47 | line-height: 2.4rem !important;
48 | /* identical to box height, or 150% */
49 | letter-spacing: 0.02em !important;
50 | }
51 |
52 | .regular-14 {
53 | /* Desk/Regular 14–20 */
54 | font-family: Inter !important;
55 | font-style: normal !important;
56 | font-weight: normal !important;
57 | font-size: 1.4rem !important;
58 | line-height: 2rem !important;
59 | /* identical to box height, or 143% */
60 | }
61 |
62 | .medium-upper-14 {
63 | /* Desk/Medium Uppercase 14–14 */
64 | font-family: Roboto Mono !important;
65 | font-style: normal !important;
66 | font-weight: 500 !important;
67 | font-size: 1.4rem !important;
68 | line-height: 1.4rem !important;
69 | /* identical to box height, or 100% */
70 | letter-spacing: 1px !important;
71 | text-transform: uppercase !important;
72 |
73 | color: #c4c4c4 !important;
74 | }
75 |
76 | .semi-16 {
77 | /* Desk/Semi 16–24 */
78 | font-family: Inter !important;
79 | font-style: normal !important;
80 | font-weight: 600 !important;
81 | font-size: 1.6rem !important;
82 | line-height: 2.4rem !important;
83 | /* identical to box height, or 150% */
84 | }
85 |
86 | .medium-upper-12 {
87 | /* Desk/Med Upper 12–14 */
88 | font-family: Inter !important;
89 | font-style: normal !important;
90 | font-weight: 600 !important;
91 | font-size: 1.2rem !important;
92 | line-height: 1.4rem !important;
93 | /* identical to box height, or 117% */
94 | letter-spacing: 1px !important;
95 | text-transform: uppercase !important;
96 | }
97 |
98 | .medium-mob-32 {
99 | /* Mob/Medium 32–40 */
100 | font-family: Roboto Mono !important;
101 | font-style: normal !important;
102 | font-weight: 500 !important;
103 | font-size: 3.2rem !important;
104 | line-height: 4rem !important;
105 | /* identical to box height, or 125% */
106 | color: #c4c4c4 !important;
107 | }
108 |
109 | .regular-mob-14 {
110 | /* Mob/Regular 14–20 */
111 | font-family: Roboto Mono !important;
112 | font-style: normal !important;
113 | font-weight: normal !important;
114 | font-size: 1.4rem !important;
115 | line-height: 2rem !important;
116 | /* identical to box height, or 143% */
117 | color: #c4c4c4 !important;
118 | }
119 |
120 | .medium-mob-14 {
121 | /* Mob/Medium 14–20 */
122 | font-family: Roboto Mono !important;
123 | font-style: normal !important;
124 | font-weight: 500 !important;
125 | font-size: 1.4rem !important;
126 | line-height: 2rem !important;
127 | /* identical to box height, or 143% */
128 | color: #c4c4c4 !important;
129 | }
130 |
131 | .medium-mob-upper-10 {
132 | /* Mob/Medium Uppercase 10–10 */
133 | font-family: Roboto Mono !important;
134 | font-style: normal !important;
135 | font-weight: 500 !important;
136 | font-size: 1rem !important;
137 | line-height: 1rem !important;
138 | /* identical to box height, or 100% */
139 | letter-spacing: 2px !important;
140 | color: #c4c4c4 !important;
141 | }
142 |
143 | .jos-bold-56 {
144 | /* Land/Josefina Bold 56-56 */
145 | font-family: Inter !important;
146 | font-style: normal !important;
147 | font-weight: bold !important;
148 | font-size: 4.8rem !important;
149 | line-height: 5.6rem !important;
150 | /* identical to box height, or 117% */
151 | color: #000000 !important;
152 | }
153 |
--------------------------------------------------------------------------------
/styles/landing.module.css:
--------------------------------------------------------------------------------
1 | .ladingLeft {
2 | margin:auto;
3 | }
4 | .landingHeading {
5 | font-family: "Inter";
6 | font-style: normal;
7 | font-weight: 600;
8 | font-size: 48px;
9 | line-height: 64px;
10 | }
11 | .landingButtonContainer {
12 | margin: 30px 0;
13 | }
14 | .landingPowered {
15 | font-family: "Inter";
16 | font-style: normal;
17 | font-weight: 600;
18 | font-size: 16px;
19 | line-height: 24px;
20 | margin: 16px 0;
21 | }
22 | .landingItems li {
23 | font-family: "Inter";
24 | font-style: normal;
25 | font-weight: 500;
26 | font-size: 16px;
27 | line-height: 24px;
28 | color: #985CFF;
29 | margin-left: 5px;
30 | }
--------------------------------------------------------------------------------
/styles/mint-nft.module.css:
--------------------------------------------------------------------------------
1 | .header {
2 | font-weight: 600;
3 | font-size: 48px;
4 | line-height: 64px;
5 | text-align: center;
6 | }
7 |
8 | .inputHeader {
9 | color: #656464;
10 | margin-bottom: 8px;
11 | font-weight: 600;
12 | font-size: 12px;
13 | line-height: 14px;
14 | letter-spacing: 1px;
15 | }
16 |
17 | .input {
18 | border: 2px solid #e0e0e0;
19 | border-radius: 4px;
20 | width: 466px;
21 | height: 64px;
22 | font-size: 16px;
23 | font-weight: 500;
24 | padding: 16px;
25 | }
26 |
27 | .uploadContainer {
28 | border: 1px solid #e0e0e0;
29 | border-radius: 4px;
30 | padding: 24px;
31 | width: 466px;
32 | position: relative;
33 | }
34 |
--------------------------------------------------------------------------------
/styles/my-nfts.module.css:
--------------------------------------------------------------------------------
1 | .header {
2 | text-align: left;
3 | font-size: 48px;
4 | line-height: 64px;
5 | font-weight: 600;
6 | }
7 |
8 | .descText {
9 | font-weight: 500;
10 | font-size: 16px;
11 | line-height: 24px;
12 | text-align: center;
13 | }
14 |
15 | .header2 {
16 | margin-top: 80px !important;
17 | text-align: center;
18 | font-size: 32px;
19 | line-height: 40px;
20 | font-weight: 600;
21 | }
22 |
23 | .subText {
24 | text-align: center;
25 | font-weight: 500;
26 | font-size: 16px;
27 | line-height: 24px;
28 | }
29 |
30 | .claimContainer {
31 | width: 320px;
32 | height: 64px;
33 | display: flex;
34 | justify-content: space-between;
35 | align-items: center;
36 | padding: 8px;
37 | border: 2px solid #e0e0e0;
38 | border-radius: 32px;
39 | background-color: #fff;
40 | }
41 |
42 | .claimHeader {
43 | letter-spacing: 1px;
44 | font-size: 12px;
45 | font-weight: 600;
46 | line-height: 14px;
47 | }
48 |
49 | .claimAmount {
50 | margin-top: 5px;
51 | font-size: 20px;
52 | line-height: 20px;
53 | font-weight: 500;
54 | width: 100px;
55 | }
56 |
57 | .claimCTA {
58 | flex-shrink: 0;
59 | background-color: #000;
60 | border-radius: 24px;
61 | text-align: center;
62 | padding: 12px 24px;
63 | width: 140px;
64 | color: #fff;
65 | font-weight: 600;
66 | font-size: 16px;
67 | cursor: pointer;
68 | line-height: 24px;
69 | }
70 |
--------------------------------------------------------------------------------
/styles/rewards.module.css:
--------------------------------------------------------------------------------
1 | .stakedText {
2 | font-family: "Inter";
3 | font-style: normal;
4 | font-weight: 600;
5 | font-size: 12px;
6 | line-height: 14px;
7 | text-align: center;
8 | letter-spacing: 1px;
9 | text-transform: uppercase;
10 | color: #A7A7A7;
11 | }
12 |
13 | .apr {
14 | text-overflow: ellipsis;
15 | white-space: nowrap;
16 | font-family: "Inter";
17 | font-style: normal;
18 | font-weight: 600;
19 | font-size: 32px;
20 | line-height: 40px;
21 | text-align: center;
22 | background-color: #C387FF;
23 | background-image: linear-gradient(90deg, #C387FF, #985CFF);
24 | background-size: 100%;
25 | -webkit-background-clip: text;
26 | -moz-background-clip: text;
27 | -webkit-text-fill-color: transparent;
28 | -moz-text-fill-color: transparent;
29 | }
30 |
31 | .stakedText {
32 | font-family: "Inter";
33 | font-style: normal;
34 | font-weight: 600;
35 | font-size: 12px;
36 | line-height: 14px;
37 | text-align: center;
38 | letter-spacing: 1px;
39 | text-transform: uppercase;
40 | color: #A7A7A7;
41 | }
42 |
43 | .stakedQuantity {
44 | font-family: "Inter";
45 | font-size: 16px;
46 | font-style: normal;
47 | font-weight: 500;
48 | line-height: 24px;
49 | letter-spacing: 0em;
50 | text-align: center;
51 | }
52 | .hoursMinutes {
53 | font-size: 12px;
54 | line-height: 14px;
55 | text-align: center;
56 | letter-spacing: 1px;
57 | text-transform: uppercase;
58 | color: #A7A7A7;
59 | }
60 | .countdown {
61 | font-size: 48px;
62 | line-height: 64px;
63 | background-color: #C387FF;
64 | background-image: linear-gradient(90deg, #C387FF, #985CFF);
65 | background-size: 100%;
66 | -webkit-background-clip: text;
67 | -moz-background-clip: text;
68 | -webkit-text-fill-color: transparent;
69 | -moz-text-fill-color: transparent;
70 | }
71 | .tabButtons {
72 | border-bottom: 1px solid #E0E0E0;
73 | }
74 | .tabButtons button, .cardTitle {
75 | font-style: normal;
76 | font-weight: 600;
77 | font-size: 16px;
78 | line-height: 35px;
79 | text-align: center;
80 | color: #405466;
81 | width: 150px;
82 | margin: auto;
83 | }
84 | .cardTitle {
85 | padding:8px 0;
86 | width: 300px;
87 | border-bottom: 1px solid #E0E0E0;
88 | }
89 | .stackedContainer {
90 | padding: 8px 24px;
91 | }
--------------------------------------------------------------------------------
/testnetfraktalauction/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/testnetfraktalauction/build/Contract/Contract.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/testnetfraktalauction/build/Contract/Contract.wasm
--------------------------------------------------------------------------------
/testnetfraktalauction/build/schema.graphql:
--------------------------------------------------------------------------------
1 | type Auction @entity {
2 | id: ID!
3 | seller: String!
4 | tokenAddress: String!
5 | reservePrice: BigInt!
6 | amountOfShare: BigInt!
7 | endTime: BigInt!
8 | sellerNonce: BigInt!
9 | auctionReserve: BigInt!
10 | participants: [String!]!
11 | }
12 |
13 | type FraktalNFT @entity{
14 | id:ID!
15 | hash: String!
16 | }
17 |
18 | type FactoryContract @entity{
19 | id:ID!
20 | address: String!
21 | }
--------------------------------------------------------------------------------
/testnetfraktalauction/build/subgraph.yaml:
--------------------------------------------------------------------------------
1 | specVersion: 0.0.2
2 | schema:
3 | file: schema.graphql
4 | dataSources:
5 | - kind: ethereum
6 | name: Contract
7 | network: rinkeby
8 | source:
9 | address: "0x2EaA5E7A501eFA561B775aEE95eeF6a113bDd0e4"
10 | abi: Contract
11 | startBlock: 9908990
12 | mapping:
13 | kind: ethereum/events
14 | apiVersion: 0.0.5
15 | language: wasm/assemblyscript
16 | entities:
17 | - AdminWithdrawFees
18 | - AuctionContribute
19 | - AuctionItemListed
20 | - Bought
21 | - Deployed
22 | - FeeUpdated
23 | - FraktalClaimed
24 | - ItemListed
25 | - OfferMade
26 | - OfferVoted
27 | - OwnershipTransferred
28 | - SellerPaymentPull
29 | abis:
30 | - name: Contract
31 | file: Contract/abis/Contract.json
32 | eventHandlers:
33 | - event: AdminWithdrawFees(uint256)
34 | handler: handleAdminWithdrawFees
35 | - event: AuctionContribute(address,address,address,uint256,uint256)
36 | handler: handleAuctionContribute
37 | - event: AuctionItemListed(address,address,uint256,uint256,uint256,uint256)
38 | handler: handleAuctionItemListed
39 | - event: Bought(address,address,address,uint256)
40 | handler: handleBought
41 | - event: Deployed()
42 | handler: handleDeployed
43 | - event: FeeUpdated(uint16)
44 | handler: handleFeeUpdated
45 | - event: FraktalClaimed(address,address)
46 | handler: handleFraktalClaimed
47 | - event: ItemListed(address,address,uint256,uint256)
48 | handler: handleItemListed
49 | - event: OfferMade(address,address,uint256)
50 | handler: handleOfferMade
51 | - event: OfferVoted(address,address,address,bool)
52 | handler: handleOfferVoted
53 | - event: OwnershipTransferred(indexed address,indexed address)
54 | handler: handleOwnershipTransferred
55 | - event: SellerPaymentPull(address,uint256)
56 | handler: handleSellerPaymentPull
57 | file: Contract/Contract.wasm
58 | templates:
59 | - name: Factory
60 | kind: ethereum/contract
61 | network: rinkeby
62 | source:
63 | abi: Factory
64 | mapping:
65 | kind: ethereum/events
66 | apiVersion: 0.0.5
67 | language: wasm/assemblyscript
68 | file: templates/Factory/Factory.wasm
69 | entities:
70 | - Factory
71 | abis:
72 | - name: Factory
73 | file: Factory/abis/Factory.json
74 | eventHandlers:
75 | - event: Minted(address,string,address,uint256)
76 | handler: handleMinted
77 |
--------------------------------------------------------------------------------
/testnetfraktalauction/build/templates/Factory/Factory.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FraktalNFT/dapp-frontend/a2d5bf179875d9744246194278f8e559e0f2b5e0/testnetfraktalauction/build/templates/Factory/Factory.wasm
--------------------------------------------------------------------------------
/testnetfraktalauction/generated/templates.ts:
--------------------------------------------------------------------------------
1 | // THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 |
3 | import {
4 | Address,
5 | DataSourceTemplate,
6 | DataSourceContext
7 | } from "@graphprotocol/graph-ts";
8 |
9 | export class Factory extends DataSourceTemplate {
10 | static create(address: Address): void {
11 | DataSourceTemplate.create("Factory", [address.toHex()]);
12 | }
13 |
14 | static createWithContext(address: Address, context: DataSourceContext): void {
15 | DataSourceTemplate.createWithContext("Factory", [address.toHex()], context);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/testnetfraktalauction/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "testnetfraktalauction",
3 | "license": "UNLICENSED",
4 | "scripts": {
5 | "codegen": "graph codegen",
6 | "build": "graph build",
7 | "deploy": "graph deploy --node https://api.studio.thegraph.com/deploy/ testnetfraktalauction",
8 | "create-local": "graph create --node http://localhost:8020/ testnetfraktalauction",
9 | "remove-local": "graph remove --node http://localhost:8020/ testnetfraktalauction",
10 | "deploy-local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 testnetfraktalauction"
11 | },
12 | "dependencies": {
13 | "@graphprotocol/graph-cli": "0.25.1",
14 | "@graphprotocol/graph-ts": "0.24.1"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/testnetfraktalauction/schema.graphql:
--------------------------------------------------------------------------------
1 | type Auction @entity {
2 | id: ID!
3 | seller: String!
4 | tokenAddress: String!
5 | reservePrice: BigInt!
6 | amountOfShare: BigInt!
7 | endTime: BigInt!
8 | sellerNonce: BigInt!
9 | auctionReserve: BigInt!
10 | participants: [String!]!
11 | }
12 |
13 | type FraktalNFT @entity{
14 | id:ID!
15 | hash: String!
16 | }
17 |
18 | type FactoryContract @entity{
19 | id:ID!
20 | address: String!
21 | }
--------------------------------------------------------------------------------
/testnetfraktalauction/src/mapping.ts:
--------------------------------------------------------------------------------
1 | import { BigInt,Address } from "@graphprotocol/graph-ts"
2 | import { Factory } from "../generated/templates";
3 | import {
4 | Contract,
5 | AdminWithdrawFees,
6 | AuctionContribute,
7 | AuctionItemListed,
8 | Bought,
9 | Deployed,
10 | FeeUpdated,
11 | FraktalClaimed,
12 | ItemListed,
13 | OfferMade,
14 | OfferVoted,
15 | OwnershipTransferred,
16 | SellerPaymentPull
17 | } from "../generated/Contract/Contract"
18 | import { Auction, FactoryContract } from "../generated/schema"
19 |
20 | export function handleAdminWithdrawFees(event: AdminWithdrawFees): void {
21 | }
22 |
23 | export function handleAuctionContribute(event: AuctionContribute): void {
24 | let participant = event.params.participant.toHexString();
25 | // let tokenAddress = event.params.tokenAddress;
26 | let seller = event.params.seller.toHexString();
27 | let sellerNonce = event.params.sellerNonce.toString();
28 | // let participantContribution = event.params.value;
29 |
30 | let entity = Auction.load(`${seller}-${sellerNonce}`);
31 | if(entity == null){
32 | entity = new Auction(`${seller}-${sellerNonce}`);
33 | }
34 |
35 | let _participants = entity.participants;
36 | if(_participants)
37 | _participants.push(participant);
38 |
39 | if(entity){
40 | entity.participants = _participants;
41 | entity.save();
42 | }
43 | }
44 |
45 | export function handleAuctionItemListed(event: AuctionItemListed): void {
46 | let nonceString = event.params.nonce.toString();
47 | let sellerString = event.params.owner.toHexString();
48 | let id = sellerString+'-'+nonceString;
49 | let entity = Auction.load(id);
50 |
51 | if(entity == null){
52 | entity = new Auction(id);
53 | entity.auctionReserve = BigInt.fromI32(0);
54 | entity.participants = [];
55 | }
56 |
57 |
58 | entity.seller = event.params.owner.toHexString();
59 | entity.tokenAddress = event.params.tokenAddress.toHexString();
60 | entity.reservePrice = event.params.reservePrice;
61 | entity.amountOfShare = event.params.amountOfShares;
62 | entity.endTime = event.params.endTime;
63 | entity.sellerNonce = event.params.nonce;
64 |
65 | entity.save();
66 | }
67 |
68 | export function handleBought(event: Bought): void {}
69 |
70 | export function handleDeployed(event: Deployed): void {
71 | let entity = new FactoryContract("factory");
72 | entity.address = "0xd8646ea0064538ec100881893d98537f611c53bc";
73 | entity.save();
74 | Factory.create(Address.fromString("0xd8646ea0064538ec100881893d98537f611c53bc"));
75 | }
76 |
77 | export function handleFeeUpdated(event: FeeUpdated): void {}
78 |
79 | export function handleFraktalClaimed(event: FraktalClaimed): void {}
80 |
81 | export function handleItemListed(event: ItemListed): void {}
82 |
83 | export function handleOfferMade(event: OfferMade): void {}
84 |
85 | export function handleOfferVoted(event: OfferVoted): void {}
86 |
87 | export function handleOwnershipTransferred(event: OwnershipTransferred): void {}
88 |
89 | export function handleSellerPaymentPull(event: SellerPaymentPull): void {}
90 |
--------------------------------------------------------------------------------
/testnetfraktalauction/src/mappings/factory.ts:
--------------------------------------------------------------------------------
1 | import {Minted} from '../../generated/templates/Factory/Factory'
2 | import {FraktalNFT} from '../../generated/schema'
3 |
4 | export function handleMinted(event: Minted): void{
5 |
6 | let nft = FraktalNFT.load(event.params.tokenAddress.toHexString());
7 | if(nft==null){
8 | nft = new FraktalNFT(event.params.tokenAddress.toHexString());
9 | }
10 | nft.hash = event.params.urlIpfs;
11 | nft.save();
12 |
13 | }
--------------------------------------------------------------------------------
/testnetfraktalauction/subgraph.yaml:
--------------------------------------------------------------------------------
1 | specVersion: 0.0.2
2 | schema:
3 | file: ./schema.graphql
4 | dataSources:
5 | - kind: ethereum
6 | name: Contract
7 | network: rinkeby
8 | source:
9 | address: "0x2EaA5E7A501eFA561B775aEE95eeF6a113bDd0e4"
10 | abi: Contract
11 | startBlock: 9908990
12 | mapping:
13 | kind: ethereum/events
14 | apiVersion: 0.0.5
15 | language: wasm/assemblyscript
16 | entities:
17 | - AdminWithdrawFees
18 | - AuctionContribute
19 | - AuctionItemListed
20 | - Bought
21 | - Deployed
22 | - FeeUpdated
23 | - FraktalClaimed
24 | - ItemListed
25 | - OfferMade
26 | - OfferVoted
27 | - OwnershipTransferred
28 | - SellerPaymentPull
29 | abis:
30 | - name: Contract
31 | file: ./abis/Contract.json
32 | eventHandlers:
33 | - event: AdminWithdrawFees(uint256)
34 | handler: handleAdminWithdrawFees
35 | - event: AuctionContribute(address,address,address,uint256,uint256)
36 | handler: handleAuctionContribute
37 | - event: AuctionItemListed(address,address,uint256,uint256,uint256,uint256)
38 | handler: handleAuctionItemListed
39 | - event: Bought(address,address,address,uint256)
40 | handler: handleBought
41 | - event: Deployed()
42 | handler: handleDeployed
43 | - event: FeeUpdated(uint16)
44 | handler: handleFeeUpdated
45 | - event: FraktalClaimed(address,address)
46 | handler: handleFraktalClaimed
47 | - event: ItemListed(address,address,uint256,uint256)
48 | handler: handleItemListed
49 | - event: OfferMade(address,address,uint256)
50 | handler: handleOfferMade
51 | - event: OfferVoted(address,address,address,bool)
52 | handler: handleOfferVoted
53 | - event: OwnershipTransferred(indexed address,indexed address)
54 | handler: handleOwnershipTransferred
55 | - event: SellerPaymentPull(address,uint256)
56 | handler: handleSellerPaymentPull
57 | file: ./src/mapping.ts
58 | templates:
59 | - name: Factory
60 | kind: ethereum/contract
61 | network: rinkeby
62 | source:
63 | abi: Factory
64 | mapping:
65 | kind: ethereum/events
66 | apiVersion: 0.0.5
67 | language: wasm/assemblyscript
68 | file: ./src/mappings/factory.ts
69 | entities:
70 | - Factory
71 | abis:
72 | - name: Factory
73 | file: ./abis/Factory.json
74 | eventHandlers:
75 | - event: Minted(address,string,address,uint256)
76 | handler: handleMinted
--------------------------------------------------------------------------------
/testnetfraktalauction/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@graphprotocol/graph-ts/types/tsconfig.base.json",
3 | "include": ["src"]
4 | }
5 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": false,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "baseUrl": ".",
17 | "paths": {
18 | "@/components/*": ["components/*"],
19 | "@/contexts/*": ["contexts/*"],
20 | "@/constants/*": ["constants/*"],
21 | "@/styles/*": ["styles/*"],
22 | "@/utils/*": ["utils/*"],
23 | "@/redux/*": ["redux/*"],
24 | "@/types/*": ["types/*"]
25 | }
26 | },
27 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
28 | "exclude": ["node_modules"]
29 | }
30 |
--------------------------------------------------------------------------------
/types.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber, BigNumberish } from "@ethersproject/bignumber";
2 |
3 | export interface FrakCard {
4 | id: number;
5 | name: string;
6 | imageURL: string;
7 | createdAt: string;
8 | countdown?: Date;
9 | contributions?: BigNumberish | BigNumber;
10 | }
11 |
12 | export interface NFTItemType {
13 | creator:string,
14 | id: number,
15 | name: string,
16 | imageURL: string,
17 | createdAt: number
18 | }
19 |
--------------------------------------------------------------------------------
/types/workflow.ts:
--------------------------------------------------------------------------------
1 | export enum Workflow {
2 | MINT_NFT = 'mint-nft',
3 | IMPORT_NFT = 'import-nft',
4 | FRAK_NFT = 'frak-nft',
5 | CLAIM_NFT = 'claim-nft'
6 | }
7 |
--------------------------------------------------------------------------------
/utils/alchemy.ts:
--------------------------------------------------------------------------------
1 | import { createAlchemyWeb3 } from "@alch/alchemy-web3";
2 | import {getAlchemyApi} from "@/utils/helpers";
3 |
4 | // Using HTTPS
5 | const web3 = createAlchemyWeb3(
6 | getAlchemyApi(parseInt(process.env.NEXT_PUBLIC_NETWORK_CHAIN_ID)) + process.env.NEXT_PUBLIC_ALCHEMY_API_KEY,
7 | );
8 |
9 | export async function getNftMetadata(contractAddress, tokenId = "1") {
10 | const response = await web3.alchemy.getNftMetadata({
11 | contractAddress: contractAddress,
12 | tokenId: tokenId
13 | })
14 |
15 | return response;
16 | }
17 |
--------------------------------------------------------------------------------
/utils/constants.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber } from "ethers";
2 |
3 | export const MAX_FRAKTIONS = 10000;
4 |
5 | export const LARGEST_UINT256 = BigNumber.from(
6 | "115792089237316195423570985008687907853269984665640564039457584007913129639935"
7 | );
8 |
9 | export const contracts = [ // old ones
10 | {providerChainId:1, address: '0x0000000000000000000000000000000000000000'},
11 | {providerChainId:4, address: '0xFf3532447a93497471279150602B6ec24ae1170f'},
12 | {providerChainId:5, address: '0xA916BbdB90bA3BA7DCca09F2D3B249180f7fE0D2'}
13 | ]
14 | export const marketContracts = [
15 | {providerChainId:1, address: '0x244763Ea2039D880B62D2BA427d8919Eba6ee50B'},
16 | {providerChainId:4, address: process.env.NEXT_PUBLIC_RINKEBY_MARKET_CONTRACT
17 | ? process.env.NEXT_PUBLIC_RINKEBY_MARKET_CONTRACT : '0x1379cf637fc4cf09D89CDc9131C38DD4dd15D1c7'},
18 | ]
19 | export const factoryContracts = [
20 | {providerChainId:1, address: '0x5DF977d385254D9a66ab8cD35e87E1E0c419b135'},
21 | {providerChainId:4, address: process.env.NEXT_PUBLIC_RINKEBY_FACTORY_CONTRACT
22 | ? process.env.NEXT_PUBLIC_RINKEBY_FACTORY_CONTRACT : '0x9c27b4310F128Fdb6cfE6b2eA32Af3774Bf6778e'},
23 | ]
24 | export const fraktalTokenContracts = [
25 | {providerChainId:1, address:'0x1f81f8f262714cc932141c7C79495B481eF27258'},
26 | {providerChainId:4, address:'0x468065C8B00C7cB3cd6B9fD76dAe9dD49e1C30e0'},
27 | ];
28 | export const lpTokenContracts = [
29 | {providerChainId:1, address:'0x2763f944fc85CAEECD559F0f0a4667A68256144d'},
30 | {providerChainId:4, address:'0x9A18671771a15CA42442F0970852670A3972A789'},
31 | ];
32 | export const airdropContract = [
33 | {providerChainId:1, address:'0x3CAf9755CE1b3db4eCF6498058E4cC5AD98446E9'},
34 | {providerChainId:4, address:'0xdA64d4c447476Ef26FD929d63Ec8f1C81C267854'},
35 | ];
36 | export const partnerAirdropContract = [
37 | {providerChainId:1, address:'0x418A5396e7E5d28CF64A58863382A5FB2671487E'},
38 | {providerChainId:4, address:''},
39 | ];
40 | export const lpStakingContracts = [
41 | {providerChainId:1, address:'0x9286Ea5E9b22262D4C1f142F1DD35Ffb1EaacD03'},
42 | {providerChainId:4, address:'0x85F625355a5DeCebb5F1609c7197597F3B125411'},
43 | ]
44 | export const tradingRewardsContracts = [
45 | {providerChainId:1, address:'0x2BA1B4cE0dedc2eE0dA59EEf31a25de42AdBe0C5'},
46 | {providerChainId:4, address:'0x92E52AF0D07b1d4cE0DA9041C1a2eC164c75174e'},
47 | ]
48 | export const feeSharingContracts = [
49 | {providerChainId:1, address:'0xa74a87Da1E4c6f3a742D3e4DDe6750a957Ca3aC3'},
50 | {providerChainId:4, address:'0xe398a2Cfa41440e7d33bbdC76f0a65C9Ca3D8373'},
51 | ]
52 |
53 | export const networkNames = {
54 | 1: "ETH Mainnet",
55 | 42: "Kovan Testnet",
56 | 3: "Ropsten Testnet",
57 | 4: "Rinkeby Testnet",
58 | 5: "Göerli Testnet",
59 | };
60 |
61 | export const networkLabels = {
62 | 1: "Mainnet",
63 | 3: "Ropsten",
64 | 4: "Rinkeby",
65 | 5: "Görli",
66 | 42: "Kovan",
67 | };
68 |
69 | export const networkCurrencies = {
70 | 1: {
71 | name: "Ethereum",
72 | symbol: "ETH",
73 | },
74 | 3: {
75 | name: "Ethereum",
76 | symbol: "ETH",
77 | },
78 | 4: {
79 | name: "Ethereum",
80 | symbol: "ETH",
81 | },
82 | 5: {
83 | name: "Ethereum",
84 | symbol: "ETH",
85 | },
86 | 42: {
87 | name: "Ethereum",
88 | symbol: "ETH",
89 | },
90 | };
91 |
92 | export const chainUrls = {
93 | 1: {
94 | rpc: "https://mainnet.infura.io/v3/" + process.env.NEXT_PUBLIC_INFURA_ID,
95 | explorer: "https://etherscan.io/",
96 | chainId: 1,
97 | name: networkNames[1],
98 | openSeaApi: 'https://api.opensea.io/api/v1/',
99 | alchemyApi: 'https://eth-mainnet.alchemyapi.io/v2/'
100 | },
101 | 3: {
102 | rpc: "https://ropsten.infura.io/v3/" + process.env.NEXT_PUBLIC_INFURA_ID,
103 | explorer: "https://ropsten.etherscan.io/",
104 | chainId: 3,
105 | name: networkNames[3]
106 | },
107 | 4: {
108 | rpc: "https://rinkeby.infura.io/v3/" + process.env.NEXT_PUBLIC_INFURA_ID,
109 | explorer: "https://rinkeby.etherscan.io/",
110 | chainId: 4,
111 | name: networkNames[4],
112 | openSeaApi: 'https://rinkeby-api.opensea.io/api/v1/',
113 | alchemyApi: 'https://eth-rinkeby.alchemyapi.io/v2/'
114 | },
115 | 5: {
116 | rpc: "https://kovan.infura.io/v3/" + process.env.NEXT_PUBLIC_INFURA_ID,
117 | explorer: "https://kovan.etherscan.io/",
118 | chainId: 5,
119 | name: networkNames[5],
120 | },
121 | 42: {
122 | rpc: "https://goerli.infura.io/v3/" + process.env.NEXT_PUBLIC_INFURA_ID,
123 | explorer: "https://goerli.etherscan.io/",
124 | chainId: 42,
125 | name: networkNames[42],
126 | },
127 | };
128 |
--------------------------------------------------------------------------------
/utils/format.ts:
--------------------------------------------------------------------------------
1 | import { BigNumberish, utils } from 'ethers';
2 | import { roundUp } from './math';
3 |
4 | export const formatEtherPrice = (wei: BigNumberish) => {
5 | return roundUp(
6 | (Number.parseFloat(utils.formatEther(wei)) * 100000) / 100000,
7 | 3
8 | );
9 | };
10 |
--------------------------------------------------------------------------------
/utils/helpers.ts:
--------------------------------------------------------------------------------
1 | import {
2 | chainUrls,
3 | networkCurrencies,
4 | networkLabels,
5 | networkNames,
6 | } from "./constants";
7 | import { utils } from "ethers";
8 | import {
9 | rescueEth,
10 | claimFraktalSold,
11 | fraktionalize,
12 | importFraktal,
13 | claimERC1155,
14 | claimERC721,
15 | approveMarket,
16 | importERC721,
17 | importERC1155,
18 | getApproved,
19 | getLockedTo,
20 | makeOffer
21 | } from './contractCalls';
22 |
23 | export const timezone = (timestamp) => {return new Date(timestamp*1000).toLocaleDateString("en-US")}
24 | export const getNetworkName = (chainId: number) => networkNames[chainId || 4];
25 | export const getNetworkLabel = (chainId: number) => networkLabels[chainId || 4];
26 | export const getRPCUrl = (chainId: number) => chainUrls[chainId || 4].rpc;
27 | export const getExplorerUrl = (chainId: number) => (chainUrls[chainId] || chainUrls[4]).explorer;
28 | export const getOpenSeaApi = (chainId: number) => (chainUrls[chainId] || chainUrls[4]).openSeaApi;
29 | export const getAlchemyApi = (chainId: number) => (chainUrls[chainId] || chainUrls[4]).alchemyApi;
30 |
31 | export const getNetworkCurrency = chainId =>
32 | networkCurrencies[chainId] || { name: "Unknown", symbol: "Unknown" };
33 |
34 | export const shortenHash = (hash) => {
35 | if (typeof hash !== 'undefined') {
36 | return `${hash.slice(0, 4)}...${hash.slice(hash.length - 4, hash.length)}`
37 | }
38 | };
39 |
40 | export const addChainToMetaMask = async (
41 | chainId: number,
42 | isNativeEthereumChain: boolean = false
43 | ) => {
44 | const { name, symbol } = getNetworkCurrency(chainId);
45 | return isNativeEthereumChain
46 | ? window.ethereum.request({
47 | method: "wallet_switchEthereumChain",
48 | params: [
49 | {
50 | chainId: utils.hexValue(chainId),
51 | },
52 | ],
53 | })
54 | : window.ethereum.request({
55 | method: "wallet_addEthereumChain",
56 | params: [
57 | {
58 | chainId: utils.hexValue(chainId),
59 | chainName: getNetworkName(chainId),
60 | nativeCurrency: {
61 | name,
62 | symbol,
63 | decimals: 18,
64 | },
65 | rpcUrls: [getRPCUrl(chainId)],
66 | blockExplorerUrls: [getExplorerUrl(chainId)],
67 | },
68 | ],
69 | });
70 | };
71 |
72 | export async function loadSigner(provider) { //Load contract instance
73 | if (typeof provider !== "undefined") {
74 | try {
75 | let signer;
76 | const accounts = await provider.listAccounts();
77 | if (accounts && accounts.length > 0) {
78 | signer = provider.getSigner();// get signer
79 | } else {
80 | signer = provider; // or use RPC (cannot sign tx's. should call a connect warning)
81 | }
82 | return signer;
83 | } catch (e) {
84 | console.log("ERROR LOADING SIGNER", e);
85 | }
86 | }
87 | }
88 |
89 | export function getParams(type){
90 | const url = `https://testnet.fraktal.io/${type}/`;
91 | let address;
92 | if(window.location.href.startsWith('http://localhost')){
93 | address = window.location.href.split(`http://localhost:3000/${type}/`);
94 | }else{
95 | address = window.location.href.split(url);
96 | }
97 | return address[1];
98 | }
99 |
100 | export async function processTx(tx){
101 | let receipt;
102 | try{
103 | receipt = await tx.wait();
104 | } catch(e) {
105 | receipt = {error: `Error: ${e}`}
106 | }
107 | return receipt;
108 | }
109 |
110 | export const awaitTokenAddress = async (tx) => {
111 | let receipt;
112 | try {
113 | receipt = await tx.wait();
114 | } catch (error) {
115 | receipt = {error: `Error: ${error}`};
116 | }
117 | if (receipt?.error) {
118 | return receipt;
119 | }
120 | const abi = new utils.Interface([
121 | 'event Minted(address creator,string urlIpfs,address tokenAddress,uint nftId)',
122 | ]);
123 | const eventFragment = abi.events[Object.keys(abi.events)[0]];
124 | const eventTopic = abi.getEventTopic(eventFragment);
125 | const event = receipt.logs.find((e) => e.topics[0] === eventTopic);
126 | if (!event) return '';
127 | const decodedLog = abi.decodeEventLog(
128 | eventFragment,
129 | event.data,
130 | event.topics,
131 | );
132 | return decodedLog.tokenAddress;
133 | };
134 |
--------------------------------------------------------------------------------
/utils/math.ts:
--------------------------------------------------------------------------------
1 | export function roundUp(num, precision) {
2 | precision = Math.pow(10, precision)
3 | return Math.ceil(num * precision) / precision
4 | };
--------------------------------------------------------------------------------
/utils/openSeaAPI.ts:
--------------------------------------------------------------------------------
1 | import {getOpenSeaApi} from "@/utils/helpers";
2 | const apiURL = getOpenSeaApi(parseInt(process.env.NEXT_PUBLIC_NETWORK_CHAIN_ID));
3 | const options = {
4 | method: 'GET',
5 | headers: {
6 | 'X-API-KEY': process.env.NEXT_PUBLIC_OPEASEA_API_KEY ? process.env.NEXT_PUBLIC_OPEASEA_API_KEY : ''
7 | }
8 | };
9 | const ASSET_METHOD = 'asset';
10 | const ASSETS_METHOD = 'assets';
11 |
12 | /**
13 | * Open Sea assets
14 | * @param address
15 | */
16 | export const assetsInWallet = (address, params = {}) => {
17 | const url = apiURL + `assets?owner=${address}&order_direction=desc&offset=${params.offset}&limit=${params.limit}`;
18 | const data = fetch(url, options)
19 | .then(response => response.json())
20 | .then(data => {
21 | return data;
22 | })
23 | .catch(err => console.error(err));
24 | return data;
25 | }
26 |
27 | /**
28 | * Validate asset
29 | * @param contract
30 | * @param tokenId
31 | */
32 | export const validateAsset = (contract, tokenId) => {
33 | const data = fetch(apiURL + ASSET_METHOD + `/` + contract + '/' + tokenId, options)
34 | .then(response => response.json())
35 | .then(data => {
36 | return data;
37 | })
38 | .catch(err => console.error(err));
39 | return data;
40 | }
41 |
--------------------------------------------------------------------------------
/utils/pinataPinner.js:
--------------------------------------------------------------------------------
1 | const axios = require('axios');
2 |
3 | export const pinByHash = (hashToPin) => {
4 | const url = `https://api.pinata.cloud/pinning/pinByHash`;
5 | const body = {
6 | hashToPin: hashToPin,
7 | hostNodes: [
8 | '/ip4/hostNode1ExternalIP/tcp/4001/ipfs/hostNode1PeerId',
9 | '/ip4/hostNode2ExternalIP/tcp/4001/ipfs/hostNode2PeerId'
10 | ],
11 | };
12 | return axios
13 | .post(url, body, {
14 | headers: {
15 | pinata_api_key: process.env.NEXT_PUBLIC_PINATA_API_KEY,
16 | pinata_secret_api_key: process.env.NEXT_PUBLIC_PINATA_API_SECRET
17 | }
18 | })
19 | .then(function (response) {
20 | //handle response here
21 | })
22 | .catch(function (error) {
23 | //handle error here
24 | });
25 | };
26 |
--------------------------------------------------------------------------------
/utils/proofsGetter.js:
--------------------------------------------------------------------------------
1 | import proofs from './merkleTreeProofs.json'
2 | import proofs2 from './merkleTreeProofsV2.json'
3 |
4 | export function getProofs(address){
5 | const addr = String(address).toLowerCase();
6 | return proofs[addr];
7 | }
8 |
9 | export function getProofs2(address){
10 | const addr = String(address).toLowerCase();
11 | return proofs2[addr];
12 | }
--------------------------------------------------------------------------------
/utils/search.ts:
--------------------------------------------------------------------------------
1 | import {createListed, createListedAuction, createObject} from "@/utils/nftHelpers";
2 | import {getSubgraphData, SEARCH_ITEMS} from "@/utils/graphQueries";
3 | import {ethers} from "ethers";
4 |
5 | //TODO - REFACTOR
6 | async function mapListed(listedItems) {
7 | let objects = await Promise.all(
8 | listedItems.map(x => {
9 | let res = createListed(x);
10 | if (typeof res !== "undefined" && x.amount > 0) {
11 | return res;
12 | }
13 | }).filter(notUndefined => notUndefined !== undefined)
14 | );
15 | return objects;
16 | }
17 |
18 | //TODO - REFACTOR
19 | async function mapAuctions(listedItems) {
20 | let objects = await Promise.all(
21 | listedItems.map(x => {
22 | x.hash = x.fraktal.hash;
23 | let res = createListedAuction(x);
24 | if (typeof res !== "undefined") {
25 | return res;
26 | }
27 | }).filter(notUndefined => notUndefined !== undefined)
28 | );
29 | return objects;
30 | }
31 |
32 |
33 | //TODO - REFACTOR
34 | async function mapFraktion(userSearch, creator) {
35 | let objects = await Promise.all(
36 | userSearch[0].fraktions.map(fraktion => {
37 | if (fraktion.nft.creator.id.toLowerCase() !== creator.toLowerCase()) {
38 | let res = createObject(fraktion);
39 | if (typeof res !== "undefined") {
40 | return res;
41 | }
42 | }
43 |
44 | }).filter(notUndefined => notUndefined !== undefined)
45 | );
46 | return objects;
47 | }
48 |
49 | //TODO - REFACTOR
50 | async function mapNotForSale(listedItems) {
51 | let objects = await Promise.all(
52 | listedItems.map(x => {
53 | let res = createListed(x);
54 | if (typeof res !== "undefined" && x.amount == 0) {
55 | return res;
56 | }
57 | }).filter(notUndefined => notUndefined !== undefined)
58 | );
59 | return objects;
60 | }
61 |
62 | /**
63 | * Get Search Items
64 | * @param query
65 | * @param options
66 | */
67 | async function getItems(query, options = []) {
68 | const provider = await ethers.providers.getDefaultProvider();
69 | if (query.length < 2) {
70 | return [];
71 | }
72 | if (/\w+\.eth\b/.test(query)) {
73 | const ensAddress = await provider.resolveName(query);
74 | query = ensAddress;
75 | }
76 | const searchData = await getSubgraphData(SEARCH_ITEMS, "", {
77 | name: "'" + query + "'" + ':*',
78 | ...options
79 | });
80 | let listedObjects = [];
81 | let notForSale = [];
82 | let auctionsObjects = [];
83 | if (searchData?.fraktalSearch !== undefined && searchData?.fraktalSearch.length > 0) {
84 | listedObjects = await mapListed(searchData.fraktalSearch);
85 | notForSale = await mapNotForSale(searchData?.fraktalSearch);
86 | }
87 | if (searchData?.userSearch !== undefined && searchData?.userSearch.length > 0) {
88 | //TODO - Validate Creator ID
89 |
90 | const creator = query;
91 | listedObjects = await mapListed(searchData.userSearch[0].listedItems);
92 | auctionsObjects = await mapAuctions(searchData.userSearch[0].auctionItems);
93 | notForSale = await mapFraktion(searchData?.userSearch, creator);
94 | }
95 |
96 | if (searchData?.auctionSearch !== undefined && searchData?.auctionSearch.length > 0) {
97 | auctionsObjects = await mapAuctions(searchData.auctionSearch);
98 | }
99 |
100 |
101 | return {
102 | fixedPrice: listedObjects,
103 | auctions: auctionsObjects,
104 | notForSale: notForSale
105 | }
106 | }
107 |
108 | export {getItems, mapAuctions, mapFraktion, mapListed, mapNotForSale}
--------------------------------------------------------------------------------
/utils/stores/ensStore.ts:
--------------------------------------------------------------------------------
1 | import { request } from 'graphql-request'
2 | import {getQueryENSForETHAddress, getQueryENSForETHAddressByLabelName} from './queries/getQueryENSForETHAddress'
3 |
4 | const HTTP_GRAPHQL_ENDPOINT =
5 | 'https://api.thegraph.com/subgraphs/name/ensdomains/ens'
6 |
7 | /*
8 | * @param ensAddress - the ENS address. Example: vitalik.eth
9 | * @return the Ethereum address or 0 string if invalid
10 | */
11 | export async function queryENSForETHAddress(ensAddress: string): Promise {
12 | const result = ensAddress.includes(".") ? await request(HTTP_GRAPHQL_ENDPOINT, getQueryENSForETHAddress(ensAddress)) : await request(HTTP_GRAPHQL_ENDPOINT, getQueryENSForETHAddressByLabelName(ensAddress))
13 | return result.domains && result.domains.length > 0
14 | ? result.domains[0].owner.id
15 | : '0'
16 | }
17 |
--------------------------------------------------------------------------------
/utils/stores/queries/getQueryENSForETHAddress.ts:
--------------------------------------------------------------------------------
1 | import { gql } from 'graphql-request'
2 |
3 | export function getQueryENSForETHAddress(ensAddress: string) {
4 | return gql`
5 | {
6 | domains(first: 1, where:{name:"${ensAddress.toLowerCase()}"}) {
7 | name
8 | labelName
9 | owner {
10 | id
11 | domains {
12 | id
13 | }
14 | }
15 | }
16 | }`
17 | }
18 |
19 | export function getQueryENSForETHAddressByLabelName(ensAddress: string) {
20 | return gql`
21 | {
22 | domains(first: 1, where:{labelName:"${ensAddress.toLowerCase()}"}) {
23 | name
24 | labelName
25 | owner {
26 | id
27 | domains {
28 | id
29 | }
30 | }
31 | }
32 | }`
33 | }
--------------------------------------------------------------------------------