|
@@ -257,6 +257,69 @@ const FILTERS: { key: string; label: string }[] = [
|
|
|
{ key: 'rejected', label: 'Отклонено' },
|
|
{ key: 'rejected', label: 'Отклонено' },
|
|
|
]
|
|
]
|
|
|
|
|
|
|
|
|
|
+function PlaceCard({ place, onEdit, onDeleted }: { place: Place; onEdit: () => void; onDeleted: () => void }) {
|
|
|
|
|
+ const [showConfirm, setShowConfirm] = useState(false)
|
|
|
|
|
+ const [deleting, setDeleting] = useState(false)
|
|
|
|
|
+ const st = STATUS_LABELS[place.status] || { label: place.status, color: 'text-white/40' }
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div className="rounded-xl bg-white/5 p-4 text-white">
|
|
|
|
|
+ <div className="flex items-start justify-between gap-3">
|
|
|
|
|
+ <div className="flex-1 min-w-0">
|
|
|
|
|
+ <h2 className="text-lg font-semibold truncate">{place.title}</h2>
|
|
|
|
|
+ {place.address && <p className="mt-1 text-sm text-white/60 truncate">{place.address}</p>}
|
|
|
|
|
+ <div className="mt-2 flex items-center gap-3 text-sm">
|
|
|
|
|
+ <span className={st.color}>{st.label}</span>
|
|
|
|
|
+ {place.type === 'studio' && <span className="text-white/40">Студия</span>}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ {place.moderation_comment && (
|
|
|
|
|
+ <p className="mt-2 rounded bg-yellow-500/10 px-3 py-2 text-sm text-yellow-400">
|
|
|
|
|
+ Комментарий модератора: {place.moderation_comment}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className="flex shrink-0 gap-2">
|
|
|
|
|
+ <button onClick={onEdit}
|
|
|
|
|
+ className="rounded-lg bg-white/10 px-4 py-1.5 text-sm text-white hover:bg-white/20 transition"
|
|
|
|
|
+ >Редактировать</button>
|
|
|
|
|
+ <button onClick={() => setShowConfirm(true)}
|
|
|
|
|
+ className="rounded-lg bg-red-600/80 px-4 py-1.5 text-sm text-white hover:bg-red-500 transition"
|
|
|
|
|
+ >Удалить</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ {showConfirm && (
|
|
|
|
|
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60" onClick={() => setShowConfirm(false)}>
|
|
|
|
|
+ <div className="w-full max-w-sm rounded-xl bg-[#1e293b] p-6 shadow-xl" onClick={(e) => e.stopPropagation()}>
|
|
|
|
|
+ <h3 className="mb-2 text-lg font-bold text-white">Удалить место?</h3>
|
|
|
|
|
+ <p className="mb-4 text-sm text-white/60">{place.title}</p>
|
|
|
|
|
+ <p className="mb-4 text-sm text-red-400">Это действие нельзя отменить.</p>
|
|
|
|
|
+ <div className="flex justify-end gap-3">
|
|
|
|
|
+ <button onClick={() => setShowConfirm(false)} disabled={deleting}
|
|
|
|
|
+ className="rounded-lg bg-white/10 px-4 py-2 text-sm text-white hover:bg-white/20 transition disabled:opacity-50"
|
|
|
|
|
+ >Отмена</button>
|
|
|
|
|
+ <button onClick={async () => {
|
|
|
|
|
+ setDeleting(true)
|
|
|
|
|
+ try {
|
|
|
|
|
+ await api.delete(`/places/${place.id}`)
|
|
|
|
|
+ setShowConfirm(false)
|
|
|
|
|
+ onDeleted()
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ setShowConfirm(false)
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ setDeleting(false)
|
|
|
|
|
+ }
|
|
|
|
|
+ }} disabled={deleting}
|
|
|
|
|
+ className="rounded-lg bg-red-600 px-4 py-2 text-sm text-white hover:bg-red-500 transition disabled:opacity-50"
|
|
|
|
|
+ >{deleting ? 'Удаление...' : 'Удалить'}</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
export default function MyPlacesPage() {
|
|
export default function MyPlacesPage() {
|
|
|
const [places, setPlaces] = useState<Place[]>([])
|
|
const [places, setPlaces] = useState<Place[]>([])
|
|
|
const [loading, setLoading] = useState(true)
|
|
const [loading, setLoading] = useState(true)
|
|
@@ -313,29 +376,20 @@ export default function MyPlacesPage() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
- <div className="space-y-4">
|
|
|
|
|
- {filtered.map((place) => {
|
|
|
|
|
- const st = STATUS_LABELS[place.status] || { label: place.status, color: 'text-white/40' }
|
|
|
|
|
- return (
|
|
|
|
|
- <div key={place.id} className="rounded-xl bg-white/5 p-4 text-white">
|
|
|
|
|
- <h2 className="text-lg font-semibold">{place.title}</h2>
|
|
|
|
|
- {place.address && <p className="mt-1 text-sm text-white/60">{place.address}</p>}
|
|
|
|
|
- <div className="mt-2 flex items-center gap-3 text-sm">
|
|
|
|
|
- <span className={st.color}>{st.label}</span>
|
|
|
|
|
- {place.type === 'studio' && <span className="text-white/40">Студия</span>}
|
|
|
|
|
- </div>
|
|
|
|
|
- {place.moderation_comment && (
|
|
|
|
|
- <p className="mt-2 rounded bg-yellow-500/10 px-3 py-2 text-sm text-yellow-400">
|
|
|
|
|
- Комментарий модератора: {place.moderation_comment}
|
|
|
|
|
- </p>
|
|
|
|
|
- )}
|
|
|
|
|
- <button onClick={() => setEditId(place.id)}
|
|
|
|
|
- className="mt-3 rounded-lg bg-white/10 px-4 py-1.5 text-sm text-white hover:bg-white/20 transition"
|
|
|
|
|
- >Редактировать</button>
|
|
|
|
|
- </div>
|
|
|
|
|
- )
|
|
|
|
|
- })}
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div className="max-h-[calc(100vh-14rem)] space-y-4 overflow-y-auto pr-1">
|
|
|
|
|
+ {filtered.map((place) => (
|
|
|
|
|
+ <PlaceCard
|
|
|
|
|
+ key={place.id}
|
|
|
|
|
+ place={place}
|
|
|
|
|
+ onEdit={() => setEditId(place.id)}
|
|
|
|
|
+ onDeleted={() => {
|
|
|
|
|
+ setPlaces((prev) => prev.filter((p) => p.id !== place.id))
|
|
|
|
|
+ setToast('Место удалено')
|
|
|
|
|
+ setTimeout(() => setToast(''), 3000)
|
|
|
|
|
+ }}
|
|
|
|
|
+ />
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
)
|
|
)
|
|
|
})()}
|
|
})()}
|
|
|
</div>
|
|
</div>
|