@graphcommerce/magento-customer 9.0.4-canary.8 → 9.1.0-canary.15

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,35 @@
1
1
  # Change Log
2
2
 
3
+ ## 9.1.0-canary.15
4
+
5
+ ### Patch Changes
6
+
7
+ - [#2493](https://github.com/graphcommerce-org/graphcommerce/pull/2493) [`0cb3ace`](https://github.com/graphcommerce-org/graphcommerce/commit/0cb3aceb09967493ecdd5040446447ff32cc3f43) - Created a AccountDashboardQueryFragment instead of only a query to allow for adding customerDownloadableProducts to the dashboard query ([@paales](https://github.com/paales))
8
+
9
+ - [#2493](https://github.com/graphcommerce-org/graphcommerce/pull/2493) [`c1f04dc`](https://github.com/graphcommerce-org/graphcommerce/commit/c1f04dcb4ddd621361e6c930fb42afae0aabe9f9) - Migrate to default OrderItem resolver and remove useOrderCardItemImages as OrderItem now returns a product. Add a custom resolver for 2.4.5 and 2.4.6 that implements the functionality for older versions. ([@paales](https://github.com/paales))
10
+
11
+ - [#2493](https://github.com/graphcommerce-org/graphcommerce/pull/2493) [`c1f04dc`](https://github.com/graphcommerce-org/graphcommerce/commit/c1f04dcb4ddd621361e6c930fb42afae0aabe9f9) - Created a refactored the AccountOrders page and refactored the OrderCard. ([@paales](https://github.com/paales))
12
+
13
+ - [#2493](https://github.com/graphcommerce-org/graphcommerce/pull/2493) [`db56933`](https://github.com/graphcommerce-org/graphcommerce/commit/db569336dddd3e955ff0b5b00cafa25079f1adee) - Implemented order sorting for account overview and account list and implement custom resolver for Magento 2.4.5 (which is slow but works). ([@paales](https://github.com/paales))
14
+
15
+ - [#2493](https://github.com/graphcommerce-org/graphcommerce/pull/2493) [`db56933`](https://github.com/graphcommerce-org/graphcommerce/commit/db569336dddd3e955ff0b5b00cafa25079f1adee) - Use OrderStateLabel in my account instead of OrderStateLabelInline and deprecate that one. ([@paales](https://github.com/paales))
16
+
17
+ - [#2493](https://github.com/graphcommerce-org/graphcommerce/pull/2493) [`dc387da`](https://github.com/graphcommerce-org/graphcommerce/commit/dc387da4c32585c251fe9dec90aa010e2a435df5) - OrderTotals/OrderDetails now only renders addres information if available ([@paales](https://github.com/paales))
18
+
19
+ - [#2493](https://github.com/graphcommerce-org/graphcommerce/pull/2493) [`623e993`](https://github.com/graphcommerce-org/graphcommerce/commit/623e993579b05e053d2d2f29684649cd4f4586de) - `<WaitForCustomer />` now accepts all props of the FullPageMessage ([@paales](https://github.com/paales))
20
+
21
+ ## 9.0.4-canary.14
22
+
23
+ ## 9.0.4-canary.13
24
+
25
+ ## 9.0.4-canary.12
26
+
27
+ ## 9.0.4-canary.11
28
+
29
+ ## 9.0.4-canary.10
30
+
31
+ ## 9.0.4-canary.9
32
+
3
33
  ## 9.0.4-canary.8
4
34
 
5
35
  ## 9.0.4-canary.7
@@ -1,6 +1,5 @@
1
1
  import { SectionContainer } from '@graphcommerce/next-ui'
2
2
  import React from 'react'
3
- import useOrderCardItemImages from '../../hooks/useOrderCardItemImages'
4
3
  import type { AccountOrdersFragment } from '../AccountOrders/AccountOrders.gql'
5
4
  import { NoOrdersFound } from '../NoOrdersFound/NoOrdersFound'
6
5
  import { OrderCard } from '../OrderCard/OrderCard'
@@ -16,7 +15,6 @@ export type AccountLatestOrderProps = AccountOrdersFragment & {
16
15
  export function AccountLatestOrder(props: AccountLatestOrderProps) {
17
16
  const { orders, loading } = props
18
17
  const latestOrderCard = orders?.items?.[(orders?.items?.length ?? 1) - 1]
19
- const images = useOrderCardItemImages(orders)
20
18
 
21
19
  // TODO: when Magento fixes their API sorting
22
20
  // const latestOrderCard = orders?.items?.[0]
@@ -26,7 +24,7 @@ export function AccountLatestOrder(props: AccountLatestOrderProps) {
26
24
  {!loading && (
27
25
  <>
28
26
  {!latestOrderCard && <NoOrdersFound />}
29
- {latestOrderCard && <OrderCard {...latestOrderCard} images={images} />}
27
+ {latestOrderCard && <OrderCard {...latestOrderCard} />}
30
28
  </>
31
29
  )}
32
30
  {loading && <OrderCard loading />}
@@ -1,5 +1,11 @@
1
1
  fragment AccountOrders on Customer {
2
- orders(filter: {}, pageSize: $pageSize, currentPage: $currentPage) {
2
+ orders(
3
+ filter: {}
4
+ pageSize: $pageSize
5
+ currentPage: $currentPage
6
+ sort: { sort_direction: DESC, sort_field: CREATED_AT }
7
+ scope: GLOBAL
8
+ ) {
3
9
  items {
4
10
  ...OrderCard
5
11
  }
@@ -1,76 +1,21 @@
1
- import { extendableComponent, Pagination, SectionContainer } from '@graphcommerce/next-ui'
2
- import { Trans } from '@lingui/react'
1
+ import { Pagination, sxx } from '@graphcommerce/next-ui'
3
2
  import type { SxProps, Theme } from '@mui/material'
4
3
  import { Box, Link } from '@mui/material'
5
4
  import React from 'react'
6
- import useOrderCardItemImages from '../../hooks/useOrderCardItemImages'
7
5
  import { NoOrdersFound } from '../NoOrdersFound/NoOrdersFound'
8
6
  import { OrderCard } from '../OrderCard/OrderCard'
9
7
  import type { AccountOrdersFragment } from './AccountOrders.gql'
10
8
 
11
9
  export type AccountOrdersProps = AccountOrdersFragment & { sx?: SxProps<Theme> }
12
10
 
13
- const parts = ['root', 'older'] as const
14
- const { classes } = extendableComponent('AccountOrders', parts)
15
-
16
11
  export function AccountOrders(props: AccountOrdersProps) {
17
12
  const { orders, sx = [] } = props
18
- const amountLatestOrders = 2
19
- const images = useOrderCardItemImages(orders)
20
-
21
13
  const pageInfo = orders?.page_info
22
- const isFirstPage = pageInfo?.current_page === 1
23
-
24
- // whenever it's possible, pick last {amountLatestOrders} items, then reverse the resulting array,
25
- // because we want to render the latest order first,
26
- // but the API returns the orders in ASC order...
27
- const latestOrders = orders?.items
28
- .slice(Math.max((orders?.items?.length ?? 0) - 2, 0), orders?.items?.length)
29
- .reverse()
30
-
31
- const olderOrders = isFirstPage
32
- ? orders?.items.slice(0, Math.max((orders?.items?.length ?? 0) - 2, 0)).reverse()
33
- : orders?.items
34
14
 
35
15
  return (
36
- <Box
37
- className={classes.root}
38
- sx={[
39
- (theme) => ({
40
- typography: 'body2',
41
- marginBottom: theme.spacings.md,
42
- }),
43
- ...(Array.isArray(sx) ? sx : [sx]),
44
- ]}
45
- >
46
- {isFirstPage && (
47
- <SectionContainer labelLeft={<Trans id='Latest orders' />}>
48
- {latestOrders?.map(
49
- (order) => order && <OrderCard key={order.number} {...order} images={images} />,
50
- )}
51
- {orders?.items && !orders?.items?.length && <NoOrdersFound />}
52
- </SectionContainer>
53
- )}
54
-
55
- {orders?.items &&
56
- ((isFirstPage && orders?.items?.length >= amountLatestOrders + 1) || !isFirstPage) && (
57
- <SectionContainer
58
- labelLeft={<Trans id='Older' />}
59
- className={classes.older}
60
- sx={(theme) => ({
61
- [theme.breakpoints.up('md')]: {
62
- marginTop: theme.spacings.lg,
63
- marginBottom: theme.spacings.lg,
64
- },
65
- marginTop: theme.spacings.md,
66
- marginBottom: theme.spacings.md,
67
- })}
68
- >
69
- {olderOrders?.map(
70
- (order) => order && <OrderCard key={order.number} {...order} images={images} />,
71
- )}
72
- </SectionContainer>
73
- )}
16
+ <Box sx={sxx((theme) => ({ display: 'grid', rowGap: theme.spacings.sm }), sx)}>
17
+ {orders?.items?.map((order) => order && <OrderCard key={order.number} {...order} />)}
18
+ {orders?.items && !orders?.items?.length && <NoOrdersFound />}
74
19
 
75
20
  <Pagination
76
21
  count={pageInfo?.total_pages ?? 1}
@@ -4,7 +4,6 @@ import { useFormGqlQuery } from '@graphcommerce/react-hook-form'
4
4
  import { Trans } from '@lingui/macro'
5
5
  import { Box, Typography } from '@mui/material'
6
6
  import { useMemo } from 'react'
7
- import { useOrderCardItemImages } from '../../hooks'
8
7
  import { ApolloCustomerErrorAlert } from '../ApolloCustomerError'
9
8
  import { OrderDetails } from '../OrderDetails/OrderDetails'
10
9
  import { OrderTotals } from '../OrderDetails/OrderTotals'
@@ -44,8 +43,6 @@ export function GuestOrderOverviewForm() {
44
43
 
45
44
  const submitHandler = handleSubmit(() => {})
46
45
 
47
- const images = useOrderCardItemImages({ items: [orderData?.guestOrder ?? null] })
48
-
49
46
  const showForm = !orderData?.guestOrder || !formState.isSubmitSuccessful
50
47
 
51
48
  return (
@@ -91,7 +88,7 @@ export function GuestOrderOverviewForm() {
91
88
  <OrderStateLabel {...orderData.guestOrder} />
92
89
  </Typography>
93
90
  <OrderDetails {...orderData?.guestOrder} />
94
- <OrderItems {...orderData?.guestOrder} images={images} />
91
+ <OrderItems {...orderData?.guestOrder} />
95
92
  <OrderTotals {...orderData?.guestOrder} />
96
93
  </>
97
94
  )}
@@ -1,157 +1,151 @@
1
+ import { Image } from '@graphcommerce/image'
1
2
  import { Money } from '@graphcommerce/magento-store'
2
- import { DateTimeFormat, extendableComponent, NextLink } from '@graphcommerce/next-ui'
3
+ import {
4
+ actionCardImageSizes,
5
+ breakpointVal,
6
+ DateTimeFormat,
7
+ filterNonNullableKeys,
8
+ iconChevronRight,
9
+ IconSvg,
10
+ NextLink,
11
+ sxx,
12
+ } from '@graphcommerce/next-ui'
13
+ import { Trans } from '@lingui/macro'
3
14
  import type { SxProps, Theme } from '@mui/material'
4
- import { Box, ListItemButton, Skeleton, styled } from '@mui/material'
5
- import type { UseOrderCardItemImages } from '../../hooks/useOrderCardItemImages'
6
- import { OrderCardItemImage } from '../OrderCardItemImage/OrderCardItemImage'
15
+ import { Box, lighten, Paper, Skeleton } from '@mui/material'
7
16
  import { OrderStateLabel } from '../OrderStateLabel/OrderStateLabel'
8
- import { TrackingLink } from '../TrackingLink/TrackingLink'
9
17
  import type { OrderCardFragment } from './OrderCard.gql'
10
18
 
11
19
  export type OrderCardProps = Partial<OrderCardFragment> & {
12
20
  loading?: boolean
13
- images?: UseOrderCardItemImages
14
21
  sx?: SxProps<Theme>
15
22
  }
16
23
 
17
- const componentName = 'OrderCard'
18
- const parts = [
19
- 'orderContainer',
20
- 'orderRow',
21
- 'orderMoney',
22
- 'orderProducts',
23
- 'images',
24
- 'placeholder',
25
- 'buttonRoot',
26
- 'tracking',
27
- ] as const
28
- const { classes } = extendableComponent(componentName, parts)
29
-
30
- const OrderContainer = styled(Box, { name: componentName, target: classes.orderContainer })(
31
- ({ theme }) => ({
32
- padding: theme.spacings.sm,
33
- display: 'grid',
34
- justifyContent: 'center',
35
- width: '100%',
36
- }),
37
- )
38
-
39
- const OrderRow = styled(Box, { name: componentName, target: classes.orderRow })(({ theme }) => ({
40
- margin: `0 auto calc(${theme.spacings.xxs} * .5) auto`,
41
- display: 'flex',
42
- gap: theme.spacings.xxs,
43
- }))
44
-
45
24
  export function OrderCard(props: OrderCardProps) {
46
- const {
47
- number,
48
- shipments,
49
- total,
50
- items,
51
- order_date,
52
- images,
53
- loading,
54
- status = '',
55
- sx = [],
56
- } = props
25
+ const { number, total, items, order_date, loading, status = '', sx = [] } = props
57
26
 
58
27
  const totalItems = items?.length ?? 0
59
- const maxItemsInRow = 5
28
+ const maxItemsToShow = totalItems <= 4 ? totalItems : 3
29
+
30
+ const sizes = actionCardImageSizes.responsive
31
+
32
+ const itemsWithImages = filterNonNullableKeys(items, ['product_url_key', 'product'])
33
+ .map((item) => {
34
+ const img = item.product.thumbnail
35
+ if (!img?.url || img.url.includes('/placeholder/')) return null
36
+ return { ...img, url: img.url }
37
+ })
38
+ .filter((v) => !!v)
39
+ .filter((v) => !v.disabled)
60
40
 
61
41
  if (loading) {
62
42
  return (
63
43
  <Box sx={sx}>
64
- <OrderContainer className={classes.orderContainer}>
65
- <OrderRow>
66
- <Skeleton variant='text' width={192} />
67
- </OrderRow>
68
- <OrderRow>
69
- <Skeleton variant='text' width={280} />
70
- </OrderRow>
71
- <Box
72
- className={classes.orderProducts}
73
- sx={{ display: 'flex', justifyContent: 'center', flexWrap: 'wrap' }}
74
- >
75
- <Skeleton variant='rectangular' width={88} height={88} />
44
+ <Paper sx={(theme) => ({ p: theme.spacings.xs })}>
45
+ <Box sx={{ display: 'grid', gap: 1 }}>
46
+ <Box sx={{ display: 'flex', gap: 1 }}>
47
+ <Skeleton variant='rectangular' width={121} height={121} />
48
+ <Box sx={{ flex: 1 }}>
49
+ <Skeleton variant='text' width={140} height={32} />
50
+ <Skeleton variant='text' width={100} height={24} />
51
+ </Box>
52
+ </Box>
76
53
  </Box>
77
- <OrderRow>
78
- <Skeleton variant='text' width={228} />
79
- </OrderRow>
80
- </OrderContainer>
54
+ </Paper>
81
55
  </Box>
82
56
  )
83
57
  }
84
58
 
85
59
  return (
86
- <ListItemButton
87
- href={`/account/orders/view?orderNumber=${number}`}
60
+ <Box
88
61
  component={NextLink}
89
- className={classes.buttonRoot}
90
- sx={[
62
+ href={`/account/orders/view?orderNumber=${number}`}
63
+ sx={sxx(
91
64
  (theme) => ({
92
- width: '100%',
93
- boxShadow: 'none',
94
- marginTop: theme.spacings.xxs,
95
- borderBottom: `1px solid ${theme.palette.divider}`,
96
- '&:hover': { background: 'none' },
65
+ display: 'flex',
66
+ textDecoration: 'none',
67
+ color: 'text.primary',
68
+ px: theme.spacings.xxs,
69
+ py: theme.spacings.xxs,
70
+ gap: theme.spacings.sm,
71
+ alignItems: 'flex-start',
72
+ background:
73
+ theme.palette.mode === 'light'
74
+ ? theme.palette.background.default
75
+ : lighten(theme.palette.background.default, 0.15),
76
+ ...breakpointVal(
77
+ 'borderRadius',
78
+ theme.shape.borderRadius * 2,
79
+ theme.shape.borderRadius * 3,
80
+ theme.breakpoints.values,
81
+ ),
82
+ '&:hover': {
83
+ backgroundColor: theme.palette.action.hover,
84
+ },
97
85
  }),
98
- ...(Array.isArray(sx) ? sx : [sx]),
99
- ]}
86
+ sx,
87
+ )}
100
88
  >
101
- <OrderContainer className={classes.orderContainer}>
102
- <OrderRow>
103
- <Box component='span' className={classes.orderMoney} sx={{ fontWeight: 'bold' }}>
104
- <Money {...total?.grand_total} />
105
- </Box>
106
- <DateTimeFormat date={order_date} />
107
- <span>#{number}</span>
108
- </OrderRow>
109
- <OrderRow>
110
- <OrderStateLabel {...props} status={status} />
111
- </OrderRow>
112
- <Box className={classes.orderProducts}>
89
+ <Box
90
+ sx={{
91
+ display: 'grid',
92
+ gridTemplateColumns: `repeat(2, calc(${sizes} / 2))`,
93
+ gridTemplateRows: `repeat(2, calc(${sizes} / 2))`,
94
+ gap: 1,
95
+ }}
96
+ >
97
+ {itemsWithImages.slice(0, maxItemsToShow).map((item) => (
98
+ <Image
99
+ key={item.url}
100
+ alt={item.label ?? ''}
101
+ layout='fill'
102
+ src={item.url}
103
+ width={96}
104
+ height={96}
105
+ sx={{ borderRadius: 4, objectFit: 'contain' }}
106
+ pictureProps={{
107
+ sx: {
108
+ gridArea: itemsWithImages.length === 1 ? '1 / 1 / 3 / 3' : undefined,
109
+ },
110
+ }}
111
+ />
112
+ ))}
113
+
114
+ {totalItems > 4 && (
113
115
  <Box
114
- className={classes.images}
115
- sx={(theme) => ({
116
- display: 'grid',
117
- gridAutoFlow: 'column',
118
- gap: theme.spacings.xxs,
119
- gridTemplateColumns: 'repeat(auto-fit, 88px)',
120
- placeContent: 'center',
121
- placeItems: 'center',
122
- padding: theme.spacings.xxs,
123
- })}
116
+ sx={{
117
+ bgcolor: 'background.paper',
118
+ borderRadius: '50%',
119
+ display: 'flex',
120
+ alignItems: 'center',
121
+ justifyContent: 'center',
122
+ boxShadow: 2,
123
+ zIndex: 1,
124
+ typography: 'body1',
125
+ gridArea: '2 / 2 / 3 / 3',
126
+ }}
124
127
  >
125
- {items
126
- ?.slice(0, maxItemsInRow)
127
- .map(
128
- (item) =>
129
- item?.product_url_key &&
130
- images?.[item.product_url_key] && (
131
- <OrderCardItemImage
132
- key={item.product_url_key}
133
- {...images[item.product_url_key]}
134
- />
135
- ),
136
- )}
137
- {totalItems > maxItemsInRow && (
138
- <Box
139
- className={classes.placeholder}
140
- sx={{
141
- display: 'flex',
142
- justifyContent: 'center',
143
- alignItems: 'center',
144
- width: 88,
145
- height: 88,
146
- }}
147
- >{`+${totalItems - maxItemsInRow}`}</Box>
148
- )}
128
+ +{totalItems - 3}
149
129
  </Box>
130
+ )}
131
+ </Box>
132
+
133
+ <Box sx={{ flex: 1 }}>
134
+ <Box sx={{ typography: 'subtitle1' }}>
135
+ <DateTimeFormat date={order_date} dateStyle='long' />
150
136
  </Box>
151
- <Box className={`${classes.orderRow} ${classes.tracking}`} sx={{ textAlign: 'center' }}>
152
- {shipments?.[0]?.tracking?.[0] && <TrackingLink {...shipments?.[0].tracking?.[0]} />}
137
+ <Box sx={{ typography: 'body1', color: 'text.secondary' }}>#{number}</Box>
138
+ <Box>
139
+ <Trans id='Grand total'>Grand Total</Trans>: <Money {...total?.grand_total} />
153
140
  </Box>
154
- </OrderContainer>
155
- </ListItemButton>
141
+
142
+ <Box>
143
+ <Trans id='Status'>Status</Trans>:{' '}
144
+ <OrderStateLabel {...props} status={status} sx={{ typography: 'body1' }} short />
145
+ </Box>
146
+ </Box>
147
+
148
+ <IconSvg src={iconChevronRight} size='medium' sx={{ alignSelf: 'center' }} />
149
+ </Box>
156
150
  )
157
151
  }
@@ -1,4 +1,10 @@
1
1
  fragment OrderCardItem on OrderItemInterface {
2
2
  product_sku
3
3
  product_url_key
4
+ product {
5
+ uid
6
+ thumbnail {
7
+ ...ProductImage
8
+ }
9
+ }
4
10
  }
@@ -102,25 +102,27 @@ export function OrderDetails(props: OrderDetailsProps) {
102
102
  </SectionContainer>
103
103
  </Box>
104
104
 
105
- <Box className={classes.orderDetailRow}>
106
- <SectionContainer
107
- variantLeft='h5'
108
- labelLeft={<Trans>Shipping method</Trans>}
109
- className={classes.orderDetailTitle}
110
- sx={{ '& .SectionHeader-root': { marginTop: 0, paddingBottom: '4px' } }}
111
- >
112
- <Typography>{shipping_method ?? ''}</Typography>
105
+ {shipping_method && (
106
+ <Box className={classes.orderDetailRow}>
107
+ <SectionContainer
108
+ variantLeft='h5'
109
+ labelLeft={<Trans>Shipping method</Trans>}
110
+ className={classes.orderDetailTitle}
111
+ sx={{ '& .SectionHeader-root': { marginTop: 0, paddingBottom: '4px' } }}
112
+ >
113
+ <Typography>{shipping_method ?? ''}</Typography>
113
114
 
114
- {shipments && shipments.length > 0 && (
115
- <>
116
- {shipments?.[0]?.tracking && shipments?.[0]?.tracking?.[0]?.title}
117
- {shipments?.[0]?.tracking?.[0] && (
118
- <TrackingLink {...shipments?.[0].tracking?.[0]} sx={{ padding: '4px 0' }} />
119
- )}
120
- </>
121
- )}
122
- </SectionContainer>
123
- </Box>
115
+ {shipments && shipments.length > 0 && (
116
+ <>
117
+ {shipments?.[0]?.tracking && shipments?.[0]?.tracking?.[0]?.title}
118
+ {shipments?.[0]?.tracking?.[0] && (
119
+ <TrackingLink {...shipments?.[0].tracking?.[0]} sx={{ padding: '4px 0' }} />
120
+ )}
121
+ </>
122
+ )}
123
+ </SectionContainer>
124
+ </Box>
125
+ )}
124
126
 
125
127
  <Box className={classes.orderDetailRow}>
126
128
  <SectionContainer
@@ -156,16 +158,18 @@ export function OrderDetails(props: OrderDetailsProps) {
156
158
  </SectionContainer>
157
159
  </Box>
158
160
 
159
- <Box className={classes.orderDetailRow}>
160
- <SectionContainer
161
- variantLeft='h5'
162
- labelLeft={<Trans>Shipping address</Trans>}
163
- className={classes.orderDetailTitle}
164
- sx={{ '& .SectionHeader-root': { marginTop: 0, paddingBottom: '4px' } }}
165
- >
166
- <AddressMultiLine {...shipping_address} />
167
- </SectionContainer>
168
- </Box>
161
+ {shipping_address && (
162
+ <Box className={classes.orderDetailRow}>
163
+ <SectionContainer
164
+ variantLeft='h5'
165
+ labelLeft={<Trans>Shipping address</Trans>}
166
+ className={classes.orderDetailTitle}
167
+ sx={{ '& .SectionHeader-root': { marginTop: 0, paddingBottom: '4px' } }}
168
+ >
169
+ <AddressMultiLine {...shipping_address} />
170
+ </SectionContainer>
171
+ </Box>
172
+ )}
169
173
 
170
174
  <Box className={classes.orderDetailRow}>
171
175
  <SectionContainer
@@ -14,7 +14,7 @@ const parts = ['totalsContainer', 'totalsRow', 'totalsDivider', 'totalsVat'] as
14
14
  const { classes } = extendableComponent(componentName, parts)
15
15
 
16
16
  export function OrderTotals(props: OrderTotalsProps) {
17
- const { total, carrier, sx = [] } = props
17
+ const { total, carrier, shipping_method, sx = [] } = props
18
18
 
19
19
  return (
20
20
  <Box
@@ -54,12 +54,17 @@ export function OrderTotals(props: OrderTotalsProps) {
54
54
  )}
55
55
  </Box>
56
56
  ))}
57
- <Box className={classes.totalsRow} sx={{ display: 'flex', justifyContent: 'space-between' }}>
58
- <Typography>
59
- <Trans id='Shipping ({0} {1})' values={{ 0: carrier }} />
60
- </Typography>
61
- <Money {...total?.total_shipping} />
62
- </Box>
57
+ {carrier && shipping_method && (
58
+ <Box
59
+ className={classes.totalsRow}
60
+ sx={{ display: 'flex', justifyContent: 'space-between' }}
61
+ >
62
+ <Typography>
63
+ <Trans id='Shipping ({0} {1})' values={{ 0: carrier, 1: shipping_method }} />
64
+ </Typography>
65
+ <Money {...total?.total_shipping} />
66
+ </Box>
67
+ )}
63
68
 
64
69
  <Divider sx={(theme) => ({ my: theme.spacings.xxs })} />
65
70
 
@@ -7,6 +7,12 @@ fragment OrderItem on OrderItemInterface {
7
7
  label
8
8
  value
9
9
  }
10
+ product {
11
+ uid
12
+ thumbnail {
13
+ ...ProductImage
14
+ }
15
+ }
10
16
  quantity_invoiced
11
17
  quantity_ordered
12
18
  quantity_refunded
@@ -40,7 +40,7 @@ export function OrderItem(props: OrderItemProps) {
40
40
  product_sale_price,
41
41
  quantity_ordered,
42
42
  product_name,
43
- thumbnail,
43
+ product,
44
44
  } = props
45
45
  const productLink = useProductLink({
46
46
  __typename: 'SimpleProduct' as const,
@@ -94,12 +94,12 @@ export function OrderItem(props: OrderItemProps) {
94
94
  <Box className={classes.picture} sx={{ gridArea: 'picture' }}>
95
95
  <Box href={productLink} component={NextLink} className={classes.productLink}>
96
96
  <Box className={classes.pictureSpacing}>
97
- {thumbnail?.url && thumbnail?.label && (
97
+ {product?.thumbnail?.url && product.thumbnail?.label && (
98
98
  <Image
99
- alt={thumbnail?.label ?? ''}
99
+ alt={product.thumbnail?.label ?? ''}
100
100
  width={104}
101
101
  height={86}
102
- src={thumbnail?.url ?? ''}
102
+ src={product.thumbnail?.url ?? ''}
103
103
  className={classes.image}
104
104
  sx={(theme) => ({
105
105
  backgroundColor: theme.palette.background.image,
@@ -3,12 +3,10 @@ import { Trans } from '@lingui/react'
3
3
  import type { SxProps, Theme } from '@mui/material'
4
4
  import { Box, Button } from '@mui/material'
5
5
  import { useState } from 'react'
6
- import type { UseOrderCardItemImages } from '../../hooks/useOrderCardItemImages'
7
6
  import { OrderItem } from '../OrderItem/OrderItem'
8
7
  import type { OrderItemsFragment } from './OrderItems.gql'
9
8
 
10
9
  export type OrderItemsProps = OrderItemsFragment & {
11
- images?: UseOrderCardItemImages
12
10
  sx?: SxProps<Theme>
13
11
  }
14
12
 
@@ -17,7 +15,7 @@ const parts = ['root', 'orderItemsInnerContainer', 'skeletonOrderItem', 'viewAll
17
15
  const { classes } = extendableComponent(componentName, parts)
18
16
 
19
17
  export function OrderItems(props: OrderItemsProps) {
20
- const { images, items, sx = [] } = props
18
+ const { items, sx = [] } = props
21
19
  const [expanded, setExpanded] = useState<boolean>(false)
22
20
  const maxItemsAboveFold = 4
23
21
 
@@ -39,9 +37,7 @@ export function OrderItems(props: OrderItemsProps) {
39
37
  ?.slice(0, maxItemsAboveFold)
40
38
  .map((orderItem) => (
41
39
  <Box key={`orderItem-${orderItem?.id}`}>
42
- {orderItem && (
43
- <OrderItem {...orderItem} {...images?.[orderItem?.product_url_key ?? '']} />
44
- )}
40
+ {orderItem && <OrderItem {...orderItem} />}
45
41
  </Box>
46
42
  ))}
47
43
 
@@ -50,9 +46,7 @@ export function OrderItems(props: OrderItemsProps) {
50
46
  ?.slice(maxItemsAboveFold, items?.length)
51
47
  .map((orderItem) => (
52
48
  <Box key={`orderItem-${orderItem?.id}`}>
53
- {orderItem && (
54
- <OrderItem {...orderItem} {...images?.[orderItem?.product_url_key ?? '']} />
55
- )}
49
+ {orderItem && <OrderItem {...orderItem} />}
56
50
  </Box>
57
51
  ))}
58
52
  </Box>
@@ -16,7 +16,7 @@ type OwnerState = {
16
16
  orderState: OrderState
17
17
  }
18
18
  const componentName = 'OrderStateLabel'
19
- const parts = ['root'] as const
19
+ const parts = ['root', 'status'] as const
20
20
  const { withState } = extendableComponent<OwnerState, typeof componentName, typeof parts>(
21
21
  componentName,
22
22
  parts,
@@ -28,31 +28,24 @@ export function OrderStateLabel(props: OrderStateLabelProps) {
28
28
 
29
29
  const classes = withState({ orderState })
30
30
 
31
- return (
31
+ const statusWithColor = (
32
32
  <Box
33
+ className={classes.status}
33
34
  component='span'
34
- className={classes.root}
35
- sx={[
36
- (theme) => ({
37
- fontStyle: 'italic',
38
- fontWeight: 'normal',
39
- '&.orderStatePending': {
40
- color: theme.palette.text.disabled,
41
- },
42
- '&.orderStateProcessing': {
43
- color: theme.palette.info.main,
44
- },
45
- '&.orderStateComplete': {
46
- color: theme.palette.success.main,
47
- },
48
- '&.orderStateClosed': {
49
- color: theme.palette.text.disabled,
50
- },
51
- }),
52
- ...(Array.isArray(sx) ? sx : [sx]),
53
- ]}
35
+ sx={(theme) => ({
36
+ '&.orderStatePending': { color: 'text.disabled' },
37
+ '&.orderStateProcessing': { color: 'info.main' },
38
+ '&.orderStateComplete': { color: 'success.main' },
39
+ '&.orderStateClosed': { color: 'text.disabled' },
40
+ })}
54
41
  >
55
- {short ? status : <Trans>Order status: {status}</Trans>}
42
+ {status}
43
+ </Box>
44
+ )
45
+
46
+ return (
47
+ <Box component='span' className={classes.root} sx={sx}>
48
+ {short ? statusWithColor : <Trans>Order status: {statusWithColor}</Trans>}
56
49
  </Box>
57
50
  )
58
51
  }
@@ -4,6 +4,7 @@ import { OrderStateLabel } from './OrderStateLabel'
4
4
 
5
5
  export type OrderStateLabelInlineProps = OrderStateLabelProps
6
6
 
7
+ /** @deprecated Use `<OrderStateLabel {...props} short />` instead */
7
8
  export function OrderStateLabelInline(props: OrderStateLabelInlineProps) {
8
9
  const { sx = [] } = props
9
10
 
@@ -5,13 +5,12 @@ import { FullPageMessage, iconPerson, IconSvg } from '@graphcommerce/next-ui'
5
5
  import { Trans } from '@lingui/react'
6
6
  import { Button, CircularProgress } from '@mui/material'
7
7
  import React from 'react'
8
+ import type { SetOptional } from 'type-fest'
8
9
  import { useCustomerSession } from '../../hooks/useCustomerSession'
9
10
  import { ApolloCustomerErrorFullPage } from '../ApolloCustomerError/ApolloCustomerErrorFullPage'
10
11
 
11
- export type WaitForCustomerProps = Omit<WaitForQueriesProps, 'fallback' | 'waitFor'> &
12
- Pick<FullPageMessageProps, 'disableMargin'> & {
13
- waitFor?: WaitForQueriesProps['waitFor']
14
- fallback?: React.ReactNode
12
+ export type WaitForCustomerProps = SetOptional<WaitForQueriesProps, 'waitFor'> &
13
+ SetOptional<FullPageMessageProps, 'title' | 'icon'> & {
15
14
  unauthenticated?: React.ReactNode
16
15
  }
17
16
 
@@ -42,7 +41,7 @@ export function nonNullable<T>(value: T): value is NonNullable<T> {
42
41
  * ```
43
42
  */
44
43
  export function WaitForCustomer(props: WaitForCustomerProps) {
45
- const { waitFor = [], children, fallback, unauthenticated, disableMargin } = props
44
+ const { waitFor = [], children, fallback, unauthenticated, ...rest } = props
46
45
 
47
46
  const session = useCustomerSession()
48
47
  const queries = Array.isArray(waitFor) ? waitFor : [waitFor]
@@ -58,7 +57,7 @@ export function WaitForCustomer(props: WaitForCustomerProps) {
58
57
  <FullPageMessage
59
58
  icon={<CircularProgress />}
60
59
  title={<Trans id='Loading your data' />}
61
- disableMargin={disableMargin}
60
+ {...rest}
62
61
  >
63
62
  <Trans id='This may take a second' />
64
63
  </FullPageMessage>
@@ -79,7 +78,7 @@ export function WaitForCustomer(props: WaitForCustomerProps) {
79
78
  )}
80
79
  </Button>
81
80
  }
82
- disableMargin={disableMargin}
81
+ {...rest}
83
82
  />
84
83
  ))}
85
84
  {session.loggedIn && error && <ApolloCustomerErrorFullPage error={error} />}
@@ -29,8 +29,6 @@ export * from './GuestOrderOverview/GuestOrderOverviewForm'
29
29
  export * from './NameFields/NameFields'
30
30
  export * from './NoOrdersFound/NoOrdersFound'
31
31
  export * from './OrderCard/OrderCard'
32
- export * from './OrderCardItem/OrderCardItem'
33
- export * from './OrderCardItemImage/OrderCardItemImage'
34
32
  export * from './OrderDetails/OrderDetails'
35
33
  export * from './OrderDetails/OrderDetails.gql'
36
34
  export * from './OrderDetails/OrderTotals'
@@ -1,16 +1,6 @@
1
1
  query AccountDashboard {
2
2
  customer {
3
- ...AccountDashboardCustomer
4
- firstname
5
- lastname
6
- orders {
7
- items {
8
- ...OrderCard
9
- }
10
- page_info {
11
- total_pages
12
- }
13
- }
14
- ...AccountAddresses
3
+ email
15
4
  }
5
+ ...AccountDashboardQueryFragment
16
6
  }
@@ -0,0 +1,21 @@
1
+ fragment AccountDashboardQueryFragment on Query {
2
+ customer {
3
+ ...AccountDashboardCustomer
4
+ firstname
5
+ lastname
6
+ orders(
7
+ pageSize: 1
8
+ currentPage: 1
9
+ sort: { sort_direction: DESC, sort_field: CREATED_AT }
10
+ scope: GLOBAL
11
+ ) {
12
+ items {
13
+ ...OrderCard
14
+ }
15
+ page_info {
16
+ total_pages
17
+ }
18
+ }
19
+ ...AccountAddresses
20
+ }
21
+ }
@@ -7,6 +7,11 @@ type UseOrderCardItemImagesProps = UseOrderCardItemImagesFragment | null
7
7
 
8
8
  export type UseOrderCardItemImages = Record<string, OrderCardItemImageFragment | null | undefined>
9
9
 
10
+ /**
11
+ * @deprecated Not used anymore
12
+ * @param orders
13
+ * @returns
14
+ */
10
15
  export default function useOrderCardItemImages(
11
16
  orders?: UseOrderCardItemImagesProps,
12
17
  ): UseOrderCardItemImages {
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.4-canary.8",
5
+ "version": "9.1.0-canary.15",
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.4-canary.8",
16
- "@graphcommerce/eslint-config-pwa": "^9.0.4-canary.8",
17
- "@graphcommerce/framer-next-pages": "^9.0.4-canary.8",
18
- "@graphcommerce/framer-utils": "^9.0.4-canary.8",
19
- "@graphcommerce/graphql": "^9.0.4-canary.8",
20
- "@graphcommerce/graphql-mesh": "^9.0.4-canary.8",
21
- "@graphcommerce/image": "^9.0.4-canary.8",
22
- "@graphcommerce/magento-graphql": "^9.0.4-canary.8",
23
- "@graphcommerce/magento-store": "^9.0.4-canary.8",
24
- "@graphcommerce/next-ui": "^9.0.4-canary.8",
25
- "@graphcommerce/prettier-config-pwa": "^9.0.4-canary.8",
26
- "@graphcommerce/react-hook-form": "^9.0.4-canary.8",
27
- "@graphcommerce/typescript-config-pwa": "^9.0.4-canary.8",
15
+ "@graphcommerce/ecommerce-ui": "^9.1.0-canary.15",
16
+ "@graphcommerce/eslint-config-pwa": "^9.1.0-canary.15",
17
+ "@graphcommerce/framer-next-pages": "^9.1.0-canary.15",
18
+ "@graphcommerce/framer-utils": "^9.1.0-canary.15",
19
+ "@graphcommerce/graphql": "^9.1.0-canary.15",
20
+ "@graphcommerce/graphql-mesh": "^9.1.0-canary.15",
21
+ "@graphcommerce/image": "^9.1.0-canary.15",
22
+ "@graphcommerce/magento-graphql": "^9.1.0-canary.15",
23
+ "@graphcommerce/magento-store": "^9.1.0-canary.15",
24
+ "@graphcommerce/next-ui": "^9.1.0-canary.15",
25
+ "@graphcommerce/prettier-config-pwa": "^9.1.0-canary.15",
26
+ "@graphcommerce/react-hook-form": "^9.1.0-canary.15",
27
+ "@graphcommerce/typescript-config-pwa": "^9.1.0-canary.15",
28
28
  "@lingui/core": "^4.2.1",
29
29
  "@lingui/macro": "^4.2.1",
30
30
  "@lingui/react": "^4.2.1",
@@ -1,21 +0,0 @@
1
- import type { ProductImage } from '@graphcommerce/graphql-mesh'
2
- import { OrderCardItemImage } from '../OrderCardItemImage/OrderCardItemImage'
3
- import type { OrderCardItemFragment } from './OrderCardItem.gql'
4
-
5
- export type OrderCardItemProps = OrderCardItemFragment & {
6
- thumbnail?: Pick<ProductImage, 'label' | 'url'>
7
- }
8
-
9
- /**
10
- * @deprecated
11
- * @public
12
- */
13
- export function OrderCardItem(props: OrderCardItemProps) {
14
- const { product_sku, product_url_key, thumbnail } = props
15
-
16
- return (
17
- <div key={`orderCardItem-${product_sku ?? ''}`}>
18
- <OrderCardItemImage thumbnail={thumbnail} url_key={product_url_key ?? ''} />
19
- </div>
20
- )
21
- }
@@ -1,36 +0,0 @@
1
- import { Image } from '@graphcommerce/image'
2
- import { extendableComponent } from '@graphcommerce/next-ui'
3
- import type { SxProps, Theme } from '@mui/material'
4
- import { Box } from '@mui/material'
5
- import type { OrderCardItemImageFragment } from '../../hooks/OrderCardItemImage.gql'
6
-
7
- export type OrderCardItemImageProps = Omit<OrderCardItemImageFragment, 'uid'> & {
8
- sx?: SxProps<Theme>
9
- }
10
-
11
- const componentName = 'OrderCardItemImage'
12
- const parts = ['image', 'placeholder'] as const
13
- const { classes } = extendableComponent(componentName, parts)
14
-
15
- export function OrderCardItemImage(props: OrderCardItemImageProps) {
16
- const { thumbnail, sx = [] } = props
17
-
18
- const sxx: SxProps<Theme> = [{ width: 88, height: 88 }, ...(Array.isArray(sx) ? sx : [sx])]
19
-
20
- return (
21
- <>
22
- {thumbnail ? (
23
- <Image
24
- alt={thumbnail?.label ?? ''}
25
- width={88}
26
- height={88}
27
- src={thumbnail?.url ?? ''}
28
- className={classes.image}
29
- sx={sxx}
30
- />
31
- ) : (
32
- <Box className={classes.placeholder} sx={sxx} />
33
- )}
34
- </>
35
- )
36
- }