Skip to content
This repository has been archived by the owner on Sep 12, 2023. It is now read-only.

Commit

Permalink
refactor(consultation): move helper functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
lemredd committed Nov 14, 2022
1 parent 787453c commit fe124e6
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 137 deletions.
143 changes: 6 additions & 137 deletions components/consultation/form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,49 +48,11 @@
class="other-reason required"
label="What are the other reasons(s)?"
type="text"/>
<div
v-if="selectedConsultants.length"
class="schedule-selector">
<div
v-if="consultantSchedules.data.length"
class="consultant-has-schedules">
<p>Please select the day and time from the consultant's available schedules</p>
<div class="required">
<SelectableOptionsField
v-model="chosenDay"
class="selectable-day"
label="Day:"
:options="selectableDays"/>
<div v-if="isCustomDate" class="selectable date-picker">
<span>Select a date:</span>
<input
v-model="customDate"
:min="castToCompatibleDate(dateToday)"
:max="castToCompatibleDate(dateInNextMonth)"
type="date"/>
</div>
</div>

<div
v-if="chosenDay"
:class="selectableTimes.length ? 'required' : ''">
<SelectableOptionsField
v-if="selectableTimes.length"
v-model="chosenTime"
class="selectable-time"
label="Time:"
:options="selectableTimes"/>
<p v-else class="selected-day-is-past">
This consultant's schedule for this day has ended.
</p>
</div>
</div>
<div v-else class="consultant-no-schedules">
<p class="consultation-no-schedules">
This consultant has not set any schedules yet.
</p>
</div>
</div>
<Scheduler
v-model:chosen-day="chosenDay"
v-model:chosen-time="chosenTime"
:consultant-schedules="consultantSchedules"
class="schedule-selector"/>

