Refactor scheduling page and date-picker component

scheduling.vue:
- Colocate inshop providers and time slots into inShopProvidersAndTimeslots
  array of { provider, timeSlots } objects, replacing two parallel arrays
- Combine mobileTimeSlots and mobileProviderNumber into a single
  mobileProviderAndTimeSlot object
- Remove unused inShopProviderNumber state
- Extract SCHEDULE_FETCH_DAYS constant to replace magic number 14
- Add JSDoc to toDateString

date-picker:
- Move from src/ux-components/ to src/layouts/scheduling/ since it is
  only used by scheduling.vue
- Replace inline SVGs with chevron-right-blue.svg and chevron-right-grey.svg
  asset files, using CSS scaleX(-1) flip for left-pointing variants
- Import desktop breakpoint from new src/constants/breakpoints.js instead
  of hardcoding 768
This commit is contained in:
scottkiener-at-safelite 2026-05-06 15:19:19 -04:00
parent bf38d11bca
commit 00611a599c
6 changed files with 54 additions and 33 deletions

View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M-6.24658e-06 12C-6.55781e-06 14.3734 0.703782 16.6935 2.02236 18.6668C3.34094 20.6402 5.21508 22.1783 7.40779 23.0866C9.60051 23.9948 12.0133 24.2324 14.3411 23.7694C16.6688 23.3064 18.807 22.1635 20.4853 20.4853C22.1635 18.8071 23.3064 16.6689 23.7694 14.3411C24.2324 12.0133 23.9948 9.60051 23.0865 7.4078C22.1783 5.21509 20.6402 3.34094 18.6668 2.02237C16.6934 0.703788 14.3734 -2.13306e-07 12 -5.24537e-07C8.8174 -9.41884e-07 5.76515 1.26428 3.51472 3.51472C1.26428 5.76515 -5.82924e-06 8.8174 -6.24658e-06 12ZM11.28 5.8872L16.8 11.4072C16.9568 11.5646 17.0449 11.7778 17.0449 12C17.0449 12.2222 16.9568 12.4354 16.8 12.5928L11.28 18.1128C11.1228 18.2719 10.9088 18.3621 10.6851 18.3634C10.4614 18.3648 10.2463 18.2772 10.0872 18.12C9.92806 17.9628 9.83791 17.7488 9.83656 17.5251C9.83521 17.3014 9.92277 17.0863 10.08 16.9272L15.012 12L10.08 7.0728C9.92278 6.91367 9.83521 6.6986 9.83656 6.47491C9.83791 6.25122 9.92807 6.03722 10.0872 5.88C10.2463 5.72278 10.4614 5.63521 10.6851 5.63656C10.9088 5.63791 11.1228 5.72807 11.28 5.8872Z" fill="#0070D1"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M-6.24658e-06 12C-6.55781e-06 14.3734 0.703782 16.6935 2.02236 18.6668C3.34094 20.6402 5.21508 22.1783 7.40779 23.0866C9.60051 23.9948 12.0133 24.2324 14.3411 23.7694C16.6688 23.3064 18.807 22.1635 20.4853 20.4853C22.1635 18.8071 23.3064 16.6689 23.7694 14.3411C24.2324 12.0133 23.9948 9.60051 23.0865 7.4078C22.1783 5.21509 20.6402 3.34094 18.6668 2.02237C16.6934 0.703788 14.3734 -2.13306e-07 12 -5.24537e-07C8.8174 -9.41884e-07 5.76515 1.26428 3.51472 3.51472C1.26428 5.76515 -5.82924e-06 8.8174 -6.24658e-06 12ZM11.28 5.8872L16.8 11.4072C16.9568 11.5646 17.0449 11.7778 17.0449 12C17.0449 12.2222 16.9568 12.4354 16.8 12.5928L11.28 18.1128C11.1228 18.2719 10.9088 18.3621 10.6851 18.3634C10.4614 18.3648 10.2463 18.2772 10.0872 18.12C9.92806 17.9628 9.83791 17.7488 9.83656 17.5251C9.83521 17.3014 9.92277 17.0863 10.08 16.9272L15.012 12L10.08 7.0728C9.92278 6.91367 9.83521 6.6986 9.83656 6.47491C9.83791 6.25122 9.92807 6.03722 10.0872 5.88C10.2463 5.72278 10.4614 5.63521 10.6851 5.63656C10.9088 5.63791 11.1228 5.72807 11.28 5.8872Z" fill="#B3B4B5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,5 @@
const Breakpoints = {
MD: 768, // This value is to match the md breakpoint in src/styles/ux-variables.scss
};
export { Breakpoints };

