feat(opportunities): Opportunity fuer andere Berater kopieren

Kopier-Symbol auf Kachel, Pipeline-Karte und Listenzeile sowie "Kopieren"
im Dialog. Ein Dialog fragt nach einem oder mehreren Beratern (aus der
Beraterliste der Akquise, ohne den eigenen) und der Phase der Kopie
(Standard: Neu). Neuer Endpoint POST /api/opportunities/:id/copy legt je
Berater eine Kopie mit Projektdaten, Ansprechpartnern, Zustaendigem und
acquisition_id an; Interaktion und naechster Schritt bleiben beim Original.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sascha Wolf
2026-09-17 13:31:59 +02:00
co-authored by Claude Opus 5
parent 33dedaedfb
commit 6724d0ab65
10 changed files with 392 additions and 3 deletions
@@ -21,6 +21,8 @@ interface OpportunityGridProps {
opportunities: Opportunity[];
onEdit: (opportunity: Opportunity) => void;
onDelete: (opportunity: Opportunity) => void;
/** Kopie fuer einen anderen Berater anlegen. */
onCopy: (opportunity: Opportunity) => void;
}
const Metric: React.FC<{ label: string; value: string; className?: string }> = ({
@@ -38,6 +40,7 @@ export const OpportunityGrid: React.FC<OpportunityGridProps> = ({
opportunities,
onEdit,
onDelete,
onCopy,
}) => (
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
{opportunities.map((opportunity) => {
@@ -76,6 +79,19 @@ export const OpportunityGrid: React.FC<OpportunityGridProps> = ({
</div>
{/* Sichtbar, nicht erst beim Ueberfahren: ein Knopf, den man nur findet,
wenn man ihn schon kennt, ist keiner. */}
<button
onClick={(event) => {
event.stopPropagation();
onCopy(opportunity);
}}
className="shrink-0 rounded-lg p-1.5 text-ink-400 transition hover:bg-brand-50 hover:text-brand-700"
title="Für anderen Berater kopieren"
aria-label={`${opportunity.title} für anderen Berater kopieren`}
>
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2" />
</svg>
</button>
<button
onClick={(event) => {
event.stopPropagation();