UNPKG

@claromentis/design-system

Version:

Claromentis Design System Component Library

218 lines (217 loc) 8.54 kB
import { h } from '@stencil/core'; import { Build } from '@stencil/core'; import { mockData } from './cla-likes-modal-util'; import { lmsg } from '../../utils/localize'; import Modal from 'bootstrap/js/dist/modal'; /** * Likes Modal * * Used to retrieve the likes for an object and display the likes using pagination */ export class ClaLikesModal { constructor() { /** * Items to display per page. */ this.ITEMS_PER_PAGE = 30; /** * Items per column. */ this.ITEMS_PER_COLUMN = 15; /** * Maximum pagination items to show. */ this.MAX_PAGES_TO_SHOW = 5; this.currentPage = 1; this.totalPages = 0; this.totalLikes = 0; this.likers = []; this.objectType = undefined; this.objectId = undefined; this.total = 0; } /** * Update `totalLikes` when component is loaded. * Pass the prop to the state */ componentWillLoad() { this.totalLikes = this.total; } /** * Set the bootstrap modal instance */ componentDidLoad() { this.modalInstance = new Modal(this.modalElement, { backdrop: true, keyboard: true, focus: true }); const originalShow = this.modalInstance.show.bind(this.modalInstance); this.modalInstance.show = () => { document.body.appendChild(this.modalElement); originalShow(); }; const originalHide = this.modalInstance.hide.bind(this.modalInstance); this.modalInstance.hide = () => { originalHide(); this.element.appendChild(this.modalElement); }; } /** * Watch the `total` being changed * Update `totalLikes` when `total` changes to keep in sync * * @param {number} newValue New value */ onTotalChange(newValue) { this.totalLikes = newValue; } /** * Fetch the likers data * * @param offset The offset (or current position) */ async fetchData(offset = 0) { try { let result; if (Build.isDev) { result = mockData(this.ITEMS_PER_PAGE, offset); } else { const response = await fetch(`/api/like/${this.objectType}/${this.objectId}?limit=${this.ITEMS_PER_PAGE}&offset=${offset}`); result = await response.json(); } this.likers = result.data; this.totalLikes = result.paging.total; this.totalPages = Math.ceil(result.paging.total / this.ITEMS_PER_PAGE); this.currentPage = Math.floor(result.paging.offset / result.paging.limit) + 1; } catch (error) { console.error('Error fetching likers:', error); } } /** * Handle page pagination click * * @param event Event * @param page Page */ handlePageClick(event, page) { event.preventDefault(); if (page >= 1) { this.currentPage = page; this.fetchData((page - 1) * this.ITEMS_PER_PAGE); } } /** * Open the modal * * @param event */ openModal(event) { event.preventDefault(); this.fetchData(0); this.modalInstance.show(); } /** * Get the likers per column * * @param {Number} index * @returns {Array} */ getLikersByColumn(index) { return this.likers.slice(index * this.ITEMS_PER_COLUMN, (index + 1) * this.ITEMS_PER_COLUMN); } /** * Render the markup * * @returns {JSX} */ render() { return (h("div", null, h("a", { href: "#", onClick: (event) => this.openModal(event) }, this.totalLikes, " ", this.totalLikes <= 1 ? lmsg('common.notifications.post_like') : lmsg('common.notifications.post_likes')), h("div", { class: "modal fade", tabindex: "-1", role: "dialog", ref: (el) => (this.modalElement = el) }, h("div", { class: "modal-dialog modal-lg" }, h("div", { class: "modal-content" }, h("div", { class: "modal-header" }, h("h5", { class: "modal-title" }, h("span", { class: "mr-3" }, lmsg('common.cla_comments.people_who_liked_this')), h("cla-badge", { slot: "status", styleclass: "badge badge-pill badge-secondary" }, this.totalLikes)), h("cla-button", { class: "close", "data-dismiss": "modal" }, h("span", { "aria-hidden": "true" }, h("ion-icon", { name: "close-outline" })))), h("div", { class: "modal-body" }, h("div", { class: "row row-col-3" }, [[], [], []].map((_, colIndex) => (this.getLikersByColumn(colIndex).length > 0 && (h("div", { class: "col" }, h("ul", { class: "list-group list-group-flush" }, this.likers .slice(colIndex * this.ITEMS_PER_COLUMN, (colIndex + 1) * this.ITEMS_PER_COLUMN) .map(liker => (h("li", { class: "list-group-item" }, h("div", { class: "media align-items-center" }, h("a", { href: liker.profile_link, target: "_blank" }, h("img", { src: liker.profile_photo, alt: "", width: "32", class: "media-object profile-img" })), h("div", { class: "media-body ml-2 text-truncate" }, h("a", { href: liker.profile_link, target: "_blank" }, liker.user_name)))))))))))), this.totalPages > 1 && (h("nav", { class: "d-flex justify-content-center", "aria-label": "Likes Modal Pagination" }, h("ul", { class: "pagination" }, h("li", { class: `page-item ${this.currentPage === 1 ? 'disabled' : ''}` }, h("a", { class: "page-link", href: "#", onClick: (event) => this.handlePageClick(event, 1), "aria-label": "First" }, "\u00AB")), h("li", { class: `page-item ${this.currentPage === 1 ? 'disabled' : ''}` }, h("a", { class: "page-link", href: "#", onClick: (event) => this.handlePageClick(event, this.currentPage - 1), "aria-label": "Previous" }, "\u2039")), (() => { let startPage = Math.max(1, this.currentPage - Math.floor(this.MAX_PAGES_TO_SHOW / 2)); let endPage = Math.min(this.totalPages, startPage + this.MAX_PAGES_TO_SHOW - 1); if (endPage - startPage < this.MAX_PAGES_TO_SHOW - 1) { startPage = Math.max(1, endPage - this.MAX_PAGES_TO_SHOW + 1); } return [...Array(endPage - startPage + 1)].map((_, index) => { const page = startPage + index; return (h("li", { class: `page-item ${page === this.currentPage ? 'active' : ''}` }, h("a", { class: "page-link", href: "#", onClick: (event) => this.handlePageClick(event, page) }, page))); }); })(), h("li", { class: `page-item ${this.currentPage === this.totalPages ? 'disabled' : ''}` }, h("a", { class: "page-link", href: "#", onClick: (event) => this.handlePageClick(event, this.currentPage + 1), "aria-label": "Next" }, "\u203A")), h("li", { class: `page-item ${this.currentPage === this.totalPages ? 'disabled' : ''}` }, h("a", { class: "page-link", href: "#", onClick: (event) => this.handlePageClick(event, this.totalPages), "aria-label": "Last" }, "\u00BB")))))), h("div", { class: "modal-footer d-flex justify-content-center" }, h("button", { type: "button", class: "btn btn-block btn-secondary d-md-inline-block w-md-25 w-100", "data-dismiss": "modal" }, lmsg('common.close')))))))); } static get is() { return "cla-likes-modal"; } static get properties() { return { "objectType": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The type of object that the component should retrieve likes for." }, "attribute": "object-type", "reflect": false }, "objectId": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The ID of the object that the component should retrieve likes for." }, "attribute": "object-id", "reflect": false }, "total": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "This is used to update the `totalLikes` state." }, "attribute": "total", "reflect": false, "defaultValue": "0" } }; } static get states() { return { "currentPage": {}, "totalPages": {}, "totalLikes": {}, "likers": {} }; } static get elementRef() { return "element"; } static get watchers() { return [{ "propName": "total", "methodName": "onTotalChange" }]; } }