Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layout 342 footer #349

Merged
merged 11 commits into from
May 6, 2024
Merged
11 changes: 4 additions & 7 deletions src/entities/Payments/Payments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,19 @@ type TPayments = {

type Logo = {
image: string
title: string
url: string
}

/** платежная система
* @param {string} image - путь к картинке
* @param {string} title - название
* @param {string} url - путь к сайту
* @param {url: string, image: string} data[] массив платежных систем
*/
const Payments: FC<TPayments> = ({ data }) => {
return (
<ul className={styles.payments}>
{data.footer.additional_logos.map(logo => (
<li className={styles['payment-nav']} key={logo.title}>
<Link to={logo.url} className={styles['payment-item']}>
<img className={styles['payment-icon']} src={logo.image} title={logo.title} alt={logo.title} />
<li className={styles['payment-nav']} key={logo.url}>
<Link to={logo.url} className={styles['payment-item']} target="_blank">
<img className={styles['payment-icon']} src={logo.image} title={logo.url} alt={logo.url} />
</Link>
</li>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@
&_footer {
max-width: 570px;
row-gap: 10px;

@include media.respond-to('large') {
max-width: 100%;
margin-bottom: 70px;
}
}

&_subscribe {
max-width: 740px;
width: 740px;
row-gap: 20px;
}
}
Expand All @@ -24,9 +29,11 @@
padding: 3px 3px 3px 14px;
border-radius: 5px;
position: relative;
border: 2px solid transparent;
transition: border-color 0.4s;

&:focus-within {
outline: 2px solid var.$theme-primary-color;
border-color: var.$theme-primary-color;
}

&_footer {
Expand All @@ -36,12 +43,28 @@
&_subscribe {
background-color: var.$white;
}

@include media.respond-to('large') {
margin-top: 20px;
}
}

.form > input {
&::placeholder {
color: var.$theme-primary-color;
transition: color 0.25s ease-in-out;
.field {
width: 100%;
padding: 10px 16px;
border: none;
outline: none;
box-shadow: none;
font-size: 14px;
font-weight: 400;
line-height: 1.5;

&_footer {
color: var.$white;
}

&_subscribe {
color: var.$black;
}

&:focus {
Expand All @@ -51,6 +74,20 @@
}
}

.span {
font-size: 14px;
font-weight: 400;
line-height: 1.5;

&_footer {
color: var.$white;
}

&_subscribe {
color: var.$black;
}
}

.button {
padding: 14px 21px;
display: flex;
Expand Down Expand Up @@ -96,6 +133,11 @@
font-size: 16px;
font-weight: 500;
line-height: 16px;

@include media.respond-to('xl') {
font-size: 14.5px;
line-height: 1;
}
}

&_subscribe {
Expand All @@ -110,7 +152,7 @@

@include media.respond-to('large') {
display: flex;
font-size: 16px;
font-size: 15px;
font-weight: 400;
line-height: 16px;
}
Expand Down
23 changes: 23 additions & 0 deletions src/features/SubscribeForm/SubscribeForm.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Meta, StoryObj } from '@storybook/react'

import SubscribeForm from './SubscribeForm'

const meta = {
title: 'features/SubscribeForm',
component: SubscribeForm,
parameters: {
layout: 'centered'
}
} as Meta<typeof SubscribeForm>

export default meta
type Story = StoryObj<typeof meta>

export const Default: Story = {
args: {
type: 'footer',
onSubmit: () => {
alert('Действие по сабмиту формы')
}
}
}
109 changes: 89 additions & 20 deletions src/features/SubscribeForm/SubscribeForm.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
import classNames from 'classnames'
import { type FC, FormEvent } from 'react'
import { Field, Form, Formik, FormikErrors, FormikTouched } from 'formik'
import { FormEvent, useState, type FC } from 'react'

import SubscribeIcon from '@/assets/images/subscriptionForm/icon-subsc.svg'
import { Input, InputSize, InputTheme } from '@/shared/ui/Input/Input'
import { useResize } from '@/shared/libs/hooks/useResize'
import { FormMsg } from '@/shared/ui/FormMsg/FormMsg'
import { EMsgType } from '@/shared/ui/FormMsg/model/types/types'
import Label from '@/shared/ui/Label/Label'
import Span from '@/shared/ui/Span/Span'

import styles from './subscribeForm.module.scss'
import { validationSchema } from './model/validationSchema/validationSchema'
import styles from './SubscribeForm.module.scss'

type TSubscribeForm = {
type: 'footer' | 'subscribe'
className?: string
onSubmit: (event: FormEvent<HTMLFormElement>) => void
onSubmit: () => void
}

// @TODO: Перевести форму на Formik + Yup
// https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/91
/**
* @param {string} type - определяет внешний вид для компонентов footer и для subscribe
* @param {string} className - нужно будет, если захотят переиспользовать компонент
* @param {string} className - для переопределения стилей <Form/>
* @param {string} onSubmit - функция для обработки формы
*/
const SubscribeForm: FC<TSubscribeForm> = ({ type, onSubmit, className = '' }) => {
const [showErrorMsg, setShowErrorMsg] = useState(false)
const { isScreenLg, isScreenMd, isScreenSm } = useResize()

const classNameContainer = classNames(styles.container, {
[styles.container]: true,
[styles.container_footer]: type === 'footer',
Expand All @@ -35,21 +42,83 @@ const SubscribeForm: FC<TSubscribeForm> = ({ type, onSubmit, className = '' }) =
[styles.form_footer]: type === 'footer',
[styles.form_subscribe]: type === 'subscribe'
})
const classNameField = classNames({
[styles.field]: true,
[styles.field_footer]: type === 'footer',
[styles.field_subscribe]: type === 'subscribe'
})
const classNameSpan = classNames({
[styles.span]: true,
[styles.span_footer]: type === 'footer',
[styles.span_subscribe]: type === 'subscribe'
})

const submitHandle = () => {
//@TODO: Доделать после появления эндпоинта на BE
onSubmit()
}

const preSubmitHandle = (
e: FormEvent<HTMLFormElement>,
touched: FormikTouched<{
email: string
}>,
errors: FormikErrors<{
email: string
}>
) => {
e.preventDefault()
setShowErrorMsg(Boolean(touched.email && errors.email))
}

return (
<div className={`${classNameContainer} ${className}`}>
{/* @TODO: Добавить компонент Label
https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/102 */}
<label className={classNameLabel}>Подписаться на рассылку</label>
<p className={styles.caption}>Мы не будем присылать вам спам. Только скидки и выгодные предложения</p>
<form className={classNameForm} onSubmit={onSubmit}>
<Input name="subscribe" placeholder="Эл.почта" theme={InputTheme.DARK} customSize={InputSize.S} />
<button className={styles.button}>
Подписаться
<SubscribeIcon className={styles.button__img} />
</button>
</form>
</div>
<Formik
initialValues={{
email: ''
}}
validationSchema={validationSchema}
onSubmit={submitHandle}>
{({ isSubmitting, errors, touched }) => (
<Form
className={`${classNameContainer} ${className}`}
onSubmit={e => {
preSubmitHandle(e, touched, errors)
}}>
<Label htmlFor={`email_${type}`} className={classNameLabel}>
Подписаться на рассылку
</Label>
{(isScreenSm || isScreenMd) && !isScreenLg && (
<Span className={classNameSpan}>
Мы не будем присылать вам спам. Только скидки и выгодные предложения
</Span>
)}
<div className={classNameForm}>
<Field
id={`email_${type}`}
name="email"
type="text"
className={classNameField}
placeholder="Эл. почта"
/>
<button className={styles.button} type="submit" disabled={isSubmitting}>
Подписаться
<SubscribeIcon className={styles.button__img} />
</button>
</div>
{showErrorMsg && errors.email && (
<FormMsg
text={errors.email || 'Ошибка валидации email!'}
isError={true}
closeHandle={() => {
setShowErrorMsg(false)
}}
disableClose={false}
type={EMsgType.popup}
/>
)}
</Form>
)}
</Formik>
)
}

Expand Down
2 changes: 2 additions & 0 deletions src/features/SubscribeForm/model/constants/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const EMAIL_VALIDATION_ERROR = 'E-mail адрес введён неверно!'
export const EMAIL_REQUIRED_ERROR = 'Укажите E-mail адрес!'
3 changes: 3 additions & 0 deletions src/features/SubscribeForm/model/types/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface ISubscribeFormValues {
email: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as Yup from 'yup'

import { EMAIL_REQUIRED_ERROR, EMAIL_VALIDATION_ERROR } from '../constants/constants'

export const validationSchema = Yup.object().shape({
email: Yup.string().required(EMAIL_REQUIRED_ERROR).email(EMAIL_VALIDATION_ERROR)
})
14 changes: 14 additions & 0 deletions src/shared/ui/FormMsg/FormMsg.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@
border-radius: 10px;
@include font(18px);

&_ispopup {
width: 300px;
opacity: 0;
position: fixed;
top: 50px;
left: -350px;
transition: all 0.5s;
}

&_popupIsOpen {
left: 50px;
opacity: 1;
}

&_iserror {
background-color: color.$promo-color;
}
Expand Down
4 changes: 2 additions & 2 deletions src/shared/ui/FormMsg/FormMsg.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const Succeed: Story = {
text: 'Данные успешно отправлены!',
isError: false,
disableClose: false,
closeHandel: () => {
closeHandle: () => {
alert('Выполненяются действия из переданной функции')
}
}
Expand All @@ -30,7 +30,7 @@ export const Error: Story = {
text: 'Ошибка отправки данных на сервер!',
isError: true,
disableClose: false,
closeHandel: () => {
closeHandle: () => {
alert('Выполненяются действия из переданной функции')
}
}
Expand Down
Loading
Loading