updated PmsEmployeeInputTag for getting all exiten employee for update
This commit is contained in:
parent
b68f8306fd
commit
937531afb6
@ -1,7 +1,7 @@
|
|||||||
import { useState, useEffect, useRef, useMemo } from "react";
|
import { useState, useEffect, useRef, useMemo } from "react";
|
||||||
import { useController } from "react-hook-form";
|
import { useController } from "react-hook-form";
|
||||||
import { useDebounce } from "../../utils/appUtils";
|
import { useDebounce } from "../../utils/appUtils";
|
||||||
import { useEmployeesName } from "../../hooks/useEmployees";
|
import { useEmployeesName, useUserCache } from "../../hooks/useEmployees";
|
||||||
import Avatar from "./Avatar";
|
import Avatar from "./Avatar";
|
||||||
|
|
||||||
const PmsEmployeeInputTag = ({
|
const PmsEmployeeInputTag = ({
|
||||||
@ -11,16 +11,17 @@ const PmsEmployeeInputTag = ({
|
|||||||
projectId,
|
projectId,
|
||||||
forAll,
|
forAll,
|
||||||
isApplicationUser = false,
|
isApplicationUser = false,
|
||||||
disabled
|
disabled,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
field: { value = [], onChange },
|
field: { value = [], onChange },
|
||||||
} = useController({ name, control });
|
} = useController({ name, control });
|
||||||
|
|
||||||
|
const { getUser, addToCache, userCache } = useUserCache();
|
||||||
|
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [showDropdown, setShowDropdown] = useState(false);
|
const [showDropdown, setShowDropdown] = useState(false);
|
||||||
const [filteredUsers, setFilteredUsers] = useState([]);
|
const [filteredUsers, setFilteredUsers] = useState([]);
|
||||||
const [userCache, setUserCache] = useState({});
|
|
||||||
const dropdownRef = useRef(null);
|
const dropdownRef = useRef(null);
|
||||||
const inputRef = useRef(null);
|
const inputRef = useRef(null);
|
||||||
const activeIndexRef = useRef(-1);
|
const activeIndexRef = useRef(-1);
|
||||||
@ -32,26 +33,28 @@ const PmsEmployeeInputTag = ({
|
|||||||
forAll
|
forAll
|
||||||
);
|
);
|
||||||
|
|
||||||
// Keep both filtered list and cache updated
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (employees?.data?.length) {
|
if (employees?.data?.length) {
|
||||||
setFilteredUsers(employees.data);
|
setFilteredUsers(employees.data);
|
||||||
activeIndexRef.current = -1;
|
activeIndexRef.current = -1;
|
||||||
|
|
||||||
// cache all fetched users by id
|
employees.data.forEach((u) => addToCache(u.id, u));
|
||||||
setUserCache((prev) => {
|
|
||||||
const updated = { ...prev };
|
|
||||||
employees.data.forEach((u) => {
|
|
||||||
updated[u.id] = u;
|
|
||||||
});
|
|
||||||
return updated;
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
setFilteredUsers([]);
|
setFilteredUsers([]);
|
||||||
}
|
}
|
||||||
}, [employees]);
|
}, [employees]);
|
||||||
|
|
||||||
// close dropdown when clicking outside
|
// load selected employees not in filtered list
|
||||||
|
useEffect(() => {
|
||||||
|
if (!Array.isArray(value) || value.length === 0) return;
|
||||||
|
|
||||||
|
value.forEach(async (id) => {
|
||||||
|
if (!userCache[id]) {
|
||||||
|
await getUser(id); // fetch and cache
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onDocClick = (e) => {
|
const onDocClick = (e) => {
|
||||||
if (
|
if (
|
||||||
@ -66,7 +69,6 @@ const PmsEmployeeInputTag = ({
|
|||||||
return () => document.removeEventListener("mousedown", onDocClick);
|
return () => document.removeEventListener("mousedown", onDocClick);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// select a user
|
|
||||||
const handleSelect = (user) => {
|
const handleSelect = (user) => {
|
||||||
if (value.includes(user.id)) return;
|
if (value.includes(user.id)) return;
|
||||||
const updated = [...value, user.id];
|
const updated = [...value, user.id];
|
||||||
@ -76,13 +78,11 @@ const PmsEmployeeInputTag = ({
|
|||||||
setTimeout(() => inputRef.current?.focus(), 0);
|
setTimeout(() => inputRef.current?.focus(), 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
// remove selected user
|
|
||||||
const handleRemove = (id) => {
|
const handleRemove = (id) => {
|
||||||
const updated = value.filter((uid) => uid !== id);
|
const updated = value.filter((uid) => uid !== id);
|
||||||
onChange(updated);
|
onChange(updated);
|
||||||
};
|
};
|
||||||
|
|
||||||
// keyboard navigation
|
|
||||||
const onInputKeyDown = (e) => {
|
const onInputKeyDown = (e) => {
|
||||||
if (!showDropdown) return;
|
if (!showDropdown) return;
|
||||||
const max = Math.max(0, filteredUsers.length - 1);
|
const max = Math.max(0, filteredUsers.length - 1);
|
||||||
@ -103,7 +103,6 @@ const PmsEmployeeInputTag = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// scroll active dropdown item into view
|
|
||||||
const scrollToActive = () => {
|
const scrollToActive = () => {
|
||||||
const wrapper = dropdownRef.current?.querySelector(
|
const wrapper = dropdownRef.current?.querySelector(
|
||||||
".tagify__dropdown__wrapper"
|
".tagify__dropdown__wrapper"
|
||||||
@ -120,24 +119,21 @@ const PmsEmployeeInputTag = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// resolve user details by ID (for rendering tags)
|
// ⬆️ FIX: allow null (not found yet)
|
||||||
const resolveUserById = (id) => {
|
const resolveUserById = (id) => {
|
||||||
return userCache[id] || filteredUsers.find((u) => u.id === id);
|
return userCache[id] || filteredUsers.find((u) => u.id === id) || null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// main visible users list (memoized)
|
|
||||||
const visibleUsers = useMemo(() => {
|
const visibleUsers = useMemo(() => {
|
||||||
const baseList = isApplicationUser
|
const baseList = isApplicationUser
|
||||||
? (filteredUsers || []).filter((u) => u?.email)
|
? (filteredUsers || []).filter((u) => u?.email)
|
||||||
: filteredUsers || [];
|
: filteredUsers || [];
|
||||||
|
|
||||||
// also include selected users even if missing from current API
|
|
||||||
const selectedUsers =
|
const selectedUsers =
|
||||||
Array.isArray(value) && value.length
|
Array.isArray(value) && value.length
|
||||||
? value.map((uid) => userCache[uid]).filter(Boolean)
|
? value.map((uid) => userCache[uid]).filter(Boolean)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
// merge unique
|
|
||||||
const merged = [
|
const merged = [
|
||||||
...selectedUsers,
|
...selectedUsers,
|
||||||
...baseList.filter((u) => !selectedUsers.some((s) => s.id === u.id)),
|
...baseList.filter((u) => !selectedUsers.some((s) => s.id === u.id)),
|
||||||
@ -148,10 +144,9 @@ const PmsEmployeeInputTag = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="tagify form-control d-flex align-items-center flex-wrap position-relative "
|
className="tagify form-control d-flex align-items-center flex-wrap position-relative"
|
||||||
ref={dropdownRef}
|
ref={dropdownRef}
|
||||||
>
|
>
|
||||||
{/* Selected tags (chips) */}
|
|
||||||
{value.map((id) => {
|
{value.map((id) => {
|
||||||
const u = resolveUserById(id);
|
const u = resolveUserById(id);
|
||||||
if (!u) return null;
|
if (!u) return null;
|
||||||
@ -190,8 +185,6 @@ const PmsEmployeeInputTag = ({
|
|||||||
type="button"
|
type="button"
|
||||||
className="tagify__tag__removeBtn border-none"
|
className="tagify__tag__removeBtn border-none"
|
||||||
onClick={() => handleRemove(id)}
|
onClick={() => handleRemove(id)}
|
||||||
aria-label={`Remove ${u.firstName}`}
|
|
||||||
title="Remove"
|
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user