0
0
Fork 0
mirror of https://github.com/kevinpapst/kimai2.git synced 2025-01-10 19:47:35 +00:00
kevinpapst_kimai2/assets/js/plugins/KimaiAlert.js
Kevin Papst 17a815e5a9
updated frontend builds (#5210)
* do not rely on node_modules path
* bump eslint to v9, run eslint via npm task, remove from build task
* loosen dependencies and update all packages
* rebuild assets with latest frontend packages
* bump webpack encore and dependencies
* bump to latest stable yarn
* explicitly mention dependencies
2024-12-06 14:31:04 +01:00

269 lines
8.9 KiB
JavaScript

/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/*!
* [KIMAI] KimaiAlert: notifications for Kimai
*/
import KimaiPlugin from "../KimaiPlugin";
import {Modal, Toast} from "bootstrap";
export default class KimaiAlert extends KimaiPlugin {
/**
* @return {string}
*/
getId() {
return 'alert';
}
/**
* @param {string} title
* @param {string|array|undefined} message
*/
error(title, message) {
const translation = this.getTranslation();
if (translation.has(title)) {
title = translation.get(title);
}
title = title.replace('%reason%', '');
if (message === undefined) {
message = null;
}
if (message !== null) {
if (translation.has(message)) {
message = translation.get(message);
}
if (Array.isArray(message)) {
message = message.join('<br>');
}
}
const id = 'alert_global_error';
const oldModalElement = document.getElementById(id);
if (oldModalElement !== null) {
Modal.getOrCreateInstance(oldModalElement).hide();
}
const html = `
<div class="modal" id="` + id + `" tabindex="-1" role="dialog">
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-status bg-` + this._mapClass('danger') + `"></div>
<div class="modal-body text-center py-4">
<i class="fas fa-exclamation-circle fa-3x mb-3 text-danger"></i>
<h2>` + title + `</h2>
` + (message !== null ? '<div class="text-muted">' + message + '</div>' : '') + `
</div>
<div class="modal-footer">
<div class="w-100">
<div class="row">
<div class="col text-center"><a href="#" class="btn btn-primary" data-bs-dismiss="modal">` + translation.get('close') + `</a></div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
this._showModal(html);
}
/**
* @param {string} message
*/
warning(message) {
this._show('warning', message);
}
/**
* @param {string} message
*/
success(message) {
this._toast('success', message);
}
/**
* @param {string} message
*/
info(message) {
this._show('info', message);
}
/**
* @param {string} html
* @private
*/
_showModal(html) {
const container = document.body;
const template = document.createElement('template');
template.innerHTML = html.trim();
const element = template.content.firstChild;
container.appendChild(element);
const modal = new Modal(element);
element.addEventListener('hidden.bs.modal', function () {
container.removeChild(element);
});
modal.show();
}
/**
* @param {string} type
* @param {string} message
* @private
*/
_show(type, message) {
const translation = this.getTranslation();
if (translation.has(message)) {
message = translation.get(message);
}
const html = `
<div class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-status bg-` + this._mapClass(type) + `"></div>
<div class="modal-body text-center py-4">
<i class="fas fa-exclamation-circle fa-3x mb-3 text-` + this._mapClass(type) + `"></i>
<h2>` + message + `</h2>
</div>
<div class="modal-footer">
<div class="w-100">
<div class="row">
<div class="col text-center"><a href="#" class="btn btn-primary" data-bs-dismiss="modal">` + translation.get('close') + `</a></div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
this._showModal(html);
}
/**
* @param {string} type
* @return {string}
* @private
*/
_mapClass(type) {
if (type === 'info' || type === 'success' || type === 'warning' || type === 'danger') {
return type;
} else if (type === 'error') {
return 'danger';
}
return 'primary';
}
/**
* @param type
* @param message
* @private
*/
_toast(type, message) {
const translation = this.getTranslation();
if (translation.has(message)) {
message = translation.get(message);
}
let icon = '<i class="fas fa-info me-2"></i>';
if (type === 'success') {
icon = '<i class="fas fa-check me-2"></i>';
} else if (type === 'warning') {
icon = '<i class="fas fa-exclamation me-2"></i>';
} else if (type === 'danger' || type === 'error') {
icon = '<i class="fas fa-exclamation-circle me-2"></i>';
}
const html =
`<div class="toast align-items-center text-white bg-` + this._mapClass(type) + ` border-0" data-bs-delay="2000" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">
` + icon + ' ' + message + `
</div>
<button type="button" class="btn-close me-2 m-auto" data-bs-dismiss="toast" aria-label="` + translation.get('close') + `"></button>
</div>
</div>`;
const container = document.getElementById('toast-container');
const template = document.createElement('template');
template.innerHTML = html.trim();
const element = template.content.firstChild;
container.appendChild(element);
const toast = new Toast(element);
element.addEventListener('hidden.bs.toast', function () {
container.removeChild(element);
});
toast.show();
}
/**
* Callback receives a bool value (true = confirm, false = cancel / close without action).
*
* @param message
* @param callback
*/
question(message, callback) {
const translation = this.getTranslation();
if (translation.has(message)) {
message = translation.get(message);
}
const css = this._mapClass('info');
const html = `
<div class="modal fade" tabindex="-1" role="dialog" data-bs-backdrop="static">
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-status bg-` + css + `"></div>
<div class="modal-body text-center py-4">
<i class="fas fa-question fa-3x mb-3 text-` + css + `"></i>
<h2>` + message + `</h2>
</div>
<div class="modal-footer">
<div class="w-100">
<div class="row">
<div class="col"><a href="#" class="question-confirm btn btn-primary w-100" data-bs-dismiss="modal">` + translation.get('confirm') + `</a></div>
<div class="col"><a href="#" class="question-cancel btn w-100" data-bs-dismiss="modal">` + translation.get('cancel') + `</a></div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
const container = document.body;
const template = document.createElement('template');
template.innerHTML = html.trim();
const element = template.content.firstChild;
container.appendChild(element);
element.querySelector('.question-confirm').addEventListener('click', () => {
callback(true);
});
element.querySelector('.question-cancel').addEventListener('click', () => {
callback(false);
});
const modal = new Modal(element);
element.addEventListener('hidden.bs.modal', () => {
container.removeChild(element);
});
modal.show();
}
}