UNPKG

@codebynithin/call-history

Version:
303 lines (240 loc) 7.7 kB
const { format, subDays, isWithinInterval, parse } = require('date-fns'); const { MultiSelect } = require('enquirer'); const fs = require('fs'); const os = require('os'); const path = require('path'); const DAYS_OF_WEEK = new Set([ 'Today', 'Yesterday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', ]); function roundTimeTo5(timeStr) { if (!timeStr?.includes('m') && !timeStr?.includes('h')) { timeStr = `0m ${timeStr}`; } if (!timeStr?.includes('h')) { timeStr = `0h ${timeStr}`; } const sanitizedTime = timeStr.replace(/[^0-9\s]/g, ''); const [hours, minutes, seconds] = sanitizedTime.split(' ').map(Number); const totalSeconds = (hours || 0) * 60 * 60 + (minutes || 0) * 60 + (seconds || 0); const roundedSeconds = 300 * Math.max(totalSeconds / 300); const roundedMinutes = Math.floor(roundedSeconds / 60); return Math.round((roundedMinutes + 1) / 5) * 5; } function getLastDayOfWeek(inputString) { const currentDate = new Date(); let targetDate = currentDate; switch (inputString.toLowerCase()) { case 'today': targetDate = currentDate; break; case 'yesterday': targetDate = subDays(currentDate, 1); break; default: targetDate = currentDate; while (format(targetDate, 'EEEE').toLowerCase() !== inputString.toLowerCase()) { targetDate = subDays(targetDate, 1); } } return targetDate; } function formatCalls(acc, curr, filter) { // eslint-disable-next-line @typescript-eslint/no-unused-vars let [person, direction, day, time] = curr.split(/\n/g); if (!day || !time) return; const formattedTime = roundTimeTo5(time); if (!formattedTime) return; person = person.split(', ').sort().join(','); day = normalizeDay(day); const hasDateFilter = filter.from && filter.to; const passesFilter = !hasDateFilter || isWithinInterval(new Date(day), { start: new Date(filter.from), end: new Date(filter.to), }); if (passesFilter) { acc.add({ day, person, time: formattedTime }); } } function normalizeDay(day) { if ((day.length === 5 && day !== 'Today') || day.includes(' PM') || day.includes(' AM')) { return format(new Date(), 'yyyy-MM-dd'); } if (day.includes('/')) { const year = day.split('/')[2]; const dateFormat = year?.length === 2 ? 'dd/MM/yy' : 'dd/MM/yyyy'; const parsedDate = parse(day, dateFormat, new Date()); if (parsedDate instanceof Date && !isNaN(parsedDate.getTime())) { return parsedDate.toISOString().split('T')[0]; } } if (DAYS_OF_WEEK.has(day)) { return format(getLastDayOfWeek(day), 'yyyy-MM-dd'); } return day; } function getItemsFromContenWithoutLineBreaks(content) { const lines = content.split('\n'); const resp = []; for (let i = 0; i < lines.length; i += 3) { const hasExtraLine = lines[i + 3] && !isNaN(lines[i + 3].charAt(0)) && lines[i + 3].charAt(0) !== ' '; if (hasExtraLine) { const item = [lines[i], lines[i + 1], lines[i + 2], lines[i + 3]].join('\n'); resp.push(item); i++; } else if (i + 2 < lines.length) { const item = [lines[i], lines[i + 1], lines[i + 2]].join('\n'); resp.push(item); } } return resp; } async function filterCalls(values) { const filter = {}; const keyMap = { from: 'from', to: 'to' }; if (values?.length) { for (const item of values) { let [key, ...itemValues] = item.split(' '); const itemValue = itemValues.join(' '); if (key.charAt(0) === '-') { key = key.substring(1); } if (keyMap[key]) { filter[keyMap[key]] = new Date(itemValue).toISOString().split('T')[0]; } else { filter.task = itemValue; } } } const filename = 'teams-call.txt'; const filePath = path.join(os.homedir(), 'Desktop/'); let content; let start = false; let allTextIdentified = false; let output; try { content = fs.readFileSync(`${filePath}${filename}`, 'utf8'); } catch (err) { console.error(`${filename} file missing or it's empty in your desktop, please try again.`); fs.appendFileSync(filename, filePath, (err) => { if (err) { throw err; } console.log('String appended to file!'); }); process.exit(1); } content = content.replace(/\n{3,}/g, '\n\n'); const calls = content?.split(/\n\n/g).reduce((acc, curr) => { if (curr.includes('Contact groups') || curr.includes('Speed dial')) { if (curr.length > 20) { getItemsFromContenWithoutLineBreaks(curr).forEach((item) => { formatCalls(acc, item, filter); }); } start = false; return acc; } if (curr === 'All') { allTextIdentified = true; return acc; } if (allTextIdentified && curr !== 'Missed') { start = true; allTextIdentified = false; } if (curr.includes('Voicemail')) { start = true; } if (start) { formatCalls(acc, curr, filter); } return acc; }, new Set()); const choices = Array.from(calls).map((item) => ({ name: `${item.day} - ${item.person} - ${item.time}`, value: item, })); const prompt = new MultiSelect({ name: 'calls', message: 'Select required calls', choices, initial: choices.map((_, index) => index), hint: '(Use <space> to select, <a> to toggle all, <i> to invert selection)', }); try { const answer = await prompt.run(); output = choices.reduce((acc, { value, name }) => { if (answer.includes(name)) { if (!acc[value.day]) { acc[value.day] = { [value.person]: { duration: 0, remarks: '', remarksArray: [] } }; } if (!acc[value.day][value.person]) { acc[value.day][value.person] = { duration: 0, remarks: '', remarksArray: [] }; } if (acc[value.day][value.person].remarksArray?.length) { acc[value.day][value.person].remarksArray.push(`${value.time}m`); } else { acc[value.day][value.person].remarksArray.push(`${value.person} ${value.time}m`); } acc[value.day][value.person].duration += +value.time; acc[value.day][value.person].remarks = acc[value.day][value.person].remarksArray.join(', '); } return acc; }, {}); joinCalls(output, filter.task); } catch (error) { console.error(error); } } function joinCalls(entriesByDate, task) { let output = ''; for (const [date, persons] of Object.entries(entriesByDate)) { const allRemarks = []; let totalDuration = 0; for (const [personName, { duration, remarksArray }] of Object.entries(persons)) { totalDuration += duration; let firstName = personName; if (!personName.includes(',')) { firstName = personName.split(' ')[0]; } allRemarks.push( `${firstName} ${duration}m${remarksArray?.length ? ` (${remarksArray.join(', ')})` : ''}`, ); } output += `timectl add -dt ${date} -t ${task || '<task id>'} -w Internal calls -du ${totalDuration} -r "${allRemarks.join(', ')}"\n`; } console.log(output); } function removeEmpty(obj) { for (let [key, val] of Object.entries(obj)) { if (val && typeof val === 'object') { removeEmpty(val); if (!(Object.keys(val).length || val instanceof Date)) { delete obj[key]; } } else { if (typeof val === 'string') { val = val.trim(); } if (val === null || val === undefined || val === '') { delete obj[key]; } else { obj[key] = val; } } } return obj; } filterCalls(); module.exports = { filterCalls, removeEmpty };