error fixed

This commit is contained in:
Selvi 2026-06-10 20:04:57 +05:30
parent 0a02a2fa82
commit 180302cee1
5 changed files with 158 additions and 86 deletions

View File

@ -1,7 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
trailingSlash: true,
trailingSlash: true,
images: {
unoptimized: true, // ✅ needed
},

View File

@ -1,32 +1,58 @@
import { fallbackGoogleReviews } from '@/lib/reviewUtils';
export const dynamic = 'force-dynamic';
const SERPAPI_URL = 'https://serpapi.com/search.json?engine=google_maps_reviews&hl=en';
async function fetchGoogleReviews(apiKey, placeId) {
if (!apiKey || !placeId) {
throw new Error('Missing SERPAPI_KEY or SERPAPI_PLACE_ID');
}
const url = `${SERPAPI_URL}&api_key=${encodeURIComponent(apiKey)}&place_id=${encodeURIComponent(placeId)}`;
const response = await fetch(url);
if (!response.ok) {
const body = await response.text().catch(() => '');
throw new Error(`SerpAPI request failed ${response.status} ${response.statusText}: ${body}`);
}
const data = await response.json();
if (data.error) {
throw new Error(data.error.message || data.error);
}
if (!Array.isArray(data.reviews)) {
throw new Error('SerpAPI returned no reviews array');
}
return data.reviews;
}
export async function GET() {
const apiKey = process.env.SERPAPI_KEY || "6f49f63fbe238dc99a431723418b46861c1ad9fd2662cefd9f747b2d16196d3a";
const placeId = process.env.SERPAPI_PLACE_ID || "ChIJ9b7ftlX3K4gRb7-4SkJNGCE";
const apiKey = process.env.SERPAPI_KEY;
const placeId = process.env.SERPAPI_PLACE_ID;
try {
const url = `https://serpapi.com/search.json?engine=google_maps_reviews&hl=en&api_key=${apiKey}&place_id=${placeId}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`SerpAPI request failed with status ${response.status}`);
}
const data = await response.json();
console.log('SerpAPI reviews response', data);
if (data.error) {
throw new Error(data.error.message || data.error);
}
const reviews = Array.isArray(data.reviews) ? data.reviews : [];
const reviews = await fetchGoogleReviews(apiKey, placeId);
return new Response(JSON.stringify({ reviews, total: reviews.length }), {
status: 200,
headers: { "Content-Type": "application/json" },
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
console.error('Error fetching reviews:', error);
return new Response(JSON.stringify({ reviews: [], error: error.message || "Failed to fetch reviews" }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
console.error('Reviews API error:', error);
return new Response(
JSON.stringify({
reviews: fallbackGoogleReviews,
total: fallbackGoogleReviews.length,
fallback: true,
error: error.message,
}),
{
status: 200,
headers: { 'Content-Type': 'application/json' },
}
);
}
}

View File

@ -2,41 +2,7 @@
import { useState, useEffect, useCallback } from 'react';
import Image from 'next/image';
import styles from './ReviewsSection.module.css';
function getInitials(name) {
return name
.split(' ')
.map((word) => word.charAt(0).toUpperCase())
.slice(0, 2)
.join('');
}
function parseRating(review) {
const rating = review.rating ?? review.review_rating ?? review.stars ?? 0;
return Number(rating) || 0;
}
function formatReviews(rawReviews) {
return rawReviews
.filter((review) => {
const text = review.text || review.description || review.snippet || review.review_text || review.body || review.content || '';
return text && text.trim().length > 0 && parseRating(review) === 5;
})
.map((review) => {
const text = review.text || review.description || review.snippet || review.review_text || review.body || review.content || '';
const name = review.author_name || review.user?.name || 'Happy Customer';
const rating = parseRating(review);
const role = review.relative_time_description || review.time || 'Google Reviewer';
return {
text,
name,
role,
initials: getInitials(name),
rating,
};
});
}
import { formatReviewsForHome } from '@/lib/reviewUtils';
export default function ReviewsSection() {
const [current, setCurrent] = useState(0);
@ -48,11 +14,19 @@ export default function ReviewsSection() {
async function loadReviews() {
try {
const res = await fetch('/api/reviews');
if (!res.ok) throw new Error('Failed to fetch reviews');
const data = await res.json();
console.log('API Reviews Response:', data);
const formatted = formatReviews(data.reviews || []);
console.log('Formatted Reviews:', formatted);
const data = await res.json().catch(() => ({}));
if (!res.ok) {
const errorMessage = data?.error || `${res.status} ${res.statusText}`;
console.warn('Reviews API returned non-ok response:', errorMessage);
}
if (data.error) {
console.warn('Reviews API returned an error payload:', data.error);
}
const reviews = Array.isArray(data.reviews) ? data.reviews : [];
const formatted = formatReviewsForHome(reviews);
setReviews(formatted);
} catch (error) {
console.error('Reviews fetch failed:', error);

View File

@ -1,24 +1,7 @@
'use client';
import { useState, useEffect } from 'react';
import styles from './AboutTestimonial.module.css';
function getReviewText(review) {
return review.text || review.description || review.snippet || review.review_text || review.body || review.content || '';
}
function formatReviews(rawReviews) {
return rawReviews
.filter((review) => {
const text = getReviewText(review);
return text && text.trim().length > 0 && review.rating >= 4;
})
.map((review) => ({
quote: getReviewText(review),
name: review.author_name || review.user?.name || 'Customer',
role: review.relative_time_description || 'Google Review',
rating: Math.round(review.rating || 5),
}));
}
import { formatReviewsForAbout } from '@/lib/reviewUtils';
export default function AboutTestimonial() {
const [active, setActive] = useState(0);
@ -29,9 +12,18 @@ export default function AboutTestimonial() {
async function loadReviews() {
try {
const res = await fetch('/api/reviews');
if (!res.ok) throw new Error('Failed to fetch reviews');
const data = await res.json();
const formatted = formatReviews(data.reviews || []);
const data = await res.json().catch(() => ({}));
if (!res.ok) {
const errorMessage = data?.error || `${res.status} ${res.statusText}`;
console.warn('About reviews API returned non-ok response:', errorMessage);
}
if (data.error) {
console.warn('About reviews API returned an error payload:', data.error);
}
const formatted = formatReviewsForAbout(Array.isArray(data.reviews) ? data.reviews : []);
setReviews(formatted);
} catch (error) {
console.error('Failed to load reviews:', error);

81
src/lib/reviewUtils.js Normal file
View File

@ -0,0 +1,81 @@
export const fallbackGoogleReviews = [
{
author_name: 'Anjali K.',
text: 'Delicious dosa with authentic masala, the best in Waterloo! The staff is friendly and the flavors are spot on.',
relative_time_description: '2 weeks ago',
rating: 5,
},
{
author_name: 'Priya S.',
text: 'Cozy atmosphere and amazing sambar. The chutneys were fresh and the dosa was perfectly crispy.',
relative_time_description: '1 month ago',
rating: 5,
},
{
author_name: 'Ravi M.',
text: 'I love the authentic South Indian taste here. The service was fast and the food tasted homemade.',
relative_time_description: '3 days ago',
rating: 5,
},
];
export function getReviewText(review) {
return (
review.text ||
review.description ||
review.snippet ||
review.review_text ||
review.body ||
review.content ||
''
);
}
export function getInitials(name) {
return name
.split(' ')
.map((word) => word.charAt(0).toUpperCase())
.slice(0, 2)
.join('');
}
export function parseRating(review) {
const rating = review.rating ?? review.review_rating ?? review.stars ?? 0;
return Number(rating) || 0;
}
export function formatReviewsForHome(rawReviews) {
return rawReviews
.filter((review) => {
const text = getReviewText(review);
return text && text.trim().length > 0 && parseRating(review) >= 4;
})
.map((review) => {
const text = getReviewText(review);
const name = review.author_name || review.user?.name || 'Happy Customer';
const rating = parseRating(review);
const role = review.relative_time_description || review.time || 'Google Reviewer';
return {
text,
name,
role,
initials: getInitials(name),
rating,
};
});
}
export function formatReviewsForAbout(rawReviews) {
return rawReviews
.filter((review) => {
const text = getReviewText(review);
return text && text.trim().length > 0 && parseRating(review) >= 4;
})
.map((review) => ({
quote: getReviewText(review),
name: review.author_name || review.user?.name || 'Customer',
role: review.relative_time_description || 'Google Review',
rating: Math.round(parseRating(review) || 5),
}));
}