diff --git a/src/app/components/settings/settings.component.html b/src/app/components/settings/settings.component.html index c4eb604..b74736b 100644 --- a/src/app/components/settings/settings.component.html +++ b/src/app/components/settings/settings.component.html @@ -12,10 +12,18 @@

Basic settings

Export

+ Export everything

This will export everything, all tracked times, all your settings.

+ CSV Export +

This will export your times as CSV.

+
+ + + +
diff --git a/src/app/components/settings/settings.component.ts b/src/app/components/settings/settings.component.ts index 7554403..beeb10b 100644 --- a/src/app/components/settings/settings.component.ts +++ b/src/app/components/settings/settings.component.ts @@ -5,7 +5,7 @@ import { SettingsFormComponent } from './settings-form/settings-form.component'; import { PageTitleComponent } from '../page-title/page-title.component'; import { DatabaseService } from '../../services/database/database.service'; import { DateTime } from 'luxon'; -import { dateTimeToLocaleData } from '../../services/time.utils'; +import { dateTimeToLocaleData, millisecondsToHumanReadable } from '../../services/time.utils'; import { FileDirective } from '../../directives/file.directive'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { TauriService } from '../../services/tauri.service'; @@ -13,6 +13,8 @@ import { CardComponent } from '../card/card.component'; import { CardSectionTitleComponent } from '../card/card-section-title/card-section-title.component'; import { Settings } from '../../services/settings/settings'; import { LoadingSpinnerComponent } from '../loading-spinner/loading-spinner.component'; +import { TimeTable } from '../../services/time-tracking/time.table'; +import { firstValueFrom } from 'rxjs'; @Component({ selector: 'kw-settings', @@ -37,12 +39,47 @@ export default class SettingsComponent { private readonly settingsTable = inject(SettingsTable); protected readonly settings$ = this.settingsTable.current$; private readonly tauriService = inject(TauriService); + private readonly timeTable = inject(TimeTable); protected async export(): Promise { const blob = await this.databaseService.exportToBlob(); await this.tauriService.save(blob, `KuwakaWakati-${dateTimeToLocaleData(DateTime.now())}.json`); } + protected async exportCSV(days: number): Promise { + const today = DateTime.now().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }); + const startDay = today.minus({ day: days }); + const items = await firstValueFrom(this.timeTable.groupByDay$(startDay.toMillis(), today.toMillis())); + const rows = items.flatMap(item => [ + ['Date', 'Start Time', 'End Time', 'Duration', 'Is A Day Off?', 'Is a non work day?', 'description'], + ...item.items.map(timeEntry => [ + DateTime.fromMillis(item.utcDate).toISODate(), + DateTime.fromMillis(timeEntry.start).toISOTime({ + includeOffset: false, + includePrefix: false, + suppressMilliseconds: true, + suppressSeconds: true, + extendedZone: false, + }), + DateTime.fromMillis(timeEntry.end).toISOTime({ + includeOffset: false, + includePrefix: false, + suppressMilliseconds: true, + suppressSeconds: true, + extendedZone: false, + }), + millisecondsToHumanReadable(timeEntry.duration.toMillis()), + timeEntry.isADayOff, + timeEntry.isNonWorkday, + timeEntry.description, + ]), + ]); + + const csv = rows.map(row => row.join(',')).join('\n'); + const csvBlob = new Blob([csv], { type: 'text/csv;charset=utf-8' }); + await this.tauriService.save(csvBlob, `KuwakaWakati-${days}days-${dateTimeToLocaleData(DateTime.now())}.csv`); + } + protected async import(): Promise { if (!this.fileControl.value) { return; diff --git a/src/app/services/time-tracking/time.table.ts b/src/app/services/time-tracking/time.table.ts index 1dde353..206b27d 100644 --- a/src/app/services/time-tracking/time.table.ts +++ b/src/app/services/time-tracking/time.table.ts @@ -43,7 +43,7 @@ export class TimeTable implements DatabaseTable { todayGroup$(): Observable { const todayDate = todayDateMilliseconds(); - return this.groupByDay$(todayDate, todayDate + 1).pipe( + return this.groupByDay$(todayDate, todayDate).pipe( map(([today]) => { if (!today) { return { @@ -61,7 +61,7 @@ export class TimeTable implements DatabaseTable { } private async items(fromTimestamp: Milliseconds = 0, toTimestamp: Milliseconds = Number.MAX_SAFE_INTEGER): Promise { - const items = await this.times.where('utcDate').between(fromTimestamp, toTimestamp, true).toArray(); + const items = await this.times.where('utcDate').between(fromTimestamp, toTimestamp, true, true).toArray(); items.sort((a, b) => { if (a.utcDate < b.utcDate) { return 1;