projects/conversational-commerce-agent/conversational-agent-examples/assets/apparel-ui/static/local.html (332 lines of code) (raw):
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="df-messenger-bernard.css">
<link rel="stylesheet" href="bernard-styles.css">
<script src="https://www.gstatic.com/dialogflow-console/fast/df-messenger/prod/v1/df-messenger.js"></script>
<script src="helper.js"></script>
<script>
// Element for retail example. Contact: bpataki@google.com
class RetailTemplate extends HTMLElement {
constructor() {
super();
this.dfPayload = null;
this.dfResponseId = null;
this.renderRoot = this.attachShadow({ mode: 'open' });
}
/** Web component Lifecycle method. */
connectedCallback() {
this.renderRoot.appendChild(this._renderStyles());
this.renderRoot.appendChild(this._renderContent());
}
/**
* Render styles.
* @return {HTMLElement!}
*/
_renderStyles() {
const styles = document.createElement('style');
styles.textContent = `
.wrapper {
color: var(--df-messenger-default-text-color);
}
.title-link {
text-decoration: none;
color: var(--df-messenger-default-text-color);
}
.item-list {
display: flex;
width: 100%;
gap: 15px;
/* No flex wrap. */
overflow-x: auto;
}
.item {
width: 50%;
// background: #E8F0FE;
border-radius: 15px;
padding: 16px;
}
.item-title {
margin-top: 0;
}
.item-price {
font-size: 1.5em;
margin-top: 20px;
}
.item-image-wrapper {
position: relative;
}
.item-image {
border-radius: 8px;
width: 100%;
box-shadow: 5px 0 20px 0 rgba(0, 0, 0, 0.1)
}
.item-description, .item-details {
padding: 8px 0;
}
.item-table {
font-size: var(--df-messenger-default-font-size);
}
.item-table td {
padding: 2px 8px;
}
.title {
display: none;
}
`;
return styles;
}
/**
* Render content.
* @return {HTMLElement!}
*/
_renderContent() {
const content = document.createElement('div');
content.classList.add('wrapper');
const itemList = document.createElement('div');
itemList.classList.add('item-list');
for (const item of this.dfPayload.items) {
itemList.appendChild(this._renderItem(item));
}
content.appendChild(itemList);
return content;
}
/**
* Render content.
* @param {Object!} itemPayload
* @return {HTMLElement!}
*/
_renderItem(itemPayload) {
let item = document.createElement('div');
item.classList.add('item');
console.log(itemPayload);
const itemData = itemPayload.product;
// console.log(itemData);
let title = document.createElement('h2');
title.classList.add('item-title');
title.textContent = itemData.title;
let imageWrapper = document.createElement('div');
imageWrapper.classList.add('item-image-wrapper');
let image = document.createElement('img');
image.classList.add('item-image');
image.src = itemData.images[0].uri;
imageWrapper.appendChild(image);
let price = document.createElement('div');
price.classList.add('item-price');
if (itemData.priceInfo) {
price.textContent = `${itemData.priceInfo.price} ${itemData.priceInfo.currencyCode || "$"}`;
}
let description;
if (itemData.description) {
description = document.createElement('div');
description.classList.add('item-description');
description.textContent = itemData.description;
}
let details;
if (itemData.categories) {
details = document.createElement('div');
details.classList.add('item-details');
details.textContent = itemData.categories;
}
item.appendChild(title);
item.appendChild(imageWrapper);
if (itemData.description) {
// item.appendChild(description); // uncomment to show the description
}
if (itemData.categories) {
item.appendChild(details);
}
if (itemData.priceInfo) {
item.appendChild(price);
}
// item.appendChild(infoLink);
return item;
}
}
// Custom Template for rendering Customer Reviews.
class ReviewTemplate extends HTMLElement {
constructor() {
super();
this.dfPayload = null;
this.dfResponseId = null;
this.renderRoot = this.attachShadow({ mode: 'open' });
}
/** Web component Lifecycle method. */
connectedCallback() {
this.renderRoot.appendChild(this._renderStyles());
this.renderRoot.appendChild(this._renderContent());
}
/**
* Render styles.
* @return {HTMLElement!}
*/
_renderStyles() {
const styles = document.createElement('style');
styles.textContent = `
.wrapper {
color: var(--df-messenger-default-text-color);
}
.title-link {
text-decoration: none;
color: var(--df-messenger-default-text-color);
}
.item-list {
display: flex;
width: 100%;
gap: 15px;
/* No flex wrap. */
overflow-x: auto;
}
.item {
width: 50%;
background: #E8F0FE;
border-radius: 15px;
padding: 16px;
}
.review {
background: #fff;
border-radius: 15px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
padding: 20px;
// width: 30%; /* Adjust as necessary for your layout */
// margin: 10px;
box-sizing: border-box;
}
.review-header {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.user-avatar {
background-color: #0077CC;
color: #fff;
font-weight: bold;
width: 50px;
height: 50px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
}
.user-info {
flex-grow: 1;
}
.user-name {
font-size: 1.1em;
color: #333;
}
.user-rating {
display: flex;
align-items: center;
}
.stars {
color: #FFD700;
font-size: 1em;
}
.rating-score {
font-size: 0.8em;
color: #777;
margin-left: 5px;
}
.review-text {
font-size: 0.9em;
color: #555;
}
.review-title {
font-size: 0.9em;
font-weight: bold;
color: #555;
}
.review-text a {
color: #0077CC;
text-decoration: none;
}
`;
return styles;
}
/**
* Render content.
* @return {HTMLElement!}
*/
_renderContent() {
const content = document.createElement('div');
content.classList.add('wrapper');
const itemList = document.createElement('div');
itemList.classList.add('item-list');
const numReviews = this.dfPayload.items.length
for (const item of this.dfPayload.items) {
itemList.appendChild(this._renderItem(item, numReviews));
}
content.appendChild(itemList);
return content;
}
/**
* Render content.
* @param {Object!} itemPayload
* @param {Number!} numReviews
* @return {HTMLElement!}
*/
_renderItem(itemPayload, numReviews) {
const item = document.createElement('div');
console.log(itemPayload);
// Clone our template node, replace the values, and re-insert into DOM.
let revTemplate = document.getElementById('review-template').cloneNode(true);
revTemplate.id = '';
revTemplate.style.display = 'block';
item.appendChild(revTemplate);
let userAvatar = revTemplate.getElementsByClassName('user-avatar')[0];
userAvatar.textContent = itemPayload.user[0];
let userName = revTemplate.getElementsByClassName('user-name')[0];
userName.textContent = itemPayload.user;
let userRating = revTemplate.getElementsByClassName('rating-score')[0];
userRating.textContent = '(' + itemPayload.rating + '/5)';
let userDesc = revTemplate.getElementsByClassName('review-text')[0];
userDesc.textContent = itemPayload.desc;
let prodTitle = revTemplate.getElementsByClassName('review-title')[0];
prodTitle.textContent = 'Item: ' + itemPayload.title;
let stars = revTemplate.getElementsByClassName('stars')[0];
let numFilled = itemPayload.rating;
let numEmpty = 5 - numFilled;
for (let i = 0; i < itemPayload.rating; i++) {
stars.textContent += '★';
}
for (let i = 0; i < numEmpty; i++) {
stars.textContent += '☆';
}
return item;
}
}
// Enable custom elements.
(function () {
customElements.define('retail-template', RetailTemplate);
customElements.define('review-template', ReviewTemplate);
})();
</script>
</head>
<body>
<div class="page">
<df-messenger agent-id="72555c64-01a0-4e26-a27c-d01ec9e368f1" project-id="kalschi-conv-commerce-5"
location="us-central1" language-code="en" intent="WelcomeEvent"
url-allowlist="https://gstatic.com/" storage-option="none">
<df-messenger-chat chat-title-icon="assets/title-Apparel.png" user-actor-image="assets/user.png"
bot-actor-image="assets/actor.png"></df-messenger-chat>
</df-messenger>
</div>
<!-- DOM element to clone for creating reviews. -->
<div id="review-template" class="review-container" style="display:none">
<div class="review">
<div class="review-header">
<div class="user-avatar"></div>
<div class="user-info">
<div class="user-name"></div>
<div class="user-rating">
<span class="stars"></span>
<span class="rating-score"></span>
</div>
</div>
</div>
<p class="review-text"></p>
<p class="review-title"></p>
</div>
</body>
</html>