mirror of https://github.com/zulip/zulip.git
ts: Convert `web/src/billing` module to TypeScript.
Converted all files inside `web/src/billing` to TypeScript.
This commit is contained in:
parent
1f4dd0705d
commit
13187ff8f6
|
@ -54,9 +54,9 @@ EXEMPT_FILES = make_set(
|
||||||
"web/src/assets.d.ts",
|
"web/src/assets.d.ts",
|
||||||
"web/src/attachments_ui.js",
|
"web/src/attachments_ui.js",
|
||||||
"web/src/avatar.js",
|
"web/src/avatar.js",
|
||||||
"web/src/billing/event_status.js",
|
"web/src/billing/event_status.ts",
|
||||||
"web/src/billing/helpers.js",
|
"web/src/billing/helpers.ts",
|
||||||
"web/src/billing/upgrade.js",
|
"web/src/billing/upgrade.ts",
|
||||||
"web/src/blueslip.ts",
|
"web/src/blueslip.ts",
|
||||||
"web/src/blueslip_stacktrace.ts",
|
"web/src/blueslip_stacktrace.ts",
|
||||||
"web/src/click_handlers.js",
|
"web/src/click_handlers.js",
|
||||||
|
|
|
@ -2,7 +2,7 @@ import $ from "jquery";
|
||||||
|
|
||||||
import * as helpers from "./helpers";
|
import * as helpers from "./helpers";
|
||||||
|
|
||||||
export function create_update_license_request() {
|
export function create_update_license_request(): void {
|
||||||
helpers.create_ajax_request(
|
helpers.create_ajax_request(
|
||||||
"/json/billing/plan",
|
"/json/billing/plan",
|
||||||
"licensechange",
|
"licensechange",
|
||||||
|
@ -12,31 +12,31 @@ export function create_update_license_request() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initialize() {
|
export function initialize(): void {
|
||||||
helpers.set_tab("billing");
|
helpers.set_tab("billing");
|
||||||
helpers.set_sponsorship_form();
|
helpers.set_sponsorship_form();
|
||||||
|
|
||||||
$("#update-card-button").on("click", (e) => {
|
$("#update-card-button").on("click", (e) => {
|
||||||
const success_callback = (response) => {
|
|
||||||
window.location.replace(response.stripe_session_url);
|
|
||||||
};
|
|
||||||
helpers.create_ajax_request(
|
helpers.create_ajax_request(
|
||||||
"/json/billing/session/start_card_update_session",
|
"/json/billing/session/start_card_update_session",
|
||||||
"cardchange",
|
"cardchange",
|
||||||
[],
|
[],
|
||||||
"POST",
|
"POST",
|
||||||
success_callback,
|
(response) => {
|
||||||
|
const response_data = helpers.stripe_session_url_schema.parse(response);
|
||||||
|
window.location.replace(response_data.stripe_session_url);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#update-licenses-button").on("click", (e) => {
|
$("#update-licenses-button").on("click", (e) => {
|
||||||
if (helpers.is_valid_input($("#new_licenses_input")) === false) {
|
if (!helpers.is_valid_input($("#new_licenses_input"))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const current_licenses = $("#licensechange-input-section").data("licenses");
|
const current_licenses: number = $("#licensechange-input-section").data("licenses");
|
||||||
const new_licenses = $("#new_licenses_input").val();
|
const new_licenses: number = Number.parseInt($("#new_licenses_input").val() as string, 10);
|
||||||
if (new_licenses > current_licenses) {
|
if (new_licenses > current_licenses) {
|
||||||
$("#new_license_count_holder").text(new_licenses);
|
$("#new_license_count_holder").text(new_licenses);
|
||||||
$("#current_license_count_holder").text(current_licenses);
|
$("#current_license_count_holder").text(current_licenses);
|
|
@ -1,10 +1,31 @@
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
|
import {z} from "zod";
|
||||||
|
|
||||||
import * as loading from "../loading";
|
import * as loading from "../loading";
|
||||||
|
|
||||||
import * as helpers from "./helpers";
|
import * as helpers from "./helpers";
|
||||||
|
|
||||||
function update_status_and_redirect(status_message, redirect_to) {
|
const stripe_response_schema = z.object({
|
||||||
|
session: z.object({
|
||||||
|
type: z.string(),
|
||||||
|
stripe_payment_intent_id: z.string().optional(),
|
||||||
|
status: z.string(),
|
||||||
|
event_handler: z
|
||||||
|
.object({
|
||||||
|
status: z.string(),
|
||||||
|
error: z
|
||||||
|
.object({
|
||||||
|
message: z.string(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
type StripeSession = z.infer<typeof stripe_response_schema>["session"];
|
||||||
|
|
||||||
|
function update_status_and_redirect(status_message: string, redirect_to: string): void {
|
||||||
$("#webhook-loading").hide();
|
$("#webhook-loading").hide();
|
||||||
$("#webhook-success").show();
|
$("#webhook-success").show();
|
||||||
$("#webhook-success").text(status_message);
|
$("#webhook-success").text(status_message);
|
||||||
|
@ -13,26 +34,26 @@ function update_status_and_redirect(status_message, redirect_to) {
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function show_error_message(message) {
|
function show_error_message(message: string): void {
|
||||||
$("#webhook-loading").hide();
|
$("#webhook-loading").hide();
|
||||||
$("#webhook-error").show();
|
$("#webhook-error").show();
|
||||||
$("#webhook-error").text(message);
|
$("#webhook-error").text(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function show_html_error_message(rendered_message) {
|
function show_html_error_message(rendered_message: string): void {
|
||||||
$("#webhook-loading").hide();
|
$("#webhook-loading").hide();
|
||||||
$("#webhook-error").show();
|
$("#webhook-error").show();
|
||||||
$("#webhook-error").html(rendered_message);
|
$("#webhook-error").html(rendered_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_session_complete_event(session) {
|
function handle_session_complete_event(session: StripeSession): void {
|
||||||
let message = "";
|
let message = "";
|
||||||
let redirect_to = "";
|
let redirect_to = "";
|
||||||
switch (session.type) {
|
switch (session.type) {
|
||||||
case "upgrade_from_billing_page":
|
case "upgrade_from_billing_page":
|
||||||
case "retry_upgrade_with_another_payment_method":
|
case "retry_upgrade_with_another_payment_method":
|
||||||
message = "We have received your billing details. Attempting to create charge...";
|
message = "We have received your billing details. Attempting to create charge...";
|
||||||
redirect_to = `/billing/event_status?stripe_payment_intent_id=${session.stripe_payment_intent_id}`;
|
redirect_to = `/billing/event_status?stripe_payment_intent_id=${session.stripe_payment_intent_id!}`;
|
||||||
break;
|
break;
|
||||||
case "free_trial_upgrade_from_billing_page":
|
case "free_trial_upgrade_from_billing_page":
|
||||||
message =
|
message =
|
||||||
|
@ -52,27 +73,29 @@ function handle_session_complete_event(session) {
|
||||||
update_status_and_redirect(message, redirect_to);
|
update_status_and_redirect(message, redirect_to);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function stripe_checkout_session_status_check(stripe_session_id) {
|
async function stripe_checkout_session_status_check(stripe_session_id: string): Promise<boolean> {
|
||||||
const response = await $.get("/json/billing/event/status", {stripe_session_id});
|
const response: unknown = await $.get("/json/billing/event/status", {stripe_session_id});
|
||||||
if (response.session.status === "created") {
|
const response_data = stripe_response_schema.parse(response);
|
||||||
|
|
||||||
|
if (response_data.session.status === "created") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (response.session.event_handler.status === "started") {
|
if (response_data.session.event_handler!.status === "started") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (response.session.event_handler.status === "succeeded") {
|
if (response_data.session.event_handler!.status === "succeeded") {
|
||||||
handle_session_complete_event(response.session);
|
handle_session_complete_event(response_data.session);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (response.session.event_handler.status === "failed") {
|
if (response_data.session.event_handler!.status === "failed") {
|
||||||
show_error_message(response.session.event_handler.error.message);
|
show_error_message(response_data.session.event_handler!.error!.message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initialize_retry_with_another_card_link_click_handler() {
|
export function initialize_retry_with_another_card_link_click_handler(): void {
|
||||||
$("#retry-with-another-card-link").on("click", (e) => {
|
$("#retry-with-another-card-link").on("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$("#webhook-error").hide();
|
$("#webhook-error").hide();
|
||||||
|
@ -82,41 +105,67 @@ export function initialize_retry_with_another_card_link_click_handler() {
|
||||||
[],
|
[],
|
||||||
"POST",
|
"POST",
|
||||||
(response) => {
|
(response) => {
|
||||||
window.location.replace(response.stripe_session_url);
|
const response_data = helpers.stripe_session_url_schema.parse(response);
|
||||||
|
|
||||||
|
window.location.replace(response_data.stripe_session_url);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function stripe_payment_intent_status_check(stripe_payment_intent_id) {
|
export async function stripe_payment_intent_status_check(
|
||||||
const response = await $.get("/json/billing/event/status", {stripe_payment_intent_id});
|
stripe_payment_intent_id: string,
|
||||||
|
): Promise<boolean> {
|
||||||
|
const response: unknown = await $.get("/json/billing/event/status", {stripe_payment_intent_id});
|
||||||
|
|
||||||
switch (response.payment_intent.status) {
|
const response_schema = z.object({
|
||||||
|
payment_intent: z.object({
|
||||||
|
status: z.string(),
|
||||||
|
event_handler: z
|
||||||
|
.object({
|
||||||
|
status: z.string(),
|
||||||
|
error: z
|
||||||
|
.object({
|
||||||
|
message: z.string(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
last_payment_error: z
|
||||||
|
.object({
|
||||||
|
message: z.string(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const response_data = response_schema.parse(response);
|
||||||
|
|
||||||
|
switch (response_data.payment_intent.status) {
|
||||||
case "requires_payment_method":
|
case "requires_payment_method":
|
||||||
if (response.payment_intent.event_handler.status === "succeeded") {
|
if (response_data.payment_intent.event_handler!.status === "succeeded") {
|
||||||
show_html_error_message(
|
show_html_error_message(
|
||||||
response.payment_intent.last_payment_error.message +
|
response_data.payment_intent.last_payment_error!.message +
|
||||||
"<br>" +
|
"<br>" +
|
||||||
'You can try adding <a id="retry-with-another-card-link"> another card or </a> or retry the upgrade.',
|
'You can try adding <a id="retry-with-another-card-link"> another card or </a> or retry the upgrade.',
|
||||||
);
|
);
|
||||||
initialize_retry_with_another_card_link_click_handler();
|
initialize_retry_with_another_card_link_click_handler();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (response.payment_intent.event_handler.status === "failed") {
|
if (response_data.payment_intent.event_handler!.status === "failed") {
|
||||||
show_error_message(response.payment_intent.event_handler.error.message);
|
show_error_message(response_data.payment_intent.event_handler!.error!.message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
case "succeeded":
|
case "succeeded":
|
||||||
if (response.payment_intent.event_handler.status === "succeeded") {
|
if (response_data.payment_intent.event_handler!.status === "succeeded") {
|
||||||
update_status_and_redirect(
|
update_status_and_redirect(
|
||||||
"Charge created successfully. Your organization has been upgraded. Redirecting to billing page...",
|
"Charge created successfully. Your organization has been upgraded. Redirecting to billing page...",
|
||||||
"/billing/",
|
"/billing/",
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (response.payment_intent.event_handler.status === "failed") {
|
if (response_data.payment_intent.event_handler!.status === "failed") {
|
||||||
show_error_message(response.payment_intent.event_handler.error.message);
|
show_error_message(response_data.payment_intent.event_handler!.error!.message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -125,30 +174,30 @@ export async function stripe_payment_intent_status_check(stripe_payment_intent_i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function check_status() {
|
export async function check_status(): Promise<boolean> {
|
||||||
if ($("#data").attr("data-stripe-session-id")) {
|
if ($("#data").attr("data-stripe-session-id")) {
|
||||||
return await stripe_checkout_session_status_check(
|
return await stripe_checkout_session_status_check(
|
||||||
$("#data").attr("data-stripe-session-id"),
|
$("#data").attr("data-stripe-session-id")!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return await stripe_payment_intent_status_check(
|
return await stripe_payment_intent_status_check(
|
||||||
$("#data").attr("data-stripe-payment-intent-id"),
|
$("#data").attr("data-stripe-payment-intent-id")!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function start_status_polling() {
|
async function start_status_polling(): Promise<void> {
|
||||||
let completed = false;
|
let completed = false;
|
||||||
try {
|
try {
|
||||||
completed = await check_status();
|
completed = await check_status();
|
||||||
} catch {
|
} catch {
|
||||||
setTimeout(start_status_polling, 5000);
|
setTimeout(() => void start_status_polling(), 5000);
|
||||||
}
|
}
|
||||||
if (!completed) {
|
if (!completed) {
|
||||||
setTimeout(start_status_polling, 5000);
|
setTimeout(() => void start_status_polling(), 5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function initialize() {
|
async function initialize(): Promise<void> {
|
||||||
const form_loading = "#webhook-loading";
|
const form_loading = "#webhook-loading";
|
||||||
const form_loading_indicator = "#webhook_loading_indicator";
|
const form_loading_indicator = "#webhook_loading_indicator";
|
||||||
|
|
||||||
|
@ -161,5 +210,5 @@ async function initialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
$(() => {
|
$(() => {
|
||||||
initialize();
|
void initialize();
|
||||||
});
|
});
|
|
@ -1,16 +1,37 @@
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
|
import {z} from "zod";
|
||||||
|
|
||||||
import * as loading from "../loading";
|
import * as loading from "../loading";
|
||||||
|
|
||||||
import {page_params} from "./page_params";
|
import {page_params} from "./page_params";
|
||||||
|
|
||||||
|
type FormDataObject = Record<string, string>;
|
||||||
|
|
||||||
|
export type Prices = {
|
||||||
|
monthly: number;
|
||||||
|
annual: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DiscountDetails = {
|
||||||
|
opensource: string;
|
||||||
|
research: string;
|
||||||
|
nonprofit: string;
|
||||||
|
event: string;
|
||||||
|
education: string;
|
||||||
|
education_nonprofit: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const stripe_session_url_schema = z.object({
|
||||||
|
stripe_session_url: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
export function create_ajax_request(
|
export function create_ajax_request(
|
||||||
url,
|
url: string,
|
||||||
form_name,
|
form_name: string,
|
||||||
ignored_inputs = [],
|
ignored_inputs: string[] = [],
|
||||||
type = "POST",
|
type = "POST",
|
||||||
success_callback,
|
success_callback: (response: unknown) => void,
|
||||||
) {
|
): void {
|
||||||
const $form = $(`#${CSS.escape(form_name)}-form`);
|
const $form = $(`#${CSS.escape(form_name)}-form`);
|
||||||
const form_loading_indicator = `#${CSS.escape(form_name)}_loading_indicator`;
|
const form_loading_indicator = `#${CSS.escape(form_name)}_loading_indicator`;
|
||||||
const form_input_section = `#${CSS.escape(form_name)}-input-section`;
|
const form_input_section = `#${CSS.escape(form_name)}-input-section`;
|
||||||
|
@ -31,7 +52,7 @@ export function create_ajax_request(
|
||||||
$(zulip_limited_section).hide();
|
$(zulip_limited_section).hide();
|
||||||
$(free_trial_alert_message).hide();
|
$(free_trial_alert_message).hide();
|
||||||
|
|
||||||
const data = {};
|
const data: FormDataObject = {};
|
||||||
|
|
||||||
for (const item of $form.serializeArray()) {
|
for (const item of $form.serializeArray()) {
|
||||||
if (ignored_inputs.includes(item.name)) {
|
if (ignored_inputs.includes(item.name)) {
|
||||||
|
@ -40,11 +61,11 @@ export function create_ajax_request(
|
||||||
data[item.name] = item.value;
|
data[item.name] = item.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
$.ajax({
|
void $.ajax({
|
||||||
type,
|
type,
|
||||||
url,
|
url,
|
||||||
data,
|
data,
|
||||||
success(response) {
|
success(response: unknown) {
|
||||||
$(form_loading).hide();
|
$(form_loading).hide();
|
||||||
$(form_error).hide();
|
$(form_error).hide();
|
||||||
$(form_success).show();
|
$(form_success).show();
|
||||||
|
@ -67,7 +88,7 @@ export function create_ajax_request(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function format_money(cents) {
|
export function format_money(cents: number): string {
|
||||||
// allow for small floating point errors
|
// allow for small floating point errors
|
||||||
cents = Math.ceil(cents - 0.001);
|
cents = Math.ceil(cents - 0.001);
|
||||||
let precision;
|
let precision;
|
||||||
|
@ -79,17 +100,17 @@ export function format_money(cents) {
|
||||||
return new Intl.NumberFormat("en-US", {
|
return new Intl.NumberFormat("en-US", {
|
||||||
minimumFractionDigits: precision,
|
minimumFractionDigits: precision,
|
||||||
maximumFractionDigits: precision,
|
maximumFractionDigits: precision,
|
||||||
}).format((cents / 100).toFixed(precision));
|
}).format(Number.parseFloat((cents / 100).toFixed(precision)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function update_charged_amount(prices, schedule) {
|
export function update_charged_amount(prices: Prices, schedule: keyof Prices): void {
|
||||||
$("#charged_amount").text(format_money(page_params.seat_count * prices[schedule]));
|
$("#charged_amount").text(format_money(page_params.seat_count * prices[schedule]));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function update_discount_details(organization_type) {
|
export function update_discount_details(organization_type: keyof DiscountDetails): void {
|
||||||
let discount_notice =
|
let discount_notice =
|
||||||
"Your organization may be eligible for a discount on Zulip Cloud Standard. Organizations whose members are not employees are generally eligible.";
|
"Your organization may be eligible for a discount on Zulip Cloud Standard. Organizations whose members are not employees are generally eligible.";
|
||||||
const discount_details = {
|
const discount_details: DiscountDetails = {
|
||||||
opensource: "Zulip Cloud Standard is free for open-source projects.",
|
opensource: "Zulip Cloud Standard is free for open-source projects.",
|
||||||
research: "Zulip Cloud Standard is free for academic research.",
|
research: "Zulip Cloud Standard is free for academic research.",
|
||||||
nonprofit: "Zulip Cloud Standard is discounted 85%+ for registered non-profits.",
|
nonprofit: "Zulip Cloud Standard is discounted 85%+ for registered non-profits.",
|
||||||
|
@ -104,7 +125,7 @@ export function update_discount_details(organization_type) {
|
||||||
$("#sponsorship-discount-details").text(discount_notice);
|
$("#sponsorship-discount-details").text(discount_notice);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function show_license_section(license) {
|
export function show_license_section(license: string): void {
|
||||||
$("#license-automatic-section").hide();
|
$("#license-automatic-section").hide();
|
||||||
$("#license-manual-section").hide();
|
$("#license-manual-section").hide();
|
||||||
|
|
||||||
|
@ -117,14 +138,14 @@ export function show_license_section(license) {
|
||||||
$(input_id).prop("disabled", false);
|
$(input_id).prop("disabled", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let current_page;
|
let current_page: string;
|
||||||
|
|
||||||
function handle_hashchange() {
|
function handle_hashchange(): void {
|
||||||
$(`#${CSS.escape(current_page)}-tabs.nav a[href="${CSS.escape(location.hash)}"]`).tab("show");
|
$(`#${CSS.escape(current_page)}-tabs.nav a[href="${CSS.escape(location.hash)}"]`).tab("show");
|
||||||
$("html").scrollTop(0);
|
$("html").scrollTop(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function set_tab(page) {
|
export function set_tab(page: string): void {
|
||||||
const hash = location.hash;
|
const hash = location.hash;
|
||||||
if (hash) {
|
if (hash) {
|
||||||
$(`#${CSS.escape(page)}-tabs.nav a[href="${CSS.escape(hash)}"]`).tab("show");
|
$(`#${CSS.escape(page)}-tabs.nav a[href="${CSS.escape(hash)}"]`).tab("show");
|
||||||
|
@ -132,14 +153,14 @@ export function set_tab(page) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$(`#${CSS.escape(page)}-tabs.nav-tabs a`).on("click", function () {
|
$(`#${CSS.escape(page)}-tabs.nav-tabs a`).on("click", function () {
|
||||||
location.hash = this.hash;
|
location.hash = (this as HTMLAnchorElement).hash;
|
||||||
});
|
});
|
||||||
|
|
||||||
current_page = page;
|
current_page = page;
|
||||||
window.addEventListener("hashchange", handle_hashchange);
|
window.addEventListener("hashchange", handle_hashchange);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function set_sponsorship_form() {
|
export function set_sponsorship_form(): void {
|
||||||
$("#sponsorship-button").on("click", (e) => {
|
$("#sponsorship-button").on("click", (e) => {
|
||||||
if (!is_valid_input($("#sponsorship-form"))) {
|
if (!is_valid_input($("#sponsorship-form"))) {
|
||||||
return;
|
return;
|
||||||
|
@ -151,6 +172,6 @@ export function set_sponsorship_form() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function is_valid_input(elem) {
|
export function is_valid_input(elem: JQuery<HTMLFormElement>): boolean {
|
||||||
return elem[0].checkValidity();
|
return elem[0].checkValidity();
|
||||||
}
|
}
|
|
@ -1,68 +0,0 @@
|
||||||
import $ from "jquery";
|
|
||||||
|
|
||||||
import * as helpers from "./helpers";
|
|
||||||
import {page_params} from "./page_params";
|
|
||||||
|
|
||||||
export const initialize = () => {
|
|
||||||
helpers.set_tab("upgrade");
|
|
||||||
helpers.set_sponsorship_form();
|
|
||||||
$("#add-card-button").on("click", (e) => {
|
|
||||||
const license_management = $("input[type=radio][name=license_management]:checked").val();
|
|
||||||
if (
|
|
||||||
helpers.is_valid_input($(`#${CSS.escape(license_management)}_license_count`)) === false
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
const success_callback = (response) => {
|
|
||||||
window.location.replace(response.stripe_session_url);
|
|
||||||
};
|
|
||||||
helpers.create_ajax_request(
|
|
||||||
"/json/billing/upgrade",
|
|
||||||
"autopay",
|
|
||||||
[],
|
|
||||||
"POST",
|
|
||||||
success_callback,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#invoice-button").on("click", (e) => {
|
|
||||||
if (helpers.is_valid_input($("#invoiced_licenses")) === false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
helpers.create_ajax_request("/json/billing/upgrade", "invoice", [], "POST", () =>
|
|
||||||
window.location.replace("/billing/"),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const prices = {};
|
|
||||||
prices.annual = page_params.annual_price * (1 - page_params.percent_off / 100);
|
|
||||||
prices.monthly = page_params.monthly_price * (1 - page_params.percent_off / 100);
|
|
||||||
|
|
||||||
$("input[type=radio][name=license_management]").on("change", function () {
|
|
||||||
helpers.show_license_section(this.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("input[type=radio][name=schedule]").on("change", function () {
|
|
||||||
helpers.update_charged_amount(prices, this.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("select[name=organization-type]").on("change", (e) => {
|
|
||||||
const string_value = $(e.currentTarget.selectedOptions).attr("data-string-value");
|
|
||||||
helpers.update_discount_details(string_value);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#autopay_annual_price").text(helpers.format_money(prices.annual));
|
|
||||||
$("#autopay_annual_price_per_month").text(helpers.format_money(prices.annual / 12));
|
|
||||||
$("#autopay_monthly_price").text(helpers.format_money(prices.monthly));
|
|
||||||
$("#invoice_annual_price").text(helpers.format_money(prices.annual));
|
|
||||||
$("#invoice_annual_price_per_month").text(helpers.format_money(prices.annual / 12));
|
|
||||||
|
|
||||||
helpers.show_license_section($("input[type=radio][name=license_management]:checked").val());
|
|
||||||
helpers.update_charged_amount(prices, $("input[type=radio][name=schedule]:checked").val());
|
|
||||||
};
|
|
||||||
|
|
||||||
$(() => {
|
|
||||||
initialize();
|
|
||||||
});
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
import $ from "jquery";
|
||||||
|
|
||||||
|
import * as helpers from "./helpers";
|
||||||
|
import type {DiscountDetails, Prices} from "./helpers";
|
||||||
|
import {page_params} from "./page_params";
|
||||||
|
|
||||||
|
export const initialize = (): void => {
|
||||||
|
helpers.set_tab("upgrade");
|
||||||
|
helpers.set_sponsorship_form();
|
||||||
|
$("#add-card-button").on("click", (e) => {
|
||||||
|
const license_management: string = $(
|
||||||
|
"input[type=radio][name=license_management]:checked",
|
||||||
|
).val() as string;
|
||||||
|
if (!helpers.is_valid_input($(`#${CSS.escape(license_management)}_license_count`))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
helpers.create_ajax_request("/json/billing/upgrade", "autopay", [], "POST", (response) => {
|
||||||
|
const response_data = helpers.stripe_session_url_schema.parse(response);
|
||||||
|
window.location.replace(response_data.stripe_session_url);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#invoice-button").on("click", (e) => {
|
||||||
|
if (!helpers.is_valid_input($("#invoiced_licenses"))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
helpers.create_ajax_request("/json/billing/upgrade", "invoice", [], "POST", () =>
|
||||||
|
window.location.replace("/billing/"),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const prices: Prices = {
|
||||||
|
annual: page_params.annual_price * (1 - page_params.percent_off / 100),
|
||||||
|
monthly: page_params.monthly_price * (1 - page_params.percent_off / 100),
|
||||||
|
};
|
||||||
|
|
||||||
|
$("input[type=radio][name=license_management]").on("change", function (this: HTMLInputElement) {
|
||||||
|
helpers.show_license_section(this.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("input[type=radio][name=schedule]").on("change", function (this: HTMLInputElement) {
|
||||||
|
helpers.update_charged_amount(prices, this.value as keyof Prices);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("select[name=organization-type]").on("change", (e) => {
|
||||||
|
const string_value = $((e.currentTarget as HTMLSelectElement).selectedOptions).attr(
|
||||||
|
"data-string-value",
|
||||||
|
);
|
||||||
|
helpers.update_discount_details(string_value as keyof DiscountDetails);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#autopay_annual_price").text(helpers.format_money(prices.annual));
|
||||||
|
$("#autopay_annual_price_per_month").text(helpers.format_money(prices.annual / 12));
|
||||||
|
$("#autopay_monthly_price").text(helpers.format_money(prices.monthly));
|
||||||
|
$("#invoice_annual_price").text(helpers.format_money(prices.annual));
|
||||||
|
$("#invoice_annual_price_per_month").text(helpers.format_money(prices.annual / 12));
|
||||||
|
|
||||||
|
helpers.show_license_section(
|
||||||
|
$("input[type=radio][name=license_management]:checked").val() as string,
|
||||||
|
);
|
||||||
|
helpers.update_charged_amount(
|
||||||
|
prices,
|
||||||
|
$("input[type=radio][name=schedule]:checked").val() as keyof Prices,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
$(() => {
|
||||||
|
initialize();
|
||||||
|
});
|
|
@ -16,6 +16,7 @@ type JQueryCaretRange = {
|
||||||
interface JQuery {
|
interface JQuery {
|
||||||
expectOne(): JQuery;
|
expectOne(): JQuery;
|
||||||
tab(action?: string): this; // From web/third/bootstrap
|
tab(action?: string): this; // From web/third/bootstrap
|
||||||
|
modal(action?: string): this; // From web/third/bootstrap
|
||||||
|
|
||||||
// Types for jquery-caret-plugin
|
// Types for jquery-caret-plugin
|
||||||
caret(): number;
|
caret(): number;
|
||||||
|
|
|
@ -42,6 +42,11 @@ run_test("initialize", ({override}) => {
|
||||||
|
|
||||||
run_test("card_update", ({override}) => {
|
run_test("card_update", ({override}) => {
|
||||||
override(helpers, "set_tab", () => {});
|
override(helpers, "set_tab", () => {});
|
||||||
|
override(helpers, "stripe_session_url_schema", {
|
||||||
|
parse(obj) {
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
});
|
||||||
let create_ajax_request_called = false;
|
let create_ajax_request_called = false;
|
||||||
function card_change_ajax(url, form_name, ignored_inputs, method, success_callback) {
|
function card_change_ajax(url, form_name, ignored_inputs, method, success_callback) {
|
||||||
assert.equal(url, "/json/billing/session/start_card_update_session");
|
assert.equal(url, "/json/billing/session/start_card_update_session");
|
||||||
|
|
|
@ -24,6 +24,11 @@ run_test("initialize_retry_with_another_card_link_click_handler", ({override}) =
|
||||||
});
|
});
|
||||||
callback({stripe_session_url: "stripe_session_url"});
|
callback({stripe_session_url: "stripe_session_url"});
|
||||||
});
|
});
|
||||||
|
override(helpers, "stripe_session_url_schema", {
|
||||||
|
parse(obj) {
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
});
|
||||||
event_status.initialize_retry_with_another_card_link_click_handler();
|
event_status.initialize_retry_with_another_card_link_click_handler();
|
||||||
const retry_click_handler = $("#retry-with-another-card-link").get_on_handler("click");
|
const retry_click_handler = $("#retry-with-another-card-link").get_on_handler("click");
|
||||||
retry_click_handler({preventDefault() {}});
|
retry_click_handler({preventDefault() {}});
|
||||||
|
@ -37,6 +42,7 @@ run_test("check_status", async ({override}) => {
|
||||||
return {
|
return {
|
||||||
session: {
|
session: {
|
||||||
status: "created",
|
status: "created",
|
||||||
|
type: "upgrade_from_billing_page",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -49,6 +55,7 @@ run_test("check_status", async ({override}) => {
|
||||||
return {
|
return {
|
||||||
session: {
|
session: {
|
||||||
status: "completed",
|
status: "completed",
|
||||||
|
type: "upgrade_from_billing_page",
|
||||||
event_handler: {
|
event_handler: {
|
||||||
status: "started",
|
status: "started",
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
"./src/billing/page_params",
|
"./src/billing/page_params",
|
||||||
"./src/bundles/portico",
|
"./src/bundles/portico",
|
||||||
"./styles/portico/landing_page.css",
|
"./styles/portico/landing_page.css",
|
||||||
"./src/billing/event_status.js",
|
"./src/billing/event_status",
|
||||||
"./src/billing/helpers",
|
"./src/billing/helpers",
|
||||||
"./styles/portico/billing.css"
|
"./styles/portico/billing.css"
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in New Issue