Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PM-375: Costco Figo Promotion #283

Merged
merged 12 commits into from
Nov 21, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions blocks/plans-quote/costco-promo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import {
PET_PLANS_ANNUAL_URL,
LS_KEY_FIGO_COSTCO,
} from '../../scripts/24petwatch-utils.js';
import APIClient, { getAPIBaseUrl } from '../../scripts/24petwatch-api.js';
import { getConfigValue } from '../../scripts/configs.js';

export const COSTCO_FIGO_PROMO_ITEMS = {
policyIdKey: 'poid',
subId: 'SBSUN000016',
};

// set eligibility flag based on the following values
const eligibilityCriteria = {
level: ['Executive'],
type: ['Costco', 'Employee-family'],
status: 'Active',
policyStatus: ['Future', 'Active'],
};

const apiBaseUrl = await getAPIBaseUrl();
const APIClientObj = new APIClient(apiBaseUrl);
const costcoFigoService = await getConfigValue('costco-figo-proxy');
const costcoFigoStoredData = localStorage.getItem(LS_KEY_FIGO_COSTCO);
const costcoFigoStoredValues = costcoFigoStoredData ? JSON.parse(costcoFigoStoredData) : {};
const costcoFigosubId = COSTCO_FIGO_PROMO_ITEMS.subId;
const hasCostcoFigoStored = costcoFigoStoredData !== null;

export const getIsMultiPet = costcoFigoStoredValues.multiPet ?? true;
export const isCostcoFigo = costcoFigoStoredValues.isEligible ?? false;
export const getSavedCouponCode = costcoFigoStoredValues.couponCode ?? null;
export const getSavedPolicyId = costcoFigoStoredValues.policyId ?? null;

// is costco figo flow
function isCostcoFigoFlow() {
return window.location.pathname.endsWith(PET_PLANS_ANNUAL_URL);
}

// get the data
async function getCostcoPolicyData(policyId) {
let policyData;
const payload = {
payload: {
policyId,
},
};

const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
};

try {
const response = await fetch(costcoFigoService, options);
if (response.ok) {
const costcoMembershipData = await response.json();
// if we have a record associated with the policy Id
if (costcoMembershipData.records && costcoMembershipData.records.length > 0) {
[policyData] = costcoMembershipData.records;
}
}
} catch (error) {
// eslint-disable-next-line no-console
console.error('There was an error fetching policy data:', error);
}
return policyData;
}

// check eligibility based on eligibilityCriteria values matching record values
async function isCostcoFigoEligible(policyId) {
let eligibilityFlag = false;
const record = await getCostcoPolicyData(policyId);
if (record) {
const status = record.Status__c ?? null;
const type = record.Type__c ?? null;
const level = record.Level__c ?? null;
const policyStatus = record.Insurance_Policy__r?.Status ?? null;

if (status === eligibilityCriteria.status
&& eligibilityCriteria.level.includes(level)
&& eligibilityCriteria.type.includes(type)
&& eligibilityCriteria.policyStatus.includes(policyStatus)) {
eligibilityFlag = true;
}
}
return eligibilityFlag;
}

// checks if all promo criteria is met and requests a coupon code
// sets sessionStorage data for accessing props if needed throughout the order journey
export async function checkCostcoFigoPromo(policyId, countryCode) {
let costcoFigoCouponData = false;
if (policyId && countryCode) {
if (isCostcoFigoFlow()) {
// returns boolean
const isEligible = await isCostcoFigoEligible(policyId);
if (isEligible) {
let costcoPromoData = {};
try {
// eslint-disable-next-line max-len
costcoPromoData = await APIClientObj.assignNextAvailableCoupon(costcoFigosubId, policyId, countryCode);
const allowMultiPet = costcoPromoData.allowMultiPet ?? null;
const couponCode = costcoPromoData.couponCode ?? null;
// eslint-disable-next-line max-len
if (allowMultiPet !== null && couponCode !== null && couponCode !== '') {
const storedCostcoFigoData = {
couponCode,
multiPet: allowMultiPet,
policyId,
isEligible,
};
// store object for next steps
localStorage.setItem(LS_KEY_FIGO_COSTCO, JSON.stringify(storedCostcoFigoData));
costcoFigoCouponData = storedCostcoFigoData;
}
} catch (status) {
// eslint-disable-next-line no-console
console.log('Failed to get couponCode for:', policyId, ' status:', status);
}
}
}
}
return costcoFigoCouponData;
}

