summaryrefslogtreecommitdiffstats
path: root/browser/components/newtab/content-src/asrouter/templates/EOYSnippet
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/newtab/content-src/asrouter/templates/EOYSnippet')
-rw-r--r--browser/components/newtab/content-src/asrouter/templates/EOYSnippet/EOYSnippet.jsx153
-rw-r--r--browser/components/newtab/content-src/asrouter/templates/EOYSnippet/EOYSnippet.schema.json171
-rw-r--r--browser/components/newtab/content-src/asrouter/templates/EOYSnippet/_EOYSnippet.scss55
3 files changed, 379 insertions, 0 deletions
diff --git a/browser/components/newtab/content-src/asrouter/templates/EOYSnippet/EOYSnippet.jsx b/browser/components/newtab/content-src/asrouter/templates/EOYSnippet/EOYSnippet.jsx
new file mode 100644
index 0000000000..f324a69853
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/templates/EOYSnippet/EOYSnippet.jsx
@@ -0,0 +1,153 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import React from "react";
+import { SimpleSnippet } from "../SimpleSnippet/SimpleSnippet";
+
+class EOYSnippetBase extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ this.handleSubmit = this.handleSubmit.bind(this);
+ }
+
+ /**
+ * setFrequencyValue - `frequency` form parameter value should be `monthly`
+ * if `monthly-checkbox` is selected or `single` otherwise
+ */
+ setFrequencyValue() {
+ const frequencyCheckbox = this.refs.form.querySelector("#monthly-checkbox");
+ if (frequencyCheckbox.checked) {
+ this.refs.form.querySelector("[name='frequency']").value = "monthly";
+ }
+ }
+
+ handleSubmit(event) {
+ event.preventDefault();
+ this.props.sendClick(event);
+ this.setFrequencyValue();
+ if (!this.props.content.do_not_autoblock) {
+ this.props.onBlock();
+ }
+ this.refs.form.submit();
+ }
+
+ renderDonations() {
+ const fieldNames = ["first", "second", "third", "fourth"];
+ const numberFormat = new Intl.NumberFormat(
+ this.props.content.locale || navigator.language,
+ {
+ style: "currency",
+ currency: this.props.content.currency_code,
+ minimumFractionDigits: 0,
+ }
+ );
+ // Default to `second` button
+ const { selected_button } = this.props.content;
+ const btnStyle = {
+ color: this.props.content.button_color,
+ backgroundColor: this.props.content.button_background_color,
+ };
+ const donationURLParams = [];
+ const paramsStartIndex = this.props.content.donation_form_url.indexOf("?");
+ for (const entry of new URLSearchParams(
+ this.props.content.donation_form_url.slice(paramsStartIndex)
+ ).entries()) {
+ donationURLParams.push(entry);
+ }
+
+ return (
+ <form
+ className="EOYSnippetForm"
+ action={this.props.content.donation_form_url}
+ method={this.props.form_method}
+ onSubmit={this.handleSubmit}
+ data-metric="EOYSnippetForm"
+ ref="form"
+ >
+ {donationURLParams.map(([key, value], idx) => (
+ <input type="hidden" name={key} value={value} key={idx} />
+ ))}
+ {fieldNames.map((field, idx) => {
+ const button_name = `donation_amount_${field}`;
+ const amount = this.props.content[button_name];
+ return (
+ <React.Fragment key={idx}>
+ <input
+ type="radio"
+ name="amount"
+ value={amount}
+ id={field}
+ defaultChecked={button_name === selected_button}
+ />
+ <label htmlFor={field} className="donation-amount">
+ {numberFormat.format(amount)}
+ </label>
+ </React.Fragment>
+ );
+ })}
+
+ <div className="monthly-checkbox-container">
+ <input id="monthly-checkbox" type="checkbox" />
+ <label htmlFor="monthly-checkbox">
+ {this.props.content.monthly_checkbox_label_text}
+ </label>
+ </div>
+
+ <input type="hidden" name="frequency" value="single" />
+ <input
+ type="hidden"
+ name="currency"
+ value={this.props.content.currency_code}
+ />
+ <input
+ type="hidden"
+ name="presets"
+ value={fieldNames.map(
+ field => this.props.content[`donation_amount_${field}`]
+ )}
+ />
+ <button
+ style={btnStyle}
+ type="submit"
+ className="ASRouterButton primary donation-form-url"
+ >
+ {this.props.content.button_label}
+ </button>
+ </form>
+ );
+ }
+
+ render() {
+ const textStyle = {
+ color: this.props.content.text_color,
+ backgroundColor: this.props.content.background_color,
+ };
+ const customElement = (
+ <em style={{ backgroundColor: this.props.content.highlight_color }} />
+ );
+ return (
+ <SimpleSnippet
+ {...this.props}
+ className={this.props.content.test}
+ customElements={{ em: customElement }}
+ textStyle={textStyle}
+ extraContent={this.renderDonations()}
+ />
+ );
+ }
+}
+
+export const EOYSnippet = props => {
+ const extendedContent = {
+ monthly_checkbox_label_text: "Make my donation monthly",
+ locale: "en-US",
+ currency_code: "usd",
+ selected_button: "donation_amount_second",
+ ...props.content,
+ };
+
+ return (
+ <EOYSnippetBase {...props} content={extendedContent} form_method="GET" />
+ );
+};
diff --git a/browser/components/newtab/content-src/asrouter/templates/EOYSnippet/EOYSnippet.schema.json b/browser/components/newtab/content-src/asrouter/templates/EOYSnippet/EOYSnippet.schema.json
new file mode 100644
index 0000000000..d9b6728067
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/templates/EOYSnippet/EOYSnippet.schema.json
@@ -0,0 +1,171 @@
+{
+ "title": "EOYSnippet",
+ "description": "Fundraising Snippet",
+ "version": "1.1.0",
+ "type": "object",
+ "definitions": {
+ "plainText": {
+ "description": "Plain text (no HTML allowed)",
+ "type": "string"
+ },
+ "richText": {
+ "description": "Text with HTML subset allowed: i, b, u, strong, em, br",
+ "type": "string"
+ },
+ "link_url": {
+ "description": "Target for links or buttons",
+ "type": "string",
+ "format": "uri"
+ }
+ },
+ "properties": {
+ "donation_form_url": {
+ "type": "string",
+ "description": "Url to the donation form."
+ },
+ "currency_code": {
+ "type": "string",
+ "description": "The code for the currency. Examle gbp, cad, usd.",
+ "default": "usd"
+ },
+ "locale": {
+ "type": "string",
+ "description": "String for the locale code.",
+ "default": "en-US"
+ },
+ "text": {
+ "allOf": [
+ { "$ref": "#/definitions/richText" },
+ {
+ "description": "Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"
+ }
+ ]
+ },
+ "text_color": {
+ "type": "string",
+ "description": "Modify the text message color"
+ },
+ "background_color": {
+ "type": "string",
+ "description": "Snippet background color."
+ },
+ "highlight_color": {
+ "type": "string",
+ "description": "Paragraph em highlight color."
+ },
+ "donation_amount_first": {
+ "type": "number",
+ "description": "First button amount."
+ },
+ "donation_amount_second": {
+ "type": "number",
+ "description": "Second button amount."
+ },
+ "donation_amount_third": {
+ "type": "number",
+ "description": "Third button amount."
+ },
+ "donation_amount_fourth": {
+ "type": "number",
+ "description": "Fourth button amount."
+ },
+ "selected_button": {
+ "type": "string",
+ "description": "Default donation_amount_second. Donation amount button that's selected by default.",
+ "default": "donation_amount_second"
+ },
+ "icon": {
+ "type": "string",
+ "description": "Snippet icon. 64x64px. SVG or PNG preferred."
+ },
+ "icon_dark_theme": {
+ "type": "string",
+ "description": "Snippet icon. Dark theme variant. 64x64px. SVG or PNG preferred."
+ },
+ "icon_alt_text": {
+ "type": "string",
+ "description": "Alt text for accessibility",
+ "default": ""
+ },
+ "title": {
+ "allOf": [
+ { "$ref": "#/definitions/plainText" },
+ { "description": "Snippet title displayed before snippet text" }
+ ]
+ },
+ "title_icon": {
+ "type": "string",
+ "description": "Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."
+ },
+ "title_icon_dark_theme": {
+ "type": "string",
+ "description": "Small icon that shows up before the title / text. Dark theme variant. 16x16px. SVG or PNG preferred. Grayscale."
+ },
+ "button_label": {
+ "allOf": [
+ { "$ref": "#/definitions/plainText" },
+ {
+ "description": "Text for a button next to main snippet text that links to button_url. Requires button_url."
+ }
+ ]
+ },
+ "button_color": {
+ "type": "string",
+ "description": "The text color of the button. Valid CSS color."
+ },
+ "button_background_color": {
+ "type": "string",
+ "description": "The background color of the button. Valid CSS color."
+ },
+ "block_button_text": {
+ "type": "string",
+ "description": "Tooltip text used for dismiss button."
+ },
+ "monthly_checkbox_label_text": {
+ "type": "string",
+ "description": "Label text for monthly checkbox.",
+ "default": "Make my donation monthly"
+ },
+ "test": {
+ "type": "string",
+ "description": "Different styles for the snippet. Options are bold and takeover."
+ },
+ "do_not_autoblock": {
+ "type": "boolean",
+ "description": "Used to prevent blocking the snippet after the CTA (link or button) has been clicked"
+ },
+ "links": {
+ "additionalProperties": {
+ "url": {
+ "allOf": [
+ { "$ref": "#/definitions/link_url" },
+ { "description": "The url where the link points to." }
+ ]
+ },
+ "metric": {
+ "type": "string",
+ "description": "Custom event name sent with telemetry event."
+ },
+ "args": {
+ "type": "string",
+ "description": "Additional parameters for link action, example which specific menu the button should open"
+ }
+ }
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "text",
+ "donation_form_url",
+ "donation_amount_first",
+ "donation_amount_second",
+ "donation_amount_third",
+ "donation_amount_fourth",
+ "button_label",
+ "currency_code"
+ ],
+ "dependencies": {
+ "button_color": ["button_label"],
+ "button_background_color": ["button_label"]
+ }
+}
diff --git a/browser/components/newtab/content-src/asrouter/templates/EOYSnippet/_EOYSnippet.scss b/browser/components/newtab/content-src/asrouter/templates/EOYSnippet/_EOYSnippet.scss
new file mode 100644
index 0000000000..d9911ff02c
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/templates/EOYSnippet/_EOYSnippet.scss
@@ -0,0 +1,55 @@
+.EOYSnippetForm {
+ margin: 10px 0 8px;
+ align-self: start;
+ font-size: 14px;
+ display: flex;
+ align-items: center;
+
+ .donation-amount,
+ .donation-form-url {
+ white-space: nowrap;
+ font-size: 14px;
+ padding: 8px 20px;
+ border-radius: 2px;
+ }
+
+ .donation-amount {
+ color: var(--newtab-text-primary-color);
+ margin-inline-end: 18px;
+ border: $input-border;
+ padding: 5px 14px;
+ background: var(--newtab-background-color-secondary);
+ cursor: pointer;
+ }
+
+ input {
+ &[type='radio'] {
+ opacity: 0;
+ margin-inline-end: -18px;
+
+ &:checked + .donation-amount {
+ // Use a text color for the background to achieve an inverted look.
+ background: var(--newtab-text-secondary-color);
+ color: var(--newtab-background-color-secondary);
+ border: $border-secondary;
+ }
+
+ // accessibility
+ &:checked:focus + .donation-amount,
+ &:not(:checked):focus + .donation-amount {
+ border: 1px dotted var(--newtab-primary-action-background);
+ }
+ }
+ }
+
+ .monthly-checkbox-container {
+ display: flex;
+ width: 100%;
+ }
+
+ .donation-form-url {
+ margin-inline-start: 18px;
+ align-self: flex-end;
+ display: flex;
+ }
+}