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

MWPW-142935 [Project PEP] PEP <> Geo Routing Modal Interactions #2403

Merged
merged 12 commits into from
Jun 17, 2024
19 changes: 17 additions & 2 deletions libs/features/webapp-prompt/webapp-prompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ const getIcon = (content) => {
return icons.company;
};

const modalsActive = () => !!document.querySelector('.dialog-modal');

const waitForClosedModalsThen = (loadPEP) => {
if (modalsActive()) {
setTimeout(() => waitForClosedModalsThen(loadPEP), 200);
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we not use a setInterval to avoid the recursive calls?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd prefer to not use setInterval since we'd have to keep track of the setInterval ID and clean it up after with clearInterval. And waitForClosedModalsThen isn't recursive in the sense that it's growing the callstack indefinitely, it, like setInterval, adds a function to the task queue, and in that sense is (to us, at least) indistinguishable in behavior from setInterval. The question is of whether we prefer the extra code to clean up the interval or the extra code for adding to the event queue.

return;
}
loadPEP();
};

class AppPrompt {
constructor({ promptPath, entName, parent, getAnchorState } = {}) {
this.promptPath = promptPath;
Expand All @@ -43,8 +53,13 @@ class AppPrompt {
this.getAnchorState = getAnchorState;
this.id = this.promptPath.split('/').pop();
this.elements = {};

this.init();
if (modalsActive()) {
window.addEventListener(
'milo:modal:closed',
() => waitForClosedModalsThen(this.init),
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we not add waitForClosedModalsThen as a class method and avoid passing the init method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like to be explicit about what I'm passing to functions, and I like the CPS-ish semantics of writing "do an action and then do this - " by explicitly passing the function (so long as we aren't doing long chains of it, of course). Though if you think the init method shouldn't be passed I can change it (my reasoning for why it's ok is that it's not a private method; anyone can call it).

{ once: true },
);
} else this.init();
}

init = async () => {
Expand Down
22 changes: 22 additions & 0 deletions test/features/webapp-prompt/webapp-prompt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,28 @@ describe('PEP', () => {
await clock.runAllAsync();
expect(document.querySelector(allSelectors.pepWrapper)).to.not.exist;
});

it('should not render PEP when the GRM is open', async () => {
document.body.insertAdjacentHTML('afterbegin', '<div class="locale-modal-v2 dialog-modal"></div>');
document.body.insertAdjacentHTML('afterbegin', '<div class="dialog-modal"></div>');

await initPep({});

try {
clock.runAll();
} catch (e) {
expect(document.querySelector(allSelectors.pepWrapper)).to.not.exist;
}

const event = new CustomEvent('milo:modal:closed');
window.dispatchEvent(event);

document.querySelector('.locale-modal-v2')?.remove();
document.querySelector('.dialog-modal')?.remove();

await clock.runAllAsync();
expect(document.querySelector(allSelectors.pepWrapper)).to.exist;
});
});

describe('PEP configuration tests', () => {
Expand Down
Loading