Skip to content

Commit 9dfa610

Browse files
[Bookings][Part 4] Booking details screen (#16192)
2 parents 4b382e3 + 198f3e5 commit 9dfa610

File tree

3 files changed

+189
-3
lines changed

3 files changed

+189
-3
lines changed

WooCommerce/Classes/ViewRelated/Bookings/Booking Details/BookingDetailsView.swift

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import Networking
44
struct BookingDetailsView: View {
55
@Environment(\.safeAreaInsets) var safeAreaInsets: EdgeInsets
66
@Environment(\.dismiss) private var dismiss
7+
@State private var showingOptions = false
8+
@State private var showingStatusSheet = false
79

810
@ObservedObject private var viewModel: BookingDetailsViewModel
911

@@ -51,13 +53,31 @@ struct BookingDetailsView: View {
5153
}
5254
ToolbarItem(placement: .navigationBarTrailing) {
5355
Button {
54-
//TODO: - present an action sheet
55-
print("On ellipsis item tap")
56+
showingOptions = true
5657
} label: {
5758
Image(systemName: "ellipsis")
5859
}
60+
.confirmationDialog("", isPresented: $showingOptions, titleVisibility: .hidden) {
61+
Button(Localization.markAsPaid) {
62+
print("On mark as paid tap")
63+
}
64+
Button(Localization.viewOrder) {
65+
print("On view order tap")
66+
}
67+
Button(Localization.cancelBookingAction, role: .destructive) {
68+
print("On cancel booking tap")
69+
}
70+
}
5971
}
6072
}
73+
.sheet(isPresented: $showingStatusSheet) {
74+
UpdateAttendanceStatusView { selectedStatus in
75+
print("Selected status: \(selectedStatus)")
76+
}
77+
.padding(.top)
78+
.presentationDetents([.medium, .large])
79+
.presentationDragIndicator(.visible)
80+
}
6181
}
6282
}
6383

@@ -145,7 +165,9 @@ private extension BookingDetailsView {
145165
value: .placeholder(content.value),
146166
selectionStyle: .disclosure,
147167
horizontalPadding: 0
148-
)
168+
) {
169+
showingStatusSheet = true
170+
}
149171
}
150172

