Client - handle date string format depending on language

This commit is contained in:
Sam 2022-11-01 10:43:47 +01:00
parent 6fce510a0a
commit d1c658b5bb
6 changed files with 215 additions and 24 deletions

View File

@ -130,7 +130,8 @@
import { TAppConfig } from '@/types/application' import { TAppConfig } from '@/types/application'
import { IAuthUserProfile, IUserProfile } from '@/types/user' import { IAuthUserProfile, IUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import { formatDate } from '@/utils/dates' import { formatDate, getDateFormat } from '@/utils/dates'
import { localeFromLanguage } from '@/utils/locales'
interface Props { interface Props {
user: IUserProfile user: IUserProfile
@ -143,6 +144,9 @@
const store = useStore() const store = useStore()
const { user, fromAdmin } = toRefs(props) const { user, fromAdmin } = toRefs(props)
const language: ComputedRef<string> = computed(
() => store.getters[ROOT_STORE.GETTERS.LANGUAGE]
)
const authUser: ComputedRef<IAuthUserProfile> = computed( const authUser: ComputedRef<IAuthUserProfile> = computed(
() => store.getters[AUTH_USER_STORE.GETTERS.AUTH_USER_PROFILE] () => store.getters[AUTH_USER_STORE.GETTERS.AUTH_USER_PROFILE]
) )
@ -157,7 +161,11 @@
) )
const birthDate = computed(() => const birthDate = computed(() =>
props.user.birth_date props.user.birth_date
? format(new Date(props.user.birth_date), authUser.value.date_format) ? format(
new Date(props.user.birth_date),
`${getDateFormat(authUser.value.date_format, language.value)}`,
{ locale: localeFromLanguage[language.value] }
)
: '' : ''
) )
const isSuccess = computed( const isSuccess = computed(

View File

@ -2,11 +2,11 @@
<div id="user-preferences" class="description-list"> <div id="user-preferences" class="description-list">
<dl> <dl>
<dt>{{ $t('user.PROFILE.LANGUAGE') }}:</dt> <dt>{{ $t('user.PROFILE.LANGUAGE') }}:</dt>
<dd>{{ language }}</dd> <dd>{{ userLanguage }}</dd>
<dt>{{ $t('user.PROFILE.TIMEZONE') }}:</dt> <dt>{{ $t('user.PROFILE.TIMEZONE') }}:</dt>
<dd>{{ timezone }}</dd> <dd>{{ timezone }}</dd>
<dt>{{ $t('user.PROFILE.DATE_FORMAT') }}:</dt> <dt>{{ $t('user.PROFILE.DATE_FORMAT') }}:</dt>
<dd>{{ date_format }}</dd> <dd>{{ getDateFormat(date_format, appLanguage) }}</dd>
<dt>{{ $t('user.PROFILE.FIRST_DAY_OF_WEEK') }}:</dt> <dt>{{ $t('user.PROFILE.FIRST_DAY_OF_WEEK') }}:</dt>
<dd>{{ $t(`user.PROFILE.${fistDayOfWeek}`) }}</dd> <dd>{{ $t(`user.PROFILE.${fistDayOfWeek}`) }}</dd>
<dt>{{ $t('user.PROFILE.UNITS.LABEL') }}:</dt> <dt>{{ $t('user.PROFILE.UNITS.LABEL') }}:</dt>
@ -30,9 +30,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed, ComputedRef } from 'vue'
import { ROOT_STORE } from '@/store/constants'
import { IAuthUserProfile } from '@/types/user' import { IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
import { getDateFormat } from '@/utils/dates'
import { languageLabels } from '@/utils/locales' import { languageLabels } from '@/utils/locales'
interface Props { interface Props {
@ -40,7 +43,12 @@
} }
const props = defineProps<Props>() const props = defineProps<Props>()
const language = computed(() => const store = useStore()
const appLanguage: ComputedRef<string> = computed(
() => store.getters[ROOT_STORE.GETTERS.LANGUAGE]
)
const userLanguage = computed(() =>
props.user.language props.user.language
? languageLabels[props.user.language] ? languageLabels[props.user.language]
: languageLabels['en'] : languageLabels['en']
@ -50,7 +58,7 @@
props.user.timezone ? props.user.timezone : 'Europe/Paris' props.user.timezone ? props.user.timezone : 'Europe/Paris'
) )
const date_format = computed(() => const date_format = computed(() =>
props.user.date_format ? props.user.date_format : 'dd/MM/yyyy' props.user.date_format ? props.user.date_format : 'MM/dd/yyyy'
) )
const display_ascent = computed(() => const display_ascent = computed(() =>
props.user.display_ascent ? 'DISPLAYED' : 'HIDDEN' props.user.display_ascent ? 'DISPLAYED' : 'HIDDEN'

View File

@ -26,15 +26,17 @@
<label class="form-items"> <label class="form-items">
{{ $t('user.PROFILE.DATE_FORMAT') }} {{ $t('user.PROFILE.DATE_FORMAT') }}
<select <select
name="date_format" id="date_format"
:disabled="loading"
v-model="userForm.date_format" v-model="userForm.date_format"
:disabled="loading"
> >
<option disabled value="">Please select one:</option> <option
<option value="dd/MM/yyyy">dd/MM/yyyy - 08/07/2022</option> v-for="dateFormat in dateFormatOptions"
<option value="MM/dd/yyyy">MM/dd/yyyy - 07/08/2022</option> :value="dateFormat.value"
<option value="MMM. do, yyyy">MMM. do, yyyy - Jul. 8th, 2022</option> :key="dateFormat.value"
<option value="yyyy-MM-dd">yyyy-MM-dd - 2022-07-08</option> >
{{ dateFormat.label }}
</option>
</select> </select>
</label> </label>
<div class="form-items form-checkboxes"> <div class="form-items form-checkboxes">
@ -120,6 +122,7 @@
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants' import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import { IUserPreferencesPayload, IAuthUserProfile } from '@/types/user' import { IUserPreferencesPayload, IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import { availableDateFormatOptions } from '@/utils/dates'
import { availableLanguages } from '@/utils/locales' import { availableLanguages } from '@/utils/locales'
interface Props { interface Props {
@ -173,6 +176,13 @@
const errorMessages: ComputedRef<string | string[] | null> = computed( const errorMessages: ComputedRef<string | string[] | null> = computed(
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES] () => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
) )
const dateFormatOptions = computed(() =>
availableDateFormatOptions(
new Date().toUTCString(),
props.user.timezone,
userForm.language
)
)
onMounted(() => { onMounted(() => {
if (props.user) { if (props.user) {

View File

@ -11,6 +11,11 @@ import {
} from 'date-fns' } from 'date-fns'
import { utcToZonedTime } from 'date-fns-tz' import { utcToZonedTime } from 'date-fns-tz'
import createI18n from '@/i18n'
import { localeFromLanguage } from '@/utils/locales'
const { locale } = createI18n.global
export const getStartDate = ( export const getStartDate = (
duration: string, duration: string,
day: Date, day: Date,
@ -70,22 +75,70 @@ export const formatWorkoutDate = (
if (!dateFormat) { if (!dateFormat) {
dateFormat = 'yyyy/MM/dd' dateFormat = 'yyyy/MM/dd'
} }
dateFormat = getDateFormat(dateFormat, locale.value)
if (!timeFormat) { if (!timeFormat) {
timeFormat = 'HH:mm' timeFormat = 'HH:mm'
} }
return { return {
workout_date: format(dateTime, dateFormat), workout_date: format(dateTime, dateFormat, {
locale: localeFromLanguage[locale.value],
}),
workout_time: format(dateTime, timeFormat), workout_time: format(dateTime, timeFormat),
} }
} }
const availableDateFormats = [
'dd/MM/yyyy',
'MM/dd/yyyy',
'yyyy-MM-dd',
'date_string',
]
const dateStringFormats: Record<string, string> = {
de: 'd MMM yyyy',
en: 'MMM. do, yyyy',
fr: 'd MMM yyyy',
}
export const getDateFormat = (dateFormat: string, language: string): string => {
return dateFormat === 'date_string' ? dateStringFormats[language] : dateFormat
}
export const formatDate = ( export const formatDate = (
dateString: string, dateString: string,
timezone: string, timezone: string,
dateFormat: string, dateFormat: string,
withTime = true withTime = true,
): string => language: string | null = null
format( ): string => {
if (!language) {
language = locale.value
}
return format(
getDateWithTZ(dateString, timezone), getDateWithTZ(dateString, timezone),
`${dateFormat}${withTime ? ' HH:mm' : ''}` `${getDateFormat(dateFormat, language)}${withTime ? ' HH:mm' : ''}`,
{ locale: localeFromLanguage[language] }
) )
}
export const availableDateFormatOptions = (
inputDate: string,
timezone: string,
language: string | null = null
) => {
const l: string = language ? language : locale.value
const options: Record<string, string>[] = []
availableDateFormats.map((df) => {
const dateFormat = getDateFormat(df, l)
options.push({
label: `${dateFormat} - ${formatDate(
inputDate,
timezone,
dateFormat,
false,
l
)}`,
value: df,
})
})
return options
}

View File

@ -1,9 +1,12 @@
import createI18n from '@/i18n'
import { ITranslatedSport } from '@/types/sports' import { ITranslatedSport } from '@/types/sports'
import { TUnit } from '@/types/units' import { TUnit } from '@/types/units'
import { ICardRecord, IRecord, IRecordsBySports } from '@/types/workouts' import { ICardRecord, IRecord, IRecordsBySports } from '@/types/workouts'
import { formatWorkoutDate, getDateWithTZ } from '@/utils/dates' import { formatDate, getDateFormat } from '@/utils/dates'
import { convertDistance, units } from '@/utils/units' import { convertDistance, units } from '@/utils/units'
const { locale } = createI18n.global
export const formatRecord = ( export const formatRecord = (
record: IRecord, record: IRecord,
tz: string, tz: string,
@ -54,8 +57,7 @@ export const formatRecord = (
) )
} }
return { return {
workout_date: formatWorkoutDate(getDateWithTZ(record.workout_date, tz), date_format) workout_date: formatDate(record.workout_date, tz, date_format, false),
.workout_date,
workout_id: record.workout_id, workout_id: record.workout_id,
id: record.id, id: record.id,
record_type: record.record_type, record_type: record.record_type,
@ -76,8 +78,9 @@ export const getRecordsBySports = (
useImperialUnits: boolean, useImperialUnits: boolean,
display_ascent: boolean, display_ascent: boolean,
date_format: string date_format: string
): IRecordsBySports => ): IRecordsBySports => {
records date_format = getDateFormat(date_format, locale.value)
return records
.filter((r) => (display_ascent ? true : r.record_type !== 'HA')) .filter((r) => (display_ascent ? true : r.record_type !== 'HA'))
.reduce((sportList: IRecordsBySports, record) => { .reduce((sportList: IRecordsBySports, record) => {
const sport = translatedSports.find((s) => s.id === record.sport_id) const sport = translatedSports.find((s) => s.id === record.sport_id)
@ -95,3 +98,4 @@ export const getRecordsBySports = (
} }
return sportList return sportList
}, {}) }, {})
}

View File

@ -6,6 +6,8 @@ import {
getStartDate, getStartDate,
formatWorkoutDate, formatWorkoutDate,
formatDate, formatDate,
availableDateFormatOptions,
getDateFormat,
} from '@/utils/dates' } from '@/utils/dates'
describe('startDate (week starting Sunday)', () => { describe('startDate (week starting Sunday)', () => {
@ -290,3 +292,109 @@ describe('formatDate (w/ default value)', () => {
) )
}) })
}) })
describe('getDateFormat', () => {
const testsParams = [
{
inputParams: {
dateFormat: 'dd/MM/yyyy',
language: 'en',
},
expectedFormat: 'dd/MM/yyyy',
},
{
inputParams: {
dateFormat: 'MM/dd/yyyy',
language: 'en',
},
expectedFormat: 'MM/dd/yyyy',
},
{
inputParams: {
dateFormat: 'yyyy-MM-dd',
language: 'en',
},
expectedFormat: 'yyyy-MM-dd',
},
{
inputParams: {
dateFormat: 'date_string',
language: 'en',
},
expectedFormat: 'MMM. do, yyyy',
},
{
inputParams: {
dateFormat: 'date_string',
language: 'fr',
},
expectedFormat: 'd MMM yyyy',
},
{
inputParams: {
dateFormat: 'date_string',
language: 'de',
},
expectedFormat: 'd MMM yyyy',
},
]
testsParams.map((testParams) => {
it(`get date format for "${testParams.inputParams.language}" and "${testParams.inputParams.dateFormat}" `, () => {
assert.deepEqual(
getDateFormat(
testParams.inputParams.dateFormat,
testParams.inputParams.language
),
testParams.expectedFormat
)
})
})
})
describe('availableDateFormatOptions', () => {
const inputDate = `Sun, 9 Oct 2022 18:18:41 GMT`
const inputTimezone = `Europe/Paris`
const testsParams = [
{
inputLanguage: 'en',
expectedOptions: [
{ label: 'dd/MM/yyyy - 09/10/2022', value: 'dd/MM/yyyy' },
{ label: 'MM/dd/yyyy - 10/09/2022', value: 'MM/dd/yyyy' },
{ label: 'yyyy-MM-dd - 2022-10-09', value: 'yyyy-MM-dd' },
{ label: 'MMM. do, yyyy - Oct. 9th, 2022', value: 'date_string' },
],
},
{
inputLanguage: 'fr',
expectedOptions: [
{ label: 'dd/MM/yyyy - 09/10/2022', value: 'dd/MM/yyyy' },
{ label: 'MM/dd/yyyy - 10/09/2022', value: 'MM/dd/yyyy' },
{ label: 'yyyy-MM-dd - 2022-10-09', value: 'yyyy-MM-dd' },
{ label: 'd MMM yyyy - 9 oct. 2022', value: 'date_string' },
],
},
{
inputLanguage: 'de',
expectedOptions: [
{ label: 'dd/MM/yyyy - 09/10/2022', value: 'dd/MM/yyyy' },
{ label: 'MM/dd/yyyy - 10/09/2022', value: 'MM/dd/yyyy' },
{ label: 'yyyy-MM-dd - 2022-10-09', value: 'yyyy-MM-dd' },
{ label: 'd MMM yyyy - 9 Okt. 2022', value: 'date_string' },
],
},
]
testsParams.map((testParams) => {
it(`returns available options for ${testParams.inputLanguage} locale`, () => {
assert.deepEqual(
availableDateFormatOptions(
inputDate,
inputTimezone,
testParams.inputLanguage
),
testParams.expectedOptions
)
})
})
})