<commit_before>import React, { useState, useCallback, useEffect } from 'react';
import PropTypes from 'prop-types';
import Modal from 'react-bootstrap4-modal';
import { CardElement, injectStripe } from 'react-stripe-elements';
import classNames from 'classnames';
import { Redirect } from 'react-router-dom';
import { useMutation, useQuery } from '@apollo/react-hooks';

import BootstrapFormInput from '../BuiltInFormControls/BootstrapFormInput';
import ErrorDisplay from '../ErrorDisplay';
import formatMoney from '../formatMoney';
import { LazyStripeElementsWrapper } from '../LazyStripe';
import LoadingIndicator from '../LoadingIndicator';
import PoweredByStripeLogo from '../images/powered_by_stripe.svg';
import { PurchaseTicket } from './mutations.gql';
import { TicketPurchaseFormQuery } from './queries.gql';
import useAsyncFunction from '../useAsyncFunction';
import { findCurrentValue } from '../ScheduledValueUtils';
import Checkmark from '../EventsApp/TeamMemberAdmin/Checkmark';
import usePageTitle from '../usePageTitle';
import useValueUnless from '../useValueUnless';
import PageLoadingIndicator from '../PageLoadingIndicator';

function TicketPurchaseForm({ stripe }) {
  const { data, loading, error: queryError } = useQuery(TicketPurchaseFormQuery);
  const availableTicketTypes = (queryError || loading
    ? []
    : data.convention.ticket_types.filter((ticketType) => ticketType.publicly_available));
  const [ticketType, setTicketType] = useState(null);
  const [name, setName] = useState(((data || {}).myProfile || {}).name_without_nickname || '');
  const [ticket, setTicket] = useState(null);
  const [purchaseTicket] = useMutation(PurchaseTicket);

  useEffect(
    () => {
      if (!loading) {
        if (availableTicketTypes.length === 1) {
          setTicketType(availableTicketTypes[0]);
        }
      }
    },
    [availableTicketTypes, loading],
  );

  const [submitPayment, error, submitting] = useAsyncFunction(useCallback(
    async () => {
      const { token, error: stripeError } = await stripe.createToken({ name });

      if (stripeError) {
        throw stripeError;
      }

      const purchaseResponse = await purchaseTicket({
        variables: {
          ticketTypeId: ticketType.id,
          stripeToken: token.id,
        },
      });
      setTicket(purchaseResponse.data.purchaseTicket.ticket);
    },
    [purchaseTicket, ticketType, name, stripe],
  ));

  usePageTitle(useValueUnless(() => `Buy a ${data.convention.ticket_name}`, queryError || loading));

  if (loading) {
    return <PageLoadingIndicator visible />;
  }

  if (queryError) {
    return <ErrorDisplay graphQLError={queryError} />;
  }

  if (data.myProfile && data.myProfile.ticket) {
    return <Redirect to="/" />;
  }

  const disabled = (!ticketType || submitting);

  const renderTicketTypeSelect = () => (
    <div className="d-flex">
      {availableTicketTypes.map((type) => {
        const { pricing_schedule: pricingSchedule, id, description } = type;
        const currentPrice = findCurrentValue(pricingSchedule);
        return (
          <button
            className={classNames(
              'btn text-left',
              {
                'btn-outline-primary': (ticketType || {}).id !== id,
                'btn-primary': (ticketType || {}).id === id,
              },
            )}
            type="button"
            onClick={() => { setTicketType(type); }}
          >
            <div className="d-flex align-items-center">
              <div>
                <strong>{description}</strong>
                <br />
                {formatMoney(currentPrice)}
              </div>
              <Checkmark value={(ticketType || {}).id === id} className="ml-2" />
            </div>
          </button>
        );
      })}
    </div>
  );

  const renderPaymentSection = () => (
    <div>
      <hr />
      <ErrorDisplay graphQLError={error} />

      <BootstrapFormInput
        name="name"
        label="Name"
        value={name}
        onTextChange={setName}
      />

      <div>
        <CardElement
          className="form-control mb-4"
          disabled={disabled || submitting}
          style={{
            base: {
              lineHeight: 1.5,
              fontSize: '16px',
            },<commit_msg>Accessibility and UI updates for ticket type selection<commit_after>import React, { useState, useCallback, useEffect } from 'react';
import PropTypes from 'prop-types';
import Modal from 'react-bootstrap4-modal';
import { CardElement, injectStripe } from 'react-stripe-elements';
import classNames from 'classnames';
import { Redirect } from 'react-router-dom';
import { useMutation, useQuery } from '@apollo/react-hooks';
import { capitalize } from 'inflected';

import BootstrapFormInput from '../BuiltInFormControls/BootstrapFormInput';
import ErrorDisplay from '../ErrorDisplay';
import formatMoney from '../formatMoney';
import { LazyStripeElementsWrapper } from '../LazyStripe';
import LoadingIndicator from '../LoadingIndicator';
import PoweredByStripeLogo from '../images/powered_by_stripe.svg';
import { PurchaseTicket } from './mutations.gql';
import { TicketPurchaseFormQuery } from './queries.gql';
import useAsyncFunction from '../useAsyncFunction';
import { findCurrentValue } from '../ScheduledValueUtils';
import Checkmark from '../EventsApp/TeamMemberAdmin/Checkmark';
import usePageTitle from '../usePageTitle';
import useValueUnless from '../useValueUnless';
import PageLoadingIndicator from '../PageLoadingIndicator';

function TicketPurchaseForm({ stripe }) {
  const { data, loading, error: queryError } = useQuery(TicketPurchaseFormQuery);
  const availableTicketTypes = (queryError || loading
    ? []
    : data.convention.ticket_types.filter((ticketType) => ticketType.publicly_available));
  const [ticketType, setTicketType] = useState(null);
  const [name, setName] = useState(((data || {}).myProfile || {}).name_without_nickname || '');
  const [ticket, setTicket] = useState(null);
  const [purchaseTicket] = useMutation(PurchaseTicket);

  useEffect(
    () => {
      if (!loading) {
        if (availableTicketTypes.length === 1) {
          setTicketType(availableTicketTypes[0]);
        }
      }
    },
    [availableTicketTypes, loading],
  );

  const [submitPayment, error, submitting] = useAsyncFunction(useCallback(
    async () => {
      const { token, error: stripeError } = await stripe.createToken({ name });

      if (stripeError) {
        throw stripeError;
      }

      const purchaseResponse = await purchaseTicket({
        variables: {
          ticketTypeId: ticketType.id,
          stripeToken: token.id,
        },
      });
      setTicket(purchaseResponse.data.purchaseTicket.ticket);
    },
    [purchaseTicket, ticketType, name, stripe],
  ));

  usePageTitle(useValueUnless(() => `Buy a ${data.convention.ticket_name}`, queryError || loading));

  if (loading) {
    return <PageLoadingIndicator visible />;
  }

  if (queryError) {
    return <ErrorDisplay graphQLError={queryError} />;
  }

  if (data.myProfile && data.myProfile.ticket) {
    return <Redirect to="/" />;
  }

  const disabled = (!ticketType || submitting);

  const renderTicketTypeSelect = () => (
    <div className="btn-group-vertical btn-group-toggle w-100" role="group" aria-label={`${capitalize(data.convention.ticket_name)} type`}>
      {availableTicketTypes.map((type) => {
        const { pricing_schedule: pricingSchedule, id, description } = type;
        const currentPrice = findCurrentValue(pricingSchedule);
        return (
          <label
            className={classNames(
              'btn text-left btn-outline-primary',
              {
                active: ticketType?.id === id,
              },
            )}
            onClick={() => { setTicketType(type); }}
          >
            <input
              type="radio"
              name="ticket_type"
              checked={ticketType?.id === id}
              onChange={() => { setTicketType(type); }}
              aria-labelledby={`ticket-type-label-${id}`}
            />
            <div className="d-flex align-items-center" id={`ticket-type-label-${id}`}>
              <div className="flex-grow-1">
                <strong>{description}</strong>
                {' '}
                &mdash;
                {' '}
                {formatMoney(currentPrice)}
              </div>
              <Checkmark value={(ticketType || {}).id === id} className="ml-2" />
            </div>
          </label>
        );
      })}
    </div>
  );

  const renderPaymentSection = () => (
    <div>
      <hr />
      <ErrorDisplay graphQLError={error} />

      <BootstrapFormInput
        name="name"
        label="Name"
        value={name}
        onTextChange={setName}
      />

      <div>
        <CardElement
          className="form-control mb-4"
          disabled={disabled || submitting}
          style={{
            base: {
              lineHeight: 1.5,
              fontSize: '16px',
            },
{'fraction_non_alphanumeric': 0.13849739207635112, 'fraction_numerical': 0.002441460437243369, 'mean_word_length': 2.642683912691997, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 60, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1553026', 'n_tokens_mistral': 2596, 'n_tokens_neox': 2511, 'n_words': 533}