diff --git a/src/js/src/lib/action/tracker-action.ts b/src/js/src/lib/action/tracker-action.ts index d6beae4..73ece0a 100644 --- a/src/js/src/lib/action/tracker-action.ts +++ b/src/js/src/lib/action/tracker-action.ts @@ -1,3 +1,4 @@ +import { ApiTrackerConnector } from "../api/api"; import { KimaiApi } from "../api/kimai-api"; import { KimaiApiTrackerConnector } from "../api/kimai-api-tracker-connector"; import { ActionKey, StateKey } from "../constants"; @@ -5,6 +6,8 @@ import { Store } from "../store/store"; import { Tracker, TrackerEvent } from "../tracker"; import { AppState } from "../types"; +const connectors = new Map(); + export function initTrackerAction(store: Store) { const trackerAction = new Action(ActionKey.track); @@ -15,6 +18,7 @@ export function initTrackerAction(store: Store) { } const tracker = Tracker.get(context)!; tracker.settings = settings; + tracker.dispatchEvent(new Event(TrackerEvent.requestWorkedToday)); } ); @@ -23,7 +27,10 @@ export function initTrackerAction(store: Store) { if (!Tracker.has(context)) { const tracker = Tracker.create(context, false); const api = await getApi(); - new KimaiApiTrackerConnector(api, store).connect(tracker); + const connector = new KimaiApiTrackerConnector(api, store).connect( + tracker + ); + connectors.set(context, connector); $SD.getSettings(context); } }); diff --git a/src/js/src/lib/api/api.ts b/src/js/src/lib/api/api.ts index 855060e..5a89e34 100644 --- a/src/js/src/lib/api/api.ts +++ b/src/js/src/lib/api/api.ts @@ -1,3 +1,6 @@ +import { Tracker } from "../tracker"; +import { BackendProvider } from "../types"; + export type ApiResponse = | { success: true; @@ -21,6 +24,11 @@ export type Category = { name: string; }; +export interface ApiTrackerConnector { + backendProvider: BackendProvider; + connect: (tracker: Tracker) => void; +} + export async function tryFetch( url: string, options: RequestInit // eslint-disable-line diff --git a/src/js/src/lib/api/kimai-api-tracker-connector.ts b/src/js/src/lib/api/kimai-api-tracker-connector.ts index e30aa3c..49efe13 100644 --- a/src/js/src/lib/api/kimai-api-tracker-connector.ts +++ b/src/js/src/lib/api/kimai-api-tracker-connector.ts @@ -2,55 +2,86 @@ import { AppEvent, StateKey } from "../constants"; import { Store } from "../store/store"; import { Tracker, TrackerEvent } from "../tracker"; import { AppState, KimaiBackendProviderPluginConfig } from "../types"; +import { ApiTrackerConnector } from "./api"; import { KimaiApi } from "./kimai-api"; -export class KimaiApiTrackerConnector { +export class KimaiApiTrackerConnector implements ApiTrackerConnector { #api: KimaiApi; #store: Store; + #tracker!: Tracker; + #bound = { + onStart: this.onStart.bind(this), + onStop: this.onStop.bind(this), + onRequestWorkedToday: this.onRequestWorkedToday.bind(this), + }; + + backendProvider = "kimai" as const; constructor(api: KimaiApi, store: Store) { this.#api = api; this.#store = store; } - connect(tracker: Tracker) { - tracker.addEventListener(TrackerEvent.start, async () => { - const response = await this.#api.startTracking(this.settings(tracker)!); + async onStart() { + const response = await this.#api.startTracking( + this.settings(this.#tracker)! + ); + if (!response.success) { + EventEmitter.emit(AppEvent.actionAlert, this.#tracker.context); + console.error("Could not start tracking"); + return; + } + EventEmitter.emit(AppEvent.actionSuccess, this.#tracker.context); + this.#store.patchState({ + [StateKey.currentEvent]: response.body, + }); + } + + async onStop() { + const event = await this.#store.once(StateKey.currentEvent); + if (typeof event?.id === "number") { + const response = await this.#api.stopTracking(event?.id); if (!response.success) { - EventEmitter.emit(AppEvent.actionAlert, tracker.context); - console.error("Could not start tracking"); + EventEmitter.emit(AppEvent.actionAlert, this.#tracker.context); + console.error("Could not stop tracking"); return; } - EventEmitter.emit(AppEvent.actionSuccess, tracker.context); - this.#store.patchState({ - [StateKey.currentEvent]: response.body, - }); - }); + EventEmitter.emit(AppEvent.actionSuccess, this.#tracker.context); + this.#tracker.dispatchEvent(new Event(TrackerEvent.requestWorkedToday)); // Prevent inconsistencies between local and persisted data + } else { + throw new Error("Cannot stop tracker. ID is undefined"); + } + this.#tracker.reset(); + } - tracker.addEventListener(TrackerEvent.stop, async () => { - const event = await this.#store.once(StateKey.currentEvent); - if (typeof event?.id === "number") { - const response = await this.#api.stopTracking(event?.id); - if (!response.success) { - EventEmitter.emit(AppEvent.actionAlert, tracker.context); - console.error("Could not stop tracking"); - return; - } - EventEmitter.emit(AppEvent.actionSuccess, tracker.context); - tracker.dispatchEvent(new Event(TrackerEvent.requestWorkedToday)); // Prevent inconsistencies between local and persisted data - } else { - throw new Error("Cannot stop tracker. ID is undefined"); - } - tracker.reset(); + async onRequestWorkedToday() { + this.#tracker.workedToday = await this.getWorkedToday({ + projectId: this.settings(this.#tracker)!.projectId, + activityId: this.settings(this.#tracker)!.activityId, }); + this.#tracker.render(); + } - tracker.addEventListener(TrackerEvent.requestWorkedToday, async () => { - tracker.workedToday = await this.getWorkedToday({ - projectId: this.settings(tracker)!.projectId, - activityId: this.settings(tracker)!.activityId, - }); - tracker.render(); - }); + connect(tracker: Tracker) { + this.#tracker = tracker; + + tracker.addEventListener(TrackerEvent.start, this.#bound.onStart); + tracker.addEventListener(TrackerEvent.stop, this.#bound.onStop); + tracker.addEventListener( + TrackerEvent.requestWorkedToday, + this.#bound.onRequestWorkedToday + ); + + return this; + } + + disconnect() { + this.#tracker.removeEventListener(TrackerEvent.start, this.#bound.onStart); + this.#tracker.removeEventListener(TrackerEvent.stop, this.#bound.onStop); + this.#tracker.removeEventListener( + TrackerEvent.requestWorkedToday, + this.#bound.onRequestWorkedToday + ); } settings(tracker: Tracker): KimaiBackendProviderPluginConfig | undefined {