Эта статья разделена на 4 части:
1. Пользовательский интерфейс с Material-UI
2. Создание форм
3. Сохранение пользовательского ввода с помощью React useContext
4. Реализация Stripe

Если вас интересует только то, как реализовать Stripe, сразу переходите к Части 4.

Теперь давайте создадим наши формы Material-UI.

ШАГ

src / views / Stepper.js

Как и в любой форме, у нас должна быть кнопка отправки, и у нас уже есть кнопка «Далее / Оплатить» в нижней части формы, поэтому было бы разумно использовать ее в качестве кнопки отправки. Но нам не нужна форма для последнего шага (шаг 3, поскольку это должна быть страница с благодарностью.

Для этого нам нужно обернуть его тегом формы. Итак, давайте изменим наш React-Fragment с помощью тега формы:

{
activeStep === 3
?
<Button onClick={handleReset} className={classes.button}>
    Reset
</Button>
:
<form className={classes.form} onSubmit={e => { e.preventDefault(); handleNext() }}>
    <Button disabled={activeStep === 0} className={classes.button} onClick={handleBack}>
         Back
     </Button>
     <Button variant="contained" color="primary" className={classes.button} type="submit">
         {activeStep === 2 ? 'Pay' : 'Next'}
    </Button>
</form>
}

Обратите внимание, что я удалил событие onClick с кнопки и переместил эту функцию в прослушиватель событий onSubmit тега формы.

И я добавил className, что означает, что был добавлен некоторый стиль:

const style = makeStyles(theme => ({
[...]
form: {
     display: "flex",
     flexDirection: "column",
     justifyContent: "space-around",
     width: "100%"
}

Приведенный выше код нарушает расположение кнопок, и теперь у вас должно получиться что-то вроде этого:

Однако кнопки «Далее» и «Назад» должны по-прежнему работать.

Итак, давайте исправим макет нашей формы, чтобы она была готова к приему различных элементов ввода.

  1. Переместите весь код внутрь компонента Grid, который был создан в первой части этой статьи и не использовался до сих пор.
  2. Добавьте контейнер сетки внутри формы с некоторым интервалом для целей проектирования (‹Интервал контейнера сетки = {3}›)
  3. Затем добавьте еще один контейнер / элемент сетки для кнопок, так как мы хотим, чтобы они находились внутри формы, но по-прежнему были отделены от остальных элементов ввода. Добавьте justify = ”flex-end”, чтобы переместить кнопки вправо.

Это должно выглядеть примерно так:

<Grid container spacing={3} 
      direction="column"
      justify="space-around"
      alignItems="center"
      style={{ height: "400px" }}
>
{activeStep === 3
?
<Button onClick={handleReset} className={classes.button}>
    Reset
</Button>
:
<form className={classes.form} onSubmit={e => { e.preventDefault(); handleNext() }}>
     <Grid container spacing={3}>
          <Grid container item justify="flex-end">
               <Button disabled={activeStep === 0}
                       className={classes.button}
                       onClick={handleBack}
               >
                    Back
               </Button>
               <Button variant="contained"
                       color="primary"
                       className={classes.button}
                       type="submit"
               >
                    {activeStep === 2 ? 'Pay' : 'Next'}
               </Button>
          </Grid>
     </Grid>
</form>
}
</Grid>

Мы внесли много изменений, поэтому на случай, если вы потерялись из виду, вот как должен выглядеть ваш файл Stepper.js:

И ваша страница должна выглядеть так:

ЕЩЕ РАЗ ВЕРСЫВАЕТСЯ С МАКЕТОМ?!?

ХОЧУ НЕКОТОРЫЕ СОДЕРЖАНИЕ !!!

Хорошо, я тебя слышу. Давайте наконец добавим немного контента.

Все еще в файле Stepper.js, но вне функции «Steppers», давайте добавим функцию StepContent (вы также можете создать файл StepContent.js, если хотите, и импортировать его в Stepper.js).

const StepContent = ({ step }) => {
     switch (step) {
          case 0:
          return "CONTACT FORM";
          case 1:
          return "SERVICE FORM";
          case 2:
          return "PAYMENT FORM";
          default:
          return <></>;
     }
}

Добавьте этот компонент в форму:

<form className={classes.form} onSubmit={e => { e.preventDefault(); handleNext() }}>
     <Grid container spacing={3}>
          <StepContent step={activeStep} />
          <Grid container item justify="flex-end">
              <Button disabled={activeStep === 0}
                      className={classes.button}
                      onClick={handleBack}
              >
                   Back
              </Button>

И ВУАЛЯ! Теперь у вас будет разный контент при каждом переключении между шагами.

Шутки в сторону?!

Я думал, что эта статья посвящена созданию форм Material-UI ?!

Хорошо, хорошо, хорошо ... Я закончил играть с файлом Stepper.js, теперь давайте создадим настоящие формы.

ФОРМА ОБРАТНОЙ СВЯЗИ

src / views / Forms / ContactForm.js

Для формы мы собираемся использовать TextField, Grid, Typography и Autocomplete из Material-UI, поэтому давайте импортируем их:

import {
     TextField,
     Grid,
     Typography
} from "@material-ui/core";
import Autocomplete from '@material-ui/lab/Autocomplete';

Я собираюсь начать с добавления заголовка, занимающего всю ширину формы (для этого я буду использовать xs = {12}. Важно, чтобы вы понимали разницу между атрибутами xs и sm компонента Grid. так как я буду использовать его для обертывания каждого входного компонента. Вы найдете документацию по этому здесь и, чтобы подвести итог, он используется для позиционирования компонента сетки пропорционально размеру экрана. Например, вам нужно, чтобы входные данные чтобы получить полную ширину на мобильном устройстве, но не на рабочем столе.

const ContactForm = () => {
     return <>
          <Grid item xs={12}>
               <Typography variant="h6">
                    Contact information
               </Typography>
          </Grid>
     </>
}

Обратите внимание, что я делаю его элементом сетки, но у него нет контейнера. Это потому, что я собираюсь вставить его в контейнер сетки, который мы создали ранее в Stepper.js.

Теперь давайте создадим наш первый элемент ввода

<Grid item xs={12} sm={4}>
     <TextField label="First Name"
                name="firstname"
                variant="outlined"
                required
                fullWidth
     />
</Grid>

Я создам 7 таких текстовых полей (имя, фамилия, адрес электронной почты, адресная строка 1, адресная строка 2, почтовый индекс и город) - последнее будет автозаполнением.

Я мог бы использовать цикл, но в этом случае я предпочел жестко закодировать все 7 из этих полей ввода, так как это немного, и я чувствовал, что с ним легче справиться.

Мне нужны имя, фамилия и адрес электронной почты в одной строке, поэтому я установил для этих двух значений sm = {4} (макс. 12 на строку, поэтому 3x4 = 12), но мне нужно только 2 поля ввода в следующей строке (адресная строка 1 и адресная строка 2), поэтому я установил sm = {6} (2x6 = 12).

ContactForm.js должен выглядеть так:

Давайте импортируем его в Stepper.js и добавим в функцию StepContent.

import ContactForm from "./Forms/ContactForm";
[...]
const StepContent = ({ step }) => {
     switch (step) {
          case 0:
          return <ContactForm />;
          case 1:
          return "SERVICE FORM";
          case 2:
          return "PAYMENT FORM";
          default:
          return <></>;
     }
}

И вы получите вот что:

Счастливы сейчас? Наконец-то красивая форма 😉

Не будем слишком в восторге, нам все еще не хватает автозаполнения для страны.

В этом примере я использую Material-UI версии V.4.9.11, а автозаполнение в настоящее время доступно только в лабораторной версии Material-UI.

Вы можете увидеть официальную документацию здесь.

Прежде всего нам нужно найти массив всех стран, потому что я не собираюсь делать это сам. Простой поиск в Google привел меня к CSS-трюкам. Возьмите массив объектов и назовите его страны.

Скопируйте / вставьте этот массив в конец файла ContactForm.js и добавьте автозаполнение в качестве последнего поля ввода.

<Grid item xs={12} sm={4}>
     <Autocomplete options={countries}
                   getOptionLabel={option => option.name}
                   renderInput={params => <TextField
                                               label="Country"
                                               name="country"
                                               variant="outlined"
                                               required
                                               fullWidth
                                               {...params}
                                           />
                                 }
     />
</Grid>

Теперь у нас есть первая форма, поэтому следующие формы будут проще простого.

УСЛУГА

src / views / Forms / ServiceForm.js

Я назвал это службой, так как обычно вы хотите, чтобы пользователь выбрал или написал, за какую услугу он платит, и я, честно говоря, понятия не имел, что туда поставить.

На этот раз я поместил 2 строки с заголовком и 2 поля ввода в каждой.

Импортируйте его в Stepper.js

import ServiceForm from "./Forms/ServiceForm";
[...]
const StepContent = ({ step }) => {
     switch (step) {
          case 0:
          return <ContactForm />;
          case 1:
          return <ServiceForm />;
          case 2:
          return "PAYMENT FORM";
          default:
          return <></>;
     }
}

Теперь мы готовы к последней форме ...

ПЛАТЕЖНАЯ ФОРМА

src / views / Forms / PaymentForm.js

Платежная форма должна включать:
• Фотографии всех принимаемых карт
• Сумму
• Валюту
• Номер кредитной карты
• Срок действия
• CVV

Stripe дает различные ссылки, где можно получить изображения различных кредитных карт здесь или, если хотите, вы можете взять ту, которую я использовал в своем git.

Сохраните все изображения в общей папке в папке под названием «карты».

Затем нам понадобится массив всех существующих валют, поскольку мы собираемся использовать автозаполнение для выбора валюты.

Опять же, вы можете найти это в Google или использовать тот, который у меня в git, внизу окончательного файла paymentForm, прямо здесь.

Вы уже знаете, как создавать TextField и Autocomplete, поэтому я просто дам вам код прямо (без полного массива валют, так как это сделает код слишком большим, но я, конечно, ожидаю, что вы туда поместите).

Обратите внимание на вызов массива «cardsLogo», я использовал его, чтобы показать, какие карты доступны в моей форме оплаты.

Вы также увидите, что я добавил «InputLabelProps = {{shrink: true}» в поля кредитной карты, потому что позже мы подключим этот TextField к Stripe, и по умолчанию он добавит заполнитель, поэтому вы не хотите поместите свою метку поверх заполнителя.

И снова добавьте эту последнюю форму в Stepper.js

import PaymentForm from "./Forms/PaymentForm";
[...]
const StepContent = ({ step }) => {
     switch (step) {
          case 0:
          return <ContactForm />;
          case 1:
          return <ServiceForm />;
          case 2:
          return <PaymentForm />;
          default:
          return <></>;
     }
}

СОВЕТ: Если вы не хотите заполнять все обязательные поля каждый раз для перехода между шагами, измените значение по умолчанию «activeStep» в Stepper.js
«Const [activeStep, setActiveStep] = useState (2);»

И ВУАЛЯ! Все формы готовы к заполнению.

Следующим шагом является сбор всех данных, чтобы их можно было отправить в Stripe. О да, я забыл упомянуть, но я не сохраняю какие-либо из этих данных в базе данных, я просто пересылаю их Stripe, который позаботится об этом за меня - в противном случае вам придется много раз проходить через свой сайт. сложных правил, вы можете прочитать об этом здесь.

Давайте перейдем к третьей части: