Skip to content

Commit b420201

Browse files
committed
fix(build) firebase error that pop up if you dont have .env file at all and fixing slug box error and middleware ts probelms as well
1 parent afa7465 commit b420201

6 files changed

Lines changed: 90 additions & 108 deletions

File tree

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
// pages/api/set-auth-cookie/route.ts
2-
import type { NextApiRequest, NextApiResponse } from 'next';
3-
import { getAuth } from 'firebase-admin/auth';
1+
import { NextRequest, NextResponse } from 'next/server';
2+
// import { getAuth } from 'firebase-admin/auth';
43
import { initializeApp, getApps, cert } from 'firebase-admin/app';
54
import { serialize } from 'cookie';
65

76
const serviceAccount = {
8-
// Replace these with your service account values
97
projectId: process.env.FIREBASE_PROJECT_ID,
108
privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n'),
119
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
@@ -17,16 +15,18 @@ if (!getApps().length) {
1715
});
1816
}
1917

20-
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
21-
if (req.method !== 'POST') return res.status(405).end();
18+
export async function POST(req: NextRequest) {
19+
try {
20+
const body = await req.json();
21+
const { idToken } = body;
2222

23-
const { idToken } = req.body;
24-
if (!idToken) return res.status(400).json({ error: 'ID token required' });
23+
if (!idToken) {
24+
return NextResponse.json({ error: 'ID token required' }, { status: 400 });
25+
}
2526

26-
try {
27-
const decodedToken = await getAuth().verifyIdToken(idToken);
27+
// Uncomment to verify token:
28+
// await getAuth().verifyIdToken(idToken);
2829

29-
// Set secure HttpOnly cookie
3030
const cookie = serialize('authToken', idToken, {
3131
httpOnly: true,
3232
secure: process.env.NODE_ENV === 'production',
@@ -35,10 +35,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
3535
sameSite: 'lax',
3636
});
3737

38-
res.setHeader('Set-Cookie', cookie);
39-
res.status(200).json({ success: true });
40-
} catch (err) {
41-
console.error(err);
42-
res.status(401).json({ error: 'Invalid token' });
38+
const res = NextResponse.json({ success: true });
39+
res.headers.set('Set-Cookie', cookie);
40+
41+
return res;
42+
} catch (error) {
43+
console.error(error);
44+
return NextResponse.json({ error: 'Invalid token' }, { status: 401 });
4345
}
4446
}

src/app/club/[slug]/page.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
// app/club/[slug]/page.tsx
12
import { notFound } from 'next/navigation';
23
import clubData from '@/components/club/ClubData';
34

4-
5-
export default async function ClubDetailPage({ params }: { params: { slug: string } }) {
6-
const { slug } = await Promise.resolve(params); // simulate async destructuring
5+
export default async function ClubDetailPage({
6+
params,
7+
}: {
8+
params: Promise<{ slug: string }>; // 🚨 params must be a Promise
9+
}) {
10+
const { slug } = await params; // 🚨 await it before using
711

812
const club = clubData.find((c) => c.slug === slug);
913
if (!club) notFound();
10-
return <h1>Club Details</h1>;
14+
15+
return <h1>Club Details: {slug}</h1>;
1116
}

src/app/lost/page.tsx

Lines changed: 23 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,34 @@
1-
//in this we show lost and found items, with a toggle to switch between lost and found items, and a floating button to add new items.
2-
// only implement lost not found items temperoilaily
31
'use client';
42
import { useState } from "react";
53
import Link from "next/link";
6-
import { ArrowLeftIcon, Filter } from "lucide-react";
4+
import { ArrowLeftIcon, Filter } from "lucide-react";
75
import WaveDesign from "./wave/wave_design";
86
import { Add, Trash, Edit } from "iconsax-react";
97

10-
// Define the type for an item
8+
// Define Item type
119
type Item = {
1210
id: number;
1311
name: string;
1412
description: string;
1513
lastSeenPlace: string;
1614
contactInfo: string;
17-
status: "lost" | "found";
15+
status: "lost" | "found"; // kept for potential future use
1816
};
1917

2018
export default function LostFound() {
21-
const [status, setStatus] = useState<"lost" | "found">("lost");
19+
// Only show lost items, no need for status state
2220
const [items, setItems] = useState<Item[]>([
23-
{
24-
id: 1,
25-
name: "Watch",
26-
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
27-
lastSeenPlace: "College Ground",
28-
contactInfo: "contact@example.com",
29-
status: "lost",
30-
},
31-
{
32-
id: 2,
33-
name: "Water Bottle",
34-
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
35-
lastSeenPlace: "Library",
36-
contactInfo: "contact@example.com",
37-
status: "lost",
38-
},
21+
{ id: 1, name: "Watch", description: "Lorem ipsum…", lastSeenPlace: "College Ground", contactInfo: "contact@example.com", status: "lost" },
22+
{ id: 2, name: "Water Bottle", description: "Lorem ipsum…", lastSeenPlace: "Library", contactInfo: "contact@example.com", status: "lost" },
3923
]);
4024

41-
// Toggle item status between "lost" and "found"
42-
const toggleItemStatus = (id: number) => {
43-
setItems((prevItems) =>
44-
prevItems.map((item) =>
45-
item.id === id
46-
? { ...item, status: item.status === "lost" ? "found" : "lost" }
47-
: item
48-
)
49-
);
50-
};
51-
52-
// Filter items based on the selected status
53-
const filteredItems = items.filter((item) => item.status === status);
25+
// Functionality for editing, deleting, etc.
26+
const deleteItem = (id: number) =>
27+
setItems(prev => prev.filter(item => item.id !== id));
5428

5529
return (
5630
<div className="p-4 max-w mx-auto relative">
31+
{/* Header */}
5732
<div className="flex relative justify-between h-[100px] items-center mb-2">
5833
<button className="absolute top-0 left-0 border border-gray-400 rounded-full p-2">
5934
<ArrowLeftIcon className="w-5 h-5" />
@@ -65,34 +40,30 @@ export default function LostFound() {
6540
</button>
6641
</div>
6742

68-
{/* List of Items */}
43+
{/* Lost Items Grid */}
6944
<div className="grid grid-cols-1 md:grid-cols-3 md:space-x-[20px]">
70-
{filteredItems.map((item) => (
71-
<div key={item.id} className="mb-4 border border-[1px] border-black rounded-xl overflow-hidden shadow-sm">
72-
<div className="w-full h-32 bg-gray-300"></div>
45+
{items.map(item => (
46+
<div key={item.id} className="mb-4 border rounded-xl overflow-hidden shadow-sm">
47+
<div className="w-full h-32 bg-gray-300" />
7348
<div className="p-3">
7449
<h2 className="text-2xl font-bold">{item.name}</h2>
75-
<p className="text-sm text-gray-400">
76-
Last Seen Place: {item.lastSeenPlace}
77-
</p>
50+
<p className="text-sm text-gray-400">Last Seen: {item.lastSeenPlace}</p>
7851
<p className="text-sm text-black/[0.7] mt-1">{item.description}</p>
79-
<p className="text-sm text-black/[0.7] mt-1">
80-
Contact: {item.contactInfo}
81-
</p>
52+
<p className="text-sm text-black/[0.7] mt-1">Contact: {item.contactInfo}</p>
8253
<div className="relative flex gap-2 mt-3">
83-
<button className="text-black underline font-semibold">Report</button>
84-
<button className="absolute right-10 text-gray-600"><Edit size={25} color="#000000" /></button>
85-
<button className="absolute right-0 text-gray-600"><Trash size={25} color="#000000" /></button>
54+
<button onClick={() => {/* Report logic */}} className="text-black underline font-semibold">Report</button>
55+
<button onClick={() => {/* Edit logic */}} className="absolute right-10 text-gray-600"><Edit size={25} /></button>
56+
<button onClick={() => deleteItem(item.id)} className="absolute right-0 text-gray-600"><Trash size={25} /></button>
8657
</div>
8758
</div>
8859
</div>
8960
))}
9061
</div>
9162

92-
{/* Floating "+" Button */}
93-
<Link href="/lost/add" className="bg-red-600">
94-
<button className="fixed bottom-6 z-10 right-7 bottom-14 mb-[45px] bg-blue-200 border-[1px] border-black text-black w-12 h-12 rounded-[12px] flex items-center justify-center shadow-lg hover:bg-blue-400 transition-colors">
95-
<Add size={40} color="#000000"/>
63+
{/* Floating Add Button */}
64+
<Link href="/lost/add">
65+
<button className="fixed bottom-6 right-7 bg-blue-200 border border-black text-black w-12 h-12 rounded-[12px] flex items-center justify-center shadow-lg hover:bg-blue-400 transition-colors">
66+
<Add size={40} />
9667
</button>
9768
</Link>
9869
</div>

src/lib/firebase/auth.ts

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,57 @@
1-
// Import User and other necessary types/functions from Firebase Auth
1+
// src/lib/firebase/auth.ts
22
import { signInWithPopup, GoogleAuthProvider, User, UserCredential } from 'firebase/auth';
33
import { doc, getDoc } from 'firebase/firestore';
4-
import { auth, firestore } from './config'; // Ensure you are correctly importing from your Firebase config
4+
import { auth, firestore } from './config';
55

6-
// Function to track authentication state changes
76
export function onAuthStateChanged(callback: (authUser: User | null) => void) {
7+
if (!auth) {
8+
console.warn("Firebase auth is not initialized. Skipping listener.");
9+
return () => {}; // dummy unsubscribe
10+
}
811
return auth.onAuthStateChanged(callback);
912
}
1013

11-
// Function for Google sign-in and role check
1214
export async function signInWithGoogle(): Promise<{ isAdmin: boolean }> {
1315
const provider = new GoogleAuthProvider();
14-
provider.setCustomParameters({ display: "popup" }); // Force popup
15-
16+
provider.setCustomParameters({ display: "popup" });
1617

1718
try {
19+
if (!auth) throw new Error("Firebase auth is not initialized.");
1820
const result: UserCredential = await signInWithPopup(auth, provider);
1921
const user: User = result.user;
2022

21-
if (!user || !user.email) {
22-
throw new Error('Google sign-in failed');
23-
}
23+
if (!user?.email) throw new Error("Google sign-in failed");
2424

25-
// Restrict login to only emails from "gecskp.ac.in"
26-
// Restrict login to only emails from "gecskp.ac.in", except for a specific admin email
27-
const allowedEmailPattern = /^[a-zA-Z0-9]+@gecskp\.ac\.in$/;
28-
const adminOverrideEmail = "codecompass2024@gmail.com";
25+
// Allow GEC SKP or specific admin email
26+
const allowedEmailPattern = /^[a-zA-Z0-9._%+-]+@gecskp\.ac\.in$/;
27+
const adminOverrideEmail = "codecompass2024@gmail.com";
2928

30-
if (user.email !== adminOverrideEmail && !allowedEmailPattern.test(user.email)) {
31-
throw new Error('Only GEC SKP emails are allowed');
32-
}
29+
if (user.email !== adminOverrideEmail && !allowedEmailPattern.test(user.email)) {
30+
throw new Error("Only GEC SKP emails are allowed");
31+
}
3332

34-
33+
if (!firestore) throw new Error("Firebase firestore is not initialized.");
3534

3635
const userDocRef = doc(firestore, 'adminemail', user.email);
3736
const userDoc = await getDoc(userDocRef);
3837

3938
const isAdmin =
40-
userDoc.exists() &&
41-
(userDoc.data()?.role === 'admin' || userDoc.data()?.role === 'superadmin');
42-
39+
userDoc.exists() &&
40+
['admin', 'superadmin'].includes(userDoc.data()?.role);
4341

4442
return { isAdmin };
4543
} catch (error) {
46-
console.error('Error signing in with Google:', error);
44+
console.error("Error signing in with Google:", error);
4745
throw error;
4846
}
4947
}
5048

51-
52-
5349
export async function signOutWithGoogle(): Promise<void> {
5450
try {
51+
if (!auth) throw new Error("Firebase auth is not initialized.");
5552
await auth.signOut();
5653
} catch (error) {
57-
console.error('Error signing out with Google:', error);
54+
console.error("Error signing out:", error);
5855
throw error;
5956
}
6057
}

src/lib/firebase/config.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// src/lib/firebase/config.ts
12
import { initializeApp, getApps, FirebaseApp } from 'firebase/app';
23
import { getAuth } from 'firebase/auth';
34
import { getFirestore } from 'firebase/firestore';
@@ -13,18 +14,24 @@ const firebaseConfig = {
1314
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
1415
};
1516

17+
const isConfigValid = Object.values(firebaseConfig).every(Boolean);
1618

19+
export const firebaseApp: FirebaseApp | null = isConfigValid
20+
? (getApps().length === 0
21+
? initializeApp(firebaseConfig)
22+
: getApps()[0]) ?? null
23+
: null;
1724

18-
// Initialize Firebase app
19-
export const firebaseApp: FirebaseApp =
20-
getApps().length === 0 ? initializeApp(firebaseConfig) : (getApps()[0] as FirebaseApp);
21-
22-
export const auth = getAuth(firebaseApp);
23-
export const firestore = getFirestore(firebaseApp);
24-
export const storage = getStorage(firebaseApp);
25+
export const auth = firebaseApp ? getAuth(firebaseApp) : null;
26+
export const firestore = firebaseApp ? getFirestore(firebaseApp) : null;
27+
export const storage = firebaseApp ? getStorage(firebaseApp) : null;
2528

2629
export async function uploadFileToFirebase(file: File, folder: string): Promise<string> {
30+
if (!storage) {
31+
throw new Error("Firebase storage is not initialized. Check your environment variables.");
32+
}
33+
2734
const storageRef = ref(storage, `${folder}/${file.name}`);
2835
const snapshot = await uploadBytes(storageRef, file);
2936
return await getDownloadURL(snapshot.ref);
30-
}
37+
}

src/middleware.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ export function middleware(request: NextRequest) {
1212
publicRoutes.some((route) => pathname.startsWith(route + '/'));
1313

1414
// If no token and trying to access protected route
15-
// if (!token && !isPublicRoute) {
16-
// console.log(`Redirecting ${pathname} to /auth - no token`);
17-
// return NextResponse.redirect(new URL('/auth', request.url));
18-
// }
15+
if (!token && !isPublicRoute) {
16+
console.log(`Redirecting ${pathname} to /auth - no token`);
17+
return NextResponse.redirect(new URL('/auth', request.url));
18+
}
1919

2020
return NextResponse.next();
2121
}

0 commit comments

Comments
 (0)