Создание системы подписки с помощью Stripe и Vue.js

Здравствуйте 🖐🏼, в этом руководстве я покажу вам, как создать систему подписки с помощью Vue.js и Stripe. Наша рабочая среда — это Vue.js Options API, Vue Router и Express.js в качестве бэкенд-менеджера. Для UI/UX я использую Vuetify. Если вы ищете интеграцию Vue 3 Composition API и TypeScript, посмотрите мой репозиторий Vue 3 Stripe Subscriptions. Из-за обширности этого руководства я оставляю ссылку на мой сайт; там лучше визуализация.

Создание системы подписки с помощью Stripe и Vue js | CodingPR

Узнайте, как построить систему подписки с помощью Stripe и Vue js Options API.

codingpr.com

Если у вас нет проекта, вы можете скопировать мой здесь:
vue-stripe-subscriptions .

1. Настройка Stripe.

Сначала давайте настроим наше окружение. Скопируйте в свой env-файл публикуемый ключ из панели инструментов stripe; вы можете найти этот ключ в разделе разработчика панели инструментов. Создайте два продукта в разделе продуктов панели инструментов: базовый план за пять долларов и премиум-план за десять. Скопируйте идентификаторы продуктов в файл env.


      VUE_APP_STRIPE_KEY=<YOUR-PUBLISHABLE-KEY>
      VUE_APP_BASIC_PLAN=<YOUR-BASIC-PLAN>
      VUE_APP_PREMIUM_PLAN=<YOUR-PREMIUM-PLAN>

Вход в полноэкранный режим Выйдите из полноэкранного режима
  • После того как вы открыли счет в Stripe, скопируйте тег script в head файла index.html.

    <head>
      <script src="https://js.stripe.com/v3/"></script>
    </head>

Вход в полноэкранный режим Выйдите из полноэкранного режима

2. Интеграция.

Наш первый шаг по интеграции Stripe в Vue.js — это создание события on-click, когда клиент хочет подписаться на ваш сервис подписки. Мы собираем email и полное имя клиента; в продакшене вы должны собирать дополнительную информацию, например, адрес клиента.


    <v-card-actions>
      <v-btn
        id="stripeBtn"
        class="mb-2"
        block
        :loading="loading"
        @click="Signup"
      >
        Sign Up
      </v-btn>
    </v-card-actions>

Вход в полноэкранный режим Выход из полноэкранного режима
  • В этом блоке try and catch мы отправляем в бэкенд личные данные клиента, которые мы собрали в форме регистрации. Если мы получим ответ, то выведем на экран представление плана с идентификатором клиента в качестве параметра. О том, как настроить передачу параметров между представлениями, читайте в документации Vue Router.

    // methods
    import PostService from '../post-service'

    async Signup() {
      const { email, fullname } = this
      try {
        const res = await PostService.createCust(
          email,
          fullname
        )

        if (res.data.customer) {
          this.$router.push({
            name:'Plan',
            params: {
              fullName: fullname,
              customerId: res.data.customer
            },
            props: true
          })
        }

      } catch (error) {
        this.alert1 = true;
        this.alertTxt = 'Error, Try again!'
      }
    }

Вход в полноэкранный режим Выход из полноэкранного режима
  • Создайте файл в корне папки src, задача этого файла — отправлять http-запросы на бэкенд с помощью Axios.

    import axios from 'axios';

    const url = 'http://localhost:3000/api/posts';

    class PostService {
      // Create customer
      static async createCust(email, fullname) {
        const res = await axios.post(url, {
          email, fullname
        });
        return res;
      }
      // Create subscription
      static async createSubs(customerId, priceId) {
        const res = await axios.post(`${url}/subs`, {
          customerId, priceId
        });
        return res;
      }
      // Delete subscription
      static async delete(subscriptionId) {
        const res = await axios.post(`${url}/delete`, {
          subscriptionId,
        });
        return res;
      }
    }
    export default PostService;

Вход в полноэкранный режим Выйти из полноэкранного режима
  • После получения ответа от сервера с идентификатором клиента, Vue Router перейдет ко второму шагу; ваш клиент должен выбрать тарифный план. Сделайте две кнопки с двумя разными событиями при нажатии. Одна из них предназначена для подписки на пятидолларовый план, а другая — на десятидолларовый.

    <v-card-actions>
      <v-btn
        id="btnColor"
        :disabled="disabled"
        class="mx-auto mb-2"
        @click="subsPlan1"
      >
        Select
      </v-btn>
    </v-card-actions>
    <v-card-actions>
      <v-btn
        id="btnColor"
        :disabled="disabled2"
        class="mx-auto mb-2"
        @click="subsPlan2"
      >
        Seclect
      </v-btn>
    </v-card-actions>

