diff --git a/client/components/CurrentPeriod.tsx b/client/components/CurrentPeriod.tsx index d76f620..1c037ca 100644 --- a/client/components/CurrentPeriod.tsx +++ b/client/components/CurrentPeriod.tsx @@ -43,14 +43,19 @@ interface CurrentPeriodProps { export function CurrentPeriod({ period, apiKey, userId }: CurrentPeriodProps) { const [summary, setSummary] = useState(null); const [isLoading, setIsLoading] = useState(true); + const [isRefreshing, setIsRefreshing] = useState(false); const [error, setError] = useState(''); useEffect(() => { fetchSummary(); }, [period.index]); - const fetchSummary = async () => { - setIsLoading(true); + const fetchSummary = async (isRefresh = false) => { + if (isRefresh) { + setIsRefreshing(true); + } else { + setIsLoading(true); + } setError(''); try { @@ -69,7 +74,11 @@ export function CurrentPeriod({ period, apiKey, userId }: CurrentPeriodProps) { } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load period data'); } finally { - setIsLoading(false); + if (isRefresh) { + setIsRefreshing(false); + } else { + setIsLoading(false); + } } }; @@ -103,13 +112,71 @@ export function CurrentPeriod({ period, apiKey, userId }: CurrentPeriodProps) { if (isLoading) { return (
+ {/* Header skeleton */}
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + {/* Ranking table skeleton */} +
+
+
+
+
+ + + + + + + + + + + + {[...Array(3)].map((_, i) => ( + + + + + + + + ))} + +
+
+
+ + {/* User detail card skeleton */} +
+
+
+ {[...Array(4)].map((_, i) => ( +
+
+
+
+ ))} +
+
); @@ -139,9 +206,26 @@ export function CurrentPeriod({ period, apiKey, userId }: CurrentPeriodProps) {
{/* Header with period info */}
-

- Current Period: {formatDate(summary.period.startAt)} → {formatDate(summary.period.endAt, true)} -

+
+

+ Current Period: {formatDate(summary.period.startAt)} → Now +

+ +
diff --git a/client/components/HistoricalPeriods.tsx b/client/components/HistoricalPeriods.tsx index cca87c7..f268bce 100644 --- a/client/components/HistoricalPeriods.tsx +++ b/client/components/HistoricalPeriods.tsx @@ -283,14 +283,71 @@ export function HistoricalPeriods({ periods, apiKey, userId }: HistoricalPeriods <> {/* Period Summary */} {isLoading ? ( -
-
-
-
-
-
+ <> + {/* Period summary skeleton */} +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+ + {/* Ranking table skeleton */} +
+
+
+
+
+ + + + + + + + + + + + {[...Array(3)].map((_, i) => ( + + + + + + + + ))} + +
+
+
+ + {/* User detail card skeleton */} +
+
+
+ {[...Array(4)].map((_, i) => ( +
+
+
+
+ ))} +
+
+
+ ) : error ? (
diff --git a/client/components/UserDetailCard.tsx b/client/components/UserDetailCard.tsx index f87c225..8b55ee4 100644 --- a/client/components/UserDetailCard.tsx +++ b/client/components/UserDetailCard.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; interface UserDetail { id: string; @@ -41,7 +41,7 @@ export function UserDetailCard({ periodIndex, apiKey, userId }: UserDetailCardPr if (!response.ok) { if (response.status === 404) { - throw new Error('You are not found in this period (possibly deleted)'); + throw new Error('You are not found in this period'); } throw new Error(`Failed to fetch user details: ${response.status}`); } @@ -92,13 +92,13 @@ export function UserDetailCard({ periodIndex, apiKey, userId }: UserDetailCardPr

Your Usage Details

-
+
-

{error}

+

{error}

@@ -186,9 +186,25 @@ export function UserDetailCard({ periodIndex, apiKey, userId }: UserDetailCardPr

Period Start Data

-
-              {JSON.stringify(userDetail.raw.start, null, 2)}
-            
+ {userDetail.raw.start ? ( +
+                {JSON.stringify(userDetail.raw.start, null, 2)}
+              
+ ) : ( +
+
+ + + +
+
+ No Start Data Available +
+
+ This likely means you had no usage before the start of this period. +
+
+ )}

Period End Data

diff --git a/server/billing-calculator.ts b/server/billing-calculator.ts index 481b734..8bcbe11 100644 --- a/server/billing-calculator.ts +++ b/server/billing-calculator.ts @@ -242,6 +242,11 @@ export class BillingCalculator { const result = computePeriodDelta(startData, endData, meId); + // Filter out users with zero activity (cost, requests, and tokens all 0) + const activeUsers = result.users.filter(u => + u.cost > 0 || u.periodTokens > 0 || u.periodRequests > 0 + ); + return { period: { ...period, @@ -249,9 +254,9 @@ export class BillingCalculator { }, totals: { totalCost: result.totalCost, - userCount: result.users.filter(u => u.cost > 0).length + userCount: activeUsers.length }, - ranking: result.users + ranking: activeUsers }; }