Timezone and hour cycle picker
The timezone and hour cycle are global state, so this component works next to ZaptimeCalendar (with locale.hideTimePreferences: true to hide the built-in controls) or inside a headless calendar.
vue
<template>
<div class="prefs">
<label>
Timezone
<select :value="timezone" @change="onTimezone">
<option v-for="tz in timezones" :key="tz" :value="tz">{{ tz }}</option>
</select>
</label>
<button v-if="timezone !== clientOriginalTimezone" type="button" @click="reset">
Use my timezone ({{ clientOriginalTimezone }})
</button>
<label>
<input type="checkbox" :checked="hourCycle === 'h23'" @change="toggleHourCycle" />
24-hour clock
</label>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { useCalendar, useCurrentTimezone, useHourCycle } from "@zaptime/core";
const props = defineProps<{ calendarId?: string; apiBaseUrl?: string }>();
const { timezone, setTimezone, clientOriginalTimezone } = useCurrentTimezone();
const { hourCycle, setHourCycle } = useHourCycle();
const { getDays } = useCalendar(props.calendarId);
const timezones = ref<string[]>([timezone.value]);
onMounted(async () => {
const base = props.apiBaseUrl ?? "https://api.zaptime.app/";
const json = await fetch(base + "timezones").then((r) => r.json());
timezones.value = json.data;
});
async function onTimezone(e: Event) {
setTimezone((e.target as HTMLSelectElement).value);
await getDays(); // slots can move across days
}
async function reset() {
setTimezone(clientOriginalTimezone);
await getDays();
}
function toggleHourCycle() {
setHourCycle(hourCycle.value === "h23" ? "h11" : "h23");
}
</script>Changing the hour cycle re-renders formatted times immediately. Changing the timezone requires getDays() to refetch the month.
