Простой компонент подписки с React и стилизованными компонентами

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

Если вы еще не знакомы с Гэтсби, уделите несколько минут и прочтите мою предыдущую статью.

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

Давайте начнем!

Создайте компонент подписки React в Gatsby

Для компонента выше я буду использовать следующую структуру:

  • Обертка, служащая контейнером для внутренних компонентов и контролирующая выравнивание формы подписки.
  • Заглавный компонент
  • Текстовый компонент
  • Компонент формы для двух полей ввода и кнопки

Поэтому мне понадобятся отдельные файлы для каждого из этих компонентов. Итак, в папке проекта создайте для каждого компонента новый файл с именем «ComponentName.js».

Я начну с заголовка и текста:

// File Title.js
import React from "react";
import styled from "styled-components";
const StyledH3 = styled.h3`
  font-size: 1.5rem;
  line-height: 2rem;
  font-weight: 600;
  color: #3F3D56;
  display: block;
  margin: ${(props) =>
    props.isCentered ? `1rem auto` : `1rem 0`};
`;
export const Heading = ({ ...props }) => {
  return (
    <StyledH3 isCentered={props.isCentered}>
       {props.heading}
    </StyledH3>
   );
};

В файле Text.js добавьте следующий код:

// File Text.js
import React from "react";
import styled from "styled-components";
const StyledTextMedium = styled.p`
  font: inherit;
  font-size: 1rem;
  line-height: 1.25rem;
  margin-bottom: 1rem;
  color: #3F3D56;
`;
export const TextMedium = ({ textMedium }) => (
  <StyledTextMedium>{textMedium}</StyledTextMedium>
);

Затем создайте новый файл с именем Column.js и добавьте следующий компонент:

import React from "react";
import styled from "styled-components";
export const Column = styled.div`
  display: flex;
  flex-flow: column wrap;
  justify-content: ${props => (props.isCentered? `center` : `flex-start`)};
  align-items: ${props => (props.isCentered? `center` : `flex-start`)};
  align-content: stretch;
  flex-basis: 1;
  margin: 2vw;
  padding: 2vw;
  border-radius: 2rem;
${props => (props.isFloating? 
    `transition: all .3s cubic-bezier(.165,.84,.44,1);  
    
      &:hover {
        transform:  translateY(-0.5rem);
        box-shadow: 0 9px 21px 0 ${colors.colorContentLight};
      }
    ` : ` `)};
  }
`
const StyledColumn100 = styled(Column)`
  width: calc(100% - 4rem);
  flex-basis: 1;
  margin-bottom: 1.25rem;
`;

export const Column100 = ({ children, ...props }) => (
  <StyledColumn100
    isFloating={props.isFloating}
    isCentered={props.isCentered}
  >
    {children}
  </StyledColumn100>
);

Теперь мы можем определить скелет компонента Subscribe, собрав вышеперечисленные и добавив недостающие части.

В папке компонентов создайте новую подпапку для хранения компонента и добавьте два файла: Subscribe.js для разметки и style.js для стиля.

В файл Subscribe.js добавьте следующий код:

import React from "react";
import { TextMedium } from "../Text.js";
import {
  SubscribeRow,
  SubscribeField,
  StyledSubscribe,
  StyledSubscribeButton,
  SubscribeFieldsContainer,
} from "./style.js";
import { Column100 } from "../Column.js";
import { Heading } from "../Title.js";
const SubscribeButton = ({ buttonText, buttonLink }) => (
  <StyledSubscribeButton to={buttonLink}>
    {buttonText}
  </StyledSubscribeButton>
);
const Subscribe = () => {
 return (
    <StyledSubscribe>
      <SubscribeRow>
        <Column100>
          <Heading/>
          <TextMedium
            textMedium="Receive actionable content strategy & marketing articles
            directly in your inbox."
          />
          <SubscribeFieldsContainer>
            <SubscribeField
              type="email"
              id="email"
              name="email"
              placeholder="Your email address*"
              value="email"
              required="required"
            />
            <SubscribeField
              type="text"
              id="firstName"
              name="firstName"
              placeholder="Your name"
              value="firstName"
            />
            <SubscribeButton
              buttonText="Sign up"
              buttonLink=""
            />
          </SubscribeFieldsContainer>
        </Column100>
      </SubscribeRow>
    </StyledSubscribe>
  );
};
export default Subscribe;

