Compare commits
19 Commits
main
...
pramod_Tas
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6fa0107792 | ||
![]() |
c00a0ecff1 | ||
![]() |
7e0acf00bd | ||
![]() |
bc9cbd61f3 | ||
![]() |
25bd5550c6 | ||
![]() |
069d12ecd6 | ||
![]() |
054c129ba5 | ||
![]() |
3ed2048e45 | ||
![]() |
114aac089b | ||
![]() |
f9d94d1b18 | ||
![]() |
0069b48ca8 | ||
![]() |
2b65f92f54 | ||
![]() |
5a59e79160 | ||
![]() |
b9f24e9954 | ||
![]() |
a2e34b91dc | ||
![]() |
e94e41a952 | ||
![]() |
766f5d31bf | ||
![]() |
ecebef71c1 | ||
![]() |
93977ba5b6 |
10
src/App.tsx
10
src/App.tsx
@ -1,3 +1,4 @@
|
||||
import { DireProvider } from "./Context/DireContext";
|
||||
import AppRoutes from "./router/AppRoutes";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
|
||||
@ -5,8 +6,13 @@ import { ToastContainer } from "react-toastify";
|
||||
const App = () => {
|
||||
return (
|
||||
<div className="app">
|
||||
<AppRoutes />
|
||||
<ToastContainer></ToastContainer>
|
||||
<DireProvider>
|
||||
<AppRoutes />
|
||||
</DireProvider>
|
||||
|
||||
<ToastContainer>
|
||||
|
||||
</ToastContainer>
|
||||
|
||||
</div>
|
||||
);
|
||||
|
21
src/Context/DireContext.jsx
Normal file
21
src/Context/DireContext.jsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React, { createContext, useContext, useState } from "react";
|
||||
|
||||
const DireContext = createContext(undefined);
|
||||
|
||||
export const DireProvider = ({ children }) => {
|
||||
const [dirActions, setDirActions] = useState([]);
|
||||
|
||||
return (
|
||||
<DireContext.Provider value={{ dirActions, setDirActions }}>
|
||||
{children}
|
||||
</DireContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useDir = () => {
|
||||
const context = useContext(DireContext);
|
||||
if (!context) {
|
||||
throw new Error("useDir must be used within a <DireProvider>");
|
||||
}
|
||||
return context;
|
||||
};
|
@ -3,6 +3,7 @@ import Avatar from "../common/Avatar";
|
||||
import { getBucketNameById } from "./DirectoryUtils";
|
||||
import { useBuckets } from "../../hooks/useDirectory";
|
||||
import { getPhoneIcon } from "./DirectoryUtils";
|
||||
import { useDir } from "../../Context/DireContext";
|
||||
const CardViewDirectory = ({
|
||||
IsActive,
|
||||
contact,
|
||||
@ -11,8 +12,10 @@ const CardViewDirectory = ({
|
||||
setOpen_contact,
|
||||
setIsOpenModalNote,
|
||||
IsDeleted,
|
||||
restore,
|
||||
}) => {
|
||||
const { buckets } = useBuckets();
|
||||
const { dirActions, setDirActions } = useDir();
|
||||
return (
|
||||
<div
|
||||
className="card text-start border-1"
|
||||
@ -30,54 +33,70 @@ const CardViewDirectory = ({
|
||||
(contact?.name || "").trim().split(" ")[1]?.charAt(0) || ""
|
||||
}
|
||||
/>{" "}
|
||||
<span className="text-heading fs-6"> {contact.name}</span>
|
||||
<span className="text-heading fs-6"> {contact.name}</span>
|
||||
</div>
|
||||
<div>
|
||||
<div className={`dropdown z-2 ${!IsActive && "d-none"}`}>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-xs btn-icon btn-text-secondary rounded-pill dropdown-toggle hide-arrow p-0 m-0"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i
|
||||
className="bx bx-dots-vertical-rounded bx-sm text-muted p-0"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-offset="0,8"
|
||||
data-bs-placement="top"
|
||||
data-bs-custom-class="tooltip-dark"
|
||||
title="More Action"
|
||||
></i>
|
||||
</button>
|
||||
<ul className="dropdown-menu dropdown-menu-end w-auto">
|
||||
<li
|
||||
onClick={() => {
|
||||
setSelectedContact(contact);
|
||||
setIsOpenModal(true);
|
||||
}}
|
||||
{IsActive && (
|
||||
<div className="dropdown z-2">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-xs btn-icon btn-text-secondary rounded-pill dropdown-toggle hide-arrow p-0 m-0"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<a className="dropdown-item px-2 cursor-pointer py-1">
|
||||
<i className="bx bx-edit bx-xs text-primary me-2"></i>
|
||||
<span className="align-left ">Modify</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="dropdown-item px-2 cursor-pointer py-1"
|
||||
onClick={() => IsDeleted(contact.id)}
|
||||
<i
|
||||
className="bx bx-dots-vertical-rounded bx-sm text-muted p-0"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-offset="0,8"
|
||||
data-bs-placement="top"
|
||||
data-bs-custom-class="tooltip-dark"
|
||||
title="More Action"
|
||||
></i>
|
||||
</button>
|
||||
<ul className="dropdown-menu dropdown-menu-end w-auto">
|
||||
<li
|
||||
onClick={() => {
|
||||
setSelectedContact(contact);
|
||||
setIsOpenModal(true);
|
||||
}}
|
||||
>
|
||||
<i className="bx bx-trash text-danger bx-xs me-2"></i>
|
||||
<span className="align-left">Delete</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<a className="dropdown-item px-2 cursor-pointer py-1">
|
||||
<i className="bx bx-edit bx-xs text-primary me-2"></i>
|
||||
<span className="align-left ">Modify</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="dropdown-item px-2 cursor-pointer py-1"
|
||||
onClick={() => IsDeleted(contact.id)}
|
||||
>
|
||||
<i className="bx bx-trash text-danger bx-xs me-2"></i>
|
||||
<span className="align-left">Delete</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
{!IsActive && (
|
||||
<i
|
||||
className={`bx bx-history ${
|
||||
dirActions.action && dirActions.id === contact.id
|
||||
? "bx-spin"
|
||||
: ""
|
||||
} me-1 text-primary cursor-pointer`}
|
||||
title="Restore"
|
||||
onClick={() => {
|
||||
setDirActions({ action: false, id: contact.id });
|
||||
restore(contact.id);
|
||||
}}
|
||||
></i>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul className="list-inline m-0 ps-4">
|
||||
<li className="list-inline-item me-1" style={{ fontSize: "10px" }}>
|
||||
<i className="bx bx-building bx-xs"></i>
|
||||
<i className="fa-solid fa-briefcase me-2"></i>
|
||||
</li>
|
||||
<li className="list-inline-item text-small">
|
||||
{contact.organization}
|
||||
@ -97,7 +116,7 @@ const CardViewDirectory = ({
|
||||
{contact.contactEmails[0] && (
|
||||
<ul className="list-inline my-1 ">
|
||||
<li className="list-inline-item me-2">
|
||||
<i className="bx bx-envelope bx-xs"></i>
|
||||
<i className="bx bx-envelope bx-xs"></i>
|
||||
</li>
|
||||
<li className="list-inline-item text-small">
|
||||
{contact.contactEmails[0]?.emailAddress}
|
||||
@ -122,27 +141,28 @@ const CardViewDirectory = ({
|
||||
|
||||
<ul className="list-inline m-0">
|
||||
<li className="list-inline-item me-2 my-1">
|
||||
<i className="fa-solid fa-tag fs-6"></i>
|
||||
|
||||
<i className="fa-solid fa-tag fs-6"></i>
|
||||
</li>
|
||||
<li className="list-inline-item text-small active">
|
||||
{contact.contactCategory.name}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul className="list-inline m-0">
|
||||
{contact.bucketIds?.map((bucketId) => (
|
||||
<li key={bucketId} className="list-inline-item me-1">
|
||||
<span className="badge bg-label-primary rounded-pill d-flex align-items-center gap-1" style={{padding:'0.1rem 0.3rem'}}>
|
||||
<i className="bx bx-pin bx-xs"></i>
|
||||
<span className="small-text">
|
||||
{getBucketNameById(buckets, bucketId)}
|
||||
</span>
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<ul className="list-inline m-0">
|
||||
{contact.bucketIds?.map((bucketId) => (
|
||||
<li key={bucketId} className="list-inline-item me-1">
|
||||
<span
|
||||
className="badge bg-label-primary rounded-pill d-flex align-items-center gap-1"
|
||||
style={{ padding: "0.1rem 0.3rem" }}
|
||||
>
|
||||
<i className="bx bx-pin bx-xs"></i>
|
||||
<span className="small-text">
|
||||
{getBucketNameById(buckets, bucketId)}
|
||||
</span>
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -6,7 +6,7 @@ export const ContactSchema = z
|
||||
contactCategoryId: z.string().nullable().optional(),
|
||||
address: z.string().optional(),
|
||||
description: z.string().min(1, { message: "Description is required" }),
|
||||
projectIds: z.array(z.string()), // min(1, "Project is required")
|
||||
projectIds: z.array(z.string()).nullable().optional(), // min(1, "Project is required")
|
||||
contactEmails: z
|
||||
.array(
|
||||
z.object({
|
||||
@ -39,7 +39,7 @@ export const ContactSchema = z
|
||||
})
|
||||
)
|
||||
.min(1, { message: "At least one tag is required" }),
|
||||
bucketIds: z.array(z.string()).min(1,{message:"At least one Label required"}),
|
||||
bucketIds: z.array(z.string()).nonempty({ message: "At least one label is required" })
|
||||
})
|
||||
|
||||
// .refine((data) => {
|
||||
|
@ -96,7 +96,7 @@ const EmployeeList = ({ employees, onChange, bucket }) => {
|
||||
>
|
||||
<span className="ps-2">Name {getSortIcon()}</span>
|
||||
</th>
|
||||
<th className="text-start">Email</th>
|
||||
<th className="text-start">Role</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@ -143,7 +143,7 @@ const EmployeeList = ({ employees, onChange, bucket }) => {
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-start">
|
||||
<small className="text-muted">{employee.email}</small>
|
||||
<small className="text-muted">{employee.jobRole}</small>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
|
@ -1,74 +1,128 @@
|
||||
import React from 'react'
|
||||
import Avatar from '../common/Avatar';
|
||||
import { getEmailIcon,getPhoneIcon } from './DirectoryUtils';
|
||||
import React, { useEffect } from "react";
|
||||
import Avatar from "../common/Avatar";
|
||||
import { getEmailIcon, getPhoneIcon } from "./DirectoryUtils";
|
||||
import { useDir } from "../../Context/DireContext";
|
||||
|
||||
const ListViewDirectory = ({
|
||||
IsActive,
|
||||
contact,
|
||||
setSelectedContact,
|
||||
setIsOpenModal,
|
||||
setOpen_contact,
|
||||
setIsOpenModalNote,
|
||||
IsDeleted,
|
||||
restore,
|
||||
}) => {
|
||||
const { dirActions, setDirActions } = useDir();
|
||||
|
||||
const ListViewDirectory = ({IsActive, contact,setSelectedContact,setIsOpenModal,setOpen_contact,setIsOpenModalNote,IsDeleted}) => {
|
||||
return (
|
||||
<tr className={!IsActive ? "bg-light" : ""}>
|
||||
<td className="text-start cursor-pointer" style={{ width: "18%" }} colSpan={2} onClick={() => {
|
||||
if (IsActive) {
|
||||
setIsOpenModalNote(true);
|
||||
setOpen_contact(contact);
|
||||
}
|
||||
}}>
|
||||
<div className="d-flex align-items-center">
|
||||
<Avatar
|
||||
size="xs"
|
||||
classAvatar="m-0"
|
||||
firstName={(contact?.name || "").trim().split(" ")[0]?.charAt(0) || ""}
|
||||
lastName={(contact?.name || "").trim().split(" ")[1]?.charAt(0) || ""}
|
||||
/>
|
||||
<span className="text-truncate mx-0" style={{ maxWidth: "150px" }}>{contact?.name || ""}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="px-2" style={{ width: "20%" }}>
|
||||
<div className="d-flex flex-column align-items-start text-truncate">
|
||||
{contact.contactEmails?.map((email, index) => (
|
||||
<span key={email.id} className="text-truncate">
|
||||
<i className={getEmailIcon(email.label)} style={{ fontSize: "12px" }}></i>
|
||||
<a href={`mailto:${email.emailAddress}`} className="text-decoration-none ms-1">{email.emailAddress}</a>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="px-2" style={{ width: "20%" }}>
|
||||
<div className="d-flex flex-column align-items-start text-truncate">
|
||||
{contact.contactPhones?.map((phone, index) => (
|
||||
<span key={phone.id}>
|
||||
<i className={getPhoneIcon(phone.label)} style={{ fontSize: "12px" }}></i>
|
||||
<span className="ms-1">{phone.phoneNumber}</span>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td colSpan={2} className="text-start text-truncate px-2" style={{ width: "20%", maxWidth: "200px" }}>
|
||||
{contact.organization}
|
||||
</td>
|
||||
|
||||
<td className="px-2" style={{ width: "10%" }}>
|
||||
<span className="badge badge-outline-secondary">
|
||||
{contact?.contactCategory?.name}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
{IsActive && (
|
||||
<td className="align-middle text-center" style={{ width: "12%" }}>
|
||||
<i className="bx bx-edit bx-sm text-primary cursor-pointer me-2"
|
||||
<tr className={!IsActive ? "bg-light" : ""}>
|
||||
<td
|
||||
className="text-start cursor-pointer"
|
||||
style={{ width: "18%" }}
|
||||
colSpan={2}
|
||||
onClick={() => {
|
||||
setSelectedContact(contact);
|
||||
setIsOpenModal(true);
|
||||
}}></i>
|
||||
<i className="bx bx-trash bx-sm text-danger cursor-pointer"
|
||||
onClick={() => IsDeleted(contact.id)}></i>
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
if (IsActive) {
|
||||
setIsOpenModalNote(true);
|
||||
setOpen_contact(contact);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="d-flex align-items-center">
|
||||
<Avatar
|
||||
size="xs"
|
||||
classAvatar="m-0"
|
||||
firstName={
|
||||
(contact?.name || "").trim().split(" ")[0]?.charAt(0) || ""
|
||||
}
|
||||
lastName={
|
||||
(contact?.name || "").trim().split(" ")[1]?.charAt(0) || ""
|
||||
}
|
||||
/>
|
||||
<span className="text-truncate mx-0" style={{ maxWidth: "150px" }}>
|
||||
{contact?.name || ""}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="px-2" style={{ width: "20%" }}>
|
||||
<div className="d-flex flex-column align-items-start text-truncate">
|
||||
{contact.contactEmails?.map((email, index) => (
|
||||
<span key={email.id} className="text-truncate">
|
||||
<i
|
||||
className={getEmailIcon(email.label)}
|
||||
style={{ fontSize: "12px" }}
|
||||
></i>
|
||||
<a
|
||||
href={`mailto:${email.emailAddress}`}
|
||||
className="text-decoration-none ms-1"
|
||||
>
|
||||
{email.emailAddress}
|
||||
</a>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="px-2" style={{ width: "20%" }}>
|
||||
<div className="d-flex flex-column align-items-start text-truncate">
|
||||
{contact.contactPhones?.map((phone, index) => (
|
||||
<span key={phone.id}>
|
||||
<i
|
||||
className={getPhoneIcon(phone.label)}
|
||||
style={{ fontSize: "12px" }}
|
||||
></i>
|
||||
<span className="ms-1">{phone.phoneNumber}</span>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td
|
||||
colSpan={2}
|
||||
className="text-start text-truncate px-2"
|
||||
style={{ width: "20%", maxWidth: "200px" }}
|
||||
>
|
||||
{contact.organization}
|
||||
</td>
|
||||
|
||||
<td className="px-2" style={{ width: "10%" }}>
|
||||
<span className="badge badge-outline-secondary">
|
||||
{contact?.contactCategory?.name}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td className="align-middle text-center" style={{ width: "12%" }}>
|
||||
{IsActive && (
|
||||
<>
|
||||
<i
|
||||
className="bx bx-edit bx-sm text-primary cursor-pointer me-2"
|
||||
onClick={() => {
|
||||
setSelectedContact(contact);
|
||||
setIsOpenModal(true);
|
||||
}}
|
||||
></i>
|
||||
<i
|
||||
className="bx bx-trash bx-sm text-danger cursor-pointer"
|
||||
onClick={() => IsDeleted(contact.id)}
|
||||
></i>
|
||||
</>
|
||||
)}
|
||||
{!IsActive && (
|
||||
<i
|
||||
className={`bx bx-history ${
|
||||
dirActions.action && dirActions.id === contact.id ? "bx-spin" : ""
|
||||
} me-1 text-primary cursor-pointer`}
|
||||
title="Restore"
|
||||
onClick={() => {
|
||||
setDirActions({ action: false, id: contact.id });
|
||||
restore(contact.id);
|
||||
}}
|
||||
></i>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
export default ListViewDirectory;
|
||||
export default ListViewDirectory;
|
||||
|
@ -12,8 +12,13 @@ import EmployeeList from "./EmployeeList";
|
||||
import { useAllEmployees, useEmployees } from "../../hooks/useEmployees";
|
||||
import { useSortableData } from "../../hooks/useSortableData";
|
||||
import ConfirmModal from "../common/ConfirmModal";
|
||||
import {useHasUserPermission} from "../../hooks/useHasUserPermission";
|
||||
import {DIRECTORY_ADMIN, DIRECTORY_MANAGER} from "../../utils/constants";
|
||||
import {useProfile} from "../../hooks/useProfile";
|
||||
|
||||
const ManageBucket = () => {
|
||||
const ManageBucket = () =>
|
||||
{
|
||||
const {profile} =useProfile()
|
||||
const [bucketList, setBucketList] = useState([]);
|
||||
const { employeesList } = useAllEmployees(false);
|
||||
const [selectedEmployee, setSelectEmployee] = useState([]);
|
||||
@ -22,7 +27,9 @@ const ManageBucket = () => {
|
||||
const [isSubmitting, setSubmitting] = useState(false);
|
||||
const [selected_bucket, select_bucket] = useState(null);
|
||||
const [deleteBucket, setDeleteBucket] = useState(null);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [ searchTerm, setSearchTerm ] = useState( "" );
|
||||
const DirManager = useHasUserPermission( DIRECTORY_MANAGER )
|
||||
const DirAdmin = useHasUserPermission(DIRECTORY_ADMIN)
|
||||
const {
|
||||
items: sortedBuckteList,
|
||||
requestSort,
|
||||
@ -336,19 +343,25 @@ const ManageBucket = () => {
|
||||
</td>
|
||||
<td>{bucket.numberOfContacts}</td>
|
||||
<td className="justify-content-center">
|
||||
<div className="d-flex justify-content-center align-items-center gap-2">
|
||||
<i
|
||||
className="bx bx-edit bx-sm text-primary cursor-pointer"
|
||||
onClick={() => {
|
||||
select_bucket(bucket);
|
||||
setAction_bucket(true);
|
||||
|
||||
{(DirManager ||
|
||||
DirAdmin ||
|
||||
bucket?.createdBy?.id ===
|
||||
profile?.employeeInfo?.id) && (
|
||||
<div className="d-flex justify-content-center align-items-center gap-2">
|
||||
<i
|
||||
className="bx bx-edit bx-sm text-primary cursor-pointer "
|
||||
onClick={() => {
|
||||
select_bucket(bucket);
|
||||
setAction_bucket(true);
|
||||
}}
|
||||
></i>
|
||||
<i
|
||||
className="bx bx-trash bx-sm text-danger cursor-pointer"
|
||||
onClick={() => setDeleteBucket(bucket?.id)}
|
||||
></i>
|
||||
</div>
|
||||
></i>
|
||||
<i
|
||||
className="bx bx-trash bx-sm text-danger cursor-pointer"
|
||||
onClick={() => setDeleteBucket(bucket?.id)}
|
||||
></i>
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
@ -386,7 +399,7 @@ const ManageBucket = () => {
|
||||
<EmployeeList
|
||||
employees={employeesList}
|
||||
onChange={(data) => setSelectEmployee(data)}
|
||||
assignedEmployee={selected_bucket?.employeeIds}
|
||||
bucket={selected_bucket}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
@ -17,24 +17,22 @@ import { changeMaster } from "../../slices/localVariablesSlice";
|
||||
import { useBuckets, useOrganization } from "../../hooks/useDirectory";
|
||||
import { useProjects } from "../../hooks/useProjects";
|
||||
import SelectMultiple from "../common/SelectMultiple";
|
||||
import {ContactSchema} from "./DirectorySchema";
|
||||
import { ContactSchema } from "./DirectorySchema";
|
||||
import InputSuggestions from "../common/InputSuggestion";
|
||||
|
||||
|
||||
|
||||
const ManageDirectory = ({ submitContact, onCLosed }) => {
|
||||
const selectedMaster = useSelector(
|
||||
(store) => store.localVariables.selectedMaster
|
||||
);
|
||||
const [ categoryData, setCategoryData ] = useState( [] );
|
||||
|
||||
const [categoryData, setCategoryData] = useState([]);
|
||||
|
||||
const [TagsData, setTagsData] = useState([]);
|
||||
const { data, loading } = useMaster();
|
||||
const { buckets, loading: bucketsLoaging } = useBuckets();
|
||||
const { projects, loading: projectLoading } = useProjects();
|
||||
const { contactCategory, loading: contactCategoryLoading } =
|
||||
useContactCategory();
|
||||
const {organizationList,loading:orgLoading} = useOrganization()
|
||||
const { organizationList, loading: orgLoading } = useOrganization();
|
||||
const { contactTags, loading: Tagloading } = useContactTags();
|
||||
const [IsSubmitting, setSubmitting] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
@ -79,15 +77,14 @@ const ManageDirectory = ({ submitContact, onCLosed }) => {
|
||||
remove: removePhone,
|
||||
} = useFieldArray({ control, name: "contactPhones" });
|
||||
|
||||
useEffect(() => {
|
||||
if (emailFields.length === 0) {
|
||||
appendEmail({ label: "Work", emailAddress: "" });
|
||||
}
|
||||
if (phoneFields.length === 0) {
|
||||
appendPhone({ label: "Office", phoneNumber: "" });
|
||||
}
|
||||
}, [emailFields.length, phoneFields.length]);
|
||||
|
||||
useEffect(() => {
|
||||
if (emailFields.length === 0) {
|
||||
appendEmail({ label: "Work", emailAddress: "" });
|
||||
}
|
||||
if (phoneFields.length === 0) {
|
||||
appendPhone({ label: "Office", phoneNumber: "" });
|
||||
}
|
||||
}, [emailFields.length, phoneFields.length]);
|
||||
|
||||
const handleAddEmail = async () => {
|
||||
const emails = getValues("contactEmails");
|
||||
@ -124,22 +121,21 @@ useEffect(() => {
|
||||
setValue("bucketIds", updated, { shouldValidate: true });
|
||||
};
|
||||
|
||||
const onSubmit = ( data ) =>
|
||||
{
|
||||
const cleaned = {
|
||||
...data,
|
||||
contactEmails: (data.contactEmails || []).filter(
|
||||
(e) => e.emailAddress?.trim() !== ""
|
||||
),
|
||||
contactPhones: (data.contactPhones || []).filter(
|
||||
(p) => p.phoneNumber?.trim() !== ""
|
||||
),
|
||||
};
|
||||
const onSubmit = (data) => {
|
||||
const cleaned = {
|
||||
...data,
|
||||
contactEmails: (data.contactEmails || []).filter(
|
||||
(e) => e.emailAddress?.trim() !== ""
|
||||
),
|
||||
contactPhones: (data.contactPhones || []).filter(
|
||||
(p) => p.phoneNumber?.trim() !== ""
|
||||
),
|
||||
};
|
||||
|
||||
setSubmitting(true);
|
||||
submitContact(cleaned, reset, setSubmitting);
|
||||
};
|
||||
const orgValue = watch("organization")
|
||||
const orgValue = watch("organization");
|
||||
|
||||
const handleClosed = () => {
|
||||
onCLosed();
|
||||
@ -165,16 +161,11 @@ useEffect(() => {
|
||||
<div className="col-md-6 text-start">
|
||||
<label className="form-label">Organization</label>
|
||||
<InputSuggestions
|
||||
organizationList={organizationList}
|
||||
value={getValues("organization") || ""}
|
||||
onChange={(val) => setValue("organization", val)}
|
||||
error={errors.organization?.message}
|
||||
/>
|
||||
{errors.organization && (
|
||||
<small className="danger-text">
|
||||
{errors.organization.message}
|
||||
</small>
|
||||
)}
|
||||
organizationList={organizationList}
|
||||
value={getValues("organization") || ""}
|
||||
onChange={(val) => setValue("organization", val)}
|
||||
error={errors.organization?.message}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row mt-1">
|
||||
@ -216,7 +207,10 @@ useEffect(() => {
|
||||
// onClick={handleAddEmail}
|
||||
// style={{ width: "24px", height: "24px" }}
|
||||
// >
|
||||
<i className="bx bx-plus-circle bx-xs ms-1 cursor-pointer text-primary" onClick={handleAddEmail} />
|
||||
<i
|
||||
className="bx bx-plus-circle bx-xs ms-1 cursor-pointer text-primary"
|
||||
onClick={handleAddEmail}
|
||||
/>
|
||||
) : (
|
||||
// <button
|
||||
// type="button"
|
||||
@ -224,8 +218,10 @@ useEffect(() => {
|
||||
// onClick={() => removeEmail(index)}
|
||||
// style={{ width: "24px", height: "24px" }}
|
||||
// >
|
||||
<i className="bx bx-minus-circle bx-xs ms-1 cursor-pointer text-primary" onClick={() => removeEmail(index)} />
|
||||
|
||||
<i
|
||||
className="bx bx-minus-circle bx-xs ms-1 cursor-pointer text-primary"
|
||||
onClick={() => removeEmail(index)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{errors.contactEmails?.[index]?.emailAddress && (
|
||||
@ -275,8 +271,10 @@ useEffect(() => {
|
||||
// onClick={handleAddPhone}
|
||||
// style={{ width: "24px", height: "24px" }}
|
||||
// >
|
||||
<i className="bx bx-plus-circle bx-xs ms-1 cursor-pointer text-primary" onClick={handleAddPhone} />
|
||||
|
||||
<i
|
||||
className="bx bx-plus-circle bx-xs ms-1 cursor-pointer text-primary"
|
||||
onClick={handleAddPhone}
|
||||
/>
|
||||
) : (
|
||||
// <button
|
||||
// type="button"
|
||||
@ -284,8 +282,10 @@ useEffect(() => {
|
||||
// onClick={() => removePhone(index)}
|
||||
// style={{ width: "24px", height: "24px" }}
|
||||
// >
|
||||
<i className="bx bx-minus-circle bx-xs ms-1 cursor-pointer text-danager" onClick={() => removePhone(index)} />
|
||||
|
||||
<i
|
||||
className="bx bx-minus-circle bx-xs ms-1 cursor-pointer text-danager"
|
||||
onClick={() => removePhone(index)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{errors.contactPhones?.[index]?.phoneNumber && (
|
||||
@ -297,9 +297,9 @@ useEffect(() => {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{errors.contactPhone?.message && (
|
||||
<div className="danger-text">{errors.contactPhone.message}</div>
|
||||
)}
|
||||
{errors.contactPhone?.message && (
|
||||
<div className="danger-text">{errors.contactPhone.message}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="row my-1">
|
||||
@ -315,7 +315,7 @@ useEffect(() => {
|
||||
</option>
|
||||
) : (
|
||||
<>
|
||||
<option disabled value="">
|
||||
<option disabled value="">
|
||||
Select Category
|
||||
</option>
|
||||
{contactCategory?.map((cate) => (
|
||||
@ -341,29 +341,23 @@ useEffect(() => {
|
||||
valueKey="id"
|
||||
IsLoading={projectLoading}
|
||||
/>
|
||||
{errors.projectIds && (
|
||||
<small className="danger-text">
|
||||
{errors.projectIds.message}
|
||||
</small>
|
||||
{errors.projectIds && (
|
||||
<small className="danger-text">{errors.projectIds.message}</small>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-12 text-start">
|
||||
<TagInput name="tags" label="Tags" options={contactTags} />
|
||||
{errors.tags && (
|
||||
<small className="danger-text">
|
||||
{errors.tags.message}
|
||||
</small>
|
||||
)}
|
||||
{errors.tags && (
|
||||
<small className="danger-text">{errors.tags.message}</small>
|
||||
)}
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-md-12 mt-1 text-start">
|
||||
<label className="form-label ">Select Label</label>
|
||||
<label className="form-label ">Select Bucket</label>
|
||||
|
||||
<ul
|
||||
className="d-flex flex-wrap px-1 list-unstyled mb-0"
|
||||
>
|
||||
<ul className="d-flex flex-wrap px-1 list-unstyled mb-0">
|
||||
{bucketsLoaging && <p>Loading...</p>}
|
||||
{buckets?.map((item) => (
|
||||
<li
|
||||
@ -387,11 +381,12 @@ useEffect(() => {
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
{errors.bucketIds && (
|
||||
<small className="danger-text mt-0">
|
||||
{errors.bucketIds.message}
|
||||
</small>
|
||||
)}
|
||||
</ul>
|
||||
|
||||
{errors.BucketIds && (
|
||||
<small className="text-danger">{errors.BucketIds.message}</small>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -7,11 +7,12 @@ import showToast from "../../services/toastService";
|
||||
import { cacheData, getCachedData } from "../../slices/apiDataManager";
|
||||
import "../common/TextEditor/Editor.css";
|
||||
|
||||
const NoteCardDirectory = ({ IsActive,noteItem, contactId, setProfileContact }) => {
|
||||
const NoteCardDirectory = ({refetchProfile,refetchNotes, noteItem, contactId, setProfileContact, }) => {
|
||||
const [editing, setEditing] = useState(false);
|
||||
const [editorValue, setEditorValue] = useState(noteItem.note);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
const [ isDeleting, setIsDeleting ] = useState( false );
|
||||
const [isActivProcess,setActiveProcessing]= useState(false)
|
||||
const handleUpdateNote = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
@ -63,10 +64,10 @@ const NoteCardDirectory = ({ IsActive,noteItem, contactId, setProfileContact })
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteNote = async () => {
|
||||
const handleDeleteNote = async (activeStatue) => {
|
||||
try {
|
||||
setIsDeleting(true);
|
||||
const resp = await DirectoryRepository.DeleteNote(noteItem.id);
|
||||
activeStatue ? setActiveProcessing(true) : setIsDeleting(true)
|
||||
const resp = await DirectoryRepository.DeleteNote(noteItem.id,activeStatue);
|
||||
setProfileContact((prev) => ({
|
||||
...prev,
|
||||
notes: prev.notes.filter((note) => note.id !== noteItem.id),
|
||||
@ -90,8 +91,11 @@ const NoteCardDirectory = ({ IsActive,noteItem, contactId, setProfileContact })
|
||||
|
||||
cacheData("Contact Profile", updatedCache);
|
||||
}
|
||||
setIsDeleting(false);
|
||||
showToast("Note Deleted Successfully", "success");
|
||||
setIsDeleting( false );
|
||||
setActiveProcessing( false )
|
||||
refetchNotes( contactId, false )
|
||||
refetchProfile(contactId)
|
||||
showToast(`Note ${activeStatue ? "Restored":"Deleted"} Successfully`, "success");
|
||||
} catch (error) {
|
||||
setIsDeleting(false);
|
||||
const msg =
|
||||
@ -101,13 +105,13 @@ const NoteCardDirectory = ({ IsActive,noteItem, contactId, setProfileContact })
|
||||
showToast(msg, "error");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="card p-1 shadow-sm border-1 mb-2 conntactNote"
|
||||
style={{ width: "100%", minWidth: "300px", borderRadius: "0px", background: `${!IsActive ? "#f8f6f6" : ""}` }}
|
||||
style={{ width: "100%", minWidth: "300px", borderRadius: "0px", background: `${noteItem.isActive ? "": "#f8f6f6"}` }}
|
||||
key={noteItem.id}
|
||||
>
|
||||
|
||||
<div className="d-flex justify-content-between align-items-center mb-1">
|
||||
<div className="d-flex align-items-center">
|
||||
<Avatar
|
||||
@ -129,26 +133,39 @@ const NoteCardDirectory = ({ IsActive,noteItem, contactId, setProfileContact })
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`${IsActive ? " ":"d-none"}`}>
|
||||
<i
|
||||
className="bx bxs-edit bx-sm me-1 text-primary cursor-pointer"
|
||||
onClick={() => setEditing(true)}
|
||||
></i>
|
||||
{!isDeleting && (
|
||||
<i
|
||||
className="bx bx-trash bx-sm me-1 text-secondary cursor-pointer"
|
||||
onClick={handleDeleteNote}
|
||||
></i>
|
||||
)}
|
||||
{isDeleting && (
|
||||
<div
|
||||
class="spinner-border spinner-border-sm text-secondary"
|
||||
role="status"
|
||||
>
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
{noteItem.isActive ? (
|
||||
<>
|
||||
<i
|
||||
className="bx bxs-edit bx-sm me-1 text-primary cursor-pointer"
|
||||
onClick={() => setEditing(true)}
|
||||
></i>
|
||||
|
||||
{!isDeleting ? (
|
||||
<i
|
||||
className="bx bx-trash bx-sm me-1 text-secondary cursor-pointer"
|
||||
onClick={() => handleDeleteNote(!noteItem.isActive)}
|
||||
></i>
|
||||
) : (
|
||||
<div
|
||||
className="spinner-border spinner-border-sm text-secondary"
|
||||
role="status"
|
||||
>
|
||||
<span className="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : isActivProcess ? (
|
||||
< i className='bx bx-refresh text-primary bx-spin' ></i>
|
||||
) : (
|
||||
<i
|
||||
className="bx bx-history me-1 text-primary cursor-pointer"
|
||||
onClick={() => handleDeleteNote(!noteItem.isActive)}
|
||||
title="Restore"
|
||||
></i>
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<hr className="mt-0" />
|
||||
|
@ -16,9 +16,9 @@ const schema = z.object({
|
||||
note: z.string().min(1, { message: "Note is required" }),
|
||||
});
|
||||
|
||||
const NotesDirectory = ({ isLoading, contactProfile, setProfileContact }) => {
|
||||
const NotesDirectory = ({refetchProfile, isLoading, contactProfile, setProfileContact }) => {
|
||||
const [IsActive, setIsActive] = useState(true);
|
||||
const { contactNotes } = useContactNotes(contactProfile?.id, !IsActive);
|
||||
const {contactNotes,refetch} = useContactNotes( contactProfile?.id, true );
|
||||
|
||||
const [NotesData, setNotesData] = useState();
|
||||
const [IsSubmitting, setIsSubmitting] = useState(false);
|
||||
@ -85,6 +85,14 @@ const NotesDirectory = ({ isLoading, contactProfile, setProfileContact }) => {
|
||||
const onCancel = () => {
|
||||
setValue("note", "");
|
||||
};
|
||||
const handleSwitch = () =>
|
||||
{
|
||||
setIsActive( !IsActive )
|
||||
if ( IsActive )
|
||||
{
|
||||
refetch(contactProfile?.id, false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-start">
|
||||
@ -95,7 +103,7 @@ const NotesDirectory = ({ isLoading, contactProfile, setProfileContact }) => {
|
||||
<input
|
||||
type="checkbox"
|
||||
className="switch-input"
|
||||
onChange={() => setIsActive(!IsActive)}
|
||||
onChange={()=>handleSwitch(!IsActive)}
|
||||
value={IsActive}
|
||||
/>
|
||||
<span className="switch-toggle-slider">
|
||||
@ -106,9 +114,13 @@ const NotesDirectory = ({ isLoading, contactProfile, setProfileContact }) => {
|
||||
{/* <i class="icon-base bx bx-x"></i> */}
|
||||
</span>
|
||||
</span>
|
||||
<span className="switch-label small-text">Show Inactive Notes</span>
|
||||
<span className="switch-label small-text">Show Including Inactive Notes</span>
|
||||
</label>
|
||||
<span
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className="d-flex justify-content-end px-2">
|
||||
<span
|
||||
className={`btn btn-xs ${addNote ? "btn-danger" : "btn-primary"}`}
|
||||
onClick={() => setAddNote(!addNote)}
|
||||
>
|
||||
@ -119,7 +131,6 @@ const NotesDirectory = ({ isLoading, contactProfile, setProfileContact }) => {
|
||||
></i> */}
|
||||
{addNote ? "close" : "Add Note"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{addNote && (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
@ -143,30 +154,34 @@ const NotesDirectory = ({ isLoading, contactProfile, setProfileContact }) => {
|
||||
</div>
|
||||
)}
|
||||
{!isLoading &&
|
||||
[...(IsActive ? contactProfile?.notes || [] : contactNotes || [])]
|
||||
.reverse()
|
||||
.map((noteItem) => (
|
||||
<NoteCardDirectory
|
||||
IsActive={IsActive}
|
||||
noteItem={noteItem}
|
||||
contactId={contactProfile?.id}
|
||||
setProfileContact={setProfileContact}
|
||||
key={noteItem.id}
|
||||
/>
|
||||
))}
|
||||
[...(IsActive ? contactProfile?.notes || [] : contactNotes || [])]
|
||||
.reverse()
|
||||
.map((noteItem) => (
|
||||
<NoteCardDirectory
|
||||
refetchProfile={refetchProfile}
|
||||
refetchNotes={refetch}
|
||||
refetchContact ={refetch}
|
||||
noteItem={noteItem}
|
||||
contactId={contactProfile?.id}
|
||||
setProfileContact={setProfileContact}
|
||||
key={noteItem.id}
|
||||
|
||||
/>
|
||||
))}
|
||||
|
||||
{IsActive && (
|
||||
<p>
|
||||
<div>
|
||||
{!isLoading && contactProfile?.notes.length == 0 && !addNote && (
|
||||
<p className="text-center">No Notes Found</p>
|
||||
<div className="text-center">No Notes Found</div>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{!IsActive && (
|
||||
<p>
|
||||
<div>
|
||||
{!isLoading && contactNotes.length == 0 && !addNote && (
|
||||
<p className="text-center">No Notes Found</p>
|
||||
<div className="text-center">No Notes Found</div>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,12 +5,28 @@ import moment from "moment";
|
||||
import NotesDirectory from "./NotesDirectory";
|
||||
|
||||
const ProfileContactDirectory = ({ contact, setOpen_contact, closeModal }) => {
|
||||
const { conatProfile, loading } = useContactProfile(contact?.id);
|
||||
const [profileContact, setProfileContact] = useState();
|
||||
const { contactProfile, loading, refetch } = useContactProfile(contact?.id);
|
||||
const [copiedIndex, setCopiedIndex] = useState(null);
|
||||
|
||||
const [profileContact, setProfileContact] = useState();
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const description = contactProfile?.description || "";
|
||||
const limit = 100;
|
||||
|
||||
const toggleReadMore = () => setExpanded(!expanded);
|
||||
|
||||
const isLong = description.length > limit;
|
||||
const displayText = expanded
|
||||
? description
|
||||
: description.slice(0, limit) + (isLong ? "..." : "");
|
||||
useEffect(() => {
|
||||
setProfileContact(conatProfile);
|
||||
}, [conatProfile]);
|
||||
setProfileContact(contactProfile);
|
||||
}, [contactProfile]);
|
||||
const handleCopy = (email, index) => {
|
||||
navigator.clipboard.writeText(email);
|
||||
setCopiedIndex(index);
|
||||
setTimeout(() => setCopiedIndex(null), 2000); // Reset after 2 seconds
|
||||
};
|
||||
return (
|
||||
<div className="p-1">
|
||||
<div className="text-center m-0 p-0">
|
||||
@ -20,6 +36,7 @@ const ProfileContactDirectory = ({ contact, setOpen_contact, closeModal }) => {
|
||||
<div className="d-flex align-items-center mb-2">
|
||||
<Avatar
|
||||
size="sm"
|
||||
classAvatar="m-0"
|
||||
firstName={
|
||||
(contact?.name || "").trim().split(" ")[0]?.charAt(0) || ""
|
||||
}
|
||||
@ -27,92 +44,187 @@ const ProfileContactDirectory = ({ contact, setOpen_contact, closeModal }) => {
|
||||
(contact?.name || "").trim().split(" ")[1]?.charAt(0) || ""
|
||||
}
|
||||
/>
|
||||
<div className="d-flex flex-column text-start ms-2">
|
||||
<div className="d-flex flex-column text-start ms-1">
|
||||
<span className="m-0 fw-semibold">{contact?.name}</span>
|
||||
<span className="small">
|
||||
<i className="bx bx-building bx-xs"></i>{" "}
|
||||
{conatProfile?.organization}
|
||||
</span>
|
||||
<span className="small-text">Manager</span>
|
||||
<small className="text-secondary small-text">
|
||||
{contactProfile?.tags?.map((tag) => tag.name).join(" | ")}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-12 col-md-6 d-flex flex-column text-start">
|
||||
{conatProfile?.contactEmails?.length > 0 && (
|
||||
<div className="d-flex mb-2">
|
||||
<div style={{ width: "100px", minWidth: "100px" }}>
|
||||
<p className="m-0">Email</p>
|
||||
<div className="col-12 col-md-6 d-flex flex-column text-start">
|
||||
{contactProfile?.contactEmails?.length > 0 && (
|
||||
<div className="d-flex mb-2">
|
||||
<div style={{ width: "100px", minWidth: "100px" }}>
|
||||
<p className="m-0">Email:</p>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-inline mb-0">
|
||||
{contactProfile.contactEmails.map((email, idx) => (
|
||||
<li
|
||||
className="list-inline-item me-3 d-flex align-items-center"
|
||||
key={idx}
|
||||
>
|
||||
<i className="bx bx-envelope bx-xs me-1"></i>
|
||||
<span className="me-2">{email.emailAddress}</span>
|
||||
<i
|
||||
className={`bx bx-copy cursor-pointer ${
|
||||
copiedIndex === idx
|
||||
? "text-secondary"
|
||||
: "text-primary"
|
||||
}`}
|
||||
title={copiedIndex === idx ? "Copied!" : "Copy Email"}
|
||||
style={{ fontSize: "16px" }}
|
||||
onClick={() => handleCopy(email.emailAddress, idx)}
|
||||
></i>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-inline mb-0">
|
||||
{conatProfile.contactEmails.map((email, idx) => (
|
||||
<li className="list-inline-item me-3" key={idx}>
|
||||
<i className="bx bx-envelope bx-xs me-1"></i>
|
||||
{email.emailAddress}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{conatProfile?.contactPhones?.length > 0 && (
|
||||
<div className="d-flex mb-2">
|
||||
<div style={{ width: "100px", minWidth: "100px" }}>
|
||||
<p className="m-0">Phone</p>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-inline mb-0">
|
||||
{conatProfile?.contactPhones.map((phone, idx) => (
|
||||
<li className="list-inline-item me-3" key={idx}>
|
||||
<i className="bx bx-phone bx-xs me-1"></i>
|
||||
{phone.phoneNumber}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
|
||||
{conatProfile?.createdAt && (
|
||||
<div className="d-flex mb-2">
|
||||
<div style={{ width: "100px", minWidth: "100px" }}>
|
||||
<p className="m-0">Created</p>
|
||||
{contactProfile?.contactPhones?.length > 0 && (
|
||||
<div className="d-flex mb-2">
|
||||
<div style={{ width: "100px", minWidth: "100px" }}>
|
||||
<p className="m-0">Phone : </p>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-inline mb-0">
|
||||
{contactProfile?.contactPhones.map((phone, idx) => (
|
||||
<li className="list-inline-item me-3" key={idx}>
|
||||
<i className="bx bx-phone bx-xs me-1"></i>
|
||||
{phone.phoneNumber}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-inline mb-0">
|
||||
<li className="list-inline-item">
|
||||
<i className="bx bx-calendar-week bx-xs me-1"></i>
|
||||
{moment(conatProfile.createdAt).format("MMMM, DD YYYY")}
|
||||
</li>
|
||||
</ul>
|
||||
)}
|
||||
|
||||
{contactProfile?.createdAt && (
|
||||
<div className="d-flex mb-2">
|
||||
<div style={{ width: "100px", minWidth: "100px" }}>
|
||||
<p className="m-0">Created : </p>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-inline mb-0">
|
||||
<li className="list-inline-item">
|
||||
<i className="bx bx-calendar-week bx-xs me-1"></i>
|
||||
{moment(contactProfile.createdAt).format("MMMM, DD YYYY")}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
|
||||
{contactProfile?.address && (
|
||||
<div className="d-flex mb-2">
|
||||
<div style={{ width: "100px", minWidth: "100px" }}>
|
||||
<p className="m-0">Location : </p>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-inline mb-0">
|
||||
<li className="list-inline-item">
|
||||
<i className="bx bx-map bx-xs me-1"></i>
|
||||
{contactProfile?.address}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{ conatProfile?.buckets?.length > 0 &&
|
||||
<div className="col-12 col-md-6 d-flex flex-column text-start">
|
||||
{conatProfile?.contactEmails?.length > 0 && (
|
||||
<div className="d-flex mb-2 align-items-center">
|
||||
<div style={{ width: "100px", minWidth: "100px" }}>
|
||||
<p className="m-0">Buckets</p>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-inline mb-0">
|
||||
{conatProfile.buckets.map((bucket) => (
|
||||
<li className="list-inline-item me-2" key={bucket.id}>
|
||||
<span class="badge bg-label-primary my-1">{ bucket.name}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="col-12 col-md-6 d-flex flex-column text-start">
|
||||
{contactProfile?.organization && (
|
||||
<div className="d-flex mb-2">
|
||||
<div style={{ width: "100px", minWidth: "100px" }}>
|
||||
<p className="m-0">Orgnization : </p>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-inline mb-0">
|
||||
<li className="list-inline-item">
|
||||
<i className="fa-solid fa-briefcase me-2"></i>
|
||||
{contactProfile.organization}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{contactProfile?.contactCategory && (
|
||||
<div className="d-flex mb-2">
|
||||
<div style={{ width: "100px", minWidth: "100px" }}>
|
||||
<p className="m-0">Category : </p>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-inline mb-0">
|
||||
<li className="list-inline-item">
|
||||
<i className="bx bx-user bx-xs me-1"></i>
|
||||
{contactProfile.contactCategory.name}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{contactProfile?.buckets?.length > 0 && (
|
||||
<div className="d-flex ">
|
||||
{contactProfile?.contactEmails?.length > 0 && (
|
||||
<div className="d-flex mb-2 align-items-center">
|
||||
<div style={{ width: "100px", minWidth: "100px" }}>
|
||||
<p className="m-0">Buckets : </p>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-inline mb-0">
|
||||
{contactProfile.buckets.map((bucket) => (
|
||||
<li className="list-inline-item me-2" key={bucket.id}>
|
||||
<span className="badge bg-label-primary my-1">
|
||||
{bucket.name}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{contactProfile?.projects?.length > 0 && (
|
||||
<div className="d-flex mb-2 align-items-start">
|
||||
<div style={{ minWidth: "100px" }}>
|
||||
<p className="m-0 text-start">Projects :</p>
|
||||
</div>
|
||||
<div className="text-start">
|
||||
<ul className="list-inline mb-0">
|
||||
{contactProfile.projects.map((project, index) => (
|
||||
<li className="list-inline-item me-2" key={project.id}>
|
||||
{project.name}
|
||||
{index < contactProfile.projects.length - 1 && ","}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="p-3 alert alert-secondary text-small text-start rounded muted">
|
||||
<small className="fw-130">
|
||||
{displayText}
|
||||
{isLong && (
|
||||
<span
|
||||
onClick={toggleReadMore}
|
||||
className="text-primary mx-1 cursor-pointer"
|
||||
>
|
||||
{expanded ? "Read less" : "Read more"}
|
||||
</span>
|
||||
)}
|
||||
</small>
|
||||
</div>
|
||||
<hr className="my-1" />
|
||||
<NotesDirectory
|
||||
refetchProfile={refetch}
|
||||
isLoading={loading}
|
||||
contactProfile={profileContact}
|
||||
setProfileContact={setProfileContact}
|
||||
|
@ -387,13 +387,10 @@ await submitContact({ ...cleaned, id: existingContact.id });
|
||||
)}
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-md-12 mt-1 text-start">
|
||||
<div className="col-md-12 mt-1 text-start">
|
||||
<label className="form-label ">Select Label</label>
|
||||
|
||||
<ul
|
||||
className="d-flex flex-wrap px-1 list-unstyled mb-0"
|
||||
|
||||
>
|
||||
<ul className="d-flex flex-wrap px-1 list-unstyled mb-0">
|
||||
{bucketsLoaging && <p>Loading...</p>}
|
||||
{buckets?.map((item) => (
|
||||
<li
|
||||
@ -417,11 +414,12 @@ await submitContact({ ...cleaned, id: existingContact.id });
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
{errors.bucketIds && (
|
||||
<small className="danger-text mt-0">
|
||||
{errors.bucketIds.message}
|
||||
</small>
|
||||
)}
|
||||
</ul>
|
||||
|
||||
{errors.BucketIds && (
|
||||
<small className="text-danger">{errors.BucketIds.message}</small>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -3,7 +3,7 @@ const Footer = () => {
|
||||
<>
|
||||
<footer className="content-footer footer bg-footer-theme">
|
||||
<div className="container-xxl d-flex flex-wrap justify-content-between py-2 flex-md-row flex-column">
|
||||
<div className="mb-2 mb-md-0" style={{width: "100%", textAlign: "right"}}>
|
||||
<div className="mb-2 mb-md-0 small-text" style={{width: "100%", textAlign: "right"}}>
|
||||
© {new Date().getFullYear()}
|
||||
, by <a href="https://marcosolutions.co.in/" target="_blank" className="font-weight-light footer-link">MARCO AIoT Technologies Pvt. Ltd.</a>
|
||||
</div>
|
||||
|
@ -60,7 +60,7 @@ useEffect(() => {
|
||||
};
|
||||
|
||||
const handleInputKeyDown = (e) => {
|
||||
if (e.key === "Enter" && input.trim() !== "") {
|
||||
if ((e.key === "Enter" || e.key === " ")&& input.trim() !== "") {
|
||||
e.preventDefault();
|
||||
const existing = options.find(
|
||||
(opt) => opt.name.toLowerCase() === input.trim().toLowerCase()
|
||||
|
@ -29,21 +29,22 @@ const Editor = ({
|
||||
"code-block",
|
||||
"link",
|
||||
"align",
|
||||
"image"
|
||||
"image",
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="editor-wrapper">
|
||||
<div id="custom-toolbar" className="ql-toolbar ql-snow custom-toolbar">
|
||||
<div id="custom-toolbar" className="ql-toolbar ql-snow custom-toolbar">
|
||||
<div className="d-flex justify-content-between align-items-center w-100">
|
||||
{/* Left: Quill Format Buttons */}
|
||||
<span className="d-flex">
|
||||
<span className="ql-formats">
|
||||
<select className="ql-header">
|
||||
<select className="ql-header" defaultValue="">
|
||||
<option value="1" />
|
||||
<option value="2" />
|
||||
<option selected />
|
||||
<option value="" />
|
||||
</select>
|
||||
|
||||
<button className="ql-bold" />
|
||||
<button className="ql-italic" />
|
||||
<button className="ql-underline" />
|
||||
@ -60,8 +61,6 @@ const Editor = ({
|
||||
<button className="ql-link" />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<ReactQuill
|
||||
@ -72,21 +71,24 @@ const Editor = ({
|
||||
theme="snow"
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
{/* Right: Submit + Cancel Buttons */}
|
||||
<div className="d-flex justify-content-end gap-2 p-1">
|
||||
<span className="btn btn-xs btn-secondary" aria-disabled={loading} onClick={onCancel}>
|
||||
Cancel
|
||||
</span>
|
||||
<span
|
||||
type="submit"
|
||||
className="btn btn-xs btn-primary"
|
||||
onClick={onSubmit}
|
||||
aria-disabled={loading}
|
||||
>
|
||||
{loading ? "Please Wait..." : "Submit"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Right: Submit + Cancel Buttons */}
|
||||
<div className="d-flex justify-content-end gap-2 p-1">
|
||||
<span
|
||||
className="btn btn-xs btn-secondary"
|
||||
aria-disabled={loading}
|
||||
onClick={onCancel}
|
||||
>
|
||||
Cancel
|
||||
</span>
|
||||
<span
|
||||
type="submit"
|
||||
className="btn btn-xs btn-primary"
|
||||
onClick={onSubmit}
|
||||
aria-disabled={loading}
|
||||
>
|
||||
{loading ? "Please Wait..." : "Submit"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -23,11 +23,6 @@
|
||||
"text": "Employees",
|
||||
"available": true,
|
||||
"link": "/employees"
|
||||
},
|
||||
{
|
||||
"text": "Directory",
|
||||
"available": true,
|
||||
"link": "/directory"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -68,6 +63,12 @@
|
||||
"link": "/activities/gallary"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "Directory",
|
||||
"icon": "bx bx-folder",
|
||||
"available": true,
|
||||
"link": "/directory"
|
||||
},
|
||||
{
|
||||
"text": "Administration",
|
||||
|
@ -72,14 +72,12 @@ export const useBuckets = () => {
|
||||
};
|
||||
|
||||
export const useContactProfile = (id) => {
|
||||
const [conatProfile, setContactProfile] = useState(null);
|
||||
const [contactProfile, setContactProfile] = useState(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [Error, setError] = useState("");
|
||||
|
||||
const fetchContactProfile = async () => {
|
||||
const cached = getCachedData("Contact Profile");
|
||||
|
||||
if (!cached || cached.contactId !== id) {
|
||||
setLoading(true);
|
||||
try {
|
||||
const resp = await DirectoryRepository.GetContactProfile(id);
|
||||
@ -94,18 +92,20 @@ export const useContactProfile = (id) => {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
useEffect( () =>
|
||||
{
|
||||
const cached = getCachedData("Contact Profile");
|
||||
if (!cached || cached.contactId !== id) {
|
||||
fetchContactProfile(id);
|
||||
} else {
|
||||
setContactProfile(cached.data);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
fetchContactProfile(id);
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
return { conatProfile, loading, Error };
|
||||
return { contactProfile, loading, Error ,refetch:fetchContactProfile};
|
||||
};
|
||||
|
||||
export const useContactNotes = (id, IsActive) => {
|
||||
@ -113,10 +113,9 @@ export const useContactNotes = (id, IsActive) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [Error, setError] = useState("");
|
||||
|
||||
const fetchContactNotes = async () => {
|
||||
const cached = getCachedData("Contact Notes");
|
||||
const fetchContactNotes = async (id,IsActive) => {
|
||||
|
||||
|
||||
if (!cached || cached.contactId !== id) {
|
||||
setLoading(true);
|
||||
try {
|
||||
const resp = await DirectoryRepository.GetNote(id, IsActive);
|
||||
@ -131,18 +130,19 @@ export const useContactNotes = (id, IsActive) => {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
} else {
|
||||
setContactNotes(cached.data);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
fetchContactNotes(id);
|
||||
const cached = getCachedData("Contact Notes");
|
||||
if (!cached || cached.contactId !== id) {
|
||||
id && fetchContactNotes(id,IsActive);
|
||||
} else {
|
||||
setContactNotes(cached.data);
|
||||
}
|
||||
}, [id]);
|
||||
}, [id,IsActive]);
|
||||
|
||||
return { contactNotes, loading, Error };
|
||||
return { contactNotes, loading, Error,refetch:fetchContactNotes };
|
||||
};
|
||||
|
||||
export const useOrganization = () => {
|
||||
|
@ -19,6 +19,7 @@ import DirectoryListTableHeader from "./DirectoryListTableHeader";
|
||||
import DirectoryPageHeader from "./DirectoryPageHeader";
|
||||
import ManageBucket from "../../components/Directory/ManageBucket";
|
||||
import {useFab} from "../../Context/FabContext";
|
||||
import {DireProvider, useDir} from "../../Context/DireContext";
|
||||
|
||||
const Directory = () =>
|
||||
{
|
||||
@ -33,12 +34,15 @@ const Directory = () =>
|
||||
const [listView, setListView] = useState(false);
|
||||
const [selectedBucketIds, setSelectedBucketIds] = useState([]);
|
||||
const [deleteContact, setDeleteContact] = useState(null);
|
||||
const [ IsDeleting, setIsDeletng ] = useState( false );
|
||||
const [openBucketModal,setOpenBucketModal] = useState(false)
|
||||
const [ IsDeleting, setDeleting ] = useState( false );
|
||||
const [ openBucketModal, setOpenBucketModal ] = useState( false )
|
||||
|
||||
|
||||
const [tempSelectedBucketIds, setTempSelectedBucketIds] = useState([]);
|
||||
const [ tempSelectedCategoryIds, setTempSelectedCategoryIds ] = useState( [] );
|
||||
const {setActions} = useFab()
|
||||
const {setActions} = useFab()
|
||||
const { dirActions, setDirActions } = useDir();
|
||||
|
||||
|
||||
const { contacts, loading , refetch} = useDirectory(IsActive);
|
||||
const { contactCategory, loading: contactCategoryLoading } =
|
||||
@ -78,28 +82,43 @@ const Directory = () =>
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteContact = async () => {
|
||||
try {
|
||||
setIsDeletng(true);
|
||||
const contacts_cache = getCachedData("contacts")?.data || [];
|
||||
|
||||
const response = await DirectoryRepository.DeleteContact(deleteContact);
|
||||
const updatedContacts = ContactList.filter( ( c ) => c.id !== deleteContact );
|
||||
setContactList(updatedContacts);
|
||||
cacheData("Contacts", {data:updatedContacts,isActive:IsActive});
|
||||
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 handleDeleteContact = async (overrideId = null) => {
|
||||
try
|
||||
{
|
||||
if (!IsActive) {
|
||||
setDirActions((prev) => ({ ...prev, action: true }));
|
||||
} else {
|
||||
setDeleting(true);
|
||||
}
|
||||
};
|
||||
const id = overrideId || (!IsActive ? dirActions.id : deleteContact);
|
||||
if (!id) {
|
||||
showToast("No contact selected for deletion", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
await DirectoryRepository.DeleteContact(id, !IsActive);
|
||||
|
||||
const updatedContacts = ContactList.filter((c) => c.id !== id);
|
||||
setContactList(updatedContacts);
|
||||
cacheData("Contacts", { data: updatedContacts, isActive: IsActive });
|
||||
|
||||
showToast(`Contact ${IsActive ? "Deleted":"Restored"} successfully`, "success");
|
||||
|
||||
setDeleteContact(null);
|
||||
setDirActions({ action: false, id: null });
|
||||
setDeleting(false);
|
||||
} catch (error) {
|
||||
const msg =
|
||||
error?.response?.data?.message ||
|
||||
error.message ||
|
||||
"Error occurred during API call";
|
||||
showToast(msg, "error");
|
||||
|
||||
setDeleting(false);
|
||||
setDirActions({ action: false, id: null });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const closedModel = () => {
|
||||
setIsOpenModal(false);
|
||||
@ -306,7 +325,6 @@ const Directory = () =>
|
||||
applyFilter={applyFilter}
|
||||
loading={loading}
|
||||
IsActive={IsActive}
|
||||
setIsOpenModal={setIsOpenModal}
|
||||
setOpenBucketModal={setOpenBucketModal}
|
||||
/>
|
||||
{!listView && loading && <p>Loading...</p>}
|
||||
@ -314,7 +332,7 @@ const Directory = () =>
|
||||
<p>No Matching Contact Found</p>
|
||||
)}
|
||||
{listView ? (
|
||||
<DirectoryListTableHeader IsActive={IsActive}>
|
||||
<DirectoryListTableHeader>
|
||||
{loading && (
|
||||
<tr>
|
||||
<td colSpan={10}>Loading...</td>
|
||||
@ -336,6 +354,7 @@ const Directory = () =>
|
||||
setOpen_contact={setOpen_contact}
|
||||
setIsOpenModalNote={setIsOpenModalNote}
|
||||
IsDeleted={setDeleteContact}
|
||||
restore={handleDeleteContact}
|
||||
/>
|
||||
))}
|
||||
</DirectoryListTableHeader>
|
||||
@ -354,15 +373,16 @@ const Directory = () =>
|
||||
setOpen_contact={setOpen_contact}
|
||||
setIsOpenModalNote={setIsOpenModalNote}
|
||||
IsDeleted={setDeleteContact}
|
||||
restore={handleDeleteContact}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{!loading && currentItems < ITEMS_PER_PAGE && (
|
||||
{!loading && currentItems < ITEMS_PER_PAGE && (
|
||||
<nav aria-label="Page ">
|
||||
<ul className="pagination pagination-sm justify-content-end py-1">
|
||||
<li
|
||||
@ -406,7 +426,7 @@ const Directory = () =>
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
import React from 'react'
|
||||
import IconButton from '../../components/common/IconButton';
|
||||
import React from "react";
|
||||
import IconButton from "../../components/common/IconButton";
|
||||
|
||||
|
||||
const DirectoryListTableHeader = ( {children, IsActive} ) =>
|
||||
{
|
||||
const DirectoryListTableHeader = ({ children }) => {
|
||||
return (
|
||||
<div className="table-responsive text-nowrap py-2">
|
||||
<table className="table px-2">
|
||||
<thead>
|
||||
<tr>
|
||||
<tr>
|
||||
<th colSpan={2}>
|
||||
<div className="d-flex align-items-center gap-1">
|
||||
<span>Name</span>
|
||||
@ -25,13 +23,10 @@ const DirectoryListTableHeader = ( {children, IsActive} ) =>
|
||||
</div>
|
||||
</th>
|
||||
<th colSpan={2} className="mx-2 ps-20">
|
||||
|
||||
|
||||
Organization
|
||||
|
||||
Organization
|
||||
</th>
|
||||
<th className="mx-2">Category</th>
|
||||
{IsActive && <th>Action</th>}
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="table-border-bottom-0 overflow-auto">
|
||||
@ -41,4 +36,4 @@ const DirectoryListTableHeader = ( {children, IsActive} ) =>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default DirectoryListTableHeader;
|
||||
export default DirectoryListTableHeader;
|
||||
|
@ -16,7 +16,6 @@ const DirectoryPageHeader = ({
|
||||
applyFilter,
|
||||
loading,
|
||||
IsActive,
|
||||
setIsOpenModal,
|
||||
setOpenBucketModal,
|
||||
}) => {
|
||||
const [filtered, setFiltered] = useState();
|
||||
@ -99,7 +98,7 @@ const DirectoryPageHeader = ({
|
||||
<div className="d-flex flex-wrap">
|
||||
{filteredBuckets.map(({ id, name }) => (
|
||||
<div
|
||||
className="form-check me-1 mb-1"
|
||||
className="form-check me-3 mb-1"
|
||||
style={{ minWidth: "33.33%" }}
|
||||
key={id}
|
||||
>
|
||||
@ -127,7 +126,7 @@ const DirectoryPageHeader = ({
|
||||
<div className="d-flex flex-wrap">
|
||||
{filteredCategories.map(({ id, name }) => (
|
||||
<div
|
||||
className="form-check me-1 mb-1"
|
||||
className="form-check me-3 mb-1"
|
||||
style={{ minWidth: "33.33%" }}
|
||||
key={id}
|
||||
>
|
||||
@ -169,38 +168,10 @@ const DirectoryPageHeader = ({
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-md-8 mb-2 px-1 d-flex justify-content-end gap-2 align-items-center text-end">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm btn-primary"
|
||||
onClick={() => setIsOpenModal(true)}
|
||||
>
|
||||
<i className="bx bx-plus-circle me-2"></i>
|
||||
New Contact
|
||||
</button>
|
||||
|
||||
<div className={`dropdown `}>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-xs btn-icon btn-text-secondary rounded-pill dropdown-toggle hide-arrow p-0 m-0"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i
|
||||
className="bx bx-dots-vertical-rounded bx-md text-muted "
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-offset="0,8"
|
||||
data-bs-placement="top"
|
||||
data-bs-custom-class="tooltip-dark"
|
||||
title="More Action"
|
||||
></i>
|
||||
</button>
|
||||
<ul className="dropdown-menu dropdown-menu-end w-auto">
|
||||
<li>
|
||||
<a className="dropdown-item px-2 ">
|
||||
<label className="switch switch-primary align-self-start mb-2">
|
||||
<label className="switch switch-primary align-self-start mb-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="switch-input"
|
||||
className="switch-input me-3"
|
||||
onChange={() => setIsActive(!IsActive)}
|
||||
value={IsActive}
|
||||
disabled={loading}
|
||||
@ -209,23 +180,10 @@ const DirectoryPageHeader = ({
|
||||
<span className="switch-on"></span>
|
||||
<span className="switch-off"></span>
|
||||
</span>
|
||||
<span className=" list-inline-item ">
|
||||
<span className=" list-inline-item ms-12 small-text">
|
||||
Show Inactive Contacts
|
||||
</span>
|
||||
</label>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="dropdown-item cursor-pointer px-2 "
|
||||
onClick={() => setOpenBucketModal(true)}
|
||||
>
|
||||
<i className="fa-solid fa-bucket fs-5 me-4"></i>
|
||||
<span className="align-left">Manage Buckets</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
@ -6,7 +6,7 @@ export const DirectoryRepository = {
|
||||
GetContacts: (isActive) => api.get( `/api/directory?active=${isActive}` ),
|
||||
CreateContact: ( data ) => api.post( '/api/directory', data ),
|
||||
UpdateContact: ( id, data ) => api.put( `/api/directory/${ id }`, data ),
|
||||
DeleteContact: ( id ) => api.delete( `/api/directory/${ id }` ),
|
||||
DeleteContact: ( id,isActive) => api.delete( `/api/directory/${ id }/?active=${isActive}` ),
|
||||
AssignedBuckets:(id,data)=>api.post(`/api/directory/assign-bucket/${id}`,data),
|
||||
|
||||
GetBucktes: () => api.get( `/api/directory/buckets` ),
|
||||
@ -19,5 +19,5 @@ export const DirectoryRepository = {
|
||||
CreateNote: ( data ) => api.post( '/api/directory/note', data ),
|
||||
GetNote: ( id,isActive ) => api.get( `/api/directory/notes/${ id }?active=${isActive}` ),
|
||||
UpdateNote: ( id, data ) => api.put( `/api/directory/note/${ id }`, data ),
|
||||
DeleteNote:(id)=> api.delete(`/api/directory/note/${ id }`)
|
||||
DeleteNote:(id,isActive)=> api.delete(`/api/directory/note/${ id }?active=${isActive}`)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user