diff --git a/assets/src/modules/Announcement.js b/assets/src/modules/Announcement.js new file mode 100644 index 0000000000..546032f047 --- /dev/null +++ b/assets/src/modules/Announcement.js @@ -0,0 +1,149 @@ +/** + * @module modules/Announcement.js + * @name Announcement + * @copyright 2026 3Liz + * @license MPL-2.0 + */ + +/** + * Fetches pending announcements from the server and displays them + * sequentially in the #lizmap-modal Bootstrap 5 modal. + */ +export default class Announcement { + + init() { + const announcementUrl = globalThis['lizUrls']?.announcement; + if (!announcementUrl) { + return; + } + + const params = globalThis['lizUrls'].params || {}; + + const url = new URL(announcementUrl, window.location.origin); + if (params.repository) { + url.searchParams.set('repository', params.repository); + } + if (params.project) { + url.searchParams.set('project', params.project); + } + + fetch(url.toString()) + .then(response => response.json()) + .then(data => { + if (data.announcements && data.announcements.length > 0) { + this._showAnnouncements(data.announcements); + } + }) + .catch(err => { + console.warn('Failed to fetch announcements:', err); + }); + } + + /** + * Show announcements one at a time. + * @param {Array} announcements + * @param {number} index + */ + _showAnnouncements(announcements, index = 0) { + if (index >= announcements.length) { + return; + } + + const announcement = announcements[index]; + this._showModal(announcement, () => { + this._markSeen(announcement.id); + // Show next announcement after a short delay + if (index + 1 < announcements.length) { + setTimeout(() => { + this._showAnnouncements(announcements, index + 1); + }, 500); + } + }); + } + + /** + * Display a single announcement in the #lizmap-modal. + * @param {Object} announcement + * @param {Function} onClose + */ + _showModal(announcement, onClose) { + const modalEl = document.getElementById('lizmap-modal'); + if (!modalEl) { + return; + } + + modalEl.innerHTML = ` +
{@admin~admin.announcement.list.empty@}
+ {else} +| {@admin~admin.announcement.col.title@} | +{@admin~admin.announcement.col.repository@} | +{@admin~admin.announcement.col.project@} | +{@admin~admin.announcement.col.groups@} | +{@admin~admin.announcement.col.maxviews@} | +{@admin~admin.announcement.col.status@} | +{@admin~admin.announcement.col.created@} | +{@admin~admin.announcement.col.actions@} | +
|---|---|---|---|---|---|---|---|
| {$item->title} | +{$item->target_repository} | +{$item->target_project} | +{$item->target_groups} | +{$item->max_display_count} | ++ {if $item->is_active} + {@admin~admin.announcement.status.active@} + {else} + {@admin~admin.announcement.status.inactive@} + {/if} + | +{$item->created_at|jdatetime:'db_datetime','lang_datetime'} | ++ {@admin~admin.announcement.btn.edit@} + {if $item->is_active}{@admin~admin.announcement.btn.deactivate@}{else}{@admin~admin.announcement.btn.activate@}{/if} + {@admin~admin.announcement.btn.delete@} + | +