88 getSubjects ,
99 getNotes
1010} from "@/lib/firebase/firestore" ;
11+ import { getAllNotes , getNoteStatistics , findOrphanedNotes } from "@/lib/firebase/migrations" ;
1112
1213export default function DBDiagnosticPage ( ) {
1314 const [ departments , setDepartments ] = useState < any [ ] > ( [ ] ) ;
@@ -22,6 +23,12 @@ export default function DBDiagnosticPage() {
2223 const [ loading , setLoading ] = useState ( false ) ;
2324 const [ error , setError ] = useState < string > ( "" ) ;
2425
26+ // Global diagnostics
27+ const [ allNotes , setAllNotes ] = useState < any [ ] > ( [ ] ) ;
28+ const [ statistics , setStatistics ] = useState < any > ( null ) ;
29+ const [ orphanedNotes , setOrphanedNotes ] = useState < any [ ] > ( [ ] ) ;
30+ const [ showGlobalView , setShowGlobalView ] = useState ( false ) ;
31+
2532 useEffect ( ( ) => {
2633 loadDepartments ( ) ;
2734 } , [ ] ) ;
@@ -40,6 +47,27 @@ export default function DBDiagnosticPage() {
4047 }
4148 }
4249
50+ async function loadGlobalStatistics ( ) {
51+ try {
52+ setLoading ( true ) ;
53+ setError ( "" ) ;
54+ const [ stats , orphaned , all ] = await Promise . all ( [
55+ getNoteStatistics ( ) ,
56+ findOrphanedNotes ( ) ,
57+ getAllNotes ( )
58+ ] ) ;
59+ setStatistics ( stats ) ;
60+ setOrphanedNotes ( orphaned ) ;
61+ setAllNotes ( all ) ;
62+ setShowGlobalView ( true ) ;
63+ } catch ( err : any ) {
64+ console . error ( "Error loading statistics:" , err ) ;
65+ setError ( err . message ) ;
66+ } finally {
67+ setLoading ( false ) ;
68+ }
69+ }
70+
4371 async function loadBatches ( deptId : string ) {
4472 try {
4573 setLoading ( true ) ;
@@ -122,7 +150,23 @@ export default function DBDiagnosticPage() {
122150
123151 return (
124152 < div style = { { padding : "2rem" , maxWidth : "1200px" , margin : "0 auto" } } >
125- < h1 style = { { marginBottom : "2rem" } } > 🔍 Firebase Database Diagnostic</ h1 >
153+ < div style = { { display : "flex" , justifyContent : "space-between" , alignItems : "center" , marginBottom : "2rem" } } >
154+ < h1 > 🔍 Firebase Database Diagnostic</ h1 >
155+ < button
156+ onClick = { loadGlobalStatistics }
157+ style = { {
158+ padding : "0.75rem 1.5rem" ,
159+ background : "#3b82f6" ,
160+ color : "white" ,
161+ border : "none" ,
162+ borderRadius : "6px" ,
163+ cursor : "pointer" ,
164+ fontWeight : "600"
165+ } }
166+ >
167+ 📊 Show Global Statistics
168+ </ button >
169+ </ div >
126170
127171 { error && (
128172 < div style = { {
@@ -139,6 +183,80 @@ export default function DBDiagnosticPage() {
139183
140184 { loading && < p > Loading...</ p > }
141185
186+ { /* Global Statistics Panel */ }
187+ { showGlobalView && statistics && (
188+ < div style = { { marginBottom : "2rem" } } >
189+ < div style = { { display : "flex" , justifyContent : "space-between" , alignItems : "center" , marginBottom : "1rem" } } >
190+ < h2 > 📊 Global Database Statistics</ h2 >
191+ < button
192+ onClick = { ( ) => setShowGlobalView ( false ) }
193+ style = { {
194+ padding : "0.5rem 1rem" ,
195+ background : "#6b7280" ,
196+ color : "white" ,
197+ border : "none" ,
198+ borderRadius : "6px" ,
199+ cursor : "pointer"
200+ } }
201+ >
202+ Hide
203+ </ button >
204+ </ div >
205+
206+ { /* Statistics Cards */ }
207+ < div style = { { display : "grid" , gridTemplateColumns : "repeat(auto-fit, minmax(200px, 1fr))" , gap : "1rem" , marginBottom : "2rem" } } >
208+ < div style = { { background : "#eff6ff" , padding : "1.5rem" , borderRadius : "8px" , border : "1px solid #bfdbfe" } } >
209+ < h3 style = { { fontSize : "2rem" , marginBottom : "0.5rem" , color : "#1e40af" } } > { statistics . total } </ h3 >
210+ < p style = { { color : "#3b82f6" , fontWeight : "600" } } > Total Notes</ p >
211+ </ div >
212+ < div style = { { background : "#d1fae5" , padding : "1.5rem" , borderRadius : "8px" , border : "1px solid #6ee7b7" } } >
213+ < h3 style = { { fontSize : "2rem" , marginBottom : "0.5rem" , color : "#065f46" } } > { statistics . withSubject } </ h3 >
214+ < p style = { { color : "#10b981" , fontWeight : "600" } } > With Subject</ p >
215+ </ div >
216+ < div style = { { background : "#fee2e2" , padding : "1.5rem" , borderRadius : "8px" , border : "1px solid #fca5a5" } } >
217+ < h3 style = { { fontSize : "2rem" , marginBottom : "0.5rem" , color : "#991b1b" } } > { statistics . orphaned } </ h3 >
218+ < p style = { { color : "#ef4444" , fontWeight : "600" } } > Orphaned (No Subject)</ p >
219+ </ div >
220+ < div style = { { background : "#fef3c7" , padding : "1.5rem" , borderRadius : "8px" , border : "1px solid #fcd34d" } } >
221+ < h3 style = { { fontSize : "2rem" , marginBottom : "0.5rem" , color : "#92400e" } } > { statistics . invalid } </ h3 >
222+ < p style = { { color : "#f59e0b" , fontWeight : "600" } } > Invalid Structure</ p >
223+ </ div >
224+ </ div >
225+
226+ { /* Orphaned Notes Details */ }
227+ { orphanedNotes . length > 0 && (
228+ < div style = { { background : "#fee2e2" , padding : "1.5rem" , borderRadius : "8px" , marginBottom : "2rem" } } >
229+ < h3 style = { { color : "#991b1b" , marginBottom : "1rem" } } > ⚠️ Orphaned Notes ({ orphanedNotes . length } )</ h3 >
230+ < p style = { { marginBottom : "1rem" , color : "#7f1d1d" } } >
231+ These files exist but are missing critical metadata. Students cannot see them.
232+ </ p >
233+ < div style = { { maxHeight : "300px" , overflow : "auto" } } >
234+ { orphanedNotes . map ( ( note , idx ) => (
235+ < div key = { note . id } style = { { background : "white" , padding : "1rem" , marginBottom : "0.5rem" , borderRadius : "6px" } } >
236+ < p style = { { fontWeight : "600" , marginBottom : "0.5rem" } } > { idx + 1 } . { note . title } </ p >
237+ < p style = { { fontSize : "0.85rem" , color : "#6b7280" } } >
238+ ID: { note . id } < br />
239+ Missing: { ! note . subjectId && "subjectId " }
240+ { ! note . departmentId && "departmentId " }
241+ { ! note . batchId && "batchId " }
242+ { ! note . semesterId && "semesterId" }
243+ </ p >
244+ </ div >
245+ ) ) }
246+ </ div >
247+ </ div >
248+ ) }
249+
250+ { /* All Notes */ }
251+ < div style = { { background : "#f9fafb" , padding : "1.5rem" , borderRadius : "8px" } } >
252+ < h3 style = { { marginBottom : "1rem" } } > 📄 All Notes in Database ({ allNotes . length } )</ h3 >
253+ < pre style = { { background : "#f5f5f5" , padding : "1rem" , borderRadius : "6px" , overflow : "auto" , maxHeight : "400px" , fontSize : "0.85rem" } } >
254+ { JSON . stringify ( allNotes , null , 2 ) }
255+ </ pre >
256+ </ div >
257+ </ div >
258+ ) }
259+
142260 < div style = { { display : "grid" , gap : "2rem" } } >
143261 { /* Departments */ }
144262 < div >
0 commit comments