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
+19 -1
View File
@@ -9,6 +9,7 @@ import {
} from './OpportunityList';
import { OpportunityPipeline } from './OpportunityPipeline';
import { OpportunityModal } from './OpportunityModal';
import { OpportunityCopyDialog } from './OpportunityCopyDialog';
import { STAGE_LABELS } from './opportunityUi';
import { ConfirmDialog } from '../ui/Modal';
import { useToast } from '../Toast';
@@ -113,6 +114,8 @@ export const Opportunities: React.FC<OpportunitiesProps> = ({
const [isModalOpen, setIsModalOpen] = useState(false);
const [editing, setEditing] = useState<Opportunity | null>(null);
const [toDelete, setToDelete] = useState<Opportunity | null>(null);
// Fuer welche Opportunity gerade Kopien fuer andere Berater angelegt werden.
const [toCopy, setToCopy] = useState<Opportunity | null>(null);
const filtered = useMemo(() => {
const terms = searchTerm
@@ -388,7 +391,7 @@ export const Opportunities: React.FC<OpportunitiesProps> = ({
)}
</div>
) : viewMode === 'grid' ? (
<OpportunityGrid opportunities={filtered} onEdit={openEdit} onDelete={setToDelete} />
<OpportunityGrid opportunities={filtered} onEdit={openEdit} onDelete={setToDelete} onCopy={setToCopy} />
) : viewMode === 'list' ? (
<OpportunityList
opportunities={filtered}
@@ -396,6 +399,7 @@ export const Opportunities: React.FC<OpportunitiesProps> = ({
onSort={handleSort}
onEdit={openEdit}
onDelete={setToDelete}
onCopy={setToCopy}
/>
) : (
<OpportunityPipeline
@@ -403,6 +407,7 @@ export const Opportunities: React.FC<OpportunitiesProps> = ({
onEdit={openEdit}
onStageChange={changeStage}
onDelete={setToDelete}
onCopy={setToCopy}
/>
)}
@@ -413,6 +418,19 @@ export const Opportunities: React.FC<OpportunitiesProps> = ({
users={users}
onClose={() => setIsModalOpen(false)}
onSaved={reload}
onCopy={(opportunity) => {
// Der Bearbeiten-Dialog schliesst, sonst laegen zwei Dialoge uebereinander.
setIsModalOpen(false);
setToCopy(opportunity);
}}
/>
)}
{toCopy && (
<OpportunityCopyDialog
opportunity={toCopy}
onClose={() => setToCopy(null)}
onCopied={reload}
/>
)}