setShowProjectsModal(false)}
- ticket={ticket}
- onUpdated={() => setProjectsRefreshKey((k) => k + 1)}
- />
-
-
-
- >
- )
-}
diff --git a/src/components/WebpageProjectPanel.jsx b/src/components/WebpageProjectPanel.jsx
deleted file mode 100644
index 5a23c05..0000000
--- a/src/components/WebpageProjectPanel.jsx
+++ /dev/null
@@ -1,109 +0,0 @@
-import { useState, useEffect, useCallback } from 'react'
-import { FaPlus, FaTrash } from 'react-icons/fa'
-import PreviewLinkButton from './PreviewLinkButton'
-import { useWebsiteProjects } from '../hooks/useWebsiteProjects'
-import { createProjectFromTemplate } from '../lib/projectAdminApi'
-import { WEBPAGE_TICKET_TYPE } from '../lib/appwrite'
-
-function slugify(v) {
- return String(v || '').toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 100)
-}
-
-export default function WebpageProjectPanel({ ticket }) {
- const { fetchAllProjects, fetchByTicketId, getAvailableProjects, assignProjects, unassignProject } = useWebsiteProjects()
- const [assigned, setAssigned] = useState([])
- const [available, setAvailable] = useState([])
- const [selectedIds, setSelectedIds] = useState([])
- const [loading, setLoading] = useState(true)
- const [actionLoading, setActionLoading] = useState(false)
- const [error, setError] = useState('')
- const [createForm, setCreateForm] = useState({ displayName: '', subdomain: '', repoName: '' })
-
- const loadProjects = useCallback(async () => {
- if (!ticket?.$id || ticket.type !== WEBPAGE_TICKET_TYPE) return
- setLoading(true)
- setError('')
- try {
- const [all, mine] = await Promise.all([fetchAllProjects(), fetchByTicketId(ticket.$id)])
- setAssigned(mine)
- const ids = new Set(mine.map((p) => p.$id))
- setAvailable(getAvailableProjects(all, ticket.customerId).filter((p) => !ids.has(p.$id)))
- } catch (err) {
- setError(err.message)
- } finally {
- setLoading(false)
- }
- }, [ticket, fetchAllProjects, fetchByTicketId, getAvailableProjects])
-
- useEffect(() => { loadProjects() }, [loadProjects])
- if (ticket?.type !== WEBPAGE_TICKET_TYPE) return null
-
- const handleAssign = async () => {
- if (!selectedIds.length || !ticket.customerId) return
- setActionLoading(true)
- const r = await assignProjects(selectedIds, { customerId: ticket.customerId, ticketId: ticket.$id })
- setActionLoading(false)
- if (r.success) { setSelectedIds([]); await loadProjects() } else setError(r.error)
- }
-
- const handleCreate = async (e) => {
- e.preventDefault()
- if (!ticket.customerId) { setError('Kein Kunde am Ticket.'); return }
- setActionLoading(true)
- setError('')
- try {
- await createProjectFromTemplate({
- repoName: createForm.repoName || createForm.subdomain,
- displayName: createForm.displayName,
- subdomain: slugify(createForm.subdomain),
- customerId: ticket.customerId,
- ticketId: ticket.$id,
- })
- setCreateForm({ displayName: '', subdomain: '', repoName: '' })
- await loadProjects()
- } catch (err) {
- setError(err.message)
- } finally {
- setActionLoading(false)
- }
- }
-
- return (
-
-
Website-Projekte
- {error &&
{error}
}
- {loading ?
Laden...
: (
- <>
-
- Zugewiesen
- {assigned.length === 0 ? Keine Projekte.
: assigned.map((p) => (
-
-
{p.projectName} ({p.subdomain})
-
-
unassignProject(p.$id).then(loadProjects)}>
-
- ))}
-
-
-
- >
- )}
-
- )
-}
diff --git a/src/components/WorksheetList.jsx b/src/components/WorksheetList.jsx
index 0f5a31f..6d589db 100644
--- a/src/components/WorksheetList.jsx
+++ b/src/components/WorksheetList.jsx
@@ -23,7 +23,7 @@ const headerButtonStyle = {
marginRight: '8px',
}
-export default function WorksheetList({ worksheets, totalTime, loading, onEditTime, onTogglePlan, canEditTimes, onEditTimes }) {
+export default function WorksheetList({ worksheets, totalTime, loading, onTogglePlan, canEditTimes, onEditTimes }) {
const [expandedWorksheets, setExpandedWorksheets] = useState({})
if (loading) {
return (
@@ -162,19 +162,6 @@ export default function WorksheetList({ worksheets, totalTime, loading, onEditTi
)}
- {needsTimeEntry(ws) && onEditTime && (
- {
- e.stopPropagation()
- onEditTime(ws)
- }}
- >
- Zeit nachtragen
-
- )}
{onEditTimes && canEditTimes?.(ws) && (
{
- return (allProjects || []).filter(isTemplateProject).filter((p) => {
- if (!p.customerId) return true
- return customerId && p.customerId === customerId
- })
- }, [])
-
const assignProject = async (projectId, { customerId, ticketId }) => {
try {
const response = await databases.updateDocument(
@@ -80,5 +68,5 @@ export function useWebsiteProjects() {
}
}
- return { projects, loading, error, fetchAllProjects, fetchByTicketId, getAvailableProjects, assignProjects, unassignProject }
+ return { projects, loading, error, fetchAllProjects, fetchByTicketId, assignProjects, unassignProject }
}
diff --git a/src/hooks/useWorksheets.js b/src/hooks/useWorksheets.js
index ac0bbe8..847e08b 100644
--- a/src/hooks/useWorksheets.js
+++ b/src/hooks/useWorksheets.js
@@ -439,29 +439,6 @@ export function useWorksheets(woid = null) {
.reduce((sum, ws) => sum + (ws.totalTime || 0), 0)
}, [worksheets])
- /**
- * Gruppiert Worksheets nach Mitarbeiter
- * @returns Object mit employeeId als Key
- */
- const getWorksheetsByEmployee = useCallback(() => {
- return worksheets.reduce((acc, ws) => {
- const empId = ws.employeeId
- if (!acc[empId]) {
- acc[empId] = {
- employeeName: ws.employeeName,
- employeeShort: ws.employeeShort,
- worksheets: [],
- totalTime: 0
- }
- }
- acc[empId].worksheets.push(ws)
- if (!ws.isComment) {
- acc[empId].totalTime += ws.totalTime || 0
- }
- return acc
- }, {})
- }, [worksheets])
-
return {
worksheets,
loading,
@@ -472,7 +449,6 @@ export function useWorksheets(woid = null) {
deleteWorksheet,
refresh: fetchWorksheets,
getTotalTime,
- getWorksheetsByEmployee,
calculateTime
}
}
diff --git a/src/lib/appwrite.js b/src/lib/appwrite.js
index 5ebf895..13130b9 100644
--- a/src/lib/appwrite.js
+++ b/src/lib/appwrite.js
@@ -37,8 +37,6 @@ export const COLLECTIONS = {
CUSTOMERS: 'customers',
EMPLOYEES: 'employees',
WORKSHEETS: 'worksheets',
- USERS: 'users',
- ATTACHMENTS: 'attachments',
WEBSITE_PROJECTS: 'websiteProjects',
LEADS: 'leads',
LEAD_SETTINGS: 'leadSettings',
@@ -47,9 +45,7 @@ export const COLLECTIONS = {
ROADMAP_NODES: 'roadmapNodes',
}
-export const WEBPAGE_TICKET_TYPE = 'Webpage'
export const PROJECT_TICKET_TYPE = 'Project'
-export const PREVIEW_TEMPLATE_NAME = 'webklar-preview-template'
export const BUCKET_ID = import.meta.env.VITE_APPWRITE_BUCKET_ID || 'woms-attachments'
diff --git a/src/lib/utils.js b/src/lib/utils.js
deleted file mode 100644
index e11b6a3..0000000
--- a/src/lib/utils.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { clsx } from 'clsx'
-import { twMerge } from 'tailwind-merge'
-
-export function cn(...inputs) {
- return twMerge(clsx(inputs))
-}
-
diff --git a/src/utils/createDummyTicket.js b/src/utils/createDummyTicket.js
deleted file mode 100644
index bb997a6..0000000
--- a/src/utils/createDummyTicket.js
+++ /dev/null
@@ -1,233 +0,0 @@
-/**
- * Erstellt ein vollständiges Dummy-Ticket mit WOID 10001
- * Zeigt alle möglichen Funktionen, Felder und Kombinationen
- */
-
-export function createDummyTicket10001() {
- const now = new Date()
- const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000)
- const lastWeek = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000)
-
- // Haupt-Ticket mit allen Feldern ausgefüllt
- const dummyTicket = {
- $id: 'dummy-10001',
- woid: '10001',
- topic: 'Kompletter Systemausfall - Server & Netzwerk',
- status: 'Assigned',
- priority: 4, // Critical
- type: 'Emergency Call',
- systemType: 'Server',
- responseLevel: '24/7',
- serviceType: 'On Site',
- customerId: 'customer-a-id',
- customerName: 'Kunde A',
- customerLocation: 'Hauptstraße 123, 12345 Musterstadt',
- assignedTo: 'user-max-id', // Max Mustermann
- requestedBy: 'Dr. Anna Schmidt',
- requestedFor: 'IT-Abteilung Kunde A',
- startDate: '30.12.2025',
- startTime: '0800',
- deadline: '31.12.2025',
- endTime: '1800',
- estimate: '480',
- mailCopyTo: 'admin@kunde-a.de, it@kunde-a.de',
- sendNotification: true,
- details: `KRITISCHER SYSTEMAUSFALL - SOFORTIGE BEARBEITUNG ERFORDERLICH
-
-Problembeschreibung:
-- Kompletter Serverausfall im Rechenzentrum
-- Alle Server sind offline (keine Verbindung möglich)
-- Netzwerk-Infrastruktur betroffen
-- Keine Backup-Systeme verfügbar
-
-Betroffene Systeme:
-- Hauptserver (Windows Server 2022)
-- Datenbankserver (SQL Server 2019)
-- Fileserver
-- Exchange Server
-- Netzwerk-Switches
-
-Auswirkungen:
-- Keine E-Mail-Kommunikation möglich
-- Alle Anwendungen offline
-- Kein Zugriff auf Datenbanken
-- Produktion steht still
-
-Dringlichkeit: KRITISCH - Produktionsausfall
-
-Erwartete Bearbeitungszeit: 8 Stunden
-Benötigte Ressourcen: 2 Techniker, Hardware-Ersatzteile`,
- approvalStatus: 'approved',
- createdAt: lastWeek.toISOString(),
- $createdAt: lastWeek.toISOString()
- }
-
- // Mehrere Worksheets mit verschiedenen Status-Änderungen und Benutzern
- const dummyWorksheets = [
- {
- $id: 'ws-10001-001',
- wsid: '100001',
- woid: '10001',
- workorderId: 'dummy-10001',
- employeeId: 'user-max-id',
- employeeName: 'Max Mustermann',
- employeeShort: 'MM',
- serviceType: 'Remote',
- oldStatus: 'Open',
- newStatus: 'Occupied',
- oldResponseLevel: '',
- newResponseLevel: '24/7',
- totalTime: 30,
- startDate: '23.12.2025',
- startTime: '0800',
- endDate: '23.12.2025',
- endTime: '0830',
- details: 'Erste Analyse durchgeführt. Server komplett offline. Keine Remote-Verbindung möglich. Vor-Ort-Einsatz erforderlich.',
- isComment: false,
- createdAt: yesterday.toISOString(),
- $createdAt: yesterday.toISOString()
- },
- {
- $id: 'ws-10001-002',
- wsid: '100002',
- woid: '10001',
- workorderId: 'dummy-10001',
- employeeId: 'user-lisa-id',
- employeeName: 'Lisa Schneider',
- employeeShort: 'LS',
- serviceType: 'On Site',
- oldStatus: 'Occupied',
- newStatus: 'Assigned',
- oldResponseLevel: '24/7',
- newResponseLevel: '24/7',
- totalTime: 120,
- startDate: '23.12.2025',
- startTime: '1000',
- endDate: '23.12.2025',
- endTime: '1200',
- details: 'Vor-Ort-Einsatz: Hardware-Check durchgeführt. Netzteil des Hauptservers defekt. Ersatzteil bestellt. Notfall-Backup-Server gestartet.',
- isComment: false,
- createdAt: yesterday.toISOString(),
- $createdAt: yesterday.toISOString()
- },
- {
- $id: 'ws-10001-003',
- wsid: '100003',
- woid: '10001',
- workorderId: 'dummy-10001',
- employeeId: 'user-tom-id',
- employeeName: 'Tom Klein',
- employeeShort: 'TK',
- serviceType: 'On Site',
- oldStatus: 'Assigned',
- newStatus: 'Assigned',
- oldResponseLevel: '24/7',
- newResponseLevel: '24/7',
- totalTime: 0,
- startDate: '24.12.2025',
- startTime: '1400',
- endDate: '24.12.2025',
- endTime: '1400',
- details: 'Warte auf Ersatzteil-Lieferung. Kunde informiert. Backup-System läuft stabil.',
- isComment: true,
- createdAt: new Date(yesterday.getTime() - 12 * 60 * 60 * 1000).toISOString(),
- $createdAt: new Date(yesterday.getTime() - 12 * 60 * 60 * 1000).toISOString()
- },
- {
- $id: 'ws-10001-004',
- wsid: '100004',
- woid: '10001',
- workorderId: 'dummy-10001',
- employeeId: 'user-max-id',
- employeeName: 'Max Mustermann',
- employeeShort: 'MM',
- serviceType: 'On Site',
- oldStatus: 'Assigned',
- newStatus: 'In Test',
- oldResponseLevel: '24/7',
- newResponseLevel: '24/7',
- totalTime: 180,
- startDate: '25.12.2025',
- startTime: '0900',
- endDate: '25.12.2025',
- endTime: '1200',
- details: 'Ersatzteil eingebaut. Server gestartet. Alle Dienste wiederhergestellt. System-Tests durchgeführt. Datenbank-Verbindungen geprüft.',
- isComment: false,
- createdAt: new Date(yesterday.getTime() - 24 * 60 * 60 * 1000).toISOString(),
- $createdAt: new Date(yesterday.getTime() - 24 * 60 * 60 * 1000).toISOString()
- },
- {
- $id: 'ws-10001-005',
- wsid: '100005',
- woid: '10001',
- workorderId: 'dummy-10001',
- employeeId: 'user-lisa-id',
- employeeName: 'Lisa Schneider',
- employeeShort: 'LS',
- serviceType: 'Remote',
- oldStatus: 'In Test',
- newStatus: 'Awaiting',
- oldResponseLevel: '24/7',
- newResponseLevel: 'Support',
- totalTime: 45,
- startDate: '26.12.2025',
- startTime: '1000',
- endDate: '26.12.2025',
- endTime: '1045',
- details: 'Remote-Monitoring eingerichtet. Warte auf Kunden-Feedback nach 24h Testphase. Alle Systeme laufen stabil.',
- isComment: false,
- createdAt: new Date(yesterday.getTime() - 48 * 60 * 60 * 1000).toISOString(),
- $createdAt: new Date(yesterday.getTime() - 48 * 60 * 60 * 1000).toISOString()
- },
- {
- $id: 'ws-10001-006',
- wsid: '100006',
- woid: '10001',
- workorderId: 'dummy-10001',
- employeeId: 'user-tom-id',
- employeeName: 'Tom Klein',
- employeeShort: 'TK',
- serviceType: 'COMMENT',
- oldStatus: 'Awaiting',
- newStatus: 'Closed',
- oldResponseLevel: 'Support',
- newResponseLevel: 'Backoffice',
- totalTime: 0,
- startDate: '30.12.2025',
- startTime: '0900',
- endDate: '30.12.2025',
- endTime: '0900',
- details: 'Kunde bestätigt: Alle Systeme funktionieren einwandfrei. Problem vollständig behoben. Ticket kann geschlossen werden.',
- isComment: true,
- createdAt: now.toISOString(),
- $createdAt: now.toISOString()
- }
- ]
-
- return {
- ticket: dummyTicket,
- worksheets: dummyWorksheets
- }
-}
-
-/**
- * Fügt das Dummy-Ticket zu den Demo-Daten hinzu
- */
-export function addDummyTicketToDemo(workorders, worksheets) {
- const { ticket, worksheets: ticketWorksheets } = createDummyTicket10001()
-
- // Prüfe ob Ticket bereits existiert
- const exists = workorders.some(wo => wo.woid === '10001')
- if (exists) {
- console.log('Dummy-Ticket 10001 existiert bereits')
- return { workorders, worksheets }
- }
-
- return {
- workorders: [ticket, ...workorders],
- worksheets: [...ticketWorksheets, ...worksheets]
- }
-}
-
-
-