text: /*
   *  This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
   *  License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
   */
  
  import {
    Button,
    ButtonToolbar,
    Row,
    Col,
    Well,
  } from "../antd-bootstrap";
  
  import { Component, React, Rendered, redux } from "../app-framework";
  
  import { ErrorDisplay, Loading } from "../r_misc";
  
  import { HelpEmailLink } from "../customize";
  
  import { powered_by_stripe } from "./util";
  import { load_stripe, StripeCard } from "./stripe";
  
  interface Props {
    on_close?: Function; // optionally called when this should be closed
    hide_cancel_button?: boolean;
  }
  
  const CARD_STYLE = {
    margin: "15px",
    border: "1px solid grey",
    padding: "30px",
    background: "white",
    borderRadius: "5px",
  };
  
  interface State {
    submitting: boolean;
    error: string;
    loading: boolean;
  }
  
  export class AddPaymentMethod extends Component<Props, State> {
    private mounted: boolean = false;
    private card?: StripeCard;
  
    constructor(props, state) {
      super(props, state);
      this.state = {
        submitting: false,
        error: "",
        loading: true,
      };
    }
  
    public async componentDidMount(): Promise<void> {
      this.mounted = true;
      const stripe = await load_stripe();
      if (!this.mounted) return;
      this.setState({ loading: false });
      const elements = stripe.elements();
      this.card = elements.create("card");
      if (this.card == null) throw Error("bug -- card cannot be null");
      this.card.mount("#card-element");
    }
  
    public componentWillUnmount(): void {
      this.mounted = false;
    }
  
    private async submit_payment_method(): Promise<void> {
      this.setState({ error: "", submitting: true });
      const actions = redux.getActions("billing");
      const store = redux.getStore('billing');
      if (store.get("customer") == null) {
        actions.setState({ continue_first_purchase: true });
      }
      const stripe = await load_stripe();
      let result: {
        error?: { message: string };
        token?: { id: string };
      } = {};
      try {
        result = await stripe.createToken(this.card);
        if (!this.mounted) return;
        if (result.error != null) {
          this.setState({ error: result.error.message });
          return;
        } else if (result.token != null) {
          await actions.submit_payment_method(result.token.id);
          if (!this.mounted) return;
        }
      } catch (err) {
        if (this.mounted) {
          result.error = { message: err.toString() }; // used in finally
          this.setState({ error: err.toString() });
        }
      } finally {
        if (this.mounted) {
          this.setState({ submitting: false });
          if (this.props.on_close != null && result.error == null)
            this.props.on_close();
        }
      }
    }
  
    private render_cancel_button(): Rendered {
      if (this.props.hide_cancel_button) return;
      return (
        <Button
          onClick={() =>
            this.props.on_close != null ? this.props.on_close() : undefined
          }
        >
          Cancel
        </Button>
      );
    }
  
    private render_add_button(): Rendered {
      return (
        <Button
          onClick={() => this.submit_payment_method()}
          bsStyle="primary"
          disabled={this.state.submitting}
        >
          {this.state.submitting ? <Loading /> : undefined} Add Credit Card
        </Button>
      );
    }
  
    private render_payment_method_buttons(): Rendered {
      return (
        <div>
          <Row>
            <Col sm={4}>{powered_by_stripe()}</Col>
            <Col sm={8}>
              <ButtonToolbar className="pull-right" style={{ marginTop: "10px" }}>
                {this.render_add_button()}
                {this.render_cancel_button()}
              </ButtonToolbar>
            </Col>
          </Row>
          <div style={{ color: "#666", marginTop: "15px" }}>
            (PayPal or wire transfers for non-recurring subscriptions above $50
            are also possible. Please email <HelpEmailLink />
            .)
          </div>
        </div>
      );
    }
  
    private render_error(): Rendered {
      if (this.state.error) {
        return (
          <ErrorDisplay
            error={this.state.error}
            onClose={() => this.setState({ error: "" })}
          />
        );
      }
    }
  
    private render_card(): Rendered {
      return (
        <div style={CARD_STYLE}>
          {this.state.loading ? <Loading theme="medium" /> : undefined}
          <div id="card-element">
            {/* a Stripe Element will be inserted here. */}
          </div>
        </div>
      );
    }
  
    public render(): Rendered {
      return (
        <Row>
          <Col sm={6} smOffset={3}>
            <Well style={{ boxShadow: "5px 5px 5px lightgray", zIndex: 2 }}>
              {this.render_card()}
              {this.render_error()}
              {this.render_payment_method_buttons()}
            </Well>
          </Col>
        </Row>
      );
    }
  }
  