Merge remote-tracking branch 'origin/main'
# Conflicts: # db/custom.db # src/components/FuseButton.tsx # src/components/SlideCommit.tsx
This commit is contained in:
commit
58521ca03a
23 files changed
+2622
-26
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>
|
||||
</>
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
Filter,
|
||||
ArrowRight,
|
||||
} from 'lucide-react'
|
||||
import { SwipeableLeadCard } from '../swipeable-lead-card'
|
||||
import { useFetch } from '@/hooks/use-fetch'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
@@ -207,6 +208,28 @@ export function LeadsView() {
|
||||
<div className="space-y-1.5 p-2">
|
||||
{filtered.map((l) => {
|
||||
const meta = STATUS_META[l.status] ?? STATUS_META.pending
|
||||
// Pending leads get SwipeRow (swipe to approve/reject/snooze)
|
||||
if (l.status === 'pending') {
|
||||
return (
|
||||
<div key={l.id} className={cn('rounded-md border overflow-hidden', selected?.id === l.id && 'ring-1 ring-foreground/40')}>
|
||||
<SwipeableLeadCard
|
||||
lead={{
|
||||
id: l.id,
|
||||
companyName: l.companyName,
|
||||
website: l.website,
|
||||
city: l.city,
|
||||
score: l.score,
|
||||
scoreLabel: l.scoreLabel,
|
||||
createdAt: l.createdAt,
|
||||
}}
|
||||
onApprove={(id) => { setSelectedId(id); review(id, 'approved') }}
|
||||
onReject={(id) => { setSelectedId(id); review(id, 'rejected', 'Nicht zur Zielgruppe') }}
|
||||
onSnooze={(id) => { setSelectedId(id); review(id, 'snoozed', 'Später erneut prüfen') }}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
// Non-pending leads keep the simple button card
|
||||
return (
|
||||
<button
|
||||
key={l.id}
|
||||
|
||||
@@ -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