@@ -305,22 +305,43 @@ function SavingsChart({ data, title, icon: Icon, period, color, gradientId, avgM
305305
306306function LoadingSkeleton ( ) {
307307 return (
308- < div className = "grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-6" >
309- { [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] . map ( ( i ) => (
310- < Card key = { i } className = "bg-card border-border" >
311- < CardHeader className = "pb-4" >
312- < div className = "flex items-center space-x-3" >
313- < Skeleton className = "h-9 w-9 rounded-lg bg-muted" />
314- < div className = "space-y-2" >
315- < Skeleton className = "h-5 w-32 bg-muted" />
316- < Skeleton className = "h-8 w-24 bg-muted" />
308+ < div className = "space-y-8" >
309+ { [ 1 , 2 , 3 ] . map ( ( groupIndex ) => (
310+ < div key = { groupIndex } className = "space-y-4" >
311+ { /* Full-width chart skeleton */ }
312+ < Card className = "bg-card border-border shadow-lg" >
313+ < CardHeader className = "pb-4" >
314+ < div className = "flex items-center space-x-3" >
315+ < Skeleton className = "h-9 w-9 rounded-lg bg-muted" />
316+ < div className = "space-y-2" >
317+ < Skeleton className = "h-5 w-32 bg-muted" />
318+ </ div >
317319 </ div >
318- </ div >
319- </ CardHeader >
320- < CardContent className = "pt-0" >
321- < Skeleton className = "h-[240px] w-full bg-muted rounded-lg" />
322- </ CardContent >
323- </ Card >
320+ </ CardHeader >
321+ < CardContent className = "pt-0" >
322+ < Skeleton className = "h-[240px] w-full bg-muted rounded-lg" />
323+ </ CardContent >
324+ </ Card >
325+
326+ { /* Side-by-side charts skeleton */ }
327+ < div className = "grid grid-cols-1 lg:grid-cols-2 gap-6" >
328+ { [ 1 , 2 ] . map ( ( chartIndex ) => (
329+ < Card key = { chartIndex } className = "bg-card border-border shadow-lg" >
330+ < CardHeader className = "pb-4" >
331+ < div className = "flex items-center space-x-3" >
332+ < Skeleton className = "h-9 w-9 rounded-lg bg-muted" />
333+ < div className = "space-y-2" >
334+ < Skeleton className = "h-5 w-32 bg-muted" />
335+ </ div >
336+ </ div >
337+ </ CardHeader >
338+ < CardContent className = "pt-0" >
339+ < Skeleton className = "h-[240px] w-full bg-muted rounded-lg" />
340+ </ CardContent >
341+ </ Card >
342+ ) ) }
343+ </ div >
344+ </ div >
324345 ) ) }
325346 </ div >
326347 )
@@ -330,13 +351,17 @@ export function AnalyticsContent() {
330351 const domain = useDomain ( )
331352 const { theme } = useTheme ( )
332353
333- const [ avgMinutesSaved , setAvgMinutesSaved ] = useState ( 2 )
334- const [ avgSalary , setAvgSalary ] = useState ( 100000 )
354+ // Store these values as strings in the state to allow us to have empty fields for better UX
355+ const [ avgMinutesSaved , setAvgMinutesSaved ] = useState ( "2" )
356+ const [ avgSalary , setAvgSalary ] = useState ( "100000" )
357+ const numericAvgMinutesSaved = parseFloat ( avgMinutesSaved ) || 0
358+ const numericAvgSalary = parseInt ( avgSalary , 10 ) || 0
335359
336360 const {
337361 data : analyticsResponse ,
338- isLoading,
339- error,
362+ isPending,
363+ isError,
364+ error
340365 } = useQuery ( {
341366 queryKey : [ "analytics" , domain ] ,
342367 queryFn : ( ) => unwrapServiceError ( getAnalytics ( domain ) ) ,
@@ -368,20 +393,20 @@ export function AnalyticsContent() {
368393 const totalSavings = useMemo ( ( ) => {
369394 if ( ! analyticsResponse ) return 0
370395 const totalOperations = analyticsResponse . reduce ( ( sum , row ) => sum + row . code_searches + row . navigations , 0 )
371- const totalMinutesSaved = totalOperations * avgMinutesSaved
372- const hourlyRate = avgSalary / ( 40 * 52 )
396+ const totalMinutesSaved = totalOperations * numericAvgMinutesSaved
397+ const hourlyRate = numericAvgSalary / ( 40 * 52 )
373398 return Math . round ( ( totalMinutesSaved / 60 * hourlyRate ) * 100 ) / 100
374- } , [ analyticsResponse , avgMinutesSaved , avgSalary ] )
399+ } , [ analyticsResponse , numericAvgMinutesSaved , numericAvgSalary ] )
375400
376- if ( isLoading ) {
401+ if ( isPending ) {
377402 return (
378403 < div className = "min-h-screen bg-background p-6" >
379404 < LoadingSkeleton />
380405 </ div >
381406 )
382407 }
383408
384- if ( error ) {
409+ if ( isError ) {
385410 return (
386411 < div className = "min-h-screen bg-background flex items-center justify-center" >
387412 < Card className = "bg-destructive/10 border-destructive/20 p-8" >
@@ -397,22 +422,6 @@ export function AnalyticsContent() {
397422 )
398423 }
399424
400- if ( ! analyticsResponse ) {
401- return (
402- < div className = "min-h-screen bg-background flex items-center justify-center" >
403- < Card className = "bg-card border-border p-8" >
404- < div className = "text-center" >
405- < div className = "p-3 rounded-full bg-muted/50 w-fit mx-auto mb-4" >
406- < Activity className = "h-8 w-8 text-muted-foreground" />
407- </ div >
408- < h3 className = "text-xl font-semibold text-card-foreground mb-2" > No Data Available</ h3 >
409- < p className = "text-muted-foreground" > No analytics data available for this domain</ p >
410- </ div >
411- </ Card >
412- </ div >
413- )
414- }
415-
416425 const dailyData = analyticsResponse . filter ( ( row ) => row . period === "day" )
417426 const weeklyData = analyticsResponse . filter ( ( row ) => row . period === "week" )
418427 const monthlyData = analyticsResponse . filter ( ( row ) => row . period === "month" )
@@ -563,10 +572,10 @@ export function AnalyticsContent() {
563572 < Input
564573 id = "avgMinutesSaved"
565574 type = "number"
566- min = "0.1 "
575+ min = "0"
567576 step = "0.1"
568577 value = { avgMinutesSaved }
569- onChange = { ( e ) => setAvgMinutesSaved ( parseFloat ( e . target . value ) || 0 ) }
578+ onChange = { ( e ) => setAvgMinutesSaved ( e . target . value ) }
570579 placeholder = "2"
571580 />
572581 < p className = "text-xs text-muted-foreground" > Estimated time saved per search or navigation operation</ p >
@@ -576,10 +585,10 @@ export function AnalyticsContent() {
576585 < Input
577586 id = "avgSalary"
578587 type = "number"
579- min = "10000 "
588+ min = "0 "
580589 step = "1000"
581590 value = { avgSalary }
582- onChange = { ( e ) => setAvgSalary ( parseInt ( e . target . value ) || 0 ) }
591+ onChange = { ( e ) => setAvgSalary ( e . target . value ) }
583592 placeholder = "100000"
584593 />
585594 < p className = "text-xs text-muted-foreground" > Average annual salary of your engineering team</ p >
@@ -608,8 +617,8 @@ export function AnalyticsContent() {
608617 period = "day"
609618 color = { getColor ( "savings" ) }
610619 gradientId = "dailySavings"
611- avgMinutesSaved = { avgMinutesSaved }
612- avgSalary = { avgSalary }
620+ avgMinutesSaved = { numericAvgMinutesSaved }
621+ avgSalary = { numericAvgSalary }
613622 />
614623
615624 < div className = "grid grid-cols-1 lg:grid-cols-2 gap-6" >
@@ -620,8 +629,8 @@ export function AnalyticsContent() {
620629 period = "week"
621630 color = { getColor ( "savings" ) }
622631 gradientId = "weeklySavings"
623- avgMinutesSaved = { avgMinutesSaved }
624- avgSalary = { avgSalary }
632+ avgMinutesSaved = { numericAvgMinutesSaved }
633+ avgSalary = { numericAvgSalary }
625634 />
626635 < SavingsChart
627636 data = { monthlyData }
@@ -630,8 +639,8 @@ export function AnalyticsContent() {
630639 period = "month"
631640 color = { getColor ( "savings" ) }
632641 gradientId = "monthlySavings"
633- avgMinutesSaved = { avgMinutesSaved }
634- avgSalary = { avgSalary }
642+ avgMinutesSaved = { numericAvgMinutesSaved }
643+ avgSalary = { numericAvgSalary }
635644 />
636645 </ div >
637646 </ div >
0 commit comments