Market-Frontend/src/pages/dashboard/plugin/ManagePlugin.tsx
2026-08-27 23:13:46 +02:00

181 lines
6.8 KiB
TypeScript

import { useState, useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import api from '../../../api';
import { useAuth } from '../../../App';
import {
LayoutGrid, Tag, Upload, DollarSign, Trash2,
Circle, BarChart3, Key, Star, ArrowRightLeft
} from 'lucide-react';
import StoreListing from './StoreListing';
import PublishUpdate from './PublishUpdate';
import Pricing from './Pricing';
import Coupons from './Coupons';
import Licenses from './Licenses';
import PluginReviewsTab from './PluginReviewsTab';
import TransferOwnership from './TransferOwnership';
import DangerZone from './DangerZone';
import PluginAnalyticsTab from './PluginAnalyticsTab';
import './ManagePlugin.css';
export type PluginData = {
id: number;
name: string;
translated_descriptions: string;
category: string;
source_link: string;
keywords: string;
price_cents: number;
type: 'free' | 'paid' | 'adwall';
screenshots: { id: number; path: string }[];
preview_path?: string;
version?: string;
status?: 'published' | 'draft' | 'review';
sale_active?: boolean;
sale_discount_percent?: number;
is_early_access?: boolean;
is_preorder?: boolean;
preorder_release_date?: string;
youtube_video_url?: string;
dev_id?: number;
};
const NAV_ITEMS = [
{ key: 'listing', label: 'Store Listing', icon: LayoutGrid },
{ key: 'update', label: 'Publish Update', icon: Upload },
{ key: 'analytics', label: 'Analytics', icon: BarChart3 },
{ key: 'reviews', label: 'Reviews', icon: Star },
{ key: 'pricing', label: 'Pricing', icon: DollarSign },
{ key: 'licenses', label: 'Licenses', icon: Key },
{ key: 'coupons', label: 'Coupons', icon: Tag },
{ key: 'transfer', label: 'Transfer', icon: ArrowRightLeft },
{ key: 'danger', label: 'Danger Zone', icon: Trash2 },
];
const ManagePlugin = () => {
const { id } = useParams<{ id: string }>();
const { user } = useAuth();
const navigate = useNavigate();
const [activeTab, setActiveTab] = useState('listing');
const [loading, setLoading] = useState(true);
const [plugin, setPlugin] = useState<PluginData | null>(null);
useEffect(() => {
if (user) {
fetchPlugin();
}
}, [id, user]);
const fetchPlugin = async () => {
try {
const res = await api.get(`/plugins/${id}`);
const data = res.data;
if (!user || (data.dev_id !== user.id && user.role !== 'admin')) {
navigate('/dashboard/plugins', { replace: true });
return;
}
setPlugin(data);
} catch {
navigate('/dashboard/plugins', { replace: true });
} finally {
setLoading(false);
}
};
const refreshPlugin = () => fetchPlugin();
if (loading) {
return (
<div className="mp-loading">
<div className="mp-loading-spinner" />
<span>Loading plugin…</span>
</div>
);
}
if (!plugin) return null;
const statusColor = {
published: 'var(--mp-success)',
draft: 'var(--mp-muted)',
review: 'var(--mp-warn)',
}[plugin.status ?? 'published'];
return (
<div className="mp-root">
{/* ── Sidebar ───────────────────────────────────────────── */}
<aside className="mp-sidebar">
<div className="mp-plugin-identity">
<div className="mp-plugin-avatar" style={plugin.preview_path ? { backgroundImage: `url(${plugin.preview_path})`, backgroundSize: 'cover', backgroundPosition: 'center', color: 'transparent' } : {}}>
{!plugin.preview_path && plugin.name.charAt(0).toUpperCase()}
</div>
<div>
<p className="mp-plugin-name">{plugin.name}</p>
<div className="mp-plugin-status">
<Circle size={7} fill={statusColor} color={statusColor} />
<span style={{ color: statusColor }}>
{plugin.status ?? 'published'}
</span>
</div>
</div>
</div>
<nav className="mp-nav">
{NAV_ITEMS.map(({ key, label, icon: Icon }) => (
<button
key={key}
className={`mp-nav-item ${activeTab === key ? 'active' : ''} ${key === 'danger' ? 'danger' : ''}`}
onClick={() => setActiveTab(key)}
>
<Icon size={16} />
{label}
</button>
))}
</nav>
<div className="mp-sidebar-meta">
<span className="mp-meta-row"><Tag size={12} /> ID: {id}</span>
{plugin.version && (
<span className="mp-meta-row">
<Upload size={12} /> v{plugin.version}
</span>
)}
</div>
</aside>
{/* ── Main Content ──────────────────────────────────────── */}
<main className="mp-main">
{activeTab === 'listing' && (
<StoreListing plugin={plugin} onSaved={refreshPlugin} />
)}
{activeTab === 'update' && (
<PublishUpdate plugin={plugin} onSaved={refreshPlugin} />
)}
{activeTab === 'analytics' && (
<PluginAnalyticsTab pluginId={plugin.id} pluginName={plugin.name} />
)}
{activeTab === 'reviews' && (
<PluginReviewsTab plugin={plugin} />
)}
{activeTab === 'pricing' && (
<Pricing plugin={plugin} onSaved={refreshPlugin} />
)}
{activeTab === 'licenses' && (
<Licenses plugin={plugin} />
)}
{activeTab === 'coupons' && (
<Coupons plugin={plugin} />
)}
{activeTab === 'transfer' && (
<TransferOwnership plugin={plugin} />
)}
{activeTab === 'danger' && (
<DangerZone plugin={plugin} />
)}
</main>
</div>
);
};
export default ManagePlugin;