// remove storage data
export async function resetCostcoFigoData() {
if (hasCostcoFigoStored) {
localStorage.removeItem(LS_KEY_FIGO_COSTCO);
}
}
82 changes: 81 additions & 1 deletion blocks/plans-quote/form.js
Original file line number Diff line number Diff line change
@@ -14,7 +14,9 @@ import {
PET_PLANS_ANNUAL_URL,
PET_PLANS_SUMMARY_QUOTE_URL,
setCookie,
deleteCookie,
getQueryParam,
hasQueryParam,
getCookie,
isSummaryPage,
getSelectedProductAdditionalInfo,
@@ -23,6 +25,13 @@ import {
} from '../../scripts/24petwatch-utils.js';
import { getConfigValue } from '../../scripts/configs.js';
import { trackGTMEvent } from '../../scripts/lib-analytics.js';
import {
checkCostcoFigoPromo,
COSTCO_FIGO_PROMO_ITEMS,
getSavedCouponCode,
getIsMultiPet,
resetCostcoFigoData,
} from './costco-promo.js';

const US_LEGAL_HEADER = '';
const US_LEGAL_CONSENT_FOR_PROMO_CONTACT = 'With your 24Pet® microchip, Pethealth Services (USA) Inc. may offer you free lost pet services, as well as exclusive offers, promotions and the latest information from 24Pet regarding microchip services. Additionally, PTZ Insurance Agency, Ltd. including its parents, PetPartners, Inc. and Independence Pet Group, Inc. and their subsidiaries (“collectively PTZ Insurance Agency, Ltd”) may offer you promotions and the latest information from 24Petprotect™ regarding pet insurance services and products. By checking “Continue”, Pethealth Services (USA) Inc. and PTZ Insurance Agency, Ltd. including its parents, PetPartners, Inc. and Independence Pet Group, Inc. and their subsidiaries (“collectively PTZ Insurance Agency, Ltd”) may contact you via commercial electronic messages, automatic telephone dialing systems, prerecorded/automated messages or text messages at the telephone number provided above, including your mobile number. These calls or emails are not a condition of the purchase of any goods or services. You understand that if you choose not to provide your consent, you will not receive the above-mentioned communications or free lost pet services, which includes being contacted with information in the event that your pet goes missing. You may withdraw your consent at any time.';
@@ -43,6 +52,11 @@ const promoResultKey = await getConfigValue('promo-result');
const apiBaseUrl = await getAPIBaseUrl();
const APIClientObj = new APIClient(apiBaseUrl);

const costcoFigoPolicyId = getQueryParam(COSTCO_FIGO_PROMO_ITEMS.policyIdKey);
const isEditing = hasQueryParam('petId');

let isMultiPet = getIsMultiPet;

// eslint-disable-next-line no-shadow
async function getPurchaseSummary(ownerId) {
Loader.showLoader();
@@ -60,6 +74,12 @@ async function getPurchaseSummary(ownerId) {
}

export default function formDecoration(block) {
// if we are not editing, is not summary page and multipet is false
if (!isSummaryPage() && !isEditing && !isMultiPet) {
// delete the saved owner id cookie
deleteCookie(COOKIE_NAME_SAVED_OWNER_ID);
}

// prepare for Canada vs US
const currencyValue = isCanada ? CURRENCY_CANADA : CURRENCY_US;
const zipcodeLabel = isCanada ? 'Postal code*' : 'Zip code*';
@@ -219,6 +239,19 @@ export default function formDecoration(block) {
const cancelButton = document.getElementById('cancel');
const addPetButton = document.getElementById('add-pet');

function disableField(element) {
const container = element.parentElement;
container.classList.add('disabled-field');
element.disabled = true;
element.addEventListener('focus', (event) => {
event.target.blur();
});
element.addEventListener('mousedown', (event) => {
event.preventDefault();
});
element.setAttribute('tab-index', '-1');
}

function showGeneralErrorMessage(errorMessage) {
const errorElement = document.querySelector('.error-message.general-error-message');
errorElement.textContent = errorMessage;
@@ -883,10 +916,52 @@ export default function formDecoration(block) {
return breedName;
}

async function executeCostcoFigoPromoCheck() {
// Check if we have a costco figo promo policy id from query string
if (costcoFigoPolicyId) {
let hasValidCoupon = false;
let costcoCoupon = null;

// check if we can apply a promo coupon for costco figo
const costcoFigoCouponData = await checkCostcoFigoPromo(costcoFigoPolicyId, countryId);
if (costcoFigoCouponData) {
isMultiPet = costcoFigoCouponData.multiPet ?? true;
costcoCoupon = costcoFigoCouponData.couponCode ?? null;
hasValidCoupon = !!costcoFigoCouponData.couponCode;
}
// If we have a coupon, trigger the promocodeHandler
if (hasValidCoupon && costcoCoupon !== null) {
// add promo code to promo field
promocodeInput.value = costcoCoupon.trim();
// disable field
disableField(promocodeInput);
// validate promo
await promocodeHandler();
} else {
// we don't have a valid code and have stored policy data
await resetCostcoFigoData();
isMultiPet = true;
}
} else {
// no policy Id parameter, reset any promo data
await resetCostcoFigoData();
isMultiPet = true;
}
}

async function prefillFormIfPossible() {
// if not summary page and not editing pet, check costco promo
if (!isSummaryPage() && !isEditing) {
Loader.showLoader();
await executeCostcoFigoPromoCheck();
Loader.hideLoader();
// if multipet is false, don't try and prefill data
if (!isMultiPet) {
return;
}
}
// the owner info must come from the cookie
const ownerId = getCookie(COOKIE_NAME_SAVED_OWNER_ID);

// promo code from query param
const promoCode = getQueryParam('promo_code');
if (promoCode) {
@@ -988,9 +1063,14 @@ export default function formDecoration(block) {
promocodeInput.value = data.couponCode;
Loader.showLoader();
await promocodeHandler();
// if coupon code is the costco figo coupon code, disable input
if (data.couponCode === getSavedCouponCode) {
promocodeInput.disabled = true;
}
Loader.hideLoader();
}
}

prefillFormIfPossible();

// Add event listener
17 changes: 17 additions & 0 deletions blocks/plans-quote/plans-quote.css
Original file line number Diff line number Diff line change
@@ -76,6 +76,23 @@ main .plans-quote form input:not(:placeholder-shown)~label {
transform: unset;
}

main .plans-quote form .wrapper.disabled-field > input {
cursor: not-allowed;
pointer-events: none;
user-select: none;
position: relative;
}

main .plans-quote form .wrapper.disabled-field::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: transparent;
}

main .plans-quote form .wrapper:not(.flex-wrapper) label {
padding-bottom: 0;
}
Loading