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({
|
const { mutate: updateClientData, isPending } = useMutation({
|
||||||
mutationKey: ["clients", client.id],
|
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: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries({ queryKey: ["clients"] });
|
queryClient.invalidateQueries({ queryKey: ["clients"] });
|
||||||
},
|
},
|
||||||
@@ -58,7 +65,6 @@ function ClientModal({ client }: { client: Client }) {
|
|||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setClientData({ ...clientData, name: e.target.value });
|
setClientData({ ...clientData, name: e.target.value });
|
||||||
}}
|
}}
|
||||||
className="relative"
|
|
||||||
required
|
required
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -76,8 +82,8 @@ function ClientModal({ client }: { client: Client }) {
|
|||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setClientData({ ...clientData, phone: e.target.value });
|
setClientData({ ...clientData, phone: e.target.value });
|
||||||
}}
|
}}
|
||||||
className="relative"
|
|
||||||
required
|
required
|
||||||
|
mask="+7 (999) 999-99-99"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="absolute top-[1.25vw] left-[17.917vw] size-[1.389vw] text-[#7D7D7D] cursor-pointer"
|
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 Button from "../Button.tsx";
|
||||||
import ProjectSelector from "../ProjectSelector.tsx";
|
import ProjectSelector from "../ProjectSelector.tsx";
|
||||||
import { useQueryClient, useMutation, useQuery } from "@tanstack/react-query";
|
import { useQueryClient, useMutation, useQuery } from "@tanstack/react-query";
|
||||||
import { useDebounce } from "@uidotdev/usehooks";
|
|
||||||
import { AnimatePresence, motion } from "motion/react";
|
import { AnimatePresence, motion } from "motion/react";
|
||||||
|
import useClientSearch from "../../hooks/useClientSearch.tsx";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
targetServerId: string | null;
|
targetServerId: string | null;
|
||||||
@@ -24,6 +24,7 @@ export default function CreateSessionModal({ targetServerId, client }: Props) {
|
|||||||
const [name, setName] = useState<string | null>(client?.name || null);
|
const [name, setName] = useState<string | null>(client?.name || null);
|
||||||
const [phone, setPhone] = useState<string | null>(client?.phone || null);
|
const [phone, setPhone] = useState<string | null>(client?.phone || null);
|
||||||
const [email, setEmail] = useState<string | null>(client?.email || null);
|
const [email, setEmail] = useState<string | null>(client?.email || null);
|
||||||
|
const [isFullPhone, setIsFullPhone] = useState(false);
|
||||||
const [isSessionExists, setIsSessionExists] = useState(false);
|
const [isSessionExists, setIsSessionExists] = useState(false);
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@@ -43,6 +44,8 @@ export default function CreateSessionModal({ targetServerId, client }: Props) {
|
|||||||
);
|
);
|
||||||
const [selectedApp, setSelectedApp] = useState<App | null>(null);
|
const [selectedApp, setSelectedApp] = useState<App | null>(null);
|
||||||
|
|
||||||
|
const { data, isLoading, error } = useClientSearch(phone);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedApp(
|
setSelectedApp(
|
||||||
selectedServer?.sessions?.[0]?.app ||
|
selectedServer?.sessions?.[0]?.app ||
|
||||||
@@ -51,28 +54,15 @@ export default function CreateSessionModal({ targetServerId, client }: Props) {
|
|||||||
);
|
);
|
||||||
}, [selectedServer]);
|
}, [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(() => {
|
useEffect(() => {
|
||||||
if (!error && data) {
|
if (!error && data) {
|
||||||
setName(data.name);
|
setName(data.name);
|
||||||
setEmail(data.email);
|
setEmail(data.email);
|
||||||
} else {
|
} else {
|
||||||
setName(null);
|
setName(isFullPhone ? name : null);
|
||||||
setEmail(null);
|
setEmail(isFullPhone ? email : null);
|
||||||
}
|
}
|
||||||
}, [data, error]);
|
}, [data, error, isFullPhone, name, email]);
|
||||||
|
|
||||||
const { mutate: createClient } = useMutation({
|
const { mutate: createClient } = useMutation({
|
||||||
mutationFn: () =>
|
mutationFn: () =>
|
||||||
@@ -206,14 +196,19 @@ export default function CreateSessionModal({ targetServerId, client }: Props) {
|
|||||||
<div className="flex flex-col gap-y-[0.556vw]">
|
<div className="flex flex-col gap-y-[0.556vw]">
|
||||||
<Input
|
<Input
|
||||||
value={phone || ""}
|
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="Номер телефона"
|
placeholder="Номер телефона"
|
||||||
mask="+7 (999) 999-99-99"
|
mask="+7 (999) 999-99-99"
|
||||||
required
|
required
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
/>
|
/>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{phone && (
|
{isFullPhone && (
|
||||||
<>
|
<>
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0 }}
|
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