← Back to Home

comstylish.com Scam Check: 25/100 Trust | ScamMinder

Website: comstylish.com

Screenshot of comstylish.com

Safety Score

25/100
✗ Scam Risk

Exercise caution when interacting with this website.

AI Analysis Results

Category: E-commerce
About this website:

Detailed Analysis Report: Is comstylish.com Safe and Legit? Website Overview and Purpose comstylish.com is an e-commerce platform that claims to offer a wide range of affordable clothing and accessories for men and women. The site promotes itself as a destination for casual wear, featuring various categories including dresses, tops, and seasonal items like Halloween and Christmas apparel. Content Quality and User Experience Key Experience Highlights Offers a large selection of products with frequent updates, claiming over 500 new items daily. Prominent discount offers, including up to 50% off, which may attract budget-conscious shoppers. Features a user-friendly interface with categories for easy navigation. Includes promotional pop-ups encouraging email sign-ups for discounts, which can be a tactic to collect user data. Claims Verification and Red Flags ⚠️ Red Flags Detected Several concerning indicators suggest that this site may not be legitimate: Unrealistic Discounts: Claims of up to 50% off on various items, which is often a tactic used by scam sites to lure customers. No Verifiable Company Information: Lacks clear contact details, physical address, or company registration information, raising transparency concerns. Domain Age: The domain is only 4 years old, which is relatively new for an e-commerce site claiming extensive product offerings. VirusTotal Detection: The site has been flagged by 1 out of 97 vendors on VirusTotal, indicating potential security risks. Archive History: No significant archive history found, suggesting a lack of established presence or credibility. ⚠️ Caution Points Users should be cautious about providing personal information, especially email addresses, due to the site's aggressive marketing tactics. Verify product quality and seller reputation through independent reviews before making purchases. Security Note: The site uses a DV SSL certificate, which provides basic encryption but does not guarantee legitimacy. Legitimacy and Reputation Assessment The domain has been operational for 4 years , which is relatively short for an e-commerce site. It is hosted in the US by Cloudflare, a common provider for many websites. However, the lack of a solid archive history and the presence of a VirusTotal flag raise concerns about its legitimacy. Final Verdict and Recommendations Conclusion: Based on the numerous red flags and lack of transparency, comstylish.com appears to be a high-risk e-commerce site . Users should exercise caution and consider alternative, more established retailers for their shopping needs. Best practices include researching the site thoroughly, checking for customer reviews, and avoiding sharing sensitive information.

Risk Assessment: scam
⚠️ Red Flags:
  • [GUARDRAIL] No deterministic evidence for scam; downgrading to warning
  • [CLAIMS] Unrealistic discounts of up to 50% off on various items, typical of scam tactics.
  • [TRANSPARENCY] Missing clear contact information and company registration details.
  • [SECURITY] VirusTotal flagged the site as potentially malicious.
  • [DOMAIN HISTORY] The domain is relatively new, raising concerns about its credibility.
📊 Analysis Reasons:
  • [FINANCIAL] Claims of up to 50% off on products, which is often a tactic used by scam sites to attract customers.
  • [TRANSPARENCY] No verifiable company information or contact details available, raising concerns about legitimacy.
  • [DOMAIN HISTORY] Domain is only 4 years old, which is relatively new for an e-commerce site claiming extensive offerings.
  • [SECURITY] The site has been flagged by 1 out of 97 vendors on VirusTotal, indicating potential security risks.
  • [ARCHIVE] No significant archive history found, suggesting a lack of established presence or credibility.
🛡️ Safety Actions Applied:
  • {"type":"scam_downgraded","reason":"No deterministic evidence for scam; downgrading to warning","scoreCeiling":null,"targetStatus":"warning"}
Score Source: openai_guardrail
AI Confidence: medium

Technical Details

\n\n\n \n \n \n Comstylish | Everyday Casual Wear Brands\n\n\n\n\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n \n \n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n
\n
\n\n\n\n\n\n\n
\n
\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n const updateHeaderMetrics = () => {\n const header = document.getElementById('header');\n const rect = header.getBoundingClientRect();\n const headerHeight = rect.bottom;\n document.documentElement.style.setProperty('--header-height', `${headerHeight}px`);\n };\n window.addEventListener('DOMContentLoaded', updateHeaderMetrics);\n window.addEventListener('resize', updateHeaderMetrics);\n\n const header = document.getElementById('header');\n const resizeObserver = new ResizeObserver(entries => {\n for (let entry of entries) {\n const rect = entry.target.getBoundingClientRect();\n const headerHeight = rect.bottom;\n document.documentElement.style.setProperty('--header-height', `${headerHeight}px`);\n }\n });\n resizeObserver.observe(header);\n\n\n\n\n
\n
\n \n
\n
\n \n \n
\n \n \n \n \n \n\n
\n
\n \n \n \n \n \n\n
\n\n \n \n
\n \n \n \n \n \n\n
\n
\n \n \n \n \n \n\n
\n \n \n\n\n\n\n\n\n\n\n
\n \n

\n \n \n
\n \n \"Comstylish\n \n \n \n \n
\n Comstylish | Everyday Casual Wear Brands\n \n \n

