diff --git a/client/app/adr/modules/AdrListEntry.jsx b/client/app/adr/modules/AdrListEntry.jsx index a979b2a..e106148 100644 --- a/client/app/adr/modules/AdrListEntry.jsx +++ b/client/app/adr/modules/AdrListEntry.jsx @@ -1,21 +1,19 @@ +//Honestly, I could probably just delete this file. + import React from "react"; import MilpacParse from "./MilpacParse"; -import lists from "../../reusableModules/BilletBank"; function AdrListEntry(props) { - let billetBankObject = lists.billetBankObject; - let selector = props.bBGroup; + const rosterGroups = props.rosterGroups.groups; + const selector = props.rGSelector; return ( -
-
{billetBankObject[selector].collapsibleTitle}
-
- -
+
+
); } diff --git a/client/app/adr/modules/ArrayMap.jsx b/client/app/adr/modules/ArrayMap.jsx index 8a24947..262f801 100644 --- a/client/app/adr/modules/ArrayMap.jsx +++ b/client/app/adr/modules/ArrayMap.jsx @@ -7,30 +7,21 @@ milpac link, name and rank, and position title.*/ function ArrayMap(props) { let inputArray = props.inputArray; + console.log(inputArray); return ( - {inputArray.map((subArray, index) => ( + {inputArray.map((item, index) => ( - - - + + + - {subArray.map((item, subIndex) => ( - - - - - ))} ))} diff --git a/client/app/adr/modules/MilpacParse.jsx b/client/app/adr/modules/MilpacParse.jsx index a7526be..0dc8960 100644 --- a/client/app/adr/modules/MilpacParse.jsx +++ b/client/app/adr/modules/MilpacParse.jsx @@ -7,15 +7,14 @@ This particular instance of milpacArray is designed to parse an entire object fo for each company within first battalion if asked to do so.*/ function MilpacParse(props) { - const billetBankObject = props.billetBankObject; + const rosterGroups = props.rosterGroups; let milpacArray = props.milpacArray; - //Currently broken. Sypolt, pls fix. - //const uniqueNamesSet = new Set(); + console.log(rosterGroups); - let returnArray = Array(billetBankObject.length) - .fill() - .map(() => []); + const uniqueNamesSet = new Set(); + + let returnArray = []; //First, check the combat roster primaries for matching billet id's, then push them to the return array if match is found. @@ -27,17 +26,17 @@ function MilpacParse(props) { let primarySortKey = milpacArray[0].combat.profiles[milpacIdCombat].primary.positionId; - for (let index in billetBankObject) { - if (billetBankObject[index].includes(primary.positionId)) { - returnArray[index].push({ + for (let index in rosterGroups) { + if (rosterGroups[index].positionId == primary.positionId) { + returnArray.push({ fullName: fullName, position: primary, isPrimary: "true", - sortKey: primarySortKey, + sortKey: rosterGroups[index].positionDisplayOrder, itemKey: milpacIdCombat, listKey: primarySortKey + milpacIdCombat, }); - //uniqueNamesSet.add(fullName); + uniqueNamesSet.add(fullName); } //Next, check the combat roster secondaries for matching billet id's, then push to return array if match is found. @@ -50,19 +49,17 @@ function MilpacParse(props) { milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2] .positionId; - if (!billetBankObject[index].includes(secondary.positionId)) { - continue; + if (rosterGroups[index].positionId == secondary.positionId) { + returnArray.push({ + fullName: fullName, + position: secondary, + isPrimary: "false", + sortKey: rosterGroups[index].positionDisplayOrder, + itemKey: milpacIdCombat, + listKey: secondarySortKey + milpacIdCombat, + }); + uniqueNamesSet.add(fullName); } - - returnArray[index].push({ - fullName: fullName, - position: secondary, - isPrimary: "false", - sortKey: secondarySortKey, - itemKey: milpacIdCombat, - listKey: secondarySortKey + milpacIdCombat, - }); - //uniqueNamesSet.add(fullName); } } } @@ -79,17 +76,17 @@ function MilpacParse(props) { //Check the Reserve primaries, then push to return array if match is found. - for (let index in billetBankObject) { - if (billetBankObject[index].includes(rPrimary.positionId)) { - returnArray[index].push({ + for (let index in rosterGroups) { + if (rosterGroups[index].positionId == rPrimary.positionId) { + returnArray.push({ fullName: rFullName, position: rPrimary, isPrimary: "true", - sortKey: rPrimarySortKey, + sortKey: rosterGroups[index].positionDisplayOrder, itemKey: milpacIdReserve, listKey: rPrimarySortKey + milpacIdReserve, }); - //uniqueNamesSet.add(rFullName); + uniqueNamesSet.add(rFullName); } //Check the Reserve secondaries, then push to return array if match is found. @@ -102,34 +99,41 @@ function MilpacParse(props) { milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex] .positionId; - if (!billetBankObject[index].includes(rSecondary.positionId)) { - continue; + if (rosterGroups[index].positionId == rSecondary.positionId) { + returnArray.push({ + fullName: rFullName, + position: rSecondary, + isPrimary: "false", + sortKey: rosterGroups[index].positionDisplayOrder, + itemKey: milpacIdReserve, + listKey: rSecondarySortKey + milpacIdReserve, + }); + uniqueNamesSet.add(rFullName); } - - returnArray[index].push({ - fullName: rFullName, - position: rSecondary, - isPrimary: "false", - sortKey: rSecondarySortKey, - itemKey: milpacIdReserve, - listKey: rSecondarySortKey + milpacIdReserve, - }); - //uniqueNamesSet.add(rFullName); } // Sort the array based on the order of positionIds in the billetBankObject array. This is mostly accurate, however ranks are not taken into account in the final display - - returnArray[index].sort((a, b) => { - const aIndex = billetBankObject[index].indexOf(a.sortKey); - const bIndex = billetBankObject[index].indexOf(b.sortKey); - return aIndex - bIndex; - }); } } + returnArray.sort((a, b) => { + const aIndex = a.sortKey; + const bIndex = b.sortKey; + return aIndex - bIndex; + }); + + console.log(returnArray); return ( -
- +
+
+
{props.subtitle}
+
+ Unit Strength: {uniqueNamesSet.size} +
+
+
+ +
); } diff --git a/client/app/adr/page.css b/client/app/adr/page.css index 1ae39a9..73d1241 100644 --- a/client/app/adr/page.css +++ b/client/app/adr/page.css @@ -239,3 +239,11 @@ /* No idea why i have to do this stupidity. For some reason if I dont do this, this shit becomes off centered */ transform-origin: 67% 67%; } + +.CounterSubtitle { + display: flex; +} + +.Counter { + font-weight: bold; +} diff --git a/client/app/adr/page.jsx b/client/app/adr/page.jsx index b830c9f..3903b7e 100644 --- a/client/app/adr/page.jsx +++ b/client/app/adr/page.jsx @@ -2,6 +2,7 @@ import Link from "next/link"; import GetCombatRoster from "../reusableModules/getCombatRoster"; import GetReserveRoster from "../reusableModules/getReserveRoster"; import GetApiTimestamp from "../reusableModules/getApiTimestamp"; +import GetRosterGroups from "../reusableModules/getGroups"; import AdrListEntry from "./modules/AdrListEntry"; import Logo from "../theme/adrLogo"; import "./page.css"; @@ -12,14 +13,30 @@ export const metadata = { }; export default async function ActiveDutyRoster() { - const [combat, reserve, timestamp] = await Promise.all([ + const [combat, reserve, timestamp, groups] = await Promise.all([ GetCombatRoster(), GetReserveRoster(), GetApiTimestamp(), + GetRosterGroups(), ]); const milpacArray = [{ combat, reserve }]; + const rosterGroups = groups; + const units = [ + { title: "Regimental Command", selectors: [0] }, + { title: "First Battalion", selectors: [2, 3, 4, 5, 6] }, + { title: "Second Battalion", selectors: [7, 8, 9, 10, 11] }, + { title: "Third Battalion", selectors: [12, 15, 13 /*, 14*/] }, + { + title: "Auxiallary Combat Division", + selectors: [16, 17, 18 /*, 19*/, 20], + }, + { + title: "Support Departments", + selectors: [1], + }, + ]; return (
@@ -50,15 +67,25 @@ export default async function ActiveDutyRoster() {
- {/* note: bBGroup = Billet Bank Group */} - - - + {units.map((unit) => ( +
+
{unit.title}
+ {unit.selectors.map((selector) => ( + + ))} +
+ ))} + {/* - + */}
); diff --git a/client/app/reusableModules/getGroups.jsx b/client/app/reusableModules/getGroups.jsx new file mode 100644 index 0000000..5c8c3f9 --- /dev/null +++ b/client/app/reusableModules/getGroups.jsx @@ -0,0 +1,17 @@ +const CLIENT_TOKEN = process.env.NEXT_PUBLIC_CLIENT_TOKEN; +const GROUP_API_URL = process.env.GROUP_API_URL; + +export default async function GetRosterGroups() { + const response = await fetch(GROUP_API_URL, { + headers: { + Authorization: CLIENT_TOKEN, + }, + cache: "no-store", + }); + + if (!response.ok) { + throw new Error("HTTP Error! status: " + response.status); + } + + return await response.json(); +} diff --git a/server/controllers/cacheManager.js b/server/controllers/cacheManager.js index 6470693..78c73de 100644 --- a/server/controllers/cacheManager.js +++ b/server/controllers/cacheManager.js @@ -6,11 +6,13 @@ let cacheStatus = { combat: false, reserve: false, individual: false, + groups: false, }; let cachedCombatRoster; let cachedReserveRoster; let cachedIndividual; +let cachedGroups; let cacheTime = {}; axiosRetry(axios, { @@ -83,6 +85,30 @@ const updateCachedIndividual = async (userName) => { } }; +const updateCachedGroups = async () => { + try { + const response = await axios( + `https://api.7cav.us/api/v1/milpacs/position/groups`, + { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + Authorization: "Bearer " + API_TOKEN, + "Accept-Encoding": "gzip", + }, + } + ); + cachedGroups = response.data; + cacheTime["individual"] = Date.now(); + cacheStatus.groups = true; + return cachedGroups; + } catch (error) { + console.error("Failed to update individual user cache:", error); + cacheStatus.groups = false; + return null; + } +}; + const scheduleCacheUpdate = (updateFunction) => { const now = new Date(); const delay = @@ -99,9 +125,14 @@ const initializeCache = async () => { // Initial cache update await updateCombatRosterCache(); await updateReserveRosterCache(); + await updateCachedGroups(); // Check if cache is valid - if (!cacheStatus["combat"] || !cacheStatus["reserve"]) { + if ( + !cacheStatus["combat"] || + !cacheStatus["reserve"] || + !cacheStatus["groups"] + ) { console.error("Failed to initialize cache. Exiting..."); process.exit(1); // Exit to trigger Docker restart } @@ -109,6 +140,7 @@ const initializeCache = async () => { // Schedule the updates scheduleCacheUpdate(updateCombatRosterCache); scheduleCacheUpdate(updateReserveRosterCache); + scheduleCacheUpdate(updateCachedGroups); } catch (error) { console.error("Critical error during cache initialization:", error); process.exit(1); // Exit to trigger Docker restart @@ -127,11 +159,16 @@ const getCachedIndividual = () => { return cachedIndividual; }; +const getCachedGroups = () => { + return cachedGroups; +}; + module.exports = { updateCachedIndividual, getCachedCombatRoster, getCachedReserveRoster, getCachedIndividual, + getCachedGroups, cacheTime, initializeCache, }; diff --git a/server/controllers/gRequest.js b/server/controllers/gRequest.js new file mode 100644 index 0000000..3a26d04 --- /dev/null +++ b/server/controllers/gRequest.js @@ -0,0 +1,11 @@ +const cacheManager = require("../controllers/cacheManager"); + +module.exports = async (req, res) => { + const cachedGroups = cacheManager.getCachedGroups(); + + if (cachedGroups) { + res.send(cachedGroups); + } else { + res.status(503).send("Cache is empty"); + } +}; diff --git a/server/routes/index.js b/server/routes/index.js index 67f962e..23878ef 100644 --- a/server/routes/index.js +++ b/server/routes/index.js @@ -4,6 +4,7 @@ const cors = require("cors"); const cRequest = require("../controllers/cRequest"); const rRequest = require("../controllers/rRequest"); const iRequest = require("../controllers/iRequest"); +const gRequest = require("../controllers/gRequest"); const app = express(); app.use( @@ -21,4 +22,5 @@ router.get("/individual", (req, res) => { } iRequest(req, res, userName); }); +router.get("/groups", gRequest); module.exports = router;
- {props.headerTitles[index]} - - Unit Strength: {inputArray[index].length} -
+ + {item.fullName} + + {item.position.positionTitle}
- - {item.fullName} - - {item.position.positionTitle}