Skip to content

Commit a23e0ee

Browse files
committed
init commit
0 parents  commit a23e0ee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+10336
-0
lines changed

.eslintrc.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}

.github/preview.png

322 KB
Loading

.gitignore

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
.pnpm-debug.log*
27+
28+
# local env files
29+
.env
30+
.env.local
31+
.env.development.local
32+
.env.test.local
33+
.env.production.local

README.md

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# 🥔🥔🥔 Super Potato NFT Raffle | Solan | Next.js + Typescript
2+
3+
<p align="center">
4+
<img src="./.github/preview.png" alt="Super potato" />
5+
</p>
6+
7+
## 📖 Requirements
8+
### 👶 User side
9+
- Collection register
10+
- Raffle create <br />
11+
They will have to pay about 0.4 SOL per NFT when creating a raffle.
12+
- Buy tickets
13+
- Withdraw NFT (after end time & and not sold any tickets)
14+
- Reveal winner
15+
- Claim reward
16+
### 👨‍💻 Admin side
17+
- User-registered Accept/Deny of collection
18+
### Like FFF Raffle (famous fox federation)
19+
[rafffle.famousfoxes.com](https://rafffle.famousfoxes.com/)
20+
<br />
21+
22+
## Mindfolk Landing Page
23+
[www.mindfolk.art](https://www.mindfolk.art/)
24+
25+
## 🌐 Deployed
26+
[superpotato-raffle.herokuapp.com/](https://superpotato-raffle.herokuapp.com/)
27+
28+
29+
## 🛠 ※ SET PROJECT ENVIRONMENT
30+
### Firebase set
31+
Replace firebase configuration values <br />
32+
`src/api/firebase.ts` <br/>
33+
```tsx
34+
const firebaseConfig = {
35+
apiKey: "AIzaSyAI_r1Rs11kIsWJFiCVA4aGt58ffsZrclY",
36+
authDomain: "mindfolk-raffle-afb92.firebaseapp.com",
37+
projectId: "mindfolk-raffle-afb92",
38+
storageBucket: "mindfolk-raffle-afb92.appspot.com",
39+
messagingSenderId: "106626330620",
40+
appId: "1:106626330620:web:c3343f7736902e58774c79",
41+
measurementId: "G-NHD9LYKTVJ"
42+
};
43+
```
44+
### Project config data
45+
`src/config.tsx` <br />
46+
```tsx
47+
export const NETWORK = "mainnet-beta"; //mainnet-beta | devnet
48+
export const ADMINS = [
49+
"7TBRMXkRbVpRWgLkrrTaqFJvXSMkMwnNKEZ4dbRh8Lnf",
50+
"FePFmE1CbbTkiKg4K9A41dQcXfhPqLSJrEBcdXwBj3aa",
51+
"A8rgsJecHutEamvb7e8p1a14LQH3vGRPr796CDaESMeu" // developer wallet address
52+
]
53+
54+
// deployed url
55+
export const LIVE_URL = "https://superpotato-raffle.herokuapp.com/"
56+
// treasury wallet address
57+
export const TREASURY_WALLET = new PublicKey('BEQZXkjg1BzY5349FXGPgvsbySWw5R7zjEC4xQhzmQR5');
58+
//smart contract program id
59+
export const PROGRAM_ID = "Geb2fkVJMgNbjPwMkcjfR3n4AiN7DKqKwctFwfErkbn7";
60+
// solana RPC url
61+
export const RPC_URL = "https://a2-mind-prd-api.azurewebsites.net/rpc";
62+
63+
```
64+
65+
## Install
66+
67+
```bash
68+
npm run install
69+
# or
70+
yarn install
71+
```
72+
## Development
73+
74+
```bash
75+
npm run dev
76+
# or
77+
yarn dev
78+
```
79+
80+
## 🔥 Database
81+
Google **Firebase**
82+
- **collections** <br />
83+
When users send a request to register a Collection, it is stored in the database Collection calls **collections**.<br />
84+
Admin can **Accept** or **Deny** those collections. <br />
85+
All collections are also stored on the blockchain.
86+
- **raffles** <br />
87+
When user create a raffle, it saved also database `raffles` document. <br />
88+
Raffle on db is updated, when those actions <br />
89+
`buy tickets`, `reveal winner`, `withdraw nft`, `claim reward`
90+
91+
## Resolved issues
92+
93+
### Transaction confirmation issue
94+
```
95+
Seems to me the transaction is taking more than 60.00 seconds…what is already a big issue…but worse than that someone coded a lock that says if its more than 60 seconds it is a fail.
96+
```
97+
- Use Solscan API<br>
98+
`https://public-api.solscan.io/transaction/[tx]`
99+
```jsx
100+
await fetch(`https://public-api.solscan.io/transaction/${txId}`)
101+
.then(resp =>
102+
resp.json()
103+
).then(async (json) => {
104+
if (json.status === "Success" && json.signer.length !== 0) {
105+
//update firebase database
106+
await updateDoc(collectionById, {
107+
status: 0,
108+
accepted: true,
109+
updateTimeStamp: new Date().getTime()
110+
})
111+
.then(() => {
112+
//clear timeout & timeinterval
113+
clearTimeout(timeout);
114+
clearInterval(timeInterval);
115+
successAlert("Transaction is confirmed..");
116+
})
117+
}
118+
})
119+
.catch((error) => {
120+
console.log(error);
121+
})
122+
```
123+
### Page re-render by real-time
124+
`onSnapshort` function of `firebase` with `useEffect`

next-env.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// <reference types="next" />
2+
/// <reference types="next/image-types/global" />
3+
4+
// NOTE: This file should not be edited
5+
// see https://nextjs.org/docs/basic-features/typescript for more information.

next.config.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/** @type {import('next').NextConfig} */
2+
const nextConfig = {
3+
reactStrictMode: true,
4+
}
5+
6+
module.exports = nextConfig

package.json

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "solarmy-collection-game-frontend",
3+
"version": "0.1.0",
4+
"author": "sasuke0601",
5+
"private": true,
6+
"scripts": {
7+
"dev": "next dev",
8+
"build": "next build",
9+
"start": "next start",
10+
"lint": "next lint"
11+
},
12+
"dependencies": {
13+
"@emotion/react": "^11.9.0",
14+
"@emotion/styled": "^11.8.1",
15+
"@metaplex/js": "4.12.0",
16+
"@mui/material": "^5.6.2",
17+
"@nfteyez/sol-rayz": "^0.10.2",
18+
"@project-serum/anchor": "0.24.2",
19+
"@solana/wallet-adapter-base": "^0.9.3",
20+
"@solana/wallet-adapter-react": "^0.15.3",
21+
"@solana/wallet-adapter-react-ui": "^0.9.5",
22+
"@solana/wallet-adapter-wallets": "^0.15.4",
23+
"@solana/web3.js": "^1.35.0",
24+
"copy-to-clipboard": "^3.3.1",
25+
"firebase": "^9.8.2",
26+
"moment": "^2.29.3",
27+
"next": "12.1.0",
28+
"next-seo": "^5.4.0",
29+
"react": "17.0.2",
30+
"react-countdown": "^2.3.2",
31+
"react-dom": "17.0.2",
32+
"react-dropdown": "^1.10.0",
33+
"react-modern-calendar-datepicker": "^3.1.6",
34+
"react-spinners": "^0.11.0",
35+
"react-toastify": "^8.2.0",
36+
"sass": "^1.49.8"
37+
},
38+
"devDependencies": {
39+
"@types/node": "17.0.18",
40+
"@types/react": "17.0.39",
41+
"eslint": "8.9.0",
42+
"eslint-config-next": "12.1.0",
43+
"typescript": "4.5.5"
44+
}
45+
}

public/android-chrome-192x192.png

23.7 KB
Loading

public/android-chrome-512x512.png

87.5 KB
Loading

public/apple-touch-icon.png

21.7 KB
Loading

public/favicon-16x16.png

755 Bytes
Loading

public/favicon-32x32.png

1.61 KB
Loading

public/favicon.ico

15 KB
Binary file not shown.

public/img/main-bg.png

124 KB
Loading

public/og-cover.jpg

337 KB
Loading

public/site.webmanifest

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

src/api/firebase.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const firebaseConfig = {
2+
apiKey: "AIzaSyAI_r1Rs11kIsWJFiCVA4aGt58ffsZrclY",
3+
authDomain: "mindfolk-raffle-afb92.firebaseapp.com",
4+
projectId: "mindfolk-raffle-afb92",
5+
storageBucket: "mindfolk-raffle-afb92.appspot.com",
6+
messagingSenderId: "106626330620",
7+
appId: "1:106626330620:web:c3343f7736902e58774c79",
8+
measurementId: "G-NHD9LYKTVJ"
9+
};
10+
// Import the functions you need from the SDKs you need
11+
import { initializeApp } from "firebase/app";
12+
import { collection, getFirestore } from "firebase/firestore"
13+
// TODO: Add SDKs for Firebase products that you want to use
14+
// https://firebase.google.com/docs/web/setup#available-libraries
15+
16+
// Your web app's Firebase configuration
17+
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
18+
19+
// Initialize Firebase
20+
export const app = initializeApp(firebaseConfig);
21+
export const database = getFirestore(app);
22+
export const db = getFirestore();
23+
24+
export const collectionsInstance = collection(database, "collections");
25+
export const rafflesInstance = collection(database, "raffles");

src/components/CopyAddress.tsx

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import copy from "copy-to-clipboard";
2+
import { useState } from "react";
3+
import { PastIcon } from "./svgIcons";
4+
5+
export default function CopyAddress(props: { address: string, length?: number }) {
6+
const { address, length } = props;
7+
const [isCopied, setIsCopied] = useState(false);
8+
const handleCopy = (text: string) => {
9+
copy(text);
10+
setIsCopied(true);
11+
setTimeout(() => {
12+
setIsCopied(false);
13+
}, 2000);
14+
}
15+
16+
return (
17+
<div className="winner-address" onClick={() => handleCopy(address)}>
18+
{length ? `${address.slice(0, length)}..${address.slice(0 - length)}` : `${address.slice(0, 8)}..${address.slice(-8)}`}
19+
<span className="copy-icon">
20+
{!isCopied ?
21+
<PastIcon /> :
22+
<span className="copied">copied!</span>
23+
}
24+
</span>
25+
</div>
26+
)
27+
}

src/components/CreateCard.tsx

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { useLayoutEffect, useRef, useState } from "react";
2+
import { CardChecked, CardUnChecked } from "./svgIcons";
3+
4+
export default function CreateCard(props: {
5+
selected: boolean,
6+
description: string,
7+
external_url: string,
8+
image: string,
9+
name: string,
10+
mint: string,
11+
handleSelect: Function,
12+
collectionName: string,
13+
collectionId: string
14+
}) {
15+
const cardRef = useRef<HTMLDivElement>(null);
16+
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
17+
18+
useLayoutEffect(() => {
19+
if (cardRef.current) {
20+
setDimensions({
21+
width: cardRef.current.offsetWidth,
22+
height: cardRef.current.offsetHeight
23+
});
24+
}
25+
}, []);
26+
27+
const [selected, setSelected] = useState(false);
28+
const onSelect = () => {
29+
setSelected(!selected);
30+
props.handleSelect({
31+
mint: props.mint,
32+
selected: !selected,
33+
collectionName: props.collectionName,
34+
collectionId: props.collectionId,
35+
})
36+
}
37+
return (
38+
<div className="create-card">
39+
<div
40+
className="card-media"
41+
ref={cardRef}
42+
style={{ height: dimensions.width }}
43+
>
44+
{/* eslint-disable-next-line */}
45+
<img
46+
src={props.image}
47+
alt=""
48+
/>
49+
</div>
50+
{!selected &&
51+
<div className="card-overlay"></div>
52+
}
53+
<span className="card-checked" onClick={() => onSelect()}>
54+
{selected ?
55+
<CardChecked />
56+
:
57+
<CardUnChecked />
58+
}
59+
</span>
60+
</div>
61+
)
62+
}

src/components/EndTimeCountdown.jsx

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import moment from "moment";
2+
import Countdown from "react-countdown";
3+
4+
export default function EndTimeCountdown({ endTime, endAction, ...props }) {
5+
const renderer = ({ days, hours, minutes, seconds, completed }) => {
6+
if (completed) {
7+
return <span>{moment(endTime).fromNow()}</span>
8+
} else {
9+
// Render a countdown
10+
return (
11+
<span>
12+
{days !== 0 ? `${days}d` : ""} {hours}h {minutes}m {seconds}s
13+
</span>
14+
);
15+
}
16+
};
17+
return (
18+
<Countdown date={endTime} renderer={renderer} onComplete={() => endAction()} />
19+
)
20+
}

0 commit comments

Comments
 (0)