Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a package UI - Add package name text field #14086

Open
wants to merge 22 commits into
base: trunk
Choose a base branch
from

Conversation

bozidarsevo
Copy link
Contributor

@bozidarsevo bozidarsevo commented Oct 1, 2024

Part of #13551

Description

  • Added package name text field in "Custom" package tab when toggle "save this as a new package template" is ON.
  • Added basic field validation, fields need to be non empty for buttons to be enabled.

Features remaining for the "Custom" tab:

  • Saving package template logic
  • Add package - gather all info from fields and using it for the package
  • Use measure type that we got from backend (centimeters, inches etc.)

Features remaining for the "Carrier" tab:

  • all

Features remaining for the "Saved" tab:

  • all

Rest of the functionalities will be done in separate stacked PRs (done on top of this branch or trunk if this gets merged before).

Testing information

  1. Install and set up the Woo Shipping extension on your store.
  2. Build and run the app with the revampedShippingLabelCreation feature flag enabled.
  3. Create an order with the processing status and at least one physical product.
  4. In the order details, select "Create Shipping Label."
  5. Tap "Select a Package" button
  6. Tap on the package type button to change the type
  7. Tap in length, width and height fields to input values and check that the "Add Package" button is enabled when all 3 values are entered
  8. Toggle "save this as a new package template" ON and "Save package template" button will show with text field for name above it.
  9. Type some text in the text field
  10. "Save package template" should be enabled when all dimension fields are non empty and text field for package name is non empty.

Screenshots

Simulator.Screen.Recording.-.iPhone.16.Pro.-.2024-10-16.at.11.26.10.mp4

  • I have considered if this change warrants user-facing release notes and have added them to RELEASE-NOTES.txt if necessary.

Reviewer (or Author, in the case of optional code reviews):

Please make sure these conditions are met before approving the PR, or request changes if the PR needs improvement:

  • The PR is small and has a clear, single focus, or a valid explanation is provided in the description. If needed, please request to split it into smaller PRs.
  • Ensure Adequate Unit Test Coverage: The changes are reasonably covered by unit tests or an explanation is provided in the PR description.
  • Manual Testing: The author listed all the tests they ran, including smoke tests when needed (e.g., for refactorings). The reviewer confirmed that the PR works as expected on all devices (phone/tablet) and no regressions are added.

@bozidarsevo bozidarsevo added the feature: shipping labels Related to creating, ordering, or printing shipping labels. label Oct 1, 2024
@bozidarsevo bozidarsevo added this to the 20.7 milestone Oct 1, 2024
@dangermattic
Copy link
Collaborator

dangermattic commented Oct 1, 2024

2 Warnings
⚠️ View files have been modified, but no screenshot or video is included in the pull request. Consider adding some for clarity.
⚠️ This PR is larger than 300 lines of changes. Please consider splitting it into smaller PRs for easier and faster reviews.

Generated by 🚫 Danger

@bozidarsevo bozidarsevo marked this pull request as ready for review October 1, 2024 12:51
@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Oct 1, 2024

WooCommerce iOS📲 You can test the changes from this Pull Request in WooCommerce iOS by scanning the QR code below to install the corresponding build.

App NameWooCommerce iOS WooCommerce iOS
Build Numberpr14086-9be5b28
Version20.8
Bundle IDcom.automattic.alpha.woocommerce
Commit9be5b28
App Center BuildWooCommerce - Prototype Builds #11196
Automatticians: You can use our internal self-serve MC tool to give yourself access to App Center if needed.

Base automatically changed from issue/13551-add-package-ui-custom-package-scaffolding to trunk October 2, 2024 08:55
@wpmobilebot wpmobilebot modified the milestones: 20.7, 20.8 Oct 11, 2024
@wpmobilebot
Copy link
Collaborator

Version 20.7 has now entered code-freeze, so the milestone of this PR has been updated to 20.8.

@rachelmcr rachelmcr self-assigned this Oct 17, 2024
Copy link
Contributor

@rachelmcr rachelmcr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good and work well in testing! I just have some suggestions below, primarily around what's included in the view model + unit testing.

@@ -1,5 +1,22 @@
import SwiftUI

