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
18 changes: 11 additions & 7 deletions src/app/client-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { QueryClientProvider } from "@tanstack/react-query";
import { queryClient } from "@/lib/react-query/queryClient";
import { useEffect, useState } from "react";
import { usePathname } from "next/navigation";
import { trackPageView } from "@/lib/firebase/analytics";

export default function ClientLayout({
children,
Expand All @@ -22,13 +23,16 @@ export default function ClientLayout({
const isAdminRoute = pathname?.startsWith("/dashboard");

useEffect(() => {
if(isAdminRoute) {
document.body.style.backgroundColor = "#fff"
}
else {
document.body.style.backgroundColor = "#080d14"
}
},[isAdminRoute])
if (isAdminRoute) {
document.body.style.backgroundColor = "#fff";
} else {
document.body.style.backgroundColor = "#080d14";
}
}, [isAdminRoute]);

useEffect(() => {
trackPageView(pathname);
}, [pathname]);

return (
<QueryClientProvider client={queryClient}>
Expand Down
122 changes: 117 additions & 5 deletions src/app/dashboard/analytics/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,124 @@
"use client";
import { useEffect, useState } from "react";
import {
collection,
query,
orderBy,
getDocs,
where,
Timestamp,
deleteDoc,
} from "firebase/firestore";
import { db } from "@/lib/firebase/firebase";
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer,
} from "recharts";

import ProtectedRoute from "@/components/admin/auth/ProtectedRoute";
import { Analytics } from "@vercel/analytics/react";
interface PageViewData {
date: string;
views: number;
}

// AnalyticsDashboard.tsx
interface WeeklyViewData {
weekLabel: string;
views: number;
}

export default function AnalyticsDashboard() {
const [weeklyData, setWeeklyData] = useState<WeeklyViewData[]>([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
const fetchWeeklyViews = async () => {
const yearAgo = new Date();
yearAgo.setFullYear(yearAgo.getFullYear() - 1);

const q = query(
collection(db, "weeklyViews"),
where("timestamp", ">=", yearAgo),
orderBy("timestamp", "asc"),
);

const snapshot = await getDocs(q);
const viewsByWeek: { [key: string]: number } = {};

// Get unique week-year combinations
snapshot.forEach((doc) => {
const data = doc.data();
const key = `${data.year}-${data.weekNumber}`;
viewsByWeek[key] = (viewsByWeek[key] || 0) + 1;
});

// Sort by year and week
const formattedData = Object.entries(viewsByWeek)
.map(([key, views]) => {
const [year, week] = key.split("-");
return {
weekLabel: `W${week}-${year}`,
views,
sortKey: `${year}${week.padStart(2, "0")}`,
};
})
.sort((a, b) => a.sortKey.localeCompare(b.sortKey))
.map(({ weekLabel, views }) => ({ weekLabel, views }));

setWeeklyData(formattedData);
setLoading(false);
};

fetchWeeklyViews();
}, []);

if (loading)
return (
<div className="flex h-96 items-center justify-center">Loading...</div>
);

const totalViews = weeklyData.reduce((sum, week) => sum + week.views, 0);
const avgViews = Math.round(totalViews / weeklyData.length);

return (
<ProtectedRoute>
<Analytics />
</ProtectedRoute>
<div className="space-y-8">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div className="rounded-lg border border-gray-200 bg-white p-6">
<h3 className="text-lg font-semibold">Total Views (in past year)</h3>
<p className="mt-2 text-2xl font-bold">{totalViews}</p>
</div>

<div className="rounded-lg border border-gray-200 bg-white p-6">
<h3 className="text-lg font-semibold">Average Weekly Views</h3>
<p className="mt-2 text-2xl font-bold">{avgViews}</p>
</div>
</div>

<div className="rounded-lg border border-gray-200 bg-white p-6">
<h3 className="mb-4 text-lg font-semibold">Weekly Page Views</h3>
<div className="h-96">
<ResponsiveContainer width="100%" height="100%">
<LineChart data={weeklyData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="weekLabel" />
<YAxis />
<Tooltip />
<Legend />
<Line
type="monotone"
dataKey="views"
stroke="#8884d8"
name="Views"
/>
</LineChart>
</ResponsiveContainer>
</div>
</div>
</div>
);
}
38 changes: 38 additions & 0 deletions src/lib/firebase/analytics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// analytics.ts
import { db } from "@/lib/firebase/firebase";
import {
collection,
addDoc,
getDocs,
query,
where,
serverTimestamp,
} from "firebase/firestore";

export const getPageViews = async (startDate: Date, endDate: Date) => {
const q = query(
collection(db, "pageViews"),
where("timestamp", ">=", startDate),
where("timestamp", "<=", endDate),
);
return await getDocs(q);
};

function getWeekNumber(date: Date): number {
const firstDayOfYear = new Date(date.getFullYear(), 0, 1);
const pastDaysOfYear = (date.getTime() - firstDayOfYear.getTime()) / 86400000;
return Math.ceil((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7);
}

export const trackPageView = async (page: string) => {
const now = new Date();
const weekNumber = getWeekNumber(now);
const year = now.getFullYear();

await addDoc(collection(db, "weeklyViews"), {
page,
weekNumber,
year,
timestamp: serverTimestamp(),
});
};
4 changes: 2 additions & 2 deletions src/lib/firebase/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const firebaseConfig = {
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
};

// Initialize Firebase
Expand All @@ -25,4 +25,4 @@ const auth = getAuth(app);
const db = getFirestore(app);
const storage = getStorage(app);

export { db, auth, app, storage };
export { db, auth, app, storage };
16 changes: 11 additions & 5 deletions src/lib/firebase/firebaseOperations.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { db } from '@/lib/firebase/firebase';
import { collection, getDocs, addDoc, updateDoc, deleteDoc, doc } from 'firebase/firestore';
import { db } from "@/lib/firebase/firebase";
import {
collection,
getDocs,
addDoc,
updateDoc,
deleteDoc,
doc,
} from "firebase/firestore";

export interface Project {
id: string; //ID of the project NOT A COLUMN IN THE DATABASE
Expand All @@ -21,11 +28,10 @@ export interface Project {
Builders: string[]; // An array of builder names or identifiers
}


// READ Operation
export const getAllProjects = async () => {
const querySnapshot = await getDocs(collection(db, "Projects"));
return querySnapshot.docs.map(doc => ({
return querySnapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
})) as Project[];
Expand All @@ -42,7 +48,7 @@ async function addData() {
const docRef = await addDoc(collection(db, "Projects"), {
name: "Claudio Sciotto",
email: "claudio@example.com",
age: 22
age: 22,
});
console.log("Document written with ID: ", docRef.id);
} catch (e) {
Expand Down
Loading