diff --git a/app/(default)/achievements/page.tsx b/app/(default)/achievements/page.tsx
index bc71271..55551c7 100644
--- a/app/(default)/achievements/page.tsx
+++ b/app/(default)/achievements/page.tsx
@@ -1,11 +1,76 @@
-export const metadata = {
- title: 'Achievements',
- description: 'Achievements page',
+"use client";
+
+import { useEffect, useState } from "react";
+
+interface Achiever {
+ imageUrl: string;
+ Email: string;
+ Name: string;
+ Batch: number;
+ Portfolio: string;
+ Internship: string;
+ CompanyPosition: string;
+ Stipend: number;
+ achievements: string[];
+}
+
+function AchievementCard({ achiever }: { achiever: Achiever }) {
+ return (
+
+
+
+
+
+
+ {achiever.Name}
+
+
+ {achiever.achievements.map((achievement, index) => (
+ -
+ {achievement}
+
+ ))}
+
+
+
+ );
}
- export default function Achievements() {
- return (
- <>
- >
- )
-}
\ No newline at end of file
+export default function AchievementsPage() {
+ const [achievers, setAchievers] = useState([]);
+
+ useEffect(() => {
+ async function fetchAchievers() {
+ try {
+ const response = await fetch("/api/achievements");
+ const data = await response.json();
+ setAchievers(data);
+ } catch (error) {
+ console.error("Error fetching achievements:", error);
+ }
+ }
+
+ fetchAchievers();
+ }, []);
+
+ return (
+
+
Achievements
+
+ {[...Array(3)].map((_, colIndex) => (
+
+ {achievers
+ .filter((_, index) => index % 3 === colIndex)
+ .map((achiever) => (
+
+ ))}
+
+ ))}
+
+
+ );
+}
diff --git a/app/(default)/api/achievements/route.ts b/app/(default)/api/achievements/route.ts
new file mode 100644
index 0000000..f1816e0
--- /dev/null
+++ b/app/(default)/api/achievements/route.ts
@@ -0,0 +1,125 @@
+import { db, storage } from "@/Firebase";
+import {
+ collection,
+ addDoc,
+ getDocs,
+ query,
+ where,
+ DocumentData,
+ DocumentSnapshot,
+} from "firebase/firestore";
+import { ref, uploadBytes, getDownloadURL } from "firebase/storage";
+import { NextResponse } from "next/server";
+
+export async function POST(request: Request) {
+ try {
+ const formData = await request.formData();
+
+ // Extract data from the form
+ const name = formData.get("Name") as string;
+ const email = formData.get("Email address") as string;
+ const batch = formData.get("Batch") as string;
+ const portfolio = formData.get("Portfolio/Github") as string;
+ const internship = formData.get(
+ "Doing internship or have done in past?"
+ ) as string;
+ const companyPosition = formData.get("Company and Position") as string;
+ const stipend = formData.get("Stipend") as string;
+ const achievements = formData.getAll("achievements") as string[];
+
+ // Check if a person with the same name already exists
+ const existingMembersQuery = query(
+ collection(db, "achievements"),
+ where("Name", "==", name)
+ );
+ const querySnapshot = await getDocs(existingMembersQuery);
+
+ if (!querySnapshot.empty) {
+ return NextResponse.json(
+ { error: `A member with the name ${name} already exists.` },
+ { status: 400 }
+ );
+ }
+
+ // Handle image upload
+ const imageFile = formData.get("image") as File;
+ if (!imageFile) {
+ return NextResponse.json(
+ { error: "Image file is required" },
+ { status: 400 }
+ );
+ }
+
+ const storageRef = ref(storage, `images/${imageFile.name}`);
+ await uploadBytes(storageRef, imageFile);
+ const imageUrl = await getDownloadURL(storageRef);
+
+ // Save data to Firestore without Timestamp
+ const docRef = await addDoc(collection(db, "achievements"), {
+ Name: name,
+ Email: email,
+ Batch: batch,
+ Portfolio: portfolio,
+ Internship: internship,
+ CompanyPosition: companyPosition,
+ Stipend: stipend,
+ achievements: achievements,
+ imageUrl: imageUrl,
+ });
+
+ return NextResponse.json({
+ message: "Data saved successfully",
+ id: docRef.id,
+ imageUrl: imageUrl,
+ });
+ } catch (error) {
+ if (error instanceof Error) {
+ console.error("Error details:", error.message);
+ return NextResponse.json(
+ { error: "An error occurred", details: error.message },
+ { status: 500 }
+ );
+ } else {
+ console.error("Unknown error:", error);
+ return NextResponse.json(
+ { error: "An unknown error occurred" },
+ { status: 500 }
+ );
+ }
+ }
+}
+
+export async function GET() {
+ try {
+ // Fetch all documents from the "achievements" collection
+ const querySnapshot = await getDocs(collection(db, "achievements"));
+
+ // Map through the documents and extract the data
+ const members = querySnapshot.docs.map(
+ (doc: DocumentSnapshot) => ({
+ id: doc.id,
+ ...doc.data(),
+ })
+ );
+
+ // Return the members data
+ return NextResponse.json(members);
+ } catch (error) {
+ if (error instanceof Error) {
+ console.error("Error fetching members:", error.message);
+ return NextResponse.json(
+ {
+ error: "An error occurred while fetching members",
+ details: error.message,
+ },
+ { status: 500 }
+ );
+ } else {
+ console.error("Unknown error:", error);
+ return NextResponse.json(
+ { error: "An unknown error occurred while fetching members" },
+ { status: 500 }
+ );
+ }
+ }
+}
diff --git a/tailwind.config.ts b/tailwind.config.ts
index f3fdcb2..e3fce6c 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -1,11 +1,11 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
- darkMode: 'class',
+ darkMode: "class",
content: [
- './app/**/*.{js,ts,jsx,tsx}',
- './pages/**/*.{js,ts,jsx,tsx}',
- './components/**/*.{js,ts,jsx,tsx}',
- './src/**/*.{ts,tsx}',
+ "./app/**/*.{js,ts,jsx,tsx}",
+ "./pages/**/*.{js,ts,jsx,tsx}",
+ "./components/**/*.{js,ts,jsx,tsx}",
+ "./src/**/*.{ts,tsx}",
],
prefix: "",
theme: {
@@ -19,37 +19,37 @@ module.exports = {
extend: {
colors: {
gray: {
- 100: '#FBFBFB',
- 200: '#EAEAEA',
- 300: '#DFDFDF',
- 400: '#999999',
- 500: '#7F7F7F',
- 600: '#666666',
- 700: '#4C4C4C',
- 800: '#333333',
- 900: '#191919',
+ 100: "#FBFBFB",
+ 200: "#EAEAEA",
+ 300: "#DFDFDF",
+ 400: "#999999",
+ 500: "#7F7F7F",
+ 600: "#666666",
+ 700: "#4C4C4C",
+ 800: "#333333",
+ 900: "#191919",
},
blue: {
- 100: '#E6F0FD',
- 200: '#CCE2FC',
- 300: '#99C5FA',
- 400: '#66A9F7',
- 500: '#338CF5',
- 600: '#0070F4',
- 700: '#0064DA',
- 800: '#0059C2',
- 900: '#004391',
+ 100: "#E6F0FD",
+ 200: "#CCE2FC",
+ 300: "#99C5FA",
+ 400: "#66A9F7",
+ 500: "#338CF5",
+ 600: "#0070F4",
+ 700: "#0064DA",
+ 800: "#0059C2",
+ 900: "#004391",
},
teal: {
- 100: '#E6FFFA',
- 200: '#B2F5EA',
- 300: '#81E6D9',
- 400: '#4FD1C5',
- 500: '#3ABAB4',
- 600: '#319795',
- 700: '#2C7A7B',
- 800: '#285E61',
- 900: '#234E52',
+ 100: "#E6FFFA",
+ 200: "#B2F5EA",
+ 300: "#81E6D9",
+ 400: "#4FD1C5",
+ 500: "#3ABAB4",
+ 600: "#319795",
+ 700: "#2C7A7B",
+ 800: "#285E61",
+ 900: "#234E52",
},
border: "hsl(var(--border))",
input: "hsl(var(--input))",
@@ -86,16 +86,17 @@ module.exports = {
},
},
boxShadow: {
- xs: '0 0 0 1px rgba(0, 0, 0, 0.16)',
- sm: '0 1px 2px 0 rgba(0, 0, 0, 0.16)',
- default: '0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 1px 2px 0 rgba(0, 0, 0, 0.03)',
- md: '0 4px 6px -1px rgba(0, 0, 0, 0.04), 0 2px 4px -1px rgba(0, 0, 0, 0.03)',
- lg: '0 10px 15px -3px rgba(0, 0, 0, 0.04), 0 4px 6px -2px rgba(0, 0, 0, 0.02)',
- xl: '0 20px 25px -5px rgba(0, 0, 0, 0.12), 0 10px 10px -5px rgba(0, 0, 0, 0.02)',
- '2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.15)',
- inner: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.04)',
- outline: '0 0 0 3px rgba(66, 153, 225, 0.5)',
- none: 'none',
+ xs: "0 0 0 1px rgba(0, 0, 0, 0.16)",
+ sm: "0 1px 2px 0 rgba(0, 0, 0, 0.16)",
+ default:
+ "0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 1px 2px 0 rgba(0, 0, 0, 0.03)",
+ md: "0 4px 6px -1px rgba(0, 0, 0, 0.04), 0 2px 4px -1px rgba(0, 0, 0, 0.03)",
+ lg: "0 10px 15px -3px rgba(0, 0, 0, 0.04), 0 4px 6px -2px rgba(0, 0, 0, 0.02)",
+ xl: "0 20px 25px -5px rgba(0, 0, 0, 0.12), 0 10px 10px -5px rgba(0, 0, 0, 0.02)",
+ "2xl": "0 25px 50px -12px rgba(0, 0, 0, 0.15)",
+ inner: "inset 0 2px 4px 0 rgba(0, 0, 0, 0.04)",
+ outline: "0 0 0 3px rgba(66, 153, 225, 0.5)",
+ none: "none",
},
borderRadius: {
lg: "var(--radius)",
@@ -103,66 +104,66 @@ module.exports = {
sm: "calc(var(--radius) - 4px)",
},
spacing: {
- '9/16': '56.25%',
- '3/4': '75%',
- '1/1': '100%',
+ "9/16": "56.25%",
+ "3/4": "75%",
+ "1/1": "100%",
},
fontFamily: {
- inter: ['var(--font-inter)', 'sans-serif'],
+ inter: ["var(--font-inter)", "sans-serif"],
},
fontSize: {
- xs: '0.75rem',
- sm: '0.875rem',
- base: '1rem',
- lg: '1.125rem',
- xl: '1.25rem',
- '2xl': '1.5rem',
- '3xl': '2rem',
- '4xl': '2.625rem',
- '5xl': '3.25rem',
- '6xl': '5.5rem',
+ xs: "0.75rem",
+ sm: "0.875rem",
+ base: "1rem",
+ lg: "1.125rem",
+ xl: "1.25rem",
+ "2xl": "1.5rem",
+ "3xl": "2rem",
+ "4xl": "2.625rem",
+ "5xl": "3.25rem",
+ "6xl": "5.5rem",
},
inset: {
- '1/2': '50%',
- 'full': '100%',
+ "1/2": "50%",
+ full: "100%",
},
letterSpacing: {
- tighter: '-0.02em',
- tight: '-0.01em',
- normal: '0',
- wide: '0.01em',
- wider: '0.02em',
- widest: '0.4em',
+ tighter: "-0.02em",
+ tight: "-0.01em",
+ normal: "0",
+ wide: "0.01em",
+ wider: "0.02em",
+ widest: "0.4em",
},
lineHeight: {
- none: '1',
- tighter: '1.125',
- tight: '1.25',
- snug: '1.375',
- normal: '1.5',
- relaxed: '1.625',
- loose: '2',
- '3': '.75rem',
- '4': '1rem',
- '5': '1.2rem',
- '6': '1.5rem',
- '7': '1.75rem',
- '8': '2rem',
- '9': '2.25rem',
- '10': '2.5rem',
+ none: "1",
+ tighter: "1.125",
+ tight: "1.25",
+ snug: "1.375",
+ normal: "1.5",
+ relaxed: "1.625",
+ loose: "2",
+ "3": ".75rem",
+ "4": "1rem",
+ "5": "1.2rem",
+ "6": "1.5rem",
+ "7": "1.75rem",
+ "8": "2rem",
+ "9": "2.25rem",
+ "10": "2.5rem",
},
minWidth: {
- '10': '2.5rem',
- '48': '12rem',
+ "10": "2.5rem",
+ "48": "12rem",
},
opacity: {
- '90': '0.9',
+ "90": "0.9",
},
scale: {
- '98': '.98'
+ "98": ".98",
},
animation: {
- float: 'float 3s ease-in-out infinite',
+ float: "float 3s ease-in-out infinite",
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
marquee: "marquee var(--duration) linear infinite",
@@ -170,8 +171,8 @@ module.exports = {
},
keyframes: {
float: {
- '0%, 100%': { transform: 'translateY(0)' },
- '50%': { transform: 'translateY(-5%)' },
+ "0%, 100%": { transform: "translateY(0)" },
+ "50%": { transform: "translateY(-5%)" },
},
"accordion-down": {
from: { height: "0" },
@@ -190,10 +191,11 @@ module.exports = {
to: { transform: "translateY(calc(-100% - var(--gap)))" },
},
},
+ screens: {
+ "2gl": "750px", // Custom breakpoint for 2 columns
+ "3gl": "1070px", // Custom breakpoint for 3 cloumns
+ },
},
},
- plugins: [
- require('@tailwindcss/forms'),
- require("tailwindcss-animate"),
- ],
-}
\ No newline at end of file
+ plugins: [require("@tailwindcss/forms"), require("tailwindcss-animate")],
+};