diff --git a/src/App.jsx b/src/App.jsx
index 99d55a675..fc136eb48 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -2,6 +2,7 @@ import { createTheme, MantineProvider } from "@mantine/core";
import "@mantine/core/styles.css";
import "@mantine/notifications/styles.css";
import { Route, Routes, Navigate, useLocation } from "react-router-dom";
+import PropTypes from "prop-types";
import { Notifications } from "@mantine/notifications";
import { Layout } from "./components/layout";
import Dashboard from "./Modules/Dashboard/dashboardNotifications";
@@ -15,6 +16,7 @@ import InactivityHandler from "./helper/inactivityhandler";
import Examination from "./Modules/Examination/examination";
import Database from "./Modules/Database/database";
import ProgrammeCurriculumRoutes from "./Modules/Program_curriculum/programmCurriculum";
+import PatentModulePage from "./Modules/Patent/PatentModulePage";
import NotFoundPage from "./components/NotFoundPage";
const theme = createTheme({
@@ -28,60 +30,127 @@ const theme = createTheme({
},
});
+function RequireAuth({ children }) {
+ const currentLocation = useLocation();
+ const token = localStorage.getItem("authToken");
+
+ if (!token) {
+ return (
+
+ );
+ }
+
+ return children;
+}
+
+RequireAuth.propTypes = {
+ children: PropTypes.node.isRequired,
+};
+
export default function App() {
const location = useLocation();
+ const hasToken = Boolean(localStorage.getItem("authToken"));
+
return (
- {location.pathname !== "/accounts/login" && }
- {location.pathname !== "/accounts/login" && }
+ {location.pathname !== "/accounts/login" && hasToken && }
+ {location.pathname !== "/accounts/login" && hasToken && (
+
+ )}
- } />
+
+ }
+ />
-
-
+
+
+
+
+
}
/>
-
-
+
+
+
+
+
}
/>
-
-
+
+
+
+
+
}
/>
-
-
+
+
+
+
+
}
/>
-
-
+
+
+
+ }
+ />
+
+
+
+
+
}
/>
} />
} />
- } />
- } />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
} />
diff --git a/src/Modules/Patent/PatentModulePage.jsx b/src/Modules/Patent/PatentModulePage.jsx
new file mode 100644
index 000000000..6b0c988b3
--- /dev/null
+++ b/src/Modules/Patent/PatentModulePage.jsx
@@ -0,0 +1,31 @@
+import { useSelector } from "react-redux";
+import ApplicantMainDashboard from "./components/Applicant/ApplicantMainDashboard";
+import DirectorMainDashboard from "./components/Director/DirectorMainDashboard";
+import PCCAdminMainDashboard from "./components/PCCAdmin/PCCAdminMainDashboard";
+
+export default function PatentModulePage() {
+ const role = useSelector((state) => state.user.role);
+
+ if (
+ [
+ "student",
+ "alumini",
+ "Professor",
+ "Associate Professor",
+ "Assistant Professor",
+ "Research Engineer",
+ ].includes(role)
+ ) {
+ return ;
+ }
+
+ if (role === "Director") {
+ return ;
+ }
+
+ if (role === "PCC Admin") {
+ return ;
+ }
+
+ return null;
+}
diff --git a/src/Modules/Patent/components/Applicant/ApplicantMainDashboard.jsx b/src/Modules/Patent/components/Applicant/ApplicantMainDashboard.jsx
new file mode 100644
index 000000000..78c872a01
--- /dev/null
+++ b/src/Modules/Patent/components/Applicant/ApplicantMainDashboard.jsx
@@ -0,0 +1,109 @@
+import React, { useEffect, useState } from "react";
+import { Grid, Container, Loader, Flex, Select } from "@mantine/core";
+import { useDispatch } from "react-redux";
+import { SortAscending } from "@phosphor-icons/react";
+import CustomBreadcrumbs from "../../../../components/Breadcrumbs.jsx";
+import ModuleTabs from "../../../../components/moduleTabs.jsx";
+import SubmitNewApplication from "./SubmitNewApplication/ApplicantSubmit.jsx";
+import ApplicantDashboard from "./Dashboard/ApplicantDashboard.jsx";
+import ViewApplicationsPage from "./ViewApplication/ApplicationView.jsx";
+import SavedDraftsPage from "./SavedDrafts/ApplicationDraft.jsx";
+import NotificationsPage from "./Notifications/ApplicantNotifications.jsx";
+import ApplicationForm from "./SubmitNewApplication/ApplicationForm.jsx";
+
+const categories = ["Most Recent", "Tags", "Title"];
+
+function ApplicantMainDashboard() {
+ const [activeTab, setActiveTab] = useState("0");
+ const [sortedBy, setSortedBy] = useState("Most Recent");
+ const [loading, setLoading] = useState(false);
+ const dispatch = useDispatch();
+
+ // Define your tabs here
+ const tabItems = [
+ { title: "Dashboard" },
+ { title: "Submit New Application" },
+ { title: "View Applications" },
+ { title: "Saved Drafts" },
+ { title: "Notifications" },
+ ];
+
+ useEffect(() => {
+ const fetchData = async () => {
+ const token = localStorage.getItem("authToken");
+ if (!token) return console.error("No authentication token found!");
+
+ try {
+ setLoading(true);
+ // Fetch data logic here if needed
+ } catch (error) {
+ console.error("Error fetching data:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchData();
+ }, [dispatch]);
+
+ return (
+ <>
+
+
+
+
+
+ }
+ data={categories}
+ value={sortedBy}
+ onChange={setSortedBy}
+ placeholder="Sort By"
+ />
+
+
+
+ {/* Render content based on the active tab */}
+
+ {loading ? (
+
+
+
+ ) : (
+ <>
+ {activeTab === "0" && (
+
+ )}
+ {activeTab === "1" && (
+
+ )}
+ {activeTab === "1.1" && (
+
+ )}
+ {activeTab === "2" && (
+
+ )}
+ {activeTab === "3" && (
+
+ )}
+ {activeTab === "4" && (
+
+ )}
+ >
+ )}
+
+ >
+ );
+}
+
+export default ApplicantMainDashboard;
diff --git a/src/Modules/Patent/components/Applicant/Dashboard/ApplicantDashboard.jsx b/src/Modules/Patent/components/Applicant/Dashboard/ApplicantDashboard.jsx
new file mode 100644
index 000000000..42c0c0cd9
--- /dev/null
+++ b/src/Modules/Patent/components/Applicant/Dashboard/ApplicantDashboard.jsx
@@ -0,0 +1,322 @@
+import React from "react";
+import PropTypes from "prop-types";
+import {
+ Grid,
+ Box,
+ Text,
+ Divider,
+ Button,
+ Container,
+ Progress,
+} from "@mantine/core";
+import { ClipboardText, FilePlus, Archive, Bell } from "@phosphor-icons/react";
+import "../../../style/Applicant/ApplicantDashboard.css";
+
+function ApplicantDashboard({ setActiveTab }) {
+ return (
+
+ {/* Page Title */}
+ Patent & Copyright Dashboard
+
+ {/* Content Below Title */}
+
+ {/* Feature Description */}
+
+ Welcome to the Patent Application Management System. This platform
+ enables you to efficiently manage your patent applications, monitor
+ their progress, and access essential resources. Please follow the
+ established workflow for a streamlined application process.
+
+
+ {/* Feature Points */}
+
+
+
+
+
+
+
+ Application Tracking:{" "}
+
+ Monitor the status of your patent applications with real-time
+ updates and comprehensive progress tracking.
+
+
+
+
+
+
+
+
+ Structured Process:{" "}
+
+ Follow our systematic approach for completing patent
+ applications with clear guidance at each stage.
+
+
+
+
+
+
+
+
+ Resource Management:{" "}
+
+ Access comprehensive documentation, guidelines, and forms
+ essential for the patent application process.
+
+
+
+
+
+
+
+
+ {/* Application Workflow */}
+
+
+ Application Workflow
+
+
+ {/* Horizontal Progress Bar for Larger Screens */}
+
+
+ {/* Dots */}
+
+ {[
+ { label: "Submitted", color: "#b3cde0" },
+ { label: "PCCAdmin", color: "#8cb3d9" },
+ { label: "Attorney Assignment", color: "#6699cc" },
+ { label: "Director's Approval", color: "#336699" },
+ { label: "Patentability Check", color: "blue" },
+ { label: "Search Report", color: "#003366" },
+ { label: "Patent Filed", color: "black" },
+ ].map((step, index) => (
+
+
+
+ ))}
+
+ {/* Labels Below Bar */}
+
+ {[
+ "Submitted",
+ "PCCAdmin",
+ "Attorney Assignment",
+ "Director's Approval",
+ "Patentability Check",
+ "Search Report",
+ "Patent Filed",
+ ].map((label, index) => (
+
+ {label}
+
+ ))}
+
+
+
+ {/* Vertical Progress Bar for Mobile Screens */}
+
+
+
+
+
+ {[
+ { label: "Submitted", color: "#b3cde0" },
+ { label: "PCCAdmin", color: "#8cb3d9" },
+ { label: "Attorney Assignment", color: "#6699cc" },
+ { label: "Director's Approval", color: "#336699" },
+ { label: "Patentability Check", color: "blue" },
+ { label: "Search Report", color: "#003366" },
+ { label: "Patent Filed", color: "black" },
+ ].map((step, index) => (
+
+
+ {step.label}
+
+ ))}
+
+
+
+
+
+
+
+ {/* Dashboard Sections */}
+
+ {/* Submit New Application */}
+
+
+
+ Submit New
+ Application
+
+
+
+ Initiate the patent application process through our comprehensive
+ submission system.
+
+ setActiveTab("1")}
+ >
+ Begin Application
+
+
+
+
+ {/* View Applications */}
+
+
+
+ View
+ Applications
+
+
+
+ Access and monitor the status of all your submitted patent
+ applications.
+
+ setActiveTab("2")}
+ >
+ View Applications
+
+
+
+
+ {/* Saved Drafts */}
+
+
+
+ Saved Drafts
+
+
+
+ Continue working on applications that have been saved as drafts.
+
+ setActiveTab("3")}
+ >
+ Access Drafts
+
+
+
+
+ {/* Notifications */}
+
+
+
+ Notifications
+
+
+
+ Receive and review important updates regarding your patent
+ applications.
+
+ setActiveTab("4")}
+ >
+ View Notifications
+
+
+
+
+
+ );
+}
+
+// Define prop types for ApplicantDashboard
+ApplicantDashboard.propTypes = {
+ setActiveTab: PropTypes.func.isRequired, // setActiveTab is a required function
+};
+
+export default ApplicantDashboard;
diff --git a/src/Modules/Patent/components/Applicant/Dashboard/DownloadsSection.jsx b/src/Modules/Patent/components/Applicant/Dashboard/DownloadsSection.jsx
new file mode 100644
index 000000000..99ded74fb
--- /dev/null
+++ b/src/Modules/Patent/components/Applicant/Dashboard/DownloadsSection.jsx
@@ -0,0 +1,179 @@
+import React, { useEffect, useState } from "react";
+import { Button, Text, Table, LoadingOverlay } from "@mantine/core";
+import { ArrowCircleDown } from "@phosphor-icons/react";
+import { fetchDocuments } from "../../../services/documentService.jsx";
+
+function DownloadsSection() {
+ const [downloadsData, setDownloadsData] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [hoveredRow, setHoveredRow] = useState(null);
+
+ const loadDocuments = async () => {
+ setLoading(true);
+ try {
+ const data = await fetchDocuments();
+ setDownloadsData(data);
+ } catch (error) {
+ console.error("Error fetching documents:", error);
+ alert("Failed to load documents");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ loadDocuments();
+ }, []);
+
+ return (
+
+
+
+
+ Documents & Downloads
+
+
+
+
+
+
+
+ S.No.
+
+
+ Document Title
+
+
+ Download
+
+
+
+
+ {downloadsData.map((download, index) => {
+ const isHovered = hoveredRow === index;
+ return (
+ setHoveredRow(index)}
+ onMouseLeave={() => setHoveredRow(null)}
+ style={{
+ backgroundColor: isHovered
+ ? "#f0f4fa"
+ : index % 2 === 0
+ ? "#f8fbff"
+ : "#ffffff",
+ transition: "background-color 0.2s ease",
+ }}
+ >
+
+ {index + 1}
+
+
+ {download.title}
+
+
+
+
+ Download
+
+
+
+ );
+ })}
+
+
+
+
+ );
+}
+
+export default DownloadsSection;
diff --git a/src/Modules/Patent/components/Applicant/Notifications/ApplicantNotifications.jsx b/src/Modules/Patent/components/Applicant/Notifications/ApplicantNotifications.jsx
new file mode 100644
index 000000000..e7a648934
--- /dev/null
+++ b/src/Modules/Patent/components/Applicant/Notifications/ApplicantNotifications.jsx
@@ -0,0 +1,180 @@
+import React, { useState } from "react";
+import PropTypes from "prop-types";
+import { Card, Button, Text, Box, Grid } from "@mantine/core";
+import { Check } from "@phosphor-icons/react";
+
+// Define styles at the top level like in DirectorNotifications
+const styles = {
+ notificationCard: {
+ padding: "1.5rem",
+ marginBottom: "1rem",
+ boxShadow: "0 5px 8px rgba(0, 0, 0, 0.1)",
+ borderRadius: "8px",
+ borderLeft: "10px solid #3182ce",
+ backgroundColor: "#fff",
+ height: "100%",
+ display: "flex",
+ flexDirection: "column",
+ marginLeft: "-10px",
+ },
+ notificationTitle: {
+ fontSize: "22px",
+ fontWeight: 500,
+ marginBottom: "0",
+ color: "#1a1b1e",
+ },
+ notificationStatus: {
+ fontSize: "1rem",
+ fontWeight: 500,
+ marginBottom: "0.5rem",
+ },
+ notificationDate: {
+ fontSize: "0.875rem",
+ color: "#666",
+ marginBottom: "1rem",
+ },
+ notificationDescription: {
+ fontSize: "0.875rem",
+ color: "#444",
+ marginBottom: "0",
+ flex: 1,
+ },
+ markReadButton: {
+ width: "100%",
+ marginTop: "auto",
+ color: "#3182ce",
+ fontWeight: 500,
+ },
+ pageTitle: {
+ fontSize: "24px",
+ fontWeight: 600,
+ marginBottom: "10px",
+ color: "#1a1b1e",
+ },
+ container: {
+ width: "100%",
+ padding: "0 1rem",
+ maxWidth: "1800px",
+ margin: "0 50px",
+ },
+};
+
+// Dummy data for notifications
+const notificationsData = [
+ {
+ id: 1,
+ title: "AI-Based Disease Detection in Crops",
+ status: "Approved by director",
+ description:
+ "Application approved by Director and sent to Attorney for Patentability check.",
+ date: "2024-10-23",
+ time: "14:30:00",
+ color: "#3182ce",
+ },
+ {
+ id: 2,
+ title: "AI-Based Disease Detection in Crops",
+ status: "Sent to director by PCC_Admin",
+ description:
+ "Application accepted by PCC Admin and forwarded to Director for initial review.",
+ date: "2024-10-22",
+ time: "10:15:30",
+ color: "#2196F3",
+ },
+ {
+ id: 3,
+ title: "AI-Based Disease Detection in Crops",
+ status: "Submitted to PCC Admin",
+ description:
+ "Application forwarded to PCC Admin for approval by Director and sent to Attorney for Patentability check.",
+ date: "2024-10-21",
+ time: "09:45:00",
+ color: "#FFC107",
+ },
+];
+
+// Notification card component
+function NotificationCard({
+ id,
+ title,
+ status,
+ description,
+ date,
+ time,
+ color,
+ onMarkAsRead,
+}) {
+ return (
+
+ {title}
+ {status}
+ {`${date} | ${time}`}
+ {description}
+ }
+ style={styles.markReadButton}
+ onClick={() => onMarkAsRead(id)}
+ >
+ Mark as Read
+
+
+ );
+}
+
+// PropTypes validation for NotificationCard
+NotificationCard.propTypes = {
+ id: PropTypes.number.isRequired,
+ title: PropTypes.string.isRequired,
+ status: PropTypes.string.isRequired,
+ description: PropTypes.string.isRequired,
+ date: PropTypes.string.isRequired,
+ time: PropTypes.string.isRequired,
+ color: PropTypes.string.isRequired,
+ onMarkAsRead: PropTypes.func.isRequired,
+};
+
+// Main NotificationsPage component
+function NotificationsPage() {
+ const [notifications, setNotifications] = useState(notificationsData);
+
+ const handleMarkAsRead = (id) => {
+ setNotifications(
+ notifications.filter((notification) => notification.id !== id),
+ );
+ };
+
+ return (
+
+ {/* Page Title */}
+ Notifications
+
+ {/* Notifications container */}
+
+
+ {notifications.map((notification) => (
+
+
+
+ ))}
+
+
+
+ );
+}
+
+export default NotificationsPage;
diff --git a/src/Modules/Patent/components/Applicant/SavedDrafts/ApplicationDraft.jsx b/src/Modules/Patent/components/Applicant/SavedDrafts/ApplicationDraft.jsx
new file mode 100644
index 000000000..ec56f4c6c
--- /dev/null
+++ b/src/Modules/Patent/components/Applicant/SavedDrafts/ApplicationDraft.jsx
@@ -0,0 +1,142 @@
+import React, { useEffect, useState } from "react";
+import PropTypes from "prop-types";
+import { Card, Button, Text, Box, Center, ThemeIcon } from "@mantine/core";
+import { ArrowRight, FileText } from "@phosphor-icons/react";
+import "../../../style/Applicant/ApplicationDraft.css";
+
+// Empty state component
+function EmptyDraftsState({ onStartNew }) {
+ return (
+
+
+
+
+
+
+ No Drafts Available
+
+
+ You haven't saved any patent application drafts yet.
+
+ }
+ onClick={onStartNew}
+ size="sm"
+ style={{ width: "100%" }}
+ >
+ Start New Application
+
+
+
+ );
+}
+
+EmptyDraftsState.propTypes = {
+ onStartNew: PropTypes.func.isRequired,
+};
+
+// Main component
+function SavedDraftsPage({ setActiveTab }) {
+ const [drafts, setDrafts] = useState([]);
+
+ const loadDrafts = () => {
+ const parsedDrafts = JSON.parse(
+ localStorage.getItem("savedDrafts") || "[]",
+ );
+ if (!Array.isArray(parsedDrafts)) {
+ setDrafts([]);
+ return;
+ }
+
+ const normalizedDrafts = parsedDrafts.map((draft, index) => ({
+ ...draft,
+ id: draft.id || Date.now() + index,
+ createdAt: draft.createdAt || new Date().toISOString(),
+ }));
+
+ setDrafts(normalizedDrafts);
+ localStorage.setItem("savedDrafts", JSON.stringify(normalizedDrafts));
+ };
+
+ useEffect(() => {
+ loadDrafts();
+ }, []);
+
+ const handleDeleteDraft = (draftId) => {
+ const updatedDrafts = drafts.filter((draft) => draft.id !== draftId);
+ setDrafts(updatedDrafts);
+ localStorage.setItem("savedDrafts", JSON.stringify(updatedDrafts));
+ };
+
+ const handleContinueEditing = (draft) => {
+ localStorage.removeItem("patentEditContext");
+ localStorage.removeItem("patentEditOriginApplicationId");
+ localStorage.setItem("patentDraftContext", JSON.stringify(draft));
+ setActiveTab("1.1");
+ };
+
+ return (
+
+
+
+
+ {drafts.length === 0 ? (
+ setActiveTab("1.1")} />
+ ) : (
+ drafts
+ .slice()
+ .reverse()
+ .map((draft) => (
+
+
+ {draft.applicationTitle || "Untitled Draft"}
+
+
+ Saved on:{" "}
+ {draft.createdAt
+ ? new Date(draft.createdAt).toLocaleString()
+ : "Unknown"}
+
+
+ Inventors:{" "}
+ {Array.isArray(draft.inventors) ? draft.inventors.length : 0}
+
+
+ handleContinueEditing(draft)}
+ >
+ Continue Editing
+
+ handleDeleteDraft(draft.id)}
+ >
+ Delete
+
+
+
+ ))
+ )}
+
+
+ );
+}
+
+SavedDraftsPage.propTypes = {
+ setActiveTab: PropTypes.func.isRequired,
+};
+
+export default SavedDraftsPage;
diff --git a/src/Modules/Patent/components/Applicant/SubmitNewApplication/ApplicantSubmit.jsx b/src/Modules/Patent/components/Applicant/SubmitNewApplication/ApplicantSubmit.jsx
new file mode 100644
index 000000000..934a75234
--- /dev/null
+++ b/src/Modules/Patent/components/Applicant/SubmitNewApplication/ApplicantSubmit.jsx
@@ -0,0 +1,52 @@
+import React from "react";
+import { Button, Card, Text, Box } from "@mantine/core";
+import { ArrowRight } from "@phosphor-icons/react";
+import "../../../style/Applicant/ApplicantSubmit.css";
+import PropTypes from "prop-types";
+
+function SubmitNewApplication({ setActiveTab }) {
+ const handleSubmit = () => {
+ setActiveTab("1.1");
+ };
+
+ return (
+
+
+
+
+
+
+ Intellectual Property Filing Form
+
+
+ Please use this form for all types of IP, including Patents,
+ Copyright, Designs etc.
+
+
+
+ Complete this form to initiate a new patent filing. Please ensure
+ all necessary details are accurate before submission. This form will
+ help streamline your application process and ensure compliance with
+ institutional guidelines.
+
+ }
+ id="pms-start-application-button"
+ onClick={handleSubmit}
+ fullWidth
+ mt="sm"
+ >
+ Start Application
+
+
+
+
+ );
+}
+
+SubmitNewApplication.propTypes = {
+ setActiveTab: PropTypes.func.isRequired,
+};
+
+export default SubmitNewApplication;
diff --git a/src/Modules/Patent/components/Applicant/SubmitNewApplication/ApplicationForm.jsx b/src/Modules/Patent/components/Applicant/SubmitNewApplication/ApplicationForm.jsx
new file mode 100644
index 000000000..bc1e671ff
--- /dev/null
+++ b/src/Modules/Patent/components/Applicant/SubmitNewApplication/ApplicationForm.jsx
@@ -0,0 +1,1323 @@
+import React, { useEffect, useState } from "react";
+import PropTypes from "prop-types";
+import {
+ TextInput,
+ Button,
+ Group,
+ Paper,
+ Title,
+ Text,
+ Textarea,
+ Table,
+ FileInput,
+ Checkbox,
+ Stack,
+ ScrollArea,
+ MultiSelect,
+ Badge,
+} from "@mantine/core";
+import { useNavigate } from "react-router-dom";
+import { useMediaQuery } from "@mantine/hooks";
+import { submitApplicantApplication } from "../../../services/applicantService";
+
+function ApplicationForm({ setActiveTab }) {
+ ApplicationForm.propTypes = {
+ setActiveTab: PropTypes.func.isRequired,
+ };
+ const isMobile = useMediaQuery("(max-width: 768px)");
+ const [inventors, setInventors] = useState([
+ {
+ name: "",
+ email: "",
+ collegeemail: "",
+ address: "",
+ mobile: "",
+ Contributionpercentage: "",
+ },
+ ]);
+ const [applicationTitle, setApplicationTitle] = useState("");
+ const IP_TYPES = [
+ {
+ value: "Patent",
+ label: "Patent",
+ description:
+ "Protects new inventions - technical solutions to problems. Covers how things work, what they do, how they do it, what they're made of, and how they're made.",
+ icon: "🔬",
+ },
+ {
+ value: "Copyright",
+ label: "Copyright",
+ description:
+ "Protects original creative works like books, music, software, art, and films. Covers the expression of ideas rather than the ideas themselves.",
+ icon: "🎨",
+ },
+ {
+ value: "Design",
+ label: "Design",
+ description:
+ "Protects the visual appearance of products including shape, configuration, pattern, or ornamentation. Focuses on aesthetic rather than functional features.",
+ icon: "✨",
+ },
+ {
+ value: "Trademark",
+ label: "Trademark",
+ description:
+ "Protects brand identifiers like names, logos, slogans that distinguish goods/services in the marketplace. Helps prevent consumer confusion.",
+ icon: "🏷️",
+ },
+ {
+ value: "Trade Secret",
+ label: "Trade Secret",
+ description:
+ "Protects confidential business information (formulas, processes, methods) that provides competitive advantage. No registration required but must be kept secret.",
+ icon: "🔒",
+ },
+ {
+ value: "Geographical Indication",
+ label: "Geographical Indication",
+ description:
+ "Protects products originating from specific regions with qualities/reputation due to that origin (e.g., Champagne, Darjeeling Tea).",
+ icon: "🌍",
+ },
+ ];
+ const [ipTypes, setIpTypes] = useState([]);
+
+ const [step, setStep] = useState(1);
+ const [generalQuestions, setGeneralQuestions] = useState({
+ inventionArea: "",
+ problemArea: "",
+ objective: "",
+ novelty: "",
+ utility: "",
+ tested: "",
+ applications: "",
+ });
+ const [section1Files, setSection1Files] = useState([]);
+ const [section2FundingFile, setSection2FundingFile] = useState(null);
+ const [section2MouFile, setSection2MouFile] = useState(null);
+ const [section3FormIII, setSection3FormIII] = useState(null);
+ const [iprOwnershipQuestions, setIprOwnershipQuestions] = useState({
+ significantUse: "",
+ fundingSource: "",
+ presentationDetails: "",
+ mOUDetails: "",
+ academicResearch: "",
+ });
+
+ const [companies, setCompanies] = useState([
+ { name: "", concernedPerson: "", contact: "" },
+ ]);
+
+ const [developmentStage, setDevelopmentStage] = useState({
+ embryonic: false,
+ partiallyDeveloped: false,
+ offTheShelf: false,
+ });
+
+ const [selectedDevelopmentStage, setSelectedDevelopmentStage] = useState("");
+
+ const normalizeIpTypes = (rawTypeOfIp) => {
+ if (!rawTypeOfIp) return [];
+
+ const rawValues = Array.isArray(rawTypeOfIp)
+ ? rawTypeOfIp
+ : String(rawTypeOfIp)
+ .split(",")
+ .map((item) => item.trim())
+ .filter(Boolean);
+
+ const canonicalByNormalized = new Map();
+ IP_TYPES.forEach((type) => {
+ canonicalByNormalized.set(type.value.toLowerCase(), type.value);
+ canonicalByNormalized.set(type.label.toLowerCase(), type.value);
+ });
+
+ return rawValues
+ .map((value) =>
+ canonicalByNormalized.get(String(value).trim().toLowerCase()),
+ )
+ .filter(Boolean);
+ };
+
+ const handleDevelopmentStageChange = (value) => {
+ setSelectedDevelopmentStage(value);
+ setDevelopmentStage({
+ embryonic: value === "embryonic",
+ partiallyDeveloped: value === "partiallyDeveloped",
+ offTheShelf: value === "offTheShelf",
+ });
+ };
+
+ useEffect(() => {
+ const rawContext = localStorage.getItem("patentEditContext");
+ const rawDraftContext = localStorage.getItem("patentDraftContext");
+
+ if (rawDraftContext) {
+ try {
+ const draftContext = JSON.parse(rawDraftContext);
+ setApplicationTitle(draftContext.applicationTitle || "");
+ setIpTypes(
+ Array.isArray(draftContext.ipTypes) ? draftContext.ipTypes : [],
+ );
+
+ if (
+ Array.isArray(draftContext.inventors) &&
+ draftContext.inventors.length > 0
+ ) {
+ setInventors(draftContext.inventors);
+ }
+
+ if (draftContext.generalQuestions) {
+ setGeneralQuestions((current) => ({
+ ...current,
+ ...draftContext.generalQuestions,
+ }));
+ }
+
+ if (draftContext.iprOwnershipQuestions) {
+ setIprOwnershipQuestions((current) => ({
+ ...current,
+ ...draftContext.iprOwnershipQuestions,
+ }));
+ }
+
+ if (
+ Array.isArray(draftContext.companies) &&
+ draftContext.companies.length > 0
+ ) {
+ setCompanies(draftContext.companies);
+ }
+
+ if (draftContext.selectedDevelopmentStage) {
+ handleDevelopmentStageChange(draftContext.selectedDevelopmentStage);
+ }
+
+ setStep(Number.isInteger(draftContext.step) ? draftContext.step : 1);
+
+ localStorage.removeItem("patentDraftContext");
+ } catch (error) {
+ console.error("Failed to load draft context:", error);
+ }
+
+ return;
+ }
+
+ if (!rawContext) {
+ return;
+ }
+
+ try {
+ const editContext = JSON.parse(rawContext);
+ const sectionI = editContext.section_I || {};
+ const sectionII = editContext.section_II || {};
+ const sectionIII = editContext.section_III || {};
+
+ setApplicationTitle(editContext.title || "");
+ setIpTypes(normalizeIpTypes(sectionI.type_of_ip));
+
+ if (
+ Array.isArray(editContext.applicants) &&
+ editContext.applicants.length > 0
+ ) {
+ setInventors(
+ editContext.applicants.map((applicant) => ({
+ name: applicant.name || "",
+ email: applicant.email || "",
+ collegeemail: applicant.email || "",
+ address: applicant.address || "",
+ mobile: applicant.mobile || "",
+ Contributionpercentage: applicant.percentage_share || "",
+ })),
+ );
+ }
+
+ setGeneralQuestions({
+ inventionArea: sectionI.area || "",
+ problemArea: sectionI.problem || "",
+ objective: sectionI.objective || "",
+ novelty: sectionI.novelty || "",
+ utility: sectionI.advantages || "",
+ tested: sectionI.is_tested ? "true" : "false",
+ applications: sectionI.applications || "",
+ });
+
+ setIprOwnershipQuestions({
+ significantUse: sectionII.funding_details || "",
+ fundingSource: sectionII.funding_source || "",
+ presentationDetails: sectionII.publication_details || "",
+ mOUDetails: sectionII.mou_details || "",
+ academicResearch: sectionII.research_details || "",
+ });
+
+ if (
+ sectionIII.company_name ||
+ sectionIII.contact_person ||
+ sectionIII.contact_no
+ ) {
+ setCompanies([
+ {
+ name: sectionIII.company_name || "",
+ concernedPerson: sectionIII.contact_person || "",
+ contact: sectionIII.contact_no || "",
+ },
+ ]);
+ }
+
+ const normalizedStage = String(
+ sectionIII.development_stage || "",
+ ).toLowerCase();
+ if (normalizedStage.includes("embryonic")) {
+ handleDevelopmentStageChange("embryonic");
+ } else if (normalizedStage.includes("partially")) {
+ handleDevelopmentStageChange("partiallyDeveloped");
+ } else if (normalizedStage.includes("off")) {
+ handleDevelopmentStageChange("offTheShelf");
+ }
+
+ setStep(1);
+ } catch (error) {
+ console.error("Failed to load edit context:", error);
+ }
+ }, []);
+
+ const navigate = useNavigate();
+
+ const handleAddInventor = () => {
+ setInventors([
+ ...inventors,
+ {
+ name: "",
+ email: "",
+ collegeemail: "",
+ address: "",
+ mobile: "",
+ Contributionpercentage: "",
+ },
+ ]);
+ };
+
+ const handleRemoveInventor = (index) => {
+ const updatedInventors = inventors.filter((_, i) => i !== index);
+ setInventors(updatedInventors);
+ };
+
+ const handleInputChange = (index, field, value) => {
+ if (field === "collegeemail") {
+ // Convert the part before @ to uppercase
+ const [username, domain] = value.split("@");
+ if (domain === "iiitdmj.ac.in") {
+ value = `${username.toUpperCase()}@${domain}`;
+ }
+ }
+ const updatedInventors = inventors.map((inventor, i) =>
+ i === index ? { ...inventor, [field]: value } : inventor,
+ );
+ setInventors(updatedInventors);
+ };
+
+ const handleGeneralInputChange = (field, value) => {
+ setGeneralQuestions({ ...generalQuestions, [field]: value });
+ };
+
+ const handleIprOwnershipInputChange = (field, value) => {
+ setIprOwnershipQuestions({ ...iprOwnershipQuestions, [field]: value });
+ };
+
+ const handleCompanyInputChange = (index, field, value) => {
+ const updatedCompanies = [...companies];
+ updatedCompanies[index][field] = value;
+ setCompanies(updatedCompanies);
+ };
+
+ const validateStep4 = () => {
+ return (
+ companies.every(
+ (company) => company.name && company.concernedPerson && company.contact,
+ ) && selectedDevelopmentStage
+ );
+ };
+
+ const validateCurrentStep = () => {
+ switch (step) {
+ case 1:
+ return (
+ applicationTitle &&
+ ipTypes.length > 0 &&
+ inventors.every(
+ (inventor) =>
+ inventor.name &&
+ inventor.email &&
+ inventor.collegeemail &&
+ inventor.address &&
+ inventor.mobile &&
+ inventor.Contributionpercentage,
+ )
+ );
+ case 2:
+ return (
+ generalQuestions.inventionArea &&
+ generalQuestions.problemArea &&
+ generalQuestions.objective &&
+ generalQuestions.novelty &&
+ generalQuestions.utility &&
+ generalQuestions.tested &&
+ generalQuestions.applications
+ );
+ case 3:
+ return (
+ iprOwnershipQuestions.significantUse &&
+ iprOwnershipQuestions.fundingSource &&
+ iprOwnershipQuestions.presentationDetails &&
+ iprOwnershipQuestions.mOUDetails &&
+ iprOwnershipQuestions.academicResearch
+ );
+ case 4:
+ return validateStep4();
+ default:
+ return false;
+ }
+ };
+
+ const addNewCompany = () => {
+ setCompanies([
+ ...companies,
+ { name: "", concernedPerson: "", contact: "" },
+ ]);
+ };
+
+ const removeCompany = (index) => {
+ const updatedCompanies = companies.filter((_, i) => i !== index);
+ setCompanies(updatedCompanies);
+ };
+
+ const handleSubmit = async (event) => {
+ event.preventDefault();
+
+ if (!validateCurrentStep()) {
+ alert("Please fill all required fields before submitting.");
+ return;
+ }
+
+ const data = {
+ title: applicationTitle,
+ ip_type: ipTypes,
+ user_id: 7108,
+ inventors: inventors.map((inventor) => ({
+ name: inventor.name,
+ institute_mail: inventor.collegeemail,
+ personal_mail: inventor.email,
+ address: inventor.address,
+ mobile: inventor.mobile,
+ percentage: inventor.Contributionpercentage,
+ })),
+ area_of_invention: generalQuestions.inventionArea,
+ problem_statement: generalQuestions.problemArea,
+ objective: generalQuestions.objective,
+ novelty: generalQuestions.novelty,
+ advantages: generalQuestions.utility,
+ tested_experimentally: generalQuestions.tested === "true",
+ applications: generalQuestions.applications,
+ funding_details: iprOwnershipQuestions.significantUse,
+ funding_source: iprOwnershipQuestions.fundingSource,
+ publication_details: iprOwnershipQuestions.presentationDetails,
+ mou_details: iprOwnershipQuestions.mOUDetails,
+ research_details: iprOwnershipQuestions.academicResearch,
+ company_details: companies.map((company) => ({
+ company_name: company.name,
+ contact_person: company.concernedPerson,
+ contact_no: company.contact,
+ })),
+ development_stage:
+ Object.keys(developmentStage).find(
+ (stage) => developmentStage[stage],
+ ) || "Prototype",
+ };
+
+ const formData = new FormData();
+ formData.append("json_data", JSON.stringify(data));
+
+ section1Files.forEach((file) => {
+ formData.append("poc_details", file);
+ });
+
+ if (section2FundingFile) {
+ formData.append("source_file", section2FundingFile);
+ }
+ if (section2MouFile) {
+ formData.append("mou_file", section2MouFile);
+ }
+
+ if (section3FormIII) {
+ formData.append("form_iii", section3FormIII);
+ }
+
+ try {
+ const yourToken = localStorage.getItem("authToken");
+ if (!yourToken) throw new Error("No token found!");
+
+ const response = await submitApplicantApplication(formData);
+ alert(`Application submitted successfully! Token: ${response.token}`);
+ localStorage.removeItem("patentEditContext");
+ localStorage.removeItem("patentEditOriginApplicationId");
+ navigate("/dashboard");
+ } catch (error) {
+ console.error("Error response:", error.response?.data);
+ alert(`Error: ${error.response?.data?.error || error.message}`);
+ }
+ };
+
+ const nextPage = () => {
+ if (validateCurrentStep()) {
+ setStep(step + 1);
+ } else {
+ alert("Please fill all required fields before proceeding.");
+ }
+ };
+
+ const prevPage = () => {
+ setStep(step - 1);
+ };
+
+ const handleSaveDraft = () => {
+ const draft = {
+ id: Date.now(),
+ createdAt: new Date().toISOString(),
+ applicationTitle,
+ inventors,
+ generalQuestions,
+ iprOwnershipQuestions,
+ ipTypes,
+ companies,
+ selectedDevelopmentStage,
+ developmentStage,
+ step,
+ };
+
+ const savedDrafts = JSON.parse(localStorage.getItem("savedDrafts")) || [];
+ savedDrafts.push(draft);
+ localStorage.setItem("savedDrafts", JSON.stringify(savedDrafts));
+
+ alert("Draft saved successfully!");
+ if (typeof setActiveTab === "function") {
+ setActiveTab("3");
+ return;
+ }
+
+ navigate("/patentsystem/applicant/");
+ };
+
+ // Button styles
+ const outlineButtonStyle = {
+ backgroundColor: "white",
+ color: "#0073e6",
+ border: "1px solid #0073e6",
+ transition: "background-color 0.3s ease, color 0.3s ease",
+ "&:hover": {
+ backgroundColor: "#0073e6",
+ color: "white",
+ },
+ };
+
+ const redButtonStyle = {
+ backgroundColor: "white",
+ color: "red",
+ border: "1px solid red",
+ transition: "background-color 0.3s ease, color 0.3s ease",
+ "&:hover": {
+ backgroundColor: "red",
+ color: "white",
+ },
+ };
+
+ const greenButtonStyle = {
+ backgroundColor: "#00a854",
+ color: "white",
+ border: "1px solid #00a854",
+ transition: "background-color 0.3s ease",
+ "&:hover": {
+ backgroundColor: "#008f48",
+ },
+ };
+
+ const blueButtonStyle = {
+ backgroundColor: "#0073e6",
+ color: "white",
+ border: "1px solid #0073e6",
+ transition: "background-color 0.3s ease",
+ "&:hover": {
+ backgroundColor: "#005bb5",
+ },
+ };
+
+ const fileInputStyles = {
+ root: {
+ marginBottom: "16px",
+ },
+ label: {
+ marginBottom: "8px",
+ fontSize: "14px",
+ fontWeight: 500,
+ },
+ input: {
+ padding: "10px 16px",
+ backgroundColor: "#e6f7ff",
+ border: "1px solid #91d5ff",
+ color: "#1890ff",
+ borderRadius: "4px",
+ cursor: "pointer",
+ transition: "all 0.2s",
+ width: isMobile ? "100%" : "50%",
+ "&:hover": {
+ backgroundColor: "#bae7ff",
+ borderColor: "#69c0ff",
+ },
+ },
+ placeholder: {
+ color: "#1890ff",
+ },
+ };
+
+ return (
+
+
+ Intellectual Property Filing Form
+
+
+ (Please use this form for all types of IP, including Patents, Copyright,
+ Designs, Marks, and even Know-how)
+
+
+
+
+
+ );
+}
+
+export default ApplicationForm;
diff --git a/src/Modules/Patent/components/Applicant/ViewApplication/ApplicationView.jsx b/src/Modules/Patent/components/Applicant/ViewApplication/ApplicationView.jsx
new file mode 100644
index 000000000..285703577
--- /dev/null
+++ b/src/Modules/Patent/components/Applicant/ViewApplication/ApplicationView.jsx
@@ -0,0 +1,1218 @@
+import React, { useState, useEffect } from "react";
+import {
+ Button,
+ Card,
+ Text,
+ Box,
+ Grid,
+ Container,
+ Stepper,
+ Badge,
+ Loader,
+ Title,
+ Divider,
+} from "@mantine/core";
+import {
+ CalendarCheck,
+ User,
+ FileText,
+ Hourglass,
+ Key,
+ ArrowLeft,
+ DownloadSimple,
+ CheckCircle,
+ CircleNotch,
+ ArrowRight,
+} from "@phosphor-icons/react";
+import PropTypes from "prop-types";
+import "../../../style/Applicant/ApplicationView.css";
+import { API_BASE_URL } from "../../../services/api";
+import {
+ fetchApplicantApplications,
+ fetchApplicantApplicationDetails,
+ withdrawApplicantApplication,
+} from "../../../services/applicantService";
+
+// Progress Bar Component
+function PatentProgressBar({ currentStatus, isMobile }) {
+ const allStatuses = [
+ "Submitted",
+ "Reviewed by PCC Admin",
+ "Needs Revision",
+ "Attorney Assigned",
+ "Returned to Director",
+ "Forwarded for Director's Review",
+ "Director's Approval Received",
+ "Patentability Check Started",
+ "Patentability Check Completed",
+ "Patentability Search Report Generated",
+ "Patent Filed",
+ "Patent Published",
+ "Patent Granted",
+ "Patent Refused",
+ "Withdrawn",
+ ];
+
+ const getStepIndex = (status) => {
+ if (status === "Rejected") return -1;
+ return allStatuses.findIndex((s) => s === status);
+ };
+
+ const currentStep = getStepIndex(currentStatus);
+ const isRejected = currentStatus === "Rejected";
+ const isRefused = currentStatus === "Patent Refused";
+ const isGranted = currentStatus === "Patent Granted";
+ const isWithdrawn = currentStatus === "Withdrawn";
+
+ // Determine which statuses to display based on current status
+ let displayStatuses;
+ if (isWithdrawn) {
+ displayStatuses = ["Submitted", "Withdrawn"];
+ } else if (isRefused) {
+ displayStatuses = ["Submitted", "Patent Refused"];
+ } else if (isGranted) {
+ // Show only the first 11 stages without "Patent Refused" for granted patents
+ displayStatuses = allStatuses.slice(0, 11);
+ } else {
+ displayStatuses = allStatuses;
+ }
+
+ return (
+
+ {isRejected && (
+
+ Application Rejected
+
+ )}
+
+ {!isMobile ? (
+ // Desktop view
+
+ {isRefused ? (
+ // Simple two-step progress for refused patents
+
+ }
+ label="Stage 1"
+ description="Submitted"
+ id="pms-completed-step"
+ />
+ }
+ label="Stage 2"
+ description="Patent Refused"
+ id="pms-completed-step"
+ />
+
+ ) : (
+ // Regular view with two rows for normal flow
+ <>
+
+ {displayStatuses.slice(0, 4).map((status, index) => (
+
+ ) : index === currentStep ? (
+
+ ) : (
+
+ )
+ }
+ label={`Stage ${index + 1}`}
+ description={status}
+ id={
+ isGranted || index <= currentStep
+ ? "pms-completed-step"
+ : "pms-pending-step"
+ }
+ />
+ ))}
+
+
+ {displayStatuses.slice(4).map((status, index) => (
+
+ ) : index + 4 === currentStep ? (
+
+ ) : (
+
+ )
+ }
+ label={`Stage ${index + 5}`}
+ description={status}
+ id={
+ isGranted || index + 4 <= currentStep
+ ? "pms-completed-step"
+ : "pms-pending-step"
+ }
+ />
+ ))}
+
+ >
+ )}
+
+ ) : (
+ // Mobile view - vertical stepper
+
+ {displayStatuses.map((status, index) => (
+
+ ) : index === (isRefused ? 1 : currentStep) ? (
+
+ ) : (
+
+ )
+ }
+ label={`Stage ${index + 1}`}
+ description={status}
+ id={
+ isGranted || index <= (isRefused ? 1 : currentStep)
+ ? "completed-step"
+ : "pending-step"
+ }
+ />
+ ))}
+
+ )}
+
+ );
+}
+
+PatentProgressBar.propTypes = {
+ currentStatus: PropTypes.string.isRequired,
+ isMobile: PropTypes.bool.isRequired,
+};
+
+// Application Card Component
+function ApplicationCard({
+ title,
+ date,
+ tokenNumber,
+ applicationNumber,
+ status,
+ attorney,
+ onViewApplication,
+}) {
+ const formattedDate = date
+ ? new Date(date).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "short",
+ day: "numeric",
+ })
+ : "Not available";
+
+ const getStatusColor = (currentStatus) => {
+ if (!currentStatus) return "gray";
+ if (
+ [
+ "Patent Granted",
+ "Director's Approval Received",
+ "Patent Filed",
+ "Patent Published",
+ ].includes(currentStatus)
+ ) {
+ return "green";
+ }
+ if (
+ [
+ "Needs Revision",
+ "Revision Expired",
+ "Patent Refused",
+ "Withdrawn",
+ ].includes(currentStatus)
+ ) {
+ return "red";
+ }
+ return "blue";
+ };
+
+ const displayStatus = status || "Pending";
+
+ return (
+
+
+ {title}
+
+
+
+
+
+ {formattedDate}
+
+
+
+
+ Application #{applicationNumber}
+
+
+ {tokenNumber ? (
+
+
+ Application No: {tokenNumber}
+
+ ) : (
+
+
+ Application No: Awaiting assignment
+
+ )}
+
+
+
+ {attorney || "No Attorney Assigned"}
+
+
+
+
+ {displayStatus}
+
+
+
+
+ onViewApplication(applicationNumber)}
+ id="pms-view-application-button"
+ >
+ View Details
+
+
+ );
+}
+
+ApplicationCard.propTypes = {
+ title: PropTypes.string.isRequired,
+ date: PropTypes.string,
+ tokenNumber: PropTypes.string,
+ applicationNumber: PropTypes.string.isRequired,
+ status: PropTypes.string,
+ attorney: PropTypes.string,
+ onViewApplication: PropTypes.func.isRequired,
+};
+
+function ConditionalFileDownload({ filePath, label, value }) {
+ const encodedFilePath = filePath ? encodeURI(filePath) : null;
+ const fileUrl = encodedFilePath ? `${API_BASE_URL}${encodedFilePath}` : null;
+
+ return (
+
+ );
+}
+
+ConditionalFileDownload.propTypes = {
+ filePath: PropTypes.string,
+ label: PropTypes.string.isRequired,
+ value: PropTypes.string,
+};
+
+// File Download Button Component
+function FileDownloadButton({ fileUrl, label, disabled }) {
+ if (!fileUrl || fileUrl === "null" || disabled) {
+ return (
+ }
+ disabled
+ >
+ No {label} Available
+
+ );
+ }
+
+ return (
+ }
+ >
+ View {label}
+
+ );
+}
+
+FileDownloadButton.propTypes = {
+ fileUrl: PropTypes.string,
+ label: PropTypes.string.isRequired,
+ disabled: PropTypes.bool,
+};
+
+function FormField({ label, value }) {
+ const isMobile = window.innerWidth <= 768;
+
+ return (
+
+
+ {label}
+
+
+ {value?.trim() ? value : "Not provided"}
+
+
+ );
+}
+
+FormField.propTypes = {
+ label: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+};
+
+// Field with download button - moved outside of the render function
+function FormFieldWithDownload({ label, value, fileUrl, fileLabel }) {
+ return (
+
+
+ {label}
+ {value || "Not provided"}
+
+
+
+
+
+ );
+}
+
+FormFieldWithDownload.propTypes = {
+ label: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ fileUrl: PropTypes.string,
+ fileLabel: PropTypes.string.isRequired,
+};
+
+// Section component for detail view - moved outside of the render function
+function FormSection({ title, children }) {
+ return (
+
+
+ {title}
+
+ {children}
+
+ );
+}
+
+FormSection.propTypes = {
+ title: PropTypes.string.isRequired,
+ children: PropTypes.node.isRequired,
+};
+
+// Main Application View Component
+function ApplicationView({ setActiveTab }) {
+ const [applications, setApplications] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [selectedApplication, setSelectedApplication] = useState(null);
+ const [viewMode, setViewMode] = useState("list");
+ const [isMobile, setIsMobile] = useState(false);
+ const [withdrawing, setWithdrawing] = useState(false);
+
+ // Retrieve authToken from local storage
+ const authToken = localStorage.getItem("authToken");
+
+ useEffect(() => {
+ const handleResize = () => {
+ setIsMobile(window.innerWidth <= 768);
+ };
+
+ handleResize();
+ window.addEventListener("resize", handleResize);
+
+ return () => window.removeEventListener("resize", handleResize);
+ }, []);
+
+ useEffect(() => {
+ const fetchApplicationData = async () => {
+ if (!authToken) {
+ setError("Authorization token is missing. Please login again.");
+ setLoading(false);
+ return;
+ }
+
+ try {
+ setLoading(true);
+ const response = await fetchApplicantApplications();
+
+ if (
+ response &&
+ response.applications &&
+ Array.isArray(response.applications)
+ ) {
+ const formattedApplications = response.applications.map(
+ (application) => {
+ const derivedStatus =
+ application.status ||
+ (application.decision_status === "Approved"
+ ? "Patent Granted"
+ : application.decision_status === "Rejected"
+ ? "Patent Refused"
+ : "Pending");
+
+ return {
+ title: application.title || "Untitled Application",
+ date: application.submitted_date || "",
+ tokenNumber:
+ application.application_number ||
+ application.token_no ||
+ null,
+ applicationNumber: application.application_id,
+ attorney: application.attorney_name || null,
+ status: derivedStatus,
+ };
+ },
+ );
+
+ setApplications(formattedApplications);
+ } else {
+ setError("No applications found or invalid response format");
+ }
+ } catch (err) {
+ console.error("Error fetching application data:", err);
+ setError("Failed to load application data. Please try again later.");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchApplicationData();
+ }, [authToken]);
+
+ const handleViewApplication = async (applicationNumber) => {
+ try {
+ setLoading(true);
+ const response =
+ await fetchApplicantApplicationDetails(applicationNumber);
+
+ if (response) {
+ setSelectedApplication(response);
+ setViewMode("detail");
+ localStorage.setItem("selectedApplicationId", applicationNumber);
+ }
+ } catch (err) {
+ console.error("Error fetching application details:", err);
+ setError("Failed to load application details. Please try again later.");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const handleBackToList = () => {
+ setViewMode("list");
+ setSelectedApplication(null);
+ };
+
+ const handleWithdrawApplication = async () => {
+ if (!selectedApplication?.application_id) {
+ return;
+ }
+
+ const confirmed = window.confirm(
+ "Withdraw this application? This cannot be undone.",
+ );
+
+ if (!confirmed) {
+ return;
+ }
+
+ try {
+ setWithdrawing(true);
+ await withdrawApplicantApplication(selectedApplication.application_id);
+ const updatedApplication = {
+ ...selectedApplication,
+ status: "Withdrawn",
+ };
+ setSelectedApplication(updatedApplication);
+ setApplications((currentApplications) =>
+ currentApplications.map((application) =>
+ application.applicationNumber === selectedApplication.application_id
+ ? { ...application, status: "Withdrawn" }
+ : application,
+ ),
+ );
+ } catch (withdrawError) {
+ console.error("Error withdrawing application:", withdrawError);
+ setError("Failed to withdraw application. Please try again later.");
+ } finally {
+ setWithdrawing(false);
+ }
+ };
+
+ const handleEditAndResubmitApplication = () => {
+ if (!selectedApplication) {
+ return;
+ }
+
+ localStorage.setItem(
+ "patentEditContext",
+ JSON.stringify(selectedApplication),
+ );
+ localStorage.setItem(
+ "patentEditOriginApplicationId",
+ String(selectedApplication.application_id),
+ );
+
+ if (typeof setActiveTab === "function") {
+ setActiveTab("1.1");
+ return;
+ }
+
+ window.history.back();
+ };
+
+ // Render application list view with improved loading and error states
+ const renderApplicationList = () => (
+ // Replace the Grid component with this structure:
+
+ Your Patent Applications
+
+ {loading ? (
+
+
+ Loading your applications...
+
+ ) : error ? (
+
+
+ Unable to Load Applications
+
+
+
+ We encountered an issue while loading your applications. Please try
+ again.
+
+ window.location.reload()}
+ fullWidth
+ >
+ Try Again
+
+
+ ) : applications.length === 0 ? (
+
+
+ No Applications Found
+
+
+ You haven't submitted any patent applications yet.
+
+ setActiveTab("newApplication")}
+ fullWidth
+ >
+ Start New Application
+
+
+ ) : (
+
+ {applications.map((app, index) => (
+
+ ))}
+
+ )}
+
+ );
+
+ // Render application detail view with enhanced UI
+ const renderApplicationDetail = () => {
+ if (!selectedApplication) return null;
+
+ const {
+ application_id,
+ title,
+ application_number,
+ token_no,
+ attorney_name,
+ status,
+ decision_status,
+ comments,
+ applicants,
+ section_I,
+ section_II,
+ section_III,
+ dates,
+ } = selectedApplication;
+ const displayApplicationNumber =
+ application_number || token_no || "Not Assigned";
+ const displayStatus = status || "Pending";
+
+ const submittedDate = dates?.submitted_date
+ ? new Date(dates.submitted_date).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not recorded";
+
+ // Build file URLs
+ const pocFileUrl = section_I?.poc_file
+ ? `${API_BASE_URL}/download/file/${section_I.poc_file}/`
+ : null;
+ const sourceAgreementFileUrl = section_II?.source_agreement_file
+ ? `${API_BASE_URL}/download/file/${section_II.source_agreement_file}/`
+ : null;
+ const mouFileUrl = section_II?.mou_file
+ ? `${API_BASE_URL}/download/file/${section_II.mou_file}/`
+ : null;
+ const formIIIFileUrl = section_III?.form_iii
+ ? `${API_BASE_URL}/download/file/${section_III.form_iii}/`
+ : null;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+
Reviewed by PCC
+
+ {dates?.reviewed_by_pcc_date
+ ? new Date(dates.reviewed_by_pcc_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not yet reviewed"}
+
+
*/}
+
+
+
Forwarded to Director
+
+ {dates?.forwarded_to_director_date
+ ? new Date(
+ dates.forwarded_to_director_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not yet forwarded"}
+
+
+
+
+
Director Approval
+
+ {dates?.director_approval_date
+ ? new Date(
+ dates.director_approval_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not yet approved"}
+
+
+
+
+
Patentability Check Start
+
+ {dates?.patentability_check_start_date
+ ? new Date(
+ dates.patentability_check_start_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not started"}
+
+
+
+
+
+ Patentability Check Completed
+
+
+ {dates?.patentability_check_completed_date
+ ? new Date(
+ dates.patentability_check_completed_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not completed"}
+
+
+
+
+
Search Report Generated
+
+ {dates?.search_report_generated_date
+ ? new Date(
+ dates.search_report_generated_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not generated"}
+
+
+
+
+
Date of Filing
+
+ {dates?.patent_filed_date
+ ? new Date(dates.patent_filed_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not recorded"}
+
+
+
+
+
Date of Publication
+
+ {dates?.patent_published_date
+ ? new Date(
+ dates.patent_published_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not yet published"}
+
+
+
+ {/*
+
Decision Date
+
+ {dates?.decision_date
+ ? new Date(dates.decision_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "No decision yet"}
+
+
*/}
+
+
+
Date of Granting
+
+ {dates?.final_decision_date
+ ? new Date(dates.final_decision_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "No final decision yet"}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {applicants && applicants.length > 0 ? (
+
+ {applicants.map((applicant, index) => (
+
+
+ Inventor {index + 1}
+
+
+
+
+
+
+
+
+
+ ))}
+
+ ) : (
+ No inventor information available
+ )}
+
+
+
+
+
+
+
+ );
+ };
+
+ return (
+
+ {viewMode === "list"
+ ? renderApplicationList()
+ : renderApplicationDetail()}
+
+ );
+}
+
+ApplicationView.propTypes = {
+ setActiveTab: PropTypes.func.isRequired,
+};
+
+export default ApplicationView;
diff --git a/src/Modules/Patent/components/Attorney/AttorneyMainDashboard.jsx b/src/Modules/Patent/components/Attorney/AttorneyMainDashboard.jsx
new file mode 100644
index 000000000..c20feb15f
--- /dev/null
+++ b/src/Modules/Patent/components/Attorney/AttorneyMainDashboard.jsx
@@ -0,0 +1,147 @@
+import React, { useEffect, useState } from "react";
+import {
+ Alert,
+ Button,
+ Card,
+ Loader,
+ Stack,
+ Text,
+ Textarea,
+ Title,
+} from "@mantine/core";
+import { attorneyService } from "../../services/attorneyService.jsx";
+
+function AttorneyMainDashboard() {
+ const [applications, setApplications] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState("");
+ const [commentsByApplication, setCommentsByApplication] = useState({});
+ const [submittingId, setSubmittingId] = useState(null);
+
+ useEffect(() => {
+ const loadApplications = async () => {
+ try {
+ setLoading(true);
+ const response = await attorneyService.fetchAttorneyApplications();
+ setApplications(response.applications || []);
+ } catch (loadError) {
+ console.error("Failed to load attorney applications:", loadError);
+ setError("Unable to load assigned applications.");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ loadApplications();
+ }, []);
+
+ const handleForward = async (applicationId) => {
+ const comments = (commentsByApplication[applicationId] || "").trim();
+ if (!comments) {
+ setError("Comments are required before forwarding to Director.");
+ return;
+ }
+
+ try {
+ setSubmittingId(applicationId);
+ await attorneyService.forwardAttorneyApplicationToDirector(
+ applicationId,
+ comments,
+ );
+ setApplications((currentApplications) =>
+ currentApplications.filter(
+ (application) => application.application_id !== applicationId,
+ ),
+ );
+ setCommentsByApplication((currentComments) => {
+ const nextComments = { ...currentComments };
+ delete nextComments[applicationId];
+ return nextComments;
+ });
+ setError("");
+ } catch (forwardError) {
+ console.error("Failed to forward application:", forwardError);
+ setError(
+ forwardError.response?.data?.error || "Unable to forward application.",
+ );
+ } finally {
+ setSubmittingId(null);
+ }
+ };
+
+ return (
+
+
+ Attorney Review Queue
+
+
+ Review the patentability assessment, add justification, and forward the
+ application back to the Director.
+
+
+ {error ? (
+
+ {error}
+
+ ) : null}
+
+ {loading ? (
+
+ ) : applications.length === 0 ? (
+
+ No applications are currently assigned to you.
+
+ ) : (
+
+ {applications.map((application) => (
+
+
+
+
+ {application.title}
+
+
+ Application ID: {application.application_id}
+
+
+ Status: {application.ui_status || application.status}
+
+
+
+
+ setCommentsByApplication((currentComments) => ({
+ ...currentComments,
+ [application.application_id]: event.currentTarget.value,
+ }))
+ }
+ required
+ />
+
+ handleForward(application.application_id)}
+ loading={submittingId === application.application_id}
+ >
+ Forward to Director
+
+
+
+ ))}
+
+ )}
+
+ );
+}
+
+export default AttorneyMainDashboard;
diff --git a/src/Modules/Patent/components/Director/Dashboard/DirectorDashboard.jsx b/src/Modules/Patent/components/Director/Dashboard/DirectorDashboard.jsx
new file mode 100644
index 000000000..d0b7ab3b5
--- /dev/null
+++ b/src/Modules/Patent/components/Director/Dashboard/DirectorDashboard.jsx
@@ -0,0 +1,186 @@
+import React, { useEffect } from "react";
+import PropTypes from "prop-types";
+import { Grid, Box, Text, Divider, Button, Paper } from "@mantine/core";
+import {
+ ClipboardText,
+ CheckCircle,
+ Eye,
+ Clock,
+ ChartBar,
+ Buildings,
+ Bell,
+} from "@phosphor-icons/react";
+import InsightsPage from "./DirectorInsights";
+import "../../../style/Director/DirectorDashboard.css";
+
+const TabKeys = {
+ NEW_APPLICATIONS: "1",
+ REVIEWED_APPLICATIONS: "2",
+ NOTIFICATIONS: "3",
+};
+
+function DirectorDashboard({ setActiveTab }) {
+ useEffect(() => {
+ const handleResize = () => {
+ // Window resize listener for future responsive features
+ };
+
+ handleResize(); // Check on initial render
+ window.addEventListener("resize", handleResize);
+
+ return () => window.removeEventListener("resize", handleResize);
+ }, []);
+
+ const featuresData = [
+ {
+ icon: ,
+ title: "Application Management and Review",
+ description:
+ "Track and review patent applications, view submission details, and monitor status updates.",
+ },
+ {
+ icon: ,
+ title: "Transparent Record-Keeping and Status Visibility",
+ description:
+ "Real-time status updates, detailed history tracking, and archive functionality.",
+ },
+ {
+ icon: ,
+ title: "Dashboard Analytics and Insights",
+ description:
+ "Analyze application volume, performance metrics, and trends to support data-driven decisions.",
+ },
+ ];
+
+ return (
+
+
+ Patent & Copyright Management Dashboard
+
+
+
+
+ Patent Management System (PMS)
+
+
+
+ The Patent Management System at IIITDM Jabalpur focuses on fostering
+ research and development activities, particularly in IT-enabled
+ design and manufacturing, as well as the design of IT systems.
+
+
+
+
+ {featuresData.map((feature, index) => (
+
+
+
+ {feature.icon}
+
+
+
+ {feature.title} :{" "}
+
+ {feature.description}
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ New
+ Applications
+
+
+
+ View all applications forwarded by PCC Admin for your review.
+ okay
+
+ setActiveTab(TabKeys.NEW_APPLICATIONS)}
+ id="pms-director-dashboard-button"
+ >
+ View Submitted Applications
+
+
+
+
+
+
+
+ {" "}
+ Reviewed Applications
+
+
+
+ Access applications that have been reviewed.
+
+ setActiveTab(TabKeys.REVIEWED_APPLICATIONS)}
+ id="pms-director-dashboard-button"
+ >
+ View Reviewed Applications
+
+
+
+
+
+
+
+ {" "}
+ Notifications
+
+
+
+ Stay updated with the latest notifications regarding your patent
+ applications.
+
+ setActiveTab(TabKeys.NOTIFICATIONS)}
+ id="pms-director-dashboard-button"
+ >
+ View Notifications
+
+
+
+
+
+
+ );
+}
+
+DirectorDashboard.propTypes = {
+ setActiveTab: PropTypes.func.isRequired,
+};
+
+export default DirectorDashboard;
diff --git a/src/Modules/Patent/components/Director/Dashboard/DirectorDownloads.jsx b/src/Modules/Patent/components/Director/Dashboard/DirectorDownloads.jsx
new file mode 100644
index 000000000..c571c3580
--- /dev/null
+++ b/src/Modules/Patent/components/Director/Dashboard/DirectorDownloads.jsx
@@ -0,0 +1,138 @@
+import React, { useEffect, useState } from "react";
+import { Button, Text, Table, LoadingOverlay } from "@mantine/core";
+import { ArrowCircleDown } from "@phosphor-icons/react";
+import { fetchDocuments } from "../../../services/documentService.jsx";
+
+function DownloadsSection() {
+ const [downloadsData, setDownloadsData] = useState([]);
+ const [loading, setLoading] = useState(false);
+ // Track which button is hovered (by id)
+ const [hoveredBtn, setHoveredBtn] = useState(null);
+
+ const loadDocuments = async () => {
+ setLoading(true);
+ try {
+ const data = await fetchDocuments();
+ setDownloadsData(data);
+ } catch (error) {
+ console.error("Error fetching documents:", error);
+ alert("Failed to load documents");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ loadDocuments();
+ }, []);
+
+ // Inline styles for button, including hover effect
+ const getButtonStyle = (isHovered) => ({
+ fontSize: "0.85rem",
+ backgroundColor: isHovered ? "#0073e6" : "#fff",
+ color: isHovered ? "#fff" : "#0073e6",
+ border: "1px solid #0073e6",
+ fontWeight: 500,
+ transition: "all 0.18s",
+ boxShadow: isHovered ? "0 2px 8px rgba(0,0,0,0.08)" : "none",
+ });
+
+ return (
+
+
+
+
+
+
+ Documents & Downloads
+
+
+
+
+
+
+ S.No.
+
+ Document Title
+
+
+ Download
+
+
+
+
+ {downloadsData.map((download, index) => (
+
+ {index + 1}
+ {download.title}
+
+ setHoveredBtn(download.id)}
+ onMouseLeave={() => setHoveredBtn(null)}
+ >
+
+ Download
+
+
+
+ ))}
+
+
+
+
+ );
+}
+
+export default DownloadsSection;
diff --git a/src/Modules/Patent/components/Director/Dashboard/DirectorInsights.jsx b/src/Modules/Patent/components/Director/Dashboard/DirectorInsights.jsx
new file mode 100644
index 000000000..1dc3fcb52
--- /dev/null
+++ b/src/Modules/Patent/components/Director/Dashboard/DirectorInsights.jsx
@@ -0,0 +1,17 @@
+import React from "react";
+import InsightsPage from "../../PCCAdmin/Dashboard/InsightsPage";
+import {
+ fetchDirectorInsightsReport,
+ downloadDirectorInsightsCsv,
+} from "../../../services/directorService";
+
+function DirectorInsights() {
+ return (
+
+ );
+}
+
+export default DirectorInsights;
diff --git a/src/Modules/Patent/components/Director/DirectorMainDashboard.jsx b/src/Modules/Patent/components/Director/DirectorMainDashboard.jsx
new file mode 100644
index 000000000..a9764779d
--- /dev/null
+++ b/src/Modules/Patent/components/Director/DirectorMainDashboard.jsx
@@ -0,0 +1,101 @@
+import React, { useEffect, useState } from "react";
+import { Grid, Container, Loader, Flex, Select } from "@mantine/core";
+import { useDispatch } from "react-redux";
+import { SortAscending } from "@phosphor-icons/react";
+import CustomBreadcrumbs from "../../../../components/Breadcrumbs.jsx";
+import ModuleTabs from "../../../../components/moduleTabs.jsx";
+import DirectorDashboard from "./Dashboard/DirectorDashboard.jsx";
+import SubmittedApplications from "./NewApplications/SubmittedApplications.jsx";
+import RecentsView from "./ReviewedApplications/RecentsView.jsx";
+import PatentApplication from "./NewApplications/StatusView.jsx";
+import DirectorNotifications from "./Notifications/DirectorNotifications.jsx"; // Import the notification component
+
+const categories = ["Most Recent", "Tags", "Title"];
+
+function DirectorMainDashboard() {
+ const [activeTab, setActiveTab] = useState("0");
+ const [sortedBy, setSortedBy] = useState("Most Recent");
+ const [loading, setLoading] = useState(false);
+ const dispatch = useDispatch();
+
+ // Define your tabs here
+ const tabItems = [
+ { title: "Dashboard" }, // Tab 0
+ { title: "New Applications" }, // Tab 1
+ { title: "Reviewed Applications" }, // Tab 2
+ { title: "Notifications" }, // Tab 3
+ ];
+
+ useEffect(() => {
+ const fetchData = async () => {
+ const token = localStorage.getItem("authToken");
+ if (!token) return console.error("No authentication token found!");
+
+ try {
+ setLoading(true);
+ // Fetch data logic here if needed
+ } catch (error) {
+ console.error("Error fetching data:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchData();
+ }, [dispatch]);
+
+ return (
+ <>
+
+
+
+
+
+ }
+ data={categories}
+ value={sortedBy}
+ onChange={setSortedBy}
+ placeholder="Sort By"
+ />
+
+
+
+ {/* Render content based on the active tab */}
+
+ {loading ? (
+
+
+
+ ) : (
+ <>
+ {activeTab === "0" && (
+
+ )}
+ {activeTab === "1" && (
+
+ )}
+ {activeTab === "1.1" && (
+
+ )}
+ {activeTab === "2" && }
+ {activeTab === "3" && }{" "}
+ {/* Render notifications */}
+ >
+ )}
+
+ >
+ );
+}
+
+export default DirectorMainDashboard;
diff --git a/src/Modules/Patent/components/Director/NewApplications/StatusView.jsx b/src/Modules/Patent/components/Director/NewApplications/StatusView.jsx
new file mode 100644
index 000000000..85d2c0405
--- /dev/null
+++ b/src/Modules/Patent/components/Director/NewApplications/StatusView.jsx
@@ -0,0 +1,647 @@
+import React, { useState, useEffect } from "react";
+import PropTypes from "prop-types";
+import {
+ Container,
+ Text,
+ Card,
+ Grid,
+ Button,
+ Loader,
+ Alert,
+ Title,
+ Group,
+ Textarea,
+} from "@mantine/core";
+import { ArrowLeft, DownloadSimple } from "@phosphor-icons/react";
+import "../../../style/Director/StatusView.css";
+import {
+ fetchDirectorApplicationDetails,
+ approveDirectorApplication,
+ rejectDirectorApplication,
+} from "../../../services/directorService";
+
+function FormField({ label, value }) {
+ return (
+
+ {label}
+ {value || "Not provided"}
+
+ );
+}
+
+FormField.propTypes = {
+ label: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+};
+
+function FileDownloadButton({ fileUrl, label, disabled }) {
+ if (!fileUrl || fileUrl === "null" || disabled) {
+ return (
+ }
+ disabled
+ >
+ No {label} Available
+
+ );
+ }
+
+ return (
+ }
+ >
+ View {label}
+
+ );
+}
+
+FileDownloadButton.propTypes = {
+ fileUrl: PropTypes.string,
+ label: PropTypes.string.isRequired,
+ disabled: PropTypes.bool,
+};
+
+function FormFieldWithDownload({ label, value, fileUrl, fileLabel }) {
+ return (
+
+ );
+}
+
+FormFieldWithDownload.propTypes = {
+ label: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ fileUrl: PropTypes.string,
+ fileLabel: PropTypes.string.isRequired,
+};
+
+function FormSection({ title, children }) {
+ return (
+
+ {title}
+ {children}
+
+ );
+}
+
+FormSection.propTypes = {
+ title: PropTypes.string.isRequired,
+ children: PropTypes.node.isRequired,
+};
+
+function PatentApplication() {
+ const [applicationData, setApplicationData] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [applicationId, setApplicationId] = useState(null);
+ const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
+ const [decisionComments, setDecisionComments] = useState("");
+ const handleAccept = async () => {
+ if (!decisionComments.trim()) {
+ alert("Comments are required to approve and forward the application.");
+ return;
+ }
+
+ try {
+ await approveDirectorApplication(applicationId, decisionComments.trim());
+
+ alert("Application approved successfully and sent to PCC Admin.");
+ window.history.back();
+ } catch (err) {
+ console.error("Error in approving application:", err);
+ alert(`Failed to approve: ${err.response?.data?.error || err.message}`);
+ }
+ };
+ const handleReject = async () => {
+ if (!decisionComments.trim()) {
+ alert("Comments are required to reject and send back for revision.");
+ return;
+ }
+
+ try {
+ await rejectDirectorApplication(applicationId, decisionComments.trim());
+ alert("Application sent back for revision successfully.");
+ window.history.back();
+ } catch (err) {
+ console.error("Error in Reverting application:", err);
+ alert(
+ `Failed to send back for revision: ${err.response?.data?.error || err.message}`,
+ );
+ }
+ };
+
+ useEffect(() => {
+ const handleResize = () => {
+ setIsMobile(window.innerWidth <= 768);
+ };
+ window.addEventListener("resize", handleResize);
+ return () => window.removeEventListener("resize", handleResize);
+ }, []);
+
+ useEffect(() => {
+ const storedId = localStorage.getItem("selectedApplicationId");
+ if (storedId) {
+ const idParts = storedId.split("_");
+ const numericId = idParts.length > 1 ? idParts[1] : storedId;
+ setApplicationId(numericId);
+ } else {
+ setError("No application selected - Please choose an application first");
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ const fetchApplicationDetails = async () => {
+ if (!applicationId) return;
+
+ try {
+ setLoading(true);
+ const response = await fetchDirectorApplicationDetails(applicationId);
+
+ if (response) {
+ setApplicationData(response);
+ setApplicationId(response.application_id);
+ setError(null);
+ }
+ } catch (err) {
+ console.error("Error fetching details:", err);
+ setError(
+ `Failed to load details: ${err.response?.data?.error || err.message}`,
+ );
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ if (applicationId) fetchApplicationDetails();
+ }, [applicationId]);
+
+ useEffect(() => {
+ return () => {
+ localStorage.removeItem("selectedApplicationId");
+ localStorage.removeItem("selectedApplicationToken");
+ };
+ }, []);
+
+ if (loading) {
+ return (
+
+
+ Loading application details...
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+ {error}
+
+ window.history.back()}>
+ Back to Applications
+
+
+ );
+ }
+
+ if (!applicationData) {
+ return (
+
+
+ No application data found
+
+ window.history.back()}>
+ Back to Applications
+
+
+ );
+ }
+
+ const {
+ application_id,
+ title,
+ application_number,
+ token_no,
+ primary_applicant_name,
+ attorney_name,
+ status,
+ decision_status,
+ budget_estimate,
+ budget_status,
+ comments,
+ applicants,
+ section_I,
+ section_II,
+ section_III,
+ dates,
+ last_updated_at,
+ } = applicationData;
+ const displayApplicationNumber =
+ application_number || token_no || "Not Assigned";
+
+ const formatDate = (dateString, fallbackText = "Not recorded") => {
+ if (!dateString) return fallbackText;
+ return new Date(dateString).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ });
+ };
+
+ return (
+
+ window.history.back()}
+ variant="outline"
+ color="blue"
+ leftIcon={ }
+ id="pms-new-status-director-view-back-button"
+ >
+ Back
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Submitted
+
+ {formatDate(dates?.submitted_date, "Not yet submitted")}
+
+
+
+
+
+ Forwarded to Director
+
+
+ {formatDate(
+ dates?.forwarded_to_director_date,
+ "Not yet forwarded",
+ )}
+
+
+
+
Director Approval
+
+ {formatDate(dates?.director_approval_date, "Not yet approved")}
+
+
+
+
+ Patentability Check Started
+
+
+ {formatDate(
+ dates?.patentability_check_start_date,
+ "Not started",
+ )}
+
+
+
+
+ Patentability Check Completed
+
+
+ {formatDate(
+ dates?.patentability_check_completed_date,
+ "Not completed",
+ )}
+
+
+
+
+ Search Report Generated
+
+
+ {formatDate(
+ dates?.search_report_generated_date,
+ "Not generated",
+ )}
+
+
+
+
Patent Filed
+
+ {formatDate(dates?.patent_filed_date, "Not filed")}
+
+
+
+
Patent Published
+
+ {formatDate(dates?.patent_published_date, "Not published")}
+
+
+
+
Final Decision
+
+ {formatDate(dates?.final_decision_date, "No final decision")}
+
+
+
+
Decision Date
+
+ {formatDate(dates?.decision_date, "No decision")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {applicants?.length > 0 ? (
+
+ {applicants.map((applicant, index) => (
+
+
+
+ Applicant {index + 1}
+
+
+
+
+
+
+
+
+ ))}
+
+ ) : (
+ No applicant information available
+ )}
+
+
+
+
+
+ Director Decision Comments
+
+
+
+ setDecisionComments(event.currentTarget.value)
+ }
+ mt="md"
+ />
+
+
+
+
+
+ Approve
+
+
+ Send Back for Revision
+
+
+
+
+
+
+
+ );
+}
+
+export default PatentApplication;
diff --git a/src/Modules/Patent/components/Director/NewApplications/SubmittedApplications.jsx b/src/Modules/Patent/components/Director/NewApplications/SubmittedApplications.jsx
new file mode 100644
index 000000000..1ab422d45
--- /dev/null
+++ b/src/Modules/Patent/components/Director/NewApplications/SubmittedApplications.jsx
@@ -0,0 +1,211 @@
+import React, { useState, useEffect } from "react";
+import {
+ Box,
+ Button,
+ ScrollArea,
+ Table,
+ Title,
+ Text,
+ Loader,
+ Alert,
+} from "@mantine/core";
+import { Eye, ArrowsClockwise } from "@phosphor-icons/react";
+import PropTypes from "prop-types";
+import "../../../style/Director/SubmittedApplications.css";
+import { fetchDirectorSubmittedApplications } from "../../../services/directorService";
+
+function SubmittedApplications({ setActiveTab }) {
+ const [applicationsData, setApplicationsData] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [isRefreshing, setIsRefreshing] = useState(false);
+ const authToken = localStorage.getItem("authToken");
+
+ const columnNames = [
+ "S.No.",
+ "Application ID",
+ "Application No",
+ "Patent Title",
+ "Submitted By",
+ "Department",
+ "Date-Time",
+ "Budget",
+ "Budget Status",
+ "Status",
+ "Assigned Attorney",
+ "Actions",
+ ];
+
+ const fetchApplicationData = async (showRefresh = false) => {
+ if (!authToken) {
+ setError("Authorization token is missing. Please login again.");
+ setLoading(false);
+ return;
+ }
+
+ try {
+ if (showRefresh) {
+ setIsRefreshing(true);
+ } else {
+ setLoading(true);
+ }
+
+ const response = await fetchDirectorSubmittedApplications();
+
+ const formattedData = Object.entries(response.applications).map(
+ ([key, app], index) => ({
+ id: index + 1,
+ applicationId: key,
+ tokenNumber: app.application_number || app.token_no,
+ title: app.title,
+ submitter: app.submitted_by,
+ Department: app.department,
+ date: new Date(app.forwarded_on).toLocaleString(),
+ budgetEstimate: app.budget_estimate || "Not set",
+ budgetStatus: app.budget_status || "Not Initiated",
+ status: app.current_status,
+ attorney: app.assigned_attorney,
+ }),
+ );
+
+ setApplicationsData(formattedData);
+ setError(null);
+ } catch (err) {
+ setError(err.response?.data?.message || "Failed to fetch applications");
+ console.error("Error fetching applications:", err);
+ } finally {
+ setLoading(false);
+ if (showRefresh) {
+ setIsRefreshing(false);
+ }
+ }
+ };
+
+ useEffect(() => {
+ fetchApplicationData();
+ }, [authToken]);
+
+ const handleViewDetails = (application) => {
+ localStorage.setItem("selectedApplicationId", application.applicationId);
+ localStorage.setItem("selectedApplicationToken", application.tokenNumber);
+ setActiveTab("1.1");
+ };
+
+ const handleRefresh = () => {
+ fetchApplicationData(true);
+ };
+
+ const renderApplicationsTable = () => {
+ if (loading) {
+ return (
+
+
+ Loading applications...
+
+ );
+ }
+
+ if (error) {
+ return (
+
+ {error}
+
+ );
+ }
+
+ if (applicationsData.length === 0) {
+ return (
+
+ There are no applications forwarded for review at this time.
+
+ );
+ }
+
+ return (
+
+
+
+
+ {applicationsData.map((application) => (
+
+ {application.id}
+ {application.applicationId}
+ {application.tokenNumber}
+ {application.title}
+ {application.submitter}
+ {application.Department}
+ {application.date}
+ {application.budgetEstimate}
+ {application.budgetStatus}
+ {application.status}
+ {application.attorney}
+
+ handleViewDetails(application)}
+ id="pms-director-submitted-viewButton"
+ >
+ View
+
+
+
+ ))}
+
+
+
+ );
+ };
+
+ return (
+
+ {/* Header with title */}
+
+
+ {/* Description text */}
+
+ {/* Refresh button */}
+ }
+ >
+ {isRefreshing ? "Refreshing..." : "Refresh"}
+
+
+
+
+ {renderApplicationsTable()}
+
+
+ );
+}
+
+SubmittedApplications.propTypes = {
+ setActiveTab: PropTypes.func.isRequired,
+};
+
+export default SubmittedApplications;
diff --git a/src/Modules/Patent/components/Director/Notifications/DirectorNotifications.jsx b/src/Modules/Patent/components/Director/Notifications/DirectorNotifications.jsx
new file mode 100644
index 000000000..f14907976
--- /dev/null
+++ b/src/Modules/Patent/components/Director/Notifications/DirectorNotifications.jsx
@@ -0,0 +1,226 @@
+import React, { useEffect, useState } from "react";
+import PropTypes from "prop-types";
+import { Card, Button, Text, Box, SimpleGrid } from "@mantine/core";
+import { fetchSystemNotifications } from "../../../services/pccAdminService";
+
+const styles = {
+ notificationCard: {
+ padding: "1.3rem 2rem",
+ marginBottom: "8px",
+ boxShadow: "0 3px 6px rgba(0, 0, 0, 0.10)",
+ borderRadius: "8px",
+ backgroundColor: "#fff",
+ height: "100%",
+ display: "flex",
+ flexDirection: "column",
+ borderLeft: "8px solid #3182ce",
+ },
+ notificationTitle: {
+ fontSize: "20px",
+ fontWeight: 500,
+ marginBottom: "2.2px",
+ lineHeight: 1.2,
+ },
+ notificationStatus: {
+ fontSize: "0.97rem",
+ fontWeight: 500,
+ marginBottom: "10px",
+ lineHeight: 1.2,
+ },
+ notificationToken: {
+ fontSize: "0.83rem",
+ color: "#666",
+ marginBottom: "5px",
+ lineHeight: 1.2,
+ },
+ notificationDate: {
+ fontSize: "0.83rem",
+ color: "#666",
+ marginBottom: "10px",
+ lineHeight: 1.2,
+ },
+ notificationDescription: {
+ fontSize: "0.83rem",
+ color: "#444",
+ padding: "0",
+ flex: 1,
+ marginBottom: "8px",
+ lineHeight: 1.25,
+ },
+ notificationActions: {
+ display: "flex",
+ justifyContent: "flex-end",
+ flexWrap: "wrap",
+ gap: "0.4rem",
+ marginTop: "0.3rem",
+ },
+ actionButton: {
+ flex: "1",
+ minWidth: "200px",
+ fontWeight: "500",
+ fontSize: "0.9rem",
+ padding: "10px 0",
+ height: "35px",
+ backgroundColor: "#fff",
+ color: "#0073e6",
+ border: "1px solid #0073e6",
+ transition: "background 0.18s, color 0.18s",
+ cursor: "pointer",
+ },
+ actionButtonHover: {
+ backgroundColor: "#0073e6",
+ color: "#fff",
+ border: "1px solid #0073e6",
+ },
+ pageTitle: {
+ fontSize: "24px",
+ marginTop: "-6px",
+ fontWeight: 600,
+ marginBottom: "8px",
+ color: "#1a1b1e",
+ lineHeight: 1.2,
+ },
+ container: {
+ width: "100%",
+ padding: "0",
+ maxWidth: "1800px",
+ margin: "0 50px",
+ },
+};
+
+function NotificationCard({
+ id,
+ token,
+ title,
+ status,
+ description,
+ date,
+ time,
+ color,
+ onMarkAsRead,
+ isRead,
+}) {
+ const [hover, setHover] = useState(false);
+
+ const getStatusColor = () => color || "#3182ce";
+ const buttonStyle = {
+ ...styles.actionButton,
+ ...(hover ? styles.actionButtonHover : {}),
+ ...(isRead && {
+ backgroundColor: "#f3f3f3",
+ color: "#888",
+ border: "1px solid #ddd",
+ }),
+ };
+
+ return (
+
+ {title}
+
+ {status}
+
+ {token}
+ {`${date} | ${time}`}
+ {description}
+
+ onMarkAsRead(id)}
+ onMouseEnter={() => setHover(true)}
+ onMouseLeave={() => setHover(false)}
+ >
+ {isRead ? "Remove Notification" : "Mark as Read"}
+
+
+
+ );
+}
+
+NotificationCard.propTypes = {
+ id: PropTypes.number.isRequired,
+ token: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ status: PropTypes.string.isRequired,
+ description: PropTypes.string.isRequired,
+ date: PropTypes.string.isRequired,
+ time: PropTypes.string.isRequired,
+ color: PropTypes.string,
+ onMarkAsRead: PropTypes.func.isRequired,
+ isRead: PropTypes.bool.isRequired,
+};
+
+function DirectorNotifications() {
+ const [notifications, setNotifications] = useState([]);
+ const [readNotifications, setReadNotifications] = useState([]);
+
+ useEffect(() => {
+ const load = async () => {
+ try {
+ const data = await fetchSystemNotifications("Director");
+ const mapped = (data || []).map((item) => {
+ const created = item.created_at
+ ? new Date(item.created_at)
+ : new Date();
+ return {
+ id: item.id,
+ token: item.application
+ ? `Application #${item.application}`
+ : "General",
+ title: item.event_type,
+ status: item.is_escalated ? "Escalated" : "Active",
+ description: item.message,
+ date: created.toLocaleDateString(),
+ time: created.toLocaleTimeString(),
+ color: item.is_escalated ? "#c53030" : "#3182ce",
+ };
+ });
+ setNotifications(mapped);
+ } catch (error) {
+ console.error("Failed to fetch director notifications", error);
+ }
+ };
+
+ load();
+ }, []);
+
+ const handleMarkAsRead = (id) => {
+ if (readNotifications.includes(id)) {
+ setNotifications(notifications.filter((n) => n.id !== id));
+ setReadNotifications(readNotifications.filter((readId) => readId !== id));
+ } else {
+ setReadNotifications([...readNotifications, id]);
+ }
+ };
+
+ return (
+
+ Notifications
+
+
+ {notifications.map((notification) => (
+
+ ))}
+
+
+
+ );
+}
+
+export default DirectorNotifications;
diff --git a/src/Modules/Patent/components/Director/ReviewedApplications/RecentsView.jsx b/src/Modules/Patent/components/Director/ReviewedApplications/RecentsView.jsx
new file mode 100644
index 000000000..58921736a
--- /dev/null
+++ b/src/Modules/Patent/components/Director/ReviewedApplications/RecentsView.jsx
@@ -0,0 +1,201 @@
+import React, { useEffect, useState } from "react";
+import {
+ Box,
+ ScrollArea,
+ Table,
+ Title,
+ Text,
+ Loader,
+ Alert,
+ Button,
+} from "@mantine/core";
+import { ArrowsClockwise } from "@phosphor-icons/react";
+import "../../../style/Director/RecentsView.css";
+import { fetchDirectorReviewedApplications } from "../../../services/directorService";
+
+function ReviewedApplications() {
+ const [applicationsData, setApplicationsData] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [isRefreshing, setIsRefreshing] = useState(false);
+ const authToken = localStorage.getItem("authToken");
+
+ const columnNames = [
+ "S.No.",
+ "Application ID",
+ "Application No",
+ "Patent Title",
+ "Submitted By",
+ "Department",
+ "Arrival Date",
+ "Reviewed Date",
+ "Budget",
+ "Budget Status",
+ "Assigned Attorney",
+ "Current Status",
+ ];
+
+ const fetchReviewedApplications = async (showRefresh = false) => {
+ if (!authToken) {
+ setError("Authorization token is missing. Please login again.");
+ setLoading(false);
+ return;
+ }
+
+ try {
+ if (showRefresh) {
+ setIsRefreshing(true);
+ } else {
+ setLoading(true);
+ }
+
+ const response = await fetchDirectorReviewedApplications();
+
+ const formattedData = Object.entries(response.applications).map(
+ ([key, app], index) => ({
+ id: index + 1,
+ applicationId: key,
+ tokenNumber: app.application_number || app.token_no,
+ title: app.title,
+ submitter: app.submitted_by,
+ department: app.department,
+ arrivalDate: new Date(app.arrival_date).toLocaleDateString(),
+ reviewedDate: app.reviewed_date
+ ? new Date(app.reviewed_date).toLocaleDateString()
+ : "N/A",
+ budgetEstimate: app.budget_estimate || "Not set",
+ budgetStatus: app.budget_status || "Not Initiated",
+ assignedAttorney: app.assigned_attorney,
+ currentStatus: app.current_status,
+ }),
+ );
+
+ setApplicationsData(formattedData);
+ setError(null);
+ } catch (err) {
+ setError(
+ err.response?.data?.message || "Failed to fetch reviewed applications",
+ );
+ console.error("Error fetching applications:", err);
+ } finally {
+ setLoading(false);
+ if (showRefresh) {
+ setIsRefreshing(false);
+ }
+ }
+ };
+
+ useEffect(() => {
+ fetchReviewedApplications();
+ }, [authToken]);
+
+ const handleRefresh = () => {
+ fetchReviewedApplications(true);
+ };
+
+ const renderApplicationsTable = () => {
+ if (loading) {
+ return (
+
+
+ Loading reviewed applications...
+
+ );
+ }
+
+ if (error) {
+ return (
+
+ {error}
+
+ );
+ }
+
+ if (applicationsData.length === 0) {
+ return (
+
+ There are no reviewed applications at this time.
+
+ );
+ }
+
+ return (
+
+
+
+
+ {applicationsData.map((item) => (
+
+ {item.id}
+ {item.applicationId}
+ {item.tokenNumber}
+ {item.title}
+ {item.submitter}
+ {item.department}
+ {item.arrivalDate}
+ {item.reviewedDate}
+ {item.budgetEstimate}
+ {item.budgetStatus}
+ {item.assignedAttorney}
+
+
+ {item.currentStatus}
+
+
+
+ ))}
+
+
+
+ );
+ };
+
+ return (
+
+ {/* Header with title */}
+
+
+ {/* Description text */}
+
+ {/* Refresh button */}
+ }
+ >
+ {isRefreshing ? "Refreshing..." : "Refresh"}
+
+
+
+ {renderApplicationsTable()}
+
+ );
+}
+
+export default ReviewedApplications;
diff --git a/src/Modules/Patent/components/PCCAdmin/Dashboard/DownloadsPage.jsx b/src/Modules/Patent/components/PCCAdmin/Dashboard/DownloadsPage.jsx
new file mode 100644
index 000000000..337dc7582
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/Dashboard/DownloadsPage.jsx
@@ -0,0 +1,165 @@
+import React, { useEffect, useState } from "react";
+import {
+ Button,
+ Container,
+ Text,
+ TextInput,
+ Group,
+ LoadingOverlay,
+} from "@mantine/core";
+import { ArrowCircleDown, Plus, Trash } from "@phosphor-icons/react";
+import "../../../style/Pcc_Admin/DownloadsPage.css";
+import {
+ fetchDocuments,
+ addDocument,
+ deleteDocument,
+} from "../../../services/documentService.jsx";
+
+function DownloadsPage() {
+ const [downloadsData, setDownloadsData] = useState([]);
+ const [newDocument, setNewDocument] = useState({
+ title: "",
+ link: "",
+ });
+ const [loading, setLoading] = useState(false);
+
+ const loadDocuments = async () => {
+ setLoading(true);
+ try {
+ const data = await fetchDocuments();
+ setDownloadsData(data);
+ } catch (error) {
+ console.error("Error fetching documents:", error);
+ alert("Failed to load documents");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const handleAddDocument = async () => {
+ if (!newDocument.title || !newDocument.link) {
+ alert("Please fill in both title and link fields");
+ return;
+ }
+
+ try {
+ const created = await addDocument(newDocument);
+ setDownloadsData((prev) => [created, ...prev]);
+ setNewDocument({ title: "", link: "" });
+ } catch (error) {
+ console.error("Error adding document:", error);
+ alert("Failed to add document");
+ }
+ };
+
+ const handleDeleteDocument = async (id) => {
+ try {
+ await deleteDocument(id);
+ setDownloadsData((prev) => prev.filter((doc) => doc.id !== id));
+ } catch (error) {
+ console.error("Error deleting document:", error);
+ alert("Failed to delete document");
+ }
+ };
+
+ useEffect(() => {
+ loadDocuments();
+ }, []);
+
+ return (
+
+
+
+
+ Download Forms and Documents
+
+
+ You can review the document title and click the "Download" button to
+ access the desired file.
+
+
+ {/* Add Document Form */}
+
+ Add New Document
+
+
+ setNewDocument({ ...newDocument, title: e.target.value })
+ }
+ style={{ flex: 2 }}
+ />
+
+ setNewDocument({ ...newDocument, link: e.target.value })
+ }
+ style={{ flex: 3 }}
+ />
+ }
+ id="pms-pcc-add-document-button"
+ >
+ Add
+
+
+
+
+
+
+
+
+ S.No.
+ Document Title
+ Download
+ Action
+
+
+
+ {downloadsData.map((download, index) => (
+
+ {index + 1}
+ {download.title}
+
+
+
+ Download
+
+
+
+ handleDeleteDocument(download.id)}
+ fullWidth
+ id="pms-pcc-delete-button"
+ >
+
+
+
+
+ ))}
+
+
+
+
+ );
+}
+
+export default DownloadsPage;
diff --git a/src/Modules/Patent/components/PCCAdmin/Dashboard/InsightsPage.jsx b/src/Modules/Patent/components/PCCAdmin/Dashboard/InsightsPage.jsx
new file mode 100644
index 000000000..60a8acefc
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/Dashboard/InsightsPage.jsx
@@ -0,0 +1,188 @@
+import React, { useEffect, useMemo, useState } from "react";
+import PropTypes from "prop-types";
+import { Table, Select, Text, Container } from "@mantine/core";
+import "../../../style/Pcc_Admin/InsightsPage.css";
+import { fetchPccInsightsReport } from "../../../services/pccAdminService";
+
+function InsightsPage({ fetchInsightsReport = fetchPccInsightsReport }) {
+ InsightsPage.propTypes = {
+ fetchInsightsReport: PropTypes.func,
+ };
+ const [selectedYear, setSelectedYear] = useState(null);
+ const [yearOptions, setYearOptions] = useState([]);
+ const [applications, setApplications] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState("");
+
+ const totalApplications = useMemo(
+ () => applications.reduce((sum, app) => sum + app.count, 0),
+ [applications],
+ );
+
+ useEffect(() => {
+ const loadInsights = async () => {
+ try {
+ setLoading(true);
+ setError("");
+ const data = await fetchInsightsReport(selectedYear);
+ setApplications(data.applications || []);
+
+ const options = (data.available_years || []).map((year) =>
+ String(year),
+ );
+ setYearOptions(options);
+
+ const resolvedYear = String(data.selected_year);
+ setSelectedYear(resolvedYear);
+ } catch (err) {
+ setError("Unable to load insights right now.");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ loadInsights();
+ }, [selectedYear, fetchInsightsReport]);
+
+ return (
+
+
+ Applications Overview - {selectedYear}
+
+
+ Select a year from the dropdown below to view the statistics of
+ applications for that year.
+
+
+
+
+ Select Year:
+
+
+
+
+ {error && (
+
+ {error}
+
+ )}
+
+ {loading ? (
+ Loading insights...
+ ) : (
+
+
+
+ {
+ applications.reduce(
+ (acc, app, index) => {
+ const { startAngle } = acc;
+ const sweepAngle = totalApplications
+ ? (app.count / totalApplications) * 360
+ : 0;
+ const endAngle = startAngle + sweepAngle;
+
+ const largeArcFlag = sweepAngle > 180 ? 1 : 0;
+ const [startX, startY] = [
+ 50 + 40 * Math.cos((Math.PI * startAngle) / 180),
+ 50 + 40 * Math.sin((Math.PI * startAngle) / 180),
+ ];
+ const [endX, endY] = [
+ 50 + 40 * Math.cos((Math.PI * endAngle) / 180),
+ 50 + 40 * Math.sin((Math.PI * endAngle) / 180),
+ ];
+
+ const midAngle = startAngle + sweepAngle / 2;
+ const [textX, textY] = [
+ 50 + 25 * Math.cos((Math.PI * midAngle) / 180),
+ 50 + 25 * Math.sin((Math.PI * midAngle) / 180),
+ ];
+
+ acc.slices.push(
+
+
+
+ {totalApplications
+ ? `${((app.count / totalApplications) * 100).toFixed(1)}%`
+ : "0.0%"}
+
+ ,
+ );
+
+ acc.startAngle = endAngle;
+ return acc;
+ },
+ { slices: [], startAngle: 0 },
+ ).slices
+ }
+
+
+
+ {applications.map((app, index) => (
+
+ ))}
+
+
+
+
+
+ Applications Data
+
+
+
+
+ Status
+ Count
+ Percentage
+
+
+
+ {applications.map((app, index) => (
+
+ {app.label}
+ {app.count}
+
+ {totalApplications
+ ? `${((app.count / totalApplications) * 100).toFixed(2)}%`
+ : "0.00%"}
+
+
+ ))}
+
+
+
+
+ )}
+
+ );
+}
+
+export default InsightsPage;
diff --git a/src/Modules/Patent/components/PCCAdmin/Dashboard/PCCAdminDashboard.jsx b/src/Modules/Patent/components/PCCAdmin/Dashboard/PCCAdminDashboard.jsx
new file mode 100644
index 000000000..f40d92508
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/Dashboard/PCCAdminDashboard.jsx
@@ -0,0 +1,133 @@
+import React from "react";
+import PropTypes from "prop-types";
+import { Grid, Box, Text, Divider, Button, Paper } from "@mantine/core";
+import {
+ Eye,
+ List,
+ Briefcase,
+ ArrowCircleDown,
+ Buildings,
+} from "@phosphor-icons/react";
+import "../../../style/Pcc_Admin/PCCAdminDashboard.css";
+import InsightsPage from "./InsightsPage";
+
+function PCCAdminDashboard({ setActiveTab }) {
+ const renderDashboardCard = (icon, title, description, tabId) => (
+
+
+ {icon} {title}
+
+
+
+ {description}
+
+ setActiveTab(tabId)}
+ >
+ {title}
+
+
+ );
+
+ return (
+
+ {/* Page Title */}
+
+ Patent & Copyright Cell Dashboard
+
+
+ {/* Combined Overview and Insights Section */}
+
+ {/* Overview Section */}
+
+
+ Patent Management System (PMS)
+
+
+
+ The Patent Management System at IIITDM Jabalpur focuses on fostering
+ research and development activities, particularly in IT-enabled
+ design and manufacturing, as well as the design of IT systems. Here,
+ you can manage applications, track their status, access important
+ resources and view insights.
+
+
+
+
+
+ {/* Insights Section */}
+
+
+
+
+
+
+
+ {/* Dashboard Cards Section */}
+
+ {/* New Applications Card */}
+
+ {renderDashboardCard(
+ ,
+ "New Applications",
+ "Review and provide feedback on the latest applications.",
+ "1",
+ )}
+
+
+ {/* Ongoing Applications Card */}
+
+ {renderDashboardCard(
+
,
+ "Ongoing Applications",
+ "Track the current status of all the ongoing applications.",
+ "2",
+ )}
+
+
+ {/* Past Applications Card */}
+
+ {renderDashboardCard(
+ ,
+ "Past Applications",
+ "Track record of all the filed and reeted applications.",
+ "3",
+ )}
+
+
+ {/* Manage Attorney Details Card */}
+
+ {renderDashboardCard(
+ ,
+ "Manage Attorney Details",
+ "Manage and update attorney information.",
+ "4",
+ )}
+
+
+ {/* Notifications Card */}
+
+ {renderDashboardCard(
+ ,
+ "Notifications",
+ "Get notifications regarding status updates and other important information.",
+ "5",
+ )}
+
+
+
+ );
+}
+
+PCCAdminDashboard.propTypes = {
+ setActiveTab: PropTypes.func.isRequired,
+};
+
+export default PCCAdminDashboard;
diff --git a/src/Modules/Patent/components/PCCAdmin/ManageAttorney/AddNewAttorneyForm.jsx b/src/Modules/Patent/components/PCCAdmin/ManageAttorney/AddNewAttorneyForm.jsx
new file mode 100644
index 000000000..48f1f4555
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/ManageAttorney/AddNewAttorneyForm.jsx
@@ -0,0 +1,127 @@
+import React, { useState } from "react";
+import { TextInput, Button, Title } from "@mantine/core";
+import {
+ UserCircle,
+ Briefcase,
+ Envelope,
+ Phone,
+ ArrowLeft,
+} from "@phosphor-icons/react";
+import PropTypes from "prop-types";
+import "../../../style/Pcc_Admin/NewAttorneyForm.css";
+
+function NewAttorneyForm({ onSubmit, onBack }) {
+ const [formData, setFormData] = useState({
+ name: "",
+ email: "",
+ phone: "",
+ firm_name: "",
+ });
+
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData({ ...formData, [name]: value });
+ };
+
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ onSubmit(formData);
+ };
+
+ return (
+
+ );
+}
+
+NewAttorneyForm.propTypes = {
+ onSubmit: PropTypes.func.isRequired,
+ onBack: PropTypes.func.isRequired,
+};
+
+export default NewAttorneyForm;
diff --git a/src/Modules/Patent/components/PCCAdmin/ManageAttorney/AttorneyDetailsForm.jsx b/src/Modules/Patent/components/PCCAdmin/ManageAttorney/AttorneyDetailsForm.jsx
new file mode 100644
index 000000000..2fe9e0820
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/ManageAttorney/AttorneyDetailsForm.jsx
@@ -0,0 +1,263 @@
+import React, { useState, useEffect } from "react";
+import PropTypes from "prop-types";
+import {
+ Text,
+ Box,
+ Tooltip,
+ Button,
+ TextInput,
+ LoadingOverlay,
+} from "@mantine/core";
+import {
+ EnvelopeSimple,
+ Phone,
+ Briefcase,
+ PencilSimple,
+ Check,
+ X,
+ CaretLeft,
+} from "@phosphor-icons/react";
+import { attorneyService } from "../../../services/attorneyService";
+import "../../../style/Pcc_Admin/AttorneyForm.css";
+
+function AttorneyForm({ attorneyId, onBack }) {
+ const [isEditing, setIsEditing] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+ const [attorney, setAttorney] = useState(null);
+ const [updatedData, setUpdatedData] = useState({});
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ const fetchAttorneyDetails = async () => {
+ if (!attorneyId) {
+ setError("No attorney selected");
+ return;
+ }
+
+ try {
+ setIsLoading(true);
+ const data = await attorneyService.getAttorneyDetails(attorneyId);
+ console.log("Received attorney data:", data);
+ setAttorney(data);
+ setUpdatedData({
+ name: data.name,
+ email: data.email,
+ phone: data.phone,
+ firm_name: data.firm_name,
+ });
+ setError(null);
+ } catch (err) {
+ setError(err.message || "Failed to fetch attorney details");
+ console.error("Error details:", err);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ fetchAttorneyDetails();
+ }, [attorneyId]);
+
+ const handleInputChange = (e) => {
+ const { name, value } = e.target;
+ setUpdatedData({ ...updatedData, [name]: value });
+ };
+
+ const handleEditSubmit = async () => {
+ try {
+ setIsLoading(true);
+ await attorneyService.updateAttorney(attorneyId, updatedData);
+ const updatedDetails =
+ await attorneyService.getAttorneyDetails(attorneyId);
+ setAttorney(updatedDetails);
+ setIsEditing(false);
+ } catch (err) {
+ setError("Failed to update attorney details");
+ console.error(err);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const handleCancel = () => {
+ setUpdatedData({
+ name: attorney.name,
+ email: attorney.email,
+ phone: attorney.phone,
+ firm_name: attorney.firm_name,
+ });
+ setIsEditing(false);
+ };
+
+ if (isLoading) {
+ return ;
+ }
+
+ if (error) {
+ return {error} ;
+ }
+
+ if (!attorney) {
+ return Attorney not found ;
+ }
+
+ return (
+
+ {/* Header with Back and Edit Buttons */}
+
+
}
+ onClick={onBack}
+ id="pms-pcc-attorney-back-btn"
+ >
+ Back
+
+ {isEditing ? (
+
+ }
+ onClick={handleEditSubmit}
+ id="pms-pcc-save-button"
+ >
+ Save Changes
+
+ }
+ onClick={handleCancel}
+ id="pms-pcc-cancel-button"
+ >
+ Cancel
+
+
+ ) : (
+
}
+ onClick={() => setIsEditing(true)}
+ id="pms-pcc-edit-details-button"
+ >
+ Edit Details
+
+ )}
+
+
+ {/* Attorney Details Grid */}
+
+
+
+ {isEditing ? (
+
+ ) : (
+
+
+ Name: {attorney.name}
+
+ )}
+
+
+
+
+
+ {isEditing ? (
+
+ ) : (
+
+
+ Email: {attorney.email}
+
+ )}
+
+
+
+
+
+ {isEditing ? (
+
+ ) : (
+
+
+ Phone: {attorney.phone || "Not Available"}
+
+ )}
+
+
+
+
+
+ {isEditing ? (
+
+ ) : (
+
+
+ Law Firm: {" "}
+ {attorney.firm_name || "Not Available"}
+
+ )}
+
+
+
+ {/* Assigned Cases Section - Full Width */}
+
+
+
+ Assigned Cases: {" "}
+ {attorney.assigned_applications_count || 0}
+
+ {attorney.applications && attorney.applications.length > 0 ? (
+
+ {attorney.applications.map((app) => (
+
+
+ Application {app.id}: {app.title}
+
+
+ ))}
+
+ ) : (
+
+ No applications assigned
+
+ )}
+
+
+
+ );
+}
+
+AttorneyForm.propTypes = {
+ attorneyId: PropTypes.number.isRequired,
+ onBack: PropTypes.func.isRequired,
+};
+
+export default AttorneyForm;
diff --git a/src/Modules/Patent/components/PCCAdmin/ManageAttorney/ManageAttorneys.jsx b/src/Modules/Patent/components/PCCAdmin/ManageAttorney/ManageAttorneys.jsx
new file mode 100644
index 000000000..040f4a31c
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/ManageAttorney/ManageAttorneys.jsx
@@ -0,0 +1,259 @@
+import React, { useState, useEffect } from "react";
+import {
+ Button,
+ ScrollArea,
+ Table,
+ Text,
+ Container,
+ Paper,
+ LoadingOverlay,
+} from "@mantine/core";
+import AttorneyForm from "./AttorneyDetailsForm.jsx";
+import NewAttorneyForm from "./AddNewAttorneyForm.jsx";
+import "../../../style/Pcc_Admin/ManageAttorneys.css";
+import { attorneyService } from "../../../services/attorneyService.jsx";
+
+function ManageAttorneys() {
+ const [attorneys, setAttorneys] = useState([]);
+ const [selectedAttorney, setSelectedAttorney] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [isRemovalMode, setIsRemovalMode] = useState(false);
+ const [selectedRows, setSelectedRows] = useState(new Set());
+ const [isAddingNewAttorney, setIsAddingNewAttorney] = useState(false);
+
+ const fetchAttorneys = async () => {
+ try {
+ setIsLoading(true);
+ const data = await attorneyService.getAttorneys();
+ setAttorneys(data);
+ setError(null);
+ } catch (err) {
+ if (err.message.includes("Authentication failed")) {
+ setError("Please log in to view attorneys");
+ } else if (err.message.includes("API endpoint not found")) {
+ setError("Server configuration error. Please contact support.");
+ } else if (err.message.includes("Network Error")) {
+ setError(
+ "Unable to connect to the server. Please check your internet connection.",
+ );
+ } else {
+ setError(
+ err.message || "Failed to fetch attorneys. Please try again later.",
+ );
+ }
+ console.error("Error details:", err);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ fetchAttorneys();
+ }, []);
+
+ const handleViewDetails = (attorney) => {
+ setSelectedAttorney(attorney);
+ setIsAddingNewAttorney(false);
+ };
+
+ const handleBackToList = async () => {
+ setSelectedAttorney(null);
+ setIsAddingNewAttorney(false);
+ await fetchAttorneys(); // 💡 Fetch updated data
+ };
+
+ const handleAddAttorney = async (newAttorney) => {
+ try {
+ setIsLoading(true);
+ await attorneyService.addAttorney(newAttorney);
+ await fetchAttorneys(); // Refresh the list after adding
+ setIsAddingNewAttorney(false); // Close the form
+ setError(null);
+ } catch (err) {
+ setError(`Failed to add attorney: ${err.message || "Unknown error"}`);
+ console.error("Error adding attorney:", err);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const handleAddNewClick = () => {
+ setIsAddingNewAttorney(true);
+ setSelectedAttorney(null);
+ };
+
+ const handleRemoveAttorneys = async () => {
+ try {
+ setIsLoading(true);
+ const removalPromises = Array.from(selectedRows).map((id) =>
+ attorneyService.removeAttorney(id),
+ );
+ await Promise.all(removalPromises);
+ await fetchAttorneys();
+ setSelectedRows(new Set());
+ setIsRemovalMode(false);
+ } catch (err) {
+ setError("Failed to remove attorneys");
+ console.error(err);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const toggleRemovalMode = () => {
+ setIsRemovalMode(!isRemovalMode);
+ if (!isRemovalMode) {
+ setSelectedRows(new Set());
+ }
+ };
+
+ const handleRowSelect = (id) => {
+ const newSelectedRows = new Set(selectedRows);
+ if (newSelectedRows.has(id)) {
+ newSelectedRows.delete(id);
+ } else {
+ newSelectedRows.add(id);
+ }
+ setSelectedRows(newSelectedRows);
+ };
+
+ if (isLoading) {
+ return ;
+ }
+
+ if (error) {
+ return {error} ;
+ }
+
+ if (selectedAttorney) {
+ return (
+
+ );
+ }
+
+ if (isAddingNewAttorney) {
+ return (
+
+ );
+ }
+
+ return (
+
+ {!selectedAttorney ? (
+ <>
+ Manage Attorney Details
+
+ {/* Action Buttons */}
+
+
+ + Add New Attorney
+
+
+
+ {isRemovalMode ? "Cancel Remove" : "Remove Attorney"}
+
+
+
+
+
+
+
+
+
+ {/* Remove Selected Button */}
+ {isRemovalMode && selectedRows.size > 0 && (
+
+ Remove Selected ({selectedRows.size})
+
+ )}
+ >
+ ) : (
+ // Detailed view of selected attorney
+
+ )}
+
+ );
+}
+
+export default ManageAttorneys;
diff --git a/src/Modules/Patent/components/PCCAdmin/NewApplication/NewApplicaion.jsx b/src/Modules/Patent/components/PCCAdmin/NewApplication/NewApplicaion.jsx
new file mode 100644
index 000000000..4a19106df
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/NewApplication/NewApplicaion.jsx
@@ -0,0 +1,330 @@
+import React, { useState, useEffect } from "react";
+import { Box, Button, Table, Text, Loader, Alert, Group } from "@mantine/core";
+import { Eye, ArrowsClockwise } from "@phosphor-icons/react";
+import ViewNewApplication from "./ViewNewApplication";
+import { fetchPccNewApplications } from "../../../services/pccAdminService";
+
+function NewApplication() {
+ const [selectedApplicationId, setSelectedApplicationId] = useState(null);
+ const [applications, setApplications] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [isRefreshing, setIsRefreshing] = useState(false);
+
+ const columnNames = [
+ "S.No.",
+ "Application Number",
+ "Application No",
+ "Patent Title",
+ "Inventor 1",
+ "Designation",
+ "Department",
+ "Date",
+ "Actions",
+ ];
+
+ // Assign percent widths to each column (total 100%)
+ const columnPercents = [
+ "5%", // S.No.
+ "12%", // Application Number
+ "10%", // Token Number
+ "22%", // Patent Title
+ "11%", // Inventor 1
+ "10%", // Designation
+ "10%", // Department
+ "10%", // Date
+ "10%", // Actions
+ ];
+
+ const fetchApplications = async (showRefresh = false) => {
+ try {
+ if (showRefresh) {
+ setIsRefreshing(true);
+ } else {
+ setLoading(true);
+ }
+ const response = await fetchPccNewApplications();
+ const applicationsArray = Object.entries(response.applications).map(
+ ([appId, appData]) => ({
+ id: appId,
+ token_no:
+ appData.application_number || appData.token_no || "Not Assigned",
+ ...appData,
+ }),
+ );
+ setApplications(applicationsArray);
+ setError(null);
+ } catch (err) {
+ setError(
+ err.response?.data?.message ||
+ "Unable to fetch applications. Please try again later.",
+ );
+ } finally {
+ setLoading(false);
+ if (showRefresh) {
+ setIsRefreshing(false);
+ }
+ }
+ };
+
+ useEffect(() => {
+ fetchApplications();
+ }, []);
+
+ const handleViewClick = (applicationId) => {
+ setSelectedApplicationId(applicationId);
+ };
+
+ const handleBackClick = () => {
+ setSelectedApplicationId(null);
+ };
+
+ const handleRefresh = () => {
+ fetchApplications(true);
+ };
+
+ const renderApplicationsTable = () => {
+ if (loading) {
+ return (
+
+
+ Loading applications...
+
+ );
+ }
+
+ if (error) {
+ return (
+
+ {error}
+
+ );
+ }
+
+ if (applications.length === 0) {
+ return (
+
+ There are no new applications to review at this time.
+
+ );
+ }
+
+ return (
+
+
+
+ {columnNames.map((col, idx) => (
+
+ {col}
+
+ ))}
+
+
+
+ {applications.map((application, index) => (
+
+
+ {index + 1}
+
+
+ {application.id}
+
+
+ {application.token_no || "Not Assigned"}
+
+
+ {application.title}
+
+
+ {application.submitted_by}
+
+
+ {application.designation}
+
+
+ {application.department}
+
+
+ {application.submitted_on}
+
+
+
+ handleViewClick(application.id)}
+ >
+
+ View
+
+
+
+
+ ))}
+
+
+ );
+ };
+
+ return (
+
+ {!selectedApplicationId ? (
+ <>
+
+ New Applications
+
+
+
+
+ }
+ >
+ {isRefreshing ? "Refreshing..." : "Refresh"}
+
+
+
+
+ {renderApplicationsTable()}
+
+ >
+ ) : (
+
+ )}
+
+ );
+}
+
+export default NewApplication;
diff --git a/src/Modules/Patent/components/PCCAdmin/NewApplication/ViewNewApplication.jsx b/src/Modules/Patent/components/PCCAdmin/NewApplication/ViewNewApplication.jsx
new file mode 100644
index 000000000..0e4732b35
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/NewApplication/ViewNewApplication.jsx
@@ -0,0 +1,1165 @@
+import React, { useState, useEffect } from "react";
+import PropTypes from "prop-types";
+import {
+ Container,
+ Text,
+ Card,
+ Grid,
+ Button,
+ Loader,
+ Alert,
+ Title,
+ Select,
+ NumberInput,
+ Textarea,
+ Modal,
+ Group,
+ ActionIcon,
+ Box,
+} from "@mantine/core";
+import { ArrowLeft, Download } from "@phosphor-icons/react"; // Changed DownloadSimple to Download
+import "../../../style/Pcc_Admin/ViewNewApplication.css";
+import { API_BASE_URL } from "../../../services/api";
+import {
+ fetchPccApplicationDetails,
+ fetchPccAttorneys,
+ fetchPccDirectors,
+ reviewPccApplication,
+ forwardPccApplicationToDirector,
+ requestPccApplicationModification,
+} from "../../../services/pccAdminService";
+
+// Field component for detail view
+function FormField({ label, value }) {
+ return (
+
+ {label}
+ {value || "Not provided"}
+
+ );
+}
+
+FormField.propTypes = {
+ label: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+};
+
+// Field with download button for direct file URLs
+function FormFieldWithDownload({ label, value, fileUrl, fileLabel }) {
+ return (
+
+ );
+}
+
+FormFieldWithDownload.propTypes = {
+ label: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ fileUrl: PropTypes.string,
+ fileLabel: PropTypes.string.isRequired,
+};
+
+// File Download Button Component
+function FileDownloadButton({ fileUrl, label, disabled }) {
+ if (!fileUrl || fileUrl === "null" || disabled) {
+ return (
+ } // Changed from DownloadSimple to Download
+ disabled
+ >
+ No {label} Available
+
+ );
+ }
+
+ return (
+ } // Changed from DownloadSimple to Download
+ >
+ View {label}
+
+ );
+}
+
+FileDownloadButton.propTypes = {
+ fileUrl: PropTypes.string,
+ label: PropTypes.string.isRequired,
+ disabled: PropTypes.bool,
+};
+
+// Section component for detail view
+function FormSection({ title, children }) {
+ return (
+
+ {title}
+ {children}
+
+ );
+}
+
+FormSection.propTypes = {
+ title: PropTypes.string.isRequired,
+ children: PropTypes.node.isRequired,
+};
+
+function ViewNewApplication({ applicationId, handleBackToList }) {
+ const [selectedApplication, setSelectedApplication] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
+ const [attorneys, setAttorneys] = useState([]);
+ const [directors, setDirectors] = useState([]);
+ const [selectedAttorneyId, setSelectedAttorneyId] = useState("");
+ const [selectedDirectorId, setSelectedDirectorId] = useState("");
+ const [budgetEstimate, setBudgetEstimate] = useState("");
+ const [comments, setComments] = useState("");
+ const [actionLoading, setActionLoading] = useState(false);
+ const [actionSuccess, setActionSuccess] = useState(null);
+ const [actionError, setActionError] = useState(null);
+ const [commentError, setCommentError] = useState(null);
+
+ // Modal states
+ const [forwardModalOpen, setForwardModalOpen] = useState(false);
+ const [modificationModalOpen, setModificationModalOpen] = useState(false);
+
+ const authToken = localStorage.getItem("authToken");
+
+ const extractApiError = (err, fallback) => {
+ const responseData = err?.response?.data;
+ return (
+ responseData?.error || responseData?.message || err?.message || fallback
+ );
+ };
+
+ useEffect(() => {
+ const handleResize = () => {
+ setIsMobile(window.innerWidth <= 768);
+ };
+
+ window.addEventListener("resize", handleResize);
+ return () => window.removeEventListener("resize", handleResize);
+ }, []);
+
+ // Fetch application details
+ useEffect(() => {
+ const fetchApplicationDetails = async () => {
+ if (!applicationId) {
+ setError("No application ID provided");
+ setLoading(false);
+ return;
+ }
+
+ try {
+ setLoading(true);
+ const response = await fetchPccApplicationDetails(applicationId);
+
+ if (response) {
+ setSelectedApplication(response);
+ setComments(response.comments || "");
+ setError(null);
+ } else {
+ setError("No application data found");
+ }
+ } catch (err) {
+ console.error("Error fetching application details:", err);
+ setError(`Failed to load application details: ${err.message}`);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchApplicationDetails();
+ }, [applicationId, authToken]);
+
+ // Fetch attorneys list for the dropdown
+ useEffect(() => {
+ const fetchAttorneys = async () => {
+ try {
+ const response = await fetchPccAttorneys();
+
+ if (response) {
+ // Transform data for select dropdown
+ const attorneyOptions = response.map((attorney) => ({
+ value: attorney.id.toString(),
+ label: attorney.name,
+ }));
+ setAttorneys(attorneyOptions);
+ }
+ } catch (err) {
+ console.error("Error fetching attorneys list:", err);
+ // Don't set error state to avoid interrupting the main UI flow
+ }
+ };
+
+ fetchAttorneys();
+ }, [authToken]);
+
+ useEffect(() => {
+ const fetchDirectors = async () => {
+ try {
+ const response = await fetchPccDirectors();
+ if (Array.isArray(response)) {
+ const directorOptions = response.map((director) => ({
+ value: director.id.toString(),
+ label: director.full_name || director.username,
+ }));
+ setDirectors(directorOptions);
+ }
+ } catch (err) {
+ console.error("Error fetching directors list:", err);
+ }
+ };
+
+ fetchDirectors();
+ }, [authToken]);
+
+ const openForwardModal = () => {
+ if (directors.length === 1) {
+ setSelectedDirectorId(directors[0].value);
+ } else {
+ setSelectedDirectorId("");
+ }
+ setSelectedAttorneyId("");
+ setComments("");
+ setBudgetEstimate("");
+ setActionError(null);
+ setCommentError(null);
+ setForwardModalOpen(true);
+ };
+
+ const openModificationModal = () => {
+ setComments("");
+ setActionError(null);
+ setCommentError(null);
+ setModificationModalOpen(true);
+ };
+
+ // Handler for forward to director
+ const handleForwardToDirector = async () => {
+ // Reset errors
+ setActionError(null);
+ setCommentError(null);
+
+ // Validate attorney selection
+ if (!selectedAttorneyId) {
+ setActionError("Please select an attorney");
+ return;
+ }
+
+ if (!selectedDirectorId) {
+ setActionError("Please select a director");
+ return;
+ }
+
+ // Validate comments
+ if (!comments.trim()) {
+ setCommentError("Comments are required for forwarding to director");
+ return;
+ }
+
+ if (budgetEstimate !== "" && Number(budgetEstimate) < 0) {
+ setActionError("Budget cannot be negative");
+ return;
+ }
+
+ setActionLoading(true);
+
+ try {
+ const selectedAttorney = attorneys.find(
+ (a) => a.value === selectedAttorneyId,
+ );
+ const attorneyName = selectedAttorney ? selectedAttorney.label : "";
+
+ // Backend allows forwarding only after PCC review; auto-review submitted applications first.
+ if (selectedApplication?.status === "Submitted") {
+ await reviewPccApplication(applicationId, comments);
+ }
+
+ await forwardPccApplicationToDirector(
+ applicationId,
+ attorneyName,
+ Number(selectedDirectorId),
+ budgetEstimate === "" ? null : Number(budgetEstimate),
+ comments,
+ );
+
+ setActionSuccess("Application successfully forwarded to director");
+ setForwardModalOpen(false);
+
+ // Refresh application details after the action
+ const response = await fetchPccApplicationDetails(applicationId);
+
+ if (response) {
+ setSelectedApplication(response);
+ }
+ } catch (err) {
+ console.error("Error forwarding to director:", err);
+ setActionError(
+ `Failed to forward application: ${extractApiError(err, "Unknown error")}`,
+ );
+ } finally {
+ setActionLoading(false);
+ // Clear success message after 3 seconds
+ if (actionSuccess) {
+ setTimeout(() => setActionSuccess(null), 3000);
+ }
+ }
+ };
+
+ // Handler for request modification
+ const handleRequestModification = async () => {
+ // Reset errors
+ setActionError(null);
+ setCommentError(null);
+
+ // Validate comments
+ if (!comments.trim()) {
+ setCommentError("Comments are required for requesting modification");
+ return;
+ }
+
+ setActionLoading(true);
+
+ try {
+ await requestPccApplicationModification(applicationId, comments);
+
+ setActionSuccess("Modification request sent successfully");
+ setModificationModalOpen(false);
+
+ // Refresh application details after the action
+ const response = await fetchPccApplicationDetails(applicationId);
+
+ if (response) {
+ setSelectedApplication(response);
+ }
+ } catch (err) {
+ console.error("Error requesting modification:", err);
+ setActionError(
+ `Failed to request modification: ${extractApiError(err, "Unknown error")}`,
+ );
+ } finally {
+ setActionLoading(false);
+ // Clear success message after 3 seconds
+ if (actionSuccess) {
+ setTimeout(() => setActionSuccess(null), 3000);
+ }
+ }
+ };
+
+ if (loading) {
+ return (
+
+
+ Loading application details...
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+ {error}
+
+
+ Back to Applications
+
+
+ );
+ }
+
+ if (!selectedApplication) {
+ return (
+
+
+ No application data found
+
+
+ Back to Applications
+
+
+ );
+ }
+
+ const {
+ application_id,
+ title,
+ application_number,
+ token_no,
+ primary_applicant_name,
+ status,
+ decision_status,
+ budget_estimate,
+ budget_status,
+ comments: app_comments,
+ applicants,
+ section_I,
+ section_II,
+ section_III,
+ dates,
+ } = selectedApplication;
+ const displayApplicationNumber =
+ application_number || token_no || "Not Assigned";
+
+ const submittedDate = dates?.submitted_date
+ ? new Date(dates.submitted_date).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not recorded";
+
+ // Build file URLs
+ const mouFileUrl = section_II?.mou_file
+ ? `${API_BASE_URL}/download/file/${section_II.mou_file}/`
+ : null;
+ const formIIIFileUrl = section_III?.form_iii
+ ? `${API_BASE_URL}/download/file/${section_III.form_iii}/`
+ : null;
+ const pocFileUrl = section_I?.poc_file
+ ? `${API_BASE_URL}/download/file/${section_I.poc_file}/`
+ : null;
+ const sourceAgreementFileUrl = section_II?.source_agreement_file
+ ? `${API_BASE_URL}/download/file/${section_II.source_agreement_file}/`
+ : null;
+
+ return (
+
+
+ }
+ style={{
+ position: "absolute",
+ left: "50px",
+ top: "50%",
+ transform: "translateY(-50%)",
+ border: "none",
+ padding: "10px",
+ fontWeight: "500",
+ }}
+ >
+ Back
+
+
+
+ Application Details
+
+
+
+ {actionSuccess && (
+
+ {actionSuccess}
+
+ )}
+
+ {/* Action buttons at the top of the form */}
+
+
+ }
+ onClick={openForwardModal}
+ id="pms-pcc-action-button"
+ sx={(theme) => ({
+ borderColor: theme.colors.green[6],
+ color: theme.colors.green[6],
+ backgroundColor: "transparent",
+ "&:hover": {
+ backgroundColor: `${theme.colors.green[6]} !important`,
+ color: "white !important",
+ },
+ })}
+ >
+ Forward to Director
+
+
+ }
+ onClick={openModificationModal}
+ id="pms-pcc-action-button"
+ sx={(theme) => ({
+ borderColor: theme.colors.orange[6],
+ color: theme.colors.orange[6],
+ backgroundColor: "transparent",
+ "&:hover": {
+ backgroundColor: `${theme.colors.orange[6]} !important`,
+ color: "white !important",
+ },
+ })}
+ >
+ Request Modification
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Forwarded to Director
+
+ {dates?.forwarded_to_director_date
+ ? new Date(
+ dates.forwarded_to_director_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not yet forwarded"}
+
+
+
+
+
Director Approval
+
+ {dates?.director_approval_date
+ ? new Date(dates.director_approval_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not yet approved"}
+
+
+
+
+
Patentability Check Start
+
+ {dates?.patentability_check_start_date
+ ? new Date(
+ dates.patentability_check_start_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not started"}
+
+
+
+
+
+ Patentability Check Completed
+
+
+ {dates?.patentability_check_completed_date
+ ? new Date(
+ dates.patentability_check_completed_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not completed"}
+
+
+
+
+
Search Report Generated
+
+ {dates?.search_report_generated_date
+ ? new Date(
+ dates.search_report_generated_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not generated"}
+
+
+
+
+
Date of Filing
+
+ {dates?.patent_filed_date
+ ? new Date(dates.patent_filed_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not recorded"}
+
+
+
+
+
Date of Publication
+
+ {dates?.patent_published_date
+ ? new Date(dates.patent_published_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not yet published"}
+
+
+
+
+
Decision Date
+
+ {dates?.decision_date
+ ? new Date(dates.decision_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "No decision yet"}
+
+
+
+
+
Final Decision Date
+
+ {dates?.final_decision_date
+ ? new Date(dates.final_decision_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "No final decision yet"}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {applicants && applicants.length > 0 ? (
+
+ {applicants.map((applicant, index) => (
+
+
+
+ Inventor {index + 1}
+
+
+
+
+
+
+
+
+ ))}
+
+ ) : (
+ No applicant information available
+ )}
+
+
+
+ {/* Forward to Director Modal - Improved UI */}
+ setForwardModalOpen(false)}
+ title={
+
+ Forward to Director
+
+ }
+ size="lg"
+ padding="xl"
+ radius="md"
+ overlayProps={{
+ opacity: 0.55,
+ blur: 3,
+ }}
+ centered
+ >
+
+ {actionError && (
+
+ {actionError}
+
+ )}
+
+
+ Select Director *
+
+ }
+ placeholder="Choose a director"
+ value={selectedDirectorId}
+ onChange={setSelectedDirectorId}
+ required
+ mb="xl"
+ size="md"
+ radius="md"
+ error={
+ !selectedDirectorId && actionLoading
+ ? "Director selection is required"
+ : null
+ }
+ withAsterisk={false}
+ />
+
+
+ Budget Estimate *
+
+ }
+ placeholder="Enter budget amount"
+ value={budgetEstimate}
+ onChange={setBudgetEstimate}
+ min={0}
+ precision={2}
+ step={1000}
+ mb="xl"
+ size="md"
+ radius="md"
+ required
+ withAsterisk={false}
+ />
+
+
+ Select Attorney *
+
+ }
+ placeholder="Choose an attorney"
+ value={selectedAttorneyId}
+ onChange={setSelectedAttorneyId}
+ required
+ mb="xl"
+ size="md"
+ radius="md"
+ error={
+ !selectedAttorneyId && actionLoading
+ ? "Attorney selection is required"
+ : null
+ }
+ withAsterisk={false}
+ />
+
+
+ Comments for Director *
+
+ }
+ placeholder="Add detailed comments for the director about this application"
+ value={comments}
+ onChange={(e) => setComments(e.target.value)}
+ minRows={4}
+ maxRows={6}
+ mb="xl"
+ size="md"
+ radius="md"
+ error={commentError}
+ required
+ withAsterisk={false}
+ />
+
+
+ Please provide detailed instructions or notes for the director to
+ review this application.
+
+
+
+ {
+ setForwardModalOpen(false);
+ setActionError(null);
+ setCommentError(null);
+ setBudgetEstimate("");
+ }}
+ sx={(theme) => ({
+ borderColor: theme.colors.gray[5],
+ color: theme.colors.gray[7],
+ "&:hover": {
+ backgroundColor: theme.colors.gray[1],
+ },
+ })}
+ >
+ Cancel
+
+ ({
+ backgroundColor: theme.colors.green[6],
+ "&:hover": {
+ backgroundColor: theme.colors.green[7],
+ },
+ })}
+ >
+ Forward to Director
+
+
+
+
+
+ {/* Request Modification Modal - Improved UI */}
+ setModificationModalOpen(false)}
+ title={
+
+ Request Modification
+
+ }
+ size="lg"
+ padding="xl"
+ radius="md"
+ overlayProps={{
+ opacity: 0.55,
+ blur: 3,
+ }}
+ centered
+ >
+
+ {actionError && (
+
+ {actionError}
+
+ )}
+
+
+ Please specify what aspects of the application need to be modified
+ by the applicant.
+
+
+
+ Modification Comments *
+
+ }
+ placeholder="Provide detailed instructions about what needs to be modified in the application"
+ value={comments}
+ onChange={(e) => setComments(e.target.value)}
+ minRows={5}
+ maxRows={8}
+ mb="xl"
+ size="md"
+ radius="md"
+ error={commentError}
+ required
+ withAsterisk={false}
+ />
+
+
+ Be specific about what information is incorrect, missing, or needs
+ clarification. These comments will be sent directly to the
+ applicant.
+
+
+
+ {
+ setModificationModalOpen(false);
+ setActionError(null);
+ setCommentError(null);
+ }}
+ sx={(theme) => ({
+ borderColor: theme.colors.gray[5],
+ color: theme.colors.gray[7],
+ "&:hover": {
+ backgroundColor: theme.colors.gray[1],
+ },
+ })}
+ >
+ Cancel
+
+ ({
+ backgroundColor: theme.colors.orange[6],
+ "&:hover": {
+ backgroundColor: theme.colors.orange[7],
+ },
+ })}
+ >
+ Request Modification
+
+
+
+
+
+ );
+}
+
+ViewNewApplication.propTypes = {
+ applicationId: PropTypes.string.isRequired,
+ handleBackToList: PropTypes.func.isRequired,
+};
+
+export default ViewNewApplication;
diff --git a/src/Modules/Patent/components/PCCAdmin/Notifications/PCCAdminNotification.jsx b/src/Modules/Patent/components/PCCAdmin/Notifications/PCCAdminNotification.jsx
new file mode 100644
index 000000000..5baf588c1
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/Notifications/PCCAdminNotification.jsx
@@ -0,0 +1,226 @@
+import React, { useEffect, useState } from "react";
+import PropTypes from "prop-types";
+import { Card, Button, Text, Box, Grid } from "@mantine/core";
+import { fetchSystemNotifications } from "../../../services/pccAdminService";
+
+const styles = {
+ notificationCard: {
+ padding: "1.5rem",
+ marginBottom: "10px",
+ boxShadow: "0 5px 8px rgba(0, 0, 0, 0.2)",
+ borderRadius: "8px",
+ backgroundColor: "#fff",
+ height: "100%",
+ display: "flex",
+ flexDirection: "column",
+ borderLeft: "10px solid #00AEEF",
+ },
+ notificationTitle: {
+ fontSize: "20px",
+ fontWeight: 500,
+ marginBottom: "0",
+ },
+ notificationStatus: {
+ fontSize: "1rem",
+ fontWeight: 500,
+ marginBottom: "0.2rem",
+ },
+ notificationDate: {
+ fontSize: "0.875rem",
+ color: "#666",
+ marginBottom: "1rem",
+ },
+ notificationDescription: {
+ fontSize: "0.875rem",
+ color: "#444",
+ padding: "0",
+ flex: 1,
+ },
+ notificationActions: {
+ display: "flex",
+ justifyContent: "space-between",
+ flexWrap: "wrap",
+ gap: "0.5rem",
+ },
+ actionButton: {
+ flex: "1",
+ minWidth: "120px",
+ fontWeight: "500",
+ },
+ pageTitle: {
+ fontSize: "26px",
+ marginTop: "-10px",
+ fontWeight: 600,
+ marginBottom: "10px",
+ },
+ container: {
+ width: "100%",
+ padding: "0",
+ maxWidth: "1800px",
+ margin: "0 50px",
+ },
+};
+
+// Notification card component
+function NotificationCard({
+ id,
+ title,
+ status,
+ description,
+ date,
+ time,
+ type,
+ onMarkAsRead,
+ onForwardToAttorney,
+ onReturnToApplicant,
+}) {
+ const getStatusColor = () => {
+ switch (type) {
+ case "approval":
+ return "#38a169"; // green
+ case "rejection":
+ return "#e53e3e"; // red
+ case "new":
+ return "#3182ce"; // blue
+ default:
+ return "#718096"; // gray
+ }
+ };
+
+ return (
+
+ {title}
+
+ {status}
+
+ {`${date} | ${time}`}
+ {description}
+
+
+ {type === "approval" && (
+ onForwardToAttorney(id)}
+ >
+ Forward to Attorney
+
+ )}
+
+ {type === "rejection" && (
+ onReturnToApplicant(id)}
+ >
+ Return to Applicant
+
+ )}
+
+ onMarkAsRead(id)}
+ >
+ Mark as Read
+
+
+
+ );
+}
+
+NotificationCard.propTypes = {
+ id: PropTypes.number.isRequired,
+ title: PropTypes.string.isRequired,
+ status: PropTypes.string.isRequired,
+ description: PropTypes.string.isRequired,
+ date: PropTypes.string.isRequired,
+ time: PropTypes.string.isRequired,
+ type: PropTypes.string.isRequired,
+ onMarkAsRead: PropTypes.func.isRequired,
+ onForwardToAttorney: PropTypes.func,
+ onReturnToApplicant: PropTypes.func,
+};
+
+function PCCAdminNotifications() {
+ const [notifications, setNotifications] = useState([]);
+
+ useEffect(() => {
+ const load = async () => {
+ try {
+ const data = await fetchSystemNotifications("PCC Admin");
+ const mapped = (data || []).map((item) => {
+ const created = item.created_at
+ ? new Date(item.created_at)
+ : new Date();
+ return {
+ id: item.id,
+ title: item.event_type,
+ status: item.is_escalated ? "Escalated" : "Active",
+ type: item.is_escalated ? "rejection" : "new",
+ description: item.message,
+ date: created.toLocaleDateString(),
+ time: created.toLocaleTimeString(),
+ };
+ });
+ setNotifications(mapped);
+ } catch (error) {
+ console.error("Failed to fetch PCC admin notifications", error);
+ }
+ };
+
+ load();
+ }, []);
+
+ const handleMarkAsRead = (id) => {
+ setNotifications(
+ notifications.filter((notification) => notification.id !== id),
+ );
+ };
+
+ const handleForwardToAttorney = (id) => {
+ alert(`Application ${id} forwarded to Attorney`);
+ handleMarkAsRead(id);
+ };
+
+ const handleReturnToApplicant = (id) => {
+ alert(`Application ${id} returned to Applicant`);
+ handleMarkAsRead(id);
+ };
+
+ return (
+
+ {/* Page Title */}
+ Notifications
+
+ {/* Notifications container */}
+
+
+ {notifications.map((notification) => (
+
+
+
+ ))}
+
+
+
+ );
+}
+
+export default PCCAdminNotifications;
diff --git a/src/Modules/Patent/components/PCCAdmin/OngoingApplication/OngoingApplication.jsx b/src/Modules/Patent/components/PCCAdmin/OngoingApplication/OngoingApplication.jsx
new file mode 100644
index 000000000..916d9b2d5
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/OngoingApplication/OngoingApplication.jsx
@@ -0,0 +1,489 @@
+import React, { useState, useEffect } from "react";
+import {
+ Box,
+ Button,
+ ScrollArea,
+ Table,
+ Text,
+ Loader,
+ Group,
+ Divider,
+} from "@mantine/core";
+import { Eye, ArrowsClockwise, Warning } from "@phosphor-icons/react";
+import ViewOngoingApplication from "./ViewOngoingApplication";
+import { fetchPccOngoingApplications } from "../../../services/pccAdminService";
+
+function OngoingApplication() {
+ const [applications, setApplications] = useState([]);
+ const [selectedApplication, setSelectedApplication] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [isRefreshing, setIsRefreshing] = useState(false);
+
+ const columnNames = [
+ "S.No",
+ "Application Number",
+ "Application No",
+ "Patent Title",
+ "Inventor 1",
+ "Designation",
+ "Department",
+ "Date",
+ "Status",
+ "View",
+ ];
+
+ // Styles
+ const styles = {
+ container: {
+ position: "relative",
+ width: "100%",
+ maxWidth: "100%",
+ },
+ title: {
+ fontSize: "24px",
+ fontWeight: 600,
+ textAlign: "left",
+ margin: "0 20px",
+ paddingLeft: "50px",
+ position: "relative",
+ },
+ outerContainer: {
+ maxWidth: "100%",
+ padding: "0px 50px",
+ backgroundColor: "transparent",
+ borderRadius: "12px",
+ marginBottom: "20px",
+ boxShadow: "0px 5px 15px rgba(0, 0, 0, 0)",
+ },
+ tableWrapper: {
+ overflowX: "auto",
+ width: "100%",
+ backgroundColor: "inherit",
+ paddingBottom: 0,
+ marginBottom: 0,
+ },
+ table: {
+ width: "100%",
+ minWidth: "100%",
+ fontSize: "14px",
+ backgroundColor: "#ffffff",
+ borderSpacing: 0,
+ borderCollapse: "separate",
+ borderRadius: "8px",
+ overflow: "hidden",
+ transition: "all 0.3s ease",
+ boxShadow: "0px 3px 8px rgba(0, 0, 0, 0.05)",
+ },
+ tableHeader: {
+ padding: "16px 20px",
+ textAlign: "left",
+ backgroundColor: "#f2f2f2",
+ fontWeight: 600,
+ color: "#444",
+ position: "sticky",
+ top: 0,
+ zIndex: 10,
+ transition: "background-color 0.2s ease",
+ whiteSpace: "nowrap",
+ },
+ tableRow: {
+ backgroundColor: "#ffffff",
+ transition: "all 0.2s ease",
+ "&:hover": {
+ backgroundColor: "#f8fbff",
+ transform: "translateY(-1px)",
+ boxShadow: "0 3px 6px rgba(0, 0, 0, 0.05)",
+ },
+ },
+ tableCell: {
+ padding: "14px 20px",
+ borderTop: "1px solid #f0f0f0",
+ verticalAlign: "middle",
+ },
+ viewButton: {
+ display: "flex",
+ alignItems: "center",
+ gap: "6px",
+ fontWeight: 600,
+ transition: "all 0.2s ease",
+ borderRadius: "6px",
+ padding: "8px 12px",
+ "&:hover": {
+ transform: "translateY(-2px)",
+ boxShadow: "0 4px 8px rgba(0, 0, 0, 0.1)",
+ },
+ },
+ loaderContainer: {
+ display: "flex",
+ flexDirection: "column",
+ alignItems: "center",
+ justifyContent: "center",
+ padding: "40px 0",
+ },
+ refreshButton: {
+ marginLeft: "50px",
+ paddingLeft: 0,
+ },
+ errorContainer: {
+ display: "flex",
+ flexDirection: "column",
+ alignItems: "center",
+ justifyContent: "center",
+ padding: "40px 20px",
+ textAlign: "center",
+ },
+ emptyContainer: {
+ display: "flex",
+ flexDirection: "column",
+ alignItems: "center",
+ justifyContent: "center",
+ padding: "40px 20px",
+ textAlign: "center",
+ },
+ };
+
+ const formatDate = (dateString) => {
+ if (!dateString || dateString === "Not Provided") return "Not Provided";
+ try {
+ return new Date(dateString).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "short",
+ day: "numeric",
+ });
+ } catch {
+ return dateString;
+ }
+ };
+
+ const getStatusColor = (status) => {
+ if (!status) return "gray";
+
+ const formatted = status.trim().toLowerCase();
+
+ switch (formatted) {
+ case "forwarded for director's review":
+ return "indigo";
+ case "director's approval received":
+ return "teal";
+ case "patentability check started":
+ return "violet";
+ case "patentability check completed":
+ return "cyan";
+ case "patentability search report generated":
+ return "blue";
+ case "patent filed":
+ return "green";
+ default:
+ return "gray";
+ }
+ };
+
+ const fetchApplications = async (refresh = false) => {
+ try {
+ // Fixed version
+ if (refresh) {
+ setIsRefreshing(true);
+ } else {
+ setLoading(true);
+ }
+ const data = await fetchPccOngoingApplications();
+
+ const formatted = Object.entries(data.applications)
+ .map(([id, details]) => ({
+ id: id.split("_")[1] || id,
+ token_no:
+ details.application_number || details.token_no || "Not Assigned",
+ title: details.title || "Not Provided",
+ submitted_by: details.submitted_by || "Not Provided",
+ designation: details.designation || "Not Provided",
+ department: details.department || "Not Provided",
+ submitted_on: details.submitted_on || "Not Provided",
+ status: details.status || "Not Provided",
+ }))
+ .sort((a, b) => {
+ if (a.submitted_on === "Not Provided") return 1;
+ if (b.submitted_on === "Not Provided") return -1;
+ return new Date(b.submitted_on) - new Date(a.submitted_on);
+ });
+
+ setApplications(formatted);
+ setError(null);
+ } catch (err) {
+ console.error("Error fetching applications:", err);
+ setError(
+ err.response?.data?.message ||
+ "Unable to fetch applications. Please try again later.",
+ );
+ } finally {
+ setLoading(false);
+ if (refresh) setIsRefreshing(false);
+ }
+ };
+
+ useEffect(() => {
+ (async () => {
+ await fetchApplications();
+ })();
+ }, []);
+
+ const handleViewClick = (id) => setSelectedApplication(id);
+ const handleRefresh = () => fetchApplications(true);
+
+ if (loading) {
+ return (
+
+
+
+ Loading applications...
+
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+
+
+ Error Loading Applications
+
+
+
+ {error}
+
+ }
+ >
+ Retry
+
+
+ );
+ }
+
+ if (applications.length === 0) {
+ return (
+
+
+ No applications found
+
+
+ There are currently no patent applications in the system.
+
+ }
+ >
+ Refresh
+
+
+ );
+ }
+
+ return (
+
+ {!selectedApplication ? (
+ <>
+ Ongoing Applications
+
+
+ }
+ >
+ {isRefreshing ? "Refreshing..." : "Refresh"}
+
+
+
+
+
+
+
+
+ {columnNames.map((columnName, index) => (
+
+ {columnName}
+
+ ))}
+
+
+
+ {applications.map((application, index) => (
+
+
+ {index + 1}
+
+
+ {application.id}
+
+
+ {application.token_no}
+
+
+ {application.title}
+
+
+ {application.submitted_by}
+
+
+ {application.designation}
+
+
+ {application.department}
+
+
+ {formatDate(application.submitted_on)}
+
+
+
+ {application.status}
+
+
+
+ handleViewClick(application.id)}
+ style={{
+ ...styles.viewButton,
+ backgroundColor: "#fff",
+ color: "#0073e6",
+ border: "1px solid #0073e6",
+ fontWeight: 500,
+ transition: "all 0.2s ease",
+ ":hover": {
+ backgroundColor: "#0073e6",
+ color: "#fff",
+ },
+ }}
+ >
+ View
+
+
+
+ ))}
+
+
+
+
+ >
+ ) : (
+
+
+
+
+ )}
+
+ );
+}
+
+export default OngoingApplication;
diff --git a/src/Modules/Patent/components/PCCAdmin/OngoingApplication/ViewOngoingApplication.jsx b/src/Modules/Patent/components/PCCAdmin/OngoingApplication/ViewOngoingApplication.jsx
new file mode 100644
index 000000000..975169fb2
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/OngoingApplication/ViewOngoingApplication.jsx
@@ -0,0 +1,1367 @@
+import React, { useState, useEffect } from "react";
+import PropTypes from "prop-types";
+import {
+ Container,
+ Text,
+ Card,
+ Grid,
+ Button,
+ Loader,
+ Alert,
+ Title,
+ Stepper,
+ Group,
+ Select,
+} from "@mantine/core";
+import {
+ ArrowLeft,
+ DownloadSimple,
+ CheckCircle,
+ CircleNotch,
+ ArrowRight,
+} from "@phosphor-icons/react";
+import "../../../style/Pcc_Admin/ViewOngoingApplication.css";
+import { API_BASE_URL } from "../../../services/api";
+import {
+ createAppeal,
+ createLegalMemo,
+ createLicensingRequest,
+ createOfficeAction,
+ createPriorArt,
+ fetchPccApplicationDetails,
+ fetchMaintenanceSchedule,
+ logExternalFiling,
+ markMaintenancePaid,
+ submitBudgetRequest,
+ submitLegalAssessment,
+ updatePccOngoingApplicationStatus,
+} from "../../../services/pccAdminService";
+
+// Field component for detail view
+function FormField({ label, value }) {
+ return (
+
+ {label}
+ {value || "Not provided"}
+
+ );
+}
+
+FormField.propTypes = {
+ label: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+};
+
+// Field with download button for direct file URLs
+function FormFieldWithDownload({ label, value, fileUrl, fileLabel }) {
+ return (
+
+ );
+}
+
+FormFieldWithDownload.propTypes = {
+ label: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ fileUrl: PropTypes.string,
+ fileLabel: PropTypes.string.isRequired,
+};
+
+// File Download Button Component
+function FileDownloadButton({ fileUrl, label, disabled }) {
+ if (!fileUrl || fileUrl === "null" || disabled) {
+ return (
+ }
+ disabled
+ >
+ No {label} Available
+
+ );
+ }
+
+ return (
+ }
+ >
+ View {label}
+
+ );
+}
+
+FileDownloadButton.propTypes = {
+ fileUrl: PropTypes.string,
+ label: PropTypes.string.isRequired,
+ disabled: PropTypes.bool,
+};
+
+// Section component for detail view
+function FormSection({ title, children }) {
+ return (
+
+ {title}
+ {children}
+
+ );
+}
+
+FormSection.propTypes = {
+ title: PropTypes.string.isRequired,
+ children: PropTypes.node.isRequired,
+};
+
+// Progress Bar Component
+function PatentProgressBar({ currentStatus, isMobile }) {
+ const allStatuses = [
+ "Submitted",
+ "Reviewed by PCC Admin",
+ "Needs Revision",
+ "Attorney Assigned",
+ "Returned to Director",
+ "Forwarded for Director's Review",
+ "Director's Approval Received",
+ "Patentability Check Started",
+ "Patentability Check Completed",
+ "Patentability Search Report Generated",
+ "Patent Filed",
+ "Patent Published",
+ "Patent Granted",
+ "Patent Refused",
+ "Withdrawn",
+ ];
+
+ const getStepIndex = (status) => {
+ if (status === "Rejected") return -1;
+ if (status === "Withdrawn") return allStatuses.length - 1;
+ return allStatuses.findIndex((s) => s === status);
+ };
+
+ const currentStep = getStepIndex(currentStatus);
+ const isRejected = currentStatus === "Rejected";
+ const isRefused = currentStatus === "Patent Refused";
+ const isGranted = currentStatus === "Patent Granted";
+ const isWithdrawn = currentStatus === "Withdrawn";
+
+ // Determine which statuses to display based on current status
+ let displayStatuses;
+ if (isWithdrawn) {
+ displayStatuses = ["Submitted", "Withdrawn"];
+ } else if (isRefused) {
+ displayStatuses = ["Submitted", "Patent Refused"];
+ } else if (isGranted) {
+ // Show only the first 11 stages without "Patent Refused" for granted patents
+ displayStatuses = allStatuses.slice(0, 11);
+ } else {
+ displayStatuses = allStatuses;
+ }
+
+ return (
+
+ {(isRejected || isWithdrawn) && (
+
+ {isWithdrawn ? "Application Withdrawn" : "Application Rejected"}
+
+ )}
+
+ {!isMobile ? (
+ // Desktop view
+
+ {isRefused ? (
+ // Simple two-step progress for refused patents
+
+ }
+ label="Stage 1"
+ description="Submitted"
+ id="pms-pcc-completed-step"
+ />
+ }
+ label="Stage 2"
+ description="Patent Refused"
+ id="pms-pcc-completed-step"
+ />
+
+ ) : (
+ // Regular view with two rows for normal flow
+ <>
+
+ {displayStatuses.slice(0, 4).map((status, index) => (
+
+ ) : index === currentStep ? (
+
+ ) : (
+
+ )
+ }
+ label={`Stage ${index + 1}`}
+ description={status}
+ className={
+ isGranted || index <= currentStep
+ ? "completed-step"
+ : "pending-step"
+ }
+ />
+ ))}
+
+
+ {displayStatuses.slice(4).map((status, index) => (
+
+ ) : index + 4 === currentStep ? (
+
+ ) : (
+
+ )
+ }
+ label={`Stage ${index + 5}`}
+ description={status}
+ className={
+ isGranted || index + 4 <= currentStep
+ ? "completed-step"
+ : "pending-step"
+ }
+ />
+ ))}
+
+ >
+ )}
+
+ ) : (
+ // Mobile view - vertical stepper
+
+ {displayStatuses.map((status, index) => (
+
+ ) : index === (isRefused ? 1 : currentStep) ? (
+
+ ) : (
+
+ )
+ }
+ label={`Stage ${index + 1}`}
+ description={status}
+ className={
+ isGranted || index <= (isRefused ? 1 : currentStep)
+ ? "completed-step"
+ : "pending-step"
+ }
+ />
+ ))}
+
+ )}
+
+ );
+}
+
+PatentProgressBar.propTypes = {
+ currentStatus: PropTypes.string.isRequired,
+ isMobile: PropTypes.bool.isRequired,
+};
+
+function ViewOngoingApplication({ applicationId, handleBackToList }) {
+ const [selectedApplication, setSelectedApplication] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
+ const [updatingStatus, setUpdatingStatus] = useState(false);
+ const [statusUpdateMessage, setStatusUpdateMessage] = useState(null);
+ const [maintenanceItems, setMaintenanceItems] = useState([]);
+ const authToken = localStorage.getItem("authToken");
+
+ // These statuses must match the backend's expected REVIEW_STATUSES
+ const statusOptions = [
+ {
+ value: "Director's Approval Received",
+ label: "Director's Approval Received",
+ },
+ {
+ value: "Patentability Check Started",
+ label: "Patentability Check Started",
+ },
+ {
+ value: "Patentability Check Completed",
+ label: "Patentability Check Completed",
+ },
+ {
+ value: "Patentability Search Report Generated",
+ label: "Patentability Search Report Generated",
+ },
+ { value: "Patent Filed", label: "Patent Filed" },
+ { value: "Patent Published", label: "Patent Published" },
+ { value: "Patent Granted", label: "Patent Granted" },
+ { value: "Patent Refused", label: "Patent Refused" },
+ ];
+
+ useEffect(() => {
+ const handleResize = () => {
+ setIsMobile(window.innerWidth <= 768);
+ };
+
+ window.addEventListener("resize", handleResize);
+ return () => window.removeEventListener("resize", handleResize);
+ }, []);
+
+ useEffect(() => {
+ const fetchApplicationDetails = async () => {
+ if (!applicationId) {
+ setError("No application ID provided");
+ setLoading(false);
+ return;
+ }
+
+ try {
+ setLoading(true);
+ const response = await fetchPccApplicationDetails(applicationId);
+
+ if (response) {
+ setSelectedApplication(response);
+ setError(null);
+ } else {
+ setError("No application data found");
+ }
+ } catch (err) {
+ console.error("Error fetching application details:", err);
+ setError(`Failed to load application details: ${err.message}`);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchApplicationDetails();
+ }, [applicationId, authToken]);
+
+ const handleStatusChange = async (newStatus) => {
+ if (!newStatus || newStatus === selectedApplication.status) return;
+
+ // Prevent moving past "Patent Granted" status
+ if (selectedApplication.status === "Patent Granted") {
+ setStatusUpdateMessage({
+ type: "info",
+ text: "This application has already been granted a patent. No further status changes are allowed.",
+ });
+
+ // Clear info message after 5 seconds
+ setTimeout(() => {
+ setStatusUpdateMessage(null);
+ }, 5000);
+
+ return;
+ }
+
+ // For "Patent Refused" status, show confirmation dialog
+ if (newStatus === "Patent Refused") {
+ const confirmRefusal = window.confirm(
+ "Are you sure you want to mark this application as 'Patent Refused'? This action cannot be undone.",
+ );
+
+ if (!confirmRefusal) {
+ return; // User canceled the operation
+ }
+ }
+
+ try {
+ setUpdatingStatus(true);
+ setStatusUpdateMessage(null);
+
+ // Update to match the backend's expected parameter name
+ const response = await updatePccOngoingApplicationStatus(
+ applicationId,
+ newStatus,
+ );
+
+ if (response.data && response.status === 200) {
+ // Update the application object with new status
+ setSelectedApplication({
+ ...selectedApplication,
+ status: newStatus,
+ });
+ setStatusUpdateMessage({
+ type: "success",
+ text: `Status successfully updated to ${newStatus}`,
+ });
+ } else {
+ setStatusUpdateMessage({
+ type: "error",
+ text: "Failed to update status. Please try again.",
+ });
+ }
+ } catch (err) {
+ console.error("Error updating application status:", err);
+ setStatusUpdateMessage({
+ type: "error",
+ text: `Error: ${err.response?.data?.error || err.message}`,
+ });
+ } finally {
+ setUpdatingStatus(false);
+
+ // Clear success message after 5 seconds
+ if (
+ statusUpdateMessage?.type === "success" ||
+ statusUpdateMessage?.type === "info"
+ ) {
+ setTimeout(() => {
+ setStatusUpdateMessage(null);
+ }, 5000);
+ }
+ }
+ };
+
+ const handleQuickLegalAssessment = async () => {
+ const opinion = window.prompt(
+ "Opinion (Patentable / Not Patentable / Needs Amendment):",
+ "Needs Amendment",
+ );
+ if (!opinion) return;
+ const priorArt = window.prompt(
+ "Prior art summary:",
+ "Initial prior-art check completed.",
+ );
+ if (!priorArt) return;
+ const action = window.prompt("Recommended action:", "Amend and continue.");
+ if (!action) return;
+
+ try {
+ await submitLegalAssessment(applicationId, {
+ opinion,
+ prior_art_summary: priorArt,
+ recommended_action: action,
+ });
+ setStatusUpdateMessage({
+ type: "success",
+ text: "Legal assessment submitted successfully.",
+ });
+ } catch (err) {
+ setStatusUpdateMessage({
+ type: "error",
+ text: err.response?.data?.error || "Failed to submit legal assessment.",
+ });
+ }
+ };
+
+ const handleQuickBudgetRequest = async () => {
+ const amount = window.prompt("Enter budget amount:", "50000");
+ if (!amount) return;
+ try {
+ const result = await submitBudgetRequest(applicationId, { amount });
+ setStatusUpdateMessage({
+ type: "success",
+ text: `Budget request submitted (${result.status}).`,
+ });
+ } catch (err) {
+ setStatusUpdateMessage({
+ type: "error",
+ text: err.response?.data?.error || "Failed to submit budget request.",
+ });
+ }
+ };
+
+ const handleQuickExternalFiling = async () => {
+ const patentOffice = window.prompt("Patent office:", "IPO India");
+ if (!patentOffice) return;
+ const reference = window.prompt("Filing reference:", "REF-001");
+ if (!reference) return;
+
+ try {
+ await logExternalFiling(applicationId, {
+ patent_office: patentOffice,
+ filing_reference: reference,
+ });
+ setStatusUpdateMessage({
+ type: "success",
+ text: "External filing recorded.",
+ });
+ } catch (err) {
+ setStatusUpdateMessage({
+ type: "error",
+ text: err.response?.data?.error || "Failed to log external filing.",
+ });
+ }
+ };
+
+ const handleLoadMaintenance = async () => {
+ try {
+ const items = await fetchMaintenanceSchedule(applicationId);
+ setMaintenanceItems(items || []);
+ setStatusUpdateMessage({
+ type: "success",
+ text: "Maintenance schedule loaded.",
+ });
+ } catch (err) {
+ setStatusUpdateMessage({
+ type: "error",
+ text:
+ err.response?.data?.error || "Failed to load maintenance schedule.",
+ });
+ }
+ };
+
+ const handleQuickOfficeAction = async () => {
+ const officeName = window.prompt("Patent office name:", "IPO India");
+ const reference = window.prompt("Office action reference:", "OA-001");
+ const summary = window.prompt(
+ "Office action summary:",
+ "Clarification requested on novelty claims.",
+ );
+ if (!officeName || !reference || !summary) return;
+ try {
+ await createOfficeAction(applicationId, {
+ office_name: officeName,
+ action_reference: reference,
+ action_summary: summary,
+ });
+ setStatusUpdateMessage({
+ type: "success",
+ text: "Office action logged.",
+ });
+ } catch (err) {
+ setStatusUpdateMessage({
+ type: "error",
+ text: err.response?.data?.error || "Failed to log office action.",
+ });
+ }
+ };
+
+ const handleQuickPriorArt = async () => {
+ const title = window.prompt("Prior-art title:", "US Patent Example");
+ const source = window.prompt("Source:", "Google Patents");
+ if (!title || !source) return;
+ try {
+ await createPriorArt(applicationId, { title, source });
+ setStatusUpdateMessage({
+ type: "success",
+ text: "Prior-art reference added.",
+ });
+ } catch (err) {
+ setStatusUpdateMessage({
+ type: "error",
+ text: err.response?.data?.error || "Failed to add prior-art reference.",
+ });
+ }
+ };
+
+ const handleQuickAppeal = async () => {
+ const grounds = window.prompt(
+ "Appeal grounds (minimum 20 chars):",
+ "Decision overlooked key prior-art distinction and claims interpretation.",
+ );
+ if (!grounds) return;
+ try {
+ await createAppeal(applicationId, { grounds });
+ setStatusUpdateMessage({ type: "success", text: "Appeal submitted." });
+ } catch (err) {
+ setStatusUpdateMessage({
+ type: "error",
+ text: err.response?.data?.error || "Failed to submit appeal.",
+ });
+ }
+ };
+
+ const handleQuickLicensing = async () => {
+ const organization = window.prompt("Organization:", "Acme Tech Pvt Ltd");
+ const proposalSummary = window.prompt(
+ "Proposal summary:",
+ "License request for non-exclusive commercialization in domestic market.",
+ );
+ if (!organization || !proposalSummary) return;
+ try {
+ await createLicensingRequest(applicationId, {
+ organization,
+ proposal_summary: proposalSummary,
+ });
+ setStatusUpdateMessage({
+ type: "success",
+ text: "Licensing request created.",
+ });
+ } catch (err) {
+ setStatusUpdateMessage({
+ type: "error",
+ text:
+ err.response?.data?.error || "Failed to create licensing request.",
+ });
+ }
+ };
+
+ const handleQuickLegalMemo = async () => {
+ const memoText = window.prompt(
+ "Legal memo text (minimum 20 chars):",
+ "Attorney assessment notes under privileged communication for filing strategy.",
+ );
+ if (!memoText) return;
+ try {
+ await createLegalMemo(applicationId, { memo_text: memoText });
+ setStatusUpdateMessage({ type: "success", text: "Legal memo recorded." });
+ } catch (err) {
+ setStatusUpdateMessage({
+ type: "error",
+ text: err.response?.data?.error || "Failed to record legal memo.",
+ });
+ }
+ };
+
+ const handleMarkMaintenancePaid = async (scheduleId) => {
+ try {
+ await markMaintenancePaid(scheduleId);
+ await handleLoadMaintenance();
+ setStatusUpdateMessage({
+ type: "success",
+ text: "Maintenance entry marked paid.",
+ });
+ } catch (err) {
+ setStatusUpdateMessage({
+ type: "error",
+ text:
+ err.response?.data?.error || "Failed to mark maintenance as paid.",
+ });
+ }
+ };
+
+ if (loading) {
+ return (
+
+
+ Loading application details...
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+ {error}
+
+
+ Back to Applications
+
+
+ );
+ }
+
+ if (!selectedApplication) {
+ return (
+
+
+ No application data found
+
+
+ Back to Applications
+
+
+ );
+ }
+
+ const {
+ application_id,
+ title,
+ application_number,
+ token_no,
+ primary_applicant_name,
+ attorney_name,
+ status,
+ decision_status,
+ comments,
+ applicants,
+ section_I,
+ section_II,
+ section_III,
+ dates,
+ } = selectedApplication;
+ const displayApplicationNumber =
+ application_number || token_no || "Not Assigned";
+
+ const submittedDate = dates?.submitted_date
+ ? new Date(dates.submitted_date).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not recorded";
+
+ // Build file URLs
+ const mouFileUrl = section_II?.mou_file
+ ? `${API_BASE_URL}/download/file/${section_II.mou_file}/`
+ : null;
+ const formIIIFileUrl = section_III?.form_iii
+ ? `${API_BASE_URL}/download/file/${section_III.form_iii}/`
+ : null;
+ const pocFileUrl = section_I?.poc_file
+ ? `${API_BASE_URL}/download/file/${section_I.poc_file}/`
+ : null;
+ const sourceAgreementFileUrl = section_II?.source_agreement_file
+ ? `${API_BASE_URL}/download/file/${section_II.source_agreement_file}/`
+ : null;
+
+ // Get the next allowed status based on current status
+ const getCurrentStatusIndex = () => {
+ const normalizedStatus = (status || "").trim();
+ return statusOptions.findIndex(
+ (option) => option.value === normalizedStatus,
+ );
+ };
+
+ const getNextStatus = () => {
+ const currentIndex = getCurrentStatusIndex();
+ return currentIndex >= 0 && currentIndex < statusOptions.length - 1
+ ? statusOptions[currentIndex + 1].value
+ : null;
+ };
+
+ const getPreviousStatus = () => {
+ const currentIndex = getCurrentStatusIndex();
+ return currentIndex > 0 ? statusOptions[currentIndex - 1].value : null;
+ };
+
+ return (
+
+
+
+ }
+ style={{
+ border: "none",
+ padding: "10px",
+ background: "none",
+ cursor: "pointer",
+ fontWeight: "500",
+ }}
+ onClick={(e) => {
+ e.stopPropagation();
+ if (typeof handleBackToList === "function") {
+ handleBackToList();
+ } else {
+ window.history.back();
+ }
+ }}
+ >
+ Back
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+
Reviewed by PCC
+
+ {dates?.reviewed_by_pcc_date
+ ? new Date(dates.reviewed_by_pcc_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not yet reviewed"}
+
+
*/}
+
+
+
Forwarded to Director
+
+ {dates?.forwarded_to_director_date
+ ? new Date(
+ dates.forwarded_to_director_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not yet forwarded"}
+
+
+
+
+
Director Approval
+
+ {dates?.director_approval_date
+ ? new Date(dates.director_approval_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not yet approved"}
+
+
+
+
+
Patentability Check Start
+
+ {dates?.patentability_check_start_date
+ ? new Date(
+ dates.patentability_check_start_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not started"}
+
+
+
+
+
+ Patentability Check Completed
+
+
+ {dates?.patentability_check_completed_date
+ ? new Date(
+ dates.patentability_check_completed_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not completed"}
+
+
+
+
+
Search Report Generated
+
+ {dates?.search_report_generated_date
+ ? new Date(
+ dates.search_report_generated_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not generated"}
+
+
+
+
+
Date of Filing
+
+ {dates?.patent_filed_date
+ ? new Date(dates.patent_filed_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not recorded"}
+
+
+
+
+
Date of Publication
+
+ {dates?.patent_published_date
+ ? new Date(dates.patent_published_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not yet published"}
+
+
+
+ {/*
+
Decision Date
+
+ {dates?.decision_date
+ ? new Date(dates.decision_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "No decision yet"}
+
+
*/}
+
+
+
Date of Granting
+
+ {dates?.final_decision_date
+ ? new Date(dates.final_decision_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "No final decision yet"}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {applicants && applicants.length > 0 ? (
+
+ {applicants.map((applicant, index) => (
+
+
+
+ Applicant {index + 1}
+
+
+
+
+
+
+
+
+ ))}
+
+ ) : (
+ No applicant information available
+ )}
+
+
+
+
+
+
+
+ Update Application Status
+
+
+ {statusUpdateMessage && (
+
setStatusUpdateMessage(null)}
+ >
+ {statusUpdateMessage.text}
+
+ )}
+
+
+
+
+
+ {
+ const nextStatus = getNextStatus();
+ if (nextStatus) {
+ handleStatusChange(nextStatus);
+ }
+ }}
+ >
+ Move to Next Stage
+
+
+ {
+ const prevStatus = getPreviousStatus();
+ if (prevStatus) {
+ handleStatusChange(prevStatus);
+ }
+ }}
+ ml="xs"
+ >
+ Move to Previous Stage
+
+
+
+
+
+
+
+
+
+ Submit Legal Assessment
+
+
+ Submit Budget Request
+
+
+ Log External Filing
+
+
+ Log Office Action
+
+
+ Add Prior Art
+
+
+ Submit Appeal
+
+
+ Create Licensing Request
+
+
+ Add Legal Memo
+
+
+ Load Maintenance Schedule
+
+
+
+ {maintenanceItems.length > 0 && (
+
+ {maintenanceItems.map((item) => (
+
+
+ Due Date: {item.due_date}
+ Status: {item.status}
+ Amount: {item.amount ?? "-"}
+ {item.status !== "Paid" && (
+ handleMarkMaintenancePaid(item.id)}
+ >
+ Mark Paid
+
+ )}
+
+
+ ))}
+
+ )}
+
+
+
+ );
+}
+
+ViewOngoingApplication.propTypes = {
+ applicationId: PropTypes.string.isRequired,
+ handleBackToList: PropTypes.func.isRequired,
+};
+
+export default ViewOngoingApplication;
diff --git a/src/Modules/Patent/components/PCCAdmin/PCCAStatusView.jsx b/src/Modules/Patent/components/PCCAdmin/PCCAStatusView.jsx
new file mode 100644
index 000000000..424f70377
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/PCCAStatusView.jsx
@@ -0,0 +1,526 @@
+import React, { useState, useEffect } from "react";
+import PropTypes from "prop-types";
+import {
+ Container,
+ Text,
+ Card,
+ Stepper,
+ Button,
+ Loader,
+ Alert,
+} from "@mantine/core";
+import { IconInfoCircle, IconAlertCircle, IconFile } from "@tabler/icons-react";
+import { CheckCircle, CircleNotch, ArrowRight } from "@phosphor-icons/react";
+import "../../style/Pcc_Admin/PCCAStatus.css";
+import { fetchPccStatusDetails } from "../../services/pccAdminService";
+
+// Progress Bar Component
+function PatentProgressBar({ currentStatus, isMobile }) {
+ const statuses = [
+ "Submitted",
+ "Reviewed by PCC Admin",
+ "Needs Revision",
+ "Attorney Assigned",
+ "Returned to Director",
+ "Forwarded for Director's Review",
+ "Director's Approval Received",
+ "Patentability Check Started",
+ "Patentability Check Completed",
+ "Patentability Search Report Generated",
+ "Patent Filed",
+ "Patent Published",
+ "Patent Granted",
+ "Patent Refused",
+ "Withdrawn",
+ ];
+
+ const getStepIndex = (status) => {
+ if (status === "Rejected") return -1;
+ if (status === "Withdrawn") return statuses.length - 1;
+ return statuses.findIndex((s) => s === status);
+ };
+
+ const currentStep = getStepIndex(currentStatus);
+ const isRejected = currentStatus === "Rejected";
+ const isWithdrawn = currentStatus === "Withdrawn";
+ const isRefused = currentStatus === "Patent Refused";
+
+ return (
+
+ {(isRejected || isWithdrawn) && (
+
+ {isWithdrawn ? "Application Withdrawn" : "Application Rejected"}
+
+ )}
+
+
+ {statuses.map((status, index) => (
+
+ ) : index === currentStep && !isWithdrawn ? (
+
+ ) : (
+
+ )
+ }
+ label={`Stage ${index + 1}`}
+ description={status}
+ className={
+ index <= currentStep || isRefused || isWithdrawn
+ ? "completed-step"
+ : "pending-step"
+ }
+ />
+ ))}
+
+
+ );
+}
+
+PatentProgressBar.propTypes = {
+ currentStatus: PropTypes.string.isRequired,
+ isMobile: PropTypes.bool.isRequired,
+};
+
+// Format date helper function
+const formatDate = (dateString) => {
+ if (!dateString) return "Not Available";
+ try {
+ const date = new Date(dateString);
+ return date.toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ });
+ } catch (error) {
+ console.error("Error formatting date:", error);
+ return "Invalid Date";
+ }
+};
+
+// File Download Button Component
+function FileDownloadButton({ fileUrl, fileName, disabled }) {
+ return (
+ }
+ >
+ View {fileName}
+
+ );
+}
+
+FileDownloadButton.propTypes = {
+ fileUrl: PropTypes.string,
+ fileName: PropTypes.string.isRequired,
+ disabled: PropTypes.bool,
+};
+
+function PCCAStatusView({ applicationId }) {
+ const [applicationData, setApplicationData] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
+
+ useEffect(() => {
+ const handleResize = () => {
+ setIsMobile(window.innerWidth <= 768);
+ };
+
+ window.addEventListener("resize", handleResize);
+ return () => {
+ window.removeEventListener("resize", handleResize);
+ };
+ }, []);
+
+ useEffect(() => {
+ const fetchApplicationDetails = async () => {
+ if (!applicationId) {
+ setError("No application ID provided");
+ setLoading(false);
+ return;
+ }
+
+ try {
+ setLoading(true);
+ const response = await fetchPccStatusDetails(applicationId);
+ setApplicationData(response);
+ setError(null);
+ } catch (err) {
+ console.error("Error fetching application details:", err);
+ setError("Failed to load application details. Please try again later.");
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchApplicationDetails();
+ }, [applicationId]);
+
+ if (loading) {
+ return (
+
+
+
+ );
+ }
+
+ if (error) {
+ return (
+
+ } title="Error" color="red">
+ {error}
+
+
+ );
+ }
+
+ if (!applicationData) {
+ return (
+
+ } title="No Data" color="blue">
+ No application data found for the specified ID.
+
+
+ );
+ }
+
+ return (
+
+ {applicationData.title || "Untitled"}
+
+
+ Application Details
+
+ Primary Applicant:
+
+ {applicationData.primary_applicant_name || "—"}
+
+
+
+ Submission Date:
+
+ {formatDate(applicationData.dates?.submitted_date)}
+
+
+
+ Application ID:
+
+ {applicationData.application_id || "—"}
+
+
+
+ Application No:
+
+ {applicationData.application_number ||
+ applicationData.token_no ||
+ "Not Assigned"}
+
+
+
+ Attorney Name:
+
+ {applicationData.attorney_name || "Not Assigned"}
+
+
+
+ Status:
+
+ {applicationData.status || "Draft"}
+
+
+
+ Decision Status:
+
+ {applicationData.decision_status || "Pending"}
+
+
+
+
+
+ Applicants
+ {applicationData.applicants && applicationData.applicants.length > 0 ? (
+ applicationData.applicants.map((applicant, index) => (
+
+
Applicant {index + 1}
+
+ Name:
+ {applicant.name || "—"}
+
+
+ Email:
+ {applicant.email || "—"}
+
+
+ Contact Address:
+ {applicant.address || "—"}
+
+
+ Mobile:
+ {applicant.mobile || "—"}
+
+
+ Percentage Share:
+
+ {applicant.percentage_share || "—"}%
+
+
+
+ ))
+ ) : (
+ No applicant information available
+ )}
+
+
+
+
+ Section I: Administrative and Technical Details
+
+
+ Title of Application:
+ {applicationData.title || "—"}
+
+
+ Area of the invention:
+
+ {applicationData.section_I?.area || "—"}
+
+
+
+ Problem in the area:
+
+ {applicationData.section_I?.problem || "—"}
+
+
+
+ Objective of your invention:
+
+ {applicationData.section_I?.objective || "—"}
+
+
+
+ Novelty:
+
+ {applicationData.section_I?.novelty || "—"}
+
+
+
+ Advantages:
+
+ {applicationData.section_I?.advantages || "—"}
+
+
+
+ Tested:
+
+ {applicationData.section_I?.is_tested === true
+ ? "Yes"
+ : applicationData.section_I?.is_tested === false
+ ? "No"
+ : "—"}
+
+
+
+ Proof of Concept Details:
+
+ {applicationData.section_I?.poc_details || "—"}
+
+
+
+ Applications:
+
+ {applicationData.section_I?.applications || "—"}
+
+
+
+
+
+ Section II: IPR Ownership
+
+ Funding Details:
+
+ {applicationData.section_II?.funding_details || "—"}
+
+
+
+ Source of funding:
+
+ {applicationData.section_II?.funding_source || "—"}
+
+
+
+
Source Agreement:
+
+ {applicationData.section_II?.source_agreement ? (
+
+ ) : (
+ "No file available"
+ )}
+
+
+
+ Publication Details:
+
+ {applicationData.section_II?.publication_details || "—"}
+
+
+
+ MOU Details:
+
+ {applicationData.section_II?.mou_details || "—"}
+
+
+
+
MOU File:
+
+ {applicationData.section_II?.mou_file ? (
+
+ ) : (
+ "No file available"
+ )}
+
+
+
+ Research Details:
+
+ {applicationData.section_II?.research_details || "—"}
+
+
+
+
+
+ Section III: Commercialization
+
+ Target Company:
+
+ {applicationData.section_III?.company_name || "—"}
+
+
+
+ Contact Person:
+
+ {applicationData.section_III?.contact_person || "—"}
+
+
+
+ Contact Number:
+
+ {applicationData.section_III?.contact_no || "—"}
+
+
+
+ Development Stage:
+
+ {applicationData.section_III?.development_stage || "—"}
+
+
+
+
Form-III:
+
+ {applicationData.section_III?.form_iii ? (
+
+ ) : (
+ "No file available"
+ )}
+
+
+
+
+
+ Important Dates
+
+ Submission Date:
+
+ {formatDate(applicationData.dates?.submitted_date)}
+
+
+
+ Assigned Date:
+
+ {formatDate(applicationData.dates?.assigned_date)}
+
+
+
+ Decision Date:
+
+ {formatDate(applicationData.dates?.decision_date)}
+
+
+
+ Patentability Check Date:
+
+ {formatDate(applicationData.dates?.patentability_check_date)}
+
+
+
+ Patentability File Date:
+
+ {formatDate(applicationData.dates?.patentability_file_date)}
+
+
+
+
+
+ Comments
+
+
+ {applicationData.comments || "No comments available."}
+
+
+
+
+
+ Application Progress
+
+
+
+ );
+}
+
+PCCAStatusView.propTypes = {
+ applicationId: PropTypes.string.isRequired,
+};
+
+export default PCCAStatusView;
diff --git a/src/Modules/Patent/components/PCCAdmin/PCCAdminMainDashboard.jsx b/src/Modules/Patent/components/PCCAdmin/PCCAdminMainDashboard.jsx
new file mode 100644
index 000000000..7c28e1b61
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/PCCAdminMainDashboard.jsx
@@ -0,0 +1,114 @@
+import React, { useEffect, useState } from "react";
+import { Grid, Container, Loader, Flex, Select } from "@mantine/core";
+import { useDispatch } from "react-redux";
+import { SortAscending } from "@phosphor-icons/react";
+import CustomBreadcrumbs from "../../../../components/Breadcrumbs.jsx";
+import ModuleTabs from "../../../../components/moduleTabs.jsx";
+import PCCAdminDashboard from "./Dashboard/PCCAdminDashboard.jsx";
+import OngoingApplication from "./OngoingApplication/OngoingApplication.jsx";
+import PastApplications from "./PastApplication/PastApplications.jsx";
+import NewApplication from "./NewApplication/NewApplicaion.jsx"; // Fixed typo in import name
+import PCCAdminNotifications from "./Notifications/PCCAdminNotification.jsx";
+import ManageAttorneys from "./ManageAttorney/ManageAttorneys.jsx";
+
+// Move constants outside of component
+const SORT_CATEGORIES = ["Most Recent", "Tags", "Title"];
+const TAB_ITEMS = [
+ { title: "Dashboard", id: "0" },
+ { title: "New Applications", id: "1" },
+ { title: "Ongoing Applications", id: "2" },
+ { title: "Past Applications", id: "3" },
+ { title: "Manage Attorney", id: "4" },
+ { title: "Notifications", id: "5" },
+];
+
+function ApplicantMainDashboard() {
+ const [activeTab, setActiveTab] = useState("0");
+ const [sortedBy, setSortedBy] = useState("Most Recent");
+ const [loading, setLoading] = useState(false);
+ const dispatch = useDispatch();
+
+ useEffect(() => {
+ const fetchData = async () => {
+ const token = localStorage.getItem("authToken");
+ if (!token) {
+ console.error("No authentication token found!");
+ return;
+ }
+
+ try {
+ setLoading(true);
+ // Fetch data logic here if needed
+ // Consider using dispatch to update Redux state
+ } catch (error) {
+ console.error("Error fetching data:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchData();
+ }, [dispatch]);
+
+ // Render the appropriate component based on active tab
+ const renderTabContent = () => {
+ if (loading) {
+ return (
+
+
+
+ );
+ }
+
+ switch (activeTab) {
+ case "0":
+ return ;
+ case "1":
+ return ;
+ case "2":
+ return ;
+ case "3":
+ return ;
+ case "4":
+ return ;
+ case "5":
+ return ;
+ default:
+ return ;
+ }
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+ }
+ data={SORT_CATEGORIES}
+ value={sortedBy}
+ onChange={setSortedBy}
+ placeholder="Sort By"
+ />
+
+
+
+ {renderTabContent()}
+ >
+ );
+}
+
+export default ApplicantMainDashboard;
diff --git a/src/Modules/Patent/components/PCCAdmin/PastApplication/PastApplications.jsx b/src/Modules/Patent/components/PCCAdmin/PastApplication/PastApplications.jsx
new file mode 100644
index 000000000..7c0b5b6f2
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/PastApplication/PastApplications.jsx
@@ -0,0 +1,390 @@
+import React, { useState, useEffect } from "react";
+import {
+ Box,
+ Button,
+ ScrollArea,
+ Table,
+ Text,
+ Loader,
+ Group,
+ Divider,
+ Select,
+} from "@mantine/core";
+import { Eye, ArrowsClockwise, Warning, Calendar } from "@phosphor-icons/react";
+import ViewPastApplication from "./ViewPastApplication";
+import "../../../style/Pcc_Admin/PastApplications.css";
+import { fetchPccPastApplications } from "../../../services/pccAdminService";
+
+function PastApplications() {
+ const [applications, setApplications] = useState([]);
+ const [filteredApplications, setFilteredApplications] = useState([]);
+ const [selectedApplication, setSelectedApplication] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [isRefreshing, setIsRefreshing] = useState(false);
+ const [selectedYears, setSelectedYears] = useState([]);
+ const [availableYears, setAvailableYears] = useState([]);
+
+ const columnNames = [
+ "S.No",
+ "Application Number",
+ "Application No",
+ "Patent Title",
+ "Inventor 1",
+ "Designation",
+ "Department",
+ "Date",
+ "Status",
+ "View",
+ ];
+
+ const formatDate = (dateString) => {
+ if (!dateString || dateString === "Not Provided") return "Not Provided";
+ try {
+ return new Date(dateString).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "short",
+ day: "numeric",
+ });
+ } catch {
+ return dateString;
+ }
+ };
+
+ const getStatusColor = (status) => {
+ if (!status) return "gray";
+ const formatted = status.trim().toLowerCase();
+ switch (formatted) {
+ case "rejected":
+ return "red";
+ case "approved":
+ return "green";
+ default:
+ return "gray";
+ }
+ };
+
+ const fetchApplications = async (refresh = false) => {
+ try {
+ if (refresh) setIsRefreshing(true);
+ else setLoading(true);
+
+ const data = await fetchPccPastApplications();
+
+ const formatted = Object.entries(data.applications || {})
+ .map(([id, details]) => ({
+ id,
+ token_no:
+ details.application_number || details.token_no || "Not Assigned",
+ title: details.title || "Not Provided",
+ submitted_by: details.submitted_by || "Not Provided",
+ designation: details.designation || "Not Provided",
+ department: details.department || "Not Provided",
+ submitted_on: details.submitted_on || "Not Provided",
+ status: details.decision_status || "Not Provided",
+ year: details.submitted_on
+ ? new Date(details.submitted_on).getFullYear().toString()
+ : "Unknown",
+ }))
+ .sort((a, b) => {
+ if (a.submitted_on === "Not Provided") return 1;
+ if (b.submitted_on === "Not Provided") return -1;
+ return new Date(b.submitted_on) - new Date(a.submitted_on);
+ });
+
+ const years = [
+ ...new Set(
+ formatted.filter((f) => f.year !== "Unknown").map((f) => f.year),
+ ),
+ ]
+ .sort((a, b) => b - a)
+ .map((year) => ({ value: year, label: year }));
+
+ setAvailableYears(years);
+ setApplications(formatted);
+ setFilteredApplications(formatted);
+ setError(null);
+ } catch (err) {
+ console.error("Error fetching applications:", err);
+ setError("Failed to load applications. Please try again later.");
+ } finally {
+ setLoading(false);
+ if (refresh) setIsRefreshing(false);
+ }
+ };
+
+ useEffect(() => {
+ fetchApplications();
+ }, []);
+
+ useEffect(() => {
+ if (!applications) return;
+ if (selectedYears.length === 0) {
+ setFilteredApplications(applications);
+ } else {
+ setFilteredApplications(
+ applications.filter((app) => selectedYears.includes(app.year)),
+ );
+ }
+ }, [selectedYears, applications]);
+
+ const handleViewClick = (id) => setSelectedApplication(id);
+ const handleRefresh = () => fetchApplications(true);
+ const handleYearChange = (years) => setSelectedYears(years);
+
+ if (loading) {
+ return (
+
+
+
+ Loading applications...
+
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+
+
+ Error Loading Applications
+
+
+
+ {error}
+
+ }
+ >
+ Retry
+
+
+ );
+ }
+
+ if (!applications || applications.length === 0) {
+ return (
+
+
+ No applications found
+
+
+ There are currently no patent applications in the system.
+
+ }
+ >
+ Refresh
+
+
+ );
+ }
+
+ return (
+
+ {!selectedApplication ? (
+ <>
+ Past Applications
+
+ }
+ >
+ {isRefreshing ? "Refreshing..." : "Refresh"}
+
+
+ }
+ id="pms-pcc-past-year-filter"
+ />
+
+
+
+
+
+
+
+ {filteredApplications.map((application, index) => (
+
+
+ {index + 1}
+
+
+ {application.id}
+
+
+ {application.token_no}
+
+
+ {application.title}
+
+
+ {application.submitted_by}
+
+
+ {application.designation}
+
+
+ {application.department}
+
+
+ {formatDate(application.submitted_on)}
+
+
+
+ {application.status}
+
+
+
+ handleViewClick(application.id)}
+ style={{
+ backgroundColor: "#fff",
+ color: "#0073e6",
+ border: "1px solid #0073e6",
+ fontWeight: 500,
+ transition: "all 0.2s ease",
+ }}
+ >
+ View
+
+
+
+ ))}
+
+
+
+
+ >
+ ) : (
+
+
+ setSelectedApplication(null)}
+ />
+
+ )}
+
+ );
+}
+
+export default PastApplications;
diff --git a/src/Modules/Patent/components/PCCAdmin/PastApplication/ViewPastApplication.jsx b/src/Modules/Patent/components/PCCAdmin/PastApplication/ViewPastApplication.jsx
new file mode 100644
index 000000000..3df3700cc
--- /dev/null
+++ b/src/Modules/Patent/components/PCCAdmin/PastApplication/ViewPastApplication.jsx
@@ -0,0 +1,702 @@
+import React, { useState, useEffect } from "react";
+import PropTypes from "prop-types";
+import {
+ Container,
+ Text,
+ Card,
+ Grid,
+ Button,
+ Loader,
+ Alert,
+ Title,
+} from "@mantine/core";
+import { ArrowLeft, DownloadSimple } from "@phosphor-icons/react";
+import "../../../style/Pcc_Admin/ViewPastApplications.css";
+import { API_BASE_URL } from "../../../services/api";
+import { fetchPccApplicationDetails } from "../../../services/pccAdminService";
+
+// Field component for detail view
+function FormField({ label, value }) {
+ return (
+
+ {label}
+ {value || "Not provided"}
+
+ );
+}
+
+FormField.propTypes = {
+ label: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+};
+
+// Field with download button for direct file URLs
+function FormFieldWithDownload({ label, value, fileUrl, fileLabel }) {
+ return (
+
+ );
+}
+
+FormFieldWithDownload.propTypes = {
+ label: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ fileUrl: PropTypes.string,
+ fileLabel: PropTypes.string.isRequired,
+};
+
+// File Download Button Component
+function FileDownloadButton({ fileUrl, label, disabled }) {
+ if (!fileUrl || fileUrl === "null" || disabled) {
+ return (
+ }
+ disabled
+ >
+ No {label} Available
+
+ );
+ }
+
+ return (
+ }
+ >
+ View {label}
+
+ );
+}
+
+FileDownloadButton.propTypes = {
+ fileUrl: PropTypes.string,
+ label: PropTypes.string.isRequired,
+ disabled: PropTypes.bool,
+};
+
+// Section component for detail view
+function FormSection({ title, children }) {
+ return (
+
+ {title}
+ {children}
+
+ );
+}
+
+FormSection.propTypes = {
+ title: PropTypes.string.isRequired,
+ children: PropTypes.node.isRequired,
+};
+
+function ViewPastApplication({ applicationId, handleBackToList }) {
+ const [selectedApplication, setSelectedApplication] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [isMobile, setIsMobile] = useState(window.innerWidth <= 768);
+ const authToken = localStorage.getItem("authToken");
+
+ useEffect(() => {
+ const handleResize = () => {
+ setIsMobile(window.innerWidth <= 768);
+ };
+
+ window.addEventListener("resize", handleResize);
+ return () => window.removeEventListener("resize", handleResize);
+ }, []);
+
+ useEffect(() => {
+ const fetchApplicationDetails = async () => {
+ if (!applicationId) {
+ setError("No application ID provided");
+ setLoading(false);
+ return;
+ }
+
+ try {
+ setLoading(true);
+ const response = await fetchPccApplicationDetails(applicationId);
+
+ if (response) {
+ setSelectedApplication(response);
+ setError(null);
+ } else {
+ setError("No application data found");
+ }
+ } catch (err) {
+ console.error("Error fetching application details:", err);
+ setError(`Failed to load application details: ${err.message}`);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchApplicationDetails();
+ }, [applicationId, authToken]);
+
+ if (loading) {
+ return (
+
+
+ Loading application details...
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+ {error}
+
+
+ Back to Applications
+
+
+ );
+ }
+
+ if (!selectedApplication) {
+ return (
+
+
+ No application data found
+
+
+ Back to Applications
+
+
+ );
+ }
+
+ const {
+ application_id,
+ title,
+ application_number,
+ token_no,
+ primary_applicant_name,
+ attorney_name,
+ status,
+ decision_status,
+ comments,
+ applicants,
+ section_I,
+ section_II,
+ section_III,
+ dates,
+ } = selectedApplication;
+ const displayApplicationNumber =
+ application_number || token_no || "Not Assigned";
+
+ const submittedDate = dates?.submitted_date
+ ? new Date(dates.submitted_date).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not recorded";
+
+ // Build file URLs
+ const mouFileUrl = section_II?.mou_file
+ ? `${API_BASE_URL}/download/file/${section_II.mou_file}/`
+ : null;
+ const formIIIFileUrl = section_III?.form_iii
+ ? `${API_BASE_URL}/download/file/${section_III.form_iii}/`
+ : null;
+ const pocFileUrl = section_I?.poc_file
+ ? `${API_BASE_URL}/download/file/${section_I.poc_file}/`
+ : null;
+ const sourceAgreementFileUrl = section_II?.source_agreement_file
+ ? `${API_BASE_URL}/download/file/${section_II.source_agreement_file}/`
+ : null;
+
+ return (
+
+
+
+ }
+ style={{
+ border: "none",
+ padding: "10px",
+ background: "none",
+ cursor: "pointer",
+ fontWeight: "500",
+ }}
+ onClick={(e) => {
+ e.stopPropagation();
+ if (typeof handleBackToList === "function") {
+ handleBackToList();
+ } else {
+ window.history.back();
+ }
+ }}
+ >
+ Back
+
+
+
+
+
+
+ Application Details
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+
Reviewed by PCC
+
+ {dates?.reviewed_by_pcc_date
+ ? new Date(dates.reviewed_by_pcc_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not yet reviewed"}
+
+
*/}
+
+
+
+ Forwarded to Director
+
+
+ {dates?.forwarded_to_director_date
+ ? new Date(
+ dates.forwarded_to_director_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not yet forwarded"}
+
+
+
+
+
Director Approval
+
+ {dates?.director_approval_date
+ ? new Date(dates.director_approval_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not yet approved"}
+
+
+
+
+
+ Patentability Check Start
+
+
+ {dates?.patentability_check_start_date
+ ? new Date(
+ dates.patentability_check_start_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not started"}
+
+
+
+
+
+ Patentability Check Completed
+
+
+ {dates?.patentability_check_completed_date
+ ? new Date(
+ dates.patentability_check_completed_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not completed"}
+
+
+
+
+
+ Search Report Generated
+
+
+ {dates?.search_report_generated_date
+ ? new Date(
+ dates.search_report_generated_date,
+ ).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ })
+ : "Not generated"}
+
+
+
+
+
Date of Filing
+
+ {dates?.patent_filed_date
+ ? new Date(dates.patent_filed_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not recorded"}
+
+
+
+
+
Date of Publication
+
+ {dates?.patent_published_date
+ ? new Date(dates.patent_published_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "Not yet published"}
+
+
+
+ {/*
+
Decision Date
+
+ {dates?.decision_date
+ ? new Date(dates.decision_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "No decision yet"}
+
+
*/}
+
+
+
Date of Granting
+
+ {dates?.final_decision_date
+ ? new Date(dates.final_decision_date).toLocaleDateString(
+ "en-US",
+ {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ },
+ )
+ : "No final decision yet"}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {applicants && applicants.length > 0 ? (
+
+ {applicants.map((applicant, index) => (
+
+
+
+ Applicant {index + 1}
+
+
+
+
+
+
+
+
+ ))}
+
+ ) : (
+ No applicant information available
+ )}
+
+
+
+ );
+}
+
+ViewPastApplication.propTypes = {
+ applicationId: PropTypes.string.isRequired,
+ handleBackToList: PropTypes.func.isRequired,
+};
+
+export default ViewPastApplication;
diff --git a/src/Modules/Patent/components/common/LoadingSpinner.jsx b/src/Modules/Patent/components/common/LoadingSpinner.jsx
new file mode 100644
index 000000000..6e17ac2a9
--- /dev/null
+++ b/src/Modules/Patent/components/common/LoadingSpinner.jsx
@@ -0,0 +1,26 @@
+import React from "react";
+import PropTypes from "prop-types";
+import { Box, Loader, Text } from "@mantine/core";
+
+function LoadingSpinner({ message = "Loading..." }) {
+ return (
+
+
+ {message}
+
+ );
+}
+
+LoadingSpinner.propTypes = {
+ message: PropTypes.string,
+};
+
+export default LoadingSpinner;
diff --git a/src/Modules/Patent/components/forms/PatentApplicationForm.jsx b/src/Modules/Patent/components/forms/PatentApplicationForm.jsx
new file mode 100644
index 000000000..9dc89fd25
--- /dev/null
+++ b/src/Modules/Patent/components/forms/PatentApplicationForm.jsx
@@ -0,0 +1 @@
+export { default as PatentApplicationForm } from "../Applicant/SubmitNewApplication/ApplicationForm";
diff --git a/src/Modules/Patent/components/tables/PatentApplicationsTable.jsx b/src/Modules/Patent/components/tables/PatentApplicationsTable.jsx
new file mode 100644
index 000000000..d84eedd2d
--- /dev/null
+++ b/src/Modules/Patent/components/tables/PatentApplicationsTable.jsx
@@ -0,0 +1 @@
+export { default as PatentApplicationsTable } from "../Applicant/ViewApplication/ApplicationView";
diff --git a/src/Modules/Patent/pages/PatentModulePage.jsx b/src/Modules/Patent/pages/PatentModulePage.jsx
new file mode 100644
index 000000000..de95e0b75
--- /dev/null
+++ b/src/Modules/Patent/pages/PatentModulePage.jsx
@@ -0,0 +1,41 @@
+import React from "react";
+import PropTypes from "prop-types";
+import ApplicantMainDashboard from "../components/Applicant/ApplicantMainDashboard";
+import AttorneyMainDashboard from "../components/Attorney/AttorneyMainDashboard";
+import DirectorMainDashboard from "../components/Director/DirectorMainDashboard";
+import PCCAdminMainDashboard from "../components/PCCAdmin/PCCAdminMainDashboard";
+
+function PatentModulePage({ role }) {
+ if (
+ [
+ "student",
+ "alumini",
+ "Professor",
+ "Associate Professor",
+ "Assistant Professor",
+ "Research Engineer",
+ ].includes(role)
+ ) {
+ return ;
+ }
+
+ if (role === "Director") {
+ return ;
+ }
+
+ if (role === "PCC Admin") {
+ return ;
+ }
+
+ if (role === "Attorney") {
+ return ;
+ }
+
+ return null;
+}
+
+PatentModulePage.propTypes = {
+ role: PropTypes.string,
+};
+
+export default PatentModulePage;
diff --git a/src/Modules/Patent/routes/PatentRoutes.jsx b/src/Modules/Patent/routes/PatentRoutes.jsx
new file mode 100644
index 000000000..d68dd7b18
--- /dev/null
+++ b/src/Modules/Patent/routes/PatentRoutes.jsx
@@ -0,0 +1,71 @@
+import { Route, Routes, Navigate } from "react-router-dom";
+import { useSelector } from "react-redux";
+import { Layout } from "../../../components/layout";
+
+import PCCStatusView from "../components/PCCAdmin/PCCAStatusView";
+import PatentModulePage from "../pages/PatentModulePage";
+
+export default function PatentRoutes() {
+ const role = useSelector((state) => state.user.role);
+
+ return (
+
+ {/* Applicant Routes - Only for applicants or inventors */}
+ {[
+ "student",
+ "alumini",
+ "Professor",
+ "Associate Professor",
+ "Assistant Professor",
+ "Research Engineer",
+ ].includes(role) && (
+
+
+
+ }
+ />
+ )}
+
+ {/* Director Routes - Only for Director */}
+ {role === "Director" && (
+
+
+
+ }
+ />
+ )}
+
+ {/* PCC Admin Routes - Only for PCC Admin */}
+ {role === "PCC Admin" && (
+
+
+
+ }
+ />
+ )}
+
+ {role === "PCC Admin" && (
+
+
+
+ }
+ />
+ )}
+
+ {/* Redirect users without access */}
+ } />
+
+ );
+}
diff --git a/src/Modules/Patent/services/api.js b/src/Modules/Patent/services/api.js
new file mode 100644
index 000000000..2bba4ffe0
--- /dev/null
+++ b/src/Modules/Patent/services/api.js
@@ -0,0 +1,22 @@
+import axios from "axios";
+import { host } from "../../../routes/globalRoutes/index.jsx";
+
+export const API_BASE_URL = `${host}/patentsystem`;
+
+const apiClient = axios.create({
+ baseURL: API_BASE_URL,
+});
+
+export const getAuthToken = () => localStorage.getItem("authToken");
+
+export const authHeaders = (extraHeaders = {}) => {
+ const token = getAuthToken();
+ return {
+ headers: {
+ Authorization: `Token ${token}`,
+ ...extraHeaders,
+ },
+ };
+};
+
+export default apiClient;
diff --git a/src/Modules/Patent/services/applicantService.js b/src/Modules/Patent/services/applicantService.js
new file mode 100644
index 000000000..ab49f53ec
--- /dev/null
+++ b/src/Modules/Patent/services/applicantService.js
@@ -0,0 +1,44 @@
+import apiClient, { authHeaders } from "./api";
+
+export const fetchApplicantApplications = async () => {
+ const response = await apiClient.get(
+ "/applicant/applications/",
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const fetchApplicantApplicationDetails = async (applicationId) => {
+ const response = await apiClient.get(
+ `/applicant/applications/details/${applicationId}`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const submitApplicantApplication = async (formData) => {
+ const response = await apiClient.post(
+ "/applicant/applications/submit/",
+ formData,
+ authHeaders({ "Content-Type": "multipart/form-data" }),
+ );
+ return response.data;
+};
+
+export const withdrawApplicantApplication = async (applicationId) => {
+ const response = await apiClient.post(
+ `/applicant/applications/${applicationId}/withdraw/`,
+ {},
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const resubmitApplicantApplication = async (applicationId) => {
+ const response = await apiClient.post(
+ `/applicant/applications/${applicationId}/resubmit/`,
+ {},
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
diff --git a/src/Modules/Patent/services/attorneyService.jsx b/src/Modules/Patent/services/attorneyService.jsx
new file mode 100644
index 000000000..98bab742f
--- /dev/null
+++ b/src/Modules/Patent/services/attorneyService.jsx
@@ -0,0 +1,253 @@
+import axios from "axios";
+import { host } from "../../../routes/globalRoutes/index.jsx";
+
+const API_BASE_URL = `${host}/patentsystem`;
+
+// Helper function to get token
+const getAuthToken = () => {
+ const token = localStorage.getItem("authToken");
+ if (!token) {
+ throw new Error("Authentication token not found. Please log in.");
+ }
+ return token;
+};
+
+// Helper function to validate ID
+const validateId = (id, entityName) => {
+ if (id === undefined || id === null || id === "") {
+ throw new Error(`${entityName} ID is required`);
+ }
+ // Convert to string for comparison since IDs might come as numbers
+ if (String(id) === "undefined") {
+ throw new Error(`Invalid ${entityName} ID provided`);
+ }
+};
+
+export const attorneyService = {
+ fetchAttorneyApplications: async () => {
+ const token = getAuthToken();
+ const response = await axios.get(`${API_BASE_URL}/attorney/applications/`, {
+ headers: {
+ Authorization: `Token ${token}`,
+ "Content-Type": "application/json",
+ },
+ });
+ return response.data;
+ },
+
+ forwardAttorneyApplicationToDirector: async (applicationId, comments) => {
+ const token = getAuthToken();
+ const response = await axios.post(
+ `${API_BASE_URL}/attorney/applications/${applicationId}/forward/`,
+ { comments },
+ {
+ headers: {
+ Authorization: `Token ${token}`,
+ "Content-Type": "application/json",
+ },
+ },
+ );
+ return response.data;
+ },
+
+ // Get all attorneys with their application counts
+ getAttorneys: async () => {
+ try {
+ const token = getAuthToken();
+ // First get the list of attorneys
+ const attorneysResponse = await axios.get(
+ `${API_BASE_URL}/pccAdmin/attorneys/`,
+ {
+ headers: {
+ Authorization: `Token ${token}`,
+ "Content-Type": "application/json",
+ },
+ },
+ );
+
+ // For each attorney, fetch their application count
+ const attorneysWithCounts = await Promise.all(
+ attorneysResponse.data.map(async (attorney) => {
+ try {
+ const applicationsResponse = await axios.get(
+ `${API_BASE_URL}/pccAdmin/attorneys/${attorney.id}/applications/`,
+ {
+ headers: {
+ Authorization: `Token ${token}`,
+ "Content-Type": "application/json",
+ },
+ },
+ );
+ return {
+ ...attorney,
+ assigned_applications_count:
+ applicationsResponse.data.assigned_applications_count || 0,
+ };
+ } catch (error) {
+ console.error(
+ `Error fetching applications for attorney ${attorney.id}:`,
+ error,
+ );
+ return {
+ ...attorney,
+ assigned_applications_count: 0,
+ };
+ }
+ }),
+ );
+
+ return attorneysWithCounts;
+ } catch (error) {
+ if (error.response?.status === 401) {
+ throw new Error("Authentication failed. Please log in again.");
+ } else if (error.response?.status === 404) {
+ throw new Error(
+ "API endpoint not found. Please check the server configuration.",
+ );
+ }
+ console.error("Error fetching attorneys:", error);
+ throw error;
+ }
+ },
+
+ // Get attorney details with applications
+ getAttorneyDetails: async (attorneyId) => {
+ try {
+ validateId(attorneyId, "attorney");
+ const token = getAuthToken();
+
+ // Get the attorney details from the main endpoint
+ const detailsResponse = await axios.get(
+ `${API_BASE_URL}/pccAdmin/attorneys/`,
+ {
+ headers: {
+ Authorization: `Token ${token}`,
+ "Content-Type": "application/json",
+ },
+ },
+ );
+
+ // Find the attorney with matching ID and normalize the data structure
+ const attorneyDetails = detailsResponse.data.find(
+ (attorney) => attorney.id === attorneyId,
+ );
+
+ if (!attorneyDetails) {
+ throw new Error("Attorney not found");
+ }
+
+ // Get the applications data from the applications endpoint
+ const applicationsResponse = await axios.get(
+ `${API_BASE_URL}/pccAdmin/attorneys/${attorneyId}/applications/`,
+ {
+ headers: {
+ Authorization: `Token ${token}`,
+ "Content-Type": "application/json",
+ },
+ },
+ );
+
+ // Combine and normalize the data from both endpoints
+ const combinedData = {
+ id: attorneyDetails.id,
+ name: attorneyDetails.name,
+ email: attorneyDetails.email,
+ phone: attorneyDetails.phone,
+ firm_name: attorneyDetails.firm_name,
+ applications: applicationsResponse.data.applications || [],
+ assigned_applications_count:
+ applicationsResponse.data.assigned_applications_count || 0,
+ };
+
+ console.log("Combined attorney details:", combinedData);
+ return combinedData;
+ } catch (error) {
+ if (error.response?.status === 401) {
+ throw new Error("Authentication failed. Please log in again.");
+ } else if (error.response?.status === 404) {
+ throw new Error("Attorney not found.");
+ }
+ console.error("Error fetching attorney details:", error);
+ throw error;
+ }
+ },
+
+ // Update attorney details
+ updateAttorney: async (attorneyId, data) => {
+ try {
+ validateId(attorneyId, "attorney");
+ const token = getAuthToken();
+ const response = await axios.put(
+ `${API_BASE_URL}/pccAdmin/attorneys/${attorneyId}/update/`,
+ data,
+ {
+ headers: {
+ Authorization: `Token ${token}`,
+ "Content-Type": "application/json",
+ },
+ },
+ );
+ return response.data;
+ } catch (error) {
+ if (error.response?.status === 401) {
+ throw new Error("Authentication failed. Please log in again.");
+ } else if (error.response?.status === 404) {
+ throw new Error("Attorney not found.");
+ }
+ console.error("Error updating attorney:", error);
+ throw error;
+ }
+ },
+
+ // Add new attorney
+ addAttorney: async (data) => {
+ try {
+ const token = getAuthToken();
+ const response = await axios.post(
+ `${API_BASE_URL}/pccAdmin/attorneys/add/`,
+ data,
+ {
+ headers: {
+ Authorization: `Token ${token}`,
+ "Content-Type": "application/json",
+ },
+ },
+ );
+ return response.data;
+ } catch (error) {
+ if (error.response?.status === 401) {
+ throw new Error("Authentication failed. Please log in again.");
+ } else if (error.response?.status === 400) {
+ throw new Error("Invalid attorney data. Please check your input.");
+ }
+ console.error("Error adding attorney:", error);
+ throw error;
+ }
+ },
+
+ // Remove attorney
+ removeAttorney: async (attorneyId) => {
+ try {
+ validateId(attorneyId, "attorney");
+ const token = getAuthToken();
+ const response = await axios.delete(
+ `${API_BASE_URL}/pccAdmin/attorneys/${attorneyId}/remove/`,
+ {
+ headers: {
+ Authorization: `Token ${token}`,
+ "Content-Type": "application/json",
+ },
+ },
+ );
+ return response.data;
+ } catch (error) {
+ if (error.response?.status === 401) {
+ throw new Error("Authentication failed. Please log in again.");
+ } else if (error.response?.status === 404) {
+ throw new Error("Attorney not found.");
+ }
+ console.error("Error removing attorney:", error);
+ throw error;
+ }
+ },
+};
diff --git a/src/Modules/Patent/services/directorService.js b/src/Modules/Patent/services/directorService.js
new file mode 100644
index 000000000..6c7138c7c
--- /dev/null
+++ b/src/Modules/Patent/services/directorService.js
@@ -0,0 +1,72 @@
+import apiClient, { authHeaders } from "./api";
+
+export const fetchDirectorReviewedApplications = async () => {
+ const response = await apiClient.get(
+ "/director/reviewedapplications",
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const fetchDirectorSubmittedApplications = async () => {
+ const response = await apiClient.get(
+ "/director/applications/new/",
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const fetchDirectorApplicationDetails = async (applicationId) => {
+ const response = await apiClient.post(
+ "/director/application/details",
+ { application_id: applicationId },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const approveDirectorApplication = async (applicationId, comments) => {
+ const response = await apiClient.post(
+ "/director/application/accept",
+ {
+ application_id: applicationId,
+ comments,
+ },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const rejectDirectorApplication = async (applicationId, comments) => {
+ const response = await apiClient.post(
+ "/director/application/reject",
+ { application_id: applicationId, comments },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchAvailableAttorneys = async () => {
+ const response = await apiClient.get("/pccAdmin/attorneys/", authHeaders());
+ return response.data;
+};
+
+export const fetchDirectorInsightsReport = async (year) => {
+ const response = await apiClient.get("/director/insights/", {
+ ...authHeaders(),
+ params: year ? { year } : {},
+ });
+ return response.data;
+};
+
+export const downloadDirectorInsightsCsv = async (year) => {
+ const response = await apiClient.get("/director/insights/", {
+ ...authHeaders(),
+ params: {
+ ...(year ? { year } : {}),
+ format: "csv",
+ },
+ responseType: "blob",
+ });
+ return response.data;
+};
diff --git a/src/Modules/Patent/services/documentService.jsx b/src/Modules/Patent/services/documentService.jsx
new file mode 100644
index 000000000..77eba60b3
--- /dev/null
+++ b/src/Modules/Patent/services/documentService.jsx
@@ -0,0 +1,42 @@
+import axios from "axios";
+import { host } from "../../../routes/globalRoutes/index.jsx";
+
+const API_BASE = `${host}/patentsystem`;
+
+const getAuthHeaders = () => {
+ const token = localStorage.getItem("authToken");
+ return {
+ headers: {
+ Authorization: `Token ${token}`,
+ },
+ };
+};
+
+export const fetchDocuments = async () => {
+ const response = await axios.get(`${API_BASE}/documents/`, getAuthHeaders());
+ return response.data;
+};
+
+export const addDocument = async (document) => {
+ try {
+ const response = await axios.post(
+ `${API_BASE}/documents/`,
+ document,
+ getAuthHeaders(),
+ );
+ return response.data;
+ } catch (error) {
+ console.error(
+ "Error adding document:",
+ error.response?.data || error.message,
+ );
+ throw error;
+ }
+};
+
+export const deleteDocument = async (id) => {
+ await axios.delete(
+ `${API_BASE}/pccAdmin/documents/${id}/delete/`,
+ getAuthHeaders(),
+ );
+};
diff --git a/src/Modules/Patent/services/pccAdminService.js b/src/Modules/Patent/services/pccAdminService.js
new file mode 100644
index 000000000..ea64db5c3
--- /dev/null
+++ b/src/Modules/Patent/services/pccAdminService.js
@@ -0,0 +1,364 @@
+import apiClient, { authHeaders } from "./api";
+
+export const fetchPccNewApplications = async () => {
+ const response = await apiClient.get(
+ "/pccAdmin/applications/new/",
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const fetchPccPastApplications = async () => {
+ const response = await apiClient.get(
+ "/pccAdmin/applications/past/",
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const fetchPccOngoingApplications = async () => {
+ const response = await apiClient.get(
+ "/pccAdmin/applications/ongoing/",
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const fetchPccApplicationDetails = async (applicationId) => {
+ const response = await apiClient.get(
+ `/pccAdmin/applications/details/${applicationId}/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const fetchPccStatusDetails = async (applicationId) => {
+ const response = await apiClient.get(
+ `/pccAdmin/applications/status/details/${applicationId}/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const fetchPccAttorneys = async () => {
+ const response = await apiClient.get("/pccAdmin/attorneys/", authHeaders());
+ return response.data;
+};
+
+export const fetchPccDirectors = async () => {
+ const response = await apiClient.get("/pccAdmin/directors/", authHeaders());
+ return response.data;
+};
+
+export const reviewPccApplication = async (applicationId, comments = "") => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/new/review/${applicationId}/`,
+ { comments },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const forwardPccApplicationToDirector = async (
+ applicationId,
+ attorneyName,
+ directorUserId,
+ budgetEstimate,
+ comments,
+) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/new/forward/${applicationId}/`,
+ {
+ attorney_name: attorneyName,
+ director_user_id: directorUserId,
+ budget_estimate: budgetEstimate,
+ comments,
+ },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const requestPccApplicationModification = async (
+ applicationId,
+ comments,
+) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/new/requestModification/${applicationId}/`,
+ { comments },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const updatePccOngoingApplicationStatus = async (
+ applicationId,
+ nextStatus,
+) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/ongoing/changeStatus/${applicationId}/`,
+ { next_status: nextStatus },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response;
+};
+
+export const fetchPccInsightsReport = async (year) => {
+ const response = await apiClient.get("/pccAdmin/insights/", {
+ ...authHeaders(),
+ params: year ? { year } : {},
+ });
+ return response.data;
+};
+
+export const downloadPccInsightsCsv = async (year) => {
+ const response = await apiClient.get("/pccAdmin/insights/", {
+ ...authHeaders(),
+ params: {
+ ...(year ? { year } : {}),
+ format: "csv",
+ },
+ responseType: "blob",
+ });
+ return response.data;
+};
+
+export const submitLegalAssessment = async (applicationId, payload) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/${applicationId}/legal-assessment/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchLegalAssessments = async (applicationId) => {
+ const response = await apiClient.get(
+ `/pccAdmin/applications/${applicationId}/legal-assessment/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const resubmitApplicationRevision = async (applicationId) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/new/resubmit/${applicationId}/`,
+ {},
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const submitBudgetRequest = async (applicationId, payload) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/${applicationId}/budget/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const decideBudgetRequest = async (budgetId, payload) => {
+ const response = await apiClient.post(
+ `/pccAdmin/budget/${budgetId}/decision/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const logExternalFiling = async (applicationId, payload) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/${applicationId}/external-filing/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchExternalFilingRecords = async (applicationId) => {
+ const response = await apiClient.get(
+ `/pccAdmin/applications/${applicationId}/external-filing/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const fetchMaintenanceSchedule = async (applicationId) => {
+ const response = await apiClient.get(
+ `/pccAdmin/applications/${applicationId}/maintenance/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const markMaintenancePaid = async (scheduleId) => {
+ const response = await apiClient.post(
+ `/pccAdmin/maintenance/${scheduleId}/mark-paid/`,
+ {},
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchSystemNotifications = async (role) => {
+ const response = await apiClient.get("/notifications/", {
+ ...authHeaders(),
+ params: role ? { role } : {},
+ });
+ return response.data;
+};
+
+export const uploadDocumentVersion = async (documentId, payload) => {
+ const response = await apiClient.post(
+ `/documents/${documentId}/versions/upload/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchDocumentVersions = async (documentId) => {
+ const response = await apiClient.get(
+ `/documents/${documentId}/versions/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const setDocumentRevisionLock = async (documentId, isLocked) => {
+ const response = await apiClient.post(
+ `/documents/${documentId}/lock/`,
+ { is_locked: isLocked },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchPrioritizedQueue = async () => {
+ const response = await apiClient.get(
+ "/pccAdmin/queue/prioritized/",
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const fetchAuditLogs = async (applicationId) => {
+ const path = applicationId ? `/audit-logs/${applicationId}/` : "/audit-logs/";
+ const response = await apiClient.get(path, authHeaders());
+ return response.data;
+};
+
+export const fetchOfficeActions = async (applicationId) => {
+ const response = await apiClient.get(
+ `/pccAdmin/applications/${applicationId}/office-actions/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const createOfficeAction = async (applicationId, payload) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/${applicationId}/office-actions/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const respondOfficeAction = async (actionId, payload) => {
+ const response = await apiClient.post(
+ `/pccAdmin/office-actions/${actionId}/respond/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchPriorArt = async (applicationId, query) => {
+ const response = await apiClient.get(
+ `/pccAdmin/applications/${applicationId}/prior-art/`,
+ {
+ ...authHeaders(),
+ params: query ? { q: query } : {},
+ },
+ );
+ return response.data;
+};
+
+export const createPriorArt = async (applicationId, payload) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/${applicationId}/prior-art/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchAppeals = async (applicationId) => {
+ const response = await apiClient.get(
+ `/pccAdmin/applications/${applicationId}/appeals/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const createAppeal = async (applicationId, payload) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/${applicationId}/appeals/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchLicensingRequests = async (applicationId) => {
+ const response = await apiClient.get(
+ `/pccAdmin/applications/${applicationId}/licensing/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const createLicensingRequest = async (applicationId, payload) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/${applicationId}/licensing/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchInventorConsents = async (applicationId) => {
+ const response = await apiClient.get(
+ `/pccAdmin/applications/${applicationId}/inventor-consents/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const createInventorConsent = async (applicationId, payload) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/${applicationId}/inventor-consents/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchLegalMemos = async (applicationId) => {
+ const response = await apiClient.get(
+ `/pccAdmin/applications/${applicationId}/legal-memos/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const createLegalMemo = async (applicationId, payload) => {
+ const response = await apiClient.post(
+ `/pccAdmin/applications/${applicationId}/legal-memos/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
diff --git a/src/Modules/Patent/style/Applicant/ApplicantDashboard.css b/src/Modules/Patent/style/Applicant/ApplicantDashboard.css
new file mode 100644
index 000000000..a895ecd34
--- /dev/null
+++ b/src/Modules/Patent/style/Applicant/ApplicantDashboard.css
@@ -0,0 +1,189 @@
+/* General Page Styling */
+/* Title Styling */
+#pms-dashboard-title {
+ font-size: 26px;
+ font-weight: bold;
+ color: #000;
+ margin-bottom: 16px;
+ text-align: center;
+}
+
+
+/* Content Below Title */
+#pms-dashboard-content-container {
+ max-width: 95%;
+ font-size: 16px;
+ margin-bottom: 32px;
+ background-color: #ffffff;
+ padding: 24px;
+ border-radius: 8px;
+ box-shadow: 0px 4px 15px rgba(0, 0, 0, 0.2);
+}
+
+/* Feature Box Container */
+#pms-dashboard-feature-box-container {
+ display: flex;
+ flex-direction: column;
+ margin: 16px;
+}
+
+/* Individual Feature Box */
+#pms-dashboard-feature-box-with-hover {
+ display: flex;
+ align-items: center;
+ padding: 16px;
+ border-radius: 8px;
+ background-color: #f5f7f8;
+ box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
+ border: 1px solid #e2e8f0;
+ margin-bottom: 16px;
+ transition: box-shadow 0.3s ease, transform 0.3s ease;
+ cursor: pointer;
+}
+
+#pms-dashboard-feature-box-with-hover:hover {
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.15);
+ transform: translateY(-4px);
+}
+
+/* Feature Icon */
+#pms-dashboard-feature-icon {
+ margin-right: 16px;
+ color: #0073e6;
+}
+
+/* Feature Title */
+#pms-dashboard-feature-box-title {
+ font-weight: 700;
+ font-size: 16px;
+ color: #2d3748;
+}
+
+#pms-dashboard-divider {
+ margin: 16px 0;
+ border: 1px solid #e2e8f0;
+ width: 100%;
+}
+
+/* Progress Bar Container */
+#pms-dashboard-workflow-container {
+ max-width: 100%;
+ margin-bottom: 32px;
+ margin-top: 32px;
+}
+
+/* Section Title */
+#pms-dashboard-section-title {
+ font-size: 1.5rem;
+ font-weight: 550;
+ color: #2d3748;
+ margin-bottom: 1rem;
+ text-align: left;
+}
+
+/* Mobile Progress Bar Container */
+#pms-dashboard-mobile-progress-container {
+ display: flex;
+ align-items: center;
+ margin-top: 24px;
+}
+
+/* Vertical Progress Bar */
+#pms-dashboard-mobile-progress-bar {
+ height: 300px;
+ width: 20px;
+
+}
+
+/* Progress Labels */
+#pms-dashboard-mobile-progress-labels {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+
+#pms-dashboard-mobile-progress-label {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+#pms-dashboard-mobile-progress-dot {
+ height: 14px;
+ width: 14px;
+ border-radius: 50%;
+ border: 2px solid white;
+ box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.2);
+}
+
+/* Hide Mobile Progress Bar on Larger Screens */
+@media (min-width: 768px) {
+ #pms-dashboard-mobile-progress-container {
+ display: none;
+ }
+}
+
+/* Hide Horizontal Progress Bar on Smaller Screens */
+@media (max-width: 768px) {
+ #pms-status-progress-container {
+ display: none;
+ }
+}
+
+/* Dashboard Grid */
+#pms-dashboard-grid {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 30px;
+ padding-top: 0px;
+}
+
+/* Responsive Behavior */
+@media (max-width: 768px) {
+ #pms-dashboard-grid {
+ grid-template-columns: 1fr;
+ }
+}
+
+/* Dashboard Cards */
+#pms-dashboard-cards {
+ background-color: #fff;
+ padding: 32px;
+ margin: 10px;
+ border-radius: 10px;
+ box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.2);
+ transition: box-shadow 0.3s ease, transform 0.3s ease;
+ text-align: left;
+ cursor: pointer;
+ flex: 1 1 calc(50% - 12px); /* Two cards per row on larger screens */
+}
+
+#pms-dashboard-cards:hover {
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.15);
+ transform: translateY(-4px);
+}
+
+/* Card Title */
+#pms-dashboard-card-title {
+ font-size: 20px;
+ font-weight: 600;
+ color:rgb(41, 146, 191);
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+/* Card Divider */
+#pms-dashboard-card-divider {
+ margin-top: 12px;
+ width: 100%;
+ border: 1px solid #f0f0f0;
+ margin-bottom: 12px;
+}
+
+/* Responsive Behavior */
+@media (max-width: 768px) {
+ #pms-dashboard-cards {
+ flex: 1 1 100%; /* One card per row on smaller screens */
+ }
+}
\ No newline at end of file
diff --git a/src/Modules/Patent/style/Applicant/ApplicantSubmit.css b/src/Modules/Patent/style/Applicant/ApplicantSubmit.css
new file mode 100644
index 000000000..dfc5e0c62
--- /dev/null
+++ b/src/Modules/Patent/style/Applicant/ApplicantSubmit.css
@@ -0,0 +1,101 @@
+/* Page title */
+#pms-submit-header-text {
+ font-size: 24px;
+ font-weight: 600;
+ letter-spacing: 0.5px;
+ padding-left: 50px;
+ margin-bottom: 10px;
+}
+
+/* Card container */
+#pms-submit-card-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 24px;
+}
+
+/* Application card */
+#pms-submit-application-card {
+ flex: 1;
+ min-width: 45%;
+ max-width: 45%;
+ margin-left: 0;
+ padding: 25px;
+ border-radius: 12px;
+ background-color: #ffffff;
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.2);
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+#pms-submit-application-card:hover {
+ transform: translateY(-4px);
+ box-shadow: 0px 6px 16px rgba(0, 0, 0, 0.15);
+}
+
+/* Card title */
+#pms-submit-card-title {
+ font-size: 22px;
+ font-weight: 500;
+ margin-bottom: 4px;
+ color: #2b3547;
+}
+
+/* Card details */
+#pms-submit-card-details {
+ font-size: 14px;
+ color: #6b7280;
+ margin-bottom: 4px;
+}
+
+/* Card description */
+#pms-submit-card-description {
+ font-size: 14px;
+ color: #4a5568;
+ line-height: 1.5;
+ margin-bottom: 16px;
+}
+
+/* Start Application button */
+#pms-start-application-button {
+ margin-top: 16px;
+ background-color: #fff;
+ border: 1px solid #15abff;
+ color: #15abff;
+ font-size: 14px;
+ font-weight: 500;
+ transition: background-color 0.3s ease, color 0.3s ease;
+}
+
+#pms-start-application-button:hover {
+ background-color: #15abff;
+ color: #fff;
+}
+
+/* Responsive behavior for smaller screens */
+@media (max-width: 768px) {
+ #pms-submit-card-container {
+ margin-left: 16px;
+ margin-right: 16px;
+ }
+
+ #pms-submit-application-card {
+ min-width: 100%;
+ max-width: 100%;
+ }
+
+ #pms-submit-header-text {
+ padding-left: 16px;
+ }
+}
+
+@media (max-width: 480px) {
+ #pms-submit-header-text {
+ padding-left: 8px;
+ font-size: 26px;
+ }
+
+ #pms-submit-card-container {
+ margin-left: 8px;
+ margin-right: 8px;
+ }
+}
\ No newline at end of file
diff --git a/src/Modules/Patent/style/Applicant/ApplicationDraft.css b/src/Modules/Patent/style/Applicant/ApplicationDraft.css
new file mode 100644
index 000000000..98850ca86
--- /dev/null
+++ b/src/Modules/Patent/style/Applicant/ApplicationDraft.css
@@ -0,0 +1,53 @@
+/* Page title */
+#patent-system-draft-header-text {
+ font-size: 24px;
+ font-weight: 700;
+ color: #2d3748;
+ letter-spacing: 0.5px;
+ padding-left: 50px;
+ margin-bottom: 10px;
+}
+
+/* Saved drafts container for flex layout */
+#patent-system-draft-app-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 24px;
+ width: 100%;
+}
+
+/* Saved draft card */
+#patent-system-saved-draft-card {
+ flex: 1;
+ min-width: 40%;
+ max-width: 40%;
+ margin-left: 50px;
+ padding: 16px;
+ border-radius: 12px;
+ background-color: #ffffff;
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.2);
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+#patent-system-saved-draft-card:hover {
+ transform: translateY(-4px);
+ box-shadow: 0px 6px 16px rgba(0, 0, 0, 0.15);
+}
+
+
+/* Responsive behavior for smaller screens */
+@media (max-width: 768px) {
+ #patent-system-draft-app-container {
+ margin-left: 16px;
+ margin-right: 16px;
+ }
+
+ #patent-system-saved-draft-card {
+ min-width: 100%;
+ max-width: 100%;
+ }
+
+ #patent-system-draft-header-text {
+ padding-left: 10px;
+ }
+}
diff --git a/src/Modules/Patent/style/Applicant/ApplicationView.css b/src/Modules/Patent/style/Applicant/ApplicationView.css
new file mode 100644
index 000000000..477c8b896
--- /dev/null
+++ b/src/Modules/Patent/style/Applicant/ApplicationView.css
@@ -0,0 +1,648 @@
+/* Application View Container */
+#pms-application-view-container {
+ width: 100%;
+ padding: 0;
+ padding-left: 0px;
+ padding-right: 0px;
+ max-width: 100%;
+ margin: 0 50px;
+}
+
+/* Page Title */
+#pms-view-app-page-title {
+ font-size: 24px;
+ font-weight: 600;
+ color: #2d3748;
+ margin-bottom: 10px;
+ margin-top: 0;
+ text-align: left;
+ padding: 0;
+}
+
+#pms-form-title::after {
+ content: "";
+ display: block;
+ width: 80px;
+ height: 4px;
+ /* background: #4c6ef5; */
+ margin: 10px auto 0;
+ border-radius: 2px;
+}
+
+/* Applications Grid - Modified for 2 cards per row */
+#pms-view-applications-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 24px;
+ margin: 0 auto;
+ padding: 0;
+ width: 100%;
+ max-width: 100%;
+}
+
+/* Application Card */
+#pms-application-card {
+ padding: 25px;
+ border-radius: 12px;
+ background-color: #ffffff;
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.2);
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+ height: 100%;
+ width: 100%;
+}
+
+#pms-application-card:hover {
+ transform: translateY(-4px);
+ box-shadow: 0px 6px 16px rgba(0, 0, 0, 0.15);
+}
+
+/* Card Title */
+#pms-app-card-title {
+ font-size: 22px;
+ font-weight: 500;
+ color: #2b3547;
+ margin-bottom: 2px;
+}
+
+/* Card Info Items */
+#pms-app-card-info {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+#pms-info-item {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+}
+
+#pms-info-text {
+ font-size: 14px;
+ color: #6b7280;
+}
+
+/* Status Badge */
+#pms-card-badge-container {
+ margin-top: 6px;
+}
+
+/* View Button */
+#pms-view-application-button {
+ margin-top: 16px;
+ background-color: #fff;
+ border: 1px solid #15abff;
+ color: #15abff;
+ font-size: 14px;
+ font-weight: 500;
+ transition: background-color 0.3s ease, color 0.3s ease;
+}
+
+#pms-view-application-button:hover {
+ background-color: #15abff;
+ color: #fff;
+}
+
+/* Empty State Card */
+#pms-empty-state-card {
+ max-width: 600px;
+ margin: 0 0;
+ text-align: left;
+ padding: 25px;
+ border-radius: 12px;
+ background-color: #ffffff;
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.2);
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+#pms-empty-state-card:hover {
+ transform: translateY(-4px);
+ box-shadow: 0px 6px 16px rgba(0, 0, 0, 0.15);
+}
+
+#pms-empty-state-card button {
+ margin-top: 16px;
+ background-color: #fff;
+ border: 1px solid #15abff;
+ color: #15abff;
+ font-size: 14px;
+ font-weight: 500;
+ transition: background-color 0.3s ease, color 0.3s ease;
+}
+
+#pms-empty-state-card button:hover {
+ background-color: #15abff;
+ color: #fff;
+}
+
+/* Loader Container */
+#pms-loader-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ min-height: 200px;
+ padding: 40px 0;
+}
+
+/* ApplicationView#pms-css - FORM PART ONLY (Detail View) */
+
+/* Detail View Container */
+#pms-detail-container {
+ width: 100%;
+ max-width: 100%;
+ margin: 0;
+ padding: 0px;
+ border-radius: 8px;
+ background-color: #f5f7f8;
+ border: 1px solid #ccc;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0);
+}
+
+/* Form Content */
+#pms-form-content {
+ background: #f5f7f8;
+ border-radius: 8px;
+ padding: 0;
+ width: 95%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin: 0 auto;
+}
+
+/* Sections */
+#pms-detail-section {
+ margin-bottom: 20px;
+ padding: 20px;
+ border-radius: 12px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+ width: 100%;
+ background-color: #ffffff;
+}
+
+#pms-form-section {
+ padding: 0;
+ margin: 0 0 20px 0;
+ width: 100%;
+ max-width: 100%;
+}
+
+#pms-form-section h3 {
+ font-size: 1.2rem;
+ color: #333;
+ margin: 0;
+ padding: 15px 20px;
+ background-color: #ffffff;
+ border-bottom: 1px solid #e9ecef;
+ width: 100%;
+ line-height: 1.5;
+}
+
+#pms-form-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 0;
+ padding: 0;
+ width: 100%;
+ max-width: 100%;
+}
+
+/* Header Section */
+#pms-application-view-detail-header {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+ margin-bottom: 10px;
+ width: 100%;
+}
+
+#pms-application-view-back-button {
+ position: absolute;
+ left: 0;
+ background-color: transparent;
+ color: #15abff;
+ border: 1px solid #15abff;
+ padding: 8px 16px;
+ font-weight: 500;
+}
+
+#pms-application-view-back-button:hover {
+ background-color: rgba(210, 217, 244, 0.1);
+ color: #15abff;
+ box-shadow: none;
+}
+
+/* Add styling for download button */
+#pms-application-view-download-button {
+ position: absolute;
+ right: 0;
+ background-color: transparent;
+ color: #15abff;
+ border: 1px solid #15abff;
+ padding: 8px 16px;
+ font-weight: 500;
+}
+
+#pms-application-view-download-button:hover {
+ background-color: rgba(76, 110, 245, 0.1);
+ color: #4c6ef5;
+ box-shadow: none;
+}
+
+#pms-view-application-back-button:active {
+ transform: translateY(0);
+ font-weight: 500;
+}
+
+#pms-application-view-page-title {
+ font-size: 24px;
+ font-weight: 600;
+ color: #2d3748;
+ letter-spacing: 0.5px;
+ margin: 0 auto;
+ text-align: center;
+ padding: 0;
+ max-width: 80%;
+}
+
+#pms-not-submitted-text {
+ color: #e03131;
+ font-size: 14px;
+ font-weight: 500;
+}
+
+/* Section Titles - Consistent styling */
+.pms-form-section-title {
+ font-size: 22px;
+ font-weight: 700;
+ color: #2d3748;
+ margin-bottom: 30px;
+ padding-bottom: 10px;
+ position: relative;
+ border-bottom: 1px solid #e9ecef;
+}
+
+/* Key Dates Section - New Design */
+#pms-key-dates-container {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ margin-top: 20px;
+}
+
+#pms-key-dates-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 16px;
+}
+
+#pms-key-date-card {
+ background: #f5f7f8;
+ border-radius: 8px;
+ padding: 16px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+ /* border-left: 3px solid #4c6ef5; */
+ transition: all 0.3s ease;
+}
+
+#pms-key-date-card:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+}
+
+#pms-key-date-title {
+ font-size: 14px;
+ font-weight: 600;
+ color: #555;
+ margin-bottom: 8px;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+#pms-key-date-value {
+ font-size: 15px;
+ font-weight: 500;
+ color: #333;
+}
+
+/* Responsive adjustments */
+@media (max-width: 768px) {
+ #pms-key-dates-grid {
+ grid-template-columns: 1fr;
+ }
+
+ #pms-key-date-card {
+ padding: 12px;
+ }
+
+ #pms-key-date-title {
+ font-size: 13px;
+ }
+
+ #pms-key-date-value {
+ font-size: 14px;
+ }
+}
+/* Progress Bar Desktop Layout */
+#pms-desktop-stepper {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+#pms-workflow-stepper {
+ width: 100%;
+}
+
+#pms-workflow-stepper#pms-second-row {
+ margin-top: -10px; /* Reduce gap between rows */
+}
+
+/* Adjust step descriptions to prevent wrapping */
+#pms-workflow-stepper #pms-mantine-Stepper-stepDescription {
+ white-space: nowrap;
+ font-size: 14px;
+}
+
+/* Mobile stepper adjustments */
+#pms-workflow-stepper#pms-mobile-view {
+ padding-left: 10px;
+}
+
+#pms-workflow-stepper#pms-mobile-view #pms-mantine-Stepper-stepDescription {
+ font-size: 13px;
+}
+
+
+/* Applicant Cards */
+#pms-applicant-card {
+ padding: 15px;
+ border-radius: 8px;
+ background: white;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
+ margin-bottom: 15px;
+}
+
+/* Download Field Container - Desktop */
+#pms-download-field-container {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+ margin-bottom: 15px;
+}
+
+/* Download Button Wrapper */
+#pms-download-button-wrapper {
+ margin-left: auto; /* Pushes button to right */
+}
+
+/* Download Button Styling */
+#pms-download-button {
+ white-space: nowrap;
+ margin-left: 16px;
+}
+
+/* Form Field Row - For fields with download buttons */
+#pms-field-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+}
+
+/* Mobile adjustments */
+@media (max-width: 768px) {
+ #pms-download-field-container {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+
+ #pms-download-button-wrapper {
+ margin-left: 0;
+ margin-top: 8px;
+ width: 100%;
+ }
+
+ #pms-download-button {
+ margin-left: 0;
+ width: 100%;
+ }
+}
+/* Form Field with Download Button */
+.pms-form-field-with-download {
+ display: flex;
+ justify-content: space-between;
+ padding: 10px;
+ align-items: center;
+ width: 100%;
+ flex-wrap: wrap;
+}
+
+#pms-field-label-container {
+ flex: 1;
+ min-width: 200px;
+}
+
+#pms-download-button-wrapper {
+ margin-left: 16px;
+ flex-shrink: 0;
+}
+
+/* Adjust the download button styling */
+#pms-download-button-container #pms-mantine-Button {
+ white-space: nowrap;
+}
+
+/* For mobile view */
+@media (max-width: 768px) {
+ #pms-form-field-with-download {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+
+ #pms-field-label-container {
+ width: 100%;
+ margin-bottom: 8px;
+ }
+
+ #pms-download-button-wrapper {
+ margin-left: 0;
+ width: 100%;
+ }
+
+ #pms-download-button-container #pms-mantine-Button {
+ width: 100%;
+ }
+}
+/* Status Stepper */
+#pms-status-stepper-container {
+ margin: 30px 0;
+ padding: 20px;
+ background-color: white;
+ border-radius: 8px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+}
+
+#pms-rejected-status {
+ margin-bottom: 16px;
+ text-align: center;
+ color: #e03131;
+ font-weight: 600;
+}
+
+/* Form Actions */
+#pms-form-actions {
+ margin-top: 30px;
+ display: flex;
+ justify-content: center;
+ gap: 15px;
+ flex-wrap: wrap;
+}
+
+#pms-form-actions #pms-mantine-Button {
+ background-color: #4c6ef5;
+ color: white;
+ border: none;
+ padding: 12px 24px;
+ border-radius: 6px;
+ font-weight: 500;
+ transition: all 0.3s ease;
+}
+
+#pms-form-actions #pms-mantine-Button:hover {
+ background-color: #3b5bdb;
+ transform: translateY(-2px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+}
+
+
+/* Responsive Behavior */
+@media (max-width: 1024px) {
+ #pms-applications-grid {
+ margin: 0;
+ padding: 0;
+ }
+}
+
+@media (max-width: 768px) {
+ #pms-page-title {
+ padding-left: 0;
+ font-size: 24px;
+ text-align: left;
+ }
+
+ #pms-applications-grid {
+ grid-template-columns: 1fr;
+ margin: 0;
+ padding: 0;
+ gap: 16px;
+ }
+
+ #pms-application-card {
+ min-width: 100%;
+ max-width: 100%;
+ }
+ #pms-detail-container {
+ padding: 0px;
+ }
+
+ #pms-application-view-detail-header {
+ margin-bottom: 20px;
+ }
+
+ #pms-form-title {
+ font-size: 20px;
+ }
+
+ #pms-detail-section {
+ padding: 15px;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
+ }
+
+ #pms-section-title {
+ font-size: 16px;
+ }
+
+ #pms-form-field {
+ text-align: center; /* Center align all text in form fields */
+ display: flex;
+ flex-direction: column;
+ align-items: center; /* Center child elements */
+ }
+
+ #pms-form-actions {
+ flex-direction: column;
+ gap: 10px;
+ }
+
+ #pms-form-actions #pms-mantine-Button {
+ width: 100%;
+ }
+
+ #pms-field-label,
+ #pms-field-value {
+ text-align: center; /* Explicit center alignment */
+ width: 100%; /* Ensure full width */
+ }
+
+}
+
+@media (max-width: 480px) {
+ #pms-page-title {
+ font-size: 22px;
+ }
+
+ #pms-application-card {
+ padding: 16px;
+ }
+
+ #pms-app-card-title {
+ font-size: 18px;
+ }
+
+ #pms-form-title {
+ font-size: 18px;
+ }
+
+ #pms-section-title {
+ font-size: 15px;
+ }
+
+ #pms-field-label {
+ font-size: 13px;
+ }
+
+ #pms-field-value {
+ font-size: 14px;
+ }
+
+ #pms-applicant-card {
+ padding: 12px;
+ }
+}
+
+.pms-form-field-container {
+ padding: 20px;
+ margin-bottom: 1rem;
+ border-radius: 8px;
+ background-color: #f5f7f8;
+ box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+.pms-form-field-label-and-value {
+ display: flex;
+ gap: 0.5rem;
+ align-items: center;
+}
+
+.pms-form-field-label {
+ font-weight: 600;
+ margin-left: 1rem;
+}
+
+.pms-form-field-value {
+ margin-left: 0px;
+}
diff --git a/src/Modules/Patent/style/Director/DirectorDashboard.css b/src/Modules/Patent/style/Director/DirectorDashboard.css
new file mode 100644
index 000000000..f9b8cd697
--- /dev/null
+++ b/src/Modules/Patent/style/Director/DirectorDashboard.css
@@ -0,0 +1,141 @@
+#pms-director-dashboard-title {
+ font-size: 26px;
+ font-weight: bold;
+ color: #000;
+ margin-bottom: 16px;
+ text-align: center;
+}
+
+#pms-director-dashboard-combined-section {
+ max-width: 95%;
+ font-size: 16px;
+ margin-bottom: 32px;
+ background-color: #ffffff;
+ padding: 24px;
+ border-radius: 8px;
+ box-shadow: 0px 4px 15px rgba(0, 0, 0, 0.2);
+}
+
+#pms-director-dashboard-overview-title {
+ font-size: 24px;
+ font-weight: 600;
+}
+
+#pms-director-overview-icon {
+ margin-bottom: -5px;
+ margin-left: 9px;
+}
+
+/* Feature Box Container */
+#pms-director-dashboard-feature-box-container {
+ display: flex;
+ flex-direction: column;
+ margin: 16px;
+}
+
+/* Individual Feature Box */
+#pms-director-dashboard-feature-box-with-hover {
+ display: flex;
+ align-items: center;
+ padding: 16px;
+ border-radius: 8px;
+ background-color: #f5f7f8;
+ box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
+ border: 1px solid #e2e8f0;
+ margin-bottom: 16px;
+ transition: box-shadow 0.3s ease, transform 0.3s ease;
+ cursor: pointer;
+}
+
+#pms-director-dashboard-feature-box-with-hover:hover {
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.15);
+ transform: translateY(-4px);
+}
+
+/* Feature Icon */
+#pms-director-dashboard-feature-icon {
+ margin-right: 16px;
+ color: #0073e6;
+}
+
+/* Feature Title */
+#pms-dashboard-feature-box-title {
+ font-weight: 700;
+ font-size: 16px;
+ color: #2d3748;
+}
+
+#pms-dashboard-divider {
+ margin: 16px 0;
+ border: 1px solid #e2e8f0;
+ width: 100%;
+}
+
+/* Dashboard Grid */
+#pms-director-dashboard-grid {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 30px;
+ padding-top: 0px;
+}
+
+/* Responsive Behavior */
+@media (max-width: 768px) {
+ #pms-director-dashboard-grid {
+ grid-template-columns: 1fr;
+ }
+}
+
+/* Dashboard Cards */
+#pms-director-dashboard-cards {
+ background-color: #fff;
+ padding: 32px;
+ margin: 10px;
+ border-radius: 10px;
+ box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.2);
+ transition: box-shadow 0.3s ease, transform 0.3s ease;
+ text-align: left;
+ cursor: pointer;
+ flex: 1 1 calc(50% - 12px); /* Two cards per row on larger screens */
+}
+
+#pms-director-dashboard-cards:hover {
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.15);
+ transform: translateY(-4px);
+}
+
+/* Card Title */
+#pms-director-dashboard-card-title {
+ font-size: 20px;
+ font-weight: 600;
+ color: #0073e6;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+/* Card Divider */
+#pms-director-dashboard-card-divider {
+ margin-top: 12px;
+ width: 100%;
+ border: 1px solid #f0f0f0;
+ margin-bottom: 12px;
+}
+
+/* Responsive Behavior */
+@media (max-width: 768px) {
+ #pms-director-dashboard-cards {
+ flex: 1 1 100%; /* One card per row on smaller screens */
+ }
+}
+
+#pms-director-dashboard-button {
+ font-weight: 500;
+ color: #0073e6;
+ background-color: #fff;
+}
+
+#pms-director-dashboard-button:hover {
+ background-color: #0073e6;
+ color: #fff;
+}
\ No newline at end of file
diff --git a/src/Modules/Patent/style/Director/RecentsView.css b/src/Modules/Patent/style/Director/RecentsView.css
new file mode 100644
index 000000000..111a9d1da
--- /dev/null
+++ b/src/Modules/Patent/style/Director/RecentsView.css
@@ -0,0 +1,199 @@
+/* Scoped container */
+#pms-reviewed-apps-container {
+ position: relative;
+ width: 100%;
+ padding-left: 30px;
+ padding-right: 30px;
+}
+
+/* Header styles */
+#pms-reviewed-apps-header {
+ padding: 0 32px;
+ margin-bottom: 8px;
+}
+
+#pms-reviewed-apps-title {
+ font-weight: 700 !important;
+ text-align: left;
+ margin-left: 0 !important;
+ margin-bottom: 5px !important;
+ font-size: 24px;
+}
+
+/* Description area */
+#pms-reviewed-apps-description {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ padding: 0 32px;
+ margin-bottom: 24px;
+}
+
+#pms-reviewed-apps-text {
+ text-align: left;
+}
+
+/* Refresh button */
+#pms-reviewed-apps-refresh {
+ align-self: flex-start;
+ background-color: #fff;
+ border: 1.5px solid #1976d2;
+ color: #1976d2;
+ font-size: 14px;
+ font-weight: 500;
+ transition: background 0.18s, color 0.18s, border 0.18s;
+ width: auto;
+ margin-top: 12px;
+ margin-bottom: -32px;
+ border-radius: 6px;
+ padding: 8px 18px;
+ cursor: pointer;
+}
+#pms-reviewed-apps-refresh:hover,
+#pms-reviewed-apps-refresh:focus {
+ background-color: #1976d2;
+ color: #fff;
+ border: 1.5px solid #1976d2;
+}
+
+/* Main content container */
+#pms-reviewed-apps-outer {
+ max-width: 100%;
+ padding: 24px 32px;
+ background-color: #f5f7f8;
+ border-radius: 12px;
+ margin-bottom: 20px;
+ box-shadow: none;
+ overflow: hidden;
+ transition: all 0.3s ease;
+}
+
+/* Table wrapper */
+#pms-reviewed-apps-outer #pms-reviewed-tableWrapper {
+ overflow-x: auto;
+ width: 100%;
+ -webkit-overflow-scrolling: touch;
+ padding-bottom: 8px;
+ margin-bottom: 12px;
+}
+
+/* Table styles - ERP theme: gray borders, light header, striped rows */
+#pms-reviewed-apps-outer #pms-reviewed-styledTable {
+ width: 100%;
+ font-size: 14px;
+ background-color: #e0e0e0;
+ border-spacing: 0;
+ border-collapse: collapse;
+ border-radius: 8px;
+ overflow: hidden;
+ transition: all 0.3s ease;
+ border: 1px solid #e0e0e0;
+ box-shadow: none;
+}
+
+#pms-reviewed-apps-outer #pms-reviewed-styledTable th,
+#pms-reviewed-apps-outer #pms-reviewed-styledTable td {
+ padding: 14px 20px;
+ vertical-align: middle;
+ border: 1px solid #e0e0e0; /* Thin gray border for all cells */
+ color: #222e3a;
+}
+
+#pms-reviewed-apps-outer #pms-reviewed-fusionTableHeader th {
+ padding: 16px 20px;
+ text-align: left;
+ background-color: #f5f7f8; /* Light gray header */
+ font-weight: 700;
+ color: #111;
+ position: sticky;
+ top: 0;
+ z-index: 10;
+ transition: background-color 0.2s ease;
+ white-space: nowrap;
+ border-bottom: 2px solid #e0e0e0;
+ border-top: 1px solid #e0e0e0;
+ border-right: 1px solid #e0e0e0;
+ border-left: 1px solid #e0e0e0;
+}
+
+#pms-reviewed-apps-outer #pms-reviewed-tableRow {
+ background-color: #fff;
+ transition: background-color 0.2s ease, transform 0.2s ease;
+}
+
+#pms-reviewed-apps-outer #pms-reviewed-tableRow:nth-child(even) {
+ background-color: #fafafa;
+}
+
+#pms-reviewed-apps-outer #pms-reviewed-tableRow:hover {
+ background-color: #f3f5f4;
+ transform: translateY(-1px);
+ box-shadow: none;
+}
+
+/* Status text colors */
+#pms-status-granted {
+ color: #2e7d32 !important;
+ font-weight: 600;
+}
+#pms-status-refused {
+ color: #d32f2f !important;
+ font-weight: 600;
+}
+#pms-status-pending {
+ color: #1976d2 !important;
+ font-weight: 600;
+}
+
+/* Loader styles */
+#pms-reviewed-apps-outer #pms-reviewed-loader-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 40px 0;
+}
+
+/* Responsive Design */
+@media (min-width: 768px) {
+ #pms-reviewed-apps-description {
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ }
+ #pms-reviewed-apps-refresh {
+ margin-top: 0;
+ }
+}
+@media (max-width: 767px) {
+ #pms-reviewed-apps-header,
+ #pms-reviewed-apps-description {
+ padding: 0 20px;
+ }
+ #pms-reviewed-apps-outer {
+ padding: 20px;
+ border-radius: 8px;
+ }
+}
+@media (max-width: 480px) {
+ #pms-reviewed-apps-header,
+ #pms-reviewed-apps-description {
+ padding: 0 16px;
+ }
+ #pms-reviewed-apps-outer {
+ padding: 16px;
+ border-radius: 6px;
+ }
+ #pms-reviewed-apps-outer #pms-reviewed-fusionTableHeader th {
+ padding: 10px 12px;
+ font-size: 12px;
+ }
+ #pms-reviewed-apps-outer #pms-reviewed-tableRow td {
+ padding: 10px 12px;
+ font-size: 12px;
+ }
+ #pms-reviewed-apps-refresh {
+ padding: 8px 12px;
+ font-size: 13px;
+ }
+}
diff --git a/src/Modules/Patent/style/Director/StatusView.css b/src/Modules/Patent/style/Director/StatusView.css
new file mode 100644
index 000000000..848467b20
--- /dev/null
+++ b/src/Modules/Patent/style/Director/StatusView.css
@@ -0,0 +1,198 @@
+.pms-new-status-director-detail-container {
+ background: transparent;
+ margin: 0 50px 40px 50px;
+ padding: 0;
+ max-width: 1400px;
+ box-sizing: border-box;
+}
+
+/* Responsive margin for mobile */
+@media (max-width: 900px) {
+ .pms-new-status-director-detail-container {
+ margin: 0 10px 30px 10px;
+ }
+}
+
+#pms-new-status-detail-section {
+ background: #f9fbfc;
+ border-radius: 14px;
+ border: 1px solid #e7eaf3;
+ margin-bottom: 32px;
+ box-shadow: 0 1px 8px 0 rgba(30, 42, 64, 0.06);
+ padding: 28px 24px 22px 24px;
+}
+
+/* Section heading centered, font 24px, fw 600 */
+#pms-new-status-section-title {
+ font-size: 24px;
+ font-weight: 600;
+ color: #2c3e60;
+ margin-bottom: 20px;
+ text-align: center;
+ width: 100%;
+}
+
+/* Main page title centered, font 24px, fw 600 */
+.pms-director-new-status-detail-page-title {
+ font-size: 24px;
+ font-weight: 600;
+ color: #253053;
+ margin: 0 auto 12px auto;
+ line-height: 1.2;
+ flex: 1;
+ text-align: center;
+}
+
+/* Back button: subtle gray, less padding, hover effect */
+#pms-new-status-director-view-back-button {
+ background: #f7f8fa;
+ color: #1a1e2e;
+ border: 1px solid #bfc5cd;
+ padding: 4px 16px;
+ font-weight: 500;
+ font-size: 15px;
+ border-radius: 6px;
+ transition: background 0.18s, color 0.18s, border 0.18s;
+ box-shadow: none;
+ min-width: 70px;
+ margin-right: 16px;
+ margin-bottom: 10px;
+}
+
+#pms-new-status-director-view-back-button:hover,
+#pms-new-status-director-view-back-button:focus {
+ background: #bfc5cd;
+ color: #f0f0f0;
+ border: 1.5px solid #bfc5cd;
+}
+
+/* Field: gray box, gray border, label bold, value inline */
+#pms-new-status-form-field,
+#pms-new-status-form-field-with-download {
+ display: flex;
+ align-items: center;
+ background: #f7f8fa;
+ border: 1px solid #d6dbe2;
+ border-radius: 8px;
+ padding: 10px 16px;
+ margin-bottom: 14px;
+ gap: 16px;
+ min-height: 44px;
+ box-sizing: border-box;
+}
+
+#pms-new-status-form-field-with-download {
+ justify-content: space-between;
+}
+
+#pms-new-status-field-label {
+ font-weight: 700;
+ color: #253053;
+ font-size: 1rem;
+ margin-right: 8px;
+ min-width: 160px;
+ flex-shrink: 0;
+}
+
+#pms-new-status-field-value {
+ font-weight: 400;
+ color: #1a1e2e;
+ font-size: 1rem;
+ flex: 1;
+ word-break: break-word;
+}
+
+/* Download button area */
+#pms-new-status-download-button-wrapper {
+ margin-left: 24px;
+ flex-shrink: 0;
+}
+
+/* Key Dates grid: cards in a grid */
+#pms-new-status-key-dates-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
+ gap: 18px;
+ margin-top: 10px;
+ margin-bottom: 6px;
+}
+
+#pms-new-status-key-date-card {
+ background: #e9edf3;
+ border-radius: 8px;
+ border: 1px solid #bfc5cd;
+ padding: 14px 12px;
+ box-shadow: 0 1px 3px 0 rgba(30, 42, 64, 0.04);
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+}
+
+#pms-new-status-key-date-title {
+ font-size: 0.98rem;
+ color: #3b4a6b;
+ font-weight: 500;
+ margin-bottom: 4px;
+}
+
+#pms-new-status-key-date-value {
+ font-size: 1.04rem;
+ color: #1a1e2e;
+ font-weight: 600;
+}
+
+/* Applicant card */
+#pms-new-status-applicant-card {
+ background: #f4f6fa;
+ border: 1px solid #e1e4ed;
+ border-radius: 10px;
+ padding: 18px 14px;
+ margin-bottom: 10px;
+ box-shadow: 0 1px 4px 0 rgba(30, 42, 64, 0.04);
+}
+
+/* Decision section */
+#pms-new-status-decision-section {
+ margin-top: 16px;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+/* Center the approve and revert buttons */
+#pms-new-status-decision-buttons {
+ display: flex;
+ justify-content: center;
+ gap: 18px;
+}
+
+#pms-new-status-decision-button {
+ min-width: 120px;
+ font-size: 1rem;
+ font-weight: 600;
+}
+
+/* Responsive tweaks */
+@media (max-width: 700px) {
+ #pms-new-status-detail-section {
+ padding: 14px 6px 12px 6px;
+ }
+ #pms-new-status-form-field,
+ #pms-new-status-form-field-with-download {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 6px;
+ padding: 8px 8px;
+ }
+ #pms-new-status-field-label {
+ min-width: unset;
+ margin-bottom: 2px;
+ }
+ #pms-new-status-download-button-wrapper {
+ margin-left: 0;
+ }
+ #pms-new-status-key-dates-grid {
+ grid-template-columns: 1fr;
+ gap: 10px;
+ }
+}
diff --git a/src/Modules/Patent/style/Director/SubmittedApplications.css b/src/Modules/Patent/style/Director/SubmittedApplications.css
new file mode 100644
index 000000000..c3a36add8
--- /dev/null
+++ b/src/Modules/Patent/style/Director/SubmittedApplications.css
@@ -0,0 +1,208 @@
+/* Scoped container */
+#pms-director-submitted-director-submitted-apps-container {
+ position: relative;
+ width: 100%;
+ padding-left: 30px;
+ padding-right: 30px;
+}
+
+/* Header styles */
+#pms-director-submitted-director-submitted-apps-header {
+ padding: 0 32px;
+ margin-bottom: 8px;
+}
+
+#pms-director-submitted-director-submitted-apps-title {
+ font-weight: 700 !important;
+ text-align: left ;
+ margin-left: 0 !important;
+ margin-bottom: 5px !important;
+ font-size: 24px ;
+}
+
+/* Description area */
+#pms-director-submitted-director-submitted-apps-description {
+ display: flex;
+ flex-direction: column;
+ gap: 16px ;
+ padding: 0 32px;
+ margin-bottom: 24px !important;
+}
+
+#pms-director-submitted-director-submitted-apps-text {
+ text-align: left;
+}
+
+/* Refresh button */
+#pms-director-submitted-director-submitted-apps-refresh {
+ align-self: flex-start;
+ background-color: #fff;
+ border: 1.5px solid #1976d2;
+ color: #1976d2;
+ font-size: 14px;
+ font-weight: 500;
+ transition: background 0.18s, color 0.18s, border 0.18s;
+ width: auto;
+ margin-top: 12px;
+ margin-bottom: -32px;
+ border-radius: 6px;
+ padding: 8px 18px;
+ cursor: pointer;
+}
+#pms-director-submitted-director-submitted-apps-refresh:hover,
+#pms-director-submitted-director-submitted-apps-refresh:focus {
+ background-color: #1976d2;
+ color: #fff;
+ border: 1.5px solid #1976d2;
+}
+
+/* Main content container */
+#pms-director-submitted-director-submitted-apps-outer {
+ max-width: 100%;
+ padding: 24px 32px;
+ background-color: #f5f7f8;
+ border-radius: 12px;
+ margin-bottom: 20px;
+ box-shadow: none;
+ overflow: hidden;
+ transition: all 0.3s ease;
+}
+
+/* Table wrapper */
+#pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-tableWrapper {
+ overflow-x: auto;
+ width: 100%;
+ -webkit-overflow-scrolling: touch;
+ padding-bottom: 8px;
+ margin-bottom: 12px;
+}
+
+/* Table styles - ERP theme: gray borders, light header, striped rows */
+#pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-styledTable {
+ width: 100%;
+ font-size: 14px;
+ background-color: #e0e0e0;
+ border-spacing: 0;
+ border-collapse: collapse;
+ border-radius: 8px;
+ overflow: hidden;
+ transition: all 0.3s ease;
+ border: 1px solid #e0e0e0;
+ box-shadow: none;
+}
+
+#pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-styledTable th,
+#pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-styledTable td {
+ padding: 14px 20px;
+ vertical-align: middle;
+ border: 1px solid #e0e0e0; /* Thin gray border for all cells */
+ color: #222e3a;
+}
+
+#pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-fusionTableHeader th {
+ padding: 16px 20px;
+ text-align: left;
+ background-color: #f5f7f8; /* Light gray header */
+ font-weight: 700;
+ color: #111;
+ position: sticky;
+ top: 0;
+ z-index: 10;
+ transition: background-color 0.2s ease;
+ white-space: nowrap;
+ border-bottom: 2px solid #e0e0e0;
+ border-top: 1px solid #e0e0e0;
+ border-right: 1px solid #e0e0e0;
+ border-left: 1px solid #e0e0e0;
+}
+
+#pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-tableRow {
+ background-color: #fff;
+ transition: background-color 0.2s ease, transform 0.2s ease;
+}
+
+#pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-tableRow:nth-child(even) {
+ background-color: #fafafa;
+}
+
+#pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-tableRow:hover {
+ background-color: #f3f5f4;
+ transform: translateY(-1px);
+ box-shadow: none;
+}
+
+/* View Button - ERP blue theme, hover effect */
+#pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-viewButton {
+ display: inline-flex;
+ align-items: center;
+ gap: 7px;
+ font-weight: 500;
+ border-radius: 6px;
+ padding: 7px 18px;
+ background: #fff;
+ color: #1976d2;
+ border: 1.5px solid #1976d2;
+ font-size: 1rem;
+ cursor: pointer;
+ transition: background 0.18s, color 0.18s, border 0.18s;
+}
+
+#pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-viewButton:hover,
+#pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-viewButton:focus {
+ background: #1976d2;
+ color: #fff;
+ border: 1.5px solid #1976d2;
+}
+
+/* Loader styles */
+#pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-loader-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 40px 0;
+}
+
+/* Responsive Design */
+@media (min-width: 768px) {
+ #pms-director-submitted-director-submitted-apps-description {
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ }
+ #pms-director-submitted-director-submitted-apps-refresh {
+ margin-top: 0;
+ }
+}
+@media (max-width: 767px) {
+ #pms-director-submitted-director-submitted-apps-header,
+ #pms-director-submitted-director-submitted-apps-description {
+ padding: 0 20px;
+ }
+ #pms-director-submitted-director-submitted-apps-outer {
+ padding: 20px;
+ border-radius: 8px;
+ }
+}
+@media (max-width: 480px) {
+ #pms-director-submitted-director-submitted-apps-header,
+ #pms-director-submitted-director-submitted-apps-description {
+ padding: 0 16px;
+ }
+ #pms-director-submitted-director-submitted-apps-outer {
+ padding: 16px;
+ border-radius: 6px;
+ }
+ #pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-fusionTableHeader th {
+ padding: 10px 12px;
+ font-size: 12px;
+ }
+ #pms-director-submitted-director-submitted-apps-outer #pms-director-submitted-tableRow td {
+ padding: 10px 12px;
+ font-size: 12px;
+ }
+ #pms-director-submitted-director-submitted-apps-refresh {
+ padding: 8px 12px;
+ font-size: 13px;
+ }
+}
diff --git a/src/Modules/Patent/style/Pcc_Admin/AttorneyDetails.css b/src/Modules/Patent/style/Pcc_Admin/AttorneyDetails.css
new file mode 100644
index 000000000..225cadfc8
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/AttorneyDetails.css
@@ -0,0 +1,156 @@
+#pms-pcc-attorney-details-container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 32px;
+}
+
+#pms-pcc-attorney-details-header {
+ display: flex;
+ align-items: center;
+ margin-bottom: 32px;
+ position: relative;
+ padding-bottom: 16px;
+ border-bottom: 1px solid #e9ecef;
+}
+
+#pms-pcc-attorney-details-back-btn {
+ padding: 8px 16px;
+ font-weight: 500;
+ color: #666;
+ background-color: transparent;
+ border: none;
+ border-radius: 4px;
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ transition: all 0.2s ease;
+ text-decoration: none;
+ cursor: pointer;
+}
+
+#pms-pcc-attorney-details-back-btn:hover {
+ background-color: transparent;
+ color: #333;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+#pms-pcc-attorney-details-title {
+ font-size: 24px;
+ font-weight: 600;
+ color: #333;
+ margin: 0 auto;
+ text-align: center;
+ flex: 1;
+}
+
+#pms-pcc-attorney-details-content {
+ display: flex;
+ gap: 48px;
+ margin-bottom: 32px;
+}
+
+#pms-pcc-attorney-details-section {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 32px;
+}
+
+#pms-pcc-attorney-details-field {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+#pms-pcc-attorney-details-label {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 14px;
+ font-weight: 500;
+ color: #495057;
+}
+
+#pms-pcc-attorney-details-icon {
+ color: #228be6;
+ flex-shrink: 0;
+}
+
+#pms-pcc-attorney-details-input {
+ width: 100%;
+}
+
+#pms-pcc-attorney-details-input #pms-pcc-mantine-TextInput-input {
+ height: 40px;
+ font-size: 14px;
+ border-radius: 4px;
+ border: 1px solid #ced4da;
+ transition: border-color 0.2s ease;
+ padding: 0 12px;
+}
+
+#pms-pcc-attorney-details-input #pms-pcc-mantine-TextInput-input:focus {
+ border-color: #228be6;
+ box-shadow: 0 0 0 2px rgba(34, 139, 230, 0.1);
+}
+
+#pms-pcc-attorney-details-item {
+ padding: 12px 16px;
+ background-color: #f8f9fa;
+ border: 1px solid #e9ecef;
+ border-radius: 4px;
+ font-size: 14px;
+ color: #495057;
+ min-height: 40px;
+ display: flex;
+ align-items: center;
+}
+
+#pms-pcc-attorney-details-footer {
+ display: flex;
+ justify-content: center;
+ padding-top: 32px;
+ border-top: 1px solid #e9ecef;
+ margin-top: 16px;
+}
+
+#pms-pcc-attorney-details-submit-btn {
+ width: 240px;
+ height: 40px;
+ font-size: 14px;
+ font-weight: 500;
+ background-color: #228be6;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ transition: all 0.2s ease;
+}
+
+#pms-pcc-attorney-details-submit-btn:hover {
+ background-color: #1c7ed6;
+}
+
+/* Responsive adjustments */
+@media (max-width: 768px) {
+ #pms-pcc-attorney-details-container {
+ padding: 24px;
+ }
+
+ #pms-pcc-attorney-details-content {
+ flex-direction: column;
+ gap: 32px;
+ }
+
+ #pms-pcc-attorney-details-section {
+ gap: 24px;
+ }
+
+ #pms-pcc-attorney-details-title {
+ font-size: 20px;
+ }
+
+ #pms-pcc-attorney-details-submit-btn {
+ width: 100%;
+ max-width: 240px;
+ }
+}
\ No newline at end of file
diff --git a/src/Modules/Patent/style/Pcc_Admin/AttorneyForm.css b/src/Modules/Patent/style/Pcc_Admin/AttorneyForm.css
new file mode 100644
index 000000000..4788a0a49
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/AttorneyForm.css
@@ -0,0 +1,123 @@
+/* Main Container */
+#pms-pcc-attorney-details-container {
+ width: 100%;
+ padding: 0 50px;
+ background-color: transparent;
+ transition: all 0.3s ease;
+ box-sizing: border-box;
+}
+
+/* Heading */
+#pms-pcc-attorney-details-heading {
+ font-size: 24px;
+ font-weight: 600;
+ margin-bottom: 0.5rem;
+}
+
+/* Top Navigation Bar */
+#pms-pcc-top-nav-container {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 1rem;
+}
+
+/* Unified Button Styling */
+#pms-pcc-attorney-back-btn,
+#pms-pcc-edit-details-button,
+#pms-pcc-save-button,
+#pms-pcc-cancel-button {
+ border: 1px solid #1e66f5;
+ color: #1e66f5;
+ background-color: white;
+ font-weight: 500;
+ transition: all 0.2s ease-in-out;
+}
+
+#pms-pcc-attorney-back-btn:hover,
+#pms-pcc-edit-details-button:hover,
+#pms-pcc-save-button:hover,
+#pms-pcc-cancel-button:hover {
+ background-color: #1e66f5;
+ color: white;
+}
+
+/* Grid Layout - Two Fields Per Row */
+#pms-pcc-attorney-details-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(300px, 1fr));
+ gap: 2rem;
+ margin-bottom: 2.5rem;
+}
+
+/* Detail Item Box */
+.detail-item {
+ background-color: #ffffff;
+ border-radius: 10px;
+ border: 2px solid #f0f0f0;
+ padding: 1.25rem 1.5rem;
+ transition: background-color 0.3s ease, border-left 0.3s ease;
+}
+
+
+/* Detail Text */
+#pms-pcc-attorney-detail {
+ display: flex;
+ align-items: center;
+ gap: 0.6rem;
+ color: #333;
+ font-size: 1rem;
+ line-height: 1.5;
+}
+
+/* Icons */
+#pms-pcc-icon {
+ color: #1e66f5;
+ flex-shrink: 0;
+}
+
+/* Input Field Style */
+#pms-pcc-edit-input {
+ margin-top: 0.4rem;
+}
+
+/* Assigned Cases - Full Width Below Grid */
+#pms-pcc-detail-item-assigned-cases {
+ width: 100%;
+ background-color: #fff;
+ border: 2px solid #f0f0f0;
+ border-radius: 10px;
+ padding: 1.5rem;
+}
+
+/* Case List */
+#pms-pcc-assigned-cases-list {
+ margin-top: 1rem;
+ padding-left: 1.2rem;
+ border-left: 4px solid #1e66f5;
+}
+
+#pms-pcc-assigned-case-item {
+ margin-bottom: 0.6rem;
+}
+
+/* No Cases Text */
+#pms-pcc-no-applications-text {
+ margin-top: 1rem;
+ font-style: italic;
+ color: #6c757d;
+}
+
+/* Responsive Adjustments */
+@media screen and (max-width: 768px) {
+ #pms-pcc-attorney-details-grid {
+ grid-template-columns: 1fr;
+ }
+
+ #pms-pcc-top-nav-container {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 1rem;
+ }
+}
diff --git a/src/Modules/Patent/style/Pcc_Admin/DownloadsPage.css b/src/Modules/Patent/style/Pcc_Admin/DownloadsPage.css
new file mode 100644
index 000000000..2be92c924
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/DownloadsPage.css
@@ -0,0 +1,185 @@
+/* DownloadsPage#pms-pcc-css */
+
+/* Title styling */
+#pms-pcc-downloads-title {
+ margin-bottom: 0px;
+ margin-top: 0px;
+ font-size: 26px;
+ color: #333;
+ font-weight: 700;
+ text-align: left;
+}
+
+/* Description styling */
+#pms-pcc-downloads-description {
+ font-size: 14px;
+ color: #555;
+ text-align: left;
+ margin-bottom: 32px;
+ margin-top: -25px;
+}
+
+/* Card styling for table */
+#pms-pcc-table-card {
+ padding: 24px;
+ border-radius: 12px;
+ background-color: #fff;
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
+ overflow-x: auto; /* Enable horizontal scrolling on small screens */
+}
+
+/* Table styling */
+#pms-pcc-downloads-container {
+ padding: 1rem;
+ max-width: 1400px;
+ margin: 0 auto;
+}
+
+#pms-pcc-downloads-table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 0 auto;
+ background-color: transparent;
+}
+
+#pms-pcc-downloads-table th,
+#pms-pcc-downloads-table td {
+ padding: 1rem;
+ text-align: left;
+ border-bottom: 1px solid #eaeaea;
+}
+
+#pms-pcc-downloads-table th {
+ background-color: #f5f7f8;
+ font-weight: 600;
+ white-space: nowrap;
+ text-align: center;
+}
+
+#pms-pcc-downloads-table td {
+ text-align: left;
+ vertical-align: middle;
+}
+
+#pms-pcc-downloads-table tr:hover {
+ background-color: #f8f9fa;
+}
+
+/* Button styling */
+#pms-pcc-download-button, #pms-pcc-delete-button {
+ min-width: 120px;
+ transition: all 0.2s ease;
+}
+
+#pms-pcc-download-button:hover, #pms-pcc-delete-button:hover {
+ transform: translateY(-1px);
+}
+
+/* Desktop-specific styles */
+@media (min-width: 769px) {
+ #pms-pcc-manage-attorney-container {
+ margin-left: 30px; /* Shift container to the right */
+ }
+}
+
+/* Responsive styles for smaller screens */
+@media (max-width: 768px) {
+ #pms-pcc-manage-attorney-container {
+ padding: 1rem;
+ }
+
+ #pms-pcc-downloads-container {
+ padding: 0.5rem;
+ }
+
+ #pms-pcc-add-document-form {
+ padding: 1rem;
+ }
+
+ #pms-pcc-downloads-table th,
+ #pms-pcc-downloads-table td {
+ padding: 0.75rem;
+ }
+
+ #pms-pcc-page-heading-title {
+ font-size: 1.5rem;
+ }
+
+ #pms-pcc-description {
+ font-size: 12px;
+ }
+}
+
+/* ...existing styles above... */
+
+/* Alternate row colors for downloads table */
+#pms-pcc-downloads-table tbody tr:nth-child(odd) {
+ background-color: #fff;
+}
+
+#pms-pcc-downloads-table tbody tr:nth-child(even) {
+ background-color: #f5f7f8;
+}
+
+/* Optional: Keep hover effect above the alternates */
+#pms-pcc-downloads-table tbody tr:hover {
+ background-color: #f8f9fa;
+}
+
+/* ...rest of your styles... */
+
+
+@media (max-width: 480px) {
+ #pms-pcc-page-heading-title {
+ font-size: 20px;
+ }
+
+ #pms-pcc-description {
+ font-size: 11px;
+ }
+
+ #pms-pcc-downloads-container {
+ padding: 0.5rem;
+ }
+
+ #pms-pcc-add-document-form {
+ padding: 0.75rem;
+ }
+
+ #pms-pcc-downloads-table th,
+ #pms-pcc-downloads-table td {
+ padding: 0.5rem;
+ }
+
+ #pms-pcc-download-button, #pms-pcc-delete-button {
+ font-size: 12px;
+ padding: 4px 8px;
+ }
+}
+
+#pms-pcc-add-document-form {
+ background-color: #f8f9fa;
+ padding: 1.5rem;
+ border-radius: 8px;
+ margin-bottom: 1.5rem;
+}
+
+#pms-pcc-add-document-form-title {
+ color: #333;
+ font-size: 18px;
+ font-weight: 600;
+ margin-bottom: 1rem;
+ text-align: center;
+}
+
+#pms-pcc-add-document-button {
+ color: #0073e6;
+ background-color: #fff;
+ border-color: #0073e6;
+}
+
+#pms-pcc-add-document-button:hover {
+ background-color: #0073e6;
+ color: #fff;
+}
+
diff --git a/src/Modules/Patent/style/Pcc_Admin/InsightsPage.css b/src/Modules/Patent/style/Pcc_Admin/InsightsPage.css
new file mode 100644
index 000000000..6531018eb
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/InsightsPage.css
@@ -0,0 +1,222 @@
+#pms-insights-page {
+ width: 100%;
+ max-width: 1800px;
+ margin: auto;
+ box-sizing: border-box;
+}
+
+#pms-page-title {
+ font-size: 24px;
+ font-weight: 600;
+ margin-bottom: 0.5rem;
+}
+
+#pms-description {
+ color: #555;
+ margin-bottom: 1rem;
+}
+
+#pms-filter {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ margin-bottom: 1.5rem;
+ flex-wrap: wrap;
+}
+
+#pms-year-select {
+ min-width: 120px;
+}
+
+#pms-insights-content {
+ display: flex;
+ gap: 2rem;
+ width: 100%;
+ box-sizing: border-box;
+}
+
+#pms-chart-section,
+#pms-table-section {
+ flex: 1 1 0;
+ min-width: 0;
+ margin: 0;
+ padding: 0;
+}
+
+#pms-chart-section {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+#pms-legend {
+ margin-top: 1.5rem;
+ display: flex;
+ flex-direction: row;
+ gap: 0.5rem;
+ flex-wrap: wrap;
+}
+
+#pms-legend-item {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+#pms-legend-color {
+ width: 16px;
+ height: 16px;
+ border-radius: 4px;
+}
+
+#pms-legend-label {
+ font-size: 0.9rem;
+ color: #333;
+}
+
+#pms-table-section {
+ min-width: 320px;
+}
+
+#pms-table-title {
+ font-size: 1.2rem;
+ font-weight: 600;
+ color: #222;
+ margin-bottom: 1rem;
+}
+
+#pms-table-section table {
+ width: 100%;
+ border-collapse: separate;
+ border-spacing: 0;
+ overflow: hidden;
+ background: #fff;
+ box-shadow: none;
+ border: 1px solid #e0e7ef;
+}
+
+#pms-table-section th,
+#pms-table-section td {
+ padding: 12px 16px;
+ text-align: left;
+ border: 1px solid #e0e7ef; /* Add border for all cells */
+}
+
+#pms-table-section thead {
+ background-color: #f5f7f8;
+ color: #333;
+}
+
+#pms-table-section thead tr {
+ background-color: #f0f0f0;
+}
+#pms-table-section th {
+ color: #000;
+ font-weight: 600;
+ padding: 12px 16px;
+ border-bottom: 2px solid #e0e7ef;
+ border-top: 1px solid #e0e7ef;
+}
+
+#pms-table-section tbody tr:nth-child(even) {
+ background-color: #f0f4fa;
+}
+#pms-table-section tbody tr:nth-child(odd) {
+ background-color: #f8fbff;
+}
+
+#pms-table-section tbody tr:hover {
+ background-color: #f0f4fa;
+ transition: background 0.15s;
+}
+
+#pms-download-csv-button {
+ display: flex;
+ justify-content: center;
+ margin-top: 1.5rem;
+}
+
+#pms-download-button {
+ background-color: #fff;
+ color: #0073e6;
+ padding: 10px 20px;
+ border-radius: 5px;
+ transition: all 0.1s ease;
+ font-weight: 500;
+ margin-top: 0;
+ margin-left: 0;
+ border: 1px solid #0073e6;
+}
+
+#pms-download-button:hover {
+ background-color: #0073e6;
+ color: #fff;
+}
+
+/* Responsive Styles */
+@media (max-width: 1100px) {
+ #pms-insights-content {
+ flex-direction: column;
+ gap: 1.5rem;
+ }
+ #pms-table-section,
+ #pms-chart-section {
+ min-width: 0;
+ width: 100%;
+ }
+}
+
+@media (max-width: 700px) {
+ #pms-insights-page {
+ padding: 0.5rem;
+ }
+ #pms-description {
+ font-size: 0.95rem;
+ }
+ #pms-filter {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0.5rem;
+ }
+ #pms-table-section th,
+ #pms-table-section td {
+ padding: 8px 8px;
+ font-size: 0.95rem;
+ }
+ #pms-table-title {
+ font-size: 1rem;
+ }
+ #pms-download-csv-button {
+ margin-top: 1rem;
+ }
+ #pms-download-button {
+ width: 100%;
+ font-size: 1rem;
+ padding: 8px 0;
+ }
+ #pms-legend-label {
+ font-size: 0.85rem;
+ }
+ #pms-legend-color {
+ width: 14px;
+ height: 14px;
+ }
+ #pms-chart-section svg {
+ height: 180px !important;
+ min-height: 120px;
+ }
+}
+
+@media (max-width: 480px) {
+ #pms-table-section th,
+ #pms-table-section td {
+ font-size: 0.85rem;
+ padding: 6px 4px;
+ }
+ #pms-table-title {
+ font-size: 0.95rem;
+ }
+ #pms-legend-label {
+ font-size: 0.8rem;
+ }
+}
diff --git a/src/Modules/Patent/style/Pcc_Admin/ManageAttorneys.css b/src/Modules/Patent/style/Pcc_Admin/ManageAttorneys.css
new file mode 100644
index 000000000..abf726ed1
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/ManageAttorneys.css
@@ -0,0 +1,221 @@
+#pms-pcc-manage-attorneys-container {
+ padding: 0;
+ width: 100%;
+ max-width: 1800px;
+ margin: 0 auto;
+ padding-left: 50px;
+ padding-right: 50px;
+}
+
+#pms-pcc-top-nav-container {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 24px;
+ width: 100%;
+}
+
+#pms-pcc-page-heading-title {
+ font-size: 24px;
+ font-weight: 600;
+ color: #333;
+ margin-bottom: 8px;
+ text-align: left;
+}
+
+#pms-pcc-description {
+ color: #666;
+ margin-bottom: 24px;
+ text-align: center;
+}
+
+#pms-pcc-button-group {
+ display: flex;
+ justify-content: start;
+ gap: 12px;
+ margin-bottom: 20px;
+}
+
+#pms-pcc-add-new-attorney-button,
+#pms-pcc-remove-attorney-button,
+#pms-pcc-remove-selected-button,
+#pms-pcc-view-details-button,
+#pms-pcc-back-button,
+#pms-pcc-edit-details-button {
+ font-weight: 500;
+ padding: 8px 16px;
+ border-radius: 4px;
+ transition: all 0.2s ease;
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+}
+
+/* Add New */
+#pms-pcc-add-new-attorney-button {
+ background-color: #fff;
+ color: #0073e6;
+ border: 1px solid #0073e6;
+}
+
+#pms-pcc-add-new-attorney-button:hover {
+ background-color: #0073e6;
+ color: #fff;
+}
+
+/* Remove */
+#pms-pcc-remove-attorney-button {
+ background-color: #fff;
+ color: #dc3545;
+ border: 1px solid #dc3545;
+}
+
+#pms-pcc-remove-attorney-button:hover {
+ background-color: #dc3545;
+ color: #fff;
+}
+
+/* Remove Selected */
+#pms-pcc-remove-selected-button {
+ margin-top: 16px;
+ background-color: #dc3545;
+ color: #fff;
+ border: none;
+}
+
+#pms-pcc-remove-selected-button:hover {
+ background-color: #c82333;
+}
+
+/* Back */
+#pms-pcc-back-button {
+ background-color: #fff;
+ color: #666;
+ border: 1px solid #666;
+}
+
+#pms-pcc-back-button:hover {
+ background-color: #666;
+ color: #fff;
+}
+
+/* Edit */
+#pms-pcc-edit-details-button {
+ background-color: #fff;
+ color: #0073e6;
+ border: 1px solid #0073e6;
+}
+
+#pms-pcc-edit-details-button:hover {
+ background-color: #0073e6;
+ color: #fff;
+}
+
+/* View Button */
+#pms-pcc-view-details-button {
+ background-color: #fff;
+ color: #0073e6;
+ border: 1px solid #0073e6;
+ padding: 6px 14px;
+ border-radius: 4px;
+ transition: all 0.2s ease;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ margin: 0 auto;
+}
+
+#pms-pcc-view-details-button:hover {
+ background-color: #0073e6;
+ color: #fff;
+}
+
+/* Table Card */
+#pms-pcc-manage-attorney-table-card {
+ background: #f9f8fa;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
+ overflow: hidden;
+}
+
+/* Table */
+#pms-pcc-manage-attorney-styledTable {
+ width: 100%;
+ border-collapse: separate;
+ border-spacing: 0;
+}
+
+#pms-pcc-fusionTableHeader {
+ background-color: #f8f9fa;
+}
+
+#pms-pcc-fusionTableHeader th {
+ padding: 12px 16px;
+ font-weight: 600;
+ color: #333;
+ text-align: left;
+ border-bottom: 2px solid #dee2e6;
+}
+
+/* Row striping and hover */
+#pms-pcc-manage-attorney-styledTable tbody tr:nth-child(odd) {
+ background-color: #f8f9fa;
+}
+
+#pms-pcc-manage-attorney-styledTable tbody tr:nth-child(even) {
+ background-color: #f5f8f9;
+}
+
+#pms-pcc-manage-attorney-styledTable tbody tr:hover {
+ background-color: #ffffff;
+}
+
+#pms-pcc-manage-attorney-styledTable td {
+ padding: 12px 16px;
+ color: #333;
+ border-bottom: 1px solid #dee2e6;
+ text-align: center;
+}
+
+#pms-pcc-manage-attorney-styledTable td:last-child {
+ display: flex;
+ justify-content: center;
+}
+
+/* Checkbox Styling */
+#pms-pcc-mantine-Checkbox-root {
+ cursor: pointer;
+}
+
+#pms-pcc-mantine-Checkbox-input:checked {
+ background-color: #0073e6;
+ border-color: #0073e6;
+}
+
+/* Responsive Styles */
+@media (max-width: 768px) {
+ #pms-pcc-manage-attorneys-container {
+ padding: 16px;
+ }
+
+ #pms-pcc-button-group {
+ flex-direction: column;
+ }
+
+ #pms-pcc-manage-attorney-styledTable {
+ font-size: 14px;
+ }
+
+ #pms-pcc-fusionTableHeader th,
+ #pms-pcc-manage-attorney-styledTable td {
+ padding: 8px 12px;
+ }
+
+ #pms-pcc-page-heading-title {
+ font-size: 20px;
+ }
+
+ #pms-pcc-view-details-button {
+ padding: 6px 10px;
+ font-size: 14px;
+ }
+}
diff --git a/src/Modules/Patent/style/Pcc_Admin/NewApplication.css b/src/Modules/Patent/style/Pcc_Admin/NewApplication.css
new file mode 100644
index 000000000..0ff4fdd6b
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/NewApplication.css
@@ -0,0 +1,266 @@
+/* General Container */
+.review-applications-container {
+ position: relative;
+ /* width: 100%; */
+}
+.detail-container1{
+ background-color: transparent;
+ width: 100%;
+ /* margin-left: 100px;
+ margin-right: 50px; */
+ max-width: none;
+}
+
+.outerContainer {
+ max-width: none;
+ padding: 24px 50px;
+ background-color:transparent;
+ margin-left: 25px;
+ border-radius: 12px;
+ margin-bottom: 20px;
+ box-shadow: 0px 5px 15px rgba(0, 0, 0, 0);
+ /* overflow: hidden; */
+ /* transition: all 0.3s ease; */
+
+}
+
+
+.new-application-title {
+ font-size: 24px;
+ font-weight: 600;
+ text-align: left;
+ margin: 0 auto;
+ padding-left: 50px;
+ position: relative;
+}
+
+.title::after {
+ content: '';
+ position: absolute;
+ bottom: -8px;
+ left: 30px;
+ width: 60px;
+ height: 3px;
+ background-color: #1c7ed6;
+ border-radius: 2px;
+}
+
+.content {
+ text-align: left;
+}
+
+.description {
+ text-align: left;
+ margin-left: 32px;
+ margin-right: 32px;
+ font-size: 15px;
+ color: #555;
+ margin-bottom: 20px;
+ line-height: 1.5;
+}
+
+/* Wrapper for horizontal scrolling */
+.tableWrapper {
+ overflow-x: auto;
+ width: 100%;
+ background-color: inherit; /* use parent background */
+ padding-bottom: 0;
+ margin-bottom: 0;
+}
+
+
+
+/* Responsive Table */
+.styledTable {
+ width: 100%;
+ font-size: 14px;
+ background-color: #ffffff;
+ border-spacing: 0;
+ border-collapse: separate;
+ border-radius: 8px;
+ overflow: hidden;
+ transition: all 0.3s ease;
+ box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.05);
+}
+
+.fusionTableHeader th {
+ padding: 16px 20px;
+ text-align: left;
+ background-color: #f2f2f2;
+ font-weight: 600;
+ color: #444;
+ position: sticky;
+ top: 0;
+ z-index: 10;
+ transition: background-color 0.2s ease;
+ white-space: nowrap;
+}
+
+.tableRow {
+ background-color: #ffffff;
+ transition: background-color 0.2s ease, transform 0.2s ease;
+}
+
+.tableRow:hover {
+ background-color: #f8fbff;
+ transform: translateY(-1px);
+ box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
+}
+
+.tableRow td {
+ padding: 14px 20px;
+ border-top: 1px solid #f0f0f0;
+ vertical-align: middle;
+}
+
+.viewButton {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-weight: 600;
+ transition: all 0.2s ease;
+ border-radius: 6px;
+ padding: 8px 12px;
+}
+
+.viewButton:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+}
+
+.back-button {
+ margin-bottom: 20px;
+ margin-right: 50px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ transition: all 0.2s ease;
+ margin-left: 30px;
+ border-radius: 6px;
+ padding: 8px 16px;
+}
+
+.back-button:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+}
+
+.detail-view-container {
+ padding: 20px 0;
+}
+
+.loader-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 40px 0;
+}
+
+/* Responsive Design */
+
+/* Small devices (up to 768px) */
+@media (max-width: 768px) {
+ .outerContainer {
+ padding: 20px;
+ margin-left: 0;
+ margin-right: 0;
+ max-width: 100vw;
+ overflow-x: hidden;
+ border-radius: 8px;
+ }
+
+ .title {
+ font-size: 24px;
+ padding-left: 20px;
+ }
+
+ .title::after {
+ left: 20px;
+ width: 50px;
+ }
+
+ .description {
+ margin-left: 20px !important;
+ margin-right: 20px !important;
+ font-size: 14px;
+ }
+
+ .tableWrapper {
+ overflow-x: auto;
+ width: 100%;
+ margin-left: 0;
+ }
+
+ .styledTable {
+ min-width: 100%;
+ }
+
+ .fusionTableHeader th {
+ padding: 12px 16px;
+ font-size: 13px;
+ }
+
+ .tableRow td {
+ padding: 12px 16px;
+ font-size: 13px;
+ }
+
+ .viewButton {
+ font-size: 13px;
+ padding: 6px 10px;
+ }
+
+ .back-button {
+ margin-left: 20px;
+ padding: 8px 14px;
+ }
+}
+
+/* Extra small devices (up to 480px) */
+@media (max-width: 480px) {
+ .outerContainer {
+ padding: 16px;
+ max-width: 100vw;
+ overflow-x: hidden;
+ box-shadow: 0px 3px 10px rgba(0, 0, 0, 0.05);
+ }
+
+ .title {
+ font-size: 22px;
+ padding-left: 16px;
+ }
+
+ .title::after {
+ left: 16px;
+ width: 40px;
+ }
+
+ .description {
+ margin-left: 16px !important;
+ margin-right: 16px !important;
+ font-size: 13px;
+ }
+
+ .fusionTableHeader th {
+ padding: 10px 14px;
+ font-size: 12px;
+ }
+
+ .tableRow td {
+ padding: 10px 14px;
+ font-size: 12px;
+ white-space: nowrap; /* Prevent text wrapping on small screens */
+ }
+
+ .viewButton {
+ font-size: 12px;
+ padding: 5px 8px;
+ }
+
+ .back-button {
+ margin-left: 16px;
+ padding: 6px 12px;
+ font-size: 13px;
+ }
+}
\ No newline at end of file
diff --git a/src/Modules/Patent/style/Pcc_Admin/NewAttorneyForm.css b/src/Modules/Patent/style/Pcc_Admin/NewAttorneyForm.css
new file mode 100644
index 000000000..72404cc88
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/NewAttorneyForm.css
@@ -0,0 +1,157 @@
+/* NewAttorneyForm#pcc-css */
+
+#pcc-new-attorney-form-container {
+ margin: 0 50px;
+ padding: 40px 32px;
+ width: 100%;
+ max-width: 1800px;
+ background-color: #fff;
+ border-radius: 12px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
+ box-sizing: border-box;
+}
+
+#pcc-new-attorney-form-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 32px;
+ padding-bottom: 16px;
+ border-bottom: 1px solid #e9ecef;
+}
+
+#pcc-new-attorney-back-btn {
+ padding: 8px 16px;
+ font-weight: 500;
+ font-size: 14px;
+ color: #0073e6;
+ border: 1px solid #0073e6;
+ background-color: white;
+ border-radius: 6px;
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ transition: all 0.2s ease;
+ text-decoration: none;
+ cursor: pointer;
+}
+
+#pcc-new-attorney-back-btn:hover {
+ background-color: #0073e6;
+ color: #fff;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
+}
+
+#pcc-new-attorney-form-title {
+ font-size: 28px;
+ font-weight: 600;
+ color: #212529;
+ margin: 0;
+}
+
+#pcc-new-attorney-form-content {
+ display: flex;
+ gap: 48px;
+ flex-wrap: wrap;
+ margin-bottom: 40px;
+}
+
+#pcc-new-attorney-form-section {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+ min-width: 300px;
+}
+
+#pcc-new-attorney-form-field {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+#pcc-new-attorney-form-label {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 14px;
+ font-weight: 500;
+ color: #495057;
+}
+
+#pcc-new-attorney-form-icon {
+ color: #228be6;
+ flex-shrink: 0;
+}
+
+#pcc-new-attorney-form-input input {
+ height: 40px;
+ font-size: 14px;
+ border-radius: 6px;
+ border: 1px solid #ced4da;
+ padding: 0 12px;
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
+}
+
+#pcc-new-attorney-form-input input:focus {
+ border-color: #228be6;
+ box-shadow: 0 0 0 3px rgba(34, 139, 230, 0.15);
+}
+
+#pcc-new-attorney-form-footer {
+ display: flex;
+ justify-content: center;
+ padding-top: 24px;
+ border-top: 1px solid #e9ecef;
+}
+
+#pcc-new-attorney-form-submit-btn {
+ width: 240px;
+ height: 44px;
+ font-size: 15px;
+ font-weight: 600;
+ background-color: #228be6;
+ color: #fff;
+ border: none;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: background-color 0.2s ease, box-shadow 0.2s ease;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
+}
+
+#pcc-new-attorney-form-submit-btn:hover {
+ background-color: #1c7ed6;
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12);
+}
+
+/* Modal specific styles */
+#pcc-new-attorney-modal #pcc-mantine-Modal-body {
+ padding: 24px;
+}
+
+#pcc-new-attorney-modal #pcc-mantine-Modal-title {
+ font-size: 20px;
+ font-weight: 600;
+ color: #333;
+}
+
+/* Responsive */
+@media (max-width: 768px) {
+ #pcc-new-attorney-form-container {
+ padding: 24px;
+ }
+
+ #pcc-new-attorney-form-content {
+ flex-direction: column;
+ gap: 24px;
+ }
+
+ #pcc-new-attorney-form-title {
+ font-size: 22px;
+ }
+
+ #pcc-new-attorney-form-submit-btn {
+ width: 100%;
+ max-width: 240px;
+ }
+}
diff --git a/src/Modules/Patent/style/Pcc_Admin/OngoingApplication.css b/src/Modules/Patent/style/Pcc_Admin/OngoingApplication.css
new file mode 100644
index 000000000..9507ecb56
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/OngoingApplication.css
@@ -0,0 +1,151 @@
+/* Centering Header */
+.status-header {
+ display: flex;
+ justify-content: flex-start;
+ margin-bottom: 20px;
+}
+.m_4081bf90 {
+ margin-top: 10px;
+ margin-left: 59px;
+}
+.status-update-group{
+ margin-left: 0px;
+}
+/* Container Styles */
+.ongoing-app-status-applications-container {
+ margin-left: 50px;
+ margin-right: 50px;
+ border: 1px solid #000;
+ max-width: 100%;
+ background-color: transparent;
+}
+
+/* Title and Description */
+.ongoing-app-status-title {
+ font-size: 24px;
+ margin: 0;
+ font-weight: 600;
+ text-align: left;
+}
+
+.stati-title {
+ font-size: 2rem;
+ color: #333;
+ margin-bottom: 16px;
+ font-weight: 700;
+ text-align: left;
+}
+
+.description {
+ font-size: 1rem;
+ color: #5f6368;
+ margin-bottom: 24px;
+ line-height: 1.6;
+}
+
+/* Loading and Error States */
+.loading-container,
+.error-container,
+.empty-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 40px;
+ background-color: #fff;
+ border-radius: 8px;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
+ margin: 20px 0;
+ text-align: center;
+}
+
+/* Table Container */
+.ongoing-app-outerContainer {
+ padding-top: 10px;
+ background-color: #ffffff;
+ border-radius: 8px;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.05);
+ overflow: hidden;
+}
+
+/* Status Cards Container */
+.status-cards-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 24px;
+ justify-content: flex-start;
+}
+
+/* Individual Card Styles */
+.status-card {
+ width: calc(48% - 8px);
+ padding: 20px;
+ border-radius: 10px;
+ background-color: #ffffff;
+ /* Paper-like shadow */
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.05);
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
+ cursor: pointer;
+}
+
+.status-card:hover {
+ /* Stronger shadow on hover to enhance floating effect */
+ box-shadow: 0px 8px 30px rgba(0, 0, 0, 0.15);
+ transform: translateY(-5px);
+}
+
+/* Card Title and Description */
+.card-title {
+ font-size: 1.2rem;
+ font-weight: bold;
+ color: #333;
+ margin-bottom: 10px;
+}
+
+.card-description {
+ font-size: 0.95rem;
+ color: #606060;
+ margin-bottom: 15px;
+ line-height: 1.5;
+}
+
+/* Button Styles */
+.view-button {
+ color: #0073e6;
+ background-color: #ffffff;
+ border: 1px solid #0073e6;
+ font-weight: 500;
+ padding: 6px 12px;
+ display: flex;
+ align-items: center;
+ gap: 5px;
+}
+
+.view-button:hover {
+ background-color: #f0f7ff;
+ color: #2563eb;
+}
+
+/* Detail View Styles */
+.detail-view-container {
+ padding: 20px;
+ background-color: transparent;
+ border-radius: 8px;
+ /* Paper-like shadow for detail view */
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1), 0 3px 6px rgba(0, 0, 0, 0.07);
+ margin-top: 20px;
+}
+
+.back-button {
+ margin-bottom: 20px;
+ font-size: 0.9rem;
+ transition: color 0.2s, border-color 0.2s;
+}
+
+/* Year Filter Styles */
+/* Year Filter Styles */
+.year-filter {
+ min-width: 200px;
+ max-width: 300px;
+
+}
\ No newline at end of file
diff --git a/src/Modules/Patent/style/Pcc_Admin/PCCAStatus.css b/src/Modules/Patent/style/Pcc_Admin/PCCAStatus.css
new file mode 100644
index 000000000..e96b95de3
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/PCCAStatus.css
@@ -0,0 +1,236 @@
+/* Global Styles */
+body {
+ background: linear-gradient(to right, #e3f2fd, #fce4ec);
+ font-family: Arial, sans-serif;
+ color: #333;
+ margin: 0;
+ padding: 0;
+}
+
+/* Main Container Styling */
+.form-container {
+ background-color: #ffffff;
+ border-radius: 15px;
+ padding: 16px;
+ margin: 20px auto;
+ max-width: 100%;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+}
+
+/* Title Styling */
+.form-title {
+ font-size: 1.5rem;
+ font-weight: 600;
+ color: #4a90e2;
+ margin-bottom: 20px;
+ text-align: center;
+}
+
+/* Section Styling */
+.form-section {
+ margin-top: 20px;
+ padding: 16px;
+ border-radius: 8px;
+ background: #f8fafc;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+}
+
+.section-title {
+ font-size: 1.2rem;
+ font-weight: 600;
+ color: #4a90e2;
+ margin-bottom: 15px;
+ padding-bottom: 8px;
+ border-bottom: 1px solid #e0e0e0;
+}
+
+/* Form Field Styling */
+.form-field {
+ margin-bottom: 15px;
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.field-heading {
+ font-size: 0.875rem;
+ font-weight: 600;
+ color: #555;
+ margin-bottom: 4px;
+ flex: 0 0 30%;
+}
+
+.field-value {
+ font-size: 0.875rem;
+ color: #333;
+ margin-left: 8px;
+ flex: 0 0 65%;
+}
+
+/* Inventor Container Styling */
+.inventor-container {
+ margin-bottom: 20px;
+ padding: 12px;
+ border-radius: 8px;
+ background: #ffffff;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
+}
+
+.inventor-title {
+ font-size: 1rem;
+ font-weight: 600;
+ color: #4a90e2;
+ margin-bottom: 10px;
+}
+
+/* Progress Bar Styling */
+.progress-container {
+ margin: 20px 0;
+ width: 100%;
+}
+
+.workflow-stepper {
+ width: 100%;
+}
+
+.completed-step {
+ color: #4caf50;
+}
+
+.pending-step {
+ color: #9e9e9e;
+}
+
+.rejection-label {
+ text-align: center;
+ margin-bottom: 15px;
+}
+
+.mobile-view {
+ padding: 10px 0;
+}
+
+/* Form Actions */
+.form-actions {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ margin-top: 20px;
+}
+
+/* Button Styling */
+.down-button {
+ background-color: #0073e6;
+ color: #fff;
+ border: none;
+ font-size: 14px;
+ font-weight: bold;
+ padding: 12px 20px;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: background-color 0.3s ease, color 0.3s ease;
+ width: 100%;
+ text-align: center;
+}
+
+.down-button:hover {
+ background-color: #005bb5;
+}
+
+.down-button:focus {
+ outline: none;
+ box-shadow: 0 0 4px 2px rgba(0, 123, 230, 0.5);
+}
+
+.down-button:disabled {
+ background-color: #cccccc;
+ color: #666666;
+ cursor: not-allowed;
+}
+
+/* Responsive Styles */
+@media (min-width: 768px) {
+ /* Desktop-specific styles */
+ .form-actions {
+ flex-direction: row;
+ justify-content: space-between;
+ }
+
+ .down-button {
+ width: auto;
+ flex: 1;
+ margin: 0 5px;
+ }
+}
+
+@media (max-width: 768px) {
+ /* Mobile-specific styles */
+ .form-container {
+ padding: 12px;
+ margin: 10px auto;
+ }
+
+ .form-title {
+ font-size: 1.2rem;
+ }
+
+ .form-section {
+ padding: 12px;
+ }
+
+ .field-heading,
+ .field-value {
+ font-size: 0.75rem;
+ }
+
+ .inventor-title {
+ font-size: 0.875rem;
+ }
+
+ .down-button {
+ font-size: 12px;
+ padding: 10px 15px;
+ }
+
+ .field-heading,
+ .field-value {
+ flex: 0 0 100%;
+ }
+
+ .field-value {
+ margin-left: 0;
+ margin-top: 4px;
+ }
+}
+
+@media (max-width: 480px) {
+ .form-container {
+ padding: 10px;
+ margin: 8px auto;
+ }
+
+ .form-title {
+ font-size: 1rem;
+ }
+
+ .form-section {
+ padding: 10px;
+ }
+
+ .field-heading,
+ .field-value {
+ font-size: 0.625rem;
+ }
+
+ .inventor-title {
+ font-size: 0.75rem;
+ }
+
+ .down-button {
+ font-size: 10px;
+ padding: 8px 12px;
+ }
+
+ .section-title {
+ font-size: 1rem;
+ }
+}
\ No newline at end of file
diff --git a/src/Modules/Patent/style/Pcc_Admin/PCCAdminDashboard.css b/src/Modules/Patent/style/Pcc_Admin/PCCAdminDashboard.css
new file mode 100644
index 000000000..1b50008ac
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/PCCAdminDashboard.css
@@ -0,0 +1,104 @@
+/* General Styles */
+#pms-pcc-dashboard-title {
+ font-size: 26px;
+ font-weight: bold;
+ text-align: center;
+ color: #333;
+ margin: 0;
+ margin-bottom: 10px;
+}
+
+/* Combined Section */
+#pms-pcc-combined-section {
+ max-width: 95%;
+ font-size: 16px;
+ margin-bottom: 32px;
+ background-color: #ffffff;
+ padding: 24px;
+ border-radius: 8px;
+ box-shadow: 0px 4px 15px rgba(0, 0, 0, 0.2);
+}
+
+/* Overview Section */
+#pms-pcc-overview-section {
+ margin: 0;
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+#pms-pcc-overview-title, #pms-pcc-table-title {
+ font-size: 24px;
+ font-weight: 600;
+ display: flex;
+ align-items: left;
+ gap: 8px;
+ color: #333;
+}
+
+#pms-pcc-overview-icon {
+ margin-top: 7px;
+ color: #000;
+}
+
+
+#pms-pcc-download-button:hover {
+ background-color: #0073e6;
+ color: #ffffff;
+}
+
+/* Dashboard Grid */
+#pms-pcc-dashboard-grid {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 30px;
+ padding-top: 0px;
+}
+
+/* Responsive Behavior */
+@media (max-width: 768px) {
+ #pms-pcc-dashboard-grid {
+ grid-template-columns: 1fr;
+ }
+}
+
+/* Dashboard Cards */
+#pms-pcc-dashboard-cards {
+ background-color: #fff;
+ padding: 32px;
+ margin: 10px;
+ border-radius: 10px;
+ box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.2);
+ transition: box-shadow 0.3s ease, transform 0.3s ease;
+ text-align: left;
+ cursor: pointer;
+ flex: 1 1 calc(50% - 12px); /* Two cards per row on larger screens */
+}
+
+#pms-pcc-dashboard-cards:hover {
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.15);
+ transform: translateY(-4px);
+}
+
+/* Card Title */
+#pms-dashboard-card-title {
+ font-size: 20px;
+ font-weight: 600;
+ color: #0073e6;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+/* Card Divider */
+#pms-dashboard-card-divider {
+ margin-top: 12px;
+ width: 100%;
+ border: 1px solid #f0f0f0;
+ margin-bottom: 12px;
+}
+
+/* Responsive Behavior */
+@media (max-width: 768px) {
+ #pms-dashboard-cards {
+ flex: 1 1 100%; /* One card per row on smaller screens */
+ }
+}
\ No newline at end of file
diff --git a/src/Modules/Patent/style/Pcc_Admin/PastApplications.css b/src/Modules/Patent/style/Pcc_Admin/PastApplications.css
new file mode 100644
index 000000000..3846ae5be
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/PastApplications.css
@@ -0,0 +1,173 @@
+/* Container */
+#pms-pcc-past-past-app-status-applications-container {
+ margin-left: 50px;
+ margin-top: 0;
+ width: 100%;
+ max-width: 1800px;
+ background: #f5f7f8;
+ min-height: 100vh;
+ padding-bottom: 32px;
+}
+
+/* Title */
+#pms-pcc-past-past-app-status-title {
+ font-size: 24px;
+ font-weight: 600;
+ margin-bottom: 18px;
+ margin-top: 0;
+ text-align: left;
+ letter-spacing: 0.01em;
+}
+
+/* Loading/Error/Empty */
+#pms-pcc-past-loading-container,
+#pms-pcc-past-error-container,
+#pms-pcc-past-empty-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 48px 0;
+ background: #fff;
+ border-radius: 10px;
+ box-shadow: 0 2px 12px rgba(0,0,0,0.08);
+ margin: 32px 0;
+ text-align: center;
+}
+
+/* Table Container */
+#pms-pcc-past-past-app-outerContainer {
+ overflow: hidden;
+ margin-right: 50px;
+ margin-top: 12px;
+}
+
+/* Table */
+.mantine-Table-root,
+#pms-pcc-past-past-app-outerContainer table {
+ width: 100%;
+ border-collapse: collapse;
+ background: transparent;
+}
+
+#pms-pcc-past-past-app-outerContainer th {
+ font-size: 13px;
+}
+
+#pms-pcc-past-past-app-outerContainer td {
+ font-size: 12px;
+}
+
+#pms-pcc-past-fusionTableHeader th {
+ padding: 14px 18px;
+ font-weight: 500;
+ color: #333;
+ text-align: left;
+ border-bottom: 2px solid #e5e7eb;
+ background: #f8f9fa;
+ font-size: 20px;
+}
+
+#pms-pcc-past-past-app-outerContainer td {
+ padding: 14px 18px;
+ color: #333;
+ border-bottom: 1px solid #e5e7eb;
+ font-size: 16px;
+ vertical-align: middle;
+}
+
+/* Alternate row colors */
+#pms-pcc-past-past-app-outerContainer tbody tr:nth-child(odd) {
+ background: #fff;
+}
+#pms-pcc-past-past-app-outerContainer tbody tr:nth-child(even) {
+ background: #f8f9fa;
+}
+
+/* Hover */
+#pms-pcc-past-past-app-outerContainer tbody tr:hover {
+ background: #eaf4fa;
+ transition: background 0.15s;
+}
+
+/* Status Badge */
+.status-badge {
+ display: inline-block;
+ padding: 4px 10px;
+ border-radius: 4px;
+ font-size: 0.95rem;
+ font-weight: 600;
+ color: #fff;
+ background: #bdbdbd;
+}
+.status-badge.approved { background: #4caf50; }
+.status-badge.rejected { background: #e53935; }
+.status-badge.pending { background: #ffb300; }
+.status-badge.default { background: #bdbdbd; }
+
+/* View Button */
+.view-button,
+#pms-pcc-past-past-app-outerContainer .mantine-Button-root {
+ color: #0073e6;
+ background: #fff;
+ border: 1px solid #0073e6;
+ font-weight: 500;
+ padding: 6px 14px;
+ border-radius: 5px;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ transition: all 0.18s;
+ font-size: 0.98rem;
+}
+
+.view-button:hover,
+#pms-pcc-past-past-app-outerContainer .mantine-Button-root:hover {
+ background: #f0f7ff;
+ color: #2563eb;
+ border-color: #2563eb;
+}
+
+/* Responsive */
+@media (max-width: 900px) {
+ #pms-pcc-past-past-app-status-applications-container {
+ margin-left: 8px;
+ padding-bottom: 16px;
+ }
+ #pms-pcc-past-past-app-outerContainer {
+ margin-right: 8px;
+ }
+ .status-card {
+ width: 100%;
+ margin-bottom: 18px;
+ }
+}
+
+@media (max-width: 600px) {
+ #pms-pcc-past-past-app-status-applications-container {
+ margin-left: 0;
+ padding-bottom: 8px;
+ }
+ #pms-pcc-past-past-app-outerContainer {
+ margin-right: 0;
+ border-radius: 7px;
+ }
+ #pms-pcc-past-past-app-status-title {
+ font-size: 1.25rem;
+ margin-bottom: 10px;
+ }
+ .status-card {
+ padding: 14px;
+ border-radius: 7px;
+ }
+ #pms-pcc-past-fusionTableHeader th,
+ #pms-pcc-past-past-app-outerContainer td {
+ padding: 8px 6px;
+ font-size: 0.92rem;
+ }
+}
+
+/* Utility */
+.text-muted {
+ color: #888 !important;
+}
diff --git a/src/Modules/Patent/style/Pcc_Admin/ReviewApplication.css b/src/Modules/Patent/style/Pcc_Admin/ReviewApplication.css
new file mode 100644
index 000000000..033a411dd
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/ReviewApplication.css
@@ -0,0 +1,164 @@
+/* General Container */
+.outerContainer {
+ max-width: 100%;
+ padding: 32px;
+ background-color: #f9fafc;
+ margin-left: 25px;
+ border-radius: 8px;
+ margin-bottom: 10px;
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1);
+ overflow-x: hidden; /* Prevent horizontal overflow */
+}
+
+.title {
+ font-size: 26px;
+ font-weight: bold;
+ text-align: left;
+ margin: 0 auto;
+ margin-top: 15px;
+ margin-bottom: 10px;
+ color: black;
+ padding-left: 30px;
+}
+
+.title span {
+ color: black;
+}
+
+.content {
+ text-align: left;
+}
+
+.description {
+ text-align: left;
+ margin-left: 32px; /* Default margin for desktop */
+ margin-right: 32px; /* Default margin for desktop */
+ font-size: 14px;
+ color: #555;
+}
+
+/* Wrapper for horizontal scrolling */
+.tableWrapper {
+ overflow-x: auto; /* Enable horizontal scrolling */
+ width: 100%;
+ -webkit-overflow-scrolling: touch; /* Smooth scrolling on mobile */
+}
+
+/* Responsive Table */
+.styledTable {
+ width: 100%;
+ font-size: 14px;
+ background-color: #ffffff;
+ border-spacing: 0 8px;
+ transition: all 0.3s ease;
+ box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.05);
+}
+
+.fusionTableHeader th {
+ padding: 14px 18px;
+ text-align: left;
+}
+
+.tableRow {
+ background-color: #ffffff;
+ border-radius: 8px;
+ transition: background-color 0.2s ease, transform 0.2s ease;
+}
+
+.viewButton {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-weight: 600;
+ transition: color 0.2s ease, transform 0.2s ease;
+}
+
+/* Responsive Design */
+
+/* Small devices (up to 768px) */
+@media (max-width: 768px) {
+ .outerContainer {
+ padding: 16px; /* Reduced padding for smaller screens */
+ margin-left: 0;
+ margin-right: 0;
+ max-width: 100vw; /* Ensure container doesn't exceed viewport width */
+ overflow-x: hidden; /* Prevent horizontal overflow */
+ }
+
+ .title {
+ font-size: 22px; /* Adjusted font size */
+ padding-left: 16px;
+ }
+
+ .description {
+ margin-left: 24px !important; /* Adjusted margin for smaller screens */
+ margin-right: 16px !important; /* Adjusted margin for smaller screens */
+ font-size: 13px; /* Smaller font size for mobile */
+ }
+
+ .tableWrapper {
+ overflow-x: auto; /* Ensure horizontal scrolling */
+ width: 100%; /* Take full width of the container */
+ margin-left: 0; /* Reset negative margin */
+ }
+
+ .styledTable {
+ min-width: 100%; /* Allow table to shrink to fit the screen */
+ }
+
+ .fusionTableHeader th {
+ padding: 10px 12px; /* Reduced padding for smaller screens */
+ font-size: 12px; /* Smaller font size for headers */
+ }
+
+ .tableRow td {
+ padding: 10px 12px; /* Reduced padding for smaller screens */
+ font-size: 12px; /* Smaller font size for table cells */
+ }
+
+ .viewButton {
+ font-size: 12px; /* Smaller font size for button */
+ }
+}
+
+/* Extra small devices (up to 480px) */
+@media (max-width: 480px) {
+ .outerContainer {
+ padding: 12px;
+ max-width: 100vw; /* Ensure container doesn't exceed viewport width */
+ overflow-x: hidden; /* Prevent horizontal overflow */
+ }
+
+ .title {
+ font-size: 20px;
+ padding-left: 8px;
+ }
+
+ .description {
+ margin-left: 16px !important; /* Further reduced margin for very small screens */
+ margin-right: 8px !important; /* Further reduced margin for very small screens */
+ font-size: 12px; /* Even smaller font size for compact screens */
+ }
+
+ .tableWrapper {
+ margin-left: 0; /* Reset negative margin */
+ }
+
+ .styledTable {
+ min-width: 100%; /* Allow table to shrink to fit the screen */
+ }
+
+ .fusionTableHeader th {
+ padding: 8px 10px; /* Further reduced padding for very small screens */
+ font-size: 11px; /* Smaller font size for headers */
+ }
+
+ .tableRow td {
+ padding: 8px 10px; /* Further reduced padding for very small screens */
+ font-size: 11px; /* Smaller font size for table cells */
+ }
+
+ .viewButton {
+ font-size: 11px; /* Smaller font size for button */
+ }
+}
\ No newline at end of file
diff --git a/src/Modules/Patent/style/Pcc_Admin/ReviewComponent.css b/src/Modules/Patent/style/Pcc_Admin/ReviewComponent.css
new file mode 100644
index 000000000..a1da0e3df
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/ReviewComponent.css
@@ -0,0 +1,88 @@
+/* Container for the form */
+.form-container {
+ width: 1300px;
+ margin: auto;
+ background-color: #ffffff; /* White background for contrast */
+ border-radius: 10px; /* Rounded corners */
+ padding: 30px; /* Padding around the content */
+ box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */
+}
+
+/* Header styles */
+.header {
+ font-size: 28px;
+ font-weight: bold;
+ color: #2d3748; /* Dark gray for text */
+ margin-bottom: 10px; /* Space below header */
+}
+
+.sub-header {
+ font-size: 16px;
+ color: #4a5568; /* Slightly lighter gray */
+ margin-bottom: 20px; /* Space below sub-header */
+}
+
+/* Section title styles */
+.section-title {
+ font-size: 22px;
+ font-weight: bold;
+ color: #2d3748; /* Dark gray */
+ margin-top: 20px; /* Space above section titles */
+}
+
+/* Question title styles */
+.question-title {
+ font-size: 18px;
+ color: #2d3748; /* Dark gray */
+ margin-top: 15px; /* Space above question titles */
+}
+
+/* Input field styles */
+.textarea,
+.text-input {
+ margin-bottom: 20px; /* Space below each input field */
+}
+
+/* Button container styling */
+.button-container {
+ display: flex;
+ justify-content: space-between; /* Space between buttons */
+}
+
+/* Action button styling */
+.action-button {
+ flex-grow: 1; /* Allow buttons to grow equally */
+ margin-right: 10px; /* Space between buttons */
+ transition: background-color .3s ease, transform .2s ease; /* Animation for hover and click effects */
+ border-radius: 5px; /* Rounded corners for buttons */
+ padding: 10px; /* Padding inside buttons */
+ border: none; /* Remove default border */
+}
+
+.action-button:hover {
+ background-color: rgba(0,0,0,0.05); /* Light hover effect for buttons */
+ transform: translateY(-2px); /* Slight lift effect on hover */
+}
+
+/* Remove margin from last button to avoid extra space at the end */
+.action-button:last-child {
+ margin-right: 0;
+}
+
+/* Textarea styling for better appearance */
+textarea {
+ border-radius: 5px; /* Rounded corners for text areas */
+ border: 1px solid #cbd5e0; /* Light gray border color for text areas */
+ padding: 10px; /* Padding inside text areas */
+ resize: vertical; /* Allow vertical resizing only */
+}
+
+textarea::placeholder {
+ color: #a0aec0; /* Placeholder text color */
+}
+
+textarea:hover,
+textarea:focus {
+ border-color: #3182ce; /* Change border color on hover and focus to blue */
+ outline: none; /* Remove default outline on focus */
+}
\ No newline at end of file
diff --git a/src/Modules/Patent/style/Pcc_Admin/StatusOfApplications.css b/src/Modules/Patent/style/Pcc_Admin/StatusOfApplications.css
new file mode 100644
index 000000000..256cf645c
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/StatusOfApplications.css
@@ -0,0 +1,111 @@
+/* Centering Header */
+.status-header {
+ display: flex;
+ justify-content: flex-start;
+ margin-bottom: 20px;
+}
+
+/* Container Styles */
+.status-container {
+ padding: 30px;
+ max-width: 100%;
+ background-color: #f9fafb;
+}
+
+/* Title and Description */
+.status-title {
+ font-size: 2rem;
+ color: #333;
+ margin-bottom: 16px;
+ font-weight: 700;
+ text-align: left;
+}
+.stati-title{
+ font-size: 2rem;
+ color: #333;
+ margin-bottom: 16px;
+ font-weight: 700;
+ text-align: left;
+}
+
+.description {
+ font-size: 1rem;
+ color: #5f6368;
+ margin-bottom: 24px;
+ line-height: 1.6;
+ text-align: center;
+}
+
+/* Status Cards Container */
+.status-cards-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 24px;
+ justify-content: flex-start;
+}
+
+/* Individual Card Styles */
+.status-card {
+ width: calc(48% - 8px);
+ padding: 20px;
+ border-radius: 10px;
+ background-color: #ffffff;
+ /* Paper-like shadow */
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.05);
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
+ cursor: pointer;
+}
+
+.status-card:hover {
+ /* Stronger shadow on hover to enhance floating effect */
+ box-shadow: 0px 8px 30px rgba(0, 0, 0, 0.15);
+
+ transform: translateY(-5px);
+}
+
+/* Card Title and Description */
+.card-title {
+ font-size: 1.2rem;
+ font-weight: bold;
+ color: #333;
+ margin-bottom: 10px;
+}
+
+.card-description {
+ font-size: 0.95rem;
+ color: #606060;
+ margin-bottom: 15px;
+ line-height: 1.5;
+}
+
+/* Button Styles */
+.view-button {
+ color: #0073e6;
+ background-color: #ffffff;
+ border: 1px solid #0073e6;
+ font-weight: 500;
+ padding: 1px;
+}
+
+.view-button:hover {
+ background-color: #2563eb;
+}
+
+/* Detail View Styles */
+.detail-view-container {
+ padding: 20px;
+ background-color: #ffffff;
+ border-radius: 8px;
+ /* Paper-like shadow for detail view */
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1), 0 3px 6px rgba(0, 0, 0, 0.07);
+ margin-top: 20px;
+}
+
+.back-button {
+ margin-bottom: 20px;
+ font-size: 0.9rem;
+
+ transition: color 0.2s, border-color 0.2s;
+}
+
+
diff --git a/src/Modules/Patent/style/Pcc_Admin/ViewNewApplication.css b/src/Modules/Patent/style/Pcc_Admin/ViewNewApplication.css
new file mode 100644
index 000000000..75fb4c6ab
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/ViewNewApplication.css
@@ -0,0 +1,311 @@
+/*========================================
+ Base & Container
+========================================*/
+#pms-pcc-new-app-detail-container1 {
+ width: 100%;
+ max-width: 1400px;
+ margin: 0 auto;
+ background-color: #f5f8f9;
+ padding: 2rem 4%;
+ box-sizing: border-box;
+ font-family: 'Inter', sans-serif;
+}
+
+.mobile-form-container {
+ padding: 1rem 2%;
+}
+
+/*========================================
+ Loader & Error States
+========================================*/
+#pms-pcc-loader-container,
+#pms-pcc-error-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 4rem 0;
+ text-align: center;
+}
+
+#pms-pcc-error-container .mantine-Alert-root {
+ max-width: 600px;
+ width: 100%;
+}
+
+/*========================================
+ Header: Back Button & Title
+========================================*/
+#pms-pcc-new-app-detail-container1 > div:first-child {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 1.5rem;
+}
+
+#pms-pcc-new-app-detail-container1 > div:first-child .mantine-Button {
+ margin-right: auto;
+ background: #ffffff;
+ border: 1px solid #dee2e6;
+ color: #1e66f5;
+ font-weight: 500;
+ padding: 0.5rem 1rem;
+ border-radius: 4px;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+}
+
+#pms-pcc-new-app-detail-container1 > div:first-child .mantine-Button:hover {
+ background-color: #1e66f5;
+ color: #ffffff;
+ box-shadow: 0 2px 6px rgba(0,0,0,0.15);
+}
+
+#pms-pcc-detail-page-title {
+ font-size: 1.75rem;
+ font-weight: 600;
+ color: #1e293b;
+ text-align: center;
+ margin: 0;
+}
+
+.mobile-detail-page-title {
+ font-size: 1.5rem;
+}
+
+/*========================================
+ Action Buttons Section
+========================================*/
+#pms-pcc-action-buttons-card {
+ margin: 0 0 1rem;
+ max-width: none;
+ padding: 1rem 2rem;
+ background-color: transparent;
+ box-shadow: none;
+}
+
+#pms-pcc-action-buttons-group {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1rem;
+ justify-content: center;
+}
+
+#pms-pcc-action-button {
+ min-width: 180px;
+ font-weight: 500;
+ transition: background-color 0.2s ease, color 0.2s ease;
+}
+
+/* Blue Download button */
+#pms-pcc-action-button[color="blue"] {
+ border: 2px solid #1e66f5;
+ color: #1e66f5;
+ background: transparent;
+}
+#pms-pcc-action-button[color="blue"]:hover {
+ background-color: #1e66f5;
+ color: white;
+}
+
+/* Green Forward button */
+#pms-pcc-action-button[color="green"] {
+ border: 2px solid #40c057;
+ color: #40c057;
+ background: transparent;
+}
+#pms-pcc-action-button[color="green"]:hover {
+ background-color: #40c057;
+ color: white;
+}
+
+/* Orange Modify button */
+#pms-pcc-action-button[color="orange"] {
+ border: 2px solid #fd7e14;
+ color: #fd7e14;
+ background: transparent;
+}
+#pms-pcc-action-button[color="orange"]:hover {
+ background-color: #fd7e14;
+ color: white;
+}
+
+/* Gray disabled/no-file button */
+#pms-pcc-download-button-wrapper .mantine-Button[color="gray"] {
+ border: 2px solid #adb5bd;
+ color: #adb5bd;
+ background: transparent;
+}
+#pms-pcc-download-button-wrapper .mantine-Button[color="gray"]:hover {
+ background-color: #adb5bd;
+ color: white;
+}
+
+/*========================================
+ Detail Form Content
+========================================*/
+#pms-pcc-pcc-form-content {
+ max-width: 1200px;
+ margin: 1rem auto 2rem;
+}
+
+/*----------------------------------------
+ FormField rows (boxed style)
+----------------------------------------*/
+#pms-pcc-form-field,
+#pms-pcc-form-field-with-download {
+ background-color: #ffffff;
+ border-radius: 6px;
+ padding: 0.75rem 1rem;
+ margin-bottom: 0.75rem;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ justify-content: flex-start;
+}
+
+#pms-pcc-form-field:last-child,
+#pms-pcc-form-field-with-download:last-child {
+ margin-bottom: 0;
+}
+
+#pms-pcc-field-label-container,
+#pms-pcc-form-field > #pms-pcc-field-label {
+ flex: 0 0 auto;
+}
+
+#pms-pcc-field-value {
+ flex: 1 1 auto;
+ background-color: #f8f9fa;
+ padding: 0.5rem 0.75rem;
+ border: 1px solid #e2e8f0;
+ border-radius: 4px;
+ font-size: 1rem;
+ color: #334155;
+ word-break: break-word;
+}
+
+/*========================================
+ Section Cards (via FormSection)
+========================================*/
+#pms-pcc-detail-section {
+ background-color: #ffffff;
+ border-radius: 8px;
+ box-shadow: 0 2px 8px rgba(0,0,0,0.05);
+ margin: 1.5rem auto;
+ max-width: 1200px;
+ padding: 1.5rem 2rem;
+}
+
+#pms-pcc-section-title {
+ font-size: 1.5rem;
+ font-weight: 600;
+ color: #1e293b;
+ margin-bottom: 1rem;
+}
+
+/*========================================
+ Key Dates Grid & Cards
+========================================*/
+#pms-pcc-key-dates-container {
+ margin-top: 1rem;
+}
+
+#pms-pcc-key-dates-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
+ gap: 1rem;
+}
+
+#pms-pcc-key-date-card {
+ background-color: #ffffff;
+ border-radius: 8px;
+ padding: 1rem;
+ text-align: center;
+ box-shadow: 0 1px 6px rgba(0,0,0,0.04);
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+#pms-pcc-key-date-card:hover {
+ transform: translateY(-4px);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+}
+
+#pms-pcc-key-date-title {
+ font-size: 0.9rem;
+ font-weight: 500;
+ color: #475569;
+ margin-bottom: 0.5rem;
+}
+
+#pms-pcc-key-date-value {
+ font-size: 1rem;
+ font-weight: 600;
+ color: #1e293b;
+}
+
+/*========================================
+ Applicants Cards
+========================================*/
+#pms-pcc-applicant-card {
+ background-color: #ffffff;
+ border-radius: 6px;
+ box-shadow: 0 1px 5px rgba(0,0,0,0.05);
+ padding: 1rem;
+ margin-bottom: 1rem;
+}
+
+/*========================================
+ Modals (override Mantine defaults)
+========================================*/
+.mantine-Modal-root .mantine-Modal-modal {
+ margin: 0 auto !important;
+}
+
+.mantine-Modal-root .mantine-Modal-inner {
+ border-radius: 8px;
+ box-shadow: 0 4px 20px rgba(0,0,0,0.1);
+ overflow: hidden;
+}
+
+.mantine-Modal-title {
+ padding-bottom: 0.5rem;
+ border-bottom: 1px solid #e2e8f0 !important;
+}
+
+.mantine-Modal-root .mantine-Modal-body {
+ padding: 1.5rem 2rem;
+}
+
+/*========================================
+ Responsive Adjustments
+========================================*/
+@media (max-width: 768px) {
+ #pms-pcc-new-app-detail-container1 {
+ padding: 1rem 2%;
+ }
+
+ #pms-pcc-pcc-form-content {
+ padding: 0 1rem;
+ }
+
+ #pms-pcc-action-buttons-group {
+ flex-direction: column;
+ }
+
+ #pms-pcc-key-dates-grid {
+ grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
+ }
+
+ #pms-pcc-detail-section {
+ padding: 1rem 1.5rem;
+ margin: 1rem 0;
+ }
+
+ #pms-pcc-detail-page-title {
+ font-size: 1.5rem;
+ }
+}
diff --git a/src/Modules/Patent/style/Pcc_Admin/ViewOngoingApplication.css b/src/Modules/Patent/style/Pcc_Admin/ViewOngoingApplication.css
new file mode 100644
index 000000000..3e04a65d6
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/ViewOngoingApplication.css
@@ -0,0 +1,273 @@
+/* ============================
+ Detail Container
+============================= */
+.pms-pcc-ongoing-detail-container {
+ max-width: 1800px;
+ margin: 0 auto;
+ background: transparent;
+ border-radius: 16px;
+ box-sizing: border-box;
+ font-family: 'Inter', 'Segoe UI', Arial, sans-serif;
+}
+
+/* ============================
+ Header Bar
+ ============================= */
+#pms-pcc-past-detail-header {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ background: #f6f8fa;
+ height: 60px;
+ margin-bottom: 2rem;
+ border-bottom: 1.5px solid #e2e8f0;
+ border-radius: 8px 8px 0 0;
+}
+
+#pms-pcc-past-detail-title {
+ font-size: 2rem;
+ font-weight: 700;
+ color: #1e293b;
+ margin: 0;
+ text-align: center;
+ letter-spacing: 0.01em;
+}
+
+#pms-pcc-past-detail-back-button,
+#pms-pcc-past-detail-download-button {
+ position: absolute;
+ top: 50%;
+ transform: translateY(-50%);
+ background: none;
+ border: none;
+ color: #2563eb;
+ font-weight: 600;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.5rem 1.25rem;
+ transition: color 0.18s, background 0.18s;
+ cursor: pointer;
+ border-radius: 5px;
+ font-size: 1rem;
+}
+
+#pms-pcc-past-detail-back-button {
+ left: 1.25rem;
+}
+
+#pms-pcc-past-detail-download-button {
+ right: 1.25rem;
+}
+
+#pms-pcc-past-detail-back-button:hover,
+#pms-pcc-past-detail-download-button:hover {
+ color: #fff;
+ background: #2563eb;
+}
+
+/* ============================
+ Section Cards
+ ============================= */
+#pms-pcc-past-detail-section {
+ background: #fff;
+ border-radius: 12px;
+ box-shadow: 0 2px 12px rgba(30, 40, 90, 0.05);
+ margin-bottom: 2.2rem;
+ padding: 2rem 2.5rem;
+ border: 1px solid #e5e7eb;
+ width: 100%;
+}
+
+#pms-pcc-past-section-title {
+ font-size: 1.3rem;
+ font-weight: 700;
+ color: #1e293b;
+ margin-bottom: 1.3rem;
+ letter-spacing: 0.01em;
+}
+
+/* ============================
+ Form Fields
+ ============================= */
+#pms-pcc-past-form-field,
+#pms-pcc-past-form-field-with-download {
+ display: flex;
+ align-items: flex-start;
+ gap: 1.2rem;
+ margin-bottom: 1.1rem;
+}
+
+#pms-pcc-past-form-field-with-download {
+ justify-content: space-between;
+}
+
+#pms-pcc-past-field-label-container,
+#pms-pcc-past-form-field>#pms-pcc-past-field-label {
+ flex: 0 0 auto;
+}
+
+#pms-pcc-past-field-label {
+ font-weight: 600;
+ color: #475569;
+ font-size: 1rem;
+ min-width: 120px;
+}
+
+#pms-pcc-past-field-value {
+ flex: 1 1 auto;
+ background: #fff;
+ padding: 0.6rem 1rem;
+ border: 1px solid #e5e7eb;
+ border-radius: 5px;
+ color: #334155;
+ font-size: 1rem;
+ word-break: break-word;
+}
+
+#pms-pcc-past-download-button-wrapper {
+ flex-shrink: 0;
+ margin-left: 1rem;
+}
+
+/* ============================
+ Key Dates Grid
+ ============================= */
+#pms-pcc-past-key-dates-container {
+ margin-top: 0.8rem;
+}
+
+#pms-pcc-past-key-dates-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
+ gap: 1.2rem;
+}
+
+#pms-pcc-past-key-date-card {
+ background: #f9fafb;
+ border-radius: 8px;
+ padding: 1.1rem 1rem;
+ text-align: center;
+ box-shadow: 0 1px 6px rgba(30, 40, 90, 0.03);
+ border: 1px solid #e5e7eb;
+ transition: transform 0.18s, box-shadow 0.18s;
+}
+
+#pms-pcc-past-key-date-card:hover {
+ transform: translateY(-3px) scale(1.02);
+ box-shadow: 0 4px 18px rgba(30, 40, 90, 0.09);
+}
+
+#pms-pcc-past-key-date-title {
+ font-size: 1.05rem;
+ font-weight: 500;
+ color: #475569;
+ margin-bottom: 0.4rem;
+}
+
+#pms-pcc-past-key-date-value {
+ font-size: 1.08rem;
+ font-weight: 600;
+ color: #2563eb;
+}
+
+/* ============================
+ Applicants Cards
+ ============================= */
+#pms-pcc-past-applicant-card {
+ background: #f9fafb;
+ border-radius: 8px;
+ box-shadow: 0 1px 7px rgba(30, 40, 90, 0.04);
+ padding: 1.2rem 1rem;
+ margin-bottom: 1.2rem;
+ border: 1px solid #e5e7eb;
+}
+
+/* ============================
+ Loader & Alerts
+ ============================= */
+#pms-pcc-past-loader-container,
+#pms-pcc-past-error-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 3.5rem 0;
+ text-align: center;
+}
+
+/* ============================
+ Responsive Design
+ ============================= */
+@media (max-width: 900px) {
+ #pms-pcc-past-detail-container {
+ padding: 1.25rem 1.5%;
+ max-width: 99vw;
+ }
+
+ #pms-pcc-past-detail-section {
+ padding: 1.2rem 1rem;
+ }
+}
+
+@media (max-width: 768px) {
+ #pms-pcc-past-detail-container {
+ padding: 0.7rem 1.5%;
+ border-radius: 10px;
+ }
+
+ #pms-pcc-past-form-field,
+ #pms-pcc-past-form-field-with-download {
+ flex-direction: column;
+ align-items: stretch;
+ gap: 0.5rem;
+ }
+
+ #pms-pcc-past-detail-section {
+ padding: 1rem 0.5rem;
+ }
+
+ #pms-pcc-past-detail-header {
+ height: 48px;
+ font-size: 1rem;
+ border-radius: 7px 7px 0 0;
+ }
+
+ #pms-pcc-past-detail-back-button,
+ #pms-pcc-past-detail-download-button {
+ font-size: 0.95rem;
+ padding: 0.4rem 0.8rem;
+ left: 0.5rem;
+ right: 0.5rem;
+ }
+
+ #pms-pcc-past-detail-title {
+ font-size: 1.1rem;
+ }
+
+ #pms-pcc-past-key-dates-grid {
+ grid-template-columns: 1fr;
+ gap: 0.7rem;
+ }
+}
+
+@media (max-width: 480px) {
+ #pms-pcc-past-detail-container {
+ padding: 0.4rem 0.2rem;
+ border-radius: 6px;
+ }
+
+ #pms-pcc-past-detail-section {
+ padding: 0.7rem 0.2rem;
+ }
+
+ #pms-pcc-past-detail-header {
+ height: 38px;
+ font-size: 0.95rem;
+ }
+
+ #pms-pcc-past-detail-title {
+ font-size: 1rem;
+ }
+}
\ No newline at end of file
diff --git a/src/Modules/Patent/style/Pcc_Admin/ViewPastApplications.css b/src/Modules/Patent/style/Pcc_Admin/ViewPastApplications.css
new file mode 100644
index 000000000..fd63d150a
--- /dev/null
+++ b/src/Modules/Patent/style/Pcc_Admin/ViewPastApplications.css
@@ -0,0 +1,246 @@
+/* ============================
+ Detail Container
+============================= */
+#pms-pcc-past-detail-container {
+ max-width: 1300px;
+ margin: 0 auto;
+ background: #f6f8fa;
+ padding: 2.5rem 2.5%;
+ border-radius: 16px;
+ box-sizing: border-box;
+ font-family: 'Inter', 'Segoe UI', Arial, sans-serif;
+ }
+
+ /* ============================
+ Header Bar
+ ============================= */
+ #pms-pcc-past-detail-header {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ background: #f6f8fa;
+ height: 60px;
+ margin-bottom: 2rem;
+ border-bottom: 1.5px solid #e2e8f0;
+ border-radius: 8px 8px 0 0;
+ }
+
+ #pms-pcc-past-detail-title {
+ font-size: 2rem;
+ font-weight: 700;
+ color: #1e293b;
+ margin: 0;
+ text-align: center;
+ letter-spacing: 0.01em;
+ }
+
+ #pms-pcc-past-detail-back-button,
+ #pms-pcc-past-detail-download-button {
+ position: absolute;
+ top: 50%;
+ transform: translateY(-50%);
+ background: none;
+ border: none;
+ color: #2563eb;
+ font-weight: 600;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.5rem 1.25rem;
+ transition: color 0.18s, background 0.18s;
+ cursor: pointer;
+ border-radius: 5px;
+ font-size: 1rem;
+ }
+ #pms-pcc-past-detail-back-button { left: 1.25rem; }
+ #pms-pcc-past-detail-download-button { right: 1.25rem; }
+ #pms-pcc-past-detail-back-button:hover,
+ #pms-pcc-past-detail-download-button:hover {
+ color: #fff;
+ background: #2563eb;
+ }
+
+ /* ============================
+ Section Cards
+ ============================= */
+ #pms-pcc-past-detail-section {
+ background: #fff;
+ border-radius: 12px;
+ box-shadow: 0 2px 12px rgba(30, 40, 90, 0.05);
+ margin-bottom: 2.2rem;
+ padding: 2rem 2.5rem;
+ border: 1px solid #e5e7eb;
+ width: 100%;
+ }
+
+ #pms-pcc-past-section-title {
+ font-size: 1.3rem;
+ font-weight: 700;
+ color: #1e293b;
+ margin-bottom: 1.3rem;
+ letter-spacing: 0.01em;
+ }
+
+ /* ============================
+ Form Fields
+ ============================= */
+ #pms-pcc-past-form-field,
+ #pms-pcc-past-form-field-with-download {
+ display: flex;
+ align-items: flex-start;
+ gap: 1.2rem;
+ margin-bottom: 1.1rem;
+ }
+ #pms-pcc-past-form-field-with-download {
+ justify-content: space-between;
+ }
+ #pms-pcc-past-field-label-container,
+ #pms-pcc-past-form-field > #pms-pcc-past-field-label {
+ flex: 0 0 auto;
+ }
+ #pms-pcc-past-field-label {
+ font-weight: 600;
+ color: #475569;
+ font-size: 1rem;
+ min-width: 120px;
+ }
+ #pms-pcc-past-field-value {
+ flex: 1 1 auto;
+ background: #fff;
+ padding: 0.6rem 1rem;
+ border: 1px solid #e5e7eb;
+ border-radius: 5px;
+ color: #334155;
+ font-size: 1rem;
+ word-break: break-word;
+ }
+ #pms-pcc-past-download-button-wrapper {
+ flex-shrink: 0;
+ margin-left: 1rem;
+ }
+
+ /* ============================
+ Key Dates Grid
+ ============================= */
+ #pms-pcc-past-key-dates-container {
+ margin-top: 0.8rem;
+ }
+ #pms-pcc-past-key-dates-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
+ gap: 1.2rem;
+ }
+ #pms-pcc-past-key-date-card {
+ background: #f9fafb;
+ border-radius: 8px;
+ padding: 1.1rem 1rem;
+ text-align: center;
+ box-shadow: 0 1px 6px rgba(30, 40, 90, 0.03);
+ border: 1px solid #e5e7eb;
+ transition: transform 0.18s, box-shadow 0.18s;
+ }
+ #pms-pcc-past-key-date-card:hover {
+ transform: translateY(-3px) scale(1.02);
+ box-shadow: 0 4px 18px rgba(30, 40, 90, 0.09);
+ }
+ #pms-pcc-past-key-date-title {
+ font-size: 1.05rem;
+ font-weight: 500;
+ color: #475569;
+ margin-bottom: 0.4rem;
+ }
+ #pms-pcc-past-key-date-value {
+ font-size: 1.08rem;
+ font-weight: 600;
+ color: #2563eb;
+ }
+
+ /* ============================
+ Applicants Cards
+ ============================= */
+ #pms-pcc-past-applicant-card {
+ background: #f9fafb;
+ border-radius: 8px;
+ box-shadow: 0 1px 7px rgba(30, 40, 90, 0.04);
+ padding: 1.2rem 1rem;
+ margin-bottom: 1.2rem;
+ border: 1px solid #e5e7eb;
+ }
+
+ /* ============================
+ Loader & Alerts
+ ============================= */
+ #pms-pcc-past-loader-container,
+ #pms-pcc-past-error-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 3.5rem 0;
+ text-align: center;
+ }
+
+ /* ============================
+ Responsive Design
+ ============================= */
+ @media (max-width: 900px) {
+ #pms-pcc-past-detail-container {
+ padding: 1.25rem 1.5%;
+ max-width: 99vw;
+ }
+ #pms-pcc-past-detail-section {
+ padding: 1.2rem 1rem;
+ }
+ }
+ @media (max-width: 768px) {
+ #pms-pcc-past-detail-container {
+ padding: 0.7rem 1.5%;
+ border-radius: 10px;
+ }
+ #pms-pcc-past-form-field,
+ #pms-pcc-past-form-field-with-download {
+ flex-direction: column;
+ align-items: stretch;
+ gap: 0.5rem;
+ }
+ #pms-pcc-past-detail-section {
+ padding: 1rem 0.5rem;
+ }
+ #pms-pcc-past-detail-header {
+ height: 48px;
+ font-size: 1rem;
+ border-radius: 7px 7px 0 0;
+ }
+ #pms-pcc-past-detail-back-button,
+ #pms-pcc-past-detail-download-button {
+ font-size: 0.95rem;
+ padding: 0.4rem 0.8rem;
+ left: 0.5rem;
+ right: 0.5rem;
+ }
+ #pms-pcc-past-detail-title {
+ font-size: 1.1rem;
+ }
+ #pms-pcc-past-key-dates-grid {
+ grid-template-columns: 1fr;
+ gap: 0.7rem;
+ }
+ }
+ @media (max-width: 480px) {
+ #pms-pcc-past-detail-container {
+ padding: 0.4rem 0.2rem;
+ border-radius: 6px;
+ }
+ #pms-pcc-past-detail-section {
+ padding: 0.7rem 0.2rem;
+ }
+ #pms-pcc-past-detail-header {
+ height: 38px;
+ font-size: 0.95rem;
+ }
+ #pms-pcc-past-detail-title {
+ font-size: 1rem;
+ }
+ }
+
\ No newline at end of file
diff --git a/src/Modules/Patent/utils/helpers.js b/src/Modules/Patent/utils/helpers.js
new file mode 100644
index 000000000..eaebb6333
--- /dev/null
+++ b/src/Modules/Patent/utils/helpers.js
@@ -0,0 +1,17 @@
+export const toDisplayDate = (value) => {
+ if (!value) return "Not Provided";
+ try {
+ return new Date(value).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "short",
+ day: "numeric",
+ });
+ } catch {
+ return value;
+ }
+};
+
+export const toSafeArray = (value) => {
+ if (Array.isArray(value)) return value;
+ return [];
+};
diff --git a/src/components/sidebarContent.jsx b/src/components/sidebarContent.jsx
index b77581b39..7880b71c4 100644
--- a/src/components/sidebarContent.jsx
+++ b/src/components/sidebarContent.jsx
@@ -26,6 +26,7 @@ import {
Wrench as IWDIcon,
City as HostelIcon,
Certificate as OtherAcademicIcon,
+ Certificate as PatentIcon,
Database as DatabaseIcon,
Question as HelpIcon,
User as ProfileIcon,
@@ -140,7 +141,7 @@ function SidebarContent({ isCollapsed, toggleSidebar }) {
icon: ,
url: "/examination",
},
- {
+ {
label: "Database",
id: "database",
icon: ,
@@ -170,6 +171,12 @@ function SidebarContent({ isCollapsed, toggleSidebar }) {
icon: ,
url: "/",
},
+ {
+ label: "Patent Management",
+ id: "patentsystem",
+ icon: ,
+ url: "/patentsystem",
+ },
];
const otherItems = [
@@ -193,11 +200,26 @@ function SidebarContent({ isCollapsed, toggleSidebar }) {
const navigate = useNavigate();
useEffect(() => {
+ const patentRoles = [
+ "student",
+ "alumini",
+ "Professor",
+ "Associate Professor",
+ "Assistant Professor",
+ "Research Engineer",
+ "Director",
+ "PCC Admin",
+ "Attorney",
+ ];
+
const filterModules = Modules.filter(
- (module) => accessibleModules[module.id] || module.id === "home",
+ (module) =>
+ accessibleModules[module.id] ||
+ module.id === "home" ||
+ (module.id === "patentsystem" && patentRoles.includes(role)),
);
setFilteredModules(filterModules);
- }, [accessibleModules]);
+ }, [accessibleModules, role]);
const handleModuleClick = (item) => {
setSelected(item.label);
diff --git a/src/services/patentService.js b/src/services/patentService.js
new file mode 100644
index 000000000..69619f2a4
--- /dev/null
+++ b/src/services/patentService.js
@@ -0,0 +1,180 @@
+import axios from "axios";
+import { host } from "../routes/globalRoutes";
+
+const apiBase = `${host}/patentsystem`;
+
+const authHeaders = (extraHeaders = {}) => {
+ const token = localStorage.getItem("authToken");
+ return {
+ headers: {
+ Authorization: `Token ${token}`,
+ ...extraHeaders,
+ },
+ };
+};
+
+export const fetchApplicantApplications = async () => {
+ const response = await axios.get(
+ `${apiBase}/applicant/applications/`,
+ authHeaders(),
+ );
+ return response.data.applications || [];
+};
+
+export const fetchApplicantApplicationDetails = async (applicationId) => {
+ const response = await axios.get(
+ `${apiBase}/applicant/applications/details/${applicationId}/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const fetchPccNewApplications = async () => {
+ const response = await axios.get(
+ `${apiBase}/pccAdmin/applications/new/`,
+ authHeaders(),
+ );
+ return response.data.applications || {};
+};
+
+export const fetchPccOngoingApplications = async () => {
+ const response = await axios.get(
+ `${apiBase}/pccAdmin/applications/ongoing/`,
+ authHeaders(),
+ );
+ return response.data.applications || {};
+};
+
+export const fetchPccPastApplications = async () => {
+ const response = await axios.get(
+ `${apiBase}/pccAdmin/applications/past/`,
+ authHeaders(),
+ );
+ return response.data.applications || {};
+};
+
+export const fetchPccApplicationDetails = async (applicationId) => {
+ const response = await axios.get(
+ `${apiBase}/pccAdmin/applications/details/${applicationId}/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const fetchPccDirectors = async () => {
+ const response = await axios.get(
+ `${apiBase}/pccAdmin/directors/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const reviewPatentApplication = async (applicationId, comments) => {
+ const response = await axios.post(
+ `${apiBase}/pccAdmin/applications/new/review/${applicationId}/`,
+ { comments },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const forwardPatentApplication = async (
+ applicationId,
+ attorneyName,
+ attorneyEmail,
+ directorUserId,
+ comments,
+) => {
+ const response = await axios.post(
+ `${apiBase}/pccAdmin/applications/new/forward/${applicationId}/`,
+ {
+ attorney_name: attorneyName,
+ attorney_email: attorneyEmail,
+ director_user_id: directorUserId,
+ comments,
+ },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const requestPatentModification = async (applicationId, comments) => {
+ const response = await axios.post(
+ `${apiBase}/pccAdmin/applications/new/requestModification/${applicationId}/`,
+ { comments },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const updatePatentApplicationStatus = async (
+ applicationId,
+ nextStatus,
+) => {
+ const response = await axios.post(
+ `${apiBase}/pccAdmin/applications/ongoing/changeStatus/${applicationId}/`,
+ { next_status: nextStatus },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchDirectorNewApplications = async () => {
+ const response = await axios.get(
+ `${apiBase}/director/applications/new/`,
+ authHeaders(),
+ );
+ return response.data.applications || {};
+};
+
+export const fetchDirectorReviewedApplications = async () => {
+ const response = await axios.get(
+ `${apiBase}/director/reviewedapplications`,
+ authHeaders(),
+ );
+ return response.data.applications || {};
+};
+
+export const fetchDirectorApplicationDetails = async (applicationId) => {
+ const response = await axios.post(
+ `${apiBase}/director/application/details`,
+ { application_id: applicationId },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const approveDirectorApplication = async (applicationId, comments) => {
+ const response = await axios.post(
+ `${apiBase}/director/application/accept`,
+ { application_id: applicationId, comments },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const rejectDirectorApplication = async (applicationId) => {
+ const response = await axios.post(
+ `${apiBase}/director/application/reject`,
+ { application_id: applicationId },
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};
+
+export const fetchCommunicationLogs = async (applicationId) => {
+ const response = await axios.get(
+ `${apiBase}/pccAdmin/applications/${applicationId}/communication-logs/`,
+ authHeaders(),
+ );
+ return response.data;
+};
+
+export const createCommunicationLog = async (applicationId, payload) => {
+ const response = await axios.post(
+ `${apiBase}/pccAdmin/applications/${applicationId}/communication-logs/`,
+ payload,
+ authHeaders({ "Content-Type": "application/json" }),
+ );
+ return response.data;
+};