/*
Copyright (C) 2025 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
For commercial licensing, please contact support@quantumnous.com
*/
import React, { useEffect, useState, useContext, useMemo } from 'react';
import {
Button,
Modal,
Empty,
Tabs,
TabPane,
Timeline,
} from '@douyinfe/semi-ui';
import { useTranslation } from 'react-i18next';
import { API, showError, getRelativeTime } from '../../helpers';
import { marked } from 'marked';
import {
IllustrationNoContent,
IllustrationNoContentDark,
} from '@douyinfe/semi-illustrations';
import { StatusContext } from '../../context/Status';
import { Bell, Megaphone } from 'lucide-react';
const NoticeModal = ({
visible,
onClose,
isMobile,
defaultTab = 'inApp',
unreadKeys = [],
}) => {
const { t } = useTranslation();
const [noticeContent, setNoticeContent] = useState('');
const [loading, setLoading] = useState(false);
const [activeTab, setActiveTab] = useState(defaultTab);
const [statusState] = useContext(StatusContext);
const announcements = statusState?.status?.announcements || [];
const unreadSet = useMemo(() => new Set(unreadKeys), [unreadKeys]);
const getKeyForItem = (item) =>
`${item?.publishDate || ''}-${(item?.content || '').slice(0, 30)}`;
const processedAnnouncements = useMemo(() => {
return (announcements || []).slice(0, 20).map((item) => {
const pubDate = item?.publishDate ? new Date(item.publishDate) : null;
const absoluteTime =
pubDate && !isNaN(pubDate.getTime())
? `${pubDate.getFullYear()}-${String(pubDate.getMonth() + 1).padStart(2, '0')}-${String(pubDate.getDate()).padStart(2, '0')} ${String(pubDate.getHours()).padStart(2, '0')}:${String(pubDate.getMinutes()).padStart(2, '0')}`
: item?.publishDate || '';
return {
key: getKeyForItem(item),
type: item.type || 'default',
time: absoluteTime,
content: item.content,
extra: item.extra,
relative: getRelativeTime(item.publishDate),
isUnread: unreadSet.has(getKeyForItem(item)),
};
});
}, [announcements, unreadSet]);
const handleCloseTodayNotice = () => {
const today = new Date().toDateString();
localStorage.setItem('notice_close_date', today);
onClose();
};
const displayNotice = async () => {
setLoading(true);
try {
const res = await API.get('/api/notice');
const { success, message, data } = res.data;
if (success) {
if (data !== '') {
const htmlNotice = marked.parse(data);
setNoticeContent(htmlNotice);
} else {
setNoticeContent('');
}
} else {
showError(message);
}
} catch (error) {
showError(error.message);
} finally {
setLoading(false);
}
};
useEffect(() => {
if (visible) {
displayNotice();
}
}, [visible]);
useEffect(() => {
if (visible) {
setActiveTab(defaultTab);
}
}, [defaultTab, visible]);
const renderMarkdownNotice = () => {
if (loading) {
return (