Lizenzen: Kunde auf der Detailseite zuweisen, ändern oder Zuordnung lösen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
a322166d01
commit
fdd51b18e2
1 changed files with 12 additions and 2 deletions
|
|
@ -29,13 +29,15 @@ const Dd = ({ label, children }: { label: string; children: ReactNode }) => <div
|
|||
const toLocalInput = (iso: string | null) => (iso ? new Date(new Date(iso).getTime() - new Date().getTimezoneOffset() * 60000).toISOString().slice(0, 10) : '');
|
||||
|
||||
export default function Lizenz() {
|
||||
const { id } = useParams<{ id: string }>(); const { can } = useSession(); const staff = can('licenses.read');
|
||||
const { id } = useParams<{ id: string }>(); const { can } = useSession(); const staff = can('licenses.read'); const w = can('licenses.write');
|
||||
const [custs, setCusts] = useState<{ id: string; name: string; customerNumber: string }[]>([]); const [assignTo, setAssignTo] = useState('');
|
||||
const [d, setD] = useState<Detail | null>(null); const [msg, setMsg] = useState<{ k: 'ok' | 'err' | 'warn'; t: string } | null>(null); const [busy, setBusy] = useState(false);
|
||||
const [confirm, setConfirm] = useState<null | { title: string; text: string; run: () => Promise<unknown> }>(null);
|
||||
const [products, setProducts] = useState<CatalogProduct[] | null>(null);
|
||||
const load = useCallback(() => api<Detail>('GET', `/licenses/${id}`).then(setD).catch((e) => setMsg({ k: 'err', t: errMsg(e) })), [id]);
|
||||
useEffect(() => { void load(); }, [load]);
|
||||
useEffect(() => { if (d?.can.manage && products === null) api<{ products: CatalogProduct[] }>('GET', '/admin/licenses/catalog').then((c) => setProducts(c.products)).catch(() => setProducts([])); }, [d?.can.manage, products]);
|
||||
useEffect(() => { if (w) api<typeof custs>('GET', '/admin/customers').then(setCusts).catch(() => undefined); }, [w]);
|
||||
if (!d) return msg ? <Alert kind={msg.k}>{msg.t}</Alert> : <p className="muted" role="status">Wird geladen …</p>;
|
||||
|
||||
async function act(fn: () => Promise<unknown>, ok: string) {
|
||||
|
|
@ -82,9 +84,17 @@ export default function Lizenz() {
|
|||
|
||||
{d.can.reveal && <div className="card"><h2>Lizenzschlüssel</h2><SecretField resourceId={d.id} /></div>}
|
||||
|
||||
{w && <div className="card"><h2>{d.orgId ? 'Kunde ändern' : 'Kunde zuweisen'}</h2>
|
||||
<div className="row" style={{ gap: 8 }}>
|
||||
<select aria-label="Kunde wählen" value={assignTo} onChange={(e) => setAssignTo(e.target.value)} style={{ minWidth: 260 }}><option value="">Kunde wählen …</option>{custs.filter((c) => c.id !== d.orgId).map((c) => <option key={c.id} value={c.id}>{c.customerNumber} · {c.name}</option>)}</select>
|
||||
<button className="btn primary" disabled={!assignTo || busy} onClick={() => { const c = custs.find((x) => x.id === assignTo); ask(d.orgId ? 'Kunde ändern' : 'Kunde zuweisen', `Die Lizenz wird ${c?.customerNumber} · ${c?.name} zugeordnet. Der Kunde sieht sie danach unter „Meine Lizenzen“ samt Schlüssel.`, async () => { await api('PATCH', `/admin/licenses/${id}/assign`, { orgId: assignTo }); setAssignTo(''); }); }}>Zuweisen</button>
|
||||
{d.orgId && <button className="btn" disabled={busy} onClick={() => ask('Zuordnung lösen', 'Die Lizenz ist danach keinem Kunden mehr zugeordnet und für den bisherigen Kunden nicht mehr sichtbar.', () => api('PATCH', `/admin/licenses/${id}/assign`, { orgId: null }))}>Zuordnung lösen</button>}
|
||||
</div>
|
||||
<p className="small muted" style={{ marginTop: 8 }}>Ändert nur die Zuordnung im Kundencenter, nicht die Lizenz im Lizenzsystem.</p></div>}
|
||||
|
||||
<div className="card"><h2>Details</h2>
|
||||
<dl className="cols" style={{ margin: 0 }}>
|
||||
{staff && <Dd label="Kunde">{d.orgId ? <Link href={`/admin/kunden/${d.orgId}`}>{d.customerNumber} · {d.orgName}</Link> : 'nicht zugewiesen'}</Dd>}
|
||||
{staff && <Dd label="Kunde">{d.orgId ? <Link href={`/admin/kunden/${d.orgId}`}>{d.customerNumber} · {d.orgName}</Link> : <span className="badge warn"><span aria-hidden="true">▲</span>Nicht zugewiesen</span>}</Dd>}
|
||||
<Dd label="Programm">{d.program ?? '–'}</Dd>
|
||||
<Dd label="Produkt">{d.product ?? d.edition ?? '–'}</Dd>
|
||||
<Dd label="Laufzeit">{d.durationType ? DURATION[d.durationType] ?? d.durationType : '–'}</Dd>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue