diff --git a/config/packages/http_discovery.yaml b/config/packages/http_discovery.yaml new file mode 100644 index 0000000..2a789e7 --- /dev/null +++ b/config/packages/http_discovery.yaml @@ -0,0 +1,10 @@ +services: + Psr\Http\Message\RequestFactoryInterface: '@http_discovery.psr17_factory' + Psr\Http\Message\ResponseFactoryInterface: '@http_discovery.psr17_factory' + Psr\Http\Message\ServerRequestFactoryInterface: '@http_discovery.psr17_factory' + Psr\Http\Message\StreamFactoryInterface: '@http_discovery.psr17_factory' + Psr\Http\Message\UploadedFileFactoryInterface: '@http_discovery.psr17_factory' + Psr\Http\Message\UriFactoryInterface: '@http_discovery.psr17_factory' + + http_discovery.psr17_factory: + class: Http\Discovery\Psr17Factory diff --git a/docs/superpowers/plans/2026-03-15-date-filter.md b/docs/superpowers/plans/2026-03-15-date-filter.md new file mode 100644 index 0000000..73db2ac --- /dev/null +++ b/docs/superpowers/plans/2026-03-15-date-filter.md @@ -0,0 +1,385 @@ +# Date Filter Component Implementation Plan + +> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add a reusable date filter component to the time-tracking page using `@vuepic/vue-datepicker`, enabling filtering by single day or date range. + +**Architecture:** A wrapper component `DateFilter.vue` encapsulates `VueDatePicker` with project-consistent styling. It integrates into the existing filter bar on the time-tracking page. Filtering is client-side, matching the existing project/tag filter pattern. + +**Tech Stack:** Vue 3, @vuepic/vue-datepicker, Tailwind CSS, @nuxtjs/i18n + +--- + +## Chunk 1: Setup and Component + +### Task 1: Install @vuepic/vue-datepicker and configure Nuxt + +**Files:** +- Modify: `frontend/package.json` +- Modify: `frontend/nuxt.config.ts:1-66` + +- [ ] **Step 1: Install the package** + +Run inside the PHP container (where Node is available): + +```bash +cd /home/r-dev/Lesstime/frontend && npm install @vuepic/vue-datepicker +``` + +- [ ] **Step 2: Add transpile config to nuxt.config.ts** + +In `frontend/nuxt.config.ts`, add `build.transpile` after the `typescript` block: + +```typescript +export default defineNuxtConfig({ + // ... existing config ... + typescript: { + strict: true + }, + build: { + transpile: ['@vuepic/vue-datepicker'] + } +}) +``` + +- [ ] **Step 3: Commit** + +```bash +git add frontend/package.json frontend/package-lock.json frontend/nuxt.config.ts +git commit -m "feat(frontend) : add @vuepic/vue-datepicker dependency" +``` + +--- + +### Task 2: Add i18n translations + +**Files:** +- Modify: `frontend/i18n/locales/fr.json:167-170` + +- [ ] **Step 1: Add date filter translations to fr.json** + +In `frontend/i18n/locales/fr.json`, add keys inside the existing `"common"` block: + +```json +"common": { + "cancel": "Annuler", + "loading": "Chargement...", + "dateFilter": "Date", + "today": "Aujourd'hui", + "thisWeek": "Cette semaine", + "clear": "Effacer" +} +``` + +- [ ] **Step 2: Commit** + +```bash +git add frontend/i18n/locales/fr.json +git commit -m "feat(frontend) : add date filter i18n translations" +``` + +--- + +### Task 3: Create DateFilter.vue component + +**Files:** +- Create: `frontend/components/ui/DateFilter.vue` + +- [ ] **Step 1: Create the component** + +Create `frontend/components/ui/DateFilter.vue`: + +```vue + + + + + +``` + +- [ ] **Step 2: Verify the component renders** + +Run `make dev-nuxt` and navigate to the time-tracking page (integration comes in Task 4). Check that no build errors occur. + +- [ ] **Step 3: Commit** + +```bash +git add frontend/components/ui/DateFilter.vue +git commit -m "feat(frontend) : create DateFilter reusable component" +``` + +--- + +## Chunk 2: Integration + +### Task 4: Integrate DateFilter into time-tracking page + +**Files:** +- Modify: `frontend/pages/time-tracking.vue:15-73` (template filter bar) +- Modify: `frontend/pages/time-tracking.vue:138` (add ref) +- Modify: `frontend/pages/time-tracking.vue:184-193` (filteredEntries computed) + +- [ ] **Step 1: Add the date filter ref** + +In `frontend/pages/time-tracking.vue`, after line 138 (`selectedProjectId`), add: + +```typescript +const selectedDateFilter = ref(null) +``` + +- [ ] **Step 2: Add DateFilter to the template filter bar** + +In the filter bar `
` (line 15), after the tag MalioSelect block (after line 72), add: + +```vue + +``` + +- [ ] **Step 3: Add date filtering to filteredEntries computed** + +In `frontend/pages/time-tracking.vue`, update the `filteredEntries` computed (around line 184) to include date filtering: + +```typescript +const filteredEntries = computed(() => { + let result = entries.value + if (selectedProjectId.value) { + result = result.filter((e) => e.project?.id === selectedProjectId.value) + } + if (selectedTagId.value) { + result = result.filter((e) => e.tags.some((t) => t.id === selectedTagId.value)) + } + if (selectedDateFilter.value) { + if (Array.isArray(selectedDateFilter.value)) { + const [start, end] = selectedDateFilter.value + const startDay = new Date(start) + startDay.setHours(0, 0, 0, 0) + const endDay = new Date(end) + endDay.setHours(23, 59, 59, 999) + result = result.filter((e) => { + const entryDate = new Date(e.startedAt) + return entryDate >= startDay && entryDate <= endDay + }) + } else { + const day = new Date(selectedDateFilter.value) + day.setHours(0, 0, 0, 0) + const nextDay = new Date(day) + nextDay.setDate(nextDay.getDate() + 1) + result = result.filter((e) => { + const entryDate = new Date(e.startedAt) + return entryDate >= day && entryDate < nextDay + }) + } + } + return result +}) +``` + +- [ ] **Step 4: Verify manually** + +Run `make dev-nuxt`, navigate to time-tracking page: +1. Verify DateFilter appears in the filter bar +2. Click a single day — entries filter to that day +3. Click a second day — entries filter to the range +4. Click "Aujourd'hui" — filters to today +5. Click "Cette semaine" — filters to current week +6. Clear the filter — all entries show again + +- [ ] **Step 5: Commit** + +```bash +git add frontend/pages/time-tracking.vue +git commit -m "feat(frontend) : integrate date filter into time-tracking page" +``` diff --git a/docs/superpowers/specs/2026-03-15-date-filter-design.md b/docs/superpowers/specs/2026-03-15-date-filter-design.md new file mode 100644 index 0000000..df611d8 --- /dev/null +++ b/docs/superpowers/specs/2026-03-15-date-filter-design.md @@ -0,0 +1,86 @@ +# Date Filter Component - Design Spec + +## Summary + +Add a reusable date filter component to the time-tracking page using `@vuepic/vue-datepicker`. Allows filtering by single day or date range via text input and mini calendar dropdown. + +## Behavior + +- **Single click** on a day = select that day +- **Second click** on another day = select range between the two dates +- **Text input**: type a date (`15/03/2026`) or a range (`15/03/2026 - 20/03/2026`) +- **Calendar dropdown**: opens on input click/focus +- **Quick shortcuts**: "Aujourd'hui" and "Cette semaine" buttons in calendar +- **No time picker**: filter by day granularity only +- **Format**: `dd/MM/yyyy` (French locale) + +## Component: `DateFilter.vue` + +Location: `frontend/components/ui/DateFilter.vue` + +### Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `modelValue` | `Date \| [Date, Date] \| null` | `null` | Selected date or range | +| `placeholder` | `string` | `t('common.dateFilter')` | Input placeholder | + +### Emits + +| Event | Payload | Description | +|-------|---------|-------------| +| `update:modelValue` | `Date \| [Date, Date] \| null` | Date selection changed | + +### Implementation + +- Wraps `VueDatePicker` with project-consistent styling +- Uses `#dp-input` slot for custom input matching MalioSelect style +- Configures `range` mode with `multi-calendars: false` +- Sets `text-input` with `format: 'dd/MM/yyyy'`, `rangeSeparator: ' - '` +- Disables time picker (`enable-time-picker: false`) +- Applies project primary color (`#222783`) via CSS overrides +- Responsive width: `!w-44 sm:!w-52` + +## Integration: Time Tracking Page + +### Filter bar addition + +Add `DateFilter` to the existing filter bar in `frontend/pages/time-tracking.vue`, alongside user/project/tag filters. + +### Filtering logic + +- Client-side filtering (same pattern as project and tag filters) +- When a single date is selected: show only entries matching that day +- When a range is selected: show entries within the range (inclusive) +- When null: show all entries (no date filter) + +## Files Impacted + +| File | Action | Description | +|------|--------|-------------| +| `frontend/components/ui/DateFilter.vue` | Create | Reusable date filter wrapper | +| `frontend/nuxt.config.ts` | Modify | Add `@vuepic/vue-datepicker` to `build.transpile` | +| `frontend/pages/time-tracking.vue` | Modify | Integrate DateFilter in filter bar + client-side filtering | +| `frontend/i18n/locales/fr.json` | Modify | Add French translations | +| `frontend/i18n/locales/en.json` | Modify | Add English translations | +| `package.json` | Modify | Add `@vuepic/vue-datepicker` dependency | + +## i18n Keys + +```json +{ + "common": { + "dateFilter": "Date", + "today": "Aujourd'hui", + "thisWeek": "Cette semaine" + } +} +``` + +## Style + +- Input height and borders match MalioSelect components +- Text size: `text-sm` +- Selected date highlight: project primary color `#222783` +- Calendar dropdown: subtle shadow, rounded corners matching project style +- Override default vue-datepicker CSS variables to match project theme diff --git a/frontend/components/ui/DateFilter.vue b/frontend/components/ui/DateFilter.vue new file mode 100644 index 0000000..c416202 --- /dev/null +++ b/frontend/components/ui/DateFilter.vue @@ -0,0 +1,161 @@ + + + + + diff --git a/frontend/i18n/locales/fr.json b/frontend/i18n/locales/fr.json index f977996..f71191e 100644 --- a/frontend/i18n/locales/fr.json +++ b/frontend/i18n/locales/fr.json @@ -166,7 +166,11 @@ }, "common": { "cancel": "Annuler", - "loading": "Chargement..." + "loading": "Chargement...", + "dateFilter": "Date", + "today": "Aujourd'hui", + "thisWeek": "Cette semaine", + "clear": "Effacer" }, "gitea": { "settings": { diff --git a/frontend/nuxt.config.ts b/frontend/nuxt.config.ts index 69c96c8..ebec92b 100644 --- a/frontend/nuxt.config.ts +++ b/frontend/nuxt.config.ts @@ -62,5 +62,8 @@ export default defineNuxtConfig({ }, typescript: { strict: true + }, + build: { + transpile: ['@vuepic/vue-datepicker'] } }) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index db1ab76..4ba6645 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,6 +12,7 @@ "@nuxtjs/i18n": "^10.2.3", "@nuxtjs/tailwindcss": "^6.14.0", "@pinia/nuxt": "^0.11.3", + "@vuepic/vue-datepicker": "^12.1.0", "chart.js": "^4.5.1", "nuxt": "^4.3.1", "nuxt-toast": "^1.4.0", @@ -541,6 +542,12 @@ "postcss-selector-parser": "^7.0.0" } }, + "node_modules/@date-fns/tz": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz", + "integrity": "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==", + "license": "MIT" + }, "node_modules/@dxup/nuxt": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@dxup/nuxt/-/nuxt-0.3.2.tgz", @@ -1094,6 +1101,68 @@ "node": "^20.19.0 || ^22.13.0 || >=24" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" + }, + "node_modules/@floating-ui/vue": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@floating-ui/vue/-/vue-1.1.11.tgz", + "integrity": "sha512-HzHKCNVxnGS35r9fCHBc3+uCnjw9IWIlCPL683cGgM9Kgj2BiAl8x1mS7vtvP6F9S/e/q4O6MApwSHj8hNLGfw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.6", + "@floating-ui/utils": "^0.2.11", + "vue-demi": ">=0.13.0" + } + }, + "node_modules/@floating-ui/vue/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -5259,6 +5328,12 @@ "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "license": "MIT" }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "license": "MIT" + }, "node_modules/@typescript-eslint/project-service": { "version": "8.56.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", @@ -5720,6 +5795,62 @@ "integrity": "sha512-w7SR0A5zyRByL9XUkCfdLs7t9XOHUyJ67qPGQjOou3p6GvBeBW+AVjUUmlxtZ4PIYaRvE+1LmK44O4uajlZwcg==", "license": "MIT" }, + "node_modules/@vuepic/vue-datepicker": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-12.1.0.tgz", + "integrity": "sha512-QuWcO+CqIGYFoRNCagp9xUY9sMK/OHUlVIDxBYjw7HjCTWXfuE/r3l3loB00faEtb0Teo3DeBn26hT3tYA5pgg==", + "license": "MIT", + "dependencies": { + "@date-fns/tz": "^1.4.1", + "@floating-ui/vue": "^1.1.9", + "@vueuse/core": "^14.1.0", + "date-fns": "^4.1.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "vue": ">=3.5.0" + } + }, + "node_modules/@vueuse/core": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.2.1.tgz", + "integrity": "sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "14.2.1", + "@vueuse/shared": "14.2.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@vueuse/metadata": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.2.1.tgz", + "integrity": "sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.2.1.tgz", + "integrity": "sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, "node_modules/abbrev": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", @@ -7126,6 +7257,16 @@ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/db0": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/db0/-/db0-0.3.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index ef4aff3..bccdaab 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,7 @@ "@nuxtjs/i18n": "^10.2.3", "@nuxtjs/tailwindcss": "^6.14.0", "@pinia/nuxt": "^0.11.3", + "@vuepic/vue-datepicker": "^12.1.0", "chart.js": "^4.5.1", "nuxt": "^4.3.1", "nuxt-toast": "^1.4.0", diff --git a/frontend/pages/projects/[id]/index.vue b/frontend/pages/projects/[id]/index.vue index 5bd364d..5d24a9d 100644 --- a/frontend/pages/projects/[id]/index.vue +++ b/frontend/pages/projects/[id]/index.vue @@ -3,13 +3,22 @@

