Skip to content

Commit 3429c06

Browse files
[Bookings][Part 2] Booking details screen (#16178)
2 parents cc8759d + affe0f3 commit 3429c06

File tree

13 files changed

+561
-78
lines changed

13 files changed

+561
-78
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import SwiftUI
2+
3+
private struct TappableViewModifier: ViewModifier {
4+
let onTap: () -> Void
5+
6+
func body(content: Content) -> some View {
7+
Button {
8+
onTap()
9+
} label: {
10+
content
11+
}
12+
.buttonStyle(.plain)
13+
}
14+
}
15+
16+
extension View {
17+
func tappable(_ onTap: @escaping () -> Void) -> some View {
18+
self.modifier(TappableViewModifier(onTap: onTap))
19+
}
20+
}

WooCommerce/Classes/ViewModels/Booking Details/AppointmentDetailsContent.swift

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ extension BookingDetailsViewModel {
2525
rows = [
2626
Row(title: Localization.appointmentDetailsDateRowTitle, value: appointmentDate),
2727
Row(title: Localization.appointmentDetailsTimeRowTitle, value: appointmentTimeFrame),
28-
Row(title: Localization.appointmentDetailsServiceTitle, value: "Women's Haircut"),
29-
Row(title: Localization.appointmentDetailsQuantityTitle, value: "1"),
28+
Row(title: Localization.appointmentDetailsAssignedStaffTitle, value: "Marianne Renoir"), /// Temporarily hardcoded
29+
Row(title: Localization.appointmentDetailsLocationTitle, value: "238 Willow Creek Drive, Montgomery ..."), /// Temporarily hardcoded
3030
Row(title: Localization.appointmentDetailsDurationTitle, value: String(durationMinutes)),
31-
Row(title: Localization.appointmentDetailsCostTitle, value: booking.cost)
31+
Row(title: Localization.appointmentDetailsPriceTitle, value: booking.cost)
3232
]
3333
}
3434
}
@@ -48,16 +48,16 @@ private extension BookingDetailsViewModel.AppointmentDetailsContent {
4848
comment: "Time row title in appointment details section in booking details view."
4949
)
5050

51-
static let appointmentDetailsServiceTitle = NSLocalizedString(
52-
"BookingDetailsView.appointmentDetails.serviceRow.title",
53-
value: "Service",
54-
comment: "Service name row title in appointment details section in booking details view."
51+
static let appointmentDetailsAssignedStaffTitle = NSLocalizedString(
52+
"BookingDetailsView.appointmentDetails.assignedStaff.title",
53+
value: "Assigned staff",
54+
comment: "Assigned staff row title in appointment details section in booking details view."
5555
)
5656

57-
static let appointmentDetailsQuantityTitle = NSLocalizedString(
58-
"BookingDetailsView.appointmentDetails.quantityRow.title",
59-
value: "Quantity",
60-
comment: "Quantity row title in appointment details section in booking details view."
57+
static let appointmentDetailsLocationTitle = NSLocalizedString(
58+
"BookingDetailsView.appointmentDetails.locationRow.title",
59+
value: "Location",
60+
comment: "Location row title in appointment details section in booking details view."
6161
)
6262

6363
static let appointmentDetailsDurationTitle = NSLocalizedString(
@@ -66,10 +66,10 @@ private extension BookingDetailsViewModel.AppointmentDetailsContent {
6666
comment: "Duration row title in appointment details section in booking details view."
6767
)
6868

69-
static let appointmentDetailsCostTitle = NSLocalizedString(
70-
"BookingDetailsView.appointmentDetails.costRow.title",
71-
value: "Cost",
72-
comment: "Cost row title in appointment details section in booking details view."
69+
static let appointmentDetailsPriceTitle = NSLocalizedString(
70+
"BookingDetailsView.appointmentDetails.priceRow.title",
71+
value: "Price",
72+
comment: "Price row title in appointment details section in booking details view."
7373
)
7474
}
7575
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Foundation
2+
3+
extension BookingDetailsViewModel {
4+
struct AttendanceContent {
5+
/// Hardcoded attendance value
6+
/// Will be replaced with model value or binding
7+
let value = "Booked"
8+
}
9+
}

WooCommerce/Classes/ViewModels/Booking Details/BookingDetailsViewModel+Section.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,25 @@ extension BookingDetailsViewModel {
66
return content.id
77
}
88

9-
let headerText: String?
9+
let header: Header?
1010
let footerText: String?
1111
let content: SectionContent
1212

1313
init(
14-
headerText: String? = nil,
14+
header: Header? = nil,
1515
footerText: String? = nil,
1616
content: SectionContent
1717
) {
18-
self.headerText = headerText
18+
self.header = header
1919
self.footerText = footerText
2020
self.content = content
2121
}
2222
}
2323
}
24+
25+
extension BookingDetailsViewModel.Section {
26+
enum Header {
27+
case empty
28+
case title(String)
29+
}
30+
}

WooCommerce/Classes/ViewModels/Booking Details/BookingDetailsViewModel+SectionContent.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ extension BookingDetailsViewModel {
77
case attendance(AttendanceContent)
88
case payment(PaymentContent)
99
case customer(CustomerContent)
10-
case teamMember(TeamMemberContent)
10+
case bookingNotes
1111
}
1212
}
1313

