Split code more into modules

This commit is contained in:
Marko Korhonen 2023-11-22 22:13:00 +02:00
parent 3246815997
commit b88e19e311
Signed by: FunctionalHacker
GPG key ID: A7F78BCB859CD890
5 changed files with 206 additions and 157 deletions

148
src/input.ts Normal file
View file

@ -0,0 +1,148 @@
import chalk from 'chalk';
import { Duration } from 'dayjs/plugin/duration';
import getConfig from './config';
import { parseDuration, parseTimestamp } from './parse';
import * as readline from 'readline/promises';
import { formatDuration, formatTime } from './format';
import dayjs, { Dayjs } from 'dayjs';
import { WtcPromptResult } from './types/WtcPromptResult';
import duration from 'dayjs/plugin/duration.js';
dayjs.extend(duration);
const { error } = console;
const input = async (): Promise<WtcPromptResult> => {
const { defaults, askInput } = getConfig();
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
let startedAt: Dayjs | undefined = undefined;
let stoppedAt: Dayjs | undefined = undefined;
let stoppedWorking = false;
try {
// Get work day duration
let workDayDuration: Duration | undefined = undefined;
if (askInput.workDayLength) {
const durationAnswer = await rl.question(
`How long is your work day today, excluding the lunch break? [${formatDuration(
defaults.workDayDuration,
true,
)}] `,
);
if (durationAnswer !== '') {
workDayDuration = parseDuration(durationAnswer);
if (workDayDuration.asMinutes() <= 0) {
error(
chalk.red(
`Failed to parse ${durationAnswer} to duration, using default work day duration ${formatDuration(
defaults.workDayDuration,
true,
)}`,
),
);
workDayDuration = undefined;
}
}
}
if (!workDayDuration) {
workDayDuration = defaults.workDayDuration;
}
if (askInput.startTime) {
const startTimeAnswer = await rl.question(
`What time did you start work today? [${formatTime(defaults.startTime)}] `,
);
if (startTimeAnswer !== '') {
startedAt = parseTimestamp(startTimeAnswer);
if (!startedAt.isValid()) {
error(
chalk.red(
`Failed to parse ${startTimeAnswer} to time, using default start time ${formatTime(
defaults.startTime,
)}`,
),
);
}
}
}
if (!startedAt?.isValid()) {
startedAt = defaults.startTime;
}
if (askInput.stopTime) {
const stoppedAnswer = await rl.question(
`What time did you stop working? [${formatTime(defaults.stopTime)}] `,
);
if (stoppedAnswer !== '') {
stoppedWorking = true;
stoppedAt = parseTimestamp(stoppedAnswer);
if (!stoppedAt.isValid()) {
error(`Failed to parse ${stoppedAnswer} to time, using current time`);
stoppedAt = dayjs();
}
}
}
if (!stoppedAt) {
stoppedAt = defaults.stopTime;
}
if (stoppedAt.isSame(startedAt) || stoppedAt.isBefore(startedAt)) {
error(
chalk.red(
`Start time (${formatTime(startedAt)}) needs to be before stop time (${formatTime(
stoppedAt,
)}). Exiting`,
),
);
process.exit(1);
}
let worked = dayjs.duration(stoppedAt.diff(startedAt));
const hadLunch =
askInput.hadLunch && (await rl.question('Did you have a lunch break? [Y/n] ')).toLowerCase() !== 'n';
if (hadLunch) {
worked = worked.subtract(defaults.lunchBreakDuration);
}
// Calculate unlogged time
let loggedAnswer = await rl.question('How many hours did you log already? [00:00] ');
if (loggedAnswer === '') {
loggedAnswer = '00:00';
}
const logged = parseDuration(loggedAnswer);
const unLogged = worked.subtract(logged);
const workLeft = workDayDuration.subtract(worked);
let workLeftMinutes = workLeft.asMinutes();
let workedOverTime: Duration | undefined;
if (workLeftMinutes < 0) {
workedOverTime = dayjs.duration(Math.round(workLeftMinutes * -1), 'minutes');
}
return {
logged,
unLogged,
startedAt,
stoppedAt,
stoppedWorking,
hadLunch,
worked,
workLeft,
};
} finally {
rl.close();
}
};
export default input;

View file

