Im working on some code thats using react hook form to capture input states and im not exactly sure why when I type into the input, specifically the one with the placeholder text of “Or search for a contact type by name…” , i dont see the input box populating with any characters, i basically type into it and it stays blank. Ive tried console.log(watch(“searchValue”)) but im just getting blank spaces in the console. Any idea whats going on here? it seems the register function in the form input isnt actually capturing the value
/* eslint-disable react-hooks/exhaustive-deps */
export default function Home() {
const ref = useRef<HTMLDivElement>(null);
const user = useAuthUser();
const depts = useDepts();
const [currentTab, setCurrentTab] = useState("My Contacts");
const [isAllDepts, setIsAllDepts] = useState(false);
const [selectedSchoolId, setSelectedSchoolId] = useState(user.DeptId);
const [selectedContactType, setSelectedContactType] = useState<ContactType | null>();
const [showModalEmplSearch, setShowModalEmplSearch] = useState(false);
const [showModalEditContact, setShowModalEditContact] = useState(false);
const [showModalExempt, setShowModalExempt] = useState(false);
const [selectedContact, setSelectedContact] = useState(initContact);
const syncContacts = useSyncContacts(selectedSchoolId);
const contactTypes = useContactTypesAppliesTo(selectedSchoolId);
const allContactTypes = useContactTypes();
const contacts = useContactsByDeptType(selectedSchoolId, selectedContactType?.PkId ?? 0);
const allContactsFromAllTypes = useContactsByDept(selectedSchoolId);
const contactsByType = useContactsbyType(selectedContactType?.PkId ?? 0);
const upsertContact = useUpsertContact();
const deleteContact = useDeleteContact();
const deleteExemption = useDeleteExemption();
const { register, watch, reset, setValue } = useForm();
console.log(watch("searchValue"));
const [isHoveredContacts, setIsHoveredContacts] = useState(false);
const [isHoveredRequested, setIsHoveredRequested] = useState(false);
const [isHoveredLookup, setIsHoveredLookup] = useState(false);
const [isHoveredGlobal, setIsHoveredGlobal] = useState(false);
const [tab, setTab] = useState("");
const handleIconMouseEnter = (e: any) => {
const tabName = e.target.parentElement.innerText.trim(); // Get the tab name from the parent element
if (tabName === "My Contacts") {
setIsHoveredContacts(true);
setTab(tabName);
} else if (tabName === "Requested Contacts") {
setIsHoveredRequested(true);
setTab(tabName);
} else if (tabName === "Contact Lookup") {
setIsHoveredLookup(true);
setTab(tabName);
} else if (tabName === "Global Search") {
setIsHoveredGlobal(true);
setTab(tabName);
setSelectedSchoolId(selectedSchoolId ?? user.DeptId);
}
};
const handleMouseLeave = (tabName: string) => {
if (tabName === "My Contacts") {
setIsHoveredContacts(false);
} else if (tabName === "Requested Contacts") {
setIsHoveredRequested(false);
} else if (tabName === "Contact Lookup") {
setIsHoveredLookup(false);
} else if (tabName === "Global Search") {
setIsHoveredGlobal(false);
}
};
useEffect(() => {
if (currentTab === "lookup") {
setIsAllDepts(true);
setSelectedContactType(null);
setSelectedSchoolId(selectedSchoolId ?? user.DeptId);
setValue("hasIssues", false);
} else if (currentTab === "Requested contacts") {
setSelectedContactType(null);
setSelectedSchoolId(selectedSchoolId ?? user.DeptId);
setValue("hasIssues", false);
setIsAllDepts(false);
} else if (currentTab === "My Contacts") {
setSelectedContactType(null);
setSelectedSchoolId(selectedSchoolId ?? user.DeptId);
setValue("hasIssues", false);
setIsAllDepts(false);
contactTypes.refetch();
} else if (currentTab === "Global Search") {
setIsAllDepts(true);
setSelectedContactType(null);
setSelectedSchoolId(selectedSchoolId ?? user.DeptId);
setValue("hasIssues", false);
}
}, [currentTab]);
// When a user first logs in, run the sync service to make sure the dept is in sync
useEffect(() => {
sync();
}, []);
// If the URL has "/issues" on first page load,
// then automatically check the box to show contact types with issues
useEffect(() => {
if (window.location.pathname.includes("issues")) {
setValue("hasIssues", true);
}
}, []);
// Every time an impersonation happens, just reset the selectedSchoolId
useEffect(() => setSelectedSchoolId(user.DeptId), [user]);
/** Call the sync service to sync the contacts with the DB */
const sync = async () => {
await syncContacts.refetch();
await contactTypes.refetch();
};
/** Handles what happens when the "View all departments" checkbox is enabled/disabled */
const handleIsAllDeptsCheckBox = () => {
setIsAllDepts(!isAllDepts);
setSelectedContactType(null);
setSelectedSchoolId(user.DeptId);
setValue("hasIssues", false);
};
const deptsRequesting = [
...new Set(
(isAllDepts ? allContactTypes.data : contactTypes.data)?.map((ct) => ct.Department.DeptName),
),
].sort((a, b) => (a > b ? 1 : -1));
const filteredContactTypes = (isAllDepts ? allContactTypes.data : contactTypes.data)?.filter(
(ct) => (watch("selectedDepts") ?? []).includes(ct.Department.DeptName),
);
/** Checks if the array of issues from a contact type includes one of the `statusIssues` elements */
const checkIfStatusIssue = (issues: ContactStatus[]) => {
for (const i of issues) if (statusIssues.includes(i)) return true;
};
const getContactTypes = () =>
(!watch("selectedDepts") || watch("selectedDepts").length === 0
? (isAllDepts ? allContactTypes.data : contactTypes.data) ?? []
: filteredContactTypes
)?.filter((ct) => ct.Title.toLowerCase().includes((watch("searchValue") ?? "").toLowerCase()));
const getAllContacts = () =>
(watch("searchValue").length === 0
? allContactsFromAllTypes.data
: allContactsFromAllTypes?.data?.filter((x) =>
x.ContactType.Title.toLowerCase().includes((watch("searchValue") ?? "").toLowerCase()),
)) ?? [];
const getDepts = () =>
(watch("searchValue").length === 0
? allContactsFromAllTypes.data
: allContactsFromAllTypes?.data?.filter((x) =>
x.ContactType.Title.toLowerCase().includes((watch("searchValue") ?? "").toLowerCase()),
)) ?? [];
// const getAllContacts = () =>
// watch("searchValue") === ""
// ? allContactsFromAllTypes?.data ?? []
// : allContactsFromAllTypes?.data?.filter((ct) =>
// ct.ContactEmployee.JobTitle.toLowerCase().includes(
// (watch("searchValue") ?? "").toLowerCase(),
// ),
// ) ?? [];
const handleRemoveExemption = async () => {
const path = `${Methods.Exemptions}/${selectedContactType?.PkId}/${selectedSchoolId}`;
const exemption = await queryClient.fetchQuery<Exemption>("exemption", () => API.Get(path));
await deleteExemption.mutateAsync(exemption.PkExemptionId ?? "");
await toast.promise(sync(), {
loading: "Removing exemption...",
success: `Successfully removed the exemption for ${selectedContactType?.Title}!`,
error: "Could not remove the exemption.",
});
const updatedCt = await queryClient.fetchQuery<ContactType[]>([
`${Methods.ContactTypesAppliesToDept}/${selectedSchoolId}`,
]);
setSelectedContactType(updatedCt.find((ct) => ct.PkId === selectedContactType?.PkId));
};
const handleAddContact = async (emp: Employee) => {
setShowModalEmplSearch(false);
const postData: ContactPostModel = {
ContactTypeId: selectedContactType?.PkId ?? 0,
DeptId: selectedSchoolId,
ContactEmplId: emp.EmplId,
ContactStatus: ContactStatus.Ok,
};
if (selectedContact.PkId) postData.PkId = selectedContact.PkId;
await upsertContact.mutateAsync(postData);
setSelectedContact(initContact);
contacts.refetch();
contactTypes.refetch();
toast.success(
`Successfully added ${emp.FirstName} ${emp.LastName} as a new contact for "${selectedContactType?.Title}"`,
);
};
const handleDeleteContact = async (c: Contact) => {
await deleteContact.mutateAsync(c.PkId ?? "");
contacts.refetch();
await toast.promise(sync(), {
loading: "Deleting contact...",
success: `Successfully removed ${c.ContactEmployee.FirstName} ${c.ContactEmployee.LastName} as a contact for ${selectedContactType?.Title}`,
error: "Could not delete this contact.",
});
};
function handleClick(e: any) {
setCurrentTab(e);
//result will be the eventKey of the tab you clicked on.
// `homeTab` (when clicked on home tab)
// `profileTab` (when clicked on profile tab)
// `constactTab` (when clicked on Contact tab)
}
const contactsTooltip = (
<Tooltip id="contacts-tooltip">Manage contacts for your school or department</Tooltip>
);
const requestedContactsTooltip = (
<Tooltip id="requested-contacts-tooltip">
Manage the contact types that are related to your department
</Tooltip>
);
const contactLookupTooltip = (
<Tooltip id="contact-lookup-tooltip">Lookup and export contacts</Tooltip>
);
return (
<div>
<Helmet>
<title>Points of Contact</title>
</Helmet>
<p>
<span style={{ fontWeight: "bold", fontSize: "2rem" }}>
{selectedSchoolId &&
`Viewing ${
isAllDepts
? "All Departments"
: getDeptName(depts.data, selectedSchoolId, user.Department)
}`}
</span>
</p>
<hr />
<ExportContacts
contacts={allContactsFromAllTypes.data ?? []}
title={getDeptName(depts.data, selectedSchoolId, user.Department)}
isEntireList
/>
<br />
<Tabs
defaultActiveKey="profile"
id="justify-tab-example"
className="mb-3"
style={{ marginTop: "20px" }}
onSelect={(e) => handleClick(e)}
activeKey={currentTab}
>
<Tab
eventKey="My Contacts"
title={
<span style={{ position: "relative", display: "inline-block" }}>
My Contacts
<OverlayTrigger placement="top" overlay={contactsTooltip} show={isHoveredContacts}>
<i
className="fa-solid fa-circle-info"
style={{ marginLeft: "10px", color: "#3870c9" }}
onMouseEnter={handleIconMouseEnter}
onMouseLeave={() => handleMouseLeave(tab)}
/>
</OverlayTrigger>
</span>
}
>
<Row style={{ backgroundColor: "#F5F5F5", padding: 20, borderRadius: 10 }}>
<Col md={4}>
<div>
<h3>My Contacts</h3>
<div id="contact-type-filter" style={{ marginBottom: "0.5rem" }}>
<i style={{ color: "#727272" }}>Manage contacts for your school or department.</i>{" "}
<Dropdown
autoClose="outside"
style={{
cursor: "pointer",
}}
>
<Dropdown.Toggle
id="filter-text"
as="span"
style={{
paddingLeft: 8,
paddingRight: 8,
}}
title="More options"
>
<i className="fa-solid fa-filter p-1" />
Dept Filter
</Dropdown.Toggle>
<Dropdown.Menu>
<label style={{ padding: "2px 14px", textAlign: "center" }}>
Filter by the department(s) requesting these contact types
</label>
<Button
variant="outline-primary"
style={{
display: "flex",
justifyContent: "center",
padding: "6px 0px",
width: "80%",
margin: "0 auto",
}}
onClick={() => reset()}
>
Reset Filters
</Button>
<Dropdown.Divider />
<Form.Group
style={{
padding: "2px 14px",
width: 350,
maxHeight: "25rem",
overflowY: "scroll",
}}
>
{deptsRequesting.map((dept) => (
<Form.Check
key={dept}
label={dept}
value={dept}
{...register("selectedDepts")}
/>
))}
</Form.Group>
</Dropdown.Menu>
</Dropdown>
</div>
{!isAllDepts && (
<Form.Check
style={{ paddingLeft: "2.2rem" }}
label="Show Contact Types With Issues"
{...register("hasIssues")}
/>
)}
<Form>
<Form.Control
placeholder="Or search for a contact type by name..."
{...register("searchValue")}
/>
</Form>
<ListGroup
style={{
borderColor: "#BCBCBC",
height: "30rem",
overflow: "auto",
border: "1px solid #bcbcbc7d",
background: "white",
marginTop: "0.5rem",
}}
>
{contactTypes.isLoading || allContactTypes.isLoading ? (
<ContactTypesLoading />
) : (
(watch("hasIssues")
? getContactTypes()?.filter(
(ct) =>
(ct.HasIssues && !ct.Issues.includes(ContactStatus.Exempted)) ||
(ct.Issues.includes(ContactStatus.Exempted) && ct.MinQty > 0),
)
: getContactTypes()
)?.map((ct) => (
<ListGroup.Item
key={ct.PkId}
onClick={() => {
setSelectedContactType(ct);
ref.current?.scrollIntoView({ behavior: "smooth" });
}}
active={selectedContactType?.PkId === ct.PkId}
style={{ border: "none" }}
action
>
<i
className={`fa-solid fa-circle-${
ct.HasIssues && checkIfStatusIssue(ct.Issues) ? "exclamation" : "check"
}`}
style={{
color: `${
selectedContactType === ct
? "white"
: ct.HasIssues && checkIfStatusIssue(ct.Issues)
? "#8f0a15"
: "green"
}`,
paddingRight: 6,
}}
title={
(ct.Issues ?? []).length > 0
? Object.values(ContactStatusDescr).find(
(c, i) =>
i === ct.Issues[0] && ct.Issues[0] !== ContactStatus.Exempted,
)
: ""
}
/>
<b>{ct.Title}</b>
<br />
<span style={{ fontSize: "0.8rem" }}>
Requested By: {ct.Department.DeptName}
</span>
<br />
{!isAllDepts && (
<span style={{ fontSize: "0.8rem" }}>
Required # of Contacts: {ct.MinQty}
</span>
)}
{(ct.Issues ?? [])?.at(0) === ContactStatus.Exempted && (
<Badge bg="warning" style={{ float: "right" }}>
Exempt
</Badge>
)}
</ListGroup.Item>
))
)}
</ListGroup>
</div>
</Col>