feat(client): Onboarding-Tour um Statistik und Feedback erweitern

Neue Tour-Schritte für Statistik-Dashboard und Feedback-Formular, Hinweis
zum Löschen der Demo-Einträge und Landung auf Statistik nach Abschluss.
Rollenauflösung bei geteilten Logbüchern fail-closed bis die Rolle bekannt ist.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-30 14:03:46 +02:00
co-authored by Cursor
parent 7d75e74679
commit 1437b75c2f
9 changed files with 172 additions and 53 deletions
+2 -1
View File
@@ -30,7 +30,8 @@ export default function DemoViewer({ onExit }: DemoViewerProps) {
useEffect(() => {
registerNavigation({
setActiveTab,
setSelectedEntryId: setTourSelectedEntryId
setSelectedEntryId: setTourSelectedEntryId,
setFeedbackOpen: () => {}
})
registerDemoTourContext({ firstEntryId: fixture.firstEntryId })
+18 -4
View File
@@ -6,31 +6,45 @@ import FeedbackModal from './FeedbackModal.tsx'
interface FeedbackHeaderButtonProps {
logbookId?: string | null
logbookTitle?: string | null
tourOpen?: boolean
onTourOpenChange?: (open: boolean) => void
tourHighlight?: boolean
}
export default function FeedbackHeaderButton({
logbookId,
logbookTitle
logbookTitle,
tourOpen = false,
onTourOpenChange,
tourHighlight = false
}: FeedbackHeaderButtonProps) {
const { t } = useTranslation()
const [open, setOpen] = useState(false)
const [userOpen, setUserOpen] = useState(false)
const open = tourOpen || userOpen
const handleClose = () => {
setUserOpen(false)
onTourOpenChange?.(false)
}
return (
<>
<button
type="button"
className="btn-icon"
onClick={() => setOpen(true)}
onClick={() => setUserOpen(true)}
title={t('feedback.button_title')}
aria-label={t('feedback.button_title')}
data-tour="feedback-button"
>
<MessageSquarePlus size={18} />
</button>
<FeedbackModal
open={open}
onClose={() => setOpen(false)}
onClose={handleClose}
logbookId={logbookId}
logbookTitle={logbookTitle}
tourMode={tourHighlight}
/>
</>
)
+13 -5
View File
@@ -10,6 +10,7 @@ interface FeedbackModalProps {
onClose: () => void
logbookId?: string | null
logbookTitle?: string | null
tourMode?: boolean
}
type SubmitState = 'idle' | 'submitting' | 'success' | 'error'
@@ -18,7 +19,8 @@ export default function FeedbackModal({
open,
onClose,
logbookId,
logbookTitle
logbookTitle,
tourMode = false
}: FeedbackModalProps) {
const { t } = useTranslation()
const [category, setCategory] = useState<FeedbackCategory>('general')
@@ -97,14 +99,20 @@ export default function FeedbackModal({
if (!open) return null
return (
<div className="disclaimer-modal-overlay" onClick={isBusy ? undefined : onClose}>
<div
className={`disclaimer-modal-overlay${tourMode ? ' feedback-modal-overlay--tour' : ''}`}
onClick={isBusy || tourMode ? undefined : onClose}
>
<div className="disclaimer-modal-panel" onClick={(event) => event.stopPropagation()}>
<div className="auth-card glass registration-disclaimer registration-disclaimer--modal feedback-modal">
<div
className="auth-card glass registration-disclaimer registration-disclaimer--modal feedback-modal"
data-tour="feedback-form"
>
<button
type="button"
className="registration-disclaimer__close feedback-modal__close"
onClick={onClose}
disabled={isBusy}
disabled={isBusy || tourMode}
aria-label={t('feedback.cancel')}
>
<X size={18} />
@@ -187,7 +195,7 @@ export default function FeedbackModal({
type="button"
className="btn secondary"
onClick={onClose}
disabled={submitState === 'submitting'}
disabled={submitState === 'submitting' || tourMode}
>
{t('feedback.cancel')}
</button>
+1 -1
View File
@@ -310,7 +310,7 @@ export default function StatsDashboard({ logbookId, logbookTitle }: StatsDashboa
}, [accountStats])
return (
<div className="form-card">
<div className="form-card" data-tour="stats-dashboard">
<div className="form-header">
<BarChart2 size={24} className="form-icon" />
<div>