А вот стиль:

// File style.js, under /components/subscribe/
import styled from "styled-components"
export const StyledSubscribe = styled.form`
  display: flex;
  flex-flow: column wrap;
  justify-content: center;
  align-items: center;
  align-content: center;
  border-radius: 2rem;
  background-color: ${ props => (props.isLight ? `#FFF3F7` : `#4C4C78`)};
  color: #4C4C78;
  padding: 1.25rem;
  margin: ${ props => ( props.isCentered? "2vw auto" : "2vw 0")};
`
export const SubscribeRow = styled.div`
  margin-bottom: 1.5rem;
  width: 80%;
  display: flex;
  flex-flow: row wrap;
  justify-content: ${props => (props.isCentered ? "center" : "flex-start")};
&:last-of-type {
    margin-bottom: 2rem;
  }
`
export const SubscribeField = styled.input`
  border: 2px solid transparent;
  border-radius: 2rem;
  flex-grow: 1;
  background: #FFFFFF;
  color: #4C4C78;
  padding: 1rem 2rem;
  font-size: 14px;
  margin-right: 0.75rem;
  margin-top: 0.75rem;
&::placeholder {
  font-family: ${fonts.fontPrimary};
  }
&:hover {
    border: 2px solid #e32248;
  }
&:focus {
    color: #e32248;
    border: 2px solid #e32248;
    outline: none;
  }
`
export const StyledFieldsContainer = styled.div`
  display: flex;
  flex-flow: row wrap;
  justify-content: ${(props) =>
    props.isCentered ? "center" : "flex-start"};
  align-content: center;
  align-items: center;
  margin: 1.25rem ${(props) => (props.isCentered ? "auto" : "0")}
    0;
  transition: all 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
a {
    margin-top: 0;
    margin-right: 2rem;
  }
`;
export const SubscribeLabel = styled.label`
  color: #4C4C78;
  font-size: 14px;
`
export const SubscribeButton = styled.button`
  text-decoration: none;
  flex-grow: 1;
  font: inherit;
  font-weight: 600;
  border-radius: 2rem;
  padding: 1rem 2rem;
  margin-top: 0.75rem;
  margin-right: 0.75rem;
  transition: all .3s cubic-bezier(0,.89,.44,1);  
