feat: implement client search hook for phone input validation in CreateSessionModal
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
export default function Selector() {
|
||||
return <div>Selector</div>;
|
||||
}
|
||||
@@ -25,7 +25,14 @@ function ClientModal({ client }: { client: Client }) {
|
||||
|
||||
const { mutate: updateClientData, isPending } = useMutation({
|
||||
mutationKey: ["clients", client.id],
|
||||
mutationFn: () => api.put(`clients/${client.id}`, { json: clientData }),
|
||||
mutationFn: () =>
|
||||
api.put(`clients/${client.id}`, {
|
||||
json: {
|
||||
name: clientData.name,
|
||||
phone: clientData.phone.replace(/\D/g, ""),
|
||||
email: clientData.email,
|
||||
},
|
||||
}),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["clients"] });
|
||||
},
|
||||
@@ -58,7 +65,6 @@ function ClientModal({ client }: { client: Client }) {
|
||||
onChange={(e) => {
|
||||
setClientData({ ...clientData, name: e.target.value });
|
||||
}}
|
||||
className="relative"
|
||||
required
|
||||
>
|
||||
<span
|
||||
@@ -76,8 +82,8 @@ function ClientModal({ client }: { client: Client }) {
|
||||
onChange={(e) => {
|
||||
setClientData({ ...clientData, phone: e.target.value });
|
||||
}}
|
||||
className="relative"
|
||||
required
|
||||
mask="+7 (999) 999-99-99"
|
||||
>
|
||||
<span
|
||||
className="absolute top-[1.25vw] left-[17.917vw] size-[1.389vw] text-[#7D7D7D] cursor-pointer"
|
||||
|
||||
@@ -11,8 +11,8 @@ import StartSessionIcon from "../icons/StartSessionIcon.tsx";
|
||||
import Button from "../Button.tsx";
|
||||
import ProjectSelector from "../ProjectSelector.tsx";
|
||||
import { useQueryClient, useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { useDebounce } from "@uidotdev/usehooks";
|
||||
import { AnimatePresence, motion } from "motion/react";
|
||||
import useClientSearch from "../../hooks/useClientSearch.tsx";
|
||||
|
||||
interface Props {
|
||||
targetServerId: string | null;
|
||||
@@ -24,6 +24,7 @@ export default function CreateSessionModal({ targetServerId, client }: Props) {
|
||||
const [name, setName] = useState<string | null>(client?.name || null);
|
||||
const [phone, setPhone] = useState<string | null>(client?.phone || null);
|
||||
const [email, setEmail] = useState<string | null>(client?.email || null);
|
||||
const [isFullPhone, setIsFullPhone] = useState(false);
|
||||
const [isSessionExists, setIsSessionExists] = useState(false);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
@@ -43,6 +44,8 @@ export default function CreateSessionModal({ targetServerId, client }: Props) {
|
||||
);
|
||||
const [selectedApp, setSelectedApp] = useState<App | null>(null);
|
||||
|
||||
const { data, isLoading, error } = useClientSearch(phone);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedApp(
|
||||
selectedServer?.sessions?.[0]?.app ||
|
||||
@@ -51,28 +54,15 @@ export default function CreateSessionModal({ targetServerId, client }: Props) {
|
||||
);
|
||||
}, [selectedServer]);
|
||||
|
||||
const debouncedPhone = useDebounce(phone, 500);
|
||||
|
||||
const { data, isLoading, error } = useQuery({
|
||||
queryKey: ["get-user-by-phone", debouncedPhone],
|
||||
queryFn: () =>
|
||||
api
|
||||
.get("clients/by-phone", {
|
||||
searchParams: debouncedPhone ? { phone: debouncedPhone } : {},
|
||||
})
|
||||
.json<Client>(),
|
||||
enabled: !!debouncedPhone,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!error && data) {
|
||||
setName(data.name);
|
||||
setEmail(data.email);
|
||||
} else {
|
||||
setName(null);
|
||||
setEmail(null);
|
||||
setName(isFullPhone ? name : null);
|
||||
setEmail(isFullPhone ? email : null);
|
||||
}
|
||||
}, [data, error]);
|
||||
}, [data, error, isFullPhone, name, email]);
|
||||
|
||||
const { mutate: createClient } = useMutation({
|
||||
mutationFn: () =>
|
||||
@@ -206,14 +196,19 @@ export default function CreateSessionModal({ targetServerId, client }: Props) {
|
||||
<div className="flex flex-col gap-y-[0.556vw]">
|
||||
<Input
|
||||
value={phone || ""}
|
||||
onChange={(e) => setPhone(e.target.value)}
|
||||
onChange={(e) => {
|
||||
setPhone(e.target.value);
|
||||
if (e.target.value.replace(/\D/g, "").length === 11) {
|
||||
setIsFullPhone(true);
|
||||
}
|
||||
}}
|
||||
placeholder="Номер телефона"
|
||||
mask="+7 (999) 999-99-99"
|
||||
required
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<AnimatePresence>
|
||||
{phone && (
|
||||
{isFullPhone && (
|
||||
<>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useDebounce } from "@uidotdev/usehooks";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Client } from "../types/Client";
|
||||
import api from "../utils/api";
|
||||
|
||||
function useClientSearch(phone: string | null) {
|
||||
const [isSearching, setIsSearching] = useState(false);
|
||||
|
||||
const isPhoneComplete = Boolean(
|
||||
phone && phone.replace(/\D/g, "").length === 11
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setIsSearching(isPhoneComplete);
|
||||
}, [isPhoneComplete]);
|
||||
|
||||
const debouncedPhone = useDebounce(phone, 500);
|
||||
|
||||
const { data, isLoading, error } = useQuery({
|
||||
queryKey: ["get-user-by-phone", debouncedPhone],
|
||||
queryFn: () =>
|
||||
api
|
||||
.get("clients/by-phone", {
|
||||
searchParams:
|
||||
debouncedPhone && debouncedPhone.replace(/\D/g, "").length === 11
|
||||
? { phone: debouncedPhone.replace(/\D/g, "") }
|
||||
: {},
|
||||
})
|
||||
.json<Client>(),
|
||||
enabled: Boolean(debouncedPhone && isPhoneComplete),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && isSearching) {
|
||||
setIsSearching(false);
|
||||
}
|
||||
}, [isLoading, isSearching]);
|
||||
|
||||
return {
|
||||
data,
|
||||
isLoading: isSearching || isLoading,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export default useClientSearch;
|
||||
Reference in New Issue
Block a user