Skip to content

Commit

Permalink
Merge pull request #7 from Tech-Nest-Ventures/5-error-sending-email-t…
Browse files Browse the repository at this point in the history
…o-backend

5 error sending email to backend
  • Loading branch information
timeowilliams authored Sep 25, 2024
2 parents abac7c7 + f75b119 commit 06ccf65
Show file tree
Hide file tree
Showing 15 changed files with 627 additions and 259 deletions.
6 changes: 3 additions & 3 deletions electron.vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ dotenv.config()

export default defineConfig({
main: {
plugins: [externalizeDepsPlugin(), bytecodePlugin()],
plugins: [externalizeDepsPlugin()],
build: {
outDir: 'out/main',
rollupOptions: {
Expand All @@ -30,13 +30,13 @@ export default defineConfig({
}
},
preload: {
plugins: [externalizeDepsPlugin(), bytecodePlugin()],
plugins: [externalizeDepsPlugin()],
build: {
outDir: 'out/preload',
rollupOptions: {
external: ['electron'],
output: {
format: 'cjs'
format: 'es'
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"electron-vite": "^2.3.0",
"node-addon-api": "^8.1.0",
"node-schedule": "^2.1.1",
"solid-js": "^1.8.23",
"solid-js": "^1.9.1",
"tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7",
"url": "^0.11.4"
Expand All @@ -50,7 +50,7 @@
"@electron-toolkit/eslint-config-ts": "^2.0.0",
"@electron-toolkit/tsconfig": "^1.0.1",
"@playwright/test": "^1.47.2",
"@types/node": "^22.6.1",
"@types/node": "^22.7.0",
"autoprefixer": "^10.4.20",
"electron": "^32.1.2",
"electron-builder": "^25.0.5",
Expand All @@ -68,7 +68,7 @@
"typescript": "^5.6.2",
"valibot": "^0.42.1",
"vinxi": "^0.4.3",
"vite": "^5.4.7",
"vite": "^5.4.8",
"vite-plugin-solid": "^2.10.2"
},
"pnpm": {
Expand Down
619 changes: 445 additions & 174 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

8 changes: 0 additions & 8 deletions src/main/config.ts

This file was deleted.

58 changes: 44 additions & 14 deletions src/main/emailService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { TypedStore } from './index'
import { app } from 'electron'
import path from 'path'
import fs from 'fs'
import dotenv from 'dotenv'
dotenv.config()

interface TopSite {
url: string
timeSpent: number
timeSpent: string
}

export class EmailService {
Expand All @@ -29,6 +31,11 @@ export class EmailService {
schedule.scheduleJob('59 23 * * *', () => {
this.sendDailySummary()
})

if (!app.isPackaged) {
// For testing, send the email immediately
this.sendDailySummary()
}
}

private async sendDailySummary(): Promise<void> {
Expand All @@ -45,10 +52,13 @@ export class EmailService {
const emailBody = this.composeEmailBody(deepWorkHours, topSites)

try {
const response = await axios.post('http://localhost:5000/api/v1/emails/send-email', {
emailBody,
userEmail: this.userEmail
})
const response = await axios.post(
`${process.env.VITE_SERVER_URL_PROD}/api/v1/emails/send-email`,
{
emailBody,
userEmail: this.userEmail
}
)

console.log('Email sent successfully:', response.data)
} catch (error) {
Expand All @@ -73,31 +83,43 @@ export class EmailService {
}

try {
const response = await axios.post('http://localhost:5000/api/v1/emails/send-email', {
emailBody,
userEmail: this.userEmail
})
const response = await axios.post(
`${process.env.VITE_SERVER_URL_PROD}/api/v1/emails/send-email`,
{
emailBody,
userEmail: this.userEmail
}
)

console.log('Response from backend email send:', response.data)
} catch (error) {
console.error('Error sending email to backend:', error)
}
}

private formatTime(timeSpentInMinutes: number): string {
if (timeSpentInMinutes >= 60) {
const hours = Math.floor(timeSpentInMinutes / 60)
const minutes = timeSpentInMinutes % 60
return `${hours}h ${minutes}m`
}
return `${timeSpentInMinutes} minutes`
}

public composeEmailBody(deepWorkHours: number, topSites: TopSite[]): string {
return `
<div style="font-family: Arial, sans-serif; color: #fff; background-color: #000; padding: 20px; border-radius: 8px; max-width: 80%; margin: auto;">
<div style="display: flex; align-items: center; margin-bottom: 20px;">
<h1 style="color: #ecf0f1; margin: 0; font-style: italic; font-family: 'Montserrat', sans-serif;">deepFocus</h1>
</div>
<p style="font-size: 16px; margin-bottom: 20px;">Total Deep Work Hours: <strong>${deepWorkHours}</strong></p>
<h3 style="color: #ecf0f1; border-bottom: 2px solid #ecf0f1; padding-bottom: 10px; margin-top: 30px;">Top 5 Sites Visited</h3>
<h3 style="color: #ecf0f1; border-bottom: 2px solid #ecf0f1; padding-bottom: 10px; margin-top: 30px;">Top 3 Sites Visited</h3>
<ul style="list-style-type: none; padding-left: 0;">
${topSites
.map(
(site) => `
<li style="background-color: #333; margin-bottom: 10px; padding: 10px; border-radius: 4px; border: 1px solid #555; color: #fff;">
<strong>${site.url}</strong>: ${site.timeSpent} minutes
<strong>${site.url}</strong>: ${site.timeSpent}
</li>
`
)
Expand All @@ -115,18 +137,26 @@ export class EmailService {
.filter((tracker) => !unproductiveSites?.includes(tracker.url))
.reduce((total, tracker) => total + tracker.timeSpent, 0)

// Convert ms to hours and return rounded to 1 decimal place
return parseFloat((productiveTime / (1000 * 60 * 60)).toFixed(1))
}

private async getTopSites(): Promise<TopSite[]> {
const siteTimeTrackers = this.store.get('siteTimeTrackers', [])

const getTrimmedTitle = (title: string): string => {
const maxLength = 50
return title.length > maxLength ? title.slice(0, maxLength) + '...' : title
}

// Filter out trackers with zero time, then sort and slice to get top 3
const topSites = siteTimeTrackers
.filter((tracker) => tracker.timeSpent > 0)
.sort((a, b) => b.timeSpent - a.timeSpent)
.slice(0, 3)
.slice(0, 3) // Get top 3
.map((tracker) => ({
url: tracker.url,
timeSpent: Math.round(tracker.timeSpent / (1000 * 60))
url: tracker.url || getTrimmedTitle(tracker.title || 'Unknown Title'),
timeSpent: this.formatTime(Math.round(tracker.timeSpent / (1000 * 60))) // Convert to minutes and format
}))

return topSites
Expand Down
81 changes: 47 additions & 34 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,30 @@ import dayjs from 'dayjs'
import fs from 'fs'
import dotenv from 'dotenv'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
// const { activeWindow } = await import('get-windows')
const { activeWindow } = await import('@deepfocus/get-windows')
import Store from 'electron-store'

import { EmailService } from './emailService'
import { StoreSchema, SiteTimeTracker, ExtendedResult } from './types'
import { getUrlFromResult, formatTime, updateSiteTimeTracker } from './productivityUtils'
import {
getUrlFromResult,
formatTime,
updateSiteTimeTracker,
getBaseURL
} from './productivityUtils'

export interface TypedStore extends Store<StoreSchema> {
get<K extends keyof StoreSchema>(key: K): StoreSchema[K]
get<K extends keyof StoreSchema>(key: K, defaultValue: StoreSchema[K]): StoreSchema[K]
set(key: string, value: any): void
delete<K extends keyof StoreSchema>(key: K): void
clear(): void
}

const store = new Store<StoreSchema>() as TypedStore
let currentSiteTimeTrackers: SiteTimeTracker[] = []

setupEnvironment()

const isProduction = process.env.NODEENV === 'production'
console.log('isProduction?', isProduction)
console.log('email', process.env.EMAIL)
console.log('API_BASE_URL', process.env.VITE_SERVER_URL_PROD)

const emailService = new EmailService(process.env.EMAIL || '', store)

// Initialize environment variables based on the environment
Expand Down Expand Up @@ -75,25 +74,30 @@ function resetCounters(type: 'daily' | 'weekly') {
if (type === 'daily') {
console.log('Resetting Daily Trackers')
currentSiteTimeTrackers.forEach((tracker) => (tracker.timeSpent = 0))
console.log('currentSiteTimeTrackers after daily reset', currentSiteTimeTrackers)
console.log('store.get(lastResetDate)', store.get('lastResetDate'))
store.set('lastResetDate', dayjs().format('YYYY-MM-DD'))
} else if (type === 'weekly') {
console.log('Resetting Weekly Trackers')
currentSiteTimeTrackers.length = 0
currentSiteTimeTrackers = []
}
store.set('siteTimeTrackers', currentSiteTimeTrackers)
}

// Periodic saving of time trackers
function setupPeriodicSave() {
setInterval(() => store.set('siteTimeTrackers', currentSiteTimeTrackers), 5 * 60 * 1000)
console.log('setupPeriodicSave', store.get('siteTimeTrackers'))
}

// Monitor system idle time and user activity
function startActivityMonitoring() {
setInterval(async () => {
const idleTime = powerMonitor.getSystemIdleTime()
if (idleTime > 60) return console.log(`System idle for ${idleTime} seconds.`)

if (idleTime > 60) {
console.log(`System idle for ${idleTime} seconds.`)
return
}
try {
const windowInfo = await activeWindow()
if (windowInfo && windowInfo!.platform === 'macos') {
Expand All @@ -107,14 +111,16 @@ function startActivityMonitoring() {
} catch (error) {
console.error('Error getting active window:', error)
}
}, 30000) // change back to 600000
}, 60000)
}

// Process activity data from active window
function processActivityData(_windowInfoData: ExtendedResult | undefined) {
if (!_windowInfoData) return

if (_windowInfoData?.siteTimeTracker) {
console.log(
`Time spent on ${_windowInfoData.siteTimeTracker.title}: ${formatTime(_windowInfoData.siteTimeTracker.timeSpent)}`
`Time spent on ${_windowInfoData.siteTimeTracker.title}: ${formatTime(_windowInfoData.siteTimeTracker.timeSpent)}. URL is ${_windowInfoData?.url ? getBaseURL(_windowInfoData?.url) : `not defined`}`
)
console.log(
`Last active timestamp: ${new Date(_windowInfoData.siteTimeTracker.lastActiveTimestamp).toISOString()}`
Expand All @@ -139,9 +145,6 @@ async function createWindow(): Promise<BrowserWindow> {
mainWindow.on('ready-to-show', async () => {
console.log('ready-to-show')
mainWindow.show()
startActivityMonitoring()
currentSiteTimeTrackers = store.get('siteTimeTrackers', [])
emailService.scheduleEmailSend()
})

mainWindow.webContents.setWindowOpenHandler(({ url }) => {
Expand All @@ -165,32 +168,42 @@ app.whenReady().then(async () => {
console.log('ready!')
electronApp.setAppUserModelId('com.electron')

loadUserData()

const now = dayjs()
const lastResetDate = dayjs(store.get('lastResetDate'))

if (!lastResetDate.isSame(now, 'day') || now.diff(lastResetDate, 'hours') > 24) {
console.log('Missed daily reset from previous session, performing now.')
schedulerWorker.postMessage({ type: 'RESET_DAILY' })
}

await createWindow()
await createWindow().then(() => {
loadUserData()
handleDailyReset()
setupPeriodicSave()
setupIPCListeners()
})

setupPeriodicSave()
emailService.scheduleEmailSend()
})

function handleUserLogout() {
store.delete('user')
store.set('siteTimeTrackers', [])
schedulerWorker.postMessage({ type: 'RESET_TRACKERS' })
}
function setupIPCListeners() {
ipcMain.on('send-user-data', (event, user) => {
console.log('Received user data from frontend:', user, event.processId)
handleUserData(user)
const savedUser = store.get('user')
if (savedUser) {
startActivityMonitoring()
currentSiteTimeTrackers = store.get('siteTimeTrackers', [])
emailService.scheduleEmailSend()
}
})
ipcMain.on('test-email-send', async () => await emailService.testEmailSend())
ipcMain.on('logout-user', () => handleUserLogout())
})

function handleUserLogout() {
store.delete('user')
store.set('siteTimeTrackers', [])
schedulerWorker.postMessage({ type: 'RESET_TRACKERS' })
}
function handleDailyReset() {
const now = dayjs()
const lastResetDate = dayjs(store.get('lastResetDate'))
if (!lastResetDate.isSame(now, 'day') || now.diff(lastResetDate, 'hours') > 24) {
console.log('Missed daily reset from previous session, performing now.')
schedulerWorker.postMessage({ type: 'RESET_DAILY' })
}
}

app.on('before-quit', () => schedulerWorker.terminate())
Expand Down
Loading

0 comments on commit 06ccf65

Please sign in to comment.