From 2b38bba51c699c4523ca31e000547f0b056bdb5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lar=C3=ADcia=20Mota?= Date: Fri, 22 Jul 2022 17:17:02 -0300 Subject: [PATCH] Feat: Newsletter form and useNewsletter hook (#134) * Add newsletter form * Add useNewsletter hook * Update CHANGELOG * Change component name * Use newsletter section * Remove newsletter from footer * Remove from home page * Update api version * Apply changes after reviews --- @generated/graphql/index.ts | 34 +++++++++++++- @generated/graphql/persisted.json | 1 + CHANGELOG.md | 1 + package.json | 2 +- .../sections/Newsletter/Newsletter.tsx | 47 +++++++++++++------ src/sdk/newsletter/useNewsletter.ts | 31 ++++++++++++ yarn.lock | 10 ++-- 7 files changed, 105 insertions(+), 21 deletions(-) create mode 100644 src/sdk/newsletter/useNewsletter.ts diff --git a/@generated/graphql/index.ts b/@generated/graphql/index.ts index ab3fdfc1..01f141f3 100644 --- a/@generated/graphql/index.ts +++ b/@generated/graphql/index.ts @@ -707,6 +707,14 @@ export type FloatQueryOperatorInput = { nin: InputMaybe>> } +/** Person data input to the newsletter. */ +export type IPersonNewsletter = { + /** Person's email. */ + email: Scalars['String'] + /** Person's name. */ + name: Scalars['String'] +} + /** Shopping cart input. */ export type IStoreCart = { /** Order information, including `orderNumber` and `acceptedOffer`. */ @@ -858,12 +866,18 @@ export type JsonQueryOperatorInput = { } export type Mutation = { + /** Subscribes a new person to the newsletter list. */ + subscribeToNewsletter: Maybe /** Checks for changes between the cart presented in the UI and the cart stored in the ecommerce platform. If changes are detected, it returns the cart stored on the platform. Otherwise, it returns `null`. */ validateCart: Maybe /** Updates a web session with the specified values. */ validateSession: Maybe } +export type MutationSubscribeToNewsletterArgs = { + data: IPersonNewsletter +} + export type MutationValidateCartArgs = { cart: IStoreCart } @@ -902,6 +916,12 @@ export type PageInfo = { totalCount: Scalars['Int'] } +/** Newsletter information. */ +export type PersonNewsletter = { + /** Person's ID in the newsletter list. */ + id: Scalars['String'] +} + export type Query = { /** Returns information about all collections. */ allCollections: StoreCollectionConnection @@ -2363,7 +2383,7 @@ export type StoreCollectionMeta = { selectedFacets: Array } -/** Product collection type. Possible values are `Department`, `Category`, `Brand` or `Cluster`. */ +/** Product collection type. Possible values are `Department`, `Category`, `Brand`, `Cluster`, `SubCategory` or `Collection`. */ export type StoreCollectionType = /** Product brand. */ | 'Brand' @@ -2371,8 +2391,12 @@ export type StoreCollectionType = | 'Category' /** Product cluster. */ | 'Cluster' + /** Product collection. */ + | 'Collection' /** First level of product categorization. */ | 'Department' + /** Third level of product categorization. */ + | 'SubCategory' /** Currency information. */ export type StoreCurrency = { @@ -2960,6 +2984,14 @@ export type CartItemFragment = { } } +export type SubscribeToNewsletterMutationVariables = Exact<{ + data: IPersonNewsletter +}> + +export type SubscribeToNewsletterMutation = { + subscribeToNewsletter: { id: string } | null +} + export type BrowserProductQueryQueryVariables = Exact<{ locator: Array | IStoreSelectedFacet }> diff --git a/@generated/graphql/persisted.json b/@generated/graphql/persisted.json index 6a972b17..02ec3e93 100644 --- a/@generated/graphql/persisted.json +++ b/@generated/graphql/persisted.json @@ -7,6 +7,7 @@ "HomePageQuery": "query HomePageQuery {\n site {\n siteMetadata {\n title\n description\n titleTemplate\n siteUrl\n }\n }\n}\n", "SearchPageQuery": "query SearchPageQuery {\n site {\n siteMetadata {\n titleTemplate\n title\n description\n }\n }\n}\n", "ValidateCartMutation": "mutation ValidateCartMutation($cart: IStoreCart!) {\n validateCart(cart: $cart) {\n order {\n orderNumber\n acceptedOffer {\n seller {\n identifier\n }\n quantity\n price\n listPrice\n itemOffered {\n sku\n name\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n }\n }\n messages {\n text\n status\n }\n }\n}\n", + "SubscribeToNewsletter": "mutation SubscribeToNewsletter($data: IPersonNewsletter!) {\n subscribeToNewsletter(data: $data) {\n id\n }\n}\n", "BrowserProductQuery": "query BrowserProductQuery($locator: [IStoreSelectedFacet!]!) {\n product(locator: $locator) {\n id: productID\n sku\n name\n gtin\n description\n isVariantOf {\n productGroupID\n name\n }\n image {\n url\n alternateName\n }\n brand {\n name\n }\n offers {\n lowPrice\n offers {\n availability\n price\n listPrice\n seller {\n identifier\n }\n }\n }\n breadcrumbList {\n itemListElement {\n item\n name\n position\n }\n }\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n}\n", "ProductsQuery": "query ProductsQuery($first: Int!, $after: String, $sort: StoreSort!, $term: String!, $selectedFacets: [IStoreSelectedFacet!]!) {\n search(\n first: $first\n after: $after\n sort: $sort\n term: $term\n selectedFacets: $selectedFacets\n ) {\n products {\n pageInfo {\n totalCount\n }\n edges {\n node {\n id: productID\n slug\n sku\n brand {\n brandName: name\n name\n }\n name\n gtin\n isVariantOf {\n productGroupID\n name\n }\n image {\n url\n alternateName\n }\n offers {\n lowPrice\n offers {\n availability\n price\n listPrice\n quantity\n seller {\n identifier\n }\n }\n }\n }\n }\n }\n }\n}\n", "SearchSuggestionsQuery": "query SearchSuggestionsQuery($term: String!, $selectedFacets: [IStoreSelectedFacet!]) {\n search(first: 5, term: $term, selectedFacets: $selectedFacets) {\n suggestions {\n terms {\n value\n }\n products {\n id: productID\n slug\n sku\n brand {\n brandName: name\n name\n }\n name\n gtin\n isVariantOf {\n productGroupID\n name\n }\n image {\n url\n alternateName\n }\n offers {\n lowPrice\n offers {\n availability\n price\n listPrice\n quantity\n seller {\n identifier\n }\n }\n }\n }\n }\n }\n}\n", diff --git a/CHANGELOG.md b/CHANGELOG.md index 5636a0f9..8a9b5e77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Newsletter form and `useNewsletter` hook ([#134](https://github.com/vtex-sites/gatsby.store/pull/134)) - Applies new local tokens to `SearchHistory`, `SearchTop`, `SearchDropdown` and `SearchSuggestions` ([#150](https://github.com/vtex-sites/gatsby.store/pull/150)) - Applies CSS Modules to `Incentives` ([#147](https://github.com/vtex-sites/gatsby.store/pull/147)) - Applies new local tokens to `Footer` ([#147](https://github.com/vtex-sites/gatsby.store/pull/147)) diff --git a/package.json b/package.json index 8855fc9c..6c09c7ba 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@envelop/core": "^1.2.0", "@envelop/parser-cache": "^2.2.0", "@envelop/validation-cache": "^2.2.0", - "@faststore/api": "^1.10.8", + "@faststore/api": "^1.10.19", "@faststore/graphql-utils": "^1.10.6", "@faststore/sdk": "^1.10.6", "@faststore/ui": "^1.10.7", diff --git a/src/components/sections/Newsletter/Newsletter.tsx b/src/components/sections/Newsletter/Newsletter.tsx index f5c4950b..1f8094a8 100644 --- a/src/components/sections/Newsletter/Newsletter.tsx +++ b/src/components/sections/Newsletter/Newsletter.tsx @@ -1,6 +1,9 @@ import type { ComponentPropsWithRef, FormEvent, ReactNode } from 'react' import { forwardRef, useRef } from 'react' -import { Form, Label, Input, Button } from '@faststore/ui' +import { Form, Label, Input, LoadingButton } from '@faststore/ui' +import { useNewsletter } from 'src/sdk/newsletter/useNewsletter' + +import Section from '../Section' export interface NewsletterProps extends Omit, 'title' | 'onSubmit'> { @@ -12,49 +15,63 @@ export interface NewsletterProps * A subtitle for the section. */ subtitle?: ReactNode - /** - * Callback function when submitted. - */ - onSubmit: (value: string) => void } const Newsletter = forwardRef( - function Newsletter({ title, subtitle, onSubmit, ...otherProps }, ref) { + function Newsletter({ title, subtitle, ...otherProps }, ref) { + const { subscribeUser, loading } = useNewsletter() + const nameInputRef = useRef(null) const emailInputRef = useRef(null) const handleSubmit = (event: FormEvent) => { event.preventDefault() + subscribeUser({ + data: { + name: nameInputRef.current?.value ?? '', + email: emailInputRef.current?.value ?? '', + }, + }) + const formElement = event.currentTarget as HTMLFormElement - if (emailInputRef.current?.value !== '') { - onSubmit(emailInputRef.current?.value ?? '') - } + formElement.reset() } return ( -
+
-
+
{title} {Boolean(subtitle) && subtitle}
-
+
+ + - + + Subscribe +
-
+
) } ) diff --git a/src/sdk/newsletter/useNewsletter.ts b/src/sdk/newsletter/useNewsletter.ts new file mode 100644 index 00000000..5d9c4961 --- /dev/null +++ b/src/sdk/newsletter/useNewsletter.ts @@ -0,0 +1,31 @@ +import { gql } from '@faststore/graphql-utils' + +import type { + SubscribeToNewsletterMutation as Mutation, + SubscribeToNewsletterMutationVariables as Variables, +} from '../../../@generated/graphql/index' +import { useLazyQuery } from '../graphql/useLazyQuery' + +export const mutation = gql` + mutation SubscribeToNewsletter($data: IPersonNewsletter!) { + subscribeToNewsletter(data: $data) { + id + } + } +` + +export const useNewsletter = () => { + const [subscribeUser, { data, error, isValidating: loading }] = useLazyQuery< + Mutation, + Variables + >(mutation, { + data: { name: '', email: '' }, + }) + + return { + subscribeUser, + data, + error, + loading, + } +} diff --git a/yarn.lock b/yarn.lock index cefd9ef4..1c46eda1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1927,10 +1927,10 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" -"@faststore/api@^1.10.8": - version "1.10.8" - resolved "https://registry.yarnpkg.com/@faststore/api/-/api-1.10.8.tgz#be0d7297e4514e6d328b42cdf722cb6099b2c08b" - integrity sha512-os6ebn8j3N1lVekZLCenDwNJI+CR8JQ04Fz4CimYrQhD461q8Hl7BzfVe5FB+aERzHLBlrUm1OkE5IaCkKD7VA== +"@faststore/api@^1.10.19": + version "1.10.19" + resolved "https://registry.yarnpkg.com/@faststore/api/-/api-1.10.19.tgz#daa99085130e65d5d62b442f8138b29e38914dcb" + integrity sha512-DK6lEU/4MMoEbLgCOU+BB8s82tkpNKp12YaWdwdxmr61hUVOkwUY3Qs3wX27nn2rL2xPgvNu0/MBIdP7GxPziQ== dependencies: "@graphql-tools/schema" "^8.2.0" "@rollup/plugin-graphql" "^1.0.0" @@ -21018,8 +21018,10 @@ watchpack@^1.7.4: resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== dependencies: + chokidar "^3.4.1" graceful-fs "^4.1.2" neo-async "^2.5.0" + watchpack-chokidar2 "^2.0.1" optionalDependencies: chokidar "^3.4.1" watchpack-chokidar2 "^2.0.1"