Удалены устаревшие файлы документации и отчетов, включая ADMIN_DESIGN_IMPROVEMENTS.md, DATABASE_SETUP.md, FIX_REPORT.md, IMPLEMENTATION_SUMMARY.md, S3_SETUP.md, S3_TROUBLESHOOTING.md. Обновлен docker-compose.yml для упрощения проверки состояния контейнера. Исправлены ошибки в компонентах админ-панели, включая улучшение логики авторизации и загрузки категорий новостей.
This commit is contained in:
@ -4,7 +4,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import { ArrowLeft, Save, Eye, Upload, X, Trash2 } from 'lucide-react';
|
||||
import { NEWS_CATEGORIES, NewsFormData, NewsCategory } from '@/lib/types';
|
||||
import { NewsFormData, NewsCategory } from '@/lib/types';
|
||||
// import { getNewsById } from '@/lib/news-data';
|
||||
|
||||
interface EditNewsPageProps {
|
||||
@ -35,8 +35,24 @@ export default function EditNewsPage({ params }: EditNewsPageProps) {
|
||||
|
||||
const [errors, setErrors] = useState<Partial<NewsFormData>>({});
|
||||
const [tagInput, setTagInput] = useState('');
|
||||
const [categories, setCategories] = useState<{ id: string; name: string }[]>([
|
||||
{ id: 'company', name: 'Новости компании' },
|
||||
{ id: 'promotions', name: 'Акции' },
|
||||
{ id: 'other', name: 'Другое' }
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
// подгружаем категории
|
||||
(async () => {
|
||||
try {
|
||||
const res = await fetch('/api/categories', { cache: 'no-store' });
|
||||
const data = await res.json();
|
||||
if (res.ok && data?.data?.length) {
|
||||
setCategories(data.data.map((c: any) => ({ id: c.slug, name: c.name })));
|
||||
}
|
||||
} catch {}
|
||||
})();
|
||||
|
||||
const loadNews = async () => {
|
||||
const resolvedParams = await params;
|
||||
const id = resolvedParams.id;
|
||||
@ -300,7 +316,7 @@ export default function EditNewsPage({ params }: EditNewsPageProps) {
|
||||
onChange={(e) => setFormData(prev => ({ ...prev, category: e.target.value as NewsCategory }))}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
>
|
||||
{NEWS_CATEGORIES.map((category) => (
|
||||
{categories.map((category) => (
|
||||
<option key={category.id} value={category.id}>
|
||||
{category.name}
|
||||
</option>
|
||||
@ -506,10 +522,8 @@ export default function EditNewsPage({ params }: EditNewsPageProps) {
|
||||
</h4>
|
||||
|
||||
<div className="flex items-center space-x-2 mb-4">
|
||||
<span className={`px-2 py-1 rounded-full text-xs font-medium text-white ${
|
||||
NEWS_CATEGORIES.find(cat => cat.id === formData.category)?.color || 'bg-gray-500'
|
||||
}`}>
|
||||
{NEWS_CATEGORIES.find(cat => cat.id === formData.category)?.name}
|
||||
<span className={`px-2 py-1 rounded-full text-xs font-medium text-white bg-gray-500`}>
|
||||
{categories.find(cat => cat.id === formData.category)?.name || 'Категория'}
|
||||
</span>
|
||||
{formData.featured && (
|
||||
<span className="px-2 py-1 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
|
||||
|
@ -1,17 +1,13 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { ArrowLeft, Save, X } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import TextEditor from '@/app/admin/components/TextEditor';
|
||||
import ImageUpload from '@/app/admin/components/ImageUpload';
|
||||
|
||||
const NEWS_CATEGORIES = [
|
||||
{ id: 'company', name: 'Новости компании' },
|
||||
{ id: 'promotions', name: 'Акции' },
|
||||
{ id: 'other', name: 'Другое' }
|
||||
];
|
||||
interface UiCategory { id: string; name: string }
|
||||
|
||||
export default function CreateNewsPage() {
|
||||
const router = useRouter();
|
||||
@ -29,6 +25,25 @@ export default function CreateNewsPage() {
|
||||
tags: [] as string[]
|
||||
});
|
||||
const [tagInput, setTagInput] = useState('');
|
||||
const [categories, setCategories] = useState<UiCategory[]>([
|
||||
{ id: 'company', name: 'Новости компании' },
|
||||
{ id: 'promotions', name: 'Акции' },
|
||||
{ id: 'other', name: 'Другое' }
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const res = await fetch('/api/categories', { cache: 'no-store' });
|
||||
const data = await res.json();
|
||||
if (res.ok && data?.data?.length) {
|
||||
setCategories(data.data.map((c: any) => ({ id: c.slug, name: c.name })));
|
||||
// если выбранная категория отсутствует — выставим первую
|
||||
setFormData(prev => ({ ...prev, category: data.data[0]?.slug || prev.category }));
|
||||
}
|
||||
} catch {}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const generateSlug = (title: string) => {
|
||||
return title
|
||||
@ -238,7 +253,7 @@ export default function CreateNewsPage() {
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
required
|
||||
>
|
||||
{NEWS_CATEGORIES.map((category) => (
|
||||
{categories.map((category) => (
|
||||
<option key={category.id} value={category.id}>
|
||||
{category.name}
|
||||
</option>
|
||||
|
@ -33,13 +33,14 @@ interface NewsCategory {
|
||||
color: string;
|
||||
}
|
||||
|
||||
const NEWS_CATEGORIES: NewsCategory[] = [
|
||||
const DEFAULT_CATEGORIES: NewsCategory[] = [
|
||||
{ id: 'company', name: 'Новости компании', slug: 'company', color: 'bg-blue-500' },
|
||||
{ id: 'promotions', name: 'Акции', slug: 'promotions', color: 'bg-green-500' },
|
||||
{ id: 'other', name: 'Другое', slug: 'other', color: 'bg-purple-500' }
|
||||
];
|
||||
|
||||
export default function AdminNewsPage() {
|
||||
const [categories, setCategories] = useState<NewsCategory[]>(DEFAULT_CATEGORIES);
|
||||
const [news, setNews] = useState<NewsItem[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
@ -52,6 +53,18 @@ export default function AdminNewsPage() {
|
||||
loadNews();
|
||||
}, [searchQuery, selectedCategory, selectedStatus, sortBy, sortOrder]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const res = await fetch('/api/categories', { cache: 'no-store' });
|
||||
const data = await res.json();
|
||||
if (res.ok && data?.data?.length) {
|
||||
setCategories(data.data.map((c: any) => ({ id: c.slug, name: c.name, slug: c.slug, color: c.color || 'bg-blue-500' })));
|
||||
}
|
||||
} catch {}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const loadNews = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
@ -102,9 +115,7 @@ export default function AdminNewsPage() {
|
||||
});
|
||||
};
|
||||
|
||||
const getCategoryInfo = (categoryId: string) => {
|
||||
return NEWS_CATEGORIES.find(cat => cat.id === categoryId);
|
||||
};
|
||||
const getCategoryInfo = (categoryId: string) => categories.find(cat => cat.id === categoryId);
|
||||
|
||||
const handleDelete = async (id: string) => {
|
||||
if (!confirm('Вы уверены, что хотите удалить эту новость?')) {
|
||||
@ -230,7 +241,7 @@ export default function AdminNewsPage() {
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
>
|
||||
<option value="all">Все категории</option>
|
||||
{NEWS_CATEGORIES.map((category) => (
|
||||
{categories.map((category) => (
|
||||
<option key={category.id} value={category.id}>
|
||||
{category.name}
|
||||
</option>
|
||||
|
Reference in New Issue
Block a user