\n \n
\n\n \n function setSearchUrl(searchValue) { return Promise.resolve({ url: '/search?q=' + searchValue }); }\n\n exportFunction('setSearchUrl', setSearchUrl);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n
\n
\n \n \n \n
\n
\n \n \n \n
\n
\n \n \n
c
\"icon\"
Women
\"icon\"
Men
\"icon\"
Dresses
\"icon\"
Halloween
\"icon\"
Christmas
\"icon\"
Cat
\"icon\"
Dog
\"icon\"
Tops
t-shirt
\"icon\"
Bohemia
\"icon\"
dresses
halloween
\"icon\"
halloween women
witch hat
\"icon\"
cat
witch
day of the dead
halloween
christmas
day of the dead dress
witch hats
\"icon\"
women
hats
\"icon\"
men
hat
viking
skeleton dress
skeleton
ha
witches hat
men halloween
witch dress
\"icon\"
hats women
leggings
w
witch dresses
christmas dress
\"icon\"
witch hats women
dog
vampire
halloween men
witch costume
s
witch
tops
\"icon\"
size chart
halloween hats
\"icon\"
fairy
h
\"icon\"
christmas dresses
clown
\"icon\"
harley quinn
\"icon\"
hallo
\"icon\"
mummy
christmas
halloween dresses
\"icon\"
bohemia
halloween dress
costumes
c
\"icon\"
Women
Search
Search
\n
\n\n \n
\n\n \n const template_name = SHOPLAZZA?.meta?.page?.template_name || '';\n const SEARCH_URL = '/search';\n const TAG = 'spz-custom-smart-search-location';\n const SMART_PRODUCR_SEARCH_WRAP_CLASSNAME = 'app-smart-product-search-container';\n const THEME_NAME = window.SHOPLAZZA.theme.merchant_theme_name.replace(/ /g,'');\n const BREAKPOINT = 960;\n const DELAY = 300;\n\n function diffThemeName(themeNameA, themeNameB){\n return themeNameA.toLocaleLowerCase().includes(themeNameB.toLocaleLowerCase())\n }\n\n const HEADER_DOM_MAP = {\n eva: 'header .header_grid_layout',\n geek: `.header-mobile-inner-container`,\n onePage: 'header .header',\n wind: 'header #header-nav',\n nova: 'header .header',\n hero: 'header .header__nav',\n 'flash': '#shoplaza-section-header>div>div',\n 'lifestyle': '#shoplaza-section-header .header__wrapper'\n }\n let HEADER_DOM = 'header';\n\n Object.keys(HEADER_DOM_MAP)\n .map(themeName=>{\n if (diffThemeName(THEME_NAME, themeName)) {\n HEADER_DOM = HEADER_DOM_MAP[themeName];\n }\n })\n\n const SEARCH_ICON_CLASS_MAP = {\n 'flash': 'app-smart-icon-search-large-flash',\n 'hero': 'app-smart-icon-search-large-hero',\n 'geek': 'app-smart-icon-search-large-geek',\n 'nova': 'app-smart-icon-search-large-nova',\n };\n let SEARCH_ICON_CLASS = 'app-smart-icon-search-large-default';\n Object.keys(SEARCH_ICON_CLASS_MAP)\n .map(themeName=>{\n if (diffThemeName(THEME_NAME, themeName)) {\n SEARCH_ICON_CLASS = SEARCH_ICON_CLASS_MAP[themeName];\n }\n })\n\n class SpzCustomSmartSearchLocation extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n this.mobileHeaderPluginParentEle = null;\n this.outsideCarouselIndex = 0;\n this.insideCarouselIndex = 0;\n this.searchItemType = 'icon';\n }\n\n static deferredMount() {\n return false;\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.LOGIC;\n }\n\n buildCallback() {\n this.init();\n this.listenerResize();\n this.initRegisterActions();\n }\n\n addIconClass(){\n document.querySelectorAll('.app-smart-icon-search-large').forEach(e=>{\n e.classList.add(SEARCH_ICON_CLASS)\n });\n }\n\n moveIcon(){\n if (!diffThemeName(THEME_NAME, 'lifestyle')) return;\n if (this.searchItemType === 'input') return;\n if (this.isDesktop()) return;\n const smart_search_dom = document.querySelector('#app-smart-product-search-container-101');\n if (!smart_search_dom) return;\n const hasMovedIcon = !!document.querySelector('.header__wrapper .container .row.header>div>#app-smart-product-search-container-101');\n if (hasMovedIcon) return;\n const headerDivList = document.querySelectorAll('.header__wrapper .container .row.header>div');\n const iconBoxDom = headerDivList[headerDivList.length-1]\n iconBoxDom.appendChild(smart_search_dom, iconBoxDom.firstChild);\n }\n\n init() {\n this.addIconClass();\n this.moveIcon();\n if ( this.searchItemType === 'input' ) {\n document.querySelectorAll('.app-smart-icon-search-large').forEach(e=>e.style.display = 'none');\n const mobileSmartSearchDom = document.querySelector(`.smart-search-mobile-container .app-smart-product-search-wrap`);\n if ( this.isDesktop() ) {\n document.querySelector(`#app-smart-product-search-container-101`).style=\"display: block\";\n if (mobileSmartSearchDom) {\n document.querySelector(`#app-smart-product-search-container-101`).appendChild(mobileSmartSearchDom);\n }\n }else{\n if( template_name=='search' ) return;\n if (!document.querySelector(`.smart-search-mobile-container`)) {\n const appSmartSearchContainer = document.createElement('div');\n appSmartSearchContainer.classList.add('smart-search-mobile-container');\n appSmartSearchContainer.classList.add('smart-search-mobile-container-'+THEME_NAME.toLocaleLowerCase());\n document.querySelector(HEADER_DOM).appendChild(appSmartSearchContainer);\n }\n if (!mobileSmartSearchDom) {\n document.querySelector(`.smart-search-mobile-container`).appendChild(\n document.querySelector(`.app-smart-product-search-wrap`)\n )\n }\n }\n }else{\n document.querySelectorAll('.app-smart-icon-search-large').forEach(e=>e.style.display = 'flex');\n }\n // PC-end not load\n if (this.isDesktop()) {\n return;\n }\n if (!window.__isLoadAppSmartSearch__) {\n this.initSmartSearch();\n console.log('__isLoadAppSmartSearch__');\n }\n // B-end must reload\n if (window.self === window.top && !window.__isLoadAppSmartSearch__) {\n window.__isLoadAppSmartSearch__ = true;\n }\n }\n\n initSmartSearch() {\n if (this.hasMobileUpperRightPlugin()) {\n this.showMobileSmartSearch();\n } else {\n this.addMobileSmartSearch();\n }\n }\n\n initRegisterActions(){\n this.registOnSearchInputChange();\n this.registOnSearchFormSubmit();\n this.registOnOutsideCarouselIndexChange();\n this.registOnInsideCarouselIndexChange();\n this.registGetSearchItemType();\n this.registGenerateHotKeywordList();\n this.registerAction('onTapHotWord',(invocation)=>{\n this.onTapHotWord(invocation.args.type);\n });\n }\n\n registOnSearchInputChange(){\n this.registerAction('onSearchInputChange',(invocation)=>{\n const keyword = invocation.args.keyword;\n if (keyword === null || !keyword.length) {\n document.querySelectorAll('.hot-words-carousel-inner-container').forEach(e=>{\n e.style='display: block';\n }); \n } else {\n document.querySelectorAll('.hot-words-carousel-inner-container').forEach(e=>{\n e.style='display: none';\n });\n }\n })\n }\n\n registOnSearchFormSubmit(){\n this.registerAction('onSearchFormSubmit',(invocation)=>{\n const event = invocation.args.event;\n const keywordArray = event.q || [];\n const keyword = keywordArray[0];\n if (keyword!==null && keyword.length) {\n this.handleSearchSubmit_(keywordArray,1);\n } else {\n this.onTapHotWord('inside')\n }\n })\n }\n\n handleSearchSubmit_(value, retryNum){\n SPZ.whenApiDefined(document.getElementById('app-smart-search-101'))\n .then((ljsSearch) => {\n try{\n ljsSearch.handleSearchSubmit_({\n value: value\n })\n }catch(e){\n console.log('catch error',retryNum)\n if( 3 > retryNum ){\n this.handleSearchSubmit_(value, retryNum + 1);\n return;\n }\n const searchStr = value[0] || '';\n const searchResult = ljsSearch.setThinkSearchData_(searchStr);\n ljsSearch.afterSearching({\n query: searchResult.query,\n url: `${SEARCH_URL}?q=${searchStr}`,\n queryType: searchResult.queryType,\n })\n }\n })\n }\n\n registOnOutsideCarouselIndexChange(){\n this.registerAction('onOutsideCarouselIndexChange',(invocation)=>{\n this.outsideCarouselIndex = invocation.args.index || 0;\n })\n }\n\n registOnInsideCarouselIndexChange(){\n this.registerAction('onInsideCarouselIndexChange',(invocation)=>{\n this.insideCarouselIndex = invocation.args.index || 0;\n })\n }\n\n registGetSearchItemType(searchItemType){\n this.registerAction('getSearchItemType',(invocation)=>{\n SPZ.whenApiDefined(document.getElementById('app-smart-search-outside-item-101'))\n .then((appSmartSearchOutsideItem) => {\n const search_item_type = appSmartSearchOutsideItem.getData()?.search_item_type;\n this.searchItemType = search_item_type || this.searchItemType;\n this.init();\n })\n })\n }\n\n registGenerateHotKeywordList(){\n this.registerAction('generateHotKeywordList',(invocation)=>{\n const search_keywords = invocation.args?.data?.data?.hotKeywordList || [];\n const isShowHotKeyword = invocation.args?.data?.data?.isShowHotKeyword || false;\n SPZ.whenApiDefined(document.getElementById('app-smart-search-outside-item-101'))\n .then((appSmartSearchOutsideItem) => {\n const hotwords = appSmartSearchOutsideItem.getData()?.search_keywords || [];\n const new_search_keywords = search_keywords.map((item, index) => {\n item.url_obj = item.url_obj || {};\n const hotwordItem = hotwords.find(e=>e.word === item.word);\n if (hotwordItem) {\n item.icon = hotwordItem.icon || '';\n }\n if (!item.urlObj || !item.urlObj.url) {\n item.urlObj = {\n ...item.url_obj,\n url: item.url_obj.type === 'search' ? `${SEARCH_URL}?q=${item.word}` : item.url_obj.url,\n };\n }\n return item;\n });\n document.querySelectorAll('.app-hot-keyword-render-child')\n .forEach((ele) => {\n SPZ.whenApiDefined(ele)\n .then((hotWordsChildDom) => {\n hotWordsChildDom.render({\n list: new_search_keywords,\n isShowHotKeyword: isShowHotKeyword,\n });\n })\n });\n })\n });\n }\n\n onTapHotWord(type){\n const index = type === 'inside' ? this.insideCarouselIndex : this.outsideCarouselIndex;\n SPZ.whenApiDefined(document.getElementById('app-smart-search-outside-item-101'))\n .then((appSmartSearchOutsideItem) => {\n const hotwords = appSmartSearchOutsideItem.getData()?.search_keywords || [];\n const currentHotwordItem = hotwords[index] || null;\n if (currentHotwordItem && currentHotwordItem.url_obj) {\n currentHotwordItem.url_obj.url = currentHotwordItem.url_obj.type === 'search' ? `${SEARCH_URL}?q=${currentHotwordItem.word}` : currentHotwordItem.url_obj.url;\n }\n SPZ.whenApiDefined(document.getElementById('app-smart-search-101'))\n .then((ljsSearch) => {\n if (currentHotwordItem) {\n ljsSearch.handleHotKeyword_({\n word: currentHotwordItem.word,\n query_type: currentHotwordItem.type,\n url: currentHotwordItem.url_obj?.url,\n });\n } else {\n this.handleSearchSubmit_([''],1);\n }\n })\n })\n }\n\n getOutsideCarouselConfig(){\n return SPZ.whenApiDefined(document.getElementById('app-smart-search-outside-item-101'))\n .then((appSmartSearchOutsideItem) => {\n return {\n ...appSmartSearchOutsideItem.getData(),\n outsideCarouselIndex: this.outsideCarouselIndex,\n }\n })\n }\n\n listenerResize() {\n window.removeEventListener('resize', window.smartSearchResizeCallback);\n\n window.smartSearchResizeCallback = SPZCore.Types.debounce(\n this.win,\n () => {\n this.init();\n },\n DELAY\n );\n\n window.addEventListener('resize', window.smartSearchResizeCallback);\n }\n\n isDesktop() {\n const mediaQueryList = window.matchMedia(`(min-width: ${BREAKPOINT}px)`);\n return mediaQueryList.matches;\n }\n\n hasMobileUpperRightPlugin() {\n return !['geek', 'flash', 'boost'].includes(THEME_NAME.toLocaleLowerCase());\n }\n\n showMobileSmartSearch() {\n this.mobileHeaderPluginParentEle = this.getMobileHeaderPluginParentEle();\n this.setMobileHeaderIconsPluginStyle(this.mobileHeaderPluginParentEle);\n }\n\n getMobileHeaderPluginParentEle() {\n const MOBILE_HEADER_PLUGIN_PARENT_ELE_MAP = {\n nova: '.header__mobile #header__plugin-container',\n hero: '.header__icons .tw-flex.tw-justify-end.tw-items-center.tw-space-x-7',\n onePage: '.header__mobile #header__plugin-container',\n wind: '#header-icons .flex.justify-end.items-center',\n eva: '#header__icons .plugin_content'\n };\n\n const headerPluginParentSelector = this.combineMultipleSelectors(\n Object.values(MOBILE_HEADER_PLUGIN_PARENT_ELE_MAP)\n );\n return document.querySelector(headerPluginParentSelector);\n }\n\n setMobileHeaderIconsPluginStyle(pluginParentEle) {\n if (!pluginParentEle) {\n return;\n }\n const containHidden = pluginParentEle.classList.contains('md:hidden');\n const containTwHidden = pluginParentEle.classList.contains('md:tw-hidden');\n\n if (containHidden || containTwHidden) {\n Array.from(pluginParentEle.children).forEach((pluginElement) => {\n if (!this.hasSmartSearchPlugin(pluginElement)) {\n pluginElement.style.display = 'none';\n }\n });\n pluginParentEle.classList.remove('md:hidden', 'md:tw-hidden');\n } else {\n const smartSearchPluginElement = Array.from(pluginParentEle.children).find(\n (pluginElement) => {\n return this.hasSmartSearchPlugin(pluginElement);\n }\n );\n smartSearchPluginElement.style.display = 'block';\n }\n }\n\n hasSmartSearchPlugin(pluginElement) {\n return (\n pluginElement.classList.contains(`${SMART_PRODUCR_SEARCH_WRAP_CLASSNAME}`) ||\n pluginElement.querySelectorAll(`.${SMART_PRODUCR_SEARCH_WRAP_CLASSNAME}`).length > 0\n );\n }\n\n addMobileSmartSearch() {\n this.mobileHeaderIconsEle = this.getMobileHeaderIconsEle();\n this.smartSearchWrapEle = this.getSmartSearchWrapEle();\n this.appendSmartSearchToHeader();\n }\n\n getMobileHeaderIconsEle() {\n // Must be the parent element of the plugin\n const MOBILE_HEADER_ICONS_ELE_MAP = {\n geek: '#header-mobile-container .flex.items-center.justify-end.flex-shrink-0',\n flash: '#header-layout .header__icons',\n boost: '.header__mobile-bottom .tw-flex.tw-items-center.tw-justify-end.tw-flex-1'\n };\n\n const headerIconsSelector = this.combineMultipleSelectors(\n Object.values(MOBILE_HEADER_ICONS_ELE_MAP)\n );\n return document.querySelector(headerIconsSelector);\n }\n\n getSmartSearchWrapEle() {\n const smartSearchWrapEle = document.querySelector(this.getSmartSearchWrapSelector());\n if (!smartSearchWrapEle) {\n return null;\n }\n return smartSearchWrapEle;\n }\n\n appendSmartSearchToHeader() {\n if (!this.smartSearchWrapEle) {\n return;\n }\n\n this.mobileHeaderIconsEle.insertAdjacentElement('afterbegin', this.smartSearchWrapEle);\n }\n\n getSmartSearchWrapSelector() {\n const PLUGIN_POSITION = {\n DRAWER: 'drawer',\n HEADER_TOP: 'headerTop'\n };\n // only one this plugin of ancestor element\n const MOBILE_PLUGIN_POSITION_ELE_MAP = {\n [PLUGIN_POSITION.DRAWER]: {\n geek: '#header-menu-mobile #menu-drawer',\n flash: '#menu-drawer .plugin__header-content',\n boost: '.header__drawer'\n },\n [PLUGIN_POSITION.HEADER_TOP]: {\n geek: '#header-menu-mobile #menu-drawer',\n flash: '#menu-drawer .plugin__header-content',\n boost: '.header-content .logo-wrap'\n }\n };\n\n const MbPluginPositionInTheme = [\n ...Object.values(MOBILE_PLUGIN_POSITION_ELE_MAP[PLUGIN_POSITION.DRAWER]),\n ...Object.values(MOBILE_PLUGIN_POSITION_ELE_MAP[PLUGIN_POSITION.HEADER_TOP])\n ];\n\n return Object.values(MbPluginPositionInTheme).reduce((pre, ancestor) => {\n if (pre === '') {\n return `${ancestor} .app-smart-product-search-container`;\n }\n if (pre.includes(ancestor)) {\n return pre;\n }\n return `${pre},${ancestor} .app-smart-product-search-container`;\n }, '');\n }\n\n combineMultipleSelectors(selectorList) {\n return selectorList.reduce((pre, selector) => {\n if (pre === '') {\n return `${selector}`;\n }\n if (pre.includes(selector)) {\n return pre;\n }\n return `${pre},${selector}`;\n }, '');\n }\n }\n\n SPZ.defineElement(TAG, SpzCustomSmartSearchLocation);\n\n\n \n
\n
\n\n\n \n
\n \n \n
\n \n
\n
Powered by \"GoogleTranslate
\n \n \n \n \n \n \n
\n \n
\n
\n \"USD\"USD\n \n \n \n \n \n
    \n \n
  • \n \"USD\"United States Dollars (USD)\n
  • \n \n
  • \n \"EUR\"Euro (EUR)\n
  • \n \n
  • \n \"GBP\"United Kingdom Pounds (GBP)\n
  • \n \n
  • \n \"CAD\"Canadian Dollars (CAD)\n
  • \n \n
  • \n \"AUD\"Australian Dollars (AUD)\n
  • \n \n
  • \n \"AFN\"Afghan Afghani (AFN)\n
  • \n \n
  • \n \"ALL\"Albanian Lek (ALL)\n
  • \n \n
  • \n \"DZD\"Algerian Dinar (DZD)\n
  • \n \n
  • \n \"AOA\"Angolan Kwanza (AOA)\n
  • \n \n
  • \n \"ARS\"Argentine Pesos (ARS)\n
  • \n \n
  • \n \"AMD\"Armenian Dram (AMD)\n
  • \n \n
  • \n \"AWG\"Aruban Florin (AWG)\n
  • \n \n
  • \n \"BBD\"Barbadian Dollar (BBD)\n
  • \n \n
  • \n \"AZN\"Azerbaijani Manat (AZN)\n
  • \n \n
  • \n \"BDT\"Bangladesh Taka (BDT)\n
  • \n \n
  • \n \"BSD\"Bahamian Dollar (BSD)\n
  • \n \n
  • \n \"BHD\"Bahraini Dinar (BHD)\n
  • \n \n
  • \n \"BYN\"Belarusian Ruble (BYN)\n
  • \n \n
  • \n \"BZD\"Belize Dollar (BZD)\n
  • \n \n
  • \n \"BTN\"Bhutanese Ngultrum (BTN)\n
  • \n \n
  • \n \"BAM\"Bosnia and Herzegovina Convertible Mark (BAM)\n
  • \n \n
  • \n \"BRL\"Brazilian Real (BRL)\n
  • \n \n
  • \n \"BOB\"Bolivian Boliviano (BOB)\n
  • \n \n
  • \n \"BWP\"Botswana Pula (BWP)\n
  • \n \n
  • \n \"BND\"Brunei Dollar (BND)\n
  • \n \n
  • \n \"BGN\"Bulgarian Lev (BGN)\n
  • \n \n
  • \n \"MMK\"Burmese Kyat (MMK)\n
  • \n \n
  • \n \"KHR\"Cambodian Riel (KHR)\n
  • \n \n
  • \n \"CVE\"Cape Verdean escudo (CVE)\n
  • \n \n
  • \n \"KYD\"Cayman Dollars (KYD)\n
  • \n \n
  • \n \"XAF\"Central African CFA Franc (XAF)\n
  • \n \n
  • \n \"CLP\"Chilean Peso (CLP)\n
  • \n \n
  • \n \"CNY\"Chinese Yuan Renminbi (CNY)\n
  • \n \n
  • \n \"COP\"Colombian Peso (COP)\n
  • \n \n
  • \n \"KMF\"Comorian Franc (KMF)\n
  • \n \n
  • \n \"CDF\"Congolese franc (CDF)\n
  • \n \n
  • \n \"CRC\"Costa Rican Colones (CRC)\n
  • \n \n
  • \n \"HRK\"Croatian Kuna (HRK)\n
  • \n \n
  • \n \"CZK\"Czech Koruny (CZK)\n
  • \n \n
  • \n \"DKK\"Danish Kroner (DKK)\n
  • \n \n
  • \n \"DOP\"Dominican Peso (DOP)\n
  • \n \n
  • \n \"XCD\"East Caribbean Dollar (XCD)\n
  • \n \n
  • \n \"EGP\"Egyptian Pound (EGP)\n
  • \n \n
  • \n \"ETB\"Ethiopian Birr (ETB)\n
  • \n \n
  • \n \"XPF\"CFP Franc (XPF)\n
  • \n \n
  • \n \"FJD\"Fijian Dollars (FJD)\n
  • \n \n
  • \n \"GMD\"Gambian Dalasi (GMD)\n
  • \n \n
  • \n \"GHS\"Ghanaian Cedi (GHS)\n
  • \n \n
  • \n \"GTQ\"Guatemalan Quetzal (GTQ)\n
  • \n \n
  • \n \"GYD\"Guyanese Dollar (GYD)\n
  • \n \n
  • \n \"GEL\"Georgian Lari (GEL)\n
  • \n \n
  • \n \"HTG\"Haitian Gourde (HTG)\n
  • \n \n
  • \n \"HNL\"Honduran Lempira (HNL)\n
  • \n \n
  • \n \"HKD\"Hong Kong Dollars (HKD)\n
  • \n \n
  • \n \"HUF\"Hungarian Forint (HUF)\n
  • \n \n
  • \n \"ISK\"Icelandic Kronur (ISK)\n
  • \n \n
  • \n \"INR\"Indian Rupees (INR)\n
  • \n \n
  • \n \"IDR\"Indonesian Rupiah (IDR)\n
  • \n \n
  • \n \"ILS\"Israeli New Shekel (NIS)\n
  • \n \n
  • \n \"JMD\"Jamaican Dollars (JMD)\n
  • \n \n
  • \n \"JPY\"Japanese Yen (JPY)\n
  • \n \n
  • \n \"JEP\"Jersey Pound (JEP)\n
  • \n \n
  • \n \"JOD\"Jordanian Dinar (JOD)\n
  • \n \n
  • \n \"KZT\"Kazakhstani Tenge (KZT)\n
  • \n \n
  • \n \"KES\"Kenyan Shilling (KES)\n
  • \n \n
  • \n \"KWD\"Kuwaiti Dinar (KWD)\n
  • \n \n
  • \n \"KGS\"Kyrgyzstani Som (KGS)\n
  • \n \n
  • \n \"LAK\"Laotian Kip (LAK)\n
  • \n \n
  • \n \"LVL\"Latvian Lati (LVL)\n
  • \n \n
  • \n \"LBP\"Lebanese Pounds (LBP)\n
  • \n \n
  • \n \"LSL\"Lesotho Loti (LSL)\n
  • \n \n
  • \n \"LRD\"Liberian Dollar (LRD)\n
  • \n \n
  • \n \"MGA\"Malagasy Ariary (MGA)\n
  • \n \n
  • \n \"MKD\"Macedonia Denar (MKD)\n
  • \n \n
  • \n \"MOP\"Macanese Pataca (MOP)\n
  • \n \n
  • \n \"MWK\"Malawian Kwacha (MWK)\n
  • \n \n
  • \n \"MVR\"Maldivian Rufiyaa (MVR)\n
  • \n \n
  • \n \"MXN\"Mexican Pesos (MXN)\n
  • \n \n
  • \n \"MYR\"Malaysian Ringgits (MYR)\n
  • \n \n
  • \n \"MUR\"Mauritian Rupee (MUR)\n
  • \n \n
  • \n \"MDL\"Moldovan Leu (MDL)\n
  • \n \n
  • \n \"MAD\"Moroccan Dirham (MAD)\n
  • \n \n
  • \n \"MNT\"Mongolian Tugrik (MNT)\n
  • \n \n
  • \n \"MZN\"Mozambican Metical (MZN)\n
  • \n \n
  • \n \"NAD\"Namibian Dollar (NAD)\n
  • \n \n
  • \n \"NPR\"Nepalese Rupee (NPR)\n
  • \n \n
  • \n \"ANG\"Netherlands Antillean Guilder (ANG)\n
  • \n \n
  • \n \"NZD\"New Zealand Dollars (NZD)\n
  • \n \n
  • \n \"NIO\"Nicaraguan Córdoba (NIO)\n
  • \n \n
  • \n \"NGN\"Nigerian Naira (NGN)\n
  • \n \n
  • \n \"NOK\"Norwegian Kroner (NOK)\n
  • \n \n
  • \n \"OMR\"Omani Rial (OMR)\n
  • \n \n
  • \n \"PKR\"Pakistani Rupee (PKR)\n
  • \n \n
  • \n \"PGK\"Papua New Guinean Kina (PGK)\n
  • \n \n
  • \n \"PYG\"Paraguayan Guarani (PYG)\n
  • \n \n
  • \n \"PEN\"Peruvian Nuevo Sol (PEN)\n
  • \n \n
  • \n \"PHP\"Philippine Peso (PHP)\n
  • \n \n
  • \n \"PLN\"Polish Zlotych (PLN)\n
  • \n \n
  • \n \"QAR\"Qatari Rial (QAR)\n
  • \n \n
  • \n \"RON\"Romanian Lei (RON)\n
  • \n \n
  • \n \"RUB\"Russian Rubles (RUB)\n
  • \n \n
  • \n \"RWF\"Rwandan Franc (RWF)\n
  • \n \n
  • \n \"WST\"Samoan Tala (WST)\n
  • \n \n
  • \n \"SAR\"Saudi Riyal (SAR)\n
  • \n \n
  • \n \"STD\"Sao Tome And Principe Dobra (STD)\n
  • \n \n
  • \n \"RSD\"Serbian dinar (RSD)\n
  • \n \n
  • \n \"SCR\"Seychellois Rupee (SCR)\n
  • \n \n
  • \n \"SGD\"Singapore Dollars (SGD)\n
  • \n \n
  • \n \"SDG\"Sudanese Pound (SDG)\n
  • \n \n
  • \n \"SYP\"Syrian Pound (SYP)\n
  • \n \n
  • \n \"ZAR\"South African Rand (ZAR)\n
  • \n \n
  • \n \"KRW\"South Korean Won (KRW)\n
  • \n \n
  • \n \"SSP\"South Sudanese Pound (SSP)\n
  • \n \n
  • \n \"SBD\"Solomon Islands Dollar (SBD)\n
  • \n \n
  • \n \"LKR\"Sri Lankan Rupees (LKR)\n
  • \n \n
  • \n \"SRD\"Surinamese Dollar (SRD)\n
  • \n \n
  • \n \"SZL\"Swazi Lilangeni (SZL)\n
  • \n \n
  • \n \"SEK\"Swedish Kronor (SEK)\n
  • \n \n
  • \n \"CHF\"Swiss Francs (CHF)\n
  • \n \n
  • \n \"TWD\"Taiwan Dollars (TWD)\n
  • \n \n
  • \n \"THB\"Thai baht (THB)\n
  • \n \n
  • \n \"TZS\"Tanzanian Shilling (TZS)\n
  • \n \n
  • \n \"TTD\"Trinidad and Tobago Dollars (TTD)\n
  • \n \n
  • \n \"TND\"Tunisian Dinar (TND)\n
  • \n \n
  • \n \"TRY\"Turkish Lira (TRY)\n
  • \n \n
  • \n \"TMT\"Turkmenistani Manat (TMT)\n
  • \n \n
  • \n \"UGX\"Ugandan Shilling (UGX)\n
  • \n \n
  • \n \"UAH\"Ukrainian Hryvnia (UAH)\n
  • \n \n
  • \n \"AED\"United Arab Emirates Dirham (AED)\n
  • \n \n
  • \n \"UYU\"Uruguayan Pesos (UYU)\n
  • \n \n
  • \n \"UZS\"Uzbekistan som (UZS)\n
  • \n \n
  • \n \"VUV\"Vanuatu Vatu (VUV)\n
  • \n \n
  • \n \"VEF\"Venezuelan Bolivares (VEF)\n
  • \n \n
  • \n \"VND\"Vietnamese đồng (VND)\n
  • \n \n
  • \n \"XOF\"West African CFA franc (XOF)\n
  • \n \n
  • \n \"YER\"Yemeni Rial (YER)\n
  • \n \n
  • \n \"ZMW\"Zambian Kwacha (ZMW)\n
  • \n \n
  • \n \"SHP\"Saint Helena pound\n
  • \n \n
  • \n \"BIF\"Burundian franc\n
  • \n \n
  • \n \"BMD\"Bermudian dollar\n
  • \n \n
  • \n \"CUP\"Cuban peso\n
  • \n \n
  • \n \"DJF\"Djiboutian franc\n
  • \n \n
  • \n \"ERN\"Eritrean nakfa\n
  • \n \n
  • \n \"GNF\"Guinean franc\n
  • \n \n
  • \n \"KPW\"North Korean won\n
  • \n \n
  • \n \"SLL\"Sierra Leonean leone\n
  • \n \n
  • \n \"SOS\"Somali shilling\n
  • \n \n
  • \n \"TJS\"Tajikistani somoni\n
  • \n \n
  • \n \"TOP\"Tongan paʻanga\n
  • \n \n
  • \n \"FKP\"Falkland Islands pound\n
  • \n \n
  • \n \"IQD\"Iraqi Dinar\n
  • \n \n
\n
\n
\n
\n
\n \n \n \n function setSearchUrl(searchValue) { return Promise.resolve({ url: '/search?q=' + searchValue }); }\n\n exportFunction('setSearchUrl', setSearchUrl);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n \n function setSearchUrl(searchValue) { return Promise.resolve({ url: '/search?q=' + searchValue }); }\n\n exportFunction('setSearchUrl', setSearchUrl);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n \n \n \n \n \n\n \n \n \n \n
\n
\n \n \n \n \n \n \n \n\n \n \n \n 0\n \n \n \n \n Cart\n \n \n
\n
\n\n \n \n \n
\n
\n
\n\n \n\n\n\n\n \n\n\n\n
\n \n \n \n \n
\n\n
\n\n \n \n \n
\n \n function setSearchUrl(searchValue) { return Promise.resolve({ url: '/search?q=' + searchValue }); }\n\n exportFunction('setSearchUrl', setSearchUrl);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n
\n\n \n\n \n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n\n\n \n \n \n\n \n\n\n\n \n
\n\n\n
\n \n\n \n\n\n\n
\n\n\n
\n\n
\n
\n
\n \n\n\n\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n
\"\"\"\"
\"\"\"\"
\"\"\"\"
\"\"\"\"
\n\n \n \n\n \n \n
\n \n \n
\n \n\n\n \n\n \n \n \n
\n\n\n\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n \n \n\n \n
\n
\n \n \n \n\n\n\n \n \n\n\n \n\n \n \n\n \n \n \n \n\n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n \n \n
\n
\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n \n \n
\n \n \n \n
\n \n \n \n\n \n
\n
\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n
\n
\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n
\n \n \n \n
\n \n \n \n\n \n
\n
\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n
\n
\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n \n
\n \n \n \n
\n \n \n \n\n \n
\n
\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n\n\n\n\n\n \n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n\n\n\n\n\n \n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n\n\n\n\n\n \n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n\n\n\n\n\n \n\n\n\n\n \n\n\n\n\n\n\n\n \n \n
\n
\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n\n\n\n\n\n \n\n\n\n\n \n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n\n\n\n\n\n \n\n\n\n\n \n\n\n\n\n\n\n\n \n \n
\n \n \n \n
\n \n
\n
\n\n\n\n
\n
\n\n
\n
\n\n
\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n \n \n \n \n \n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n
\n
\n
\n \n \n \"\"\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n
\n
\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n
\n
\n
\n \n
\n \n \n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n
\n
\n\n\n
\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n \n \n \n \n \n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n
\n
\n
\n \n \n \"\"\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n
\n
\n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n \n
\n
\n
\n \n
\n \n \n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
\n \n \n \n
\n \n
\n
\n\n\n
\n\n\n\n
\n\n\n\n\n\n\n
\n \n \n
You May Also Like
  • Comstylish Birds Boho Embroidery Art Print Sweatshirt
  • Comstylish Whisper Words Of Wisdom Let It Be Print T-Shirt
  • Comstylish Santa Claus Print Crew Neck Casual Sweatshirt
  • Comstylish Elegant Lace Embroidery Art Long Sleeve Midi Dress
  • Colorful Spring Cats Pattern Cozy Hooded Cardigan
  • Comstylish Fuzzy Golden Doodle Dog Felt Cozy Knit Sweater
  • Comstylish Vintage Dandelion Crystal Necklace
  • Comstylish Cherry Blossom Japanese Flowy Midi Dress
  • Comstylish 3/4 Sleeve Round Neck Cotton and Linen T-Shirt
  • Comstylish Floral Print Loose Casual Pants
  • Comstylish Turtle Sea Print V Neck Short Sleeve T-Shirt
  • Comstylish Women's Dragonfly Print Casual Shirt
  • Comstylish Vintage Stripe Pattern Women's Linen Dress
  • Comstylish Wild Flowers Oil Painting Art Cozy Knit Hooded Cardigan
  • Comstylish Striped Crew Neck Tank Midi Dress
  • Comstylish Viking Tribal Celtic Knot Art Lace Linen Tank Dress
  • Comstylish Creative Cat Piercing Stud Earrings
  • Comstylish Elegant Violet Wildflower Embroidery Art Comfy T Shirt
  • Comstylish Flying Bees Embroidery Pattern Cozy Knit Sweater
  • Comstylish Funny Farm Chicken Embroidery Pattern Linen Blend Dress
  • Comstylish Casual Loose Colorful Sweater Cardigan
  • Comstylish Japanese Art Flower Print Short Sleeve Loose Midi Dress
  • Comstylish Vintage Pockets Comfy Cotton Linen Pants
  • Comstylish St. Patrick's Day Shamrock Print Sweatshirt
  • Comstylish Vintage Witch Skull Rib Cage Rose Pattern Maxi Dress
  • Comstylish Women's Pastoral Floral Art Print Casual Cotton Linen Shirt
  • Comstylish Dog Art Print Casual Short Sleeve T-Shirt
  • Comstylish Japanese Traditional Sashiko Art Cropped Casual Pants
  • Comstylish Retro Striped Pocket Casual Cotton And Linen Round Neck Long Dress
  • Comstylish Women's Christmas Colorful Christmas Tree Print Casual Sweatshirt
  • Comstylish Funny Alpaca Print Casual Sweatshirt
  • Comstylish Women's Salem Broom Co Quality Handcrafted Enchanted Est 1692 Printed Round Neck Long Sleeve Sweatshirt
  • Comstylish Women's Vintage Pink Rose Embroidery Art Round Neck Long Sleeve Linen Blend T-shirt
  • Comstylish Solid Color Linen Blend Button Casual Shirt
  • Comstylish Vintage Floral Embroidered Lace Hem Linen Blend Maxi Dress
  • Comstylish Vintage Western Floral Tassels Cowgirl Blouse
  • Comstylish Japanese Art Octopus Graphic Printed Casual Pants
  • Comstylish Women's Retro Floral Print Cotton and Linen Dress
  • Comstylish Women's Halloween Skeleton And Rose V-neck Dress
  • Comstylish Vintage Floral Print V-Neck Long Sleeved Blouse
  • Japanese Art Painting Pattern Cozy Flowy Tunic
  • Comstylish Hippie Guitar Lake Whisper Words Of Wisdom Let It Be Print Sweatshirt
  • Comstylish Women's Halloween Skull Flowers Moss Witch Midi Dress
  • Comstylish Women Japanese Art Plum Blossom Linen Blend Long Sleeve Maxi Dress
  • Comstylish Women's Flower And Bird Embroidery Art Linen V-neck Shirt
  • Comstylish Comstylish Vintage Boho Lavender Art Linen Patchwork Art Linen Tank Dress
  • Comstylish Vintage Stripes Printed Cotton Linen Cozy Pants
  • Comstylish Fuzzy Dog Plush Patchwork Knit Sweater
  • Comstylish Women's 1692 They Missed One Salem Witch Printed Round Neck Long Sleeve Sweatshirt
  • Comstylish Fashion Fleece Windproof Ear Protection Warm Hat
  • Comstylish Vintage Fairman Island Knit Jacquard Crew Neck Sweater
  • Comstylish Vintage Viking Tribal Celtic Knot Art Linen V-neck Maxi Dress
  • Comstylish Japanese Art Crane Print V-Neck Loose Blouse
  • Comstylish Women's Vintage Geometric Line Art Print Cotton Dress
  • Comstylish Women's Pockets Design Linen Blend Elastic Waist Pants
  • Comstylish Vintage Canned Pickles Printed Sweatshirt
  • Comstylish Christmas Santa Claus Jewel Art Cozy Knit Sweater
  • Comstylish Women's Watercolor Dragonfly Print Casual Pants
  • Comstylish Retro Bohemian Floral Embroidery Art Graphics Cotton And Linen Blend Loose Blouse
  • Comstylish Vintage Bohemian Resort Floral Spring Midi Dress
  • Comstylish Women's Halloween Rose Spider Web Witch Cosplay Midi Dress
  • Comstylish Geometric Print V-Neck Casual Loose Midi Dress
  • Comstylish Women's Floral Embroidered Art V-neck Short Sleeved Linen Blend T-shirt
  • Comstylish Women's Retro Floral Print Dress
  • Comstylish Women's Simple Linen Blend Elastic Waist Casual Pants
  • Comstylish Vintage Floral Art Cotton Linen Comfy Shirt
  • Comstylish Cute Bunny Embroidery Art Cozy Knit Sweater
  • Comstylish Cute Dog Print Short Sleeve T-Shirt
  • Comstylish Roosters Embroidery Pattern Cozy Knit Sweater
  • Comstylish Vintage Japanese Art Flower Print V-Neck Loose Blouse
  • Comstylish Vintage Faith Carving Dandelion Earrings
  • Comstylish Men's Broken Crayons Still Color Print Short Sleeve T-Shirt
  • Comstylish Japanese Flower And Bird Painting Art Print Long Sleeved Tunic
  • Comstylish Women's Mother's Day Boy Mama Mommy Mom Bruh. Print T-Shirt
  • Comstylish Border Collie & Sheep Landscape Felt Art Cozy Sweater
  • Comstylish Vintage crew neck casual linen T-shirt
  • Comstylish Winter Funny Cute Wonderland Clothing Floral Cat Printed Casual Sweatshirt
  • Comstylish Elegant Christmas Tree Jewel Art Cozy Knit Sweater
  • Comstylish Women's Casual Funny Black Cat Print Sweatshirt
  • Comstylish Underwater World Print V-Neck Casual Midi Dress
  • Comstylish Japanese Plum Blossom Art Long Sleeved Loose Midi Dress
  • Comstylish Japanese Cherry Blossoms Art Linen Blend Maxi Dress
  • Comstylish Women's Solid Color Cotton Linen Print Maxi Dress
  • Comstylish Women's Floral And Bird Embroidery Art Pattern Cotton And Linen V-neck Shirt
  • Comstylish Pansy Floral Embroidery Pattern Cozy Hooded Cardigan
  • Comstylish Casual Hooded Sweater Coat
  • Comstylish Christmas Tree Print Round Neck Long Sleeve Sweatshirt
  • Comstylish Heart Print Casual Long Sleeve T-Shirt
  • Comstylish Mountains Inspired Moonstone Studded Ring
  • Comstylish Vintage Japanese Art Flower Print Casual Midi Dress
  • Comstylish Wildflowers Oil Painting Art Cozy Knit Cardigan
  • Comstylish Bohemian Heart Double Chain Anklet
  • Comstylish Vintage Star And Sun Embroidery Cotton Linen V Neck Mixi Dress
  • Comstylish Bohemian Shell Clay Bracelet
  • Comstylish Casual Multi-layer Design Linen Dress
  • Comstylish Japanese Art Cherry Blossom Print Short Sleeve Loose Midi Dress
  • Comstylish Cherry Blossom Japanese Lino Art Vintage Hoodie
  • Comstylish Vintage Tribal Icelandic Knit Pullover Sweater
  • Comstylish Halloween Gothic Dark Party Ruffled Witch Hat
  • Comstylish Elegant Japanese Art Floral Print Lace-up Casual Midi Dress
\n\n \n \n \n\n \n\n
\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n \n const isSpecialHeroTheme = window.SHOPLAZZA?.theme?.merchant_theme_name == 'Hero' && window.SHOPLAZZA?.theme?.merchant_theme_c_version == '2.2.19';\n const specialHeroThemeClassName = 'hero_2_2_19_smart_recommend_block';\n class SpzSmartBlockComponent extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n this.templates_ = null;\n this.container_ = null;\n this.i18n_ = {};\n this.config_ = {};\n this.show_type_ = 3;\n this.product_resource_id_ = '';\n this.collection_resource_id_ = '';\n this.cart_items_ = [];\n this.customer_id_ = '';\n this.order_id_ = '';\n }\n\n static deferredMount() {\n return false;\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n\n buildCallback() {\n const template_type = window.C_SETTINGS.meta.page.template_type;\n if (template_type === 1) {\n this.show_type_ = 3;\n this.product_resource_id_ = window.C_SETTINGS.meta.page.resource_id;\n } else if (template_type === 2) {\n this.show_type_ = 4;\n this.collection_resource_id_ = window.C_SETTINGS.meta.page.resource_id;\n } else if (template_type === 15){\n this.show_type_ = 5;\n } else if (template_type === 13){\n this.show_type_ = 6;\n } else if (template_type === 20){\n this.show_type_ = 7;\n this.customer_id_ = window.C_SETTINGS.customer.customer_id;\n } else if (template_type === 35){\n this.show_type_ = 8;\n this.order_id_ = window.location.pathname.split('/').pop();\n }\n this.templates_ = SPZServices.templatesForDoc(this.element);\n this.setAction_();\n }\n\n mountCallback() {\n const that = this;\n const themeName = window.C_SETTINGS.theme.merchant_theme_name;\n const isGeek = /Geek/.test(themeName);\n this.fetchRules().then((res) => {\n if (res && res.rules && res.rules.length) {\n const blockEl = document.getElementById('smart_recommend_block');\n this.initBlockClass(blockEl);\n this.initItemClass(blockEl);\n SPZ.whenApiDefined(blockEl).then((api) => {\n api.render({data: res}, true).then(() => {\n if (isGeek && that.show_type_ === 6) {\n blockEl.querySelector('.plugin_container_wrpper').style.padding = '30px 0';\n }\n const recommendStyle = document.createElement('style');\n recommendStyle.innerHTML = `\n .plugin__recommend_container,.app-recommend-card {\n display: none !important;\n }\n `;\n document.head.appendChild(recommendStyle);\n const fetchList = [];\n res.rules.forEach((rule) => {\n fetchList.push(this.fetchRuleProductList(rule.id));\n });\n const fetchAll = Promise.all(fetchList);\n fetchAll.then((p_res) => {\n res.rules.forEach((rule, index) => {\n rule.products = p_res[index] && p_res[index].products;\n\n if (rule.products && rule.products.length) {\n const modalRender = document.getElementById('smart_recommend_js_root');\n const $dest = document.getElementById('cart');\n const isLifeStyle = /Life.*Style/.test(window.C_SETTINGS.theme.merchant_theme_name);\n if (modalRender && isLifeStyle && $dest.clientWidth > 767) {\n modalRender.classList.add('zb-mt-[-180px]')\n }\n }\n const ruleEl = document.getElementById('smart_recommend_rule_' + rule.id);\n SPZ.whenApiDefined(ruleEl).then((api) => {\n api.render({data: rule}, true).then(() => {\n that.impressListen(`#smart_recommend_rule_ul_${rule.id}`, function(){\n that.trackRuleImpress(rule);\n });\n const btnElList = document.querySelectorAll(`#smart_recommend_rule_ul_${rule.id} button`);\n btnElList.forEach((btnEl) => {\n if (btnEl && rule.config && rule.config.quick_shop_button_bg_color && rule.config.quick_shop_button_text_color) {\n btnEl.style.backgroundColor = rule.config.quick_shop_button_bg_color;\n btnEl.style.color = rule.config.quick_shop_button_text_color;\n }\n })\n if (isSpecialHeroTheme) {\n ruleEl.querySelectorAll(`.smart_recommend_title`).forEach(dom=>{\n dom.classList.add('type-title-font-family');\n });\n document.querySelectorAll(`.${specialHeroThemeClassName} #smart_recommend_rule_ul_${rule.id} .zb-recommend-price-line-through .money`).forEach(dom=>{\n dom.classList.add('type-body-font-family');\n });\n }\n });\n });\n });\n });\n })\n })\n } else {\n if (window.top !== window.self) {\n const template_type = window.C_SETTINGS.meta.page.template_type;\n const holderEl = document.getElementById('smart_recommend_preview_no_data_placeholder');\n SPZ.whenApiDefined(holderEl).then((api) => {\n api.render({data: { isCart: template_type === 13, isCollection: template_type === 2, isProduct: template_type === 1, isIndex: template_type === 15 }}, true);\n });\n }\n }\n });\n }\n \n initBlockClass(blockEl) {\n if (!blockEl) return;\n if (blockEl.parentElement && blockEl.parentElement.offsetWidth === document.body.clientWidth) {\n blockEl.classList.add('smart_recommend_block_fullscreen');\n }\n if (isSpecialHeroTheme) {\n blockEl.classList.add(specialHeroThemeClassName);\n }\n }\n\n initItemClass(blockEl) {\n if (blockEl) {\n const containerWidth = blockEl.offsetWidth;\n let itemWidth = '';\n if (containerWidth > 780) {\n itemWidth = '16%';\n } else if (containerWidth > 600) {\n itemWidth = '20%';\n } else {\n itemWidth = '24%';\n }\n const itemStyleEl = document.createElement('style');\n itemStyleEl.innerHTML = `.zb-recommend-li-item{ width: ${itemWidth}; }`;\n document.body.appendChild(itemStyleEl);\n }\n }\n\n setAction_() {\n this.registerAction('quickShop', (data) => {\n const that = this;\n const product_id = data.args.product_id;\n const productIndex = data.args.productIndex;\n const rule_id = data.args.rule_id;\n const ssp = data.args.ssp;\n const scm = data.args.scm;\n const cfb = data.args.cfb;\n const ifb = data.args.ifb;\n const modalRender = document.getElementById('smart_recommend_product_modal_render');\n if (modalRender) {\n document.body.appendChild(modalRender);\n }\n if (product_id) {\n this.fetchProductData(product_id).then((res) => {\n const product = res.products && res.products.length && res.products[0] || {};\n product.cfb = cfb;\n product.ifb = ifb;\n SPZ.whenApiDefined(modalRender).then((api) => {\n api.render({product: product, productIndex: productIndex, rule_id: rule_id, ssp: ssp, scm: scm, show_type: that.show_type_}, true).then(() => {\n const modalEl = document.getElementById('smart_recommend_product_modal');\n SPZ.whenApiDefined(modalEl).then((modal) => {\n that.impressListen('#smart_recommend_product_modal', function(){\n that.trackQuickShop({ rule_id: rule_id, product_id: product_id });\n });\n modal.open();\n });\n const formEl = document.getElementById('smart_recommend_product_form');\n SPZ.whenApiDefined(formEl).then((form) => {\n form.setProduct(product);\n });\n const variantEl = document.getElementById('smart_recommend_product_variants');\n SPZ.whenApiDefined(variantEl).then((variant) => {\n variant.handleRender(product);\n });\n });\n })\n });\n }\n });\n this.registerAction('handleScroll', (data) => {\n this.directTo(data.args.rule_id, data.args.direction);\n });\n this.registerAction('handleProductChange', (data) => {\n const variant = data.args.data.variant;\n const product = data.args.data.product;\n const imageRenderEl = document.getElementById('smart_recommend_product_image');\n SPZ.whenApiDefined(imageRenderEl).then((api) => {\n api.render({ variant: variant, product: product });\n });\n });\n this.registerAction('handleAtcSuccess', (detail) => {\n const data = detail.args;\n data.data.product = data.data.product || {};\n data.data.variant = data.data.variant || {};\n const product_id = data.data.product.id;\n const product_title = data.data.product.title;\n const variant_id = data.data.variant.id;\n const price = data.data.variant.price;\n const rule_id = data.rule_id;\n const aid = `smart_recommend.${this.show_type_}.${rule_id}`;\n const ifb = data.data.product.ifb;\n const cfb = data.data.product.cfb;\n const ssp = data.ssp;\n const scm = data.scm;\n const spm = `smart_recommend_${this.show_type_}.${data.spmIndex}`;\n const params = {\n id: product_id,\n product_id: product_id,\n number: 1,\n name: product_title,\n variant_id: variant_id,\n childrenId: variant_id,\n item_price: price,\n source: 'add_to_cart',\n _extra: {\n aid: aid,\n ifb: ifb,\n cfb: cfb,\n scm: scm,\n spm: `..${window.C_SETTINGS.meta.page.template_name}.${spm}`,\n ssp: ssp,\n }\n };\n this.tranckAddToCart(params);\n });\n this.registerAction('addATCHook', (data) => {\n const params = data.args;\n const spm = `smart_recommend_${this.show_type_}.${params.spmIndex}`;\n this.myInterceptor_ = window.djInterceptors && window.djInterceptors.track.use({\n event: 'dj.addToCart',\n params: {\n aid: `smart_recommend.${this.show_type_}.` + params.rule_id,\n ssp: params.ssp,\n scm: params.scm,\n cfb: params.cfb,\n spm: `..${window.C_SETTINGS.meta.page.template_name}.${spm}`,\n },\n once: true\n });\n });\n }\n\n tranckAddToCart(detail) {\n if (window.$) {\n window.$(document.body).trigger('dj.addToCart', detail);\n }\n }\n\n fetchRules() {\n const payload = {\n show_type: this.show_type_,\n };\n let that = this;\n if (this.show_type_ === 6) {\n let line_items = [];\n return this.fetchCart().then((res) => {\n if (res && res.cart && res.cart.line_items) {\n line_items = res.cart.line_items.map((item) => {\n return { product_id: item.product_id, variant_id: item.variant_id, quantity: item.quantity, price: item.price }\n });\n }\n payload.line_items = line_items;\n that.cart_items_ = line_items;\n return that.fetchRulesRequest(payload);\n });\n } else {\n if (this.show_type_ === 3) {\n payload.line_items = [{ product_id: this.product_resource_id_ }];\n } else if (this.show_type_ === 4) {\n payload.collection_id = this.collection_resource_id_;\n } else if (this.show_type_ === 7) {\n payload.customer_id = this.customer_id_;\n } else if (this.show_type_ === 8) {\n payload.order_id = this.order_id_;\n }\n return this.fetchRulesRequest(payload);\n }\n }\n\n fetchRulesRequest(payload) {\n return fetch(window.C_SETTINGS.routes.root + \"/api/possum/recommend_query\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(payload)\n }).then(function(res){\n if(res.ok){\n return res.json();\n }\n });\n }\n\n fetchCart() {\n return fetch(`/api/cart/cart-select?r=${Math.random().toString(36).slice(-4)}`)\n .then((res) => {\n if (res.ok) {\n return res.json();\n }\n });\n }\n\n fetchRuleProductList(rule_id) {\n const payload = {\n page: 1,\n limit: 100,\n fields: [\"title\", \"url\", \"image\", \"min_price_variant.price\", \"min_price_variant.compare_at_price\"],\n rule_id: rule_id,\n };\n if (this.show_type_ === 3) {\n payload.line_items = [{ product_id: this.product_resource_id_ }];\n } else if (this.show_type_ === 4) {\n payload.collection_id = this.collection_resource_id_;\n } else if (this.show_type_ === 6) {\n payload.line_items = this.cart_items_;\n } else if (this.show_type_ === 7) {\n payload.customer_id = this.customer_id_;\n } else if (this.show_type_ === 8) {\n payload.order_id = this.order_id_;\n }\n return fetch(window.C_SETTINGS.routes.root + \"/api/possum/recommend_products\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(payload)\n }).then(function(res){\n if(res.ok){\n return res.json();\n }\n }).catch(function(err){\n console.log(err);\n });\n }\n\n fetchProductData(product_id) {\n return fetch(window.C_SETTINGS.routes.root + \"/api/possum/products\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify({\n product_ids: [product_id],\n fields: [ \"images\", \"options\", \"min_price_variant\", \"variants\"]\n })\n }).then(function(res){\n if(res.ok){\n return res.json();\n }\n }).catch(function(err){\n console.log(err);\n const loadingEl = document.getElementById('smart_recommend_loading');\n if (loadingEl) {\n loadingEl.style.display = 'none';\n }\n });\n }\n\n getStyle(ele, style) {\n if (!ele) return;\n if (window.getComputedStyle) {\n return window.getComputedStyle(ele)[style];\n }\n return ele.currentStyle[style];\n }\n\n directTo(id, direction) {\n const scrollElement = document.getElementById(`smart_recommend_rule_ul_${id}`);\n const blockWidth = parseInt(this.getStyle(scrollElement, 'width'));\n const scrollLength = (blockWidth * 0.19 - 12) * 5;\n const scrollPoint = scrollElement.scrollWidth - scrollElement.clientWidth;\n if (!scrollElement) return;\n if (direction === 'left') {\n if (document.dir === 'rtl') {\n scrollElement.scrollTo({\n left: Math.abs(scrollElement.scrollLeft) >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft - scrollLength,\n behavior: 'smooth'\n });\n return;\n }\n scrollElement.scrollTo({\n left: Math.max(scrollElement.scrollLeft - scrollLength, 0),\n behavior: 'smooth'\n });\n } else {\n if (document.dir === 'rtl') {\n scrollElement.scrollTo({\n left: Math.abs(scrollElement.scrollLeft) >= scrollPoint + 100 ? 0 : scrollElement.scrollLeft + scrollLength,\n behavior: 'smooth'\n });\n return;\n }\n scrollElement.scrollTo({\n left: scrollElement.scrollLeft >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft + scrollLength,\n behavior: 'smooth'\n });\n }\n }\n\n trackRuleImpress(rule) {\n if (window.sa && window.sa.track) {\n window.sa.track(\"plugin_common\", {\n plugin_name: \"upsell\",\n event_type: \"impressions\",\n rule_id: rule.id,\n ssp: rule.ssp,\n scm: rule.scm,\n show_type: this.show_type_,\n support_app_block: window.C_SETTINGS.theme.support_app_block\n });\n window.sa.track(\"module_impressions\", {\n aid: `smart_recommend.${this.show_type_}.${rule.id}`,\n support_app_block: window.C_SETTINGS.theme.support_app_block\n });\n }\n }\n\n trackQuickShop(data) {\n window.sa && sa.track && sa.track(\"plugin_common\", {\n plugin_name: \"upsell\",\n event_type: \"quick_shop\",\n rule_id: data.rule_id,\n product_id: data.product_id,\n show_type: this.show_type_,\n });\n }\n\n impressListen(selector, cb) {\n const el = document.querySelector(selector);\n const onImpress = (e) => {\n if (e) {\n e.stopPropagation();\n }\n cb();\n };\n if (el && !el.getAttribute('imprsd')) {\n el.addEventListener('impress', onImpress)\n } else if (el) {\n onImpress();\n }\n }\n }\n SPZ.defineElement('spz-custom-smart-block', SpzSmartBlockComponent);\n\n\n\n\n\n\n
\n\n\n\n\n \n\n\n let section_id = '1709781152049';\n window.reviewSettings = {};\n window.reviewSettings[section_id] = {\n \"sub_title\": \"Subscribe to get special offers, free giveaways, and once-in-a-lifetime deals.\",\n \"star_least\": \"3\",\n \"only_featured\": false,\n \"with_photo\": false,\n \"review_insufficient\": \"no_reviews\",\n \"minimum_comment_num\": 5,\n \"fill_strategy\": \"hide\",\n \"layout\": \"grid\",\n \"image_size\": \"natural\",\n \"wall_mobile_num\": 2,\n \"wall_pc_num\": 4,\n \"limit\": 8,\n \"show_product\": true,\n \"hide_review_section\": true,\n \"title\": \"Customer Reviews\",\n \"accent_color\": null,\n \"color_title\": \"#000000\",\n \"text_color\": \"#000000\",\n \"card_wrap_color\": null,\n \"background_color\": \"#ffffff\"\n };\n\n\n\n\n
\n
\n\n\n const TAG = 'spz-custom-revue-util';\n const DEFAULT_DELAY_TIME = 100;\n\n class SpzCustomRevueUtil extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n this.templates_ = SPZServices.templatesForDoc();\n }\n buildCallback = () => {\n this.action_ = SPZServices.actionServiceForDoc(this.element);\n this.templates_ = SPZServices.templatesForDoc(this.element);\n this.xhr_ = SPZServices.xhrFor(this.win);\n }\n\n static deferredMount() {\n return false;\n }\n mountCallback() {\n }\n\n debounceRender(el, thisEl, containerStr) {\n return this.smoothRender_(el, thisEl, containerStr).then(() => this.attemptToFit_(thisEl));\n }\n \n smoothRender_(newEl, thisEl, containerStr) {\n const that = this;\n that.appendAsUnvisibleContainer_(newEl, thisEl);\n const components = newEl.querySelectorAll('[layout]');\n return Promise.race([\n Promise.all(\n Array.prototype.map.call(components, (e) =>\n SPZ.whenDefined(e).then(() => e.whenBuilt())\n )\n ),\n SPZServices.timerFor(that.win).promise(DEFAULT_DELAY_TIME),\n ]).then(() => {\n return containerStr !== 'form_' ? thisEl.mutateElement(() => that.quickReplace(thisEl, newEl)) : thisEl.mutateElement(() => that.quickReplaceForm(thisEl, newEl));\n });\n }\n\n quickReplace(thisEl, newEl) {\n thisEl.container_ && this.toggleVisible_(thisEl.container_);\n this.toggleVisible_(newEl, true);\n thisEl.container_ && SPZCore.Dom.removeElement(thisEl.container_);\n thisEl.container_ = newEl;\n };\n\n quickReplaceForm(thisEl, newEl) {\n thisEl.form_ && this.toggleVisible_(thisEl.form_);\n this.toggleVisible_(newEl, true);\n const children = thisEl.form_.querySelector('*:not(template)');\n children && SPZCore.Dom.removeElement(children);\n this.toggleVisible_(thisEl.form_, true);\n thisEl.form_.appendChild(newEl);\n };\n \n appendAsUnvisibleContainer_(el, thisEl) {\n this.toggleVisible_(el);\n thisEl.element.appendChild(el);\n }\n \n attemptToFit_(thisEl) {\n const fitFunc = () => {\n thisEl.mutateElement(this.setElementHeight_.bind(thisEl));\n };\n const container = thisEl.container_ || thisEl.form_;\n if (container) {\n const children = container.querySelectorAll('*:not(template)');\n const spzChildren = Array.prototype.filter\n .call(children, SPZUtils.isSpzElement)\n .filter((e) => !(e.isMount && e.isMount()));\n spzChildren\n .map((e) => SPZ.whenDefined(e).then(() => e.whenMounted()))\n .forEach((p) => p.then(() => fitFunc()));\n }\n return fitFunc();\n }\n \n setElementHeight_() {\n const targetHeight = (this.container_ || this.form_)?./*OK*/ scrollHeight;\n const height = this.element./*OK*/ offsetHeight;\n if (height !== targetHeight) {\n SPZCore.Dom.setStyles(this.element, {\n height: `${targetHeight}px`,\n });\n }\n }\n \n toggleVisible_(el, visible = false) {\n if (!visible) {\n el.classList.add('i-spzhtml-layout-fill');\n SPZCore.Dom.setStyles(el, {\n 'z-index': -100000,\n 'opacity': 0,\n });\n } else {\n el.classList.remove('i-spzhtml-layout-fill');\n SPZCore.Dom.setStyles(el, {\n 'z-index': 'auto',\n 'opacity': 1,\n });\n }\n }\n \n setMinWidth_() {\n const targetWidth = this.container_?./*OK*/ scrollWidth;\n const width = this.element./*OK*/ offsetWidth;\n if (width !== targetWidth) {\n SPZCore.Dom.setStyles(this.element, {\n 'min-width': `${targetWidth}px`,\n });\n }\n }\n\n triggerEvent_ = (name, data) => {\n const event = SPZUtils.Event.create(this.win, `${TAG}.${name}`, data || {});\n this.action_.trigger(this.element, name, event);\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n\n }\n SPZ.defineElement(TAG, SpzCustomRevueUtil);\n\n\n const TAG = 'spz-custom-revue-render';\n class SPZCustomRevueRender extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n }\n\n static deferredMount() {\n return false;\n }\n\n buildCallback = () => {\n this.action_ = SPZServices.actionServiceForDoc(this.element);\n this.templates_ = SPZServices.templatesForDoc(this.element);\n this.xhr_ = SPZServices.xhrFor(this.win);\n }\n\n mountCallback = () => {}\n\n render = (data) => {\n return this.templates_\n .findAndRenderTemplate(this.element, data, null)\n .then((el) => {\n if (this.element.children.length > 0) {\n this.element.children[0].style.display = 'none';\n }\n this.element.appendChild(el);\n // const utilsEl = document.getElementById('spz_custom_revue_util');\n // utilsEl && SPZ.whenApiDefined(utilsEl).then((api) => {\n // api.debounceRender(el, this);\n // });\n });\n }\n\n triggerEvent_(name, data) {\n const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});\n this.action_.trigger(this.element, name, event);\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n }\n SPZ.defineElement(TAG, SPZCustomRevueRender)\n\n\n\n\n\n\n\n\n\n\n const TAG = 'spz-custom-revue-star';\n class SPZCustomRevueStar extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n }\n\n static deferredMount() {\n return false;\n }\n\n buildCallback = () => {\n this.action_ = SPZServices.actionServiceForDoc(this.element);\n this.templates_ = SPZServices.templatesForDoc(this.element);\n this.xhr_ = SPZServices.xhrFor(this.win);\n this.starNum = this.element.getAttribute('starNum');\n this.starTotal = this.element.getAttribute('starTotal');\n this.showStarText = this.element.getAttribute('showStarText');\n this.starColor = this.element.getAttribute('color');\n this.interact = this.element.getAttribute('interact');\n this.starSize = this.element.getAttribute('starSize') || 14;\n }\n\n mountCallback = () => {\n this.doRender_({\n starTotal: this.starTotal,\n totalArray: Array.from({ length: Number(this.starTotal) }, (v, k) => k + 1),\n starNum: this.starNum,\n showStarText: this.showStarText,\n starColor: this.starColor,\n starSize: this.starSize\n }).then(() => {\n if (this.interact) {\n this.addEventListeners_();\n }\n });\n }\n\n addEventListeners_ = () => {\n \n const stars = document.querySelectorAll('.revue-star__star');\n\n \n stars.forEach(star => {\n star.addEventListener('click', event => {\n const starEl = star.closest('.revue-star__star');\n const starIndex = Number(starEl.dataset.index);\n let isHalf = event.offsetX < star.offsetWidth / 2;\n // rtl\n if (document.documentElement.getAttribute('dir') === 'rtl') {\n isHalf = event.offsetX > star.offsetWidth / 2;\n }\n const starValue = isHalf ? starIndex - 0.5 : starIndex;\n this.starClickHandler_({ value: starValue });\n });\n });\n\n }\n\n renderStar = () => {\n \n\n const isRtl = document.documentElement.getAttribute('dir') === 'rtl';\n const stars = this.element.querySelectorAll('.revue-star__star');\n stars.forEach((star, i) => {\n const starIndex = i + 1;\n const starEl = star.querySelector('svg:nth-child(2)');\n const isHalf = this.starNum % 1 > 0 && Math.ceil(this.starNum) === starIndex;\n const isSolid = starIndex <= Math.ceil(this.starNum);\n starEl.style.display = isSolid ? 'block' : 'none';\n if (isHalf) {\n if (isRtl) {\n // RTL布局下,如果是半星,显示星星的右半边\n starEl.style.clipPath = `polygon(50% 0, 100% 0, 100% 100%, 50% 100%)`;\n } else {\n // LTR布局下,如果是半星,显示星星的左半边\n starEl.style.clipPath = `polygon(0 0, 50% 0, 50% 100%, 0 100%)`;\n }\n } else {\n starEl.style.clipPath = `polygon(0 0, 100% 0, 100% 100%, 0 100%)`\n }\n });\n\n const showCountEle = this.element.querySelector('#revue-star-show-count');\n showCountEle && SPZ.whenApiDefined(showCountEle).then((api) => {\n api.render({ starNum: this.starNum, starTotal: this.starTotal });\n });\n }\n\n doRender_ = (data) => {\n return this.templates_\n .findAndRenderTemplate(this.element, { starSize: this.starSize, ...data }, null)\n .then((el) => {\n const children = this.element.querySelector('*:not(template)');\n children && SPZCore.Dom.removeElement(children);\n this.element.appendChild(el);\n })\n .then(() => {\n this.starNum = data.starNum;\n this.renderStar();\n\n });\n }\n\n starClickHandler_ = (event) => {\n this.starNum = event.value;\n this.renderStar();\n this.triggerEvent_('change', { value: event.value });\n }\n\n triggerEvent_(name, data) {\n const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});\n this.action_.trigger(this.element, name, event);\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n }\n SPZ.defineElement(TAG, SPZCustomRevueStar)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n const TAG = 'spz-custom-revue-like';\n class SPZCustomRevueLike extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n }\n\n static deferredMount() {\n return false;\n }\n\n buildCallback = () => {\n this.action_ = SPZServices.actionServiceForDoc(this.element);\n this.templates_ = SPZServices.templatesForDoc(this.element);\n this.xhr_ = SPZServices.xhrFor(this.win);\n this.grayColor = this.element.getAttribute('gray_color') || \"#BDBDBD\";\n this.likedColor = this.element.getAttribute('like_color') || \"#FFCB44\";\n this.color = this.grayColor;\n this.count = this.element.getAttribute('count');\n this.revueId = this.element.getAttribute('revue-id');\n this.location = this.element.getAttribute('location');\n }\n\n mountCallback = () => {\n const likes = sessionStorage.getItem('likes') ? JSON.parse(sessionStorage.getItem('likes')) : [];\n const like = likes.find(item => item.id === this.revueId);\n if (like) {\n this.color = like.like_status === 1 ? this.likedColor : this.grayColor;\n }\n // 如果location是modal,则找到相同revue-id的list的元素,拿到其count,存在list count变了,但是modal的count没变的情况\n if (this.location === 'modal') {\n const listElement = document.querySelector(`spz-custom-revue-like[revue-id=\"${this.revueId}\"] .revue-like-count`);\n if (listElement) {\n this.count = listElement.getAttribute('data-real-count');\n }\n }\n this.doRender_({\n color: this.color,\n count: this.count\n }).then(() => {\n this.addEventListeners_();\n if(this.location === 'list') { // modal数量变更,list同步变更\n document.addEventListener('like-clicked', (e) => {\n if (e.detail.location !== this.location && e.detail.id === this.revueId) {\n this.color = e.detail.like_status === 1 ? this.likedColor : this.grayColor;\n this.count = e.detail.count;\n this.element.querySelector('.revue-like__icon').querySelector('svg').setAttribute('fill', this.color);\n this.element.querySelector('.revue-like__icon').querySelector('svg').querySelector('path').setAttribute('fill', this.color);\n this.element.querySelector('.revue-like-count').innerText = this.count > 99 ? '99+' : this.count < 1 ? '' : this.count;\n this.element.querySelector('.revue-like-count').setAttribute('data-real-count', this.count);\n if(this.count > 0){\n this.element.querySelector('.revue-like-count').classList.remove('hidden');\n }else{\n this.element.querySelector('.revue-like-count').classList.add('hidden');\n }\n }\n });\n }\n });\n }\n\n addEventListeners_ = () => {\n const icon = this.element.querySelector('.revue-like__icon');\n icon.addEventListener('click', (e) => {\n e.stopPropagation();\n const likeStatus = this.color === this.likedColor ? 0 : 1;\n this.color = this.color === this.likedColor ? this.grayColor : this.likedColor;\n this.count = likeStatus === 1 ? parseInt(this.count) + 1 : parseInt(this.count) - 1;\n icon.querySelector('svg').setAttribute('fill', this.color);\n icon.querySelector('svg').querySelector('path').setAttribute('fill', this.color);\n this.element.querySelector('.revue-like-count').innerText = this.count > 99 ? '99+' : this.count < 1 ? '' : this.count;\n this.element.querySelector('.revue-like-count').setAttribute('data-real-count', this.count);\n if(this.count > 0){\n this.element.querySelector('.revue-like-count').classList.remove('hidden');\n }else{\n this.element.querySelector('.revue-like-count').classList.add('hidden');\n }\n this.postLike(likeStatus);\n\n if (this.location === 'modal') {\n const clickedEvent = new CustomEvent('like-clicked', {\n detail: {\n id: this.revueId,\n like_status: likeStatus,\n count: this.count,\n location: this.location\n }\n });\n document.dispatchEvent(clickedEvent);\n }\n\n });\n }\n\n setLikeToStorage = (likeToStore) => {\n if (typeof (Storage) !== 'function') return;\n const likesInStore = sessionStorage.getItem('likes') ? JSON.parse(sessionStorage.getItem('likes')) : [];\n const reviewIndex = likesInStore.findIndex(item => item.id === likeToStore.id);\n\n if (reviewIndex !== -1) {\n likesInStore[reviewIndex].like_status = likeToStore.like_status;\n likesInStore[reviewIndex].count = likeToStore.count;\n } else {\n likesInStore.push(likeToStore);\n }\n sessionStorage.setItem('likes', JSON.stringify(likesInStore));\n }\n\n doRender_ = (data) => {\n return this.templates_\n .findAndRenderTemplate(this.element, data, null)\n .then((el) => {\n const children = this.element.querySelector('*:not(template)');\n children && SPZCore.Dom.removeElement(children);\n this.element.appendChild(el);\n });\n }\n\n postLike = (likeStatus) => {\n fetch('/api/comment/like', {\n method: 'POST',\n headers: {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n id: this.revueId,\n status: likeStatus\n })\n }).then((res) => {\n if (res.status === 200) {\n this.setLikeToStorage({\n id: this.revueId,\n like_status: likeStatus,\n count: this.count\n });\n }\n });\n }\n\n triggerEvent_(name, data) {\n const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});\n this.action_.trigger(this.element, name, event);\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n }\n SPZ.defineElement(TAG, SPZCustomRevueLike)\n\n\n\n\n\n\n\n\n\n\n\n\n\n const TAG = 'spz-custom-revue-media';\n class SPZCustomRevueMedia extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n }\n\n static deferredMount() {\n return false;\n }\n\n buildCallback = () => {\n this.action_ = SPZServices.actionServiceForDoc(this.element);\n this.templates_ = SPZServices.templatesForDoc(this.element);\n this.xhr_ = SPZServices.xhrFor(this.win);\n this.imgCover = this.element.getAttribute('img-cover') ?? false;\n this.pc_layout = this.element.getAttribute('pc-layout') ?? '';\n // data-images 格式为 xxxx.png?width=1&height=1,xxxx.png?width=1&height=1\n const images = this.element.getAttribute('data-images').split(',') || [];\n const parsedImages = images.map(image => {\n return this.mediaParse_(image);\n });\n this.images = parsedImages;\n this.isPC = window.innerWidth > 960;\n }\n\n mountCallback = () => {\n this.doRender_({\n images: this.images,\n isPC: this.isPC,\n imgCover: this.imgCover,\n pc_layout: this.pc_layout\n }).then(() => {\n this.addEventListeners_();\n });\n }\n\n addEventListeners_ = () => {\n const images = this.element.querySelectorAll('.revue-image-item');\n images.forEach((image, index) => {\n image.addEventListener('click', () => {\n const carousel = document.querySelector('#revue-image-carousel-render');\n carousel && SPZ.whenApiDefined(carousel).then((api) => {\n \n const width = this.isPC ? 460 : window.innerWidth * 0.9;\n const height = this.isPC ? 630 : 500;\n api.render({ images: this.images, index: index, width: width, height: height });\n });\n });\n });\n }\n\n doRender_ = (data) => {\n return this.templates_\n .findAndRenderTemplate(this.element, data, null)\n .then((el) => {\n const children = this.element.querySelector('*:not(template)');\n children && SPZCore.Dom.removeElement(children);\n this.element.appendChild(el);\n });\n }\n\n mediaParse_ = function (url) {\n var result = {};\n try {\n url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {\n try {\n result[key] = decodeURIComponent(value);\n } catch (e) {\n result[key] = value;\n }\n });\n result.preview_image = url.split('?')[0];\n } catch (e) {};\n return result;\n }\n\n triggerEvent_(name, data) {\n const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});\n this.action_.trigger(this.element, name, event);\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n }\n SPZ.defineElement(TAG, SPZCustomRevueMedia)\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n const TAG = 'spz-custom-revue-sort';\n class SPZCustomRevueSort extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n }\n\n static deferredMount() {\n return false;\n }\n\n triggerEvent_(name, data) {\n const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});\n this.action_.trigger(this.element, name, event);\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n\n buildCallback = () => {\n this.action_ = SPZServices.actionServiceForDoc(this.element);\n this.templates_ = SPZServices.templatesForDoc(this.element);\n this.xhr_ = SPZServices.xhrFor(this.win);\n this.isPC = window.innerWidth > 960;\n this.width = this.isPC ? `${this.element.getAttribute('width') || 150}px` : '100%';\n this.randomStr = Math.random().toString(36).substr(2);\n this.sectionId = this.element.getAttribute('section-id') || '1709781152049';\n this.prefix = this.element.getAttribute('prefix');\n }\n\n mountCallback = () => {\n const data = {\n width: this.width,\n randomStr: this.randomStr\n };\n this.doRender_(data).then(() => {\n let revueSortListRender = this.isPC ? this.element.querySelector(`#${this.prefix}-revue-sort-list-render-${this.sectionId}`) : this.element.querySelector(`#${this.prefix}-revue-sort-dropdown-render-${this.sectionId}`);\n revueSortListRender && SPZ.whenApiDefined(revueSortListRender).then((api) => {\n api.render(data).then(() => {\n if (this.isPC) {\n this.addEventListenersForPC_();\n } else {\n this.addEventListenersForMobile_();\n }\n });\n });\n });\n }\n\n doRender_ = (data) => {\n return this.templates_\n .findAndRenderTemplate(this.element, data, null)\n .then((el) => {\n const children = this.element.querySelector('*:not(template)');\n children && SPZCore.Dom.removeElement(children);\n this.element.appendChild(el);\n });\n }\n\n addEventListenersForPC_ = () => {\n const revueSelectList = this.element.querySelector('.revue_select_list');\n const revueSelectItem = this.element.querySelectorAll('.revue_select_item');\n\n const revueSelectSortIcon = this.element.querySelector(`#${this.prefix}-revue_select_sort_icon-${this.sectionId}`);\n \n revueSelectItem.forEach(item => {\n item.addEventListener('click', () => {\n const sort = item.getAttribute('data-sort');\n const direction = item.getAttribute('data-direction');\n \n \n this.triggerEvent_('sort', { sort, direction });\n\n this.element.querySelector('.revue_select_label').innerText = item.innerText;\n revueSelectList.classList.remove('revue_select_list_active');\n\n \n const revueChecked = this.element.querySelector(`#${this.prefix}-revue_checked`);\n revueChecked && SPZCore.Dom.removeElement(revueChecked);\n const revueCheckedClone = revueChecked.cloneNode(true);\n item.appendChild(revueCheckedClone);\n\n const pcDropdownEle = document.querySelector(`#${this.prefix}-revue-sort-pc-dropdown-${this.sectionId}`);\n if (!revueSelectSortIcon.classList.contains('up_icon')) {\n return;\n }\n revueSelectSortIcon.classList.remove('up_icon');\n SPZ.whenApiDefined(pcDropdownEle).then((api) => {\n api.close();\n });\n });\n });\n\n \n window.addEventListener('scroll', (e) => {\n if (!revueSelectSortIcon || !revueSelectSortIcon.classList.contains('up_icon')) {\n return;\n }\n revueSelectSortIcon.classList.remove('up_icon');\n SPZ.whenApiDefined(pcDropdownEle).then((api) => {\n api.close();\n });\n });\n }\n\n addEventListenersForMobile_ = () => {\n const revueSortDropdownRender = document.querySelector(`#${this.prefix}-revue-sort-dropdown-render-${this.sectionId}`);\n\n revueSortDropdownRender && SPZ.whenApiDefined(revueSortDropdownRender).then(async (api) => {\n await api.render();\n\n const revueSortDropdownItem = document.querySelectorAll(`#${this.prefix}-revue-sort-dropdown-${this.sectionId} .revue_sort_dropdown_item`);\n\n revueSortDropdownItem.forEach(item => {\n item.addEventListener('click', () => {\n const sort = item.getAttribute('data-sort');\n const direction = item.getAttribute('data-direction');\n revueSortDropdownItem.forEach((_item)=>{_item.classList.remove('selected')})\n item.classList.add('selected');\n // 抛出事件\n this.triggerEvent_('sort', { sort, direction });\n\n // 移除revue_checked元素,复制一个新的到当前选中的元素 \n const revueChecked = document.querySelector(`#${this.prefix}-revue-sort-dropdown-${this.sectionId} #${this.prefix}-revue_checked`);\n revueChecked && SPZCore.Dom.removeElement(revueChecked);\n const revueCheckedClone = revueChecked.cloneNode(true);\n item.appendChild(revueCheckedClone);\n \n const mDropdownEle = document.querySelector(`#${this.prefix}-revue-sort-dropdown-${this.sectionId}`);\n SPZ.whenApiDefined(mDropdownEle).then((api) => {\n api.close();\n }); \n });\n });\n })\n }\n }\n SPZ.defineElement(TAG, SPZCustomRevueSort)\n\n\n\n\n\n const TAG = 'spz-custom-revue-flow';\n class SpzCustomRevueFlow extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n this.sectionId = this.element.getAttribute('section-id');\n this.show_product = '';\n this.with_photo = '';\n this.limit = '';\n this.star_least = '';\n this.layout = ''\n this.wall_pc_num = ''\n this.wall_mobile_num = ''\n this.accent_color = ''\n this.isProductPage = '15' == 1;\n this.isCollectionPage = '15' == 2;\n this.isCartPage = '15' == 13;\n this.lastWidth = window.innerWidth;\n }\n\n static deferredMount() {\n return false;\n }\n buildCallback = () => {\n this.action_ = SPZServices.actionServiceForDoc(this.element);\n this.xhr_ = SPZServices.xhrFor(this.win);\n this.setupAction_();\n const url = new URL(window.location.href);\n const preview_theme_id = url.searchParams.get('preview_theme_id');\n if (preview_theme_id) {\n this.preview_theme_id = preview_theme_id;\n }\n this.commentConfig = {};\n this.sort = 'created_at';\n this.direction = 'desc';\n this.isPC = window.innerWidth > (window.breakpoint || 960);\n this.appendList = [];\n this.commentListRes = [];\n this.cardConfig = window.reviewSettings[this.sectionId];\n }\n\n render_ = (data={}) => {\n const {star_least, with_photo, show_product, limit, layout, wall_pc_num, wall_mobile_num, accent_color, fill_strategy, review_insufficient, minimum_comment_num, only_featured, hide_review_section} = this.cardConfig;\n Object.assign(this, {star_least, with_photo, show_product, limit, layout, wall_pc_num, wall_mobile_num, accent_color, fill_strategy, review_insufficient, minimum_comment_num, only_featured, hide_review_section});\n if(this.layout === 'wall'){\n this.with_photo = 1;\n };\n this.params = {\n offset: this.appendList.length || 0,\n sort_by: this.sort,\n sort_direction: this.direction,\n show_reply: 1 || this.commentConfig.show_reply ? 1 : 0,\n with_photo: this.with_photo,\n ...data\n }\n if(this.fill_strategy == 'store'){\n if(this.review_insufficient == 'less_than'){\n this.params.fill_min_threshold = minimum_comment_num;\n }else{\n this.params.fill_min_threshold = 1;\n }\n this.params.fill_strategy = this.fill_strategy;\n }\n const summaryObj = {\n star_least:this.star_least,\n product_ids: this.isProductPage ? '' : this.isCartPage ? '' : '',\n collection_id: this.isCollectionPage ? '' : '',\n filter_type: (this.isProductPage || this.isCartPage) ? 'product' : this.isCollectionPage ? 'collection' : 'store',\n fill_strategy: this.params?.fill_strategy || '',\n only_media: !!this.params.with_photo,\n only_featured:this.only_featured\n }\n if(this.params.fill_min_threshold){\n summaryObj.fill_min_threshold = this.params.fill_min_threshold;\n }\n Promise.all([\n this.fetchSummary_(summaryObj),\n this.fetchCommentConfig_(),\n this.fetchCommentList_(this.params)\n ]).then(response => {\n const [starCountRes,commentConfigRes, commentListRes] = response;\n this.commentConfig = commentConfigRes.data;\n this.commentConfig.show_product = this.show_product;\n this.commentListRes = commentListRes;\n this.starCountRes = starCountRes;\n const showEmpty = this.review_insufficient == 'less_than' && commentListRes?.data?.count < this.minimum_comment_num && this.fill_strategy == 'hide'\n const showEmpty2 = (!commentListRes?.data?.count || commentListRes?.data?.count*1 == 0) && (this.hide_review_section || this.fill_strategy == 'hide')\n if(showEmpty2 || showEmpty){\n this.renderEmpty_();\n return;\n }\n if (this.preview_theme_id) {\n this.fetchThemeConfig_(this.preview_theme_id).then(themeConfig => {\n if (themeConfig?.star_color) {\n this.commentConfig.star_color = themeConfig.star_color;\n }\n if(this.accent_color && this.accent_color != 'null'){\n this.commentConfig.star_color = this.accent_color;\n }\n });\n }\n \n const colums = this.calculateColums_();\n this.renderFlowMain_({ config: this.commentConfig, comment: commentListRes.data, column_count: colums }).then(() => {\n this.renderHeader_({\n starData: this.starCountRes.data,\n listData: this.commentListRes.data,\n star_color: this.commentConfig.star_color,\n comment_avg_star: this.commentListRes.data.avg_star,\n comment_count: this.commentListRes.data?.count,\n isPC: this.isPC,\n });\n this.renderStarCounts_(this.starCountRes.data);\n this.addImpression(`[data-section-id=\"${this.sectionId}\"] .revue_container`);\n this.renderCommentList_({ list: commentListRes.data, config: this.commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name },true);\n });\n window.removeEventListener('resize', this.rerenderFn);\n window.addEventListener('resize', this.rerenderFn);\n })\n .catch(error => {\n this.renderEmpty_();\n console.error('error', error);\n });\n }\n mountCallback = () => {\n this.render_()\n }\n \n fetchCommentConfig_ = async () => {\n const response = await fetch('/api/comment-config');\n return response.json();\n }\n\n fetchSummary_ = async (data) => {\n const response = await fetch('/api/v1/comments/summary',{\n method: 'POST',\n headers: {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(data)\n });\n return response.json();\n }\n\n fetchCommentList_ = async(data) => {\n const response = await fetch(`/api/v1/comments`,{\n method: 'POST',\n headers: {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n ...data,\n offset: data.offset,\n show_product:!!this.show_product,\n star_least:this.star_least,\n limit:this.limit,\n sort_by:data.sort_by || 'created_at',\n sort_direction: data.sort_direction || 'desc',\n filter_type:(this.isProductPage || this.isCartPage) ? 'product' : this.isCollectionPage ? 'collection' : 'store',\n show_reply: !!data.show_reply,\n only_media: !!data.with_photo,\n product_ids: this.isProductPage ? '' : this.isCartPage ? '' : '',\n collection_id: this.isCollectionPage ? '' : '',\n only_featured: this.only_featured,\n })\n });\n if(response.status != 200){\n return Promise.reject(false);\n }\n return response.json();\n }\n\n fetchThemeConfig_ = async(themeId) => {\n const response = await fetch(`/api/comment/theme-config?theme_id=${themeId}`);\n return response.json();\n }\n\n renderEmpty_ = () => {\n const holderEl = document.getElementById(`revue_no_data_placeholder_${this.sectionId}`);\n const skeleton = document.getElementById(`revue_flow_skeleton-${this.sectionId}`);\n if(skeleton){\n skeleton.style.display = 'none';\n };\n if (window.top !== window.self) {\n SPZ.whenApiDefined(holderEl).then((api) => {\n api.render({}, true);\n });\n }else{\n holderEl.style.display = 'none';\n }\n }\n\n renderFlowMain_ = async (data) => {\n const mainEle = document.querySelector(`#revue_flow_render-${this.sectionId}`);\n if (mainEle) {\n const api = await SPZ.whenApiDefined(mainEle);\n return api.render({ ...data },true);\n }\n }\n\n calculateColums_ = () => {\n let colums = 1;\n this.isPC = window.innerWidth > (window.breakpoint || 960);\n if (this.layout === 'grid') {\n colums = this.isPC ? 4 : 2;\n \n } else {\n colums = this.isPC ? 2 : 1;\n }\n if(this.layout == 'wall'){\n colums = this.isPC ? (this.wall_pc_num || 4) : (this.wall_mobile_num || 2);\n }\n \n return colums\n }\n\n rerenderFn = (list) => {\n try{\n if(!this?.commentListRes?.data) return;\n const currentWidth = window.innerWidth;\n if (currentWidth == this.lastWidth ) {\n return\n } else {\n this.lastWidth = currentWidth;\n }\n const throttleHandle = SPZCore.Types.throttle(window,()=>{\n let colums = this.calculateColums_();\n this.renderFlowMain_({ config: this.commentConfig, comment: this.commentListRes.data, column_count: colums }).then(() => {\n this.renderHeader_({\n starData: this.starCountRes.data,\n listData: this.commentListRes.data,\n star_color: this.commentConfig.star_color,\n comment_avg_star: this.commentListRes.data.avg_star,\n comment_count: this.commentListRes.data?.count,\n isPC: this.isPC,\n });\n this.renderStarCounts_(this.starCountRes.data);\n this.renderCommentList_({ list: this.commentListRes.data, config: this.commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name }, true);\n }); \n },200)\n throttleHandle()\n }catch(e){\n console.log(e);\n }\n }\n\n renderCommentList_ = (data,redo=false) => {\n if(this.accent_color && this.accent_color != 'null'){\n this.commentConfig.star_color = this.accent_color;\n }\n const listEle = document.querySelector(`#revue_flow_list-${this.sectionId}`);\n if (listEle) {\n const current_list = data.list.list.map((item, index) => {\n return {\n ...item,\n config: this.commentConfig,\n index: data.sorted ? index : this.appendList.length + index,\n shop_name: window.SHOPLAZZA.shop.shop_name\n }\n });\n if (data.sorted) {\n this.appendList = current_list;\n SPZ.whenApiDefined(listEle).then((api) => {\n api.listRender({ count: data.list.count, list: current_list },true);\n });\n } else {\n let obj = {};\n this.appendList = this.appendList.concat(current_list).reduce((cur,next) => {\n obj[next.id] ? \"\" : obj[next.id] = true && cur.push(next);\n return cur;\n },[]);\n SPZ.whenApiDefined(listEle).then((api) => {\n api.listRender({ count: data.list.count, list: current_list },redo);\n });\n }\n };\n this.renderLoadMoreBtn(data.list);\n }\n\n mediaParse_ = function (url) {\n var result = {};\n try {\n url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {\n try {\n result[key] = decodeURIComponent(value);\n } catch (e) {\n result[key] = value;\n }\n });\n result.src = url.split('?')[0];\n } catch (e) {};\n return result;\n }\n\n impFunc = function (selector, cb) {\n // 添加自动曝光\n const el = document.querySelector(selector);\n const onImpress = () => {\n cb();\n };\n // 元素未曝光时添加曝光事件监听,已曝光则可以立刻触发处理器\n if (el && !el.getAttribute('imprsd')) {\n el.addEventListener('impress', onImpress);\n } else if (el) {\n onImpress();\n }\n };\n\n addImpression = function (selector) {\n this.impFunc(selector, () => {\n window.sa && window.sa.track('plugin_reviews_masonry_pv', {\n layout_type: this.layout,\n level_type: this.star_least,\n show_number: this.limit,\n plugin_timestamp: new Date().valueOf().toString(),\n reviews_num: this.appendList.length\n });\n });\n };\n\n addModalImpression = function (selector, params) {\n this.impFunc(selector, () => {\n window.sa && window.sa.track('plugin_reviews_modal_pv', {\n ...params,\n plugin_timestamp: new Date().valueOf().toString(),\n });\n });\n };\n\n \n setupAction_ = () => {\n this.registerAction('refresh', async(invocation) => {\n this.render_({\n ...this.params,\n offset: 0,\n sort_by: 'created_at',\n sort_direction: 'desc',\n show_reply: true,\n with_photo: false,\n })\n });\n this.registerAction('renderTypeChangeList', async(invocation) => {\n const {type,direction } = invocation.args.data;\n this.with_photo = type === 'with_photo';\n this.direction = direction;\n this.params = {\n ...this.params,\n offset: 0,\n sort_by: this.sort,\n sort_direction: this.direction,\n show_reply: 1,\n with_photo: this.with_photo\n };\n this.fetchCommentList_(this.params).then(response => {\n this.renderCommentList_({ sorted: true, list: response.data, config: this.commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name }, true);\n });\n })\n\n this.registerAction('renderSortedList', async(invocation) => {\n const {sort, direction} = invocation.args.data;\n this.sort = sort;\n this.direction = direction;\n const panelId = this.panelId;\n this.params = {\n ...this.params,\n offset: 0,\n sort_by: this.sort,\n sort_direction: this.direction,\n show_reply: 1 ,\n with_photo: this.with_photo\n }\n this.fetchCommentList_(this.params).then(response => {\n this.renderCommentList_({ sorted: true, list: response.data, config: this.commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name }, true);\n });\n });\n this.registerAction('renderProductCommentModal', async(invocation) => {\n const id = invocation.args.id;\n const current = this.appendList?.find(_data => _data.id == id);\n const modalEle = document.querySelector(`#revueDetailModal-${this.sectionId}`);\n \n \n const imgArr = current.img.map(image => {\n const width = this.getUrlKey('width', image);\n const height = this.getUrlKey('height', image);\n return {\n width,\n height,\n rate: (height/width).toFixed(2)*100,\n url: image\n };\n });\n if (modalEle) {\n SPZ.whenApiDefined(modalEle).then((api) => {\n api.renderModalFn({\n data: {\n ...current,\n img: imgArr\n },\n commentConfig: this.commentConfig,\n layout: this.layout,\n level_type: this.star_least,\n show_number: this.limit\n });\n });\n }\n });\n this.registerAction('loadMore', async(invocation) => {\n this.params = {\n ...this.params,\n offset: this.appendList.length,\n sort_by: this.sort,\n sort_direction: this.direction,\n show_reply: 1 || this.commentConfig.show_reply ? 1 : 0,\n with_photo: this.with_photo\n }\n this.fetchCommentList_(this.params).then(response => {\n this.renderCommentList_({ list: response.data, config: this.commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name });\n });\n });\n }\n\n\n getUrlKey = (name, url) => {\n return (\n decodeURIComponent(\n (new RegExp(\"[?|&]\" + name + \"=\" + \"([^&;]+?)(&|#|;|$)\").exec(\n url\n ) || [, \"\"])[1].replace(/\\+/g, \"%20\")\n ) || null\n );\n }\n\n renderHeader_ = (data) => {\n if(this.accent_color && this.accent_color != 'null'){\n data.star_color = this.commentConfig.star_color = this.accent_color;\n }\n const headerEle = document.querySelector(`#review-revue-header-${this.sectionId}`);\n if (headerEle) {\n SPZ.whenApiDefined(headerEle).then(async (api) => {\n api.render(data);\n });\n }\n }\n\n renderStarCounts_ = (data) => {\n const summaryEle = document.querySelector(`#revue-summary-${this.sectionId}`);\n if (summaryEle) {\n SPZ.whenApiDefined(summaryEle).then((api) => {\n api.render({\n ...data,\n star_color: this.commentConfig.star_color\n });\n });\n }\n }\n\n renderLoadMoreBtn = (data) => {\n const loadEle = document.querySelector(`#revue_flow_load_more_render-${this.sectionId}`);\n if (loadEle) {\n SPZ.whenApiDefined(loadEle).then((api) => {\n api.render({ comment: data }, true);\n });\n }\n }\n\n triggerEvent_(name, data) {\n const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});\n this.action_.trigger(this.element, name, event);\n }\n\n unmountCallback(){\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n }\n SPZ.defineElement(TAG, SpzCustomRevueFlow)\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\n\n const TAG = 'spz-custom-revue-modal';\n class SPZCustomRevueModal extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n this.renderedId = '';\n this.closeCB = null;\n this.sectionId = this.element.getAttribute('section-id');\n }\n\n static deferredMount() {\n return false;\n }\n\n buildCallback = () => {\n this.setupAction_();\n }\n\n mountCallback = () => {\n \n }\n \n setupAction_ = () => {\n this.registerAction('renderModal', this.renderModalFn)\n this.registerAction('closeFn',() => {\n this?.closeCB?.()\n })\n }\n\n\n mediaParse_ = function (url) {\n var result = {};\n try {\n url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {\n try {\n result[key] = decodeURIComponent(value);\n } catch (e) {\n result[key] = value;\n }\n });\n result.src = url.split('?')[0];\n } catch (e) {};\n return result;\n }\n\n\n impFunc = function (selector, cb) {\n // 添加自动曝光\n const el = document.querySelector(selector);\n const onImpress = () => {\n cb();\n };\n // 元素未曝光时添加曝光事件监听,已曝光则可以立刻触发处理器\n if (el && !el.getAttribute('imprsd')) {\n el.addEventListener('impress', onImpress);\n } else if (el) {\n onImpress();\n }\n };\n \n addModalImpression = function (selector, params) {\n this.impFunc(selector, () => {\n window.sa && window.sa.track('plugin_reviews_modal_pv', {\n ...params,\n plugin_timestamp: new Date().valueOf().toString(),\n });\n });\n };\n\n renderModalFn(receivedData){\n if(!receivedData) return;\n const {\n data:current,\n commentConfig,\n layout,\n level_type,\n show_number,\n closeCB,\n mimic_mobile_style,\n props\n } = receivedData;\n try{\n if(closeCB){\n this.closeCB = () => {\n closeCB()\n };\n }\n }catch(e){\n console.log(e);\n };\n const commentModalEl = document.querySelector(`#revue-product-comment-modal-${this.sectionId}`);\n const modalRenderEl = document.querySelector(`#revue_flow_modal_render-${this.sectionId}`);\n if (!!mimic_mobile_style) {\n if (commentModalEl) {\n commentModalEl.classList.add('mobile-wrap');\n }\n if (modalRenderEl) {\n modalRenderEl.classList.add('w-h-full-h5');\n }\n };\n const parsedImages = current?.img?.map(image => {\n return this.mediaParse_(`${image.url}?width=${image.width}&height=${image.height}`);\n });\n\n const modalEle = document.querySelector(`#revue_flow_modal_render-${this.sectionId}`);\n if (modalEle) {\n SPZ.whenApiDefined(modalEle).then((api) => {\n api.render({ ...current, img: parsedImages, config: commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name, mimic_mobile_style }, true).then(() => {\n this.addModalImpression('.revue_modal_container', {\n id: current.id,\n username: current.username,\n content: current.content,\n star: current.star,\n is_verified: current.is_verified,\n is_featured: current.is_featured,\n anonymous: current.anonymous,\n iso_code_3: current.iso_code_3,\n like_count: current.like,\n layout_type: layout,\n level_type: level_type,\n show_number: show_number,\n });\n }).then(()=>{\n this.renderedId = current.id\n });\n });\n }\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n }\n SPZ.defineElement('spz-custom-revue-modal', SPZCustomRevueModal)\n\n\n\n\n\n\n\n const TAG = 'spz-custom-revue-video';\n class SPZCustomRevueVideo extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n }\n\n static deferredMount() {\n return false;\n }\n\n buildCallback = () => {\n this.action_ = SPZServices.actionServiceForDoc(this.element);\n this.templates_ = SPZServices.templatesForDoc(this.element);\n this.xhr_ = SPZServices.xhrFor(this.win);\n // data-images 格式为 xxxx.png?width=1&height=1,xxxx.png?width=1&height=1\n const images = this.element.getAttribute('data-images').split(',') || [];\n const parsedImages = images.map(image => {\n return this.mediaParse_(image);\n });\n this.images = parsedImages;\n this.isPC = window.innerWidth > 960;\n }\n\n loadVideo = () => {\n this.doRender_({\n images: this.images,\n isPC: this.isPC\n }).then(()=>{\n this.triggerEvent_('connected', {});\n })\n }\n mountCallback = () => {\n this.loadVideo();\n \n this.registerAction('loadVideo', async(invocation) => {\n this.loadVideo();\n })\n }\n\n doRender_ = (data) => {\n return this.templates_\n .findAndRenderTemplate(this.element, data, null)\n .then((el) => {\n const children = this.element.querySelector('*:not(template)');\n children && SPZCore.Dom.removeElement(children);\n this.element.appendChild(el);\n });\n }\n\n mediaParse_ = function (url) {\n var result = {};\n try {\n url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {\n try {\n result[key] = decodeURIComponent(value);\n } catch (e) {\n result[key] = value;\n }\n });\n result.preview_image = url.split('?')[0];\n } catch (e) {};\n return result;\n }\n\n triggerEvent_(name, data) {\n const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});\n this.action_.trigger(this.element, name, event);\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n }\n SPZ.defineElement(TAG, SPZCustomRevueVideo)\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n const TAG = 'spz-custom-revue-header';\n\n class SPZCustomRevueHeader extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n this.showCount = this.element.getAttribute('show-count');\n }\n\n static deferredMount() {\n return false;\n }\n \n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n\n buildCallback() {\n this.action_ = SPZServices.actionServiceForDoc(this.element);\n this.templates_ = SPZServices.templatesForDoc(this.element);\n this.xhr_ = SPZServices.xhrFor(this.win);\n this.showCount = this.element.getAttribute('show-count');\n this.showSummary = this.element.getAttribute('show-summary');\n this.showWriteReview = this.element.getAttribute('show-write-review');\n this.showType = this.element.getAttribute('show-type') ;\n this.showSort = this.element.getAttribute('show-sort') ;\n this.sectionId = this.element.getAttribute('section-id');\n this.viewall = this.element.getAttribute('viewall') ?? false;\n this.prefix = this.element.getAttribute('prefix');\n }\n\n mountCallback() {\n \n }\n\n triggerEvent_(name, data) {\n const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});\n this.action_.trigger(this.element, name, event);\n }\n\n render(data) {\n const ndata = {\n ...data,\n showCount: this.showCount,\n showSummary: this.showSummary,\n showWriteReview: this.showWriteReview,\n showType: this.showType,\n showSort: this.showSort,\n }\n if(this.viewall == 'review'){\n ndata.viewall = false\n }\n return this.templates_\n .findAndRenderTemplate(this.element, ndata, null, true)\n .then(({el}) => {\n const children = this.element.querySelector('*:not(template)');\n children && SPZCore.Dom.removeElement(children);\n this.element.appendChild(el);\n }).then(() => {\n if(data && Object.keys(data).length > 0) {\n this.updateRender(data);\n this.setupSummaryContainerEffects_(data);\n }\n });\n }\n \n updateRender(data) {\n this.renderStarCounts_(data);\n this.renderTypeSelect(data);\n this.renderSortSelect(data);\n }\n\n renderStarCounts_(data) {\n const renderData = {\n ...data.starData,\n star_color: data.star_color,\n isPC: data.isPC,\n }\n const summaryEle = data.isPC ? this.element.querySelector(`#${this.prefix}-revue-summary-${this.sectionId}_header_pc`) : this.element.querySelector(`#${this.prefix}-revue-summary-${this.sectionId}_header`);\n if(summaryEle) {\n SPZ.whenApiDefined(summaryEle).then((api) => {\n api.render(renderData);\n });\n }\n }\n\n renderTypeSelect(data) {\n const typeSelect = this.element.querySelector(`#${this.prefix}-revue-header-type-${this.sectionId}`);\n if(typeSelect) {\n SPZ.whenApiDefined(typeSelect).then((api) => {\n api.render(data);\n api.registerAction('headerType_', (invocation) => {\n this.triggerEvent_('headerType', invocation.args.data);\n });\n });\n }\n }\n\n renderSortSelect(data) {\n const suffix = data.suffix || this.sectionId;\n const sortSelect = this.element.querySelector(`#${this.prefix}-revue-header-sort-${suffix}`);\n if(sortSelect) {\n SPZ.whenApiDefined(sortSelect).then((api) => {\n api.registerAction('headerSort_', (invocation) => {\n this.triggerEvent_('headerSort', invocation.args.data);\n });\n });\n }\n }\n\n setupSummaryContainerEffects_(data) {\n if(data.isPC) {\n this.setupSummaryContainerHover_();\n } else {\n this.setupSummaryContainerTap_();\n }\n }\n\n setupSummaryContainerHover_() {\n const summaryContainer = this.element.querySelector(`#revue-header-summary-container-${this.sectionId}`);\n const summaryEle = this.element.querySelector(`#${this.prefix}-revue-summary-${this.sectionId}_header_pc`);\n if (!summaryContainer || !summaryEle) return;\n\n let isHovering = false;\n\n // 鼠标移入容器时显示summary\n SPZUtils.Event.listen(summaryContainer, 'mouseenter', () => {\n isHovering = true;\n summaryEle.removeAttribute('hidden');\n const selectIcon = summaryContainer.querySelector(`#revue-header-summary-icon-${this.sectionId}`);\n if(selectIcon) {\n selectIcon.classList.add('up-icon');\n }\n });\n // 鼠标移入summary时也保持显示\n SPZUtils.Event.listen(summaryEle, 'mouseenter', () => {\n isHovering = true;\n });\n \n // 鼠标移出容器时,检查是否还在summary上\n SPZUtils.Event.listen(summaryContainer, 'mouseleave', () => {\n isHovering = false;\n setTimeout(() => {\n if (!isHovering) {\n summaryEle.setAttribute('hidden', 'true');\n const selectIcon = summaryContainer.querySelector(`#revue-header-summary-icon-${this.sectionId}`);\n if(selectIcon) {\n selectIcon.classList.remove('up-icon');\n }\n }\n }, 50);\n });\n // 鼠标移出summary时,检查是否还在容器上\n SPZUtils.Event.listen(summaryEle, 'mouseleave', () => {\n isHovering = false;\n setTimeout(() => {\n if (!isHovering) {\n summaryEle.setAttribute('hidden', 'true');\n const selectIcon = summaryEle.querySelector(`#revue-header-summary-icon-${this.sectionId}`);\n if(selectIcon) {\n selectIcon.classList.remove('up-icon');\n }\n }\n }, 50);\n });\n }\n\n setupSummaryContainerTap_() {\n const selectIcon = this.element.querySelector(`#revue-header-summary-icon-${this.sectionId}`);\n const summaryEle = this.element.querySelector(`#${this.prefix}-revue-summary-${this.sectionId}_header`);\n if(!summaryEle) return;\n\n let isTapped = false; // 是否显示summary\n SPZ.whenApiDefined(summaryEle).then((api) => {\n api.registerAction('display', () => {\n if(isTapped) {\n isTapped = false;\n summaryEle.removeAttribute('hidden');\n selectIcon.classList.add('up-icon');\n } else {\n isTapped = true;\n summaryEle.setAttribute('hidden', 'true');\n selectIcon.classList.remove('up-icon');\n }\n });\n });\n }\n }\n\n SPZ.defineElement(TAG, SPZCustomRevueHeader);\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n const TAG = 'spz-custom-revue-type';\n class SPZCustomRevueType extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n }\n\n static deferredMount() {\n return false;\n }\n\n triggerEvent_(name, data) {\n const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});\n this.action_.trigger(this.element, name, event);\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n\n buildCallback = () => {\n this.action_ = SPZServices.actionServiceForDoc(this.element);\n this.templates_ = SPZServices.templatesForDoc(this.element);\n this.xhr_ = SPZServices.xhrFor(this.win);\n this.isPC = window.innerWidth > 960;\n this.width = this.isPC ? `${this.element.getAttribute('width') || 150}px` : '100%';\n this.randomStr = Math.random().toString(36).substr(2);\n this.sectionId = this.element.getAttribute('section-id') || '1709781152049';\n this.prefix = this.element.getAttribute('prefix');\n }\n\n mountCallback = () => {\n }\n\n render = (data) => {\n const renderData = {\n ...data,\n width: this.width,\n randomStr: this.randomStr\n };\n return this.templates_\n .findAndRenderTemplate(this.element, renderData, null)\n .then((el) => {\n const children = this.element.querySelector('*:not(template)');\n children && SPZCore.Dom.removeElement(children);\n this.element.appendChild(el);\n }).then(() => {\n let revueTypeListRender = this.isPC ? this.element.querySelector(`#${this.prefix}-revue-type-list-render-${this.sectionId}`) : this.element.querySelector(`#${this.prefix}-revue-type-dropdown-render-${this.sectionId}`);\n revueTypeListRender && SPZ.whenApiDefined(revueTypeListRender).then((api) => {\n api.render(renderData).then(() => {\n if (this.isPC) {\n this.addEventListenersForPC_();\n } else {\n this.addEventListenersForMobile_();\n }\n });\n });\n });\n }\n\n\n addEventListenersForPC_ = () => {\n const revueSelectList = this.element.querySelector('.revue_select_list');\n const revueSelectItem = this.element.querySelectorAll('.revue_select_item');\n\n const revueSelectTypeIcon = this.element.querySelector(`#${this.prefix}-revue_select_type_icon-${this.sectionId}`);\n \n revueSelectItem.forEach(item => {\n item.addEventListener('click', () => {\n const type = item.getAttribute('data-type');\n const direction = item.getAttribute('data-direction');\n\n \n this.triggerEvent_('type', { type, direction });\n\n this.element.querySelector('.revue_select_label').innerText = item.innerText;\n revueSelectList.classList.remove('revue_select_list_active');\n\n \n const revueChecked = this.element.querySelector(`#${this.prefix}-revue_checked`);\n revueChecked && SPZCore.Dom.removeElement(revueChecked);\n const revueCheckedClone = revueChecked.cloneNode(true);\n item.appendChild(revueCheckedClone);\n\n if (!revueSelectTypeIcon.classList.contains('up_icon')) {\n return;\n }\n\n const pcDropdownEle = this.element.querySelector(`#${this.prefix}-revue-type-pc-dropdown-${this.sectionId}`);\n revueSelectTypeIcon.classList.remove('up_icon');\n SPZ.whenApiDefined(pcDropdownEle).then((api) => {\n api.close();\n });\n });\n });\n \n window.addEventListener('scroll', (e) => {\n if (!revueSelectTypeIcon.classList.contains('up_icon')) {\n return;\n }\n revueSelectTypeIcon.classList.remove('up_icon');\n SPZ.whenApiDefined(pcDropdownEle).then((api) => {\n api.close();\n });\n });\n }\n\n addEventListenersForMobile_ = () => {\n const revueTypeDropdownItem = this.element.querySelectorAll(`#${this.prefix}-revue-type-dropdown-${this.sectionId} .revue_type_dropdown_item`);\n\n revueTypeDropdownItem.forEach(item => {\n item.addEventListener('click', () => {\n const type = item.getAttribute('data-type');\n const direction = item.getAttribute('data-direction');\n revueTypeDropdownItem.forEach((_item)=>{_item.classList.remove('selected')})\n item.classList.add('selected');\n // 抛出事件\n this.triggerEvent_('type', { type, direction });\n\n // 移除revue_checked元素,复制一个新的到当前选中的元素 \n const revueChecked = this.element.querySelector(`#${this.prefix}-revue-type-dropdown-${this.sectionId} #${this.prefix}-revue_checked`);\n revueChecked && SPZCore.Dom.removeElement(revueChecked);\n const revueCheckedClone = revueChecked.cloneNode(true);\n item.appendChild(revueCheckedClone);\n\n const mDropdownEle = this.element.querySelector(`#${this.prefix}-revue-type-dropdown-${this.sectionId}`);\n SPZ.whenApiDefined(mDropdownEle).then((api) => {\n api.close();\n });\n });\n });\n }\n }\n SPZ.defineElement(TAG, SPZCustomRevueType)\n\n\n\n\n \n\n \n\n\n const TAG = 'spz-custom-revue-progress';\n class SPZCustomRevueProgress extends SPZ.BaseElement {\n constructor(element) {\n super(element);\n }\n\n static deferredMount() {\n return false;\n }\n\n buildCallback = () => {\n this.action_ = SPZServices.actionServiceForDoc(this.element);\n this.templates_ = SPZServices.templatesForDoc(this.element);\n this.xhr_ = SPZServices.xhrFor(this.win);\n this.isPC = window.innerWidth > (window.breakpoint || 960);\n this.height = '6px';\n this.color = this.element.getAttribute('color') || '#000000';\n this.show_percentage = 'false';\n this.show_percentage_num = 100;\n this.count = this.element.getAttribute('count');\n this.total = this.element.getAttribute('total');\n\n }\n\n mountCallback = () => {\n this.doRender_({\n count: Number(this.count),\n total: Number(this.total),\n height: this.height,\n color: this.color,\n show_percentage: this.show_percentage,\n show_percentage_num: this.show_percentage_num\n }).then(() => {\n });\n }\n\n doRender_ = (data) => {\n return this.templates_\n .findAndRenderTemplate(this.element, data, null)\n .then((el) => {\n const children = this.element.querySelector('*:not(template)');\n children && SPZCore.Dom.removeElement(children);\n this.element.appendChild(el);\n });\n }\n\n triggerEvent_(name, data) {\n const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});\n this.action_.trigger(this.element, name, event);\n }\n\n isLayoutSupported(layout) {\n return layout == SPZCore.Layout.CONTAINER;\n }\n }\n SPZ.defineElement(TAG, SPZCustomRevueProgress)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n \n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n \n \n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n \n
\n \n \n \n
\n\n\n \n
Customer Reviews (500+)
All
All(13979)
With Photos(1)
Newest
Newest
Most liked
Highest ratings
Lowest ratings
Wearing it, whether it is for work or leisure, you can show your unique taste.
Rogers
Nov 06, 2025
The simple but not simple design can easily control various styles and is versatile.
Mahr
Nov 06, 2025
The fabric is breathable and can keep you fresh and not stuffy even in the hot summer.
Ramos
Nov 06, 2025
The bright and vivid colors make people feel bright and bright, which is a bright color in the wardrobe.
Lopez
Nov 06, 2025
The classic style will never go out of style and can show elegant temperament anytime and anywhere.
Pogalz
Nov 06, 2025
This clothing is extremely comfortable and can be worn for a long time without any pressure.
Miller
Nov 06, 2025
The design is clever, which can well modify the figure and make people more confident.
DeMarche
Nov 06, 2025
The design of this clothing is very slimming, and it is easy to create a slender figure.
Stephany
Nov 06, 2025
View more
\n\n\n\n
\n
\n \n
\n\n
\n \n \n\n\n
\n
\n \n
Sign up to receive special offers, giveaways and one-time deals.\n—\nDiscount code:: COMST\n
\n \n
\n \n \n
\n\n \n
\n\n\n \n \n \n
\n \n\n
\n\n
\n ©  Comstylish | Everyday Casual Wear Brands\n \n \n \n
\n\n
\n\n
\n \n \n
\n \n\n \n\n \n\n\n \n \n\n\n \n\n\n\n \n\n\n \n\n \n\n \n\n\n \n\n\n\n \n \n\n \n\n \n\n \n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n \n\n\n \n
\n\n\n
\n\n\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\"\"
\"\"\"\"
\"\"\"\"
\"\"\"\"
\n
\n
\n
×
\n
\n
\n \"\"\n
\n
\n
\n
\n Don't leave without taking discount\n
\n
\n UP TO 50% OFF\n
\n
\n On your first order\n
\n \n \n \n
* Ihre persönlichen Daten werden strengstens vor Offenlegung geschützt.
\n \n \n\n \n \n \n
\n
\n
\n
×
\n
\n
\n \"\"\n
\n
\n
\n
\n Don't leave without taking discount\n
\n
\n UP TO 50% OFF\n
\n
\n On your first order\n
\n
\n *I agree to receive recurring automated marketing text messages (e.g. cart reminders) at the phone number provided. Consent is not a condition to purchase. Msg & data rates may apply. Msg frequency varies. Reply HELP for help and STOP to cancel. View our Terms of Service and Privacy Policy.\n
\n
\n
invalid phone number
\n \n
\n\n \n \n
\n
\n
111
\n
\n
\n
\n \"gifts\"\n
\n
\n\n
\n
\n \"membership\"\n
\n
\n\n
\n
\n \"gifts\"\n \"membership\"\n
\n
\n
\n \"gifts\"\n GIFTS\n
\n
\n
\n \"membership\"\n POINTS\n
\n
\n
\n
\n
111
$0.00

1

Item has been added
const zebu_ativity_pop_show_history_key = 'zebu_ativity_pop_show_history'; class SpzCustomComponent extends SPZ.BaseElement { constructor(element) { super(element); this.templates_ = null; this.container_ = null; this._atcLineItem = {}; this.cart_ = {}; this.top_product_ids_ = []; this.products_ = []; this.activityId_ = null; this.rendered_ = false; this.myInterceptor_ = null; this.i18n_ = {}; this.config_ = {}; this.page_ = 1; this.limit_ = 10; this.loading_ = false; this.activityPopShowHistoryConfig = null; } static deferredMount() { return false; } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } buildCallback() { this.templates_ = SPZServices.templatesForDoc(this.element); this.setAction_(); } generateActivityPopShowHistoryKey(activity_id){ const customer_id = window.C_SETTINGS.customer.customer_id || 'unlogin'; return customer_id + '-' + activity_id; } judgeCanShowCartPop(data){ const pop_frequency = data.config.pop_frequency; if (pop_frequency == 'once'){ return { show: !window.sessionStorage.getItem('smart_pop_times'), type: 'once' }; } if( pop_frequency == 'not_limit' ){ return { show: true, type: 'not_limit' }; } const activityPopShowHistory = this.getActivityPopShowHistory(); if( !activityPopShowHistory ){ return { show: true, type: 'no_history' }; } const historyKey = this.generateActivityPopShowHistoryKey(data.id); const historyItem = activityPopShowHistory[historyKey]; if( !historyItem ){ return { show: true, type: 'no_history' }; } if( pop_frequency == 'once' ){ return { show: false, type: 'once' }; } const splitArray = pop_frequency.split(':'); if( splitArray.length != 3 ){ return { show: true, type: 'rule_error' }; } const limitType = splitArray[0]; const limitTypeNum = Number(splitArray[1]); const limitNum = Number(splitArray[2]); const startTime = Number(historyItem['startTime']); const count = Number(historyItem['count']); if( new Date().getTime() >= this.getLimitEndTime( startTime, limitType, limitTypeNum ) ){ return { show: true, type: 'another_range' }; } if( limitNum > count ){ return { show: true, type: 'under_limit' }; } return { show: false, type: 'exceed_range' }; } getActivityPopShowHistory(){ try{ const activityPopShowHistory = JSON.parse(window.localStorage.getItem(zebu_ativity_pop_show_history_key)); if( typeof activityPopShowHistory != 'object' ) return null; return activityPopShowHistory; }catch(e){ return null; } } addActivityPopShowHistory(props){ if( !props ) return; const { data, ruleCheckResult } = props; const pop_frequency = data.config.pop_frequency; if( pop_frequency == 'once' ){ return window.sessionStorage.setItem('smart_pop_times', Number(window.sessionStorage.getItem('smart_pop_times')) + 1); } const historyKey = this.generateActivityPopShowHistoryKey(data.id); const activityPopShowHistory = this.getActivityPopShowHistory() || {}; const historyItem = activityPopShowHistory[historyKey]; if( ruleCheckResult.type == 'another_range' || !historyItem ){ activityPopShowHistory[historyKey] = { startTime: new Date().getTime(), count: 1, }; }else{ activityPopShowHistory[historyKey].count += 1; } return window.localStorage.setItem(zebu_ativity_pop_show_history_key,JSON.stringify(activityPopShowHistory)); } removeActivityPopShowHistory(){ return window.localStorage.removeItem(zebu_ativity_pop_show_history_key); } getLimitEndTime(startTime, rangeType, rangeNum){ if( rangeType == 'day' ){ return startTime + 24*60*60*1000 * rangeNum; } if( rangeType == 'week' ){ return startTime + 24*60*60*1000 * 7 * rangeNum; } if( rangeType == 'month' ){ const date = new Date(startTime); date.setMonth( date.getMonth() + rangeNum ); return date.getTime(); } return startTime; } mountCallback() { this.i18n_ = (window.smartRecommendI18n && window.smartRecommendI18n[document.documentElement.lang] || window.smartRecommendI18n['en-US']) || {}; const cartPopRenderEl = document.getElementById(\"smart_cart_pop_render\"); const modalEl = document.getElementById(\"smart_cart_pop_modal\"); const spmBase = `smart_recommend_2`; const extra = { spmBase: spmBase, i18n: this.i18n_, }; const that = this; document.addEventListener('dj.addToCart', (event) => { try { const e = event.detail; if (e.source === 'buy_now' || window.__upsell_block || this.rendered_) return; that.fetchActivityData({product_id: e.product_id, variant_id: e.variant_id}).then(data => { if (!data || !data.products || !data.products.length) return; const ruleCheckResult = that.judgeCanShowCartPop(data); if( !ruleCheckResult.show ) return; that.config_ = data.config; const recommendStyle = document.createElement('style'); recommendStyle.innerHTML = ` #plugin_recommend_atc_pop { display: none !important; } `; document.head.appendChild(recommendStyle); SPZ.whenApiDefined(cartPopRenderEl).then(function(api){ api.render(Object.assign({}, data, extra), true).then(function() { that.rendered_ = true; if (data.products.length) { const headEl = document.getElementById(\"smart_cart_pop_head_render\"); if (headEl) { SPZ.whenApiDefined(headEl).then(function(head){ head.render({ data: data }); }); } SPZ.whenApiDefined(modalEl).then(function(api){ that.impressListen('#smart_cart_pop_activity', function(){ that.trackPluginImpression_(data); }); api.open(); that.activityPopShowHistoryConfig = { data, ruleCheckResult }; const intersectionObserver = new IntersectionObserver( function (entries) { if (entries[0].intersectionRatio > 0){ !that.loading_ && (that.products_.length - that.target_top_product_num_) === that.page_ * that.limit_ && that.viewMore(); } }, { threshold: [0.1] } ); if( document.querySelector('#smart_cart_pop_view_more_text') ){ intersectionObserver.observe( document.querySelector('#smart_cart_pop_view_more_text') ); } }); } }) }); }) } catch (e) { console.error(e); } }); } unmountCallback() { } viewMore () { const cartPopRenderEl = document.getElementById(\"smart_cart_pop_render\"); const that = this; const data = {}; SPZ.whenApiDefined(cartPopRenderEl).then(function(api){ that.fetchActivityData({ page: that.page_ + 1, limit: that.limit_ }).then(function(data) { data.products = that.products_; data.target_top_product_num = that.target_top_product_num_; data.i18n = that.i18n_; data.spmBase = `smart_recommend_2`; api.render(data); }) }) } fetchActivityData(data) { const that = this; if (data.product_id) { that._atcLineItem = data; } that.loading_ = true; return that.getCart().then(cart => { that.cart_ = cart.cart; return fetch(window.C_SETTINGS.routes.root + \"/api/possum/recommend_activities\", { method: \"POST\", headers: { \"Content-Type\": \"application/json\", \"store-id\": window.C_SETTINGS.shop.shop_id, }, body: JSON.stringify({ \"show_type\": 2, \"line_item\": { \"product_id\": that._atcLineItem.product_id, \"variant_id\": that._atcLineItem.variant_id, }, line_items: cart.cart.line_items, \"page\": data.page || 1, \"limit\": data.limit || 10, }) }).then(function(res){ if(res.ok){ return res.json(); } }).then(function(data){ data.cart = cart.cart; if (data.page === 1) { that.target_top_product_num_ = data.target_top_product_num || 0; } that.products_ = that.products_.concat(data.products || []); that.page_ = data.page || 1; that.limit_ = data.limit || 10; return data; }).catch(function(e){ console.log(e); }).finally(function(){ that.loading_ = false; }) }); }; setMatchDrawerHeight_(data) { const modalContent = document.querySelector(\"#smart_cart_pop_product_list\"); const windowHeight = window.innerHeight; modalContent.style.maxHeight = windowHeight * 0.85 + \"px\"; } setAction_() { this.registerAction('changeBannerColor', (data) => { if (!data.args.data || !data.args.data.data || !data.args.data.data.data) return false; const config = data.args.data.data.data.config; const bannerBgEl = document.querySelector('.smart_cart_pop_banner_bg'); if (bannerBgEl && config) { bannerBgEl.style.background = config.banner_bg_color; bannerBgEl.style.color = config.banner_text_color; } }); this.registerAction('handleProductChange', (data) => { const that = this; const imageEl = document.getElementById(`smart_cart_pop_image_${data.args.data.product_id}`); SPZ.whenApiDefined(imageEl).then(function(api){ api.render({ data: data.args.data, config: that.config_ }); }); const atcTextEl = document.getElementById(`smart_cart_pop_atc_${data.args.data.product_id}`); SPZ.whenApiDefined(atcTextEl).then(function(api){ api.render({ data: data.args.data, defaultText: data.args.defaultText, soldOutText: that.i18n_.sold_out }); }); if (data.args.data.variant.available) { document.getElementById(`smart_cart_pop_atc_btn_${data.args.data.product_id}`).classList.remove('zb-pointer-events-none'); } else { document.getElementById(`smart_cart_pop_atc_btn_${data.args.data.product_id}`).classList.add('zb-pointer-events-none'); } }); this.registerAction('handleProduct', (detail) => { const that = this; this.renderProductsForm_(detail.args.data.data); }); this.registerAction('addATCHook', (data) => { const params = data.args; this.myInterceptor_ = window.djInterceptors && window.djInterceptors.track.use({ event: 'dj.addToCart', params: { aid: 'smart_recommend.2.' + params.activity_id, ssp: params.ssp, scm: params.scm, cfb: params.cfb, spm: `..${window.C_SETTINGS.meta.page.template_name}.${params.spm}`, }, once: true }); }); this.registerAction('handleAtcSuccess', (detail) => { detail.args.data.product = detail.args.data.product || {}; detail.args.data.variant = detail.args.data.variant || {}; const defParams = detail.args.product.split('__'); const product_id = detail.args.data.product.id; const product_title = detail.args.data.product.title; const variant_id = detail.args.data.variant.id; const price = detail.args.data.variant.price; const aid = defParams[0]; const ifb = detail.args.data.product.ifb; const cfb = detail.args.data.product.cfb; const scm = defParams[1]; const spm = defParams[2]; const ssp = defParams[3]; const params = { id: product_id, product_id: product_id, number: 1, name: product_title, variant_id: variant_id, childrenId: variant_id, item_price: price, source: 'add_to_cart', _extra: { aid: aid, ifb: ifb, cfb: cfb, scm: scm, spm: `..${window.C_SETTINGS.meta.page.template_name}.${spm}`, ssp: ssp, } }; const activity_id = `${detail.args.activity_id}`; const target_drive_way = detail.args.target_drive_way; document.getElementById(`smart_cart_pop_loading_${product_id}`).classList.add('zb-hidden'); document.getElementById(`smart_cart_pop_added_${product_id}`).classList.remove('zb-hidden'); setTimeout(() => { document.getElementById(`smart_cart_pop_added_${product_id}`).classList.add('zb-hidden'); document.getElementById(`smart_cart_pop_atc_${product_id}`).classList.remove('zb-hidden'); document.getElementById(`smart_cart_pop_atc_btn_${product_id}`).classList.remove('zb-pointer-events-none'); }, 1000); this.tranckAddToCart(params); if (target_drive_way === 'rebate') { const bannerEl = document.getElementById(`smart_cart_pop_banner`); this.getRecommendInfo(activity_id).then(res => { if (res && res.rebate_tips) { bannerEl.innerHTML = res.rebate_tips; } }) } }); this.registerAction('handleCartSummary', (event) => { const that = this; const checkoutButtonEle = document.getElementById(\"smart_cart_pop_checkout_button\"); if (checkoutButtonEle) { SPZ.whenApiDefined(checkoutButtonEle).then(function(api){ api.render({ i18n: that.i18n_ }, false); }); } const tipEl = document.getElementById(\"smart_cart_pop_tip_info\"); const cart = event && event.args && event.args.data && event.args.data.data; if (!tipEl || !cart) return; let total_price = cart.total_price; if (!total_price) { SPZ.whenApiDefined(tipEl).then(function(api){ api.render({ total_price: total_price, i18n: that.i18n_ }, false); }); } else { this.getBindDiscount_(cart.line_items).then(res => { if (res && res.discount_code){ const total = cart.line_price - cart.total_discount - res.bundle_discount_value; if (total > 0) { total_price = total; } else { total_price = 0; } } SPZ.whenApiDefined(tipEl).then(function(api){ api.render({ total_price: total_price, i18n: that.i18n_ }, false); }); }) } }); this.registerAction('open', () => { this.setMatchDrawerHeight_(); this.addActivityPopShowHistory( this.activityPopShowHistoryConfig ); }); this.registerAction('close', () => { this.rendered_ = false; this.products_ = []; window.djInterceptors && window.djInterceptors.track.eject(this.myInterceptor_); }); } getCart() { return fetch(`${window.C_SETTINGS.routes.root || ''}/api/cart`, { method: 'GET', headers: { 'Content-Type': 'application/json; charset=UTF-8', }, }).then(res => res.json()) } getRecommendInfo (activity_id) { return this.getCart().then(cart => { this.cart_ = cart.cart; return fetch(`${window.C_SETTINGS.routes.root || ''}/api/possum/recommend_info`, { method: 'POST', headers: { 'Content-Type': 'application/json; charset=UTF-8', }, body: JSON.stringify({ show_type: 2, rule_id: `${activity_id}`, line_items: cart.cart.line_items, line_item: this._atcLineItem, }) }).then(res => res.json()) }) } renderProductsForm_(data) { const products = data.products; const listPopRenderEl = document.getElementById(\"smart_cart_pop_render\"); if (!listPopRenderEl) return; listPopRenderEl.querySelectorAll('.smart_cart_pop_atc_btn_bg').forEach(function(el){ el.style.color = data.config.add_to_cart_button_text_color; el.style.background = data.config.add_to_cart_button_color; }); products.forEach(function(product){ const productId = product.id; const productFormEls = listPopRenderEl.querySelectorAll(`ljs-product-form[product-id=\"${productId}\"]`); let variantsEl = listPopRenderEl.querySelectorAll(`ljs-product-form[product-id=\"${productId}\"] #smart_cart_pop_variant_${productId}_mobile ljs-variants`); if (window.innerWidth > 768) { variantsEl = listPopRenderEl.querySelectorAll(`ljs-product-form[product-id=\"${productId}\"] #smart_cart_pop_variant_${productId}_pc ljs-variants`); } productFormEls.forEach(function(el){ SPZ.whenApiDefined(el).then(function(api){ api.setProduct(product); }); }); variantsEl.forEach(function(el){ SPZ.whenApiDefined(el).then(function(api){ api.handleRender(product); }); }) }); } tranckAddToCart(detail) { if (window.$) { window.$(document.body).trigger('dj.addToCart', detail); } } trackPluginImpression_(rule){ if (window.sa && window.sa.track) { window.sa.track(\"module_impressions\", { aid: `smart_recommend.2.${rule.id}` }); } } getBindDiscount_(carts) { let bundle_sale_ids = []; try { bundle_sale_ids = sessionStorage['bundle_sale_ids'] && JSON.parse(sessionStorage['bundle_sale_ids']).filter((item, index, arr) => arr.indexOf(item, 0) === index).slice(-5); } catch (err) { console.error(err); } if (!carts.length) { Promise.resolve(); } return fetch(`${window.C_SETTINGS.routes.root || ''}/api/bundle-sales/cart`, { method: 'POST', headers: { 'Content-Type': 'application/json; charset=UTF-8', 'store-id': window.C_SETTINGS.shop.shop_id, }, body: JSON.stringify({ cart: carts, action_type: 'cart', bundle_sale_ids }) }).then(res => res.json()) } impressListen(selector, cb) { const el = document.querySelector(selector); const onImpress = (e) => { if (e) { e.stopPropagation(); } cb(); }; if (el && !el.getAttribute('imprsd')) { el.addEventListener('impress', onImpress) } else if (el) { onImpress(); } } } SPZ.defineElement('spz-custom-smart', SpzCustomComponent);
Quantity

1

\n\n\n \n\n\n
\"\"
Original text
Rate this translation
Your feedback will be used to help improve Google Translate
","screenshot":"https://cdn.scamminder.com/include/uploads/2025/11/comstylish.com-20251108-045713.webp","loadTimeInSeconds":8.018,"title":"Comstylish | Everyday Casual Wear Brands","keywords":"women clothes,affordable,casual,women wear,fashion,christmas,sweatshirt,leggings,men's clothing,shirt,t-shirt,dresses","description":"Comstylish integrates design, production and sales to provide you with great value for money clothing for men and women. 500+ new products every day, providing massive selection and great discounts.","links":["https://comstylish.com","https://comstylish.com/account/login","https://comstylish.com/account/register","https://comstylish.com/cart","https://comstylish.com/collections/womens-clothing","https://comstylish.com/collections/christmas-womens-collection","https://comstylish.com/collections/halloween-womens-collection","https://comstylish.com/collections/freedom","https://comstylish.com/collections/forest-collection","https://comstylish.com/collections/bohemian","https://comstylish.com/collections/animal-womens-collection","https://comstylish.com/collections/womens-linen","https://comstylish.com/collections/japanese-art-womens-collection","https://comstylish.com/collections/mental-health","https://comstylish.com/collections/magical-ocean-womens-collection","https://comstylish.com/collections/western-style-womens-collection","https://comstylish.com/collections/vikings-celtics-womens-collection","https://comstylish.com/collections/slogan","https://comstylish.com/collections/national-style","https://comstylish.com/collections/hippie","https://comstylish.com/collections/egypt-womens-collection","https://comstylish.com/collections/paisley-style","https://comstylish.com/collections/tops","https://comstylish.com/collections/shirts-blouses","https://comstylish.com/collections/t-shirts","https://comstylish.com/collections/loose-blouse","https://comstylish.com/collections/tank-tops","https://comstylish.com/collections/denim-jacket-womens-collection","https://comstylish.com/collections/hoodies-sweatshirts","https://comstylish.com/collections/sweaters-cardigans","https://comstylish.com/collections/outerwear","https://comstylish.com/collections/bottoms","https://comstylish.com/collections/womens-skirt","https://comstylish.com/collections/pants","https://comstylish.com/collections/jeans","https://comstylish.com/collections/leggings","https://comstylish.com/collections/dresses","https://comstylish.com/collections/swimsuit","https://comstylish.com/collections/jumpsuits","https://comstylish.com/collections/womens-set","https://comstylish.com/collections/acc-shoes-dtbh","https://comstylish.com/collections/women-s-acc","https://comstylish.com/collections/women-s-shoes","https://comstylish.com/collections/women-s-socks","https://comstylish.com/collections/women-s-cap","https://comstylish.com/collections/women-s-scarf","https://comstylish.com/collections/women-s-bag","https://comstylish.com/collections/womens-new-arrivals","https://comstylish.com/collections/mens-clothing","https://comstylish.com/collections/christmas-mens-collection","https://comstylish.com/collections/halloween-mens-collection","https://comstylish.com/collections/bohemian-mens-collection","https://comstylish.com/collections/faith-mens-collection","https://comstylish.com/collections/japanese-art-mens-collection","https://comstylish.com/collections/mens-linen","https://comstylish.com/collections/magical-ocean-mens-collection","https://comstylish.com/collections/vikings-celtics-mens-collection","https://comstylish.com/collections/embroidery-art","https://comstylish.com/collections/western-style-mens-collection","https://comstylish.com/collections/dragon-mens-collection","https://comstylish.com/collections/rock-music","https://comstylish.com/collections/reggae-mens-collection","https://comstylish.com/collections/veterans-day","https://comstylish.com/collections/juneteenth-mens-collection","https://comstylish.com/collections/egypt-mens-collection","https://comstylish.com/collections/mens-t-shirts","https://comstylish.com/collections/mens-shirts","https://comstylish.com/collections/mens-polo-shirt","https://comstylish.com/collections/mens-tank-tops","https://comstylish.com/collections/mens-bottoms","https://comstylish.com/collections/mens-sweatshirt-hoodie","https://comstylish.com/collections/denim-jacket-mens-collection","https://comstylish.com/collections/mens-cardigan","https://comstylish.com/collections/mens-sweaters","https://comstylish.com/collections/mens-outerwear","https://comstylish.com/collections/mens-sets","https://comstylish.com/collections/mens-shirt-sets","https://comstylish.com/collections/mens-sweater-sets","https://comstylish.com/collections/mens-accessories","https://comstylish.com/collections/mens-acc","https://comstylish.com/collections/mens-cap","https://comstylish.com/collections/suits-blazers","https://comstylish.com/collections/mens-new-arrivals","https://comstylish.com/collections/best-sellers","https://comstylish.com/collections/womens-best-sellers","https://comstylish.com/collections/mens-best-sellers","https://comstylish.com/collections/new-arrivals","https://comstylish.com/collections/christmas","https://comstylish.com/collections/animals-pattern-collection","https://comstylish.com/collections/cat-collection","https://comstylish.com/collections/dog-collection","https://comstylish.com/collections/household-products","https://comstylish.com/collections/pajamas","https://comstylish.com/collections/blanket","https://comstylish.com/collections/pillows","https://comstylish.com/collections/carpets","https://comstylish.com/collections/bath-towels","https://comstylish.com/collections/shower-curtains","https://comstylish.com/collections/apron","https://comstylish.com/collections/tablecloths"],"scraper_engine":"Puppeteer (Enhanced)","screenshot_size_bytes":96742,"domSignals":{"lang":"en-US","canonical":"https://www.comstylish.com/","hasLogin":false,"hasCheckout":false,"hasContact":true,"hasPolicy":true,"ogTitle":"Comstylish | Everyday Casual Wear Brands","ogSite":"Comstylish | Everyday Casual Wear Brands","ogDescription":"Comstylish integrates design, production and sales to provide you with great value for money clothing for men and women. 500+ new products every day, providing massive selection and great discounts."},"formRisks":[],"httpStatus":200,"finalUrl":"https://www.comstylish.com/","htmlLength":2868326,"textLength":72473,"lowEvidenceRecovery":false,"parkingDetection":{"isParked":false},"otherpages":{"internalLinks":["https://comstylish.com"],"internalPageContents":["const updateHeaderMetrics = () => { const header = document.getElementById('header'); const rect = header.getBoundingClientRect(); const headerHeight = rect.bottom; document.documentElement.style.setProperty('--header-height', `${headerHeight}px`); }; window.addEventListener('DOMContentLoaded', updateHeaderMetrics); window.addEventListener('resize', updateHeaderMetrics); const header = document.getElementById('header'); const resizeObserver = new ResizeObserver(entries => { for (let entry of entries) { const rect = entry.target.getBoundingClientRect(); const headerHeight = rect.bottom; document.documentElement.style.setProperty('--header-height', `${headerHeight}px`); } }); resizeObserver.observe(header);\nfunction setSearchUrl(searchValue) { return Promise.resolve({ url: '/search?q=' + searchValue }); } exportFunction('setSearchUrl', setSearchUrl);\nconst template_name = SHOPLAZZA?.meta?.page?.template_name || ''; const SEARCH_URL = '/search'; const TAG = 'spz-custom-smart-search-location'; const SMART_PRODUCR_SEARCH_WRAP_CLASSNAME = 'app-smart-product-search-container'; const THEME_NAME = window.SHOPLAZZA.theme.merchant_theme_name.replace(/ /g,''); const BREAKPOINT = 960; const DELAY = 300; function diffThemeName(themeNameA, themeNameB){ return themeNameA.toLocaleLowerCase().includes(themeNameB.toLocaleLowerCase()) } const HEADER_DOM_MAP = { eva: 'header .header_grid_layout', geek: `.header-mobile-inner-container`, onePage: 'header .header', wind: 'header #header-nav', nova: 'header .header', hero: 'header .header__nav', 'flash': '#shoplaza-section-header>div>div', 'lifestyle': '#shoplaza-section-header .header__wrapper' } let HEADER_DOM = 'header'; Object.keys(HEADER_DOM_MAP) .map(themeName=>{ if (diffThemeName(THEME_NAME, themeName)) { HEADER_DOM = HEADER_DOM_MAP[themeName]; } }) const SEARCH_ICON_CLASS_MAP = { 'flash': 'app-smart-icon-search-large-flash', 'hero': 'app-smart-icon-search-large-hero', 'geek': 'app-smart-icon-search-large-geek', 'nova': 'app-smart-icon-search-large-nova', }; let SEARCH_ICON_CLASS = 'app-smart-icon-search-large-default'; Object.keys(SEARCH_ICON_CLASS_MAP) .map(themeName=>{ if (diffThemeName(THEME_NAME, themeName)) { SEARCH_ICON_CLASS = SEARCH_ICON_CLASS_MAP[themeName]; } }) class SpzCustomSmartSearchLocation extends SPZ.BaseElement { constructor(element) { super(element); this.mobileHeaderPluginParentEle = null; this.outsideCarouselIndex = 0; this.insideCarouselIndex = 0; this.searchItemType = 'icon'; } static deferredMount() { return false; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } buildCallback() { this.init(); this.listenerResize(); this.initRegisterActions(); } addIconClass(){ document.querySelectorAll('.app-smart-icon-search-large').forEach(e=>{ e.classList.add(SEARCH_ICON_CLASS) }); } moveIcon(){ if (!diffThemeName(THEME_NAME, 'lifestyle')) return; if (this.searchItemType === 'input') return; if (this.isDesktop()) return; const smart_search_dom = document.querySelector('#app-smart-product-search-container-79'); if (!smart_search_dom) return; const hasMovedIcon = !!document.querySelector('.header__wrapper .container .row.header>div>#app-smart-product-search-container-79'); if (hasMovedIcon) return; const headerDivList = document.querySelectorAll('.header__wrapper .container .row.header>div'); const iconBoxDom = headerDivList[headerDivList.length-1] iconBoxDom.appendChild(smart_search_dom, iconBoxDom.firstChild); } init() { this.addIconClass(); this.moveIcon(); if ( this.searchItemType === 'input' ) { document.querySelectorAll('.app-smart-icon-search-large').forEach(e=>e.style.display = 'none'); const mobileSmartSearchDom = document.querySelector(`.smart-search-mobile-container .app-smart-product-search-wrap`); if ( this.isDesktop() ) { document.querySelector(`#app-smart-product-search-container-79`).style=\"display: block\"; if (mobileSmartSearchDom) { document.querySelector(`#app-smart-product-search-container-79`).appendChild(mobileSmartSearchDom); } }else{ if( template_name=='search' ) return; if (!document.querySelector(`.smart-search-mobile-container`)) { const appSmartSearchContainer = document.createElement('div'); appSmartSearchContainer.classList.add('smart-search-mobile-container'); appSmartSearchContainer.classList.add('smart-search-mobile-container-'+THEME_NAME.toLocaleLowerCase()); document.querySelector(HEADER_DOM).appendChild(appSmartSearchContainer); } if (!mobileSmartSearchDom) { document.querySelector(`.smart-search-mobile-container`).appendChild( document.querySelector(`.app-smart-product-search-wrap`) ) } } }else{ document.querySelectorAll('.app-smart-icon-search-large').forEach(e=>e.style.display = 'flex'); } // PC-end not load if (this.isDesktop()) { return; } if (!window.__isLoadAppSmartSearch__) { this.initSmartSearch(); console.log('__isLoadAppSmartSearch__'); } // B-end must reload if (window.self === window.top && !window.__isLoadAppSmartSearch__) { window.__isLoadAppSmartSearch__ = true; } } initSmartSearch() { if (this.hasMobileUpperRightPlugin()) { this.showMobileSmartSearch(); } else { this.addMobileSmartSearch(); } } initRegisterActions(){ this.registOnSearchInputChange(); this.registOnSearchFormSubmit(); this.registOnOutsideCarouselIndexChange(); this.registOnInsideCarouselIndexChange(); this.registGetSearchItemType(); this.registGenerateHotKeywordList(); this.registerAction('onTapHotWord',(invocation)=>{ this.onTapHotWord(invocation.args.type); }); } registOnSearchInputChange(){ this.registerAction('onSearchInputChange',(invocation)=>{ const keyword = invocation.args.keyword; if (keyword === null || !keyword.length) { document.querySelectorAll('.hot-words-carousel-inner-container').forEach(e=>{ e.style='display: block'; }); } else { document.querySelectorAll('.hot-words-carousel-inner-container').forEach(e=>{ e.style='display: none'; }); } }) } registOnSearchFormSubmit(){ this.registerAction('onSearchFormSubmit',(invocation)=>{ const event = invocation.args.event; const keywordArray = event.q || []; const keyword = keywordArray[0]; if (keyword!==null && keyword.length) { this.handleSearchSubmit_(keywordArray,1); } else { this.onTapHotWord('inside') } }) } handleSearchSubmit_(value, retryNum){ SPZ.whenApiDefined(document.getElementById('app-smart-search-79')) .then((ljsSearch) => { try{ ljsSearch.handleSearchSubmit_({ value: value }) }catch(e){ console.log('catch error',retryNum) if( 3 > retryNum ){ this.handleSearchSubmit_(value, retryNum + 1); return; } const searchStr = value[0] || ''; const searchResult = ljsSearch.setThinkSearchData_(searchStr); ljsSearch.afterSearching({ query: searchResult.query, url: `${SEARCH_URL}?q=${searchStr}`, queryType: searchResult.queryType, }) } }) } registOnOutsideCarouselIndexChange(){ this.registerAction('onOutsideCarouselIndexChange',(invocation)=>{ this.outsideCarouselIndex = invocation.args.index || 0; }) } registOnInsideCarouselIndexChange(){ this.registerAction('onInsideCarouselIndexChange',(invocation)=>{ this.insideCarouselIndex = invocation.args.index || 0; }) } registGetSearchItemType(searchItemType){ this.registerAction('getSearchItemType',(invocation)=>{ SPZ.whenApiDefined(document.getElementById('app-smart-search-outside-item-79')) .then((appSmartSearchOutsideItem) => { const search_item_type = appSmartSearchOutsideItem.getData()?.search_item_type; this.searchItemType = search_item_type || this.searchItemType; this.init(); }) }) } registGenerateHotKeywordList(){ this.registerAction('generateHotKeywordList',(invocation)=>{ const search_keywords = invocation.args?.data?.data?.hotKeywordList || []; const isShowHotKeyword = invocation.args?.data?.data?.isShowHotKeyword || false; SPZ.whenApiDefined(document.getElementById('app-smart-search-outside-item-79')) .then((appSmartSearchOutsideItem) => { const hotwords = appSmartSearchOutsideItem.getData()?.search_keywords || []; const new_search_keywords = search_keywords.map((item, index) => { item.url_obj = item.url_obj || {}; const hotwordItem = hotwords.find(e=>e.word === item.word); if (hotwordItem) { item.icon = hotwordItem.icon || ''; } if (!item.urlObj || !item.urlObj.url) { item.urlObj = { ...item.url_obj, url: item.url_obj.type === 'search' ? `${SEARCH_URL}?q=${item.word}` : item.url_obj.url, }; } return item; }); document.querySelectorAll('.app-hot-keyword-render-child') .forEach((ele) => { SPZ.whenApiDefined(ele) .then((hotWordsChildDom) => { hotWordsChildDom.render({ list: new_search_keywords, isShowHotKeyword: isShowHotKeyword, }); }) }); }) }); } onTapHotWord(type){ const index = type === 'inside' ? this.insideCarouselIndex : this.outsideCarouselIndex; SPZ.whenApiDefined(document.getElementById('app-smart-search-outside-item-79')) .then((appSmartSearchOutsideItem) => { const hotwords = appSmartSearchOutsideItem.getData()?.search_keywords || []; const currentHotwordItem = hotwords[index] || null; if (currentHotwordItem && currentHotwordItem.url_obj) { currentHotwordItem.url_obj.url = currentHotwordItem.url_obj.type === 'search' ? `${SEARCH_URL}?q=${currentHotwordItem.word}` : currentHotwordItem.url_obj.url; } SPZ.whenApiDefined(document.getElementById('app-smart-search-79')) .then((ljsSearch) => { if (currentHotwordItem) { ljsSearch.handleHotKeyword_({ word: currentHotwordItem.word, query_type: currentHotwordItem.type, url: currentHotwordItem.url_obj?.url, }); } else { this.handleSearchSubmit_([''],1); } }) }) } getOutsideCarouselConfig(){ return SPZ.whenApiDefined(document.getElementById('app-smart-search-outside-item-79')) .then((appSmartSearchOutsideItem) => { return { ...appSmartSearchOutsideItem.getData(), outsideCarouselIndex: this.outsideCarouselIndex, } }) } listenerResize() { window.removeEventListener('resize', window.smartSearchResizeCallback); window.smartSearchResizeCallback = SPZCore.Types.debounce( this.win, () => { this.init(); }, DELAY ); window.addEventListener('resize', window.smartSearchResizeCallback); } isDesktop() { const mediaQueryList = window.matchMedia(`(min-width: ${BREAKPOINT}px)`); return mediaQueryList.matches; } hasMobileUpperRightPlugin() { return !['geek', 'flash', 'boost'].includes(THEME_NAME.toLocaleLowerCase()); } showMobileSmartSearch() { this.mobileHeaderPluginParentEle = this.getMobileHeaderPluginParentEle(); this.setMobileHeaderIconsPluginStyle(this.mobileHeaderPluginParentEle); } getMobileHeaderPluginParentEle() { const MOBILE_HEADER_PLUGIN_PARENT_ELE_MAP = { nova: '.header__mobile #header__plugin-container', hero: '.header__icons .tw-flex.tw-justify-end.tw-items-center.tw-space-x-7', onePage: '.header__mobile #header__plugin-container', wind: '#header-icons .flex.justify-end.items-center', eva: '#header__icons .plugin_content' }; const headerPluginParentSelector = this.combineMultipleSelectors( Object.values(MOBILE_HEADER_PLUGIN_PARENT_ELE_MAP) ); return document.querySelector(headerPluginParentSelector); } setMobileHeaderIconsPluginStyle(pluginParentEle) { if (!pluginParentEle) { return; } const containHidden = pluginParentEle.classList.contains('md:hidden'); const containTwHidden = pluginParentEle.classList.contains('md:tw-hidden'); if (containHidden || containTwHidden) { Array.from(pluginParentEle.children).forEach((pluginElement) => { if (!this.hasSmartSearchPlugin(pluginElement)) { pluginElement.style.display = 'none'; } }); pluginParentEle.classList.remove('md:hidden', 'md:tw-hidden'); } else { const smartSearchPluginElement = Array.from(pluginParentEle.children).find( (pluginElement) => { return this.hasSmartSearchPlugin(pluginElement); } ); smartSearchPluginElement.style.display = 'block'; } } hasSmartSearchPlugin(pluginElement) { return ( pluginElement.classList.contains(`${SMART_PRODUCR_SEARCH_WRAP_CLASSNAME}`) || pluginElement.querySelectorAll(`.${SMART_PRODUCR_SEARCH_WRAP_CLASSNAME}`).length > 0 ); } addMobileSmartSearch() { this.mobileHeaderIconsEle = this.getMobileHeaderIconsEle(); this.smartSearchWrapEle = this.getSmartSearchWrapEle(); this.appendSmartSearchToHeader(); } getMobileHeaderIconsEle() { // Must be the parent element of the plugin const MOBILE_HEADER_ICONS_ELE_MAP = { geek: '#header-mobile-container .flex.items-center.justify-end.flex-shrink-0', flash: '#header-layout .header__icons', boost: '.header__mobile-bottom .tw-flex.tw-items-center.tw-justify-end.tw-flex-1' }; const headerIconsSelector = this.combineMultipleSelectors( Object.values(MOBILE_HEADER_ICONS_ELE_MAP) ); return document.querySelector(headerIconsSelector); } getSmartSearchWrapEle() { const smartSearchWrapEle = document.querySelector(this.getSmartSearchWrapSelector()); if (!smartSearchWrapEle) { return null; } return smartSearchWrapEle; } appendSmartSearchToHeader() { if (!this.smartSearchWrapEle) { return; } this.mobileHeaderIconsEle.insertAdjacentElement('afterbegin', this.smartSearchWrapEle); } getSmartSearchWrapSelector() { const PLUGIN_POSITION = { DRAWER: 'drawer', HEADER_TOP: 'headerTop' }; // only one this plugin of ancestor element const MOBILE_PLUGIN_POSITION_ELE_MAP = { [PLUGIN_POSITION.DRAWER]: { geek: '#header-menu-mobile #menu-drawer', flash: '#menu-drawer .plugin__header-content', boost: '.header__drawer' }, [PLUGIN_POSITION.HEADER_TOP]: { geek: '#header-menu-mobile #menu-drawer', flash: '#menu-drawer .plugin__header-content', boost: '.header-content .logo-wrap' } }; const MbPluginPositionInTheme = [ ...Object.values(MOBILE_PLUGIN_POSITION_ELE_MAP[PLUGIN_POSITION.DRAWER]), ...Object.values(MOBILE_PLUGIN_POSITION_ELE_MAP[PLUGIN_POSITION.HEADER_TOP]) ]; return Object.values(MbPluginPositionInTheme).reduce((pre, ancestor) => { if (pre === '') { return `${ancestor} .app-smart-product-search-container`; } if (pre.includes(ancestor)) { return pre; } return `${pre},${ancestor} .app-smart-product-search-container`; }, ''); } combineMultipleSelectors(selectorList) { return selectorList.reduce((pre, selector) => { if (pre === '') { return `${selector}`; } if (pre.includes(selector)) { return pre; } return `${pre},${selector}`; }, ''); } } SPZ.defineElement(TAG, SpzCustomSmartSearchLocation);\nfunction setSearchUrl(searchValue) { return Promise.resolve({ url: '/search?q=' + searchValue }); } exportFunction('setSearchUrl', setSearchUrl);\nfunction setSearchUrl(searchValue) { return Promise.resolve({ url: '/search?q=' + searchValue }); } exportFunction('setSearchUrl', setSearchUrl);\nWomen's Clothing\nMen's Clothing\nAccessories\nHousehold Products\nComstylish Vintage Dandelion Crystal Necklace\n$6.99\nComstylish Retro Christmas Tree Casual Sweatshirt\n$21.68\n$28.99\nSave $7.31\nView more\nChristmas\n\n\n\nView More\n\nThanksgiving\n\nView More\n\nVikings & Celtics\n\n\n\n\nView More\n\nJapanese Art\n\n\n\n\n\n\n\nView More\n\nSee more hot-selling styles\nBEST SELLERS\nShop now\nComstylish Vintage Dandelion Crystal Necklace\n$6.99\nComstylish Fuzzy Golden Doodle Dog Felt Cozy Knit Sweater\n$26.59\n$31.99\nSave $5.40\nComstylish 3/4 Sleeve Round Neck Cotton and Linen T-Shirt\n$25.99\nComstylish Creative Cat Piercing Stud Earrings\n$8.99\nComstylish Women's Dragonfly Print Casual Shirt\n$31.99\nComstylish St. Patrick's Day Shamrock Print Sweatshirt\n$26.99\nComstylish Wild Flowers Oil Painting Art Cozy Knit Hooded Cardigan\n$41.35\n$46.99\nSave $5.64\nComstylish Casual Loose Colorful Sweater Cardigan\n$31.99\nComstylish Elegant Violet Wildflower Embroidery Art Comfy T Shirt\n$22.99\n$25.99\nSave $3.00\nComstylish Cherry Blossom Japanese Flowy Midi Dress\n$27.27\n$30.99\nSave $3.72\nComstylish Santa Claus Print Crew Neck Casual Sweatshirt\n$26.99\nNEW ARRIVALS\nShop now\nComstylish Lady Christmas Retro Hooded Cloak\n$49.99\nComstylish Lady Christmas Retro Hooded Cloak\n$49.99\nComstylish Lady Christmas Retro Hooded Cloak\n$49.99\nComstylish Fox And Floral Pattern Warm Plush Pullover Sweater\n$35.99\nComstylish Women's Winter Warm Cute Dogs Knitted Sweater Coat\n$49.99\nComstylish Vintage Khaki Plaid Inspired Belted Cottagecore Autumn Winter Long Sleeve Button-up Shirt Maxi Dress\n$75.99\nComstylish Vintage Red Plaid Inspired Long Sleeve Button-up Shirt Maxi Dress\n$55.99\nComstylish Vintage Green Plaid Inspired Long Sleeve Button-up Shirt Maxi Dress\n$55.99\nComstylish Vintage Green Plaid Inspired Belted Cottagecore Autumn Winter Long Sleeve Button-up Shirt Maxi Dress\n$75.99\nComstylish Vintage Khaki Plaid Inspired Belted Cottagecore Autumn Winter Long Sleeve Button-up Shirt Maxi Dress\n$75.99\nComstylish Vintage Red Plaid Inspired Long Sleeve Button-up Shirt Maxi Dress\n$55.99\nconst isSpecialHeroTheme = window.SHOPLAZZA?.theme?.merchant_theme_name == 'Hero' && window.SHOPLAZZA?.theme?.merchant_theme_c_version == '2.2.19'; const specialHeroThemeClassName = 'hero_2_2_19_smart_recommend_block'; class SpzSmartBlockComponent extends SPZ.BaseElement { constructor(element) { super(element); this.templates_ = null; this.container_ = null; this.i18n_ = {}; this.config_ = {}; this.show_type_ = 3; this.product_resource_id_ = ''; this.collection_resource_id_ = ''; this.cart_items_ = []; this.customer_id_ = ''; this.order_id_ = ''; } static deferredMount() { return false; } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } buildCallback() { const template_type = window.C_SETTINGS.meta.page.template_type; if (template_type === 1) { this.show_type_ = 3; this.product_resource_id_ = window.C_SETTINGS.meta.page.resource_id; } else if (template_type === 2) { this.show_type_ = 4; this.collection_resource_id_ = window.C_SETTINGS.meta.page.resource_id; } else if (template_type === 15){ this.show_type_ = 5; } else if (template_type === 13){ this.show_type_ = 6; } else if (template_type === 20){ this.show_type_ = 7; this.customer_id_ = window.C_SETTINGS.customer.customer_id; } else if (template_type === 35){ this.show_type_ = 8; this.order_id_ = window.location.pathname.split('/').pop(); } this.templates_ = SPZServices.templatesForDoc(this.element); this.setAction_(); } mountCallback() { const that = this; const themeName = window.C_SETTINGS.theme.merchant_theme_name; const isGeek = /Geek/.test(themeName); this.fetchRules().then((res) => { if (res && res.rules && res.rules.length) { const blockEl = document.getElementById('smart_recommend_block'); this.initBlockClass(blockEl); this.initItemClass(blockEl); SPZ.whenApiDefined(blockEl).then((api) => { api.render({data: res}, true).then(() => { if (isGeek && that.show_type_ === 6) { blockEl.querySelector('.plugin_container_wrpper').style.padding = '30px 0'; } const recommendStyle = document.createElement('style'); recommendStyle.innerHTML = ` .plugin__recommend_container,.app-recommend-card { display: none !important; } `; document.head.appendChild(recommendStyle); const fetchList = []; res.rules.forEach((rule) => { fetchList.push(this.fetchRuleProductList(rule.id)); }); const fetchAll = Promise.all(fetchList); fetchAll.then((p_res) => { res.rules.forEach((rule, index) => { rule.products = p_res[index] && p_res[index].products; if (rule.products && rule.products.length) { const modalRender = document.getElementById('smart_recommend_js_root'); const $dest = document.getElementById('cart'); const isLifeStyle = /Life.*Style/.test(window.C_SETTINGS.theme.merchant_theme_name); if (modalRender && isLifeStyle && $dest.clientWidth > 767) { modalRender.classList.add('zb-mt-[-180px]') } } const ruleEl = document.getElementById('smart_recommend_rule_' + rule.id); SPZ.whenApiDefined(ruleEl).then((api) => { api.render({data: rule}, true).then(() => { that.impressListen(`#smart_recommend_rule_ul_${rule.id}`, function(){ that.trackRuleImpress(rule); }); const btnElList = document.querySelectorAll(`#smart_recommend_rule_ul_${rule.id} button`); btnElList.forEach((btnEl) => { if (btnEl && rule.config && rule.config.quick_shop_button_bg_color && rule.config.quick_shop_button_text_color) { btnEl.style.backgroundColor = rule.config.quick_shop_button_bg_color; btnEl.style.color = rule.config.quick_shop_button_text_color; } }) if (isSpecialHeroTheme) { ruleEl.querySelectorAll(`.smart_recommend_title`).forEach(dom=>{ dom.classList.add('type-title-font-family'); }); document.querySelectorAll(`.${specialHeroThemeClassName} #smart_recommend_rule_ul_${rule.id} .zb-recommend-price-line-through .money`).forEach(dom=>{ dom.classList.add('type-body-font-family'); }); } }); }); }); }); }) }) } else { if (window.top !== window.self) { const template_type = window.C_SETTINGS.meta.page.template_type; const holderEl = document.getElementById('smart_recommend_preview_no_data_placeholder'); SPZ.whenApiDefined(holderEl).then((api) => { api.render({data: { isCart: template_type === 13, isCollection: template_type === 2, isProduct: template_type === 1, isIndex: template_type === 15 }}, true); }); } } }); } initBlockClass(blockEl) { if (!blockEl) return; if (blockEl.parentElement && blockEl.parentElement.offsetWidth === document.body.clientWidth) { blockEl.classList.add('smart_recommend_block_fullscreen'); } if (isSpecialHeroTheme) { blockEl.classList.add(specialHeroThemeClassName); } } initItemClass(blockEl) { if (blockEl) { const containerWidth = blockEl.offsetWidth; let itemWidth = ''; if (containerWidth > 780) { itemWidth = '16%'; } else if (containerWidth > 600) { itemWidth = '20%'; } else { itemWidth = '24%'; } const itemStyleEl = document.createElement('style'); itemStyleEl.innerHTML = `.zb-recommend-li-item{ width: ${itemWidth}; }`; document.body.appendChild(itemStyleEl); } } setAction_() { this.registerAction('quickShop', (data) => { const that = this; const product_id = data.args.product_id; const productIndex = data.args.productIndex; const rule_id = data.args.rule_id; const ssp = data.args.ssp; const scm = data.args.scm; const cfb = data.args.cfb; const ifb = data.args.ifb; const modalRender = document.getElementById('smart_recommend_product_modal_render'); if (modalRender) { document.body.appendChild(modalRender); } if (product_id) { this.fetchProductData(product_id).then((res) => { const product = res.products && res.products.length && res.products[0] || {}; product.cfb = cfb; product.ifb = ifb; SPZ.whenApiDefined(modalRender).then((api) => { api.render({product: product, productIndex: productIndex, rule_id: rule_id, ssp: ssp, scm: scm, show_type: that.show_type_}, true).then(() => { const modalEl = document.getElementById('smart_recommend_product_modal'); SPZ.whenApiDefined(modalEl).then((modal) => { that.impressListen('#smart_recommend_product_modal', function(){ that.trackQuickShop({ rule_id: rule_id, product_id: product_id }); }); modal.open(); }); const formEl = document.getElementById('smart_recommend_product_form'); SPZ.whenApiDefined(formEl).then((form) => { form.setProduct(product); }); const variantEl = document.getElementById('smart_recommend_product_variants'); SPZ.whenApiDefined(variantEl).then((variant) => { variant.handleRender(product); }); }); }) }); } }); this.registerAction('handleScroll', (data) => { this.directTo(data.args.rule_id, data.args.direction); }); this.registerAction('handleProductChange', (data) => { const variant = data.args.data.variant; const product = data.args.data.product; const imageRenderEl = document.getElementById('smart_recommend_product_image'); SPZ.whenApiDefined(imageRenderEl).then((api) => { api.render({ variant: variant, product: product }); }); }); this.registerAction('handleAtcSuccess', (detail) => { const data = detail.args; data.data.product = data.data.product || {}; data.data.variant = data.data.variant || {}; const product_id = data.data.product.id; const product_title = data.data.product.title; const variant_id = data.data.variant.id; const price = data.data.variant.price; const rule_id = data.rule_id; const aid = `smart_recommend.${this.show_type_}.${rule_id}`; const ifb = data.data.product.ifb; const cfb = data.data.product.cfb; const ssp = data.ssp; const scm = data.scm; const spm = `smart_recommend_${this.show_type_}.${data.spmIndex}`; const params = { id: product_id, product_id: product_id, number: 1, name: product_title, variant_id: variant_id, childrenId: variant_id, item_price: price, source: 'add_to_cart', _extra: { aid: aid, ifb: ifb, cfb: cfb, scm: scm, spm: `..${window.C_SETTINGS.meta.page.template_name}.${spm}`, ssp: ssp, } }; this.tranckAddToCart(params); }); this.registerAction('addATCHook', (data) => { const params = data.args; const spm = `smart_recommend_${this.show_type_}.${params.spmIndex}`; this.myInterceptor_ = window.djInterceptors && window.djInterceptors.track.use({ event: 'dj.addToCart', params: { aid: `smart_recommend.${this.show_type_}.` + params.rule_id, ssp: params.ssp, scm: params.scm, cfb: params.cfb, spm: `..${window.C_SETTINGS.meta.page.template_name}.${spm}`, }, once: true }); }); } tranckAddToCart(detail) { if (window.$) { window.$(document.body).trigger('dj.addToCart', detail); } } fetchRules() { const payload = { show_type: this.show_type_, }; let that = this; if (this.show_type_ === 6) { let line_items = []; return this.fetchCart().then((res) => { if (res && res.cart && res.cart.line_items) { line_items = res.cart.line_items.map((item) => { return { product_id: item.product_id, variant_id: item.variant_id, quantity: item.quantity, price: item.price } }); } payload.line_items = line_items; that.cart_items_ = line_items; return that.fetchRulesRequest(payload); }); } else { if (this.show_type_ === 3) { payload.line_items = [{ product_id: this.product_resource_id_ }]; } else if (this.show_type_ === 4) { payload.collection_id = this.collection_resource_id_; } else if (this.show_type_ === 7) { payload.customer_id = this.customer_id_; } else if (this.show_type_ === 8) { payload.order_id = this.order_id_; } return this.fetchRulesRequest(payload); } } fetchRulesRequest(payload) { return fetch(window.C_SETTINGS.routes.root + \"/api/possum/recommend_query\", { method: \"POST\", headers: { \"Content-Type\": \"application/json\" }, body: JSON.stringify(payload) }).then(function(res){ if(res.ok){ return res.json(); } }); } fetchCart() { return fetch(`/api/cart/cart-select?r=${Math.random().toString(36).slice(-4)}`) .then((res) => { if (res.ok) { return res.json(); } }); } fetchRuleProductList(rule_id) { const payload = { page: 1, limit: 100, fields: [\"title\", \"url\", \"image\", \"min_price_variant.price\", \"min_price_variant.compare_at_price\"], rule_id: rule_id, }; if (this.show_type_ === 3) { payload.line_items = [{ product_id: this.product_resource_id_ }]; } else if (this.show_type_ === 4) { payload.collection_id = this.collection_resource_id_; } else if (this.show_type_ === 6) { payload.line_items = this.cart_items_; } else if (this.show_type_ === 7) { payload.customer_id = this.customer_id_; } else if (this.show_type_ === 8) { payload.order_id = this.order_id_; } return fetch(window.C_SETTINGS.routes.root + \"/api/possum/recommend_products\", { method: \"POST\", headers: { \"Content-Type\": \"application/json\" }, body: JSON.stringify(payload) }).then(function(res){ if(res.ok){ return res.json(); } }).catch(function(err){ console.log(err); }); } fetchProductData(product_id) { return fetch(window.C_SETTINGS.routes.root + \"/api/possum/products\", { method: \"POST\", headers: { \"Content-Type\": \"application/json\" }, body: JSON.stringify({ product_ids: [product_id], fields: [ \"images\", \"options\", \"min_price_variant\", \"variants\"] }) }).then(function(res){ if(res.ok){ return res.json(); } }).catch(function(err){ console.log(err); const loadingEl = document.getElementById('smart_recommend_loading'); if (loadingEl) { loadingEl.style.display = 'none'; } }); } getStyle(ele, style) { if (!ele) return; if (window.getComputedStyle) { return window.getComputedStyle(ele)[style]; } return ele.currentStyle[style]; } directTo(id, direction) { const scrollElement = document.getElementById(`smart_recommend_rule_ul_${id}`); const blockWidth = parseInt(this.getStyle(scrollElement, 'width')); const scrollLength = (blockWidth * 0.19 - 12) * 5; const scrollPoint = scrollElement.scrollWidth - scrollElement.clientWidth; if (!scrollElement) return; if (direction === 'left') { if (document.dir === 'rtl') { scrollElement.scrollTo({ left: Math.abs(scrollElement.scrollLeft) >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft - scrollLength, behavior: 'smooth' }); return; } scrollElement.scrollTo({ left: Math.max(scrollElement.scrollLeft - scrollLength, 0), behavior: 'smooth' }); } else { if (document.dir === 'rtl') { scrollElement.scrollTo({ left: Math.abs(scrollElement.scrollLeft) >= scrollPoint + 100 ? 0 : scrollElement.scrollLeft + scrollLength, behavior: 'smooth' }); return; } scrollElement.scrollTo({ left: scrollElement.scrollLeft >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft + scrollLength, behavior: 'smooth' }); } } trackRuleImpress(rule) { if (window.sa && window.sa.track) { window.sa.track(\"plugin_common\", { plugin_name: \"upsell\", event_type: \"impressions\", rule_id: rule.id, ssp: rule.ssp, scm: rule.scm, show_type: this.show_type_, support_app_block: window.C_SETTINGS.theme.support_app_block }); window.sa.track(\"module_impressions\", { aid: `smart_recommend.${this.show_type_}.${rule.id}`, support_app_block: window.C_SETTINGS.theme.support_app_block }); } } trackQuickShop(data) { window.sa && sa.track && sa.track(\"plugin_common\", { plugin_name: \"upsell\", event_type: \"quick_shop\", rule_id: data.rule_id, product_id: data.product_id, show_type: this.show_type_, }); } impressListen(selector, cb) { const el = document.querySelector(selector); const onImpress = (e) => { if (e) { e.stopPropagation(); } cb(); }; if (el && !el.getAttribute('imprsd')) { el.addEventListener('impress', onImpress) } else if (el) { onImpress(); } } } SPZ.defineElement('spz-custom-smart-block', SpzSmartBlockComponent);\nSign up to receive special offers, giveaways and one-time deals. — Discount code:: COMST\nCOMPANY INFO\nHELP & SUPPORT\nFollow us\nWe Accept\n© 2025 Comstylish | Everyday Casual Wear Brands"]}},"webrisk":{"overall_risk":"unknown","threats":[],"malware":false,"social_engineering":false,"unwanted_software":false,"error":"Request failed with status code 400"},"metadata":{"preflight":{"bestUrl":"https://comstylish.com","probes":[{"url":"https://comstylish.com","ok":true,"status":200},{"url":"https://www.comstylish.com","ok":true,"status":200},{"url":"http://comstylish.com","ok":true,"status":200}],"zyteCheck":null},"best_url":"https://comstylish.com","phase_a_duration_ms":3857,"phase_b_duration_ms":23201,"early_exit_reason":null,"tls_warnings":[],"zyte_preflight":null,"low_evidence_recovery":false},"virustotal":{"malicious":1,"suspicious":0,"total":97,"scanned":true},"evidence_coverage":"90","ai_result_latest":{"flag":"high_risk","rate":25,"about":"

Detailed Analysis Report: Is comstylish.com Safe and Legit?

\n

Website Overview and Purpose

\n

comstylish.com is an e-commerce platform that claims to offer a wide range of affordable clothing and accessories for men and women. The site promotes itself as a destination for casual wear, featuring various categories including dresses, tops, and seasonal items like Halloween and Christmas apparel.

\n

Content Quality and User Experience

\n

Key Experience Highlights

\n\n

Claims Verification and Red Flags

\n

⚠️ Red Flags Detected

\n

Several concerning indicators suggest that this site may not be legitimate:

\n\n

⚠️ Caution Points

\n\n

Security Note: The site uses a DV SSL certificate, which provides basic encryption but does not guarantee legitimacy.

\n

Legitimacy and Reputation Assessment

\n

The domain has been operational for 4 years, which is relatively short for an e-commerce site. It is hosted in the US by Cloudflare, a common provider for many websites. However, the lack of a solid archive history and the presence of a VirusTotal flag raise concerns about its legitimacy.

\n

Final Verdict and Recommendations

\n

Conclusion: Based on the numerous red flags and lack of transparency, comstylish.com appears to be a high-risk e-commerce site. Users should exercise caution and consider alternative, more established retailers for their shopping needs.

\n

Best practices include researching the site thoroughly, checking for customer reviews, and avoiding sharing sensitive information.

","status":"scam","reasons":["[FINANCIAL] Claims of up to 50% off on products, which is often a tactic used by scam sites to attract customers.","[TRANSPARENCY] No verifiable company information or contact details available, raising concerns about legitimacy.","[DOMAIN HISTORY] Domain is only 4 years old, which is relatively new for an e-commerce site claiming extensive offerings.","[SECURITY] The site has been flagged by 1 out of 97 vendors on VirusTotal, indicating potential security risks.","[ARCHIVE] No significant archive history found, suggesting a lack of established presence or credibility."],"category":"E-commerce","red_flags":["[GUARDRAIL] No deterministic evidence for scam; downgrading to warning","[CLAIMS] Unrealistic discounts of up to 50% off on various items, typical of scam tactics.","[TRANSPARENCY] Missing clear contact information and company registration details.","[SECURITY] VirusTotal flagged the site as potentially malicious.","[DOMAIN HISTORY] The domain is relatively new, raising concerns about its credibility.","[ARCHIVE] Lack of significant archive history indicating a short operational timeline."],"final_score":25,"subcategory":"Clothing Retail","final_status":"warning","score_source":"openai_guardrail","ai_confidence":"medium","claimed_brand":null,"brand_evidence":[],"business_model":"Selling clothing and accessories at discounted prices","expected_domain":null,"target_audience":"Online shoppers looking for affordable fashion","confidence_level":"medium","guardrail_actions":[{"type":"scam_downgraded","reason":"No deterministic evidence for scam; downgrading to warning","scoreCeiling":null,"targetStatus":"warning"}],"analysis_timestamp":"2025-11-08T09:58:15.157Z","user_recommendation":"Exercise caution and consider alternative retailers.","contact_transparency":"poor","professionalism_score":4,"brand_claim_confidence":null},"final_domain_age":{"days":1615,"years":4,"source":"rdap","verified":true,"allSources":["rdap"]},"guardrail_summary":{"actions":[{"type":"scam_downgraded","reason":"No deterministic evidence for scam; downgrading to warning","scoreCeiling":null,"targetStatus":"warning"}],"scoreSource":"openai_guardrail","aiConfidence":"medium"}},"reviews":[],"has_archive":false,"archive_data":null,"archive_stats":null}};