EscolaLMS/Front

View on GitHub
src/components/Cart/CartContent/stripe.tsx

Summary

Maintainability
D
2 days
Test Coverage
import { useState } from "react";
import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next";
import Layout from "@/components/_App/Layout";
import { Title } from "@escolalms/components/lib/components/atoms/Typography/Title";
import { Text } from "@escolalms/components/lib/components/atoms/Typography/Text";
import { CheckoutCard } from "@escolalms/components/lib/components/molecules/CheckoutCard/CheckoutCard";
import { CartCard } from "@escolalms/components/lib/components/molecules/CartCard/CartCard";
import { Button } from "@escolalms/components/lib/components/atoms/Button/Button";
import { Link as ComponentLink } from "@escolalms/components/lib/components/atoms/Link/Link";
import { CartItem } from "@escolalms/sdk/lib/types/api";
import { isMobile } from "react-device-detect";
import Preloader from "@/components/_App/Preloader";
import Collapse from "@/components/Common/Collapse";
import PaymentForm from "@/components/Cart/PaymentForm";

import {
  useStripe,
  useElements,
  CardNumberElement,
} from "@stripe/react-stripe-js";
import CoursesSlider from "@/components/Courses/CoursesSlider";
import Breadcrumbs from "@/components/Common/Breadcrumbs";
import Placeholder from "../../../images/image.svg";
import { Col, Row } from "react-grid-system";
import Container from "@/components/Common/Container";
import { formatPrice } from "@/utils/index";
import CartSuccess from "@/components/Cart/CartSuccess";
import routeRoutes from "@/components/Routes/routes";
import { CartPageStyled } from "@/components/Cart/CartContent/styles";
import usePayment from "@/hooks/usePayment";
import { toast } from "@/utils/toast";

const StripeContent = ({ stripeKey }: { stripeKey: string }) => {
  const {
    processing,
    setProcessing,
    discountStatus,
    fetchCart,
    payByStripe,
    removeFromCart,
    courses,
    cart,
    location,
    realizeVoucher,
    push,
    setDiscountStatus,
  } = usePayment();

  const { t } = useTranslation();

  const stripe = useStripe();
  const elements = useElements();

  const [billingDetails, setBillingDetails] = useState<{ name: string }>({
    name: "",
  });

  const isTestKey = stripeKey.includes("_test_");

  const handleSubmit = (): void => {
    if (!billingDetails.name) {
      toast(`${t("Cart.EmptyNameWarning")}`, "error");
      return;
    }

    if (!stripe || !elements) {
      toast(`${t("UnexpectedError")}`, "error");
      return;
    }
    const cardNumber = elements.getElement(CardNumberElement);
    cardNumber && setProcessing(true);
    cardNumber &&
      stripe
        .createPaymentMethod({
          type: "card",
          card: cardNumber,
          billing_details: billingDetails,
        })
        .then((res) => {
          if (res.error) {
            setProcessing(false);
            toast(res.error.message, "error");
            console.log(res.error);
          } else {
            payByStripe(res?.paymentMethod?.id);
            setTimeout(() => {
              setProcessing(false);
            }, 3000);
          }
        })
        .catch(() => {
          setProcessing(false);
          toast(`${t("UnexpectedError")}`, "error");
        });
  };
  if (location.search.includes("?status=success")) {
    return <CartSuccess />;
  }
  return (
    <Layout metaTitle={t("Cart.Cart")}>
      <CartPageStyled $isMobile={isMobile}>
        <Container>
          {!(cart.value?.items.length === 0) ? (
            <Row>
              <Col lg={9}>
                <Breadcrumbs
                  items={[
                    <Link to={routeRoutes.home}>{t("Home")}</Link>,
                    <Text size="12">{t("Cart.YourCart")}</Text>,
                  ]}
                />

                <div className="module-wrapper">
                  <Title level={4}>{t<string>("Cart.YourCart")}</Title>
                  <div className="products-container">
                    {cart.value?.items.map((item: CartItem) => (
                      <CheckoutCard
                        key={item.id}
                        mobile={isMobile}
                        img={{
                          src: item.product?.poster_url || Placeholder,
                          alt: item.product?.name || "",
                        }}
                        title={item.product?.name}
                        // subtitle="5 lekcji"
                        price={`${formatPrice(
                          item.product?.price,
                          item.product?.tax_rate
                        )} zł`}
                        oldPrice={
                          item.product?.price_old
                            ? `${formatPrice(
                                item.product?.price_old,
                                item.product?.tax_rate
                              )} zł`
                            : undefined
                        }
                        handleDelete={() =>
                          removeFromCart(Number(item.product?.id))
                        }
                      />
                    ))}
                  </div>
                </div>
                <div className="module-wrapper">
                  <Title level={4}>
                    {t<string>("Cart.ChoosePaymentMethod")}
                  </Title>
                  <div className="payments-form">
                    <div className="collapse-wrapper">
                      <Collapse active title={t<string>("Cart.CreditCard")}>
                        <PaymentForm
                          setBillingDetails={setBillingDetails}
                          billingDetails={billingDetails}
                        />
                      </Collapse>
                    </div>

                    {isTestKey && (
                      <div className="card-info">
                        <Text size="14">
                          {t("Cart.UseTestCard")}:{" "}
                          <ComponentLink
                            href="https://docs.wellms.io/getting-started/demo.html"
                            target="_blank"
                            rel="noreferrer nofollow"
                          >
                            {t("Cart.LearnMore")}
                          </ComponentLink>
                        </Text>
                      </div>
                    )}
                  </div>
                </div>
                <section className="slider-section">
                  <Title level={4}>{t<string>("Cart.Interest")}</Title>
                  {courses && courses.list && (
                    <CoursesSlider courses={courses.list.data} />
                  )}
                </section>
              </Col>
              <Col lg={3}>
                <Title style={{ marginBottom: 20 }} level={4} as="h3">
                  {t<string>("Cart.Summary")}
                </Title>
                <div className="summary-box-wrapper">
                  <CartCard
                    mobile={isMobile}
                    onBuyClick={() => handleSubmit()}
                    id={1}
                    title={`${formatPrice(
                      Number(cart.value?.total_with_tax || 0)
                    )} zł`}
                    discount={{
                      onDiscountClick: (discountValue) =>
                        realizeVoucher(discountValue)
                          .then((response) => {
                            if (response.success) {
                              setDiscountStatus("granted");
                              fetchCart();
                            } else {
                              setDiscountStatus("error");
                            }
                          })
                          .catch(() => {
                            setDiscountStatus("error");
                          }),
                      onDeleteDiscountClick: () => console.log("clicked"),
                      status: discountStatus,
                    }}
                  />
                </div>
              </Col>
            </Row>
          ) : (
            <>
              <div className="empty-cart">
                <Title level={3}>{t<string>("Cart.EmptyCartTitle")}</Title>
                <Text>{t<string>("Cart.EmptyCartText")}</Text>
                <Button
                  mode="secondary"
                  onClick={() => push(routeRoutes.courses)}
                >
                  {t<string>("Cart.EmptyCartBtnText")}
                </Button>
              </div>
              <section className="slider-section">
                <Title level={4}>{t<string>("Cart.Interest")}</Title>
                {courses && courses.list && (
                  <CoursesSlider courses={courses.list.data} />
                )}
              </section>
            </>
          )}
        </Container>
        {(cart.loading || processing) && <Preloader />}
      </CartPageStyled>
    </Layout>
  );
};

export default StripeContent;