feat: ReactBits micro components integration
Installed 6 ReactBits micro components (src/components/): - SwipeRow: swipe-to-action cards (lead approve/reject/snooze) - CometDial: circular dial selector (future: dashboard KPI selector) - CodeSlots: code input slots (future: API token confirmation) - FuseButton: fuse-animated CTA with undo window - SlideCommit: slide-to-confirm (timesheet week lock) - HoldButton: hold-to-confirm (contract sign, dangerous actions) Integrated into views: - Timesheet: SlideCommit replaces 'Woche sperren' button - Contracts: HoldButton replaces 'E-Signatur anfordern' (hold 1.5s to sign) - Recurring: FuseButton replaces 'Jetzt ausführen' (with undo window) - Leads: SwipeableLeadCard created (swipe to approve/reject/snooze) Created wrapper components: - swipeable-lead-card.tsx: SwipeRow wrapper for lead cards - hold-to-confirm.tsx: HoldButton wrapper with loading state - fuse-cta.tsx: FuseButton wrapper with toast feedback - slide-to-lock.tsx: SlideCommit wrapper for GoBD week lock 0 TS errors, ESLint clean, no console errors.
This commit is contained in:
1 parent
21e112e5cb
commit
37e976a732
17 files changed
+2884
-25
No files matched your search
@@ -28,6 +28,7 @@ import {
|
||||
} from '@/components/ui/dialog'
|
||||
import { PageHeader } from '../primitives'
|
||||
import { formatEuro, formatDate, formatDateTime, daysUntil } from '@/lib/format'
|
||||
import { HoldToConfirm } from '../hold-to-confirm'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
@@ -312,10 +313,17 @@ export function ContractsView() {
|
||||
<DialogFooter className="gap-2">
|
||||
<Button variant="outline" onClick={() => setSelected(null)}>Schließen</Button>
|
||||
{canSign && (
|
||||
<Button onClick={() => sign(selected)} disabled={signing} className="gap-1.5">
|
||||
{signing ? <Loader2 className="size-3.5 animate-spin" /> : <PenLine className="size-3.5" />}
|
||||
E-Signatur anfordern
|
||||
</Button>
|
||||
<HoldToConfirm
|
||||
onConfirm={() => sign(selected)}
|
||||
holdTime={1500}
|
||||
size="md"
|
||||
disabled={signing}
|
||||
>
|
||||
<span className="flex items-center gap-1.5">
|
||||
<PenLine className="size-3.5" />
|
||||
E-Signatur anfordern
|
||||
</span>
|
||||
</HoldToConfirm>
|
||||
)}
|
||||
</DialogFooter>
|
||||
</>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
import { PageHeader } from '../primitives'
|
||||
import { FuseCTA } from '../fuse-cta'
|
||||
import { formatEuro, formatEuroCompact, formatDate } from '@/lib/format'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { toast } from 'sonner'
|
||||
@@ -76,10 +77,13 @@ export function RecurringView() {
|
||||
title="Wiederkehrende Rechnungen"
|
||||
description="Automatische Generierung von wiederkehrenden Rechnungen (Wartung/SLA-Verträge). Bei Mahnstufe 3: automatische Lizenz-Suspendierung (PRD §6.4)."
|
||||
actions={
|
||||
<Button size="sm" onClick={runNow} disabled={running} className="gap-1.5">
|
||||
{running ? <Loader2 className="size-4 animate-spin" /> : <Play className="size-4" />}
|
||||
Jetzt ausführen
|
||||
</Button>
|
||||
<FuseCTA
|
||||
label="Jetzt ausführen"
|
||||
doneLabel="Ausgeführt"
|
||||
onCommit={runNow}
|
||||
disabled={running}
|
||||
size="sm"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { formatMinutes } from '@/lib/format'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { toast } from 'sonner'
|
||||
import { ChevronLeft, ChevronRight, Lock, Clock, TrendingUp, CheckCircle2, Calendar } from 'lucide-react'
|
||||
import { SlideToLock } from '../slide-to-lock'
|
||||
|
||||
interface DayData {
|
||||
date: string
|
||||
@@ -83,10 +84,7 @@ export function TimesheetView() {
|
||||
description="Wochen-basierte Zeiterfassung mit PM-Freigabe (Lock). Nach Freigabe können Einträge nicht mehr geändert werden — GoBD-konform."
|
||||
actions={
|
||||
!stats.allLocked && stats.totalEntries > 0 ? (
|
||||
<Button size="sm" onClick={lockWeek} disabled={locking} className="gap-1.5">
|
||||
<Lock className="size-4" />
|
||||
Woche sperren
|
||||
</Button>
|
||||
<SlideToLock onConfirm={lockWeek} disabled={locking} />
|
||||
) : stats.allLocked ? (
|
||||
<Badge variant="outline" className="gap-1">
|
||||
<CheckCircle2 className="size-3" />Gesperrt
|
||||
|
||||
Reference in new issue
Block a user