Skip to content

Commit

Permalink
feat: export CSV
Browse files Browse the repository at this point in the history
fixes #38
  • Loading branch information
ManuelRauber committed Sep 2, 2024
1 parent 1edfec9 commit 440bb12
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 3 deletions.
8 changes: 8 additions & 0 deletions src/app/components/settings/settings.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@ <h2 header>Basic settings</h2>
<kw-card>
<h2 header>Export</h2>
<ng-container body>
<kw-card-section-title>Export everything</kw-card-section-title>
<p>This will export everything, all tracked times, all your settings.</p>
<div class="mt-4">
<button (click)="export()" class="kw-button">Export</button>
</div>
<kw-card-section-title class="mt-8">CSV Export</kw-card-section-title>
<p>This will export your times as CSV.</p>
<div class="mt-4 space-x-4">
<button (click)="exportCSV(7)" class="kw-button">7 Days</button>
<button (click)="exportCSV(14)" class="kw-button">14 Days</button>
<button (click)="exportCSV(30)" class="kw-button">30 Days</button>
</div>
</ng-container>
</kw-card>

Expand Down
39 changes: 38 additions & 1 deletion src/app/components/settings/settings.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ 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';
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',
Expand All @@ -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<void> {
const blob = await this.databaseService.exportToBlob();
await this.tauriService.save(blob, `KuwakaWakati-${dateTimeToLocaleData(DateTime.now())}.json`);
}

protected async exportCSV(days: number): Promise<void> {
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<void> {
if (!this.fileControl.value) {
return;
Expand Down
4 changes: 2 additions & 2 deletions src/app/services/time-tracking/time.table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class TimeTable implements DatabaseTable<TimeEntry> {

todayGroup$(): Observable<TimeEntryGroup> {
const todayDate = todayDateMilliseconds();
return this.groupByDay$(todayDate, todayDate + 1).pipe(
return this.groupByDay$(todayDate, todayDate).pipe(
map(([today]) => {
if (!today) {
return {
Expand All @@ -61,7 +61,7 @@ export class TimeTable implements DatabaseTable<TimeEntry> {
}

private async items(fromTimestamp: Milliseconds = 0, toTimestamp: Milliseconds = Number.MAX_SAFE_INTEGER): Promise<TimeEntryWithDuration[]> {
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;
Expand Down

0 comments on commit 440bb12

Please sign in to comment.