| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- <script lang="ts">
- import type { AppointmentDateTimes } from '$lib/dbdata';
- import { isSameDate } from '$lib/funcs';
- import { t } from '$lib/translations';
- import moment, { type Moment } from 'moment';
- import { onMount } from 'svelte';
- let currentDate: Date = new Date();
- let days: Array<{ day: number; isActive: boolean; isAvailable: boolean }> = [];
- let currentMonth: string = '';
- export let selectedDate: Date;
- export let appointmentDateTimes: AppointmentDateTimes[];
- $: {
- if (appointmentDateTimes.length > 0) {
- renderCalendar();
- }
- }
- function isDayAvailable(year: number, month: number, day: number) {
- const dateStr = `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
- const testDate: Date = moment(dateStr).toDate();
- return appointmentDateTimes.some((date) => isSameDate(testDate, date.date));
- }
- /**
- * Updates the calendar display by calculating the days of the current month.
- */
- const renderCalendar = (): void => {
- const mDate: Moment = moment(currentDate).locale("de");
- const year: number = currentDate.getFullYear();
- const month: number = mDate.month();
- let locale: string = "en-US";
- if (navigator.language.includes("de")) locale = "de";
- // make sure to properly translate this
- currentMonth = currentDate.toLocaleDateString(locale, { month: 'long', year: 'numeric' });
- const firstDayOfMonth: Date = new Date(year, month, 1);
- const lastDayOfMonth: Date = new Date(year, month + 1, 0);
- let firstDayIndex: number = firstDayOfMonth.getDay() - 1;
- if (firstDayIndex === -1) firstDayIndex = 6;
- const daysInMonth: number = lastDayOfMonth.getDate();
- // Reset days array
- days = [];
- // Add empty cells for days before the first of the month
- for (let i = 0; i < firstDayIndex; i++) {
- days.push({ day: 0, isActive: false, isAvailable: false });
- }
- // Add days of the month
- for (let day = 1; day <= daysInMonth; day++) {
- days.push({ day, isActive: false, isAvailable: isDayAvailable(year, month + 1, day) }); // Example: Make day 20 active
- }
- };
- /**
- * Changes the current month by a given offset and re-renders the calendar.
- * @param offset - The number of months to move forward or backward.
- */
- const changeMonth = (offset: number): void => {
- //currentDate.setMonth(currentDate.getMonth() + offset);
- if (offset === -1) {
- currentDate = moment(currentDate).subtract(1, 'month').toDate();
- } else {
- currentDate = moment(currentDate).add(1, 'month').toDate();
- }
- renderCalendar();
- };
- onMount(() => {
- currentDate = new Date();
- renderCalendar();
- });
- /**
- * Handles the selection of a day in the calendar.
- * @param selectedDay - The day number that was clicked.
- */
- const selectDay = (selectedDay: number): void => {
- days = days.map((d) => ({ ...d, isActive: d.day === selectedDay }));
- const selectedDateValue = new Date(
- currentDate.getFullYear(),
- currentDate.getMonth(),
- selectedDay
- );
- selectedDate = selectedDateValue;
- };
- </script>
- <div class="date-picker border center">
- <div class="date-picker-header">
- <button class="button square secondary medium" on:click={() => changeMonth(-1)}><</button>
- <h4 id="currentMonth" class="small wrap center-align">{currentMonth}</h4>
- <button class="button square secondary medium" on:click={() => changeMonth(1)}>></button>
- </div>
- <div class="date-picker-grid">
- <!-- Days of the week -->
- <div class="date-picker-day">{$t("common.monday-short")}</div>
- <div class="date-picker-day">{$t("common.tuesday-short")}</div>
- <div class="date-picker-day">{$t("common.wednesday-short")}</div>
- <div class="date-picker-day">{$t("common.thursday-short")}</div>
- <div class="date-picker-day">{$t("common.friday-short")}</div>
- <div class="date-picker-day">{$t("common.saturday-short")}</div>
- <div class="date-picker-day">{$t("common.sunday-short")}</div>
- <!-- Render days -->
- {#each days as { day, isActive, isAvailable }, index}
- {#if isAvailable}
- <!-- svelte-ignore a11y_click_events_have_key_events -->
- <!-- svelte-ignore a11y_no_static_element_interactions -->
- <div
- class="date-picker-cell {!isActive ? 'secondary' : ''} {isActive ? 'active' : ''} {day ===
- 0
- ? 'empty'
- : ''}"
- on:click={() => day && selectDay(day)}
- >
- {day || ''}
- </div>
- {:else}
- <!-- svelte-ignore a11y_click_events_have_key_events -->
- <!-- svelte-ignore a11y_no_static_element_interactions -->
- <div class="date-picker-cell">
- {day || ''}
- </div>
- {/if}
- {/each}
- </div>
- </div>
- <style>
- .date-picker {
- border: 1px solid var(--border-color);
- border-radius: var(--border-radius);
- padding: 1rem;
- max-width: 600px;
- background: var(--background);
- box-shadow: var(--shadow);
- }
- .date-picker-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 1rem;
- }
- .date-picker-grid {
- display: grid;
- grid-template-columns: repeat(7, 1fr);
- gap: 0.5rem;
- text-align: center;
- }
- .date-picker-day {
- font-weight: bold;
- color: var(--secondary);
- }
- .date-picker-cell {
- padding: 0.5rem;
- border-radius: var(--border-radius);
- cursor: pointer;
- user-select: none;
- }
- .date-picker-cell:hover {
- background-color: var(--hover-background);
- }
- .date-picker-cell.active {
- background-color: var(--primary);
- color: var(--background);
- }
- .empty {
- pointer-events: none;
- visibility: hidden;
- }
- </style>
|