Skip to content

Commit

Permalink
MWPW-152411: MAS technical documentation (#2944)
Browse files Browse the repository at this point in the history
* MWPW-152411: checkout-link documentation

* revert typo

* revert typo

* update headings

* added permalinks

* update doc

* update doc

* Add mas and mas.js documentation

* Typos fixed

* update doc

* update doc
  • Loading branch information
yesil authored Sep 24, 2024
1 parent d1f6547 commit 5ddeb73
Show file tree
Hide file tree
Showing 14 changed files with 1,541 additions and 76 deletions.
9 changes: 4 additions & 5 deletions libs/features/mas/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ Refer to the corresponding README.md under any of the packages:
* commerce - contains generic commerce-related logic, 'price' and 'checkout-link' web components
* web-components - merch-card, merch-offer-selector and other web components

# Consumption of artifacts in Milo
Please run 'npm run build'
```
npm run build
### Generate docs

```sh
node run build:docs
```
Copy required artifacts folder to milo/libs/deps/mas.

#### Troubleshooting
Please reach out to us in `#tacocat-friends` for any questions.
85 changes: 85 additions & 0 deletions libs/features/mas/build-docs.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// build-docs.mjs

import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import markdownIt from 'markdown-it';
import markdownItAttrs from 'markdown-it-attrs';
import markdownItAnchor from 'markdown-it-anchor';
import markdownItContainer from 'markdown-it-container';
import markdownItHighlightjs from 'markdown-it-highlightjs';

// Reconstruct __dirname and __filename in ES6 modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const sourceFile = process.argv[2];
if (!sourceFile) {
console.error('Please provide a source file as an argument');
process.exit(1);
}

const targetFile = process.argv[3];
if (!targetFile) {
console.error('Please provide a target file as an argument');
process.exit(1);
}

const skipMas = process.argv.includes('--skip-mas');

// Initialize markdown-it with desired plugins
const md = markdownIt({
html: true,
linkify: true,
typographer: true,
})
.use(markdownItAttrs)
.use(markdownItAnchor, {
permalink: markdownItAnchor.permalink.headerLink(),
})
.use(markdownItContainer, 'warning')
.use(markdownItHighlightjs);

// Define input and output paths
const inputPath = path.join(__dirname, sourceFile);
const outputPath = path.join(targetFile);

// Read the Markdown file
const inputContent = fs.readFileSync(inputPath, 'utf8');

// Render Markdown to HTML
const htmlContent = md.render(inputContent);

const masJs = skipMas
? ''
: '<script type="module" src="../../../deps/mas/mas.js"></script>';

// HTML template with your custom element script
const htmlTemplate = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Custom Element Documentation</title>
<!-- Include your custom element script as an ES6 module -->
<script src="../../../features/spectrum-web-components/dist/theme.js" type="module"></script>
<script src="../../../features/spectrum-web-components/dist/button.js" type="module"></script>
${masJs}
<!-- Include Highlight.js stylesheet for syntax highlighting -->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/default.min.css">
<!-- Include any additional stylesheets -->
<link rel="stylesheet" href="styles.css">
</head>
<body>
<main>
<sp-theme color="light" scale="medium">
${htmlContent}
</sp-theme>
</main>
</body>
</html>
`;

// Write the HTML file
fs.writeFileSync(outputPath, htmlTemplate, 'utf8');
console.log('Documentation generated at', outputPath);
10 changes: 10 additions & 0 deletions libs/features/mas/build-docs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

# Build documentation for commerce/checkout-link.md and output to docs/checkout-link.html
node build-docs.mjs commerce/checkout-link.md docs/checkout-link.html

# Build documentation for mas/mas.md and output to docs/mas.html
node build-docs.mjs mas/mas.md docs/mas.html

# Build documentation for mas/mas.js.md and output to docs/mas.js.html, does not include mas.js in the generated html
node build-docs.mjs mas/mas.js.md docs/mas.js.html --skip-mas
198 changes: 198 additions & 0 deletions libs/features/mas/commerce/checkout-link.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
# checkout-link {#checkout-link}

## Introduction {#introduction}
This custom element renders a checkout link supporting most of the features documented at https://wiki.corp.adobe.com/pages/viewpage.action?spaceKey=businessservices&title=UCv3+Link+Creation+Guide.<br>
Sometimes a checkout-link can be also referred as placeholder as it can be used as an inline link resolving at runtime.<br>
The term placeholder will be deprecated and it is recommended to refer as **checkout-link custom element** going forward.

Behind the scene, it uses https://git.corp.adobe.com/PandoraUI/commerce-core to generate the checkout url.

It requires an Offer Selector ID to retrieve the offer from WCS.

### Offer Selector ID <br>
AOS generated a stable reference for a set of natural keys allowing to retrieve a specific offer whose offer ID can change over time.

[API: Create an offer selector](https://developers.corp.adobe.com/aos/docs/guide/apis/api.yaml#/paths/offer_selectors/post)

### WCS {#wcs}
[WCS](https://developers.corp.adobe.com/wcs/docs/guide/introduction.md) (pronounced weks) provides APIs returning Commerce data required by Adobe.com.

API: https://developers.corp.adobe.com/wcs/docs/api/openapi/wcs/latest.yaml#/schemas/Web-Commerce-Artifacts




### Example <br>

```html
<a href="#" is="checkout-link" data-wcs-osi="A1xn6EL4pK93bWjM8flffQpfEL-bnvtoQKQAvkx574M">Buy now</a>
```

#### Demo<br>

This is a functional **buy now** button: <a href="#" is="checkout-link" data-wcs-osi="A1xn6EL4pK93bWjM8flffQpfEL-bnvtoQKQAvkx574M">Buy now</a>


## Attributes {#attributes}

| Attribute | Description | Default Value | Required |
|------------------------------|-------------------------------------------------------------------------------------------------|---------------|----------|
| `data-wcs-osi` | Offer Selector ID, can be multiple, separeted by comma | | `true` |
| `data-checkout-workflow` | Target checkout workflow for the generation of checkout urls | UCv3 | `false` |
| `data-checkout-workflow-step`| [workflow step](https://wiki.corp.adobe.com/pages/viewpage.action?spaceKey=businessservices&title=UCv3+Link+Creation+Guide#UCv3LinkCreationGuide-RegularWorkflow) to land on the unified checkout page| email | `false` |
| `data-extra-options` | additional query params to append to the url, see: [Table of public query params](https://wiki.corp.adobe.com/pages/viewpage.action?spaceKey=businessservices&title=UCv3+Link+Creation+Guide#UCv3LinkCreationGuide-Tableofpublicqueryparams)| {} | `false` |
| `data-ims-country` | the ims country to code of the user if signed in, overrides the locale country in the generated checkout url | | `false` |
| `data-perpetual` | whether this is a perpetual offer `true\|false` | | `false` |
| `data-promotion-code` | Flex promotion code, if applicable | | `false` |
| `data-quantity` | Quantity of the offer to purchase | 1 | `false` |
| `data-entitlement` | `entitlement` flag for client side interpretation | `false` | `false` |
| `data-upgrade` | `upgrade` flag for client side interpretation | `false` | `false` |
| `data-modal` | `modal` flag for client side interpretation | `false` | `false` |



### Examples {#examples}


#### Custom Workflow Step

```html
<a href="#" is="checkout-link" data-wcs-osi="A1xn6EL4pK93bWjM8flffQpfEL-bnvtoQKQAvkx574M" data-checkout-workflow-step="recommendation">Buy now</a>
```

##### Demo<br>
<a href="#" is="checkout-link" data-wcs-osi="A1xn6EL4pK93bWjM8flffQpfEL-bnvtoQKQAvkx574M" data-checkout-workflow-step="recommendation">Buy now</a>

#### Multiple Quantities
Two photoshop and three acrobat pro single apps (TEAMS):

```html
<a href="#" is="checkout-link" data-wcs-osi="yHKQJK2VOMSY5bINgg7oa2ov9RnmnU1oJe4NOg4QTYI,vV01ci-KLH6hYdRfUKMBFx009hdpxZcIRG1-BY_PutE" data-quantity="2,3">Buy now</a>
```

##### Demo<br>
<a href="#" is="checkout-link" data-wcs-osi="yHKQJK2VOMSY5bINgg7oa2ov9RnmnU1oJe4NOg4QTYI,vV01ci-KLH6hYdRfUKMBFx009hdpxZcIRG1-BY_PutE" data-quantity="2,3">Buy now</a>


#### Custom query params

```html
<a href="#" is="checkout-link" data-wcs-osi="A1xn6EL4pK93bWjM8flffQpfEL-bnvtoQKQAvkx574M" data-extra-options="{&quot;promoid&quot;:&quot;promo12345&quot;,&quot;mv&quot;:1,&quot;mv2&quot;:2}">Buy now</a>
```

##### Demo<br>
<a href="#" is="checkout-link" data-wcs-osi="A1xn6EL4pK93bWjM8flffQpfEL-bnvtoQKQAvkx574M" data-extra-options="{&quot;promoid&quot;:&quot;promo12345&quot;,&quot;mv&quot;:1,&quot;mv2&quot;:2}">Buy now</a>


#### IMS Country

```html
<a href="#" is="checkout-link" data-wcs-osi="A1xn6EL4pK93bWjM8flffQpfEL-bnvtoQKQAvkx574M" data-ims-country="JP">Buy now</a>
```

##### Demo<br>
<a href="#" is="checkout-link" data-wcs-osi="A1xn6EL4pK93bWjM8flffQpfEL-bnvtoQKQAvkx574M" data-ims-country="JP">Buy now</a>


## Properties {#properties}

| Property | Description |
|---------------|-----------------------------------|
| `onceSettled` | promise that resolves when the custom-element either resolves or fails to resolve the offer |
| `options` | JSON object with the complete set of properties used to resolve the offer |
| `value` | The actual offer that is used to render the checkout link. In some cases WCS can return multiple offers but only one will be picked to render for a single app. |

### Example <br>

```html
<a id="co1" href="#" is="checkout-link" data-wcs-osi="A1xn6EL4pK93bWjM8flffQpfEL-bnvtoQKQAvkx574M" data-ims-country="CA">Buy now</a>
<script type="module">
document.getElementById('co1').onceSettled().then(el => {
document.getElementById('coValue').innerHTML = JSON.stringify(el.value, null, '\t');
document.getElementById('coOptions').innerHTML = JSON.stringify(el.options, null, '\t');
});
</script>
```
<a id="co1" href="#" is="checkout-link" data-wcs-osi="A1xn6EL4pK93bWjM8flffQpfEL-bnvtoQKQAvkx574M" data-ims-country="CA">Buy now</a>
<script type="module">
document.getElementById('co1').onceSettled().then(el => {
document.getElementById('coValue').innerHTML = JSON.stringify(el.value, null, '\t');
document.getElementById('coOptions').innerHTML = JSON.stringify(el.options, null, '\t');
});
</script>

#### value property
```json {#coValue}
```

#### options property
```json {#coOptions}
```


## Methods {#methods}

| Property | Description |
|---------------|-----------------------------------|
| `requestUpdate(true\|false)` | causes a re-render using the actual options |


## Events {#events}

| Event | Description |
|-----------|-----------------------------------|
| `wcms:placeholder:pending` | fires when checkout link starts loading |
| `wcms:placeholder:resolved`| fires when the offer is successfully resolved |
| `wcms:placeholder:failed` | fires when the offer could not be found or fetched |
| `click` | native click event on the `a` element |


<br>

For each event except `click`, the following css classes are toggled on the element: `placeholder-pending`, `placeholder-resolved`, `placeholder-failed`.

::: warning
**Note**: Event names with `wcms:placeholder` prefix can be subject to change.
:::


### Example <br>

```html
<a id="co2" href="#" is="checkout-link" data-wcs-osi="A1xn6EL4pK93bWjM8flffQpfEL-bnvtoQKQAvkx574M">Buy now (click me)</a>
<script type="module">
const logTarget = document.getElementById('logTarget');
const log = (...messages) => logTarget.innerHTML = `${logTarget.innerHTML}<br>${messages.join(' ')}`;
const a = document.getElementById('co2');
a.addEventListener('wcms:placeholder:pending', () => log('placeholder pending'));
a.addEventListener('wcms:placeholder:resolved', () => log('placeholder resolved'));
a.addEventListener('wcms:placeholder:failed', () => log('placeholder failed'));
a.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
log('checkout link is clicked: ', e.target.href);
});
a.addEvent
</script>
```

<a id="co2" href="#" is="checkout-link" data-wcs-osi="A1xn6EL4pK93bWjM8flffQpfEL-bnvtoQKQAvkx574M">Buy now (click me)</a>
<script type="module">
const logTarget = document.getElementById('logTarget');
const log = (...messages) => logTarget.innerHTML = `${logTarget.innerHTML}<br>${messages.join(' ')}`;
const a = document.getElementById('co2');
a.addEventListener('wcms:placeholder:pending', () => log('placeholder pending'));
a.addEventListener('wcms:placeholder:resolved', () => log('placeholder resolved'));
a.addEventListener('wcms:placeholder:failed', () => log('placeholder failed'));
a.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
log('checkout link is clicked: ', e.target.href);
});
a.addEvent
</script>


#### Logs <br>
```html {#logTarget}
```
Loading

0 comments on commit 5ddeb73

Please sign in to comment.