import SwiftUI /// Customer rating dialog shown when completing a service point task. /// Matches Android RatingDialog: 4 yes/no questions about the customer. struct RatingDialog: View { let onSubmit: ([String: Bool]) -> Void let onDismiss: () -> Void let isSubmitting: Bool @State private var prepared: Bool? @State private var completedScope: Bool? @State private var respectful: Bool? @State private var wouldAutoAssign: Bool? private var allAnswered: Bool { prepared != nil && completedScope != nil && respectful != nil && wouldAutoAssign != nil } var body: some View { VStack(spacing: 20) { // Star icon Image(systemName: "star.fill") .font(.system(size: 48)) .foregroundColor(Color(red: 1.0, green: 0.76, blue: 0.03)) // Golden yellow Text("Rate this customer") .font(.title2.bold()) Text("Quick feedback helps improve the experience.") .font(.subheadline) .foregroundColor(.secondary) .multilineTextAlignment(.center) VStack(spacing: 16) { RatingQuestion(question: "Was the customer prepared?", value: $prepared) RatingQuestion(question: "Was the scope clear?", value: $completedScope) RatingQuestion(question: "Was the customer respectful?", value: $respectful) RatingQuestion(question: "Would you serve them again?", value: $wouldAutoAssign) } HStack(spacing: 12) { if !isSubmitting { Button("Cancel") { onDismiss() } .buttonStyle(.bordered) .foregroundColor(.secondary) } Button { guard let p = prepared, let c = completedScope, let r = respectful, let w = wouldAutoAssign else { return } onSubmit([ "prepared": p, "completedScope": c, "respectful": r, "wouldAutoAssign": w ]) } label: { if isSubmitting { ProgressView() .progressViewStyle(CircularProgressViewStyle(tint: .white)) .frame(maxWidth: .infinity, minHeight: 44) } else { Text("Submit & Complete") .font(.headline) .frame(maxWidth: .infinity, minHeight: 44) } } .buttonStyle(.borderedProminent) .tint(.payfritGreen) .disabled(!allAnswered || isSubmitting) } } .padding(24) .background(Color(.systemBackground)) .cornerRadius(20) .shadow(radius: 20) .padding(.horizontal, 24) } } /// A single yes/no rating question with thumb up/down toggle chips. private struct RatingQuestion: View { let question: String @Binding var value: Bool? var body: some View { VStack(alignment: .leading, spacing: 6) { Text(question) .font(.subheadline.weight(.medium)) HStack(spacing: 8) { ToggleChip( label: "Yes", icon: "hand.thumbsup.fill", isSelected: value == true, selectedColor: .green ) { value = true } ToggleChip( label: "No", icon: "hand.thumbsdown.fill", isSelected: value == false, selectedColor: .red ) { value = false } } } .frame(maxWidth: .infinity, alignment: .leading) } } /// A selectable chip with icon, similar to Android FilterChip. private struct ToggleChip: View { let label: String let icon: String let isSelected: Bool let selectedColor: Color let action: () -> Void var body: some View { Button(action: action) { HStack(spacing: 4) { if isSelected { Image(systemName: icon) .font(.caption) .foregroundColor(selectedColor) } Text(label) .font(.subheadline) .foregroundColor(isSelected ? selectedColor : .primary) } .padding(.horizontal, 14) .padding(.vertical, 8) .background( isSelected ? selectedColor.opacity(0.15) : Color(.systemGray5) ) .cornerRadius(20) .overlay( RoundedRectangle(cornerRadius: 20) .stroke(isSelected ? selectedColor.opacity(0.4) : Color.clear, lineWidth: 1) ) } .buttonStyle(.plain) } } #Preview { ZStack { Color.black.opacity(0.4).ignoresSafeArea() RatingDialog( onSubmit: { rating in print(rating) }, onDismiss: { print("dismissed") }, isSubmitting: false ) } }