Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ struct ContactDetailView: View {
}

private var contactTypeBadge: some View {
ContactTypeBadge(role: displayContact.role)
ContactTypeBadge(kind: ContactTypeBadge.Kind(role: displayContact.role, contactType: displayContact.contactType))
}

// MARK: - Actions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,49 @@ import VellumAssistantShared
/// A tag showing a contact's classification (Guardian, Assistant, Human)
/// with a distinguishing icon. Thin wrapper around VTag.
struct ContactTypeBadge: View {
let role: String?
/// Closed set of display variants the badge can render.
enum Kind {
case guardian
case assistant
case human

/// Derives the badge kind from a contact's `role` and `contactType` fields.
/// `role == "guardian"` takes precedence; otherwise `contactType == "assistant"`
/// selects the assistant variant, and anything else falls back to human.
init(role: String?, contactType: String?) {
if role == "guardian" {
self = .guardian
} else if contactType == "assistant" {
self = .assistant
} else {
self = .human
}
}
}

let kind: Kind

init(kind: Kind) {
self.kind = kind
}

var body: some View {
VTag(label, color: VColor.primaryBase, icon: icon)
}

private var label: String {
switch role {
case "guardian": return "Guardian"
case "assistant": return "Assistant"
default: return "Human"
switch kind {
case .guardian: return "Guardian"
case .assistant: return "Assistant"
case .human: return "Human"
}
}

private var icon: VIcon {
switch role {
case "guardian": return .shieldCheck
case "assistant": return .sparkles
default: return .user
switch kind {
case .guardian: return .shieldCheck
case .assistant: return .sparkles
case .human: return .user
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ struct ContactsContainerView: View {
Text(contact.displayName.hasPrefix("vellum-principal-") ? "You" : "\(contact.displayName) (You)")
.font(VFont.titleSmall)
.foregroundStyle(VColor.contentDefault)
ContactTypeBadge(role: "guardian")
ContactTypeBadge(kind: .guardian)
}
Text("\(contact.interactionCount) interaction\(contact.interactionCount == 1 ? "" : "s")")
.font(VFont.labelDefault)
Expand Down Expand Up @@ -312,7 +312,7 @@ struct ContactsContainerView: View {
Text("\(cachedAssistantName) (Your Assistant)")
.font(VFont.titleSmall)
.foregroundStyle(VColor.contentDefault)
ContactTypeBadge(role: "assistant")
ContactTypeBadge(kind: .assistant)
}
.padding(.horizontal, VSpacing.lg)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct ContactsListView: View {
VStack(alignment: .leading, spacing: VSpacing.sm) {
contactListRow(
name: "Your Assistant",
role: "assistant",
badgeKind: .assistant,
isSelected: selection == .assistant,
isHovered: isAssistantHovered,
onTap: { selection = .assistant },
Expand All @@ -54,7 +54,7 @@ struct ContactsListView: View {
if let guardian = viewModel.guardianContact {
contactListRow(
name: "You",
role: guardian.role,
badgeKind: ContactTypeBadge.Kind(role: guardian.role, contactType: guardian.contactType),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use a valid initializer for ContactTypeBadge.Kind

ContactTypeBadge.Kind is an enum with only cases, but this call constructs it with Kind(role:contactType:); that initializer is defined on ContactTypeBadge, not on Kind. This introduces a compile-time error in the macOS client (and the same pattern appears again in this file at line 86), so the contacts feature cannot be built from this commit.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in 9523949. The init(role:contactType:) now lives on ContactTypeBadge.Kind (where the mapping actually belongs), so ContactTypeBadge.Kind(role:contactType:) resolves, and the call site in ContactDetailView was updated to ContactTypeBadge(kind: .init(role:contactType:)). Resolved.

isSelected: selection == .contact(guardian.id),
isHovered: hoveredContactId == guardian.id,
onTap: { selection = .contact(guardian.id) },
Expand Down Expand Up @@ -83,7 +83,7 @@ struct ContactsListView: View {
ForEach(viewModel.filteredRegularContacts, id: \.id) { contact in
contactListRow(
name: contact.displayName,
role: contact.role,
badgeKind: ContactTypeBadge.Kind(role: contact.role, contactType: contact.contactType),
isSelected: selection == .contact(contact.id),
isHovered: hoveredContactId == contact.id,
onTap: { selection = .contact(contact.id) },
Expand Down Expand Up @@ -151,7 +151,7 @@ struct ContactsListView: View {

private func contactListRow(
name: String,
role: String?,
badgeKind: ContactTypeBadge.Kind,
isSelected: Bool,
isHovered: Bool,
onTap: @escaping () -> Void,
Expand All @@ -166,7 +166,7 @@ struct ContactsListView: View {

Spacer()

ContactTypeBadge(role: role)
ContactTypeBadge(kind: badgeKind)
}
.padding(.horizontal, VSpacing.sm)
.padding(.vertical, VSpacing.md)
Expand Down