diff --git a/WooCommerce/Classes/ViewModels/Booking Details/BookingDetailsViewModel+SectionContent.swift b/WooCommerce/Classes/ViewModels/Booking Details/BookingDetailsViewModel+SectionContent.swift index 4dda47f5a36..9b2953249ba 100644 --- a/WooCommerce/Classes/ViewModels/Booking Details/BookingDetailsViewModel+SectionContent.swift +++ b/WooCommerce/Classes/ViewModels/Booking Details/BookingDetailsViewModel+SectionContent.swift @@ -7,7 +7,7 @@ extension BookingDetailsViewModel { case attendance(AttendanceContent) case payment(PaymentContent) case customer(CustomerContent) - case bookingNotes + case bookingNotes(NotesContent) } } diff --git a/WooCommerce/Classes/ViewModels/Booking Details/BookingDetailsViewModel.swift b/WooCommerce/Classes/ViewModels/Booking Details/BookingDetailsViewModel.swift index 0591b8a32ed..13344dd11d4 100644 --- a/WooCommerce/Classes/ViewModels/Booking Details/BookingDetailsViewModel.swift +++ b/WooCommerce/Classes/ViewModels/Booking Details/BookingDetailsViewModel.swift @@ -18,6 +18,7 @@ final class BookingDetailsViewModel: ObservableObject { private let appointmentDetailsContent = AppointmentDetailsContent() private let attendanceContent = AttendanceContent() private let paymentContent = PaymentContent() + private let notesContent = NotesContent() // EntityListener: Update / Deletion Notifications. /// @@ -34,8 +35,6 @@ final class BookingDetailsViewModel: ObservableObject { booking.attendanceStatus } - var note: String { booking.note } - init(booking: Booking, stores: StoresManager = ServiceLocator.stores, storage: StorageManagerType = ServiceLocator.storageManager) { @@ -74,7 +73,7 @@ private extension BookingDetailsViewModel { let bookingNotes = Section( header: .title(Localization.bookingNoteSectionHeaderTitle.uppercased()), footerText: Localization.bookingNoteSectionFooterText, - content: .bookingNotes + content: .bookingNotes(notesContent) ) sections = [ @@ -104,6 +103,7 @@ private extension BookingDetailsViewModel { attendanceContent.update(with: booking) paymentContent.update(with: booking) + notesContent.update(with: booking) } func setupCustomerSectionVisibility() { diff --git a/WooCommerce/Classes/ViewModels/Booking Details/NotesContent.swift b/WooCommerce/Classes/ViewModels/Booking Details/NotesContent.swift new file mode 100644 index 00000000000..ce38214bdcf --- /dev/null +++ b/WooCommerce/Classes/ViewModels/Booking Details/NotesContent.swift @@ -0,0 +1,12 @@ +import Foundation +import struct Networking.Booking + +extension BookingDetailsViewModel { + final class NotesContent: ObservableObject { + @Published var value: String = "" + + func update(with booking: Booking) { + value = booking.note + } + } +} diff --git a/WooCommerce/Classes/ViewRelated/Bookings/Booking Details/BookingDetailsView.swift b/WooCommerce/Classes/ViewRelated/Bookings/Booking Details/BookingDetailsView.swift index dfb3d063fee..a593825ec50 100644 --- a/WooCommerce/Classes/ViewRelated/Bookings/Booking Details/BookingDetailsView.swift +++ b/WooCommerce/Classes/ViewRelated/Bookings/Booking Details/BookingDetailsView.swift @@ -159,8 +159,10 @@ private extension BookingDetailsView { }) case .payment(let content): paymentDetailsView(with: content) - case .bookingNotes: - bookingNotesView() + case .bookingNotes(let content): + BookingNotesRowView(content: content) { newNote in + await viewModel.updateNote(to: newNote) + } } } @@ -240,14 +242,6 @@ private extension BookingDetailsView { } .padding(.vertical) } - - func bookingNotesView() -> some View { - MultilineEditableTextRow(value: viewModel.note, - placeholder: Localization.bookingNotesRowText, - detailTitle: Localization.bookingNoteNavbarText) { newNote in - return await viewModel.updateNote(to: newNote) - } - } } extension BookingDetailsView { diff --git a/WooCommerce/Classes/ViewRelated/Bookings/Booking Details/BookingNotesRowView.swift b/WooCommerce/Classes/ViewRelated/Bookings/Booking Details/BookingNotesRowView.swift new file mode 100644 index 00000000000..3a44f01cc20 --- /dev/null +++ b/WooCommerce/Classes/ViewRelated/Bookings/Booking Details/BookingNotesRowView.swift @@ -0,0 +1,15 @@ +import SwiftUI + +struct BookingNotesRowView: View { + @ObservedObject var content: BookingDetailsViewModel.NotesContent + let onCommit: (String) async -> MultilineCommitResult + + var body: some View { + MultilineEditableTextRow( + value: $content.value, + placeholder: BookingDetailsView.Localization.bookingNotesRowText, + detailTitle: BookingDetailsView.Localization.bookingNoteNavbarText, + onCommit: onCommit + ) + } +} diff --git a/WooCommerce/Classes/ViewRelated/ReusableViews/SwiftUI Components/MultilineEditableTextRow/MultilineEditableTextRow.swift b/WooCommerce/Classes/ViewRelated/ReusableViews/SwiftUI Components/MultilineEditableTextRow/MultilineEditableTextRow.swift index febca79f970..29d8351a45d 100644 --- a/WooCommerce/Classes/ViewRelated/ReusableViews/SwiftUI Components/MultilineEditableTextRow/MultilineEditableTextRow.swift +++ b/WooCommerce/Classes/ViewRelated/ReusableViews/SwiftUI Components/MultilineEditableTextRow/MultilineEditableTextRow.swift @@ -1,17 +1,17 @@ import SwiftUI struct MultilineEditableTextRow: View { - @State var value: String + @Binding var value: String let placeholder: String let detailTitle: String? let onCommit: (String) async -> MultilineCommitResult - init(value: String, + init(value: Binding, placeholder: String, detailTitle: String? = nil, onCommit: @escaping (String) async -> MultilineCommitResult ) { - self._value = State(initialValue: value) + self._value = value self.placeholder = placeholder self.detailTitle = detailTitle self.onCommit = onCommit @@ -64,7 +64,7 @@ fileprivate extension MultilineEditableTextRow { @Previewable @State var text: String = "" NavigationStack { - MultilineEditableTextRow(value: text, placeholder: "Add note") { _ in + MultilineEditableTextRow(value: $text, placeholder: "Add note") { _ in return .success } .padding(.horizontal, 16) diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index 8cbb193824f..addcd4b38d7 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -1338,6 +1338,8 @@ 57F2C6CD246DECC10074063B /* SummaryTableViewCellViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57F2C6CC246DECC10074063B /* SummaryTableViewCellViewModelTests.swift */; }; 57F42E40253768D600EA87F7 /* TitleAndEditableValueTableViewCellViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57F42E3F253768D600EA87F7 /* TitleAndEditableValueTableViewCellViewModelTests.swift */; }; 640DA3482E97DE4F00317FB2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640DA3472E97DE4F00317FB2 /* SceneDelegate.swift */; }; + 647C05FB2ED5D9E800E5FF3F /* NotesContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647C05FA2ED5D9E200E5FF3F /* NotesContent.swift */; }; + 647C05FD2ED5E1C000E5FF3F /* BookingNotesRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647C05FC2ED5E1C000E5FF3F /* BookingNotesRowView.swift */; }; 6489DFFF2EA78E0D00D96802 /* MockProductDetailCoordinatorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6489DFFE2EA78E0D00D96802 /* MockProductDetailCoordinatorFactory.swift */; }; 6489E0012EA78E2D00D96802 /* MockProductDetailCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6489E0002EA78E2D00D96802 /* MockProductDetailCoordinator.swift */; }; 64D355A52E99048E005F53F7 /* TestingSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D355A42E99048E005F53F7 /* TestingSceneDelegate.swift */; }; @@ -4232,6 +4234,8 @@ 57F2C6CC246DECC10074063B /* SummaryTableViewCellViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SummaryTableViewCellViewModelTests.swift; sourceTree = ""; }; 57F42E3F253768D600EA87F7 /* TitleAndEditableValueTableViewCellViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleAndEditableValueTableViewCellViewModelTests.swift; sourceTree = ""; }; 640DA3472E97DE4F00317FB2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 647C05FA2ED5D9E200E5FF3F /* NotesContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesContent.swift; sourceTree = ""; }; + 647C05FC2ED5E1C000E5FF3F /* BookingNotesRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookingNotesRowView.swift; sourceTree = ""; }; 6489DFFE2EA78E0D00D96802 /* MockProductDetailCoordinatorFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockProductDetailCoordinatorFactory.swift; sourceTree = ""; }; 6489E0002EA78E2D00D96802 /* MockProductDetailCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockProductDetailCoordinator.swift; sourceTree = ""; }; 64D355A42E99048E005F53F7 /* TestingSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingSceneDelegate.swift; sourceTree = ""; }; @@ -7916,6 +7920,7 @@ 2DAC251E2E829FF9008521AF /* Booking Details */ = { isa = PBXGroup; children = ( + 647C05FA2ED5D9E200E5FF3F /* NotesContent.swift */, 2D05E8122E8AADB2004111FD /* PaymentContent.swift */, 2D05E8102E8A98FE004111FD /* CustomerContent.swift */, 2D05E80E2E86BE4F004111FD /* AttendanceContent.swift */, @@ -7941,6 +7946,7 @@ 2DAC2C962E82A169008521AF /* Booking Details */ = { isa = PBXGroup; children = ( + 647C05FC2ED5E1C000E5FF3F /* BookingNotesRowView.swift */, 2D0555802E9693E1004111FD /* HeaderView.swift */, 2D052FB22E9408AF004111FD /* BookingDetailsView+RowTextStyle.swift */, 2D052FB32E9408AF004111FD /* CustomerDetailsView.swift */, @@ -14232,6 +14238,7 @@ EEBA02A52ADD606D001FE8E4 /* BlazeCampaignDashboardViewModel.swift in Sources */, 77E53EB8250E6A4E003D385F /* ProductDownloadListViewController.swift in Sources */, 26CE6F392B7E71AA008DB858 /* ConnectivityTool.swift in Sources */, + 647C05FD2ED5E1C000E5FF3F /* BookingNotesRowView.swift in Sources */, 020EF5EB2A8C7105009D2169 /* SiteSnapshotTracker.swift in Sources */, 029106C02BE3349500C2248B /* OrderCustomerSectionViewModel.swift in Sources */, 74460D4022289B7600D7316A /* Coordinator.swift in Sources */, @@ -14664,6 +14671,7 @@ 26F94E2E267A96A000DB6CCF /* ProductAddOnViewModel.swift in Sources */, 02A9BCD42737DE0D00159C79 /* JetpackBenefitsView.swift in Sources */, EE19058E2B5F747200617C53 /* BlazeAddPaymentMethodWebViewModel.swift in Sources */, + 647C05FB2ED5D9E800E5FF3F /* NotesContent.swift in Sources */, 20D5CB512AFCF856009A39C3 /* PaymentsRow.swift in Sources */, E10459C627BBC22E00C1DCBA /* CardPresentConfigurationLoader.swift in Sources */, B586906621A5F4B1001F1EFC /* UINavigationController+Woo.swift in Sources */,