Skip to content

Commit

Permalink
Finalize move to module script.
Browse files Browse the repository at this point in the history
  • Loading branch information
davepeck committed May 14, 2024
1 parent d88ec46 commit f797cf9
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 96 deletions.
11 changes: 5 additions & 6 deletions server/static/js/fireworks.js

Large diffs are not rendered by default.

138 changes: 114 additions & 24 deletions server/static/js/voterbowl.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,36 @@
import * as htmx from "./htmx.min.js";
import { Fireworks } from "./fireworks.js";

/*-----------------------------------------------------------------
* API Calls
* -----------------------------------------------------------------*/

const api = {
/**
* Finalize a verify and, possibly, mint a new gift ca
*
* @param {string} first_name
* @param {string} last_name
* @param {string} email
* @param {HTMLElement} target
* @returns {Promise<void>}
*/
finishVerify: async (first_name, last_name, email, target) => {
/** @type {HTMLElement|null} */
try {
await htmx.ajax("POST", "./finish/", {
target,
values: {
first_name,
last_name,
email,
},
});
} catch (error) {
console.error(error);
}
},
};

/*-----------------------------------------------------------------
* Check Page Component
Expand Down Expand Up @@ -40,42 +72,100 @@ class CheckPage extends HTMLElement {
console.error("Missing data in event");
return;
}
this.finishVerify(data.first_name, data.last_name, data.email);
/** @type {HTMLElement|null} */
const target = this.querySelector(".urgency");
if (!target) {
console.error("Missing target element");
return;
}
api.finishVerify(data.first_name, data.last_name, data.email, target);
}
};
}

customElements.define("check-page", CheckPage);

/*-----------------------------------------------------------------
* Fail Check Partial
* -----------------------------------------------------------------*/

