Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
2 changes: 1 addition & 1 deletion Modules/Sources/Networking/Model/Bookings/Booking.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Foundation

/// Represents a Booking Entity.
///
public struct Booking: Codable, GeneratedCopiable, Equatable, GeneratedFakeable {
public struct Booking: Codable, GeneratedCopiable, Hashable, GeneratedFakeable {
public let siteID: Int64
public let bookingID: Int64
public let allDay: Bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ struct BookingListView: View {
}
}
}
.navigationDestination(for: Booking.self) { booking in
let viewModel = BookingDetailsViewModel(booking: booking)
BookingDetailsView(viewModel)
}
.task {
viewModel.loadBookings()
}
Expand Down Expand Up @@ -113,7 +117,10 @@ private extension BookingListView {
LazyVStack(spacing: 0, pinnedViews: .sectionHeaders) {
Section {
ForEach(viewModel.bookings) { item in
bookingItem(item)
NavigationLink(value: item) {
bookingItem(item)
}
.buttonStyle(.plain)
}
} header: {
headerView
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import struct Networking.Booking
import class WooFoundationCore.CurrencyFormatter

extension BookingDetailsViewModel {
struct AppointmentDetailsContent {
Expand All @@ -15,7 +16,6 @@ extension BookingDetailsViewModel {
let rows: [Row]

init(_ booking: Booking) {
let durationMinutes = Int(booking.endDate.timeIntervalSince(booking.startDate) / 60)
let appointmentDate = booking.startDate.formatted(date: .numeric, time: .omitted)
let appointmentTimeFrame = [
booking.startDate.formatted(date: .omitted, time: .shortened),
Expand All @@ -27,13 +27,41 @@ extension BookingDetailsViewModel {
Row(title: Localization.appointmentDetailsTimeRowTitle, value: appointmentTimeFrame),
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.appointmentDetailsPriceTitle, value: booking.cost)
Row(
title: Localization.appointmentDetailsDurationTitle,
value: Self.formatDuration(
from: booking.startDate,
to: booking.endDate
)
),
Row(title: Localization.appointmentDetailsPriceTitle, value: Self.formatPrice(booking.cost))
]
}
}
}

private extension BookingDetailsViewModel.AppointmentDetailsContent {
static let durationFormatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .short
formatter.allowedUnits = [.hour, .minute]
return formatter
}()

static func formatDuration(from startDate: Date, to endDate: Date) -> String {
durationFormatter.string(from: startDate, to: endDate) ?? ""
}

static func formatPrice(_ price: String) -> String {
guard let decimalPrice = Decimal(string: price) else {
return price
}
return CurrencyFormatter(
currencySettings: ServiceLocator.currencySettings
).formatAmount(decimalPrice) ?? price
}
}

private extension BookingDetailsViewModel.AppointmentDetailsContent {
enum Localization {
static let appointmentDetailsDateRowTitle = NSLocalizedString(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import struct Networking.Booking

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

init(booking: Booking) {
navigationTitle = Self.navigationTitle(for: booking)

let headerSection = Section.init(
content: .header(HeaderContent(booking))
)
Expand Down Expand Up @@ -56,6 +59,17 @@ final class BookingDetailsViewModel: ObservableObject {
}
}

private extension BookingDetailsViewModel {
static func navigationTitle(for booking: Booking) -> String {
let titleFormat = NSLocalizedString(
"BookingDetailsView.navTitle",
value: "Booking #%1$d",
comment: "Booking Details screen nav bar title. %1$d is a placeholder for the booking ID."
)
return String(format: titleFormat, booking.bookingID)
}
}

private extension BookingDetailsViewModel {
enum Localization {
static let appointmentDetailsSectionHeaderTitle = NSLocalizedString(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import struct Networking.Booking
import class WooFoundationCore.CurrencyFormatter

extension BookingDetailsViewModel {
struct PaymentContent {
Expand All @@ -8,10 +9,10 @@ extension BookingDetailsViewModel {

init(booking: Booking) {
amounts = [
.init(value: booking.cost, type: .service),
.init(value: "$0", type: .tax),
.init(value: Self.formatPrice(booking.cost), type: .service),
.init(value: Self.formatPrice("0"), type: .tax),
.init(value: "-", type: .discount),
.init(value: "$55.00", type: .total, emphasized: true),
.init(value: Self.formatPrice(booking.cost), type: .total, emphasized: true),
]

actions = [
Expand All @@ -22,6 +23,17 @@ extension BookingDetailsViewModel {
}
}

private extension BookingDetailsViewModel.PaymentContent {
static func formatPrice(_ price: String) -> String {
guard let decimalPrice = Decimal(string: price) else {
return price
}
return CurrencyFormatter(
currencySettings: ServiceLocator.currencySettings
).formatAmount(decimalPrice) ?? price
}
}

extension BookingDetailsViewModel.PaymentContent {
struct Amount {
enum AmountType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Networking

struct BookingDetailsView: View {
@Environment(\.safeAreaInsets) var safeAreaInsets: EdgeInsets
@Environment(\.dismiss) private var dismiss

@ObservedObject private var viewModel: BookingDetailsViewModel

Expand Down Expand Up @@ -37,7 +38,26 @@ struct BookingDetailsView: View {
print("Refresh triggered")
}
.navigationBarTitleDisplayMode(.inline)
.navigationTitle(viewModel.navigationTitle)
.background(Color(uiColor: .systemGroupedBackground))
.navigationBarBackButtonHidden(true)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
dismiss()
} label: {
Image(systemName: "chevron.backward")
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button {
//TODO: - present an action sheet
print("On ellipsis item tap")
} label: {
Image(systemName: "ellipsis")
}
}
}
}
}

Expand Down