Skip to content

Commit

Permalink
wip - πŸ€”πŸŽ…
Browse files Browse the repository at this point in the history
  • Loading branch information
erikdstock committed Dec 24, 2023
1 parent 17ac742 commit e510542
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 88 deletions.
140 changes: 69 additions & 71 deletions src/Apps/Order/Routes/Shipping2/Components/AddressModal2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
Banner,
} from "@artsy/palette"

import { Formik, FormikHelpers, FormikProps } from "formik"
import { Form, Formik, FormikHelpers, FormikProps } from "formik"
import { AddressModalFields } from "Components/Address/AddressModalFields"

import {
Expand Down Expand Up @@ -49,6 +49,10 @@ export const AddressModal: React.FC<AddressModalProps> = ({
const [showDialog, setShowDialog] = useState<boolean>(false)
const shippingContext = useShippingContext()

// Formik context from parent form is available via ShippingContext
// ( or useFormikContext<FulfillmentValues>() )
const formikContext = shippingContext.state.formHelpers

const createSavedAddress = useCreateSavedAddress().submitMutation
const deleteSavedAddress = useDeleteSavedAddress().submitMutation
const updateSavedAddress = useUpdateSavedAddress().submitMutation
Expand Down Expand Up @@ -213,78 +217,72 @@ export const AddressModal: React.FC<AddressModalProps> = ({
return (
<>
<ModalDialog title={title} onClose={handleModalClose} width={900}>
<Formik
validateOnMount
initialValues={initialAddress}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{(formik: FormikProps<SavedAddressType>) => (
<form onSubmit={formik.handleSubmit}>
{createUpdateError && (
<Banner my={2} data-testid="form-banner-error" variant="error">
{createUpdateError}
</Banner>
)}

<AddressModalFields />

<Spacer y={2} />

<Input
title="Phone number"
description="Required for shipping logistics"
placeholder="Add phone number"
name="phoneNumber"
type="tel"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.phoneNumber && formik.errors.phoneNumber}
value={formik.values?.phoneNumber || ""}
data-test="phoneInputWithoutValidationFlag"
/>

<Spacer y={2} />

{!initialAddress?.isDefault && (
<Checkbox
onSelect={selected => {
formik.setFieldValue("isDefault", selected)
}}
selected={formik.values?.isDefault}
data-test="setAsDefault"
>
Set as default
</Checkbox>
)}

{modalAction.type === "editUserAddress" && (
<Flex mt={2} flexDirection="column" alignItems="center">
<Clickable
data-test="deleteButton"
onClick={() => setShowDialog(true)}
>
<Text variant="xs" color="red100">
Delete address
</Text>
</Clickable>
</Flex>
)}

<Button
data-test="saveButton"
type="submit"
variant="primaryBlack"
loading={formik.isSubmitting || undefined}
disabled={Object.keys(formik.errors).length > 0}
width="100%"
mt={2}
<Form>
{createUpdateError && (
<Banner my={2} data-testid="form-banner-error" variant="error">
{createUpdateError}
</Banner>
)}

<AddressModalFields />

<Spacer y={2} />

<Input
title="Phone number"
description="Required for shipping logistics"
placeholder="Add phone number"
name="phoneNumber"
type="tel"
onChange={formikContext.handleChange}
onBlur={formikContext.handleBlur}
error={
formikContext.touched.phoneNumber &&
formikContext.errors.phoneNumber
}
value={formikContext.values?.phoneNumber || ""}
data-test="phoneInputWithoutValidationFlag"
/>

<Spacer y={2} />

{!initialAddress?.isDefault && (
<Checkbox
onSelect={selected => {
formikContext.setFieldValue("isDefault", selected)
}}
selected={formikContext.values?.isDefault}
data-test="setAsDefault"
>
Set as default
</Checkbox>
)}

{modalAction.type === "editUserAddress" && (
<Flex mt={2} flexDirection="column" alignItems="center">
<Clickable
data-test="deleteButton"
onClick={() => setShowDialog(true)}
>
Save
</Button>
</form>
<Text variant="xs" color="red100">
Delete address
</Text>
</Clickable>
</Flex>
)}
</Formik>

<Button
data-test="saveButton"
type="submit"
variant="primaryBlack"
loading={formikContext.isSubmitting || undefined}
disabled={Object.keys(formikContext.errors).length > 0}
width="100%"
mt={2}
>
Save
</Button>
</Form>
</ModalDialog>

{showDialog && (
Expand Down
135 changes: 124 additions & 11 deletions src/Apps/Order/Routes/Shipping2/Components/FulfillmentDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { ShippingContextProps } from "Apps/Order/Routes/Shipping2/ShippingContex
import { useHandleUserAddressUpdates } from "Apps/Order/Routes/Shipping2/Hooks/useHandleUserAddressUpdates"
import { useRouter } from "System/Router/useRouter"
import { useOrderTracking } from "Apps/Order/Hooks/useOrderTracking"
import { FormikHelpers } from "formik"

const logger = createLogger("Routes/Shipping2/FulfillmentDetails.tsx")

Expand Down Expand Up @@ -154,6 +155,118 @@ export const FulfillmentDetails: FC<FulfillmentDetailsProps> = ({
setVerifyAddressNow(false)
}

const submitFulfillmentDetailsWithAddressVerificationAndUpdates = async (
values: FulfillmentValues,
helpers: FormikHelpers<FulfillmentValues>
) => {
// Assume the form environment will handle validation. If the nested
// SavedAddress formik context is handling values, the outer form validation
// will not be triggered (Currently by passing an empty validation schema).
// Alternative: Putting all form values in a single context?

// Trigger address verification and return early if appropriate
if (shouldVerifyAddressOnSubmit(values)) {
setVerifyAddressNow(true)
return
}

try {
let fulfillmentMutationValues: CommerceSetShippingInput
let requiresArtsyShippingToDestination: boolean

shippingContext.actions.setIsPerformingOperation(true)

if (values.fulfillmentType === FulfillmentType.PICKUP) {
fulfillmentMutationValues = {
id: orderData.internalID,
fulfillmentType: FulfillmentType.PICKUP,
phoneNumber: values.attributes.phoneNumber,
shipping: {
addressLine1: "",
addressLine2: "",
country: "",
name: "",
city: "",
postalCode: "",
region: "",
phoneNumber: "",
},
}
} else {
requiresArtsyShippingToDestination = shippingContext.orderData.requiresArtsyShippingTo(
values.attributes.country
)

const { phoneNumber, ...addressValues } = values.attributes

// TODO: Ponder, should we be using the same values for the fulfillment mutation
// in all cases, or should we use the result of the user address action if it is
// used? We are assuming the result of the user address action
// will be consistent with the values in the form which seems fair. OTOH the
// result there could include a saved address ID... Seems unumportant for today.

fulfillmentMutationValues = {
id: orderData.internalID,
fulfillmentType: requiresArtsyShippingToDestination
? "SHIP_ARTA"
: FulfillmentType.SHIP,
phoneNumber,
shipping: { ...addressValues, phoneNumber: "" },
}

if (values.meta.addressVerifiedBy) {
fulfillmentMutationValues.addressVerifiedBy =
values.meta.addressVerifiedBy
}

switch (values.meta.savedAddressAction?.action) {
case "edit": {
const userAddressID = values.meta.savedAddressAction.addressID
// Do & await the user update address mutation
break
}
case "create": {
// Do & await the user create address mutation
break
}
default: {
// Do nothing, user address is not persisted
// TODO: Where/does it need to be un-saved? Can we combine that logic with
// the delete address mutation logic from SavedAddresses?
}
}
}
const result = await saveFulfillmentDetails.submitMutation({
variables: { input: fulfillmentMutationValues },
})

const orderOrError = result.commerceSetShipping?.orderOrError

if (orderOrError?.__typename === "CommerceOrderWithMutationFailure") {
shippingContext.actions.setIsPerformingOperation(false)

shippingContext.actions.handleExchangeError(orderOrError.error, logger)
return
}

handleFulfillmentDetailsSaved({
requiresArtsyShipping: requiresArtsyShippingToDestination,
})
} catch (error) {
orderTracking.errorMessageViewed({
error_code: null,
title: "An error occurred",
message:
"Something went wrong. Please try again or contact [email protected].",
flow: "user selects a shipping option",
})

shippingContext.actions.dialog.showErrorDialog()
} finally {
shippingContext.actions.setIsPerformingOperation(false)
}
}

const submitFulfillmentDetails = async ({
performUserAddressUpdates,
formValues,
Expand Down Expand Up @@ -245,17 +358,17 @@ export const FulfillmentDetails: FC<FulfillmentDetailsProps> = ({
}
}

const handleSubmit = values => {
if (shouldVerifyAddressOnSubmit(values)) {
setVerifyAddressNow(true)
return
} else {
return submitFulfillmentDetails({
performUserAddressUpdates: shippingMode === "new_address",
formValues: values,
})
}
}
// const handleSubmit = values => {
// if (shouldVerifyAddressOnSubmit(values)) {
// setVerifyAddressNow(true)
// return
// } else {
// return submitFulfillmentDetails({
// performUserAddressUpdates: shippingMode === "new_address",
// formValues: values,
// })
// }
// }

return (
<FulfillmentDetailsForm
Expand Down
11 changes: 9 additions & 2 deletions src/Apps/Order/Routes/Shipping2/Utils/shippingUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@ export interface PickupValues {

export interface ShipValues {
fulfillmentType: FulfillmentType.SHIP
attributes: ShippingAddressFormValues & {
saveAddress: boolean
attributes: ShippingAddressFormValues
meta: {
savedAddressAction:
| {
action: "edit"
addressID?: string
}
| { action: "create" }
| null
addressVerifiedBy: AddressVerifiedBy | null
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/Apps/Order/Routes/Shipping2/__tests__/Shipping2.jest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ describe("Shipping", () => {
expect(screen.getByTestId("AddressForm_country")).toBeEnabled()
})

it("sets shipping on order, saves address on user and advances to payment", async () => {
it.only("sets shipping on order, saves address on user and advances to payment", async () => {
const { mockResolveLastOperation } = renderWithRelay(
{
CommerceOrder: () => ({ ...order, __id: order.id }),
Expand Down Expand Up @@ -1762,7 +1762,7 @@ describe("Shipping", () => {
})

describe("with saved addresses", () => {
it("re-saves an already-saved shipping address on load to refresh shipping quotes without saving address", async () => {
it.only("re-saves an already-saved shipping address on load to refresh shipping quotes without saving address", async () => {
const { mockResolveLastOperation } = renderWithRelay(
{
CommerceOrder: () => BuyOrderWithArtaShippingDetails,
Expand Down Expand Up @@ -2111,7 +2111,7 @@ describe("Shipping", () => {
})
})

it("selects a different shipping quote and saves it", async () => {
it.only("selects a different shipping quote and saves it", async () => {
const { mockResolveLastOperation } = renderWithRelay(
{
// Simulate the condition with an order with saved shipping quotes
Expand Down
2 changes: 1 addition & 1 deletion src/Apps/Order/Routes/Shipping2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ import { useSelectFirstShippingQuote } from "Apps/Order/Routes/Shipping2/Hooks/u
import { CollapseDetails } from "Apps/Order/Routes/Shipping2/Components/CollapseDetails"

export type ShippingStage =
| "advance_on_click"
| "fulfillment_details"
| "shipping_quotes"
| "advance_on_click"

export interface ShippingProps {
order: Shipping2_order$data
Expand Down

0 comments on commit e510542

Please sign in to comment.