Skip to content

Commit

Permalink
api: improve timezone management, ui fixes
Browse files Browse the repository at this point in the history
- headers + query
- clearable input
- debug infos
- migration script
  • Loading branch information
kernoeb committed Oct 21, 2024
1 parent fb41607 commit e417fb5
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .idea/dataSources.local.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion .idea/jsLibraryMappings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

77 changes: 56 additions & 21 deletions components/TimezoneSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,33 @@
item-text="label"
item-value="value"
label="Chercher un fuseau horaire"
clearable
:clear-icon="mdiClose"
hide-details
/>
<div
v-if="infos"
class="text-caption mt-1"
>
<template #item="{ item }">
{{ item.label }}
</template>
</v-autocomplete>
Navigateur: <code>{{ infos.browser }}</code><span v-if="infos.target">, Cible: <code>{{ infos.target }}</code></span>
</div>
</div>
</template>

<script>
import { mdiClose } from '@mdi/js'
export default {
name: 'TimezoneSelector',
data () {
return {
// Icons
mdiClose,
loaded: false,
targetTz: null,
infos: null,
timezones: [ // Merci StackOverflow pour la liste
{ label: '(GMT-12:00) International Date Line West', value: 'Etc/GMT+12' },
{ label: '(GMT-11:00) Midway Island, Samoa', value: 'Pacific/Midway' },
Expand Down Expand Up @@ -111,26 +125,47 @@ export default {
]
}
},
computed: {
targetTz: {
get () {
let cookieTz = this.$cookies.get('timezone', { parseJSON: true })?.target
return this.timezones.find(t => cookieTz === t.value)?.value || ''
},
set (value) {
const browserTz = Intl.DateTimeFormat().resolvedOptions().timeZone
value = value ?? browserTz
this.$cookies.set('timezone', JSON.stringify({
target: value,
browser: browserTz
}), { maxAge: 2147483646 })
this.$emit('fetch')
}
watch: {
targetTz (tz) {
if (!this.loaded) return
this.updateTz(tz)
}
},
mounted () {
if (!this.targetTz) {
this.targetTz = Intl.DateTimeFormat().resolvedOptions().timeZone
this.infos = {
browser: Intl.DateTimeFormat().resolvedOptions().timeZone
}
const timezoneCookie = this.$cookies.get('timezone', { parseJSON: false })
if (!this.targetTz && timezoneCookie) {
if (this.timezones.find(tz => tz.value === timezoneCookie)) {
this.targetTz = timezoneCookie
this.$set(this.infos, 'target', timezoneCookie)
} else {
console.warn('Invalid timezone stored in cookies')
this.$cookies.remove('timezone')
}
}
this.$nextTick(() => {
this.loaded = true
})
},
methods: {
updateTz (tz) {
console.log('updateTz', tz)
if (!tz) {
this.$delete(this.infos, 'target')
this.$cookies.remove('timezone')
} else {
const browser = Intl.DateTimeFormat().resolvedOptions().timeZone
const target = tz ?? browser
this.$set(this.infos, 'target', target)
this.$cookies.set('timezone', target, { maxAge: 2147483646 })
}
this.$emit('fetch')
}
}
}
Expand Down
1 change: 1 addition & 0 deletions nuxt.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export default {
name: TITLE,
hideWeekends: process.env.HIDE_WEEKENDS !== 'false',
defaultPlanning: process.env.DEFAULT_PLANNING_ID || 'iutdevannes.butdutinfo.1ereannee.gr1a.gr1a1',
defaultTimezone: process.env.DEFAULT_TIMEZONE || 'Europe/Paris',
i18n: {
week: 'Semaine',
weeks: 'Semaines',
Expand Down
64 changes: 44 additions & 20 deletions pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@
<script>
import { mdiMinusBox, mdiTwitter, mdiClose, mdiMail, mdiChevronLeft, mdiChevronDown, mdiFormatListBulleted, mdiCalendar, mdiCalendarToday, mdiCogOutline, mdiChevronRight, mdiSchool, mdiWifiOff, mdiMenuDown, mdiCheckboxBlankOutline, mdiCheckboxMarked } from '@mdi/js'
import humanizeDuration from 'humanize-duration'
import { AxiosHeaders } from 'axios'
const shortFrenchHumanizer = humanizeDuration.humanizer({
language: 'shortFr',
Expand Down Expand Up @@ -397,13 +398,16 @@ export default {
tmpP: null,
nbHours: null,
lastTimestamp: null,
localeUtils: {}
timezone: undefined
}
},
fetchOnServer: false,
async fetch () {
if (this.loading) return
this.loading = true
// ====================
// UPGRADE
// Planning v1 migration
this.$cookies.remove('edt')
this.$cookies.remove('customColors')
Expand All @@ -420,6 +424,21 @@ export default {
}
}
// Remove old timezone cookie
try {
const oldTzCookie = this.$cookies.get('locale-utils')
if (oldTzCookie !== undefined) {
this.$cookies.remove('locale-utils')
if (oldTzCookie.newTZ && typeof oldTzCookie.newTZ === 'string') {
console.info('Removed old timezone cookie, migrating to new one with value:', oldTzCookie.newTZ)
this.$cookies.set('timezone', oldTzCookie.newTZ, { maxAge: 2147483646 })
}
}
} catch (err) {
console.error(err)
}
// ====================
if (this.selectedPlanningsIds == null) {
let planningString
try {
Expand All @@ -438,16 +457,13 @@ export default {
if (this.$cookies.get('timezone') !== undefined) {
try {
const tmp = this.$cookies.get('timezone', { parseJSON: true })
if (tmp && Object.keys(tmp).length > 0 && tmp.target && tmp.browser) {
this.localeUtils = tmp
} else {
this.$cookies.remove('timezone')
}
const tmp = this.$cookies.get('timezone', { parseJSON: false })
if (tmp) this.timezone = tmp
} catch (e) {
this.$cookies.remove('timezone')
}
}
if (!this.timezone) this.timezone = this.getBrowserTimezone()
try {
await this.getEvents()
Expand Down Expand Up @@ -518,15 +534,6 @@ export default {
this.$vuetify.theme.dark = true
}
const oldTzCookie = this.$cookies.get('locale-utils')
if (oldTzCookie !== undefined) {
this.$cookies.remove('locale-utils')
this.$cookies.set('timezone', {
target: oldTzCookie.oldTz,
browser: oldTzCookie.newTz
}, { maxAge: 2147483646 })
}
this.$nextTick(function () {
try {
const start = this.$moment(this.$refs.calendar.start).week().toString()
Expand Down Expand Up @@ -574,11 +581,21 @@ export default {
}, 120000)
},
methods: {
getBrowserTimezone () {
try {
return Intl.DateTimeFormat().resolvedOptions().timeZone || this.$config.defaultTimezone
} catch (err) {
return this.$config.defaultTimezone
}
},
async getEvents () {
const events = await this.$axios.$get('/api/v1/calendars',
{
params: { p: [...(this.selectedPlanningsIds || [])].join(',') },
headers: { 'ignore-statistics': this.$route?.query?.['ignore-statistics'] !== undefined ? 'true' : 'false' }
headers: new AxiosHeaders({
'ignore-statistics': this.$route?.query?.['ignore-statistics'] !== undefined ? 'true' : 'false',
'x-timezone': this.getBrowserTimezone()
})
})
this.setEvents(events)
this.$cookies.set('plannings', this.selectedPlanningsIds.join(','), { maxAge: 2147483646 })
Expand Down Expand Up @@ -671,10 +688,17 @@ export default {
this.value = this.$refs.calendar.timestampToDate(day)
},
updateTime () {
const timeZone = this.localeUtils.target || Intl.DateTimeFormat().resolvedOptions().timeZone || 'Europe/Paris'
// convert it to defined timezone
const tzDate = new Date(new Date().toLocaleString('en-US', { timeZone }))
/** @type {Date} */
let tzDate
try {
tzDate = new Date(new Date().toLocaleString('en-US', { timeZone: this.timezone }))
} catch (err) {
console.error(err)
this.timezone = this.$config.defaultTimezone
tzDate = new Date(new Date().toLocaleString('en-US', { timeZone: this.timezone }))
}
this.dateNow = this.$moment(tzDate).format('YYYY-MM-DD')
if (this.$refs.calendar && tzDate.getHours() >= 7) {
Expand Down
7 changes: 4 additions & 3 deletions server/routes/calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ router.get('/calendars', asyncWrapper(async (req, res) => {
// Get custom timezone and locale
let localeUtils = null
try {
if (req.cookies?.timezone) {
const { target, browser } = JSON.parse(req.cookies.timezone)
if (target && browser) localeUtils = { target, browser }
const browser = req.headers['x-timezone'] || req.headers['x-browser-timezone'] || req.query['browser-timezone']
const target = req.headers['x-target-timezone'] || req.query['target-timezone'] || req.cookies.timezone
if (browser && target && typeof browser === 'string' && typeof target === 'string') {
localeUtils = { target, browser }
}
} catch (e) {
}
Expand Down

0 comments on commit e417fb5

Please sign in to comment.