This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/admin-v2/components/sdk/dsr/DSRWorkflowStepper.tsx
BreakPilot Dev 19855efacc
Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
feat: BreakPilot PWA - Full codebase (clean push without large binaries)
All services: admin-v2, studio-v2, website, ai-compliance-sdk,
consent-service, klausur-service, voice-service, and infrastructure.
Large PDFs and compiled binaries excluded via .gitignore.
2026-02-11 13:25:58 +01:00

177 lines
5.9 KiB
TypeScript

'use client'
import React from 'react'
import { DSRStatus, DSR_STATUS_INFO } from '@/lib/sdk/dsr/types'
interface WorkflowStep {
id: DSRStatus
label: string
description?: string
}
const WORKFLOW_STEPS: WorkflowStep[] = [
{ id: 'intake', label: 'Eingang', description: 'Anfrage dokumentiert' },
{ id: 'identity_verification', label: 'ID-Pruefung', description: 'Identitaet verifizieren' },
{ id: 'processing', label: 'Bearbeitung', description: 'Anfrage bearbeiten' },
{ id: 'completed', label: 'Abschluss', description: 'Antwort versenden' }
]
interface DSRWorkflowStepperProps {
currentStatus: DSRStatus
onStepClick?: (status: DSRStatus) => void
className?: string
}
export function DSRWorkflowStepper({
currentStatus,
onStepClick,
className = ''
}: DSRWorkflowStepperProps) {
const currentIndex = WORKFLOW_STEPS.findIndex(s => s.id === currentStatus)
const isRejectedOrCancelled = currentStatus === 'rejected' || currentStatus === 'cancelled'
const getStepState = (index: number): 'completed' | 'current' | 'upcoming' => {
if (isRejectedOrCancelled) {
return index <= currentIndex ? 'completed' : 'upcoming'
}
if (index < currentIndex) return 'completed'
if (index === currentIndex) return 'current'
return 'upcoming'
}
return (
<div className={`${className}`}>
<div className="flex items-center justify-between">
{WORKFLOW_STEPS.map((step, index) => {
const state = getStepState(index)
const isLast = index === WORKFLOW_STEPS.length - 1
return (
<React.Fragment key={step.id}>
{/* Step */}
<div
className={`flex flex-col items-center ${
onStepClick && state !== 'upcoming' ? 'cursor-pointer' : ''
}`}
onClick={() => onStepClick && state !== 'upcoming' && onStepClick(step.id)}
>
{/* Circle */}
<div
className={`
w-10 h-10 rounded-full flex items-center justify-center font-medium text-sm
transition-all duration-200
${state === 'completed'
? 'bg-green-500 text-white'
: state === 'current'
? 'bg-purple-600 text-white ring-4 ring-purple-100'
: 'bg-gray-200 text-gray-400'
}
`}
>
{state === 'completed' ? (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
) : (
index + 1
)}
</div>
{/* Label */}
<div className="mt-2 text-center">
<div
className={`text-sm font-medium ${
state === 'current' ? 'text-purple-600' :
state === 'completed' ? 'text-green-600' : 'text-gray-400'
}`}
>
{step.label}
</div>
{step.description && (
<div className="text-xs text-gray-500 mt-0.5 hidden sm:block">
{step.description}
</div>
)}
</div>
</div>
{/* Connector Line */}
{!isLast && (
<div
className={`
flex-1 h-1 mx-2 rounded-full
${state === 'completed' || getStepState(index + 1) === 'completed' || getStepState(index + 1) === 'current'
? 'bg-green-500'
: 'bg-gray-200'
}
`}
/>
)}
</React.Fragment>
)
})}
</div>
{/* Rejected/Cancelled Badge */}
{isRejectedOrCancelled && (
<div className={`
mt-4 px-4 py-2 rounded-lg text-center text-sm font-medium
${currentStatus === 'rejected'
? 'bg-red-100 text-red-700 border border-red-200'
: 'bg-gray-100 text-gray-700 border border-gray-200'
}
`}>
{currentStatus === 'rejected' ? 'Anfrage wurde abgelehnt' : 'Anfrage wurde storniert'}
</div>
)}
</div>
)
}
// Compact version for list views
export function DSRWorkflowStepperCompact({
currentStatus,
className = ''
}: {
currentStatus: DSRStatus
className?: string
}) {
const statusInfo = DSR_STATUS_INFO[currentStatus]
const currentIndex = WORKFLOW_STEPS.findIndex(s => s.id === currentStatus)
const totalSteps = WORKFLOW_STEPS.length
const isTerminal = currentStatus === 'rejected' || currentStatus === 'cancelled' || currentStatus === 'completed'
return (
<div className={`flex items-center gap-2 ${className}`}>
{/* Mini progress dots */}
<div className="flex items-center gap-1">
{WORKFLOW_STEPS.map((step, index) => (
<div
key={step.id}
className={`
w-2 h-2 rounded-full transition-all
${index < currentIndex
? 'bg-green-500'
: index === currentIndex
? isTerminal
? currentStatus === 'completed'
? 'bg-green-500'
: currentStatus === 'rejected'
? 'bg-red-500'
: 'bg-gray-500'
: 'bg-purple-500'
: 'bg-gray-200'
}
`}
/>
))}
</div>
{/* Status label */}
<span className={`text-xs font-medium px-2 py-0.5 rounded-full ${statusInfo.bgColor} ${statusInfo.color}`}>
{statusInfo.label}
</span>
</div>
)
}