Files
cpost-admin-front/src/components/branches/CreateBranches.jsx
Samandar Turgunboyev 1e5357ec39 Initial commit
2025-09-09 10:46:03 +05:00

283 lines
8.4 KiB
JavaScript

'use client';
import { Map, Placemark, YMaps } from '@pbe/react-yandex-maps';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useEffect, useState } from 'react';
import axiosInstance from '../../api/axiosInstance';
// Reverse geocoding (OSM orqali)
async function getAddress(lat, lon) {
const response = await fetch(`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=json`);
const data = await response.json();
const address = data.address || {};
return {
fullAddress: data.display_name || '',
country: address.country || '',
region: address.state || '',
city: address.city || address.town || address.village || '',
street: address.road || '',
house: address.house_number || '',
postalCode: address.postcode || '',
};
}
const CreateBranches = ({ branches, setAlert, setBranches }) => {
const queryClient = useQueryClient();
const [formData, setFormData] = useState({
id: '',
title: '',
titleRu: '',
address: '',
addressRu: '',
workingHours: '',
workingHoursRu: '',
phone: '',
telegramAdmin: '',
telegramChannel: '',
code: '',
active: true,
});
const [coords, setCoords] = useState({
latitude: 41.311081, // Toshkent
longitude: 69.240562,
});
const [locationDetails, setLocationDetails] = useState({
fullAddress: '',
country: '',
region: '',
city: '',
street: '',
house: '',
postalCode: '',
});
const resetForm = () => {
setFormData({
id: '',
title: '',
titleRu: '',
address: '',
addressRu: '',
workingHours: '',
workingHoursRu: '',
phone: '',
telegramAdmin: '',
telegramChannel: '',
code: '',
active: true,
});
setCoords({
latitude: 41.311081,
longitude: 69.240562,
});
setLocationDetails({
fullAddress: '',
country: '',
region: '',
city: '',
street: '',
house: '',
postalCode: '',
});
};
useEffect(() => {
if (locationDetails.fullAddress) {
setFormData((prev) => ({
...prev,
address: locationDetails.fullAddress,
addressRu: locationDetails.fullAddress,
}));
}
}, [locationDetails]);
const { data: branchData, refetch } = useQuery({
queryKey: ['one_branch', branches],
queryFn: () => axiosInstance.get(`/branches/${branches}`).then((res) => res.data),
enabled: !!branches,
});
useEffect(() => {
if (branches) {
refetch();
}
}, [branches, refetch]);
useEffect(() => {
if (branchData) {
setFormData({
id: branchData.id || '',
title: branchData.title || '',
titleRu: branchData.titleRu || '',
address: branchData.address || '',
addressRu: branchData.addressRu || '',
workingHours: branchData.workingHours || '',
workingHoursRu: branchData.workingHoursRu || '',
phone: branchData.phone || '',
telegramAdmin: branchData.telegramAdmin || '',
telegramChannel: branchData.telegramChannel || '',
code: branchData.code || '',
active: branchData.active ?? true,
});
setCoords({
latitude: branchData.latitude || 41.311081,
longitude: branchData.longitude || 69.240562,
});
}
}, [branchData]);
const { mutate: createBranch } = useMutation({
mutationFn: (body) => axiosInstance.post('/branches', body),
onSuccess: () => {
setAlert({ type: 'success', message: "Filial muvaffaqiyatli qo'shildi." });
queryClient.invalidateQueries({ queryKey: ['branch_list'] });
resetForm();
},
onError: () => {
setAlert({
type: 'warning',
message: "Filial qo'shilmadi, xatolik yuz berdi.",
});
},
});
const { mutate: editBranch } = useMutation({
mutationFn: (body) => axiosInstance.put(`/branches/${body.id}`, body),
onSuccess: () => {
setBranches(null);
setAlert({
type: 'success',
message: 'Filial muvaffaqiyatli yangilandi.',
});
queryClient.invalidateQueries({ queryKey: ['branch_list'] });
resetForm();
},
onError: () => {
setAlert({
type: 'warning',
message: 'Filial yangilanmadi, xatolik yuz berdi.',
});
},
});
const addBranch = () => {
const { id, ...dataWithoutId } = formData;
createBranch({
...dataWithoutId,
latitude: Number(coords.latitude) || 0,
longitude: Number(coords.longitude) || 0,
});
};
const updateBranch = (id) => {
editBranch({
...formData,
id,
latitude: Number(coords.latitude) || 0,
longitude: Number(coords.longitude) || 0,
});
};
const handleMapClick = async (e) => {
const lat = e.get('coords')[0];
const lon = e.get('coords')[1];
setCoords({ latitude: lat, longitude: lon });
const details = await getAddress(lat, lon);
setLocationDetails(details);
};
return (
<div className="flex flex-col bg-white shadow rounded-lg p-6 mb-6">
<div className="h-96 mb-10">
<YMaps query={{ lang: 'en_RU' }}>
<Map
defaultState={{
center: [coords.latitude, coords.longitude],
zoom: 13,
}}
width="100%"
height="400px"
onClick={handleMapClick}
>
<Placemark geometry={[coords.latitude, coords.longitude]} />
</Map>
</YMaps>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
{Object.keys(formData)
.filter((key) => key !== 'id')
.map((key) => (
<div key={key} className="flex flex-col">
<label className="mb-1 font-semibold text-slate-700">
{key === 'title'
? 'Filial nomi'
: key === 'titleRu'
? 'Filial nomi (RU)'
: key === 'address'
? 'Manzil'
: key === 'addressRu'
? 'Manzil (RU)'
: key === 'workingHours'
? 'Ish vaqti'
: key === 'workingHoursRu'
? 'Ish vaqti (RU)'
: key === 'phone'
? 'Telefon'
: key === 'telegramAdmin'
? 'Telegram Admin'
: key === 'telegramChannel'
? 'Telegram Kanal'
: key === 'code'
? 'Kod'
: key === 'active'
? 'Faol'
: key}
</label>
{key === 'active' ? (
<div className="flex items-center gap-3">
<button type="button" onClick={() => setFormData({ ...formData, active: !formData.active })} className={`w-14 h-8 flex items-center rounded-full p-1 transition-colors duration-300 ${formData.active ? 'bg-[#3489e3]' : 'bg-gray-300'}`}>
<div className={`w-6 h-6 bg-white rounded-full shadow-md transform transition-transform duration-300 ${formData.active ? 'translate-x-6' : 'translate-x-0'}`}></div>
</button>
<span>{formData.active ? 'Faol' : 'Faol emas'}</span>
</div>
) : (
<input
type="text"
className="border border-slate-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[#3489e3]"
value={formData[key]}
onChange={(e) =>
setFormData({
...formData,
[key]: e.target.value,
})
}
/>
)}
</div>
))}
</div>
<div className="flex flex-wrap gap-3 mb-8 mt-6">
{!branches && (
<button onClick={addBranch} className="bg-[#3489e3] hover:bg-blue-500 text-white px-5 py-2 rounded-lg shadow">
Yaratish
</button>
)}
{branches && (
<button onClick={() => updateBranch(formData.id)} disabled={!formData.id} className={`px-5 py-2 rounded-lg shadow text-white ${!formData.id ? 'bg-gray-400 cursor-not-allowed' : 'bg-[#3489e3] hover:bg-blue-500'}`}>
Yangilash
</button>
)}
<button onClick={resetForm} className="bg-gray-400 hover:bg-gray-500 text-white px-5 py-2 rounded-lg shadow">
Tozalash
</button>
</div>
</div>
);
};
export default CreateBranches;