From aa7f9b2483b07bac7085550c8620f4990985e837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miszczyszyn?= Date: Wed, 8 Nov 2023 12:59:36 +0000 Subject: [PATCH 01/11] Fix promo code (#1008) --- .github/workflows/main.yml | 8 +- src/checkout/hooks/useAlerts/consts.ts | 9 --- src/checkout/hooks/useForm/useForm.ts | 75 +------------------ .../sections/Summary/PromoCodeAdd.tsx | 2 +- .../SummaryItemMoneyEditableSection.tsx | 1 + 5 files changed, 9 insertions(+), 86 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 15732d2bd..571f04b6d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,9 +1,5 @@ name: Build, TypeScripts, tests -on: - push: - branches: [canary] - pull_request: - branches: [canary] +on: deployment_status concurrency: group: tests-${{ github.event.pull_request.number || github.ref }} @@ -11,6 +7,8 @@ concurrency: jobs: build_and_test: + if: ${{ github.event.deployment_status.state == 'success' }} + runs-on: ubuntu-latest env: NEXT_PUBLIC_SALEOR_API_URL: https://storefront1.saleor.cloud/graphql/ diff --git a/src/checkout/hooks/useAlerts/consts.ts b/src/checkout/hooks/useAlerts/consts.ts index c9328f817..ad7d1e2c9 100644 --- a/src/checkout/hooks/useAlerts/consts.ts +++ b/src/checkout/hooks/useAlerts/consts.ts @@ -1,13 +1,4 @@ -import clsx from "clsx"; -import { type TypeOptions } from "react-toastify"; - export const alertsContainerProps = { - toastClassName: "rounded shadow-none mb-2 p-0 flex font-sans text-base text-neutral-900 min-h-0 bg-white", - bodyClassName: (data?: { type?: TypeOptions }) => - clsx("flex w-full items-start px-5 py-3", { - ["bg-red-400"]: data?.type === "error", - ["bg-green-400"]: data?.type === "success", - }), autoClose: 4000, hideProgressBar: true, closeButton: () => null, diff --git a/src/checkout/hooks/useForm/useForm.ts b/src/checkout/hooks/useForm/useForm.ts index b6d91ab61..efe6becbf 100644 --- a/src/checkout/hooks/useForm/useForm.ts +++ b/src/checkout/hooks/useForm/useForm.ts @@ -1,78 +1,17 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { useFormik, useFormikContext } from "formik"; -import { isEqual } from "lodash-es"; -import { useCallback, useState } from "react"; import { type ValidationError } from "yup"; -import { - type ChangeHandler, - type FormDataBase, - type FormDataField, - type FormProps, - type UseFormReturn, -} from "@/checkout/hooks/useForm/types"; +import { type FormDataBase, type FormProps, type UseFormReturn } from "@/checkout/hooks/useForm/types"; -export const useForm = ({ - initialDirty = false, - ...formProps -}: FormProps): UseFormReturn => { +export const useForm = (formProps: FormProps) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const { validationSchema } = formProps; // @ts-expect-error because the props we pass and overwrite here don't // always match what formik wants like e.g validateForm const form = useFormik(formProps); - // we do this because in some cases it's not updated properly - // https://github.com/jaredpalmer/formik/issues/3165 - const [dirty, setDirty] = useState(initialDirty); - const [formValues, setFormValues] = useState(formProps.initialValues); - const { - handleSubmit: handleFormikSubmit, - handleChange: formikHandleChange, - setErrors: setFormikErrors, - setFieldValue: setFormikFieldValue, - } = form; - - const handleSubmit = useCallback( - (event?: React.FormEvent) => { - event?.preventDefault(); - - // we do it here because formik doesn't pass props like dirty to onSubmit - if (dirty) { - handleFormikSubmit(event); - } - }, - [dirty, handleFormikSubmit], - ); - - const setValues = useCallback( - (newValues: Partial) => { - const updatedValues = { ...formValues, ...newValues }; - setDirty(!isEqual(formProps.initialValues, updatedValues)); - setFormValues(updatedValues); - }, - [formProps.initialValues, formValues], - ); - - const handleChange: ChangeHandler = useCallback( - (event) => { - const { name, value } = event.target; - - setValues({ [name]: value } as Partial); - - formikHandleChange(event); - }, - [setValues, formikHandleChange], - ); - - const setFieldValue = async (field: FormDataField, value: TData[FormDataField]) => { - if (formValues[field] === value) { - return; - } - - await setFormikFieldValue(field, value); - setFormValues({ ...formValues, [field]: value }); - }; + const { setErrors: setFormikErrors } = form; const validateForm = (values: TData) => { if (!validationSchema) { @@ -103,14 +42,8 @@ export const useForm = ({ return { ...form, - handleSubmit, - handleChange, - values: formValues, - dirty, - setFieldValue, validateForm, - setValues, - }; + } as unknown as UseFormReturn; }; export const useFormContext = useFormikContext; diff --git a/src/checkout/sections/Summary/PromoCodeAdd.tsx b/src/checkout/sections/Summary/PromoCodeAdd.tsx index 8990c5297..e2f14c8b4 100644 --- a/src/checkout/sections/Summary/PromoCodeAdd.tsx +++ b/src/checkout/sections/Summary/PromoCodeAdd.tsx @@ -42,7 +42,7 @@ export const PromoCodeAdd: FC = ({ className }) => { {showApplyButton && ( +
+ + My orders + + +
) : ( diff --git a/src/app/(main)/orders/page.tsx b/src/app/(main)/orders/page.tsx new file mode 100644 index 000000000..6c8d9ad92 --- /dev/null +++ b/src/app/(main)/orders/page.tsx @@ -0,0 +1,11 @@ +"use client"; + +import dynamic from "next/dynamic"; + +const OrderList = dynamic(() => import("../../../ui/components/OrderList").then((m) => m.OrderList), { + ssr: false, +}); + +export default function OrderPage() { + return ; +} diff --git a/src/graphql/CurrentUserOrderList.graphql b/src/graphql/CurrentUserOrderList.graphql new file mode 100644 index 000000000..b1c5d6ce5 --- /dev/null +++ b/src/graphql/CurrentUserOrderList.graphql @@ -0,0 +1,52 @@ +query CurrentUserOrderList { + me { + id + email + firstName + lastName + avatar { + url + alt + } + orders(first: 10) { + edges { + node { + id + number + created + total { + gross { + amount + currency + } + } + lines { + variant { + id + name + product { + id + name + description + slug + thumbnail { + url + alt + } + } + pricing { + price { + gross { + amount + currency + } + } + } + } + quantity + } + } + } + } + } +} diff --git a/src/lib/date.ts b/src/lib/date.ts new file mode 100644 index 000000000..00d8ee798 --- /dev/null +++ b/src/lib/date.ts @@ -0,0 +1 @@ +export const formatDate = (date: Date | number) => new Intl.DateTimeFormat("en-US").format(date); diff --git a/src/ui/components/OrderList.tsx b/src/ui/components/OrderList.tsx new file mode 100644 index 000000000..e26fd87c9 --- /dev/null +++ b/src/ui/components/OrderList.tsx @@ -0,0 +1,108 @@ +"use client"; +import { useQuery } from "urql"; +import Image from "next/image"; +import { CurrentUserOrderListDocument, type CurrentUserOrderListQuery } from "@/gql/graphql"; +import { formatMoney } from "@/lib/graphql"; +import { formatDate } from "@/lib/date"; + +export function OrderList() { + const [{ data, fetching }] = useQuery({ + query: CurrentUserOrderListDocument.toString(), + }); + + if (fetching) { + return
Loading...
; + } + + const user = data?.me; + const email = user?.email; + + if (!email) { + return
User does not have email
; + } + + const orders = user.orders?.edges || []; + + return ( +
+

{user.firstName}’s Orders

+ + {orders.length === 0 ? ( +
+
+
No orders found
+
+
+ ) : ( +
    + {orders.map( + ({ node: order }) => + order.id && + order.created && ( +
  • +
    +
    +
    +
    Order number
    +
    {order.number}
    +
    +
    +
    Date placed
    +
    + +
    +
    +
    +
    Total amount
    +
    + {order.total && formatMoney(order.total.gross.amount, order.total.gross.currency)} +
    +
    +
    +
    + + {order.lines && ( +
      + {order.lines.map((item) => { + const product = item.variant?.product; + + if (product) { + return ( + product.id && ( +
    • +
      +
      + {product.thumbnail?.url && ( + image + )} +
      +
      +

      + {product.name} +

      +
      +
      +
    • + ) + ); + } + })} +
    + )} +
  • + ), + )} +
+ )} +
+ ); +} diff --git a/src/ui/components/UserCard.tsx b/src/ui/components/UserCard.tsx index 3d85fe6d9..708e9a53b 100644 --- a/src/ui/components/UserCard.tsx +++ b/src/ui/components/UserCard.tsx @@ -2,7 +2,7 @@ import Image from "next/image"; export const UserCard = ({ user }: { user: { email: string; avatarURL?: string } }) => { return ( -
+
{user.avatarURL && ( { return ( -