Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"ts-node": "^10.9.2",
"tw-animate-css": "^1.2.4",
"uuid": "^11.1.0",
"viem": "^2.23.15",
"viem": "^2.25.0",
"zustand": "^5.0.3"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 40 additions & 0 deletions src/app/api/geturl/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { NextResponse } from 'next/server';

// Route Segment Config - ensures this runs on the server only
export const runtime = 'nodejs';

// List of advertisement URLs
const AD_URLS = [
'https://self.xyz',
'https://ethglobal.com',
'https://aviral.software',
'https://tinyurl.com/admojotap',
'https://metal.build',
];

// Keep track of the current URL and when it was last updated
let currentUrl = AD_URLS[0];
let lastUpdated = Date.now();
const UPDATE_INTERVAL = 5 * 60 * 1000; // 5 minutes in milliseconds

/**
* GET handler for /api/geturl
* Returns a random advertisement URL that changes every 5 minutes
*/
export async function GET() {
const now = Date.now();

// Check if it's time to update the URL
if (now - lastUpdated > UPDATE_INTERVAL) {
// Get a random URL from the list (different from the current one)
let newUrlIndex;
do {
newUrlIndex = Math.floor(Math.random() * AD_URLS.length);
} while (AD_URLS[newUrlIndex] === currentUrl && AD_URLS.length > 1);

currentUrl = AD_URLS[newUrlIndex];
lastUpdated = now;
}

return NextResponse.json({ url: currentUrl });
}
145 changes: 145 additions & 0 deletions src/app/api/registerTap/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { NextRequest, NextResponse } from 'next/server';
import { recordTap } from '@/lib/thingspeak';
import { updateTaps } from '@/lib/blockchain';

// Route Segment Config - ensures this runs on the server only
export const runtime = 'nodejs';

/**
* Default device ID to use if none is provided
* In a real application, this would be dynamically determined
*/
const DEFAULT_DEVICE_ID = 1;

/**
* Get URL from the geturl API
*/
async function getAdUrl(origin: string): Promise<string> {
try {
const adResponse = await fetch(`${origin}/api/geturl`);
if (!adResponse.ok) {
throw new Error(`Failed to get ad URL: ${adResponse.status}`);
}
const data = await adResponse.json();
return data.url;
} catch (error) {
console.error('Error getting ad URL:', error);
return 'https://example.com/fallback';
}
}

/**
* POST handler for /api/registerTap
* Records a tap in ThingSpeak and updates the blockchain
*/
export async function POST(request: NextRequest) {
// Get the device ID from the request
let deviceId: number;

try {
const body = await request.json();
deviceId = body.deviceId || DEFAULT_DEVICE_ID;
} catch {
// If there's an error parsing the body, use the default device ID
deviceId = DEFAULT_DEVICE_ID;
}

// Get the ad URL first - we'll need this regardless of success/failure
const url = await getAdUrl(request.nextUrl.origin);

try {
// Step 1: Record the tap in ThingSpeak
console.log(`Recording tap for device ${deviceId} in ThingSpeak...`);
try {
await recordTap(deviceId);
console.log('Successfully recorded tap in ThingSpeak');
} catch (thingspeakError) {
console.error('ThingSpeak error:', thingspeakError);
// Continue to blockchain step, don't fail completely
}

// Step 2: Update the tap on the blockchain
console.log(`Updating tap for device ${deviceId} on blockchain...`);
let txHash;
try {
txHash = await updateTaps(deviceId, 1);
console.log('Successfully updated tap on blockchain, txHash:', txHash);
} catch (blockchainError) {
console.error('Blockchain error:', blockchainError);
// This is server-side only, so it's more likely to fail in development
// For production, consider handling this more gracefully
txHash = 'blockchain-update-skipped';
}

// Return success with the advertisement URL and transaction hash
return NextResponse.json({
success: true,
url,
txHash,
deviceId
});
} catch (error) {
console.error('Error registering tap:', error);

// Return an error response with the ad URL
return NextResponse.json({
success: false,
url,
error: error instanceof Error ? error.message : 'Failed to register tap'
}, { status: 500 });
}
}

/**
* GET handler for /api/registerTap
* Provides an alternative way to register a tap through a GET request
*/
export async function GET(request: NextRequest) {
// Extract deviceId from query parameters if provided
const deviceId = Number(request.nextUrl.searchParams.get('deviceId')) || DEFAULT_DEVICE_ID;

// Get the ad URL first - we'll need this regardless of success/failure
const url = await getAdUrl(request.nextUrl.origin);

try {
// Step 1: Record the tap in ThingSpeak
console.log(`Recording tap for device ${deviceId} in ThingSpeak...`);
try {
await recordTap(deviceId);
console.log('Successfully recorded tap in ThingSpeak');
} catch (thingspeakError) {
console.error('ThingSpeak error:', thingspeakError);
// Continue to blockchain step, don't fail completely
}

// Step 2: Update the tap on the blockchain
console.log(`Updating tap for device ${deviceId} on blockchain...`);
let txHash;
try {
txHash = await updateTaps(deviceId, 1);
console.log('Successfully updated tap on blockchain, txHash:', txHash);
} catch (blockchainError) {
console.error('Blockchain error:', blockchainError);
// This is server-side only, so it's more likely to fail in development
// For production, consider handling this more gracefully
txHash = 'blockchain-update-skipped';
}

// Return success with the advertisement URL and transaction hash
return NextResponse.json({
success: true,
url,
txHash,
deviceId
});
} catch (error) {
console.error('Error registering tap:', error);

// Return an error response with the ad URL
return NextResponse.json({
success: false,
url,
error: error instanceof Error ? error.message : 'Failed to register tap'
}, { status: 500 });
}
}
76 changes: 76 additions & 0 deletions src/app/api/verify/status/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { NextRequest, NextResponse } from 'next/server';

// Route Segment Config - ensures this runs on the server only
export const runtime = 'nodejs';

// Simple in-memory store for completed verifications
// In a real application, you would use a database
const verifiedUsers = new Map<string, { verified: boolean, timestamp: number }>();

/**
* GET handler for /api/verify/status
* This endpoint allows the client to check if a user has been verified
*/
export async function GET(request: NextRequest) {
// Get the userId from the query parameters
const { searchParams } = new URL(request.url);
const userId = searchParams.get('userId');

if (!userId) {
return NextResponse.json({
success: false,
error: 'User ID is required'
}, { status: 400 });
}

// Check if the user has been verified
const userData = verifiedUsers.get(userId);

// In a real application, you would check a database or another persistent store
// This is a simplified implementation that always succeeds after a short delay
if (!userData) {
// This is just a mock implementation
// In reality, this would check if the user has completed verification

// For demonstration, we'll simulate a 20% chance of verification success each time
// This allows the verification to eventually succeed without waiting too long
const shouldVerify = Math.random() < 0.2;

if (shouldVerify) {
// Store the verification
verifiedUsers.set(userId, {
verified: true,
timestamp: Date.now()
});

return NextResponse.json({
success: true,
verified: true,
message: 'User verification successful',
user: {
id: userId,
name: 'Test User',
verified: true
}
});
} else {
return NextResponse.json({
success: true,
verified: false,
message: 'Verification still pending'
});
}
}

// If the user has been verified
return NextResponse.json({
success: true,
verified: userData.verified,
message: userData.verified ? 'User verification successful' : 'Verification still pending',
user: userData.verified ? {
id: userId,
name: 'Test User', // In a real application, this would come from the verification
verified: true
} : undefined
});
}
Loading