@@ -24,8 +24,8 @@ extension BookingDetailsViewModel.SectionContent: Identifiable {
2424
return "payment"
2525
case .customer:
2626
return "customer"
27-
case .teamMember:
28-
return "teamMember"
27+
case .bookingNotes:
28+
return "bookingNotes"
2929
}
3030
}
3131
}

WooCommerce/Classes/ViewModels/Booking Details/BookingDetailsViewModel+Status.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import SwiftUI
33

44
extension BookingDetailsViewModel {
55
enum Status {
6-
case booked, paid
6+
case booked, paid, payAtLocation
77
}
88
}
99

@@ -14,6 +14,8 @@ extension BookingDetailsViewModel.Status {
1414
return Localization.bookingStatusBooked
1515
case .paid:
1616
return Localization.bookingStatusPaid
17+
case .payAtLocation:
18+
return Localization.bookingStatusPayAtLocation
1719
}
1820
}
1921

@@ -23,22 +25,30 @@ extension BookingDetailsViewModel.Status {
2325
return Color(UIColor.systemGray6)
2426
case .paid:
2527
return Color(UIColor.systemGray6)
28+
case .payAtLocation:
29+
return Color(UIColor(hexString: "FFE365"))
2630
}
2731
}
2832
}
2933

3034
private extension BookingDetailsViewModel.Status {
3135
enum Localization {
3236
static let bookingStatusBooked = NSLocalizedString(
33-
"BookingDetailsView.appointmentDetails.statusLabel.booked",
37+
"BookingDetailsView.statusLabel.booked",
3438
value: "Booked",
35-
comment: "Title for the 'Booked' status label in the appointment details view."
39+
comment: "Title for the 'Booked' status label in the header view."
3640
)
3741

3842
static let bookingStatusPaid = NSLocalizedString(
39-
"BookingDetailsView.appointmentDetails.statusLabel.paid",
43+
"BookingDetailsView.statusLabel.paid",
4044
value: "Paid",
41-
comment: "Title for the 'Paid' status label in the appointment details view."
45+
comment: "Title for the 'Paid' status label in the header view."
46+
)
47+
48+
static let bookingStatusPayAtLocation = NSLocalizedString(
49+
"BookingDetailsView.statusLabel.payAtLocation",
50+
value: "Pay at location",
51+
comment: "Title for the 'Pay at location' status label in the header view."
4252
)
4353
}
4454
}
Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,6 @@
11
import Foundation
22
import struct Networking.Booking
33

