diff --git a/package-lock.json b/package-lock.json
index 70d1847e..69afe483 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,7 +22,9 @@
"eslint-config-next": "13.0.7",
"firebase": "^9.23.0",
"firebase-admin": "^11.11.1",
+ "framer-motion": "^12.4.2",
"js-cookie": "^3.0.1",
+ "lucide-react": "^0.474.0",
"next": "13.0.7",
"nextjs-progressbar": "^0.0.16",
"react": "18.2.0",
@@ -3303,6 +3305,32 @@
"url": "https://www.patreon.com/infusion"
}
},
+ "node_modules/framer-motion": {
+ "version": "12.4.2",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.4.2.tgz",
+ "integrity": "sha512-pW307cQKjDqEuO1flEoIFf6TkuJRfKr+c7qsHAJhDo4368N/5U8/7WU8J+xhd9+gjmOgJfgp+46evxRRFM39dA==",
+ "dependencies": {
+ "motion-dom": "^12.0.0",
+ "motion-utils": "^12.0.0",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -4673,6 +4701,14 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="
},
+ "node_modules/lucide-react": {
+ "version": "0.474.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.474.0.tgz",
+ "integrity": "sha512-CmghgHkh0OJNmxGKWc0qfPJCYHASPMVSyGY8fj3xgk4v84ItqDg64JNKFZn5hC6E0vHi6gxnbCgwhyVB09wQtA==",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/markdown-it": {
"version": "12.3.2",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
@@ -4799,6 +4835,19 @@
"node": ">=10"
}
},
+ "node_modules/motion-dom": {
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.0.0.tgz",
+ "integrity": "sha512-CvYd15OeIR6kHgMdonCc1ihsaUG4MYh/wrkz8gZ3hBX/uamyZCXN9S9qJoYF03GqfTt7thTV/dxnHYX4+55vDg==",
+ "dependencies": {
+ "motion-utils": "^12.0.0"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.0.0.tgz",
+ "integrity": "sha512-MNFiBKbbqnmvOjkPyOKgHUp3Q6oiokLkI1bEwm5QA28cxMZrv0CbbBGDNmhF6DIXsi1pCQBSs0dX8xjeER1tmA=="
+ },
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -9021,6 +9070,16 @@
"integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
"dev": true
},
+ "framer-motion": {
+ "version": "12.4.2",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.4.2.tgz",
+ "integrity": "sha512-pW307cQKjDqEuO1flEoIFf6TkuJRfKr+c7qsHAJhDo4368N/5U8/7WU8J+xhd9+gjmOgJfgp+46evxRRFM39dA==",
+ "requires": {
+ "motion-dom": "^12.0.0",
+ "motion-utils": "^12.0.0",
+ "tslib": "^2.4.0"
+ }
+ },
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -10036,6 +10095,12 @@
}
}
},
+ "lucide-react": {
+ "version": "0.474.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.474.0.tgz",
+ "integrity": "sha512-CmghgHkh0OJNmxGKWc0qfPJCYHASPMVSyGY8fj3xgk4v84ItqDg64JNKFZn5hC6E0vHi6gxnbCgwhyVB09wQtA==",
+ "requires": {}
+ },
"markdown-it": {
"version": "12.3.2",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
@@ -10120,6 +10185,19 @@
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"optional": true
},
+ "motion-dom": {
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.0.0.tgz",
+ "integrity": "sha512-CvYd15OeIR6kHgMdonCc1ihsaUG4MYh/wrkz8gZ3hBX/uamyZCXN9S9qJoYF03GqfTt7thTV/dxnHYX4+55vDg==",
+ "requires": {
+ "motion-utils": "^12.0.0"
+ }
+ },
+ "motion-utils": {
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.0.0.tgz",
+ "integrity": "sha512-MNFiBKbbqnmvOjkPyOKgHUp3Q6oiokLkI1bEwm5QA28cxMZrv0CbbBGDNmhF6DIXsi1pCQBSs0dX8xjeER1tmA=="
+ },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
diff --git a/package.json b/package.json
index ead2f7b6..4e4cc75f 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"eslint-config-next": "13.0.7",
"firebase": "^9.23.0",
"firebase-admin": "^11.11.1",
+ "framer-motion": "^12.4.2",
"js-cookie": "^3.0.1",
"lucide-react": "^0.474.0",
"next": "13.0.7",
diff --git a/src/components/Common/Navbar.tsx b/src/components/Common/Navbar.tsx
index 38c923a0..72759046 100644
--- a/src/components/Common/Navbar.tsx
+++ b/src/components/Common/Navbar.tsx
@@ -6,6 +6,7 @@ import { FiLogOut } from 'react-icons/fi'
import { useRouter } from 'next/router'
import { useAuth } from '../../contexts/auth'
import Image from 'next/image'
+import Link from 'next/link'
export const Navbar: FC<{}> = ({}) => {
const router = useRouter()
@@ -23,7 +24,7 @@ export const Navbar: FC<{}> = ({}) => {
}, [router, activeRef, activeRef.current?.offsetWidth])
return (
-
+
{user ? (
@@ -33,7 +34,7 @@ export const Navbar: FC<{}> = ({}) => {
>
= ({}) => {
Logout
+
+
Profile
+
+
+
)}
@@ -103,9 +109,7 @@ export const Navbar: FC<{}> = ({}) => {
>
Courses
-
-
- {
router.push('/rateprofessor')
@@ -114,7 +118,13 @@ export const Navbar: FC<{}> = ({}) => {
>
Rate Professor
-
+ router.push('/template')}
+ className={`cursor-pointer p-3 relative before:content-[''] before:absolute before:bottom-[-7px] before:left-0 before:w-full before:h-[5px] before:bg-primary/40 before:rounded-[8px_8px_0_0] before:opacity-0 before:duration-100 text-gray-600 hover:before:opacity-100 hover:before:bottom-0 hover:text-gray-800`}
+ >
+ Templates
+
{},
@@ -32,11 +32,12 @@ export const AuthProvider = ({ children }: any) => {
const [photoURL, setPhotoURL] = useState('');
const [displayName, setDisplayName] = useState('');
const [loading, setLoading] = useState(true);
+ const auth = firebaseAuth;
+
- // Functions
const logout = async () => {
try {
- await signOut(firebaseAuth);
+ await signOut(auth);
cookies.remove('accessToken');
setUser(null);
setPhotoURL('');
@@ -49,9 +50,8 @@ export const AuthProvider = ({ children }: any) => {
const login = async () => {
const provider = new GoogleAuthProvider();
-
try {
- const res = await signInWithPopup(firebaseAuth, provider);
+ const res = await signInWithPopup(auth, provider);
const { user }: any = res;
const { accessToken } = user;
@@ -67,7 +67,7 @@ export const AuthProvider = ({ children }: any) => {
setUser(userData);
setPhotoURL(picture);
setDisplayName(name);
- return isAdmin
+ return isAdmin;
}
toast.success('Login Successful');
}
@@ -75,7 +75,6 @@ export const AuthProvider = ({ children }: any) => {
toast.error((err as FirebaseError).message);
}
};
-
async function loadUserFromCookie() {
const accessToken = cookies.get('accessToken');
if (accessToken) {
@@ -114,9 +113,9 @@ export const AuthProvider = ({ children }: any) => {
setLoading(false);
}
- // Effects
+
useEffect(() => {
- const unsubscribe = onAuthStateChanged(firebaseAuth, async (authUser: FirebaseUser | null) => { // ✅ Use firebaseAuth
+ const unsubscribe = onAuthStateChanged(firebaseAuth, async (authUser: FirebaseUser | null) => {
if (authUser) {
const token = await authUser.getIdToken();
@@ -158,14 +157,13 @@ export const AuthProvider = ({ children }: any) => {
export const useAuth = () => {
const authContext = useContext(AuthContext);
-
if (!authContext) {
- throw new Error("useAuth must be used within an AuthProvider");
+ throw new Error('useAuth must be used within an AuthProvider');
}
return authContext as {
isAuthenticated: boolean;
- user: User | null; // Use the defined User type
+ user: User | null;
photoURL: string;
displayName: string;
login: () => void;
@@ -174,14 +172,13 @@ export const useAuth = () => {
};
};
-
-
export const ProtectRoute = ({ children }: any) => {
- const router = useRouter();
- const { isAuthenticated, loading }: any = useAuth();
+ const router = useRouter();
+ const { isAuthenticated, loading } = useAuth();
if (loading || (!isAuthenticated && router.pathname !== '/login')) {
return Loading...
;
}
return children;
};
+
diff --git a/src/pages/api/db/profile/index.ts b/src/pages/api/db/profile/index.ts
new file mode 100644
index 00000000..b5153383
--- /dev/null
+++ b/src/pages/api/db/profile/index.ts
@@ -0,0 +1,62 @@
+import { firestore } from '../../../../utils/firebaseInit';
+import {
+ collection,
+ doc,
+ getDoc,
+ getDocs,
+ updateDoc,
+ setDoc,
+} from 'firebase/firestore';
+import { NextApiRequest, NextApiResponse } from 'next';
+
+const profilesCollection = collection(firestore, 'profiles');
+
+export default async function handler(req: NextApiRequest, res: NextApiResponse) {
+ const { method, body, query } = req;
+
+ switch (method) {
+ case 'GET':
+ try {
+ const { id } = query;
+ if (!id || typeof id !== 'string') {
+ return res.status(400).json({ message: 'Profile ID is required' });
+ }
+
+ const profileDoc = await getDoc(doc(profilesCollection, id));
+ if (!profileDoc.exists()) {
+ return res.status(404).json({ message: 'Profile not found' });
+ }
+
+ res.status(200).json({ message: 'Profile Fetched', result: profileDoc.data() });
+ } catch (err) {
+ res.status(500).json({ message: 'Error fetching profile', error: err });
+ }
+ break;
+
+ case 'PUT':
+ try {
+ const { id } = query;
+ if (!id || typeof id !== 'string') {
+ return res.status(400).json({ message: 'Profile ID is required' });
+ }
+
+ const profileRef = doc(profilesCollection, id);
+ const profileDoc = await getDoc(profileRef);
+
+ if (!profileDoc.exists()) {
+ await setDoc(profileRef, body);
+ } else {
+ await updateDoc(profileRef, body);
+ }
+
+ res.status(200).json({ message: 'Hoorayy! Profile Updated' });
+ } catch (err) {
+ res.status(500).json({ message: 'Error updating profile', error: err });
+ }
+ break;
+
+ default:
+ res.status(405).json({ message: 'Method Not Allowed' });
+ }
+}
+
diff --git a/src/pages/discussion.tsx b/src/pages/discussion.tsx
new file mode 100644
index 00000000..6c6384fb
--- /dev/null
+++ b/src/pages/discussion.tsx
@@ -0,0 +1,96 @@
+import { useState, useEffect } from 'react';
+import { firestore } from '../utils/firebaseInit';
+import { collection, addDoc, query, orderBy, onSnapshot, serverTimestamp } from 'firebase/firestore';
+import { useAuth } from '../contexts/auth';
+import { FaThumbsUp, FaReply, FaThumbtack, FaEdit, FaTrash } from 'react-icons/fa';
+import bgImage from 'assets/discussion-bg.png';
+
+
+const DiscussionPage = () => {
+ const { user } = useAuth();
+ const [messages, setMessages] = useState([]);
+ const [newMessage, setNewMessage] = useState('');
+ const [selectedMessage, setSelectedMessage] = useState(null);
+
+ useEffect(() => {
+ const messagesCollection = collection(firestore, 'discussion');
+ const q = query(messagesCollection, orderBy('createdAt', 'asc'));
+
+ const unsubscribe = onSnapshot(q, (querySnapshot) => {
+ const fetchedMessages = querySnapshot.docs.map((doc) => ({
+ id: doc.id,
+ ...doc.data(),
+ }));
+ setMessages(fetchedMessages);
+ });
+
+ return () => unsubscribe();
+ }, []);
+
+ const sendMessage = async () => {
+ if (!newMessage.trim()) return;
+ try {
+ await addDoc(collection(firestore, 'discussion'), {
+ text: newMessage,
+ author: user?.displayName || 'Anonymous',
+ createdAt: serverTimestamp(),
+ });
+ setNewMessage('');
+ } catch (error) {
+ console.error('Error sending message:', error);
+ }
+ };
+
+ return (
+
+
💬 Welcome to the Discussion
+
+
+
+
+ {messages.length === 0 && (
+
No messages yet. Start the conversation!
+ )}
+ {messages.map((msg) => (
+
setSelectedMessage(msg.id === selectedMessage ? null : msg.id)}
+ >
+
{msg.author}
+
{msg.text}
+ {selectedMessage === msg.id && (
+
+
+
+
+
+
+
+ )}
+
+ ))}
+
+
+
+ setNewMessage(e.target.value)}
+ className="flex-1 p-4 border rounded-lg shadow-md focus:outline-none focus:ring-2 focus:ring-blue-400 text-lg"
+ placeholder="Type a message..."
+ />
+
+
+
+
+ );
+};
+
+export default DiscussionPage;
+
diff --git a/src/pages/profile.tsx b/src/pages/profile.tsx
new file mode 100644
index 00000000..2d6f85e9
--- /dev/null
+++ b/src/pages/profile.tsx
@@ -0,0 +1,198 @@
+import React, { useEffect, useState } from 'react';
+import { ProfileData } from '../types/profileColumnData';
+import { toast } from 'react-hot-toast';
+import { updateProfile } from '../services/db/profile/updateProfile';
+import { useAuth } from '../contexts/auth';
+import { firestore } from '../utils/firebaseInit';
+import { collection, query, where, getDocs } from 'firebase/firestore';
+import { useRouter } from 'next/router';
+
+const ProfilePage: React.FC = () => {
+ const router = useRouter();
+ const [profile, setProfile] = useState(null);
+ const [editMode, setEditMode] = useState(false);
+ const [formData, setFormData] = useState({
+ name: '',
+ email: '',
+ branch: '',
+ college: '',
+ bio: '',
+ profileImage: '',
+ });
+
+ useEffect(() => {
+ const fetchProfile = async () => {
+ try {
+ const storedProfile = localStorage.getItem("userProfile");
+
+ if (storedProfile) {
+ const parsedProfile = JSON.parse(storedProfile);
+ setProfile(parsedProfile);
+ setFormData(parsedProfile);
+ } else {
+ const userEmail = "john.doe@example.com";
+ const profilesCollection = collection(firestore, "profiles");
+ const q = query(profilesCollection, where("email", "==", userEmail));
+ const querySnapshot = await getDocs(q);
+
+ if (!querySnapshot.empty) {
+ const userProfile = querySnapshot.docs[0].data() as ProfileData;
+ setProfile(userProfile);
+ setFormData(userProfile);
+
+ localStorage.setItem("userProfile", JSON.stringify(userProfile));
+ } else {
+ console.warn("Profile not found for email:", userEmail);
+ }
+ }
+ } catch (error) {
+ console.error("Error fetching profile:", error);
+ }
+ };
+
+ fetchProfile();
+ }, []);
+
+ const handleInputChange = (e: React.ChangeEvent) => {
+ const { name, value } = e.target;
+ setFormData((prev) => ({ ...prev, [name]: value }));
+ };
+
+ const handleSave = async () => {
+ try {
+ await updateProfile(formData);
+ setProfile(formData);
+ setEditMode(false);
+ localStorage.setItem("userProfile", JSON.stringify(formData));
+ } catch (err) {
+ toast.error('Failed to update profile. Please try again.');
+ }
+ };
+
+ const handleCancel = () => {
+ setEditMode(false);
+ setFormData(profile!);
+ };
+
+ return (
+
+
+ {profile && (
+
+
+

+
+
+
+ {editMode ? (
+
+ ) : (
+
+
{profile.name}
+
{profile.branch}
+
{profile.college}
+
+
+
+
+ )}
+
+
+
📑 My Courses
+
+ {[...Array(4)].map((_, i) => (
+
+ ))}
+
+
+
+
+
+
+
+
+ )}
+
+
+ );
+};
+
+export default ProfilePage;
diff --git a/src/pages/template.tsx b/src/pages/template.tsx
new file mode 100644
index 00000000..8b5b904c
--- /dev/null
+++ b/src/pages/template.tsx
@@ -0,0 +1,260 @@
+import React, { useState, useEffect } from 'react';
+import { useRouter } from 'next/router';
+import Link from 'next/link';
+import { FaUniversity, FaGraduationCap, FaPlus } from 'react-icons/fa';
+
+// Define the college data for each template
+const collegesData = {
+ iits: ['IIT Bombay', 'IIT Delhi', 'IIT Madras', 'IIT Kanpur', 'IIT Kharagpur'],
+ nits: ['NIT Trichy', 'NIT Warangal', 'NIT Surathkal', 'NIT Calicut', 'NIT Rourkela'],
+ iiits: ['IIIT Hyderabad', 'IIIT Bangalore', 'IIIT Delhi', 'IIIT Allahabad', 'IIIT Jabalpur'],
+ other: [], // For user-added colleges
+};
+
+// TemplateCard component
+interface TemplateCardProps {
+ name: string;
+ route: string;
+ description?: string;
+ isAddCard?: boolean; // For the "Add College" card
+ onAddCollege?: (collegeName: string) => void; // Function to add a college
+}
+
+const TemplateCard: React.FC = ({ name, route, description, isAddCard, onAddCollege }) => {
+ const [newCollegeName, setNewCollegeName] = useState('');
+
+ const handleAddCollege = () => {
+ if (newCollegeName.trim() && onAddCollege) {
+ onAddCollege(newCollegeName);
+ setNewCollegeName('');
+ }
+ };
+
+ return (
+
+ );
+};
+
+// CollegeCard component
+interface CollegeCardProps {
+ name: string;
+}
+
+const CollegeCard: React.FC = ({ name }) => {
+ return (
+ {/* Adjusted height */}
+
+
+
+
{name}
+
+
Explore courses, notes, and PYQs for {name}.
+
+
+
+ );
+};
+
+// CollegeList component
+interface CollegeListProps {
+ colleges: string[];
+ onAddCollege?: (collegeName: string) => void; // Function to add a college
+}
+
+const CollegeList: React.FC = ({ colleges, onAddCollege }) => {
+ const router = useRouter();
+
+ return (
+ {/* Increased top padding to move cards down */}
+
+
Colleges
+
+ {colleges.map((college, index) => (
+
+ ))}
+
+
+
+ );
+};
+
+// SkeletonCard component (for loading state)
+const SkeletonCard = () => {
+ return (
+ {/* Adjusted height */}
+
+
+
+ );
+};
+
+// Main TemplatePage component
+const TemplatePage = () => {
+ const router = useRouter();
+ const { template } = router.query;
+ const [isLoading, setIsLoading] = useState(true); // Simulate loading state
+ const [colleges, setColleges] = useState(collegesData); // State for colleges
+
+ // Simulate loading delay
+ useEffect(() => {
+ const timer = setTimeout(() => setIsLoading(false), 1000); // 1 second delay
+ return () => clearTimeout(timer);
+ }, []);
+
+ // Function to add a college to a specific category
+ const handleAddCollege = (category: keyof typeof colleges, collegeName: string) => {
+ setColleges((prev) => ({
+ ...prev,
+ [category]: [...prev[category], collegeName],
+ }));
+ };
+
+ // If a template is selected, show the list of colleges
+ if (template) {
+ const selectedColleges = colleges[template as keyof typeof colleges] || [];
+ return (
+
+ handleAddCollege(template as keyof typeof colleges, collegeName)}
+ />
+
+ );
+ }
+
+ // Otherwise, show the list of templates
+ const templates = [
+ {
+ id: 1,
+ name: 'IITs',
+ route: '/template?template=iits',
+ description: 'Indian Institutes of Technology - Premier engineering institutes in India.',
+ },
+ {
+ id: 2,
+ name: 'NITs',
+ route: '/template?template=nits',
+ description: 'National Institutes of Technology - Top engineering colleges in India.',
+ },
+ {
+ id: 3,
+ name: 'IIITs',
+ route: '/template?template=iiits',
+ description: 'Indian Institutes of Information Technology - Focused on IT and computer science.',
+ },
+ {
+ id: 4,
+ name: 'Other',
+ route: '/template?template=other',
+ description: 'Add your college here.',
+ },
+ ];
+
+ return (
+
+
{/* Increased top padding to move cards down */}
+
College Templates
+ {isLoading ? (
+
+ {[...Array(8)].map((_, index) => (
+
+ ))}
+
+ ) : (
+
+ {templates.map((template) => (
+
+ ))}
+
+ )}
+
+
+ );
+};
+
+export default TemplatePage;
diff --git a/src/services/db/courses/updateCourse.ts b/src/services/db/courses/updateCourse.ts
index 92b162b8..a97c439e 100644
--- a/src/services/db/courses/updateCourse.ts
+++ b/src/services/db/courses/updateCourse.ts
@@ -2,11 +2,11 @@ import { toast } from 'react-hot-toast'
import { api } from '../../../utils/api'
interface Props {
- id: number
- title: string
- code: string
- isAnonymous: boolean
- refetch: Function
+ id: number;
+ title: string;
+ code: string;
+ isAnonymous: boolean;
+ refetch: Function;
}
export const updateCourse = ({
diff --git a/src/services/db/profile/getProfile.ts b/src/services/db/profile/getProfile.ts
new file mode 100644
index 00000000..29463400
--- /dev/null
+++ b/src/services/db/profile/getProfile.ts
@@ -0,0 +1,11 @@
+import { toast } from 'react-hot-toast'
+import { api } from '../../../utils/api'
+
+export const getProfile = async () => {
+ try {
+ const { data } = await api.get('/api/db/profile')
+ return data.result
+ } catch (err: any) {
+ toast.error(err.message)
+ }
+}
diff --git a/src/services/db/profile/updateProfile.ts b/src/services/db/profile/updateProfile.ts
new file mode 100644
index 00000000..ca3b2ae6
--- /dev/null
+++ b/src/services/db/profile/updateProfile.ts
@@ -0,0 +1,21 @@
+import { toast } from 'react-hot-toast';
+import { api } from '../../../utils/api';
+
+interface Props {
+ id: number;
+ name: string;
+ email: string;
+ bio: string;
+}
+
+export const updateProfile = async ({ id, name, email, bio }: Props) => {
+ try {
+ const res = await api.put(`/api/db/profile?id=${id}`, { name, email, bio });
+ toast.success(res.data.message);
+ return res.data;
+ } catch (err: any) {
+ toast.error(`Error: ${err.message}`);
+ throw err;
+ }
+};
+
diff --git a/src/types/profileColumnData.ts b/src/types/profileColumnData.ts
new file mode 100644
index 00000000..409583c1
--- /dev/null
+++ b/src/types/profileColumnData.ts
@@ -0,0 +1,8 @@
+export type ProfileData = {
+ id?: string;
+ name: string;
+ email: string;
+ bio?: string;
+ profileImage?: string;
+};
+