From 9396caea575fb551073b145b8b78488cdbed148d Mon Sep 17 00:00:00 2001 From: Kartik sharma Date: Fri, 27 Jun 2025 15:47:36 +0530 Subject: [PATCH] In Directory changing filter logic and adding popup. --- .../Directory/NoteCardDirectoryEditable.jsx | 68 +++++- .../Directory/NotesCardViewDirectory.jsx | 90 ++++---- src/pages/Directory/Directory.jsx | 9 +- src/pages/Directory/DirectoryPageHeader.jsx | 204 ++++++++++++++---- 4 files changed, 279 insertions(+), 92 deletions(-) diff --git a/src/components/Directory/NoteCardDirectoryEditable.jsx b/src/components/Directory/NoteCardDirectoryEditable.jsx index 6a6f9be7..35f0b946 100644 --- a/src/components/Directory/NoteCardDirectoryEditable.jsx +++ b/src/components/Directory/NoteCardDirectoryEditable.jsx @@ -7,6 +7,8 @@ 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, @@ -20,6 +22,8 @@ const NoteCardDirectoryEditable = ({ 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 { @@ -69,6 +73,13 @@ const NoteCardDirectoryEditable = ({ } }; + const contactProfile = (contactId) => { + DirectoryRepository.GetContactProfile(contactId).then((res) => { + setOpen_contact(res?.data); + setIsOpenModalNote(true); + }); + }; + const handleRestore = async () => { try { setIsRestoring(true); @@ -84,6 +95,25 @@ const NoteCardDirectoryEditable = ({ return ( <> + + {isOpenModalNote && ( + { + setOpen_contact(null); + setIsOpenModalNote(false); + }} + size="xl" + > + {open_contact && ( + setIsOpenModalNote(false)} + /> + )} + + )}
+ -
- - {noteItem?.createdBy?.firstName} {noteItem?.createdBy?.lastName} - - - {moment - .utc(noteItem?.createdAt) - .add(5, "hours") - .add(30, "minutes") - .format("MMMM DD, YYYY [at] hh:mm A")} - +
+
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")} + + + +
diff --git a/src/components/Directory/NotesCardViewDirectory.jsx b/src/components/Directory/NotesCardViewDirectory.jsx index 57130112..be207ffd 100644 --- a/src/components/Directory/NotesCardViewDirectory.jsx +++ b/src/components/Directory/NotesCardViewDirectory.jsx @@ -2,20 +2,39 @@ import React, { useEffect, useState, useMemo } from "react"; import { DirectoryRepository } from "../../repositories/DirectoryRepository"; import NoteCardDirectoryEditable from "./NoteCardDirectoryEditable"; -const NotesCardViewDirectory = ({ notes, setNotes, searchText, selectedNoteNames }) => { // ✅ Changed to array +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 { @@ -23,52 +42,51 @@ const NotesCardViewDirectory = ({ notes, setNotes, searchText, selectedNoteNames } }; - useEffect(() => { - fetchNotes(); - }, []); - useEffect(() => { + + 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 fullName = `${noteItem?.createdBy?.firstName || ""} ${noteItem?.createdBy?.lastName || ""}`.trim(); - const lowerFullName = fullName.toLowerCase(); - const createdDate = new Date(noteItem?.createdAt).toLocaleDateString("en-IN").toLowerCase(); - // ✅ Collect all string values in the note object to search through const stringValues = []; - const extractStrings = (obj) => { for (const key in obj) { - if (!obj.hasOwnProperty(key)) continue; const value = obj[key]; if (typeof value === "string") { stringValues.push(value.toLowerCase()); } else if (typeof value === "object" && value !== null) { - extractStrings(value); // Recursively extract from nested objects + extractStrings(value); } } }; - extractStrings(noteItem); - // Add manually stripped note, full name, date, etc. - stringValues.push(plainNote, lowerFullName, createdDate); + stringValues.push(plainNote, creator.toLowerCase()); const matchesSearch = stringValues.some((val) => val.includes(lowerSearch)); - const matchesNameFilter = - selectedNoteNames.length === 0 || selectedNoteNames.includes(fullName); - - return matchesSearch && matchesNameFilter; + return matchesCreator && matchesOrg && matchesSearch; }); setFilteredNotes(filtered); - setNotes(filtered); setCurrentPage(1); setTotalPages(Math.ceil(filtered.length / pageSize)); - }, [searchText, allNotes, selectedNoteNames]); + }; + useEffect(() => { + applyCombinedFilter(); + }, [searchText, allNotes]); + + useEffect(() => { + setFilteredNotes(filterAppliedNotes); + }, [filterAppliedNotes]) const currentItems = useMemo(() => { const startIndex = (currentPage - 1) * pageSize; @@ -81,19 +99,19 @@ const NotesCardViewDirectory = ({ notes, setNotes, searchText, selectedNoteNames } }; - if (loading) { - return

Loading notes...

; - } + if (loading) return

Loading notes...

; + + if (!filteredNotes.length) return

No matching notes found

; - if (!filteredNotes.length) { - return

No matching notes found

; - } return ( -
-
+
+ {/* Filter Dropdown */} +
+
+ + {/* Notes List */} +
{currentItems.map((noteItem) => ( (n.id === updatedNote.id ? updatedNote : n)) ); }} - onNoteDelete={() => { - fetchNotes(); - }} + onNoteDelete={() => fetchNotes()} /> ))}
+ {/* Pagination */} {totalPages > 1 && (
@@ -128,7 +145,8 @@ const NotesCardViewDirectory = ({ notes, setNotes, searchText, selectedNoteNames return (
@@ -421,9 +425,10 @@ const Directory = ({ IsPage = true, prefernceContacts }) => {
)} diff --git a/src/pages/Directory/DirectoryPageHeader.jsx b/src/pages/Directory/DirectoryPageHeader.jsx index 40c19f36..e0152532 100644 --- a/src/pages/Directory/DirectoryPageHeader.jsx +++ b/src/pages/Directory/DirectoryPageHeader.jsx @@ -19,12 +19,19 @@ const DirectoryPageHeader = ({ IsActive, contactsToExport, notesToExport, - selectedNoteNames, // ✅ Changed to array - setSelectedNoteNames, // ✅ Changed to array + selectedNoteNames, + setSelectedNoteNames, + notesForFilter, + setFilterAppliedNotes }) => { const [filtered, setFiltered] = useState(0); - + const [filteredNotes, setFilteredNotes] = useState([]); const [noteCreators, setNoteCreators] = useState([]); + const [allCreators, setAllCreators] = useState([]); + const [allOrganizations, setAllOrganizations] = useState([]); + const [filteredOrganizations, setFilteredOrganizations] = useState([]); + const [selectedCreators, setSelectedCreators] = useState([]); // Corrected to setSelectedCreators + const [selectedOrgs, setSelectedOrgs] = useState([]); useEffect(() => { setFiltered(tempSelectedBucketIds?.length + tempSelectedCategoryIds?.length); @@ -55,6 +62,23 @@ const DirectoryPageHeader = ({ } }, [viewType]); + useEffect(() => { + const creatorsSet = new Set(); + const orgsSet = new Set(); + + notesForFilter.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); + }); + + setAllCreators([...creatorsSet].sort()); + setAllOrganizations([...orgsSet].sort()); + setFilteredOrganizations([...orgsSet].sort()); + }, [notesForFilter]) + const handleToggleNoteName = (name) => { setSelectedNoteNames(prevSelectedNames => { @@ -66,6 +90,45 @@ const DirectoryPageHeader = ({ }); }; + const updateFilteredOrganizations = () => { + if (selectedCreators.length === 0) { + setFilteredOrganizations(allOrganizations); + return; + } + + const filteredOrgsSet = new Set(); + notesForFilter.forEach((note) => { + const creator = `${note.createdBy?.firstName || ""} ${note.createdBy?.lastName || ""}`.trim(); + if (selectedCreators.includes(creator)) { + if (note.organizationName) { + filteredOrgsSet.add(note.organizationName); + } + } + }); + + setFilteredOrganizations([...filteredOrgsSet].sort()); + }; + + const handleToggleCreator = (name) => { + const updated = selectedCreators.includes(name) + ? selectedCreators.filter((n) => n !== name) + : [...selectedCreators, name]; + + setSelectedCreators(updated); + }; + + const handleToggleOrg = (name) => { + const updated = selectedOrgs.includes(name) + ? selectedOrgs.filter((n) => n !== name) + : [...selectedOrgs, name]; + + setSelectedOrgs(updated); + }; + + useEffect(() => { + updateFilteredOrganizations(); + }, [selectedCreators]); + const handleExport = (type) => { let dataToExport = []; @@ -149,6 +212,41 @@ const DirectoryPageHeader = ({ } }; + const applyCombinedFilter = () => { + const lowerSearch = searchText?.toLowerCase() || ""; + + const filtered = notesForFilter.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); + setFilterAppliedNotes(filtered); + }; + return ( <>
@@ -189,52 +287,72 @@ const DirectoryPageHeader = ({ style={{ width: "200px" }} /> - {/* Name Filter Dropdown - now with checkboxes */} - {viewType === "notes" && noteCreators.length > 0 && ( -
- + + +
+
)}