diff --git a/README.md b/README.md
index 299ffa8..2dcc1cb 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
**DeCleanup Rewards** is a decentralized application (dApp) build on steller network and designed to:
a) **tokenize IRL impact created via global/local cleanup efforts**
-b) **incentivize environmental actions via DeFi mechanics**.
+b) **incentivize environmental actions via DeFi mechanics**.
The platform promotes environmental stewardship globally, with plans to activate global/local communities and scale across multiple blockchain ecosystems.

@@ -11,13 +11,13 @@ The platform promotes environmental stewardship globally, with plans to activate
**Smart Contract GitHub Repository** - ππ https://github.com/DeCleanUp-DCU/Smart-Contract
-**Smart Contract onchain** [Arbiscan](https://arbiscan.io/address/0xf21389b64e0eb749fd150d0c44742692e19a69c8)
+**Smart Contract onchain** [Arbiscan](https://arbiscan.io/address/0xf21389b64e0eb749fd150d0c44742692e19a69c8)
## Uniqueness
**How DeCleanup dApp works**: Participants engage in cleanups, submit proof via photos, and earn dynamic NFTs that evolve based on their contributions. More details in our [Mirror Article](https://mirror.xyz/decleanupnet.eth/ZzncKRu-Q-leEZkQ48Txm-NQRxG_hH3V3wyHaYUKfYI).
-**User-Centric Design & Functionality**: The DeCleanup dApp offers a seamless user experience with an intuitive interface, allowing individuals and communities to easily submit proof of cleanups and earn dynamic NFTs, reflecting real-world impact on-chain. The verification system ensures quick approval for rewards, making the process simple and efficient.
+**User-Centric Design & Functionality**: The DeCleanup dApp offers a seamless user experience with an intuitive interface, allowing individuals and communities to easily submit proof of cleanups and earn dynamic NFTs, reflecting real-world impact on-chain. The verification system ensures quick approval for rewards, making the process simple and efficient.
More details in our [Guide](https://mirror.xyz/decleanupnet.eth/A5uzOpx9HUgXZEopCKUsbgffw9SajL4Q9eECgrguq-4).
**Gasless Approach**: We chose Arbitrum for its low gas fees, with only the first claim requiring gas payment, while the rest of the experience is gasless. This eliminates barriers to onboarding non-tech-savvy users into Web3, enhancing real-world impact - our key KPI. Gasless transactions make Web3 more accessible to everyday people.
@@ -33,19 +33,22 @@ More details in our [Guide](https://mirror.xyz/decleanupnet.eth/A5uzOpx9HUgXZEop

The collection items have common traits that remain consistent with each NFT upgrade:
+
- **Category**: Cleanup Impact NFT
- **Type**: Dynamic
- **Impact**: Environmental
There are dynamic traits, which grow every three cleanups:
+
- **Rarity**: Common (1-3 cleanups), Rare (4-6 cleanups), Legendary (7-9 cleanups), Unique (10 cleanups)
- **Level**: Newbie (1-3 cleanups), Pro (4-6 cleanups), Hero (7-9 cleanups), Guardian (10 cleanups)
And dynamic traits which grow with every cleanup done:
+
- **Impact Value**: 1 (first cleanup) to 10 (last cleanup)
- **DCU Points**: 10 (first cleanup) to 100 (last cleanup)
-While the first two categories of traits determine the general information required for this impact productβs classification on the Impact Marketplace, the last categories are mainly dynamic traits, which will determine the rewards value via Impact Marketplace DeFi utility and will contribute for userβs IRL impact rank.
+While the first two categories of traits determine the general information required for this impact productβs classification on the Impact Marketplace, the last categories are mainly dynamic traits, which will determine the rewards value via Impact Marketplace DeFi utility and will contribute for userβs IRL impact rank.
Read more on this topic in the article by EcoSynthesisX on [Mirror](https://mirror.xyz/ecosynthesisx.eth/zOdeuaeFfJUFScZZKu1OGF7cWCiRgUHQSGE-14cf8fo).

diff --git a/package.json b/package.json
index db329b0..9d2d16b 100644
--- a/package.json
+++ b/package.json
@@ -43,7 +43,7 @@
"react-medium-image-zoom": "^5.2.12",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7",
- "thirdweb": "^5.0.3",
+ "thirdweb": "^5.0.3",
"viem": "^2.26.2",
"wagmi": "^2.14.16"
},
@@ -54,10 +54,10 @@
"@types/react": "^19.0.1",
"@types/react-dom": "^19",
"@types/react-window": "^1.8.8",
- "@typescript-eslint/eslint-plugin": "7.18.0",
- "@typescript-eslint/parser": "7.18.0",
+ "@typescript-eslint/eslint-plugin": "7.18.0",
+ "@typescript-eslint/parser": "7.18.0",
"autoprefixer": "^10.4.20",
- "eslint": "8.57.1",
+ "eslint": "8.57.1",
"eslint-config-airbnb-typescript": "^18.0.0",
"eslint-config-next": "^15.1.0",
"eslint-config-prettier": "^9.1.0",
@@ -76,4 +76,4 @@
"tailwindcss": "^3.4.16",
"typescript": "^5.7.2"
}
-}
\ No newline at end of file
+}
diff --git a/src/app/api/auth/[...nextauth].ts b/src/app/api/auth/[...nextauth].ts
index 0b57621..f9b9053 100644
--- a/src/app/api/auth/[...nextauth].ts
+++ b/src/app/api/auth/[...nextauth].ts
@@ -1,27 +1,31 @@
-import NextAuth from "next-auth";
-import GoogleProvider from "next-auth/providers/google";
+import NextAuth from 'next-auth'
+import GoogleProvider from 'next-auth/providers/google'
// Extend the Session and User types to include the idToken
-declare module "next-auth" {
+declare module 'next-auth' {
interface User {
- idToken?: string;
+ idToken?: string
}
interface Session {
- idToken?: string | undefined;
+ idToken?: string | undefined
}
}
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
GoogleProvider({
- clientId: process.env.GOOGLE_CLIENT_ID ?? "",
- clientSecret: process.env.GOOGLE_CLIENT_SECRET ?? (() => { throw new Error("GOOGLE_CLIENT_SECRET is not defined"); })(),
+ clientId: process.env.GOOGLE_CLIENT_ID ?? '',
+ clientSecret:
+ process.env.GOOGLE_CLIENT_SECRET ??
+ (() => {
+ throw new Error('GOOGLE_CLIENT_SECRET is not defined')
+ })(),
authorization: {
params: {
- prompt: "consent",
- access_type: "offline",
- response_type: "code",
- scope: "openid profile email",
+ prompt: 'consent',
+ access_type: 'offline',
+ response_type: 'code',
+ scope: 'openid profile email',
},
},
}),
@@ -30,19 +34,19 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
// Store the Google id_token in the JWT
async jwt({ token, account }) {
if (account) {
- token.idToken = account.id_token;
+ token.idToken = account.id_token
}
- return token;
+ return token
},
// Add the id_token to the session
async session({ session, token }) {
- session.idToken = token.idToken as string;
- return session;
+ session.idToken = token.idToken as string
+ return session
},
},
session: {
- strategy: "jwt",
+ strategy: 'jwt',
},
-});
+})
-export default handlers;
\ No newline at end of file
+export default handlers
diff --git a/src/app/api/auth/login.ts b/src/app/api/auth/login.ts
index d3876d6..383e35e 100644
--- a/src/app/api/auth/login.ts
+++ b/src/app/api/auth/login.ts
@@ -1,71 +1,81 @@
-"use client"
-import type { NextApiRequest, NextApiResponse } from "next";
-import { getServerSession } from "next-auth";
-import { createThirdwebClient, generatePayload, getUser, verifyPayload } from "thirdweb";
-import { inMemoryWallet } from "thirdweb/wallets";
-import { auth } from "./[...nextauth]";
-import { serialize } from "cookie";
+'use client'
+import type { NextApiRequest, NextApiResponse } from 'next'
+import { getServerSession } from 'next-auth'
+import {
+ createThirdwebClient,
+ generatePayload,
+ getUser,
+ verifyPayload,
+} from 'thirdweb'
+import { inMemoryWallet } from 'thirdweb/wallets'
+import { auth } from './[...nextauth]'
+import { serialize } from 'cookie'
// Initialize ThirdWeb client
const client = createThirdwebClient({
clientId: process.env.NEXT_PUBLIC_THIRDWEB_CLIENT_ID,
-});
+})
-export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- if (req.method !== "POST") {
- return res.status(405).json({ error: "Method not allowed" });
+export default async function handler(
+ req: NextApiRequest,
+ res: NextApiResponse,
+) {
+ if (req.method !== 'POST') {
+ return res.status(405).json({ error: 'Method not allowed' })
}
try {
// Get the NextAuth session (Google OAuth)
- const session = await getServerSession(req, res, auth);
+ const session = await getServerSession(req, res, auth)
if (!session || !session.idToken) {
- return res.status(401).json({ error: "Unauthorized" });
+ return res.status(401).json({ error: 'Unauthorized' })
}
// Use the Google id_token as the identifier
- const idToken = session.idToken;
+ const idToken = session.idToken
// Generate a ThirdWeb Auth payload
const payload = await generatePayload({
client,
address: idToken, // Use id_token as the unique identifier
- });
+ })
// Sign the payload with an in-memory wallet (for demo purposes)
- const wallet = inMemoryWallet();
- const signedPayload = await wallet.signPayload(payload);
+ const wallet = inMemoryWallet()
+ const signedPayload = await wallet.signPayload(payload)
// Verify the signed payload
const verified = await verifyPayload({
client,
payload: signedPayload,
- });
+ })
if (!verified) {
- return res.status(401).json({ error: "Verification failed" });
+ return res.status(401).json({ error: 'Verification failed' })
}
// Get the ThirdWeb user (includes wallet address)
- const thirdwebUser = await getUser({ client, address: idToken });
+ const thirdwebUser = await getUser({ client, address: idToken })
// Store the ThirdWeb session in a cookie
const sessionData = {
address: thirdwebUser.address,
idToken,
- };
- const encryptedSessionData = JSON.stringify(sessionData); // In production, encrypt this
- const cookie = serialize("thirdweb_session", encryptedSessionData, {
+ }
+ const encryptedSessionData = JSON.stringify(sessionData) // In production, encrypt this
+ const cookie = serialize('thirdweb_session', encryptedSessionData, {
httpOnly: true,
- secure: process.env.NODE_ENV === "production",
+ secure: process.env.NODE_ENV === 'production',
maxAge: 60 * 60 * 24 * 7, // 1 week
- path: "/",
- });
+ path: '/',
+ })
- res.setHeader("Set-Cookie", cookie);
- res.status(200).json({ message: "Login successful", address: thirdwebUser.address });
+ res.setHeader('Set-Cookie', cookie)
+ res
+ .status(200)
+ .json({ message: 'Login successful', address: thirdwebUser.address })
} catch (error) {
- console.error("Login error:", error);
- res.status(500).json({ error: "Internal server error" });
+ console.error('Login error:', error)
+ res.status(500).json({ error: 'Internal server error' })
}
-}
\ No newline at end of file
+}
diff --git a/src/app/client.ts b/src/app/client.ts
index 4b43bf4..3ace347 100644
--- a/src/app/client.ts
+++ b/src/app/client.ts
@@ -1,12 +1,14 @@
-import { createThirdwebClient } from "thirdweb";
+import { createThirdwebClient } from 'thirdweb'
+
const clientId = process.env.NEXT_PUBLIC_THIRDWEB_CLIENT_ID;
+
if (!clientId) {
- throw new Error("No client ID provided");
+ throw new Error('No client ID provided')
}
export const client = createThirdwebClient({
clientId: clientId,
-});
\ No newline at end of file
+})
diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx
index fcf0829..f7cb0cd 100644
--- a/src/app/dashboard/page.tsx
+++ b/src/app/dashboard/page.tsx
@@ -24,14 +24,12 @@ export default function Page() {
console.log('Uploaded images:', images)
}
return (
-
+
-
-
{/* 24 WEEKS STREAK*/}
-
+
-
+
@@ -202,7 +202,7 @@ function LongButton({ text, isNotBlack }: LongButtonProps) {