mirror of https://github.com/zulip/zulip.git
sponsorsihp: Make submitting the form work.
Includes various changes to make submitting the sponsorship form work.
This commit is contained in:
parent
a75c8ee6f0
commit
ff5e1c3aee
|
@ -4,12 +4,12 @@
|
||||||
{% set PAGE_TITLE = "💚 Request sponsorship" %}
|
{% set PAGE_TITLE = "💚 Request sponsorship" %}
|
||||||
|
|
||||||
{% block portico_content %}
|
{% block portico_content %}
|
||||||
<div class="register-account flex full-page">
|
<div class="register-account flex full-page sponsorship-page">
|
||||||
<div class="center-block new-style">
|
<div class="center-block new-style">
|
||||||
<div class="pitch">
|
<div class="pitch">
|
||||||
<h1>💚 Request sponsorship</h1>
|
<h1>💚 Request sponsorship</h1>
|
||||||
</div>
|
</div>
|
||||||
<div id="registration" class="white-box">
|
<div class="white-box">
|
||||||
<div id="sponsorship-error" class="alert alert-danger"></div>
|
<div id="sponsorship-error" class="alert alert-danger"></div>
|
||||||
<div id="sponsorship-input-section">
|
<div id="sponsorship-input-section">
|
||||||
<form id="sponsorship-form" method="post">
|
<form id="sponsorship-form" method="post">
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="input-box sponsorship-form-field">
|
<div class="input-box sponsorship-form-field">
|
||||||
<div class="inline-block relative">
|
<div class="inline-block relative">
|
||||||
<select name="realm_type" id="realm_type" class="sponsorship-form-select">
|
<select name="organization-type" id="organization-type" class="sponsorship-form-select">
|
||||||
{% for org_type in sorted_org_types %}
|
{% for org_type in sorted_org_types %}
|
||||||
{% if not org_type[1].hidden %}
|
{% if not org_type[1].hidden %}
|
||||||
<option data-string-value="{{ org_type[0] }}"
|
<option data-string-value="{{ org_type[0] }}"
|
||||||
|
@ -32,11 +32,11 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<label for="realm_type" class="inline-block label-title">{{ _('Organization type') }}</label>
|
<label for="organization-type" class="inline-block label-title">{{ _('Organization type') }}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-box sponsorship-form-field no-validation">
|
<div class="input-box sponsorship-form-field no-validation">
|
||||||
<label for="org-website" class="inline-block label-title">{{ _('Organization website') }}</label>
|
<label for="org-website" class="inline-block label-title">{{ _('Organization website') }}</label>
|
||||||
<input id="org-website" name="website" type="text" class="input-large" placeholder="{{ _('Leave blank if your organization does not have a website.') }}"/>
|
<input id="org-website" name="website" type="text" placeholder="{{ _('Leave blank if your organization does not have a website.') }}"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-box sponsorship-form-field">
|
<div class="input-box sponsorship-form-field">
|
||||||
<label for="description" class="inline-block label-title">{{ _('Describe your organization briefly') }}</label>
|
<label for="description" class="inline-block label-title">{{ _('Describe your organization briefly') }}</label>
|
||||||
|
@ -46,8 +46,8 @@
|
||||||
<!-- Disabled buttons do not fire any events, so we need a container div that isn't disabled for tippyjs to work -->
|
<!-- Disabled buttons do not fire any events, so we need a container div that isn't disabled for tippyjs to work -->
|
||||||
<div class="upgrade-button-container" {% if is_demo_organization %}data-tippy-content="{% trans %}Convert demo organization before upgrading.{% endtrans %}"{% endif %}>
|
<div class="upgrade-button-container" {% if is_demo_organization %}data-tippy-content="{% trans %}Convert demo organization before upgrading.{% endtrans %}"{% endif %}>
|
||||||
<button type="submit" id="sponsorship-button" class="stripe-button-el invoice-button" {% if is_demo_organization %}disabled{% endif %}>
|
<button type="submit" id="sponsorship-button" class="stripe-button-el invoice-button" {% if is_demo_organization %}disabled{% endif %}>
|
||||||
Submit
|
<span class="sponsorship-button-text">Submit</span>
|
||||||
<object class="loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
|
<object class="loader sponsorship-button-loader" type="image/svg+xml" data="{{ static('images/loading/loader-white.svg') }}"></object>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -58,7 +58,6 @@ EXEMPT_FILES = make_set(
|
||||||
"web/src/avatar.ts",
|
"web/src/avatar.ts",
|
||||||
"web/src/billing/event_status.ts",
|
"web/src/billing/event_status.ts",
|
||||||
"web/src/billing/helpers.ts",
|
"web/src/billing/helpers.ts",
|
||||||
"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/browser_history.ts",
|
"web/src/browser_history.ts",
|
||||||
|
|
|
@ -5,7 +5,7 @@ import * as loading from "../loading";
|
||||||
|
|
||||||
import {page_params} from "./page_params";
|
import {page_params} from "./page_params";
|
||||||
|
|
||||||
type FormDataObject = Record<string, string>;
|
export type FormDataObject = Record<string, string>;
|
||||||
|
|
||||||
export const schedule_schema = z.enum(["monthly", "annual"]);
|
export const schedule_schema = z.enum(["monthly", "annual"]);
|
||||||
export type Prices = Record<z.infer<typeof schedule_schema>, number>;
|
export type Prices = Record<z.infer<typeof schedule_schema>, number>;
|
||||||
|
@ -108,7 +108,7 @@ export function update_charged_amount(prices: Prices, schedule: keyof Prices): v
|
||||||
$("#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: keyof DiscountDetails): void {
|
export function update_discount_details(organization_type: string): 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: DiscountDetails = {
|
const discount_details: DiscountDetails = {
|
||||||
|
@ -120,9 +120,20 @@ export function update_discount_details(organization_type: keyof DiscountDetails
|
||||||
education_nonprofit:
|
education_nonprofit:
|
||||||
"Zulip Cloud Standard is discounted 90% for education non-profits with online purchase.",
|
"Zulip Cloud Standard is discounted 90% for education non-profits with online purchase.",
|
||||||
};
|
};
|
||||||
if (discount_details[organization_type]) {
|
|
||||||
discount_notice = discount_details[organization_type];
|
try {
|
||||||
|
const parsed_organization_type = organization_type_schema.parse(organization_type);
|
||||||
|
discount_notice = discount_details[parsed_organization_type];
|
||||||
|
} catch {
|
||||||
|
// This will likely fail if organization_type is not in organization_type_schema or
|
||||||
|
// parsed_organization_type is not preset in discount_details. In either case, we will
|
||||||
|
// fallback to the default discount_notice.
|
||||||
|
//
|
||||||
|
// Why use try / catch?
|
||||||
|
// Because organization_type_schema.options.includes wants organization_type to be of type
|
||||||
|
// opensource | research | ... and defining a type like that is not useful.
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#sponsorship-discount-details").text(discount_notice);
|
$("#sponsorship-discount-details").text(discount_notice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,18 +172,6 @@ export function set_tab(page: string): void {
|
||||||
window.addEventListener("hashchange", handle_hashchange);
|
window.addEventListener("hashchange", handle_hashchange);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function set_sponsorship_form(): void {
|
|
||||||
$("#sponsorship-button").on("click", (e) => {
|
|
||||||
if (!is_valid_input($("#sponsorship-form"))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
create_ajax_request("/json/billing/sponsorship", "sponsorship", [], "POST", () =>
|
|
||||||
window.location.replace("/"),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function is_valid_input(elem: JQuery<HTMLFormElement>): boolean {
|
export function is_valid_input(elem: JQuery<HTMLFormElement>): boolean {
|
||||||
return elem[0].checkValidity();
|
return elem[0].checkValidity();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,56 @@ import $ from "jquery";
|
||||||
|
|
||||||
import * as helpers from "./helpers";
|
import * as helpers from "./helpers";
|
||||||
|
|
||||||
|
function show_submit_loading_indicator(): void {
|
||||||
|
$("#sponsorship-button .sponsorship-button-loader").css("display", "inline-block");
|
||||||
|
$("#sponsorship-button").prop("disabled", true);
|
||||||
|
$("#sponsorship-button .sponsorship-button-text").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide_submit_loading_indicator(): void {
|
||||||
|
$("#sponsorship-button .sponsorship-button-loader").css("display", "none");
|
||||||
|
$("#sponsorship-button").prop("disabled", false);
|
||||||
|
$("#sponsorship-button .sponsorship-button-text").show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_ajax_request(): void {
|
||||||
|
show_submit_loading_indicator();
|
||||||
|
const $form = $("#sponsorship-form");
|
||||||
|
const data: helpers.FormDataObject = {};
|
||||||
|
|
||||||
|
for (const item of $form.serializeArray()) {
|
||||||
|
data[item.name] = item.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void $.ajax({
|
||||||
|
type: "post",
|
||||||
|
url: "/json/billing/sponsorship",
|
||||||
|
data,
|
||||||
|
success() {
|
||||||
|
window.location.reload();
|
||||||
|
},
|
||||||
|
error(xhr) {
|
||||||
|
hide_submit_loading_indicator();
|
||||||
|
if (xhr.responseJSON?.msg) {
|
||||||
|
$("#sponsorship-error").show().text(xhr.responseJSON.msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function initialize(): void {
|
export function initialize(): void {
|
||||||
helpers.set_sponsorship_form();
|
$("#sponsorship-button").on("click", (e) => {
|
||||||
|
if (!helpers.is_valid_input($("#sponsorship-form"))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
create_ajax_request();
|
||||||
|
});
|
||||||
|
|
||||||
|
$<HTMLSelectElement>("#organization-type").on("change", (e) => {
|
||||||
|
const string_value = $(e.currentTarget.selectedOptions).attr("data-string-value") ?? "";
|
||||||
|
helpers.update_discount_details(string_value);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(() => {
|
$(() => {
|
||||||
|
|
|
@ -44,11 +44,6 @@ export const initialize = (): void => {
|
||||||
helpers.update_charged_amount(prices, helpers.schedule_schema.parse(this.value));
|
helpers.update_charged_amount(prices, helpers.schedule_schema.parse(this.value));
|
||||||
});
|
});
|
||||||
|
|
||||||
$<HTMLSelectElement>("select[name=organization-type]").on("change", (e) => {
|
|
||||||
const string_value = $(e.currentTarget.selectedOptions).attr("data-string-value");
|
|
||||||
helpers.update_discount_details(helpers.organization_type_schema.parse(string_value));
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#autopay_annual_price").text(helpers.format_money(prices.annual));
|
$("#autopay_annual_price").text(helpers.format_money(prices.annual));
|
||||||
$("#autopay_annual_price_per_month").text(helpers.format_money(prices.annual / 12));
|
$("#autopay_annual_price_per_month").text(helpers.format_money(prices.annual / 12));
|
||||||
$("#autopay_monthly_price").text(helpers.format_money(prices.monthly));
|
$("#autopay_monthly_price").text(helpers.format_money(prices.monthly));
|
||||||
|
|
|
@ -371,6 +371,33 @@ input[name="licenses"] {
|
||||||
background-color: hsl(240deg 96% 68%);
|
background-color: hsl(240deg 96% 68%);
|
||||||
}
|
}
|
||||||
|
|
||||||
#sponsorship-form {
|
.sponsorship-page .white-box {
|
||||||
margin: 30px;
|
margin: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sponsorship-page #sponsorship-form {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sponsorship-discount-details {
|
||||||
|
font-weight: normal;
|
||||||
|
margin: 2px;
|
||||||
|
padding-top: 25px;
|
||||||
|
text-align: left;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
width: 450px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (width < 600px) {
|
||||||
|
.sponsorship-page {
|
||||||
|
transform: scale(0.8);
|
||||||
|
margin: -50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (width < 460px) {
|
||||||
|
.sponsorship-page {
|
||||||
|
transform: scale(0.6);
|
||||||
|
margin: -150px -100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -916,6 +916,7 @@ button#register_auth_button_gitlab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#sponsorship-form,
|
||||||
#registration,
|
#registration,
|
||||||
#new-realm-creation {
|
#new-realm-creation {
|
||||||
width: auto;
|
width: auto;
|
||||||
|
@ -1012,7 +1013,8 @@ button#register_auth_button_gitlab {
|
||||||
width: 450px;
|
width: 450px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.register-button .loader {
|
.register-button .loader,
|
||||||
|
.sponsorship-button-loader {
|
||||||
display: none;
|
display: none;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
Loading…
Reference in New Issue