Skip to content

Commit af851ff

Browse files
committed
Add Overhour analysis (last 6 month) - wip
1 parent 9e194bd commit af851ff

File tree

2 files changed

+70
-2
lines changed

2 files changed

+70
-2
lines changed

src/components/views/Statistics.tsx

+28-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import { ErrorTooltip } from '../atoms/Tooltip'
1212
import { WifiOff } from 'preact-feather'
1313
import { ActionLink } from '../atoms/ActionLink'
1414
import { formatDuration } from '../../utils/datetime'
15+
import { useOptions } from 'src/hooks/useOptions'
16+
import { Conditional } from '../atoms/Conditional'
1517

1618
const Body = styled.div`
1719
display: flex;
@@ -32,12 +34,14 @@ export const StatisticsView: React.FC = () => {
3234
actions: { setYear, getRequiredSeconds, refresh },
3335
loading
3436
} = useStatistics()
37+
const { domain } = useOptions().data
38+
const isWebfleet = domain?.includes('jira.ttt-sp.com')
3539
const self = useSelf()
3640

3741
const { data: options, actions } = useStatisticsOptions()
3842
const getRequiredSecondsPeriod = useGetRequiredSecondsForPeriod(options.lifetimeYear)
3943
const {
40-
data: { lifeTimeTotal, yearWeeksLifetime, lifeTimeMedianTop, lifeTimeMedianLow }
44+
data: { lifeTimeTotal, yearWeeksLifetime, lifeTimeMedianTop, lifeTimeMedianLow, overhourStats }
4145
} = useLifetimeStatistics(loading ? {} : { stats, year })
4246

4347
const updateOptionKey = (key) => (e) => actions.merge({ [key]: Number(e.target.value) })
@@ -92,6 +96,29 @@ export const StatisticsView: React.FC = () => {
9296
</Value>
9397
</Column>
9498
</Block>
99+
<Conditional enable={isWebfleet}>
100+
<H6>Overhour Statistics</H6>
101+
<Block>
102+
<Column>
103+
<Label>Current Overhours (6 Month)</Label>
104+
<Value>
105+
{overhourStats.totalDiffSeconds > 0 ? formatDuration(overhourStats?.totalDiffSeconds * 1000, true, true) : <>&mdash;</>}
106+
</Value>
107+
</Column>
108+
<Column>
109+
<Label>Overhours at risk</Label>
110+
<Value>
111+
{overhourStats.secondsInLastMonth > 0 ? formatDuration(overhourStats?.secondsInLastMonth * 1000, true, true) : <>&mdash;</>}
112+
</Value>
113+
</Column>
114+
<Column>
115+
<Label>Overhours (Last Week)</Label>
116+
<Value>
117+
{overhourStats.secondsInLastWeek ? formatDuration(overhourStats?.secondsInLastWeek * 1000, true, true) : <>&mdash;</>}
118+
</Value>
119+
</Column>
120+
</Block>
121+
</Conditional>
95122
<H6>Work-time Settings</H6>
96123
<Block>
97124
<Column>

src/hooks/useStatistics.ts

+42-1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ export function useLifetimeStatistics({ year, stats }: { year?: number, stats?:
162162
return lifeTimeStatsMap
163163
}, CACHE.LIFETIME_STATS_CACHE, {}, Number.MAX_SAFE_INTEGER)
164164

165+
const getRequiredSeconds = useGetRequiredSecondsForPeriod(lifetimeYear)
166+
165167
useEffect(() => {
166168
forceFetch()
167169
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -196,6 +198,44 @@ export function useLifetimeStatistics({ year, stats }: { year?: number, stats?:
196198
}, []).sort((a, b) => a.workedSeconds - b.workedSeconds)
197199
}, [data, lifetimeYear])
198200

201+
const overhourStats: {totalDiffSeconds: number, secondsInLastWeek: number, secondsInLastMonth: number} = useMemo(() => {
202+
const sorted = [...yearWeeksLifetime].sort((a, b) => `${a.year}-${a.week}`.localeCompare(`${b.year}-${b.week}`))
203+
const resolvedLastHalfYear = sorted.reduce((array, {year, week, workedSeconds}, index) => {
204+
let currentDiff = workedSeconds - getRequiredSeconds(year, week)
205+
for (let x = 0; x < index; x++) {
206+
const oldWeek = array[x]
207+
if (currentDiff === 0) {
208+
break
209+
}
210+
if (oldWeek.diffSeconds === 0 || currentDiff > 0 === oldWeek.diffSeconds > 0) {
211+
continue
212+
}
213+
if (Math.abs(currentDiff) - Math.abs(oldWeek.diffSeconds) > 0) {
214+
currentDiff += oldWeek.diffSeconds
215+
oldWeek.diffSeconds = 0
216+
}
217+
else {
218+
oldWeek.diffSeconds += currentDiff
219+
currentDiff = 0
220+
}
221+
}
222+
223+
array.push({year, week, workedSeconds, diffSeconds: currentDiff})
224+
return array.slice(-25)
225+
}, [])
226+
227+
return resolvedLastHalfYear.reduce((stats, result, index) => {
228+
if (index === 0) {
229+
stats.secondsInLastWeek = result.diffSeconds
230+
}
231+
if (index < 4) {
232+
stats.secondsInLastMonth += result.diffSeconds
233+
}
234+
stats.totalDiffSeconds += result.diffSeconds
235+
return stats
236+
}, {totalDiffSeconds: 0, secondsInLastWeek: 0, secondsInLastMonth: 0})
237+
}, [yearWeeksLifetime, getRequiredSeconds])
238+
199239
const lifeTimeTotal = useMemo(() => {
200240
const years = Array.from({ length: (new Date().getFullYear()) - lifetimeYear + 1 }, (_v, idx) => lifetimeYear + idx)
201241
return years.reduce((total, year) => total + (data[year]?.total ?? 0), 0)
@@ -212,10 +252,11 @@ export function useLifetimeStatistics({ year, stats }: { year?: number, stats?:
212252
}, [yearWeeksLifetime])
213253

214254
return {
215-
data: { lifeTimeTotal, yearWeeksLifetime, lifeTimeMedianTop, lifeTimeMedianLow },
255+
data: { lifeTimeTotal, yearWeeksLifetime, lifeTimeMedianTop, lifeTimeMedianLow, overhourStats },
216256
actions: {
217257
refresh: forceFetch
218258
},
219259
loading
220260
}
221261
}
262+

0 commit comments

Comments
 (0)