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

feat: adds prop update listening to modal browser zoid polyfill #1161

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from

Conversation

danzhaaspaypal
Copy link
Contributor

@danzhaaspaypal danzhaaspaypal commented Dec 4, 2024

Description

Updates the modal lander to support communicating bi-directionally with the v6 modal wrapper

Screenshots

Testing instructions

  1. Prepare local env to test corresponding PR feat: add learn more modal wrapper for messages in an internal repo (DM Dan for more details).
  2. in that internal repo, go to LearnMore.ts, and on line 52, append &stage_tag=merc3611_test to end of url query.
  3. Try combinations of the below lines inserted onto the demo page (again DM Dan for more details):
try {
    const clientToken = await getClientToken();
    const sdkInstance = await window.paypal.createInstance({
      clientToken,
      components: ["paypal-payments", "paypal-messages"],
    });
    const msgInstance = sdkInstance.createPayPalMessages({buyerCountry: "us"});
    const learnMore = await msgInstance.createLearnMore({amount:"50", presentationType:"modal"});
    // const learnMore = await msgInstance.createLearnMore({amount:"50", presentationType:"popup"});
    // const learnMore = await msgInstance.createLearnMore({amount:"50", presentationType:"redirect"});
    // const learnMore = await msgInstance.createLearnMore({amount:"50", presentationType:"auto"});
    // await learnMore.update({amount:"70", offerTypes:["PAY_LATER_LONG_TERM"]});
    // await learnMore.update({amount:"70", offerTypes:["PAY_LATER_SHORT_TERM"]});
    // await learnMore.open({amount:"70"});
    // await learnMore.update({amount:"90"});
    // await learnMore.open({amount:"90"});

@danzhaaspaypal danzhaaspaypal force-pushed the feature/DTCRCMERC-3611-modal-lander-v6 branch from 48ed5aa to ecf1a92 Compare December 10, 2024 18:11
Comment on lines 21 to 25
const merchantOrigin = decodeURIComponent(initialProps.origin);

if (eventOrigin === merchantOrigin && eventName === 'PROPS_UPDATE' && newProps && typeof newProps === 'object') {
// send event ack so PostMessenger will stop reposting event
sendEventAck(id, merchantOrigin);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we chatted about this internally, but I think we can go with

Suggested change
const merchantOrigin = decodeURIComponent(initialProps.origin);
if (eventOrigin === merchantOrigin && eventName === 'PROPS_UPDATE' && newProps && typeof newProps === 'object') {
// send event ack so PostMessenger will stop reposting event
sendEventAck(id, merchantOrigin);
const clientOrigin = decodeURIComponent(initialProps.origin);
if (eventOrigin === clientOrigin && eventName === 'PROPS_UPDATE' && newProps && typeof newProps === 'object') {
// send event ack so PostMessenger will stop reposting event
sendEventAck(id, clientOrigin);


export function sendEventAck(eventId, trustedOrigin) {
// skip this step if running in test env because jest's target windows don't support postMessage
if (window.process?.env?.NODE_ENV === 'test') {
Copy link
Contributor

@perco12 perco12 Jan 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did we perhaps mean?

Suggested change
if (window.process?.env?.NODE_ENV === 'test') {
if (process.env.NODE_ENV === 'test') {

@danzhaaspaypal danzhaaspaypal marked this pull request as ready for review February 5, 2025 21:34
@erikacolette29 erikacolette29 added the DO NOT MERGE Requires a change from some external dependency or service label Feb 24, 2025
Comment on lines +117 to +131
export function createUUID() {
// crypto.randomUUID() is only available in HTTPS secure environments and modern browsers
if (typeof crypto !== 'undefined' && crypto && crypto.randomUUID instanceof Function) {
return crypto.randomUUID();
}

const validChars = '0123456789abcdefghijklmnopqrstuvwxyz';
const stringLength = 32;
let randomId = '';
for (let index = 0; index < stringLength; index++) {
const randomIndex = Math.floor(Math.random() * validChars.length);
randomId += validChars.charAt(randomIndex);
}
return randomId;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a belter util we can leverage that meets our needs here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

belter has uniqueID that returns uid_${randomID}_${timeID}. Considerations are that the existing postMessenger message ids have a format that is different from that (32 alphanumeric vs the above format in hex); however, there is no validation for nor true consumer of the id we will generate here. Would you like me to use this belter uniqueID?

Comment on lines +153 to +159
let targetWindow;
const popupCheck = window.parent === window;
if (popupCheck) {
targetWindow = window.opener;
} else {
targetWindow = window.parent;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let targetWindow;
const popupCheck = window.parent === window;
if (popupCheck) {
targetWindow = window.opener;
} else {
targetWindow = window.parent;
}
const targetWindow = window.parent === window ? window.opener : window.parent;

Comment on lines +9 to +14
function listenAndAssignProps(newProps, propListeners) {
Array.from(propListeners.values()).forEach(listener => {
listener({ ...window.xprops, ...newProps });
});
Object.assign(window.xprops, newProps);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of this function makes it sound like we are creating a listener of some sort when in reality we calling the listeners that have already been registered. Consider avoiding the listen verb as part of the function name.

Copy link
Contributor Author

@danzhaaspaypal danzhaaspaypal Mar 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about handleNewProps or handleUpdatedProps?

Comment on lines +136 to +141
const [k, v] = entry;
if (k === 'offerTypes') {
validatedProps.offer = validate.offer({ props: { offer: v } });
} else {
validatedProps[k] = validate[k]({ props: { [k]: v } });
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we guaranteed to only pass in props that we have validation for? Should we account for the scenario where validate[k] is undefined which would throw an error here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. See #1170 for this fix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved DO NOT MERGE Requires a change from some external dependency or service testing complete
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants