From d6dd6d3374cc2ec0cbed6c5e98747e9186c5e23f Mon Sep 17 00:00:00 2001 From: faucomte97 Date: Wed, 2 Oct 2024 13:41:02 +0100 Subject: [PATCH 01/10] First instance of donate popup --- Pipfile.lock | 143 ++++++++------- cfl_common/common/helpers/emails.py | 21 +++ example_project/portal_test_settings.py | 2 + example_project/settings.py | 2 + portal/context_processors.py | 6 +- portal/forms/dotmailer.py | 43 ++++- portal/static/django_reverse_js/js/reverse.js | 171 ++++++++++++++++++ portal/static/portal/js/common.js | 57 +++++- .../static/portal/sass/modules/_levels.scss | 2 +- .../static/portal/sass/partials/_popup.scss | 1 + portal/templates/portal/base.html | 16 +- .../portal/partials/donate_popup.html | 44 +++++ portal/templates/portal/partials/header.html | 61 ++++--- portal/urls.py | 4 + portal/views/dotmailer.py | 16 +- setup.py | 1 + 16 files changed, 480 insertions(+), 110 deletions(-) create mode 100644 portal/static/django_reverse_js/js/reverse.js create mode 100644 portal/templates/portal/partials/donate_popup.html diff --git a/Pipfile.lock b/Pipfile.lock index 31e51eb02..48f78a4ad 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -268,11 +268,11 @@ }, "idna": { "hashes": [ - "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", - "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], "markers": "python_version >= '3.6'", - "version": "==3.8" + "version": "==3.10" }, "importlib-metadata": { "hashes": [ @@ -363,38 +363,51 @@ }, "pandas": { "hashes": [ - "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863", - "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2", - "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1", - "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad", - "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db", - "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76", - "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51", - "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32", - "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08", - "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b", - "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4", - "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921", - "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288", - "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee", - "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0", - "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24", - "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99", - "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151", - "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd", - "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce", - "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57", - "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef", - "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54", - "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a", - "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238", - "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23", - "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772", - "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce", - "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad" + "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", + "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", + "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5", + "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", + "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", + "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32", + "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea", + "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", + "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f", + "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348", + "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", + "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", + "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5", + "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e", + "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", + "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645", + "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", + "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30", + "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", + "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", + "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", + "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3", + "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039", + "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", + "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd", + "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761", + "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", + "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57", + "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c", + "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c", + "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", + "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", + "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", + "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42", + "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", + "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39", + "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc", + "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698", + "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed", + "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", + "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", + "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319" ], "markers": "python_version >= '3.9'", - "version": "==2.2.2" + "version": "==2.2.3" }, "pgeocode": { "hashes": [ @@ -525,15 +538,15 @@ "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.9.0.post0" }, "pytz": { "hashes": [ - "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812", - "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319" + "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", + "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725" ], - "version": "==2024.1" + "version": "==2024.2" }, "pyyaml": { "hashes": [ @@ -604,10 +617,10 @@ }, "rapid-router": { "hashes": [ - "sha256:69b2b933f4c994610b8a3be244eb7d38ac4b81a569604c5a9d5eee4be1d4fbb7", - "sha256:c962147760b6a16d318fe5c865d287cef94f9d72017fcd46a643bda7e83375bd" + "sha256:112fe62d5ebae8953511903b80dc08207c2af120344a1e1a6b60ff81802e80ef", + "sha256:953ccadf6d03177367bfc9186213359a6837c7a17facab683f557f8503d6a843" ], - "version": "==6.4.4" + "version": "==6.5.4" }, "reportlab": { "hashes": [ @@ -681,7 +694,7 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" }, "sqlparse": { @@ -710,27 +723,27 @@ }, "tzdata": { "hashes": [ - "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", - "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", + "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" ], "markers": "python_version >= '2'", - "version": "==2024.1" + "version": "==2024.2" }, "urllib3": { "hashes": [ - "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", - "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168" + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], "markers": "python_version >= '3.8'", - "version": "==2.2.2" + "version": "==2.2.3" }, "zipp": { "hashes": [ - "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064", - "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b" + "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", + "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29" ], "markers": "python_version >= '3.8'", - "version": "==3.20.1" + "version": "==3.20.2" } }, "develop": { @@ -1038,11 +1051,11 @@ }, "idna": { "hashes": [ - "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", - "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], "markers": "python_version >= '3.6'", - "version": "==3.8" + "version": "==3.10" }, "iniconfig": { "hashes": [ @@ -1095,11 +1108,11 @@ }, "platformdirs": { "hashes": [ - "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", - "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" + "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", + "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb" ], "markers": "python_version >= '3.8'", - "version": "==4.2.2" + "version": "==4.3.6" }, "pluggy": { "hashes": [ @@ -1128,12 +1141,12 @@ }, "pytest": { "hashes": [ - "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", - "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce" + "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", + "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==8.3.2" + "version": "==8.3.3" }, "pytest-cov": { "hashes": [ @@ -1182,10 +1195,10 @@ }, "pytz": { "hashes": [ - "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812", - "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319" + "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", + "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725" ], - "version": "==2024.1" + "version": "==2024.2" }, "pyvirtualdisplay": { "hashes": [ @@ -1294,11 +1307,11 @@ }, "urllib3": { "hashes": [ - "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", - "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168" + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], "markers": "python_version >= '3.8'", - "version": "==2.2.2" + "version": "==2.2.3" }, "wasmer": { "hashes": [ diff --git a/cfl_common/common/helpers/emails.py b/cfl_common/common/helpers/emails.py index 070c61511..b97c27c1d 100644 --- a/cfl_common/common/helpers/emails.py +++ b/cfl_common/common/helpers/emails.py @@ -144,6 +144,27 @@ def add_to_dotmailer(first_name: str, last_name: str, email: str, user_type: Dot return HttpResponse(status=404) +def add_donor_to_dotmailer(first_name: str, last_name: str, email: str): + try: + create_contact(first_name, last_name, email) + main_address_book_url = "https://r1-api.dotmailer.com/v2/address-books/37649245/contacts" + + body = { + "email": email, + "optInType": "VerifiedDouble", + "emailType": "Html", + "dataFields": [ + {"key": "FIRSTNAME", "value": first_name}, + {"key": "LASTNAME", "value": last_name}, + {"key": "FULLNAME", "value": f"{first_name} {last_name}"}, + ], + } + + post(main_address_book_url, json=body, auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD)) + except RequestException: + return HttpResponse(status=404) + + def create_contact(first_name, last_name, email): url = app_settings.DOTMAILER_CREATE_CONTACT_URL body = { diff --git a/example_project/portal_test_settings.py b/example_project/portal_test_settings.py index 0fe3ae5b6..a923c3a34 100644 --- a/example_project/portal_test_settings.py +++ b/example_project/portal_test_settings.py @@ -105,6 +105,7 @@ "treebeard", "two_factor", "preventconcurrentlogins", + "django_reverse_js", ] PIPELINE = { @@ -172,6 +173,7 @@ "common.context_processors.module_name", "common.context_processors.cookie_management_enabled", "portal.context_processors.process_newsletter_form", + "portal.context_processors.process_donate_form", ] }, } diff --git a/example_project/settings.py b/example_project/settings.py index 3c39414a2..e7e10ffa5 100644 --- a/example_project/settings.py +++ b/example_project/settings.py @@ -61,6 +61,7 @@ "treebeard", "two_factor", "preventconcurrentlogins", + "django_reverse_js", ] PIPELINE = { @@ -130,6 +131,7 @@ "common.context_processors.module_name", "common.context_processors.cookie_management_enabled", "portal.context_processors.process_newsletter_form", + "portal.context_processors.process_donate_form", ] } } diff --git a/portal/context_processors.py b/portal/context_processors.py index 96dbefdf5..6b39fd91a 100644 --- a/portal/context_processors.py +++ b/portal/context_processors.py @@ -1,5 +1,9 @@ -from portal.forms.dotmailer import NewsletterForm +from portal.forms.dotmailer import DonateForm, NewsletterForm def process_newsletter_form(request): return {"news_form": NewsletterForm()} + + +def process_donate_form(request): + return {"donate_form": DonateForm()} diff --git a/portal/forms/dotmailer.py b/portal/forms/dotmailer.py index f16d0870f..20185b2b5 100644 --- a/portal/forms/dotmailer.py +++ b/portal/forms/dotmailer.py @@ -5,16 +5,51 @@ class NewsletterForm(forms.Form): email = forms.EmailField( label="Sign up to receive updates about Code for Life games and teaching resources.", label_suffix="", - widget=forms.EmailInput(attrs={"placeholder": "Your email address", "id": "newsletter_email_field"}), + widget=forms.EmailInput( + attrs={ + "placeholder": "Your email address", + "id": "newsletter_email_field", + } + ), help_text="Enter email address above", ) - age_verification = forms.BooleanField(widget=forms.CheckboxInput(), initial=False, required=True) + age_verification = forms.BooleanField( + widget=forms.CheckboxInput(), initial=False, required=True + ) + + +class DonateForm(forms.Form): + email = forms.EmailField( + label="This data will only be used for this purpose and you will be " + "able to opt out anytime. Please read our privacy notice for " + "futher details.", + label_suffix="", + widget=forms.EmailInput( + attrs={ + "placeholder": "Enter your email address", + "id": "donate_email_field", + } + ), + help_text="Enter your email address", + ) + + age_verification = forms.BooleanField( + widget=forms.CheckboxInput(attrs={"id": "donate_age_verification"}), + initial=False, + required=True, + ) class ConsentForm(forms.Form): email = forms.EmailField( - label="Email", label_suffix="", widget=forms.EmailInput(attrs={"placeholder": "your.name@yourdomain.com"}) + label="Email", + label_suffix="", + widget=forms.EmailInput( + attrs={"placeholder": "your.name@yourdomain.com"} + ), ) - consent_ticked = forms.BooleanField(widget=forms.CheckboxInput(), initial=False, required=True) + consent_ticked = forms.BooleanField( + widget=forms.CheckboxInput(), initial=False, required=True + ) diff --git a/portal/static/django_reverse_js/js/reverse.js b/portal/static/django_reverse_js/js/reverse.js new file mode 100644 index 000000000..576d8b549 --- /dev/null +++ b/portal/static/django_reverse_js/js/reverse.js @@ -0,0 +1,171 @@ +this.Urls = (function () { + var data = {"urls": [["about", [["about", []]]], ["admin:app_list", [["administration/%(app_label)s/", ["app_label"]]]], ["admin:auth_group_add", [["administration/auth/group/add/", []]]], ["admin:auth_group_change", [["administration/auth/group/%(object_id)s/change/", ["object_id"]]]], ["admin:auth_group_changelist", [["administration/auth/group/", []]]], ["admin:auth_group_delete", [["administration/auth/group/%(object_id)s/delete/", ["object_id"]]]], ["admin:auth_group_history", [["administration/auth/group/%(object_id)s/history/", ["object_id"]]]], ["admin:auth_user_add", [["administration/auth/user/add/", []]]], ["admin:auth_user_change", [["administration/auth/user/%(object_id)s/change/", ["object_id"]]]], ["admin:auth_user_changelist", [["administration/auth/user/", []]]], ["admin:auth_user_delete", [["administration/auth/user/%(object_id)s/delete/", ["object_id"]]]], ["admin:auth_user_history", [["administration/auth/user/%(object_id)s/history/", ["object_id"]]]], ["admin:auth_user_password_change", [["administration/auth/user/%(id)s/password/", ["id"]]]], ["admin:autocomplete", [["administration/autocomplete/", []]]], ["admin:common_class_add", [["administration/common/class/add/", []]]], ["admin:common_class_change", [["administration/common/class/%(object_id)s/change/", ["object_id"]]]], ["admin:common_class_changelist", [["administration/common/class/", []]]], ["admin:common_class_delete", [["administration/common/class/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_class_history", [["administration/common/class/%(object_id)s/history/", ["object_id"]]]], ["admin:common_dailyactivity_add", [["administration/common/dailyactivity/add/", []]]], ["admin:common_dailyactivity_change", [["administration/common/dailyactivity/%(object_id)s/change/", ["object_id"]]]], ["admin:common_dailyactivity_changelist", [["administration/common/dailyactivity/", []]]], ["admin:common_dailyactivity_delete", [["administration/common/dailyactivity/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_dailyactivity_history", [["administration/common/dailyactivity/%(object_id)s/history/", ["object_id"]]]], ["admin:common_dynamicelement_add", [["administration/common/dynamicelement/add/", []]]], ["admin:common_dynamicelement_change", [["administration/common/dynamicelement/%(object_id)s/change/", ["object_id"]]]], ["admin:common_dynamicelement_changelist", [["administration/common/dynamicelement/", []]]], ["admin:common_dynamicelement_delete", [["administration/common/dynamicelement/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_dynamicelement_history", [["administration/common/dynamicelement/%(object_id)s/history/", ["object_id"]]]], ["admin:common_school_add", [["administration/common/school/add/", []]]], ["admin:common_school_change", [["administration/common/school/%(object_id)s/change/", ["object_id"]]]], ["admin:common_school_changelist", [["administration/common/school/", []]]], ["admin:common_school_delete", [["administration/common/school/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_school_history", [["administration/common/school/%(object_id)s/history/", ["object_id"]]]], ["admin:common_schoolteacherinvitation_add", [["administration/common/schoolteacherinvitation/add/", []]]], ["admin:common_schoolteacherinvitation_change", [["administration/common/schoolteacherinvitation/%(object_id)s/change/", ["object_id"]]]], ["admin:common_schoolteacherinvitation_changelist", [["administration/common/schoolteacherinvitation/", []]]], ["admin:common_schoolteacherinvitation_delete", [["administration/common/schoolteacherinvitation/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_schoolteacherinvitation_history", [["administration/common/schoolteacherinvitation/%(object_id)s/history/", ["object_id"]]]], ["admin:common_student_add", [["administration/common/student/add/", []]]], ["admin:common_student_change", [["administration/common/student/%(object_id)s/change/", ["object_id"]]]], ["admin:common_student_changelist", [["administration/common/student/", []]]], ["admin:common_student_delete", [["administration/common/student/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_student_history", [["administration/common/student/%(object_id)s/history/", ["object_id"]]]], ["admin:common_teacher_add", [["administration/common/teacher/add/", []]]], ["admin:common_teacher_change", [["administration/common/teacher/%(object_id)s/change/", ["object_id"]]]], ["admin:common_teacher_changelist", [["administration/common/teacher/", []]]], ["admin:common_teacher_delete", [["administration/common/teacher/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_teacher_history", [["administration/common/teacher/%(object_id)s/history/", ["object_id"]]]], ["admin:common_totalactivity_add", [["administration/common/totalactivity/add/", []]]], ["admin:common_totalactivity_change", [["administration/common/totalactivity/%(object_id)s/change/", ["object_id"]]]], ["admin:common_totalactivity_changelist", [["administration/common/totalactivity/", []]]], ["admin:common_totalactivity_delete", [["administration/common/totalactivity/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_totalactivity_history", [["administration/common/totalactivity/%(object_id)s/history/", ["object_id"]]]], ["admin:common_userprofile_add", [["administration/common/userprofile/add/", []]]], ["admin:common_userprofile_change", [["administration/common/userprofile/%(object_id)s/change/", ["object_id"]]]], ["admin:common_userprofile_changelist", [["administration/common/userprofile/", []]]], ["admin:common_userprofile_delete", [["administration/common/userprofile/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_userprofile_history", [["administration/common/userprofile/%(object_id)s/history/", ["object_id"]]]], ["admin:game_attempt_add", [["administration/game/attempt/add/", []]]], ["admin:game_attempt_change", [["administration/game/attempt/%(object_id)s/change/", ["object_id"]]]], ["admin:game_attempt_changelist", [["administration/game/attempt/", []]]], ["admin:game_attempt_delete", [["administration/game/attempt/%(object_id)s/delete/", ["object_id"]]]], ["admin:game_attempt_history", [["administration/game/attempt/%(object_id)s/history/", ["object_id"]]]], ["admin:game_block_add", [["administration/game/block/add/", []]]], ["admin:game_block_change", [["administration/game/block/%(object_id)s/change/", ["object_id"]]]], ["admin:game_block_changelist", [["administration/game/block/", []]]], ["admin:game_block_delete", [["administration/game/block/%(object_id)s/delete/", ["object_id"]]]], ["admin:game_block_history", [["administration/game/block/%(object_id)s/history/", ["object_id"]]]], ["admin:game_episode_add", [["administration/game/episode/add/", []]]], ["admin:game_episode_change", [["administration/game/episode/%(object_id)s/change/", ["object_id"]]]], ["admin:game_episode_changelist", [["administration/game/episode/", []]]], ["admin:game_episode_delete", [["administration/game/episode/%(object_id)s/delete/", ["object_id"]]]], ["admin:game_episode_history", [["administration/game/episode/%(object_id)s/history/", ["object_id"]]]], ["admin:game_level_add", [["administration/game/level/add/", []]]], ["admin:game_level_change", [["administration/game/level/%(object_id)s/change/", ["object_id"]]]], ["admin:game_level_changelist", [["administration/game/level/", []]]], ["admin:game_level_delete", [["administration/game/level/%(object_id)s/delete/", ["object_id"]]]], ["admin:game_level_history", [["administration/game/level/%(object_id)s/history/", ["object_id"]]]], ["admin:game_leveldecor_add", [["administration/game/leveldecor/add/", []]]], ["admin:game_leveldecor_change", [["administration/game/leveldecor/%(object_id)s/change/", ["object_id"]]]], ["admin:game_leveldecor_changelist", [["administration/game/leveldecor/", []]]], ["admin:game_leveldecor_delete", [["administration/game/leveldecor/%(object_id)s/delete/", ["object_id"]]]], ["admin:game_leveldecor_history", [["administration/game/leveldecor/%(object_id)s/history/", ["object_id"]]]], ["admin:game_workspace_add", [["administration/game/workspace/add/", []]]], ["admin:game_workspace_change", [["administration/game/workspace/%(object_id)s/change/", ["object_id"]]]], ["admin:game_workspace_changelist", [["administration/game/workspace/", []]]], ["admin:game_workspace_delete", [["administration/game/workspace/%(object_id)s/delete/", ["object_id"]]]], ["admin:game_workspace_history", [["administration/game/workspace/%(object_id)s/history/", ["object_id"]]]], ["admin:index", [["administration/", []]]], ["admin:jsi18n", [["administration/jsi18n/", []]]], ["admin:login", [["administration/login/", []]]], ["admin:logout", [["administration/logout/", []]]], ["admin:otp_static_staticdevice_add", [["administration/otp_static/staticdevice/add/", []]]], ["admin:otp_static_staticdevice_change", [["administration/otp_static/staticdevice/%(object_id)s/change/", ["object_id"]]]], ["admin:otp_static_staticdevice_changelist", [["administration/otp_static/staticdevice/", []]]], ["admin:otp_static_staticdevice_delete", [["administration/otp_static/staticdevice/%(object_id)s/delete/", ["object_id"]]]], ["admin:otp_static_staticdevice_history", [["administration/otp_static/staticdevice/%(object_id)s/history/", ["object_id"]]]], ["admin:otp_totp_totpdevice_add", [["administration/otp_totp/totpdevice/add/", []]]], ["admin:otp_totp_totpdevice_change", [["administration/otp_totp/totpdevice/%(object_id)s/change/", ["object_id"]]]], ["admin:otp_totp_totpdevice_changelist", [["administration/otp_totp/totpdevice/", []]]], ["admin:otp_totp_totpdevice_config", [["administration/otp_totp/totpdevice/%(pk)s/config/", ["pk"]]]], ["admin:otp_totp_totpdevice_delete", [["administration/otp_totp/totpdevice/%(object_id)s/delete/", ["object_id"]]]], ["admin:otp_totp_totpdevice_history", [["administration/otp_totp/totpdevice/%(object_id)s/history/", ["object_id"]]]], ["admin:otp_totp_totpdevice_qrcode", [["administration/otp_totp/totpdevice/%(pk)s/qrcode/", ["pk"]]]], ["admin:password_change", [["administration/password_change/", []]]], ["admin:password_change_done", [["administration/password_change/done/", []]]], ["admin:sites_site_add", [["administration/sites/site/add/", []]]], ["admin:sites_site_change", [["administration/sites/site/%(object_id)s/change/", ["object_id"]]]], ["admin:sites_site_changelist", [["administration/sites/site/", []]]], ["admin:sites_site_delete", [["administration/sites/site/%(object_id)s/delete/", ["object_id"]]]], ["admin:sites_site_history", [["administration/sites/site/%(object_id)s/history/", ["object_id"]]]], ["admin:two_factor_phonedevice_add", [["administration/two_factor/phonedevice/add/", []]]], ["admin:two_factor_phonedevice_change", [["administration/two_factor/phonedevice/%(object_id)s/change/", ["object_id"]]]], ["admin:two_factor_phonedevice_changelist", [["administration/two_factor/phonedevice/", []]]], ["admin:two_factor_phonedevice_delete", [["administration/two_factor/phonedevice/%(object_id)s/delete/", ["object_id"]]]], ["admin:two_factor_phonedevice_history", [["administration/two_factor/phonedevice/%(object_id)s/history/", ["object_id"]]]], ["admin:view_on_site", [["administration/r/%(content_type_id)s/%(object_id)s/", ["content_type_id", "object_id"]]]], ["administration_password_change", [["administration/password_change/", []]]], ["administration_password_change_done", [["administration/password_change_done/", []]]], ["anonymise-unverified-accounts", [["cron/user/unverified/delete/", []]]], ["anonymise_orphan_schools", [["schools/anonymise/%(start_id)s/", ["start_id"]]]], ["block-detail", [["rapidrouter/api/blocks/%(pk)s/", ["pk"]]]], ["block-list", [["rapidrouter/api/blocks/", []]]], ["celebrate", [["celebrate/", []]]], ["character-detail", [["rapidrouter/api/characters/%(pk)s/", ["pk"]]]], ["character-list", [["rapidrouter/api/characters/", []]]], ["codingClub", [["codingClub/", []]]], ["consent_form", [["consent_form/", []]]], ["contribute", [["contribute", []]]], ["dashboard", [["teach/dashboard/", []]]], ["decor-detail", [["rapidrouter/api/decors/%(pk)s/", ["pk"]]]], ["decor-list", [["rapidrouter/api/decors/", []]]], ["delete_account", [["delete/account/", []]]], ["delete_level", [["rapidrouter/level_moderation/delete/%(levelID)s/", ["levelID"]]]], ["delete_level_for_editor", [["rapidrouter/level_editor/delete/%(levelId)s/", ["levelId"]]]], ["delete_teacher_invite", [["teach/dashboard/delete_teacher_invite/%(token)s", ["token"]]]], ["delete_workspace", [["rapidrouter/workspace/delete/%(workspaceID)s/", ["workspaceID"]]]], ["download_student_pack", [["codingClub/%(student_pack_type)s/", ["student_pack_type"]]]], ["email_verification", [["verify_email/", []]]], ["episode-detail", [["rapidrouter/api/episodes/%(pk)s/", ["pk"]]]], ["episode-list", [["rapidrouter/api/episodes/", []]]], ["final-inactivity-reminder", [["cron/user/inactive/send-final-reminder/", []]]], ["first-inactivity-reminder", [["cron/user/inactive/send-first-reminder/", []]]], ["first-verify-email-reminder", [["cron/user/unverified/send-first-reminder/", []]]], ["generate_random_map_for_editor", [["rapidrouter/level_editor/random/", []]]], ["get_sharing_information_for_editor", [["rapidrouter/level_editor/get_sharing_information/%(levelID)s/", ["levelID"]]]], ["getinvolved", [["getinvolved", []]]], ["home", [["", []]]], ["home-learning", [["home-learning", []]]], ["inactive_users", [["users/inactive/", []]]], ["independent_edit_account", [["play/account/independent/", []]]], ["independent_student_details", [["play/details/independent", []]]], ["independent_student_login", [["login/independent/", []]]], ["invite_toggle_admin", [["teach/dashboard/toggle_admin_invite/%(invite_id)s/", ["invite_id"]]]], ["invited_teacher", [["invited_teacher/%(token)s/", ["token"]]]], ["js-reverse", [["rapidrouter/reverse.js", []], ["reverse.js", []]]], ["last-connected-since", [["api/lastconnectedsince/%(year)s/%(month)s/%(day)s/", ["year", "month", "day"]]]], ["level-detail", [["rapidrouter/api/levels/%(pk)s/", ["pk"]]]], ["level-for-episode", [["rapidrouter/api/episodes/%(pk)s/levels/", ["pk"]]]], ["level-list", [["rapidrouter/api/levels/", []]]], ["level_editor", [["rapidrouter/level_editor/", []]]], ["level_editor_chosen_level", [["rapidrouter/level_editor/%(levelId)s/", ["levelId"]]]], ["level_moderation", [["rapidrouter/level_moderation/", []]]], ["levelblock-detail", [["rapidrouter/api/levelblocks/%(pk)s/", ["pk"]]]], ["levelblock-for-level", [["rapidrouter/api/levels/%(pk)s/blocks/", ["pk"]]]], ["leveldecor-detail", [["rapidrouter/api/leveldecors/%(pk)s/", ["pk"]]]], ["leveldecor-for-level", [["rapidrouter/api/levels/%(pk)s/decors/", ["pk"]]]], ["levels", [["rapidrouter/", []]]], ["load_level_for_editor", [["rapidrouter/level_editor/get/%(levelID)s/", ["levelID"]]]], ["load_list_of_workspaces", [["rapidrouter/workspace/load_list/", []]]], ["load_workspace", [["rapidrouter/workspace/load/%(workspaceID)s/", ["workspaceID"]]]], ["load_workspace_solution", [["rapidrouter/workspace/solution/%(level_name)s/", ["level_name"]]]], ["locked_out", [["locked_out/", []]]], ["logout_view", [["logout/", []]]], ["map-for-level", [["rapidrouter/api/levels/%(pk)s/map/", ["pk"]]]], ["map-list", [["rapidrouter/api/maps/", []]]], ["mode-for-level", [["rapidrouter/api/levels/%(pk)s/mode/", ["pk"]]]], ["number_users_per_country", [["api/userspercountry/%(country)s/", ["country"]]]], ["old_login_form", [["login_form", []]]], ["onboarding-class", [["teach/onboarding-class/%(access_code)s", ["access_code"]]]], ["onboarding-classes", [["teach/onboarding-classes", []]]], ["onboarding-organisation", [["teach/onboarding-organisation/", []]]], ["organisation_kick", [["teach/dashboard/kick/%(pk)s/", ["pk"]]]], ["organisation_leave", [["teach/dashboard/school/leave/", []]]], ["organisation_toggle_admin", [["teach/dashboard/toggle_admin/%(pk)s/", ["pk"]]]], ["owned_levels", [["rapidrouter/level_editor/levels/owned/", []]]], ["password_reset_check_and_confirm", [["user/password/reset/%(uidb64)s-%(token)s/", ["uidb64", "token"]]]], ["password_reset_complete", [["teacher/password/reset/complete/", []]]], ["play", [["play/", []]]], ["play_anonymous_level", [["rapidrouter/level_editor/play_anonymous/%(levelId)s/", ["levelId"]]]], ["play_custom_level", [["rapidrouter/custom/%(levelId)s/", ["levelId"]]]], ["play_custom_level_from_editor", [["rapidrouter/level_editor/play_custom/%(levelId)s/", ["levelId"]]]], ["play_default_level", [["rapidrouter/%(level_name)s/", ["level_name"]], ["%(level_name)s/", ["level_name"]]]], ["play_python_default_level", [["pythonden/%(level_name)s/", ["level_name"]]]], ["privacy_notice", [["privacy-notice/", []]]], ["privacy_policy", [["privacy-policy/", []]]], ["process_donate_form", [["donate_signup/", []]]], ["process_newsletter_form", [["news_signup/", []]]], ["python_levels", [["pythonden/", []]]], ["python_scoreboard", [["pythonden/scoreboard/", []]]], ["random_level_for_episode", [["rapidrouter/levels/random/%(_0)s/", ["_0"]]]], ["rapid-router/javascript-catalog", [["rapidrouter/js-i18n/", []]]], ["register", [["register_form", []]]], ["registered-users", [["api/registered/%(year)s/%(month)s/%(day)s/", ["year", "month", "day"]]]], ["remove_fake_accounts", [["removeFakeAccounts/", []]]], ["resend_invite_teacher", [["teach/dashboard/resend_invite/%(token)s/", ["token"]]]], ["reset_password_email_sent", [["user/password/reset/done/", []]]], ["reset_screentime_warning", [["user/reset_screentime_warning/", []]]], ["reset_session_time", [["user/reset_session_time/", []]]], ["rest_framework:login", [["rapidrouter/api-auth/login/", []]]], ["rest_framework:logout", [["rapidrouter/api-auth/logout/", []]]], ["save_level_for_editor", [["rapidrouter/level_editor/save/%(levelId)s/", ["levelId"]], ["rapidrouter/level_editor/save/", []]]], ["save_workspace", [["rapidrouter/workspace/save/%(workspaceID)s/", ["workspaceID"]], ["rapidrouter/workspace/save/", []]]], ["school_student_edit_account", [["play/account/school_student/", []]]], ["scoreboard", [["rapidrouter/scoreboard/", []]]], ["second-inactivity-reminder", [["cron/user/inactive/send-second-reminder/", []]]], ["second-verify-email-reminder", [["cron/user/unverified/send-second-reminder/", []]]], ["set_language", [["i18n/setlang/", []]]], ["share_level_for_editor", [["rapidrouter/level_editor/share/%(levelID)s/", ["levelID"]]]], ["shared_levels", [["rapidrouter/level_editor/levels/shared/", []]]], ["start_episode", [["rapidrouter/episode/%(episodeId)s/", ["episodeId"]]]], ["start_python_episode", [["pythonden/episode/%(episodeId)s/", ["episodeId"]]]], ["student_details", [["play/details/", []]]], ["student_direct_login", [["u/%(user_id)s/%(login_id)s/", ["user_id", "login_id"]]]], ["student_edit_account", [["play/account/", []]]], ["student_join_organisation", [["play/join/", []]]], ["student_login", [["login/student/%(access_code)s/", ["access_code"]], ["login/student/%(access_code)s/%(login_type)s/", ["access_code", "login_type"]]]], ["student_login_access_code", [["login/student/", []]]], ["student_password_reset", [["user/password/reset/student/", []]]], ["submit_attempt", [["rapidrouter/submit/", []]]], ["teach", [["teach/", []]]], ["teacher_accept_student_request", [["teach/dashboard/student/accept/%(pk)s/", ["pk"]]]], ["teacher_class_password_reset", [["teach/class/%(access_code)s/password_reset/", ["access_code"]]]], ["teacher_delete_class", [["teach/class/delete/%(access_code)s", ["access_code"]]]], ["teacher_delete_students", [["teach/class/%(access_code)s/students/delete/", ["access_code"]]]], ["teacher_disable_2FA", [["teach/dashboard/disable_2FA/%(pk)s/", ["pk"]]]], ["teacher_dismiss_students", [["teach/class/%(access_code)s/students/dismiss/", ["access_code"]]]], ["teacher_download_csv", [["teach/onboarding-class/%(access_code)s/download_csv/", ["access_code"]]]], ["teacher_edit_class", [["teach/class/edit/%(access_code)s", ["access_code"]]]], ["teacher_edit_student", [["teach/class/student/edit/%(pk)s/", ["pk"]]]], ["teacher_login", [["login/teacher/", []]]], ["teacher_move_students", [["teach/class/%(access_code)s/students/move/", ["access_code"]]]], ["teacher_move_students_to_class", [["teach/class/%(access_code)s/students/move/disambiguate/", ["access_code"]]]], ["teacher_password_reset", [["user/password/reset/teacher/", []]]], ["teacher_print_reminder_cards", [["teach/onboarding-class/%(access_code)s/print_reminder_cards/", ["access_code"]]]], ["teacher_reject_student_request", [["teach/dashboard/student/reject/%(pk)s/", ["pk"]]]], ["terms", [["terms", []]]], ["theme-detail", [["rapidrouter/api/themes/%(pk)s/", ["pk"]]]], ["theme-list", [["rapidrouter/api/themes/", []]]], ["two_factor:backup_tokens", [["account/two_factor/backup/tokens/", []]]], ["two_factor:disable", [["account/two_factor/disable/", []]]], ["two_factor:profile", [["account/two_factor/", []]]], ["two_factor:qr", [["account/two_factor/qrcode/", []]]], ["two_factor:setup", [["account/two_factor/setup/", []]]], ["two_factor:setup_complete", [["account/two_factor/setup/complete/", []]]], ["verify_email", [["verify_email/%(token)s/", ["token"]]]], ["view_class", [["teach/class/%(access_code)s", ["access_code"]]]]], "prefix": "/"}; + var resolverFactory; +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "UrlResolver": () => (/* binding */ UrlResolver), +/* harmony export */ "factory": () => (/* binding */ factory) +/* harmony export */ }); +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } + +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } + +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } + +function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + +function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var UrlResolver = /*#__PURE__*/function () { + function UrlResolver(prefix, patterns) { + _classCallCheck(this, UrlResolver); + + this.prefix = prefix; + this.patterns = patterns; + this.reverse = this.reverse.bind(this); + } + + _createClass(UrlResolver, [{ + key: "reverse", + value: function reverse() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + var validateArgs, buildKwargs; + + if (args.length === 1 && _typeof(args[0]) === 'object') { + // kwargs mode + var providedKeys = Object.keys(args[0]); + + validateArgs = function validateArgs(_ref) { + var _ref2 = _slicedToArray(_ref, 2), + _urlTemplate = _ref2[0], + urlParams = _ref2[1]; + + // check every needed param was provided (without extra elements) + return urlParams.length === providedKeys.length && urlParams.every(function (p) { + return providedKeys.includes(p); + }); + }; // return first element + + + buildKwargs = function buildKwargs() { + return args[0]; + }; + } else { + // args mode + // check every required param + validateArgs = function validateArgs(_ref3) { + var _ref4 = _slicedToArray(_ref3, 2), + _urlTemplate = _ref4[0], + urlParams = _ref4[1]; + + return urlParams.length === args.length; + }; // build keyword-arguments from arguments + + + buildKwargs = function buildKwargs(keys) { + return Object.fromEntries(keys.map(function (key, i) { + return [key, args[i]]; + })); + }; + } // search between patterns if one matches provided args + + + var urlPattern = this.patterns.find(validateArgs); + + if (!urlPattern) { + return null; + } + + var _urlPattern = _slicedToArray(urlPattern, 2), + urlTemplate = _urlPattern[0], + urlKwargNames = _urlPattern[1]; + + var urlKwargs = buildKwargs(urlKwargNames); + var url = Object.entries(urlKwargs).reduce(function (partialUrl, _ref5) { + var _ref6 = _slicedToArray(_ref5, 2), + pName = _ref6[0], + pValue = _ref6[1]; + + if (pValue == null) pValue = ''; // replace variable with param + + return partialUrl.replace("%(".concat(pName, ")s"), pValue); + }, urlTemplate); + return "".concat(this.prefix).concat(url); + } + }]); + + return UrlResolver; +}(); +function factory(config) { + var urlPatterns = config.urls, + urlPrefix = config.prefix; + return urlPatterns.reduce(function (resolver, _ref7) { + var _ref8 = _slicedToArray(_ref7, 2), + name = _ref8[0], + pattern = _ref8[1]; + + var urlResolver = new UrlResolver(urlPrefix, pattern); + resolver[name] = urlResolver.reverse; // turn snake-case into camel-case + + resolver[name.replace(/[-_]+(.)/g, function (_m, p1) { + return p1.toUpperCase(); + })] = urlResolver.reverse; // turn snake-case into dash-case + + resolver[name.replace(/-/g, '_')] = urlResolver.reverse; + return resolver; + }, {}); +} +resolverFactory = __webpack_exports__; +/******/ })() +; + return data ? resolverFactory.factory(data) : resolverFactory.factory; +})(); diff --git a/portal/static/portal/js/common.js b/portal/static/portal/js/common.js index 94561ab36..a721c3681 100644 --- a/portal/static/portal/js/common.js +++ b/portal/static/portal/js/common.js @@ -38,13 +38,59 @@ function hidePopupConfirmation() { $("#popup").find(".popup-text").remove(); } +function showDonatePopup(title, text) { + let popup = $("#donate-popup"); + popup.find(".popup-box__title").text(title); + popup.find(".popup-box__msg").append(text); -/** + popup.addClass("popup--fade"); +} + +function hideDonatePopup() { + $("#donate-popup").removeClass("popup--fade"); + $("#donate-popup").find(".popup-text").remove(); + $('#donate_age_verification').prop("checked", false); + const donateSubmitButton = $('#confirm_donate_button'); + donateSubmitButton.addClass("disabled"); + donateSubmitButton.prop("disabled", true); +} + +function processDonateForm() { + const email = $("#donate_email_field").val(); + $.ajax({ + url: Urls.process_donate_form(), + type: 'POST', + dataType: 'json', + data: { + email: email + }, + error: function (xhr, errmsg, err) { + console.error( + xhr.status + ': ' + errmsg + ' ' + err + ' ' + xhr.responseText + ) + }.bind(this) + }) + hideDonatePopup(); +} + +function showDonateConfirmation(path) { + let title = "We would love to have you support our non-profit mission! ❤️"; + let text = + ""; + let confirm_handler = "postWithCsrf('" + path + "')"; + + showDonatePopup(title, text, confirm_handler); +} -Show a service unavailable popup with a close button in the top-right corner. -@param {String} title The title of the popup. -@param {String} text The message of the popup. -*/ +/** + * Show a service unavailable popup with a close button in the top-right corner. + * @param {String} title The title of the popup. + * @param {String} text The message of the popup. + */ function showServiceUnavailable(title, text) { let popup = $("#service-unavailable-popup"); @@ -57,6 +103,7 @@ function showServiceUnavailable(title, text) { function hideServiceUnavailable() { $("#service-unavailable-popup").removeClass("popup--fade"); } + /** * Show an info popup with a close button in the top-right corner. * @param {String} title The title of the popup. diff --git a/portal/static/portal/sass/modules/_levels.scss b/portal/static/portal/sass/modules/_levels.scss index 8812a67fb..717e954bb 100644 --- a/portal/static/portal/sass/modules/_levels.scss +++ b/portal/static/portal/sass/modules/_levels.scss @@ -1,4 +1,4 @@ $hover-content-level: 100; $nav-bar-level: 1001; -$popup-overlay-level: 300; +$popup-overlay-level: 1100; $behind-content-level: -100; diff --git a/portal/static/portal/sass/partials/_popup.scss b/portal/static/portal/sass/partials/_popup.scss index 4e58c18ac..64d669654 100644 --- a/portal/static/portal/sass/partials/_popup.scss +++ b/portal/static/portal/sass/partials/_popup.scss @@ -47,6 +47,7 @@ .popup-box__title { @include _padding(5 * $spacing, 5 * $spacing, 0px, 5 * $spacing); background-color: $color-background-secondary; + color: $color-text-primary; display: flex; justify-content: flex-start; font-family: "Space Grotesk", sans-serif; diff --git a/portal/templates/portal/base.html b/portal/templates/portal/base.html index e9e795dbc..049a6e585 100644 --- a/portal/templates/portal/base.html +++ b/portal/templates/portal/base.html @@ -32,7 +32,7 @@ type="image/x-icon"> {% endblock css %} {% include "portal/tag_manager/tag_manager_head.html" %} - + @@ -82,6 +82,7 @@ {% include "portal/tag_manager/tag_manager_body.html" %} {% render_block "js" %} {% include 'portal/mouseflow.html' %} + {% include "portal/partials/donate_popup.html" %} @@ -36,8 +35,8 @@