feat(i18n): add German and English email templates for invitations and verifications
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m29s

This commit is contained in:
2026-03-02 18:55:38 +01:00
parent 9be3be7712
commit 4a4ec0a3a3
4 changed files with 122 additions and 9 deletions

View File

@@ -5,16 +5,38 @@ import api from '../services/api';
// Lazily created Audio instance — reused across calls to avoid memory churn
let _audio = null;
let _audioUnlocked = false;
function getAudio() {
if (!_audio) {
_audio = new Audio('/sounds/notification.mp3');
_audio.volume = 0.5;
}
return _audio;
}
/** Called once on the first user gesture to silently play→pause the element,
* which "unlocks" it so later timer-based .play() calls are not blocked. */
function unlockAudio() {
if (_audioUnlocked) return;
_audioUnlocked = true;
const audio = getAudio();
audio.muted = true;
audio.play().then(() => {
audio.pause();
audio.muted = false;
audio.currentTime = 0;
}).catch(() => {
audio.muted = false;
});
}
function playNotificationSound() {
try {
if (!_audio) {
_audio = new Audio('/sounds/notification.mp3');
_audio.volume = 0.5;
}
// Reset to start so rapid arrivals always play from beginning
_audio.currentTime = 0;
_audio.play().catch(() => {
// Autoplay blocked (user hasn't interacted yet) or file missing — silent fail
const audio = getAudio();
audio.currentTime = 0;
audio.play().catch(() => {
// Autoplay still blocked — silent fail
});
} catch {
// Ignore any other errors (e.g. unsupported format)
@@ -61,6 +83,19 @@ export function NotificationProvider({ children }) {
}
}, [user]);
// Unlock audio playback on the first real user interaction.
// Browsers block audio from timer callbacks unless the element was previously
// "touched" inside a gesture handler — this one-time listener does exactly that.
useEffect(() => {
const events = ['click', 'keydown', 'pointerdown'];
const handler = () => {
unlockAudio();
events.forEach(e => window.removeEventListener(e, handler));
};
events.forEach(e => window.addEventListener(e, handler, { once: true }));
return () => events.forEach(e => window.removeEventListener(e, handler));
}, []);
useEffect(() => {
if (!user) {
setNotifications([]);