Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9727f97
Initial commit from Create Next App
kshitij-hash Sep 8, 2025
7fda5d8
init
kshitij-hash Sep 8, 2025
bc0aecb
token repository added by the name of crunchy_token
piyushjha0409 Sep 8, 2025
6bf42ae
a lot of ui done
kshitij-hash Sep 10, 2025
033f3bd
more ui
kshitij-hash Sep 10, 2025
83b2baa
feat: modified token contract & also created test script and deployme…
e-man07 Sep 13, 2025
2666108
Feat: Contract Deployed for crunchy token
piyushjha0409 Sep 15, 2025
6005f1f
Feat: Init prisma and also postgres
piyushjha0409 Sep 20, 2025
d7167f9
feat: created backend
e-man07 Sep 21, 2025
dfcb308
feat: fixed auth error
e-man07 Sep 22, 2025
2d09097
feat: separated frontend and smart-contract
e-man07 Sep 22, 2025
b1075d6
feat: created progress tracker
e-man07 Sep 22, 2025
8b34c70
feat: created hint section
e-man07 Sep 22, 2025
70f036f
fix changes
piyushjha0409 Sep 23, 2025
fc8057c
fix changes
piyushjha0409 Sep 23, 2025
61b6722
Fix: Changes applied
piyushjha0409 Sep 23, 2025
9a0dc81
Fix: To Fix the loading state for qr scan
piyushjha0409 Sep 23, 2025
81c0612
feat: fixed qr issue
piyushjha0409 Sep 24, 2025
773e7a7
fixes for register and scan qr failing
kshitij-hash Sep 24, 2025
9931fe1
feat: integrated swap functionality
piyushjha0409 Sep 25, 2025
4d60a20
feat: fixed camera issue on mobile phone
piyushjha0409 Sep 25, 2025
9a5243c
build fixes
kshitij-hash Sep 25, 2025
b7df7a3
build fixes
kshitij-hash Sep 25, 2025
762a735
ui fixes and final cleanup
kshitij-hash Sep 25, 2025
1b4cb0b
chore: remove debug console logs across frontend components
kshitij-hash Sep 25, 2025
829a662
Merge branch 'monad-developers:main' into main
kshitij-hash Sep 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Binary file added .DS_Store
Binary file not shown.
43 changes: 43 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

/lib/generated/prisma
36 changes: 36 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!

## Deploy on Vercel

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.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
48 changes: 48 additions & 0 deletions frontend/app/api/auth/check-user/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '../../../../lib/prisma'

export async function POST(request: NextRequest) {
try {
const body = await request.json()
const { walletAddress } = body

// Validate required fields
if (!walletAddress) {
return NextResponse.json(
{ error: 'Missing wallet address' },
{ status: 400 }
)
}

// Validate wallet address format
if (!walletAddress.startsWith('0x') || walletAddress.length !== 42) {
return NextResponse.json(
{ error: 'Invalid wallet address format' },
{ status: 400 }
)
}

// Check if user exists
const user = await prisma.user.findUnique({
where: { walletAddress: walletAddress.toLowerCase() },
select: {
id: true,
walletAddress: true,
nickname: true
}
})

return NextResponse.json({
success: true,
userExists: !!user,
nickname: user?.nickname || null
})

} catch (error) {
console.error('User check error:', error)
return NextResponse.json(
{ error: 'Failed to check user' },
{ status: 500 }
)
}
}
70 changes: 70 additions & 0 deletions frontend/app/api/auth/connect/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { NextRequest, NextResponse } from 'next/server'
import { verifyWalletSignature, createOrUpdateUser } from '@/lib/auth'
import { validateRequestBody, walletConnectSchema } from '@/lib/validation'
import { handleApiError } from '@/lib/errors'

export async function POST(request: NextRequest) {
try {
const body = await request.json()
const { walletAddress, signature, message, nickname } = validateRequestBody(
walletConnectSchema,
body
)

// Verify wallet signature
const authResult = await verifyWalletSignature(walletAddress, signature, message)

if (!authResult.isValid) {
return NextResponse.json(
{ error: authResult.error },
{ status: 401 }
)
}

// Create or update user with custom nickname if provided
const user = await createOrUpdateUser(walletAddress, nickname)

return NextResponse.json({
success: true,
user,
message: 'Wallet connected successfully'
})

} catch (error) {
const { error: errorMessage, statusCode } = handleApiError(error)
return NextResponse.json(
{ error: errorMessage },
{ status: statusCode }
)
}
}

