fix: instance detail crash — use safe accessors for events/license (null check)
Root cause: useFetch returns the full API response { instance: {...} } but
the code assigned it directly: const instance = data
This meant instance.events and instance.license were undefined (data.events
doesn't exist, data.instance.events does).
Fix:
- const events = instance?.events ?? []
- const license = instance?.license ?? null
- Replaced all instance.events → events
- Replaced all instance.license → license
- format.ts already had null-safe date functions
This commit is contained in:
1 parent
52effad4a5
commit
76f3d93873
1 file changed
+15
-11
@@ -631,6 +631,10 @@ function InstanceDetailSheet({
|
|||||||
const status = instance?.status ?? ''
|
const status = instance?.status ?? ''
|
||||||
const fullDomain = instance ? `${instance.subdomain}.dfmpanel.eu` : ''
|
const fullDomain = instance ? `${instance.subdomain}.dfmpanel.eu` : ''
|
||||||
|
|
||||||
|
// Safe accessors — events and license may be undefined during loading
|
||||||
|
const events = instance?.events ?? []
|
||||||
|
const license = instance?.license ?? null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sheet open={open} onOpenChange={onOpenChange}>
|
<Sheet open={open} onOpenChange={onOpenChange}>
|
||||||
<SheetContent
|
<SheetContent
|
||||||
@@ -735,7 +739,7 @@ function InstanceDetailSheet({
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* License info */}
|
{/* License info */}
|
||||||
{instance.license && (
|
{license && (
|
||||||
<section className="space-y-2">
|
<section className="space-y-2">
|
||||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Lizenz
|
Lizenz
|
||||||
@@ -745,20 +749,20 @@ function InstanceDetailSheet({
|
|||||||
label="Key"
|
label="Key"
|
||||||
value={
|
value={
|
||||||
<code className="text-xs">
|
<code className="text-xs">
|
||||||
{maskLicenseKey(instance.license.key)}
|
{maskLicenseKey(license.key)}
|
||||||
</code>
|
</code>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<DetailRow label="Produkt" value={instance.license.product} />
|
<DetailRow label="Produkt" value={license.product} />
|
||||||
<DetailRow
|
<DetailRow
|
||||||
label="Abrechnung"
|
label="Abrechnung"
|
||||||
value={
|
value={
|
||||||
instance.license.billingCycle === 'yearly' ? 'Jährlich' : 'Monatlich'
|
license.billingCycle === 'yearly' ? 'Jährlich' : 'Monatlich'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<DetailRow
|
<DetailRow
|
||||||
label="Nettopreis"
|
label="Nettopreis"
|
||||||
value={`${(instance.license.netPriceCents / 100).toLocaleString('de-DE', {
|
value={`${(license.netPriceCents / 100).toLocaleString('de-DE', {
|
||||||
minimumFractionDigits: 2,
|
minimumFractionDigits: 2,
|
||||||
maximumFractionDigits: 2,
|
maximumFractionDigits: 2,
|
||||||
})} €`}
|
})} €`}
|
||||||
@@ -767,15 +771,15 @@ function InstanceDetailSheet({
|
|||||||
label="Lizenzstatus"
|
label="Lizenzstatus"
|
||||||
value={
|
value={
|
||||||
<Badge variant="outline" className="border-foreground/20">
|
<Badge variant="outline" className="border-foreground/20">
|
||||||
{instance.license.status}
|
{license.status}
|
||||||
</Badge>
|
</Badge>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<DetailRow
|
<DetailRow
|
||||||
label="Gekündigt"
|
label="Gekündigt"
|
||||||
value={
|
value={
|
||||||
instance.license.cancelledAt
|
license.cancelledAt
|
||||||
? formatDate(instance.license.cancelledAt)
|
? formatDate(license.cancelledAt)
|
||||||
: '—'
|
: '—'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -819,7 +823,7 @@ function InstanceDetailSheet({
|
|||||||
</h3>
|
</h3>
|
||||||
<div className="rounded-md border border-border bg-muted/20 p-3 text-xs">
|
<div className="rounded-md border border-border bg-muted/20 p-3 text-xs">
|
||||||
{(() => {
|
{(() => {
|
||||||
const graphEvents = instance.events.filter(
|
const graphEvents = events.filter(
|
||||||
(e) => e.type.startsWith('graphify.')
|
(e) => e.type.startsWith('graphify.')
|
||||||
)
|
)
|
||||||
const buildQueued = graphEvents.some(
|
const buildQueued = graphEvents.some(
|
||||||
@@ -874,11 +878,11 @@ function InstanceDetailSheet({
|
|||||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
Ereignisverlauf
|
Ereignisverlauf
|
||||||
</h3>
|
</h3>
|
||||||
{instance.events.length === 0 ? (
|
{events.length === 0 ? (
|
||||||
<p className="text-xs text-muted-foreground">Keine Ereignisse protokolliert.</p>
|
<p className="text-xs text-muted-foreground">Keine Ereignisse protokolliert.</p>
|
||||||
) : (
|
) : (
|
||||||
<ol className="space-y-2">
|
<ol className="space-y-2">
|
||||||
{instance.events.map((ev) => (
|
{events.map((ev) => (
|
||||||
<EventRow key={ev.id} event={ev} />
|
<EventRow key={ev.id} event={ev} />
|
||||||
))}
|
))}
|
||||||
</ol>
|
</ol>
|
||||||
|
|||||||
Reference in new issue
Block a user