diff --git a/client/src/components/Planner/DayDetailPanel.tsx b/client/src/components/Planner/DayDetailPanel.tsx
index d36cba9..3001b8a 100644
--- a/client/src/components/Planner/DayDetailPanel.tsx
+++ b/client/src/components/Planner/DayDetailPanel.tsx
@@ -56,6 +56,7 @@ export default function DayDetailPanel({ day, days, places, categories = [], tri
const { t, language, locale } = useTranslation()
const isFahrenheit = useSettingsStore(s => s.settings.temperature_unit) === 'fahrenheit'
const is12h = useSettingsStore(s => s.settings.time_format) === '12h'
+ const blurCodes = useSettingsStore(s => s.settings.blur_booking_codes)
const fmtTime = (v) => formatTime12(v, is12h)
const unit = isFahrenheit ? '°F' : '°C'
const [weather, setWeather] = useState(null)
@@ -368,7 +369,12 @@ export default function DayDetailPanel({ day, days, places, categories = [], tri
{linked.title}
{confirmed ? t('reservations.confirmed') : t('reservations.pending')}
- {linked.confirmation_number && #{linked.confirmation_number}}
+ {linked.confirmation_number && { if (blurCodes) e.currentTarget.style.filter = 'none' }}
+ onMouseLeave={e => { if (blurCodes) e.currentTarget.style.filter = 'blur(4px)' }}
+ onClick={e => { if (blurCodes) { const el = e.currentTarget; el.style.filter = el.style.filter === 'none' ? 'blur(4px)' : 'none' } }}
+ style={{ filter: blurCodes ? 'blur(4px)' : 'none', transition: 'filter 0.2s', cursor: blurCodes ? 'pointer' : 'default' }}
+ >#{linked.confirmation_number}}
diff --git a/client/src/components/Planner/DayPlanSidebar.tsx b/client/src/components/Planner/DayPlanSidebar.tsx
index 277662f..1afcb48 100644
--- a/client/src/components/Planner/DayPlanSidebar.tsx
+++ b/client/src/components/Planner/DayPlanSidebar.tsx
@@ -1449,7 +1449,7 @@ export default function DayPlanSidebar({
if (meta.platform) detailFields.push({ label: t('reservations.meta.platform'), value: meta.platform })
if (meta.seat) detailFields.push({ label: t('reservations.meta.seat'), value: meta.seat })
}
- if (res.confirmation_number) detailFields.push({ label: t('reservations.confirmationCode'), value: res.confirmation_number })
+ if (res.confirmation_number) detailFields.push({ label: t('reservations.confirmationCode'), value: res.confirmation_number, sensitive: true })
if (res.location) detailFields.push({ label: t('reservations.locationAddress'), value: res.location })
return (
@@ -1486,12 +1486,25 @@ export default function DayPlanSidebar({
{/* Detail-Felder */}
{detailFields.length > 0 && (
- {detailFields.map((f, i) => (
-
-
{f.label}
-
{f.value}
-
- ))}
+ {detailFields.map((f, i) => {
+ const shouldBlur = f.sensitive && useSettingsStore.getState().settings.blur_booking_codes
+ return (
+
+
{f.label}
+
{ if (shouldBlur) e.currentTarget.style.filter = 'none' }}
+ onMouseLeave={e => { if (shouldBlur) e.currentTarget.style.filter = 'blur(5px)' }}
+ onClick={e => { if (shouldBlur) { const el = e.currentTarget; el.style.filter = el.style.filter === 'none' ? 'blur(5px)' : 'none' } }}
+ style={{
+ fontSize: 12, fontWeight: 500, color: 'var(--text-primary)', wordBreak: 'break-word',
+ filter: shouldBlur ? 'blur(5px)' : 'none', transition: 'filter 0.2s',
+ cursor: shouldBlur ? 'pointer' : 'default',
+ userSelect: shouldBlur ? 'none' : 'auto',
+ }}
+ >{f.value}
+
+ )
+ })}
)}
diff --git a/client/src/components/Planner/ReservationsPanel.tsx b/client/src/components/Planner/ReservationsPanel.tsx
index cd36f06..987ff18 100644
--- a/client/src/components/Planner/ReservationsPanel.tsx
+++ b/client/src/components/Planner/ReservationsPanel.tsx
@@ -63,6 +63,8 @@ function ReservationCard({ r, tripId, onEdit, onDelete, files = [], onNavigateTo
const toast = useToast()
const { t, locale } = useTranslation()
const timeFormat = useSettingsStore(s => s.settings.time_format) || '24h'
+ const blurCodes = useSettingsStore(s => s.settings.blur_booking_codes)
+ const [codeRevealed, setCodeRevealed] = useState(false)
const typeInfo = getType(r.type)
const TypeIcon = typeInfo.Icon
const confirmed = r.status === 'confirmed'
@@ -136,7 +138,19 @@ function ReservationCard({ r, tripId, onEdit, onDelete, files = [], onNavigateTo
{r.confirmation_number && (
{t('reservations.confirmationCode')}
-
{r.confirmation_number}
+
blurCodes && setCodeRevealed(true)}
+ onMouseLeave={() => blurCodes && setCodeRevealed(false)}
+ onClick={() => blurCodes && setCodeRevealed(v => !v)}
+ style={{
+ fontSize: 11, fontWeight: 600, color: 'var(--text-primary)', marginTop: 1,
+ filter: blurCodes && !codeRevealed ? 'blur(5px)' : 'none',
+ cursor: blurCodes ? 'pointer' : 'default',
+ transition: 'filter 0.2s',
+ }}
+ >
+ {r.confirmation_number}
+
)}
diff --git a/client/src/i18n/translations/de.ts b/client/src/i18n/translations/de.ts
index 0aea7ff..9449693 100644
--- a/client/src/i18n/translations/de.ts
+++ b/client/src/i18n/translations/de.ts
@@ -139,6 +139,7 @@ const de: Record = {
'settings.temperature': 'Temperatureinheit',
'settings.timeFormat': 'Zeitformat',
'settings.routeCalculation': 'Routenberechnung',
+ 'settings.blurBookingCodes': 'Buchungscodes verbergen',
'settings.on': 'An',
'settings.off': 'Aus',
'settings.account': 'Konto',
diff --git a/client/src/i18n/translations/en.ts b/client/src/i18n/translations/en.ts
index 46e6310..95e2018 100644
--- a/client/src/i18n/translations/en.ts
+++ b/client/src/i18n/translations/en.ts
@@ -139,6 +139,7 @@ const en: Record = {
'settings.temperature': 'Temperature Unit',
'settings.timeFormat': 'Time Format',
'settings.routeCalculation': 'Route Calculation',
+ 'settings.blurBookingCodes': 'Blur Booking Codes',
'settings.on': 'On',
'settings.off': 'Off',
'settings.account': 'Account',
diff --git a/client/src/pages/AdminPage.tsx b/client/src/pages/AdminPage.tsx
index b63306f..b729a61 100644
--- a/client/src/pages/AdminPage.tsx
+++ b/client/src/pages/AdminPage.tsx
@@ -333,7 +333,7 @@ export default function AdminPage(): React.ReactElement {
-
Administration
+
{t('admin.title')}
{t('admin.subtitle')}
diff --git a/client/src/pages/SettingsPage.tsx b/client/src/pages/SettingsPage.tsx
index 7846f5e..49b5c8a 100644
--- a/client/src/pages/SettingsPage.tsx
+++ b/client/src/pages/SettingsPage.tsx
@@ -34,7 +34,7 @@ interface SectionProps {
function Section({ title, icon: Icon, children }: SectionProps): React.ReactElement {
return (
-
+
{title}
@@ -220,12 +220,15 @@ export default function SettingsPage(): React.ReactElement {
-
-
+
+
+
{t('settings.title')}
{t('settings.subtitle')}
+
+
{/* Map settings */}
@@ -439,6 +442,36 @@ export default function SettingsPage(): React.ReactElement {
))}
+
+ {/* Blur Booking Codes */}
+
+
+
+ {[
+ { value: true, label: t('settings.on') || 'On' },
+ { value: false, label: t('settings.off') || 'Off' },
+ ].map(opt => (
+
+ ))}
+
+
{/* Immich — only when Memories addon is enabled */}
@@ -888,6 +921,7 @@ export default function SettingsPage(): React.ReactElement {
)}
+
diff --git a/client/src/types.ts b/client/src/types.ts
index e5913ab..f0da1ee 100644
--- a/client/src/types.ts
+++ b/client/src/types.ts
@@ -171,6 +171,7 @@ export interface Settings {
time_format: string
show_place_description: boolean
route_calculation?: boolean
+ blur_booking_codes?: boolean
}
export interface AssignmentsMap {