added calendar on press create date
This commit is contained in:
50
src/components/DateCalendarPopup.jsx
Normal file
50
src/components/DateCalendarPopup.jsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
|
||||
const MONTHS = ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"];
|
||||
const DAYS = ["Пн","Вт","Ср","Чт","Пт","Сб","Вс"];
|
||||
|
||||
export default function DateCalendarPopup({ date, onClose }) {
|
||||
const ref = useRef(null);
|
||||
const d = new Date(date);
|
||||
const [year, setYear] = useState(d.getFullYear());
|
||||
const [month, setMonth] = useState(d.getMonth());
|
||||
|
||||
useEffect(() => {
|
||||
const handler = (e) => { if (ref.current && !ref.current.contains(e.target)) onClose(); };
|
||||
document.addEventListener("mousedown", handler);
|
||||
return () => document.removeEventListener("mousedown", handler);
|
||||
}, [onClose]);
|
||||
|
||||
const firstDay = new Date(year, month, 1).getDay();
|
||||
const offset = firstDay === 0 ? 6 : firstDay - 1;
|
||||
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
||||
|
||||
const cells = [];
|
||||
for (let i = 0; i < offset; i++) cells.push(null);
|
||||
for (let i = 1; i <= daysInMonth; i++) cells.push(i);
|
||||
|
||||
const isSameDay = (day) =>
|
||||
d.getFullYear() === year && d.getMonth() === month && d.getDate() === day;
|
||||
|
||||
return (
|
||||
<div className="f-date-calendar" ref={ref}>
|
||||
<div className="f-cal-header">
|
||||
<button onClick={() => setMonth(m => m === 0 ? (setYear(y => y - 1), 11) : m - 1)}>‹</button>
|
||||
<span>{MONTHS[month]} {year}</span>
|
||||
<button onClick={() => setMonth(m => m === 11 ? (setYear(y => y + 1), 0) : m + 1)}>›</button>
|
||||
</div>
|
||||
<div className="f-cal-grid">
|
||||
{DAYS.map(d => <div key={d} className="f-cal-day-name">{d}</div>)}
|
||||
{cells.map((day, i) =>
|
||||
day ? (
|
||||
<div key={i}
|
||||
className={`f-cal-day${isSameDay(day) ? " f-cal-selected" : ""}`}
|
||||
>
|
||||
{day}
|
||||
</div>
|
||||
) : <div key={i} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -441,13 +441,6 @@ export default function MainFeed() {
|
||||
|
||||
{/* Фильтр по типу объявления */}
|
||||
<div className="f-filter-bar">
|
||||
<button
|
||||
className={`f-filter-btn${typeFilter === null ? " active"
|
||||
: ""}`}
|
||||
onClick={() => setTypeFilter(null)}
|
||||
>
|
||||
Все объявления
|
||||
</button>
|
||||
<button
|
||||
className={`f-filter-btn${typeFilter === "loss" ? " active"
|
||||
: ""}`}
|
||||
@@ -455,6 +448,13 @@ export default function MainFeed() {
|
||||
>
|
||||
🔴 Потери
|
||||
</button>
|
||||
<button
|
||||
className={`f-filter-btn${typeFilter === null ? " active"
|
||||
: ""}`}
|
||||
onClick={() => setTypeFilter(null)}
|
||||
>
|
||||
Все объявления
|
||||
</button>
|
||||
<button
|
||||
className={`f-filter-btn${typeFilter === "found" ? " active"
|
||||
: ""}`}
|
||||
|
||||
@@ -4,12 +4,15 @@ import PhoneIcon from "./icons/PhoneIcon";
|
||||
import MapIcon from "./icons/MapIcon";
|
||||
import HeartIcon from "./icons/HeartIcon";
|
||||
import TrashIcon from "./icons/TrashIcon";
|
||||
import { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useChats } from "../hooks/useChats";
|
||||
import { useAuthContext } from "../context/AuthContext";
|
||||
import { API_URL } from "../config/authConstants";
|
||||
import DateCalendarPopup from "./DateCalendarPopup";
|
||||
|
||||
export default function PostOnFeed({ ad, liked, onLike, onEdit, onDelete, onMarkFound, isOwner, onImageClick, onAuthRequired }) {
|
||||
const [showCalendar, setShowCalendar] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const { createOrGetChat } = useChats();
|
||||
const { isAuthenticated } = useAuthContext();
|
||||
@@ -76,15 +79,21 @@ export default function PostOnFeed({ ad, liked, onLike, onEdit, onDelete, onMark
|
||||
{ad.type === "loss" ? "Потеря" : "Находка"}
|
||||
</div>
|
||||
{roleBadge}
|
||||
{isClosed && <div className="f-status-badge f-status-closed">✓ Найдено</div>}
|
||||
</div>
|
||||
<div className="f-card-title">{ad.title}</div>
|
||||
<div className="f-card-title">
|
||||
{ad.title}
|
||||
{isClosed && <span className="f-status-badge f-status-closed">✓ Найдено</span>}
|
||||
</div>
|
||||
<div className="f-card-desc">{ad.description}</div>
|
||||
<div className="f-card-meta">
|
||||
{/* ✅ address вместо ad.location */}
|
||||
{address && <div className="f-meta-pill"><PinIcon /> {address}</div>}
|
||||
{/* ✅ createdAt вместо ad.date */}
|
||||
{createdAt && <div className="f-meta-pill"><CalendarIcon /> {createdAt}</div>}
|
||||
{createdAt && (
|
||||
<div className="f-meta-pill f-date-pill" onClick={e => { e.stopPropagation(); setShowCalendar(s => !s); }}>
|
||||
<CalendarIcon /> {createdAt}
|
||||
{showCalendar && <DateCalendarPopup date={ad.createdAt} onClose={() => setShowCalendar(false)} />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{address && (
|
||||
<button className="f-card-map" onClick={e => e.stopPropagation()}>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// ─── CONSTANTS ────────────────────────────────────────────────────────────────
|
||||
export const NAV_ITEMS = [
|
||||
{ icon: "grid", label: "Главная" },
|
||||
{ icon: "file", label: "Мои объявления" },
|
||||
{ icon: "box", label: "Вещи" },
|
||||
{ icon: "paw", label: "Питомцы" },
|
||||
{ icon: "chat", label: "Чат" },
|
||||
{ icon: "file", label: "Мои объявления" },
|
||||
];
|
||||
|
||||
export const NAV_BOTTOM = [
|
||||
|
||||
@@ -43,9 +43,10 @@
|
||||
|
||||
/* Status badge for closed/found posts */
|
||||
.f-status-badge {
|
||||
border-radius: 20px; padding: 3px 10px;
|
||||
font-size: .72rem; font-weight: 900;
|
||||
position: absolute; left: 50%; transform: translateX(-50%);
|
||||
border-radius: 20px; padding: 2px 8px;
|
||||
font-size: .7rem; font-weight: 900;
|
||||
display: inline-block; vertical-align: middle;
|
||||
margin-left: 8px;
|
||||
}
|
||||
.f-status-closed {
|
||||
background: rgba(72,187,120,.2); color: #48bb78; border: 1px solid rgba(72,187,120,.3);
|
||||
@@ -109,6 +110,13 @@
|
||||
background: var(--hover-bg); border: 1px solid var(--border);
|
||||
border-radius: 20px; padding: 3px 9px; font-size: .73rem; color: var(--muted);
|
||||
}
|
||||
.f-date-pill {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
.f-date-pill:hover {
|
||||
background: rgba(128,128,128,.12);
|
||||
}
|
||||
|
||||
/* Map stub */
|
||||
.f-card-map {
|
||||
@@ -220,4 +228,62 @@
|
||||
.f-card-phone {
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Calendar Popup ── */
|
||||
.f-date-calendar {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 6px);
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 10px;
|
||||
width: 220px;
|
||||
box-shadow: 0 8px 32px rgba(0,0,0,.25);
|
||||
}
|
||||
.f-cal-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
font-size: .82rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
.f-cal-header button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-primary);
|
||||
font-size: 1.1rem;
|
||||
cursor: pointer;
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
line-height: 1;
|
||||
}
|
||||
.f-cal-header button:hover {
|
||||
background: rgba(128,128,128,.15);
|
||||
}
|
||||
.f-cal-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
gap: 2px;
|
||||
text-align: center;
|
||||
font-size: .75rem;
|
||||
}
|
||||
.f-cal-day-name {
|
||||
font-weight: 700;
|
||||
color: var(--muted);
|
||||
padding: 4px 0;
|
||||
font-size: .68rem;
|
||||
}
|
||||
.f-cal-day {
|
||||
padding: 4px 0;
|
||||
border-radius: 6px;
|
||||
cursor: default;
|
||||
}
|
||||
.f-cal-selected {
|
||||
background: rgba(var(--teal-rgb), .25);
|
||||
color: var(--teal);
|
||||
font-weight: 800;
|
||||
}
|
||||
Reference in New Issue
Block a user