@salla.sa/twilight-components
Version:
Salla Web Component
452 lines (451 loc) • 16.4 kB
JavaScript
/*!
* Crafted with ❤ by Salla
*/
import { h } from "@stencil/core";
import { CommentType } from "./interfaces";
import anime from "animejs";
import Helper from "../../Helpers/Helper";
import ChatBubbles from "../../assets/svg/chat-bubbles.svg";
export class SallaComments {
constructor() {
this.itemId = undefined;
this.loadMoreText = undefined;
this.hideForm = undefined;
this.blockTitle = undefined;
this.hideTitle = undefined;
this.type = CommentType.PAGE;
this.showFormAvatar = false;
this.hideBought = false;
this.sort = undefined;
this.testimonials = false;
this.comments = undefined;
this.pagination = undefined;
this.total = undefined;
this.showPlaceholder = undefined;
this.nextPage = undefined;
this.mostHelpfulLabel = undefined;
this.noComments = salla.lang.get('blocks.comments.no_comments');
this.comment_title = salla.lang.get('blocks.comments.title');
this.comment_name = salla.lang.get('blocks.comments.comment');
this.placeholder_text = undefined;
this.showRatingSummary = salla.config.get('store.settings.rating.show_rating_summary');
this.allowLikes = salla.config.get('store.settings.rating.allow_likes');
salla.onReady(() => {
this.allowLikes = salla.config.get('store.settings.rating.allow_likes');
this.showRatingSummary = salla.config.get('store.settings.rating.show_rating_summary');
});
salla.lang.onLoaded(() => {
this.comment_title = salla.lang.get('blocks.comments.title');
this.comment_name = salla.lang.get('blocks.comments.comment');
this.noComments = salla.lang.get('pages.rating.no_ratings');
const setNestedAsync = (lang, key, value) => {
return new Promise((resolve) => {
salla.helpers.setNested(salla.lang.messages[lang], key, value);
resolve(true);
});
};
const setTranslations = async () => {
await setNestedAsync('ar.trans', 'blocks.comments.most_helpful', 'الأكثر إفادة');
await setNestedAsync('en.trans', 'blocks.comments.most_helpful', 'Most helpful');
this.mostHelpfulLabel = salla.lang.get('blocks.comments.most_helpful');
this.comment_title = salla.lang.get('blocks.comments.title');
this.comment_name = salla.lang.get('blocks.comments.comment');
this.noComments = salla.lang.get('pages.rating.no_ratings');
};
setTranslations();
});
}
// TOOD: it's a good idea to move this into lang.js
// Pluralize a string based on the count
pluralize(phrases, count) {
const options = phrases.split('|');
const conditions = [
{ condition: count === 0, index: 0 },
{ condition: count === 1, index: 1 },
{ condition: count === 2, index: 2 },
{ condition: count > 2 && count <= 10, index: 3 },
{ condition: count >= 11, index: 4 }
];
const { index } = conditions.find(({ condition }) => condition) || { index: options.length - 1 };
const selectedOption = options[index];
return selectedOption.replace(':count', salla.helpers.number(count.toString()))
.replace(/\{[0-9]+\}/g, '')
.replace(/\[\d+,\d+\]|\[11,\*\]/g, '');
}
// Initiate infinite scroll
initiateInfiniteScroll() {
var _a, _b, _c;
if (!this.wrapper) {
console.error('Wrapper is undefined. Cannot initiate infinite scroll.');
return;
}
this.infiniteScroll = salla.infiniteScroll.initiate(this.wrapper, this.wrapper, {
path: () => this.nextPage,
history: true,
nextPage: this.nextPage,
scrollThreshold: false,
}, true);
(_a = this.infiniteScroll) === null || _a === void 0 ? void 0 : _a.on('request', _response => {
this.loading();
});
(_b = this.infiniteScroll) === null || _b === void 0 ? void 0 : _b.on('load', response => {
this.pagination = response.pagination;
this.nextPage = typeof response.pagination.links == 'object' && !!response.pagination.links.next ? response.pagination.links.next : null;
this.handleResponse(response).forEach(card => this.wrapper.append(card));
let items = this.host.querySelectorAll('salla-comment-item:not(.animated):not(.s-comments-item-admin)');
this.animateItems(items);
this.loading(false);
});
(_c = this.infiniteScroll) === null || _c === void 0 ? void 0 : _c.on('error', (e) => {
salla.console.error('Error loading more comments:', e);
});
}
// Show/hide loading
loading(isLoading = true) {
var _a;
let btnText = (_a = this.status) === null || _a === void 0 ? void 0 : _a.querySelector('.s-button-text');
if (btnText) {
Helper.toggleElementClassIf(btnText, 's-button-hide', 's-button-show', () => isLoading);
this.btnLoader.style.display = isLoading ? 'inherit' : 'none';
}
}
// Animate newly added items
animateItems(items) {
anime({
targets: items,
opacity: [0, 1],
duration: 1200,
translateY: [20, 0],
delay: function (_el, i) {
return i * 100;
},
easing: 'easeOutExpo',
complete: function (_anim) {
items.forEach(item => {
item.classList.add('animated');
});
}
});
}
async reload() {
this.showPlaceholder = false;
if (this.wrapper) {
this.wrapper.innerHTML = "";
let loading = document.createElement('salla-loading');
this.wrapper.append(loading);
}
this.nextPage = null;
this.loadInitialData();
}
// Get comment item HTML
getCommentHTML(comment) {
const commentItem = document.createElement('salla-comment-item');
commentItem.comment = comment;
commentItem.hideBought = this.hideBought;
return commentItem;
}
// Parse response and return an array of comment items to be appended to the wrapper
handleResponse(response) {
var _a;
return ((_a = response.data) === null || _a === void 0 ? void 0 : _a.map(comment => this.getCommentHTML(comment))) || [];
}
componentWillLoad() {
return salla.onReady()
.then(() => this.showRatingSummary = salla.config.get('store.settings.rating.show_rating_summary'))
.then(() => this.loading())
.then(() => {
this.hideTitle = this.hideTitle || this.testimonials;
this.hideForm = this.hideForm || this.testimonials;
return this.loadInitialData();
});
}
// Load initial data
async loadInitialData() {
try {
let resp, searchParams = new URLSearchParams(window.location.search);
searchParams.has('sort') && (this.sort = searchParams.get('sort'));
if (this.testimonials) {
let params = {
sort: this.sort,
type: "store"
};
resp = await salla.api.request('reviews', { params }, 'get');
}
else {
resp = await salla.api.comment.getComments(this.type, this.itemId);
}
if (!resp.data || !resp.data.length) {
this.showPlaceholder = false;
this.loading(false);
return;
}
this.wrapper && (this.wrapper.innerHTML = "");
this.comments = resp.data;
this.pagination = resp.pagination;
this.total = resp.pagination.total;
this.nextPage = typeof resp.pagination.links == 'object' && !!resp.pagination.links.next ? resp.pagination.links.next : null;
setTimeout(() => {
this.handleResponse(resp).forEach(card => this.wrapper.append(card));
this.initiateInfiniteScroll(); // Initiate infinite scroll after the initial data is loaded
let items = this.wrapper.querySelectorAll('salla-comment-item:not(.animated)');
this.animateItems(items);
}, 100);
}
catch (error) {
console.error('Error loading initial data:', error);
this.showPlaceholder = true;
this.loading(false);
}
}
// Get next page
async loadMore() {
var _a;
(_a = this.infiniteScroll) === null || _a === void 0 ? void 0 : _a.loadNextPage();
}
render() {
// We should show a different placeholder for pages and products (WIP)
if (this.showPlaceholder) {
return (h("div", null, !!this.total && !this.hideTitle ? h("h2", { class: "s-comments-title" }, this.blockTitle ? this.blockTitle : this.comment_title) : '', !this.hideForm && !this.testimonials ? h("salla-comment-form", { showAvatar: this.showFormAvatar, type: this.type, "item-id": this.itemId }) : '', h("div", { class: "s-comments-placeholder" }, h("span", { innerHTML: ChatBubbles }), h("p", null, this.noComments))));
}
return (h("div", { class: `s-comments s-comments-${this.testimonials ? 'testimonials' : this.type}` }, h("div", { class: `${this.type == CommentType.PAGE ? "s-comments-page-container" : "s-comments-container"}` }, !!this.total && !this.hideTitle ? h("h2", { class: "s-comments-title" }, this.blockTitle ? this.blockTitle : this.comment_title) : '', !this.hideForm && h("salla-comment-form", { showAvatar: this.showFormAvatar, type: this.type, "item-id": this.itemId }), this.showRatingSummary && salla.url.is_page('product.single') ? h("salla-reviews-summary", { itemId: this.itemId }) : '', h("div", { class: `s-comments-header ${!!this.total ? "has-total" : ""}` }, !!this.total && h("h2", { class: "s-comments-count-label", innerHTML: this.pluralize(this.comment_name, this.total) }), !!this.total && !this.testimonials && this.type !== CommentType.BLOG ?
h("div", { class: "s-comments-filter-wrapper" }, h("label", { class: "s-comments-filter-label", htmlFor: "comments-filter" }, salla.lang.get('pages.categories.sorting')), h("select", { id: "comments-filter", class: "s-form-control s-comments-sort-input", onChange: (e) => {
this.sort = e.target.value;
this.reload();
} }, h("option", { value: "latest", selected: true }, salla.lang.get("pages.testimonials.sort_by_date_desc")), h("option", { value: "oldest" }, salla.lang.get("pages.testimonials.sort_by_date_asc")), this.allowLikes && h("option", { value: "most_helpful" }, this.mostHelpfulLabel)))
: ''), h("div", { ref: wrapper => this.wrapper = wrapper }), this.nextPage && (h("div", { class: "s-infinite-scroll-wrapper", ref: status => this.status = status }, h("button", { onClick: () => this.loadMore(), class: "s-infinite-scroll-btn s-button-btn s-button-primary", type: "button" }, h("span", { class: "s-button-text s-infinite-scroll-btn-text" }, this.loadMoreText ? this.loadMoreText : salla.lang.get('common.elements.load_more')), h("span", { class: "s-button-loader s-button-loader-center s-infinite-scroll-btn-loader", ref: btnLoader => this.btnLoader = btnLoader, style: { "display": "none" } })))))));
}
static get is() { return "salla-comments"; }
static get originalStyleUrls() {
return {
"$": ["salla-comments.scss"]
};
}
static get styleUrls() {
return {
"$": ["salla-comments.css"]
};
}
static get properties() {
return {
"itemId": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": true,
"optional": false,
"docs": {
"tags": [],
"text": "Page or product ID"
},
"attribute": "item-id",
"reflect": false
},
"loadMoreText": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Load more text"
},
"attribute": "load-more-text",
"reflect": false
},
"hideForm": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Load more text"
},
"attribute": "hide-form",
"reflect": false
},
"blockTitle": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Block Title"
},
"attribute": "block-title",
"reflect": false
},
"hideTitle": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Hide Title"
},
"attribute": "hide-title",
"reflect": false
},
"type": {
"type": "string",
"mutable": false,
"complexType": {
"original": "CommentType.PAGE | CommentType.PRODUCT | CommentType.BLOG",
"resolved": "CommentType.BLOG | CommentType.PAGE | CommentType.PRODUCT",
"references": {
"CommentType": {
"location": "import",
"path": "./interfaces",
"id": "src/components/salla-comments/interfaces.ts::CommentType"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Comment Type"
},
"attribute": "type",
"reflect": false,
"defaultValue": "CommentType.PAGE"
},
"showFormAvatar": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Show or hide avatar"
},
"attribute": "show-form-avatar",
"reflect": false,
"defaultValue": "false"
},
"hideBought": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Hide Bought"
},
"attribute": "hide-bought",
"reflect": false,
"defaultValue": "false"
},
"sort": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string | 'latest' | 'oldest' | 'bottom_rating' | 'top_rating'",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Sort comments"
},
"attribute": "sort",
"reflect": false
},
"testimonials": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Determines if the comments are testimonials"
},
"attribute": "testimonials",
"reflect": false,
"defaultValue": "false"
}
};
}
static get states() {
return {
"comments": {},
"pagination": {},
"total": {},
"showPlaceholder": {},
"nextPage": {},
"mostHelpfulLabel": {},
"noComments": {},
"comment_title": {},
"comment_name": {},
"placeholder_text": {},
"showRatingSummary": {},
"allowLikes": {}
};
}
static get methods() {
return {
"reload": {
"complexType": {
"signature": "() => Promise<void>",
"parameters": [],
"references": {
"Promise": {
"location": "global",
"id": "global::Promise"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "",
"tags": []
}
}
};
}
static get elementRef() { return "host"; }
}
//# sourceMappingURL=salla-comments.js.map