From 8a10562f608709611b2e9a3041ce8c0c8a40cfae Mon Sep 17 00:00:00 2001 From: Hiago Lucas Cardeal de Melo Silva Date: Tue, 20 Aug 2024 22:57:19 -0300 Subject: [PATCH] . --- react/components/ShippingOptionButton.tsx | 18 ++++-- react/components/ShippingOptionDrawer.tsx | 73 +++++++++++++++++------ react/index.tsx | 64 +++++++++++++++++--- react/typings/vtex.render-runtime.d.ts | 1 + react/typings/vtex.styleguide.d.ts | 1 + react/utils/cookie.ts | 53 ++++++++++++---- 6 files changed, 168 insertions(+), 42 deletions(-) diff --git a/react/components/ShippingOptionButton.tsx b/react/components/ShippingOptionButton.tsx index e5f8b46..f812be0 100644 --- a/react/components/ShippingOptionButton.tsx +++ b/react/components/ShippingOptionButton.tsx @@ -1,5 +1,6 @@ import React from 'react' import { useCssHandles } from 'vtex.css-handles' +import { Spinner } from 'vtex.styleguide' import TruckIcon from './TruckIcon' import '../styles.css' @@ -12,21 +13,28 @@ const CSS_HANDLES = [ interface Props { onClick: () => void + loading: boolean zipCode?: string } -const ShippingOptionButton = ({ onClick, zipCode }: Props) => { +const ShippingOptionButton = ({ onClick, zipCode, loading }: Props) => { const handles = useCssHandles(CSS_HANDLES) return ( ) } diff --git a/react/components/ShippingOptionDrawer.tsx b/react/components/ShippingOptionDrawer.tsx index 3c819cd..8a87b9d 100644 --- a/react/components/ShippingOptionDrawer.tsx +++ b/react/components/ShippingOptionDrawer.tsx @@ -1,7 +1,7 @@ /* eslint-disable jsx-a11y/no-static-element-interactions */ /* eslint-disable jsx-a11y/click-events-have-key-events */ import React, { useState } from 'react' -import { IconClose, Input } from 'vtex.styleguide' +import { IconClose, Input, Spinner } from 'vtex.styleguide' import styles from '../styles.css' @@ -22,12 +22,24 @@ const Overlay = ({ open, onClose }: OverlayProps) => ( interface DrawerProps { open: boolean onClose: () => void - onSubmit: (zipCode: string) => void + isLoading: boolean + onSubmit: (zipCode?: string) => void + inputErrorMessage?: string } -const Drawer = ({ open, onClose, onSubmit }: DrawerProps) => { +const Drawer = ({ + open, + onClose, + onSubmit, + inputErrorMessage, + isLoading, +}: DrawerProps) => { const [zipCode, setZipCode] = useState() + const onSubmitForm = () => { + onSubmit(zipCode) + } + return (
{ onChange={(e: React.ChangeEvent) => { setZipCode(e.target.value) }} + type="text" size="large" placeholder="Zip code" + onKeyDown={(e: { key: string }) => { + if (e.key === 'Enter') { + onSubmitForm() + } + }} + error={inputErrorMessage} + errorMessage={inputErrorMessage} + autocomplete="off" />
- + + {isLoading ? ( +
+ +
+ ) : ( + + )} ) } @@ -74,14 +97,28 @@ const Drawer = ({ open, onClose, onSubmit }: DrawerProps) => { interface Props { open: boolean onClose: () => void - onSubmit: (zipCode: string) => void + onSubmit: (zipCode?: string) => void + isLoading: boolean + inputErrorMessage?: string } -const ShippingOptionDrawer = ({ open, onClose, onSubmit }: Props) => { +const ShippingOptionDrawer = ({ + open, + onClose, + onSubmit, + inputErrorMessage, + isLoading, +}: Props) => { return ( <> - + ) } diff --git a/react/index.tsx b/react/index.tsx index 534dc0e..9e434f6 100644 --- a/react/index.tsx +++ b/react/index.tsx @@ -1,27 +1,31 @@ /* eslint-disable no-restricted-globals */ import React, { useEffect, useState } from 'react' import { createPortal } from 'react-dom' -import { useSSR } from 'vtex.render-runtime' +import { useSSR, useRuntime } from 'vtex.render-runtime' import ShippingOptionButton from './components/ShippingOptionButton' import ShippingOptionDrawer from './components/ShippingOptionDrawer' -import { getCookie, setCookie } from './utils/cookie' - -const SHIPPING_ZIPCODE_COOKIE = 'shipping-zipcode' +import { getCountryCode, getZipCode } from './utils/cookie' function ShippingOptionZipCode() { const body = window?.document?.body const isSSR = useSSR() + const { account } = useRuntime() const shouldCreatePortal = !isSSR && !!body const [open, setOpen] = useState(false) const [zipCode, setZipCode] = useState() + const [isLoading, setIsLoading] = useState(true) + const [countryCode, setCountryCode] = useState() + const [inputErrorMessage, setInputErrorMessage] = useState() useEffect(() => { if (isSSR) { return } - setZipCode(getCookie(SHIPPING_ZIPCODE_COOKIE)) + setZipCode(getZipCode()) + setIsLoading(false) + setCountryCode(getCountryCode) }, [isSSR]) if (shouldCreatePortal) { @@ -36,21 +40,65 @@ function ShippingOptionZipCode() { setOpen(false) } - const onSubmit = (submittedZipCode: string) => { + const onError = (message: string) => { + setInputErrorMessage(message) + setIsLoading(false) + + setTimeout(() => { + setInputErrorMessage(undefined) + }, 3000) + } + + const onSubmit = async (submittedZipCode?: string) => { + if (!submittedZipCode) { + onError('Please enter your zipcode') + + return + } + setZipCode(submittedZipCode) - setCookie(SHIPPING_ZIPCODE_COOKIE, submittedZipCode) + setIsLoading(true) + + const postalCodeCall = await fetch( + `/api/checkout/pub/postal-code/${countryCode}/${submittedZipCode}?an=${account}` + ) + + const { geoCoordinates } = await postalCodeCall.json() + + if (geoCoordinates.length === 0) { + onError('There are no deliveries for this region') + + return + } + + await fetch('/api/sessions', { + method: 'POST', + body: `{"public":{"facets":{"value":"zip-code=${submittedZipCode};coordinates=${geoCoordinates.join( + ',' + )}"}}}`, + headers: { + 'Content-Type': 'application/json', + }, + }) + location.reload() } return ( <> - + {shouldCreatePortal ? createPortal( , body ) diff --git a/react/typings/vtex.render-runtime.d.ts b/react/typings/vtex.render-runtime.d.ts index bdd08f7..7857bd0 100644 --- a/react/typings/vtex.render-runtime.d.ts +++ b/react/typings/vtex.render-runtime.d.ts @@ -1,3 +1,4 @@ declare module 'vtex.render-runtime' { export const useSSR + export const useRuntime } diff --git a/react/typings/vtex.styleguide.d.ts b/react/typings/vtex.styleguide.d.ts index 856af57..db4ea45 100644 --- a/react/typings/vtex.styleguide.d.ts +++ b/react/typings/vtex.styleguide.d.ts @@ -1,4 +1,5 @@ declare module 'vtex.styleguide' { export const IconClose export const Input + export const Spinner } diff --git a/react/utils/cookie.ts b/react/utils/cookie.ts index 1757ba8..3197fea 100644 --- a/react/utils/cookie.ts +++ b/react/utils/cookie.ts @@ -1,14 +1,3 @@ -export function setCookie(name: string, val: string) { - const date = new Date() - const value = val - - // Set it expire in 7 days - date.setTime(date.getTime() + 1 * 24 * 60 * 60 * 1000) - - // Set it - document.cookie = `${name}=${value}; expires=${date.toUTCString()}; path=/` -} - export function getCookie(name: string) { const value = `; ${document.cookie}` const parts = value.split(`; ${name}=`) @@ -19,3 +8,45 @@ export function getCookie(name: string) { return undefined } + +export function getZipCode() { + const segment = (window as any)?.__RUNTIME__.segmentToken + + if (!segment) { + return + } + + const { facets } = JSON.parse(atob(segment)) + + if (!facets) { + return + } + + const zipCodeFacet = facets + .split(';') + .find((facet: string) => facet.indexOf('zip=code')) + + if (!zipCodeFacet) { + return + } + + const [, zipCode] = zipCodeFacet.split('=') + + if (zipCode && zipCode[zipCode.length - 1] === ';') { + return zipCode.substring(0, zipCode.length - 1) + } + + return zipCode +} + +export function getCountryCode() { + const segment = (window as any)?.__RUNTIME__.segmentToken + + if (!segment) { + return + } + + const { countryCode } = JSON.parse(atob(segment)) + + return countryCode +}