Skip to content

Commit

Permalink
collection integration
Browse files Browse the repository at this point in the history
  • Loading branch information
codeSTACKr committed Jan 31, 2022
1 parent 1e3e4e9 commit f5836eb
Show file tree
Hide file tree
Showing 10 changed files with 307 additions and 73 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
.env
package-lock.json
# Local Netlify folder
.netlify
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
# Basic DAPP Landing Page
# Basic dApp NFT Landing Page

This repo is a work-in-progress and pairs with the Mint 10k NFT project.
This repo is a work-in-progress and pairs with my Mint 10k NFT project.

## Video Walkthrough

[video here]()
### Getting Started & Integrate MetaMask

[![Thumbnail](https://img.youtube.com/vi/WZQSVv67NBc/maxresdefault.jpg)](https://youtu.be/WZQSVv67NBc)

Associated Source Code: [v1.0.0](https://github.com/codeSTACKr/nft-landing-page/releases/tag/v1.0.0)

### Collection Integration & Owner Check

[![Thumbnail](https://img.youtube.com/vi/WZQSVv67NBc/maxresdefault.jpg)](https://youtu.be/WZQSVv67NBc)

Associated Source Code: [v1.1.0](https://github.com/codeSTACKr/nft-landing-page/releases/tag/v1.1.0)

## How to Create and Mint 10k NFTs

Expand All @@ -24,4 +34,4 @@ This repo is a work-in-progress and pairs with the Mint 10k NFT project.
- Fonts
- Colors

## Watch the [video walkthrough](#video-walkthrough) above for more detailed instructions.
## Watch the [video walkthroughs](#video-walkthrough) above for more detailed instructions.
66 changes: 0 additions & 66 deletions app.js

This file was deleted.

13 changes: 12 additions & 1 deletion style.css → css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ body {
}

.container {
display: flex;
flex-direction: column;
max-width: 960px;
margin: 0 auto;
padding: 1rem 2rem;
Expand All @@ -43,7 +45,7 @@ header {
}

header .container {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
Expand Down Expand Up @@ -153,6 +155,15 @@ section {
text-align: center;
}

/* OWNER STYLES */

.owner-status {
font-size: 2rem;
text-align: center;
}

/* MEDIA QUERIES */

@media screen and (max-width: 768px) {
.menu {
gap: 1rem;
Expand Down
90 changes: 90 additions & 0 deletions functions/isowner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const fetch = require('node-fetch')

const CONTRACT = process.env.CONTRACT_ADDRESS;
const AUTH = process.env.NFTPORT_AUTH;
const chain = "polygon";
const include = "metadata";

exports.handler = async (event, context) => {
const wallet = event.queryStringParameters && event.queryStringParameters.wallet
const page = event.queryStringParameters && event.queryStringParameters.page

const isOwner = (wallet) => {
if(!wallet) {
return {
isOwner: false
}
} else {
return getOwnedNfts(wallet, page)
}
}

const response = await isOwner(wallet)

return {
'statusCode': 200,
'headers': {
'Cache-Control': 'no-cache',
'Content-Type': 'application/json',
},
'body': JSON.stringify(response)
}
}

const getOwnedNfts = async (wallet, page) => {
const url = `https://api.nftport.xyz/v0/accounts/${wallet}/?`;

const options = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: AUTH
}
};
const query = new URLSearchParams({
chain,
include,
page_number: page
});

let editions = []
try {
const data = await fetchData(url + query, options)
console.log(`Recieved page ${page}`)
const total = data.total;
const pages = Math.ceil(total / 50);
data.nfts.forEach(nft => {
if(nft.contract_address === CONTRACT) {
editions.push(nft.token_id)
}
})

return {
isOwner: editions.length > 0 ? true : false,
editions,
next_page: +page === pages ? null : +page + 1,
}
} catch(err) {
console.log(`Catch: ${JSON.stringify(err)}`)
return {
error: err
}
}
}

async function fetchData(url, options) {
return new Promise((resolve, reject) => {
return fetch(url, options).then(res => {
const status = res.status;

if(status === 200) {
return resolve(res.json());
} else {
console.log(`Fetch failed with status ${status}`);
return reject(res.json());
}
}).catch(function (error) {
reject(error)
});
});
}
6 changes: 4 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<link rel="icon" type="image/png" sizes="32x32" href="images/x-icon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="images/x-icon/favicon-16x16.png">
<link rel="manifest" href="images/x-icon/site.webmanifest">
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<header>
Expand Down Expand Up @@ -51,6 +51,7 @@
</header>

<section class="container">
<div class="owner-status"></div>
<div class="countdown">
<ul
id="countdown"
Expand Down Expand Up @@ -87,6 +88,7 @@ <h1>NFT Drop Coming Soon!!</h1>
</section>

<script src="https://cdn.jsdelivr.net/npm/@metamask/[email protected]/dist/metamask-onboarding.bundle.js"></script>
<script src="app.js"></script>
<script src="js/countdown.js"></script>
<script src="js/app.js"></script>
</body>
</html>
133 changes: 133 additions & 0 deletions js/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// METAMASK CONNECTION
const TIMEOUT = 1000;
const COLLECTION_NAME = 'CodeCats';
let editions = [];
let dots = 1;

window.addEventListener('DOMContentLoaded', () => {
const onboarding = new MetaMaskOnboarding();
const onboardButton = document.getElementById('connectWallet');
let accounts;

const updateButton = async () => {
if (!MetaMaskOnboarding.isMetaMaskInstalled()) {
onboardButton.innerText = 'Install MetaMask!';
onboardButton.onclick = () => {
onboardButton.innerText = 'Connecting...';
onboardButton.disabled = true;
onboarding.startOnboarding();
};
} else if (accounts && accounts.length > 0) {
onboardButton.innerText = `✔ ...${accounts[0].slice(-4)}`;
onboardButton.disabled = true;
onboarding.stopOnboarding();
checkOwner(accounts[0]);
} else {
onboardButton.innerText = 'Connect MetaMask!';
onboardButton.onclick = async () => {
await window.ethereum.request({
method: 'eth_requestAccounts',
})
.then(function(accounts) {
onboardButton.innerText = `✔ ...${accounts[0].slice(-4)}`;
onboardButton.disabled = true;
checkOwner(accounts[0]);
});
};
}
};

updateButton();
if (MetaMaskOnboarding.isMetaMaskInstalled()) {
window.ethereum.on('accountsChanged', (newAccounts) => {
accounts = newAccounts;
updateButton();
});
}
});

const checkOwner = async (account) => {
if(account) {
let isOwner = false;
let page = 1

const data = await fetchWithRetry(`/.netlify/functions/isowner/?wallet=${account}&page=${page}`);

isOwner = !isOwner ? data.isOwner : isOwner;
updateStatusText(isOwner, true)

editions = [...data.editions]
let nextPage = data.next_page

while(nextPage) {
page = nextPage
const data = await fetchWithRetry(`/.netlify/functions/isowner/?wallet=${account}&page=${page}`);

isOwner = !isOwner ? data.isOwner : isOwner;
updateStatusText(isOwner, true)

editions = [...editions, ...data.editions]
nextPage = data.next_page
}

updateStatusText(isOwner, false)
}
}

function updateStatusText(isOwner, checking) {
const statusText = document.querySelector('.owner-status');
if(checking) {
if(isOwner) {
statusText.innerText = `You do own ${COLLECTION_NAME}!! 😻 Let's see how many${renderDots(dots)}`;
} else {
statusText.innerText = `Checking to see if you own any ${COLLECTION_NAME} 😻${renderDots(dots)}`;
}
} else {
if(isOwner) {
statusText.innerText = `You own ${editions.length} ${COLLECTION_NAME}!! 😻`;
} else {
statusText.innerText = `You don't own any ${COLLECTION_NAME} 😿`;
}
}
dots = dots === 3 ? 1 : dots + 1;
}

function renderDots(dots) {
let dotsString = '';
for (let i = 0; i < dots; i++) {
dotsString += '.';
}
return dotsString;
}

function timer(ms) {
return new Promise(res => setTimeout(res, ms));
}

async function fetchWithRetry(url) {
await timer(TIMEOUT);
return new Promise((resolve, reject) => {
const fetch_retry = (_url) => {
return fetch(_url).then(async (res) => {
const status = res.status;

if(status === 200) {
return resolve(res.json());
}
else {
console.error(`ERROR STATUS: ${status}`)
console.log('Retrying')
await timer(TIMEOUT)
fetch_retry(_url)
}
})
.catch(async (error) => {
console.error(`CATCH ERROR: ${error}`)
console.log('Retrying')
await timer(TIMEOUT)
fetch_retry(_url)
});
}
return fetch_retry(url);
});
}
Loading

0 comments on commit f5836eb

Please sign in to comment.