227 lines
5.9 KiB
Svelte
227 lines
5.9 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from 'svelte';
|
|
import { pb } from '$lib/pocketbase';
|
|
import Sun from '$lib/components/svgs/Sun.svelte';
|
|
import Moon from '$lib/components/svgs/Moon.svelte';
|
|
import Milk from '$lib/components/svgs/Milk.svelte';
|
|
import ToiletPaper from '$lib/components/svgs/ToiletPaper.svelte';
|
|
import Poop from '$lib/components/svgs/Poop.svelte';
|
|
|
|
// State for current week
|
|
let currentWeekStart: Date = new Date();
|
|
|
|
// Adjust currentWeekStart to the beginning of the week
|
|
currentWeekStart.setDate(currentWeekStart.getDate() - currentWeekStart.getDay());
|
|
const oldestDataDate: Date = new Date('2024-01-22');
|
|
|
|
// Reactive store to hold actions
|
|
$: actions = [];
|
|
|
|
type Action = {
|
|
id: any;
|
|
type: string;
|
|
timestamp: string;
|
|
};
|
|
|
|
onMount(async () => {
|
|
actions = await fetchAllActions(currentWeekStart);
|
|
});
|
|
|
|
async function fetchAllActions(startOfWeek: Date) {
|
|
// Get current date and calculate start and end of the week
|
|
|
|
const endOfWeek = new Date(
|
|
startOfWeek.getFullYear(),
|
|
startOfWeek.getMonth(),
|
|
startOfWeek.getDate() + 7
|
|
);
|
|
|
|
const result = await pb.collection('actions').getList(1, 1000, {
|
|
sort: 'timestamp'
|
|
});
|
|
|
|
// Filter actions within the current week
|
|
const filteredActions = result.items.filter((action) => {
|
|
const actionDate = new Date(action.timestamp);
|
|
return actionDate >= startOfWeek && actionDate < endOfWeek;
|
|
});
|
|
|
|
return filteredActions;
|
|
}
|
|
|
|
// Handlers for next and previous week
|
|
const handleNextWeek = async () => {
|
|
currentWeekStart.setDate(currentWeekStart.getDate() + 7);
|
|
actions = await fetchAllActions(currentWeekStart);
|
|
};
|
|
|
|
const handlePreviousWeek = async () => {
|
|
currentWeekStart.setDate(currentWeekStart.getDate() - 7);
|
|
actions = await fetchAllActions(currentWeekStart);
|
|
};
|
|
|
|
// Function to get the day of the week from a date string
|
|
const getDayOfWeek = (dateString: string) => {
|
|
return new Date(dateString).getDay();
|
|
};
|
|
|
|
// Function to get the hour of the day from a date string
|
|
const getHourOfDay = (dateString: string) => {
|
|
return new Date(dateString).getHours();
|
|
};
|
|
|
|
// Days of the week for headers
|
|
//const daysOfWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
|
const daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
|
|
// Generate hours for the grid
|
|
const hours = Array.from({ length: 24 }, (_, i) => i);
|
|
|
|
// Function to format hour in HH:mm format
|
|
const formatHour = (hour: number) => {
|
|
return `${hour.toString().padStart(2, '0')}:00`;
|
|
};
|
|
|
|
// function formatTime(date: Date): string {
|
|
// const hours = date.getHours().toString().padStart(2, '0');
|
|
// const minutes = date.getMinutes().toString().padStart(2, '0');
|
|
// return `${hours}:${minutes}`;
|
|
// }
|
|
|
|
function formatTime(dateString: string): string {
|
|
const date = new Date(dateString);
|
|
const hours = date.getHours().toString().padStart(2, '0');
|
|
const minutes = date.getMinutes().toString().padStart(2, '0');
|
|
return `${hours}:${minutes}`;
|
|
}
|
|
|
|
// Function to check if it's the current week
|
|
function isCurrentWeek() {
|
|
const today = new Date();
|
|
const startOfTodayWeek = new Date(
|
|
today.getFullYear(),
|
|
today.getMonth(),
|
|
today.getDate() - today.getDay()
|
|
);
|
|
|
|
return (
|
|
currentWeekStart.getFullYear() === startOfTodayWeek.getFullYear() &&
|
|
currentWeekStart.getMonth() === startOfTodayWeek.getMonth() &&
|
|
currentWeekStart.getDate() === startOfTodayWeek.getDate()
|
|
);
|
|
}
|
|
|
|
// Function to check if it's the oldest data week
|
|
function isOldestWeek() {
|
|
return currentWeekStart <= oldestDataDate;
|
|
}
|
|
</script>
|
|
|
|
<!-- {#if !isOldestWeek()} -->
|
|
<button on:click={handlePreviousWeek}>Previous Week</button>
|
|
<!-- {/if} -->
|
|
<!-- {#if !isCurrentWeek()} -->
|
|
<button on:click={handleNextWeek}>Next Week</button>
|
|
<!-- {/if} -->
|
|
|
|
<div class="calendar-wrapper">
|
|
<div class="calendar">
|
|
<!-- Empty cell for top-left corner -->
|
|
<div></div>
|
|
|
|
<!-- Day Headers -->
|
|
{#each daysOfWeek as day (day)}
|
|
<div class="day-header">{day}</div>
|
|
{/each}
|
|
|
|
<!-- Hour Labels and Calendar Grid -->
|
|
{#each hours as hour (hour)}
|
|
<div class="hour-label">{formatHour(hour)}</div>
|
|
<!-- Hour label -->
|
|
{#each daysOfWeek as _, dayIndex}
|
|
<div class="hour">
|
|
{#each actions as action (action.id)}
|
|
{#if getDayOfWeek(action.timestamp) === dayIndex && getHourOfDay(action.timestamp) === hour}
|
|
<div class="event event--{action.type}">
|
|
{#if action.type == 'awake'}
|
|
<Sun />
|
|
{:else if action.type == 'asleep'}
|
|
<Moon />
|
|
{:else if action.type == 'food'}
|
|
<Milk />
|
|
{:else if action.type == 'diaper'}
|
|
<ToiletPaper />
|
|
{:else if action.type == 'poop'}
|
|
<Poop />
|
|
{/if}
|
|
<!-- <span class="event__title">{action.type}</span> -->
|
|
<span class="event__time">{formatTime(action.timestamp)}</span>
|
|
</div>
|
|
{/if}
|
|
{/each}
|
|
</div>
|
|
{/each}
|
|
{/each}
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.calendar-wrapper {
|
|
max-width: 100%;
|
|
/* outline: 1px solid #ccc; */
|
|
overflow-x: auto;
|
|
position: relative;
|
|
}
|
|
.calendar {
|
|
display: grid;
|
|
grid-template-columns: 60px repeat(7, 1fr); /* Adjusted for hour column */
|
|
text-align: center;
|
|
min-width: 700px;
|
|
}
|
|
.day-header,
|
|
.hour-label {
|
|
font-weight: bold;
|
|
font-size: 1.2rem;
|
|
background: var(--c-border);
|
|
}
|
|
.day-header {
|
|
border-radius: 1em 1em 0 0;
|
|
margin-top: 1rem;
|
|
padding: 0.5rem;
|
|
}
|
|
.hour-label {
|
|
border-radius: 1em 0 0 1em;
|
|
padding: 0.5rem;
|
|
margin-left: 0.5rem;
|
|
}
|
|
.hour {
|
|
border: 1px solid var(--c-border);
|
|
min-height: 60px;
|
|
}
|
|
.event {
|
|
background-color: var(--color);
|
|
border-radius: 4px;
|
|
padding: 0.3em 0.8em;
|
|
line-height: 1;
|
|
margin: 2px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
--c-event: rgba(255, 255, 255, 0.5);
|
|
}
|
|
|
|
.event__title {
|
|
font-weight: 900;
|
|
font-size: 1.2rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.2em;
|
|
color: rgba(255, 255, 255, 0.5);
|
|
}
|
|
|
|
.event__time {
|
|
line-height: 1;
|
|
font-size: 1.2rem;
|
|
font-weight: 300;
|
|
color: var(--c-event);
|
|
}
|
|
</style>
|