@graphcommerce/magento-payment-tokens 9.1.0-canary.17

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.
@@ -0,0 +1,134 @@
1
+ import type { ApolloClient, NormalizedCacheObject } from '@graphcommerce/graphql'
2
+ import {
3
+ getCustomerAccountIsDisabled,
4
+ useCustomerQuery,
5
+ WaitForCustomer,
6
+ } from '@graphcommerce/magento-customer'
7
+ import { PageMeta, StoreConfigDocument } from '@graphcommerce/magento-store'
8
+ import {
9
+ breakpointVal,
10
+ filterNonNullableKeys,
11
+ iconCreditCard,
12
+ LayoutOverlayHeader,
13
+ LayoutTitle,
14
+ sxx,
15
+ type GetStaticProps,
16
+ } from '@graphcommerce/next-ui'
17
+ import { i18n } from '@lingui/core'
18
+ import { Trans } from '@lingui/macro'
19
+ import { Alert, Box, Container, lighten, Typography } from '@mui/material'
20
+ import type { PaymentTokenFragment } from '../../graphql/fragments/PaymentToken.gql'
21
+ import { CustomerPaymentTokensDocument } from '../../graphql/queries/PaymentTokens.gql'
22
+ import { DeletePaymentTokenButton } from '../DeletePaymentTokenButton'
23
+
24
+ export type CustomerTokensPageProps = Record<string, unknown>
25
+ type CustomerTokensGetStaticProps = GetStaticProps<Record<string, unknown>, CustomerTokensPageProps>
26
+
27
+ export function CustomerTokensPage() {
28
+ const dashboard = useCustomerQuery(CustomerPaymentTokensDocument, {
29
+ fetchPolicy: 'cache-and-network',
30
+ })
31
+
32
+ const loading = dashboard.loading && !dashboard.previousData
33
+
34
+ const paymentTokens = filterNonNullableKeys(
35
+ dashboard.data?.customerPaymentTokens?.items ??
36
+ dashboard.previousData?.customerPaymentTokens?.items,
37
+ )
38
+
39
+ return (
40
+ <>
41
+ <LayoutOverlayHeader>
42
+ <LayoutTitle size='small' component='span' icon={iconCreditCard}>
43
+ <Trans id='Payment information'>Payment information</Trans>
44
+ </LayoutTitle>
45
+ </LayoutOverlayHeader>
46
+
47
+ <Container maxWidth='md'>
48
+ <PageMeta title={i18n._('Payment information')} metaRobots={['noindex']} />
49
+
50
+ <LayoutTitle icon={iconCreditCard} sx={(theme) => ({ mb: theme.spacings.xs })}>
51
+ <Trans id='Stored payment methods'>Stored payment methods</Trans>
52
+ </LayoutTitle>
53
+
54
+ <WaitForCustomer waitFor={!loading}>
55
+ {!paymentTokens?.length && (
56
+ <Alert severity='info'>
57
+ <Trans id='No stored payment methods found.'>No stored payment methods found.</Trans>
58
+ </Alert>
59
+ )}
60
+
61
+ <Box sx={sxx((theme) => ({ display: 'grid', rowGap: theme.spacings.xs }))}>
62
+ {paymentTokens?.map((token) => (
63
+ <Box
64
+ key={token.public_hash}
65
+ sx={(theme) => ({
66
+ px: theme.spacings.xxs,
67
+ py: theme.spacings.xxs,
68
+ background:
69
+ theme.palette.mode === 'light'
70
+ ? theme.palette.background.default
71
+ : lighten(theme.palette.background.default, 0.15),
72
+ ...breakpointVal(
73
+ 'borderRadius',
74
+ theme.shape.borderRadius * 2,
75
+ theme.shape.borderRadius * 3,
76
+ theme.breakpoints.values,
77
+ ),
78
+ display: 'grid',
79
+ gridTemplate: `
80
+ "details delete"
81
+ "type method" / 1fr auto
82
+ `,
83
+ rowGap: 0.5,
84
+ columnGap: 1,
85
+ })}
86
+ >
87
+ <Box sx={{ gridArea: 'details', color: 'text.secondary' }}>{token.details}</Box>
88
+
89
+ <Typography
90
+ variant='subtitle1'
91
+ noWrap
92
+ sx={{ gridArea: 'type', overflow: 'hidden', textOverflow: 'ellipsis' }}
93
+ >
94
+ {token.type}
95
+ </Typography>
96
+
97
+ {/* <Box sx={{ gridArea: 'method', color: 'text.secondary' }}>
98
+ {token.payment_method_code}
99
+ </Box> */}
100
+
101
+ {token.details && (
102
+ <Box sx={{ gridArea: 'details', color: 'text.secondary' }}>{token.details}</Box>
103
+ )}
104
+
105
+ <DeletePaymentTokenButton
106
+ sx={{ gridArea: 'delete' }}
107
+ publicHash={token.public_hash}
108
+ />
109
+ </Box>
110
+ ))}
111
+ </Box>
112
+ </WaitForCustomer>
113
+ </Container>
114
+ </>
115
+ )
116
+ }
117
+
118
+ export function createGetStaticProps(
119
+ client: ApolloClient<NormalizedCacheObject>,
120
+ ): CustomerTokensGetStaticProps {
121
+ return async (context) => {
122
+ if (getCustomerAccountIsDisabled(context.locale)) return { notFound: true }
123
+
124
+ const conf = client.query({ query: StoreConfigDocument })
125
+
126
+ return {
127
+ props: {
128
+ apolloState: await conf.then(() => client.cache.extract()),
129
+ variantMd: 'bottom',
130
+ up: { href: '/account', title: i18n._('Account') },
131
+ },
132
+ }
133
+ }
134
+ }
@@ -0,0 +1,28 @@
1
+ import { ApolloErrorSnackbar, useFormGqlMutation } from '@graphcommerce/ecommerce-ui'
2
+ import { Fab, iconBin, sxx } from '@graphcommerce/next-ui'
3
+ import { t } from '@lingui/macro'
4
+ import { type SxProps, type Theme } from '@mui/material'
5
+ import { DeletePaymentTokenDocument } from '../graphql/mutations/DeletePaymentToken.gql'
6
+
7
+ export function DeletePaymentTokenButton(props: { sx: SxProps<Theme>; publicHash: string }) {
8
+ const { sx, publicHash } = props
9
+
10
+ const { handleSubmit, formState, error } = useFormGqlMutation(DeletePaymentTokenDocument, {
11
+ values: { publicHash },
12
+ })
13
+
14
+ const submit = handleSubmit(() => {})
15
+
16
+ return (
17
+ <form onSubmit={submit}>
18
+ <Fab
19
+ type='submit'
20
+ aria-label={t`Remove`}
21
+ loading={formState.isSubmitting}
22
+ icon={iconBin}
23
+ sx={sxx({ boxShadow: 0 }, sx)}
24
+ />
25
+ <ApolloErrorSnackbar error={error} />
26
+ </form>
27
+ )
28
+ }
@@ -0,0 +1,31 @@
1
+ import {
2
+ AccountDashboardDocument,
3
+ AccountMenuItem,
4
+ useCustomerQuery,
5
+ type AccountMenuItemProps,
6
+ } from '@graphcommerce/magento-customer'
7
+ import { iconCreditCard } from '@graphcommerce/next-ui'
8
+ import { Trans } from '@lingui/macro'
9
+ import type { SetOptional } from 'type-fest'
10
+
11
+ type PaymentTokensAccountMenuItemProps = SetOptional<
12
+ Omit<AccountMenuItemProps, 'href'>,
13
+ 'iconSrc' | 'title'
14
+ >
15
+
16
+ export function PaymentTokensAccountMenuItem(props: PaymentTokensAccountMenuItemProps) {
17
+ const dashboard = useCustomerQuery(AccountDashboardDocument, { fetchPolicy: 'cache-only' })
18
+ const tokens = dashboard.data?.customerPaymentTokens?.items
19
+
20
+ if (!tokens || tokens.length === 0) return null
21
+
22
+ return (
23
+ <AccountMenuItem
24
+ href='/account/payment-tokens'
25
+ iconSrc={iconCreditCard}
26
+ title={<Trans id='Stored payment methods'>Stored payment methods</Trans>}
27
+ subtitle={<Trans id='For faster checkout'>For faster checkout</Trans>}
28
+ {...props}
29
+ />
30
+ )
31
+ }
@@ -0,0 +1,2 @@
1
+ export * from './CustomerTokensPage/CustomerTokensPage'
2
+ export * from './PaymentTokensAccountMenuItem/PaymentTokensAccountMenuItem'
@@ -0,0 +1,29 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+ import type { PageOptions } from '@graphcommerce/framer-next-pages'
3
+ // eslint-disable-next-line import/no-extraneous-dependencies
4
+ import {
5
+ createGetStaticProps,
6
+ CustomerTokensPage,
7
+ type CustomerTokensPageProps,
8
+ } from '@graphcommerce/magento-payment-tokens'
9
+ import type { GetStaticProps, LayoutOverlayProps } from '@graphcommerce/next-ui'
10
+ import { LayoutOverlay } from '@graphcommerce/next-ui'
11
+ import { graphqlSharedClient } from '../../lib/graphql/graphqlSsrClient'
12
+
13
+ type GetPageStaticProps = GetStaticProps<LayoutOverlayProps>
14
+
15
+ export default function Page(props: CustomerTokensPageProps) {
16
+ return <CustomerTokensPage {...props} />
17
+ }
18
+
19
+ const pageOptions: PageOptions<LayoutOverlayProps> = {
20
+ overlayGroup: 'account',
21
+ Layout: LayoutOverlay,
22
+ }
23
+
24
+ Page.pageOptions = pageOptions
25
+
26
+ export const getStaticProps: GetPageStaticProps = async (context) => {
27
+ const client = graphqlSharedClient(context)
28
+ return createGetStaticProps(client)(context)
29
+ }
@@ -0,0 +1,6 @@
1
+ fragment PaymentToken on PaymentToken {
2
+ details
3
+ payment_method_code
4
+ public_hash
5
+ type
6
+ }
@@ -0,0 +1,8 @@
1
+ fragment CustomerPaymentTokensAccountDashboard on Query
2
+ @inject(into: ["AccountDashboardQueryFragment"]) {
3
+ customerPaymentTokens {
4
+ items {
5
+ __typename
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,10 @@
1
+ mutation DeletePaymentToken($publicHash: String!) {
2
+ deletePaymentToken(public_hash: $publicHash) {
3
+ customerPaymentTokens {
4
+ items {
5
+ ...PaymentToken
6
+ }
7
+ }
8
+ result
9
+ }
10
+ }
@@ -0,0 +1,7 @@
1
+ query CustomerPaymentTokens {
2
+ customerPaymentTokens {
3
+ items {
4
+ ...PaymentToken
5
+ }
6
+ }
7
+ }
package/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './components'
2
+ export * from './graphql/fragments/PaymentToken.gql'
3
+ export * from './graphql/inject/AccountDashboardPaymentTokens.gql'
4
+ export * from './graphql/mutations/DeletePaymentToken.gql'
5
+ export * from './graphql/queries/PaymentTokens.gql'
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@graphcommerce/magento-payment-tokens",
3
+ "homepage": "https://www.graphcommerce.org/",
4
+ "repository": "github:graphcommerce-org/graphcommerce",
5
+ "version": "9.1.0-canary.17",
6
+ "sideEffects": false,
7
+ "prettier": "@graphcommerce/prettier-config-pwa",
8
+ "eslintConfig": {
9
+ "extends": "@graphcommerce/eslint-config-pwa",
10
+ "parserOptions": {
11
+ "project": "./tsconfig.json"
12
+ }
13
+ },
14
+ "peerDependencies": {
15
+ "@graphcommerce/ecommerce-ui": "^9.1.0-canary.17",
16
+ "@graphcommerce/eslint-config-pwa": "^9.1.0-canary.17",
17
+ "@graphcommerce/graphql": "^9.1.0-canary.17",
18
+ "@graphcommerce/image": "^9.1.0-canary.17",
19
+ "@graphcommerce/magento-cart": "^9.1.0-canary.17",
20
+ "@graphcommerce/magento-cart-payment-method": "^9.1.0-canary.17",
21
+ "@graphcommerce/magento-customer": "^9.1.0-canary.17",
22
+ "@graphcommerce/magento-store": "^9.1.0-canary.17",
23
+ "@graphcommerce/next-ui": "^9.1.0-canary.17",
24
+ "@graphcommerce/prettier-config-pwa": "^9.1.0-canary.17",
25
+ "@graphcommerce/typescript-config-pwa": "^9.1.0-canary.17",
26
+ "@lingui/core": "^4.2.1",
27
+ "@lingui/macro": "^4.2.1",
28
+ "@lingui/react": "^4.2.1",
29
+ "@mui/material": "^5.10.16",
30
+ "framer-motion": "^11.0.0",
31
+ "next": "*",
32
+ "react": "^18.2.0",
33
+ "react-dom": "^18.2.0"
34
+ }
35
+ }
@@ -0,0 +1,19 @@
1
+ import type { AccountMenuItemProps } from '@graphcommerce/magento-customer'
2
+ import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
3
+ import { PaymentTokensAccountMenuItem } from '../components'
4
+
5
+ export const config: PluginConfig = {
6
+ module: '@graphcommerce/magento-customer',
7
+ type: 'component',
8
+ }
9
+
10
+ export function AccountMenuItem(props: PluginProps<AccountMenuItemProps>) {
11
+ const { Prev, href, ...rest } = props
12
+
13
+ return (
14
+ <>
15
+ <Prev {...rest} href={href} />
16
+ {href === '/account/orders' && <PaymentTokensAccountMenuItem />}
17
+ </>
18
+ )
19
+ }