'use strict'
import { Client, GatewayIntentBits } from 'discord.js'
import cron from 'node-cron'
import dotenv from 'dotenv'
import { getNumberEmoji, logger } from './utils.js'
import { createClient } from '@supabase/supabase-js'
dotenv.config()
if (!process.env.SUPABASE_URL || !process.env.SUPABASE_ANON_KEY) {
throw new Error('Missing Supabase environment variables')
}
const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
)
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
})
const botToken = process.env.DISCORD_BOT_TOKEN
const channelId = process.env.DISCORD_CHANNEL_ID
// Fetch tasks from Supabase.
async function fetchTasksFromSupabase() {
console.log('DEBUG: Fetching tasks from Supabase...')
const { data, error } = await supabase.from('tasks').select('*')
if (error) {
console.error('Error fetching tasks from Supabase:', error.message)
return []
}
console.log(`DEBUG: Retrieved ${data.length} tasks from Supabase.`)
return data
}
// Fetch users with their discord IDs from the database
async function fetchUserProfiles(userIds) {
if (!userIds || userIds.length === 0) return []
console.log('DEBUG: Fetching user profiles for IDs:', userIds)
// Query using user_id which should match the UUID from schedules
const { data, error } = await supabase
.from('profiles')
.select('id, user_id, discord_id')
.in('user_id', userIds)
if (error) {
console.error('Error fetching user profiles:', error.message)
return []
}
console.log(`DEBUG: Retrieved ${data.length} user profiles.`)
console.log('DEBUG: User profiles data:', JSON.stringify(data))
return data
}
// Modify the fetchCurrentlyWorkingEmployees function to handle timezones correctly.
async function fetchCurrentlyWorkingEmployees() {
const now = new Date().toISOString()
console.log(`DEBUG: Fetching schedules for current time: ${now}`)
const { data, error } = await supabase
.from('schedules')
.select('user_id')
.lte('start_time', now)
.gte('end_time', now)
if (error) {
console.error('Error fetching schedules:', error.message)
return []
}
const userIds = data.map(schedule => schedule.user_id)
console.log('DEBUG: User IDs from schedules:', userIds)
return userIds
}
// Determine if a task is due.
function isTaskDue(task, today) {
const startDate = new Date(task.start_date)
if (startDate > today) return false
const daysSinceStart = Math.floor((today - startDate) / (1000 * 60 * 60 * 24))
return daysSinceStart % task.interval === 0
}
// Modify the sendTasks function
async function sendTasks(tasksToSend, currentTime) {
console.log(`DEBUG: Preparing to send ${tasksToSend.length} task(s) for ${currentTime}.`)
console.log(`DEBUG: Attempting to fetch channel with ID: ${channelId}`)
const channel = await client.channels.fetch(channelId)
if (!channel) {
console.error('Channel not found! Channel ID:', channelId)
return
}
console.log('DEBUG: Channel found successfully:', channel.name)
const workingEmployeeIds = await fetchCurrentlyWorkingEmployees()
console.log('DEBUG: Currently working employees:', workingEmployeeIds)
// Fetch user profiles for working employees
const workingEmployees = await fetchUserProfiles(workingEmployeeIds)
console.log('DEBUG: Working employees to tag:', workingEmployees)
let messageContent = workingEmployees.length > 0
? `${workingEmployees.filter(emp => emp.discord_id).map(emp => `<@${emp.discord_id}>`).join(' ')}\n\n`
: '\n\n'
tasksToSend.forEach((task, idx) => {
messageContent += `${getNumberEmoji(idx + 1)} ${task.name}\n`
})
console.log('DEBUG: Message content:', messageContent)
try {
const sentMessage = await channel.send(messageContent)
console.log('DEBUG: Message sent. Now adding reactions...')
for (let i = 1; i <= tasksToSend.length; i++) {
const emoji = getNumberEmoji(i)
if (emoji) {
await sentMessage.react(emoji)
console.log(`DEBUG: Added reaction ${emoji}`)
}
}
logger(`Tasks sent for ${currentTime}.`)
} catch (err) {
console.error('DEBUG: Error sending tasks:', err)
}
}
// Cron job: runs every minute in Sofia time.
cron.schedule(
'* * * * *',
async () => {
const now = new Date()
const currentTime = now.toLocaleTimeString('en-GB', {
timeZone: 'Europe/Sofia',
hour12: false,
hour: '2-digit',
minute: '2-digit',
})
console.log(`DEBUG: Cron job triggered at ${currentTime} (Sofia time).`)
const allTasks = await fetchTasksFromSupabase()
const today = new Date()
// Filter tasks that are due and scheduled for the current time.
const dueTasks = allTasks.filter((task) => {
return isTaskDue(task, today) && task.time === currentTime
})
if (dueTasks.length > 0) {
console.log(
`DEBUG: Found ${dueTasks.length} due task(s) for ${currentTime}.`
)
await sendTasks(dueTasks, currentTime)
} else {
console.log(`DEBUG: No tasks due for ${currentTime}. Enjoy the silence.`)
}
},
{ timezone: 'Europe/Sofia' }
)
client.once('ready', () => {
logger('Bot is ready.')
console.log('DEBUG: Discord client is now ready.')
})
client.login(botToken)