class FailCheck extends HTMLElement {
connectedCallback() {
const { schoolName, firstName, lastName } = this.dataset;
if (!schoolName || !firstName || !lastName) {
console.error("Missing data attributes");
return;
}

/** @type {HTMLElement|null} */
const target = this.querySelector(".urgency");
if (!target) {
console.error("Missing target element");
return;
}

const email = this.demandValidEmail(schoolName, 3);
if (!email) {
console.log("No email provided");
return;
}

api.finishVerify(firstName, lastName, email, target);
}

/**
* Finalize a verify and, possibly, mint a new gift card if all is well.
* Prompt the user for a valid email address.
*
* @param {string} first_name
* @param {string} last_name
* @param {string} email
* @returns {Promise<void>}
* @param {string} schoolName The name of the school.
* @param {number} tries The number of tries to allow.
* @returns {string|null} The email address or null if not provided.
* @private
* @memberof FailCheck
*/
async finishVerify(first_name, last_name, email) {
/** @type {HTMLElement|null} */
const urgency = this.querySelector(".urgency");
if (!urgency) {
console.error("Missing urgency element");
demandValidEmail(schoolName, tries) {
/** @type {string|null} */
let email = null;
let count = 0;
while (email === null && count < tries) {
email = prompt(
`Sorry, but we need your ${schoolName} student email to continue. Please enter it below:`
);
count++;
}
return email;
}
}

customElements.define("fail-check", FailCheck);

/*-----------------------------------------------------------------
* Finish Check Partial
* -----------------------------------------------------------------*/

class FinishCheck extends HTMLElement {
connectedCallback() {
// smoothly scroll to the top of the page after a slight delay
setTimeout(() => window.scrollTo({ top: 0, behavior: "smooth" }), 100);

// if the user is a winner, start the fireworks
const { isWinner } = this.dataset;
if (isWinner !== "true") {
return;
}
try {
await htmx.ajax("POST", "./finish/", {
target: urgency,
values: {
first_name,
last_name,
email,
},
});
} catch (error) {
console.error(error);

// CONSIDER: use of document needed here?
/** @type {HTMLElement|null} */
const target = document.querySelector(".fireworks");
if (!target) {
console.error("Missing target element");
return;
}
const fireworks = new Fireworks(target);
fireworks.start();
setTimeout(() => fireworks.stop(), 10_000);
}
}

customElements.define("check-page", CheckPage);

/*-----------------------------------------------------------------
* Gift code clipboard behavior
* -----------------------------------------------------------------*/
Expand Down
42 changes: 20 additions & 22 deletions server/vb/components/check_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@
from django.templatetags.static import static
from django.urls import reverse

from server.utils.components import js, style
from server.utils.components import style

from ..models import Contest, ContestEntry, School
from .base_page import base_page
from .countdown import countdown
from .logo import school_logo
from .utils import Fragment, fragment

check_page_elt = h.Element("check-page", {}, None)


def check_page(school: School, current_contest: Contest | None) -> h.Element:
"""Render a school-specific 'check voter registration' form page."""
Expand All @@ -28,7 +26,7 @@ def check_page(school: School, current_contest: Contest | None) -> h.Element:
show_faq=False,
show_footer=False,
)[
check_page_elt[
h.check_page[
h.div[
style(
__file__,
Expand Down Expand Up @@ -70,16 +68,15 @@ def fail_check_partial(
"""Render a partial page for when the user's email is invalid."""
return fragment[
school_logo(school),
h.p[
js(
__file__,
"fail_check_partial.js",
school_name=school.short_name,
first_name=first_name,
last_name=last_name,
),
h.b["We could not use your email"],
f". Please use your { school.short_name } student email.",
h.fail_check(
data_school_name=school.short_name,
data_first_name=first_name,
data_last_name=last_name,
)[
h.p[
h.b["We could not use your email"],
f". Please use your { school.short_name } student email.",
]
],
]

Expand Down Expand Up @@ -136,13 +133,14 @@ def finish_check_partial(
"""Render a partial page for when the user has finished the check."""
return fragment[
school_logo(school),
h.p[
style(__file__, "finish_check_partial.css"),
js(
__file__,
"finish_check_partial.js",
is_winner=contest_entry and contest_entry.is_winner,
),
_finish_check_description(school, contest_entry, most_recent_winner),
h.finish_check(
data_is_winner="true"
if contest_entry and contest_entry.is_winner
else "false"
)[
h.p[
style(__file__, "finish_check_partial.css"),
_finish_check_description(school, contest_entry, most_recent_winner),
]
],
]
4 changes: 1 addition & 3 deletions server/vb/components/countdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

from ..models import Contest

big_countdown = h.Element("big-countdown", {}, None)


def countdown(contest: Contest) -> h.Element:
"""Render a countdown timer for the given contest."""
Expand All @@ -24,7 +22,7 @@ def countdown(contest: Contest) -> h.Element:
"giveaway " if contest.is_giveaway else "contest ",
"ends in:",
],
big_countdown(data_end_at=contest.end_at.isoformat())[
h.big_countdown(data_end_at=contest.end_at.isoformat())[
h.div(".countdown")[
h.span(".number", data_number="h0"),
h.span(".number", data_number="h1"),
Expand Down
22 changes: 0 additions & 22 deletions server/vb/components/fail_check_partial.js

This file was deleted.

13 changes: 0 additions & 13 deletions server/vb/components/finish_check_partial.js

This file was deleted.

4 changes: 1 addition & 3 deletions server/vb/components/ongoing_contest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
from .button import button
from .logo import school_logo

small_countdown = h.Element("small-countdown", {}, None)


def ongoing_contest(contest: Contest) -> h.Element:
"""Render an ongoing contest."""
Expand All @@ -29,7 +27,7 @@ def ongoing_contest(contest: Contest) -> h.Element:
)["Visit event"]
],
],
small_countdown(data_end_at=contest.end_at.isoformat())[
h.small_countdown(data_end_at=contest.end_at.isoformat())[
h.div(".box countdown")[""]
],
]
4 changes: 1 addition & 3 deletions server/vb/components/validate_email_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
from .base_page import base_page
from .logo import school_logo

gift_code = h.Element("gift-code", {}, None)


def _congrats(contest_entry: ContestEntry, claim_code: str) -> h.Node:
return [
Expand Down Expand Up @@ -68,7 +66,7 @@ def validate_email_page(
main_bg_color=school.logo.bg_color,
),
h.main[
gift_code[
h.gift_code[
h.div(".container")[
school_logo(school),
_congrats(contest_entry, claim_code)
Expand Down

0 comments on commit f797cf9

Please sign in to comment.