-
Notifications
You must be signed in to change notification settings - Fork 183
/
Copy pathAnnouncementsDisplay.tsx
123 lines (111 loc) · 3.86 KB
/
AnnouncementsDisplay.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import { DialogButton, Focusable, PanelSection } from '@decky/ui';
import { useEffect, useMemo, useState } from 'react';
import { FaTimes } from 'react-icons/fa';
import { Announcement, getAnnouncements } from '../store';
import { useSetting } from '../utils/hooks/useSetting';
const SEVERITIES = {
High: {
color: '#bb1414',
text: '#fff',
},
Medium: {
color: '#bbbb14',
text: '#fff',
},
Low: {
color: '#1488bb',
text: '#fff',
},
};
const welcomeAnnouncement: Announcement = {
id: 'welcomeAnnouncement',
title: 'Welcome to Decky!',
text: 'We hope you enjoy using Decky! If you have any questions or feedback, please let us know.',
created: Date.now().toString(),
updated: Date.now().toString(),
};
export function AnnouncementsDisplay() {
const [announcements, setAnnouncements] = useState<Announcement[]>([welcomeAnnouncement]);
// showWelcome will display a welcome motd, the welcome motd has an id of "welcome" and once that is saved to hiddenMotdId, it will not show again
const [hiddenAnnouncementIds, setHiddenAnnouncementIds] = useSetting<string[]>('hiddenAnnouncementIds', []);
function addAnnouncements(newAnnouncements: Announcement[]) {
// Removes any duplicates and sorts by created date
setAnnouncements((oldAnnouncements) => {
const newArr = [...oldAnnouncements, ...newAnnouncements];
const setOfIds = new Set(newArr.map((a) => a.id));
return (
(
Array.from(setOfIds)
.map((id) => newArr.find((a) => a.id === id))
// Typescript doesn't type filter(Boolean) correctly, so I have to assert this
.filter(Boolean) as Announcement[]
).sort((a, b) => {
return new Date(b.created).getTime() - new Date(a.created).getTime();
})
);
});
}
async function fetchAnnouncement() {
const announcements = await getAnnouncements();
announcements && addAnnouncements(announcements);
}
useEffect(() => {
void fetchAnnouncement();
}, []);
const currentlyDisplayingAnnouncement: Announcement | null = useMemo(() => {
return announcements.find((announcement) => !hiddenAnnouncementIds.includes(announcement.id)) || null;
}, [announcements, hiddenAnnouncementIds]);
function hideAnnouncement(id: string) {
setHiddenAnnouncementIds([...hiddenAnnouncementIds, id]);
void fetchAnnouncement();
}
if (!currentlyDisplayingAnnouncement) {
return null;
}
// Severity is not implemented in the API currently
const severity = SEVERITIES['Low'];
return (
<PanelSection>
<Focusable
style={{
// Transparency is 20% of the color
backgroundColor: `${severity.color}33`,
color: severity.text,
borderColor: severity.color,
borderWidth: '2px',
borderStyle: 'solid',
padding: '0.7rem',
display: 'flex',
flexDirection: 'column',
position: 'relative',
}}
>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<span style={{ fontWeight: 'bold' }}>{currentlyDisplayingAnnouncement.title}</span>
<DialogButton
style={{
width: '1rem',
minWidth: '1rem',
height: '1rem',
padding: '0',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
top: '.75rem',
right: '.75rem',
}}
onClick={() => hideAnnouncement(currentlyDisplayingAnnouncement.id)}
>
<FaTimes
style={{
height: '.75rem',
}}
/>
</DialogButton>
</div>
<span style={{ fontSize: '0.75rem', whiteSpace: 'pre-line' }}>{currentlyDisplayingAnnouncement.text}</span>
</Focusable>
</PanelSection>
);
}