diff --git a/CHANGELOG.md b/CHANGELOG.md index 7621777..bc68c91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## v1.7.0 - Add mode for viewing chart and stats relative to contract hours. +- Add loading indicator. ## v1.6.0 diff --git a/src/EventEmitter.ts b/src/EventEmitter.ts new file mode 100644 index 0000000..728baef --- /dev/null +++ b/src/EventEmitter.ts @@ -0,0 +1,13 @@ +export type EventHandler = (value: T) => void | Promise; + +export class EventEmitter { + private listeners: EventHandler[] = []; + + public addListener(l: EventHandler) { + this.listeners.push(l); + } + + public fire(value: T) { + this.listeners.forEach((h) => h(value)); + } +} diff --git a/src/content/add-billability-chart.ts b/src/content/add-billability-chart.ts index c4a0ecf..abcc24b 100644 --- a/src/content/add-billability-chart.ts +++ b/src/content/add-billability-chart.ts @@ -4,7 +4,6 @@ import { toIsoDate } from '../date'; import { endOfWeek, getWeek, startOfWeek, subWeeks } from 'date-fns'; import { calculateTimeStats } from './stats'; import { getSettings, updateSettings } from './settings'; -import { render } from './index'; const api = new TimeChimpApi(); @@ -39,10 +38,12 @@ async function doAddBillabilityChart(date: Date, user: User) { chartContainer = createBillabilityCard(addTimePanel); } + updateLoadingState(true); const [times, company] = await Promise.all([ getTimes(user.id, date, GET_TIMES_WEEKS), api.getCompany(), ]); + updateLoadingState(false); const settings = getSettings(); @@ -71,7 +72,15 @@ function createBillabilityCard(addTimePanel: Element) { const actions = document.createElement('div'); card.appendChild(actions); - actions.className = 'actions text-align-right'; + actions.className = 'actions'; + + const spinner = document.createElement('tc-spinner'); + actions.appendChild(spinner); + spinner.className = 'title-date-spinner'; + const spinnerIcon = document.createElement('i'); + spinner.appendChild(spinnerIcon); + spinnerIcon.id = 'billability-loading'; + spinnerIcon.className = 'fa fa-circle-o-notch fa-spin hidden'; const toggleViewBtn = document.createElement('button'); @@ -91,13 +100,21 @@ function createBillabilityCard(addTimePanel: Element) { relativeToContractHours: !getSettings().relativeToContractHours, }); setBtnText(); - render(); }); addTimePanel.appendChild(card); return chartContainer; } +function updateLoadingState(loading: boolean) { + const spinner = document.getElementById('billability-loading'); + if (spinner) { + loading + ? spinner.classList.remove('hidden') + : spinner.classList.add('hidden'); + } +} + /** * Gets times from TimeChimp for the given weeks in the past, and filters out the ones for the given user id. * Optionally a date can be provided, by default it will get times for the current date. diff --git a/src/content/index.ts b/src/content/index.ts index 56fe771..6596029 100644 --- a/src/content/index.ts +++ b/src/content/index.ts @@ -4,12 +4,13 @@ import { addBillabilityChart } from './add-billability-chart'; import { Message } from '../message'; import setDefaultOptions from 'date-fns/setDefaultOptions'; import { TimeChimpApi, User } from '../TimeChimpApi'; +import { settingsUpdateEvent } from './settings'; // Default date-fns options. setDefaultOptions({ // Weeks start on Monday. weekStartsOn: 1, - // Week number 1 should contain the 4th on January. + // Week number 1 should contain the 4th of January. firstWeekContainsDate: 4, }); @@ -18,6 +19,8 @@ const api = new TimeChimpApi(); let currentDate = new Date(); let currentUser: User | undefined; +settingsUpdateEvent.addListener(() => render()); + /** * Listens to incoming messages, and update the billability chart. */ @@ -31,7 +34,7 @@ chrome.runtime.onMessage.addListener(async (msg: Message) => { await render(msg.userName); }); -export async function render(userName?: string) { +async function render(userName?: string) { if (!currentUser || (userName && userName !== currentUser.userName)) { currentUser = await getUser(userName); } diff --git a/src/content/settings.ts b/src/content/settings.ts index 44e7f44..ffbfaa0 100644 --- a/src/content/settings.ts +++ b/src/content/settings.ts @@ -1,3 +1,5 @@ +import { EventEmitter } from '../EventEmitter'; + const STORAGE_KEY = 'tcbc-settings'; export interface Settings { @@ -10,6 +12,8 @@ const DEFAULT_SETTINGS: Settings = { relativeToContractHours: false, }; +export const settingsUpdateEvent = new EventEmitter(); + export function getSettings(): Settings { // Try to load the settings. if (!settings) { @@ -33,6 +37,7 @@ export function updateSettings(updates: Partial) { ...updates, }; saveSettings(); + settingsUpdateEvent.fire(); } function tryLoadSettings() { diff --git a/src/content/style.css b/src/content/style.css index 6941907..8b84c32 100644 --- a/src/content/style.css +++ b/src/content/style.css @@ -2,7 +2,9 @@ height: 350px; } -.billability-card > .actions > button { - margin-right: 20px; - margin-bottom: 20px; +.billability-card > .actions { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 20px 20px; }