Demo-Modus entfernt

isDemoMode war nie aktiv: appwrite.js hat immer eine Projekt-ID als
Fallback. Weg sind die Demo-Zweige in Anmeldung und Hooks sowie die
Beispieldaten aus der alten IT-Welt (Serverausfall, Drucker, Kunde A–E).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-09-27 14:36:33 +00:00
1 parent 889a2f42eb
commit b758b1f9a7
11 files changed
+25 -451

No files matched your search

+2 -2
View File
@@ -2,7 +2,7 @@ import { useState, useEffect, useMemo } from 'react'
import { FaTimes } from 'react-icons/fa' import { FaTimes } from 'react-icons/fa'
import { useAdminConfig } from '../hooks/useAdminConfig' import { useAdminConfig } from '../hooks/useAdminConfig'
import { useEmployees } from '../hooks/useEmployees' import { useEmployees } from '../hooks/useEmployees'
import { databases, DATABASE_ID, COLLECTIONS, Query, isDemoMode } from '../lib/appwrite' import { databases, DATABASE_ID, COLLECTIONS, Query } from '../lib/appwrite'
import { import {
SERVICE_TYPES, SERVICE_TYPES,
todayIso, todayIso,
@@ -63,7 +63,7 @@ export default function CreateTicketModal({ isOpen, onClose, onCreate, customers
// Namen aus den letzten Tickets fuer die Autovervollstaendigung // Namen aus den letzten Tickets fuer die Autovervollstaendigung
useEffect(() => { useEffect(() => {
if (!isOpen || isDemoMode) return if (!isOpen) return
let cancelled = false let cancelled = false
databases databases
.listDocuments(DATABASE_ID, COLLECTIONS.WORKORDERS, [Query.orderDesc('$createdAt'), Query.limit(200)]) .listDocuments(DATABASE_ID, COLLECTIONS.WORKORDERS, [Query.orderDesc('$createdAt'), Query.limit(200)])
+1 -26
View File
@@ -7,14 +7,11 @@ import {
ID, ID,
Query, Query,
hasAppwriteSession, hasAppwriteSession,
isDemoMode,
projectId as PROJECT_ID, projectId as PROJECT_ID,
} from '../lib/appwrite' } from '../lib/appwrite'
const AuthContext = createContext() const AuthContext = createContext()
const DEMO_MODE = isDemoMode
function clearStaleAppwriteSessions() { function clearStaleAppwriteSessions() {
if (typeof window === 'undefined' || !window.localStorage) return if (typeof window === 'undefined' || !window.localStorage) return
try { try {
@@ -55,7 +52,7 @@ async function createSessionWithCleanup(email, password) {
// Hilfsfunktion: Fügt User automatisch zur employees Collection hinzu und liefert // Hilfsfunktion: Fügt User automatisch zur employees Collection hinzu und liefert
// den Mitarbeiter-Eintrag (Kürzel = Gitea-Name, siehe isWorksheetCreator) oder null // den Mitarbeiter-Eintrag (Kürzel = Gitea-Name, siehe isWorksheetCreator) oder null
async function ensureEmployeeExists(user) { async function ensureEmployeeExists(user) {
if (!user || DEMO_MODE) return null if (!user) return null
try { try {
const response = await databases.listDocuments( const response = await databases.listDocuments(
@@ -98,15 +95,6 @@ export function AuthProvider({ children }) {
}, []) }, [])
async function checkUser() { async function checkUser() {
if (DEMO_MODE) {
const demoUser = localStorage.getItem('demo_user')
if (demoUser) {
setUser(JSON.parse(demoUser))
}
setLoading(false)
return
}
if (!hasAppwriteSession()) { if (!hasAppwriteSession()) {
setUser(null) setUser(null)
setLoading(false) setLoading(false)
@@ -131,13 +119,6 @@ export function AuthProvider({ children }) {
} }
async function login(email, password) { async function login(email, password) {
if (DEMO_MODE) {
const demoUser = { $id: 'demo', email, name: email.split('@')[0] }
localStorage.setItem('demo_user', JSON.stringify(demoUser))
setUser(demoUser)
return { success: true }
}
try { try {
const normalizedEmail = email.trim() const normalizedEmail = email.trim()
const normalizedPassword = password.trim() const normalizedPassword = password.trim()
@@ -176,12 +157,6 @@ export function AuthProvider({ children }) {
} }
async function logout() { async function logout() {
if (DEMO_MODE) {
localStorage.removeItem('demo_user')
setUser(null)
return
}
try { try {
await account.deleteSessions() await account.deleteSessions()
} catch (error) { } catch (error) {
+2 -16
View File
@@ -1,9 +1,7 @@
import { useState, useEffect, useCallback } from 'react' import { useState, useEffect, useCallback } from 'react'
import { databases, DATABASE_ID, COLLECTIONS, ID, isDemoMode } from '../lib/appwrite' import { databases, DATABASE_ID, COLLECTIONS, ID } from '../lib/appwrite'
const DEMO_MODE = isDemoMode // Standardwerte, solange das Config-Dokument fehlt oder nicht lesbar ist
// Default-Werte für Demo-Modus
const DEFAULT_CONFIG = { const DEFAULT_CONFIG = {
ticketTypes: [ ticketTypes: [
'Home Office', 'Holidays', 'Trip', 'Supportrequest', 'Change Request', 'Home Office', 'Holidays', 'Trip', 'Supportrequest', 'Change Request',
@@ -54,12 +52,6 @@ export function useAdminConfig() {
const [error, setError] = useState(null) const [error, setError] = useState(null)
const fetchConfig = useCallback(async () => { const fetchConfig = useCallback(async () => {
if (DEMO_MODE) {
setConfig(DEFAULT_CONFIG)
setLoading(false)
return
}
try { try {
// Versuche Config-Dokument zu laden (ID: 'config') // Versuche Config-Dokument zu laden (ID: 'config')
try { try {
@@ -104,12 +96,6 @@ export function useAdminConfig() {
}, [fetchConfig]) }, [fetchConfig])
const updateConfig = async (newConfig) => { const updateConfig = async (newConfig) => {
if (DEMO_MODE) {
setConfig(newConfig)
localStorage.setItem('admin_config', JSON.stringify(newConfig))
return { success: true }
}
try { try {
const configData = { const configData = {
ticketTypes: newConfig.ticketTypes, ticketTypes: newConfig.ticketTypes,
-44
View File
@@ -4,7 +4,6 @@ import {
DATABASE_ID, DATABASE_ID,
Query, Query,
databases, databases,
isDemoMode,
} from '../lib/appwrite' } from '../lib/appwrite'
import { import {
createCustomerWithPortalAccess, createCustomerWithPortalAccess,
@@ -13,26 +12,12 @@ import {
updateCustomerWithPortalAccess, updateCustomerWithPortalAccess,
} from '../lib/customerAdminApi' } from '../lib/customerAdminApi'
const DEMO_MODE = isDemoMode
// Demo-Kunden für Testing
const DEMO_CUSTOMERS = [
{ $id: '1', code: 'C001', name: 'Kunde A', location: 'Berlin', email: 'kunde.a@example.com', phone: '030-123456' },
{ $id: '2', code: 'C002', name: 'Kunde B', location: 'München', email: 'kunde.b@example.com', phone: '089-654321' }
]
export function useCustomers() { export function useCustomers() {
const [customers, setCustomers] = useState([]) const [customers, setCustomers] = useState([])
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [error, setError] = useState(null) const [error, setError] = useState(null)
const fetchCustomers = useCallback(async () => { const fetchCustomers = useCallback(async () => {
if (DEMO_MODE) {
setCustomers(DEMO_CUSTOMERS)
setLoading(false)
return
}
try { try {
try { try {
const response = await listCustomersForAdmin() const response = await listCustomersForAdmin()
@@ -67,17 +52,6 @@ export function useCustomers() {
}, [fetchCustomers]) }, [fetchCustomers])
const createCustomer = async (data) => { const createCustomer = async (data) => {
if (DEMO_MODE) {
const { password, ...rest } = data
const newCustomer = {
...rest,
portalPassword: password || rest.portalPassword || '',
$id: Date.now().toString(),
}
setCustomers(prev => [...prev, newCustomer])
return { success: true, data: newCustomer }
}
try { try {
const { password, ...fields } = data const { password, ...fields } = data
const result = await createCustomerWithPortalAccess({ ...fields, password }) const result = await createCustomerWithPortalAccess({ ...fields, password })
@@ -93,19 +67,6 @@ export function useCustomers() {
} }
const updateCustomer = async (id, data) => { const updateCustomer = async (id, data) => {
if (DEMO_MODE) {
const { password, ...rest } = data
setCustomers(prev =>
prev.map(c => {
if (c.$id !== id) return c
const next = { ...c, ...rest }
if (password) next.portalPassword = password
return next
})
)
return { success: true }
}
try { try {
const { password, ...fields } = data const { password, ...fields } = data
const payload = { ...fields } const payload = { ...fields }
@@ -135,11 +96,6 @@ export function useCustomers() {
} }
const deleteCustomer = async (id) => { const deleteCustomer = async (id) => {
if (DEMO_MODE) {
setCustomers(prev => prev.filter(c => c.$id !== id))
return { success: true }
}
try { try {
await deleteCustomerWithPortalAccess(id) await deleteCustomerWithPortalAccess(id)
setCustomers(prev => prev.filter(c => c.$id !== id)) setCustomers(prev => prev.filter(c => c.$id !== id))
+11 -51
View File
@@ -4,7 +4,6 @@ import {
DATABASE_ID, DATABASE_ID,
Query, Query,
databases, databases,
isDemoMode,
} from '../lib/appwrite' } from '../lib/appwrite'
import { import {
createEmployeeWithLogin, createEmployeeWithLogin,
@@ -13,26 +12,6 @@ import {
updateEmployeeWithLogin, updateEmployeeWithLogin,
} from '../lib/employeeAdminApi' } from '../lib/employeeAdminApi'
const DEMO_MODE = isDemoMode
const DEMO_EMPLOYEES = [
{
$id: '1',
userId: 'user1',
displayName: 'Kenso Grimm',
email: 'kenso@example.com',
shortcode: 'KNSO',
isAdmin: true,
},
{
$id: '2',
userId: 'user2',
displayName: 'Christian Lehmann',
email: 'christian@example.com',
shortcode: 'CHLE',
isAdmin: false,
},
]
export function useEmployees() { export function useEmployees() {
const [employees, setEmployees] = useState([]) const [employees, setEmployees] = useState([])
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
@@ -41,20 +20,16 @@ export function useEmployees() {
const fetchEmployees = useCallback(async () => { const fetchEmployees = useCallback(async () => {
setLoading(true) setLoading(true)
try { try {
if (DEMO_MODE) { try {
setEmployees(DEMO_EMPLOYEES) const result = await listEmployeesForAdmin()
} else { setEmployees(result.employees || [])
try { } catch {
const result = await listEmployeesForAdmin() const result = await databases.listDocuments(
setEmployees(result.employees || []) DATABASE_ID,
} catch { COLLECTIONS.EMPLOYEES,
const result = await databases.listDocuments( [Query.orderAsc('displayName')]
DATABASE_ID, )
COLLECTIONS.EMPLOYEES, setEmployees(result.documents || [])
[Query.orderAsc('displayName')]
)
setEmployees(result.documents || [])
}
} }
setError(null) setError(null)
} catch (err) { } catch (err) {
@@ -71,15 +46,6 @@ export function useEmployees() {
const createEmployee = async (data) => { const createEmployee = async (data) => {
try { try {
if (DEMO_MODE) {
const employee = {
...data,
userId: crypto.randomUUID(),
$id: Date.now().toString(),
}
setEmployees((current) => [...current, employee])
return { success: true, data: employee }
}
const result = await createEmployeeWithLogin(data) const result = await createEmployeeWithLogin(data)
setEmployees((current) => [...current, result.employee]) setEmployees((current) => [...current, result.employee])
return { success: true, data: result.employee } return { success: true, data: result.employee }
@@ -90,12 +56,6 @@ export function useEmployees() {
const updateEmployee = async (id, data) => { const updateEmployee = async (id, data) => {
try { try {
if (DEMO_MODE) {
setEmployees((current) =>
current.map((employee) => employee.$id === id ? { ...employee, ...data } : employee)
)
return { success: true }
}
const result = await updateEmployeeWithLogin(id, data) const result = await updateEmployeeWithLogin(id, data)
setEmployees((current) => setEmployees((current) =>
current.map((employee) => employee.$id === id ? result.employee : employee) current.map((employee) => employee.$id === id ? result.employee : employee)
@@ -108,7 +68,7 @@ export function useEmployees() {
const deleteEmployee = async (id) => { const deleteEmployee = async (id) => {
try { try {
if (!DEMO_MODE) await deleteEmployeeWithLogin(id) await deleteEmployeeWithLogin(id)
setEmployees((current) => current.filter((employee) => employee.$id !== id)) setEmployees((current) => current.filter((employee) => employee.$id !== id))
return { success: true } return { success: true }
} catch (err) { } catch (err) {
+2 -7
View File
@@ -1,5 +1,5 @@
import { useState, useCallback } from 'react' import { useState, useCallback } from 'react'
import { databases, DATABASE_ID, COLLECTIONS, ID, isDemoMode } from '../lib/appwrite' import { databases, DATABASE_ID, COLLECTIONS, ID } from '../lib/appwrite'
import { import {
fetchRoadmapNodes, fetchRoadmapNodes,
logNodeStatusWorksheet, logNodeStatusWorksheet,
@@ -14,7 +14,7 @@ export function useRoadmapNodes() {
const [error, setError] = useState(null) const [error, setError] = useState(null)
const fetchNodes = useCallback(async (roadmapId) => { const fetchNodes = useCallback(async (roadmapId) => {
if (!roadmapId || isDemoMode) return [] if (!roadmapId) return []
setLoading(true) setLoading(true)
setError(null) setError(null)
try { try {
@@ -30,7 +30,6 @@ export function useRoadmapNodes() {
}, []) }, [])
const createNode = async (roadmapId, { title, column, row, kind }) => { const createNode = async (roadmapId, { title, column, row, kind }) => {
if (isDemoMode) return { success: false, error: 'Demo-Modus' }
try { try {
const now = new Date().toISOString() const now = new Date().toISOString()
const doc = await databases.createDocument(DATABASE_ID, COLLECTIONS.ROADMAP_NODES, ID.unique(), { const doc = await databases.createDocument(DATABASE_ID, COLLECTIONS.ROADMAP_NODES, ID.unique(), {
@@ -51,7 +50,6 @@ export function useRoadmapNodes() {
} }
const updateNode = async (nodeId, data) => { const updateNode = async (nodeId, data) => {
if (isDemoMode) return { success: false, error: 'Demo-Modus' }
try { try {
const doc = await databases.updateDocument(DATABASE_ID, COLLECTIONS.ROADMAP_NODES, nodeId, { const doc = await databases.updateDocument(DATABASE_ID, COLLECTIONS.ROADMAP_NODES, nodeId, {
...data, ...data,
@@ -66,7 +64,6 @@ export function useRoadmapNodes() {
/** Knoten loeschen inkl. Bereinigung eingehender Kanten bei den Nachfolgern. */ /** Knoten loeschen inkl. Bereinigung eingehender Kanten bei den Nachfolgern. */
const deleteNode = async (node) => { const deleteNode = async (node) => {
if (isDemoMode) return { success: false, error: 'Demo-Modus' }
if (node.kind === NODE_KIND.START) { if (node.kind === NODE_KIND.START) {
return { success: false, error: 'Der Start-Knoten kann nicht geloescht werden.' } return { success: false, error: 'Der Start-Knoten kann nicht geloescht werden.' }
} }
@@ -96,7 +93,6 @@ export function useRoadmapNodes() {
/** Kante anlegen: immer vorwaerts (Zielspalte > Quellspalte), keine Duplikate. */ /** Kante anlegen: immer vorwaerts (Zielspalte > Quellspalte), keine Duplikate. */
const connectNodes = async (source, target) => { const connectNodes = async (source, target) => {
if (isDemoMode) return { success: false, error: 'Demo-Modus' }
if (source.$id === target.$id) return { success: false, error: 'Knoten kann nicht mit sich selbst verbunden werden.' } if (source.$id === target.$id) return { success: false, error: 'Knoten kann nicht mit sich selbst verbunden werden.' }
if (target.column <= source.column) { if (target.column <= source.column) {
return { success: false, error: 'Verbindungen laufen immer vorwaerts (nach rechts).' } return { success: false, error: 'Verbindungen laufen immer vorwaerts (nach rechts).' }
@@ -113,7 +109,6 @@ export function useRoadmapNodes() {
/** Statuswechsel inkl. Worksheet-Log am Projektticket; meldet, ob alle Ziele fertig sind. */ /** Statuswechsel inkl. Worksheet-Log am Projektticket; meldet, ob alle Ziele fertig sind. */
const setNodeStatus = async (roadmap, node, newStatus, user) => { const setNodeStatus = async (roadmap, node, newStatus, user) => {
if (isDemoMode) return { success: false, error: 'Demo-Modus' }
const oldStatus = node.status || NODE_STATUS.OPEN const oldStatus = node.status || NODE_STATUS.OPEN
if (oldStatus === newStatus) return { success: true, allGoalsDone: false } if (oldStatus === newStatus) return { success: true, allGoalsDone: false }
const result = await updateNode(node.$id, { status: newStatus }) const result = await updateNode(node.$id, { status: newStatus })
+2 -8
View File
@@ -1,5 +1,5 @@
import { useState, useCallback } from 'react' import { useState, useCallback } from 'react'
import { databases, DATABASE_ID, COLLECTIONS, Query, isDemoMode } from '../lib/appwrite' import { databases, DATABASE_ID, COLLECTIONS, Query } from '../lib/appwrite'
import { import {
createRoadmapPlan, createRoadmapPlan,
deleteRoadmapPlan, deleteRoadmapPlan,
@@ -13,7 +13,6 @@ export function useRoadmaps() {
const [error, setError] = useState(null) const [error, setError] = useState(null)
const fetchAll = useCallback(async () => { const fetchAll = useCallback(async () => {
if (isDemoMode) return []
setLoading(true) setLoading(true)
setError(null) setError(null)
try { try {
@@ -32,7 +31,7 @@ export function useRoadmaps() {
}, []) }, [])
const fetchById = useCallback(async (roadmapId) => { const fetchById = useCallback(async (roadmapId) => {
if (!roadmapId || isDemoMode) return null if (!roadmapId) return null
try { try {
return await databases.getDocument(DATABASE_ID, COLLECTIONS.ROADMAPS, roadmapId) return await databases.getDocument(DATABASE_ID, COLLECTIONS.ROADMAPS, roadmapId)
} catch { } catch {
@@ -41,7 +40,6 @@ export function useRoadmaps() {
}, []) }, [])
const fetchByTicketId = useCallback(async (ticketId) => { const fetchByTicketId = useCallback(async (ticketId) => {
if (isDemoMode) return null
try { try {
return await fetchRoadmapByTicketId(ticketId) return await fetchRoadmapByTicketId(ticketId)
} catch { } catch {
@@ -50,7 +48,6 @@ export function useRoadmaps() {
}, []) }, [])
const createRoadmap = async (project, data, user) => { const createRoadmap = async (project, data, user) => {
if (isDemoMode) return { success: false, error: 'Demo-Modus' }
try { try {
const result = await createRoadmapPlan(project, data, user) const result = await createRoadmapPlan(project, data, user)
setRoadmaps((prev) => [result.roadmap, ...prev]) setRoadmaps((prev) => [result.roadmap, ...prev])
@@ -61,7 +58,6 @@ export function useRoadmaps() {
} }
const updateRoadmap = async (roadmapId, data) => { const updateRoadmap = async (roadmapId, data) => {
if (isDemoMode) return { success: false, error: 'Demo-Modus' }
try { try {
const doc = await databases.updateDocument(DATABASE_ID, COLLECTIONS.ROADMAPS, roadmapId, { const doc = await databases.updateDocument(DATABASE_ID, COLLECTIONS.ROADMAPS, roadmapId, {
...data, ...data,
@@ -75,7 +71,6 @@ export function useRoadmaps() {
} }
const deleteRoadmap = async (roadmap, user) => { const deleteRoadmap = async (roadmap, user) => {
if (isDemoMode) return { success: false, error: 'Demo-Modus' }
try { try {
await deleteRoadmapPlan(roadmap, user) await deleteRoadmapPlan(roadmap, user)
setRoadmaps((prev) => prev.filter((r) => r.$id !== roadmap.$id)) setRoadmaps((prev) => prev.filter((r) => r.$id !== roadmap.$id))
@@ -86,7 +81,6 @@ export function useRoadmaps() {
} }
const completePlan = async (roadmap, user) => { const completePlan = async (roadmap, user) => {
if (isDemoMode) return { success: false, error: 'Demo-Modus' }
try { try {
const updated = await completeRoadmap(roadmap, user) const updated = await completeRoadmap(roadmap, user)
setRoadmaps((prev) => prev.map((r) => (r.$id === updated.$id ? updated : r))) setRoadmaps((prev) => prev.map((r) => (r.$id === updated.$id ? updated : r)))
+2 -3
View File
@@ -1,5 +1,5 @@
import { useState, useCallback } from 'react' import { useState, useCallback } from 'react'
import { databases, DATABASE_ID, COLLECTIONS, Query, isDemoMode } from '../lib/appwrite' import { databases, DATABASE_ID, COLLECTIONS, Query } from '../lib/appwrite'
export function useWebsiteProjects() { export function useWebsiteProjects() {
const [projects, setProjects] = useState([]) const [projects, setProjects] = useState([])
@@ -7,7 +7,6 @@ export function useWebsiteProjects() {
const [error, setError] = useState(null) const [error, setError] = useState(null)
const fetchAllProjects = useCallback(async () => { const fetchAllProjects = useCallback(async () => {
if (isDemoMode) return []
setLoading(true) setLoading(true)
setError(null) setError(null)
try { try {
@@ -26,7 +25,7 @@ export function useWebsiteProjects() {
}, []) }, [])
const fetchByTicketId = useCallback(async (ticketId) => { const fetchByTicketId = useCallback(async (ticketId) => {
if (!ticketId || isDemoMode) return [] if (!ticketId) return []
try { try {
const response = await databases.listDocuments( const response = await databases.listDocuments(
DATABASE_ID, COLLECTIONS.WEBSITE_PROJECTS, DATABASE_ID, COLLECTIONS.WEBSITE_PROJECTS,
+2 -108
View File
@@ -1,7 +1,5 @@
import { useState, useEffect, useCallback, useMemo } from 'react' import { useState, useEffect, useCallback, useMemo } from 'react'
import { databases, DATABASE_ID, COLLECTIONS, Query, ID, isDemoMode } from '../lib/appwrite' import { databases, DATABASE_ID, COLLECTIONS, Query, ID } from '../lib/appwrite'
const DEMO_MODE = isDemoMode
function buildFiltersKey(filters = {}) { function buildFiltersKey(filters = {}) {
return JSON.stringify({ return JSON.stringify({
@@ -15,68 +13,6 @@ function buildFiltersKey(filters = {}) {
}) })
} }
// Demo data for testing without Appwrite
const lastWeek = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
const DEMO_WORKORDERS = [
{
$id: 'dummy-10001',
woid: '10001',
topic: 'Kompletter Systemausfall - Server & Netzwerk',
status: 'Assigned',
priority: 4,
type: 'Emergency Call',
systemType: 'Server',
responseLevel: 'Backoffice',
serviceType: 'On Site',
customerName: 'Kunde A',
customerLocation: 'Hauptstraße 123, 12345 Musterstadt',
assignedTo: 'user-max-id',
assignedName: '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()
},
{ $id: '2', woid: '10002', title: 'Netzwerk Problem', description: 'WLAN funktioniert nicht', status: 'Occupied', priority: 3, type: 'Support', customerName: 'Kunde B', assignedName: 'Lisa S.', response: 'Remote', $createdAt: new Date().toISOString() },
{ $id: '3', woid: '10003', title: 'Software Installation', description: 'Office 365 Setup', status: 'Assigned', priority: 1, type: 'Installation', customerName: 'Kunde C', assignedName: 'Tom K.', response: 'Onsite', $createdAt: new Date().toISOString() },
{ $id: '4', woid: '10004', title: 'Drucker defekt', description: 'Papierstau', status: 'Awaiting', priority: 2, type: 'Hardware', customerName: 'Kunde D', assignedName: '', response: 'Pickup', $createdAt: new Date().toISOString() },
{ $id: '5', woid: '10005', title: 'Kritischer Serverausfall', description: 'Produktionsserver down', status: 'Open', priority: 4, type: 'Emergency', customerName: 'Kunde E', assignedName: 'Max M.', response: 'Onsite', $createdAt: new Date().toISOString() },
]
export function useWorkorders(filters = {}) { export function useWorkorders(filters = {}) {
const [workorders, setWorkorders] = useState([]) const [workorders, setWorkorders] = useState([])
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
@@ -94,27 +30,7 @@ export function useWorkorders(filters = {}) {
const fetchWorkorders = useCallback(async () => { const fetchWorkorders = useCallback(async () => {
const activeFilters = JSON.parse(filtersKey) const activeFilters = JSON.parse(filtersKey)
setLoading(true) setLoading(true)
if (DEMO_MODE) {
// Filter demo data
let filtered = [...DEMO_WORKORDERS]
if (activeFilters.status?.length > 0) {
filtered = filtered.filter(wo => activeFilters.status.includes(wo.status))
}
if (activeFilters.priority?.length > 0) {
filtered = filtered.filter(wo => activeFilters.priority.includes(wo.priority))
}
if (activeFilters.woid) {
filtered = filtered.filter(wo => String(wo.woid) === String(activeFilters.woid))
}
if (activeFilters.limit) {
filtered = filtered.slice(0, activeFilters.limit)
}
setWorkorders(filtered)
setLoading(false)
return
}
try { try {
const queries = [Query.orderDesc('$createdAt')] const queries = [Query.orderDesc('$createdAt')]
@@ -236,18 +152,6 @@ export function useWorkorders(filters = {}) {
} }
const createWorkorder = async (data) => { const createWorkorder = async (data) => {
if (DEMO_MODE) {
// Finde höchste WOID und +1
const maxWoid = workorders.length > 0
? Math.max(...workorders.map(wo => parseInt(wo.woid)).filter(w => !isNaN(w)))
: 9999;
const nextWoid = maxWoid + 1;
const newWo = { ...data, $id: Date.now().toString(), woid: nextWoid.toString(), status: 'Open', $createdAt: new Date().toISOString() }
setWorkorders(prev => [newWo, ...prev])
return { success: true, data: newWo }
}
try { try {
// Validierung: Prüfe required fields // Validierung: Prüfe required fields
if (!data.topic || data.topic.trim() === '') { if (!data.topic || data.topic.trim() === '') {
@@ -323,11 +227,6 @@ export function useWorkorders(filters = {}) {
} }
const updateWorkorder = async (id, data) => { const updateWorkorder = async (id, data) => {
if (DEMO_MODE) {
setWorkorders(prev => prev.map(wo => wo.$id === id ? { ...wo, ...data } : wo))
return { success: true }
}
try { try {
// Status-Automatik beim Update: // Status-Automatik beim Update:
// Wenn assignedTo gesetzt wird → Status = "Assigned" // Wenn assignedTo gesetzt wird → Status = "Assigned"
@@ -361,11 +260,6 @@ export function useWorkorders(filters = {}) {
} }
const deleteWorkorder = async (id) => { const deleteWorkorder = async (id) => {
if (DEMO_MODE) {
setWorkorders(prev => prev.filter(wo => wo.$id !== id))
return { success: true }
}
try { try {
await databases.deleteDocument( await databases.deleteDocument(
DATABASE_ID, DATABASE_ID,
+1 -182
View File
@@ -1,149 +1,7 @@
import { useState, useEffect, useCallback } from 'react' import { useState, useEffect, useCallback } from 'react'
import { databases, DATABASE_ID, COLLECTIONS, Query, ID, isDemoMode } from '../lib/appwrite' import { databases, DATABASE_ID, COLLECTIONS, Query, ID } from '../lib/appwrite'
import { canEditWorksheetTimes, isGitWorksheet } from '../lib/ticketForm' import { canEditWorksheetTimes, isGitWorksheet } from '../lib/ticketForm'
const DEMO_MODE = isDemoMode
// Demo data für Testing - Vollständiges Dummy-Ticket 10001 mit allen Worksheets
const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000)
const twoDaysAgo = new Date(Date.now() - 48 * 60 * 60 * 1000)
const threeDaysAgo = new Date(Date.now() - 72 * 60 * 60 * 1000)
const DEMO_WORKSHEETS = [
{
$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: threeDaysAgo.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: threeDaysAgo.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: twoDaysAgo.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: twoDaysAgo.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: yesterday.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: new Date().toISOString()
}
]
export function useWorksheets(woid = null) { export function useWorksheets(woid = null) {
const [worksheets, setWorksheets] = useState([]) const [worksheets, setWorksheets] = useState([])
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
@@ -158,16 +16,6 @@ export function useWorksheets(woid = null) {
} }
setLoading(true) setLoading(true)
if (DEMO_MODE) {
// Filter demo data by WOID if provided
const filtered = woid
? DEMO_WORKSHEETS.filter(ws => ws.woid === woid)
: DEMO_WORKSHEETS
setWorksheets(filtered)
setLoading(false)
return
}
try { try {
// Ohne limit liefert Appwrite nur 25 Eintraege, ein Ticket sammelt aber viele Git-Pushes // Ohne limit liefert Appwrite nur 25 Eintraege, ein Ticket sammelt aber viele Git-Pushes
const queries = [Query.orderDesc('$createdAt'), Query.equal('woid', woid), Query.limit(5000)] const queries = [Query.orderDesc('$createdAt'), Query.equal('woid', woid), Query.limit(5000)]
@@ -212,13 +60,6 @@ export function useWorksheets(woid = null) {
* Startet bei 100000 und zählt sequentiell hoch * Startet bei 100000 und zählt sequentiell hoch
*/ */
const generateWSID = useCallback(async () => { const generateWSID = useCallback(async () => {
if (DEMO_MODE) {
const maxWsid = worksheets.length > 0
? Math.max(...worksheets.map(ws => parseInt(ws.wsid)).filter(w => !isNaN(w)))
: 99999
return (maxWsid + 1).toString()
}
try { try {
// Hole ALLE Worksheets (nicht gefiltert) um höchste WSID zu finden // Hole ALLE Worksheets (nicht gefiltert) um höchste WSID zu finden
const response = await databases.listDocuments( const response = await databases.listDocuments(
@@ -287,18 +128,6 @@ export function useWorksheets(woid = null) {
* Erstellt ein neues Worksheet * Erstellt ein neues Worksheet
*/ */
const createWorksheet = async (data, currentUser) => { const createWorksheet = async (data, currentUser) => {
if (DEMO_MODE) {
const wsid = await generateWSID()
const newWs = {
...data,
$id: Date.now().toString(),
wsid,
$createdAt: new Date().toISOString()
}
setWorksheets(prev => [newWs, ...prev])
return { success: true, data: newWs }
}
try { try {
// Validierung // Validierung
if (!data.woid || data.woid.trim() === '') { if (!data.woid || data.woid.trim() === '') {
@@ -371,11 +200,6 @@ export function useWorksheets(woid = null) {
* Aktualisiert ein Worksheet * Aktualisiert ein Worksheet
*/ */
const updateWorksheet = async (id, data) => { const updateWorksheet = async (id, data) => {
if (DEMO_MODE) {
setWorksheets(prev => prev.map(ws => ws.$id === id ? { ...ws, ...data } : ws))
return { success: true }
}
try { try {
const response = await databases.updateDocument( const response = await databases.updateDocument(
DATABASE_ID, DATABASE_ID,
@@ -410,11 +234,6 @@ export function useWorksheets(woid = null) {
* Löscht ein Worksheet (sollte normalerweise nicht erlaubt sein - Audit Trail!) * Löscht ein Worksheet (sollte normalerweise nicht erlaubt sein - Audit Trail!)
*/ */
const deleteWorksheet = async (id) => { const deleteWorksheet = async (id) => {
if (DEMO_MODE) {
setWorksheets(prev => prev.filter(ws => ws.$id !== id))
return { success: true }
}
try { try {
await databases.deleteDocument( await databases.deleteDocument(
DATABASE_ID, DATABASE_ID,
-4
View File
@@ -8,14 +8,10 @@ export const projectId = (
import.meta.env.VITE_APPWRITE_PROJECT_ID || DEFAULT_PROJECT_ID import.meta.env.VITE_APPWRITE_PROJECT_ID || DEFAULT_PROJECT_ID
).trim() ).trim()
/** Demo-Modus nur wenn wirklich keine Projekt-ID (sollte mit Defaults nie passieren) */
export const isDemoMode = !projectId
if (import.meta.env.DEV) { if (import.meta.env.DEV) {
console.log('🔧 Appwrite Konfiguration:') console.log('🔧 Appwrite Konfiguration:')
console.log('Endpoint:', endpoint) console.log('Endpoint:', endpoint)
console.log('Project ID:', projectId || 'NICHT GESETZT') console.log('Project ID:', projectId || 'NICHT GESETZT')
console.log('Demo-Modus:', isDemoMode)
console.log('Database ID:', import.meta.env.VITE_APPWRITE_DATABASE_ID || 'woms-database') console.log('Database ID:', import.meta.env.VITE_APPWRITE_DATABASE_ID || 'woms-database')
} }