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/license-examples.tsx
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import {6discount_monthly_pct,7discount_yearly_pct,8MIN_QUOTE,9} from "@cocalc/util/licenses/purchase/consts";10import { Cost, User } from "@cocalc/util/licenses/purchase/types";11import { COLORS } from "@cocalc/util/theme";12import { Col, Row, Panel } from "@cocalc/frontend/antd-bootstrap";13import { React } from "../app-framework";14import { Icon, IconName, Gap } from "../components";1516// This component renders 3 price examples for licensed upgrades in a row1718export interface Example {19title: string;20icon: IconName;21user: User;22lines: { value: number; unit: string; resource: string }[];23price?: Cost;24price_monthly?: Cost; // optional, show monthly price25price_yearly?: Cost; // optional, show yearly price26period?: string;27}2829interface Props {30// only renders exactly 3 examples31examples: Example[];32show_discount_pct: boolean;33}3435export const LicenseExamples: React.FC<Props> = ({36examples,37show_discount_pct,38}: Props) => {39if (examples.length != 3) throw Error("I can only render exactly 3 examples");4041function render_example_line({ value, unit, resource }) {42const value_str =43value == Number.POSITIVE_INFINITY ? <span>∞</span> : value;44return (45<div key={value_str} style={{ marginBottom: "5px", marginLeft: "10px" }}>46<span style={{ fontWeight: "bold", color: "#444" }}>47{value_str} {unit}48</span>49<Gap />50<span style={{ color: COLORS.GRAY }}>{resource}</span>51</div>52);53}5455function render_price_number(56usd,57small,58large,59emph: boolean,60online: boolean,61descr?: string,62) {63const smallpx = `${small}px`;64const largepx = `${large}px`;65const e = emph ? { fontWeight: "bold" as "bold" } : { color: COLORS.GRAY };66const style = { ...{ whiteSpace: "nowrap" as "nowrap" }, ...e };67if (!online && usd < MIN_QUOTE) {68return (69<span style={{ fontSize: largepx, color: COLORS.GRAY_L }}>N/A</span>70);71} else {72return (73<span style={style}>74<span style={{ fontSize: smallpx, verticalAlign: "super" }}>$</span>75<Gap />76<span style={{ fontSize: largepx }}>{usd.toFixed(2)}</span>77{descr && <span style={{ fontSize: smallpx }}> / {descr}</span>}78</span>79);80}81}8283function render_example_price(price) {84return (85<>86{render_price_number(price.cost, 14, 30, false, false, "retail price")}87<br />88{render_price_number(89price.cost,9014,9130,92true,93true,94"purchased online",95)}96</>97);98}99100function render_single_price({ price }: { price?: Cost }) {101if (price == null) return;102return (103<div style={{ textAlign: "center", marginTop: "10px" }}>104{render_example_price(price)}105</div>106);107}108109function render_monthyear_price({110price_monthly,111price_yearly,112}: {113price_monthly?: Cost;114price_yearly?: Cost;115}) {116if (price_monthly == null || price_yearly == null) return;117const large = 26;118return (119<>120<table>121<tbody>122<tr>123<td></td>124<td>retail</td>125<th>online</th>126</tr>127<tr>128<td>monthly</td>129<td>130{render_price_number(131price_monthly.cost,13214,133large,134false,135false,136)}137</td>138<td>139{render_price_number(price_monthly.cost, 14, large, true, true)}140</td>141</tr>142<tr>143<th>yearly</th>144<td>145{render_price_number(146price_yearly.cost,14714,148large,149false,150false,151)}152</td>153<td>154{render_price_number(price_yearly.cost, 14, large, true, true)}155</td>156</tr>157</tbody>158</table>159</>160);161}162163function render_example(example: Example) {164const { title, icon, lines, period } = example;165const header = (166<div style={{ paddingLeft: "10px" }}>167<Icon name={icon} /> <span style={{ fontWeight: "bold" }}>{title}</span>168{period && <> ({period})</>}169</div>170);171return (172<Col sm={4} key={title}>173<Panel header={header}>174<Gap />175{lines.map((line) => render_example_line(line))}176<Gap />177178{render_single_price(example)}179{render_monthyear_price(example)}180</Panel>181</Col>182);183}184185function render() {186return <Row>{examples.map((ex) => render_example(ex))}</Row>;187}188189return (190<>191<h4>Examples</h4>192<p>193Here are three typical configurations. All parameters can be adjusted to194fit your needs. Listed upgrades are for each project. Exact prices may195vary. Below ${MIN_QUOTE} only online purchases are available.196{show_discount_pct && (197<>198{" "}199Compared to one-off purchases, the discounts are{" "}200{discount_monthly_pct}% for monthly and {discount_yearly_pct}% for201yearly subscriptions.202</>203)}204</p>205<Gap />206{render()}207<Gap />208</>209);210};211212213