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
20 changes: 20 additions & 0 deletions WooCommerce/Classes/View Modifiers/View+Tappable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import SwiftUI

private struct TappableViewModifier: ViewModifier {
let onTap: () -> Void

func body(content: Content) -> some View {
Button {
onTap()
} label: {
content
}
.buttonStyle(.plain)
}
}

extension View {
func tappable(_ onTap: @escaping () -> Void) -> some View {
self.modifier(TappableViewModifier(onTap: onTap))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ extension BookingDetailsViewModel {
rows = [
Row(title: Localization.appointmentDetailsDateRowTitle, value: appointmentDate),
Row(title: Localization.appointmentDetailsTimeRowTitle, value: appointmentTimeFrame),
Row(title: Localization.appointmentDetailsServiceTitle, value: "Women's Haircut"),
Row(title: Localization.appointmentDetailsQuantityTitle, value: "1"),
Row(title: Localization.appointmentDetailsAssignedStaffTitle, value: "Marianne Renoir"), /// Temporarily hardcoded
Row(title: Localization.appointmentDetailsLocationTitle, value: "238 Willow Creek Drive, Montgomery ..."), /// Temporarily hardcoded
Row(title: Localization.appointmentDetailsDurationTitle, value: String(durationMinutes)),
Row(title: Localization.appointmentDetailsCostTitle, value: booking.cost)
Row(title: Localization.appointmentDetailsPriceTitle, value: booking.cost)
]
}
}
Expand All @@ -48,16 +48,16 @@ private extension BookingDetailsViewModel.AppointmentDetailsContent {
comment: "Time row title in appointment details section in booking details view."
)

static let appointmentDetailsServiceTitle = NSLocalizedString(
"BookingDetailsView.appointmentDetails.serviceRow.title",
value: "Service",
comment: "Service name row title in appointment details section in booking details view."
static let appointmentDetailsAssignedStaffTitle = NSLocalizedString(
"BookingDetailsView.appointmentDetails.assignedStaff.title",
value: "Assigned staff",
comment: "Assigned staff row title in appointment details section in booking details view."
)

static let appointmentDetailsQuantityTitle = NSLocalizedString(
"BookingDetailsView.appointmentDetails.quantityRow.title",
value: "Quantity",
comment: "Quantity row title in appointment details section in booking details view."
static let appointmentDetailsLocationTitle = NSLocalizedString(
"BookingDetailsView.appointmentDetails.locationRow.title",
value: "Location",
comment: "Location row title in appointment details section in booking details view."
)

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

static let appointmentDetailsCostTitle = NSLocalizedString(
"BookingDetailsView.appointmentDetails.costRow.title",
value: "Cost",
comment: "Cost row title in appointment details section in booking details view."
static let appointmentDetailsPriceTitle = NSLocalizedString(
"BookingDetailsView.appointmentDetails.priceRow.title",
value: "Price",
comment: "Price row title in appointment details section in booking details view."
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Foundation

extension BookingDetailsViewModel {
struct AttendanceContent {
/// Hardcoded attendance value
/// Will be replaced with model value or binding
let value = "Booked"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,25 @@ extension BookingDetailsViewModel {
return content.id
}

let headerText: String?
let header: Header?
let footerText: String?
let content: SectionContent

init(
headerText: String? = nil,
header: Header? = nil,
footerText: String? = nil,
content: SectionContent
) {
self.headerText = headerText
self.header = header
self.footerText = footerText
self.content = content
}
}
}

extension BookingDetailsViewModel.Section {
enum Header {
case empty
case title(String)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ extension BookingDetailsViewModel {
case attendance(AttendanceContent)
case payment(PaymentContent)
case customer(CustomerContent)
case teamMember(TeamMemberContent)
case bookingNotes
}
}

Expand All @@ -24,8 +24,8 @@ extension BookingDetailsViewModel.SectionContent: Identifiable {
return "payment"
case .customer:
return "customer"
case .teamMember:
return "teamMember"
case .bookingNotes:
return "bookingNotes"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import SwiftUI

extension BookingDetailsViewModel {
enum Status {
case booked, paid
case booked, paid, payAtLocation
}
}

Expand All @@ -14,6 +14,8 @@ extension BookingDetailsViewModel.Status {
return Localization.bookingStatusBooked
case .paid:
return Localization.bookingStatusPaid
case .payAtLocation:
return Localization.bookingStatusPayAtLocation
}
}

Expand All @@ -23,22 +25,30 @@ extension BookingDetailsViewModel.Status {
return Color(UIColor.systemGray6)
case .paid:
return Color(UIColor.systemGray6)
case .payAtLocation:
return Color(UIColor(hexString: "FFE365"))
}
}
}

private extension BookingDetailsViewModel.Status {
enum Localization {
static let bookingStatusBooked = NSLocalizedString(
"BookingDetailsView.appointmentDetails.statusLabel.booked",
"BookingDetailsView.statusLabel.booked",
value: "Booked",
comment: "Title for the 'Booked' status label in the appointment details view."
comment: "Title for the 'Booked' status label in the header view."
)

static let bookingStatusPaid = NSLocalizedString(
"BookingDetailsView.appointmentDetails.statusLabel.paid",
"BookingDetailsView.statusLabel.paid",
value: "Paid",
comment: "Title for the 'Paid' status label in the appointment details view."
comment: "Title for the 'Paid' status label in the header view."
)

static let bookingStatusPayAtLocation = NSLocalizedString(
"BookingDetailsView.statusLabel.payAtLocation",
value: "Pay at location",
comment: "Title for the 'Pay at location' status label in the header view."
)
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
import Foundation
import struct Networking.Booking

extension BookingDetailsViewModel {
struct AttendanceContent {
}

struct PaymentContent {
}

struct CustomerContent {
}

struct TeamMemberContent {
}
}

final class BookingDetailsViewModel: ObservableObject {
let sections: [Section]

Expand All @@ -24,13 +10,48 @@ final class BookingDetailsViewModel: ObservableObject {
)

let appointmentDetailsSection = Section(
headerText: Localization.appointmentDetailsSectionHeaderTitle.uppercased(),
header: .title(Localization.appointmentDetailsSectionHeaderTitle.uppercased()),
content: .appointmentDetails(AppointmentDetailsContent(booking))
)

let attendanceSection = Section(
header: .title(Localization.attendanceSectionHeaderTitle.uppercased()),
footerText: Localization.attendanceSectionFooterText,
content: .attendance(AttendanceContent())
)

let customerSection = Section(
header: .title(Localization.customerSectionHeaderTitle.uppercased()),
content: .customer(
/// Temporary hardcode
CustomerContent(
nameText: "Margarita Nikolaevna",
emailText: "[email protected]",
phoneText: "+1 742582943798",
billingAddressText: """
238 Willow Creek Drive
Montgomery
AL 36109
"""
)
)
)

let paymentSection = Section(
header: .title(Localization.paymentSectionHeaderTitle.uppercased()),
content: .payment(PaymentContent(booking: booking))
)

let bookingNotes = Section(
header: .title(Localization.bookingNotesSectionHeaderTitle.uppercased()),
content: .bookingNotes
)

sections = [
headerSection,
appointmentDetailsSection
appointmentDetailsSection,
customerSection,
attendanceSection,
paymentSection,
bookingNotes
]
}
}
Expand All @@ -42,5 +63,35 @@ private extension BookingDetailsViewModel {
value: "Appointment Details",
comment: "Header title for the 'Appointment Details' section in the booking details screen."
)

static let attendanceSectionHeaderTitle = NSLocalizedString(
"BookingDetailsView.attendance.headerTitle",
value: "Attendance",
comment: "Header title for the 'Attendance' section in the booking details screen."
)

static let customerSectionHeaderTitle = NSLocalizedString(
"BookingDetailsView.customer.headerTitle",
value: "Customer",
comment: "Header title for the 'Customer' section in the booking details screen."
)

static let attendanceSectionFooterText = NSLocalizedString(
"BookingDetailsView.attendance.footerText",
value: "Mark attendance to keep your reports accurate and spot booking trends.",
comment: "Footer text for the 'Attendance' section in the booking details screen."
)

static let paymentSectionHeaderTitle = NSLocalizedString(
"BookingDetailsView.payment.headerTitle",
value: "Payment",
comment: "Header title for the 'Payment' section in the booking details screen."
)

static let bookingNotesSectionHeaderTitle = NSLocalizedString(
"BookingDetailsView.bookingNotes.headerTitle",
value: "Booking notes",
comment: "Header title for the 'Booking notes' section in the booking details screen."
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Foundation

extension BookingDetailsViewModel {
struct CustomerContent {
let nameText: String
let emailText: String
let phoneText: String
let billingAddressText: String?
}
}
25 changes: 19 additions & 6 deletions WooCommerce/Classes/ViewModels/Booking Details/HeaderContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,28 @@ import struct Networking.Booking
extension BookingDetailsViewModel {
struct HeaderContent: Hashable {
let bookingDate: String
let serviceName: String
let customerName: String
let serviceAndCustomerLine: String
let status: [Status]

init(_ booking: Booking) {
bookingDate = booking.startDate.formatted(date: .numeric, time: .omitted)
serviceName = "Women's Haircut"
customerName = "Margarita Nikolaevna"
status = [.paid, .booked]
bookingDate = booking.startDate.formatted(
date: .numeric,
time: .shortened
)

/// Temporary hardcode
serviceAndCustomerLine = [
"Women's Haircut",
"Margarita Nikolaevna"
].joined(separator: Constants.dotSeparator)

status = [.booked, .payAtLocation]
}
}
}

private extension BookingDetailsViewModel {
enum Constants {
static let dotSeparator: String = " • "
}
}
Loading