mirror of
https://github.com/mito-systems/ranger-app.git
synced 2025-12-28 06:04:07 +00:00
try now
This commit is contained in:
parent
c44ba31b04
commit
89484ad2a9
@ -146,34 +146,11 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
||||
const formData = await req.formData()
|
||||
const imageFile = formData.get('image')
|
||||
|
||||
// Check for wallet address in form data, URL params, and headers
|
||||
let walletAddress = formData.get('walletAddress');
|
||||
|
||||
// Check URL query parameters (most reliable on Vercel)
|
||||
const url = new URL(req.url);
|
||||
const queryWalletAddress = url.searchParams.get('wallet');
|
||||
if (queryWalletAddress && !walletAddress) {
|
||||
console.log('Found wallet address in URL query parameter:', queryWalletAddress);
|
||||
walletAddress = queryWalletAddress;
|
||||
}
|
||||
|
||||
// Also check custom header (less reliable with Vercel)
|
||||
const walletHeaderAddress = req.headers.get('X-Wallet-Address');
|
||||
if (walletHeaderAddress && !walletAddress) {
|
||||
console.log('Found wallet address in custom header:', walletHeaderAddress);
|
||||
walletAddress = walletHeaderAddress;
|
||||
}
|
||||
|
||||
// Log more detailed data about the wallet address
|
||||
// Simple request data logging
|
||||
console.log('Request data received:', {
|
||||
hasImage: !!imageFile,
|
||||
imageType: imageFile ? typeof imageFile : 'undefined',
|
||||
hasWalletAddressInForm: !!formData.get('walletAddress'),
|
||||
hasWalletAddressInHeader: !!walletHeaderAddress,
|
||||
hasWalletAddressInQuery: !!queryWalletAddress,
|
||||
requestUrl: req.url,
|
||||
searchParams: Object.fromEntries(url.searchParams.entries()),
|
||||
finalWalletAddress: walletAddress || 'Not provided',
|
||||
formDataKeys: Array.from(formData.keys())
|
||||
});
|
||||
|
||||
@ -249,11 +226,12 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
||||
: "🌿 No wildlife detected in this image. Try uploading a photo of an animal!"
|
||||
}`
|
||||
|
||||
// Prepare user response with extra fields for token data we'll add later
|
||||
// Prepare user response with animal type for token awarding later
|
||||
const responseData = {
|
||||
description: responseMessage,
|
||||
isAnimal: visionResult.isAnimal,
|
||||
tokenReward: null
|
||||
animalType: visionResult.mainObject || 'Unknown wildlife',
|
||||
pointsAwarded: visionResult.isAnimal ? 50 : 0 // Default points value
|
||||
};
|
||||
|
||||
// Background processing for animal images
|
||||
@ -393,76 +371,8 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
||||
// Even if points award fails, we continue to try token rewards
|
||||
}
|
||||
|
||||
// AFTER points are awarded, try to award tokens if wallet is connected
|
||||
// This is separate so issues with token rewards don't affect points
|
||||
try {
|
||||
// We already extracted the wallet address at the beginning of the request
|
||||
// walletAddress is already defined in the outer scope
|
||||
|
||||
// Ensure it's a string type
|
||||
const walletAddressString = walletAddress ? String(walletAddress) : null;
|
||||
|
||||
console.log('Wallet address for token award (final check):', {
|
||||
walletAddress,
|
||||
walletAddressString,
|
||||
walletAddressType: typeof walletAddress
|
||||
});
|
||||
|
||||
// Log the wallet address for debugging
|
||||
console.log('Wallet address for token award:', {
|
||||
processedValue: walletAddress || 'Not provided',
|
||||
valueType: typeof walletAddress
|
||||
});
|
||||
|
||||
// Import dynamically to avoid server-side issues with window object
|
||||
const { awardTokensForSighting } = await import('../../../services/blockchain/tokenRewardService');
|
||||
|
||||
// Get species from vision result for token amount calculation
|
||||
const species = visionResult.mainObject || 'animal';
|
||||
|
||||
// Skip token award if no wallet address is provided
|
||||
if (!walletAddress) {
|
||||
console.log('No wallet address provided, skipping token award');
|
||||
// Continue with other operations without token reward
|
||||
} else {
|
||||
// Log wallet information
|
||||
console.log('Token award attempt:', {
|
||||
walletAddressProvided: true,
|
||||
walletAddress: walletAddress,
|
||||
species
|
||||
});
|
||||
|
||||
// Log detailed information for debugging
|
||||
console.log('Starting token award with explicit address:', walletAddress);
|
||||
|
||||
// Attempt to award tokens for this wildlife sighting
|
||||
// Make sure we're passing a properly processed string
|
||||
const tokenResult = await awardTokensForSighting(
|
||||
species,
|
||||
undefined,
|
||||
walletAddressString // Use the explicitly string-converted version
|
||||
);
|
||||
|
||||
// Add token reward info to response if successful
|
||||
if (tokenResult.success) {
|
||||
responseData.tokenReward = {
|
||||
amount: tokenResult.tokenAmount,
|
||||
txHash: tokenResult.txHash
|
||||
};
|
||||
|
||||
console.log('Token reward successful:', tokenResult);
|
||||
} else if (tokenResult.walletConnected) {
|
||||
// Wallet was connected but award failed
|
||||
console.error('Token reward failed:', tokenResult.error);
|
||||
} else {
|
||||
// No wallet connected - this is not an error, just informational
|
||||
console.log('No wallet connected, skipping token reward');
|
||||
}
|
||||
}
|
||||
} catch (tokenError) {
|
||||
console.error('Error processing token reward:', tokenError);
|
||||
// Continue without token rewards if there's an error
|
||||
}
|
||||
// Note: We've moved token awarding to a separate endpoint
|
||||
// This simplifies the flow and avoids wallet connection issues on the server
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to award points for image:', err);
|
||||
|
||||
@ -54,9 +54,6 @@ const WildlifeIdentifier: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to check for wallet connection - the process works for both user types
|
||||
// Tokens will be awarded automatically if wallet is connected
|
||||
|
||||
setIsProcessing(true);
|
||||
setError(null);
|
||||
|
||||
@ -65,7 +62,6 @@ const WildlifeIdentifier: React.FC = () => {
|
||||
const formData = new FormData();
|
||||
formData.append('image', selectedImage);
|
||||
|
||||
// Add wallet address to the request if connected
|
||||
// Get the wallet address both from memory and localStorage as backup
|
||||
let userAddress = getWalletAddress();
|
||||
|
||||
@ -82,45 +78,12 @@ const WildlifeIdentifier: React.FC = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Hard-code a wallet connection check - let's be very explicit
|
||||
const isConnected = isWalletConnected();
|
||||
console.log('Explicitly checking wallet connection status:', isConnected);
|
||||
|
||||
if (userAddress) {
|
||||
console.log('Found wallet address to include in upload:', userAddress);
|
||||
// Explicitly add as string to avoid any type issues
|
||||
formData.append('walletAddress', String(userAddress));
|
||||
|
||||
// Debug check - verify the value was properly added
|
||||
const check = formData.get('walletAddress');
|
||||
console.log('Verification after append:', {
|
||||
walletAddressInForm: check,
|
||||
matches: check === userAddress,
|
||||
formDataKeys: Array.from(formData.keys())
|
||||
});
|
||||
} else {
|
||||
console.log('No wallet address found for upload');
|
||||
|
||||
// Force add a wallet check flag to help debug
|
||||
formData.append('walletChecked', 'true');
|
||||
formData.append('walletStatus', isConnected ? 'connected_but_no_address' : 'not_connected');
|
||||
}
|
||||
|
||||
console.log('Uploading image for analysis...');
|
||||
console.log('Wallet connection status:', isWalletConnected());
|
||||
console.log('Wallet connection status:', isConnected);
|
||||
console.log('User wallet address:', userAddress || 'Not connected');
|
||||
|
||||
// Construct the URL with wallet address as a query parameter if available
|
||||
let url = '/api/analyze';
|
||||
if (userAddress) {
|
||||
// Encode the wallet address for URL safety
|
||||
const encodedWalletAddress = encodeURIComponent(userAddress);
|
||||
url += `?wallet=${encodedWalletAddress}`;
|
||||
console.log('Adding wallet address as query parameter:', userAddress);
|
||||
}
|
||||
|
||||
// Send to the Next.js API route with wallet in the URL
|
||||
const response = await fetch(url, {
|
||||
// Send to the Next.js API route for analysis (points only)
|
||||
const response = await fetch('/api/analyze', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
@ -133,12 +96,43 @@ const WildlifeIdentifier: React.FC = () => {
|
||||
const analysisResult = await response.json();
|
||||
console.log('Analysis result:', analysisResult);
|
||||
|
||||
// IMPORTANT: New approach - if the analysis was successful and we have a wallet address,
|
||||
// make a separate call to award tokens
|
||||
let tokenResult = null;
|
||||
|
||||
if (analysisResult.isAnimal && userAddress && isConnected) {
|
||||
try {
|
||||
console.log('Animal detected and wallet connected. Awarding tokens separately...');
|
||||
|
||||
const tokenResponse = await fetch('/api/award-tokens', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
walletAddress: userAddress,
|
||||
animalName: analysisResult.animalType || 'Unknown wildlife'
|
||||
})
|
||||
});
|
||||
|
||||
if (tokenResponse.ok) {
|
||||
tokenResult = await tokenResponse.json();
|
||||
console.log('Token award result:', tokenResult);
|
||||
} else {
|
||||
console.error('Failed to award tokens:', await tokenResponse.json());
|
||||
}
|
||||
} catch (tokenError) {
|
||||
console.error('Error awarding tokens:', tokenError);
|
||||
}
|
||||
}
|
||||
|
||||
// Format the result for display
|
||||
setResult({
|
||||
success: analysisResult.isAnimal,
|
||||
message: analysisResult.description,
|
||||
rewardAmount: analysisResult.tokenReward?.amount?.toString(),
|
||||
txHash: analysisResult.tokenReward?.txHash,
|
||||
// If we have token results from the separate endpoint, use those
|
||||
rewardAmount: tokenResult?.amount?.toString() || analysisResult.pointsAwarded?.toString() || '0',
|
||||
txHash: tokenResult?.txHash,
|
||||
});
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Error processing image');
|
||||
|
||||
@ -36,94 +36,45 @@ export const isRareSpecies = (species: string): boolean => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Award tokens for a wildlife sighting if wallet is connected
|
||||
* Award tokens for a wildlife sighting with an explicit wallet address
|
||||
* @param walletAddress The recipient wallet address
|
||||
* @param userEmail The user's email (for logging/tracking)
|
||||
* @param species The detected animal species
|
||||
* @param points Optional number of points to convert to tokens (if not provided, calculates based on species)
|
||||
* @param explicitWalletAddress Optional wallet address to use instead of checking connection state
|
||||
* @returns Object containing success status and transaction info
|
||||
*/
|
||||
export const awardTokensForSighting = async (
|
||||
species: string,
|
||||
points?: number,
|
||||
explicitWalletAddress?: string
|
||||
walletAddress: string,
|
||||
userEmail: string,
|
||||
species: string
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
tokenAmount?: number;
|
||||
amount?: number;
|
||||
txHash?: string;
|
||||
error?: string;
|
||||
walletConnected: boolean;
|
||||
}> => {
|
||||
try {
|
||||
// Determine wallet address - either from parameter or connected wallet
|
||||
let walletAddress = explicitWalletAddress;
|
||||
|
||||
// If explicit address was provided, use it directly (server-side case)
|
||||
if (walletAddress) {
|
||||
console.log('Using explicitly provided wallet address:', walletAddress);
|
||||
} else {
|
||||
// Client-side case - check if wallet is connected
|
||||
console.log('No explicit wallet address provided, checking wallet connection state...');
|
||||
|
||||
// Try to get from memory first
|
||||
if (isWalletConnected()) {
|
||||
walletAddress = getWalletAddress();
|
||||
console.log('Found connected wallet in memory:', walletAddress);
|
||||
}
|
||||
|
||||
// Try localStorage as a fallback (client-side only)
|
||||
if (!walletAddress && typeof window !== 'undefined') {
|
||||
try {
|
||||
const storedAddress = localStorage.getItem('wildlife_wallet_address');
|
||||
if (storedAddress) {
|
||||
console.log('Using wallet address from localStorage:', storedAddress);
|
||||
walletAddress = storedAddress;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Error accessing localStorage:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// If we still don't have an address, return no wallet connected
|
||||
if (!walletAddress) {
|
||||
console.log('No wallet connected, skipping token award.');
|
||||
return {
|
||||
success: false,
|
||||
error: 'No wallet connected',
|
||||
walletConnected: false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Validate we have a wallet address by this point
|
||||
if (!walletAddress) {
|
||||
console.log('No valid wallet address available for token award.');
|
||||
console.error('No wallet address provided for token award');
|
||||
return {
|
||||
success: false,
|
||||
error: 'No wallet address available',
|
||||
walletConnected: false
|
||||
error: 'No wallet address provided'
|
||||
};
|
||||
}
|
||||
|
||||
console.log('Processing token award for wallet:', walletAddress);
|
||||
console.log(`Processing token award for wallet ${walletAddress} and species ${species}`);
|
||||
|
||||
// Calculate token reward amount - either from points or from species
|
||||
let totalReward: number;
|
||||
|
||||
if (typeof points === 'number' && points > 0) {
|
||||
// If points are provided, use them directly (1 point = 1 token)
|
||||
totalReward = points;
|
||||
} else {
|
||||
// Otherwise calculate based on species
|
||||
const baseReward = TOKEN_REWARDS.WILDLIFE_SIGHTING;
|
||||
const isRare = isRareSpecies(species);
|
||||
const rareBonus = isRare ? TOKEN_REWARDS.RARE_SPECIES : 0;
|
||||
totalReward = baseReward + rareBonus;
|
||||
}
|
||||
// Calculate token reward amount based on species
|
||||
const baseReward = TOKEN_REWARDS.WILDLIFE_SIGHTING;
|
||||
const isRare = isRareSpecies(species);
|
||||
const rareBonus = isRare ? TOKEN_REWARDS.RARE_SPECIES : 0;
|
||||
const totalReward = baseReward + rareBonus;
|
||||
|
||||
// Call the backend service to award tokens through the distributor
|
||||
const apiUrl = process.env.NEXT_PUBLIC_TOKEN_BACKEND_URL || 'http://localhost:3001';
|
||||
const apiKey = process.env.NEXT_PUBLIC_TOKEN_API_KEY || '';
|
||||
|
||||
console.log(`Sending token award request to ${apiUrl}/api/award-tokens`);
|
||||
|
||||
// Request tokens from the backend service
|
||||
const response = await fetch(`${apiUrl}/api/award-tokens`, {
|
||||
method: 'POST',
|
||||
@ -133,24 +84,26 @@ export const awardTokensForSighting = async (
|
||||
},
|
||||
body: JSON.stringify({
|
||||
recipientAddress: walletAddress,
|
||||
species: species.toLowerCase()
|
||||
species: species.toLowerCase(),
|
||||
userEmail
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
console.error('Token service error response:', errorData);
|
||||
throw new Error(errorData.error || 'Error from token service');
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
console.log('Token service success response:', result);
|
||||
|
||||
if (result.success) {
|
||||
console.log(`Awarded tokens for ${species} sighting to wallet ${walletAddress}`);
|
||||
console.log(`Awarded ${result.amount || totalReward} tokens for ${species} to wallet ${walletAddress}`);
|
||||
return {
|
||||
success: true,
|
||||
tokenAmount: result.amount,
|
||||
txHash: result.txHash,
|
||||
walletConnected: true
|
||||
amount: result.amount || totalReward,
|
||||
txHash: result.txHash
|
||||
};
|
||||
} else {
|
||||
throw new Error(result.error || 'Failed to award tokens');
|
||||
@ -159,8 +112,7 @@ export const awardTokensForSighting = async (
|
||||
console.error('Error in token reward service:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error processing token reward',
|
||||
walletConnected: true
|
||||
error: error instanceof Error ? error.message : 'Unknown error processing token reward'
|
||||
};
|
||||
}
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user