Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>

This commit is contained in:
Matt Bruce 2026-01-09 11:44:07 -06:00
parent 1080590fde
commit 4145f73bc9
2 changed files with 139 additions and 6 deletions

View File

@ -81,6 +81,9 @@
}
}
}
},
"Add Contact Fields" : {
},
"Add note" : {
@ -176,9 +179,6 @@
},
"Contact" : {
},
"Contact Fields" : {
},
"Country" : {
@ -249,6 +249,9 @@
},
"Developer" : {
},
"Drag to reorder. Swipe to delete." : {
},
"e.g. MBA, CPA, PhD" : {
@ -733,6 +736,9 @@
},
"Write down a memorable reminder about your contact" : {
},
"Your Contact Fields" : {
},
"ZIP Code" : {

View File

@ -50,6 +50,10 @@ struct CardEditorView: View {
// Photo editor state - just one variable!
@State private var editingImageType: ImageType?
// Contact field editor state
@State private var selectedFieldTypeForAdd: ContactFieldType?
@State private var fieldToEdit: AddedContactField?
@State private var showingPreview = false
enum ImageType: String, Identifiable {
@ -196,11 +200,34 @@ struct CardEditorView: View {
Text("Card Label")
}
// Contact & social fields manager
// Current contact fields (reorderable list)
if !contactFields.isEmpty {
Section {
ForEach(contactFields) { field in
ContactFieldRowView(field: field) {
fieldToEdit = field
}
}
.onMove { from, to in
contactFields.move(fromOffsets: from, toOffset: to)
}
.onDelete { indexSet in
contactFields.remove(atOffsets: indexSet)
}
} header: {
Text("Your Contact Fields")
} footer: {
Text("Drag to reorder. Swipe to delete.")
}
}
// Add new contact fields
Section {
ContactFieldsManagerView(fields: $contactFields)
ContactFieldPickerView { fieldType in
selectedFieldTypeForAdd = fieldType
}
} header: {
Text("Contact Fields")
Text("Add Contact Fields")
}
// Bio section
@ -244,6 +271,29 @@ struct CardEditorView: View {
editingImageType = nil
}
}
.sheet(item: $selectedFieldTypeForAdd) { fieldType in
ContactFieldEditorSheet(
fieldType: fieldType,
initialValue: "",
initialTitle: fieldType.titleSuggestions.first ?? "",
onSave: { value, title in
addContactField(fieldType: fieldType, value: value, title: title)
}
)
}
.sheet(item: $fieldToEdit) { field in
ContactFieldEditorSheet(
fieldType: field.fieldType,
initialValue: field.value,
initialTitle: field.title,
onSave: { value, title in
updateContactField(id: field.id, value: value, title: title)
},
onDelete: {
deleteContactField(id: field.id)
}
)
}
.onAppear { loadCardData() }
.sheet(isPresented: $showingPreview) {
CardPreviewSheet(card: buildPreviewCard())
@ -524,6 +574,54 @@ private struct ProfilePhotoView: View {
}
}
// MARK: - Contact Field Row View
private struct ContactFieldRowView: View {
let field: AddedContactField
let onTap: () -> Void
var body: some View {
Button(action: onTap) {
HStack(spacing: Design.Spacing.medium) {
// Drag handle
Image(systemName: "line.3.horizontal")
.font(.subheadline)
.foregroundStyle(Color.Text.tertiary)
.accessibilityHidden(true)
// Icon
Circle()
.fill(field.fieldType.iconColor)
.frame(width: Design.CardSize.avatarSize, height: Design.CardSize.avatarSize)
.overlay(
field.fieldType.iconImage()
.font(.title3)
.foregroundStyle(.white)
)
// Content
VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) {
Text(field.value.isEmpty ? field.fieldType.valuePlaceholder : field.shortDisplayValue)
.font(.subheadline)
.foregroundStyle(field.value.isEmpty ? Color.Text.secondary : Color.Text.primary)
.lineLimit(1)
Text(field.title.isEmpty ? field.fieldType.displayName : field.title)
.font(.caption)
.foregroundStyle(Color.Text.secondary)
.lineLimit(1)
}
Spacer()
}
.contentShape(.rect)
}
.buttonStyle(.plain)
.accessibilityLabel("\(field.fieldType.displayName): \(field.shortDisplayValue)")
.accessibilityHint(String.localized("Tap to edit, drag to reorder"))
}
}
// MARK: - Accreditations Row
private struct AccreditationsRow: View {
@ -828,6 +926,35 @@ private extension CardEditorView {
return previewCard
}
// MARK: - Contact Field Operations
func addContactField(fieldType: ContactFieldType, value: String, title: String) {
guard !value.isEmpty else { return }
withAnimation {
let newField = AddedContactField(
fieldType: fieldType,
value: value,
title: title
)
contactFields.append(newField)
}
}
func updateContactField(id: UUID, value: String, title: String) {
if let index = contactFields.firstIndex(where: { $0.id == id }) {
withAnimation {
contactFields[index].value = value
contactFields[index].title = title
}
}
}
func deleteContactField(id: UUID) {
withAnimation {
contactFields.removeAll { $0.id == id }
}
}
// MARK: - Contact Fields Sync
/// Saves the contactFields array to the BusinessCard model