end
This commit is contained in:
@@ -41,17 +41,19 @@ const CreateRequestPage = () => {
|
||||
latitude &&
|
||||
longitude;
|
||||
|
||||
// профиль
|
||||
const getAccessToken = () => {
|
||||
if (typeof window === "undefined") return null;
|
||||
const saved = localStorage.getItem("authUser");
|
||||
const authUser = saved ? JSON.parse(saved) : null;
|
||||
return authUser?.accessToken || null;
|
||||
};
|
||||
|
||||
// профиль + автоподстановка адреса/города/телефона
|
||||
useEffect(() => {
|
||||
const fetchProfile = async () => {
|
||||
if (!API_BASE) return;
|
||||
|
||||
const saved =
|
||||
typeof window !== "undefined"
|
||||
? localStorage.getItem("authUser")
|
||||
: null;
|
||||
const authUser = saved ? JSON.parse(saved) : null;
|
||||
const accessToken = authUser?.accessToken;
|
||||
const accessToken = getAccessToken();
|
||||
if (!accessToken) return;
|
||||
|
||||
try {
|
||||
@@ -67,32 +69,43 @@ const CreateRequestPage = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
const data = await res.json(); // UserProfile
|
||||
const fullName =
|
||||
[data.first_name, data.last_name]
|
||||
.filter(Boolean)
|
||||
.join(" ")
|
||||
.trim() || data.email;
|
||||
[data.first_name, data.last_name].filter(Boolean).join(" ").trim() ||
|
||||
data.email;
|
||||
setUserName(fullName);
|
||||
|
||||
// подставляем только если поля ещё пустые, чтобы не перетирать ручной ввод
|
||||
if (!address && data.address) {
|
||||
setAddress(data.address);
|
||||
}
|
||||
if (!city && data.city) {
|
||||
setCity(data.city);
|
||||
}
|
||||
if (!phone && data.phone) {
|
||||
setPhone(data.phone);
|
||||
}
|
||||
} catch (e) {
|
||||
setProfileError("Ошибка загрузки профиля");
|
||||
}
|
||||
};
|
||||
|
||||
fetchProfile();
|
||||
}, []);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []); // однократно при монтировании
|
||||
|
||||
// геолокация
|
||||
useEffect(() => {
|
||||
if (!("geolocation" in navigator)) {
|
||||
if (typeof navigator === "undefined" || !("geolocation" in navigator)) {
|
||||
setGeoError("Геолокация не поддерживается браузером");
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(pos) => {
|
||||
const { latitude, longitude } = pos.coords;
|
||||
setLatitude(latitude.toFixed(6));
|
||||
setLongitude(longitude.toFixed(6));
|
||||
const { latitude: lat, longitude: lon } = pos.coords;
|
||||
setLatitude(lat.toFixed(6));
|
||||
setLongitude(lon.toFixed(6));
|
||||
setGeoError("");
|
||||
},
|
||||
(err) => {
|
||||
@@ -115,13 +128,7 @@ const CreateRequestPage = () => {
|
||||
setError("");
|
||||
setIsSubmitting(true);
|
||||
|
||||
const saved =
|
||||
typeof window !== "undefined"
|
||||
? localStorage.getItem("authUser")
|
||||
: null;
|
||||
const authUser = saved ? JSON.parse(saved) : null;
|
||||
const accessToken = authUser?.accessToken;
|
||||
|
||||
const accessToken = getAccessToken();
|
||||
if (!accessToken) {
|
||||
setError("Вы не авторизованы");
|
||||
setIsSubmitting(false);
|
||||
@@ -132,7 +139,7 @@ const CreateRequestPage = () => {
|
||||
const desired_completion_date = desiredDateTime.toISOString();
|
||||
|
||||
const body = {
|
||||
request_type_id: 1, // можно потом вынести в селект
|
||||
request_type_id: 1, // TODO: вынести в селект типов
|
||||
title,
|
||||
description,
|
||||
latitude: Number(latitude),
|
||||
@@ -236,7 +243,7 @@ const CreateRequestPage = () => {
|
||||
</div>
|
||||
|
||||
{/* Адрес */}
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex flex-col gap-1 mt-2">
|
||||
<label className="font-montserrat font-bold text-[10px] text-white/90">
|
||||
Адрес
|
||||
</label>
|
||||
@@ -258,7 +265,7 @@ const CreateRequestPage = () => {
|
||||
type="text"
|
||||
value={city}
|
||||
onChange={(e) => setCity(e.target.value)}
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm font-mонтserrat text-white placeholder:text-white/70 outline-none focus:ring-2 focus:ring-blue-200"
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm font-montserrat text-white placeholder:text-white/70 outline-none focus:ring-2 focus:ring-blue-200"
|
||||
placeholder="Например: Пермь"
|
||||
/>
|
||||
</div>
|
||||
@@ -287,7 +294,7 @@ const CreateRequestPage = () => {
|
||||
step="0.000001"
|
||||
value={longitude}
|
||||
onChange={(e) => setLongitude(e.target.value)}
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm font-mонтserrat text-white placeholder:text.white/70 outline-none focus:ring-2 focus:ring-blue-200"
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm font-montserrat text-white placeholder:text-white/70 outline-none focus:ring-2 focus:ring-blue-200"
|
||||
placeholder="37.618423"
|
||||
/>
|
||||
</div>
|
||||
@@ -299,9 +306,8 @@ const CreateRequestPage = () => {
|
||||
</p>
|
||||
)}
|
||||
|
||||
|
||||
{/* Дата и Время */}
|
||||
<div className="flex gap-3">
|
||||
<div className="flex gap-3 mt-2">
|
||||
<div className="flex-1 flex flex-col gap-1">
|
||||
<label className="font-montserrat font-bold text-[10px] text-white/90">
|
||||
Дата
|
||||
@@ -321,20 +327,20 @@ const CreateRequestPage = () => {
|
||||
type="time"
|
||||
value={time}
|
||||
onChange={(e) => setTime(e.target.value)}
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm font-mонтserrat text-white outline-none focus:ring-2 focus:ring-blue-200"
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm font-montserrat text-white outline-none focus:ring-2 focus:ring-blue-200"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Срочность */}
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex flex-col gap-1 mt-2">
|
||||
<label className="font-montserrat font-bold text-[10px] text-white/90">
|
||||
Срочность
|
||||
</label>
|
||||
<select
|
||||
value={urgency}
|
||||
onChange={(e) => setUrgency(e.target.value)}
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm.font-montserrat text-white outline-none focus:ring-2 focus:ring-blue-200"
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm font-montserrat text-white outline-none focus:ring-2 focus:ring-blue-200"
|
||||
>
|
||||
<option value="low">Низкая</option>
|
||||
<option value="medium">Средняя</option>
|
||||
@@ -344,7 +350,7 @@ const CreateRequestPage = () => {
|
||||
</div>
|
||||
|
||||
{/* Телефон для связи */}
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex flex-col gap-1 mt-2">
|
||||
<label className="font-montserrat font-bold text-[10px] text-white/90">
|
||||
Телефон для связи
|
||||
</label>
|
||||
@@ -352,65 +358,48 @@ const CreateRequestPage = () => {
|
||||
type="tel"
|
||||
value={phone}
|
||||
onChange={(e) => setPhone(e.target.value)}
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm.font-montserrat text-white placeholder:text.white/70 outline-none focus:ring-2 focus:ring-blue-200"
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm font-montserrat text-white placeholder:text-white/70 outline-none focus:ring-2 focus:ring-blue-200"
|
||||
placeholder="+7 900 000 00 00"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Описание */}
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="font-montserrat font-bold text-[10px] text-white/90">
|
||||
<div className="flex flex-col gap-1 mt-2">
|
||||
<label className="font-montserrat font-bold text-[10px] text-white">
|
||||
Описание
|
||||
</label>
|
||||
<textarea
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
rows={3}
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm.font-montserrat text-white.placeholder:text-white/70 outline-none focus:ring-2 focus:ring-blue-200 resize-none"
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm font-montserrat text-white placeholder:text-white/70 outline-none focus:ring-2 focus:ring-blue-200 resize-none"
|
||||
placeholder="Подробно опишите, что нужно сделать"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Дополнительно */}
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="font-montserrat.font-bold text-[10px] text-white/90">
|
||||
<div className="flex flex-col gap-1 mt-2">
|
||||
<label className="font-montserrat font-bold text-[10px] text-white/90">
|
||||
Дополнительно
|
||||
</label>
|
||||
<textarea
|
||||
value={note}
|
||||
onChange={(e) => setNote(e.target.value)}
|
||||
rows={2}
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm.font-montserrat text-white.placeholder:text.white/70 outline-none focus:ring-2 focus:ring-blue-200 resize-none"
|
||||
className="w-full bg-[#72B8E2] rounded-lg px-3 py-3 text-sm font-montserrat text-white placeholder:text-white/70 outline-none focus:ring-2 focus:ring-blue-200 resize-none"
|
||||
placeholder="Комментарий (необязательно)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Добавить фото — пока без API */}
|
||||
<div className="flex items-center gap-3 mt-5">
|
||||
<button
|
||||
type="button"
|
||||
className="w-15 h-15 bg-[#f3f3f3] rounded-lg flex items-center justify-center"
|
||||
>
|
||||
<span className="text-2xl text-[#E2E2E2] leading-none">+</span>
|
||||
</button>
|
||||
<div className="flex gap-2">
|
||||
<div className="w-15 h-15 bg-[#E2E2E2] rounded-lg" />
|
||||
<div className="w-15 h-15 bg-[#E2E2E2] rounded-lg" />
|
||||
</div>
|
||||
<span className="font-montserrat font-bold text-[14px] text-[#72B8E2] ml-2">
|
||||
Добавить фото
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Кнопка Отправить */}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!isFormValid || isSubmitting}
|
||||
className={`mt-5 w-full rounded-lg py-3 text-center font-montserrat font-bold text-sm transition-colors
|
||||
${isFormValid && !isSubmitting
|
||||
className={`mt-5 w-full rounded-lg py-3 text-center font-montserrat font-bold text-sm transition-colors ${
|
||||
isFormValid && !isSubmitting
|
||||
? "bg-[#94E067] text-white hover:bg-green-600"
|
||||
: "bg-[#94E067]/60 text-white/70 cursor-not-allowed"
|
||||
}`}
|
||||
}`}
|
||||
>
|
||||
{isSubmitting ? "Отправка..." : "Отправить"}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user