@claromentis/design-system
Version:
Claromentis Design System Component Library
218 lines (217 loc) • 8.54 kB
JavaScript
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"
}];
}
}