Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/frontend/billing/plan-info.tsx
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { PROJECT_UPGRADES } from "@cocalc/util/schema";6import { plural, capitalize } from "@cocalc/util/misc";7import { Component, Rendered } from "../app-framework";8import { Tip } from "../components/tip";9import { Icon } from "../components/icon";10import { Gap } from "../components/gap";11import { r_join } from "../components/r_join";12import { Button, Panel } from "@cocalc/frontend/antd-bootstrap";13import { PeriodName } from "./types";1415interface Props {16plan: string;17periods: PeriodName[];18selected?: boolean;19on_click?: Function;20}2122export class PlanInfo extends Component<Props> {23private render_plan_info_line(name: string, value: number, data): Rendered {24return (25<div key={name} style={{ marginBottom: "5px", marginLeft: "10px" }}>26<Tip title={data.display} tip={data.desc}>27<span style={{ fontWeight: "bold", color: "#444" }}>28{value * data.pricing_factor}{" "}29{plural(value * data.pricing_factor, data.pricing_unit)}30</span>31<Gap />32<span style={{ color: "#666" }}>{data.display}</span>33</Tip>34</div>35);36}3738private render_cost(price: string, period: string): Rendered {39period =40PROJECT_UPGRADES.period_names[period] != null41? PROJECT_UPGRADES.period_names[period]42: period;43return (44<span key={period} style={{ whiteSpace: "nowrap" }}>45<span style={{ fontSize: "16px", verticalAlign: "super" }}>$</span>46<Gap />47<span style={{ fontSize: "30px" }}>{price}</span>48<span style={{ fontSize: "14px" }}> / {period}</span>49</span>50);51}5253private render_price(prices: string[]): Rendered[] | Rendered {54if (this.props.on_click != null) {55// note: in non-static, there is always just *one* price56// (several only on "static" pages)57const result: Rendered[] = [];58for (let i = 0; i < prices.length; i++) {59result.push(60<Button key={i} bsStyle={this.props.selected ? "primary" : undefined}>61{this.render_cost(prices[i], this.props.periods[i])}62</Button>,63);64}65return result;66} else {67const result: Rendered[] = [];68for (let i = 0; i < prices.length; i++) {69result.push(this.render_cost(prices[i], this.props.periods[i]));70}71return <h3 style={{ textAlign: "left" }}>{r_join(result, <br />)}</h3>;72}73}7475private render_plan_name(plan_data): Rendered {76let name;77if (plan_data.desc != null) {78name = plan_data.desc;79if (name.indexOf("\n") !== -1) {80const v = name.split("\n");81name = (82<span>83{v[0].trim()}84<br />85{v[1].trim()}86</span>87);88}89} else {90name = capitalize(this.props.plan).replace(/_/g, " ") + " plan";91}92return (93<div style={{ paddingLeft: "10px" }}>94<Icon name={plan_data.icon} />{" "}95<span style={{ fontWeight: "bold" }}>{name}</span>96</div>97);98}99100public render(): Rendered {101const plan_data = PROJECT_UPGRADES.subscription[this.props.plan];102if (plan_data == null) {103return <div>Unknown plan type: {this.props.plan}</div>;104}105106const { params } = PROJECT_UPGRADES;107const prices: string[] = [];108for (const period of this.props.periods) {109prices.push(plan_data.price[period]);110}111const { benefits } = plan_data;112113const style = {114cursor: this.props.on_click != null ? "pointer" : undefined,115};116117return (118<Panel119style={style}120header={this.render_plan_name(plan_data)}121onClick={() =>122this.props.on_click != null ? this.props.on_click() : undefined123}124>125<Gap />126{PROJECT_UPGRADES.field_order127.filter((name) => benefits[name])128.map((name) =>129this.render_plan_info_line(130name,131benefits[name] != null ? benefits[name] : 0,132params[name],133),134)}135<Gap />136137<div style={{ textAlign: "center", marginTop: "10px" }}>138{this.render_price(prices)}139</div>140</Panel>141);142}143}144145146