1- import { Box , Button , Container , Typography } from "@mui/material" ;
1+ import {
2+ Box ,
3+ Button ,
4+ CircularProgress ,
5+ Container ,
6+ Typography ,
7+ } from "@mui/material" ;
8+ import { signIn , useSession } from "next-auth/react" ;
29import Head from "next/head" ;
10+ import { useCallback , useEffect , useState } from "react" ;
311import { useDarkMode } from "../lib/DarkModeContext" ;
412
513const CLAUDE_BILLING_DASHBOARD_ID = "9127e39ec5a7410ebb419fac06a08ca0" ;
614
715export default function ClaudeBillingPage ( ) {
816 const { themeMode, darkMode } = useDarkMode ( ) ;
17+ const session = useSession ( ) ;
18+ const [ permissionState , setPermissionState ] = useState <
19+ "unchecked" | "checking" | "sufficient" | "insufficient"
20+ > ( "unchecked" ) ;
21+
22+ const checkUserPermissions = useCallback ( async ( ) => {
23+ if ( ! session . data ?. user || permissionState !== "unchecked" ) return ;
24+
25+ setPermissionState ( "checking" ) ;
26+ try {
27+ const response = await fetch ( "/api/torchagent-check-permissions" , {
28+ method : "GET" ,
29+ headers : { "Content-Type" : "application/json" } ,
30+ } ) ;
31+
32+ if ( response . ok ) {
33+ setPermissionState ( "sufficient" ) ;
34+ } else {
35+ setPermissionState ( "insufficient" ) ;
36+ }
37+ } catch ( error ) {
38+ console . error ( "Error checking permissions:" , error ) ;
39+ setPermissionState ( "insufficient" ) ;
40+ }
41+ } , [ session . data ?. user , permissionState ] ) ;
42+
43+ useEffect ( ( ) => {
44+ if ( session . data ?. user && permissionState === "unchecked" ) {
45+ checkUserPermissions ( ) ;
46+ }
47+ } , [ session . data ?. user , permissionState , checkUserPermissions ] ) ;
948
1049 let chartTheme = "light" ;
1150 if ( themeMode === "system" ) {
@@ -17,6 +56,137 @@ export default function ClaudeBillingPage() {
1756 const dashboardUrl = `https://disz2yd9jqnwc.cloudfront.net/public-dashboards/${ CLAUDE_BILLING_DASHBOARD_ID } ?theme=${ chartTheme } ` ;
1857 const grafanaUrl = `https://pytorchci.grafana.net/public-dashboards/${ CLAUDE_BILLING_DASHBOARD_ID } ` ;
1958
59+ // Loading state
60+ if ( session . status === "loading" || permissionState === "checking" ) {
61+ return (
62+ < >
63+ < Head >
64+ < title > Claude Code Review Billing - PyTorch CI HUD</ title >
65+ </ Head >
66+ < Container
67+ maxWidth = { false }
68+ sx = { {
69+ py : 10 ,
70+ display : "flex" ,
71+ flexDirection : "column" ,
72+ alignItems : "center" ,
73+ } }
74+ >
75+ < CircularProgress />
76+ < Typography variant = "h6" sx = { { mt : 2 } } >
77+ { session . status === "loading"
78+ ? "Checking authentication..."
79+ : "Checking permissions..." }
80+ </ Typography >
81+ </ Container >
82+ </ >
83+ ) ;
84+ }
85+
86+ // Unauthenticated
87+ if (
88+ session . status === "unauthenticated" ||
89+ ! session . data ?. user ||
90+ ! ( session . data as any ) ?. accessToken
91+ ) {
92+ return (
93+ < >
94+ < Head >
95+ < title > Claude Code Review Billing - PyTorch CI HUD</ title >
96+ </ Head >
97+ < Container
98+ maxWidth = { false }
99+ sx = { {
100+ py : 10 ,
101+ display : "flex" ,
102+ flexDirection : "column" ,
103+ alignItems : "center" ,
104+ } }
105+ >
106+ < Typography variant = "h4" gutterBottom >
107+ Authentication Required
108+ </ Typography >
109+ < Typography variant = "body1" sx = { { mb : 2 } } >
110+ You must be signed in with write permissions to pytorch/pytorch to
111+ view Claude billing data.
112+ </ Typography >
113+ < Typography variant = "body2" color = "text.secondary" sx = { { mb : 3 } } >
114+ Please sign in with GitHub to continue.
115+ </ Typography >
116+ < Button
117+ variant = "contained"
118+ color = "primary"
119+ size = "large"
120+ onClick = { ( ) => signIn ( ) }
121+ sx = { { minWidth : "200px" } }
122+ >
123+ Sign In
124+ </ Button >
125+ </ Container >
126+ </ >
127+ ) ;
128+ }
129+
130+ // Insufficient permissions
131+ if ( permissionState === "insufficient" ) {
132+ return (
133+ < >
134+ < Head >
135+ < title > Claude Code Review Billing - PyTorch CI HUD</ title >
136+ </ Head >
137+ < Container
138+ maxWidth = { false }
139+ sx = { {
140+ py : 10 ,
141+ display : "flex" ,
142+ flexDirection : "column" ,
143+ alignItems : "center" ,
144+ } }
145+ >
146+ < Typography variant = "h4" gutterBottom >
147+ Insufficient Permissions
148+ </ Typography >
149+ < Typography variant = "body1" sx = { { mb : 2 } } >
150+ You are signed in as{ " " }
151+ < strong > { session . data . user . name || session . data . user . email } </ strong >
152+ , but you need write permissions to pytorch/pytorch to view this
153+ page.
154+ </ Typography >
155+ < Box
156+ sx = { {
157+ display : "flex" ,
158+ gap : 2 ,
159+ justifyContent : "center" ,
160+ flexWrap : "wrap" ,
161+ } }
162+ >
163+ < Button
164+ variant = "contained"
165+ color = "primary"
166+ component = "a"
167+ href = "https://forms.gle/SoLgaCucjJqc6F647"
168+ target = "_blank"
169+ rel = "noopener noreferrer"
170+ >
171+ Request Access
172+ </ Button >
173+ < Button
174+ variant = "outlined"
175+ color = "secondary"
176+ onClick = { ( ) => {
177+ setPermissionState ( "unchecked" ) ;
178+ checkUserPermissions ( ) ;
179+ } }
180+ >
181+ Try Again
182+ </ Button >
183+ </ Box >
184+ </ Container >
185+ </ >
186+ ) ;
187+ }
188+
189+ // Authorized — show the dashboard
20190 return (
21191 < >
22192 < Head >
0 commit comments