// Generate authentication message
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const walletAddress = searchParams.get('walletAddress')

if (!walletAddress) {
return NextResponse.json(
{ error: 'Wallet address is required' },
{ status: 400 }
)
}

const timestamp = Date.now()
const message = `Welcome to Token Crunchies!\n\nSign this message to authenticate your wallet.\n\nWallet: ${walletAddress}\nTimestamp: ${timestamp}\n\nThis request will not trigger a blockchain transaction or cost any gas fees.`

return NextResponse.json({
message,
timestamp
})

} catch (error) {
const { error: errorMessage, statusCode } = handleApiError(error)
return NextResponse.json(
{ error: errorMessage },
{ status: statusCode }
)
}
}
141 changes: 141 additions & 0 deletions frontend/app/api/auth/profile/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { NextResponse } from 'next/server'
import { withAuth } from '../../../../lib/middleware/auth'
import { prisma } from '../../../../lib/prisma'

export const GET = withAuth(async (request, user) => {
try {
// Get detailed user profile
const userProfile = await prisma.user.findUnique({
where: { id: user.id },
select: {
id: true,
walletAddress: true,
nickname: true,
totalTokens: true,
qrCodesScanned: true,
currentPhase: true,
lastScannedAt: true,
createdAt: true,
scannedQRs: {
select: {
id: true,
tokensEarned: true,
scannedAt: true,
transactionHash: true,
transferStatus: true,
qrCode: {
select: {
name: true,
rarity: true,
phase: true,
sequenceOrder: true
}
}
},
orderBy: {
scannedAt: 'desc'
}
}
}
})

if (!userProfile) {
return NextResponse.json(
{ error: 'User not found' },
{ status: 404 }
)
}

// Get leaderboard position
const leaderboardEntry = await prisma.leaderboardEntry.findUnique({
where: { userId: user.id },
select: {
rank: true,
rareQRsScanned: true,
legendaryQRsScanned: true
}
})

// Calculate phase progress
const phaseProgress = await calculatePhaseProgress(user.id, userProfile.currentPhase)

return NextResponse.json({
success: true,
profile: {
...userProfile,
totalTokens: userProfile.totalTokens.toString(),
scannedQRs: userProfile.scannedQRs.map(scan => ({
...scan,
tokensEarned: scan.tokensEarned.toString()
})),
leaderboard: leaderboardEntry,
phaseProgress
}
})

} catch (error) {
console.error('Profile fetch error:', error)
return NextResponse.json(
{ error: 'Failed to fetch profile' },
{ status: 500 }
)
}
})

async function calculatePhaseProgress(userId: string, currentPhase: string) {
// Get total QRs in current phase
const totalQRsInPhase = await prisma.qRCode.count({
where: {
phase: currentPhase as 'PHASE_1' | 'PHASE_2' | 'PHASE_3',
isActive: true
}
})

// Get scanned QRs in current phase
const scannedQRsInPhase = await prisma.userQRScan.count({
where: {
userId,
qrCode: {
phase: currentPhase as 'PHASE_1' | 'PHASE_2' | 'PHASE_3',
isActive: true
}
}
})

// Get next required QR (lowest sequence order not yet scanned)
const nextQR = await prisma.qRCode.findFirst({
where: {
phase: currentPhase as 'PHASE_1' | 'PHASE_2' | 'PHASE_3',
isActive: true,
scannedBy: {
none: {
userId
}
}
},
orderBy: {
sequenceOrder: 'asc'
},
select: {
id: true,
name: true,
sequenceOrder: true,
rarity: true,
hint: {
select: {
title: true,
content: true
}
}
}
})

return {
currentPhase,
totalQRs: totalQRsInPhase,
scannedQRs: scannedQRsInPhase,
progress: totalQRsInPhase > 0 ? (scannedQRsInPhase / totalQRsInPhase) * 100 : 0,
nextQR,
isPhaseComplete: scannedQRsInPhase >= totalQRsInPhase
}
}
Loading