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:
Elia Bieri 2022-09-20 11:12:05 +00:00
parent da13345511
commit 722b9f7937
4 changed files with 47 additions and 3 deletions

View File

@ -4,6 +4,7 @@ import type { LearningContent, LearningSequence } from '@/types'
import { useCircleStore } from '@/stores/circle' import { useCircleStore } from '@/stores/circle'
import { computed } from 'vue' import { computed } from 'vue'
import _ from 'lodash' import _ from 'lodash'
import { humanizeDuration } from '@/utils/humanizeDuration'
const props = defineProps<{ const props = defineProps<{
learningSequence: LearningSequence learningSequence: LearningSequence
@ -73,14 +74,14 @@ const learningSequenceBorderClass = computed(() => {
<h3 class="text-xl font-semibold"> <h3 class="text-xl font-semibold">
{{ learningSequence.title }} {{ learningSequence.title }}
</h3> </h3>
<div>{{ learningSequence.minutes }} Minuten</div> <div>{{ humanizeDuration(learningSequence.minutes) }}</div>
</div> </div>
<div class="bg-white px-4 lg:px-6 border border-gray-500" :class="learningSequenceBorderClass"> <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 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="pb-3 lg:pg-6 flex gap-4 text-blue-900" v-if="learningUnit.title">
<div class="font-semibold">{{ learningUnit.title }}</div> <div class="font-semibold">{{ learningUnit.title }}</div>
<div>{{ learningUnit.minutes }} Minuten</div> <div>{{ humanizeDuration(learningUnit.minutes) }}</div>
</div> </div>
<div <div

View File

@ -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')
})

View File

@ -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}`
}

View File

@ -10,6 +10,7 @@ import { useCircleStore } from '@/stores/circle'
import { useAppStore } from '@/stores/app' import { useAppStore } from '@/stores/app'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import _ from 'lodash' import _ from 'lodash'
import { humanizeDuration } from '@/utils/humanizeDuration'
const route = useRoute() const route = useRoute()
@ -28,7 +29,7 @@ const circleStore = useCircleStore()
const duration = computed(() => { const duration = computed(() => {
if (circleStore.circle) { if (circleStore.circle) {
const minutes = _.sumBy(circleStore.circle.learningSequences, 'minutes') const minutes = _.sumBy(circleStore.circle.learningSequences, 'minutes')
return `${minutes} Minuten` return humanizeDuration(minutes)
} }
return '' return ''