`
export const StyledSubscribeButton = styled(SubscribeButton)`
  border: none;
  background: linear-gradient(
    to right,
    #e32248,
    #A31149);
  color: #FFFFFF;
&:hover {
    background: #FFFFFF;
    box-shadow: 0 9px 21px 0 #FFE1EC;
    -moz-box-shadow: 0 9px 21px 0 #FFE1EC;
    -webkit-box-shadow: 0 9px 21px 0 #FFE1EC;
    -webkit-text-fill-color: #e32248;
    cursor: pointer;
`
export const SubscribeButtonContainer = styled(ButtonContainer)`
  justify-content: ${(props) =>
    props.isCentered ? "center" : "flex-start"};
  width: 100%;
`;

Теперь ваш компонент готов, поэтому мы можем двигаться дальше и реализовать логику, необходимую для поддержки интеграции HubSpot.

Добавить состояние в компонент подписки React

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

//File Subscribe.js
import React, { useState } from "react";
import { TextMedium } from "../Text.js";
import {
  SubscribeRow,
  SubscribeField,
  StyledSubscribe,
  StyledSubscribeButton,
  SubscribeFieldsContainer,
} from "./style.js";
import { Column100 } from "../Column.js";
import { Heading } from "../Title.js";
const SubscribeButton = ({ buttonText, buttonLink }) => (
  <StyledSubscribeButton to={buttonLink}>
    {buttonText}
  </StyledSubscribeButton>
);
const Subscribe = () => {
const [firstName, setFirstname] = useState("");
const [email, setEmail] = useState("");
const handleSubmit = (event) => {
  event.preventDefault();
};
return (
    <StyledSubscribe method="POST" action="/subscribe-success/" onSubmit={handleSubmit}>
      <SubscribeRow isCentered>
        <Column100 isFloating>
          <Heading heading="Sign up for our newsletter" /
          <TextMedium
            textMedium="Receive actionable content strategy & marketing articles
            directly in your inbox."
          />
          <SubscribeFieldsContainer>
            <SubscribeField
              type="email"
              id="email"
              name="email"
              placeholder="Your email address*"
              value={email}
              onChange={ e => setEmail(e.target.value)}
              required="required"
            />
            <SubscribeField
              type="text"
              id="firstName"
              name="firstName"
              placeholder="Your name"
              value={firstName}    
              onChange={ e => setFirstname(e.target.value)}
            />
            <SubscribeButton
              buttonText="Sign up"
              buttonLink=""
            />
          </SubscribeFieldsContainer>
        </Column100>
      </SubscribeRow>
    </StyledSubscribe>
  );
};
export default Subscribe;

Итак, вот что я сделал:

  • В форму я добавил обработчик событий onSubmit, который вызывает функцию handleSubmit. Эта функция отправит данные, которые мы собираем из полей ввода, в HubSpot API.
  • В полях ввода я добавил в качестве значений значения состояния {firstName} и {email}.
  • Также я добавил обработчик событий onChange. Когда значение этого поля изменяется, установщик setFirstname изменяет значение firstName в состоянии на event.target.value, то есть то, что пользователь добавляет в поле ввода.
  • Функция handleSubmit пока мало что делает, но я добавил метод preventDefault(). Это препятствует тому, чтобы кнопка перенаправляла пользователя на другую страницу при отправке формы.

Теперь мы готовы к последнему шагу: интеграции HubSpot.

Интегрируйте форму HubSpot с Gatsby для компонента подписки

Сначала создайте новую учетную запись на HubSpot и выберите бесплатную опцию CRM. Когда вы закончите, перейдите на вкладку "Маркетинг" и нажмите "Формы".

Добавьте новую форму и настройте ее со следующими полями:

Затем нажмите «Опубликовать» и в открывшемся окне нажмите «Вставить код»:

Отсюда вам понадобятся portalId и formId.

Теперь перейдите в документацию по HubSpot API и посмотрите пример кода для отправки данных в API.

Следуя этому примеру, мы добавим приведенный ниже код в функциюhandleSubmit function:

var xhr = new XMLHttpRequest();
var url = "https://api.hsforms.com/submissions/v3/integration/submit/portalId/formId";
// In var url above, replace portalId and formId with your values from HubSpot.
// Example request JSON:
var data = {
  submittedAt: Date.now(),
  fields: [
    {
      name: "email",
      value: email,
    },
    {
      name: "firstname",
      value: firstName,
    },
  ],
  context: {
    pageUri: "subscribe-success",
    pageName: "Subscribe successful",
  },
};
var final_data = JSON.stringify(data);
xhr.open("POST", url);
// Sets the value of the 'Content-Type' HTTP request headers to 'application/json'
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    alert(xhr.responseText); // Returns a 200 response if the submission is successful.
  } else if (xhr.readyState == 4 && xhr.status == 400) {
    alert(xhr.responseText); // Returns a 400 error the submission is rejected.
  } else if (xhr.readyState == 4 && xhr.status == 403) {
    alert(xhr.responseText); // Returns a 403 error if the portal isn't allowed to post submissions.
  } else if (xhr.readyState == 4 && xhr.status == 404) {
    alert(xhr.responseText); //Returns a 404 error if the formGuid isn't found
  }
};
// Sends the request
xhr.send(final_data);

Вывод

Вот и все! Теперь ваша форма должна работать.

Если вы заполните его и нажмете кнопку отправки, данные будут отправлены в базу данных HubSpot, так что вы увидите всех подписчиков в CRM.

Надеюсь, вам понравился этот урок!