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}'s +
+
+

+ {achiever.Name} +

+ +
+
+ ); } - 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")], +};