Вход в полноэкранный режим Выход из полноэкранного режима
  • Функция создания подписки получит параметры плана, который выберет клиент, плюс реквизиты из первого шага. Эта функция отправит в бэкенд идентификатор клиента и идентификатор цены и создаст подписку; если данные ответа будут хорошими, то будет выведено представление оформления заказа с параметрами.

    props: {
      fullName: String,
      customerId: String
    },

    data: () => ({
      disabled: false,
      disabled2: false,
      alert2: false,
      alertTxt: '',
    }),

    methods: {
      async createSubscription(priceId, price, plan) {
        const {fullName, customerId } = this
        try {
          const res = await PostService.createSubs(
            customerId,
            priceId,
          )

          if (res.data) {
            const subscriptionId = res.data.subscriptionId
            const clientSecret = res.data.clientSecret
            this.$router.push({
              name: 'Checkout',
              params: {
                fullName,
                price,
                plan,
                clientSecret,
                subscriptionId
              }
            })
          }

        } catch (err) {
          this.alert2 = true
          this.disabled = false
          this.alertTxt = 'An error has occurred. Try again later'
        }
      },

      async subsPlan1() {
        const priceId = process.env.VUE_APP_BASIC_PLAN
        const price = '5.00'
        const plan = 'Basic'
        this.disabled = true
        this.disabled2 = false
        await this.createSubscription(priceId, price, plan)
      },

      async subsPlan2() {
        const priceId = process.env.VUE_APP_PREMIUM_PLAN
        const price = '10.00'
        const plan = 'Premium'
        this.disabled2 = true
        this.disabled = false
        await this.createSubscription(priceId, price, plan)
      }
    }

Вход в полноэкранный режим Выход из полноэкранного режима

3. Монтаж элемента карточки.

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


    <!-- Stripe Element-->
    <div
      ref="card"
      class="inputCard"
    />

    <!-- Error messages in this element -->
    <div
      id="card-errors"
      role="alert"
    />
    <br>
    <v-alert
      v-model="alert"
      color="red"
      dense
      dismissible
      type="error"
    >
      <!-- alertTxt -->
    </v-alert>
    <v-btn
      id="stripeBtn"
      class="my-3"
      block
      :loading="loading"
      @click="Submit"
    >
      Pay with Stripe
    </v-btn>

Вход в полноэкранный режим Выход из полноэкранного режима
  • Используйте секрет клиента для доступа к функции Stripe «подтвердить оплату картой». Внутри этой функции отправьте метод оплаты и информацию о биллинге клиента; проверьте список параметров, которые вы можете отправить в Stripe. Если подписка прошла успешно, выведите благодарственное представление с идентификатором подписки в качестве параметра.

    import PostService from '../post-service'

    const stripe = window.Stripe(process.env.VUE_APP_STRIPE_KEY)

    // Create an instance of Elements.
    const elements = stripe.elements()
    const style = {
      base: {
        color: '#32325d',
        fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
        fontSmoothing: 'antialiased',
        fontSize: '16px',
        '::placeholder': {
          color: '#aab7c4',
        },
      },
      invalid: {
        color: '#fa755a',
        iconColor: '#fa755a',
      },
    };

    const card = elements.create('card', { style: style })

    export default {
      props: {
        fullName: String,
        price: String,
        plan: String,
        clientSecret: String,
        subscriptionId: String
      },

      mounted() {
        card.mount(this.$refs.card)

        card.on('change', (event) => {
          this.displayError(event)
        })
      },

      methods: {
        displayError(event) {
          const displayError = document.getElementById('card-errors')
          if (event.error) {
            displayError.textContent = event.error.message
          } else {
            displayError.textContent = ''
          }
        },

        async Submit() {
          this.loading = true
          const { clientSecret, fullName, alert, alertTxt, loading } = this
          const result = await stripe.confirmCardPayment(clientSecret, {
            payment_method: {
              type: 'card',
              card: card,
              billing_details: {
                name: fullName,
              }
            }
          })

          if (result.error) {
            alert = true
            alertTxt = result.error.message
            loading = false
          } else {
            // Successful subscription payment
            // The subscription automatically becomes active upon payment.
            this.$router.push({
              name: 'ThankYou',
              params: {
                subscriptionId: this.subscriptionId
              }
            })
          }
        }
      }
    }

Вход в полноэкранный режим Выход из полноэкранного режима

Ознакомьтесь с бэкендом здесь: Система подписки с Stripe и Express

Оцените статью
devanswers.ru
Добавить комментарий