Skip to content

Commit 2a8867a

Browse files
committed
years page
1 parent 600af66 commit 2a8867a

File tree

3 files changed

+278
-2
lines changed

3 files changed

+278
-2
lines changed

backend/src/db/load.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -498,10 +498,8 @@ async function listStatutesByYear(year: number, language: string): Promise<strin
498498
console.log(`listStatutesByYear: ${year} filtered to ${latestVersions.length} latest versions in ${language}`);
499499

500500
return latestVersions;
501-
502501
}
503502

504-
505503
async function listJudgmentNumbersByYear(year: number, language: string, level: string): Promise<string[]> {
506504
let courtLevel = {
507505
fi: '',

frontend/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { Helmet } from "react-helmet"
1212
import { ThreeDot } from 'react-loading-indicators'
1313
import axios from 'axios'
1414
import YearDocumentList from './components/YearDocumentList'
15+
import YearsPage from './components/YearsPage'
1516

1617

1718
const App = () => {
@@ -124,6 +125,7 @@ const App = () => {
124125
element={<DocumentPage language={language} apipath="judgment" />
125126
}
126127
/>
128+
<Route key="admin" path="/summary" element={<YearsPage />} />
127129
<Route key="admin" path="/admin" element={<AdminPage language={language} />} />
128130
</Routes>
129131
</div>
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
import axios from "axios"
2+
import { useState, useEffect } from "react"
3+
4+
interface Document {
5+
docTitle: string
6+
docNumber: string
7+
docYear: number
8+
isEmpty: boolean
9+
docVersion: string
10+
}
11+
12+
interface YearData {
13+
year: number
14+
totalDocuments: number
15+
documentsWithContent: number
16+
emptyDocuments: number
17+
contentPercentage: number
18+
documents: Document[]
19+
}
20+
21+
const YearsPage = () => {
22+
const [yearData, setYearData] = useState<YearData[]>([])
23+
const [loading, setLoading] = useState(true)
24+
const [error, setError] = useState<string | null>(null)
25+
26+
console.log('YEARS')
27+
28+
useEffect(() => {
29+
const fetchAllYears = async () => {
30+
try {
31+
setLoading(true)
32+
const years = Array.from({ length: 20 }, (_, i) => 1960 + i) // 1960-1970
33+
34+
const promises = years.map(async (year) => {
35+
try {
36+
const response = await axios.get(`/api/statute/${year}/fin`)
37+
const documents: Document[] = response.data
38+
39+
const totalDocuments = documents.length
40+
const documentsWithContent = documents.filter(doc => !doc.isEmpty).length
41+
const emptyDocuments = documents.filter(doc => doc.isEmpty).length
42+
const contentPercentage = totalDocuments > 0 ? Math.round((documentsWithContent / totalDocuments) * 100) : 0
43+
44+
return {
45+
year,
46+
totalDocuments,
47+
documentsWithContent,
48+
emptyDocuments,
49+
contentPercentage,
50+
documents
51+
}
52+
} catch (error) {
53+
console.error(`Error fetching data for year ${year}:`, error)
54+
return {
55+
year,
56+
totalDocuments: 0,
57+
documentsWithContent: 0,
58+
emptyDocuments: 0,
59+
contentPercentage: 0,
60+
documents: []
61+
}
62+
}
63+
})
64+
65+
const results = await Promise.all(promises)
66+
setYearData(results.sort((a, b) => b.year - a.year)) // Sort by year descending
67+
setError(null)
68+
} catch (error) {
69+
console.error('Error fetching year data:', error)
70+
setError('Virhe tietojen lataamisessa')
71+
} finally {
72+
setLoading(false)
73+
}
74+
}
75+
76+
fetchAllYears()
77+
}, [])
78+
79+
const tableStyle: React.CSSProperties = {
80+
width: '100%',
81+
borderCollapse: 'collapse',
82+
marginTop: '20px',
83+
backgroundColor: 'white',
84+
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
85+
borderRadius: '8px',
86+
overflow: 'hidden'
87+
}
88+
89+
const headerStyle: React.CSSProperties = {
90+
backgroundColor: '#0C6FC0',
91+
color: 'white',
92+
padding: '12px 16px',
93+
textAlign: 'left',
94+
fontWeight: 'bold',
95+
fontSize: '14px'
96+
}
97+
98+
const cellStyle: React.CSSProperties = {
99+
padding: '12px 16px',
100+
borderBottom: '1px solid #e0e0e0',
101+
fontSize: '14px'
102+
}
103+
104+
const numberCellStyle: React.CSSProperties = {
105+
...cellStyle,
106+
textAlign: 'center',
107+
fontFamily: 'monospace',
108+
fontWeight: 'bold'
109+
}
110+
111+
const yearCellStyle: React.CSSProperties = {
112+
...cellStyle,
113+
fontWeight: 'bold',
114+
color: '#0C6FC0',
115+
fontSize: '16px'
116+
}
117+
118+
const percentageCellStyle: React.CSSProperties = {
119+
...cellStyle,
120+
textAlign: 'center',
121+
fontWeight: 'bold'
122+
}
123+
124+
const getPercentageColor = (percentage: number): string => {
125+
if (percentage >= 80) return '#00b894'
126+
if (percentage >= 60) return '#fdcb6e'
127+
if (percentage >= 40) return '#e17055'
128+
return '#d63031'
129+
}
130+
131+
const totalStats = {
132+
totalDocuments: yearData.reduce((sum, year) => sum + year.totalDocuments, 0),
133+
documentsWithContent: yearData.reduce((sum, year) => sum + year.documentsWithContent, 0),
134+
emptyDocuments: yearData.reduce((sum, year) => sum + year.emptyDocuments, 0)
135+
}
136+
137+
const overallPercentage = totalStats.totalDocuments > 0
138+
? Math.round((totalStats.documentsWithContent / totalStats.totalDocuments) * 100)
139+
: 0
140+
141+
if (loading) {
142+
return (
143+
<div style={{ padding: '40px', textAlign: 'center' }}>
144+
<div>Ladataan vuosien 1960-1970 tietoja...</div>
145+
<div style={{ marginTop: '10px', fontSize: '12px', color: '#666' }}>
146+
Tämä voi kestää hetken...
147+
</div>
148+
</div>
149+
)
150+
}
151+
152+
if (error) {
153+
return (
154+
<div style={{ padding: '40px', textAlign: 'center', color: '#d63031' }}>
155+
<div>{error}</div>
156+
</div>
157+
)
158+
}
159+
160+
return (
161+
<div style={{ padding: '20px' }}>
162+
<h2 style={{ marginBottom: '20px', color: '#333' }}>
163+
Lainsäädäntö vuosilta 1960-1970
164+
</h2>
165+
166+
{/* Summary Stats */}
167+
<div style={{
168+
display: 'grid',
169+
gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
170+
gap: '16px',
171+
marginBottom: '30px'
172+
}}>
173+
<div style={{
174+
backgroundColor: '#f8f9fa',
175+
padding: '20px',
176+
borderRadius: '8px',
177+
textAlign: 'center',
178+
border: '1px solid #e9ecef'
179+
}}>
180+
<div style={{ fontSize: '24px', fontWeight: 'bold', color: '#0C6FC0' }}>
181+
{totalStats.totalDocuments}
182+
</div>
183+
<div style={{ fontSize: '14px', color: '#666' }}>Yhteensä dokumentteja</div>
184+
</div>
185+
<div style={{
186+
backgroundColor: '#d1f2eb',
187+
padding: '20px',
188+
borderRadius: '8px',
189+
textAlign: 'center',
190+
border: '1px solid #00b894'
191+
}}>
192+
<div style={{ fontSize: '24px', fontWeight: 'bold', color: '#00b894' }}>
193+
{totalStats.documentsWithContent}
194+
</div>
195+
<div style={{ fontSize: '14px', color: '#666' }}>Sisältöä sisältävät</div>
196+
</div>
197+
<div style={{
198+
backgroundColor: '#ffeaa7',
199+
padding: '20px',
200+
borderRadius: '8px',
201+
textAlign: 'center',
202+
border: '1px solid #fdcb6e'
203+
}}>
204+
<div style={{ fontSize: '24px', fontWeight: 'bold', color: '#d63031' }}>
205+
{totalStats.emptyDocuments}
206+
</div>
207+
<div style={{ fontSize: '14px', color: '#666' }}>Tyhjät dokumentit</div>
208+
</div>
209+
<div style={{
210+
backgroundColor: '#ddd6fe',
211+
padding: '20px',
212+
borderRadius: '8px',
213+
textAlign: 'center',
214+
border: '1px solid #8b5cf6'
215+
}}>
216+
<div style={{
217+
fontSize: '24px',
218+
fontWeight: 'bold',
219+
color: getPercentageColor(overallPercentage)
220+
}}>
221+
{overallPercentage}%
222+
</div>
223+
<div style={{ fontSize: '14px', color: '#666' }}>Sisältöprosentti</div>
224+
</div>
225+
</div>
226+
227+
{/* Year-by-year table */}
228+
<table style={tableStyle}>
229+
<thead>
230+
<tr>
231+
<th style={headerStyle}>Vuosi</th>
232+
<th style={headerStyle}>Yhteensä</th>
233+
<th style={headerStyle}>Sisältöä</th>
234+
<th style={headerStyle}>Tyhjiä</th>
235+
<th style={headerStyle}>Sisältö %</th>
236+
</tr>
237+
</thead>
238+
<tbody>
239+
{yearData.map((data, index) => (
240+
<tr
241+
key={data.year}
242+
style={{
243+
backgroundColor: index % 2 === 0 ? '#fafafa' : 'white'
244+
}}
245+
onMouseEnter={(e) => {
246+
e.currentTarget.style.backgroundColor = '#f0f8ff'
247+
}}
248+
onMouseLeave={(e) => {
249+
e.currentTarget.style.backgroundColor = index % 2 === 0 ? '#fafafa' : 'white'
250+
}}
251+
>
252+
<td style={yearCellStyle}>{data.year}</td>
253+
<td style={numberCellStyle}>{data.totalDocuments}</td>
254+
<td style={numberCellStyle}>{data.documentsWithContent}</td>
255+
<td style={numberCellStyle}>{data.emptyDocuments}</td>
256+
<td style={{
257+
...percentageCellStyle,
258+
color: getPercentageColor(data.contentPercentage)
259+
}}>
260+
{data.contentPercentage}%
261+
</td>
262+
</tr>
263+
))}
264+
</tbody>
265+
</table>
266+
267+
{yearData.length === 0 && (
268+
<div style={{ textAlign: 'center', padding: '40px', color: '#666' }}>
269+
Ei tietoja saatavilla
270+
</div>
271+
)}
272+
</div>
273+
)
274+
}
275+
276+
export default YearsPage

0 commit comments

Comments
 (0)