4-
extension BookingDetailsViewModel {
5-
struct AttendanceContent {
6-
}
7-
8-
struct PaymentContent {
9-
}
10-
11-
struct CustomerContent {
12-
}
13-
14-
struct TeamMemberContent {
15-
}
16-
}
17-
184
final class BookingDetailsViewModel: ObservableObject {
195
let sections: [Section]
206

@@ -24,13 +10,48 @@ final class BookingDetailsViewModel: ObservableObject {
2410
)
2511

2612
let appointmentDetailsSection = Section(
27-
headerText: Localization.appointmentDetailsSectionHeaderTitle.uppercased(),
13+
header: .title(Localization.appointmentDetailsSectionHeaderTitle.uppercased()),
2814
content: .appointmentDetails(AppointmentDetailsContent(booking))
2915
)
3016

17+
let attendanceSection = Section(
18+
header: .title(Localization.attendanceSectionHeaderTitle.uppercased()),
19+
footerText: Localization.attendanceSectionFooterText,
20+
content: .attendance(AttendanceContent())
21+
)
22+
23+
let customerSection = Section(
24+
header: .title(Localization.customerSectionHeaderTitle.uppercased()),
25+
content: .customer(
26+
/// Temporary hardcode
27+
CustomerContent(
28+
nameText: "Margarita Nikolaevna",
29+
emailText: "[email protected]",
30+
phoneText: "+1 742582943798",
31+
billingAddressText: """
32+
238 Willow Creek Drive
Montgomery
AL 36109
33+
"""
34+
)
35+
)
36+
)
37+
38+
let paymentSection = Section(
39+
header: .title(Localization.paymentSectionHeaderTitle.uppercased()),
40+
content: .payment(PaymentContent(booking: booking))
41+
)
42+
43+
let bookingNotes = Section(
44+
header: .title(Localization.bookingNotesSectionHeaderTitle.uppercased()),
45+
content: .bookingNotes
46+
)
47+
3148
sections = [
3249
headerSection,
33-
appointmentDetailsSection
50+
appointmentDetailsSection,
51+
customerSection,
52+
attendanceSection,
53+
paymentSection,
54+
bookingNotes
3455
]
3556
}
3657
}
@@ -42,5 +63,35 @@ private extension BookingDetailsViewModel {
4263
value: "Appointment Details",
4364
comment: "Header title for the 'Appointment Details' section in the booking details screen."
4465
)
66+
67+
static let attendanceSectionHeaderTitle = NSLocalizedString(
68+
"BookingDetailsView.attendance.headerTitle",
69+
value: "Attendance",
70+
comment: "Header title for the 'Attendance' section in the booking details screen."
71+
)
72+
73+
static let customerSectionHeaderTitle = NSLocalizedString(
74+
"BookingDetailsView.customer.headerTitle",
75+
value: "Customer",
76+
comment: "Header title for the 'Customer' section in the booking details screen."
77+
)
78+
79+
static let attendanceSectionFooterText = NSLocalizedString(
80+
"BookingDetailsView.attendance.footerText",
81+
value: "Mark attendance to keep your reports accurate and spot booking trends.",
82+
comment: "Footer text for the 'Attendance' section in the booking details screen."
83+
)
84+
85+
static let paymentSectionHeaderTitle = NSLocalizedString(
86+
"BookingDetailsView.payment.headerTitle",
87+
value: "Payment",
88+
comment: "Header title for the 'Payment' section in the booking details screen."
89+
)
90+
91+
static let bookingNotesSectionHeaderTitle = NSLocalizedString(
92+
"BookingDetailsView.bookingNotes.headerTitle",
93+
value: "Booking notes",
94+
comment: "Header title for the 'Booking notes' section in the booking details screen."
95+
)
4596
}
4697
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import Foundation
2+
3+
extension BookingDetailsViewModel {
4+
struct CustomerContent {
5+
let nameText: String
6+
let emailText: String
7+
let phoneText: String
8+
let billingAddressText: String?
9+
}
10+
}

WooCommerce/Classes/ViewModels/Booking Details/HeaderContent.swift

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,28 @@ import struct Networking.Booking
44
extension BookingDetailsViewModel {
55
struct HeaderContent: Hashable {
66
let bookingDate: String
7-
let serviceName: String
8-
let customerName: String
7+
let serviceAndCustomerLine: String
98
let status: [Status]
109

1110
init(_ booking: Booking) {
12-
bookingDate = booking.startDate.formatted(date: .numeric, time: .omitted)
13-
serviceName = "Women's Haircut"
14-
customerName = "Margarita Nikolaevna"
15-
status = [.paid, .booked]
11+
bookingDate = booking.startDate.formatted(
12+
date: .numeric,
13+
time: .shortened
14+
)
15+
16+
/// Temporary hardcode
17+
serviceAndCustomerLine = [
18+
"Women's Haircut",
19+
"Margarita Nikolaevna"
20+
].joined(separator: Constants.dotSeparator)
21+
22+
status = [.booked, .payAtLocation]
1623
}
1724
}
1825
}
26+
27+
private extension BookingDetailsViewModel {
28+
enum Constants {
29+
static let dotSeparator: String = ""
30+
}
31+
}

0 commit comments

Comments
 (0)