diff --git a/packages/magento-send-friend/components/SendEmailToFriend/SendEmailToFriend.tsx b/packages/magento-send-friend/components/SendEmailToFriend/SendEmailToFriend.tsx new file mode 100644 index 0000000000..ad25807c03 --- /dev/null +++ b/packages/magento-send-friend/components/SendEmailToFriend/SendEmailToFriend.tsx @@ -0,0 +1,274 @@ +import { + ApolloErrorSnackbar, + EmailElement, + FormPersist, + TextFieldElement, + useFieldArray, + useFormGqlMutation, + type Control, +} from '@graphcommerce/ecommerce-ui' +import { useQuery } from '@graphcommerce/graphql' +import { + CustomerDocument, + useCustomerQuery, + useCustomerSession, +} from '@graphcommerce/magento-customer' +import type { ProductPageItemFragment } from '@graphcommerce/magento-product' +import { StoreConfigDocument } from '@graphcommerce/magento-store' +import { + Button, + Container, + extendableComponent, + Fab, + FormRow, + iconClose, + iconEmail, + IconSvg, + LinkOrButton, + Overlay, + OverlayHeader, + sxx, +} from '@graphcommerce/next-ui' +import { alpha, Box, IconButton } from '@mui/material' +import { useState } from 'react' +import { + SendEmailToFriendDocument, + type SendEmailToFriendMutationVariables, +} from '../../graphql/SendEmailToFriend.gql' + +export type SendEmailToFriendProps = { + product: ProductPageItemFragment +} + +const componentName = 'SendEmailToFriend' +const { classes } = extendableComponent(componentName, ['root', 'recipients', 'recipient']) + +function FieldArray(props: { control: Control }) { + const { control } = props + const recipients = useFieldArray({ + control, + name: 'input.recipients', + rules: { minLength: 1 }, + }) + + return ( + <> + ({ + typography: 'h6', + display: 'flex', + justifyContent: 'space-between', + alignItems: 'end', + gap: theme.spacings.xs, + mb: theme.spacings.xs, + })} + > + Recipients + + + + {recipients.fields.map((recipient, idx) => ( + ({ + display: 'grid', + gridTemplateColumns: '1fr 1fr auto', + gap: theme.spacings.xs, + p: theme.spacings.xs, + border: `1px solid ${theme.palette.divider}`, + borderRadius: theme.shape.borderRadius, + + '&:not(:first-child)': { + borderTopLeftRadius: 0, + borderTopRightRadius: 0, + borderTop: 'none', + }, + '&:not(:last-child)': { + borderBottomLeftRadius: 0, + borderBottomRightRadius: 0, + }, + })} + > + + + + recipients.remove(idx)} + size='small' + disabled={recipients.fields.length === 1} + > + + + + + ))} + + + ) +} + +export function SendEmailToFriendForm(props: SendEmailToFriendProps & { onClose: () => void }) { + const { product, onClose } = props + + const customer = useCustomerQuery(CustomerDocument).data?.customer + const name = customer + ? [customer.prefix, customer.firstname, customer.middlename, customer.lastname, customer.suffix] + .filter((v) => !!v) + .join(' ') + : undefined + const email = customer?.email ?? undefined + + const form = useFormGqlMutation( + SendEmailToFriendDocument, + { + defaultValues: { + input: { + sender: { name, email }, + product_id: product.id ?? undefined, + recipients: [{}], + }, + }, + onComplete: () => {}, + }, + { errorPolicy: 'all' }, + ) + const submit = form.handleSubmit(() => {}) + + return ( +
+ + Send + + } + > + Send to friend + + + ({ pt: theme.spacings.md })}> + + + + + + + + + + + + + + + + ) +} + +export function SendEmailToFriendBase(props: SendEmailToFriendProps) { + const { product } = props + + const [open, setOpen] = useState(true) + + const preventAnimationBubble = ( + e: React.TouchEvent | React.MouseEvent, + ) => { + e.stopPropagation() + if (e.type === 'mousedown') { + e.preventDefault() + } + } + + return ( + <> + { + e.preventDefault() + setOpen(true) + }} + onMouseDown={preventAnimationBubble} + onTouchStart={preventAnimationBubble} + size='responsive' + color='inherit' + sx={sxx((theme) => ({ + boxShadow: theme.shadows[6], + backgroundColor: + theme.palette.mode === 'light' ? theme.palette.background.paper : 'transparent', + flex: '0 0 auto', + '& svg': { + stroke: + theme.palette.mode === 'light' + ? theme.palette.text.secondary + : theme.palette.background.paper, + }, + '&:hover': { + backgroundColor: alpha(theme.palette.text.primary, theme.palette.action.hoverOpacity), + }, + }))} + title='Send to friend' + aria-label='Send to friend' + icon={iconEmail} + loading={false} + /> + + setOpen(false)}> + setOpen(false)} /> + + + ) +} + +export function SendEmailToFriend(props: SendEmailToFriendProps) { + const { product } = props + + const { enabled_for_customers = false, enabled_for_guests = false } = + useQuery(StoreConfigDocument).data?.storeConfig?.send_friend ?? {} + + const { loggedIn } = useCustomerSession() + if (loggedIn && !enabled_for_customers) return null + if (!loggedIn && !enabled_for_guests) return null + + return +} diff --git a/packages/magento-send-friend/graphql/SendEmailToFriend.graphql b/packages/magento-send-friend/graphql/SendEmailToFriend.graphql new file mode 100644 index 0000000000..ac4c1b2ff5 --- /dev/null +++ b/packages/magento-send-friend/graphql/SendEmailToFriend.graphql @@ -0,0 +1,13 @@ +mutation SendEmailToFriend($input: SendEmailToFriendInput!) { + sendEmailToFriend(input: $input) { + recipients { + email + name + } + sender { + email + name + message + } + } +} diff --git a/packages/magento-send-friend/graphql/SendFriendStoreConfig.graphql b/packages/magento-send-friend/graphql/SendFriendStoreConfig.graphql new file mode 100644 index 0000000000..519d9902dd --- /dev/null +++ b/packages/magento-send-friend/graphql/SendFriendStoreConfig.graphql @@ -0,0 +1,6 @@ +fragment SendFriendStoreConfig on StoreConfig @inject(into: ["StoreConfigFragment"]) { + send_friend { + enabled_for_customers + enabled_for_guests + } +} diff --git a/packages/magento-send-friend/package.json b/packages/magento-send-friend/package.json new file mode 100644 index 0000000000..f37b938838 --- /dev/null +++ b/packages/magento-send-friend/package.json @@ -0,0 +1,34 @@ +{ + "name": "@graphcommerce/magento-send-friend", + "homepage": "https://www.graphcommerce.org/", + "repository": "github:graphcommerce-org/graphcommerce", + "version": "9.0.4-canary.9", + "sideEffects": false, + "prettier": "@graphcommerce/prettier-config-pwa", + "eslintConfig": { + "extends": "@graphcommerce/eslint-config-pwa", + "parserOptions": { + "project": "./tsconfig.json" + } + }, + "peerDependencies": { + "@graphcommerce/ecommerce-ui": "^9.0.4-canary.9", + "@graphcommerce/eslint-config-pwa": "^9.0.4-canary.9", + "@graphcommerce/framer-utils": "^9.0.4-canary.9", + "@graphcommerce/graphql": "^9.0.4-canary.9", + "@graphcommerce/magento-customer": "^9.0.4-canary.9", + "@graphcommerce/magento-product": "^9.0.4-canary.9", + "@graphcommerce/magento-store": "^9.0.4-canary.9", + "@graphcommerce/next-ui": "^9.0.4-canary.9", + "@graphcommerce/prettier-config-pwa": "^9.0.4-canary.9", + "@graphcommerce/typescript-config-pwa": "^9.0.4-canary.9", + "@lingui/core": "^4.2.1", + "@lingui/macro": "^4.2.1", + "@lingui/react": "^4.2.1", + "@mui/material": "^5.10.16", + "framer-motion": "*", + "next": "*", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } +} diff --git a/packages/magento-send-friend/plugins/ProductPageAddToCartActionsRowSendEmailToFriend.tsx b/packages/magento-send-friend/plugins/ProductPageAddToCartActionsRowSendEmailToFriend.tsx new file mode 100644 index 0000000000..f9e6c6f3f7 --- /dev/null +++ b/packages/magento-send-friend/plugins/ProductPageAddToCartActionsRowSendEmailToFriend.tsx @@ -0,0 +1,19 @@ +import type { ProductPageAddToCartRowProps } from '@graphcommerce/magento-product' +import type { PluginConfig, PluginProps } from '@graphcommerce/next-config' +import { SendEmailToFriend } from '../components/SendEmailToFriend/SendEmailToFriend' + +export const config: PluginConfig = { + type: 'component', + module: '@graphcommerce/magento-product', +} + +export function ProductPageAddToCartActionsRow(props: PluginProps) { + const { Prev, product, children, ...rest } = props + + return ( + + {children} + + + ) +} diff --git a/packages/next-ui/icons.ts b/packages/next-ui/icons.ts index abc59ee7d3..e6c41c1ed6 100644 --- a/packages/next-ui/icons.ts +++ b/packages/next-ui/icons.ts @@ -7,6 +7,9 @@ export { default as iconBin } from './icons/bin.svg' export { default as iconInvoice } from './icons/box-alt.svg' export { default as iconBox } from './icons/box.svg' export { default as iconOrderBefore } from './icons/calendar.svg' +export { default as iconShare } from './icons/share.svg' +export { default as iconShareIos } from './icons/share-ios.svg' +export { default as iconShareAndroid } from './icons/share-android.svg' export { default as iconCancelAlt } from './icons/cancel-alt.svg' export { default as iconCancel } from './icons/cancel.svg' export { default as iconCartAdd } from './icons/cart-add.svg'