171 lines
5.2 KiB
TypeScript
171 lines
5.2 KiB
TypeScript
import { useForm, SubmitHandler } from 'react-hook-form';
|
|
import { ContactsProps } from '../../pages/Chat.tsx';
|
|
import { axiosClient } from '../../App.tsx';
|
|
import { AxiosResponse } from 'axios';
|
|
import { useEffect, useState } from 'react';
|
|
import LoadingWheel from './LoadingWheel.tsx';
|
|
|
|
type Input = {
|
|
contact: string;
|
|
};
|
|
|
|
type ContactFormProps = {
|
|
InitializeContact: (contact: ContactsProps) => void;
|
|
setContactsList: React.Dispatch<React.SetStateAction<ContactsProps[]>>;
|
|
};
|
|
|
|
function ContactForm({ InitializeContact, setContactsList }: ContactFormProps) {
|
|
const { register, handleSubmit, reset, watch } = useForm<Input>();
|
|
const contactInput = watch('contact');
|
|
const [suggestions, setSuggestions] = useState<string[]>([]);
|
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
const [notFound, setNotFound] = useState<boolean>(false);
|
|
const [selectedIndex, setSelectedIndex] = useState<number>(0);
|
|
|
|
useEffect(() => {
|
|
const fetchSuggestions = async () => {
|
|
if (contactInput?.length >= 3) {
|
|
try {
|
|
setIsLoading(true);
|
|
const response: AxiosResponse<string[]> = await axiosClient.get(
|
|
`/api/chat/contacts/suggestions/${contactInput}`,
|
|
);
|
|
setSuggestions(response.data);
|
|
setSelectedIndex(0); // Reset selection to first item when suggestions update
|
|
if (response.data.length < 1) {
|
|
setIsLoading(false);
|
|
setNotFound(true);
|
|
} else {
|
|
setIsLoading(false);
|
|
setNotFound(false);
|
|
}
|
|
} catch (error) {
|
|
setIsLoading(false);
|
|
console.error('Error fetching suggestions:', error);
|
|
}
|
|
} else {
|
|
setNotFound(false);
|
|
setIsLoading(false);
|
|
setSuggestions([]);
|
|
}
|
|
};
|
|
|
|
const delay = setTimeout(() => {
|
|
fetchSuggestions();
|
|
}, 300);
|
|
|
|
return () => clearTimeout(delay);
|
|
}, [contactInput]);
|
|
|
|
const submitContact: SubmitHandler<Input> = async (data) => {
|
|
const contactToSubmit =
|
|
suggestions.length > 0 ? suggestions[selectedIndex] : data.contact.trim();
|
|
|
|
try {
|
|
setContactsList((prevContacts) => {
|
|
if (prevContacts.some((c) => c.username === contactToSubmit)) {
|
|
return prevContacts;
|
|
}
|
|
return prevContacts;
|
|
});
|
|
|
|
console.log('Submit contact: ', contactToSubmit);
|
|
const response: AxiosResponse<ContactsProps> = await axiosClient.post(
|
|
`/api/chat/contact/${contactToSubmit}`,
|
|
);
|
|
|
|
console.log('contact post response: ', response.data);
|
|
InitializeContact(response.data);
|
|
|
|
setContactsList((prevContacts) => {
|
|
if (!prevContacts.some((c) => c.username === contactToSubmit)) {
|
|
return [...prevContacts, response.data];
|
|
}
|
|
return prevContacts;
|
|
});
|
|
|
|
reset({ contact: '' });
|
|
setSuggestions([]);
|
|
} catch (error) {
|
|
console.error('Error adding contact:', error);
|
|
}
|
|
};
|
|
|
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
if (suggestions.length > 0) {
|
|
switch (e.key) {
|
|
case 'ArrowDown':
|
|
e.preventDefault();
|
|
setSelectedIndex((prev) => (prev + 1) % suggestions.length);
|
|
break;
|
|
case 'ArrowUp':
|
|
e.preventDefault();
|
|
setSelectedIndex(
|
|
(prev) => (prev - 1 + suggestions.length) % suggestions.length,
|
|
);
|
|
break;
|
|
case 'Enter':
|
|
if (suggestions.length > 0) {
|
|
e.preventDefault();
|
|
reset({ contact: suggestions[selectedIndex] });
|
|
handleSubmit(submitContact)();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div className="text-center">
|
|
<form onSubmit={handleSubmit(submitContact)}>
|
|
<input
|
|
className="text-black bg-green-50 pl-2 shadow-lg rounded-md h-8 mb-2 mt-2"
|
|
type="text"
|
|
placeholder="Search for user"
|
|
onKeyDown={handleKeyDown}
|
|
{...register('contact', {
|
|
minLength: 4,
|
|
maxLength: 20,
|
|
})}
|
|
/>
|
|
</form>
|
|
<div className="m-1">
|
|
{suggestions?.length > 0 ? (
|
|
<ul className="text-left p-2 bg-gray-900 shadow-md rounded-md w-full border">
|
|
{suggestions.map((suggestion, index) => (
|
|
<li
|
|
key={suggestion}
|
|
className={`p-1 cursor-pointer rounded-md mt-1 mb-1 ${
|
|
index === selectedIndex
|
|
? 'bg-gray-500'
|
|
: 'hover:bg-gray-500'
|
|
}`}
|
|
onClick={() => {
|
|
reset({ contact: suggestion });
|
|
handleSubmit(() =>
|
|
submitContact({ contact: suggestion }),
|
|
)();
|
|
setSuggestions([]);
|
|
}}
|
|
>
|
|
{suggestion}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
) : isLoading ? (
|
|
<LoadingWheel />
|
|
) : null}
|
|
{notFound ? (
|
|
<p className="p-1 bg-gray-800 shadow-md rounded-md w-full border text-gray-400">
|
|
user not found
|
|
</p>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default ContactForm;
|