diff --git a/package-lock.json b/package-lock.json index 1bc508ef8..cb4bdf3d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "react-chrono": "^2.6.1", "react-d3-cloud": "^1.0.6", "react-dom": "^18.2.0", + "react-hot-toast": "^2.5.1", "react-icon-cloud": "^1.1.3", "react-icons": "^5.2.1", "react-router-dom": "^6.23.0", @@ -24,6 +25,7 @@ "simple-icons": "^5.24.0", "stats.js": "^0.17.0", "three": "^0.165.0", + "typewriter-effect": "^2.21.0", "uuid": "^8.3.2" }, "devDependencies": { @@ -6893,6 +6895,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/goober": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", + "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -9435,6 +9446,12 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -9868,6 +9885,15 @@ } ] }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "license": "MIT", + "dependencies": { + "performance-now": "^2.1.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -9993,6 +10019,23 @@ "react": ">=16.8" } }, + "node_modules/react-hot-toast": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.5.1.tgz", + "integrity": "sha512-54Gq1ZD1JbmAb4psp9bvFHjS7lje+8ubboUmvKZkCsQBLH6AOpZ9JemfRvIdHcfb9AZXRaFLrb3qUobGYDJhFQ==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.3", + "goober": "^2.1.16" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/react-icon-cloud": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/react-icon-cloud/-/react-icon-cloud-1.1.3.tgz", @@ -11870,6 +11913,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typewriter-effect": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/typewriter-effect/-/typewriter-effect-2.21.0.tgz", + "integrity": "sha512-Y3VL1fuJpUBj0gS4OTXBLzy1gnYTYaBuVuuO99tGNyTkkub5CXi+b/hsV7Og9fp6HlhogOwWJwgq7iXI5sQlEg==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1", + "raf": "^3.4.1" + }, + "peerDependencies": { + "react": "^17.x || ^18.x", + "react-dom": "^17.x || ^18.x" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", diff --git a/package.json b/package.json index d555ef09d..597918cbd 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "react-chrono": "^2.6.1", "react-d3-cloud": "^1.0.6", "react-dom": "^18.2.0", + "react-hot-toast": "^2.5.1", "react-icon-cloud": "^1.1.3", "react-icons": "^5.2.1", "react-router-dom": "^6.23.0", @@ -26,6 +27,7 @@ "simple-icons": "^5.24.0", "stats.js": "^0.17.0", "three": "^0.165.0", + "typewriter-effect": "^2.21.0", "uuid": "^8.3.2" }, "devDependencies": { diff --git a/src/Components/Achievements.jsx b/src/Components/Achievements.jsx index 3214455e2..d6aad302c 100644 --- a/src/Components/Achievements.jsx +++ b/src/Components/Achievements.jsx @@ -1,31 +1,304 @@ -import React from 'react'; -import CircularCard from './CircularCard'; +import React, { useState, useEffect } from "react"; +import Typewriter from "typewriter-effect"; +import toast, { Toaster } from "react-hot-toast"; + +const AchievementsPage = () => { + const [showForm, setShowForm] = useState(false); + const [sections, setSections] = useState({}); + + + useEffect(() => { + const savedSections = localStorage.getItem("sections"); + if (savedSections) { + setSections(JSON.parse(savedSections)); + } + }, []); + + const handleAddEntry = (sectionName, newEntry) => { + setSections((prevSections) => { + const updatedSections = { ...prevSections }; + if (!updatedSections[sectionName]) { + updatedSections[sectionName] = []; + } + updatedSections[sectionName].push(newEntry); + localStorage.setItem("sections", JSON.stringify(updatedSections)); + return updatedSections; + }); + + setShowForm(false); + toast.success("Achievement added successfully! 🎉"); + }; -const Achievements = () => { return ( -
-

- GSoC Contributors -

-
-
- - - - -
+
+ + + {/* Header Section */} +
+

+ +

+
+ + + + + +
+ {Object.keys(sections).length > 0 ? ( + Object.entries(sections).map(([section, entries], index) => ( +
+
+

+ {section} +

+
+
+ {entries.map((entry, i) => ( + + ))} +
+
+ )) + ) : ( +

+ No entries yet. Add some achievements or competitions! +

+ )}
-
-
-
- - - -
-
+ + + {showForm && ( + setShowForm(false)} + onSubmit={handleAddEntry} + /> + )} +
+ ); +}; + +const AchievementCard = ({ + title, + description, + participants, + branch, + image, +}) => { + const [isExpanded, setIsExpanded] = useState(false); + + const toggleDescription = () => { + setIsExpanded(!isExpanded); + }; + + return ( +
+ {image && ( +
+ {title}
+ )} +
+

+ {title} +

+

+ Participants: {participants} +

+

+ Branch: {branch} +

+
+ Description: +

+ {description} +

+
+ +
+
+
+
+ ); +}; + +const FormModal = ({ sections, onClose, onSubmit }) => { + const [isNewSection, setIsNewSection] = useState(true); + const [sectionName, setSectionName] = useState(""); + const [title, setTitle] = useState(""); + const [description, setDescription] = useState(""); + const [participants, setParticipants] = useState(""); + const [branch, setBranch] = useState(""); + const [image, setImage] = useState(""); + + const handleSubmit = (e) => { + e.preventDefault(); + + + const descriptionWordCount = description.trim().split(/\s+/).length; + if (descriptionWordCount > 30) { + alert("Description must be less than 30 words."); + return; + } + + const newEntry = { title, description, participants, branch, image }; + if (isNewSection) { + onSubmit(sectionName, newEntry); + } else { + onSubmit(sectionName, newEntry); + } + }; + + return ( +
+
+ + +

+ {isNewSection ? "Add New Section" : "Add Entry to Section"} +

+
+ {isNewSection ? ( +
+ + setSectionName(e.target.value)} + className="w-full p-2 border rounded" + required + /> +
+ ) : ( +
+ + +
+ )} +
+ + setTitle(e.target.value)} + className="w-full p-2 border rounded" + required + /> +
+
+ + +
+
+ + setParticipants(e.target.value)} + className="w-full p-2 border rounded" + required + /> +
+
+ + setBranch(e.target.value)} + className="w-full p-2 border rounded" + required + /> +
+
+ + setImage(e.target.value)} + className="w-full p-2 border rounded" + placeholder="Enter image URL" + /> +
+
+ + +
+
+
); -} +}; -export default Achievements; +export default AchievementsPage;