@@ -5,7 +5,8 @@ import type { AppSettings } from "./lib/types";
55import { Settings as SettingsIcon , Clock , ListChecks , HelpCircle } from "lucide-react" ;
66import { Button } from "./components/ui/Button" ;
77import { TicketList } from "./components/TicketList" ;
8- import { cn } from "./lib/utils" ;
8+ import { cn , formatDuration } from "./lib/utils" ;
9+ import { fetchTodaysTime } from "./lib/jira" ;
910
1011
1112
@@ -15,6 +16,22 @@ function App() {
1516 const [ view , setView ] = useState < View > ( "list" ) ;
1617 const [ settings , setSettings ] = useState < AppSettings | null > ( null ) ;
1718 const [ loading , setLoading ] = useState ( true ) ;
19+ const [ todaysTimeSeconds , setTodaysTimeSeconds ] = useState < number | null > ( null ) ;
20+ const [ isTimeRefreshing , setIsTimeRefreshing ] = useState ( false ) ;
21+
22+ const fetchTime = async ( currentSettings : AppSettings ) => {
23+ setIsTimeRefreshing ( true ) ;
24+ try {
25+ const time = await fetchTodaysTime ( currentSettings ) ;
26+ setTodaysTimeSeconds ( time ) ;
27+ } catch ( e ) {
28+ console . error ( "Failed to fetch time:" , e ) ;
29+ // Don't reset to 0 on error, keep last known good value or 0 if none
30+ if ( todaysTimeSeconds === null ) setTodaysTimeSeconds ( 0 ) ;
31+ } finally {
32+ setIsTimeRefreshing ( false ) ;
33+ }
34+ } ;
1835
1936 // Easter Egg State
2037 const [ logoClicks , setLogoClicks ] = useState ( 0 ) ;
@@ -76,6 +93,10 @@ function App() {
7693 setView ( "settings" ) ;
7794 }
7895 setLoading ( false ) ;
96+ // Fetch time after config is loaded
97+ if ( s ?. jiraHost && s ?. jiraPat ) {
98+ fetchTime ( s ) ;
99+ }
79100 } ;
80101
81102 const handleSaveSettings = ( ) => {
@@ -105,6 +126,27 @@ function App() {
105126 < h1 className = "text-lg font-bold tracking-tight text-gray-900 dark:text-white" > JiraTime</ h1 >
106127 </ div >
107128
129+ { /* Today's Time Display - Centered/Right in header */ }
130+ { settings && view !== "settings" && (
131+ < div className = "flex flex-col items-end mr-auto ml-4" >
132+ < span className = "text-[10px] text-gray-400 dark:text-gray-500 uppercase font-bold leading-none" > Today</ span >
133+ { todaysTimeSeconds !== null ? (
134+ < span className = { cn (
135+ "text-xs font-semibold text-gray-700 dark:text-gray-300 tabular-nums transition-opacity duration-300" ,
136+ isTimeRefreshing && "opacity-50"
137+ ) } >
138+ { formatDuration ( todaysTimeSeconds ) }
139+ </ span >
140+ ) : (
141+ < div className = "flex items-center gap-1 h-4" >
142+ < div className = "w-1.5 h-1.5 bg-gray-300 dark:bg-gray-600 rounded-full animate-pulse" > </ div >
143+ < div className = "w-1.5 h-1.5 bg-gray-300 dark:bg-gray-600 rounded-full animate-pulse delay-75" > </ div >
144+ < div className = "w-1.5 h-1.5 bg-gray-300 dark:bg-gray-600 rounded-full animate-pulse delay-150" > </ div >
145+ </ div >
146+ ) }
147+ </ div >
148+ ) }
149+
108150 < div className = "flex items-center gap-1" >
109151 { settings && view !== "about" && (
110152 < Button variant = "ghost" className = "p-2 h-auto text-gray-500" onClick = { ( ) => setView ( "about" ) } title = "About" >
@@ -127,15 +169,17 @@ function App() {
127169 { /* Main Content */ }
128170 < main className = "flex-1 overflow-auto" >
129171 { view === "settings" ? (
130- < Settings
131- onSave = { handleSaveSettings }
132- showCancel = { ! ! settings }
133- onCancel = { ( ) => {
134- setPreviewTheme ( null ) ;
135- setView ( "list" ) ;
136- } }
137- onThemeChange = { setPreviewTheme }
138- />
172+ < div className = "h-full overflow-y-auto" >
173+ < Settings
174+ onSave = { handleSaveSettings }
175+ showCancel = { ! ! settings }
176+ onCancel = { ( ) => {
177+ setPreviewTheme ( null ) ;
178+ setView ( "list" ) ;
179+ } }
180+ onThemeChange = { setPreviewTheme }
181+ />
182+ </ div >
139183 ) : view === "about" ? (
140184 < div className = "flex flex-col items-center justify-center h-full p-8 text-center space-y-6" >
141185 < div className = "bg-blue-100 dark:bg-blue-900/30 p-6 rounded-full text-blue-600 dark:text-blue-400 mb-2 animate-bounce" >
@@ -159,7 +203,11 @@ function App() {
159203 </ Button >
160204 </ div >
161205 ) : settings ? (
162- < TicketList settings = { settings } onSettingsChange = { checkConfig } />
206+ < TicketList
207+ settings = { settings }
208+ onSettingsChange = { checkConfig }
209+ onTimeUpdate = { ( ) => fetchTime ( settings ) }
210+ />
163211 ) : (
164212 < div className = "p-8 text-center text-gray-500" >
165213 Please configure settings first.
0 commit comments