import { Component, inject, signal, OnInit } from '@angular/core';
import { ActivatedRoute, RouterLink } from '@angular/router';
import { ApiService } from '../../core/services/api.service';
import { ToastService } from '../../core/services/toast.service';
import { IDomainDetail, IService } from '../../core/types/api.types';
import {
CardComponent,
CardHeaderComponent,
CardTitleComponent,
CardDescriptionComponent,
CardContentComponent,
} from '../../ui/card/card.component';
import { ButtonComponent } from '../../ui/button/button.component';
import { BadgeComponent } from '../../ui/badge/badge.component';
import {
TableComponent,
TableHeaderComponent,
TableBodyComponent,
TableRowComponent,
TableHeadComponent,
TableCellComponent,
} from '../../ui/table/table.component';
import { SkeletonComponent } from '../../ui/skeleton/skeleton.component';
@Component({
selector: 'app-domain-detail',
standalone: true,
imports: [
RouterLink,
CardComponent,
CardHeaderComponent,
CardTitleComponent,
CardDescriptionComponent,
CardContentComponent,
ButtonComponent,
BadgeComponent,
TableComponent,
TableHeaderComponent,
TableBodyComponent,
TableRowComponent,
TableHeadComponent,
TableCellComponent,
SkeletonComponent,
],
template: `
Back to Domains
@if (loading() && !domain()) {
} @else if (domain()) {
{{ domain()!.domain.domain }}
{{ domain()!.domain.dnsProvider || 'Manual' }}
@if (domain()!.domain.defaultWildcard) {
Wildcard
}
@if (domain()!.domain.isObsolete) {
Obsolete
}
}
@if (domain()) {
Certificates
{{ domain()!.certificates.length }}
Requirements
{{ domain()!.requirements.length }}
Services
{{ domain()!.serviceCount }}
SSL Certificates
Active certificates for this domain
@if (domain()!.certificates.length === 0) {
No certificates
} @else {
Domain
Type
Status
Expires
Issuer
Actions
@for (cert of domain()!.certificates; track cert.id) {
{{ cert.certDomain }}
{{ cert.isWildcard ? 'Wildcard' : 'Standard' }}
{{ getCertStatus(cert) }}
{{ formatDate(cert.expiryDate) }}
({{ getDaysRemaining(cert.expiryDate) }} days)
{{ cert.issuer }}
}
}
Services
Services using this domain
@if (services().length === 0) {
No services using this domain
} @else {
Service
Domain
Status
Actions
@for (svc of services(); track svc.name) {
{{ svc.name }}
{{ svc.domain }}
{{ svc.status }}
}
}
}
`,
})
export class DomainDetailComponent implements OnInit {
private route = inject(ActivatedRoute);
private api = inject(ApiService);
private toast = inject(ToastService);
domain = signal(null);
services = signal([]);
loading = signal(false);
ngOnInit(): void {
const domainName = this.route.snapshot.paramMap.get('domain');
if (domainName) {
this.loadDomain(domainName);
this.loadServices(domainName);
}
}
async loadDomain(name: string): Promise {
this.loading.set(true);
try {
const response = await this.api.getDomainDetail(name);
if (response.success && response.data) {
this.domain.set(response.data);
}
} catch {
this.toast.error('Failed to load domain');
} finally {
this.loading.set(false);
}
}
async loadServices(domainName: string): Promise {
try {
const response = await this.api.getServices();
if (response.success && response.data) {
this.services.set(response.data.filter(s => s.domain?.includes(domainName)));
}
} catch {
// Silent fail
}
}
formatDate(timestamp: number): string {
return new Date(timestamp).toLocaleDateString();
}
getDaysRemaining(timestamp: number): number {
const now = Date.now();
return Math.floor((timestamp - now) / (1000 * 60 * 60 * 24));
}
getCertStatus(cert: any): string {
if (!cert.isValid) return 'Invalid';
const days = this.getDaysRemaining(cert.expiryDate);
if (days < 0) return 'Expired';
if (days <= 30) return 'Expiring';
return 'Valid';
}
getCertStatusVariant(cert: any): 'success' | 'warning' | 'destructive' {
const status = this.getCertStatus(cert);
switch (status) {
case 'Valid': return 'success';
case 'Expiring': return 'warning';
default: return 'destructive';
}
}
async renewCertificate(domain: string): Promise {
try {
const response = await this.api.renewCertificate(domain);
if (response.success) {
this.toast.success('Certificate renewal initiated');
} else {
this.toast.error(response.error || 'Failed to renew certificate');
}
} catch {
this.toast.error('Failed to renew certificate');
}
}
}