View file

@ -5,12 +5,16 @@
:disabled="!canGoBack"
aria-label="Previous dates"
@click="goBack">
<svg v-if="canGoBack" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform: rotate(180deg)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M-6.24658e-06 12C-6.55781e-06 14.3734 0.703782 16.6935 2.02236 18.6668C3.34094 20.6402 5.21508 22.1783 7.40779 23.0866C9.60051 23.9948 12.0133 24.2324 14.3411 23.7694C16.6688 23.3064 18.807 22.1635 20.4853 20.4853C22.1635 18.8071 23.3064 16.6689 23.7694 14.3411C24.2324 12.0133 23.9948 9.60051 23.0865 7.4078C22.1783 5.21509 20.6402 3.34094 18.6668 2.02237C16.6934 0.703788 14.3734 -2.13306e-07 12 -5.24537e-07C8.8174 -9.41884e-07 5.76515 1.26428 3.51472 3.51472C1.26428 5.76515 -5.82924e-06 8.8174 -6.24658e-06 12ZM11.28 5.8872L16.8 11.4072C16.9568 11.5646 17.0449 11.7778 17.0449 12C17.0449 12.2222 16.9568 12.4354 16.8 12.5928L11.28 18.1128C11.1228 18.2719 10.9088 18.3621 10.6851 18.3634C10.4614 18.3648 10.2463 18.2772 10.0872 18.12C9.92806 17.9628 9.83791 17.7488 9.83656 17.5251C9.83521 17.3014 9.92277 17.0863 10.08 16.9272L15.012 12L10.08 7.0728C9.92278 6.91367 9.83521 6.6986 9.83656 6.47491C9.83791 6.25122 9.92807 6.03722 10.0872 5.88C10.2463 5.72278 10.4614 5.63521 10.6851 5.63656C10.9088 5.63791 11.1228 5.72807 11.28 5.8872Z" fill="#0070D1"/>
</svg>
<svg v-else width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M24 12C24 9.62663 23.2962 7.30655 21.9776 5.33316C20.6591 3.35977 18.7849 1.8217 16.5922 0.913447C14.3995 0.00519388 11.9867 -0.232445 9.65892 0.230578C7.33115 0.6936 5.19295 1.83649 3.51472 3.51472C1.83649 5.19295 0.693606 7.33114 0.230583 9.65891C-0.23244 11.9867 0.00519859 14.3995 0.91345 16.5922C1.8217 18.7849 3.35977 20.6591 5.33316 21.9776C7.30655 23.2962 9.62663 24 12 24C15.1826 24 18.2348 22.7357 20.4853 20.4853C22.7357 18.2348 24 15.1826 24 12ZM12.72 18.1128L7.2 12.5928C7.04319 12.4354 6.95514 12.2222 6.95514 12C6.95514 11.7778 7.04319 11.5646 7.2 11.4072L12.72 5.8872C12.8772 5.72807 13.0912 5.63791 13.3149 5.63656C13.5386 5.63521 13.7537 5.72278 13.9128 5.88C14.0719 6.03722 14.1621 6.25122 14.1634 6.47491C14.1648 6.6986 14.0772 6.91367 13.92 7.0728L8.988 12L13.92 16.9272C14.0772 17.0863 14.1648 17.3014 14.1634 17.5251C14.1621 17.7488 14.0719 17.9628 13.9128 18.12C13.7537 18.2772 13.5386 18.3648 13.3149 18.3634C13.0912 18.3621 12.8772 18.2719 12.72 18.1128Z" fill="#B3B4B5"/>
</svg>
<img
v-if="canGoBack"
src="@/assets/img/icons/chevron-right-blue.svg"
class="date-picker__nav-icon date-picker__nav-icon--flipped"
alt="" />
<img
v-else
src="@/assets/img/icons/chevron-right-grey.svg"
class="date-picker__nav-icon date-picker__nav-icon--flipped"
alt="" />
</button>
<div class="date-picker__track d-flex flex-grow-1">
<button
@ -34,17 +38,23 @@
:disabled="!canGoForward"
aria-label="Next dates"
@click="goForward">
<svg v-if="canGoForward" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M-6.24658e-06 12C-6.55781e-06 14.3734 0.703782 16.6935 2.02236 18.6668C3.34094 20.6402 5.21508 22.1783 7.40779 23.0866C9.60051 23.9948 12.0133 24.2324 14.3411 23.7694C16.6688 23.3064 18.807 22.1635 20.4853 20.4853C22.1635 18.8071 23.3064 16.6689 23.7694 14.3411C24.2324 12.0133 23.9948 9.60051 23.0865 7.4078C22.1783 5.21509 20.6402 3.34094 18.6668 2.02237C16.6934 0.703788 14.3734 -2.13306e-07 12 -5.24537e-07C8.8174 -9.41884e-07 5.76515 1.26428 3.51472 3.51472C1.26428 5.76515 -5.82924e-06 8.8174 -6.24658e-06 12ZM11.28 5.8872L16.8 11.4072C16.9568 11.5646 17.0449 11.7778 17.0449 12C17.0449 12.2222 16.9568 12.4354 16.8 12.5928L11.28 18.1128C11.1228 18.2719 10.9088 18.3621 10.6851 18.3634C10.4614 18.3648 10.2463 18.2772 10.0872 18.12C9.92806 17.9628 9.83791 17.7488 9.83656 17.5251C9.83521 17.3014 9.92277 17.0863 10.08 16.9272L15.012 12L10.08 7.0728C9.92278 6.91367 9.83521 6.6986 9.83656 6.47491C9.83791 6.25122 9.92807 6.03722 10.0872 5.88C10.2463 5.72278 10.4614 5.63521 10.6851 5.63656C10.9088 5.63791 11.1228 5.72807 11.28 5.8872Z" fill="#0070D1"/>
</svg>
<svg v-else width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform: rotate(180deg)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M24 12C24 9.62663 23.2962 7.30655 21.9776 5.33316C20.6591 3.35977 18.7849 1.8217 16.5922 0.913447C14.3995 0.00519388 11.9867 -0.232445 9.65892 0.230578C7.33115 0.6936 5.19295 1.83649 3.51472 3.51472C1.83649 5.19295 0.693606 7.33114 0.230583 9.65891C-0.23244 11.9867 0.00519859 14.3995 0.91345 16.5922C1.8217 18.7849 3.35977 20.6591 5.33316 21.9776C7.30655 23.2962 9.62663 24 12 24C15.1826 24 18.2348 22.7357 20.4853 20.4853C22.7357 18.2348 24 15.1826 24 12ZM12.72 18.1128L7.2 12.5928C7.04319 12.4354 6.95514 12.2222 6.95514 12C6.95514 11.7778 7.04319 11.5646 7.2 11.4072L12.72 5.8872C12.8772 5.72807 13.0912 5.63791 13.3149 5.63656C13.5386 5.63521 13.7537 5.72278 13.9128 5.88C14.0719 6.03722 14.1621 6.25122 14.1634 6.47491C14.1648 6.6986 14.0772 6.91367 13.92 7.0728L8.988 12L13.92 16.9272C14.0772 17.0863 14.1648 17.3014 14.1634 17.5251C14.1621 17.7488 14.0719 17.9628 13.9128 18.12C13.7537 18.2772 13.5386 18.3648 13.3149 18.3634C13.0912 18.3621 12.8772 18.2719 12.72 18.1128Z" fill="#B3B4B5"/>
</svg>
<img
v-if="canGoForward"
src="@/assets/img/icons/chevron-right-blue.svg"
class="date-picker__nav-icon"
alt="" />
<img
v-else
src="@/assets/img/icons/chevron-right-grey.svg"
class="date-picker__nav-icon"
alt="" />
</button>
</div>
</template>
<script>
import { Breakpoints } from "@/constants/breakpoints";
const DAY_ABBRS = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
const MONTH_ABBRS = [
"Jan",
@ -62,7 +72,7 @@ const MONTH_ABBRS = [
];
const MOBILE_WINDOW_SIZE = 3;
const DESKTOP_WINDOW_SIZE = 5;
const DESKTOP_BREAKPOINT_PX = 768;
const DESKTOP_BREAKPOINT_PX = Breakpoints.MD;
function toLocalDateString(date) {
const y = date.getFullYear();
@ -113,17 +123,10 @@ export default {
const hasBounds = this.startDate && this.endDate;
const hasAvailable = this.availableDates.length > 0;
if (!hasBounds && !hasAvailable) return [];
if (!hasBounds || !hasAvailable) return [];
let first, last;
if (hasBounds) {
first = parseLocalDate(this.startDate);
last = parseLocalDate(this.endDate);
} else {
const sorted = [...this.availableDates].sort();
first = parseLocalDate(sorted[0]);
last = parseLocalDate(sorted[sorted.length - 1]);
}
const first = parseLocalDate(this.startDate);
const last = parseLocalDate(this.endDate);
const dates = [];
const cursor = new Date(first);
@ -150,13 +153,6 @@ export default {
return !this.isLoadingDates && this.allDates.length > 0;
},
},
watch: {
// Only reset position when startDate changes that signals a fresh range.
// Extending endDate/availableDates (loading more) keeps the current window.
startDate() {
this.windowStart = 0;
},
},
mounted() {
this.updateWindowSize();
window.addEventListener("resize", this.updateWindowSize);
@ -286,5 +282,14 @@ export default {
line-height: 1.4;
white-space: nowrap;
}
&__nav-icon {
width: 24px;
height: 24px;
&--flipped {
transform: scaleX(-1);
}
}
}
</style>

View file

@ -35,7 +35,7 @@ import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import navbar from "@/fmg-components/nav-bar/nav-bar";
import { Form } from "vee-validate";
import datePicker from "@/ux-components/date-picker/date-picker";
import datePicker from "@/layouts/scheduling/date-picker/date-picker";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import store from "@/store";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
@ -117,7 +117,10 @@ export default {
timeSlots: resultMap[`inshopTimeSlots_${i}`] ?? null,
}));
vm.mobileProviderAndTimeSlot = mobileProviderNumber
? { providerNumber: mobileProviderNumber, timeSlots: resultMap.mobileTimeSlots ?? null }
? {
providerNumber: mobileProviderNumber,
timeSlots: resultMap.mobileTimeSlots ?? null,
}
: null;
});
},
@ -129,7 +132,9 @@ export default {
const inshopDates = this.inShopProvidersAndTimeslots.flatMap(({ timeSlots }) =>
(timeSlots?.days ?? []).map((d) => d.date)
);
const mobileDates = (this.mobileProviderAndTimeSlot?.timeSlots?.days ?? []).map((d) => d.date);
const mobileDates = (this.mobileProviderAndTimeSlot?.timeSlots?.days ?? []).map(
(d) => d.date
);
return [...new Set([...inshopDates, ...mobileDates])].sort();
},
},