Skip to content

Commit f2dab9d

Browse files
authored
System Alerts + Warnings (#149)
* single place for warnings * a few checks * 🔀 Apply suggestions from code review Signed-off-by: Ian Hunter <ianfhunter@gmail.com> * fix tests --------- Signed-off-by: Ian Hunter <ianfhunter@gmail.com>
1 parent b3dca39 commit f2dab9d

File tree

10 files changed

+771
-20
lines changed

10 files changed

+771
-20
lines changed

backend/package-lock.json

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 1 addition & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { useState, useEffect } from 'react';
2+
import { detectSystemWarnings, dismissWarning, WARNING_TYPES } from '../utils/systemWarnings';
3+
import styles from './DismissibleAlert.module.css';
4+
5+
const DismissibleAlert = () => {
6+
const [isVisible, setIsVisible] = useState(false);
7+
const [warning, setWarning] = useState(null);
8+
9+
useEffect(() => {
10+
const checkForWarnings = async () => {
11+
try {
12+
// Check for Git LFS warning specifically
13+
const warnings = await detectSystemWarnings([WARNING_TYPES.GIT_LFS]);
14+
15+
if (warnings.length > 0) {
16+
const gitLfsWarning = warnings[0];
17+
setWarning(gitLfsWarning);
18+
setIsVisible(true);
19+
}
20+
} catch (error) {
21+
console.log('Failed to check for system warnings:', error);
22+
}
23+
};
24+
25+
checkForWarnings();
26+
}, []);
27+
28+
const handleDismiss = () => {
29+
if (warning) {
30+
dismissWarning(warning.id);
31+
}
32+
setIsVisible(false);
33+
};
34+
35+
if (!isVisible || !warning) {
36+
return null;
37+
}
38+
39+
return (
40+
<div className={styles.alertContainer}>
41+
<div className={styles.alert}>
42+
<div className={styles.alertIcon}>{warning.icon}</div>
43+
<div className={styles.alertContent}>
44+
<div className={styles.alertTitle}>{warning.title}</div>
45+
<div className={styles.alertMessage}>
46+
{warning.message}
47+
{warning.action && (
48+
<>
49+
{' '}Please run <code>{warning.action}</code> to resolve this issue.
50+
</>
51+
)}
52+
</div>
53+
</div>
54+
<button
55+
className={styles.dismissButton}
56+
onClick={handleDismiss}
57+
title="Dismiss this warning"
58+
>
59+
60+
</button>
61+
</div>
62+
</div>
63+
);
64+
};
65+
66+
export default DismissibleAlert;
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
.alertContainer {
2+
position: fixed;
3+
top: 0;
4+
left: 0;
5+
right: 0;
6+
z-index: 9999;
7+
background: linear-gradient(180deg, rgba(251, 191, 36, 0.1) 0%, rgba(251, 191, 36, 0.05) 100%);
8+
border-bottom: 1px solid rgba(251, 191, 36, 0.3);
9+
backdrop-filter: blur(10px);
10+
animation: slideDown 0.3s ease-out;
11+
}
12+
13+
.alert {
14+
max-width: 1200px;
15+
margin: 0 auto;
16+
padding: 1rem 1.5rem;
17+
display: flex;
18+
align-items: center;
19+
gap: 1rem;
20+
background: rgba(255, 255, 255, 0.95);
21+
border-radius: 0 0 8px 8px;
22+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
23+
position: relative;
24+
}
25+
26+
:global([data-theme="dark"]) .alert {
27+
background: rgba(20, 10, 40, 0.95);
28+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
29+
border-bottom: 1px solid rgba(251, 191, 36, 0.2);
30+
}
31+
32+
.alertIcon {
33+
font-size: 1.5rem;
34+
flex-shrink: 0;
35+
}
36+
37+
.alertContent {
38+
flex: 1;
39+
display: flex;
40+
flex-direction: column;
41+
gap: 0.25rem;
42+
}
43+
44+
.alertTitle {
45+
font-weight: 700;
46+
color: #d97706;
47+
font-size: 0.9rem;
48+
text-transform: uppercase;
49+
letter-spacing: 0.05em;
50+
}
51+
52+
:global([data-theme="dark"]) .alertTitle {
53+
color: #f59e0b;
54+
}
55+
56+
.alertMessage {
57+
font-size: 0.85rem;
58+
color: #6b7280;
59+
line-height: 1.4;
60+
}
61+
62+
:global([data-theme="dark"]) .alertMessage {
63+
color: #9ca3af;
64+
}
65+
66+
.alertMessage code {
67+
background: rgba(0, 0, 0, 0.05);
68+
padding: 0.125rem 0.375rem;
69+
border-radius: 4px;
70+
font-family: 'Courier New', monospace;
71+
font-size: 0.8rem;
72+
border: 1px solid rgba(0, 0, 0, 0.1);
73+
}
74+
75+
:global([data-theme="dark"]) .alertMessage code {
76+
background: rgba(255, 255, 255, 0.05);
77+
border-color: rgba(255, 255, 255, 0.1);
78+
}
79+
80+
.dismissButton {
81+
background: transparent;
82+
border: none;
83+
font-size: 1.25rem;
84+
cursor: pointer;
85+
padding: 0.25rem;
86+
border-radius: 4px;
87+
color: #6b7280;
88+
transition: all 0.2s ease;
89+
flex-shrink: 0;
90+
}
91+
92+
.dismissButton:hover {
93+
background: rgba(0, 0, 0, 0.05);
94+
color: #374151;
95+
}
96+
97+
:global([data-theme="dark"]) .dismissButton {
98+
color: #9ca3af;
99+
}
100+
101+
:global([data-theme="dark"]) .dismissButton:hover {
102+
background: rgba(255, 255, 255, 0.05);
103+
color: #e5e7eb;
104+
}
105+
106+
@keyframes slideDown {
107+
from {
108+
transform: translateY(-100%);
109+
opacity: 0;
110+
}
111+
to {
112+
transform: translateY(0);
113+
opacity: 1;
114+
}
115+
}
116+
117+
/* Responsive design */
118+
@media (max-width: 768px) {
119+
.alert {
120+
padding: 0.75rem 1rem;
121+
gap: 0.75rem;
122+
}
123+
124+
.alertContent {
125+
gap: 0.2rem;
126+
}
127+
128+
.alertTitle {
129+
font-size: 0.8rem;
130+
}
131+
132+
.alertMessage {
133+
font-size: 0.8rem;
134+
}
135+
}

src/components/Layout/Layout.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { setEnglishVariant } from '../../data/wordFrequency';
1010
import { supportedLanguages, getEnglishVariant } from '../../i18n';
1111
import { fuzzySearchGames } from '../../utils/fuzzySearch';
1212
import AuthModal from '../AuthModal';
13+
import DismissibleAlert from '../DismissibleAlert';
1314
const logo = '/branding/logo-simple-e.svg';
1415
import styles from './Layout.module.css';
1516

@@ -324,6 +325,9 @@ export default function Layout() {
324325
</a>
325326
</footer>
326327

328+
{/* Dismissible alert for System Alerts*/}
329+
<DismissibleAlert />
330+
327331
{/* Auth modal - cannot be closed when not authenticated */}
328332
<AuthModal
329333
isOpen={!isAuthenticated}

src/i18n/locales/en.json

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@
246246
"deleteAccountWarning": "Permanently delete your account and all associated data. This action cannot be undone.",
247247
"deleteMyAccount": "Delete My Account",
248248
"yesDeleteMyAccount": "Yes, Delete My Account",
249-
"enterPasswordToConfirm": "Enter your password to confirm"
249+
"enterPasswordToConfirm": "Enter your password to confirm",
250+
"actionItems": "Action Items"
250251
},
251252
"settings": {
252253
"title": "Settings",
@@ -590,5 +591,28 @@
590591
"gaveUpMessage": "Study the pattern and try another puzzle!",
591592
"howItWorks": "How It Works",
592593
"explanation": "Each column has a value (1, 2, 3... from left). When you fill a cell, its column value is added to that row's sum. Similarly, each row has a value that contributes to column sums. Match all targets to win!"
594+
},
595+
"actionItems": {
596+
"loading": "Loading action items...",
597+
"failedToLoad": "Failed to load action items",
598+
"updated": "Action item updated!",
599+
"deleted": "Action item deleted!",
600+
"added": "Action item added!",
601+
"overview": "Overview",
602+
"addNew": "Add New Item",
603+
"myItems": "My Items",
604+
"noItems": "No action items yet. Add your first task above!",
605+
"placeholder": "What needs to be done?",
606+
"add": "Add Item",
607+
"created": "Created",
608+
"delete": "Delete",
609+
"priority": {
610+
"low": "Low",
611+
"medium": "Medium",
612+
"high": "High"
613+
},
614+
"total": "Total",
615+
"completed": "Completed",
616+
"completionRate": "Completion Rate"
593617
}
594618
}

0 commit comments

Comments
 (0)