Files
LightningLotto/telegram_bot/src/messages/index.ts
Michilis 404fdf2610 Maintenance mode activates after current draw completes
- When admin enables maintenance, it's set to 'pending' state
- Maintenance activates automatically after the current draw completes
- Admin can use immediate=true to force immediate activation
- Frontend shows 'Maintenance Scheduled' banner when pending
- Telegram bot warns users but still allows purchases when pending
- Both mode and pending status tracked in system_settings table
2025-12-09 00:46:55 +00:00

681 lines
25 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* All Telegram bot messages centralized for easy management and future i18n support
*/
export const messages = {
// ═══════════════════════════════════════════════════════════════════════════
// ERRORS
// ═══════════════════════════════════════════════════════════════════════════
errors: {
userNotIdentified: '❌ Could not identify user.',
startFirst: '❌ Please start the bot first with /start',
generic: '❌ An error occurred. Please try again.',
startAgain: '❌ An error occurred. Please try again with /start',
systemUnavailable: '❌ The lottery system is temporarily unavailable. Please try again soon.',
invoiceCreationFailed: '❌ Failed to create invoice. Please try again.',
fetchTicketsFailed: '❌ Failed to fetch tickets. Please try again.',
fetchWinsFailed: '❌ Failed to fetch wins. Please try again.',
ticketNotFound: '❌ Ticket not found.',
fetchTicketDetailsFailed: '❌ Failed to fetch ticket details.',
checkStatusFailed: '❌ Failed to check status',
noPendingPurchase: '❌ No pending purchase. Please start again with /buyticket',
setAddressFirst: '❌ Please set your Lightning Address first.',
maintenance: (message: string) => `🔧 *Maintenance Mode*
${message}
Please try again later. We'll be back soon! ⚡`,
maintenancePending: `⏳ *Maintenance Scheduled*
Maintenance will begin after the current draw completes.
This is your *last chance* to buy tickets for the current round! 🎟️`,
},
// ═══════════════════════════════════════════════════════════════════════════
// START / ONBOARDING
// ═══════════════════════════════════════════════════════════════════════════
start: {
welcome: `⚡🎉 *Welcome to Lightning Jackpot!* 🎉⚡
You can buy Bitcoin Lightning lottery tickets, and if you win, your prize is paid instantly to your Lightning Address!
🎯 *How it works:*
1⃣ Set your Lightning Address (where you'll receive winnings)
2⃣ Buy tickets with Lightning
3⃣ Wait for the draw
4⃣ If you win, prize is sent instantly!`,
needAddress: `Before you can play, I need your Lightning Address to send any winnings.
*Example:* \`yourname@getalby.com\`
Please send your Lightning Address now:`,
needAddressWithOptions: (username?: string) => {
let msg = `Before you can play, I need your Lightning Address to send any winnings.\n\n`;
if (username) {
msg += `🤖 *Quick Setup* - Choose a tip bot below:\n\n`;
msg += `Or send me your Lightning Address to set a custom one.\n`;
msg += `*Example:* \`yourname@getalby.com\``;
} else {
msg += `*Example:* \`yourname@getalby.com\`\n\n`;
msg += `Please send your Lightning Address now:`;
}
return msg;
},
addressSet: (address: string) =>
`✅ Your payout address is set to: \`${address}\`
Use the menu below to get started! Good luck! 🍀`,
welcomeUnknown: '👋 Welcome! Please use /start to begin.',
},
// ═══════════════════════════════════════════════════════════════════════════
// LIGHTNING ADDRESS
// ═══════════════════════════════════════════════════════════════════════════
address: {
currentAddress: (address: string) =>
`⚡ *Your Current Payout Address:*
\`${address}\`
Send me your new Lightning Address to update it:`,
currentAddressWithOptions: (address: string, username?: string) => {
let msg = `⚡ *Your Current Payout Address:*\n\`${address}\`\n\n`;
if (username) {
msg += `🤖 *Quick Options* - Choose a tip bot below:\n\n`;
msg += `Or send me your Lightning Address to set a custom one.`;
} else {
msg += `Send me your new Lightning Address to update it:`;
}
return msg;
},
noAddressSet: `⚡ You don't have a Lightning Address set yet.
Send me your Lightning Address now:
*Example:* \`yourname@getalby.com\``,
noAddressSetWithOptions: (username?: string) => {
let msg = `⚡ You don't have a Lightning Address set yet.\n\n`;
if (username) {
msg += `🤖 *Quick Setup* - Choose a tip bot below:\n\n`;
msg += `Or send me your Lightning Address to set a custom one.\n`;
msg += `*Example:* \`yourname@getalby.com\``;
} else {
msg += `Send me your Lightning Address now:\n\n`;
msg += `*Example:* \`yourname@getalby.com\``;
}
return msg;
},
invalidFormat: `❌ That doesn't look like a valid Lightning Address.
*Format:* \`username@domain.com\`
*Example:* \`satoshi@getalby.com\`
Please try again:`,
verifying: '🔍 Verifying your Lightning Address...',
verificationFailed: (address: string, error?: string) =>
`❌ *Could not verify Lightning Address*
Address: \`${address}\`
${error ? `Error: ${error}\n` : ''}
Please check the address and try again, or choose a different option:`,
verifyingService: (service: string, address: string) =>
`🔍 Verifying your ${service} address: \`${address}\`...`,
serviceNotSetup: (service: string, error?: string) =>
`❌ *${service} address not found*
It looks like you haven't set up ${service} yet, or your username doesn't match.
${error ? `Error: ${error}\n\n` : ''}Please set up ${service} first, or enter a different Lightning Address:`,
noUsername: `❌ You don't have a Telegram username set!
To use 21Tipbot or Bittip, you need a Telegram username.
Please set a username in Telegram settings, or enter a custom Lightning Address:`,
firstTimeSuccess: (address: string) =>
`✅ *Perfect!* I'll use \`${address}\` to send any winnings.
You're all set! Use the menu below to buy tickets and check your results. Good luck! 🍀`,
updateSuccess: (address: string) =>
`✅ *Lightning Address updated!*
New address: \`${address}\`
⚠️ *Note:* Previous ticket purchases will still use their original addresses.`,
saveFailed: '❌ An error occurred saving your address. Please try again.',
needAddressFirst: `❌ I don't have your Lightning Address yet!
Please send your Lightning Address first:
*Example:* \`yourname@getalby.com\``,
},
// ═══════════════════════════════════════════════════════════════════════════
// BUY TICKETS
// ═══════════════════════════════════════════════════════════════════════════
buy: {
noActiveJackpot: `😔 *No Active Jackpot*
There's no lottery cycle available right now. Please check back soon!`,
jackpotInfo: (
potSats: string,
ticketPrice: string,
drawTime: string,
timeLeft: string
) =>
`🎰 *Next Jackpot Info*
💰 *Prize Pool:* ${potSats} sats
🎟 *Ticket Price:* ${ticketPrice} sats each
⏰ *Draw at:* ${drawTime}
⏳ *Time left:* ${timeLeft}
How many tickets do you want to buy?`,
customAmountPrompt: (maxTickets: number) =>
`🔢 *Custom Amount*
Enter the number of tickets you want to buy (1-${maxTickets}):`,
invalidNumber: (maxTickets: number) =>
`❌ Please enter a valid number (1-${maxTickets}):`,
tooManyTickets: (maxTickets: number) =>
`❌ Maximum ${maxTickets} tickets per purchase.
Please enter a smaller number:`,
confirmPurchase: (
ticketCount: number,
ticketPrice: string,
totalAmount: string,
drawTime: string
) =>
`📋 *Confirm Purchase*
🎟 *Tickets:* ${ticketCount}
💰 *Price:* ${ticketPrice} sats each
💵 *Total:* ${totalAmount} sats
⏰ *Draw:* ${drawTime}
Confirm this purchase?`,
creatingInvoice: 'Creating invoice...',
invoiceCreated: '💸 *Pay this Lightning invoice to complete your purchase:*',
invoiceCaption: (
ticketCount: number,
totalAmount: string,
expiryMinutes: number
) =>
`🎟 *${ticketCount} ticket${ticketCount > 1 ? 's' : ''}*
💰 *Amount:* ${totalAmount} sats
⏳ Expires in ${expiryMinutes} minutes`,
invoiceString: (paymentRequest: string) =>
`\`${paymentRequest}\``,
paymentReceived: (ticketNumbers: string, drawTime: string) =>
`🎉 *Payment Received!*
Your tickets have been issued!
*Your Ticket Numbers:*
${ticketNumbers}
*Draw Time:* ${drawTime}
Good luck! 🍀 I'll notify you after the draw!`,
invoiceExpired: `❌ *Invoice Expired*
No payment was received in time. No tickets were issued.
Use /buyticket to try again.`,
invoiceExpiredShort: `❌ *Invoice Expired*
This invoice has expired. No tickets were issued.
Use /buyticket to try again.`,
jackpotUnavailable: '❌ Jackpot is no longer available.',
},
// ═══════════════════════════════════════════════════════════════════════════
// TICKETS
// ═══════════════════════════════════════════════════════════════════════════
tickets: {
header: `🧾 *Your Recent Purchases*\n\n`,
empty: `🧾 *Your Tickets*
You haven't purchased any tickets yet!
Use /buyticket to get started! 🎟`,
notFound: `🧾 *Your Tickets*
No ticket purchases found. Purchase history may have expired.
Use /buyticket to get new tickets! 🎟`,
tapForDetails: `\nTap a ticket below for details:`,
statusPending: 'Pending',
statusExpired: 'Expired',
statusActive: 'Active',
statusWon: 'Won!',
statusLost: 'Lost',
// Ticket detail view
detailHeader: '🎫 *Ticket Details*',
detailAwaitingPayment: '⏳ *Status:* Awaiting Payment',
detailExpired: '❌ *Status:* Invoice Expired (No tickets issued)',
detailActive: '🎟 *Status:* Active - Draw Pending',
detailWinner: (prizeSats: string, payoutStatus: string) =>
`🏆 *Status:* WINNER!
💰 *Prize:* ${prizeSats} sats
📤 *Payout:* ${payoutStatus}`,
detailLost: (winningTicketId: string) =>
`😔 *Status:* Did not win this round
🎯 *Winning Ticket:* #${winningTicketId}`,
detailFormat: (
purchaseId: string,
ticketCount: number,
ticketNumbers: string,
amountSats: string,
drawDate: string,
statusSection: string
) =>
`🎫 *Ticket Details*
📋 *Purchase ID:* \`${purchaseId}...\`
🎟 *Tickets:* ${ticketCount}
🔢 *Numbers:* ${ticketNumbers}
💰 *Amount Paid:* ${amountSats} sats
📅 *Draw:* ${drawDate}
${statusSection}`,
// Status check responses
checkStatusPending: '⏳ Still waiting for payment...',
checkStatusConfirmed: '✅ Payment confirmed! Tickets issued. Waiting for draw...',
checkStatusWon: '🏆 YOU WON! Check your Lightning wallet!',
checkStatusLost: '😔 Draw completed. Better luck next time!',
checkStatusExpired: '❌ Invoice expired. No tickets were issued.',
checkStatusProcessing: '⏳ Processing...',
},
// ═══════════════════════════════════════════════════════════════════════════
// WINS
// ═══════════════════════════════════════════════════════════════════════════
wins: {
empty: `🏆 *Your Wins*
You haven't purchased any tickets yet, so no wins to show!
Use /buyticket to get started! 🎟`,
noWinsYet: `🏆 *Your Wins*
You haven't won any jackpots yet. Keep playing!
Use /buyticket to get more tickets! 🎟🍀`,
header: (totalWinnings: string, paidWinnings: string) =>
`🏆 *Your Wins*
💰 *Total Winnings:* ${totalWinnings} sats
✅ *Paid:* ${paidWinnings} sats
*Win History:*
`,
},
// ═══════════════════════════════════════════════════════════════════════════
// HELP
// ═══════════════════════════════════════════════════════════════════════════
help: {
message: `⚡🎰 *Lightning Jackpot Bot* 🎰⚡
This is the Lightning Jackpot lottery bot! Buy tickets with Bitcoin Lightning, and if you win, your prize is paid instantly!
*How It Works:*
1⃣ Set your Lightning Address (where winnings go)
2⃣ Buy tickets using the menu
3⃣ Pay the Lightning invoice
4⃣ Wait for the draw
5⃣ If you win, sats are sent to your address instantly!
*Commands:*
• /buyticket — Buy lottery tickets
• /tickets — View your tickets
• /wins — View your past wins
• /lottoaddress — Update Lightning Address
• /lottomenu — Show main menu
• /lottohelp — Show this help
• /jackpot — View current jackpot info
*Settings (use ⚙️ Settings button):*
• Set your display name (shown if you win)
• Enable/disable draw reminders
• Enable/disable draw results notifications
• Enable/disable new jackpot alerts
*Tips:*
🎟 Each ticket is one chance to win
💰 Prize pool grows with each ticket sold
⚡ Winnings are paid instantly via Lightning
🔔 You'll be notified after every draw you participate in
Good luck! 🍀`,
groupMessage: `⚡🎰 *Lightning Jackpot Bot - Group Help* 🎰⚡
*User Commands:*
• /jackpot — View current jackpot info
• /buyticket — Buy lottery tickets
• /lottohelp — Show this help
*Admin Commands:*
• /lottosettings — Configure bot settings for this group
*Admin Settings:*
👉 *Bot Enabled* — Enable/disable the bot in this group
👉 *Draw Announcements* — Announce draw winners in this group
👉 *Draw Reminders* — Send reminders before draws
👉 *Ticket Purchases* — Allow /buyticket command in group
💡 *Tip:* For privacy, ticket purchases in groups can be disabled. Users can always buy tickets by messaging the bot directly.
To buy tickets privately, message me directly!`,
},
// ═══════════════════════════════════════════════════════════════════════════
// MENU
// ═══════════════════════════════════════════════════════════════════════════
menu: {
header: `🎰 *Lightning Jackpot Menu*
What would you like to do?`,
cancelled: '❌ Cancelled.',
whatToDo: 'What would you like to do?',
didNotUnderstand:
"I didn't understand that. Use the menu below or type /help for available commands.",
},
// ═══════════════════════════════════════════════════════════════════════════
// DRAW NOTIFICATIONS
// ═══════════════════════════════════════════════════════════════════════════
notifications: {
winner: (
prizeSats: string,
winningTicket: string,
payoutStatus: string
) =>
`🎉 *YOU WON THE LIGHTNING JACKPOT!* 🎉
💰 *Prize:* ${prizeSats} sats
🎟 *Winning Ticket:* #${winningTicket}
📤 *Payout Status:* ${payoutStatus}
Congratulations! 🥳`,
loser: (winningTicket: string, prizeSats: string) =>
`The draw has finished!
Your tickets did not win this time.
🎟 *Winning Ticket:* #${winningTicket}
💰 *Prize:* ${prizeSats} sats
Good luck next round! 🍀`,
drawAnnouncement: (
winnerName: string,
winningTicket: string,
prizeSats: string,
totalTickets: number
) =>
`🎰 *JACKPOT DRAW COMPLETE!* 🎰
🏆 *Winner:* ${winnerName}
🎟 *Winning Ticket:* #${winningTicket}
💰 *Prize:* ${prizeSats} sats
📊 *Total Tickets:* ${totalTickets}
Congratulations to the winner! ⚡
Use /buyticket to enter the next draw! 🍀`,
drawCompleted: (potSats: number, hasWinner: boolean) =>
hasWinner
? `🎰 *JACKPOT DRAW COMPLETE!* 🎰
💰 *Jackpot:* ${potSats.toLocaleString()} sats
🏆 A winner has been selected!
Use /buyticket to enter the next round! 🍀`
: `🎰 *JACKPOT DRAW COMPLETE!* 🎰
No tickets were sold this round.
The jackpot rolls over to the next draw!
Use /buyticket to be the first to enter! 🍀`,
drawReminder: (value: number, unit: string, drawTime: Date, potSats: number) => {
const timeStr = unit === 'days'
? `${value} day${value > 1 ? 's' : ''}`
: unit === 'hours'
? `${value} hour${value > 1 ? 's' : ''}`
: `${value} minute${value > 1 ? 's' : ''}`;
const drawTimeStr = drawTime.toLocaleString('en-US', {
weekday: 'short',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
timeZoneName: 'short',
});
return `⏰ *Draw Reminder!*
🎰 The next Lightning Jackpot draw is in *${timeStr}*!
💰 *Current Prize Pool:* ${potSats.toLocaleString()} sats
🕐 *Draw Time:* ${drawTimeStr}
Don't miss your chance to win! Use /buyticket to get your tickets! 🎟`;
},
newJackpot: (lotteryName: string, ticketPrice: number, drawTime: Date) => {
const drawTimeStr = drawTime.toLocaleString('en-US', {
weekday: 'short',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
timeZoneName: 'short',
});
return `🎉 *NEW JACKPOT STARTED!* 🎉
⚡ *${lotteryName}*
A new lottery round has begun!
🎟 *Ticket Price:* ${ticketPrice} sats
🕐 *Draw Time:* ${drawTimeStr}
Be first to enter! Use /buyticket to buy tickets! 🍀`;
},
},
// ═══════════════════════════════════════════════════════════════════════════
// USER SETTINGS
// ═══════════════════════════════════════════════════════════════════════════
settings: {
overview: (displayName: string, notifications: { drawReminders: boolean; drawResults: boolean; newJackpotAlerts: boolean }) =>
`⚙️ *Your Settings*
👤 *Display Name:* ${displayName}
_(Used when announcing winners)_
*Notifications:*
${notifications.drawReminders ? '✅' : '❌'} Draw Reminders _(15 min before draws)_
${notifications.drawResults ? '✅' : '❌'} Draw Results _(when your tickets are drawn)_
${notifications.newJackpotAlerts ? '✅' : '❌'} New Jackpot Alerts _(when new rounds start)_
Tap buttons below to change settings:`,
enterDisplayName: `👤 *Set Display Name*
Enter your display name (max 20 characters).
This name will be shown if you win!
_Send "Anon" to stay anonymous._`,
nameTooLong: '❌ Display name must be 20 characters or less. Please try again:',
nameUpdated: (name: string) =>
`✅ *Display Name Updated!*
Your display name is now: *${name}*
This will be shown when announcing winners.`,
},
// ═══════════════════════════════════════════════════════════════════════════
// GROUPS
// ═══════════════════════════════════════════════════════════════════════════
groups: {
welcome: (groupName: string) =>
`⚡🎰 *Lightning Jackpot Bot Added!* 🎰⚡
Hello *${groupName}*! I'm the Lightning Jackpot lottery bot.
I can announce lottery draws and remind you when jackpots are coming up!
*Group Admin Commands:*
• /lottosettings — Configure bot settings for this group
*User Commands:*
• /buyticket — Buy lottery tickets
• /jackpot — View current jackpot info
• /lottohelp — Get help
To buy tickets privately, message me directly! 🎟`,
privateChat: '❌ This command only works in groups. Use /lottomenu to see available commands.',
adminOnly: '⚠️ Only group administrators can change these settings.',
settingsOverview: (settings: {
groupTitle: string;
enabled: boolean;
drawAnnouncements: boolean;
reminders: boolean;
newJackpotAnnouncement?: boolean;
ticketPurchaseAllowed: boolean;
reminder1Enabled?: boolean;
reminder1Time?: { value: number; unit: string };
reminder2Enabled?: boolean;
reminder2Time?: { value: number; unit: string };
reminder3Enabled?: boolean;
reminder3Time?: { value: number; unit: string };
announcementDelaySeconds?: number;
newJackpotDelayMinutes?: number;
}) => {
const announceDelay = settings.announcementDelaySeconds ?? 10;
const formatAnnounce = announceDelay === 0
? 'Immediately'
: announceDelay >= 60
? `${announceDelay / 60} min after draw`
: `${announceDelay}s after draw`;
const newJackpotDelay = settings.newJackpotDelayMinutes ?? 5;
const formatNewJackpotDelay = newJackpotDelay === 0
? 'Immediately'
: `${newJackpotDelay} min after start`;
// Format helper for reminder times
const formatTime = (t?: { value: number; unit: string }) => {
if (!t) return '?';
if (t.unit === 'minutes') return `${t.value}m`;
if (t.unit === 'hours') return t.value === 1 ? '1h' : `${t.value}h`;
return t.value === 1 ? '1d' : `${t.value}d`;
};
// Format reminder times (3-tier system)
const r1 = settings.reminder1Enabled !== false;
const r2 = settings.reminder2Enabled === true;
const r3 = settings.reminder3Enabled === true;
const activeReminders: string[] = [];
if (r1) activeReminders.push(formatTime(settings.reminder1Time) || '1h');
if (r2) activeReminders.push(formatTime(settings.reminder2Time) || '1d');
if (r3) activeReminders.push(formatTime(settings.reminder3Time) || '6d');
const formatReminderList = activeReminders.length > 0
? activeReminders.join(', ')
: 'None';
const newJackpot = settings.newJackpotAnnouncement !== false;
return `⚙️ *Group Settings*
📍 *Group:* ${settings.groupTitle}
*Current Configuration:*
${settings.enabled ? '✅' : '❌'} Bot Enabled
${newJackpot ? '✅' : '❌'} New Jackpot Announcements ${newJackpot ? `_(${formatNewJackpotDelay})_` : ''}
${settings.drawAnnouncements ? '✅' : '❌'} Draw Announcements ${settings.drawAnnouncements ? `_(${formatAnnounce})_` : ''}
${settings.reminders ? '✅' : '❌'} Draw Reminders ${settings.reminders ? `_(${formatReminderList})_` : ''}
${settings.ticketPurchaseAllowed ? '✅' : '❌'} Ticket Purchases in Group
_Tap buttons to toggle features or adjust times._
_This message will auto-delete in 2 minutes._`;
},
settingUpdated: (setting: string, enabled: boolean) =>
`✅ *${setting}* has been ${enabled ? 'enabled' : 'disabled'}.`,
botDisabled: 'The Lightning Jackpot bot is currently disabled for this group.',
purchasesDisabled: `🎟 Ticket purchases are disabled in this group for privacy.
Please message me directly to buy tickets: @LightningLottoBot`,
},
};
export default messages;