diff --git a/functions.php b/functions.php index 6ca88dc6d12ed997e426ea0940007e571a5e11e6..3bda3f62d1d9fe7caee934de50b08cad959f5526 100644 --- a/functions.php +++ b/functions.php @@ -9,7 +9,7 @@ if ( ! defined( '_S_VERSION' ) ) { // Replace the version number of the theme on each release. - define( '_S_VERSION', '1.0.0' ); + define( '_S_VERSION', '1.1.0' ); } /** @@ -180,4 +180,3 @@ require get_template_directory() . '/inc/customizer.php'; if ( defined( 'JETPACK__VERSION' ) ) { require get_template_directory() . '/inc/jetpack.php'; } - diff --git a/js/memberships.js b/js/memberships.js index dc6f1820191c2e22a3af7f5c1138ebf4e8342dfc..7c5d0197e3d7198686def9b7eb041feef6ebe3a4 100644 --- a/js/memberships.js +++ b/js/memberships.js @@ -8,34 +8,40 @@ */ ( function() { const membershipsBtnGroupClass = 'memberships-btn-group'; + const membershipsGroupSelectId = 'memberships-group-select'; const purchaseFormId = 'purchase-form-ele'; const purchaseItemsClass = 'purchase-form-items'; const purchaseItemsSelector = `#${purchaseFormId} .${purchaseItemsClass} .list-group-item label` - const defaultMembershipTypesSelector = `.${membershipsBtnGroupClass} button:first-child`; + const defaultmembershipsTypesSelector = `.${membershipsBtnGroupClass} button:first-child`; const activeClass = 'active'; - // add const for discerning if it's a subscription. + const membershipDisplayType = 'flex'; + + let memberships = { + groups: [], + items: [] + }; + + let membershipsState = { + // membershipsType: 'one-time', + membershipsType: 'recurring', + membershipsGroup: '1 Year' + }; function injectMembershipsBtnGroup() { const btnGroupHTML = `<div class="${membershipsBtnGroupClass} btn-group" role="group" aria-label="Membership Types" - > - <button - class="btn btn-light active" - data-show-memberships="all" - > - All - </button><button + ><button class="btn btn-light" - data-show-memberships="one-time" + data-show-memberships="recurring" > - One-time + Recurring </button><button class="btn btn-light" - data-show-memberships="recurring" + data-show-memberships="one-time" > - Recurring + One-time </button> </div>`; @@ -50,17 +56,29 @@ }); } - function injectMembershipDescriptions() { - const descrClassName = 'purchasable-item-description'; + function isLifetimeGroup(group) { + return group.intv > 1000; + } - document.getElementById(purchaseFormId).querySelectorAll( - '.purchasable-items .list-group-item label' - ).forEach(ele => { - if (!ele.getElementsByClassName(descrClassName).length) { - const descrEle = `<p class="${descrClassName}">Full Access to Our Puzzle Archive</p>`; - ele.insertAdjacentHTML('beforeend', descrEle); - } - }) + function injectMembershipsGroupSelect() { + const selectGroupHTML = `<select + name="purchasable-item-interval-group" + class="form-control" + id="${membershipsGroupSelectId}" + >${memberships.groups + .filter(group => !isLifetimeGroup(group)) + .map( + group => `<option value="${group.name}">${group.name}</option>` + ).join('') + }</select>`; + + document.querySelectorAll(`.${purchaseItemsClass}`).forEach(ele => { + ele.insertAdjacentHTML('beforebegin', selectGroupHTML); + }); + + document.getElementById( + membershipsGroupSelectId + ).addEventListener('change', toggleMembershipsGroup); } function injectMembershipsPurchaseBtns() { @@ -74,76 +92,162 @@ }); } - function injectMembershipEles() { - const isGrouped = document.querySelector('.grouped'); - document.querySelectorAll( `.${purchaseItemsClass} input[type="radio"]` ).forEach(ele => { - ele.style.visibility = 'hidden' + ele.style.visibility = 'hidden'; ele.style.height = 0; ele.style.width = 0; }); - /* - * @todo Implement. - */ - // if (!isGrouped) { - // injectMembershipsBtnGroup(); - //} - - injectMembershipDescriptions(); + injectMembershipsBtnGroup(); injectMembershipsPurchaseBtns(); + injectMembershipsGroupSelect(); } function toggleMemberships(ev) { - const membershipType = ev.target.dataset.showMemberships; - renderMemberships(membershipType); + membershipsState.membershipsType = ev.target.dataset.showMemberships; + membershipsState.selectedMembershipId = ev.target.id + + renderMemberships(); ev.stopPropagation(); ev.preventDefault(); } - function renderMemberships(membershipType) { - const oneTimeMembershipClass = 'one-time-purchasable-item'; - const recurringMembershipClass = 'recurring-purchasable-item'; - - const membershipDisplayType = 'flex'; - const showRecurring = membershipType === 'recurring' ? membershipDisplayType : 'none'; - const showOneTime = membershipType === 'one-time' ? membershipDisplayType : 'none'; - - document.querySelectorAll( - `.${recurringMembershipClass}, .purchase-if-recurring` - ).forEach(ele => { - ele.style.display = showRecurring; - }) - - document.querySelectorAll(` - .${oneTimeMembershipClass}` - ).forEach(ele => { - ele.style.display = showOneTime; - }); + function toggleMembershipsGroup(ev) { + membershipsState.membershipsGroup = ev.target.value; + renderMemberships(); + ev.stopPropagation(); + ev.preventDefault(); + } - selectDefaultMembership(membershipType); + function renderMemberships() { + showMembershipsByState(); + selectDefaultMembership(); deactivateBtnGroup(); activateBtn( document.querySelector( - `button[data-show-memberships="${membershipType}"]` + `button[data-show-memberships='${membershipsState.membershipsType}']` ) ); + + renderScholarships(); } - function selectDefaultMembership(membershipType) { - const defaultMembershipEle = document.querySelector( - `.${purchaseItemsClass} .${membershipType}-purchasable-item + function renderScholarships() { + scholarshipMemberships().forEach(membership => { + const scholarshipEle = document.querySelector( + `#${membership.purchasableItemContainerId}` + ); + + scholarshipEle.classList.add('scholarship'); + }); + } + + function showLifetimeMembership() { + document.querySelector( + '.lifetime-purchasable-item' + ).style.display = membershipDisplayType; + } + + function showMembershipsByState() { + [ + 'one-time', 'recurring' + ].forEach(possibleType => { + memberships.groups.forEach(group => { + const showState = ( + membershipsState.membershipsType === possibleType + ) && ( + membershipsState.membershipsGroup === group.name + ) ? membershipDisplayType : 'none'; + + document.querySelectorAll( + `.${possibleType}-purchasable-item[data-purchasable-item-subscription-group-name='${group.name}']` + ).forEach(ele => { + ele.style.display = showState; + }); + }); + }); + } + + function scholarshipMemberships() { + return memberships.items.filter(item => + item.purchasableItemTags.includes('scholarship') + ); + } + + function setMemberships() { + memberships.items = []; + const membershipAttrs = [ + 'purchaseSubscription', + 'purchaseRecurring', + 'purchaseSubscription', + 'purchasePaymentId', + 'purchasableItemContainerId', + 'purchaseableItemId', + 'purchasableItemInterval', + 'purchasableItemPrice', + 'purchasableItemSubscriptionGroupName', + 'purchasableItemTags' + ]; + + document.querySelectorAll(`${purchaseItemsSelector} input[type=radio]`).forEach(ele => { + let membership = {}; + membershipAttrs.forEach(attr => { + let val = ele.dataset[attr]; + if (attr === 'purchasableItemTags') { + val = val ? val.split(',') : []; + } + + // Handle existing, but empty, dataset values. + if (val !== undefined) { + val = val === '' ? true : val; + } + + membership[attr] = val; + }); + + memberships.items.push(membership); + }); + + memberships.groups = getMembershipsGroups(); + } + + function getMembershipsGroups() { + return [...new Map( + memberships.items.map( + item => [ + item.purchasableItemSubscriptionGroupName, + Number( + item.purchasableItemInterval.split('.')[0] + ) + ] + ) + )].map(group => { + return { + name: group[0], + intv: group[1] + } + }); + } + + function selectDefaultMembership() { + let defaultMembershipEle; + document.querySelectorAll( + `.${purchaseItemsClass} .${membershipsState.membershipsType}-purchasable-item label input[data-purchase-subscription]` - ) + ).forEach(ele => { + if (!defaultMembershipEle && ele.dataset.purchasableItemPrice > 15 && ele.checkVisibility()) { + defaultMembershipEle = ele; + } + }); defaultMembershipEle.dispatchEvent(new Event('click')); /* * This really should be handled via an event, but the scope of the - * `PuzzleAnywhere` plugin currently does not allow for it, - * so instead we manually trigger the function that the event would. + * `PuzzleAnywhere` plugin currently does not allow for it. + * Instead, we manually trigger the function that the event would. */ onPurchaseSubscriptionSelected(defaultMembershipEle); } @@ -169,10 +273,10 @@ ) } - function handleMembershipSelection( ev ) { - let targetId = ev.target.getAttribute( 'id' ); - targetId = targetId || ev.target.getAttribute( 'for' ); - const isRecurring = ev.target.dataset.purchaseRecurring; + function handleMembershipSelection(ev) { + let targetId = ev.currentTarget.getAttribute( 'id' ); + targetId = targetId || ev.currentTarget.getAttribute( 'for' ); + const isRecurring = ev.currentTarget.dataset.purchaseRecurring; document.querySelectorAll( `#${purchaseFormId} .${purchaseItemsClass} label.${activeClass}` @@ -180,35 +284,54 @@ ele.classList.remove( activeClass ); }); - // Bubble-up. - if ( !targetId ) { return; } + // Bubble-up if no target found. + if (!targetId) { return; } - document.querySelector( - `label[for="${targetId}"]` - ).classList.add( activeClass ); + let labelEle = document.querySelector(`label[for="${targetId}"]`); + labelEle.classList.add( activeClass ); + labelEle.querySelector('input[type=radio]').checked = true; + + onPurchaseSubscriptionSelected( + labelEle.querySelector('input[data-purchase-subscription]') + ); + + ev.stopPropagation(); + ev.preventDefault(); } function addMembershipsEvents() { document.querySelectorAll( purchaseItemsSelector ).forEach(ele => { ele.addEventListener( 'click', handleMembershipSelection, true ); }); + + document.querySelectorAll( `#${purchaseFormId}` ).forEach(form => { + form.addEventListener( 'submit', onPurchaseFormSubmit ); + }); } - if ( document.getElementById( purchaseFormId ) ) { + function onPurchaseFormSubmit(ev) { + ev.target.querySelectorAll( + 'input[type=submit], button[type=submit]' + ).forEach(ele => { + ele.disabled = true; + ele.querySelector( '.purchase-btn-lbl' ).insertAdjacentHTML( + 'afterbegin', '<span class="loading"></span>' + ); + }); + } + + function isMembershipPage() { + return document.querySelector('.subscription-purchasable-item'); + } + + if (isMembershipPage()) { removeExtraneousEles(); + + setMemberships(); + addMembershipsEvents(); injectMembershipEles(); - const membershipTypesEles = document.querySelector( - defaultMembershipTypesSelector - ); - - if (membershipTypesEles) { - renderMemberships( - membershipTypesEles.dataset.showMemberships - ) - } else { - selectDefaultMembership('one-time'); - } + renderMemberships(); } }() ); diff --git a/style.css b/style.css index d35009ccad64d84418b769c03db2056d2aba7ec6..d1c72d3a57a46e943c0150470878e36f803cf8b2 100644 --- a/style.css +++ b/style.css @@ -66,7 +66,7 @@ Nicolas Gallagher and Jonathan Neal https://necolas.github.io/normalize.css/ * 1. Correct the line height in all browsers. * 2. Prevent adjustments of font size after orientation changes in iOS. */ -html { + html { line-height: 1.15; -webkit-text-size-adjust: 100%; } @@ -721,6 +721,46 @@ select, option { line-height: 1.15; } +.memberships #memberships-group-select { + background-color: #fff; + border-color: #000; + border-width: 2px; + color: #000; + margin-bottom: 10px; + max-width: 100%; + text-transform: none; + width: 100%; + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='black'><polygon points='0,0 100,0 50,50'/></svg>") no-repeat; + background-size: 12px; + background-position: calc(100% - 20px) center; + background-repeat: no-repeat; +} + +.memberships #memberships-group-select:after { + content: " "; + position: absolute; + top: 50%; + margin-top: -2px; + right: 8px; + width: 0; + height: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid white; +} + +.memberships #memberships-group-select:focus { + border-color: #44656d; +} + +.memberships #memberships-group-select, +.memberships #memberships-group-select option { + text-align: center; +} + .memberships .free-trial input[type="submit"], .subscribe .free-trial input[type="submit"], input[type="text"], @@ -818,7 +858,8 @@ main { align-items: flex-start; } -.alert.alert-info { +.alert.alert-info, +.alert.alert-success.purchasable-item-description { color: #0c5460; background-color: #e6eee3; border-color: #81bda0; @@ -875,6 +916,10 @@ main { margin-bottom: 1rem; } +#purchase-form-ele .memberships-btn-group button { + min-width: 150px; +} + #purchase-form-ele ul { margin-top: 10px; } @@ -916,6 +961,191 @@ main { padding: 0; } +.purchase-form-submit-btn .purchase-btn-lbl { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; +} + +.purchase-form-submit-btn .purchase-btn-lbl .loading { + background-position: left center; + background-size: contain; + height: 40px; + width: 40px; +} + +.purchase-form-submit-btn button[type=submit] .purchase-btn-lbl > span { + align-items: center; + display: flex; + flex-direction: row; + justify-content: center; +} + +#purchase-form-ele button[disabled], +#purchase-form-ele button:disabled { + background-color: #ccc !important; + cursor: wait; +} + +#purchase-form-ele ul.purchasable-items li.list-group-item.scholarship { + background-color: #f3fbff; + border: solid 1px #44656d; + border-radius: 15px; + align-items: center; + color: #44656d; + min-height: auto; + width: 100%; +} + +#purchase-form-ele ul.purchasable-items li.list-group-item.scholarship label { + display: grid; + align-items: center; + border-radius: 10px; + font-size: smaller; + grid-template-columns: 0 200px 1fr 1fr 1fr; + padding: 10px 20px; +} + +#purchase-form-ele li.list-group-item.scholarship label.active button::before { + color: #047abe; +} + +#purchase-form-ele ul.purchasable-items li.list-group-item.scholarship label .purchasable-item-name { + text-align: left; +} + +#purchase-form-ele ul.purchasable-items li.list-group-item.scholarship label .purchasable-item-name, +#purchase-form-ele ul.purchasable-items li.list-group-item.scholarship label .purchasable-item-price { + font-size: 1.2rem; + font-weight: 500; +} + +#purchase-form-ele ul.purchasable-items li.list-group-item.scholarship label .purchasable-item-price { + display: block; + justify-self: start; + text-align: left; +} + +#purchase-form-ele ul.purchasable-items li.list-group-item.scholarship label .purchasable-item-description { + display: flex; + grid-column-start: 1; + grid-column-end: 5; + grid-row-start: 2; + z-index: 1; + background-color: transparent; + border-width: 1px 0 0 0; + border-radius: 0; + border-color: #44656d; + margin-bottom: 0; + padding: 5px 0 0 0; +} + +#purchase-form-ele ul.purchasable-items li.list-group-item.scholarship label.active .purchasable-item-description { + border-color: #fff; + color: #fff; +} + +#purchase-form-ele ul.purchasable-items li.list-group-item.scholarship .btn { + background-color: #81bda0; + max-height: 36px; + grid-row-start: 1; + grid-row-end: 3; + grid-column-start: 5; + grid-column-end: 5; + margin-bottom: 0; +} + +@media (min-width: 991px) { + #purchase-form-ele ul.purchasable-items li.list-group-item.lifetime-purchasable-item label { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; + } + + #purchase-form-ele ul.purchasable-items li.list-group-item.lifetime-purchasable-item label button, + #purchase-form-ele ul.purchasable-items li.list-group-item.lifetime-purchasable-item label p, + #purchase-form-ele ul.purchasable-items li.list-group-item.lifetime-purchasable-item label span { + margin: 0; + } +} + +@media (max-width: 991px) { + #page.memberships { + width: 95% + } + + #purchase-form-ele ul.purchasable-items { + margin: 0; + width: 100%; + justify-content: center; + } + + .grouped #purchase-form-ele ul.purchasable-items li, + #purchase-form-ele ul.purchasable-items li { + width: 100%; + } + + #purchase-form-ele ul.purchasable-items li.list-group-item { + margin-left: 1%; + margin-right: 1%; + } + + #purchase-form-ele ul.purchasable-items li.list-group-item.scholarship label { + grid-template-columns: 0 2fr 1fr 0 0; + justify-content: center; + justify-items: center; + } + + #purchase-form-ele ul.purchasable-items li.list-group-item.scholarship .btn { + grid-row-start: 3; + grid-row-end: 4; + grid-column-start: 2; + grid-column-end: 5; + } + + #purchase-form-ele ul.purchasable-items li.list-group-item.scholarship label .purchasable-item-name { + justify-self: start; + } + + #purchase-form-ele ul.purchasable-items li.list-group-item.scholarship label .purchasable-item-price { + justify-self: end; + } + + #purchase-form-ele ul.purchasable-items li.list-group-item.scholarship label .purchasable-item-description { + padding: 0.25em 0; + width: 100%; + } + + #purchase-form-ele ul.purchasable-items .recurring-purchasable-item .purchasable-item-name { + font-size: 1.6rem; + } + +#purchase-form-ele .alert-warning.purchase-if-recurring { + font-size: 1.1rem !important; + } + + #puzzle .puzzle-header { + flex-direction: column-reverse; + row-gap: 0.5em; + } + + #puzzle .puzzle-header .difficulty { + text-align: center; + } + + .purchasable-item-options { + display: flex; + flex-direction: column; + row-gap: 0.5em; + } + + .purchasable-item-options a { + text-align: center; + } +} + #purchase-form-ele ul.purchasable-items li.list-group-item p { font-size: 0.9rem; font-weight: 400; @@ -950,6 +1180,7 @@ button.purchase-form-submit-btn, background-color: rgb(220, 53, 69); } + #purchase-form-ele ul.purchasable-items li.list-group-item.lifetime-purchasable-item { background-color: #000; color: #fff; @@ -989,7 +1220,8 @@ button.purchase-form-submit-btn, display: none; } -#purchase-form-ele ul.purchasable-items .purchasable-item-name { +#purchase-form-ele ul.purchasable-items .purchasable-item-name, +#purchase-form-ele #memberships-group-select { font-size: 1.8rem; font-weight: 600; } @@ -1002,10 +1234,6 @@ button.purchase-form-submit-btn, font-weight: 400; } -#purchase-form-ele ul.purchasable-items div.purchasable-item-description { - display: none !important; -} - #purchase-form-ele ul.purchasable-items .purchasable-item-price .purchasable-item-savings { margin-left: 0.5rem; } @@ -1019,20 +1247,6 @@ button.purchase-form-submit-btn, width: 100%; } -.purchase-form-submit-btn .purchase-btn-lbl { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; -} - -.purchase-form-submit-btn button[type=submit] .purchase-btn-lbl > span { - align-items: center; - display: flex; - flex-direction: row; - justify-content: center; -} - .purchase-form-submit-btn .purchase-btn-lbl .purchase-btn-txt { margin: 0 0.5em; } @@ -1145,6 +1359,10 @@ button.purchase-form-submit-btn, width: 100%; } +.memberships .free-trial { + display: none; +} + .memberships .free-trial, .subscribe .free-trial { border: solid 1px #81bda0; @@ -1164,62 +1382,6 @@ button.purchase-form-submit-btn, margin-top: 1.5em; } -@media (min-width: 991px) { - #purchase-form-ele ul.purchasable-items li.list-group-item.lifetime-purchasable-item label { - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-around; - } - - #purchase-form-ele ul.purchasable-items li.list-group-item.lifetime-purchasable-item label button, - #purchase-form-ele ul.purchasable-items li.list-group-item.lifetime-purchasable-item label p, - #purchase-form-ele ul.purchasable-items li.list-group-item.lifetime-purchasable-item label span { - margin: 0; - } -} - -@media (max-width: 991px) { - #purchase-form-ele ul.purchasable-items { - margin: 0; - width: 100%; - justify-content: center; - } - - .grouped #purchase-form-ele ul.purchasable-items li, - #purchase-form-ele ul.purchasable-items li { - width: 48%; - } - - #purchase-form-ele ul.purchasable-items li.list-group-item { - margin-left: 1%; - margin-right: 1%; - } - - #purchase-form-ele ul.purchasable-items .recurring-purchasable-item .purchasable-item-name { - font-size: 1.6rem; - } - - #puzzle .puzzle-header { - flex-direction: column-reverse; - row-gap: 0.5em; - } - - #puzzle .puzzle-header .difficulty { - text-align: center; - } - - .purchasable-item-options { - display: flex; - flex-direction: column; - row-gap: 0.5em; - } - - .purchasable-item-options a { - text-align: center; - } -} - #account .nav.nav-tabs { margin-top: 1em; text-align: center; @@ -2197,6 +2359,7 @@ footer .footer-legal-cont .copyright { background-image: url('images/loader.svg'); background-repeat: no-repeat; background-position: center 1em; + display: inline-block; } /* Media