<div class="may-not-start-right-away-msg">
<label>
Expand Down Expand Up @@ -203,7 +165,6 @@
<script setup lang="ts">
import { ref, computed, inject, watch } from "vue"
import { Day, DayValues } from "$/types/database"
import type { PageContext } from "$/types/renderer"
import type { OptionInfo } from "$@/types/component"
import type { DeserializedUserResource } from "$/types/documents/user"
Expand All @@ -216,19 +177,13 @@ import Fetcher from "$@/fetchers/consultation"
import EmployeeScheduleFetcher from "$@/fetchers/employee_schedule"
import Overlay from "@/helpers/overlay.vue"
import makeUnique from "$/array/make_unique"
import assignPath from "$@/external/assign_path"
import convertToTitle from "$/string/convert_to_title"
import makeOptionInfo from "$@/helpers/make_option_info"
import getTimePart from "@/helpers/schedule_picker/get_time_part"
import jumpNextMonth from "@/helpers/schedule_picker/jump_next_month"
import loadRemainingResource from "$@/helpers/load_remaining_resource"
import extractAllErrorDetails from "$@/helpers/extract_all_error_details"
import generateTimeRange from "@/helpers/schedule_picker/generate_time_range"
import convertMinutesToTimeObject from "%/helpers/convert_minutes_to_time_object"
import convertToTimeString from "@/helpers/schedule_picker/convert_time_object_to_time_string"
import castToCompatibleDate from "@/helpers/schedule_picker/convert_date_to_range_compatible_date"
import Scheduler from "./helpers/scheduler.vue"
import NonSensitiveTextField from "@/fields/non-sensitive_text.vue"
import SearchableChip from "@/consultation/form/searchable_chip.vue"
import SelectableOptionsField from "@/fields/selectable_options.vue"
Expand Down Expand Up @@ -301,97 +256,11 @@ async function fetchConsultantSchedules(selectedConsultant: DeserializedUserReso
}))
}
const dateToday = ref(new Date())
const dateInNextMonth = jumpNextMonth(dateToday.value)
const dayIndex = dateToday.value.getDay()
const reorderedDays = [ ...DayValues.slice(dayIndex), ...DayValues.slice(0, dayIndex) ]
const chosenDay = ref("")
const customDate = ref("")
const isCustomDate = computed(() => chosenDay.value === "custom")
const selectableDays = computed(() => {
const dates: Date[] = []
if (consultantSchedules.value.data.length) {
const consultantDays = makeUnique(
consultantSchedules.value.data.map(schedule => schedule.dayName)
)
consultantDays.sort((element1, element2) => {
const element1Index = reorderedDays.indexOf(element1 as Day)
const element2Index = reorderedDays.indexOf(element2 as Day)
return Math.sign(element1Index - element2Index)
})
for (const day of consultantDays) {
const dateCounter = new Date()
const reorderedDayIndex = reorderedDays.indexOf(day)
dateCounter.setDate(dateCounter.getDate() + reorderedDayIndex)
dates.push(dateCounter)
}
}
const actualSelectableDays = dates.map(date => {
const previewDate = date.toDateString().split(" ")
previewDate.shift()
return {
"label": `${convertToTitle(DayValues[date.getDay()])} (${previewDate.join(" ")})`,
"value": date.toJSON()
}
})
actualSelectableDays.push({
"label": "Custom...",
"value": "custom"
})
return actualSelectableDays as OptionInfo[]
})
const chosenTime = ref("")
const selectableTimes = computed(() => {
const availableTimes: OptionInfo[] = []
const dayToDerive = isCustomDate.value && customDate.value
? customDate.value
: chosenDay.value
if (consultantSchedules.value.data.length && dayToDerive) {
const convertedDate = new Date(dayToDerive)
const day = DayValues[convertedDate.getDay()]
const schedulesByDay = consultantSchedules.value.data.filter(
schedule => schedule.dayName === day
)
schedulesByDay.forEach(schedule => {
const times = generateTimeRange({
"end": schedule.scheduleEnd,
"start": schedule.scheduleStart
})
times.forEach(time => {
const timeObject = convertMinutesToTimeObject(time)
const timeString = convertToTimeString(timeObject)
const midday = getTimePart(time, "midday")
const label = `${timeString} ${midday}`
const comparableDate = new Date(chosenDay.value)
comparableDate.setHours(timeObject.hours)
comparableDate.setMinutes(timeObject.minutes)
comparableDate.setSeconds(0)
comparableDate.setMilliseconds(0)
if (comparableDate > dateToday.value) {
availableTimes.push({
label,
"value": String(time)
})
}
})
})
}
return availableTimes
})
const scheduledStartAt = computed(() => {
const chosenDate = isCustomDate.value && customDate.value
Expand Down
181 changes: 181 additions & 0 deletions components/consultation/helpers/scheduler.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
<template>
<div class="scheduler">
<div
v-if="consultantSchedules.data.length"
class="consultant-has-schedules">
<p>Please select the day and time from the consultant's available schedules</p>
<div class="required">
<SelectableOptionsField
v-model="chosenDay"
class="selectable-day"
label="Day:"
:options="selectableDays"/>
<div v-if="isCustomDate" class="selectable date-picker">
<span>Select a date:</span>
<input
v-model="customDate"
:min="castToCompatibleDate(dateToday)"
:max="castToCompatibleDate(dateInNextMonth)"
type="date"/>
</div>
</div>

<div
v-if="chosenDay"
:class="selectableTimes.length ? 'required' : ''">
<SelectableOptionsField
v-if="selectableTimes.length"
v-model="chosenTime"
class="selectable-time"
label="Time:"
:options="selectableTimes"/>
<p v-else class="selected-day-is-past">
This consultant's schedule for this day has ended.
</p>
</div>
</div>
<div v-else class="consultant-no-schedules">
<p class="consultation-no-schedules">
This consultant has not set any schedules yet.
</p>
</div>
</div>
</template>

<style></style>

<script setup lang="ts">
import { ref, computed } from "vue"
import { Day, DayValues } from "$/types/database"
import type { OptionInfo } from "$@/types/component"
import type { DeserializedEmployeeScheduleListDocument } from "$/types/documents/employee_schedule"
import makeUnique from "$/array/make_unique"
import convertToTitle from "$/string/convert_to_title"
import convertMinutesToTimeObject from "%/helpers/convert_minutes_to_time_object"
import getTimePart from "@/helpers/schedule_picker/get_time_part"
import jumpNextMonth from "@/helpers/schedule_picker/jump_next_month"
import generateTimeRange from "@/helpers/schedule_picker/generate_time_range"
import convertToTimeString from "@/helpers/schedule_picker/convert_time_object_to_time_string"
import castToCompatibleDate from "@/helpers/schedule_picker/convert_date_to_range_compatible_date"
import SelectableOptionsField from "@/fields/selectable_options.vue"
type DefinedProps = {
consultantSchedules: DeserializedEmployeeScheduleListDocument
chosenDay: string
chosenTime: string
}
type CustomEvents = {
(event: "update:chosenDay", newChosenDay: string): void
(event: "update:chosenTime", newChosenDay: string): void
}
const props = defineProps<DefinedProps>()
const emit = defineEmits<CustomEvents>()
const dateToday = ref(new Date())
const dateInNextMonth = jumpNextMonth(dateToday.value)
const dayIndex = dateToday.value.getDay()
const reorderedDays = [ ...DayValues.slice(dayIndex), ...DayValues.slice(0, dayIndex) ]
const chosenDay = computed({
get() { return props.chosenDay },
set(newValue: string) {
console.log("set new value", newValue)
emit("update:chosenDay", newValue)
}
})
const customDate = ref("")
const isCustomDate = computed(() => chosenDay.value === "custom")
const selectableDays = computed(() => {
const { consultantSchedules } = props
const dates: Date[] = []
if (consultantSchedules.data.length) {
const consultantDays = makeUnique(
consultantSchedules.data.map(schedule => schedule.dayName)
)
consultantDays.sort((element1, element2) => {
const element1Index = reorderedDays.indexOf(element1 as Day)
const element2Index = reorderedDays.indexOf(element2 as Day)
return Math.sign(element1Index - element2Index)
})
for (const day of consultantDays) {
const dateCounter = new Date()
const reorderedDayIndex = reorderedDays.indexOf(day)
dateCounter.setDate(dateCounter.getDate() + reorderedDayIndex)
dates.push(dateCounter)
}
}
const actualSelectableDays = dates.map(date => {
const previewDate = date.toDateString().split(" ")
previewDate.shift()
return {
"label": `${convertToTitle(DayValues[date.getDay()])} (${previewDate.join(" ")})`,
"value": date.toJSON()
}
})
actualSelectableDays.push({
"label": "Custom...",
"value": "custom"
})
return actualSelectableDays as OptionInfo[]
})
const chosenTime = computed({
get() { return props.chosenDay },
set(newValue: string) { emit("update:chosenTime", newValue) }
})
const selectableTimes = computed(() => {
const { consultantSchedules } = props
const availableTimes: OptionInfo[] = []
const dayToDerive = isCustomDate.value && customDate.value
? customDate.value
: chosenDay.value
if (consultantSchedules.data.length && dayToDerive) {
const convertedDate = new Date(dayToDerive)
const day = DayValues[convertedDate.getDay()]
const schedulesByDay = consultantSchedules.data.filter(
schedule => schedule.dayName === day
)
schedulesByDay.forEach(schedule => {
const times = generateTimeRange({
"end": schedule.scheduleEnd,
"start": schedule.scheduleStart
})
times.forEach(time => {
const timeObject = convertMinutesToTimeObject(time)
const timeString = convertToTimeString(timeObject)
const midday = getTimePart(time, "midday")
const label = `${timeString} ${midday}`
const comparableDate = new Date(chosenDay.value)
comparableDate.setHours(timeObject.hours)
comparableDate.setMinutes(timeObject.minutes)
comparableDate.setSeconds(0)
comparableDate.setMilliseconds(0)
if (comparableDate > dateToday.value) {
availableTimes.push({
label,
"value": String(time)
})
}
})
})
}
return availableTimes
})
</script>

0 comments on commit fe124e6

Please sign in to comment.