151173
func appointmentDetailsView(with content: BookingDetailsViewModel.AppointmentDetailsContent) -> some View {
@@ -312,6 +334,22 @@ private extension View {
312334

313335
private extension BookingDetailsView {
314336
enum Localization {
337+
static let markAsPaid = NSLocalizedString(
338+
"BookingDetailsView.options.markAsPaid",
339+
value: "Mark as paid",
340+
comment: "Action sheet option to mark a booking as paid."
341+
)
342+
static let viewOrder = NSLocalizedString(
343+
"BookingDetailsView.options.viewOrder",
344+
value: "View order",
345+
comment: "Action sheet option to view the order for a booking."
346+
)
347+
static let cancelBookingAction = NSLocalizedString(
348+
"BookingDetailsView.options.cancelBooking",
349+
value: "Cancel booking",
350+
comment: "Action sheet option to cancel a booking."
351+
)
352+
315353
static let cancelBooking = NSLocalizedString(
316354
"BookingDetailsView.customer.cancelBookingButton.title",
317355
value: "Cancel booking",
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import SwiftUI
2+
3+
struct UpdateAttendanceStatusView: View {
4+
@Environment(\.dismiss) private var dismiss
5+
private let statuses = AttendanceStatus.allCases
6+
private let onStatusSelected: (AttendanceStatus) -> Void
7+
8+
init(onStatusSelected: @escaping (AttendanceStatus) -> Void) {
9+
self.onStatusSelected = onStatusSelected
10+
}
11+
12+
var body: some View {
13+
ScrollView {
14+
VStack(alignment: .leading, spacing: 24) {
15+
Text(Localization.title)
16+
.font(.subheadline.weight(.medium))
17+
.foregroundColor(.secondary)
18+
.padding(.horizontal)
19+
20+
ForEach(statuses) { status in
21+
HStack(alignment: .top, spacing: 16) {
22+
Image(systemName: status.iconName)
23+
.font(.title3.weight(.medium))
24+
.foregroundStyle(Color(.systemGray))
25+
VStack(alignment: .leading, spacing: 4) {
26+
Text(status.title)
27+
.font(.body.weight(.medium))
28+
.fixedSize(horizontal: false, vertical: true)
29+
Text(status.description)
30+
.font(.subheadline)
31+
.foregroundColor(.secondary)
32+
.fixedSize(horizontal: false, vertical: true)
33+
}
34+
}
35+
.padding(.horizontal)
36+
.contentShape(Rectangle())
37+
.tappable {
38+
onStatusSelected(status)
39+
dismiss()
40+
}
41+
}
42+
}
43+
.padding(.top)
44+
}
45+
}
46+
}
47+
48+
extension UpdateAttendanceStatusView {
49+
enum AttendanceStatus: CaseIterable, Identifiable {
50+
case booked
51+
case checkedIn
52+
case noShow
53+
54+
var id: Self { self }
55+
}
56+
}
57+
58+
private extension UpdateAttendanceStatusView.AttendanceStatus {
59+
var title: String {
60+
switch self {
61+
case .booked:
62+
return UpdateAttendanceStatusView.Localization.bookedTitle
63+
case .checkedIn:
64+
return UpdateAttendanceStatusView.Localization.checkedInTitle
65+
case .noShow:
66+
return UpdateAttendanceStatusView.Localization.noShowTitle
67+
}
68+
}
69+
70+
var description: String {
71+
switch self {
72+
case .booked:
73+
return UpdateAttendanceStatusView.Localization.bookedDescription
74+
case .checkedIn:
75+
return UpdateAttendanceStatusView.Localization.checkedInDescription
76+
case .noShow:
77+
return UpdateAttendanceStatusView.Localization.noShowDescription
78+
}
79+
}
80+
81+
var iconName: String {
82+
switch self {
83+
case .booked:
84+
return "calendar.badge.checkmark"
85+
case .checkedIn:
86+
return "calendar.and.person"
87+
case .noShow:
88+
return "calendar.badge.exclamationmark"
89+
}
90+
}
91+
}
92+
93+
private extension UpdateAttendanceStatusView {
94+
enum Localization {
95+
static let title = NSLocalizedString(
96+
"UpdateAttendanceStatusView.title",
97+
value: "Update attendance status",
98+
comment: "Title of the update attendance status bottom sheet."
99+
)
100+
101+
static let bookedTitle = NSLocalizedString(
102+
"UpdateAttendanceStatusView.booked.title",
103+
value: "Booked",
104+
comment: "Title for the 'Booked' attendance status."
105+
)
106+
static let bookedDescription = NSLocalizedString(
107+
"UpdateAttendanceStatusView.booked.description",
108+
value: "The appointment is scheduled but hasn't happened yet.",
109+
comment: "Description for the 'Booked' attendance status."
110+
)
111+
112+
static let checkedInTitle = NSLocalizedString(
113+
"UpdateAttendanceStatusView.checkedIn.title",
114+
value: "Checked-in",
115+
comment: "Title for the 'Checked-in' attendance status."
116+
)
117+
static let checkedInDescription = NSLocalizedString(
118+
"UpdateAttendanceStatusView.checkedIn.description",
119+
value: "The customer arrived and the session took place as planned.",
120+
comment: "Description for the 'Checked-in' attendance status."
121+
)
122+
123+
static let noShowTitle = NSLocalizedString(
124+
"UpdateAttendanceStatusView.noShow.title",
125+
value: "No-show",
126+
comment: "Title for the 'No-show' attendance status."
127+
)
128+
static let noShowDescription = NSLocalizedString(
129+
"UpdateAttendanceStatusView.noShow.description",
130+
value: "The client missed the appointment without canceling in advance.",
131+
comment: "Description for the 'No-show' attendance status."
132+
)
133+
}
134+
}
135+
136+
#if DEBUG
137+
struct UpdateAttendanceStatusView_Previews: PreviewProvider {
138+
static var previews: some View {
139+
UpdateAttendanceStatusView { selectedStatus in
140+
print("Selected status: \(selectedStatus)")
141+
}
142+
}
143+
}
144+
#endif

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,6 +1260,7 @@
12601260
2D05E8112E8A9905004111FD /* CustomerContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D05E8102E8A98FE004111FD /* CustomerContent.swift */; };
12611261
2D05E8132E8AADB9004111FD /* PaymentContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D05E8122E8AADB2004111FD /* PaymentContent.swift */; };
12621262
2D05F7102E8BE921004111FD /* View+Tappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D05F70F2E8BE91E004111FD /* View+Tappable.swift */; };
1263+
2D05FE962E8D71EA004111FD /* UpdateAttendanceStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D05FE952E8D71EA004111FD /* UpdateAttendanceStatusView.swift */; };
12631264
2D09E0D12E61BC7F005C26F3 /* ApplicationPasswordsExperimentState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D09E0D02E61BC7D005C26F3 /* ApplicationPasswordsExperimentState.swift */; };
12641265
2D09E0D52E65C9B9005C26F3 /* ApplicationPasswordsExperimentStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D09E0D42E65C9B9005C26F3 /* ApplicationPasswordsExperimentStateTests.swift */; };
12651266
2D7A3E232E7891DB00C46401 /* CIABEligibilityCheckerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7A3E222E7891D200C46401 /* CIABEligibilityCheckerTests.swift */; };
@@ -4466,6 +4467,7 @@
44664467
2D05E8102E8A98FE004111FD /* CustomerContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerContent.swift; sourceTree = "<group>"; };
44674468
2D05E8122E8AADB2004111FD /* PaymentContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentContent.swift; sourceTree = "<group>"; };
44684469
2D05F70F2E8BE91E004111FD /* View+Tappable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Tappable.swift"; sourceTree = "<group>"; };
4470+
2D05FE952E8D71EA004111FD /* UpdateAttendanceStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateAttendanceStatusView.swift; sourceTree = "<group>"; };
44694471
2D09E0D02E61BC7D005C26F3 /* ApplicationPasswordsExperimentState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationPasswordsExperimentState.swift; sourceTree = "<group>"; };
44704472
2D09E0D42E65C9B9005C26F3 /* ApplicationPasswordsExperimentStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationPasswordsExperimentStateTests.swift; sourceTree = "<group>"; };
44714473
2D7A3E222E7891D200C46401 /* CIABEligibilityCheckerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIABEligibilityCheckerTests.swift; sourceTree = "<group>"; };
@@ -9178,6 +9180,7 @@
91789180
isa = PBXGroup;
91799181
children = (
91809182
2DAC2C972E82A185008521AF /* BookingDetailsView.swift */,
9183+
2D05FE952E8D71EA004111FD /* UpdateAttendanceStatusView.swift */,
91819184
);
91829185
path = "Booking Details";
91839186
sourceTree = "<group>";
@@ -16551,6 +16554,7 @@
1655116554
DE2FE5862925DA050018040A /* SiteCredentialLoginView.swift in Sources */,
1655216555
020DD48F232392C9005822B1 /* UIViewController+AppReview.swift in Sources */,
1655316556
2687165524D21BC80042F6AE /* SurveySubmittedViewController.swift in Sources */,
16557+
2D05FE962E8D71EA004111FD /* UpdateAttendanceStatusView.swift in Sources */,
1655416558
CE263DE8206ACE3E0015A693 /* MainTabBarController.swift in Sources */,
1655516559
20A3AFE32B10EF860033AF2D /* CardReaderSettingsFlowPresentingView.swift in Sources */,
1655616560
CE14452E2188C11700A991D8 /* ZendeskManager.swift in Sources */,

0 commit comments

Comments
 (0)