@graphcommerce/magento-customer 9.0.0-canary.60 → 9.0.0-canary.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Change Log
2
2
 
3
+ ## 9.0.0-canary.61
4
+
5
+ ### Minor Changes
6
+
7
+ - [#2327](https://github.com/graphcommerce-org/graphcommerce/pull/2327) [`be719fc`](https://github.com/graphcommerce-org/graphcommerce/commit/be719fc465c8804ddcb720a93813262e3a292b69) - Implement CancelOrder mutation, add cancel order overlay to account section ([@Giovanni-Schroevers](https://github.com/Giovanni-Schroevers))
8
+
9
+ - [#2327](https://github.com/graphcommerce-org/graphcommerce/pull/2327) [`af83d81`](https://github.com/graphcommerce-org/graphcommerce/commit/af83d81656a4c1a014802fb052a94a079e9f60c1) - Add reorderItems mutation, add reorder button to order detail page ([@Giovanni-Schroevers](https://github.com/Giovanni-Schroevers))
10
+
3
11
  ## 9.0.0-canary.60
4
12
 
5
13
  ## 9.0.0-canary.59
@@ -0,0 +1,12 @@
1
+ mutation CancelOrder($orderId: ID!, $reason: String!) {
2
+ cancelOrder(input: { order_id: $orderId, reason: $reason }) {
3
+ error
4
+ order {
5
+ ...OrderDetails
6
+ ...OrderItems
7
+ shipments {
8
+ number
9
+ }
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,160 @@
1
+ import { ApolloErrorSnackbar, CheckboxElement, SelectElement } from '@graphcommerce/ecommerce-ui'
2
+ import {
3
+ breakpointVal,
4
+ Button,
5
+ filterNonNullableKeys,
6
+ FormRow,
7
+ iconChevronDown,
8
+ IconSvg,
9
+ } from '@graphcommerce/next-ui'
10
+ import { useFormGqlMutation } from '@graphcommerce/react-hook-form'
11
+ import { Trans } from '@lingui/macro'
12
+ import {
13
+ Accordion,
14
+ AccordionDetails,
15
+ AccordionProps,
16
+ AccordionSummary,
17
+ Alert,
18
+ Box,
19
+ } from '@mui/material'
20
+ import {
21
+ CancelOrderDocument,
22
+ CancelOrderMutation,
23
+ CancelOrderMutationVariables,
24
+ } from './CancelOrder.gql'
25
+ import { OrderDetailsFragment } from '../OrderDetails/OrderDetails.gql'
26
+ import { useQuery } from '@graphcommerce/graphql'
27
+ import { StoreConfigDocument } from '@graphcommerce/magento-store'
28
+ import { canCancelOrder } from '../../utils'
29
+
30
+ type CancelOrderFormProps = {
31
+ order: OrderDetailsFragment
32
+ } & Omit<AccordionProps, 'children'>
33
+
34
+ export function CancelOrderForm(props: CancelOrderFormProps) {
35
+ const { order, sx, ...rest } = props
36
+ const { id: orderId, number: orderNumber } = order
37
+
38
+ const form = useFormGqlMutation<
39
+ CancelOrderMutation,
40
+ CancelOrderMutationVariables & { confirm: boolean }
41
+ >(CancelOrderDocument, { defaultValues: { orderId: atob(orderId) } })
42
+
43
+ const options = useQuery(StoreConfigDocument).data?.storeConfig?.order_cancellation_reasons
44
+
45
+ const { control, formState, required, handleSubmit, error, data: cancelOrderData } = form
46
+
47
+ const submitHandler = handleSubmit(() => {})
48
+
49
+ const submittedWithoutErrors =
50
+ formState.isSubmitSuccessful && !error && !cancelOrderData?.cancelOrder?.error
51
+
52
+ const visible = canCancelOrder(order) || submittedWithoutErrors
53
+
54
+ if (!visible) return null
55
+
56
+ if (submittedWithoutErrors)
57
+ return (
58
+ <Alert sx={(theme) => ({ mb: theme.spacings.xxl })}>
59
+ <Trans>Order has successfully been canceled</Trans>
60
+ </Alert>
61
+ )
62
+
63
+ return (
64
+ <Accordion
65
+ sx={[
66
+ (theme) => ({
67
+ mb: theme.spacings.xxl,
68
+ ...breakpointVal(
69
+ 'borderRadius',
70
+ theme.shape.borderRadius * 2,
71
+ theme.shape.borderRadius * 3,
72
+ theme.breakpoints.values,
73
+ ),
74
+ '::before': { display: 'none' },
75
+ '&.Mui-expanded:last-of-type': {
76
+ mb: theme.spacings.xxl,
77
+ },
78
+ }),
79
+ ...(Array.isArray(sx) ? sx : [sx]),
80
+ ]}
81
+ {...rest}
82
+ >
83
+ <AccordionSummary
84
+ expandIcon={<IconSvg src={iconChevronDown} />}
85
+ sx={[
86
+ (theme) => ({
87
+ px: theme.spacings.xs,
88
+ '& .MuiAccordionSummary-content': {
89
+ alignItems: 'center',
90
+ columnGap: 2,
91
+ justifyContent: 'space-between',
92
+ },
93
+ }),
94
+ ]}
95
+ >
96
+ <Trans>Cancel order</Trans>
97
+ </AccordionSummary>
98
+ <AccordionDetails sx={(theme) => ({ px: theme.spacings.xs, py: 0 })}>
99
+ <Box component='form' onSubmit={submitHandler} noValidate>
100
+ <FormRow>
101
+ <SelectElement
102
+ control={control}
103
+ name='reason'
104
+ label={<Trans>Reason</Trans>}
105
+ required={required.reason}
106
+ disabled={formState.isSubmitting || submittedWithoutErrors}
107
+ options={filterNonNullableKeys(options)?.map(({ description }) => ({
108
+ id: description,
109
+ label: description,
110
+ }))}
111
+ />
112
+ </FormRow>
113
+
114
+ <CheckboxElement
115
+ required
116
+ control={control}
117
+ name='confirm'
118
+ color='error'
119
+ label={
120
+ <Trans>I understand that my order will be canceled and this can not be undone.</Trans>
121
+ }
122
+ />
123
+
124
+ {submittedWithoutErrors && (
125
+ <Alert>
126
+ <Trans>Order has successfully been canceled</Trans>
127
+ </Alert>
128
+ )}
129
+
130
+ {cancelOrderData?.cancelOrder?.error && (
131
+ <Alert severity='error'>{cancelOrderData?.cancelOrder?.error}</Alert>
132
+ )}
133
+
134
+ <ApolloErrorSnackbar error={error} />
135
+
136
+ <FormRow
137
+ sx={(theme) => ({
138
+ justifyContent: 'center',
139
+ justifyItems: 'start',
140
+ gridAutoFlow: 'column',
141
+ gap: theme.spacings.sm,
142
+ })}
143
+ >
144
+ <Button
145
+ type='submit'
146
+ variant='pill'
147
+ color='error'
148
+ loading={formState.isSubmitting}
149
+ disabled={submittedWithoutErrors}
150
+ size='large'
151
+ sx={{ color: 'white', bgcolor: 'error.main' }}
152
+ >
153
+ <Trans>Cancel order</Trans>
154
+ </Button>
155
+ </FormRow>
156
+ </Box>
157
+ </AccordionDetails>
158
+ </Accordion>
159
+ )
160
+ }
@@ -1,10 +1,12 @@
1
1
  fragment OrderCard on CustomerOrder {
2
2
  number
3
3
  shipments {
4
+ id
4
5
  tracking {
5
6
  ...TrackingLink
6
7
  }
7
8
  }
9
+
8
10
  total {
9
11
  grand_total {
10
12
  ...Money
@@ -15,4 +17,13 @@ fragment OrderCard on CustomerOrder {
15
17
  }
16
18
  ...OrderStateLabel
17
19
  order_date
20
+ shipping_address {
21
+ city
22
+ postcode
23
+ firstname
24
+ lastname
25
+ street
26
+ country_code
27
+ region_id
28
+ }
18
29
  }
@@ -73,7 +73,7 @@ export function OrderCard(props: OrderCardProps) {
73
73
 
74
74
  return (
75
75
  <ListItemButton
76
- href={`/account/orders/view?orderId=${number}`}
76
+ href={`/account/orders/view?orderNumber=${number}`}
77
77
  component={NextLink}
78
78
  className={classes.buttonRoot}
79
79
  sx={[
@@ -96,7 +96,7 @@ export function OrderCard(props: OrderCardProps) {
96
96
  <span>#{number}</span>
97
97
  </OrderRow>
98
98
  <OrderRow>
99
- <OrderStateLabel items={items} />
99
+ <OrderStateLabel {...props} />
100
100
  </OrderRow>
101
101
  <Box className={classes.orderProducts}>
102
102
  <Box
@@ -1,6 +1,8 @@
1
1
  fragment OrderDetails on CustomerOrder {
2
+ id
2
3
  number
3
4
  order_date
5
+ status
4
6
  invoices {
5
7
  id
6
8
  number
@@ -9,9 +11,7 @@ fragment OrderDetails on CustomerOrder {
9
11
  shipments {
10
12
  id
11
13
  tracking {
12
- title
13
- carrier
14
- number
14
+ ...TrackingLink
15
15
  }
16
16
  }
17
17
  payment_methods {
@@ -6,7 +6,7 @@ import {
6
6
  breakpointVal,
7
7
  DateTimeFormat,
8
8
  } from '@graphcommerce/next-ui'
9
- import { Trans } from '@lingui/react'
9
+ import { Trans } from '@lingui/macro'
10
10
  import { Box, SxProps, Theme, Typography, lighten } from '@mui/material'
11
11
  import { AddressMultiLine } from '../AddressMultiLine/AddressMultiLine'
12
12
  import { TrackingLink } from '../TrackingLink/TrackingLink'
@@ -41,7 +41,7 @@ export function OrderDetails(props: OrderDetailsProps) {
41
41
 
42
42
  return (
43
43
  <SectionContainer
44
- labelLeft={<Trans id='Order details' />}
44
+ labelLeft={<Trans>Order details</Trans>}
45
45
  sx={[
46
46
  (theme) => ({
47
47
  padding: theme.spacings.sm,
@@ -82,7 +82,7 @@ export function OrderDetails(props: OrderDetailsProps) {
82
82
  <Box className={classes.orderDetailRow}>
83
83
  <SectionContainer
84
84
  variantLeft='h5'
85
- labelLeft={<Trans id='Order number' />}
85
+ labelLeft={<Trans>Order number</Trans>}
86
86
  className={classes.orderDetailTitle}
87
87
  sx={{ '& .SectionHeader-root': { marginTop: 0, paddingBottom: '4px' } }}
88
88
  >
@@ -93,7 +93,7 @@ export function OrderDetails(props: OrderDetailsProps) {
93
93
  <Box className={classes.orderDetailRow}>
94
94
  <SectionContainer
95
95
  variantLeft='h5'
96
- labelLeft={<Trans id='Order date' />}
96
+ labelLeft={<Trans>Order date</Trans>}
97
97
  className={classes.orderDetailTitle}
98
98
  sx={{ '& .SectionHeader-root': { marginTop: 0, paddingBottom: '4px' } }}
99
99
  >
@@ -104,7 +104,7 @@ export function OrderDetails(props: OrderDetailsProps) {
104
104
  <Box className={classes.orderDetailRow}>
105
105
  <SectionContainer
106
106
  variantLeft='h5'
107
- labelLeft={<Trans id='Shipping method' />}
107
+ labelLeft={<Trans>Shipping method</Trans>}
108
108
  className={classes.orderDetailTitle}
109
109
  sx={{ '& .SectionHeader-root': { marginTop: 0, paddingBottom: '4px' } }}
110
110
  >
@@ -124,13 +124,13 @@ export function OrderDetails(props: OrderDetailsProps) {
124
124
  <Box className={classes.orderDetailRow}>
125
125
  <SectionContainer
126
126
  variantLeft='h5'
127
- labelLeft={<Trans id='Payment method' />}
127
+ labelLeft={<Trans>Payment method</Trans>}
128
128
  className={classes.orderDetailTitle}
129
129
  sx={{ '& .SectionHeader-root': { marginTop: 0, paddingBottom: '4px' } }}
130
130
  >
131
131
  {payment_methods && payment_methods.length < 1 && (
132
132
  <Typography>
133
- <Trans id='No payment information' />
133
+ <Trans>No payment information</Trans>
134
134
  </Typography>
135
135
  )}
136
136
 
@@ -158,7 +158,7 @@ export function OrderDetails(props: OrderDetailsProps) {
158
158
  <Box className={classes.orderDetailRow}>
159
159
  <SectionContainer
160
160
  variantLeft='h5'
161
- labelLeft={<Trans id='Shipping address' />}
161
+ labelLeft={<Trans>Shipping address</Trans>}
162
162
  className={classes.orderDetailTitle}
163
163
  sx={{ '& .SectionHeader-root': { marginTop: 0, paddingBottom: '4px' } }}
164
164
  >
@@ -169,7 +169,7 @@ export function OrderDetails(props: OrderDetailsProps) {
169
169
  <Box className={classes.orderDetailRow}>
170
170
  <SectionContainer
171
171
  variantLeft='h5'
172
- labelLeft={<Trans id='Billing address' />}
172
+ labelLeft={<Trans>Billing address</Trans>}
173
173
  className={classes.orderDetailTitle}
174
174
  sx={{ '& .SectionHeader-root': { marginTop: 0, paddingBottom: '4px' } }}
175
175
  >
@@ -1,9 +1,6 @@
1
1
  import { Image } from '@graphcommerce/image'
2
2
  // eslint-disable-next-line import/no-extraneous-dependencies
3
- import {
4
- useProductLink,
5
- ProductLinkProps,
6
- } from '@graphcommerce/magento-product/hooks/useProductLink'
3
+ import { useProductLink } from '@graphcommerce/magento-product/hooks/useProductLink'
7
4
  import { Money } from '@graphcommerce/magento-store'
8
5
  import { responsiveVal, extendableComponent, NextLink } from '@graphcommerce/next-ui'
9
6
  import { Box } from '@mui/material'
@@ -1,4 +1,6 @@
1
1
  fragment OrderItems on CustomerOrder {
2
+ id
3
+ number
2
4
  items {
3
5
  ...OrderItem
4
6
  }
@@ -1,18 +1,9 @@
1
1
  import { extendableComponent } from '@graphcommerce/next-ui'
2
2
  import { Trans } from '@lingui/react'
3
3
  import { Box, SxProps, Theme } from '@mui/material'
4
- import { OrderStateLabelFragment } from './OrderStateLabel.gql'
4
+ import { OrderStateProps, OrderState, getOrderState } from '../../utils'
5
5
 
6
- type OrderState =
7
- | 'Ordered'
8
- | 'Invoiced'
9
- | 'Shipped'
10
- | 'Refunded'
11
- | 'Canceled'
12
- | 'Returned'
13
- | 'Partial'
14
-
15
- type OrderStateLabelPropsBase = OrderStateLabelFragment
6
+ type OrderStateLabelPropsBase = OrderStateProps
16
7
 
17
8
  export type OrderStateRenderer = Record<
18
9
  OrderState,
@@ -36,12 +27,12 @@ const { withState } = extendableComponent<OwnerState, typeof componentName, type
36
27
 
37
28
  const defaultRenderer: OrderStateRenderer = {
38
29
  Ordered: () => <Trans id='Your order is being processed' />,
39
- Invoiced: () => <Trans id='Your order has been invoiced' />,
40
- Shipped: () => <Trans id='Your order is on its way!' />,
30
+ Processing: () => <Trans id='Your order has been invoiced' />,
31
+ Closed: () => <Trans id='Your order is on its way!' />,
41
32
  Refunded: () => <Trans id='Your order has been refunded' />,
42
33
  Canceled: () => <Trans id='Your order has been canceled' />,
43
34
  Returned: () => <Trans id='Your order has been returned' />,
44
- Partial: () => <Trans id='Your order has been partially processed' />,
35
+ Pending: () => <Trans id='Your order has been partially processed' />,
45
36
  }
46
37
 
47
38
  export function OrderStateLabel(props: OrderStateLabelProps) {
@@ -49,17 +40,7 @@ export function OrderStateLabel(props: OrderStateLabelProps) {
49
40
 
50
41
  const renderer: OrderStateRenderer = { ...defaultRenderer, ...incomingRenderer }
51
42
 
52
- let orderState: OrderState = 'Partial'
53
- if (items?.every((item) => item?.quantity_ordered === item?.quantity_invoiced))
54
- orderState = 'Invoiced'
55
- if (items?.every((item) => item?.quantity_ordered === item?.quantity_shipped))
56
- orderState = 'Shipped'
57
- if (items?.every((item) => item?.quantity_ordered === item?.quantity_refunded))
58
- orderState = 'Refunded'
59
- if (items?.every((item) => item?.quantity_ordered === item?.quantity_canceled))
60
- orderState = 'Canceled'
61
- if (items?.every((item) => item?.quantity_ordered === item?.quantity_returned))
62
- orderState = 'Returned'
43
+ const orderState = getOrderState(props)
63
44
 
64
45
  const StateLabel = renderer[orderState]
65
46
 
@@ -76,13 +57,13 @@ export function OrderStateLabel(props: OrderStateLabelProps) {
76
57
  '&.orderStateOrdered': {
77
58
  color: theme.palette.secondary.main,
78
59
  },
79
- '&.orderStateInvoiced': {
60
+ '&.orderStateProcessing': {
80
61
  color: theme.palette.secondary.main,
81
62
  },
82
63
  '&.orderStateRefunded': {
83
64
  color: theme.palette.primary.main,
84
65
  },
85
- '&.orderStateShipped': {
66
+ '&.orderStateClosed': {
86
67
  color: theme.palette.success.main,
87
68
  fontStyle: 'normal',
88
69
  fontWeight: 600,
@@ -93,7 +74,7 @@ export function OrderStateLabel(props: OrderStateLabelProps) {
93
74
  '&.orderStateReturned': {
94
75
  color: theme.palette.secondary.main,
95
76
  },
96
- '&.orderStatePartial': {
77
+ '&.orderStatePending': {
97
78
  color: theme.palette.secondary.main,
98
79
  },
99
80
  }),
@@ -5,12 +5,12 @@ type OrderStateLabelInlineProps = OrderStateLabelProps
5
5
 
6
6
  const defaultRenderer: OrderStateRenderer = {
7
7
  Ordered: () => <Trans id='processed' />,
8
- Invoiced: () => <Trans id='invoiced' />,
9
- Shipped: () => <Trans id='shipped' />,
8
+ Processing: () => <Trans id='invoiced' />,
9
+ Closed: () => <Trans id='shipped' />,
10
10
  Refunded: () => <Trans id='refunded' />,
11
11
  Canceled: () => <Trans id='canceled' />,
12
12
  Returned: () => <Trans id='returned' />,
13
- Partial: () => <Trans id='partially processed' />,
13
+ Pending: () => <Trans id='partially processed' />,
14
14
  }
15
15
 
16
16
  export function OrderStateLabelInline(props: OrderStateLabelInlineProps) {
@@ -34,7 +34,7 @@ export function OrderStateLabelInline(props: OrderStateLabelInlineProps) {
34
34
  color: theme.palette.primary.main,
35
35
  background: `${theme.palette.primary.main}20`,
36
36
  },
37
- '&.orderStateShipped': {
37
+ '&.orderStateClosed': {
38
38
  color: theme.palette.success.main,
39
39
  fontWeight: 'normal',
40
40
  background: `${theme.palette.success.main}20`,
@@ -0,0 +1,11 @@
1
+ mutation ReorderItems($orderNumber: String!) {
2
+ reorderItems(orderNumber: $orderNumber) {
3
+ cart {
4
+ ...CartItemCountChanged
5
+ }
6
+ userInputErrors {
7
+ code
8
+ message
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,47 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+ import { AddProductsToCartSnackbarMessage } from '@graphcommerce/magento-product/components/AddProductsToCart/AddProductsToCartSnackbarMessage'
3
+ import { iconChevronRight, IconSvg, LinkOrButton, nonNullable } from '@graphcommerce/next-ui'
4
+ import { useFormGqlMutation } from '@graphcommerce/react-hook-form'
5
+ import { Trans } from '@lingui/macro'
6
+ import { Box } from '@mui/material'
7
+ import { OrderItemsFragment } from '../OrderItems/OrderItems.gql'
8
+ import { ReorderItemsDocument } from './ReorderItems.gql'
9
+
10
+ export type ReorderItemsProps = { order: OrderItemsFragment }
11
+
12
+ export function ReorderItems(props: ReorderItemsProps) {
13
+ const { order } = props
14
+
15
+ const form = useFormGqlMutation(ReorderItemsDocument, {
16
+ defaultValues: { orderNumber: order.number },
17
+ })
18
+ const { formState, handleSubmit, error, data: cartData } = form
19
+ const submitHandler = handleSubmit(() => {})
20
+
21
+ const errors = cartData?.reorderItems?.userInputErrors
22
+ const cart = cartData?.reorderItems?.cart
23
+
24
+ if (!order.items) return null
25
+
26
+ return (
27
+ <Box component='form' onSubmit={submitHandler}>
28
+ <LinkOrButton
29
+ color='secondary'
30
+ button={{ variant: 'pill', sx: { whiteSpace: 'nowrap' } }}
31
+ link={{ whiteSpace: 'nowrap' }}
32
+ type='submit'
33
+ loading={formState.isSubmitting}
34
+ endIcon={<IconSvg src={iconChevronRight} />}
35
+ >
36
+ <Trans>Reorder</Trans>
37
+ </LinkOrButton>
38
+
39
+ <AddProductsToCartSnackbarMessage
40
+ addedItems={order.items.map((item) => item?.product_name).filter(nonNullable)}
41
+ error={error}
42
+ userErrors={errors?.filter(nonNullable)}
43
+ showSuccess={!!cart}
44
+ />
45
+ </Box>
46
+ )
47
+ }
@@ -11,6 +11,7 @@ export * from './AddressFields'
11
11
  export * from './AddressMultiLine/AddressMultiLine'
12
12
  export * from './AddressSingleLine/AddressSingleLine'
13
13
  export * from './ApolloCustomerError'
14
+ export * from './CancelOrder/CancelOrderForm'
14
15
  export * from './ChangeNameForm/ChangeNameForm'
15
16
  export * from './ChangePasswordForm/ChangePassword.gql'
16
17
  export * from './ChangePasswordForm/ChangePasswordForm'
@@ -36,6 +37,7 @@ export * from './OrderItem/OrderItem'
36
37
  export * from './OrderItems/OrderItems'
37
38
  export * from './OrderStateLabel/OrderStateLabel'
38
39
  export * from './OrderStateLabel/OrderStateLabelInline'
40
+ export * from './ReorderItems/ReorderItems'
39
41
  export * from './ResetPasswordForm/ResetPasswordForm'
40
42
  export * from './SignInForm/SignIn.gql'
41
43
  export * from './SignInForm/SignInForm'
package/index.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export * from './components'
2
- export * from './hooks'
3
- export * from './typePolicies'
4
- export * from './graphql/AccountDashboardOrders.gql'
5
- export * from './graphql/AccountDashboardAddresses.gql'
6
2
  export * from './graphql/AccountDashboard.gql'
3
+ export * from './graphql/AccountDashboardAddresses.gql'
4
+ export * from './graphql/AccountDashboardOrders.gql'
7
5
  export * from './graphql/OrderDetailPage.gql'
6
+ export * from './hooks'
7
+ export * from './typePolicies'
8
+ export * from './utils'
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/magento-customer",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "9.0.0-canary.60",
5
+ "version": "9.0.0-canary.61",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -12,19 +12,19 @@
12
12
  }
13
13
  },
14
14
  "peerDependencies": {
15
- "@graphcommerce/ecommerce-ui": "^9.0.0-canary.60",
16
- "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.60",
17
- "@graphcommerce/framer-next-pages": "^9.0.0-canary.60",
18
- "@graphcommerce/framer-utils": "^9.0.0-canary.60",
19
- "@graphcommerce/graphql": "^9.0.0-canary.60",
20
- "@graphcommerce/graphql-mesh": "^9.0.0-canary.60",
21
- "@graphcommerce/image": "^9.0.0-canary.60",
22
- "@graphcommerce/magento-graphql": "^9.0.0-canary.60",
23
- "@graphcommerce/magento-store": "^9.0.0-canary.60",
24
- "@graphcommerce/next-ui": "^9.0.0-canary.60",
25
- "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.60",
26
- "@graphcommerce/react-hook-form": "^9.0.0-canary.60",
27
- "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.60",
15
+ "@graphcommerce/ecommerce-ui": "^9.0.0-canary.61",
16
+ "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.61",
17
+ "@graphcommerce/framer-next-pages": "^9.0.0-canary.61",
18
+ "@graphcommerce/framer-utils": "^9.0.0-canary.61",
19
+ "@graphcommerce/graphql": "^9.0.0-canary.61",
20
+ "@graphcommerce/graphql-mesh": "^9.0.0-canary.61",
21
+ "@graphcommerce/image": "^9.0.0-canary.61",
22
+ "@graphcommerce/magento-graphql": "^9.0.0-canary.61",
23
+ "@graphcommerce/magento-store": "^9.0.0-canary.61",
24
+ "@graphcommerce/next-ui": "^9.0.0-canary.61",
25
+ "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.61",
26
+ "@graphcommerce/react-hook-form": "^9.0.0-canary.61",
27
+ "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.61",
28
28
  "@lingui/core": "^4.2.1",
29
29
  "@lingui/macro": "^4.2.1",
30
30
  "@lingui/react": "^4.2.1",
package/utils/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './orderState'
@@ -0,0 +1,43 @@
1
+ import { OrderDetailsFragment } from '../components/OrderDetails/OrderDetails.gql'
2
+ import { OrderStateLabelFragment } from '../components/OrderStateLabel/OrderStateLabel.gql'
3
+
4
+ export type OrderState =
5
+ | 'Ordered'
6
+ | 'Processing'
7
+ | 'Closed'
8
+ | 'Refunded'
9
+ | 'Canceled'
10
+ | 'Returned'
11
+ | 'Pending'
12
+
13
+ export type OrderStateProps = Pick<OrderDetailsFragment, 'shipping_address' | 'shipments'> &
14
+ OrderStateLabelFragment
15
+
16
+ export function getOrderState(props: OrderStateProps) {
17
+ const { items, shipping_address } = props
18
+
19
+ let orderState: OrderState = 'Pending'
20
+ if (items?.every((item) => item?.quantity_ordered === item?.quantity_invoiced))
21
+ orderState = 'Processing'
22
+ if (items?.every((item) => item?.quantity_ordered === item?.quantity_shipped))
23
+ orderState = 'Closed'
24
+ if (items?.every((item) => item?.quantity_ordered === item?.quantity_refunded))
25
+ orderState = 'Refunded'
26
+ if (items?.every((item) => item?.quantity_ordered === item?.quantity_canceled))
27
+ orderState = 'Canceled'
28
+ if (items?.every((item) => item?.quantity_ordered === item?.quantity_returned))
29
+ orderState = 'Returned'
30
+
31
+ if (orderState === 'Processing' && !shipping_address) {
32
+ orderState = 'Closed'
33
+ }
34
+
35
+ return orderState
36
+ }
37
+
38
+ export function canCancelOrder(props: OrderStateProps) {
39
+ const state = getOrderState(props)
40
+ const { shipments } = props
41
+
42
+ return (state === 'Pending' || state === 'Processing') && !shipments?.length
43
+ }