diff --git a/app/(root)/TableComponent.tsx b/app/(root)/TableComponent.tsx index 1c71aed..1714f57 100644 --- a/app/(root)/TableComponent.tsx +++ b/app/(root)/TableComponent.tsx @@ -1,31 +1,8 @@ "use client"; import { useRouter } from "next/navigation"; import React from "react"; -const data = [ - { - id: 1, - platform: "LinkedIn", - title: "Pranav, Radhika Gupta has a new post for you", - description: "To every woman who sometimes wonders, can I do it, here is a thought...", - date: "Mar 17", - }, - { - id: 2, - platform: "LinkedIn", - title: "Pranav, Nikhil Kamath has a new post for you", - description: "Digressing from the post, but it's about time we need an Indian answer to...", - date: "Mar 14", - }, - { - id: 3, - platform: "LinkedIn", - title: "Pranav, Nikhil Kamath has a new post for you", - description: "Digressing from the post, but it's about time we need an Indian answer to...", - date: "Mar 12", - }, -]; - +const data: Array<{id: number; platform: string; title: string; description: string; date: string;}> = []; const TableComponent = () => { const router = useRouter(); @@ -33,22 +10,35 @@ const TableComponent = () => { return ( - {data.map((item, index) => ( - router.push(`/notification/${item.id}`)} - > - - - + - - ))} + ) : ( + data.map((item) => ( + router.push(`/notification/${item.id}`)} + > + + + + + + )) + )}
- e.stopPropagation()} /> - {item.platform} - {item.title} - {item.description} + {data.length === 0 ? ( +
+ No items to display. {item.date}
+ e.stopPropagation()} + className="accent-brand-500" + /> + {item.platform} + {item.title} + — {item.description} + {item.date}
); diff --git a/app/(root)/TabsComponent2.tsx b/app/(root)/TabsComponent2.tsx index f0ceb7e..02d4b1c 100644 --- a/app/(root)/TabsComponent2.tsx +++ b/app/(root)/TabsComponent2.tsx @@ -1,80 +1,95 @@ -'use client'; +"use client"; -import * as React from 'react'; -import Tabs from '@mui/material/Tabs'; -import Tab from '@mui/material/Tab'; -import Box from '@mui/material/Box'; +import * as React from "react"; +import Tabs from "@mui/material/Tabs"; +import Tab from "@mui/material/Tab"; +import Box from "@mui/material/Box"; interface TabPanelProps { - children?: React.ReactNode; - index: number; - value: number; + children?: React.ReactNode; + index: number; + value: number; } interface TabsProps { - tabTitles: string[]; - tabContents: React.ReactNode[]; + tabTitles: string[]; + tabContents: React.ReactNode[]; } function CustomTabPanel(props: TabPanelProps) { - const { children, value, index, ...other } = props; - - return ( - - ); + const { children, value, index, ...other } = props; + return ( + + ); } function a11yProps(index: number) { - return { - id: `simple-tab-${index}`, - 'aria-controls': `simple-tabpanel-${index}`, - }; + return { + id: `tab-${index}`, + "aria-controls": `tabpanel-${index}`, + }; } export default function TabsComponent2({ tabTitles, tabContents }: TabsProps) { - const [value, setValue] = React.useState(0); + const [value, setValue] = React.useState(0); - const handleChange = (event: React.SyntheticEvent, newValue: number) => { - setValue(newValue); - }; + const handleChange = (_event: React.SyntheticEvent, newValue: number) => { + setValue(newValue); + }; - return ( - - - - {tabTitles.map((title, index) => ( - - ))} - - - - {tabContents.map((content, index) => ( - - {content} - - ))} - - - ); + return ( + + + + {tabTitles.map((title, index) => ( + + ))} + + + + {tabContents.map((content, index) => ( + + {content} + + ))} + + + ); } diff --git a/app/(root)/application/ApplicationsList.tsx b/app/(root)/application/ApplicationsList.tsx new file mode 100644 index 0000000..dc48331 --- /dev/null +++ b/app/(root)/application/ApplicationsList.tsx @@ -0,0 +1,86 @@ +"use client"; +import React, { useEffect, useState } from "react"; +import axios from "axios"; +import { Clock } from "lucide-react"; +import Link from "next/link"; + +interface JoinRequest { + _id: string; + project: { _id: string; title: string }; + status: string; + createdAt: string; +} + +const ApplicationsList = ({ filterStatus }: { filterStatus: string }) => { + const [requests, setRequests] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchRequests = async () => { + try { + const response = await axios.get("/api/applications"); + const filtered = response.data.filter( + (r: JoinRequest) => r.status === filterStatus + ); + setRequests(filtered); + } catch (error) { + console.error("Error fetching applications:", error); + } finally { + setLoading(false); + } + }; + + fetchRequests(); + }, [filterStatus]); + + if (loading) { + return ( +
+ {[1, 2, 3].map((i) => ( +
+ ))} +
+ ); + } + + if (requests.length === 0) { + return ( +
+ No applications found. +
+ ); + } + + return ( +
+ {requests.map((item) => ( + +
+ + {item.project?.title || "Unknown Project"} + +
+ + {item.status} + + + + {new Date(item.createdAt).toLocaleDateString()} + +
+
+ + ))} +
+ ); +}; + +export default ApplicationsList; diff --git a/app/(root)/application/page.tsx b/app/(root)/application/page.tsx index fdaa7d8..e8de568 100644 --- a/app/(root)/application/page.tsx +++ b/app/(root)/application/page.tsx @@ -1,39 +1,60 @@ +"use client"; import React from "react"; import TabsComponent2 from "../TabsComponent2"; -import TableComponent from "../TableComponent"; -import Image from "next/image"; +import ApplicationsList from "./ApplicationsList"; +import useAuthStore from "@/app/store/useAuthStore"; +import { motion } from "framer-motion"; +import { Briefcase, Sparkles } from "lucide-react"; -// Tab contents with table components const tabContents = [ - , - , - , + , + , + , ]; -const Page = async () => { - // const requests = await fetchJoinRequests() - const tabTitles = ["Submitted(56)", "Bookmarks(23)", "Rejected(23)"]; +const Page = () => { + const { user } = useAuthStore(); + const tabTitles = ["Pending", "Accepted", "Rejected"]; + return ( -
-
Hello, Rohit!
-
-
-

