diff --git a/src/components/Dashboard/ProjectProgressChart.jsx b/src/components/Dashboard/ProjectProgressChart.jsx
index afc5e11d..6159dbc9 100644
--- a/src/components/Dashboard/ProjectProgressChart.jsx
+++ b/src/components/Dashboard/ProjectProgressChart.jsx
@@ -69,6 +69,7 @@ const ProjectProgressChart = () => {
);
const lineChartCategoriesDates = sortedDashboardData.map((d) =>
new Date(d.date).toLocaleDateString("en-US", {
+ weekday:"short",
month: "short",
day: "numeric",
year: "numeric",
diff --git a/src/components/Directory/ListViewDirectory.jsx b/src/components/Directory/ListViewDirectory.jsx
index 4eb522f8..801d9915 100644
--- a/src/components/Directory/ListViewDirectory.jsx
+++ b/src/components/Directory/ListViewDirectory.jsx
@@ -88,10 +88,16 @@ const ListViewDirectory = ({
{contact.organization}
-
+ {/* |
{contact?.contactCategory?.name || "Other"}
+ | */}
+
+
+
+ {contact?.contactCategory?.name || "Other"}
+
|
diff --git a/src/components/Directory/NoteCardDirectoryEditable.jsx b/src/components/Directory/NoteCardDirectoryEditable.jsx
new file mode 100644
index 00000000..7759e62a
--- /dev/null
+++ b/src/components/Directory/NoteCardDirectoryEditable.jsx
@@ -0,0 +1,256 @@
+import React, { useState } from "react";
+import ReactQuill from "react-quill";
+import moment from "moment";
+import Avatar from "../common/Avatar";
+import { DirectoryRepository } from "../../repositories/DirectoryRepository";
+import showToast from "../../services/toastService";
+import { cacheData, getCachedData } from "../../slices/apiDataManager";
+import ConfirmModal from "../common/ConfirmModal"; // Make sure path is correct
+import "../common/TextEditor/Editor.css";
+import ProfileContactDirectory from "./ProfileContactDirectory";
+import GlobalModel from "../common/GlobalModel";
+
+const NoteCardDirectoryEditable = ({
+ noteItem,
+ contactId,
+ onNoteUpdate,
+ onNoteDelete,
+}) => {
+ const [editing, setEditing] = useState(false);
+ const [editorValue, setEditorValue] = useState(noteItem.note);
+ const [isLoading, setIsLoading] = useState(false);
+ const [isDeleting, setIsDeleting] = useState(false);
+ const [isRestoring, setIsRestoring] = useState(false);
+ const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
+ const [open_contact, setOpen_contact] = useState(null);
+ const [isOpenModalNote, setIsOpenModalNote] = useState(false);
+
+ const handleUpdateNote = async () => {
+ try {
+ setIsLoading(true);
+ const payload = {
+ id: noteItem.id,
+ note: editorValue,
+ contactId,
+ };
+ const response = await DirectoryRepository.UpdateNote(noteItem.id, payload);
+
+ const cachedContactProfile = getCachedData("Contact Profile");
+ if (cachedContactProfile?.contactId === contactId) {
+ const updatedCache = {
+ ...cachedContactProfile,
+ data: {
+ ...cachedContactProfile.data,
+ notes: cachedContactProfile.data.notes.map((note) =>
+ note.id === noteItem.id ? response.data : note
+ ),
+ },
+ };
+ cacheData("Contact Profile", updatedCache);
+ }
+
+ onNoteUpdate?.(response.data);
+ setEditing(false);
+ showToast("Note updated successfully", "success");
+ } catch (error) {
+ showToast("Failed to update note", "error");
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const suspendEmployee = async () => {
+ try {
+ setIsDeleting(true);
+ await DirectoryRepository.DeleteNote(noteItem.id, false);
+ onNoteDelete?.(noteItem.id);
+ setIsDeleteModalOpen(false);
+ showToast("Note deleted successfully", "success");
+ } catch (error) {
+ showToast("Failed to delete note", "error");
+ } finally {
+ setIsDeleting(false);
+ }
+ };
+
+ const contactProfile = (contactId) => {
+ DirectoryRepository.GetContactProfile(contactId).then((res) => {
+ setOpen_contact(res?.data);
+ setIsOpenModalNote(true);
+ });
+ };
+
+ const handleRestore = async () => {
+ try {
+ setIsRestoring(true);
+ await DirectoryRepository.DeleteNote(noteItem.id, true);
+ onNoteDelete?.(noteItem.id);
+ showToast("Note restored successfully", "success");
+ } catch (error) {
+ showToast("Failed to restore note", "error");
+ } finally {
+ setIsRestoring(false);
+ }
+ };
+
+ return (
+ <>
+
+ {isOpenModalNote && (
+ {
+ setOpen_contact(null);
+ setIsOpenModalNote(false);
+ }}
+ size="xl"
+ >
+ {open_contact && (
+ setIsOpenModalNote(false)}
+ />
+ )}
+
+ )}
+
+ {/* Header */}
+
+
+
+
+
+ contactProfile(noteItem.contactId)}>
+
+ {noteItem?.contactName}
+ ({noteItem?.organizationName})
+
+
+
+
+
+
+
+
+
+
+ by {noteItem?.createdBy?.firstName} {noteItem?.createdBy?.lastName}
+
+ on {moment
+ .utc(noteItem?.createdAt)
+ .add(5, "hours")
+ .add(30, "minutes")
+ .format("MMMM DD, YYYY [at] hh:mm A")}
+
+
+
+
+
+
+
+ {/* Action Icons */}
+
+ {noteItem.isActive ? (
+ <>
+ setEditing(true)}
+ title="Edit"
+ >
+ {!isDeleting ? (
+ setIsDeleteModalOpen(true)}
+ title="Delete"
+ >
+ ) : (
+
+ )}
+ >
+ ) : isRestoring ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ {/* Editor or Content */}
+ {editing ? (
+ <>
+
+
+ setEditing(false)}
+ >
+ Cancel
+
+
+ {isLoading ? "Saving..." : "Submit"}
+
+
+ >
+ ) : (
+
+ )}
+
+
+ {/* Delete Confirm Modal */}
+ {isDeleteModalOpen && (
+
+ setIsDeleteModalOpen(false)}
+ loading={isDeleting}
+ paramData={noteItem}
+ />
+
+ )}
+ >
+ );
+};
+
+export default NoteCardDirectoryEditable;
diff --git a/src/components/Directory/NotesCardViewDirectory.jsx b/src/components/Directory/NotesCardViewDirectory.jsx
new file mode 100644
index 00000000..0dbbe5bd
--- /dev/null
+++ b/src/components/Directory/NotesCardViewDirectory.jsx
@@ -0,0 +1,176 @@
+import React, { useEffect, useState, useMemo } from "react";
+import { DirectoryRepository } from "../../repositories/DirectoryRepository";
+import NoteCardDirectoryEditable from "./NoteCardDirectoryEditable";
+
+const NotesCardViewDirectory = ({ notes, setNotesForFilter, searchText, filterAppliedNotes }) => {
+ const [allNotes, setAllNotes] = useState([]);
+ const [filteredNotes, setFilteredNotes] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [currentPage, setCurrentPage] = useState(1);
+ const [totalPages, setTotalPages] = useState(1);
+ const [selectedCreators, setSelectedCreators] = useState([]);
+ const [selectedOrgs, setSelectedOrgs] = useState([]);
+ const pageSize = 20;
+
+ useEffect(() => {
+ fetchNotes();
+ }, []);
+
+ const fetchNotes = async () => {
+ setLoading(true);
+ try {
+ const response = await DirectoryRepository.GetNotes(1000, 1);
+ const fetchedNotes = response.data?.data || [];
+ setAllNotes(fetchedNotes);
+ setNotesForFilter(fetchedNotes)
+
+ const creatorsSet = new Set();
+ const orgsSet = new Set();
+
+ fetchedNotes.forEach((note) => {
+ const creator = `${note.createdBy?.firstName || ""} ${note.createdBy?.lastName || ""}`.trim();
+ if (creator) creatorsSet.add(creator);
+
+ const org = note.organizationName;
+ if (org) orgsSet.add(org);
+ });
+
+ } catch (error) {
+ console.error("Failed to fetch notes:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+
+
+ const applyCombinedFilter = () => {
+ const lowerSearch = searchText?.toLowerCase() || "";
+
+ const filtered = allNotes.filter((noteItem) => {
+ const creator = `${noteItem.createdBy?.firstName || ""} ${noteItem.createdBy?.lastName || ""}`.trim();
+ const org = noteItem.organizationName;
+
+ const matchesCreator = selectedCreators.length === 0 || selectedCreators.includes(creator);
+ const matchesOrg = selectedOrgs.length === 0 || selectedOrgs.includes(org);
+
+ const plainNote = noteItem?.note?.replace(/<[^>]+>/g, "").toLowerCase();
+
+ const stringValues = [];
+ const extractStrings = (obj) => {
+ for (const key in obj) {
+ const value = obj[key];
+ if (typeof value === "string") {
+ stringValues.push(value.toLowerCase());
+ } else if (typeof value === "object" && value !== null) {
+ extractStrings(value);
+ }
+ }
+ };
+ extractStrings(noteItem);
+ stringValues.push(plainNote, creator.toLowerCase());
+
+ const matchesSearch = stringValues.some((val) => val.includes(lowerSearch));
+
+ return matchesCreator && matchesOrg && matchesSearch;
+ });
+
+ setFilteredNotes(filtered);
+ setCurrentPage(1);
+ setTotalPages(Math.ceil(filtered.length / pageSize));
+ };
+
+ useEffect(() => {
+ applyCombinedFilter();
+ }, [searchText, allNotes]);
+
+ useEffect(() => {
+ setFilteredNotes(filterAppliedNotes);
+ }, [filterAppliedNotes])
+
+ const currentItems = useMemo(() => {
+ const startIndex = (currentPage - 1) * pageSize;
+ return filteredNotes.slice(startIndex, startIndex + pageSize);
+ }, [filteredNotes, currentPage]);
+
+ const handlePageClick = (page) => {
+ if (page !== currentPage) {
+ setCurrentPage(page);
+ }
+ };
+
+ if (loading) return Loading notes... ;
+
+ if (!filteredNotes.length) return No matching notes found ;
+
+
+ return (
+
+ {/* Filter Dropdown */}
+
+
+
+ {/* Notes List */}
+
+ {currentItems.map((noteItem) => (
+ {
+ setAllNotes((prevNotes) =>
+ prevNotes.map((n) => (n.id === updatedNote.id ? updatedNote : n))
+ );
+ }}
+ onNoteDelete={() => fetchNotes()}
+ />
+ ))}
+
+
+ {/* Pagination */}
+ {totalPages > 1 && (
+
+ {/* Previous Button */}
+
+
+ {/* Page Number Buttons */}
+ {[...Array(totalPages)].map((_, i) => {
+ const page = i + 1;
+ return (
+
+ );
+ })}
+
+ {/* Next Button */}
+
+
+ )}
+
+ );
+};
+
+export default NotesCardViewDirectory;
diff --git a/src/components/Directory/NotesDirectory.jsx b/src/components/Directory/NotesDirectory.jsx
index 5ddb37c8..61908853 100644
--- a/src/components/Directory/NotesDirectory.jsx
+++ b/src/components/Directory/NotesDirectory.jsx
@@ -135,7 +135,7 @@ const NotesDirectory = ({
setAddNote(!addNote)}
>
{addNote ? "Hide Editor" : "Add a Note"}
diff --git a/src/components/Employee/DemoTable.jsx b/src/components/Employee/DemoTable.jsx
index 108314cf..1d645cc3 100644
--- a/src/components/Employee/DemoTable.jsx
+++ b/src/components/Employee/DemoTable.jsx
@@ -3,7 +3,7 @@ import React from "react";
const DemoTable = () => {
return (
-
+
diff --git a/src/components/Employee/ManageEmployee.jsx b/src/components/Employee/ManageEmployee.jsx
index 7cb4b0f1..e3c34b30 100644
--- a/src/components/Employee/ManageEmployee.jsx
+++ b/src/components/Employee/ManageEmployee.jsx
@@ -172,8 +172,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
.then((response) => {
cacheData("employeeProfileInfo", data);
showToast(
- `Employee details ${
- data.id == null ? "created" : "updated"
+ `Employee details ${data.id == null ? "created" : "updated"
} successfully.`,
"success"
);
@@ -207,24 +206,24 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
reset(
currentEmployee
? {
- id: currentEmployee.id || null,
- firstName: currentEmployee.firstName || "",
- middleName: currentEmployee.middleName || "",
- lastName: currentEmployee.lastName || "",
- email: currentEmployee.email || "",
- currentAddress: currentEmployee.currentAddress || "",
- birthDate: formatDate(currentEmployee.birthDate) || "",
- joiningDate: formatDate(currentEmployee.joiningDate) || "",
- emergencyPhoneNumber: currentEmployee.emergencyPhoneNumber || "",
- emergencyContactPerson:
- currentEmployee.emergencyContactPerson || "",
- aadharNumber: currentEmployee.aadharNumber || "",
- gender: currentEmployee.gender || "",
- panNumber: currentEmployee.panNumber || "",
- permanentAddress: currentEmployee.permanentAddress || "",
- phoneNumber: currentEmployee.phoneNumber || "",
- jobRoleId: currentEmployee.jobRoleId?.toString() || "",
- }
+ id: currentEmployee.id || null,
+ firstName: currentEmployee.firstName || "",
+ middleName: currentEmployee.middleName || "",
+ lastName: currentEmployee.lastName || "",
+ email: currentEmployee.email || "",
+ currentAddress: currentEmployee.currentAddress || "",
+ birthDate: formatDate(currentEmployee.birthDate) || "",
+ joiningDate: formatDate(currentEmployee.joiningDate) || "",
+ emergencyPhoneNumber: currentEmployee.emergencyPhoneNumber || "",
+ emergencyContactPerson:
+ currentEmployee.emergencyContactPerson || "",
+ aadharNumber: currentEmployee.aadharNumber || "",
+ gender: currentEmployee.gender || "",
+ panNumber: currentEmployee.panNumber || "",
+ permanentAddress: currentEmployee.permanentAddress || "",
+ phoneNumber: currentEmployee.phoneNumber || "",
+ jobRoleId: currentEmployee.jobRoleId?.toString() || "",
+ }
: {} // Empty object resets the form
);
setCurrentAddressLength(currentEmployee?.currentAddress?.length || 0);
@@ -233,410 +232,417 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
return (
<>
-
- {/*
+
+ {/*
{!currentEmployee && empLoading && employeeId && (
Loading Employee Data...
)} */}
-
-
>
);
};
diff --git a/src/components/Layout/Header.jsx b/src/components/Layout/Header.jsx
index a66be189..53fbec05 100644
--- a/src/components/Layout/Header.jsx
+++ b/src/components/Layout/Header.jsx
@@ -103,7 +103,8 @@ const Header = () => {
}, [projectNames]);
/** Check if current page id project details page */
- const isProjectPath = /^\/projects\/[a-f0-9-]{36}$/.test(location.pathname);
+ const isProjectPath = /^\/projects\/[a-f0-9-]{36}$/.test(location.pathname)
+ const isDirectoryPath = /^\/directory$/.test(location.pathname);
const handler = useCallback(
async (data) => {
@@ -145,7 +146,7 @@ const Header = () => {
}, [handler]);
return (
|