added get and create posts with back

This commit is contained in:
SlimusMinus
2026-05-07 01:10:10 +03:00
parent 1c9c84fe0e
commit a5cdfdd8b4
3 changed files with 58 additions and 33 deletions

View File

@@ -1,19 +1,17 @@
import {useCallback, useState} from "react"; import {useCallback, useState} from "react";
import {API_URL} from "../config/constants";
import PinIcon from "./icons/PinIcon"; import PinIcon from "./icons/PinIcon";
import CloseIcon from "./icons/CloseIcon"; import CloseIcon from "./icons/CloseIcon";
import { EMPTY_FORM, CATEGORIES } from "../config/feedConstants"; import { EMPTY_FORM, CATEGORIES } from "../config/feedConstants";
import { useCreatePost } from "../hooks/useCreatePost";
export default function PostModal({ onClose, onSuccess }) { export default function PostModal({ onClose, onSuccess }) {
const [form, setForm] = useState(EMPTY_FORM); const [form, setForm] = useState(EMPTY_FORM);
const [errors, setErrors] = useState({}); const [errors, setErrors] = useState({});
const [loading, setLoading] = useState(false); const { createAd, loading, error: apiError } = useCreatePost();
const [apiError, setApiError] = useState("");
const set = useCallback((k, v) => { const set = useCallback((k, v) => {
setForm(p => ({ ...p, [k]: v })); setForm(p => ({ ...p, [k]: v }));
setErrors(p => ({ ...p, [k]: "" })); setErrors(p => ({ ...p, [k]: "" }));
setApiError("");
}, []); }, []);
const validate = () => { const validate = () => {
@@ -28,25 +26,20 @@ export default function PostModal({ onClose, onSuccess }) {
const handleSubmit = async () => { const handleSubmit = async () => {
if (!validate()) return; if (!validate()) return;
setLoading(true);
setApiError(""); const payload = {
try { type: form.type, // "loss" | "found"
const res = await fetch(`${API_URL}/api/ads`, { title: form.title.trim(),
method: "POST", description: form.description.trim(),
headers: { "Content-Type": "application/json" }, category: form.category,
body: JSON.stringify(form), date: form.date || null,
}); phone: form.phone.trim(),
if (!res.ok) { };
const data = await res.json().catch(() => ({}));
throw new Error(data.message || `Ошибка ${res.status}`); const newAd = await createAd(payload);
} if (newAd) {
const newAd = await res.json();
onSuccess(newAd); onSuccess(newAd);
onClose(); onClose();
} catch (err) {
setApiError(err.message || "Не удалось разместить объявление");
} finally {
setLoading(false);
} }
}; };
@@ -107,15 +100,7 @@ export default function PostModal({ onClose, onSuccess }) {
</select> </select>
{errors.category && <p className="f-err-msg">{errors.category}</p>} {errors.category && <p className="f-err-msg">{errors.category}</p>}
</div> </div>
<div className="f-m-group">
<label className="f-m-label">Дата события</label>
<input
className="f-m-field"
type="date"
value={form.date}
onChange={e => set("date", e.target.value)}
/>
</div>
</div> </div>
<div className="f-m-group"> <div className="f-m-group">

View File

@@ -0,0 +1,42 @@
import { useState } from "react";
import { API_URL } from "../config/constants";
export function useCreatePost() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [success, setSuccess] = useState(false);
const createAd = async (adData) => {
setLoading(true);
setError(null);
try {
const token = localStorage.getItem("token");
const res = await fetch(`${API_URL}/api/v1/posts`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
},
body: JSON.stringify(adData),
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.message || "Ошибка при создании объявления");
}
setSuccess(true);
return data; // возвращает созданное объявление
} catch (e) {
setError(e.message);
return null;
} finally {
setLoading(false);
}
};
return { createAd, loading, error, success };
}

View File

@@ -7,7 +7,6 @@ import AdCard from "../components/AdCard";
import PostModal from "../components/PostModal"; import PostModal from "../components/PostModal";
import MenuIcon from "../components/icons/MenuIcon" import MenuIcon from "../components/icons/MenuIcon"
// ─── FEED PAGE ────────────────────────────────────────────────────────────────
export default function FeedPage() { export default function FeedPage() {
const [sidebarOpen, setSidebarOpen] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(false);
const [activeNav, setActiveNav] = useState("Главная"); const [activeNav, setActiveNav] = useState("Главная");
@@ -17,13 +16,12 @@ export default function FeedPage() {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(""); const [error, setError] = useState("");
// Загрузка объявлений с бэка
useEffect(() => { useEffect(() => {
const load = async () => { const load = async () => {
setLoading(true); setLoading(true);
setError(""); setError("");
try { try {
const res = await fetch(`${API_URL}/api/ads`); const res = await fetch(`${API_URL}/api/v1/posts`);
if (!res.ok) { if (!res.ok) {
throw new Error(`Ошибка ${res.status}`); throw new Error(`Ошибка ${res.status}`);
} }