// JOURNEY BUILDER CUSTOM ACTIVITY - discountCode ACTIVITY // ```````````````````````````````````````````````````````````` // This example demonstrates a custom activity that utilizes an external service to generate // a discount code where the user inputs the discount percent in the configuration. // // Journey Builder's Postmonger Events Reference can be found here: // https://developer.salesforce.com/docs/atlas.en-us.noversion.mc-app-development.meta/mc-app-development/using-postmonger.htm // Custom activities load inside an iframe. We'll use postmonger to manage // the cross-document messaging between Journey Builder and the activity import Postmonger from 'postmonger'; // Create a new connection for this session. // We use this connection to talk to Journey Builder. You'll want to keep this // reference handy and pass it into your UI framework if you're using React, Angular, Vue, etc. const connection = new Postmonger.Session(); // we'll store the activity on this variable when we receive it let activity = null; // Wait for the document to load before we doing anything document.addEventListener('DOMContentLoaded', function main() { // Setup a test harness so we can interact with our custom activity // outside of journey builder using window functions & browser devtools. // This isn't required by your activity, its for example purposes only setupExampleTestHarness(); // setup our ui event handlers setupEventHandlers(); // Bind the initActivity event... // Journey Builder will respond with "initActivity" after it receives the "ready" signal connection.on('initActivity', onInitActivity); // We're all set! let's signal Journey Builder // that we're ready to receive the activity payload... // Tell the parent iFrame that we are ready. connection.trigger('ready'); }); // this function is triggered by Journey Builder via Postmonger. // Journey Builder will send us a copy of the activity here function onInitActivity(payload) { // set the activity object from this payload. We'll refer to this object as we // modify it before saving. activity = payload; const hasInArguments = Boolean( activity.arguments && activity.arguments.execute && activity.arguments.execute.inArguments && activity.arguments.execute.inArguments.length > 0 ); const inArguments = hasInArguments ? activity.arguments.execute.inArguments : []; console.log('-------- triggered:onInitActivity({obj}) --------'); console.log('activity:\n ', JSON.stringify(activity, null, 4)); console.log('Has In Arguments: ', hasInArguments); console.log('inArguments', inArguments); console.log('-------------------------------------------------'); // check if this activity has an incoming argument. // this would be set on the server side when the activity executes // (take a look at execute() in ./discountCode/app.js to see where that happens) const discountArgument = inArguments.find((arg) => arg.discount); console.log('Discount Argument', discountArgument); // if a discountCode back argument was set, show the message in the view. if (discountArgument) { selectDiscountCodeOption(discountArgument.discount); } // if the discountCode back argument doesn't exist the user can pick // a discountCode message from the drop down list. the discountCode back arg // will be set once the journey executes the activity } function onDoneButtonClick() { // we set must metaData.isConfigured in order to tell JB that // this activity is ready for activation activity.metaData.isConfigured = true; // get the option that the user selected and save it to const select = document.getElementById('discount-code'); const option = select.options[select.selectedIndex]; activity.arguments.execute.inArguments = [{ discount: option.value, }]; // you can set the name that appears below the activity with the name property activity.name = `Issue ${activity.arguments.execute.inArguments[0].discount}% Code`; console.log('------------ triggering:updateActivity({obj}) ----------------'); console.log('Sending message back to updateActivity'); console.log('saving\n', JSON.stringify(activity, null, 4)); console.log('--------------------------------------------------------------'); connection.trigger('updateActivity', activity); } function onCancelButtonClick() { // tell Journey Builder that this activity has no changes. // we wont be prompted to save changes when the inspector closes connection.trigger('setActivityDirtyState', false); // now request that Journey Builder closes the inspector/drawer connection.trigger('requestInspectorClose'); } function onDiscountCodeSelectChange() { // enable or disable the done button when the select option changes const select = document.getElementById('discount-code'); if (select.selectedIndex) { document.getElementById('done').removeAttribute('disabled'); } else { document.getElementById('done').setAttribute('disabled', ''); } // let journey builder know the activity has changes connection.trigger('setActivityDirtyState', true); } function selectDiscountCodeOption(value) { const select = document.getElementById('discount-code'); const selectOption = select.querySelector(`[value='${value}']`); if (selectOption) { selectOption.selected = true; onDiscountCodeSelectChange(); } else { console.log('Could not select value from list', `[value='${value}]'`); } } function setupEventHandlers() { // Listen to events on the form document.getElementById('done').addEventListener('click', onDoneButtonClick); document.getElementById('cancel').addEventListener('click', onCancelButtonClick); document.getElementById('discount-code').addEventListener('change', onDiscountCodeSelectChange); } // this function is for example purposes only. it sets ups a Postmonger // session that emulates how Journey Builder works. You can call jb.ready() // from the console to kick off the initActivity event with a mock activity object function setupExampleTestHarness() { const isLocalhost = location.hostname === 'localhost' || location.hostname === '127.0.0.1'; if (!isLocalhost) { // don't load the test harness functions when running in Journey Builder return; } const jbSession = new Postmonger.Session(); const jb = {}; window.jb = jb; jbSession.on('setActivityDirtyState', function(value) { console.log('[echo] setActivityDirtyState -> ', value); }); jbSession.on('requestInspectorClose', function() { console.log('[echo] requestInspectorClose'); }); jbSession.on('updateActivity', function(activity) { console.log('[echo] updateActivity -> ', JSON.stringify(activity, null, 4)); }); jbSession.on('ready', function() { console.log('[echo] ready'); console.log('\tuse jb.ready() from the console to initialize your activity') }); // fire the ready signal with an example activity jb.ready = function() { jbSession.trigger('initActivity', { name: '', key: 'EXAMPLE-1', metaData: {}, configurationArguments: {}, arguments: { executionMode: "{{Context.ExecutionMode}}", definitionId: "{{Context.DefinitionId}}", activityId: "{{Activity.Id}}", contactKey: "{{Context.ContactKey}}", execute: { inArguments: [ { discount: 10 } ], outArguments: [] }, startActivityKey: "{{Context.StartActivityKey}}", definitionInstanceId: "{{Context.DefinitionInstanceId}}", requestObjectId: "{{Context.RequestObjectId}}" } }); }; }