Vertrags-Forms: Mini-Links zu Stammdaten in neuem Tab
ContractEmailsSection (Vertragsansicht): Zusätzlich zu "Postfach öffnen" gibt es jetzt "Stressfrei wechseln Adressen" → Tab in der Kundenakte. ContractForm (Bearbeiten): Kleine ExternalLink-Icons neben den Select-Labels: - Lieferadresse + Rechnungsadresse → Kundenakte/Adressen - Bankkarte → Kundenakte/Bankkarten - Ausweis → Kundenakte/Ausweise - Anbieter + Tarif → Settings/Anbieter & Tarife - Vertriebsplattform → Settings/Vertriebsplattformen Select-Komponente nimmt jetzt ReactNode als label (statt nur string), um JSX-Labels mit eingebettetem Link zu erlauben. Rückwärts- kompatibel zu allen bestehenden String-Aufrufen. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -298,6 +298,16 @@ export default function ContractEmailsSection({
|
|||||||
<ExternalLink className="w-3 h-3" />
|
<ExternalLink className="w-3 h-3" />
|
||||||
Postfach öffnen
|
Postfach öffnen
|
||||||
</Link>
|
</Link>
|
||||||
|
<Link
|
||||||
|
to={`/customers/${customerId}?tab=stressfrei`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="inline-flex items-center gap-1 text-xs text-blue-600 hover:text-blue-800 hover:underline font-normal"
|
||||||
|
title="Stressfrei-Wechseln-Adressen des Kunden in neuem Tab öffnen"
|
||||||
|
>
|
||||||
|
<ExternalLink className="w-3 h-3" />
|
||||||
|
Stressfrei wechseln Adressen
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
actions={
|
actions={
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { SelectHTMLAttributes, forwardRef } from 'react';
|
import { SelectHTMLAttributes, forwardRef, ReactNode } from 'react';
|
||||||
|
|
||||||
interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
|
interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
|
||||||
label?: string;
|
label?: ReactNode;
|
||||||
error?: string;
|
error?: string;
|
||||||
options: { value: string | number; label: string }[];
|
options: { value: string | number; label: string }[];
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { useNavigate, useParams, useSearchParams, useLocation } from 'react-router-dom';
|
import { useNavigate, useParams, useSearchParams, useLocation, Link } from 'react-router-dom';
|
||||||
import { popHistory } from '../../utils/navigation';
|
import { popHistory } from '../../utils/navigation';
|
||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
@@ -12,7 +12,29 @@ import Select from '../../components/ui/Select';
|
|||||||
import type { ContractType } from '../../types';
|
import type { ContractType } from '../../types';
|
||||||
import { formatDate } from '../../utils/dateFormat';
|
import { formatDate } from '../../utils/dateFormat';
|
||||||
import { useProviderSettings } from '../../hooks/useProviderSettings';
|
import { useProviderSettings } from '../../hooks/useProviderSettings';
|
||||||
import { Plus, Trash2, Eye, EyeOff, Info, X, ArrowLeft } from 'lucide-react';
|
import { Plus, Trash2, Eye, EyeOff, Info, X, ArrowLeft, ExternalLink } from 'lucide-react';
|
||||||
|
|
||||||
|
// Kleine Helper-Komponente: Label + Mini-Link im neuen Tab. Wird neben
|
||||||
|
// Select-Feldern eingesetzt, deren Stammdaten an anderer Stelle gepflegt
|
||||||
|
// werden (Kundenakte, Settings) – damit der User direkt von dort in die
|
||||||
|
// passende Verwaltungsseite springen kann.
|
||||||
|
function LabelWithLink({ children, to, title }: { children: React.ReactNode; to: string; title: string }) {
|
||||||
|
return (
|
||||||
|
<span className="inline-flex items-center gap-2">
|
||||||
|
<span>{children}</span>
|
||||||
|
<Link
|
||||||
|
to={to}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="inline-flex items-center text-blue-600 hover:text-blue-800"
|
||||||
|
title={title}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<ExternalLink className="w-3 h-3" />
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
import { calculateConsumption, calculateMultiMeterConsumption } from '../../utils/energyCalculations';
|
import { calculateConsumption, calculateMultiMeterConsumption } from '../../utils/energyCalculations';
|
||||||
|
|
||||||
// Contract types are now loaded dynamically from the database
|
// Contract types are now loaded dynamically from the database
|
||||||
@@ -752,7 +774,11 @@ export default function ContractForm() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
label="Vertriebsplattform"
|
label={
|
||||||
|
<LabelWithLink to="/settings/platforms" title="Vertriebsplattformen verwalten (neuer Tab)">
|
||||||
|
Vertriebsplattform
|
||||||
|
</LabelWithLink>
|
||||||
|
}
|
||||||
{...register('salesPlatformId')}
|
{...register('salesPlatformId')}
|
||||||
options={platforms.map((p) => ({ value: p.id, label: p.name }))}
|
options={platforms.map((p) => ({ value: p.id, label: p.name }))}
|
||||||
/>
|
/>
|
||||||
@@ -799,7 +825,11 @@ export default function ContractForm() {
|
|||||||
<Card className="mb-6" title="Kundendaten verknüpfen">
|
<Card className="mb-6" title="Kundendaten verknüpfen">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||||
<Select
|
<Select
|
||||||
label="Lieferadresse"
|
label={
|
||||||
|
<LabelWithLink to={`/customers/${customerId}?tab=addresses`} title="Adressen des Kunden in neuem Tab öffnen">
|
||||||
|
Lieferadresse
|
||||||
|
</LabelWithLink>
|
||||||
|
}
|
||||||
{...register('addressId')}
|
{...register('addressId')}
|
||||||
options={addresses
|
options={addresses
|
||||||
.filter((a) => a.type === 'DELIVERY_RESIDENCE')
|
.filter((a) => a.type === 'DELIVERY_RESIDENCE')
|
||||||
@@ -810,7 +840,11 @@ export default function ContractForm() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
label="Rechnungsadresse"
|
label={
|
||||||
|
<LabelWithLink to={`/customers/${customerId}?tab=addresses`} title="Adressen des Kunden in neuem Tab öffnen">
|
||||||
|
Rechnungsadresse
|
||||||
|
</LabelWithLink>
|
||||||
|
}
|
||||||
{...register('billingAddressId')}
|
{...register('billingAddressId')}
|
||||||
options={addresses
|
options={addresses
|
||||||
.filter((a) => a.type === 'BILLING')
|
.filter((a) => a.type === 'BILLING')
|
||||||
@@ -823,7 +857,11 @@ export default function ContractForm() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<Select
|
<Select
|
||||||
label="Bankkarte"
|
label={
|
||||||
|
<LabelWithLink to={`/customers/${customerId}?tab=bankcards`} title="Bankkarten des Kunden in neuem Tab öffnen">
|
||||||
|
Bankkarte
|
||||||
|
</LabelWithLink>
|
||||||
|
}
|
||||||
{...register('bankCardId')}
|
{...register('bankCardId')}
|
||||||
options={bankCards.map((c) => ({
|
options={bankCards.map((c) => ({
|
||||||
value: c.id,
|
value: c.id,
|
||||||
@@ -832,7 +870,11 @@ export default function ContractForm() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
label="Ausweis"
|
label={
|
||||||
|
<LabelWithLink to={`/customers/${customerId}?tab=documents`} title="Ausweise des Kunden in neuem Tab öffnen">
|
||||||
|
Ausweis
|
||||||
|
</LabelWithLink>
|
||||||
|
}
|
||||||
{...register('identityDocumentId')}
|
{...register('identityDocumentId')}
|
||||||
options={documents.map((d) => ({
|
options={documents.map((d) => ({
|
||||||
value: d.id,
|
value: d.id,
|
||||||
@@ -846,12 +888,20 @@ export default function ContractForm() {
|
|||||||
<Card className="mb-6" title="Anbieter & Tarif">
|
<Card className="mb-6" title="Anbieter & Tarif">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<Select
|
<Select
|
||||||
label="Anbieter"
|
label={
|
||||||
|
<LabelWithLink to="/settings/providers" title="Anbieter & Tarife verwalten (neuer Tab)">
|
||||||
|
Anbieter
|
||||||
|
</LabelWithLink>
|
||||||
|
}
|
||||||
{...register('providerId')}
|
{...register('providerId')}
|
||||||
options={providers.map((p) => ({ value: p.id, label: p.name }))}
|
options={providers.map((p) => ({ value: p.id, label: p.name }))}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
label="Tarif"
|
label={
|
||||||
|
<LabelWithLink to="/settings/providers" title="Anbieter & Tarife verwalten (neuer Tab)">
|
||||||
|
Tarif
|
||||||
|
</LabelWithLink>
|
||||||
|
}
|
||||||
{...register('tariffId')}
|
{...register('tariffId')}
|
||||||
options={availableTariffs.map((t) => ({ value: t.id, label: t.name }))}
|
options={availableTariffs.map((t) => ({ value: t.id, label: t.name }))}
|
||||||
disabled={!selectedProviderId}
|
disabled={!selectedProviderId}
|
||||||
|
|||||||
Reference in New Issue
Block a user