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/invoice.tsx
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { useState } from "../app-framework";6import { Row, Col } from "../antd-bootstrap";7import { Icon } from "../components";8import { open_popup_window } from "../misc/open-browser-tab";9import { capitalize, stripeDate } from "@cocalc/util/misc";10import { render_amount } from "./util";11import { InvoiceMap, InvoiceLineMap } from "./types";1213interface Props {14invoice: InvoiceMap;15}1617export const Invoice: React.FC<Props> = ({ invoice }) => {18const [hide_line_items, set_hide_line_items] = useState<boolean>(true);1920function download(e): void {21e.preventDefault();22const url = invoice.get("hosted_invoice_url");23if (url) {24open_popup_window(url as string);25}26return;27}2829function render_paid_status(): JSX.Element {30// The status of the invoice: one of draft, open, paid, uncollectible, or void31const status = capitalize(invoice.get("status") ?? "");32if (invoice.get("hosted_invoice_url")) {33return (34<a35style={status == "Open" ? { color: "red" } : undefined}36onClick={download}37>38{status == "Open" ? " Click here to pay..." : status}39</a>40);41} else {42return <span>{status}</span>;43}44}4546function render_description(): JSX.Element {47const cnt = invoice.getIn(["lines", "total_count"]) ?? 0;48if (hide_line_items && cnt > 0) {49// This is much more useful as a summary than the totally generic description we usually have...50return (51<span>52{invoice.getIn(["lines", "data", 0, "description"])}53{cnt > 1 ? ", etc." : ""}54</span>55);56}57if (invoice.get("description")) {58return <span>{invoice.get("description")}</span>;59} else {60// This is what the description always is when it is non-empty, and it seems useful enough...61return <span>Thank you for using CoCalc by Sagemath, Inc.</span>;62}63}6465function render_line_description(line: InvoiceLineMap): string[] {66const v: string[] = [];67if (line.get("quantity") > 1) {68v.push(`${line.get("quantity")} × `);69}70if (line.get("description") != null) {71v.push(line.get("description"));72}73if (line.get("plan") != null) {74v.push(line.getIn(["plan", "name"]));75v.push(` (start: ${stripeDate(line.getIn(["period", "start"]))})`);76}77return v;78}7980function render_line_item(line: InvoiceLineMap, n): JSX.Element {81return (82<Row key={line.get("id")} style={{ borderBottom: "1px solid #aaa" }}>83<Col sm={1}>{n}.</Col>84<Col sm={9}>{render_line_description(line)}</Col>85<Col sm={2}>86{render_amount(line.get("amount"), invoice.get("currency"))}87</Col>88</Row>89);90}9192function render_tax(): JSX.Element {93return (94<Row key="tax" style={{ borderBottom: "1px solid #aaa" }}>95<Col sm={1} />96<Col sm={9}>WA State Sales Tax ({invoice.get("tax_percent")}%)</Col>97<Col sm={2}>98{render_amount(invoice.get("tax"), invoice.get("currency"))}99</Col>100</Row>101);102}103104function render_line_items(): undefined | JSX.Element | JSX.Element[] {105if (invoice.get("lines") == null) return;106if (hide_line_items) {107return (108<a109href=""110onClick={(e) => {111e.preventDefault();112set_hide_line_items(false);113}}114>115(show details)116</a>117);118} else {119const v: JSX.Element[] = [];120v.push(121<a122key="hide"123href=""124onClick={(e) => {125e.preventDefault();126set_hide_line_items(true);127}}128>129(hide details)130</a>131);132let n = 1;133for (const line of invoice.getIn(["lines", "data"], [] as any)) {134v.push(render_line_item(line, n));135n += 1;136}137if (invoice.get("tax")) {138v.push(render_tax());139}140return v;141}142}143144const style: React.CSSProperties = {145borderBottom: "1px solid #999",146padding: hide_line_items ? "0" : "15px 0",147margin: "0",148};149return (150<Row style={style}>151<Col md={1}>152{render_amount(invoice.get("amount_due"), invoice.get("currency"))}153</Col>154<Col md={1}>{render_paid_status()}</Col>155<Col md={2}>{stripeDate(invoice.get("created"))}</Col>156<Col md={6}>157{render_description()} {render_line_items()}158</Col>159<Col md={2}>160<a onClick={download} href="">161<Icon name="external-link" />162{hide_line_items ? "" : " Download..."}163</a>164</Col>165</Row>166);167};168169170