api ulandi
This commit is contained in:
70
src/pages/tour-settings/lib/api.ts
Normal file
70
src/pages/tour-settings/lib/api.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import type {
|
||||
GetDetailSiteSetting,
|
||||
GetSiteSetting,
|
||||
} from "@/pages/tour-settings/lib/types";
|
||||
import httpClient from "@/shared/config/api/httpClient";
|
||||
import { SITE_SETTING } from "@/shared/config/api/URLs";
|
||||
import type { AxiosResponse } from "axios";
|
||||
|
||||
const createSiteSetting = async (body: {
|
||||
address: string;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
telegram: string;
|
||||
instagram: string;
|
||||
facebook: string;
|
||||
twitter: string;
|
||||
email: string;
|
||||
main_phone: string;
|
||||
other_phone: string;
|
||||
}) => {
|
||||
const res = await httpClient.post(SITE_SETTING, body);
|
||||
return res;
|
||||
};
|
||||
|
||||
const updateSiteSetting = async ({
|
||||
body,
|
||||
id,
|
||||
}: {
|
||||
id: number;
|
||||
body: {
|
||||
address: string;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
telegram: string;
|
||||
instagram: string;
|
||||
facebook: string;
|
||||
twitter: string;
|
||||
email: string;
|
||||
main_phone: string;
|
||||
other_phone: string;
|
||||
};
|
||||
}) => {
|
||||
const res = await httpClient.patch(`${SITE_SETTING}${id}/`, body);
|
||||
return res;
|
||||
};
|
||||
|
||||
const getSiteSetting = async (): Promise<AxiosResponse<GetSiteSetting>> => {
|
||||
const res = await httpClient.get(SITE_SETTING);
|
||||
return res;
|
||||
};
|
||||
|
||||
const getDetailSiteSetting = async (
|
||||
id: number,
|
||||
): Promise<AxiosResponse<GetDetailSiteSetting>> => {
|
||||
const res = await httpClient.get(`${SITE_SETTING}${id}/`);
|
||||
return res;
|
||||
};
|
||||
|
||||
const deleteSiteSetting = async (id: number) => {
|
||||
const res = await httpClient.delete(`${SITE_SETTING}${id}/`);
|
||||
return res;
|
||||
};
|
||||
|
||||
export {
|
||||
createSiteSetting,
|
||||
deleteSiteSetting,
|
||||
getDetailSiteSetting,
|
||||
getSiteSetting,
|
||||
updateSiteSetting,
|
||||
};
|
||||
43
src/pages/tour-settings/lib/types.ts
Normal file
43
src/pages/tour-settings/lib/types.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
export interface GetSiteSetting {
|
||||
status: boolean;
|
||||
data: {
|
||||
links: {
|
||||
previous: string;
|
||||
next: string;
|
||||
};
|
||||
total_items: number;
|
||||
total_pages: number;
|
||||
page_size: number;
|
||||
current_page: number;
|
||||
results: {
|
||||
id: number;
|
||||
address: string;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
telegram: string;
|
||||
instagram: string;
|
||||
facebook: string;
|
||||
twitter: string;
|
||||
email: string;
|
||||
main_phone: string;
|
||||
other_phone: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface GetDetailSiteSetting {
|
||||
status: boolean;
|
||||
data: {
|
||||
id: number;
|
||||
address: string;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
telegram: string;
|
||||
instagram: string;
|
||||
facebook: string;
|
||||
twitter: string;
|
||||
email: string;
|
||||
main_phone: string;
|
||||
other_phone: string;
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
createSiteSetting,
|
||||
deleteSiteSetting,
|
||||
getDetailSiteSetting,
|
||||
getSiteSetting,
|
||||
updateSiteSetting,
|
||||
} from "@/pages/tour-settings/lib/api";
|
||||
import formatPhone from "@/shared/lib/formatPhone";
|
||||
import { Button } from "@/shared/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/shared/ui/card";
|
||||
import {
|
||||
@@ -12,27 +20,28 @@ import {
|
||||
import { Input } from "@/shared/ui/input";
|
||||
import { Label } from "@/shared/ui/label";
|
||||
import { Map, Placemark, YMaps } from "@pbe/react-yandex-maps";
|
||||
import { Edit, Plus, Trash } from "lucide-react";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { Edit, Loader2, Plus, Trash } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from "sonner";
|
||||
|
||||
type MapClickEvent = {
|
||||
get: (key: "coords") => [number, number];
|
||||
};
|
||||
|
||||
type ContactInfo = {
|
||||
telegram?: string;
|
||||
instagram?: string;
|
||||
facebook?: string;
|
||||
twiter?: string;
|
||||
linkedin?: string;
|
||||
address?: string;
|
||||
email?: string;
|
||||
phonePrimary?: string;
|
||||
phoneSecondary?: string;
|
||||
telegram: string;
|
||||
instagram: string;
|
||||
facebook: string;
|
||||
twiter: string;
|
||||
linkedin: string;
|
||||
address: string;
|
||||
email: string;
|
||||
phonePrimary: string;
|
||||
phoneSecondary: string;
|
||||
};
|
||||
|
||||
const STORAGE_KEY = "site_contact_info";
|
||||
|
||||
async function getAddressFromCoords(lat: number, lon: number) {
|
||||
const response = await fetch(
|
||||
`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=json`,
|
||||
@@ -42,26 +51,174 @@ async function getAddressFromCoords(lat: number, lon: number) {
|
||||
}
|
||||
|
||||
export default function ContactSettings() {
|
||||
const [contact, setContact] = useState<ContactInfo | null>(null);
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [editing, setEditing] = useState(false);
|
||||
const [form, setForm] = useState<ContactInfo>({});
|
||||
const [editing, setEditing] = useState<number | null>(null);
|
||||
const [form, setForm] = useState<ContactInfo>({
|
||||
telegram: "",
|
||||
instagram: "",
|
||||
facebook: "",
|
||||
twiter: "",
|
||||
linkedin: "",
|
||||
address: "",
|
||||
email: "",
|
||||
phonePrimary: "+998",
|
||||
phoneSecondary: "+998",
|
||||
});
|
||||
const [coords, setCoords] = useState({
|
||||
latitude: 41.311081,
|
||||
longitude: 69.240562,
|
||||
}); // Toshkent default
|
||||
});
|
||||
const { mutate: create, isPending } = useMutation({
|
||||
mutationFn: (body: {
|
||||
address: string;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
telegram: string;
|
||||
instagram: string;
|
||||
facebook: string;
|
||||
twitter: string;
|
||||
email: string;
|
||||
main_phone: string;
|
||||
other_phone: string;
|
||||
}) => createSiteSetting(body),
|
||||
onSuccess: () => {
|
||||
setForm({
|
||||
telegram: "",
|
||||
instagram: "",
|
||||
facebook: "",
|
||||
twiter: "",
|
||||
linkedin: "",
|
||||
address: "",
|
||||
email: "",
|
||||
phonePrimary: "",
|
||||
phoneSecondary: "",
|
||||
});
|
||||
setOpen(false);
|
||||
queryClient.refetchQueries({ queryKey: ["contact"] });
|
||||
queryClient.refetchQueries({ queryKey: ["contact_detail"] });
|
||||
setEditing(null);
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(t("Xatolik yuz berdi"), {
|
||||
position: "top-center",
|
||||
richColors: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Load saved contact
|
||||
useEffect(() => {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (raw) setContact(JSON.parse(raw));
|
||||
}, []);
|
||||
const { mutate: update } = useMutation({
|
||||
mutationFn: ({
|
||||
body,
|
||||
id,
|
||||
}: {
|
||||
id: number;
|
||||
body: {
|
||||
address: string;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
telegram: string;
|
||||
instagram: string;
|
||||
facebook: string;
|
||||
twitter: string;
|
||||
email: string;
|
||||
main_phone: string;
|
||||
other_phone: string;
|
||||
};
|
||||
}) => updateSiteSetting({ body, id }),
|
||||
onSuccess: () => {
|
||||
setForm({
|
||||
telegram: "",
|
||||
instagram: "",
|
||||
facebook: "",
|
||||
twiter: "",
|
||||
linkedin: "",
|
||||
address: "",
|
||||
email: "",
|
||||
phonePrimary: "",
|
||||
phoneSecondary: "",
|
||||
});
|
||||
setOpen(false);
|
||||
queryClient.refetchQueries({ queryKey: ["contact"] });
|
||||
queryClient.refetchQueries({ queryKey: ["contact_detail"] });
|
||||
setEditing(null);
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(t("Xatolik yuz berdi"), {
|
||||
position: "top-center",
|
||||
richColors: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const { mutate: remover } = useMutation({
|
||||
mutationFn: (id: number) => deleteSiteSetting(id),
|
||||
onSuccess: () => {
|
||||
setForm({
|
||||
telegram: "",
|
||||
instagram: "",
|
||||
facebook: "",
|
||||
twiter: "",
|
||||
linkedin: "",
|
||||
address: "",
|
||||
email: "",
|
||||
phonePrimary: "",
|
||||
phoneSecondary: "",
|
||||
});
|
||||
setOpen(false);
|
||||
queryClient.refetchQueries({ queryKey: ["contact"] });
|
||||
queryClient.refetchQueries({ queryKey: ["contact_detail"] });
|
||||
setEditing(null);
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(t("Xatolik yuz berdi"), {
|
||||
position: "top-center",
|
||||
richColors: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const { data, isLoading } = useQuery({
|
||||
queryKey: ["contact"],
|
||||
queryFn: () => {
|
||||
return getSiteSetting();
|
||||
},
|
||||
select: (data) => {
|
||||
return data.data.data;
|
||||
},
|
||||
});
|
||||
|
||||
const { data: detail } = useQuery({
|
||||
queryKey: ["contact_detail", editing],
|
||||
queryFn: () => {
|
||||
return getDetailSiteSetting(editing!);
|
||||
},
|
||||
select: (data) => {
|
||||
return data.data.data;
|
||||
},
|
||||
enabled: !!editing,
|
||||
});
|
||||
|
||||
// Populate form when editing
|
||||
useEffect(() => {
|
||||
if (open && editing && contact) setForm(contact);
|
||||
if (!open && !editing) setForm({});
|
||||
}, [open, editing, contact]);
|
||||
if (editing && detail) {
|
||||
setForm({
|
||||
address: detail.address,
|
||||
email: detail.email,
|
||||
facebook: detail.facebook,
|
||||
instagram: detail.instagram,
|
||||
linkedin: detail.twitter,
|
||||
phonePrimary: detail.main_phone,
|
||||
phoneSecondary: detail.other_phone,
|
||||
telegram: detail.telegram,
|
||||
twiter: detail.twitter,
|
||||
});
|
||||
setCoords({
|
||||
latitude: Number(detail.latitude),
|
||||
longitude: Number(detail.longitude),
|
||||
});
|
||||
}
|
||||
}, [editing, detail]);
|
||||
|
||||
const handleChange = <K extends keyof ContactInfo>(
|
||||
key: K,
|
||||
@@ -80,139 +237,196 @@ export default function ContactSettings() {
|
||||
};
|
||||
|
||||
const saveContact = () => {
|
||||
if (!form.email && !form.phonePrimary) {
|
||||
alert("Iltimos email yoki telefon kiriting");
|
||||
return;
|
||||
const shortLat = Number(coords.latitude.toFixed(6)); // 6ta raqamgacha
|
||||
const shortLon = Number(coords.longitude.toFixed(6));
|
||||
if (editing) {
|
||||
update({
|
||||
body: {
|
||||
address: form.address,
|
||||
email: form.email,
|
||||
facebook: form.facebook,
|
||||
instagram: form.instagram,
|
||||
latitude: String(shortLat),
|
||||
longitude: String(shortLon),
|
||||
main_phone: form.phonePrimary,
|
||||
other_phone: form.phoneSecondary,
|
||||
telegram: form.telegram,
|
||||
twitter: form.twiter,
|
||||
},
|
||||
id: editing,
|
||||
});
|
||||
} else {
|
||||
create({
|
||||
address: form.address,
|
||||
email: form.email,
|
||||
facebook: form.facebook,
|
||||
instagram: form.instagram,
|
||||
latitude: String(shortLat),
|
||||
longitude: String(shortLon),
|
||||
main_phone: form.phonePrimary,
|
||||
other_phone: form.phoneSecondary,
|
||||
telegram: form.telegram,
|
||||
twitter: form.twiter,
|
||||
});
|
||||
}
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(form));
|
||||
setContact(form);
|
||||
setOpen(false);
|
||||
setEditing(false);
|
||||
};
|
||||
|
||||
const startAdd = () => {
|
||||
setForm({});
|
||||
setEditing(false);
|
||||
setForm({
|
||||
telegram: "",
|
||||
instagram: "",
|
||||
facebook: "",
|
||||
twiter: "",
|
||||
linkedin: "",
|
||||
address: "",
|
||||
email: "",
|
||||
phonePrimary: "",
|
||||
phoneSecondary: "",
|
||||
});
|
||||
setEditing(null);
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const startEdit = () => {
|
||||
setEditing(true);
|
||||
const startEdit = (id: number) => {
|
||||
setEditing(id);
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const removeContact = () => {
|
||||
if (!confirm("Contact ma'lumotlarini o'chirishni xohlaysizmi?")) return;
|
||||
localStorage.removeItem(STORAGE_KEY);
|
||||
setContact(null);
|
||||
const removeContact = (id: number) => {
|
||||
remover(id);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full mx-auto p-4">
|
||||
<div className="w-full h-screen mx-auto p-4">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h2 className="text-2xl font-semibold text-gray-100">
|
||||
Contact settings
|
||||
{t("Contact settings")}
|
||||
</h2>
|
||||
{!contact && (
|
||||
{data && data?.total_items === 0 && (
|
||||
<Button onClick={startAdd} className="flex items-center gap-2">
|
||||
<Plus size={16} /> Qo'shish
|
||||
<Plus size={16} /> {t("Qo'shish")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{!contact ? (
|
||||
<Card className="bg-gray-900">
|
||||
<CardHeader>
|
||||
<CardTitle>Hozircha kontakt ma'lumotlari qo'shilmagan</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Sayt uchun telegram, instagram, manzil, email va telefonni bu
|
||||
yerda saqlang. Siz faqat bir marta qo'sha olasiz — keyin
|
||||
tahrirlash mumkin.
|
||||
</p>
|
||||
<div className="mt-4">
|
||||
<Button onClick={startAdd} className="flex items-center gap-2">
|
||||
<Plus size={14} /> Qo'shish
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{isLoading ? (
|
||||
<div className="flex justify-center items-center h-60">
|
||||
<Loader2 className="w-6 h-6 animate-spin text-gray-400" />
|
||||
<span className="ml-2 text-gray-400">{t("Yuklanmoqda...")}</span>
|
||||
</div>
|
||||
) : (
|
||||
<Card className="bg-gray-900">
|
||||
<CardHeader className="flex items-center justify-between">
|
||||
<CardTitle>Kontakt ma'lumotlari</CardTitle>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={startEdit}
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Edit size={14} /> Tahrirlash
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={removeContact}
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Trash size={14} /> O'chirish
|
||||
</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground">Telegram</div>
|
||||
<div className="text-sm">{contact.telegram || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">Instagram</div>
|
||||
<div className="text-sm">{contact.instagram || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">Facebook</div>
|
||||
<div className="text-sm">{contact.facebook || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">LinkedIn</div>
|
||||
<div className="text-sm">{contact.linkedin || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">Twitter</div>
|
||||
<div className="text-sm">{contact.twiter || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">Manzil</div>
|
||||
<div className="text-sm">{contact.address || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">Email</div>
|
||||
<div className="text-sm">{contact.email || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">Telefonlar</div>
|
||||
<div className="text-sm">
|
||||
{contact.phonePrimary || "—"}
|
||||
{contact.phoneSecondary ? ` • ${contact.phoneSecondary}` : ""}
|
||||
<>
|
||||
{data && data?.total_items === 0 ? (
|
||||
<Card className="bg-gray-900">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
{t("Hozircha kontakt ma'lumotlari qo'shilmagan")}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t(
|
||||
"Sayt uchun telegram, instagram, manzil, email va telefonni bu yerda saqlang. Siz faqat bir marta qo'sha olasiz — keyin tahrirlash mumkin.",
|
||||
)}
|
||||
</p>
|
||||
<div className="mt-4">
|
||||
<Button
|
||||
onClick={startAdd}
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Plus size={14} /> {t("Qo'shish")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<>
|
||||
{data &&
|
||||
data.results.map((e) => (
|
||||
<Card className="bg-gray-900">
|
||||
<CardHeader className="flex items-center justify-between">
|
||||
<CardTitle>{t("Kontakt ma'lumotlari")}</CardTitle>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => startEdit(e.id)}
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Edit size={14} /> {t("Tahrirlash")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() => removeContact(e.id)}
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Trash size={14} /> {t("O'chirish")}
|
||||
</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Telegram
|
||||
</div>
|
||||
<div className="text-sm">{e.telegram || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
Instagram
|
||||
</div>
|
||||
<div className="text-sm">{e.instagram || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
Facebook
|
||||
</div>
|
||||
<div className="text-sm">{e.facebook || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
Twitter
|
||||
</div>
|
||||
<div className="text-sm">{e.twitter || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{t("Manzil")}
|
||||
</div>
|
||||
<div className="text-sm">{e.address || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
Email
|
||||
</div>
|
||||
<div className="text-sm">{e.email || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{t("Telefon raqam")}
|
||||
</div>
|
||||
<p>{e.main_phone}</p>
|
||||
<p>{e.other_phone}</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Dialog */}
|
||||
<Dialog
|
||||
open={open}
|
||||
onOpenChange={(v) => {
|
||||
setOpen(v);
|
||||
if (!v) setEditing(false);
|
||||
if (!v) setEditing(null);
|
||||
}}
|
||||
>
|
||||
<DialogContent className="h-[90%] overflow-y-scroll">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{editing ? "Kontaktni tahrirlash" : "Kontakt qo'shish"}
|
||||
{editing ? t("Kontaktni tahrirlash") : t("Kontakt qo'shish")}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -233,7 +447,7 @@ export default function ContactSettings() {
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6 mt-4">
|
||||
<div className="flex flex-col gap-2 sm:col-span-2">
|
||||
<Label>Manzil</Label>
|
||||
<Label>{t("Manzil")}</Label>
|
||||
<Input
|
||||
value={form.address || ""}
|
||||
onChange={(e) => handleChange("address", e.target.value)}
|
||||
@@ -282,16 +496,16 @@ export default function ContactSettings() {
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label>Asosiy telefon</Label>
|
||||
<Label>{t("Asosiy telefon")}</Label>
|
||||
<Input
|
||||
value={form.phonePrimary || ""}
|
||||
value={formatPhone(form.phonePrimary)}
|
||||
onChange={(e) => handleChange("phonePrimary", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<Label>Qo'shimcha telefon</Label>
|
||||
<Label>{t("Qo'shimcha telefon")}</Label>
|
||||
<Input
|
||||
value={form.phoneSecondary || ""}
|
||||
value={formatPhone(form.phoneSecondary)}
|
||||
onChange={(e) => handleChange("phoneSecondary", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
@@ -302,12 +516,14 @@ export default function ContactSettings() {
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
setOpen(false);
|
||||
setEditing(false);
|
||||
setEditing(null);
|
||||
}}
|
||||
>
|
||||
Bekor qilish
|
||||
{t("Bekor qilish")}
|
||||
</Button>
|
||||
<Button onClick={saveContact}>
|
||||
{isPending ? <Loader2 className="animate-spin" /> : t("Saqlash")}
|
||||
</Button>
|
||||
<Button onClick={saveContact}>Saqlash</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
Reference in New Issue
Block a user