import { useEffect, useRef, useState } from 'react'
import { Timeline } from './components/timeline/Timeline'
import { DuplicatesView } from './components/duplicates/DuplicatesView'
import { MapView } from './components/map/MapView'
import { MemoriesView } from './components/memories/MemoriesView'
import { TagsView } from './components/tags/TagsView'
import { ColorsView } from './components/colors/ColorsView'
import { RatedView } from './components/rated/RatedView'
import { LeftSidebar } from './components/layout/LeftSidebar'
import { RightSidebar } from './components/layout/RightSidebar'
import { TopBar } from './components/layout/TopBar'
import { ScanProgress } from './components/ScanProgress'
import { ToastContainer } from './components/ToastContainer'
import { KeyboardHints } from './components/KeyboardHints'
import { PreviewView } from './components/preview/PreviewView'
import { FilterBar } from './components/filter/FilterBar'
import { DiscardActionBar } from './components/discard/DiscardActionBar'
import { SettingsPage } from './components/dialogs/SettingsDialog'
import { usePhotoStore } from './store/photoStore'
import { useFilterStore } from './store/filterStore'
import { useKeyboardShortcuts } from './hooks/useKeyboardShortcuts'
import { useFilterUrlSync } from './hooks/useFilterUrlSync'
import { usePhotosQuery } from './hooks/usePhotosQuery'
import { AuthProvider, useAuth } from './contexts/AuthContext'
import { LoginPage } from './components/auth/LoginPage'
import { SetupPage } from './components/auth/SetupPage'
import { OidcCallback } from './components/auth/OidcCallback'
import { TooltipProvider } from '@/components/ui/tooltip'
function MainApp() {
const [leftSidebarOpen, setLeftSidebarOpen] = useState(true)
const [rightSidebarOpen, setRightSidebarOpen] = useState(true)
// Respect the user's manual collapse of the metadata panel. Once they
// close it explicitly (via `i` hotkey or the sidebar toggle button),
// selecting a new photo should NOT force it back open. Cleared when
// they open it manually again.
const rightCollapsedByUser = useRef(false)
const viewMode = usePhotoStore((state) => state.viewMode)
const activePhotoId = usePhotoStore((state) => state.activePhotoId)
const currentSection = useFilterStore((s) => s.currentSection)
// Close the metadata panel when the user switches between sections so
// it doesn't carry over a now-irrelevant selection. It re-opens once a
// photo gains focus in the new section (effect below).
const prevSectionRef = useRef(currentSection)
useEffect(() => {
if (prevSectionRef.current !== currentSection) {
prevSectionRef.current = currentSection
setRightSidebarOpen(false)
}
}, [currentSection])
useEffect(() => {
if (!activePhotoId) {
setRightSidebarOpen(false)
return
}
// User explicitly collapsed the panel — don't undo that just because
// they picked a different photo.
if (rightCollapsedByUser.current) return
setRightSidebarOpen(true)
}, [activePhotoId])
const toggleRightSidebar = () => {
setRightSidebarOpen((prev) => {
const next = !prev
rightCollapsedByUser.current = !next
return next
})
}
// Bidirectional sync of filter store with URL query params.
useFilterUrlSync()
// Subscribe to the same photos query the Timeline uses, so the keyboard
// "open preview on first photo" path can read from the live cache regardless
// of what filter key it's stored under.
const { data: allPhotos } = usePhotosQuery()
// Set up global keyboard shortcuts. Prefer the Timeline's published
// visible sequence (which respects per-month ordering) over the raw
// backend list — otherwise "Space on a blank selection" would open
// the globally first photo, which isn't what the user sees at the
// top-left of the grid.
useKeyboardShortcuts({
onToggleLeftSidebar: () => setLeftSidebarOpen(!leftSidebarOpen),
onToggleRightSidebar: toggleRightSidebar,
getFirstPhotoId: () =>
usePhotoStore.getState().visiblePhotoIds[0] ??
allPhotos?.[0]?.id ??
null,
})
// Settings page is a full-page section — hide filter bar, right sidebar,
// and keyboard hints when it's active.
const isSettings = currentSection === 'settings'
// Right sidebar stays open by default and shows whatever's selected
// (or an empty state if nothing is). User can still toggle it manually.
const showRightSidebar = rightSidebarOpen && !isSettings
return (