From 7147116d8e2837e2a2a5d66aed3729809d023958 Mon Sep 17 00:00:00 2001 From: Pramod Mahajan Date: Wed, 21 May 2025 22:37:00 +0530 Subject: [PATCH 1/9] added delete contact api --- src/repositories/DirectoryRepository.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/repositories/DirectoryRepository.jsx b/src/repositories/DirectoryRepository.jsx index 2bfbd528..5de1691b 100644 --- a/src/repositories/DirectoryRepository.jsx +++ b/src/repositories/DirectoryRepository.jsx @@ -3,7 +3,8 @@ import {api} from "../utils/axiosClient"; export const DirectoryRepository = { GetContacts: () => api.get( '/api/directory' ), CreateContact: ( data ) => api.post( '/api/directory', data ), - UpdateContact:(id,data)=>api.put(`/api/directory/${id}`,data), + UpdateContact: ( id, data ) => api.put( `/api/directory/${ id }`, data ), + DeleteContact:(id)=>api.delete(`/api/directory/${id}`), GetBucktes: () => api.get( `/api/directory/buckets` ), From 3b82653f237154735edf7689bc686d8d1212a0ef Mon Sep 17 00:00:00 2001 From: Pramod Mahajan Date: Wed, 21 May 2025 22:39:07 +0530 Subject: [PATCH 2/9] implement contact deletion with confirmation and toast feedback --- .../Directory/CardViewDirectory.jsx | 4 +- .../Directory/ListViewDirectory.jsx | 26 ++++----- src/pages/Directory/Directory.jsx | 57 ++++++++++++++++++- 3 files changed, 70 insertions(+), 17 deletions(-) diff --git a/src/components/Directory/CardViewDirectory.jsx b/src/components/Directory/CardViewDirectory.jsx index 9f7128a0..2f29cc72 100644 --- a/src/components/Directory/CardViewDirectory.jsx +++ b/src/components/Directory/CardViewDirectory.jsx @@ -1,7 +1,7 @@ import React from "react"; import Avatar from "../common/Avatar"; -const CardViewDirectory = ({ contact, setSelectedContact, setIsOpenModal,setOpen_contact,setIsOpenModalNote }) => { +const CardViewDirectory = ({ contact, setSelectedContact, setIsOpenModal,setOpen_contact,setIsOpenModalNote,IsDeleted }) => { return (
@@ -48,7 +48,7 @@ const CardViewDirectory = ({ contact, setSelectedContact, setIsOpenModal,setOpen
  • - + IsDeleted(contact.id)}> Delete diff --git a/src/components/Directory/ListViewDirectory.jsx b/src/components/Directory/ListViewDirectory.jsx index 538bdd3a..7fb0031a 100644 --- a/src/components/Directory/ListViewDirectory.jsx +++ b/src/components/Directory/ListViewDirectory.jsx @@ -3,9 +3,9 @@ import Avatar from '../common/Avatar'; const getEmailIcon = (type) => { switch (type) { - case 'work': return "bx bx-briefcase me-1 " ; - case 'personal': return "bx bx-user me-1"; - case 'support': return "bxr headphone-mic me-1"; + case 'Work': return "bx bx-briefcase me-1 " ; + case 'Personal': return "bx bx-user me-1"; + case 'support': return "bx headphone-mic me-1"; case 'billing': return "bx bx-receipt me-1"; default: return "bx bx-envelope me-1"; } @@ -13,21 +13,21 @@ const getEmailIcon = (type) => { const getPhoneIcon = (type) => { switch (type) { - case 'business': return "bx bx-briefcase me-1 "; - case 'home': return "bx bx-mobile me-1 "; - case 'personal': return "bx bx-user me-1 "; - case 'landline': return "bx bx-phone me-1 "; - case 'fax': return "bx bx-printer me-1"; - case 'whatsapp': return "bxl-whatsapp me-1"; - case 'emergency': return "bx bx-error-circle me-1"; + case 'Business': return "bx bx-phone me-1 "; + case 'Personal': return "bx bx-mobile me-1 "; + case 'Office': return "bx bx-phone me-1 "; default: return "bx bx-phone me-1"; } }; -const ListViewDirectory = ({ contact,setSelectedContact,setIsOpenModal}) => { +const ListViewDirectory = ({ contact,setSelectedContact,setIsOpenModal,setOpen_contact,setIsOpenModalNote,IsDeleted}) => { return ( - + + { + setIsOpenModalNote(true) + setOpen_contact(contact) + }}>
    { setSelectedContact( contact ) setIsOpenModal(true) }}> - + IsDeleted(contact.id)}> ); diff --git a/src/pages/Directory/Directory.jsx b/src/pages/Directory/Directory.jsx index 8ec2c23e..77f837f7 100644 --- a/src/pages/Directory/Directory.jsx +++ b/src/pages/Directory/Directory.jsx @@ -6,7 +6,7 @@ import ManageDirectory from "../../components/Directory/ManageDirectory"; import ListViewDirectory from "../../components/Directory/ListViewDirectory"; import { useBuckets, useDirectory } from "../../hooks/useDirectory"; import { DirectoryRepository } from "../../repositories/DirectoryRepository"; -import { getCachedData } from "../../slices/apiDataManager"; +import { cacheData, getCachedData } from "../../slices/apiDataManager"; import showToast from "../../services/toastService"; import UpdateContact from "../../components/Directory/UpdateContact"; import CardViewDirectory from "../../components/Directory/CardViewDirectory"; @@ -14,6 +14,7 @@ import { useContactCategory } from "../../hooks/masterHook/useMaster"; import usePagination from "../../hooks/usePagination"; import { ITEMS_PER_PAGE } from "../../utils/constants"; import ProfileContactDirectory from "../../components/Directory/ProfileContactDirectory"; +import ConfirmModal from "../../components/common/ConfirmModal"; const Directory = () => { const [isOpenModal, setIsOpenModal] = useState(false); @@ -24,7 +25,9 @@ const Directory = () => { const [contactCategories, setContactCategories] = useState([]); const [searchText, setSearchText] = useState(""); const [listView, setListView] = useState(false); - const [selectedBucketIds, setSelectedBucketIds] = useState([]); + const [ selectedBucketIds, setSelectedBucketIds ] = useState( [] ); + const [deleteContact,setDeleteContact] = useState(null) + const[IsDeleting,setIsDeletng] = useState(false) const { contacts, loading } = useDirectory(); const { contactCategory, loading: contactCategoryLoading } = @@ -61,6 +64,29 @@ const Directory = () => { } }; + const handleDeleteContact = async() => + { + try + { setIsDeletng(true) + const contacts_cache = getCachedData( "contacts" ) || []; + + const response = await DirectoryRepository.DeleteContact( deleteContact ); + const updatedContacts = ContactList.filter((c) => c.id !== deleteContact); + setContactList( updatedContacts ); + cacheData("Contacts",updatedContacts) + showToast("Contact deleted successfully", "success"); + setDeleteContact( null ) + + setIsDeletng(false) + } catch ( error ) + { + const msg = error.response.data.message || error.message || "Error occured during API calling" + showToast( msg, "error" ) + setIsDeletng(false) + } + + } + const closedModel = () => { setIsOpenModal(false); setSelectedContact(null); @@ -179,6 +205,29 @@ const Directory = () => { )} )} + {deleteContact && ( + +
    + setDeleteContact(null)} + loading={IsDeleting} + /> +
    + )} +
    @@ -369,6 +418,9 @@ const Directory = () => { contact={contact} setSelectedContact={setSelectedContact} setIsOpenModal={setIsOpenModal} + setOpen_contact={setOpen_contact} + setIsOpenModalNote={setIsOpenModalNote} + IsDeleted={setDeleteContact} /> ))} @@ -387,6 +439,7 @@ const Directory = () => { setIsOpenModal={setIsOpenModal} setOpen_contact={setOpen_contact} setIsOpenModalNote={setIsOpenModalNote} + IsDeleted={setDeleteContact} />
    ))} From a69dd5042524830b80dfbfe9c3d8972d875dc420 Mon Sep 17 00:00:00 2001 From: Pramod Mahajan Date: Thu, 22 May 2025 15:08:27 +0530 Subject: [PATCH 3/9] changed filter name --- src/pages/Directory/Directory.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Directory/Directory.jsx b/src/pages/Directory/Directory.jsx index 77f837f7..df3a1ac5 100644 --- a/src/pages/Directory/Directory.jsx +++ b/src/pages/Directory/Directory.jsx @@ -274,7 +274,7 @@ const Directory = () => { data-bs-toggle="dropdown" aria-expanded="false" > - +
      Date: Thu, 22 May 2025 17:10:43 +0530 Subject: [PATCH 4/9] modified filter functionality- added apply call function button --- src/pages/Directory/Directory.jsx | 282 ++++++++++++++++++------------ 1 file changed, 169 insertions(+), 113 deletions(-) diff --git a/src/pages/Directory/Directory.jsx b/src/pages/Directory/Directory.jsx index df3a1ac5..dfbcbb81 100644 --- a/src/pages/Directory/Directory.jsx +++ b/src/pages/Directory/Directory.jsx @@ -25,9 +25,12 @@ const Directory = () => { const [contactCategories, setContactCategories] = useState([]); const [searchText, setSearchText] = useState(""); const [listView, setListView] = useState(false); - const [ selectedBucketIds, setSelectedBucketIds ] = useState( [] ); - const [deleteContact,setDeleteContact] = useState(null) - const[IsDeleting,setIsDeletng] = useState(false) + const [selectedBucketIds, setSelectedBucketIds] = useState([]); + const [deleteContact, setDeleteContact] = useState(null); + const [IsDeleting, setIsDeletng] = useState(false); + + const [tempSelectedBucketIds, setTempSelectedBucketIds] = useState([]); + const [tempSelectedCategoryIds, setTempSelectedCategoryIds] = useState([]); const { contacts, loading } = useDirectory(); const { contactCategory, loading: contactCategoryLoading } = @@ -64,59 +67,64 @@ const Directory = () => { } }; - const handleDeleteContact = async() => - { - try - { setIsDeletng(true) - const contacts_cache = getCachedData( "contacts" ) || []; + const handleDeleteContact = async () => { + try { + setIsDeletng(true); + const contacts_cache = getCachedData("contacts") || []; - const response = await DirectoryRepository.DeleteContact( deleteContact ); - const updatedContacts = ContactList.filter((c) => c.id !== deleteContact); - setContactList( updatedContacts ); - cacheData("Contacts",updatedContacts) + const response = await DirectoryRepository.DeleteContact(deleteContact); + const updatedContacts = ContactList.filter((c) => c.id !== deleteContact); + setContactList(updatedContacts); + cacheData("Contacts", updatedContacts); showToast("Contact deleted successfully", "success"); - setDeleteContact( null ) - - setIsDeletng(false) - } catch ( error ) - { - const msg = error.response.data.message || error.message || "Error occured during API calling" - showToast( msg, "error" ) - setIsDeletng(false) - } - - } + setDeleteContact(null); + + setIsDeletng(false); + } catch (error) { + const msg = + error.response.data.message || + error.message || + "Error occured during API calling"; + showToast(msg, "error"); + setIsDeletng(false); + } + }; const closedModel = () => { setIsOpenModal(false); setSelectedContact(null); setOpen_contact(null); }; - useEffect(() => { - setContactList(contacts); - }, [contacts]); - const [selectedCategoryIds, setSelectedCategoryIds] = useState( contactCategory.map((category) => category.id) ); + useEffect(() => { + setContactList(contacts); + + // Set temp filter list only (UI checkboxes, not actual filtering yet) + setTempSelectedCategoryIds([]); + setTempSelectedBucketIds([]); + }, [contacts]); + const usedCategoryIds = [ ...new Set(contacts.map((c) => c.contactCategory?.id)), ]; const filteredCategories = contactCategory.filter((category) => usedCategoryIds.includes(category.id) ); - const handleCategoryChange = (id) => { - setSelectedCategoryIds((prev) => + const handleTempBucketChange = (id) => { + setTempSelectedBucketIds((prev) => + prev.includes(id) ? prev.filter((bid) => bid !== id) : [...prev, id] + ); + }; + + const handleTempCategoryChange = (id) => { + setTempSelectedCategoryIds((prev) => prev.includes(id) ? prev.filter((cid) => cid !== id) : [...prev, id] ); }; - const handleBucketChange = (id) => { - setSelectedBucketIds((prev) => - prev.includes(id) ? prev.filter((bid) => bid !== id) : [...prev, id] - ); - }; const usedBucketIds = [ ...new Set(contacts.flatMap((c) => c.bucketIds || [])), ]; @@ -143,6 +151,18 @@ const Directory = () => { }).sort((a, b) => a.name.localeCompare(b.name)); }, [ContactList, searchText, selectedCategoryIds, selectedBucketIds]); + const applyFilter = () => { + setSelectedBucketIds(tempSelectedBucketIds); + setSelectedCategoryIds(tempSelectedCategoryIds); + }; + + const clearFilter = () => { + setTempSelectedBucketIds([]); + setTempSelectedCategoryIds([]); + setSelectedBucketIds([]); + setSelectedCategoryIds([]); + }; + const { currentPage, totalPages, currentItems, paginate } = usePagination( filteredContacts, ITEMS_PER_PAGE @@ -171,7 +191,7 @@ const Directory = () => { @@ -206,7 +226,6 @@ const Directory = () => { )} {deleteContact && ( -
      { }} aria-hidden="false" > - setDeleteContact(null)} loading={IsDeleting} /> -
      - )} +
    + )}
    @@ -268,69 +287,108 @@ const Directory = () => {
    -
    - -
      -

      Filter by

      -
      - {/* Bucket Filter */} -
      -

      Buckets

      - {filteredBuckets.map(({ id, name }) => ( -
      - handleBucketChange(id)} - /> - -
      - ))} -
      +
      +
      + - {/* Category Filter */} -
      -

      Categories

      - {filteredCategories.map(({ id, name }) => ( -
      - handleCategoryChange(id)} - /> - +
        +
        +

        Filter by

        + + {/* Bucket Filter */} +
        +

        Buckets

        +
        + {filteredBuckets.map(({ id, name }) => ( +
        + handleTempBucketChange(id)} + /> + +
        + ))}
        - ))} +
        +
        + {/* Category Filter */} +
        +

        Categories

        +
        + {filteredCategories.map(({ id, name }) => ( +
        + handleTempCategoryChange(id)} + /> + +
        + ))} +
        +
        + +
        + + +
        -
      -
    + +
    -
    +
    {!listView && loading &&

    Loading...

    } - {!listView && !loading && currentItems.length == 0 &&

    Not Found Contact

    } + {!listView && !loading && currentItems.length == 0 && ( +

    No Matching Contact Found

    + )} {listView ? (
    @@ -392,10 +452,7 @@ const Directory = () => { - + @@ -404,13 +461,12 @@ const Directory = () => { )} - {!loading && - currentItems.length === 0 && ( - - - - )} - + {!loading && currentItems.length === 0 && ( + + + + )} + {!loading && currentItems.map((contact) => ( { contact={contact} setSelectedContact={setSelectedContact} setIsOpenModal={setIsOpenModal} - setOpen_contact={setOpen_contact} - setIsOpenModalNote={setIsOpenModalNote} - IsDeleted={setDeleteContact} + setOpen_contact={setOpen_contact} + setIsOpenModalNote={setIsOpenModalNote} + IsDeleted={setDeleteContact} /> ))} @@ -446,7 +502,7 @@ const Directory = () => { )} - {!loading && ( + {!loading && currentItems < ITEMS_PER_PAGE && (
    Category - Action - Action
    Loading...
    Not Found Contact
    No Matching Contact Found