diff --git a/src/app/dashboard/components/ActionCard/ActionCard.tsx b/src/app/dashboard/components/ActionCard/ActionCard.tsx new file mode 100644 index 0000000..a4f5da3 --- /dev/null +++ b/src/app/dashboard/components/ActionCard/ActionCard.tsx @@ -0,0 +1,25 @@ +"use client"; + +import React from "react"; + +interface ActionCardProps { + label: string; + buttonText: string; + onClick?: () => void; +} + +const ActionCard: React.FC = ({ label, buttonText, onClick }) => { + return ( +
+ {label} + +
+ ); +}; + +export default ActionCard; diff --git a/src/app/dashboard/components/header.tsx b/src/app/dashboard/components/header.tsx index 086f6d2..45c91b0 100644 --- a/src/app/dashboard/components/header.tsx +++ b/src/app/dashboard/components/header.tsx @@ -26,7 +26,7 @@ const Header = () => { const titleMap: Record = { admin: "Admin Dashboard", "project-owner": "Project Owner Dashboard", - researcher: "Researcher Dashboard", + researcher: "Security Researcher Dashboard", validator: "Validator Dashboard", }; diff --git a/src/app/dashboard/components/resuables/ChartCard.tsx b/src/app/dashboard/components/resuables/ChartCard.tsx new file mode 100644 index 0000000..99460bd --- /dev/null +++ b/src/app/dashboard/components/resuables/ChartCard.tsx @@ -0,0 +1,70 @@ +import React from "react"; + +interface ChatCardProps { + role: "Validator" | "Researcher"; + name: string; + address: string; + message: string; + stats: { label: string; value: string | number }[]; + reputation: number; +} + +const ChatCard: React.FC = ({ + role, + name, + address, + message, + stats, + reputation, +}) => { + return ( +
+ {/* Role */} +

{role}

+ + {/* Header */} +
+
+
+

{name}

+

{address}

+
+
+ + {/* Message */} +
+ {message} +
+ + {/* Stats */} +
+ {stats.map((s, i) => ( + + {s.label} | {s.value} + + ))} + + Reputation | {reputation}% + +
+ + {/* Input Box */} +
+ + +
+ +

+ All conversations are monitored and recorded for security purposes. +

+
+ ); +}; + +export default ChatCard; diff --git a/src/app/dashboard/components/resuables/ProjectCard.tsx b/src/app/dashboard/components/resuables/ProjectCard.tsx index 08d2757..7428d23 100644 --- a/src/app/dashboard/components/resuables/ProjectCard.tsx +++ b/src/app/dashboard/components/resuables/ProjectCard.tsx @@ -9,33 +9,9 @@ type Props = { project: Project; }; -// pick top two langs and normalize them to 100% -function getTopTwoNormalized( - langs: Record< - string, - { percentage: number; bgColor: string; logo: string; icon: string } - > -) { - const entries = Object.values(langs) - .sort((a, b) => b.percentage - a.percentage) - .slice(0, 2); - - const total = entries.reduce((sum, l) => sum + l.percentage, 0) || 1; - return entries.map((l) => ({ - ...l, - normalized: (l.percentage / total) * 100, - })); -} - export const ProjectCard: React.FC = ({ project }) => { - const top = getTopTwoNormalized(project.language ?? {}); - - // 📝Fallback for project‐level logo: if none, use first lang’s icon/bg - const fallback = top[0] ?? { icon: "?", bgColor: "bg-gray-700" }; - const logoText = project.logo.text || fallback.icon; - const logoBg = project.logo.bgColor || fallback.bgColor; - const shortenText = (text: string, max: number) => { + if (!text) return ""; if (text.length <= max) return text; const cut = text.slice(0, max); const last = cut.lastIndexOf(" "); @@ -45,117 +21,104 @@ export const ProjectCard: React.FC = ({ project }) => { return ( + className="block col-span-12 sm:col-span-6 lg:col-span-4" + > - {/* Logo + Title */} - -
- {project.logo.logo ? ( + className="bg-[#110D0F] text-white p-6 rounded-2xl border border-gray-700 w-full max-w-md" + > +
+
+ + + {project.status} + +
+ +
+ {/* Logo + Title + Priority */} +
+
+
+ {project.logo.logo ? ( + {project.title} + ) : ( +
+ {project.logo.text} +
+ )} +
+

{project.title}

+
+ + {/* Priority badge */} + + {`Priority: ${project.priority}`} + + + +
+
+ + {/* Amount, Deadline, Status */} +
+ {project.amount && ( +
{project.title} - ) : ( -
- {logoText} + {project.amount} +
+ )} +
+ {/* Left side: Deadline */} +
+ Deadline: +
+ {project.deadline}
- )} +
+ + {/* Right side: Button */} + +
+ View Details +
+
-

{project.title}

- - {/* Description */} - - {shortenText(project.description, 150)} - - {/* Amount & Deadline */} - -
- Money bag - {project.amount} -
-
- Deadline - Deadline: {project.deadline} -
-
+
- {/* Tags */} - - {project.tags.map((tag) => ( - - {tag} - - ))} - - {/* Progress Bar (top 2 langs) */} - {top.length === 2 && ( - -
- {top.map((lang) => ( -
- {lang.logo ? ( - {`${lang.icon} - ) : ( - {lang.icon} - )} - {Math.round(lang.normalized)}% -
- ))} -
-
- )} ); diff --git a/src/app/dashboard/components/resuables/ReportCard.tsx b/src/app/dashboard/components/resuables/ReportCard.tsx index 181bf8a..111b41e 100644 --- a/src/app/dashboard/components/resuables/ReportCard.tsx +++ b/src/app/dashboard/components/resuables/ReportCard.tsx @@ -1,64 +1,37 @@ "use client"; import { cards } from "../../researcher/projects/mockData"; -import { X } from "lucide-react"; -import { motion, AnimatePresence } from "framer-motion"; -type CardGridProps = { - isOpen: boolean; - onClose: () => void; -}; - -export default function CardGrid({ isOpen, onClose }: CardGridProps) { +export default function CardGrid() { return ( - - {isOpen && ( - -
- {/* Close Button */} - - -

- DeFi Guard Reports -

+
+

+ DeFi Guard Reports +

-
- {cards.map((card) => ( -
-
- {card.id} - {card.date} -
-

{card.title}

-
- - - {card.severity} - - {card.score} - - {card.reward} -
-
- ))} +
+ {cards.map((card) => ( +
+
+ {card.id} + {card.date} +
+

{card.title}

+
+ + + {card.severity} + + {card.score} + + {card.reward}
- - )} - + ))} +
+
); } diff --git a/src/app/dashboard/components/resuables/ReportDiscussion.tsx b/src/app/dashboard/components/resuables/ReportDiscussion.tsx new file mode 100644 index 0000000..dc18677 --- /dev/null +++ b/src/app/dashboard/components/resuables/ReportDiscussion.tsx @@ -0,0 +1,33 @@ +import ChatCard from "./ChartCard"; + +const ReportDiscussion = () => { + return ( +
+ + + alert('XSS') in the name field executes on public profiles. High impact—could steal sessions. PoC attached.\n\nSuggestions: Sanitize inputs, add CSP. Need more details?`} + stats={[ + { label: "Ranks", value: 12 }, + { label: "Audits Made", value: 2 }, + ]} + reputation={91} + /> +
+ ); +}; + +export default ReportDiscussion; diff --git a/src/app/dashboard/components/resuables/WriteAReport.css b/src/app/dashboard/components/resuables/WriteAReport.css new file mode 100644 index 0000000..0ea713b --- /dev/null +++ b/src/app/dashboard/components/resuables/WriteAReport.css @@ -0,0 +1,7 @@ +.ql-toolbar button svg { + width: 18px; + height: 18px; + stroke: currentColor; /* ensure outline icons */ + fill: none !important; /* prevent solid fill */ + } + \ No newline at end of file diff --git a/src/app/dashboard/components/resuables/WriteAReport.tsx b/src/app/dashboard/components/resuables/WriteAReport.tsx index 920c308..bb35cee 100644 --- a/src/app/dashboard/components/resuables/WriteAReport.tsx +++ b/src/app/dashboard/components/resuables/WriteAReport.tsx @@ -1,93 +1,128 @@ "use client"; -import { useState, useRef, useEffect, useMemo } from "react"; +import { useState, useRef, useEffect } from "react"; import dynamic from "next/dynamic"; -import { ChevronDownIcon, X } from "lucide-react"; +import { ChevronDownIcon, Redo, Undo, Upload } from "lucide-react"; import { motion, AnimatePresence } from "framer-motion"; import "react-quill/dist/quill.snow.css"; -import Image from "next/image"; -import { ReportData, uploadToPinata } from "@/lib/utils"; import toast from "react-hot-toast"; -import { writeContractWithStarknetJs } from "@/hooks/useBlockchain"; import { Account, byteArray, cairo } from "starknet"; +import { ReportData, uploadToPinata } from "@/lib/utils"; +import { writeContractWithStarknetJs } from "@/hooks/useBlockchain"; import { useAccount } from "@starknet-react/core"; -import { has } from "lodash"; +import { Quill } from "react-quill"; +import { renderToStaticMarkup } from "react-dom/server"; + const ReactQuill = dynamic(() => import("react-quill"), { ssr: false }); +if (typeof window !== "undefined") { + const icons = Quill.import("ui/icons"); + icons["undo"] = renderToStaticMarkup(); + icons["redo"] = renderToStaticMarkup(); +} const modules = { - toolbar: [ - ["header", "font", "size"], - ["bold", "italic", "underline", "strike", "blockquote"], - [ - { list: "ordered" }, - { list: "bullet" }, - { indent: "-1" }, - { indent: "+1" }, + toolbar: { + container: [ + ['undo', 'redo'], + [{ header: [1, 2, 3, 4, 5, 6, false] }], + [{ font: [] }], + [{ size: [] }], + ['bold', 'italic', 'underline', 'strike'], + [{ color: [] }, { background: [] }], + [{ script: 'sub' }, { script: 'super' }], + ['blockquote', 'code-block'], + [{ list: 'ordered' }, { list: 'bullet' }], + [{ indent: '-1' }, { indent: '+1' }], + [{ align: [] }], + ['link', 'image', 'video'], + ['clean'] ], - ["link", "image", "video"], - ["clean"], - ], + handlers: { + undo: function () { + // @ts-ignore + this.quill.history.undo(); + }, + redo: function () { + // @ts-ignore + this.quill.history.redo(); + } + } + }, + history: { + delay: 1000, + maxStack: 100, + userOnly: true + } }; + + const formats = [ - "header", - "font", - "size", - "bold", - "italic", - "underline", - "strike", - "blockquote", - "list", - "bullet", - "indent", - "link", - "image", - "video", - "align", - "code-block", + 'header', 'font', 'size', + 'bold', 'italic', 'underline', 'strike', + 'color', 'background', + 'script', 'blockquote', 'code-block', + 'list', 'bullet', 'indent', + 'align', + 'link', 'image', 'video', + 'clean' ]; + type WriteAReportProps = { - isOpen: boolean; - onClose: () => void; projectId?: number; }; -export default function WriteAReport({ - isOpen, - onClose, - projectId, -}: WriteAReportProps) { - const [value, setValue] = useState(""); - const [previewMode, setPreviewMode] = useState(false); - const [isSubmitted, setIsSubmitted] = useState(false); - const [isSubmitting, setIsSubmitting] = useState(false); - const [ipfsHash, setIpfsHash] = useState(""); - const [contractReportId, setContractReportId] = useState(""); - const [generatedReportId, setGeneratedReportId] = useState(""); - const [title, setTitle] = useState(""); - const [project, setProject] = useState(""); - +export default function WriteAReport({ projectId }: WriteAReportProps) { const [severityLevel] = useState([ { id: 1, name: "Low" }, { id: 2, name: "Medium" }, { id: 3, name: "High" }, { id: 4, name: "Critical" }, ]); + const [categories] = useState([ + { id: 1, name: "Smart Contract" }, + { id: 2, name: "Frontend" }, + { id: 3, name: "Backend" }, + { id: 4, name: "Infrastructure" }, + ]); + const [selectedLevel, setSelectedLevel] = useState(severityLevel[0]); - const [showOptions, setShowOptions] = useState(false); - const dropdownRef = useRef(null); + const [selectedCategory, setSelectedCategory] = useState(categories[0]); + const [showLevelOptions, setShowLevelOptions] = useState(false); + const [showCategoryOptions, setShowCategoryOptions] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); + const [ipfsHash, setIpfsHash] = useState(""); + const [contractReportId, setContractReportId] = useState(""); + const [generatedReportId, setGeneratedReportId] = useState(""); + const [title, setTitle] = useState(""); + const [description, setDescription] = useState(""); + const [risk, setRisk] = useState(""); + const [recommendation, setRecommendation] = useState(""); + const [file, setFile] = useState(null); const { account } = useAccount(); - const toggleOptions = () => { - setShowOptions((prev) => !prev); - }; + const dropdownRef = useRef(null); + + useEffect(() => { + function handleClickOutside(event: MouseEvent) { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target as Node) + ) { + setShowLevelOptions(false); + setShowCategoryOptions(false); + } + } + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); - const handleSelect = (level: { id: number; name: string }) => { - setSelectedLevel(level); - setShowOptions(false); + const handleFileChange = (e: React.ChangeEvent) => { + if (e.target.files && e.target.files[0]) { + setFile(e.target.files[0]); + } }; const generateUniqueId = (): string => { @@ -102,12 +137,10 @@ export default function WriteAReport({ return; } - - setIsSubmitting(true); try { - const severityMap: { [key: string]: ReportData["severity"] } = { + const severityMap: { [key: string]: ReportData["severity"] | "" } = { Low: "low", Medium: "high", High: "high", @@ -128,13 +161,6 @@ export default function WriteAReport({ setIpfsHash(hash); toast.success(`Report uploaded to IPFS! Hash: ${hash}`); - console.log({ - reportData, - projectId, - account, - hash, - }, 'hash'); - if (account && projectId) { toast.loading("Submitting to contract..."); @@ -149,284 +175,216 @@ export default function WriteAReport({ contractArgs ); - - console.log({ - contractResult - }, 'result'); - if (contractResult && contractResult.result && contractResult.status) { setContractReportId(reportId); - setIsSubmitted(true); toast.dismiss(); toast.success( `Report submitted to blockchain successfully! Report ID: ${reportId}` ); } else { - console.error( - "❌ WriteAReport: Contract transaction failed:", - contractResult - ); + console.error("❌ Contract transaction failed:", contractResult); toast.dismiss(); toast.error("Contract transaction failed. Please try again."); } } else if (account && !projectId) { - setIsSubmitted(true); toast.success(`Report uploaded to IPFS successfully! Hash: ${hash}`); } else { toast.error("Please connect your wallet to submit to blockchain."); } - } catch (error) { + } catch (error: any) { console.error("Error submitting report:", error); - toast.error("Failed to submit report. Please try again."); + toast.error(`Failed to submit report: ${error.message || "Unknown error"}`); } finally { - // setIsSubmitting(false); + setIsSubmitting(false); } }; - const handleGoBack = () => { - setIsSubmitted(false); - setIsSubmitting(false); - setIpfsHash(""); - setContractReportId(""); - setGeneratedReportId(""); - setTitle(""); - setProject(""); - setValue(""); - setPreviewMode(false); - setSelectedLevel(severityLevel[0]); - }; - useEffect(() => { - function handleClickOutside(event: MouseEvent) { - if ( - dropdownRef.current && - !dropdownRef.current.contains(event.target as Node) - ) { - setShowOptions(false); - } - } - document.addEventListener("mousedown", handleClickOutside); - return () => { - document.removeEventListener("mousedown", handleClickOutside); - }; - }, []); - - if (!isOpen) { - return null; - } return ( -
- {!isSubmitted ? ( -
- - - Write a Report - - + +

+ Fortichain Security Vulnerability Report +

+ +

+ Submit your security findings and vulnerability reports +

+ + {/* Section 1 */} +
+

+ Section 1 | Description +

+
+ setTitle(e.target.value)} + className="flex-1 bg-[#161113] border border-[#464043] rounded-lg px-4 py-3 text-sm text-gray-300 outline-none" + /> + {/* Severity Dropdown */} +
- - - {/* Report Title */} - - - setTitle(e.target.value)} - /> - - - {/* Project and Severity Level */} - - {/* Project Input */} -
- - setProject(e.target.value)} - /> -
- - {/* Severity Level Dropdown */} -
+ {showLevelOptions && ( + - -
- {selectedLevel.name} - + {severityLevel.map((level) => ( + ))} + + )} + +
- - {showOptions && ( - - {severityLevel.map((level) => ( - - ))} - - )} - -
-
- - - {/* Quill Editor */} - -

Report Body

-
-
- {!previewMode ? ( -
- -
- ) : ( -
-
{value}
-
- )} -
-
+ {/* Category Dropdown */} +
+ + + {showCategoryOptions && ( + + {categories.map((cat) => ( -
-
- - - {/* Submit Button */} - - - - - -
- ) : ( - // ✅ Success Modal -
-
-
-

- Report Submitted Successfully -

-

- Your report has been submitted. -

- check - -
+ ))} + + )} +
- )} -
+ +
+ + {/* Section 2 */} +
+

+ Section 2 | Potential Risk +

+ +
+ + {/* Section 3 */} +
+

+ Section 3 | Recommendation +

+ +
+ + {/* Section 4 */} +
+

+ Section 4 | Attachments +

+
+

+ Upload Vulnerability Assessments, Pen Test Results, And Compliance + Reports +

+ + +

+ Supports PDF, DOC, DOCX up to 10MB +

+
+
+ + {/* Submit */} +
+ +
+
); } diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx index f4498ec..f147d65 100644 --- a/src/app/dashboard/layout.tsx +++ b/src/app/dashboard/layout.tsx @@ -2,14 +2,23 @@ import React from "react"; import { Sidebar } from "./components/sidenav"; import Header from "./components/header"; import { ProjectsProvider } from "@/context/project-context"; +import Foot from "@/components/foot"; const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => { return ( -
+
+ {/* Header at the top */}
-
- {children} + + {/* Main content area grows, pushes footer down */} +
+
{children}
+
+ + {/* Footer always below content, not fixed */} +
+
diff --git a/src/app/dashboard/researcher/projects/[projectId]/page.tsx b/src/app/dashboard/researcher/projects/[projectId]/page.tsx index cf77f04..cb478b0 100644 --- a/src/app/dashboard/researcher/projects/[projectId]/page.tsx +++ b/src/app/dashboard/researcher/projects/[projectId]/page.tsx @@ -3,11 +3,15 @@ import { projects } from "../mockData"; import { notFound } from "next/navigation"; import Image from "next/image"; -import { Bookmark, SquarePen } from "lucide-react"; +import { ArrowUpRight, Bookmark, FileCode } from "lucide-react"; import { useState } from "react"; import CardGrid from "@/app/dashboard/components/resuables/ReportCard"; import { motion } from "framer-motion"; import WriteAReport from "@/app/dashboard/components/resuables/WriteAReport"; +import { IoLogoGithub } from "react-icons/io"; +import ActionCard from "@/app/dashboard/components/ActionCard/ActionCard"; +import ReportDiscussion from "@/app/dashboard/components/resuables/ReportDiscussion"; +import WriteAReportWriteAReport from "@/app/dashboard/components/resuables/WriteAReport"; type Props = { params: { @@ -24,15 +28,11 @@ export default function ProjectDetailsPage({ params }: Props) { } const [bookmark, setBookmark] = useState(false); - const [isWriteModalOpen, setIsWriteModalOpen] = useState(false); - const [isViewModalOpen, setIsViewModalOpen] = useState(false); + const [showWriteReport, setShowWriteReport] = useState(false); + const [showViewReport, setShowViewReport] = useState(false); + const [showDiscussion, setShowDiscussion] = useState(false); const handleBookmark = () => setBookmark(!bookmark); - const handleOpenWriteModal = () => setIsWriteModalOpen(true); - const handleCloseWriteModal = () => setIsWriteModalOpen(false); - - const handleOpenViewModal = () => setIsViewModalOpen(true); - const handleCloseViewModal = () => setIsViewModalOpen(false); const bookmarkIcon = bookmark ? ( @@ -40,8 +40,6 @@ export default function ProjectDetailsPage({ params }: Props) { ); - const report = ["fhf"]; - return ( - {/* Main project details */} + {/* Project details */} - {/* Project header */} - -
-
- {project.logo.text} -
-

{project.title}

-
- -
- - {/* Project description */} - - {project.description} - - - {/* Tags, Prize Pool, Deadline, Repository */} - -
- {project.tags.map((tag) => ( + {/* Header */} +
+
+
- {tag} + className={`w-1 h-1 rounded-full ${ + project.status === "Completed" + ? "bg-green-500" + : project.status === "Available" + ? "bg-blue-900" + : "bg-gray-400" + }`} + > + + {project.status} - ))} -
- -
-
- Money bag logo - Prize Pool: {project.amount}
- -
- deadline - Deadline: {project.deadline} +
+
+ +

+ {project.title} +

+
+
+ Bounty Amount + + {project.amount} +
-
- - {/* Repository */} -
- {project.repository?.map((repo) => ( -
- repository - {repo.name} +
+
+ Bounty Amount + + + {project.amount} +
- ))} +
- +
- {/* Languages */} - -

Languages

-
- {project.language && ( -
- {Object.entries(project.language).map( - ([languageName, languageData]) => ( -
- {`${languageName} - - {languageName} - - - {languageData.percentage}% - -
- ) - )} -
- )} + {/* Deadline */} +
+ Deadline: +
+ {project.deadline}
- +
- {/* Action Buttons */} - - {/* Write a Report */} - +
- {/* View Report */} - {report.length > 0 && ( - - )} -
+ {/* Description */} + Details + + {project.description} + + + {/* Links */} +
+

Links

+
+
+ + Github Repo +
+
+ + Contract Address +
+
+
- {/* Modals */} - - + {/* Action Cards */} +
+
+ setShowWriteReport(!showWriteReport)} + /> +
+
+ setShowDiscussion(!showDiscussion)} + /> +
+
+ setShowViewReport(!showViewReport)} + /> +
+
+ + {/* Inline Sections */} + {showWriteReport && ( +
+ +
+ )} + {showViewReport && ( +
+ +
+ )} + {showDiscussion && ( +
+ +
+ )} ); } diff --git a/src/app/dashboard/researcher/projects/mockData.ts b/src/app/dashboard/researcher/projects/mockData.ts index 798c6ef..f2c63ee 100644 --- a/src/app/dashboard/researcher/projects/mockData.ts +++ b/src/app/dashboard/researcher/projects/mockData.ts @@ -1,396 +1,180 @@ -type LanguageDetails = { +// types.ts + +export type LanguageDetails = { percentage: number; logo: string; icon: string; bgColor: string; -}; - -export type Project = { + }; + + export type Project = { id: number; logo: { - logo: string; - text: string; - bgColor: string; + logo: string; + text: string; + bgColor: string; }; title: string; description: string; - amount: string; + amount?: string; // optional, since you don’t use it yet + priority: "Low" | "Medium" | "High" | "Critical"; + viewDetails: string; deadline: string; - tags: string[]; + status: "Available" | "Completed"; + tags?: string[]; + }; - repository?: { - name: string; - link: string; - }[]; - language?: { - typescript?: LanguageDetails; - javascript?: LanguageDetails; - solidity?: LanguageDetails; - cairo?: LanguageDetails; - rust?: LanguageDetails; - go?: LanguageDetails; - python?: LanguageDetails; - java?: LanguageDetails; - c?: LanguageDetails; - }; -}; - - -export const projects: Project[] = [ + // ✅ Mock data + export const projects: Project[] = [ { - id: 1, - logo: { - logo: "/researcherIcon/DG.svg", - text: "DG", - bgColor: "bg-yellow-600", - }, - title: "Defi Guard", - description: - "A decentralized finance (DeFi) security tool designed to protect users and protocols by proactively scanning for vulnerabilities and potential exploits. It leverages advanced threat detection to identify security risks in smart contracts and DeFi platforms, providing real-time alerts and actionable insights. By helping prevent hacks and unauthorized access, it enhances trust and safety within the DeFi ecosystem, ensuring a more secure experience for all participaA decentralized finance (DeFi) protection tool that scans for vulnerabilities in DeFi protocols and helps prevent hacks.nts", - amount: "$50,000", - deadline: "24/09/2025", - tags: ["DeFi", "Storage", "NFTs"], - repository: [ - { - name: "DeFi-Guard-Smartcontract", - link: "www.github.com/defi-guard/smartcontract", - }, - { - name: "DeFi-Guard-Frontend", - link: "www.github.com/defi-guard/frontend", - }, - ], - language: { - typescript: { - percentage: 30, - logo: "/researcherIcon/typescript.svg", - icon: "TS", - bgColor: "bg-[#000055]", - }, - javascript: { - percentage: 10, - logo: "/researcherIcon/javascript.svg", - icon: "JS", - bgColor: "bg-[#4F4F07]", - }, - python: { - percentage: 10, - logo: "/researcherIcon/python.svg", - icon: "PY", - bgColor: "bg-[#0000AA]", - }, - cairo: { - percentage: 50, - logo: "/researcherIcon/cairo.svg", - icon: "CA", - bgColor: "bg-[#5B1712]", - }, - }, + id: 1, + title: "Smart Contract Audit", + logo: { + logo: "/researcherIcon/P1.svg", + text: "SC", + bgColor: "bg-blue-800", + }, + description: "Smart Contract Audit is a planned, thorough evaluation of a smart contract’s codebase, designed to equip researchers with a clear framework for assessing its security, functionality, and efficiency within the Mindblitz ecosystem or related blockchain applications. The audit, to be conducted by specialized security experts, will utilize automated analysis tools and in-depth manual code review to uncover potential vulnerabilities, logical errors, or inefficiencies that could lead to exploits or operational issues. Researchers will focus on verifying the contract’s alignment with its specified requirements, compliance with blockchain industry best practices, and robustness against common attack vectors, such as reentrancy, integer overflows, or unauthorized access. The process will result in a detailed report that identifies any issues, evaluates their severity, and provides actionable recommendations for remediation, enabling researchers to ensure the smart contract’s reliability, security, and trustworthiness prior to its deployment in decentralized systems.", + priority: "High", + viewDetails: "/projects/1", + deadline: "17th - Aug - 2025", + status: "Available", + amount:"$1500" + }, { - id: 2, - logo: { - logo: "/researcherIcon/PC.svg", - text: "PC", - bgColor: "bg-blue-700", - }, - title: "Plankton Chain", - description: - "A Layer 2 blockchain that enhances security while abstracting complex processes, providing a seamless and user-friendly experience for developers and users alike.", - amount: "$50,000", - deadline: "24/09/2025", - tags: ["DeFi", "Storage", "NFTs"], - repository: [ - { - name: "Plankton-Chain-Smartcontract", - link: "www.github.com/plankton-chain/smartcontract", - }, - { - name: "Plankton-Chain-Frontend", - link: "www.github.com/plankton-chain/frontend", - }, - ], - language: { - typescript: { - percentage: 30, - logo: "/researcherIcon/typescript.svg", - icon: "TS", - bgColor: "bg-[#000055]", - }, - javascript: { - percentage: 70, - logo: "/researcherIcon/javascript.svg", - icon: "JS", - bgColor: "bg-[#4F4F07]", - }, - python: { - percentage: 50, - logo: "/researcherIcon/python.svg", - icon: "PY", - bgColor: "bg-[#0000AA]", - }, - cairo: { - percentage: 50, - logo: "/researcherIcon/cairo.svg", - icon: "CA", - bgColor: "bg-[#5B1712]", - }, - }, + id: 2, + title: "Funding Function Audit", + logo: { + logo: "/researcherIcon/P2.svg", + text: "FF", + bgColor: "bg-green-700", + }, + description: "Security assessment of funding mechanisms in decentralized apps.", + priority: "Critical", + viewDetails: "/projects/2", + deadline: "17th - Aug - 2025", + status: "Available", + amount:"$1200" + }, { - id: 3, - logo: { - logo: "/researcherIcon/P1.svg", - text: "FD", - bgColor: "bg-blue-800", - }, - title: "FortiChain", - description: - "A decentralized bug bounty and smart contract security platform that rewards researchers and secures smart contracts by identifying and fixing vulnerabilities.", - amount: "$50,000", - deadline: "24/09/2025", - tags: ["Security", "AI"], - repository: [ - { - name: "FortiChain-Smartcontract", - link: "www.github.com/fortichain/smartcontract", - }, - { - name: "FortiChain-Frontend", - link: "www.github.com/fortichain/frontend", - }, - ], - language: { - typescript: { - percentage: 10, - logo: "/researcherIcon/typescript.svg", - icon: "TS", - bgColor: "bg-[#000055]", - }, - javascript: { - percentage: 30, - logo: "/researcherIcon/javascript.svg", - icon: "JS", - bgColor: "bg-[#4F4F07]", - }, - python: { - percentage: 10, - logo: "/researcherIcon/python.svg", - icon: "PY", - bgColor: "bg-[#0000AA]", - }, - cairo: { - percentage: 50, - logo: "/researcherIcon/cairo.svg", - icon: "CA", - bgColor: "bg-[#5B1712]", - }, - }, + id: 3, + title: "Strategy Review Audit", + logo: { + logo: "/researcherIcon/P2.svg", + text: "SR", + bgColor: "bg-purple-600", + }, + description: "Comprehensive audit of platform’s strategic security approach.", + priority: "Medium", + viewDetails: "/projects/3", + deadline: "17th - Aug - 2025", + status: "Available", + amount:"$800" + }, { - id: 4, - logo: { - logo: "/researcherIcon/DG.svg", - text: "DG", - bgColor: "bg-blue-800", - }, - title: "FortiChain", - description: - "A decentralized bug bounty and smart contract security platform that rewards researchers and secures smart contracts by identifying and fixing vulnerabilities.", - amount: "$50,000", - deadline: "24/09/2025", - tags: ["Security", "AI"], - repository: [ - { - name: "FortiChain-Smartcontract", - link: "www.github.com/fortichain/smartcontract", - }, - { - name: "FortiChain-Frontend", - link: "www.github.com/fortichain/frontend", - }, - ], - language: { - typescript: { - percentage: 10, - logo: "/researcherIcon/typescript.svg", - icon: "TS", - bgColor: "bg-[#000055]", - }, - javascript: { - percentage: 35, - logo: "/researcherIcon/javascript.svg", - icon: "JS", - bgColor: "bg-[#4F4F07]", - }, - python: { - percentage: 50, - logo: "/researcherIcon/python.svg", - icon: "PY", - bgColor: "bg-[#0000AA]", - }, - cairo: { - percentage: 5, - logo: "/researcherIcon/cairo.svg", - icon: "CA", - bgColor: "bg-[#5B1712]", - }, - }, + id: 4, + title: "User Experience Testing", + logo: { + logo: "/researcherIcon/PC.svg", + text: "UX", + bgColor: "bg-red-600", + }, + description: "Testing app usability and detecting issues with user flows.", + priority: "High", + viewDetails: "/projects/4", + deadline: "17th - Aug - 2025", + status: "Completed", + amount:"$1200" }, { - id: 5, - logo: { - logo: "/researcherIcon/P2.svg", - text: "FD", - bgColor: "bg-blue-800", - }, - title: "FortiChain", - description: - "A decentralized bug bounty and smart contract security platform that rewards researchers and secures smart contracts by identifying and fixing vulnerabilities.", - amount: "$50,000", - deadline: "24/09/2025", - tags: ["Security", "AI"], - repository: [ - { - name: "FortiChain-Smartcontract", - link: "www.github.com/fortichain/smartcontract", - }, - { - name: "FortiChain-Frontend", - link: "www.github.com/fortichain/frontend", - }, - ], - language: { - typescript: { - percentage: 40, - logo: "/researcherIcon/typescript.svg", - icon: "TS", - bgColor: "bg-[#000055]", - }, - javascript: { - percentage: 30, - logo: "/researcherIcon/javascript.svg", - icon: "JS", - bgColor: "bg-[#4F4F07]", - }, - python: { - percentage: 10, - logo: "/researcherIcon/python.svg", - icon: "PY", - bgColor: "bg-[#0000AA]", - }, - cairo: { - percentage: 20, - logo: "/researcherIcon/cairo.svg", - icon: "CA", - bgColor: "bg-[#5B1712]", - }, - }, + id: 5, + title: "Quarterly Financial Report", + logo: { + logo: "/researcherIcon/PC.svg", + text: "FR", + bgColor: "bg-yellow-600", + }, + description: "Analysis and audit of the quarterly financial reporting system.", + priority: "Low", + viewDetails: "/projects/5", + deadline: "17th - Aug - 2025", + status: "Completed", + amount:"$1800" + }, { - id: 6, - logo: { - logo: "/researcherIcon/P1.svg", - text: "FD", - bgColor: "bg-blue-800", - }, - title: "FortiChain", - description: - "A decentralized bug bounty and smart contract security platform that rewards researchers and secures smart contracts by identifying and fixing vulnerabilities.", - amount: "$50,000", - deadline: "24/09/2025", - tags: ["Security", "AI"], - repository: [ - { - name: "FortiChain-Smartcontract", - link: "www.github.com/fortichain/smartcontract", - }, - { - name: "FortiChain-Frontend", - link: "www.github.com/fortichain/frontend", - }, - ], - language: { - typescript: { - percentage: 0, - logo: "/researcherIcon/typescript.svg", - icon: "TS", - bgColor: "bg-[#000055]", - }, - javascript: { - percentage: 50, - logo: "/researcherIcon/javascript.svg", - icon: "JS", - bgColor: "bg-[#4F4F07]", - }, - python: { - percentage: 20, - logo: "/researcherIcon/python.svg", - icon: "PY", - bgColor: "bg-[#0000AA]", - }, - cairo: { - percentage: 30, - logo: "/researcherIcon/cairo.svg", - icon: "CA", - bgColor: "bg-[#5B1712]", - }, - }, - }, -]; - - -// cards.ts + id: 6, + title: "Product Launch Plan", + logo: { + logo: "/researcherIcon/P2.svg", + text: "PL", + bgColor: "bg-teal-700", + }, + description: "Audit and review of product launch security and workflows.", + priority: "Medium", + viewDetails: "/projects/6", + deadline: "17th - Aug - 2025", + status: "Completed", + amount:"$1900" -export type Card = { + }, + ]; + + // ------------------ Cards ------------------ + + export type Card = { id: string; date: string; title: string; - severity: string; + severity: "Low" | "Medium" | "High" | "Critical"; score: number; reward: string; }; + // ✅ Mock data export const cards: Card[] = [ { - id: '#8793', - date: '3 Jan, 4:35 PM', - title: 'Filename parameter on Home Page -', - severity: 'Critical', + id: "#8793", + date: "3 Jan, 4:35 PM", + title: "Filename parameter vulnerability on Home Page", + severity: "Critical", score: 9.0, - reward: '$200' + reward: "$200", }, { - id: '#8793', - date: '3 Jan, 4:35 PM', - title: 'Filename parameter on Home Page -', - severity: 'Critical', - score: 9.0, - reward: '$200' + id: "#8794", + date: "4 Jan, 2:15 PM", + title: "SQL injection issue on login form", + severity: "High", + score: 8.5, + reward: "$180", }, { - id: '#8793', - date: '3 Jan, 4:35 PM', - title: 'Filename parameter on Home Page -', - severity: 'Critical', - score: 9.0, - reward: '$200' + id: "#8795", + date: "5 Jan, 11:00 AM", + title: "Unprotected API endpoint exposing user data", + severity: "Critical", + score: 9.3, + reward: "$300", }, { - id: '#8793', - date: '3 Jan, 4:35 PM', - title: 'Filename parameter on Home Page -', - severity: 'Critical', - score: 9.0, - reward: '$200' + id: "#8796", + date: "6 Jan, 9:45 AM", + title: "Cross-site scripting vulnerability in comments section", + severity: "Medium", + score: 6.7, + reward: "$120", }, { - id: '#8793', - date: '3 Jan, 4:35 PM', - title: 'Filename parameter on Home Page -', - severity: 'Critical', - score: 9.0, - reward: '$200' - } + id: "#8797", + date: "7 Jan, 5:30 PM", + title: "Weak password hashing algorithm detected", + severity: "High", + score: 7.8, + reward: "$150", + }, ]; \ No newline at end of file diff --git a/src/app/dashboard/researcher/projects/page.tsx b/src/app/dashboard/researcher/projects/page.tsx index 1599743..a339ce0 100644 --- a/src/app/dashboard/researcher/projects/page.tsx +++ b/src/app/dashboard/researcher/projects/page.tsx @@ -1,68 +1,96 @@ "use client"; -import { motion } from "framer-motion"; // import framer motion -import { SearchIcon } from "lucide-react"; +import { motion } from "framer-motion"; +import { ChevronDown, Check, Filter } from "lucide-react"; import { ProjectCard } from "../../components/resuables/ProjectCard"; import { projects } from "./mockData"; +import { useState } from "react"; +import Foot from "@/components/foot"; const Projects = () => { + const [filter, setFilter] = useState("Available"); + const [open, setOpen] = useState(false); + + // Filter projects by status + const filteredProjects = + filter === "All" ? projects : projects.filter((p) => p.status === filter); + + const options = ["All", "Available", "Assigned"]; + return ( - - {/* Search and Filters */} - + {/* Content */} + -
- - -
-
- - -
-
+ {/* Dropdown + Filter Badge Row */} + + {/* Dropdown */} +
+ - {/* Project Cards */} - - {projects.map((project) => ( - + {/* Dropdown Menu */} + {open && ( +
+ {options.map((option) => ( +
{ + setFilter(option); + setOpen(false); + }} + className={`flex items-center justify-between px-4 py-2 cursor-pointer text-sm rounded-md ${ + filter === option + ? "bg-[#1F1A1C] text-white" + : "text-[#B5B3B4] hover:bg-[#1F1A1C]" + }`} + > + {option} + {filter === option && } +
))} - - +
+ )} +
+ + {/* Active Filter Badge */} +
+ + 1 +
+
+ + + {/* Project Cards */} + + {filteredProjects.map((project) => ( + + ))} + +
+
); }; diff --git a/src/app/dashboard/researcher/reports/[id]/page.tsx b/src/app/dashboard/researcher/reports/[id]/page.tsx index 85cd606..dea50d4 100644 --- a/src/app/dashboard/researcher/reports/[id]/page.tsx +++ b/src/app/dashboard/researcher/reports/[id]/page.tsx @@ -155,7 +155,7 @@ export default function ReportDetailPage({ params }: PageProps) { onClose={() => setShowProvideMoreDetailsModal(false)} onSubmit={(details) => { console.log("Additional details provided:", details); - // Here you would typically send the details to your backend + // Here you would typically send the details to your // For now, we'll just log it and close the modal setShowProvideMoreDetailsModal(false); }} diff --git a/src/components/foot.tsx b/src/components/foot.tsx new file mode 100644 index 0000000..d5d3217 --- /dev/null +++ b/src/components/foot.tsx @@ -0,0 +1,9 @@ +// components/Footer.tsx +export default function Foot() { + return ( + + ); + } + \ No newline at end of file