Админ панель создания медиа

Пользователи с ролью "editor" и "admin" могут создавать и в дальнейшем редактировать медиа
This commit is contained in:
degradin 2025-05-07 13:38:46 +03:00
parent 89bbc975ce
commit 690c18e601

View File

@ -1,13 +1,19 @@
import { useState } from "react";
import React, { useEffect, useState } from 'react';
import { useMedia } from '../contexts/MediaContext';
import { listMedia } from '../services/supabase';
import { mediaTypes } from '../services/mediaService';
import { useAuth } from "../contexts/AuthContext";
import { useNavigate } from "react-router-dom";
import { createMedia } from "../services/supabase";
import { useAuth } from "../contexts/AuthContext";
function AdminMediaPage() {
const AdminMediaPage = () => {
const [media, setMedia] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const navigate = useNavigate();
const { currentUser, userProfile } = useAuth();
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const [mediaData, setMediaData] = useState({
title: "",
@ -19,21 +25,36 @@ function AdminMediaPage() {
is_published: false,
});
// Check if user has admin/moderator privileges
if (
!userProfile?.role ||
!["admin", "moderator"].includes(userProfile.role)
) {
// Проверка прав доступа
if (!userProfile?.role || !["admin", "editor"].includes(userProfile.role)) {
return (
<div className="pt-20 container-custom py-12">
<div className="bg-status-error bg-opacity-20 text-status-error p-6 rounded-lg">
<h2 className="text-xl font-bold mb-2">Access Denied</h2>
<p>You don't have permission to access this page.</p>
<h2 className="text-xl font-bold mb-2">Доступ запрещен</h2>
<p>У вас нет прав для доступа к этой странице.</p>
</div>
</div>
);
}
useEffect(() => {
const fetchMedia = async () => {
try {
setLoading(true);
setError(null);
const data = await listMedia(null, 1, 100); // Получаем все медиа
setMedia(data || []);
} catch (err) {
console.error('Error fetching media:', err);
setError('Не удалось загрузить медиа');
} finally {
setLoading(false);
}
};
fetchMedia();
}, []); // Запускаем только при монтировании компонента
const handleInputChange = (e) => {
const { name, value, type, checked } = e.target;
setMediaData((prev) => ({
@ -53,161 +74,148 @@ function AdminMediaPage() {
created_by: currentUser.id,
});
navigate(`/media/${newMedia.id}`);
setMedia(prev => [newMedia, ...prev]);
setMediaData({
title: "",
type: "movie",
poster_url: "",
backdrop_url: "",
overview: "",
release_date: "",
is_published: false,
});
} catch (err) {
setError("Failed to create media. Please try again.");
setError("Ошибка при создании медиа. Пожалуйста, попробуйте снова.");
console.error("Error creating media:", err);
} finally {
setLoading(false);
}
};
if (loading) {
return <div className="text-center">Загрузка...</div>;
}
if (error) {
return <div className="text-red-500">{error}</div>;
}
return (
<div className="pt-20 container-custom py-12">
<h1 className="text-3xl font-bold mb-6">Create New Media</h1>
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-8">Управление медиа</h1>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{media.map((item) => (
<div key={`${item.id}-${item.type}`} className="bg-white rounded-lg shadow-md p-4">
<h3 className="text-lg font-semibold mb-2">{item.title}</h3>
<p className="text-gray-600 mb-2">Тип: {item.type}</p>
{item.rating && (
<p className="text-gray-600">Рейтинг: {item.rating}</p>
)}
</div>
))}
</div>
{error && (
<div className="bg-status-error bg-opacity-20 text-status-error p-4 rounded-md mb-6">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="max-w-2xl">
<div className="space-y-6">
{/* Форма создания медиа */}
<div className="bg-campfire-charcoal p-6 rounded-lg mb-8">
<h2 className="text-2xl font-bold mb-4">Создать новое медиа</h2>
{error && (
<div className="bg-status-error bg-opacity-20 text-status-error p-4 rounded-lg mb-4">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-campfire-light mb-2" htmlFor="title">
Title *
</label>
<label className="block text-sm font-medium mb-1">Название</label>
<input
type="text"
id="title"
name="title"
value={mediaData.title}
onChange={handleInputChange}
className="input w-full"
required
className="input w-full"
/>
</div>
<div>
<label className="block text-campfire-light mb-2" htmlFor="type">
Type *
</label>
<label className="block text-sm font-medium mb-1">Тип</label>
<select
id="type"
name="type"
value={mediaData.type}
onChange={handleInputChange}
className="input w-full"
required
>
<option value="movie">Movie</option>
<option value="tv">TV Show</option>
<option value="game">Game</option>
<option value="movie">Фильм</option>
<option value="series">Сериал</option>
<option value="game">Игра</option>
</select>
</div>
<div>
<label
className="block text-campfire-light mb-2"
htmlFor="poster_url"
>
Poster URL
</label>
<label className="block text-sm font-medium mb-1">URL постера</label>
<input
type="url"
id="poster_url"
name="poster_url"
value={mediaData.poster_url}
onChange={handleInputChange}
className="input w-full"
placeholder="https://example.com/poster.jpg"
/>
</div>
<div>
<label
className="block text-campfire-light mb-2"
htmlFor="backdrop_url"
>
Backdrop URL
</label>
<label className="block text-sm font-medium mb-1">URL фона</label>
<input
type="url"
id="backdrop_url"
name="backdrop_url"
value={mediaData.backdrop_url}
onChange={handleInputChange}
className="input w-full"
placeholder="https://example.com/backdrop.jpg"
/>
</div>
<div>
<label
className="block text-campfire-light mb-2"
htmlFor="overview"
>
Overview *
</label>
<label className="block text-sm font-medium mb-1">Описание</label>
<textarea
id="overview"
name="overview"
value={mediaData.overview}
onChange={handleInputChange}
className="input w-full h-32"
required
/>
</div>
<div>
<label
className="block text-campfire-light mb-2"
htmlFor="release_date"
>
Release Date
</label>
<label className="block text-sm font-medium mb-1">Дата выхода</label>
<input
type="date"
id="release_date"
name="release_date"
value={mediaData.release_date}
onChange={handleInputChange}
className="input w-full"
/>
</div>
<div className="flex items-center">
<input
type="checkbox"
id="is_published"
name="is_published"
checked={mediaData.is_published}
onChange={handleInputChange}
className="w-4 h-4 text-campfire-amber bg-campfire-dark border-campfire-ash rounded focus:ring-campfire-amber"
className="mr-2"
/>
<label className="ml-2 text-campfire-light" htmlFor="is_published">
Publish immediately
</label>
<label className="text-sm font-medium">Опубликовать сразу</label>
</div>
<div className="flex justify-end gap-4">
<button
type="button"
onClick={() => navigate(-1)}
className="btn-secondary"
disabled={loading}
>
Cancel
</button>
<button type="submit" className="btn-primary" disabled={loading}>
{loading ? "Creating..." : "Create Media"}
</button>
</div>
</div>
</form>
<button
type="submit"
disabled={loading}
className="btn-primary w-full"
>
{loading ? "Создание..." : "Создать медиа"}
</button>
</form>
</div>
</div>
);
}
};
export default AdminMediaPage;