From f8574e5f398638e8a25db71602ad8dce80db0f95 Mon Sep 17 00:00:00 2001 From: mboehmlaender Date: Wed, 5 Aug 2026 15:56:09 +0200 Subject: [PATCH] Refine help UX and monthly close layout --- frontend/src/App.tsx | 60 +++-- frontend/src/components/HelpLink.tsx | 35 ++- frontend/src/help-content.ts | 277 ++++++++++++++++++++++++ frontend/src/views/FaqPage.tsx | 202 +++-------------- frontend/src/views/MonthlyClosePage.tsx | 36 +-- 5 files changed, 396 insertions(+), 214 deletions(-) create mode 100644 frontend/src/help-content.ts diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 55d606f..f3b137f 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -69,6 +69,19 @@ import { TimerPage } from "./views/TimerPage"; import type { AuthUser, PeriodType } from "./types"; import type { Dispatch, SetStateAction } from "react"; +type NavMenuEntry = + | { + type: "item"; + href: string; + label: string; + icon: typeof Timer; + active: boolean; + } + | { + type: "separator"; + key: string; + }; + function routeFromPath(pathname: string) { const periodTicketMatch = pathname.match(/^\/analysis\/(month|day)\/([^/]+)\/tickets\/(\d+)$/); @@ -518,17 +531,20 @@ export function App() { return ; } - const navItems = [ - { href: "/timer", label: "Timer", icon: Timer, active: path.startsWith("/timer") || path === "/" }, - { href: "/analysis", label: "Auswertung", icon: BarChart3, active: path.startsWith("/analysis") }, - { href: "/monthly-close", label: "Monatsabschluss", icon: ClipboardCheck, active: path.startsWith("/monthly-close") }, - { href: "/statistics", label: "Statistiken", icon: ChartNoAxesCombined, active: path.startsWith("/statistics") }, - { href: "/recurring", label: "Fixe Abrechnung", icon: Repeat, active: path.startsWith("/recurring") }, - { href: "/faq", label: "FAQ", icon: CircleHelp, active: path.startsWith("/faq") }, - { href: "/profile", label: "Profil", icon: UserCog, active: path.startsWith("/profile") }, + const navItems: NavMenuEntry[] = [ + { type: "item", href: "/timer", label: "Timer", icon: Timer, active: path.startsWith("/timer") || path === "/" }, + { type: "item", href: "/analysis", label: "Auswertung", icon: BarChart3, active: path.startsWith("/analysis") }, + { type: "separator", key: "after-analysis" }, + { type: "item", href: "/monthly-close", label: "Monatsabschluss", icon: ClipboardCheck, active: path.startsWith("/monthly-close") }, + { type: "separator", key: "after-monthly-close" }, + { type: "item", href: "/statistics", label: "Statistiken", icon: ChartNoAxesCombined, active: path.startsWith("/statistics") }, + { type: "item", href: "/recurring", label: "Fixe Abrechnung", icon: Repeat, active: path.startsWith("/recurring") }, + { type: "item", href: "/profile", label: "Profil", icon: UserCog, active: path.startsWith("/profile") }, ...(currentUser.role === "admin" - ? [{ href: "/admin/users", label: "Benutzer", icon: Shield, active: path.startsWith("/admin/users") }] + ? [{ type: "item" as const, href: "/admin/users", label: "Benutzer", icon: Shield, active: path.startsWith("/admin/users") }] : []), + { type: "separator", key: "before-faq" }, + { type: "item", href: "/faq", label: "FAQ", icon: CircleHelp, active: path.startsWith("/faq") }, ]; const runningTimer = timers.find((timer) => timer.phase === "running") ?? null; const runningElapsedSeconds = runningTimer ? Math.floor(activeElapsedMs(runningTimer, tick) / 1000) : 0; @@ -589,16 +605,22 @@ export function App() { Workflows - {navItems.map((item) => ( - - - - - {item.label} - - - - ))} + {navItems.map((item) => + item.type === "separator" ? ( + + + + ) : ( + + + + + {item.label} + + + + ) + )} diff --git a/frontend/src/components/HelpLink.tsx b/frontend/src/components/HelpLink.tsx index 346bd13..14a604c 100644 --- a/frontend/src/components/HelpLink.tsx +++ b/frontend/src/components/HelpLink.tsx @@ -1,6 +1,8 @@ import { CircleHelp } from "lucide-react"; import { Button } from "@/components/ui/button"; +import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; +import { getHelpSection } from "../help-content"; type HelpLinkProps = { anchor: string; @@ -9,11 +11,34 @@ type HelpLinkProps = { }; export function HelpLink({ anchor, label = "Hilfe öffnen", className }: HelpLinkProps) { + const section = getHelpSection(anchor); + return ( - + + + + + + + {section.title} + {section.description} + +
    + {section.quickItems.map((item) => ( +
  • + + {item} +
  • + ))} +
+ + + +
+
); } diff --git a/frontend/src/help-content.ts b/frontend/src/help-content.ts new file mode 100644 index 0000000..34df3c9 --- /dev/null +++ b/frontend/src/help-content.ts @@ -0,0 +1,277 @@ +export type HelpSection = { + id: string; + title: string; + description: string; + quickItems: string[]; + details: string[]; +}; + +export const helpSections: HelpSection[] = [ + { + id: "grundprinzip", + title: "Grundprinzip", + description: "TicketTracker ist die Arbeitszeiterfassung neben Ticketsystem und CRM. Die App misst Arbeit, bewertet Sessions und macht Monatsabschlüsse kontrollierbar.", + quickItems: [ + "Sessions sind die getrackten oder nachgetragenen Arbeitszeiten.", + "Teamspace-Werte sind Tageswerte pro Ticket, nicht einzelne Sessions.", + "Abgeschlossen wird nur der Monat." + ], + details: [ + "TicketTracker ersetzt nicht das Ticketsystem. Ticketnummern dienen als Bezug zur Arbeit, die eigentliche Dokumentation bleibt im vorhandenen Ticketsystem.", + "TicketTracker ersetzt auch nicht das CRM. Die CRM- beziehungsweise Teamspace-Zeit wird als Kontrollwert gepflegt, damit getrackte Zeiten und eingetragene Abrechnung gegenübergestellt werden können.", + "Eine Session ist immer einem Benutzer zugeordnet. In den normalen Auswertungen sieht jeder Benutzer nur seine eigenen Sessions.", + "Ticketdaten wie Organisation und Art können aus bestehenden Tickets übernommen werden, auch wenn ein anderer Benutzer das Ticket schon bearbeitet hat.", + "Tickets werden nicht abgeschlossen. Sie gruppieren Sessions. Relevant für den Abschluss ist nur, ob alle Sessions eines Monats bewertet sind.", + "Der Monatsabschluss sperrt den Monat gegen versehentliche Änderungen. Muss doch noch etwas korrigiert werden, kann der Monat wieder geöffnet werden." + ] + }, + { + id: "timer", + title: "Timer", + description: "Timer erfassen laufende Arbeit an Tickets. Es können mehrere Timer vorbereitet sein, aber immer nur einer läuft aktiv.", + quickItems: [ + "Ticketnummer eingeben und Timer starten.", + "Aktivieren eines Timers pausiert alle anderen Timer automatisch.", + "Beim Beenden stoppt die Zeit sofort; Details werden danach gespeichert." + ], + details: [ + "Neue Timer werden mit einer Ticketnummer im Format Ticket#XXXXXX gestartet.", + "Alle laufenden und pausierten Timer bleiben in der Seitenleiste sichtbar, damit du auf jeder Unterseite sehen kannst, was vorbereitet oder aktiv ist.", + "Wenn ein anderer Timer aktiviert wird, pausiert TicketTracker die übrigen Timer automatisch. Dadurch kann nie versehentlich auf zwei Tickets gleichzeitig Zeit laufen.", + "Beim Klick auf Beenden wird die Stoppuhr sofort angehalten. Das Speichern der Tätigkeit findet danach statt und verlängert die gemessene Zeit nicht.", + "Existiert das Ticket bereits, übernimmt TicketTracker Organisation und Art. Dann muss beim Beenden nur noch die Tätigkeit eingetragen werden.", + "Existiert das Ticket noch nicht, müssen Organisation, Tätigkeit und Art angegeben werden.", + "Pausen werden von der Gesamtdauer abgezogen. Die gespeicherte Zeit wird auf volle Minuten gerundet.", + "Der Schnellstart im Kopfbereich funktioniert auf allen Unterseiten und nutzt dieselbe Timerlogik." + ] + }, + { + id: "session-nachtragen", + title: "Session Nachtragen", + description: "Nachtragen ist für vergessene Zeiten gedacht, wenn kein Timer gelaufen ist.", + quickItems: [ + "Datum, Von, Bis und Tätigkeit eintragen.", + "Benutzer tragen eigene Sessions nach; Admins können Benutzer auswählen.", + "Tätigkeiten sind mehrzeilig." + ], + details: [ + "Beim Nachtragen wird aus Datum, Startzeit und Endzeit automatisch die Dauer berechnet.", + "Das Ende muss nach dem Beginn liegen. Übernacht-Sessions sind aktuell nicht vorgesehen und sollten als getrennte Einträge gepflegt werden.", + "Die Organisation muss aus der synchronisierten Organisationsliste gewählt werden. Freitext ist absichtlich gesperrt.", + "Die Tätigkeit ist eine Textarea. Zeilenumbrüche bleiben erhalten und werden in der Ticketdetailansicht wieder ausgegeben.", + "Nachgetragene Sessions starten immer offen. Sie müssen später als Abgerechnet oder Nicht abrechenbar bewertet werden.", + "Admins können im Adminbereich zusätzlich bestimmen, welchem Benutzer die nachgetragene Session gehört.", + "In der Ticketdetailansicht kann eine Session direkt zum geöffneten Ticket nachgetragen werden. Ticketnummer und Stammdaten sind dort schon vorbelegt beziehungsweise aus dem Ticket abgeleitet." + ] + }, + { + id: "ticketdaten", + title: "Ticketdaten", + description: "Ticketdaten sind Stammdaten für ein Ticket und können nachträglich korrigiert werden.", + quickItems: [ + "Ticketnummer, Organisation und Art sind bearbeitbar.", + "Organisationen kommen aus der lokalen Zammad-Synchronisation.", + "Die Art wiederkehrender Sessions kommt aus der Regel." + ], + details: [ + "Ticketnummern können korrigiert werden, falls beim Starten oder Nachtragen ein falscher Bezug gewählt wurde.", + "Die Organisation wird immer über die Suchliste gewählt. Dadurch sind spätere Auswertungen pro Organisation zuverlässig.", + "Änderungen an Organisation und Art werden auf vorhandene manuelle Sessions dieses Tickets übernommen.", + "Bei wiederkehrenden Sessions ist die Art nicht direkt an der Session änderbar. Sie wird ausschließlich über die fixe Abrechnungsregel gesteuert.", + "Wenn ein Ticket bereits durch einen anderen Benutzer bekannt ist, können dessen Ticketdaten beim Beenden eines Timers übernommen werden. Die Session selbst bleibt trotzdem deinem Benutzer zugeordnet." + ] + }, + { + id: "organisationen", + title: "Organisationen", + description: "Organisationen kommen aus Zammad und bilden die Grundlage für saubere Kunden- und Monatsauswertungen.", + quickItems: [ + "Nur Admins synchronisieren Organisationen.", + "Freitext ist danach nicht mehr möglich.", + "Gespeichert werden Zammad-ID, Name und Zeitstempel." + ], + details: [ + "Im Adminbereich werden Zammad-URL und API-Key gespeichert. Der API-Key wird danach nicht mehr im Klartext angezeigt.", + "Beim Sync fragt TicketTracker die Organisationen aus Zammad ab und schreibt sie in die lokale Datenbank.", + "Neue Organisationen werden angelegt, geänderte Namen werden aktualisiert.", + "Organisationen, die in Zammad nicht mehr vorhanden sind, werden aus der lokalen Liste entfernt beziehungsweise von vorhandenen Tickets und Sessions gelöst.", + "Alte Sessions oder Tickets mit Freitext-Organisationen müssen manuell korrigiert werden, indem eine Organisation aus der Liste gewählt wird.", + "Die bewusst schlanke Organisationstabelle enthält interne ID, Zammad-ID, Name sowie Erstell- und Änderungszeitpunkte." + ] + }, + { + id: "auswertung", + title: "Auswertung", + description: "Die Auswertung ist die Arbeitsliste für Monat und Tag: Tickets öffnen, Sessions prüfen, sortieren und bewerten.", + quickItems: [ + "Monat oder Tag wählen; die Ansicht aktualisiert automatisch.", + "Tickets können gefiltert, gruppiert und sortiert werden.", + "Die Einstellungen bleiben nach Refresh und Browserneustart erhalten." + ], + details: [ + "Die Monatsansicht zeigt alle Tickets, die im gewählten Monat mindestens eine Session haben.", + "Die Tagesansicht zeigt dieselben Datenlogiken auf einen einzelnen Tag gefiltert. Es gibt keinen Tagesabschluss.", + "Die Pfeile neben der Zeitraum-Eingabe springen jeweils einen Monat oder einen Tag vor beziehungsweise zurück.", + "Der Gesamtaufwand-Graph zeigt den getrackten Aufwand im Zeitraum. In der Monatsansicht pro Tag, in der Tagesansicht pro Stunde.", + "Die Ticketliste kann nach Typ, Organisation oder Status gruppiert werden. Gruppenüberschriften zeigen Anzahl, Zeit und offene Bewertungen.", + "Filter und Sortierungen bleiben im Browser gespeichert und können über Zurücksetzen wieder auf Standard gestellt werden.", + "Das Copy-Icon neben der Ticketnummer kopiert die Nummer direkt in die Zwischenablage." + ] + }, + { + id: "ticketdetail", + title: "Ticketdetailansicht", + description: "Die Ticketdetailansicht ist die Bearbeitungsfläche für Sessions, Bewertungen und Teamspace-Tageswerte eines Tickets.", + quickItems: [ + "Sessions sind nach Tag gruppiert.", + "Teamspace wird pro Ticket und Tag gespeichert.", + "Monats- und Tagesansicht verwenden denselben Teamspace-Wert." + ], + details: [ + "Oben steht die Ticketnummer mit Copy-Icon, damit sie schnell in andere Systeme übernommen werden kann.", + "Die Session-Einträge sind nach Kalendertagen gruppiert. Pro Tagesgruppe steht die Summe der getrackten Zeit.", + "Das Teamspace-Feld wird als Stundenwert gepflegt, zum Beispiel 1, 1,5 oder 2.25.", + "Während der Eingabe wird der Teamspace-Wert nicht sofort gespeichert. Sobald eine Änderung vorliegt, erscheint ein Speichern-Button.", + "Ein leeres Teamspace-Feld entfernt den gespeicherten Teamspace-Wert für diesen Ticket-Tag.", + "Der Teamspace-Wert hängt am Ticket, Benutzer und Tag. Deshalb ist er in Monats- und Tagesansicht identisch.", + "Sessions können bewertet, bearbeitet oder gelöscht werden. Gelöschte letzte Sessions können dazu führen, dass ein leeres Ticket entfernt wird." + ] + }, + { + id: "sessions-bewerten", + title: "Sessions Bewerten", + description: "Bewertungen bestimmen, ob eine Session abgerechnet wurde oder bewusst nicht abrechenbar ist.", + quickItems: [ + "Jede Session braucht genau eine Bewertung.", + "Abgerechnet und Nicht abrechenbar können durch erneuten Klick zurückgenommen werden.", + "Offene Bewertungen blockieren den Monatsabschluss." + ], + details: [ + "Abgerechnet bedeutet: Die Session wurde für die Abrechnung beziehungsweise im CRM berücksichtigt.", + "Nicht abrechenbar bedeutet: Die Session gehört zum Arbeitsnachweis, wird aber nicht abgerechnet.", + "Ein erneuter Klick auf den aktiven Bewertungsbutton entfernt die Bewertung und macht die Session wieder offen.", + "Nicht abrechenbare Sessions zählen als bewertet. Sie blockieren den Monatsabschluss nicht.", + "Wenn ein Monat abgeschlossen ist, sind Bewertungen gesperrt. Öffne den Monat zuerst wieder, wenn du etwas korrigieren musst.", + "Die offenen Bewertungen findest du gebündelt im Monatsabschluss." + ] + }, + { + id: "sessions-bearbeiten", + title: "Sessions Bearbeiten und Löschen", + description: "Sessions können korrigiert, gelöscht und bei wiederkehrenden Einträgen als Ausnahme behandelt werden.", + quickItems: [ + "Bearbeiten läuft über das Stift-Icon.", + "Löschen läuft über das Papierkorb-Icon.", + "Wiederkehrende gelöschte Sessions werden nicht neu erzeugt." + ], + details: [ + "Beim Bearbeiten sind Datum, Von-Uhrzeit, Bis-Uhrzeit, Organisation und Tätigkeit änderbar.", + "Die Art ist bei manuellen Sessions änderbar. Bei wiederkehrenden Sessions ist sie gesperrt und kommt aus der Regel.", + "Die Dauer wird aus Von und Bis neu berechnet und wieder auf Minuten gerundet.", + "Beim Löschen wird geprüft, ob dadurch ein Ticket für dich oder komplett leer wird. Leere Tickets werden entfernt.", + "Wenn die letzte Session eines Tickets gelöscht wird, springt die Ansicht zurück zur Auswertung.", + "Wiederkehrend erzeugte Sessions werden beim Löschen als Ausnahme gespeichert. Dadurch erscheinen sie beim nächsten Öffnen des Monats nicht wieder automatisch.", + "Wenn eine wiederkehrende Leistung nur an einem anderen Tag erledigt wurde, wird die erzeugte Session bearbeitet beziehungsweise verschoben." + ] + }, + { + id: "monatsabschluss", + title: "Monatsabschluss", + description: "Der Monatsabschluss ist die Kontrollseite für offene Bewertungen und Teamspace-Punkte vor dem Abschluss.", + quickItems: [ + "Bewertungen sind Pflicht für den Abschluss.", + "Tage ohne Teamspace-Wert können zur Kenntnis genommen werden.", + "Der Monat kann wieder geöffnet werden." + ], + details: [ + "Ein Monat kann abgeschlossen werden, sobald alle Sessions dieses Monats bewertet sind.", + "Tage ohne Teamspace-Wert blockieren den Abschluss nicht automatisch. Sie sind eine Prüfliste für CRM-Abgleich und Nacharbeit.", + "Wenn eine Session bewusst nicht in Teamspace eingetragen wird, kann der fehlende Tageswert zur Kenntnis genommen werden.", + "Zur Kenntnis genommene Einträge können über die Checkbox Zur Kenntnis anzeigen wieder eingeblendet werden.", + "Die Kenntnisnahme kann pro Eintrag über Zurücknehmen rückgängig gemacht werden.", + "Die Einstellung, ob zur Kenntnis genommene Einträge angezeigt werden, bleibt im Browser gespeichert.", + "Offene Bewertungen werden nach Ticket gruppiert. Ein Klick auf Ticket öffnen führt zur Bewertung im Ticket.", + "Es gibt keinen Tagesabschluss. Tagesansichten dienen nur der Kontrolle." + ] + }, + { + id: "fixe-abrechnungen", + title: "Fixe Abrechnungen", + description: "Fixe Abrechnungen erzeugen wiederkehrende Sessions für planbare regelmäßige Leistungen.", + quickItems: [ + "Jeder Benutzer verwaltet eigene fixe Abrechnungen.", + "Ticket ist optional; ohne Ticket entsteht Fix#ID.", + "Feiertage in Bayern werden übersprungen." + ], + details: [ + "Fixe Abrechnungen sind für regelmäßige Leistungen gedacht, zum Beispiel jeden Donnerstag vier Stunden oder mehrere Wochentage mit unterschiedlichen Dauern.", + "Das Ticketfeld darf leer bleiben. Dann gruppiert TicketTracker die erzeugten Sessions automatisch unter Fix#ID.", + "Die Organisation, Art und Tätigkeit kommen aus der Regel und werden auf erzeugte Sessions angewendet.", + "Beim Muster Wochentage werden einzelne Slots mit Wochentag, Startzeit und Dauer gepflegt.", + "Beim Muster Alle X Wochen zählt das Gültig-von-Datum als Startpunkt. Das Intervall läuft wochenweise.", + "Gültig bis ist optional. Wird es später gesetzt oder geändert, werden erzeugte Sessions außerhalb der Gültigkeit entfernt.", + "Bayerische Feiertage werden bei der automatischen Anlage ausgelassen.", + "Einzelne erzeugte Sessions können wegen Urlaub, Krankheit oder Feiertagsverschiebung gelöscht oder verschoben werden." + ] + }, + { + id: "statistiken", + title: "Statistiken", + description: "Statistiken vergleichen getrackte Arbeit, bewertete Sessions und Teamspace-Werte.", + quickItems: [ + "Sessions und Teamspace haben getrennte Farben.", + "Positive oder gleiche Differenz ist grün.", + "Negative Differenz ist rot." + ], + details: [ + "Die Statistikseite betrachtet immer einen Monat.", + "Getrackt zeigt die Summe aller Session-Zeiten und die Anzahl der Sessions und Tickets.", + "Teamspace zeigt, wie viel Zeit für dieselben Ticket-Tage im CRM eingetragen wurde.", + "Eine positive Differenz bedeutet: In Teamspace steht mehr Zeit als in den Sessions getrackt wurde.", + "Eine negative Differenz bedeutet: In Teamspace steht weniger Zeit als getrackt wurde.", + "Bewertet umfasst sowohl Abgerechnet als auch Nicht abrechenbar. Offen sind nur Sessions ohne Bewertung.", + "Der Monatsverlauf zeigt getrackte Session-Zeit als Balken und Teamspace als Linie.", + "Organisationen, Typen und Ticket-Hotspots helfen dabei, Auffälligkeiten im Monat schnell zu finden." + ] + }, + { + id: "profil", + title: "Profil", + description: "Im Profil pflegt jeder Benutzer die eigenen Zugangsdaten.", + quickItems: [ + "Benutzername und voller Name sind änderbar.", + "Passwortänderung benötigt das aktuelle Passwort.", + "Der volle Name wird in der Oberfläche angezeigt." + ], + details: [ + "Der Benutzername wird beim Login verwendet und muss eindeutig sein.", + "Der volle Name erscheint in der App, zum Beispiel im Kopfbereich oder im Adminbereich.", + "Wenn du dein Passwort ändern willst, musst du das aktuelle Passwort sowie das neue Passwort zweimal eingeben.", + "Bleiben die Passwortfelder leer, werden nur Benutzername und voller Name gespeichert.", + "Admins können Benutzer ebenfalls verwalten, aber jeder Benutzer kann die eigenen Daten jederzeit selbst pflegen." + ] + }, + { + id: "admin", + title: "Adminbereich", + description: "Der Adminbereich verwaltet Benutzer, Session-Zuordnung, manuelle Admin-Nachträge und Zammad-Sync.", + quickItems: [ + "Admins legen Benutzer an und bearbeiten Rollen.", + "Sessions können anderen Benutzern zugewiesen werden.", + "Zammad-Organisationen werden über Data-Sync aktualisiert." + ], + details: [ + "Neue Benutzer bekommen Benutzername, vollen Namen, Passwort, Rolle und Aktivstatus.", + "Admins können bestehende Benutzer bearbeiten, Passwörter setzen und Benutzer deaktivieren.", + "Der eigene Admin-Zugang kann nicht versehentlich deaktiviert oder zur normalen User-Rolle herabgestuft werden.", + "In der Session-Zuordnung sehen Admins die letzten Sessions inklusive Besitzer und können einzelne Sessions umverteilen.", + "Beim Umverteilen werden die betroffenen Monatsabschlüsse für alten und neuen Besitzer wieder geöffnet, damit Bewertungen und Auswertungen konsistent bleiben.", + "Admins können Sessions für andere Benutzer nachtragen, wenn Zeiten vergessen wurden.", + "Der Data-Sync speichert Zammad-Zugangsdaten und synchronisiert Organisationen in die lokale Datenbank." + ] + } +]; + +export function getHelpSection(anchor: string) { + return helpSections.find((section) => section.id === anchor) ?? helpSections[0]; +} diff --git a/frontend/src/views/FaqPage.tsx b/frontend/src/views/FaqPage.tsx index 610c2af..daa59e2 100644 --- a/frontend/src/views/FaqPage.tsx +++ b/frontend/src/views/FaqPage.tsx @@ -3,163 +3,7 @@ import { ArrowUp, BookOpenCheck } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; - -type FaqSection = { - id: string; - title: string; - description: string; - items: string[]; -}; - -const faqSections: FaqSection[] = [ - { - id: "grundprinzip", - title: "Grundprinzip", - description: "TicketTracker ersetzt weder Ticketsystem noch CRM. Die App misst Zeiten, bewertet Sessions und bereitet den Monatsabschluss vor.", - items: [ - "Session-Zeit ist die gemessene oder manuell erfasste Arbeitszeit einer Tätigkeit.", - "Teamspace-Zeit ist der Tageswert, der für ein Ticket wirklich im CRM eingetragen wurde.", - "Abgeschlossen wird nur ein Monat. Tickets werden nicht geschlossen, sondern nur über ihre Sessions bewertet." - ] - }, - { - id: "timer", - title: "Timer", - description: "Timer sind für laufende Arbeit an Tickets gedacht.", - items: [ - "Ticketnummer im Format Ticket#XXXXXX eingeben und Timer starten.", - "Es können mehrere Timer vorbereitet sein, aber immer nur einer läuft aktiv.", - "Wird ein Timer aktiviert, werden alle anderen automatisch pausiert.", - "Beim Klick auf Beenden stoppt die Zeit sofort. Danach werden Tätigkeit und gegebenenfalls Organisation und Art gespeichert." - ] - }, - { - id: "session-nachtragen", - title: "Session Nachtragen", - description: "Vergessene Zeiten können nachträglich als Session angelegt werden.", - items: [ - "Benutzer tragen eigene Sessions nach. Admins können Sessions auch anderen Benutzern zuweisen.", - "Pflichtangaben sind Ticket, Organisation, Art, Datum, Von, Bis und Tätigkeit.", - "Das Tätigkeitsfeld ist mehrzeilig. Zeilenumbrüche bleiben in den Auswertungen erhalten." - ] - }, - { - id: "ticketdaten", - title: "Ticketdaten", - description: "Ticketdaten können in der Ticketdetailansicht korrigiert werden.", - items: [ - "Bearbeitbar sind Ticketnummer, Organisation und Art.", - "Änderungen an Organisation und Art werden auf vorhandene manuelle Sessions des Tickets übernommen.", - "Bei wiederkehrenden Sessions kommt die Art aus der Regel der fixen Abrechnung." - ] - }, - { - id: "organisationen", - title: "Organisationen", - description: "Organisationen werden aus Zammad synchronisiert und danach aus der lokalen Liste gewählt.", - items: [ - "Freitext ist nicht mehr erlaubt, damit Auswertungen je Organisation sauber möglich sind.", - "Alte Freitexte müssen manuell korrigiert werden.", - "Der Zammad-Sync speichert nur interne ID, Zammad-ID, Name und Zeitstempel." - ] - }, - { - id: "auswertung", - title: "Auswertung", - description: "Die Auswertung zeigt Monats- oder Tageswerte und listet Tickets im gewählten Zeitraum.", - items: [ - "Mit den Pfeilen neben Monat oder Datum wechselst du den Zeitraum. Die Daten aktualisieren sich automatisch.", - "Tickets können gefiltert, gruppiert und sortiert werden. Diese Einstellungen bleiben gespeichert.", - "Der Graph zeigt den Gesamtaufwand des gewählten Zeitraums." - ] - }, - { - id: "ticketdetail", - title: "Ticketdetailansicht", - description: "Hier werden alle Sessions eines Tickets im gewählten Monat oder Tag bearbeitet.", - items: [ - "Sessions sind nach Tagen gruppiert.", - "Pro Tag wird die getrackte Zeit angezeigt.", - "Das Teamspace-Feld speichert die Stunden, die für diesen Ticket-Tag wirklich im CRM eingetragen wurden.", - "Der Teamspace-Wert ist in Monats- und Tagesansicht derselbe." - ] - }, - { - id: "sessions-bewerten", - title: "Sessions Bewerten", - description: "Jede Session braucht eine Bewertung für die Abrechnung.", - items: [ - "Möglich sind Abgerechnet und Nicht abrechenbar.", - "Ein erneuter Klick auf die gewählte Bewertung nimmt sie zurück.", - "Bewertungen können bei abgeschlossenem Monat erst geändert werden, nachdem der Monat wieder geöffnet wurde." - ] - }, - { - id: "sessions-bearbeiten", - title: "Sessions Bearbeiten und Löschen", - description: "Sessions können korrigiert oder gelöscht werden.", - items: [ - "Bearbeitbar sind Datum, Von, Bis, Organisation, Tätigkeit und Art.", - "Bei wiederkehrenden Sessions ist die Art gesperrt und wird über die Regel geändert.", - "Wird die letzte Session eines Tickets gelöscht, wird das leere Ticket entfernt.", - "Gelöschte wiederkehrende Sessions werden als Ausnahme gespeichert und nicht automatisch neu erzeugt." - ] - }, - { - id: "monatsabschluss", - title: "Monatsabschluss", - description: "Der Monatsabschluss bündelt offene Bewertungen und Teamspace-Prüfpunkte.", - items: [ - "Ein Monat kann abgeschlossen werden, sobald alle Sessions des Monats bewertet sind.", - "Tage ohne Teamspace-Wert können zur Kenntnis genommen werden, wenn sie bewusst nicht ins CRM gehören.", - "Zur Kenntnis genommene Teamspace-Punkte können eingeblendet und zurückgenommen werden.", - "Einen Tagesabschluss gibt es nicht." - ] - }, - { - id: "fixe-abrechnungen", - title: "Fixe Abrechnungen", - description: "Fixe Abrechnungen erzeugen wiederkehrende Sessions für den eigenen Account.", - items: [ - "Ticket ist optional. Ohne Ticket wird automatisch Fix#ID verwendet.", - "Muster können Wochentage oder alle X Wochen sein.", - "Gültig bis ist optional. Wird es später gesetzt, werden nicht mehr gültige erzeugte Sessions entfernt.", - "Bayerische Feiertage werden übersprungen." - ] - }, - { - id: "statistiken", - title: "Statistiken", - description: "Die Statistikseite vergleicht getrackte Sessions mit Teamspace-Zeiten.", - items: [ - "Sessions und Teamspace haben eigene Farben.", - "Eine positive oder ausgeglichene Differenz ist grün.", - "Eine negative Differenz ist rot und bedeutet: in Teamspace ist weniger eingetragen als getrackt.", - "Organisationen, Typen und Ticket-Hotspots helfen bei der Monatskontrolle." - ] - }, - { - id: "profil", - title: "Profil", - description: "Jeder Benutzer kann eigene Accountdaten pflegen.", - items: [ - "Benutzername und voller Name können geändert werden.", - "Passwortänderungen benötigen das aktuelle Passwort.", - "Der volle Name wird in der App angezeigt." - ] - }, - { - id: "admin", - title: "Adminbereich", - description: "Admins verwalten Benutzer, Sessions und Zammad-Organisationen.", - items: [ - "Admins legen Benutzer an und können deren Daten bearbeiten.", - "Sessions können zwischen Benutzern umverteilt werden.", - "Admins können Sessions für andere Benutzer nachtragen.", - "Der Zammad-Zugang wird gespeichert und der Organisationssync aktualisiert die lokale Organisationsliste." - ] - } -]; +import { helpSections } from "../help-content"; export function FaqPage() { return ( @@ -167,9 +11,9 @@ export function FaqPage() {

FAQ und Anleitung

-

Kurzanleitung für Timer, Auswertung, Teamspace, fixe Abrechnungen und Adminfunktionen.

+

Ausführliche Anleitung für Timer, Auswertung, Teamspace, fixe Abrechnungen, Monatsabschluss und Adminfunktionen.

- {faqSections.length} Abschnitt(e) + {helpSections.length} Abschnitt(e)
@@ -178,10 +22,10 @@ export function FaqPage() { Schnellnavigation - Die Fragezeichen in der App springen direkt in diese Abschnitte. + Die Fragezeichen in der App öffnen eine Kurzfassung. Von dort gelangst du direkt zum passenden ausführlichen Abschnitt. - {faqSections.map((section) => ( + {helpSections.map((section) => ( @@ -190,22 +34,36 @@ export function FaqPage() {
- {faqSections.map((section) => ( + {helpSections.map((section) => ( {section.title} {section.description} - -
    - {section.items.map((item) => ( -
  • - - {item} -
  • - ))} -
-
+ +
+

Kurzfassung

+
    + {section.quickItems.map((item) => ( +
  • + + {item} +
  • + ))} +
+
+
+

Details

+
    + {section.details.map((item) => ( +
  • + + {item} +
  • + ))} +
+
+