Skip to content

Commit c9bd3bb

Browse files
[Bookings] Add "Note" to booking customer details (#16381)
2 parents 57dc91a + ddf95f3 commit c9bd3bb

File tree

11 files changed

+1310
-9
lines changed

11 files changed

+1310
-9
lines changed

Modules/Sources/Networking/Model/Bookings/BookingCustomerInfo.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import Foundation
22

33
public struct BookingCustomerInfo: Hashable {
44
public let billingAddress: Address
5+
public let note: String?
56

6-
public init(billingAddress: Address) {
7+
public init(billingAddress: Address, note: String? = nil) {
78
self.billingAddress = billingAddress
9+
self.note = note
810
}
911
}

Modules/Sources/Networking/Model/Bookings/BookingOrderInfo.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ public struct BookingOrderInfo: Hashable {
2222
guard let billingAddress = order.billingAddress else {
2323
return nil
2424
}
25-
return BookingCustomerInfo(billingAddress: billingAddress)
25+
return BookingCustomerInfo(
26+
billingAddress: billingAddress,
27+
note: order.customerNote
28+
)
2629
}()
2730
self.productInfo = BookingProductInfo(name: order.items.first(where: { $0.productID == booking.productID })?.name ?? "")
2831
self.paymentInfo = BookingPaymentInfo(

Modules/Sources/Storage/Model/Booking/BookingCustomerInfo+CoreDataProperties.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extension BookingCustomerInfo {
1313
@NSManaged public var billingPhone: String?
1414
@NSManaged public var billingPostcode: String?
1515
@NSManaged public var billingState: String?
16+
@NSManaged public var note: String?
1617
@NSManaged public var orderInfo: BookingOrderInfo?
1718

1819
}

Modules/Sources/Storage/Resources/WooCommerce.xcdatamodeld/.xccurrentversion

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
<plist version="1.0">
44
<dict>
55
<key>_XCCurrentVersionName</key>
6-
<string>Model 130.xcdatamodel</string>
6+
<string>Model 131.xcdatamodel</string>
77
</dict>
88
</plist>

Modules/Sources/Storage/Resources/WooCommerce.xcdatamodeld/Model 131.xcdatamodel/contents

Lines changed: 1178 additions & 0 deletions
Large diffs are not rendered by default.

Modules/Sources/Yosemite/Model/Booking/BookingCustomerInfo+ReadOnlyConvertible.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ extension Storage.BookingCustomerInfo: ReadOnlyConvertible {
1616
billingPhone = customerInfo.billingAddress.phone
1717
billingPostcode = customerInfo.billingAddress.postcode
1818
billingState = customerInfo.billingAddress.state
19+
note = customerInfo.note
1920
}
2021

2122
public func toReadOnly() -> Yosemite.BookingCustomerInfo {
@@ -30,6 +31,6 @@ extension Storage.BookingCustomerInfo: ReadOnlyConvertible {
3031
country: billingCountry ?? "",
3132
phone: billingPhone,
3233
email: billingEmail)
33-
return .init(billingAddress: address)
34+
return .init(billingAddress: address, note: note)
3435
}
3536
}

Modules/Tests/StorageTests/CoreData/MigrationTests.swift

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2333,6 +2333,36 @@ final class MigrationTests: XCTestCase {
23332333
// `note` should be present in `migratedBooking`
23342334
XCTAssertNotNil(migratedBooking.entity.attributesByName["note"])
23352335
}
2336+
2337+
func test_migrating_from_130_to_131_adds_note_attribute_to_bookingCustomerInfo() throws {
2338+
// Given
2339+
let sourceContainer = try startPersistentContainer("Model 130")
2340+
let sourceContext = sourceContainer.viewContext
2341+
2342+
let customerInfo = insertBookingCustomerInfo(to: sourceContext)
2343+
try sourceContext.save()
2344+
2345+
XCTAssertNil(customerInfo.entity.attributesByName["note"], "Precondition. Attribute does not exist.")
2346+
2347+
// When
2348+
let targetContainer = try migrate(sourceContainer, to: "Model 131")
2349+
2350+
// Then
2351+
let targetContext = targetContainer.viewContext
2352+
let migratedCustomerInfo = try XCTUnwrap(targetContext.first(entityName: "BookingCustomerInfo"))
2353+
2354+
// `note` should be present in `migratedCustomerInfo`
2355+
XCTAssertNotNil(migratedCustomerInfo.entity.attributesByName["note"])
2356+
2357+
let noteValue = migratedCustomerInfo.value(forKey: "note") as? String
2358+
XCTAssertNil(noteValue)
2359+
2360+
let updatedNote = "Customer note"
2361+
migratedCustomerInfo.setValue(updatedNote, forKey: "note")
2362+
try targetContext.save()
2363+
2364+
XCTAssertEqual(migratedCustomerInfo.value(forKey: "note") as? String, updatedNote)
2365+
}
23362366
}
23372367

23382368
// MARK: - Persistent Store Setup and Migrations
@@ -3275,7 +3305,7 @@ private extension MigrationTests {
32753305

32763306
@discardableResult
32773307
func insertBookingCustomerInfo(to context: NSManagedObjectContext) -> NSManagedObject {
3278-
context.insert(entityName: "BookingCustomerInfo", properties: [
3308+
var properties: [String: Any] = [
32793309
"billingFirstName": "John",
32803310
"billingLastName": "Doe",
32813311
"billingEmail": "[email protected]",
@@ -3284,7 +3314,12 @@ private extension MigrationTests {
32843314
"billingState": "CA",
32853315
"billingPostcode": "94102",
32863316
"billingCountry": "US"
3287-
])
3317+
]
3318+
if let entity = NSEntityDescription.entity(forEntityName: "BookingCustomerInfo", in: context),
3319+
entity.attributesByName.keys.contains("note") {
3320+
properties["note"] = "Sample note"
3321+
}
3322+
return context.insert(entityName: "BookingCustomerInfo", properties: properties)
32883323
}
32893324

32903325
@discardableResult

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,10 @@ private extension BookingDetailsViewModel {
9292
headerContent.update(with: booking)
9393

9494
setupCustomerSectionVisibility()
95-
if let billingAddress = booking.orderInfo?.customerInfo?.billingAddress, !billingAddress.isEmpty {
96-
customerContent.update(with: billingAddress)
95+
if let orderInfo = booking.orderInfo,
96+
let customerInfo = orderInfo.customerInfo,
97+
customerInfo.billingAddress.isEmpty == false {
98+
customerContent.update(with: customerInfo)
9799
}
98100

99101
appointmentDetailsContent.update(with: booking, resource: bookingResource)

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ extension BookingDetailsViewModel {
77
@Published var emailText: String?
88
@Published var phoneText: String?
99
@Published var billingAddressText: String?
10+
@Published var noteText: String?
1011

11-
func update(with billingAddress: Address) {
12+
func update(with customerInfo: BookingCustomerInfo) {
13+
let billingAddress = customerInfo.billingAddress
1214
nameText = billingAddress.fullName
1315
emailText = billingAddress.email ?? ""
1416
phoneText = billingAddress.phone ?? ""
1517
billingAddressText = formatAddress(billingAddress)
18+
noteText = formattedNote(customerInfo.note)
1619
}
1720

1821
private func formatAddress(_ address: Address) -> String {
@@ -28,5 +31,13 @@ extension BookingDetailsViewModel {
2831
.filter { !$0.isEmpty }
2932
.joined(separator: "\n")
3033
}
34+
35+
private func formattedNote(_ note: String?) -> String? {
36+
guard let trimmedNote = note?.trimmingCharacters(in: .whitespacesAndNewlines),
37+
trimmedNote.isEmpty == false else {
38+
return nil
39+
}
40+
return trimmedNote
41+
}
3142
}
3243
}

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extension BookingDetailsView {
1313
case email(String)
1414
case phone(String)
1515
case billingAddress(String)
16+
case note(String)
1617
}
1718

1819
private var rows: [Row] {
@@ -29,6 +30,9 @@ extension BookingDetailsView {
2930
if let address = content.billingAddressText, !address.isEmpty {
3031
result.append(.billingAddress(address))
3132
}
33+
if let note = content.noteText, !note.isEmpty {
34+
result.append(.note(note))
35+
}
3236
return result
3337
}
3438

@@ -56,6 +60,8 @@ extension BookingDetailsView {
5660
phoneView(with: phoneText)
5761
case .billingAddress(let billingAddressText):
5862
billingAddressView(with: billingAddressText)
63+
case .note(let noteText):
64+
noteView(with: noteText)
5965
}
6066
}
6167

@@ -136,6 +142,21 @@ extension BookingDetailsView {
136142
}
137143
.padding(.vertical, Layout.rowTextVerticalPadding)
138144
}
145+
146+
private func noteView(with noteText: String) -> some View {
147+
HStack {
148+
VStack(alignment: .leading) {
149+
Text(Localization.noteRowTitle)
150+
.rowTextStyle()
151+
Text(noteText)
152+
.font(TextFont.bodyMedium)
153+
.foregroundStyle(.secondary)
154+
.multilineTextAlignment(.leading)
155+
}
156+
Spacer()
157+
}
158+
.padding(.vertical, Layout.rowTextVerticalPadding)
159+
}
139160
}
140161
}
141162

@@ -177,5 +198,11 @@ private extension BookingDetailsView.CustomerDetailsView {
177198
value: "Billing address",
178199
comment: "Billing address row title in customer section in booking details view."
179200
)
201+
202+
static let noteRowTitle = NSLocalizedString(
203+
"BookingDetailsView.customer.note.title",
204+
value: "Note",
205+
comment: "Customer note row title in customer section in booking details view."
206+
)
180207
}
181208
}

0 commit comments

Comments
 (0)