Merged in feature/vbv-148-human-readable-duration (pull request #8)
Implement human readable durations * Implement duration formatting for humans * Add UTs * Rework rounding and formatting * Rename function
This commit is contained in:
parent
da13345511
commit
722b9f7937
|
|
@ -4,6 +4,7 @@ import type { LearningContent, LearningSequence } from '@/types'
|
|||
import { useCircleStore } from '@/stores/circle'
|
||||
import { computed } from 'vue'
|
||||
import _ from 'lodash'
|
||||
import { humanizeDuration } from '@/utils/humanizeDuration'
|
||||
|
||||
const props = defineProps<{
|
||||
learningSequence: LearningSequence
|
||||
|
|
@ -73,14 +74,14 @@ const learningSequenceBorderClass = computed(() => {
|
|||
<h3 class="text-xl font-semibold">
|
||||
{{ learningSequence.title }}
|
||||
</h3>
|
||||
<div>{{ learningSequence.minutes }} Minuten</div>
|
||||
<div>{{ humanizeDuration(learningSequence.minutes) }}</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white px-4 lg:px-6 border border-gray-500" :class="learningSequenceBorderClass">
|
||||
<div v-for="learningUnit in learningSequence.learningUnits" :key="learningUnit.id" class="pt-3 lg:pt-6">
|
||||
<div class="pb-3 lg:pg-6 flex gap-4 text-blue-900" v-if="learningUnit.title">
|
||||
<div class="font-semibold">{{ learningUnit.title }}</div>
|
||||
<div>{{ learningUnit.minutes }} Minuten</div>
|
||||
<div>{{ humanizeDuration(learningUnit.minutes) }}</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
import { expect, test } from 'vitest'
|
||||
import { humanizeDuration } from '../humanizeDuration'
|
||||
|
||||
test('format duration for humans', () => {
|
||||
expect(humanizeDuration(1)).toBe('1 Minute')
|
||||
expect(humanizeDuration(15)).toBe('15 Minuten')
|
||||
expect(humanizeDuration(42)).toBe('45 Minuten')
|
||||
expect(humanizeDuration(60)).toBe('1 Stunde')
|
||||
expect(humanizeDuration(122)).toBe('2 Stunden')
|
||||
expect(humanizeDuration(120)).toBe('2 Stunden')
|
||||
expect(humanizeDuration(132)).toBe('2 Stunden 15 Minuten')
|
||||
expect(humanizeDuration(632)).toBe('10 Stunden')
|
||||
})
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
function pluralize(text: string, count: number) {
|
||||
if (count === 1) {
|
||||
return text;
|
||||
}
|
||||
return text + 'n';
|
||||
}
|
||||
|
||||
|
||||
export function humanizeDuration(minutes: number) {
|
||||
const hours = Math.floor(minutes / 60)
|
||||
const remainingMinutes = minutes % 60
|
||||
|
||||
if (hours === 0 && minutes < 16) {
|
||||
return pluralize(`${remainingMinutes} Minute`, remainingMinutes)
|
||||
}
|
||||
|
||||
// Remaining minutes are rounded to 15 mins
|
||||
const roundToMinutes = 15
|
||||
const roundedMinutes = Math.round((minutes % 60) / roundToMinutes) * roundToMinutes
|
||||
|
||||
const hoursString = hours > 0 ? pluralize(`${hours} Stunde`, hours) : ''
|
||||
|
||||
const showMinutesUpToHours = 10
|
||||
const minutesString = roundedMinutes > 0 && hours < showMinutesUpToHours
|
||||
? pluralize(`${roundedMinutes} Minute`, roundedMinutes) : ''
|
||||
|
||||
const delimiter = hoursString && minutesString ? ' ' : ''
|
||||
return `${hoursString}${delimiter}${minutesString}`
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import { useCircleStore } from '@/stores/circle'
|
|||
import { useAppStore } from '@/stores/app'
|
||||
import { useRoute } from 'vue-router'
|
||||
import _ from 'lodash'
|
||||
import { humanizeDuration } from '@/utils/humanizeDuration'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ const circleStore = useCircleStore()
|
|||
const duration = computed(() => {
|
||||
if (circleStore.circle) {
|
||||
const minutes = _.sumBy(circleStore.circle.learningSequences, 'minutes')
|
||||
return `${minutes} Minuten`
|
||||
return humanizeDuration(minutes)
|
||||
}
|
||||
|
||||
return ''
|
||||
|
|
|
|||
Loading…
Reference in New Issue