react_size_chart
Version:
Vestfoy smart size charts react package
414 lines • 18.6 kB
JavaScript
import React, { useState, useEffect, useLayoutEffect } from 'react';
import InnerHTML from 'dangerously-set-html-content';
import $ from 'jquery';
import '../../assets/bootstrap.min.css';
import '../../assets/vestofy.css';
export var EButtonIcon;
(function (EButtonIcon) {
EButtonIcon["meter_icon"] = "meter";
EButtonIcon["meter_icon_dark"] = "meter-dark";
})(EButtonIcon || (EButtonIcon = {}));
export var EAlignButton;
(function (EAlignButton) {
EAlignButton[EAlignButton["eAlignLeft"] = 0] = "eAlignLeft";
EAlignButton[EAlignButton["eAlignCenter"] = 1] = "eAlignCenter";
EAlignButton[EAlignButton["eAlignRight"] = 2] = "eAlignRight";
})(EAlignButton || (EAlignButton = {}));
export class Border {
BorderWidth;
BorderColor;
BorderRadius;
constructor() {
this.BorderColor = "#FFFFFF";
this.BorderWidth = 0;
this.BorderRadius = 0;
}
}
const g_sContactMail = "contact@vestofy.com";
let g_sHtmlContent = "";
const devUrl = false;
let isString = (value) => typeof value === 'string';
function SaveStorageDialogContent(a_sHtmlDialogContent, a_sShop, a_sSizeChartId = null, a_sProductID = null, a_sVendor = null, a_sProductType = null, a_sTags = null) {
try {
if (isString(a_sSizeChartId)) {
sessionStorage.setItem(a_sShop + a_sSizeChartId, a_sHtmlDialogContent);
}
else if (isString(a_sProductID)) {
sessionStorage.setItem(a_sShop + a_sProductID, a_sHtmlDialogContent);
}
else if (isString(a_sVendor)) {
sessionStorage.setItem(a_sShop + a_sVendor, a_sHtmlDialogContent);
}
else if (isString(a_sProductType)) {
sessionStorage.setItem(a_sShop + a_sProductType, a_sHtmlDialogContent);
}
else if (isString(a_sTags)) {
sessionStorage.setItem(a_sShop + a_sTags, a_sHtmlDialogContent);
}
else {
console.warn('Cant save content to storage');
}
}
catch (e) {
console.error('Save content to localstorage exception\n', e);
}
}
function LoadStorageDialogContent(a_sShop, a_sSizeChartId = null, a_sVendor = null, a_sProductType = null, a_sTags = null) {
try {
if (isString(a_sSizeChartId)) {
return sessionStorage.getItem(a_sShop + a_sSizeChartId);
}
else if (isString(a_sVendor)) {
return sessionStorage.getItem(a_sShop + a_sVendor);
}
else if (isString(a_sProductType)) {
return sessionStorage.getItem(a_sShop + a_sProductType);
}
else if (isString(a_sTags)) {
return sessionStorage.getItem(a_sShop + a_sTags);
}
else {
return null;
}
}
catch (e) {
console.error('Load content from storage exception\n', e);
return null;
}
}
const defaultBtnOptions = {
/**
* Text displayed on the button that open the guid popup (default: Size Guide)
*/
buttonText: 'Size Guide',
/**
* Text size displayed on the button that open the guid popup (default: 15px)
*/
buttonTextSize: 15,
/**
* Text color (hex format) displayed on the button that open the guid popup (default: #000000)
*/
buttonTextColor: '#000000',
/**
* Background color (hex format) of the button that open the guid popup (default: transparent)
*/
buttonBackgroundColor: '#FF000000',
/**
* Image displayed on the side of button
*/
buttonImgSrc: EButtonIcon.meter_icon.toString(),
/**
* Button alignment in parent component rule
*/
btnAlign: EAlignButton.eAlignLeft,
/*
* Button border
*/
border: { BorderColor: "#FFFFFFFF", BorderWidth: 0, BorderRadius: 0 },
/**
* Show size advice on parent window (product window)
*/
advice: true,
/**
* Size advice background color
*/
adviceBackgroundColor: "#FAB823",
/**
* Clearing sessionStorage every reload and some additional log (Use in while development)
*/
dev: false
};
const defaultPopupOptions = {
dialogTitle: 'Size Guide',
};
function buildBtnOptions(a_oPropsOptions) {
try {
const l_oOptions = {
buttonText: a_oPropsOptions.buttonText ?? defaultBtnOptions.buttonText,
buttonTextSize: a_oPropsOptions.buttonTextSize ?? defaultBtnOptions.buttonTextSize,
buttonTextColor: a_oPropsOptions.buttonTextColor ?? defaultBtnOptions.buttonTextColor,
buttonBackgroundColor: a_oPropsOptions.buttonBackgroundColor ?? defaultBtnOptions.buttonBackgroundColor,
buttonImgSrc: a_oPropsOptions.buttonImgSrc ?? defaultBtnOptions.buttonImgSrc,
btnAlign: a_oPropsOptions.btnAlign ?? defaultBtnOptions.btnAlign,
border: a_oPropsOptions.border ?? defaultBtnOptions.border,
advice: a_oPropsOptions.advice ?? defaultBtnOptions.advice,
adviceText: a_oPropsOptions.adviceText ?? 'Find your best size',
adviceBackgroundColor: a_oPropsOptions.adviceBackgroundColor ?? defaultBtnOptions.adviceBackgroundColor,
dev: a_oPropsOptions.dev ?? defaultBtnOptions.dev
};
return l_oOptions;
}
catch (e) {
console.error('build options error:\n', e);
return defaultBtnOptions;
}
}
function buildPopupOptions(a_oPropsOptions) {
try {
const l_oOptions = {
dialogTitle: a_oPropsOptions.dialogTitle ?? defaultPopupOptions.dialogTitle,
// dev: typeof a_oPropsOptions.dev != 'undefined' ? a_oPropsOptions.dev : defaultPopupOptions.dev
};
return l_oOptions;
}
catch (e) {
console.error('build options error:\n', e);
return defaultPopupOptions;
}
}
const g_oVestofyContentLoadedEvent = new CustomEvent("VestofyContentLoadedEvent", {
detail: {},
bubbles: true,
cancelable: true,
composed: false,
});
function addScript(src, id, integrity, crossorigin, onLoad) {
try {
const existing = document.getElementById(id);
if (existing) {
onLoad();
return existing;
}
else {
const script = document.createElement("script");
script.src = src;
script.id = id;
if (integrity) {
script.integrity = integrity;
}
if (crossorigin) {
script.crossOrigin = crossorigin;
}
script.async = true;
script.onload = () => {
if (onLoad) {
onLoad();
}
};
document.head.appendChild(script);
return script;
}
}
catch (e) {
console.error('Add script exception\n', e);
return null;
}
}
// *********************************************************
// ------Download Vestofy popup content---------------------
// *********************************************************
function loadFittingRoom(a_sShop, a_sPlatform = 'Standalone', a_sOutlineImage = undefined, a_sBottomDescription = undefined, a_sKey = "", a_sAssignment = undefined, a_sSizeChartId = undefined, a_sVendor = undefined, a_sProductType = undefined, a_sTags = undefined, a_sLang = "en") {
return new Promise(function (resolve, reject) {
try {
let l_sSrc = "https://proxy.vestofy.com/proxy/";
if (devUrl) {
l_sSrc = "https://proxy.tunnelto.me/proxy/";
console.warn('Vestofy: About to load debug fitting room\n', l_sSrc);
}
const params = {
size_chart_id: a_sSizeChartId,
product_id: undefined,
product_type: a_sProductType,
product_vendor: a_sVendor,
product_tags: a_sTags,
assignment: a_sAssignment,
shop: a_sShop,
key: a_sKey,
locale: a_sLang,
platform: a_sPlatform,
outline_image: a_sOutlineImage,
bottom_description: a_sBottomDescription,
add_header: false
};
const queryString = Object.entries(params)
.filter(([_, value]) => value !== undefined && value !== null && value !== "")
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join("&");
l_sSrc = `${l_sSrc}?${queryString}`;
$.ajax({
url: encodeURI(l_sSrc),
dataType: "jsonp",
method: "GET",
success: function (a_oDialogData) {
try {
window.$ = $; /**Add jQuery to dialog html */
if (a_oDialogData.html) {
resolve(a_oDialogData.html);
}
else {
resolve(a_oDialogData);
}
}
catch (e) {
console.error("insert Vestofy html exception\n", e);
resolve(`<h3>Ooops, Something wrong: Error to parse data :(</br>Try to refresh.</br>If the problem continue contact support: ${g_sContactMail}/h3>`);
}
},
error: function (error) {
console.error(`Ooops, Error to fetch content from: ${l_sSrc}\n`, error);
resolve(`<h3>Ooops, Something wrong: Error to fetch content :(</br>Try to refresh.</br>If the problem continue contact support: ${g_sContactMail}</h3>`);
},
});
}
catch (e) {
console.error("Vestofy script exception:\n", e);
reject(e);
}
});
}
function renderLoader() {
return React.createElement("div", { className: "d-flex justify-content-center align-items-center", style: { height: "100vh" } },
React.createElement("div", { className: "spinner-border text-info", role: "status" },
React.createElement("span", { className: "sr-only" }, "Loading...")));
}
const FittingRoomContent = (props) => {
useEffect(() => {
try {
if (!props.loading && props.contentHtml && props.contentHtml.length > 0) {
if (props.dev) {
setTimeout(() => {
console.log('Vestofy: dispatch content event');
document.dispatchEvent(g_oVestofyContentLoadedEvent);
}, 10);
}
else {
document.dispatchEvent(g_oVestofyContentLoadedEvent);
}
}
}
catch (e) {
console.error('dispatch Vestofy init event exception\n', e);
}
return (() => {
});
});
return (props.loading ? renderLoader() : React.createElement(InnerHTML, { html: props.contentHtml, allowRerender: props.dev == true }));
};
function renderBtnImage(a_sSrc, a_iWidth) {
if (a_sSrc == EButtonIcon.meter_icon) {
return React.createElement("span", { className: 'buttonLogo buttonLogoPosition', style: { width: a_iWidth } });
}
else if (a_sSrc == EButtonIcon.meter_icon_dark) {
return React.createElement("span", { className: 'buttonLogoDark buttonLogoPosition', style: { width: a_iWidth } });
}
else if (a_sSrc == null) {
return null;
}
else {
return React.createElement("img", { className: 'buttonLogoPosition', src: a_sSrc, alt: 'size guide', width: a_iWidth, height: a_iWidth });
}
}
export function VestofyContent() {
const [htmlContent, setHtmlContent] = useState("");
const [dev, setDev] = useState(false);
addEventListener("vestofy_content_loaded_event", (e) => {
setHtmlContent(e.detail.html);
setDev(e.detail.dev);
});
return React.createElement("div", { id: 'vestofyTag' },
React.createElement(FittingRoomContent, { contentHtml: htmlContent, loading: htmlContent.length == 0, dev: dev }));
}
// ******************************************
// --------render Popup-----------
// ******************************************
export function VestofySizeChartPopup(a_oOptions = defaultPopupOptions) {
const [htmlContent, setHtmlContent] = useState("");
const [dev, setDev] = useState(false);
addEventListener("vestofy_content_loaded_event", (e) => {
setHtmlContent(e.detail.html);
setDev(e.detail.dev);
});
try {
const l_oOptions = buildPopupOptions(a_oOptions);
return React.createElement("div", null,
React.createElement("div", { className: "modal fade", id: "vestofy-chart-modal", role: "dialog", tabIndex: -1, "data-keyboard": 'true', "data-backdrop": 'false', "aria-hidden": "true", "aria-labelledby": "sizeChartDialogDescribe" },
React.createElement("div", { className: "modal-dialog modal-dialog-scrollable", role: "document" },
React.createElement("div", { className: "modal-content" },
React.createElement("div", { className: "modal-header d-flex justify-content-between align-items-start" },
React.createElement("button", { type: "button", className: "close position-absolute", style: { right: '1rem' }, "data-dismiss": "modal", "aria-label": "Close" },
React.createElement("span", { "aria-hidden": "true" }, "\u00D7")),
React.createElement("h5", { className: "modal-title", id: "sizeChartDialogDescribe", style: { fontSize: '1.5em' } },
l_oOptions.dialogTitle,
dev ? React.createElement("span", { className: 'small text-muted' },
" ",
`(Preview)`) : null)),
React.createElement("div", { className: "modal-body", id: "chart-body" },
React.createElement("div", { id: 'vestofyTag' },
React.createElement(FittingRoomContent, { contentHtml: htmlContent, loading: htmlContent.length == 0, dev: dev })))))));
}
catch (e) {
console.error('SizeChartPopup exception:\n', e);
return null;
}
}
// ******************************************
// --------render button---------------------
// ******************************************
export function VestofyShowBtn(props = defaultBtnOptions) {
const l_oOptions = buildBtnOptions(props);
let btnStyle = { outline: 'none', fontSize: l_oOptions.buttonTextSize, color: l_oOptions.buttonTextColor, backgroundColor: l_oOptions.buttonBackgroundColor, border: `${l_oOptions.border?.BorderWidth}px solid ${l_oOptions.border?.BorderColor}`, borderRadius: `${l_oOptions.border?.BorderRadius}px` };
let adviceStyle = { display: l_oOptions.advice ? 'block' : 'none !important', fontSize: l_oOptions.buttonTextSize, backgroundColor: l_oOptions.adviceBackgroundColor, marginBottom: '2px' };
let align = 'vestofy-content-left';
if (l_oOptions.btnAlign == EAlignButton.eAlignCenter) {
align = 'vestofy-content-center';
}
else if (l_oOptions.btnAlign == EAlignButton.eAlignRight) {
align = 'vestofy-content-right';
}
btnStyle = Object.assign({}, btnStyle);
adviceStyle = Object.assign({}, adviceStyle);
return React.createElement("div", { className: 'vestofy-root vestofy-btn-wrapper' },
l_oOptions.advice ? React.createElement("div", { className: `vestofy-btn-wrapper` },
React.createElement("span", { className: `${align}`, style: adviceStyle, id: "showVestofySizeAdvice" }, l_oOptions.adviceText)) : null,
React.createElement("div", { className: `${align}` },
React.createElement("button", { type: "button", id: "showVestofyBtn", className: `btn btn-primary vestofy-btn ${align}`, style: btnStyle, "data-toggle": "modal", "data-target": "#vestofy-chart-modal", onClick: props.onClick },
renderBtnImage(l_oOptions.buttonImgSrc, l_oOptions.buttonTextSize),
l_oOptions.buttonText)));
}
async function InitDialogContent(props) {
const l_sTags = props.tags?.join(',');
if (props.options?.dev) {
console.log(`size_charts_id: ${props.size_chart_id} vendor: ${props.vendor} product type: ${props.product_type} tags: ${l_sTags}`);
}
const l_sHtmlContent = LoadStorageDialogContent(props.shop, props.size_chart_id, props.vendor, props.product_type, l_sTags);
if (l_sHtmlContent == null || props.options?.dev) {
return await loadFittingRoom(props.shop, props.platform, props.bottom_image, props.bottom_description, props.key, props.assignment, props.size_chart_id, props.vendor, props.product_type, l_sTags, props.locale);
}
else {
return g_sHtmlContent;
}
}
// *******************************************
// ---------Component hook--------------------
// *******************************************
const Vestofy = (props) => {
const local = typeof props.locale != 'undefined' ? props.locale : 'en';
/**Initialize and import scripts before render*/
useLayoutEffect(() => {
addScript(`https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js`, "jQuery", undefined, undefined, () => {
addScript(`https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.min.js`, "bootstrap", undefined, // "sha384-+sLIOodYLS7CIrQpBjl+C7nPvqq+FbNUBDunl/OZv93DB7Ln/533i8e/mZXLi/P+",
undefined, // "anonymous",
async () => {
ContentLoader();
});
});
}, [local]);
const ContentLoader = async () => {
try {
if (props.options && props.options.dev) {
sessionStorage.clear();
}
const l_sDialogContent = await InitDialogContent(props);
SaveStorageDialogContent(l_sDialogContent, props.shop, props.size_chart_id, props.vendor, props.product_type, props.tags?.join(','));
g_sHtmlContent = `${l_sDialogContent}`; //deep copy
const vestofyContentEvent = new CustomEvent("vestofy_content_loaded_event", { detail: { html: l_sDialogContent, dev: props.options?.dev } });
dispatchEvent(vestofyContentEvent);
}
catch (e) {
console.error(`Vestofy content load failed`, e);
}
};
return (React.createElement(React.Fragment, null, (props.Popup ?? true) ? VestofyShowBtn(props.options) : VestofyContent()));
};
export default Vestofy;
//# sourceMappingURL=App.js.map