feat(opportunities): Phasen des Vermittlungsprozesses, Kanban zuerst, Zahlen im Menue
Drei Dinge: - Die Phasen sind jetzt die des Vermittlungsprozesses: Neu, Beworben, Erstgespraech Berater, Kundenvorstellung, Interview Kunde, Zusage, Beauftragt, Absage. Offen ist alles bis einschliesslich Zusage - dort ist der Einsatz bestaetigt, die Beauftragung steht aber noch aus. migrateOpportunityStages() stellt bestehende Datenbanken um und setzt alle vorhandenen Opportunities auf "Neu": in welcher der neuen Phasen ein Projekt steckt, sagt der alte Trichter nicht (so mit dem Nutzer entschieden). Der Datenbankwert heisst 'Erstgespraech Berater' ohne Umlaut - Projektkonvention fuer Datenbankwerte. Angezeigt wird er ueber STAGE_LABELS; dazu gibt es STAGE_HINTS mit der Erlaeuterung je Phase als Titelhinweis an Auswahl, Badge und Spaltenkopf. - Kanban ist die erste Ansicht der Opportunities. Die Pipeline ist die Arbeitsansicht, Kachel und Liste sind zum Nachschauen. - Hinter "Archiv", beiden "Papierkorb"-Punkten und "Unpassend" steht die Anzahl, wie schon bei "Aus Mails". Die Zahlen kommen aus einem eigenen Endpunkt (/api/badges), weil sie alle ins Menue gehoeren und zusammen kommen sollen; Inhalte laedt weiter jede Ansicht selbst. Der Scanner liegt in einer eigenen Datenbank und kann fehlen - sein Zaehler ist dann null und die Leiste zeigt dort einfach keine Zahl. Der Aufruf haengt bewusst hinter den Daten und nicht im Promise.all: faellt er aus, bleibt das Menue ohne Zahlen statt die Ansicht mit einem Fehler. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1ac0e2d2c7
commit
42639c65fa
@@ -9,6 +9,7 @@ import {
|
||||
} from './OpportunityList';
|
||||
import { OpportunityPipeline } from './OpportunityPipeline';
|
||||
import { OpportunityModal } from './OpportunityModal';
|
||||
import { STAGE_LABELS } from './opportunityUi';
|
||||
import { ConfirmDialog } from '../ui/Modal';
|
||||
import { useToast } from '../Toast';
|
||||
import { opportunitiesApi } from '../../lib/api';
|
||||
@@ -100,7 +101,9 @@ export const Opportunities: React.FC<OpportunitiesProps> = ({
|
||||
reload,
|
||||
}) => {
|
||||
const { addToast } = useToast();
|
||||
const [viewMode, setViewMode] = useState<OpportunityViewMode>('grid');
|
||||
// Kanban zuerst: die Pipeline ist die Arbeitsansicht, Kachel und Liste sind
|
||||
// zum Nachschauen.
|
||||
const [viewMode, setViewMode] = useState<OpportunityViewMode>('pipeline');
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [stageFilter, setStageFilter] = useState<OpportunityStage | 'Alle' | 'Offen'>('Alle');
|
||||
const [sortConfig, setSortConfig] = useState<OpportunitySortConfig>({
|
||||
@@ -191,7 +194,7 @@ export const Opportunities: React.FC<OpportunitiesProps> = ({
|
||||
const changeStage = async (opportunity: Opportunity, stage: OpportunityStage) => {
|
||||
try {
|
||||
await opportunitiesApi.update(opportunity.id, { stage });
|
||||
addToast(`"${opportunity.title}" ist jetzt in Phase ${stage}.`, 'success');
|
||||
addToast(`„${opportunity.title}" ist jetzt in Phase ${STAGE_LABELS[stage]}.`, 'success');
|
||||
reload();
|
||||
} catch (err) {
|
||||
addToast(err instanceof Error ? err.message : 'Phase konnte nicht geändert werden.', 'error');
|
||||
@@ -255,7 +258,7 @@ export const Opportunities: React.FC<OpportunitiesProps> = ({
|
||||
<option value="Offen">Nur offene</option>
|
||||
{OPPORTUNITY_STAGES.map((stage) => (
|
||||
<option key={stage} value={stage}>
|
||||
{stage}
|
||||
{STAGE_LABELS[stage]}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
Reference in New Issue
Block a user