Compare commits

...

4 Commits

Author SHA1 Message Date
elpatron b9c908169b chore: release v0.1.0.78 2026-06-01 13:44:36 +02:00
elpatron e6bde5c525 fix: shorten travel day badge to "Reisetag x"
Use travel_day_number i18n key in journal cards and live log subtitle.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 13:41:27 +02:00
elpatron eab7b86c0b chore: release v0.1.0.77 2026-06-01 13:28:24 +02:00
elpatron b86789ae4c fix: show profile button while a logbook is open
Extract ProfileHeaderButton and open UserProfilePage from any screen
without leaving the active logbook.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 13:28:03 +02:00
11 changed files with 61 additions and 34 deletions
+1 -1
View File
@@ -1 +1 @@
0.1.0.77
0.1.0.79
+20 -12
View File
@@ -44,6 +44,7 @@ import { useLiveQuery } from 'dexie-react-hooks'
import { Ship, LogOut, ChevronLeft, Users, FileText, Settings, Wifi, WifiOff, Languages, BarChart2 } from 'lucide-react'
import DisclaimerHeaderButton from './components/DisclaimerHeaderButton.tsx'
import FeedbackHeaderButton from './components/FeedbackHeaderButton.tsx'
import ProfileHeaderButton from './components/ProfileHeaderButton.tsx'
import { useTranslation } from 'react-i18next'
import { cycleAppLanguage } from './utils/i18nLanguages.js'
import {
@@ -557,22 +558,27 @@ function App() {
const isLogbookOwner =
activeAccessRole === 'OWNER' || activeLogbookRecord?.isShared !== 1
if (showUserProfile) {
return (
<div style={{ display: 'contents' }}>
{pwaInstallBanner}
<UserProfilePage
onBack={() => setShowUserProfile(false)}
onLogout={handleLogout}
/>
</div>
)
}
if (!activeLogbookId) {
return (
<div style={{ display: 'contents' }}>
{pwaInstallBanner}
{showUserProfile ? (
<UserProfilePage
onBack={() => setShowUserProfile(false)}
onLogout={handleLogout}
/>
) : (
<LogbookDashboard
onSelectLogbook={selectLogbook}
onLogout={handleLogout}
onOpenProfile={() => setShowUserProfile(true)}
/>
)}
<LogbookDashboard
onSelectLogbook={selectLogbook}
onLogout={handleLogout}
onOpenProfile={() => setShowUserProfile(true)}
/>
</div>
)
}
@@ -622,6 +628,8 @@ function App() {
<Languages size={18} />
</button>
<ProfileHeaderButton onClick={() => setShowUserProfile(true)} />
<DisclaimerHeaderButton />
<FeedbackHeaderButton
+1 -1
View File
@@ -765,7 +765,7 @@ export default function LiveLogView({
<h2>{t('logs.live_title')}</h2>
{date && (
<p className="live-log-subtitle">
{t('logs.day_of_travel')} {dayOfTravel} · {new Date(date).toLocaleDateString()}
{t('logs.travel_day_number', { number: dayOfTravel })} · {new Date(date).toLocaleDateString()}
</p>
)}
</div>
+1 -1
View File
@@ -474,7 +474,7 @@ export default function LogEntriesList({
</h3>
<div className="card-meta">
<span className="sync-badge synced">
{t('logs.day_of_travel')} {item.dayOfTravel}
{t('logs.travel_day_number', { number: item.dayOfTravel })}
</span>
<EntrySkipperSignBadge status={item.skipperSignStatus} />
<span className="date-badge">
+3 -14
View File
@@ -8,9 +8,10 @@ import BetaBadge from './BetaBadge.tsx'
import { PlausibleEvents, trackPlausibleEvent } from '../services/analytics.js'
import { logoutUser } from '../services/auth.js'
import { useDialog } from './ModalDialog.tsx'
import { BookOpen, Plus, Trash2, LogOut, Languages, RefreshCw, Ship, User, Wifi, WifiOff, Search, X, CalendarDays, CaseSensitive, ArrowUp, ArrowDown } from 'lucide-react'
import { BookOpen, Plus, Trash2, LogOut, Languages, RefreshCw, Ship, Wifi, WifiOff, Search, X, CalendarDays, CaseSensitive, ArrowUp, ArrowDown } from 'lucide-react'
import DisclaimerHeaderButton from './DisclaimerHeaderButton.tsx'
import FeedbackHeaderButton from './FeedbackHeaderButton.tsx'
import ProfileHeaderButton from './ProfileHeaderButton.tsx'
interface LogbookDashboardProps {
onSelectLogbook: (id: string, title: string) => void
@@ -74,7 +75,6 @@ export default function LogbookDashboard({ onSelectLogbook, onLogout, onOpenProf
const [sortDirection, setSortDirection] = useState<LogbookSortDirection>('desc')
const filterInputRef = useRef<HTMLInputElement>(null)
const [online, setOnline] = useState(navigator.onLine)
const [username] = useState(localStorage.getItem('active_username') || 'Skipper')
const { pendingCount, showSpinner, showPendingWarning, connStatusClassName } = useSyncIndicator()
@@ -370,18 +370,7 @@ export default function LogbookDashboard({ onSelectLogbook, onLogout, onOpenProf
)}
</div>
{/* Skipper profile */}
<button
type="button"
className="btn-icon skipper-badge"
onClick={onOpenProfile}
title={t('dashboard.open_profile', { name: username })}
aria-label={t('dashboard.open_profile', { name: username })}
data-tour="nav-profile"
>
<User size={18} aria-hidden="true" />
<span className="skipper-badge__name">{username}</span>
</button>
<ProfileHeaderButton onClick={onOpenProfile} />
{/* Lang toggle */}
<button className="btn-icon" onClick={toggleLanguage} title="Switch Language">
@@ -0,0 +1,25 @@
import { useTranslation } from 'react-i18next'
import { User } from 'lucide-react'
interface ProfileHeaderButtonProps {
onClick: () => void
}
export default function ProfileHeaderButton({ onClick }: ProfileHeaderButtonProps) {
const { t } = useTranslation()
const username = localStorage.getItem('active_username') || 'Skipper'
return (
<button
type="button"
className="btn-icon skipper-badge"
onClick={onClick}
title={t('dashboard.open_profile', { name: username })}
aria-label={t('dashboard.open_profile', { name: username })}
data-tour="nav-profile"
>
<User size={18} aria-hidden="true" />
<span className="skipper-badge__name">{username}</span>
</button>
)
}
+2 -1
View File
@@ -150,7 +150,8 @@
"sign_cleared_skipper_re_sign_title": "Skippers underskrift fjernet",
"sign_cleared_skipper_re_sign": "Hændelsesloggen er blevet ændret. Skipperens underskrift er blevet fjernet. Godkend venligst igen.",
"date": "dato",
"day_of_travel": "Rejsedag / rejsedag",
"day_of_travel": "Rejsedag",
"travel_day_number": "Rejsedag {{number}}",
"departure": "Starthavn (rejse fra)",
"destination": "Destinationsport (til)",
"route": "Rejse fra/til",
+2 -1
View File
@@ -150,7 +150,8 @@
"sign_cleared_skipper_re_sign_title": "Skipper-Unterschrift entfernt",
"sign_cleared_skipper_re_sign": "Das Ereignisprotokoll wurde geändert. Die Skipper-Unterschrift wurde entfernt. Bitte erneut freigeben.",
"date": "Datum",
"day_of_travel": "Tag der Reise / Reisetag",
"day_of_travel": "Reisetag",
"travel_day_number": "Reisetag {{number}}",
"departure": "Start-Hafen (Reise von)",
"destination": "Ziel-Hafen (nach)",
"route": "Reise von/nach",
+2 -1
View File
@@ -150,7 +150,8 @@
"sign_cleared_skipper_re_sign_title": "Skipper signature removed",
"sign_cleared_skipper_re_sign": "The event log was changed. The skipper signature was removed. Please sign again.",
"date": "Date",
"day_of_travel": "Day of Travel",
"day_of_travel": "Travel day",
"travel_day_number": "Travel day {{number}}",
"departure": "Departure Port (von)",
"destination": "Destination Port (nach)",
"route": "Route / Journey",
+2 -1
View File
@@ -150,7 +150,8 @@
"sign_cleared_skipper_re_sign_title": "Skippers signatur fjernet",
"sign_cleared_skipper_re_sign": "Hendelsesloggen har blitt endret. Skipperens signatur er fjernet. Vennligst godkjenn på nytt.",
"date": "dato",
"day_of_travel": "Reisens dag / reisedag",
"day_of_travel": "Reisedag",
"travel_day_number": "Reisedag {{number}}",
"departure": "Starthavn (reise fra)",
"destination": "Destinasjonsport (til)",
"route": "Reise fra/til",
+2 -1
View File
@@ -150,7 +150,8 @@
"sign_cleared_skipper_re_sign_title": "Skippers signatur borttagen",
"sign_cleared_skipper_re_sign": "Händelseloggen har ändrats. Skepparens signatur har tagits bort. Vänligen godkänn igen.",
"date": "datum",
"day_of_travel": "Resedag / resedag",
"day_of_travel": "Resedag",
"travel_day_number": "Resedag {{number}}",
"departure": "Starthamn (resa från)",
"destination": "Destinationsport (till)",
"route": "Resa från/till",