mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-04 13:22:41 +02:00
feat: added announcements
This commit is contained in:
parent
0e96e4492b
commit
e9979dfa7d
11 changed files with 833 additions and 3 deletions
65
surfsense_web/lib/announcements/announcements-data.ts
Normal file
65
surfsense_web/lib/announcements/announcements-data.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import type { Announcement } from "@/contracts/types/announcement.types";
|
||||
|
||||
/**
|
||||
* Static announcements data.
|
||||
*
|
||||
* To add a new announcement, append an entry to this array.
|
||||
* Set `isImportant: true` to trigger a toast notification for the user.
|
||||
*
|
||||
* This file can be replaced with an API call in the future.
|
||||
*/
|
||||
export const announcements: Announcement[] = [
|
||||
{
|
||||
id: "2026-02-12-announcement-syste",
|
||||
title: "Introducing Announcements",
|
||||
description:
|
||||
"Stay up to date with the latest SurfSense news! Important announcements will appear as toast notifications so you never miss critical updates. Visit the Announcements page from the sidebar to browse all past announcements.",
|
||||
category: "feature",
|
||||
date: "2026-02-12T00:00:00Z",
|
||||
isImportant: true,
|
||||
link: {
|
||||
label: "Learn more",
|
||||
url: "/changelog",
|
||||
},
|
||||
},
|
||||
// {
|
||||
// id: "2026-02-10-podcast-improvements",
|
||||
// title: "Podcast Generation Improvements",
|
||||
// description:
|
||||
// "We've improved podcast generation with faster processing, better audio quality, and support for longer documents. Try it out in any search space.",
|
||||
// category: "update",
|
||||
// date: "2026-02-10T00:00:00Z",
|
||||
// isImportant: false,
|
||||
// },
|
||||
// {
|
||||
// id: "2026-02-08-scheduled-maintenance",
|
||||
// title: "Scheduled Maintenance — Feb 15",
|
||||
// description:
|
||||
// "SurfSense will undergo scheduled maintenance on February 15, 2026 from 2:00 AM to 4:00 AM UTC. During this window, the service may be temporarily unavailable. We apologize for any inconvenience.",
|
||||
// category: "maintenance",
|
||||
// date: "2026-02-08T00:00:00Z",
|
||||
// isImportant: true,
|
||||
// },
|
||||
// {
|
||||
// id: "2026-02-05-new-connectors",
|
||||
// title: "New Connectors Available",
|
||||
// description:
|
||||
// "We've added support for new connectors including Linear, Jira, and Confluence. Connect your project management tools and start chatting with your data.",
|
||||
// category: "feature",
|
||||
// date: "2026-02-05T00:00:00Z",
|
||||
// isImportant: false,
|
||||
// link: {
|
||||
// label: "View connectors",
|
||||
// url: "#connectors",
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// id: "2026-01-28-team-collaboration",
|
||||
// title: "Enhanced Team Collaboration",
|
||||
// description:
|
||||
// "Shared search spaces now support real-time mentions, comment threads, and role-based access control. Invite your team and collaborate more effectively.",
|
||||
// category: "feature",
|
||||
// date: "2026-01-28T00:00:00Z",
|
||||
// isImportant: false,
|
||||
// },
|
||||
];
|
||||
107
surfsense_web/lib/announcements/announcements-storage.ts
Normal file
107
surfsense_web/lib/announcements/announcements-storage.ts
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import type { AnnouncementUserState } from "@/contracts/types/announcement.types";
|
||||
|
||||
const STORAGE_KEY = "surfsense_announcements_state";
|
||||
|
||||
const defaultState: AnnouncementUserState = {
|
||||
readIds: [],
|
||||
toastedIds: [],
|
||||
dismissedIds: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current announcement user state from localStorage
|
||||
*/
|
||||
export function getAnnouncementState(): AnnouncementUserState {
|
||||
if (typeof window === "undefined") return defaultState;
|
||||
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (!raw) return defaultState;
|
||||
const parsed = JSON.parse(raw) as Partial<AnnouncementUserState>;
|
||||
return {
|
||||
readIds: Array.isArray(parsed.readIds) ? parsed.readIds : [],
|
||||
toastedIds: Array.isArray(parsed.toastedIds) ? parsed.toastedIds : [],
|
||||
dismissedIds: Array.isArray(parsed.dismissedIds) ? parsed.dismissedIds : [],
|
||||
};
|
||||
} catch {
|
||||
return defaultState;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save announcement user state to localStorage
|
||||
*/
|
||||
function saveAnnouncementState(state: AnnouncementUserState): void {
|
||||
if (typeof window === "undefined") return;
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
|
||||
} catch {
|
||||
// Silently fail if localStorage is full or unavailable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark an announcement as read
|
||||
*/
|
||||
export function markAnnouncementRead(id: string): void {
|
||||
const state = getAnnouncementState();
|
||||
if (!state.readIds.includes(id)) {
|
||||
state.readIds.push(id);
|
||||
saveAnnouncementState(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark all announcements as read
|
||||
*/
|
||||
export function markAllAnnouncementsRead(ids: string[]): void {
|
||||
const state = getAnnouncementState();
|
||||
const newIds = ids.filter((id) => !state.readIds.includes(id));
|
||||
if (newIds.length > 0) {
|
||||
state.readIds.push(...newIds);
|
||||
saveAnnouncementState(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss an announcement (hide it from the list)
|
||||
*/
|
||||
export function dismissAnnouncement(id: string): void {
|
||||
const state = getAnnouncementState();
|
||||
if (!state.dismissedIds.includes(id)) {
|
||||
state.dismissedIds.push(id);
|
||||
saveAnnouncementState(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark an important announcement as already toasted (shown as toast)
|
||||
*/
|
||||
export function markAnnouncementToasted(id: string): void {
|
||||
const state = getAnnouncementState();
|
||||
if (!state.toastedIds.includes(id)) {
|
||||
state.toastedIds.push(id);
|
||||
saveAnnouncementState(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an announcement has been read
|
||||
*/
|
||||
export function isAnnouncementRead(id: string): boolean {
|
||||
return getAnnouncementState().readIds.includes(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an announcement has been toasted
|
||||
*/
|
||||
export function isAnnouncementToasted(id: string): boolean {
|
||||
return getAnnouncementState().toastedIds.includes(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an announcement has been dismissed
|
||||
*/
|
||||
export function isAnnouncementDismissed(id: string): boolean {
|
||||
return getAnnouncementState().dismissedIds.includes(id);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue