summaryrefslogtreecommitdiff
path: root/Rune/Views/Domains/DomainDetailView.swift
blob: dbb90a1c12ac62f3a587e1caee34f0cf1476812f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import SwiftUI

struct DomainDetailView: View {
    let domainName: String
    @ObservedObject var viewModel: DomainViewModel
    let client: NjallaClient

    var body: some View {
        Group {
            if viewModel.isLoadingDetail && viewModel.selectedDomain?.name != domainName {
                ProgressView()
            } else if let domain = currentDomain {
                List {
                    Section("Status") {
                        DetailRow(label: "Name", value: domain.name)
                        DetailRow(label: "Status", value: textValue(domain.status))
                        DetailRow(label: "Expiry", value: domain.expiry?.formattedExpiry() ?? "Not available")
                        DetailRow(label: "Autorenew", value: boolText(domain.autorenew))
                    }

                    Section("Settings") {
                        DetailRow(label: "Mail Forwarding", value: boolText(domain.mailforwarding))
                        DetailRow(label: "DNSSEC", value: boolText(domain.dnssec))
                        DetailRow(label: "Registrar Lock", value: boolText(domain.lock))
                        DetailRow(label: "Nameservers", value: nameserverText(domain.nameservers))
                    }

                    Section("DNS") {
                        NavigationLink("Records") {
                            RecordListView(domainName: domain.name, viewModel: viewModel, client: client)
                        }
                    }
                }
                .listStyle(.insetGrouped)
                .toolbar {
                    NavigationLink("Edit") {
                        DomainEditView(domain: domain, viewModel: viewModel, client: client)
                    }
                }
            } else {
                ContentUnavailableView("Domain Unavailable", systemImage: "globe", description: Text("The domain details could not be loaded."))
            }
        }
        .navigationTitle(domainName)
        .navigationBarTitleDisplayMode(.inline)
        .task {
            await viewModel.loadDomainDetail(named: domainName, client: client)
        }
        .alert("API Error", isPresented: errorBinding) {
            Button("OK", role: .cancel) {}
        } message: {
            Text(viewModel.errorMessage ?? "")
        }
    }

    private var currentDomain: Domain? {
        if viewModel.selectedDomain?.name == domainName {
            return viewModel.selectedDomain
        }

        return viewModel.domains.first(where: { $0.name == domainName })
    }

    private func boolText(_ value: Bool?) -> String {
        guard let value else { return "Not available" }
        return value ? "On" : "Off"
    }

    private func nameserverText(_ nameservers: [String]?) -> String {
        guard let nameservers else {
            return "Not available"
        }

        guard !nameservers.isEmpty else {
            return "Default"
        }

        return nameservers.joined(separator: ", ")
    }

    private func textValue(_ value: String?) -> String {
        guard let value, !value.isEmpty else {
            return "Not available"
        }

        return value
    }

    private var errorBinding: Binding<Bool> {
        Binding(
            get: { viewModel.errorMessage != nil },
            set: { newValue in
                if !newValue {
                    viewModel.errorMessage = nil
                }
            }
        )
    }
}

private struct DetailRow: View {
    let label: String
    let value: String

    var body: some View {
        HStack {
            Text(label)
            Spacer()
            Text(value)
                .foregroundStyle(.secondary)
                .multilineTextAlignment(.trailing)
        }
    }
}