{{ project?.name ?? '' }}

- +
+ + +
@@ -120,6 +129,13 @@ @saved="onSaved" /> + +
@@ -132,7 +148,9 @@ import type { TaskPriority } from '~/services/dto/task-priority' import type { TaskTag } from '~/services/dto/task-tag' import type { TaskGroup } from '~/services/dto/task-group' import type { UserData } from '~/services/dto/user-data' +import type { Client } from '~/services/dto/client' import { useProjectService } from '~/services/projects' +import { useClientService } from '~/services/clients' import { useTaskService } from '~/services/tasks' import { useTaskStatusService } from '~/services/task-statuses' import { useTaskEffortService } from '~/services/task-efforts' @@ -147,6 +165,7 @@ const projectId = computed(() => Number(route.params.id)) useHead({ title: 'Projet' }) const projectService = useProjectService() +const clientService = useClientService() const taskService = useTaskService() const statusService = useTaskStatusService() const effortService = useTaskEffortService() @@ -163,6 +182,7 @@ const priorities = ref([]) const tags = ref([]) const groups = ref([]) const users = ref([]) +const clients = ref([]) const isLoading = ref(true) const selectedGroupId = ref(null) @@ -172,6 +192,7 @@ const selectedStatusId = ref(null) const dragOverStatusId = ref(null) const dragCounter = ref(0) const taskDrawerOpen = ref(false) +const projectDrawerOpen = ref(false) const selectedTask = ref(null) const groupFilterOptions = computed(() => @@ -218,7 +239,7 @@ const backlogTasks = computed(() => async function loadData() { isLoading.value = true try { - const [p, t, s, e, pr, ty, g, u] = await Promise.all([ + const [p, t, s, e, pr, ty, g, u, c] = await Promise.all([ projectService.getById(projectId.value), taskService.getByProject(projectId.value), statusService.getAll(), @@ -227,6 +248,7 @@ async function loadData() { tagService.getAll(), groupService.getByProject(projectId.value), userService.getAll(), + clientService.getAll(), ]) project.value = p tasks.value = t @@ -236,6 +258,7 @@ async function loadData() { tags.value = ty groups.value = g users.value = u + clients.value = c } finally { isLoading.value = false } @@ -290,6 +313,10 @@ async function onSaved() { await loadData() } +async function onProjectSaved() { + await loadData() +} + onMounted(() => { loadData() }) diff --git a/frontend/pages/time-tracking.vue b/frontend/pages/time-tracking.vue index b567208..c3518d9 100644 --- a/frontend/pages/time-tracking.vue +++ b/frontend/pages/time-tracking.vue @@ -70,6 +70,8 @@ text-value="text-sm" />
+ +
@@ -136,6 +138,7 @@ const startDate = ref(getMonday(new Date())) const selectedUserId = ref(authStore.user?.id ?? null) const selectedTagId = ref(null) const selectedProjectId = ref(null) +const selectedDateFilter = ref(null) const entries = ref([]) const users = ref([]) @@ -189,6 +192,28 @@ const filteredEntries = computed(() => { if (selectedTagId.value) { result = result.filter((e) => e.tags.some((t) => t.id === selectedTagId.value)) } + if (selectedDateFilter.value) { + if (Array.isArray(selectedDateFilter.value)) { + const [start, end] = selectedDateFilter.value + const startDay = new Date(start) + startDay.setHours(0, 0, 0, 0) + const endDay = new Date(end) + endDay.setHours(23, 59, 59, 999) + result = result.filter((e) => { + const entryDate = new Date(e.startedAt) + return entryDate >= startDay && entryDate <= endDay + }) + } else { + const day = new Date(selectedDateFilter.value) + day.setHours(0, 0, 0, 0) + const nextDay = new Date(day) + nextDay.setDate(nextDay.getDate() + 1) + result = result.filter((e) => { + const entryDate = new Date(e.startedAt) + return entryDate >= day && entryDate < nextDay + }) + } + } return result })