Welcome to Application Status.

-

- This page is designed to help you track and manage your project - collaboration applications with ease. View the status of your - submissions, from drafts to approved or rejected applications, all - in one place. Stay organized, keep track of your progress, and - refine your proposals for future opportunities. +

+ + Hello, {user?.firstName || "Developer"}! + + + +
+
+ +

Application Status

+
+

+ Track and manage your project collaboration applications. View submissions, + bookmarks, and stay informed about your progress.

-
- +
+
-
+
-
Applications
- + +

Applications

+ +
); }; diff --git a/app/(root)/components/AchievementsCard.tsx b/app/(root)/components/AchievementsCard.tsx index 03e2764..11715ed 100644 --- a/app/(root)/components/AchievementsCard.tsx +++ b/app/(root)/components/AchievementsCard.tsx @@ -1,17 +1,45 @@ import React from "react"; +import { Award } from "lucide-react"; const AchievementsCard = () => { return ( - <> -
-
-

Achievements

-
-
- Lorem Ipsum +
+
+

+ + Achievements +

+
+
+
+
+ +
+
+

First Project Completed

+

Complete your first project to earn this badge

+
-
- +
+
+ +
+
+

Team Player

+

Join 5 projects to unlock

+
+
+
+
+ +
+
+

S-Rank Developer

+

Reach S rank to unlock

+
+
+
+
); }; diff --git a/app/(root)/components/Badge.tsx b/app/(root)/components/Badge.tsx index f5631c0..3b2c7f4 100644 --- a/app/(root)/components/Badge.tsx +++ b/app/(root)/components/Badge.tsx @@ -5,27 +5,21 @@ type BadgeProps = { color: string; }; -const colorMap: { [key: string]: string } = { - red: "border-red-500 bg-red-100 text-red-500", - blue: "border-blue-500 bg-blue-100 text-blue-500", - yellow: "border-[#F2AF04] bg-[#FEF9E8] text-[#F2AF04]", - green: "border-green-500 bg-green-100 text-green-500", - purple: "border-purple-500 bg-purple-100 text-purple-500", - pink: "border-pink-500 bg-pink-100 text-pink-500", +const colorMap: { [key: string]: { bg: string; border: string; text: string; glow: string } } = { + red: { bg: "bg-red-500/10", border: "border-red-500/30", text: "text-red-500", glow: "shadow-[0_0_20px_rgba(239,68,68,0.3)]" }, + blue: { bg: "bg-blue-500/10", border: "border-blue-500/30", text: "text-blue-500", glow: "shadow-[0_0_20px_rgba(59,130,246,0.3)]" }, + yellow: { bg: "bg-amber-500/10", border: "border-amber-500/30", text: "text-amber-500", glow: "shadow-[0_0_20px_rgba(245,158,11,0.3)]" }, + green: { bg: "bg-green-500/10", border: "border-green-500/30", text: "text-green-500", glow: "shadow-[0_0_20px_rgba(16,185,129,0.3)]" }, + purple: { bg: "bg-purple-500/10", border: "border-purple-500/30", text: "text-purple-500", glow: "shadow-[0_0_20px_rgba(139,92,246,0.3)]" }, }; +const defaultColor = { bg: "bg-gray-500/10", border: "border-gray-500/30", text: "text-gray-500", glow: "" }; + const Badge: FC = ({ title, color }) => { + const c = colorMap[color] || defaultColor; return ( -
-
+
+
{title}
diff --git a/app/(root)/components/EditProfile.tsx b/app/(root)/components/EditProfile.tsx index 1044306..4e485da 100644 --- a/app/(root)/components/EditProfile.tsx +++ b/app/(root)/components/EditProfile.tsx @@ -3,13 +3,16 @@ import useAuthStore from "@/app/store/useAuthStore"; import { User } from "@/app/types/user"; import Image from "next/image"; import React, { useState } from "react"; +import { toast } from "sonner"; +import axios from "axios"; +import { X, Plus } from "lucide-react"; type EditProfileProps = { onProfileUpdate: (data: User) => void; }; const EditProfile = ({ onProfileUpdate }: EditProfileProps) => { - const { user } = useAuthStore(); + const { user, setUser } = useAuthStore(); const [firstName, setFirstName] = useState(user?.firstName || ""); const [lastName, setLastName] = useState(user?.lastName || ""); @@ -21,201 +24,233 @@ const EditProfile = ({ onProfileUpdate }: EditProfileProps) => { const [skills, setSkills] = useState(user?.skills || []); const [newSkill, setNewSkill] = useState(""); const [isChecked, setIsChecked] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); - // Add new skill to the skills list const addSkill = () => { - if (newSkill.trim() && !skills.includes(newSkill)) { - setSkills([...skills, newSkill]); + if (newSkill.trim() && !skills.includes(newSkill.trim())) { + setSkills([...skills, newSkill.trim()]); setNewSkill(""); } }; - // Remove skill from the list const removeSkill = (index: number) => { setSkills(skills.filter((_, i) => i !== index)); }; - // Submit profile data - const handleSubmit = (e: React.FormEvent) => { + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - const updatedProfileData = { + setIsSubmitting(true); + const toastId = toast.loading("Saving profile..."); + + const updatedProfileData: User = { firstName, lastName, id: user?.id || "", name: `${firstName} ${lastName}`, email, - collegeDetails: { - name: instituteName, - }, + collegeDetails: { name: instituteName }, location, skills, github, linkedin, }; - onProfileUpdate(updatedProfileData); + + try { + await axios.put( + `${process.env.NEXT_PUBLIC_CLIENT_URL}/api/user/${user?.id}`, + updatedProfileData + ); + + // Update Zustand store + setUser({ + ...user, + ...updatedProfileData, + id: user?.id || "", + }); + + toast.success("Profile updated successfully!", { id: toastId }); + onProfileUpdate(updatedProfileData); + } catch (error) { + console.error("Error updating profile:", error); + toast.error("Failed to update profile.", { id: toastId }); + } finally { + setIsSubmitting(false); + } }; return ( -
- {/* Left Section with Profile Image */} -