Guest User

Untitled

a guest
Jun 27th, 2024
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 32.47 KB | None | 0 0
  1. const fs = require('fs');
  2. const path = require('path');
  3. const { Client, GatewayIntentBits, Collection, EmbedBuilder, REST, Routes, SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder, TextInputBuilder, ModalBuilder, TextInputStyle } = require('discord.js');
  4. const { token, clientId, guildId } = require('./config.json'); // Import the token from config.json
  5.  
  6. const client = new Client({
  7. intents: [
  8. GatewayIntentBits.Guilds,
  9. GatewayIntentBits.GuildMessages,
  10. GatewayIntentBits.MessageContent,
  11. GatewayIntentBits.GuildMessageReactions
  12. ]
  13. });
  14.  
  15. const flightPlansPath = path.join(__dirname, './data/flightPlans.json');
  16. const embedMessageIdsPath = path.join(__dirname, './data/embedMessageIds.json');
  17.  
  18. // Ensure flightPlans.json and embedMessageIds.json exist and are initialized properly
  19. if (!fs.existsSync(flightPlansPath)) {
  20. fs.writeFileSync(flightPlansPath, JSON.stringify({}));
  21. }
  22.  
  23. if (!fs.existsSync(embedMessageIdsPath)) {
  24. fs.writeFileSync(embedMessageIdsPath, JSON.stringify({}));
  25. }
  26.  
  27. let embedMessageIds = JSON.parse(fs.readFileSync(embedMessageIdsPath, 'utf-8'));
  28. const logChannelId = '1255176551063097489'; // Replace with your log channel ID
  29. const roleID = '1241813787280015361'; // Role ID that can use the commands
  30.  
  31. client.commands = new Collection();
  32.  
  33. const airportChannels = {
  34. 'MDPC': '1255157149194125342',
  35. 'MDAB': '1255157175442083900',
  36. 'MDST': '1255157186552922142',
  37. 'EGKK': '1255157200511303771',
  38. 'EFKT': '1255157212616065166',
  39. 'LYTV': '1255157226000093205',
  40. 'LEMH': '1255157238620754001',
  41. 'GCLP': '1255157255637303381',
  42. 'EGHI': '1255157273140133940'
  43. };
  44.  
  45. Object.keys(airportChannels).forEach(airport => {
  46. client.commands.set(`embed${airport.toLowerCase()}`, {
  47. name: `embed${airport.toLowerCase()}`,
  48. description: `Shows filed flight plans for ${airport}`,
  49. execute: async (message) => {
  50. try {
  51. console.log(`Executing command /embed${airport.toLowerCase()}`);
  52.  
  53. // Load flight plans from file
  54. let flightPlans = JSON.parse(fs.readFileSync(flightPlansPath, 'utf-8'));
  55. embedMessageIds = JSON.parse(fs.readFileSync(embedMessageIdsPath, 'utf-8'));
  56. console.log(`Loaded flight plans: ${JSON.stringify(flightPlans)}`);
  57.  
  58. // Ensure the airport is initialized in flightPlans
  59. if (!flightPlans[airport]) {
  60. flightPlans[airport] = { departures: [], arrivals: [] };
  61. console.log(`Initialized flight plans for ${airport}`);
  62. }
  63.  
  64. const departures = flightPlans[airport].departures.map(plan => `${plan.callsign} | ${plan.destination} | ${plan.squawk || 'No squawk'}`).join('\n') || 'No departures';
  65. const arrivals = flightPlans[airport].arrivals.map(plan => `${plan.callsign} | ${plan.departedFrom} | ${plan.squawk || 'No squawk'}`).join('\n') || 'No arrivals';
  66.  
  67. const embed = new EmbedBuilder()
  68. .setColor('#88ebff')
  69. .setTitle(`${airport} | Filed Flight Plans | Departing & Arriving`)
  70. .addFields(
  71. { name: '**Departures**', value: departures },
  72. { name: '**Arrivals**', value: arrivals }
  73. );
  74.  
  75. const row = new ActionRowBuilder()
  76. .addComponents(
  77. new ButtonBuilder()
  78. .setCustomId(`remove_aircraft_${airport.toLowerCase()}`)
  79. .setLabel('Remove Aircraft')
  80. .setStyle(ButtonStyle.Danger),
  81. new ButtonBuilder()
  82. .setCustomId(`get_details_${airport.toLowerCase()}`)
  83. .setLabel('Get Details')
  84. .setStyle(ButtonStyle.Secondary),
  85. new ButtonBuilder()
  86. .setCustomId(`assign_squawk_${airport.toLowerCase()}`)
  87. .setLabel('Assign Squawk')
  88. .setStyle(ButtonStyle.Primary)
  89. );
  90.  
  91. console.log(`Sending embed for ${airport}`);
  92. const embedMessage = await message.channel.send({ embeds: [embed], components: [row] });
  93. embedMessageIds[airport] = embedMessage.id;
  94. fs.writeFileSync(embedMessageIdsPath, JSON.stringify(embedMessageIds, null, 2));
  95. console.log(`Embed sent for ${airport} with message ID: ${embedMessage.id}`);
  96.  
  97. const logChannel = message.guild.channels.cache.get(logChannelId);
  98. if (logChannel) {
  99. const logEmbed = new EmbedBuilder()
  100. .setColor('#88ebff')
  101. .setTitle('Command Log')
  102. .addFields(
  103. { name: 'User', value: message.author.tag },
  104. { name: 'Command', value: message.content },
  105. { name: 'Time', value: new Date().toISOString() }
  106. );
  107. await logChannel.send({ embeds: [logEmbed] });
  108. console.log(`Log sent for ${airport} command`);
  109. }
  110. } catch (error) {
  111. console.error(`Error in command /embed${airport.toLowerCase()}:`, error);
  112. await message.reply('There was an error while executing this command!');
  113. }
  114. }
  115. });
  116. });
  117.  
  118. client.commands.set('fileflightplan', {
  119. name: 'fileflightplan',
  120. description: 'Files a flight plan',
  121. execute: async (message, args) => {
  122. try {
  123. console.log('Executing command /fileflightplan');
  124. if (args.length < 6) {
  125. return message.reply('Please provide a callsign, departure, arrival, aircraft type, IFR/VFR, and CRZ FL.');
  126. }
  127.  
  128. const crzFl = args.pop().toUpperCase();
  129. const ifrVfr = args.pop().toUpperCase();
  130. const aircraftType = args.pop().toUpperCase();
  131. const arrival = args.pop().toUpperCase();
  132. const departure = args.pop().toUpperCase();
  133. const callsign = args.join(' ').toUpperCase();
  134.  
  135. let flightPlans = JSON.parse(fs.readFileSync(flightPlansPath, 'utf-8'));
  136. embedMessageIds = JSON.parse(fs.readFileSync(embedMessageIdsPath, 'utf-8'));
  137.  
  138. if (!flightPlans[departure]) {
  139. flightPlans[departure] = { departures: [], arrivals: [] };
  140. }
  141. if (!flightPlans[arrival]) {
  142. flightPlans[arrival] = { departures: [], arrivals: [] };
  143. }
  144.  
  145. flightPlans[departure].departures.push({ callsign, destination: arrival, aircraftType, ifrVfr, crzFl });
  146. flightPlans[arrival].arrivals.push({ callsign, departedFrom: departure, aircraftType, ifrVfr, crzFl });
  147.  
  148. fs.writeFileSync(flightPlansPath, JSON.stringify(flightPlans, null, 2));
  149.  
  150. message.reply(`Filed flight plan for ${callsign} from ${departure} to ${arrival}.`);
  151. console.log(`Filed flight plan for ${callsign} from ${departure} to ${arrival}`);
  152.  
  153. const logChannel = message.guild.channels.cache.get(logChannelId);
  154. if (logChannel) {
  155. const logEmbed = new EmbedBuilder()
  156. .setColor('#88ebff')
  157. .setTitle('Flight Plan Filed')
  158. .addFields(
  159. { name: 'User', value: message.author.tag },
  160. { name: 'Callsign', value: callsign },
  161. { name: 'Departure', value: departure },
  162. { name: 'Arrival', value: arrival },
  163. { name: 'Aircraft Type', value: aircraftType },
  164. { name: 'IFR/VFR', value: ifrVfr },
  165. { name: 'CRZ FL', value: crzFl },
  166. { name: 'Time', value: new Date().toISOString() }
  167. );
  168. await logChannel.send({ embeds: [logEmbed] });
  169. console.log('Log sent for flight plan command');
  170. }
  171.  
  172. // Update the embed for the departure and arrival airports
  173. const updateEmbed = async (airport) => {
  174. const channel = message.guild.channels.cache.get(airportChannels[airport]);
  175. if (!channel) return;
  176.  
  177. const departures = flightPlans[airport].departures.map(plan => `${plan.callsign} | ${plan.destination} | ${plan.squawk || 'No squawk'}`).join('\n') || 'No departures';
  178. const arrivals = flightPlans[airport].arrivals.map(plan => `${plan.callsign} | ${plan.departedFrom} | ${plan.squawk || 'No squawk'}`).join('\n') || 'No arrivals';
  179.  
  180. const embed = new EmbedBuilder()
  181. .setColor('#88ebff')
  182. .setTitle(`${airport} | Filed Flight Plans | Departing & Arriving`)
  183. .addFields(
  184. { name: '**Departures**', value: departures },
  185. { name: '**Arrivals**', value: arrivals }
  186. );
  187.  
  188. const row = new ActionRowBuilder()
  189. .addComponents(
  190. new ButtonBuilder()
  191. .setCustomId(`remove_aircraft_${airport.toLowerCase()}`)
  192. .setLabel('Remove Aircraft')
  193. .setStyle(ButtonStyle.Danger),
  194. new ButtonBuilder()
  195. .setCustomId(`get_details_${airport.toLowerCase()}`)
  196. .setLabel('Get Details')
  197. .setStyle(ButtonStyle.Secondary),
  198. new ButtonBuilder()
  199. .setCustomId(`assign_squawk_${airport.toLowerCase()}`)
  200. .setLabel('Assign Squawk')
  201. .setStyle(ButtonStyle.Primary)
  202. );
  203.  
  204. if (embedMessageIds[airport]) {
  205. try {
  206. const embedMessage = await channel.messages.fetch(embedMessageIds[airport]);
  207. await embedMessage.edit({ embeds: [embed], components: [row] });
  208. } catch (error) {
  209. if (error.code === 10008) {
  210. console.log(`Message for ${airport} in channel ${channel.name} no longer exists.`);
  211. } else {
  212. console.error(`Failed to update embed for ${airport} in channel ${channel.name}:`, error);
  213. }
  214. }
  215. }
  216. };
  217.  
  218. await updateEmbed(departure);
  219. await updateEmbed(arrival);
  220. } catch (error) {
  221. console.error('Error in command /fileflightplan:', error);
  222. await message.reply('There was an error while executing this command!');
  223. }
  224. },
  225. slashExecute: async (interaction) => {
  226. try {
  227. console.log('Executing slash command /fileflightplan');
  228. const callsign = interaction.options.getString('callsign').toUpperCase();
  229. const departure = interaction.options.getString('departure').toUpperCase();
  230. const arrival = interaction.options.getString('arrival').toUpperCase();
  231. const aircraftType = interaction.options.getString('aircrafttype').toUpperCase();
  232. const ifrVfr = interaction.options.getString('ifrvfr').toUpperCase();
  233. const crzFl = interaction.options.getString('crzfl').toUpperCase();
  234.  
  235. let flightPlans = JSON.parse(fs.readFileSync(flightPlansPath, 'utf-8'));
  236. embedMessageIds = JSON.parse(fs.readFileSync(embedMessageIdsPath, 'utf-8'));
  237.  
  238. if (!flightPlans[departure]) {
  239. flightPlans[departure] = { departures: [], arrivals: [] };
  240. }
  241. if (!flightPlans[arrival]) {
  242. flightPlans[arrival] = { departures: [], arrivals: [] };
  243. }
  244.  
  245. flightPlans[departure].departures.push({ callsign, destination: arrival, aircraftType, ifrVfr, crzFl });
  246. flightPlans[arrival].arrivals.push({ callsign, departedFrom: departure, aircraftType, ifrVfr, crzFl });
  247.  
  248. fs.writeFileSync(flightPlansPath, JSON.stringify(flightPlans, null, 2));
  249.  
  250. await interaction.reply({ content: `Filed flight plan for ${callsign} from ${departure} to ${arrival}.`, ephemeral: true });
  251. console.log(`Filed flight plan for ${callsign} from ${departure} to ${arrival}`);
  252.  
  253. const logChannel = interaction.guild.channels.cache.get(logChannelId);
  254. if (logChannel) {
  255. const logEmbed = new EmbedBuilder()
  256. .setColor('#88ebff')
  257. .setTitle('Flight Plan Filed')
  258. .addFields(
  259. { name: 'User', value: interaction.user.tag },
  260. { name: 'Callsign', value: callsign },
  261. { name: 'Departure', value: departure },
  262. { name: 'Arrival', value: arrival },
  263. { name: 'Aircraft Type', value: aircraftType },
  264. { name: 'IFR/VFR', value: ifrVfr },
  265. { name: 'CRZ FL', value: crzFl },
  266. { name: 'Time', value: new Date().toISOString() }
  267. );
  268. await logChannel.send({ embeds: [logEmbed] });
  269. console.log('Log sent for flight plan command');
  270. }
  271.  
  272. // Update the embed for the departure and arrival airports
  273. const updateEmbed = async (airport) => {
  274. const channel = interaction.guild.channels.cache.get(airportChannels[airport]);
  275. if (!channel) return;
  276.  
  277. const departures = flightPlans[airport].departures.map(plan => `${plan.callsign} | ${plan.destination} | ${plan.squawk || 'No squawk'}`).join('\n') || 'No departures';
  278. const arrivals = flightPlans[airport].arrivals.map(plan => `${plan.callsign} | ${plan.departedFrom} | ${plan.squawk || 'No squawk'}`).join('\n') || 'No arrivals';
  279.  
  280. const embed = new EmbedBuilder()
  281. .setColor('#88ebff')
  282. .setTitle(`${airport} | Filed Flight Plans | Departing & Arriving`)
  283. .addFields(
  284. { name: '**Departures**', value: departures },
  285. { name: '**Arrivals**', value: arrivals }
  286. );
  287.  
  288. const row = new ActionRowBuilder()
  289. .addComponents(
  290. new ButtonBuilder()
  291. .setCustomId(`remove_aircraft_${airport.toLowerCase()}`)
  292. .setLabel('Remove Aircraft')
  293. .setStyle(ButtonStyle.Danger),
  294. new ButtonBuilder()
  295. .setCustomId(`get_details_${airport.toLowerCase()}`)
  296. .setLabel('Get Details')
  297. .setStyle(ButtonStyle.Secondary),
  298. new ButtonBuilder()
  299. .setCustomId(`assign_squawk_${airport.toLowerCase()}`)
  300. .setLabel('Assign Squawk')
  301. .setStyle(ButtonStyle.Primary)
  302. );
  303.  
  304. if (embedMessageIds[airport]) {
  305. try {
  306. const embedMessage = await channel.messages.fetch(embedMessageIds[airport]);
  307. await embedMessage.edit({ embeds: [embed], components: [row] });
  308. } catch (error) {
  309. if (error.code === 10008) {
  310. console.log(`Message for ${airport} in channel ${channel.name} no longer exists.`);
  311. } else {
  312. console.error(`Failed to update embed for ${airport} in channel ${channel.name}:`, error);
  313. }
  314. }
  315. }
  316. };
  317.  
  318. await updateEmbed(departure);
  319. await updateEmbed(arrival);
  320. } catch (error) {
  321. if (error.code === 10062) {
  322. console.log('Interaction no longer valid.');
  323. } else {
  324. console.error('Error in slash command /fileflightplan:', error);
  325. await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
  326. }
  327. }
  328. }
  329. });
  330.  
  331. client.once('ready', async () => {
  332. console.log('Bot is online!');
  333.  
  334. const commands = [
  335. new SlashCommandBuilder()
  336. .setName('fileflightplan')
  337. .setDescription('Files a flight plan')
  338. .addStringOption(option =>
  339. option.setName('callsign')
  340. .setDescription('The callsign of the aircraft')
  341. .setRequired(true))
  342. .addStringOption(option =>
  343. option.setName('departure')
  344. .setDescription('The departure airport ICAO code')
  345. .setRequired(true))
  346. .addStringOption(option =>
  347. option.setName('arrival')
  348. .setDescription('The arrival airport ICAO code')
  349. .setRequired(true))
  350. .addStringOption(option =>
  351. option.setName('aircrafttype')
  352. .setDescription('The aircraft type')
  353. .setRequired(true))
  354. .addStringOption(option =>
  355. option.setName('ifrvfr')
  356. .setDescription('IFR or VFR')
  357. .setRequired(true))
  358. .addStringOption(option =>
  359. option.setName('crzfl')
  360. .setDescription('The cruising flight level')
  361. .setRequired(true))
  362. ];
  363.  
  364. const rest = new REST({ version: '10' }).setToken(token);
  365.  
  366. try {
  367. await rest.put(
  368. Routes.applicationGuildCommands(clientId, guildId),
  369. { body: commands }
  370. );
  371. console.log('Successfully registered application commands.');
  372. } catch (error) {
  373. console.error(error);
  374. }
  375. });
  376.  
  377. client.on('messageCreate', async message => {
  378. if (!message.content.startsWith('!') || message.author.bot) return;
  379.  
  380. const args = message.content.slice(1).trim().split(/ +/);
  381. const commandName = args.shift().toLowerCase();
  382.  
  383. if (!client.commands.has(commandName)) return;
  384.  
  385. const command = client.commands.get(commandName);
  386.  
  387. try {
  388. await command.execute(message, args);
  389. } catch (error) {
  390. console.error(error);
  391. message.reply('There was an error executing that command.');
  392. }
  393. });
  394.  
  395. client.on('interactionCreate', async interaction => {
  396. if (interaction.isButton()) {
  397. const [action, airport] = interaction.customId.split('_').slice(1);
  398.  
  399. if (action === 'aircraft') {
  400. // Handle remove aircraft action
  401. const flightPlans = JSON.parse(fs.readFileSync(flightPlansPath, 'utf-8'));
  402. const airportData = flightPlans[airport.toUpperCase()];
  403. const options = [
  404. ...airportData.departures.map(plan => ({ label: `${plan.callsign} (Departure)`, value: `departure_${plan.callsign}` })),
  405. ...airportData.arrivals.map(plan => ({ label: `${plan.callsign} (Arrival)`, value: `arrival_${plan.callsign}` }))
  406. ];
  407.  
  408. if (options.length === 0) {
  409. return interaction.reply({ content: 'There are no aircraft to remove.', ephemeral: true });
  410. }
  411.  
  412. const row = new ActionRowBuilder()
  413. .addComponents(
  414. new StringSelectMenuBuilder()
  415. .setCustomId(`select_remove_aircraft_${airport.toLowerCase()}`)
  416. .setPlaceholder('Select an aircraft to remove')
  417. .addOptions(options)
  418. );
  419.  
  420. await interaction.reply({ content: 'Select an aircraft to remove:', components: [row], ephemeral: true });
  421. } else if (action === 'details') {
  422. // Handle get details action
  423. const flightPlans = JSON.parse(fs.readFileSync(flightPlansPath, 'utf-8'));
  424. const airportData = flightPlans[airport.toUpperCase()];
  425. const options = [
  426. ...airportData.departures.map(plan => ({ label: `${plan.callsign} (Departure)`, value: `departure_${plan.callsign}` })),
  427. ...airportData.arrivals.map(plan => ({ label: `${plan.callsign} (Arrival)`, value: `arrival_${plan.callsign}` }))
  428. ];
  429.  
  430. if (options.length === 0) {
  431. return interaction.reply({ content: 'There are no aircraft to get details for.', ephemeral: true });
  432. }
  433.  
  434. const row = new ActionRowBuilder()
  435. .addComponents(
  436. new StringSelectMenuBuilder()
  437. .setCustomId(`select_get_details_${airport.toLowerCase()}`)
  438. .setPlaceholder('Select an aircraft to get details')
  439. .addOptions(options)
  440. );
  441.  
  442. await interaction.reply({ content: 'Select an aircraft to get details:', components: [row], ephemeral: true });
  443. } else if (action === 'squawk') {
  444. // Handle assign squawk action
  445. const flightPlans = JSON.parse(fs.readFileSync(flightPlansPath, 'utf-8'));
  446. const airportData = flightPlans[airport.toUpperCase()];
  447. const options = [
  448. ...airportData.departures.map(plan => ({ label: `${plan.callsign} (Departure)`, value: `departure_${plan.callsign}` })),
  449. ...airportData.arrivals.map(plan => ({ label: `${plan.callsign} (Arrival)`, value: `arrival_${plan.callsign}` }))
  450. ];
  451.  
  452. if (options.length === 0) {
  453. return interaction.reply({ content: 'There are no aircraft to assign squawk.', ephemeral: true });
  454. }
  455.  
  456. const row = new ActionRowBuilder()
  457. .addComponents(
  458. new StringSelectMenuBuilder()
  459. .setCustomId(`select_assign_squawk_${airport.toLowerCase()}`)
  460. .setPlaceholder('Select an aircraft to assign squawk')
  461. .addOptions(options)
  462. );
  463.  
  464. await interaction.reply({ content: 'Select an aircraft to assign squawk:', components: [row], ephemeral: true });
  465. }
  466. } else if (interaction.isStringSelectMenu()) {
  467. const [action, type, callsign] = interaction.values[0].split('_');
  468. const airport = interaction.customId.split('_')[3].toUpperCase();
  469. const flightPlans = JSON.parse(fs.readFileSync(flightPlansPath, 'utf-8'));
  470.  
  471. if (action === 'remove') {
  472. if (type === 'departure') {
  473. flightPlans[airport].departures = flightPlans[airport].departures.filter(plan => plan.callsign !== callsign);
  474. } else {
  475. flightPlans[airport].arrivals = flightPlans[airport].arrivals.filter(plan => plan.callsign !== callsign);
  476. }
  477.  
  478. fs.writeFileSync(flightPlansPath, JSON.stringify(flightPlans, null, 2));
  479.  
  480. await interaction.update({ content: `Removed ${callsign} from ${type === 'departure' ? 'departures' : 'arrivals'} of ${airport}.`, components: [] });
  481.  
  482. // Update the embed for the airport
  483. const updateEmbed = async (airport) => {
  484. const channel = interaction.guild.channels.cache.get(airportChannels[airport]);
  485. if (!channel) return;
  486.  
  487. const departures = flightPlans[airport].departures.map(plan => `${plan.callsign} | ${plan.destination} | ${plan.squawk || 'No squawk'}`).join('\n') || 'No departures';
  488. const arrivals = flightPlans[airport].arrivals.map(plan => `${plan.callsign} | ${plan.departedFrom} | ${plan.squawk || 'No squawk'}`).join('\n') || 'No arrivals';
  489.  
  490. const embed = new EmbedBuilder()
  491. .setColor('#88ebff')
  492. .setTitle(`${airport} | Filed Flight Plans | Departing & Arriving`)
  493. .addFields(
  494. { name: '**Departures**', value: departures },
  495. { name: '**Arrivals**', value: arrivals }
  496. );
  497.  
  498. const row = new ActionRowBuilder()
  499. .addComponents(
  500. new ButtonBuilder()
  501. .setCustomId(`remove_aircraft_${airport.toLowerCase()}`)
  502. .setLabel('Remove Aircraft')
  503. .setStyle(ButtonStyle.Danger),
  504. new ButtonBuilder()
  505. .setCustomId(`get_details_${airport.toLowerCase()}`)
  506. .setLabel('Get Details')
  507. .setStyle(ButtonStyle.Secondary),
  508. new ButtonBuilder()
  509. .setCustomId(`assign_squawk_${airport.toLowerCase()}`)
  510. .setLabel('Assign Squawk')
  511. .setStyle(ButtonStyle.Primary)
  512. );
  513.  
  514. if (embedMessageIds[airport]) {
  515. try {
  516. const embedMessage = await channel.messages.fetch(embedMessageIds[airport]);
  517. await embedMessage.edit({ embeds: [embed], components: [row] });
  518. } catch (error) {
  519. if (error.code === 10008) {
  520. console.log(`Message for ${airport} in channel ${channel.name} no longer exists.`);
  521. } else {
  522. console.error(`Failed to update embed for ${airport} in channel ${channel.name}:`, error);
  523. }
  524. }
  525. }
  526. };
  527.  
  528. await updateEmbed(airport);
  529. } else if (action === 'details') {
  530. const plan = flightPlans[airport][type === 'departure' ? 'departures' : 'arrivals'].find(plan => plan.callsign === callsign);
  531. if (!plan) {
  532. return interaction.update({ content: `Details not found for ${callsign}.`, components: [] });
  533. }
  534.  
  535. const detailsEmbed = new EmbedBuilder()
  536. .setColor('#88ebff')
  537. .setTitle(`Details for ${callsign}`)
  538. .addFields(
  539. { name: 'Callsign', value: plan.callsign },
  540. { name: 'Departing', value: plan.departedFrom || 'N/A' },
  541. { name: 'Arriving', value: plan.destination || 'N/A' },
  542. { name: 'Aircraft Type', value: plan.aircraftType || 'N/A' },
  543. { name: 'IFR/VFR', value: plan.ifrVfr || 'N/A' },
  544. { name: 'CRZ FL', value: plan.crzFl || 'N/A' }
  545. );
  546.  
  547. await interaction.update({ embeds: [detailsEmbed], components: [] });
  548. } else if (action === 'squawk') {
  549. const modal = new ModalBuilder()
  550. .setCustomId(`submit_squawk_${type}_${callsign}_${airport}`)
  551. .setTitle('Assign Squawk Code')
  552. .addComponents(
  553. new ActionRowBuilder().addComponents(
  554. new TextInputBuilder()
  555. .setCustomId('squawk_code')
  556. .setLabel('Squawk Code')
  557. .setStyle(TextInputStyle.Short)
  558. .setRequired(true)
  559. )
  560. );
  561.  
  562. await interaction.showModal(modal);
  563. }
  564. } else if (interaction.isModalSubmit()) {
  565. const [action, type, callsign, airport] = interaction.customId.split('_').slice(1);
  566. const squawkCode = interaction.fields.getTextInputValue('squawk_code');
  567. const flightPlans = JSON.parse(fs.readFileSync(flightPlansPath, 'utf-8'));
  568.  
  569. const plan = flightPlans[airport.toUpperCase()][type === 'departure' ? 'departures' : 'arrivals'].find(plan => plan.callsign === callsign);
  570. if (!plan) {
  571. return interaction.reply({ content: `Plan not found for ${callsign}.`, ephemeral: true });
  572. }
  573.  
  574. plan.squawk = squawkCode;
  575. fs.writeFileSync(flightPlansPath, JSON.stringify(flightPlans, null, 2));
  576.  
  577. await interaction.reply({ content: `Assigned squawk code ${squawkCode} to ${callsign}.`, ephemeral: true });
  578.  
  579. // Update the embed for the airport
  580. const updateEmbed = async (airport) => {
  581. const channel = interaction.guild.channels.cache.get(airportChannels[airport]);
  582. if (!channel) return;
  583.  
  584. const departures = flightPlans[airport].departures.map(plan => `${plan.callsign} | ${plan.destination} | ${plan.squawk || 'No squawk'}`).join('\n') || 'No departures';
  585. const arrivals = flightPlans[airport].arrivals.map(plan => `${plan.callsign} | ${plan.departedFrom} | ${plan.squawk || 'No squawk'}`).join('\n') || 'No arrivals';
  586.  
  587. const embed = new EmbedBuilder()
  588. .setColor('#88ebff')
  589. .setTitle(`${airport} | Filed Flight Plans | Departing & Arriving`)
  590. .addFields(
  591. { name: '**Departures**', value: departures },
  592. { name: '**Arrivals**', value: arrivals }
  593. );
  594.  
  595. const row = new ActionRowBuilder()
  596. .addComponents(
  597. new ButtonBuilder()
  598. .setCustomId(`remove_aircraft_${airport.toLowerCase()}`)
  599. .setLabel('Remove Aircraft')
  600. .setStyle(ButtonStyle.Danger),
  601. new ButtonBuilder()
  602. .setCustomId(`get_details_${airport.toLowerCase()}`)
  603. .setLabel('Get Details')
  604. .setStyle(ButtonStyle.Secondary),
  605. new ButtonBuilder()
  606. .setCustomId(`assign_squawk_${airport.toLowerCase()}`)
  607. .setLabel('Assign Squawk')
  608. .setStyle(ButtonStyle.Primary)
  609. );
  610.  
  611. if (embedMessageIds[airport]) {
  612. try {
  613. const embedMessage = await channel.messages.fetch(embedMessageIds[airport]);
  614. await embedMessage.edit({ embeds: [embed], components: [row] });
  615. } catch (error) {
  616. if (error.code === 10008) {
  617. console.log(`Message for ${airport} in channel ${channel.name} no longer exists.`);
  618. } else {
  619. console.error(`Failed to update embed for ${airport} in channel ${channel.name}:`, error);
  620. }
  621. }
  622. }
  623. };
  624.  
  625. await updateEmbed(airport);
  626. } else if (interaction.isCommand()) {
  627. const command = client.commands.get(interaction.commandName);
  628.  
  629. if (!command) return;
  630.  
  631. if (!interaction.member.roles.cache.has(roleID)) {
  632. return interaction.reply({ content: 'You do not have permission to use this command.', ephemeral: true });
  633. }
  634.  
  635. try {
  636. console.log(`Executing command /${interaction.commandName}`);
  637. await command.slashExecute(interaction);
  638.  
  639. const logChannel = interaction.guild.channels.cache.get(logChannelId);
  640. if (logChannel) {
  641. const logEmbed = new EmbedBuilder()
  642. .setColor('#88ebff')
  643. .setTitle('Command Log')
  644. .addFields(
  645. { name: 'User', value: interaction.user.tag },
  646. { name: 'Command', value: interaction.commandName },
  647. { name: 'Time', value: new Date().toISOString() }
  648. );
  649. await logChannel.send({ embeds: [logEmbed] });
  650. console.log('Log sent for command');
  651. }
  652. } catch (error) {
  653. if (error.code === 10062) {
  654. console.log('Interaction no longer valid.');
  655. } else {
  656. console.error(`Error handling interaction for command ${interaction.commandName}:`, error);
  657. await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
  658. }
  659. }
  660. }
  661. });
  662.  
  663. client.login(token);
  664.  
  665. module.exports = client;
  666.  
Advertisement
Add Comment
Please, Sign In to add comment