final class WooShippingAddPackageViewModel: ObservableObject {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add unit tests for this view model? Not sure if you have that planned as a separate task.

Also, a small thing, but we usually add the view model as a separate file. Not a huge deal at this stage but it will likely help as we expand it to include more logic e.g. network calls.

Comment on lines 56 to 62
// Holds type of selected package, it can be `custom`, `carrier` or `saved`
@State var selectedPackageType = PackageProviderType.custom
var addPackageButtonDisabled: Bool {
for (_, value) in fieldValues {
if value.isEmpty {
return true
}
}
return fieldValues.count != WooShippingAddPackageDimensionView.DimensionType.allCases.count
}
// Holds selected package type when custom package is selected, it can be `box` or `envelope`
@State var packageType: PackageType = .box
// Holds value for toggle that determines if we are showing button for saving the template
@State var showSaveTemplate: Bool = false
@State var packageTemplateName: String = ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about moving these to the view model, as well? It could be helpful for unit testing, and for handling the values e.g. for packageType and packageTemplateName in network calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was planning to but left it here in case I change something, but will move it! 👍

Text(Localization.saveNewPackageTemplate)
.font(.subheadline)
}
.tint(Color(.withColorStudio(.wooCommercePurple, shade: .shade60)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest using the semantic color Color(.primary) or Color(.accent) here (and elsewhere in this view). That makes it easier to adjust later if we update the app colors, and it adjusts the color in dark mode to fit our usual dark mode theme.

Comment on lines 268 to 287
// MARK: - actions

private func validateCustomPackageInputFields() -> Bool {
guard !customPackageViewModel.areFieldValuesInvalid else {
return false
}
if showSaveTemplate {
return !packageTemplateName.isEmpty
}
return true
}

private func addPackageButtonTapped() {
// TODO: implement adding a package
guard validateCustomPackageInputFields() else { return }
}

private func savePackageAsTemplateButtonTapped() {
// TODO: implement saving package as a template
guard validateCustomPackageInputFields() else { return }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest putting actions like these in the view model, so we can unit test them.

Comment on lines 200 to 201
.onChange(of: showSaveTemplate) { newValue in
packageTemplateNameFieldFocused = newValue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we should also reset packageTemplateName to an empty string when this is toggled? It feels a little odd that any text entered there is retained if I toggle this off and on again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can reset it but I am thinking what would be the least bad case:

  • user enters a name, accidentally toggles it off, toggles it back on and the text is cleared (user needs to enter text again)
  • user enters a name, toggles it off on purpose, toggles it back on and sees the last entered text (user can save with that name or change it) - my preference

I would prefer that the string is kept until the template is saved, and then we reset it. But we can see when we test it with more people what feels better?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good point, that's a fair concern.

But we can see when we test it with more people what feels better?

Sounds good!

}))
.onChange(of: packageTemplateNameFieldFocused) { focused in
if focused {
DispatchQueue.main.asyncAfter(deadline: .now() + Constants.scrollToDelay, execute: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reasoning behind the delay for this scroll action? It feels fine in testing, I'm just curious if it's needed for some reason or if it's just for the feel.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When text field for name gets focused (packageTemplateNameFieldFocused changed) the SwiftUI automatically scrolls so that text field is visible, but the save button is not, and if I do not do the scrolling to button with a small delay this is basically called in paralel as scrolling to text field so save button is overlayed a bit with keyboard.
This is how it goes without a delay (half of the button is visible):

Simulator.Screen.Recording.-.iPhone.16.Pro.-.2024-10-18.at.09.45.17.mp4

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah, that makes sense. Thanks for the explanation! Maybe it's worth a small note in the code about that so that later on we remember why it's needed?

@wpmobilebot wpmobilebot modified the milestones: 20.8, 20.9 Oct 18, 2024
@wpmobilebot
Copy link
Collaborator

Version 20.8 has now entered code-freeze, so the milestone of this PR has been updated to 20.9.

Copy link
Contributor

@rachelmcr rachelmcr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great and continues to test well. 👍 I have a few minor questions below, mainly about the unit tests, but nothing blocking.

Also this is something to deal with later, maybe after checking with design, but I noticed that the screen isn't really usable in landscape mode. Just sharing it now since I just saw this:

Simulator Screenshot - iPhone 15 Pro - 2024-10-18 at 16 37 01

Simulator Screenshot - iPhone 15 Pro - 2024-10-18 at 16 39 02

let viewModel = WooShippingAddCustomPackageViewModel()

// When
viewModel.clearFieldValues()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that it inits with empty field values, how about entering some values (e.g. the viewModel.fillWithDummyFieldValues() method you use below) before clearing them in this test?

let viewModel = WooShippingAddCustomPackageViewModel()

// When
viewModel.clearFieldValues()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need this step in the test? If it inits with empty fields I'd think we could skip this and just do:

// When
viewModel.fieldValues[.height] = "1"

let viewModel = WooShippingAddCustomPackageViewModel()

// When
viewModel.clearFieldValues()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, do you need this step in these tests?

Comment on lines +28 to +32
func resetValues() {
clearFieldValues()
showSaveTemplate = false
packageTemplateName = ""
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this also reset the packageType to .box? I could see it going either way (remembering the previously used package type or resetting it), but just asking because I noticed that if I select the envelope type that isn't reset.

@rachelmcr rachelmcr removed their assignment Oct 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature: shipping labels Related to creating, ordering, or printing shipping labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants