diff --git a/i18n/locales/en.json b/i18n/locales/en.json index 9fa23a67..2ed7fc59 100644 --- a/i18n/locales/en.json +++ b/i18n/locales/en.json @@ -71,7 +71,10 @@ "new": "New", "today_deals": "Today's deals", "best_sellers": "Best sellers", - "no_products_found": "No products found" + "no_products_found": "No products found", + "seller_hero_title": "Join Nuvann Store today and start earning with your shop!", + "seller_hero_desc": "Sell ​​all your products in Nuvann Store and have thousands of customers all over the world.", + "become_a_seller_button": "Become a seller" }, "details": { "add_to_cart": "Add to cart", @@ -96,7 +99,8 @@ "see_more": "See more shipping options", "see_less": "See less shipment options", "unavailable": "Unavailable", - "unit_s": "unit(s)" + "unit_s": "unit(s)", + "not_available_message": "This item cannot be shipped to your selected delivery location." }, "cart": { "shopping_cart": "Shopping cart", diff --git a/i18n/locales/es.json b/i18n/locales/es.json index 05f4b32e..1beaa8cb 100644 --- a/i18n/locales/es.json +++ b/i18n/locales/es.json @@ -71,8 +71,10 @@ "new": "Nuevo", "today_deals": "Ofertas del día", "best_sellers": "Los más vendidos", - "no_products_found": "No se encontraron productos" - + "no_products_found": "No se encontraron productos", + "seller_hero_title": "¡Únete a Nuvann Store hoy y comienza a ganar con tu tienda!", + "seller_hero_desc": "Vende tus productos en Nuvann Store y llega a miles de clientes en todo el mundo.", + "become_a_seller_button": "Conviértete en vendedor" }, "details": { "available_s": "Disponible", @@ -97,7 +99,8 @@ "see_more": "Ver más opciones de envío", "see_less": "Ver menos opciones de envío", "unavailable": "No disponible", - "unit_s": "unidad(es)" + "unit_s": "unidad(es)", + "not_available_message": "Este artículo no se puede enviar a la ubicación de entrega seleccionada." }, "cart": { "shopping_cart": "Carro de la compra", diff --git a/i18n/locales/fr.json b/i18n/locales/fr.json index 7fa55f2c..fdcc87d7 100644 --- a/i18n/locales/fr.json +++ b/i18n/locales/fr.json @@ -72,7 +72,10 @@ "today_deals": "Offres du jour", "best_sellers": "Meilleures ventes", "no_products_found": "Aucun produit trouvé", - "please_select_size_or_color": "Veuillez sélectionner une taille ou une couleur" + "please_select_size_or_color": "Veuillez sélectionner une taille ou une couleur", + "seller_hero_title": "Rejoignez Nuvann Store aujourd'hui et commencez à gagner avec votre boutique!", + "seller_hero_desc": "Vendez vos produits sur Nuvann Store et attirez des milliers de clients à travers le monde.", + "become_a_seller_button": "Devenir vendeur" }, "details": { "available_s": "Disponible(s)", @@ -97,7 +100,8 @@ "see_more": "Voir plus d'options d'expédition", "see_less": "Voir moins d'options d'expédition", "unavailable": "Indisponible", - "unit_s": "unité(s)" + "unit_s": "unité(s)", + "not_available_message": "Cet article ne peut pas être expédié à l'adresse de livraison sélectionnée." }, "cart": { "shopping_cart": "Panier", diff --git a/i18n/locales/ht.json b/i18n/locales/ht.json index 57945cfd..30c231d6 100644 --- a/i18n/locales/ht.json +++ b/i18n/locales/ht.json @@ -73,7 +73,10 @@ "today_deals": "Òf jounen an", "best_sellers": "Pwodui ki vann plis", "no_products_found": "Pa gen pwodui disponib", - "please_select_size_or_color": "Tanpri chwazi yon gwosè oswa yon koulè" + "please_select_size_or_color": "Tanpri chwazi yon gwosè oswa yon koulè", + "seller_hero_title": "Jwenn Nuvann Store jodi a epi kòmanse fè lajan ak boutik ou an!", + "seller_hero_desc": "Vann pwodwi ou yo sou Nuvann Store epi atire plizyè milye kliyan atravè mond lan.", + "become_a_seller_button": "Vin yon machann" }, "details": { "available_s": "Disponib", @@ -98,7 +101,8 @@ "see_more": "Wè plis opsyon livrezon", "see_less": "Wè mwens opsyon livrezon", "unavailable": "Non disponib", - "unit_s": "inite" + "unit_s": "inite", + "not_available_message": "Atik sa a pa disponib nan peyi ou ye an." }, "cart": { "shopping_cart": "Panye", diff --git a/package-lock.json b/package-lock.json index 4bbb96a0..5eb0a033 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nuvann-store", - "version": "0.1.135", + "version": "0.1.140", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nuvann-store", - "version": "0.1.135", + "version": "0.1.140", "dependencies": { "@auth0/auth0-react": "^2.2.4", "@emotion/react": "^11.11.4", diff --git a/package.json b/package.json index cbd26dd4..c63365fc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nuvann-store", - "version": "0.1.135", + "version": "0.1.140", "private": true, "scripts": { "dev": "next dev", diff --git a/public/assets/hero/heroOnboarding.svg b/public/assets/hero/heroOnboarding.svg new file mode 100644 index 00000000..f1f2d678 --- /dev/null +++ b/public/assets/hero/heroOnboarding.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/footer/index.tsx b/src/components/footer/index.tsx index a5839283..ce8e8bfc 100644 --- a/src/components/footer/index.tsx +++ b/src/components/footer/index.tsx @@ -1,6 +1,5 @@ -import React, { use } from 'react' -import { AiOutlineUser, AiOutlineShoppingCart, AiOutlineLogout } from 'react-icons/ai'; -import {FaMapMarkerAlt, FaPhoneAlt, FaEnvelope} from 'react-icons/fa'; +import React from 'react' +import { AiOutlineShoppingCart } from 'react-icons/ai'; import Image from 'next/image'; import styles from './styles.module.scss' diff --git a/src/components/navbar/index.tsx b/src/components/navbar/index.tsx index 6357b43a..b65a6791 100644 --- a/src/components/navbar/index.tsx +++ b/src/components/navbar/index.tsx @@ -17,7 +17,7 @@ import { useCountriesInfo } from '@/hooks/use-countries-info'; import { formatCountriesArray } from '@/utils/format-countries-array'; import { UserRoles } from '@/utils/enums/user.enum'; import { useNavigation } from '@/hooks/useNavigation'; -import { RoutesUrls } from '@/utils/enums/routesUrl'; +import { RoutesUrls, RouteUrl } from '@/utils/enums/routesUrl'; import { Category } from '@/contexts/categories/types'; import { useRouter } from 'next/router'; import getDeviceType from '@/utils/get-device-type'; @@ -42,41 +42,36 @@ export const Navbar: React.FC = () => { logout, isAuthenticated, loginWithRedirect: handleLogin, } = useAuth0(); - const {countries} = useCountriesInfo(); const { cartState} = useCartInfo(); const { categoriesState} = useCategoriesInfo(); const {dispatch: userDispatch} =useUser(); const { - handleBecomeSeller, getUserInfo, user: userInfos, isLoading: userInfosLoader, - modalTerm, token, - setModalTerm } = useUserInfo(); - const [businessName, setBusinessName] = React.useState(""); - const [selectedCountry, setSelectedCountry] = React.useState([]); const { redirect } = useNavigation(); const handleClickToBecomeSeller = () => { - if(!isAuthenticated) { - return handleLogin(); - } + // if(!isAuthenticated) { + // return handleLogin(); + // } cookie.setCookie({name: 'nuvann_store_referral', days: 1, value: generateRandomString(24), domain: process.env.NEXT_PUBLIC_COOKIE_DOMAIN || ''}); if(Array.isArray(userInfos?.roles) && userInfos?.roles?.some(role => [UserRoles.SELLER, UserRoles.ADMINISTRATOR]?.includes(role))) { return window.open(process.env.NEXT_PUBLIC_DASHBOARD_ACCESS_URL as string, '_blank'); } - setModalTerm(true) + // setModalTerm(true) + redirect('/seller-onboarding' as RouteUrl); } const handleRedirectToCategory = (category: Category) => { - redirect(`/search?category_id=${category.id}` as RoutesUrls); + redirect(`/search?category_id=${category.id}` as RouteUrl); } const handleSearch = (searchText: string) => { - redirect(`/search?search=${searchText}` as RoutesUrls) + redirect(`/search?search=${searchText}` as RouteUrl) } const setSession = async() => { @@ -88,12 +83,12 @@ export const Navbar: React.FC = () => { } - React.useEffect(() => { - if(becomeseller) { - handleClickToBecomeSeller(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [becomeseller]); + // React.useEffect(() => { + // if(becomeseller) { + // handleClickToBecomeSeller(); + // } + // // eslint-disable-next-line react-hooks/exhaustive-deps + // }, [becomeseller]); const onLogout = () => { logout(); @@ -171,7 +166,7 @@ export const Navbar: React.FC = () => { ) } - { > setBusinessName(e)} /> setSelectedCountry(e)} title={t('country')} /> - + */} ); }; diff --git a/src/hooks/use-products-info/index.ts b/src/hooks/use-products-info/index.ts index 0080335c..a40f3d97 100644 --- a/src/hooks/use-products-info/index.ts +++ b/src/hooks/use-products-info/index.ts @@ -2,7 +2,7 @@ import { useProducts } from "@/contexts/products"; import { getProductsParams, PostQuickPurchaseType, ProductDetailsParams } from "@/contexts/products/types"; import { nuvannApi, nuvannPublicApi } from "@/services/api"; import { useNavigation } from "../useNavigation"; -import { RoutesUrls } from "@/utils/enums/routesUrl"; +import { RoutesUrls, RouteUrl } from "@/utils/enums/routesUrl"; import { useToast } from "@/contexts/toast"; export function useProductsInfo() { @@ -84,7 +84,7 @@ export function useProductsInfo() { productsDispatch({ type: 'SET_PRODUCT_DETAILS', value: response.data }); } catch (error: any) { - redirect(RoutesUrls.HOME as RoutesUrls) + redirect(RoutesUrls.HOME) errorToast(error.response.data.message); } finally { productsDispatch({ type: 'SET_LOADING', value: false }); @@ -97,7 +97,7 @@ export function useProductsInfo() { productsDispatch({ type: 'SET_QUICK_PURCHASE_LOADER', value: true }); try { const response = await nuvannApi.post(`/products/${productId}/quick-purchase`, data) - redirect(RoutesUrls.CHECKOUT + `?orderid=${response.data.order_id}` as RoutesUrls) + redirect(RoutesUrls.CHECKOUT + `?orderid=${response.data.order_id}` as RouteUrl) } catch (error: any) { errorToast(error.response.data.message); } finally { diff --git a/src/pages/_app.page.tsx b/src/pages/_app.page.tsx index aaa6d9c3..4d9f9d7c 100644 --- a/src/pages/_app.page.tsx +++ b/src/pages/_app.page.tsx @@ -22,7 +22,7 @@ import { Auth0Provider } from "@auth0/auth0-react"; import { SellerDetailsProvider } from "@/contexts/seller-details"; import useBeforeLeave from "@/hooks/use-befor-leave"; import { useNavigation } from "@/hooks/useNavigation"; -import { RoutesUrls } from "@/utils/enums/routesUrl"; +import { RoutesUrls, RouteUrl } from "@/utils/enums/routesUrl"; export default function App({ Component, pageProps }: AppProps) { const {redirect} = useNavigation(); @@ -40,7 +40,7 @@ export default function App({ Component, pageProps }: AppProps) { ? `${window.location.origin}${getRedirectUrl}` : window.location.origin; - redirect(redirectUrl as RoutesUrls); + redirect(redirectUrl as RouteUrl); } return ( <> diff --git a/src/pages/checkout/controller/checkout.controller.tsx b/src/pages/checkout/controller/checkout.controller.tsx index f78ddae4..1b493ab8 100644 --- a/src/pages/checkout/controller/checkout.controller.tsx +++ b/src/pages/checkout/controller/checkout.controller.tsx @@ -34,12 +34,17 @@ const schema = z.object({ name: z .string().min(1, "Name is required"), phoneNumber: z - .string() - .trim() - .min(1, "Phone is required") - .regex(/^[0-9]*$/, "Phone must be a number") // Garante que seja um número - .transform((val) => parseInt(val)), - zipCode: z.string().min(1, "Zip code is required").regex(/^[0-9]*$/, "Zip code must be a number"), + .string() + .trim() + .min(1, "Phone is required") + .regex( + /^(\+55|55)?\s?\(?\d{2}\)?\s?\d{5}-?\d{4}$/, + "Phone must be a valid Brazilian number (e.g., (55)49 99999-9999, 5549999999999, +5549999999999)" + ), + + zipCode: z.string() + .min(1, "Zip code is required") + .regex(/^\d{5}-?\d{3}$/, "Zip code must be a valid format (e.g., 99999999 or 99999-999)"), state_or_department: z.string().min(1, "State or department is required"), city: z.string().min(1, "City is required"), neighborhood: z.string().min(1, "Neighborhood is required"), diff --git a/src/pages/login.page.tsx b/src/pages/login.page.tsx index 16111ac8..c4798bd5 100644 --- a/src/pages/login.page.tsx +++ b/src/pages/login.page.tsx @@ -1,6 +1,6 @@ import { HomePageDefault } from '@/components/home-page-default'; import { useNavigation } from '@/hooks/useNavigation'; -import { RoutesUrls } from '@/utils/enums/routesUrl'; +import { RoutesUrls, RouteUrl } from '@/utils/enums/routesUrl'; import { useAuth0 } from '@auth0/auth0-react'; import { Backdrop, CircularProgress } from '@mui/material'; import React, { useEffect } from 'react' @@ -13,7 +13,7 @@ export default function LoginPage() { if (!isAuthenticated && !loading) { loginWithRedirect(); } else { - redirect(window.location.origin as RoutesUrls); + redirect(window.location.origin as RouteUrl); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isAuthenticated]); diff --git a/src/pages/orders-details/components/order-resume/index.tsx b/src/pages/orders-details/components/order-resume/index.tsx index 0f3caf18..d423bbad 100644 --- a/src/pages/orders-details/components/order-resume/index.tsx +++ b/src/pages/orders-details/components/order-resume/index.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'; import { Skeleton } from '@mui/material'; import { OrderItem } from '@/contexts/orders/types'; import Title from '../title'; -import { RoutesUrls } from '@/utils/enums/routesUrl'; +import { RoutesUrls, RouteUrl } from '@/utils/enums/routesUrl'; import { useNavigation } from '@/hooks/useNavigation'; import { useProductsInfo } from '@/hooks/use-products-info'; import { formatMoney } from '@/utils/formatter/format-money.util'; @@ -78,7 +78,7 @@ const OrdersResume: React.FC = (props: OrderResumeProps) => { {t('name')}:{' '} redirect(`${RoutesUrls.SELLER_DETAILS}?orderId=${order?.seller?.business_account_id}&name=${encodeURIComponent(order?.seller?.name)}&country=${encodeURIComponent(order.seller.country.name)}&createdAt=${encodeURIComponent(order.seller.created_at)}` as RoutesUrls)} + onClick={() => redirect(`${RoutesUrls.SELLER_DETAILS}?orderId=${order?.seller?.business_account_id}&name=${encodeURIComponent(order?.seller?.name)}&country=${encodeURIComponent(order.seller.country.name)}&createdAt=${encodeURIComponent(order.seller.created_at)}` as RouteUrl)} > {order?.seller?.name} diff --git a/src/pages/orders/components/order-card/index.tsx b/src/pages/orders/components/order-card/index.tsx index f2ea03d0..f553aa21 100644 --- a/src/pages/orders/components/order-card/index.tsx +++ b/src/pages/orders/components/order-card/index.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import Image from 'next/image'; import Styles from './order-card.module.scss'; import { Order, OrderItem } from '@/contexts/orders/types'; -import { RoutesUrls } from '@/utils/enums/routesUrl'; +import { RoutesUrls, RouteUrl } from '@/utils/enums/routesUrl'; import { useNavigation } from '@/hooks/useNavigation'; import CustomButton from '@/components/custom-button'; import { formatDate } from '@/utils/date-convert'; @@ -141,7 +141,7 @@ const OrderCard: React.FC = ({ order }) => { - redirect(`${RoutesUrls.ORDERS_DETAILS}?orderId=${item.id}` as RoutesUrls) + redirect(`${RoutesUrls.ORDERS_DETAILS}?orderId=${item.id}` as RouteUrl) } > {t('see_more')} diff --git a/src/pages/product/[id]/components/details/index.tsx b/src/pages/product/[id]/components/details/index.tsx index 1ea394b9..17754ecf 100644 --- a/src/pages/product/[id]/components/details/index.tsx +++ b/src/pages/product/[id]/components/details/index.tsx @@ -9,7 +9,7 @@ import CustomButton from '@/components/custom-button'; import { AiOutlineShoppingCart } from 'react-icons/ai'; import { useTranslation } from 'react-i18next'; import { DetailsProps } from '../../types'; -import { RoutesUrls } from '@/utils/enums/routesUrl'; +import { RoutesUrls, RouteUrl } from '@/utils/enums/routesUrl'; import { useNavigation } from '@/hooks/useNavigation'; export default function Details(props: DetailsProps) { @@ -34,9 +34,11 @@ export default function Details(props: DetailsProps) { } = props; const redirectToSellerDetails = () => { - redirect(`${RoutesUrls.SELLER_DETAILS}?sellerId=${props.productInfos.seller.business_account_id}&name=${encodeURIComponent(props.productInfos.seller.name)}&country=${encodeURIComponent(props.productInfos.seller.country.name)}&createdAt=${encodeURIComponent(props.productInfos.seller.created_at)}` as RoutesUrls) + redirect(`${RoutesUrls.SELLER_DETAILS}?sellerId=${props.productInfos.seller.business_account_id}&name=${encodeURIComponent(props.productInfos.seller.name)}&country=${encodeURIComponent(props.productInfos.seller.country.name)}&createdAt=${encodeURIComponent(props.productInfos.seller.created_at)}` as RouteUrl); }; + const disabledButtons = productInfos?.available_amount < qty || !productInfos?.available_in_current_country + return (
@@ -104,7 +106,14 @@ export default function Details(props: DetailsProps) { decrement={onDecrement} disabled={productInfos?.available_amount < qty} /> - + { + productInfos?.available_in_current_country ? '' : +
+

{t('not_available_message')}

+
+ }
{t('add_to_cart')} @@ -123,7 +132,7 @@ export default function Details(props: DetailsProps) { backgroundColor="#00B127" textColor='#fff' onClick={onPurchase} - disabled={productInfos?.available_amount < qty} + disabled={disabledButtons} > {t('buy_now')} diff --git a/src/pages/search/controller/search.controller.tsx b/src/pages/search/controller/search.controller.tsx index e03113e7..e80be7b4 100644 --- a/src/pages/search/controller/search.controller.tsx +++ b/src/pages/search/controller/search.controller.tsx @@ -5,7 +5,7 @@ import { HomePageDefault } from '@/components/home-page-default'; import { useProductsInfo } from '@/hooks/use-products-info'; import { getProductsParams } from '@/contexts/products/types'; import { useNavigation } from '@/hooks/useNavigation'; -import { RoutesUrls } from '@/utils/enums/routesUrl'; +import { RoutesUrls, RouteUrl } from '@/utils/enums/routesUrl'; import { useCategoriesInfo } from '@/hooks/use-categories-info'; export default function SearchController() { @@ -31,14 +31,14 @@ export default function SearchController() { }, [search, category_id, in_promotion]) const handleRedirectToProductDetails = React.useCallback( (id: string | number) => { - redirect(`/product/${id}` as RoutesUrls) + redirect(`/product/${id}` as RouteUrl) }, [redirect]) const handleChangeFilter = React.useCallback( (categoryId: string, inPromotion: boolean) => { setDefaultCheckedPromotion(inPromotion); setCategoryID(categoryId); setOpenMobileFilter(false); - redirect(`/search?search=${search || ''}&category_id=${categoryId}&in_promotion=${inPromotion}` as RoutesUrls) + redirect(`/search?search=${search || ''}&category_id=${categoryId}&in_promotion=${inPromotion}` as RouteUrl) // eslint-disable-next-line react-hooks/exhaustive-deps }, [Boolean(in_promotion)]) diff --git a/src/pages/seller-details/controller/seller-details.controller.tsx b/src/pages/seller-details/controller/seller-details.controller.tsx index 158e893f..25c1ca77 100644 --- a/src/pages/seller-details/controller/seller-details.controller.tsx +++ b/src/pages/seller-details/controller/seller-details.controller.tsx @@ -5,7 +5,7 @@ import SellerDetails from '../view'; import SellerCardSkeleton from '../components/seller-card-skeleton'; import { useSellerDetailsInfo } from '@/hooks/use-seller-details-info'; import { useNavigation } from '@/hooks/useNavigation'; -import { RoutesUrls } from '@/utils/enums/routesUrl'; +import { RoutesUrls, RouteUrl } from '@/utils/enums/routesUrl'; export default function SellerDetailsController() { const router = useRouter(); @@ -19,7 +19,7 @@ export default function SellerDetailsController() { const { products, isLoading } = useSellerDetailsInfo(sellerId as string); const handleRedirectToProductDetails = React.useCallback((id: string | number) => { - redirect(`/product/${id}` as RoutesUrls); + redirect(`/product/${id}` as RouteUrl); }, [redirect]); return ( diff --git a/src/pages/seller-onboarding/components/hero-stepper/hero-stepper.module.scss b/src/pages/seller-onboarding/components/hero-stepper/hero-stepper.module.scss new file mode 100644 index 00000000..65b642fb --- /dev/null +++ b/src/pages/seller-onboarding/components/hero-stepper/hero-stepper.module.scss @@ -0,0 +1,59 @@ +.seller_onboarding_hero_stepper { + height: 500px; + display: flex; + justify-content: center; + flex-direction: column; + padding: 0 16px; + + @media (max-width: 1024px) { + height: auto; + } +} + +.stepper_content { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 64px; + gap: 32px; + + h1 { + color: var(--blue-principal-000052); + margin-bottom: 16px; + font-size: 32px; + + @media (max-width: 768px) { + font-size: 28px; + } + + @media (max-width: 480px) { + font-size: 24px; + text-align: center; + } + } + + p { + color: rgb(119, 114, 114); + font-size: 1.125rem; + line-height: 1.75rem; + + @media (max-width: 768px) { + font-size: 1rem; + line-height: 1.5rem; + } + + @media (max-width: 480px) { + text-align: center; + } + } + + @media (max-width: 1024px) { + gap: 16px; + } + + @media (max-width: 768px) { + flex-direction: column; + align-items: center; + text-align: center; + } +} diff --git a/src/pages/seller-onboarding/components/hero-stepper/index.tsx b/src/pages/seller-onboarding/components/hero-stepper/index.tsx new file mode 100644 index 00000000..3ef743a6 --- /dev/null +++ b/src/pages/seller-onboarding/components/hero-stepper/index.tsx @@ -0,0 +1,43 @@ +import { Step, StepLabel, Stepper } from '@mui/material'; +import React from 'react'; +import Styles from './hero-stepper.module.scss'; + +const SellerOnboardingHeroStepper: React.FC = () => { + const steps = [ + 'Select master blaster campaign settings', + 'Create an ad group', + 'Create an ad', + ]; + + return ( +
+
+ + {steps.map((label) => ( + + + + ))} + +
+ +
+
+

Apply to shop and start earning today

+

Sign up now and see why over 600,000 shoppers choose Instacart for flexible earnings.

+
+
+

Apply to shop and start earning today

+

Sign up now and see why over 600,000 shoppers choose Instacart for flexible earnings.

+
+ +
+

Apply to shop and start earning today

+

Sign up now and see why over 600,000 shoppers choose Instacart for flexible earnings.

+
+
+
+ ); +}; + +export default SellerOnboardingHeroStepper; diff --git a/src/pages/seller-onboarding/components/seller-onboarding-hero/hero.module.scss b/src/pages/seller-onboarding/components/seller-onboarding-hero/hero.module.scss new file mode 100644 index 00000000..adb43c6c --- /dev/null +++ b/src/pages/seller-onboarding/components/seller-onboarding-hero/hero.module.scss @@ -0,0 +1,81 @@ +.seller_onboarding_hero{ + display: grid; + grid-template-columns: 53.5% 41%; + gap: 0px 32px; + height: 480px; + + .hero_content { + display: flex; + justify-content: center; + flex-direction: column; + align-content: center; + height: 100%; + gap: 32px 0; + + h1 { + margin-top: 32px; + font-size: 4.5vw; + line-height: 1.2; + color: var(--blue-principal-000052); + } + p { + color: rgb(119, 114, 114); + font-size: 1.125rem; + line-height: 1.75rem; + } + } + + .hero_image { + background-image: url('../../../../../public/assets/hero/heroOnboarding.svg'); + background-repeat: no-repeat; + background-position: center; + background-size: 100%; + object-fit: cover; + } +} + +@media (max-width: 768px) { + + .seller_onboarding_hero{ + grid-template-columns: 1fr; + height: 100%; + margin-bottom: 16px; + .hero_content { + display: flex; + justify-content: center; + text-align: center; + h1 { + font-size: 36px; + } + p { + font-size: 0.9rem; + } + + button { + align-self: center; + } + } + .hero_image { + height: 300px; + margin: 32px 0; + } + } + +} + +@media (max-width: 480px) { + .hero_content { + display: flex; + justify-content: center; + h1 { + font-size: 28px; + } + p { + font-size: 0.8rem; + } + } + + .hero_image { + height: 200px; + } +} \ No newline at end of file diff --git a/src/pages/seller-onboarding/components/seller-onboarding-hero/index.tsx b/src/pages/seller-onboarding/components/seller-onboarding-hero/index.tsx new file mode 100644 index 00000000..eda487a8 --- /dev/null +++ b/src/pages/seller-onboarding/components/seller-onboarding-hero/index.tsx @@ -0,0 +1,98 @@ +import CustomButton from '@/components/custom-button'; +import React from 'react'; +import Styles from './hero.module.scss' +import { useUserInfo } from '@/hooks/use-user-info'; +import ModalActions from '@/components/modal-actions'; +import CustomInput from '@/components/custom-input'; +import CustomSelect from '@/components/custom-select'; +import { useCountriesInfo } from '@/hooks/use-countries-info'; +import { useTranslation } from 'react-i18next'; +import { formatCountriesArray } from '@/utils/format-countries-array'; +import cookie from '@/utils/cookie'; +import { generateRandomString } from '@/utils/generate-random-string'; +import { useAuth0 } from '@auth0/auth0-react'; +import { UserRoles } from '@/utils/enums/user.enum'; + +interface selectedCountry { + label: string; + value: string; +} + +const SellerOnboardingHero: React.FC = () => { + const { t } = useTranslation("home"); + const {countries, loading} = useCountriesInfo(); + const { + getAccessTokenSilently, + user, + logout, isAuthenticated, + loginWithRedirect: handleLogin, +} = useAuth0(); +const { + getUserInfo, + user: userInfos, + isLoading: userInfosLoader, + token, +} = useUserInfo(); + + const { + handleBecomeSeller, + modalTerm, + setModalTerm, + isLoading, + } = useUserInfo(); + + const [businessName, setBusinessName] = React.useState(""); + const [selectedCountry, setSelectedCountry] = React.useState([]); + + const handleClickBecomeSeller = async () => { + if(!isAuthenticated) { + return handleLogin(); + } + cookie.setCookie({name: 'nuvann_store_referral', days: 1, value: generateRandomString(24), domain: process.env.NEXT_PUBLIC_COOKIE_DOMAIN || ''}); + if(Array.isArray(userInfos?.roles) && userInfos?.roles?.some(role => [UserRoles.SELLER, UserRoles.ADMINISTRATOR]?.includes(role))) { + return window.open(process.env.NEXT_PUBLIC_DASHBOARD_ACCESS_URL as string, '_blank'); + } + setModalTerm(true) + } + + return ( +
+
+
+

{t('seller_hero_title')}

+

{t('seller_hero_desc')}

+ handleClickBecomeSeller()} + > + {t('become_a_seller_button')} + +
+
+ +
+
+ + { + handleBecomeSeller({ + business_name: businessName, + country: selectedCountry + }) + }} + > + setBusinessName(e)} /> + setSelectedCountry(e)} title={t('country')} /> + +
+ ); +}; + +export default SellerOnboardingHero; diff --git a/src/pages/seller-onboarding/controller/seller-onboarding.controller.tsx b/src/pages/seller-onboarding/controller/seller-onboarding.controller.tsx new file mode 100644 index 00000000..49b53e4c --- /dev/null +++ b/src/pages/seller-onboarding/controller/seller-onboarding.controller.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { HomePageDefault } from '@/components/home-page-default'; +import SellerOnboarding from '../view/seller-onboarding.view'; + +export default function SellerOnboardingController() { + + + return ( + + + + ); +} diff --git a/src/pages/seller-onboarding/index.page.tsx b/src/pages/seller-onboarding/index.page.tsx new file mode 100644 index 00000000..de8ce7f8 --- /dev/null +++ b/src/pages/seller-onboarding/index.page.tsx @@ -0,0 +1,3 @@ +import SellerOnboardingController from "./controller/seller-onboarding.controller"; + +export default SellerOnboardingController; \ No newline at end of file diff --git a/src/pages/seller-onboarding/view/seller-onboarding.view.tsx b/src/pages/seller-onboarding/view/seller-onboarding.view.tsx new file mode 100644 index 00000000..d890f69a --- /dev/null +++ b/src/pages/seller-onboarding/view/seller-onboarding.view.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import SellerOnboardingHero from '../components/seller-onboarding-hero'; +import SellerOnboardingHeroStepper from '../components/hero-stepper'; + +export default function SellerOnboarding() { + + return ( +
+ + +
+ ); +} diff --git a/src/services/api.ts b/src/services/api.ts index 7b9f8738..5f6b93d8 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -74,7 +74,8 @@ nuvannPublicApi.interceptors.request.use( const selectedLanguage = getCookie('NEXT_I18LANG'); config.headers = { ...config.headers, - 'Accept-Language' : selectedLanguage || process.env.NEXT_I18LANG + 'Accept-Language' : selectedLanguage || process.env.NEXT_I18LANG, + 'X-Country-Code' : config.headers['X-Country-Code'] }; return config; }, diff --git a/src/utils/enums/routesUrl.ts b/src/utils/enums/routesUrl.ts index 4edd4df3..aedc7ce2 100644 --- a/src/utils/enums/routesUrl.ts +++ b/src/utils/enums/routesUrl.ts @@ -9,6 +9,7 @@ export enum RoutesUrls { SELLER_DETAILS = '/seller-details', Login = '/login', PROFILE = '/profile', + SellerOnboarding = '/seller-onboarding', } export type RouteUrl =