import React, { useEffect, useState, useRef } from 'react';
import { Card, Row, Col, Spin, Alert, Image, Layout, Switch, App } from 'antd';
import { LoadingOutlined } from '@ant-design/icons';
import { Link } from 'react-router-dom';
import { getClientProjects } from '../services/projectService';
import UserMenu from '../components/UserMenu';
import Sortable from 'sortablejs';
const backendUrl = process.env.REACT_APP_BACKEND || '';
export default function ClientProjects({ user, darkMode, onLogout, onToggleDarkMode }) {
const { message } = App.useApp();
const [projects, setProjects] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [sortMode, setSortMode] = useState(false);
const [saving, setSaving] = useState(false);
const normalProjectsRef = useRef(null);
const heProjectsRef = useRef(null);
const normalSortableRef = useRef(null);
const heSortableRef = useRef(null);
useEffect(() => {
const token = localStorage.getItem('jwt');
getClientProjects(token).then(res => {
if (res.success) {
setProjects(res.projects);
} else {
setError(res.error?.message || 'Fehler beim Laden der Projekte');
}
}).catch(() => setError('Serverfehler')).finally(() => setLoading(false));
}, []);
// SortableJS initialisieren/zerstören
useEffect(() => {
if (sortMode && normalProjectsRef.current && heProjectsRef.current) {
// Zerstöre bestehende Instanzen falls vorhanden
if (normalSortableRef.current) {
try {
normalSortableRef.current.destroy();
} catch (e) {
// Ignore cleanup errors
}
normalSortableRef.current = null;
}
if (heSortableRef.current) {
try {
heSortableRef.current.destroy();
} catch (e) {
// Ignore cleanup errors
}
heSortableRef.current = null;
}
// Initialisiere SortableJS für beide Bereiche
normalSortableRef.current = Sortable.create(normalProjectsRef.current, {
animation: 150,
ghostClass: 'sortable-ghost',
chosenClass: 'sortable-chosen',
dragClass: 'sortable-drag',
onEnd: handleSortEnd
});
heSortableRef.current = Sortable.create(heProjectsRef.current, {
animation: 150,
ghostClass: 'sortable-ghost',
chosenClass: 'sortable-chosen',
dragClass: 'sortable-drag',
onEnd: handleSortEnd
});
} else {
// Zerstöre SortableJS Instanzen sicher
if (normalSortableRef.current) {
try {
normalSortableRef.current.destroy();
} catch (e) {
// Ignore cleanup errors
}
normalSortableRef.current = null;
}
if (heSortableRef.current) {
try {
heSortableRef.current.destroy();
} catch (e) {
// Ignore cleanup errors
}
heSortableRef.current = null;
}
}
return () => {
// Cleanup beim Unmount
if (normalSortableRef.current) {
try {
normalSortableRef.current.destroy();
} catch (e) {
// Ignore cleanup errors
}
normalSortableRef.current = null;
}
if (heSortableRef.current) {
try {
heSortableRef.current.destroy();
} catch (e) {
// Ignore cleanup errors
}
heSortableRef.current = null;
}
};
}, [sortMode]);
const handleSortEnd = async (evt) => {
// Neue Reihenfolge aus DOM extrahieren
const newOrder = [];
// Normale Projekte
if (normalProjectsRef.current) {
const normalElements = normalProjectsRef.current.children;
for (let el of normalElements) {
const projectName = el.getAttribute('data-project-name');
if (projectName) newOrder.push(projectName);
}
}
// HE Projekte
if (heProjectsRef.current) {
const heElements = heProjectsRef.current.children;
for (let el of heElements) {
const projectName = el.getAttribute('data-project-name');
if (projectName) newOrder.push(projectName);
}
}
// Speichere neue Reihenfolge
await saveProjectOrder(newOrder);
};
const saveProjectOrder = async (order) => {
setSaving(true);
try {
const token = localStorage.getItem('jwt');
const response = await fetch(`${backendUrl}/api/projects/${encodeURIComponent(user?.dir)}/project-order`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ order })
});
const result = await response.json();
if (result.success) {
message.success('Reihenfolge gespeichert');
// Projekte neu laden um die neue Reihenfolge zu übernehmen
const token = localStorage.getItem('jwt');
const res = await getClientProjects(token);
if (res.success) {
setProjects(res.projects);
}
} else {
message.error('Fehler beim Speichern: ' + (result.error?.message || 'Unbekannter Fehler'));
}
} catch (err) {
message.error('Netzwerkfehler beim Speichern');
} finally {
setSaving(false);
}
};
if (loading) {
return } size="large" tip="Lade Projekte..." fullscreen />;
}
if (error) {
return ;
}
// Projekte trennen
const normalProjects = projects.filter(p => !p.isHE);
const heProjects = projects.filter(p => p.isHE);
return (
Übersicht
Cinema
{normalProjects.length === 0 && }
{normalProjects.map((p, i) => {
return (
{p.poster && (
)}
);
})}
Home Entertainment
{heProjects.length === 0 && }
{heProjects.map((p, i) => {
return (
{p.poster && (
)}
);
})}
);
}