@ -1,163 +1,9 @@
import chalk from 'chalk';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import dayjs, { Dayjs } from 'dayjs';
import * as readline from 'readline/promises';
import { formatDuration, formatTime, formatTimestamp, getHoursRoundedStr } from './format.js';
import duration, { Duration } from 'dayjs/plugin/duration.js';
import { parseDuration, parseTimestamp } from './parse.js';
import getConfig from './config.js';
dayjs.extend(duration);
const { log, error } = console;
const ui = async () => {
const { defaults, askInput } = getConfig();
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
let startedAt: Dayjs | undefined = undefined;
let stoppedAt: Dayjs | undefined = undefined;
let stoppedWorking = false;
try {
// Get work day duration
let workDayDuration: Duration | undefined = undefined;
if (askInput.workDayLength) {
const durationAnswer = await rl.question(
`How long is your work day today, excluding the lunch break? [${formatDuration(
defaults.workDayDuration,
true,
)}] `,
);
if (durationAnswer !== '') {
workDayDuration = parseDuration(durationAnswer);
if (workDayDuration.asMinutes() <= 0) {
error(
chalk.red(
`Failed to parse ${durationAnswer} to duration, using default work day duration ${formatDuration(
defaults.workDayDuration,
true,
)}`,
),
);
workDayDuration = undefined;
}
}
}
if (!workDayDuration) {
workDayDuration = defaults.workDayDuration;
}
if (askInput.startTime) {
const startTimeAnswer = await rl.question(
`What time did you start work today? [${formatTime(defaults.startTime)}] `,
);
if (startTimeAnswer !== '') {
startedAt = parseTimestamp(startTimeAnswer);
if (!startedAt.isValid()) {
error(
chalk.red(
`Failed to parse ${startTimeAnswer} to time, using default start time ${formatTime(
defaults.startTime,
)}`,
),
);
}
}
}
if (!startedAt?.isValid()) {
startedAt = defaults.startTime;
}
if (askInput.stopTime) {
const stoppedAnswer = await rl.question(
`What time did you stop working? [${formatTime(defaults.stopTime)}] `,
);
if (stoppedAnswer !== '') {
stoppedWorking = true;
stoppedAt = parseTimestamp(stoppedAnswer);
if (!stoppedAt.isValid()) {
error(`Failed to parse ${stoppedAnswer} to time, using current time`);
stoppedAt = dayjs();
}
}
}
if (!stoppedAt) {
stoppedAt = defaults.stopTime;
}
if (stoppedAt.isSame(startedAt) || stoppedAt.isBefore(startedAt)) {
error(
chalk.red(
`Start time (${formatTime(startedAt)}) needs to be before stop time (${formatTime(
stoppedAt,
)}). Exiting`,
),
);
process.exit(1);
}
let worked = dayjs.duration(stoppedAt.diff(startedAt));
const hadLunch =
askInput.hadLunch && (await rl.question('Did you have a lunch break? [Y/n] ')).toLowerCase() !== 'n';
if (hadLunch) {
worked = worked.subtract(defaults.lunchBreakDuration);
}
// Calculate unlogged time
let loggedAnswer = await rl.question('How many hours did you log already? [00:00] ');
if (loggedAnswer === '') {
loggedAnswer = '00:00';
}
const logged = parseDuration(loggedAnswer);
const unLogged = worked.subtract(logged);
// Log result
log();
log('Started working at:', formatTimestamp(startedAt));
log((stoppedWorking ? 'Stopped working' : 'Hours calculated') + ' at:', formatTimestamp(stoppedAt));
log('Worked today:', chalk.green(formatDuration(worked)), chalk.yellow(getHoursRoundedStr(worked)));
if (unLogged.asMinutes() == 0) {
log('Unlogged today:', chalk.green('none'));
} else if (unLogged.asMinutes() > 0) {
log('Unlogged today:', chalk.red(formatDuration(unLogged)), chalk.yellow(getHoursRoundedStr(unLogged)));
} else if (unLogged.asMinutes() < 0) {
log(
chalk.red(`You have logged ${formatDuration(unLogged)} more than you worked today!`),
chalk.yellow(getHoursRoundedStr(unLogged)),
);
}
const workLeft = workDayDuration.subtract(worked);
const workLeftMinutes = workLeft.asMinutes();
if (workLeftMinutes > 0) {
log('You still have to work', chalk.green(formatDuration(workLeft)), 'more today');
} else if (workLeft.asMinutes() < 0) {
log(
'You worked',
chalk.green(
formatDuration(dayjs.duration(Math.round(workLeftMinutes * -1), 'minutes')),
'overtime today',
),
);
}
} finally {
rl.close();
}
};
import ui from './ui.js';
// Process args. Yargs will exit if it detects help or version
yargs(hideBin(process.argv)).usage('Work time calculator').alias('help', 'h').alias('version', 'v').argv;
// Run UI if help or version is not prompted
ui();

32
src/output.ts Normal file
View file

@ -0,0 +1,32 @@
import chalk from 'chalk';
import { formatDuration, formatTimestamp, getHoursRoundedStr } from './format';
import { WtcPromptResult } from './types/WtcPromptResult';
const { log } = console;
const output = (result: WtcPromptResult) => {
const { startedAt, stoppedAt, stoppedWorking, worked, unLogged, workLeft, workedOverTime } = result;
log();
log('Started working at:', formatTimestamp(startedAt));
log((stoppedWorking ? 'Stopped working' : 'Hours calculated') + ' at:', formatTimestamp(stoppedAt));
log('Worked today:', chalk.green(formatDuration(worked)), chalk.yellow(getHoursRoundedStr(worked)));
if (unLogged.asMinutes() == 0) {
log('Unlogged today:', chalk.green('none'));
} else if (unLogged.asMinutes() > 0) {
log('Unlogged today:', chalk.red(formatDuration(unLogged)), chalk.yellow(getHoursRoundedStr(unLogged)));
} else if (unLogged.asMinutes() < 0) {
log(
chalk.red(`You have logged ${formatDuration(unLogged)} more than you worked today!`),
chalk.yellow(getHoursRoundedStr(unLogged)),
);
}
if (workLeft.asMinutes() > 0) {
log('You still have to work', chalk.green(formatDuration(workLeft)), 'more today');
} else if (workedOverTime) {
log('You worked', chalk.green(formatDuration(workedOverTime), 'overtime today'));
}
};
export default output;

View file

@ -0,0 +1,14 @@
import { Dayjs } from 'dayjs';
import { Duration } from 'dayjs/plugin/duration';
export interface WtcPromptResult {
startedAt: Dayjs;
stoppedAt: Dayjs;
stoppedWorking: boolean;
logged: Duration;
unLogged: Duration;
hadLunch: boolean;
worked: Duration;
workLeft: Duration;
workedOverTime?: Duration;
}

9
src/ui.ts Normal file
View file

@ -0,0 +1,9 @@
import input from './input.js';
import output from './output.js';
const ui = async () => {
const result = await input();
output(result);
};
export default ui;