From b73b56761b9e8ed48ec9c27f09c74fa26fda8612 Mon Sep 17 00:00:00 2001 From: Vercin-G <97210222+Vercin-G@users.noreply.github.com> Date: Mon, 21 Jul 2025 12:54:02 -0600 Subject: [PATCH 01/11] Update Cache Manager to get groups --- server/controllers/cacheManager.js | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/server/controllers/cacheManager.js b/server/controllers/cacheManager.js index 6470693..0f4b3a9 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", + }, + } + ); + cachedGroup = response.data; + cacheTime["individual"] = Date.now(); + cacheStatus.groups = true; + return cachedIndividual; + } 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,6 +125,7 @@ const initializeCache = async () => { // Initial cache update await updateCombatRosterCache(); await updateReserveRosterCache(); + await updateCachedGroups(); // Check if cache is valid if (!cacheStatus["combat"] || !cacheStatus["reserve"]) { @@ -109,6 +136,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 +155,16 @@ const getCachedIndividual = () => { return cachedIndividual; }; +const getCachedGroups = () => { + return cachedGroups; +}; + module.exports = { updateCachedIndividual, getCachedCombatRoster, getCachedReserveRoster, getCachedIndividual, + getCachedGroups, cacheTime, initializeCache, }; From 1b022fe5481e53056a5db4348c49c31091e1836c Mon Sep 17 00:00:00 2001 From: Vercin-G <97210222+Vercin-G@users.noreply.github.com> Date: Mon, 21 Jul 2025 12:56:06 -0600 Subject: [PATCH 02/11] Implement gRequest Function --- server/controllers/gRequest.js | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 server/controllers/gRequest.js 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"); + } +}; From df20fbddbe6d80add85c7d6e9a1bbaa2ec381844 Mon Sep 17 00:00:00 2001 From: Vercin-G <97210222+Vercin-G@users.noreply.github.com> Date: Mon, 21 Jul 2025 12:59:42 -0600 Subject: [PATCH 03/11] add group request to router --- server/routes/index.js | 2 ++ 1 file changed, 2 insertions(+) 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; From 1e5353a09e692112f87a970a2303131c0e621a9a Mon Sep 17 00:00:00 2001 From: Vercin-G <97210222+Vercin-G@users.noreply.github.com> Date: Mon, 21 Jul 2025 13:08:26 -0600 Subject: [PATCH 04/11] getGroups function for clientside --- client/app/reusableModules/getGroups.jsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 client/app/reusableModules/getGroups.jsx diff --git a/client/app/reusableModules/getGroups.jsx b/client/app/reusableModules/getGroups.jsx new file mode 100644 index 0000000..191e336 --- /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 GetCombatRoster() { + 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(); +} From d9a9383936aa5a478d4283dfaf881780a986880d Mon Sep 17 00:00:00 2001 From: Vercin-G <97210222+Vercin-G@users.noreply.github.com> Date: Mon, 21 Jul 2025 13:11:20 -0600 Subject: [PATCH 05/11] verify result on test page --- client/app/reusableModules/getGroups.jsx | 2 +- client/app/test/page.jsx | 30 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 client/app/test/page.jsx diff --git a/client/app/reusableModules/getGroups.jsx b/client/app/reusableModules/getGroups.jsx index 191e336..5c8c3f9 100644 --- a/client/app/reusableModules/getGroups.jsx +++ b/client/app/reusableModules/getGroups.jsx @@ -1,7 +1,7 @@ const CLIENT_TOKEN = process.env.NEXT_PUBLIC_CLIENT_TOKEN; const GROUP_API_URL = process.env.GROUP_API_URL; -export default async function GetCombatRoster() { +export default async function GetRosterGroups() { const response = await fetch(GROUP_API_URL, { headers: { Authorization: CLIENT_TOKEN, diff --git a/client/app/test/page.jsx b/client/app/test/page.jsx new file mode 100644 index 0000000..1436fa4 --- /dev/null +++ b/client/app/test/page.jsx @@ -0,0 +1,30 @@ +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"; +import "../globals.css"; + +export const metadata = { + title: "Active Duty Roster", +}; + +export default async function ActiveDutyRoster() { + const [combat, reserve, timestamp, groups] = await Promise.all([ + GetCombatRoster(), + GetReserveRoster(), + GetApiTimestamp(), + GetRosterGroups(), + ]); + + const milpacArray = [{ combat, reserve }]; + const rosterGroups = groups; + + console.log(milpacArray); + console.log(rosterGroups); + + return

Hello there!

; +} From b5f8f3f768409669bfcc1337059794382b13d84a Mon Sep 17 00:00:00 2001 From: Vercin-G <97210222+Vercin-G@users.noreply.github.com> Date: Mon, 21 Jul 2025 13:21:54 -0600 Subject: [PATCH 06/11] fix bugs in prior commits --- client/app/test/page.jsx | 5 ++--- server/controllers/cacheManager.js | 10 +++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/client/app/test/page.jsx b/client/app/test/page.jsx index 1436fa4..3d60884 100644 --- a/client/app/test/page.jsx +++ b/client/app/test/page.jsx @@ -3,10 +3,9 @@ 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"; -import "../globals.css"; +//import "./page.css"; +//import "../globals.css"; export const metadata = { title: "Active Duty Roster", diff --git a/server/controllers/cacheManager.js b/server/controllers/cacheManager.js index 0f4b3a9..78c73de 100644 --- a/server/controllers/cacheManager.js +++ b/server/controllers/cacheManager.js @@ -98,10 +98,10 @@ const updateCachedGroups = async () => { }, } ); - cachedGroup = response.data; + cachedGroups = response.data; cacheTime["individual"] = Date.now(); cacheStatus.groups = true; - return cachedIndividual; + return cachedGroups; } catch (error) { console.error("Failed to update individual user cache:", error); cacheStatus.groups = false; @@ -128,7 +128,11 @@ const initializeCache = async () => { 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 } From 143f677855a190e2a1053cb9f9fdb8915e528a52 Mon Sep 17 00:00:00 2001 From: Vercin-G <97210222+Vercin-G@users.noreply.github.com> Date: Mon, 21 Jul 2025 13:29:23 -0600 Subject: [PATCH 07/11] import current ADR code to set up dev enviornment --- client/app/test/loading.jsx | 18 ++ client/app/test/modules/AdrListEntry.jsx | 23 +++ client/app/test/modules/ArrayBuilder.js | 11 ++ client/app/test/modules/ArrayMap.jsx | 41 ++++ client/app/test/modules/MilpacParse.jsx | 137 +++++++++++++ client/app/test/page.css | 241 +++++++++++++++++++++++ client/app/test/page.jsx | 48 ++++- 7 files changed, 516 insertions(+), 3 deletions(-) create mode 100644 client/app/test/loading.jsx create mode 100644 client/app/test/modules/AdrListEntry.jsx create mode 100644 client/app/test/modules/ArrayBuilder.js create mode 100644 client/app/test/modules/ArrayMap.jsx create mode 100644 client/app/test/modules/MilpacParse.jsx create mode 100644 client/app/test/page.css diff --git a/client/app/test/loading.jsx b/client/app/test/loading.jsx new file mode 100644 index 0000000..1da2465 --- /dev/null +++ b/client/app/test/loading.jsx @@ -0,0 +1,18 @@ +import "./page.css"; + +export default function Loading() { + return ( +
+
+
+ {/*This gif is about 150kb. Kinda big, relatively speaking. An Svg may be desired in the furture */} + Loading +
+
Loading...
+
+ ); +} diff --git a/client/app/test/modules/AdrListEntry.jsx b/client/app/test/modules/AdrListEntry.jsx new file mode 100644 index 0000000..a979b2a --- /dev/null +++ b/client/app/test/modules/AdrListEntry.jsx @@ -0,0 +1,23 @@ +import React from "react"; +import MilpacParse from "./MilpacParse"; +import lists from "../../reusableModules/BilletBank"; + +function AdrListEntry(props) { + let billetBankObject = lists.billetBankObject; + let selector = props.bBGroup; + + return ( +
+
{billetBankObject[selector].collapsibleTitle}
+
+ +
+
+ ); +} + +export default AdrListEntry; diff --git a/client/app/test/modules/ArrayBuilder.js b/client/app/test/modules/ArrayBuilder.js new file mode 100644 index 0000000..094b05a --- /dev/null +++ b/client/app/test/modules/ArrayBuilder.js @@ -0,0 +1,11 @@ +//This is included as a dev tool to generate bulk billet list entries in sequential order. run this outside of cavApps. +let countString = ""; +let i = 629; +let stopper = 644; + +do { + countString = `${countString},'${i}'`; + i++; +} while (i <= stopper); + +console.log(countString); diff --git a/client/app/test/modules/ArrayMap.jsx b/client/app/test/modules/ArrayMap.jsx new file mode 100644 index 0000000..8a24947 --- /dev/null +++ b/client/app/test/modules/ArrayMap.jsx @@ -0,0 +1,41 @@ +import React from "react"; + +/*This function is probably the most complicated code in the ADR. Essentially, it takes inputArray and headerTitles, and iterates through the first layer of inputArray's arrays +which in this case is the battalion level. At the battalion level, it creates a table row for each company, adding the company title (defined in BilletBank.js) and unit strength counter. +After the title and counter are created for the company level, the lists themselves for each company are created, which are the second layer of arrays. The lists themselves contain +milpac link, name and rank, and position title.*/ + +function ArrayMap(props) { + let inputArray = props.inputArray; + + return ( + + + {inputArray.map((subArray, index) => ( + + + + + + {subArray.map((item, subIndex) => ( + + + + + ))} + + ))} + +
+ {props.headerTitles[index]} + + Unit Strength: {inputArray[index].length} +
+ + {item.fullName} + + {item.position.positionTitle}
+ ); +} + +export default ArrayMap; diff --git a/client/app/test/modules/MilpacParse.jsx b/client/app/test/modules/MilpacParse.jsx new file mode 100644 index 0000000..a7526be --- /dev/null +++ b/client/app/test/modules/MilpacParse.jsx @@ -0,0 +1,137 @@ +import React from "react"; +import ArrayMap from "./ArrayMap"; + +/*Milpac Parse is used to compare the API response (milpacArray) against desired position ID's (billetBankObject). If for example, a person is a Milpacs Clerk and billetBankObject +is set to check for Milpacs Clerks, Milpac Parse will search for matching entries within the API resonse. If there is someone that matches, they are pushed to an output array. (returnArray) +This particular instance of milpacArray is designed to parse an entire object for matching entries, i.e. It will parse all of First Battalion, and push out an array +for each company within first battalion if asked to do so.*/ + +function MilpacParse(props) { + const billetBankObject = props.billetBankObject; + let milpacArray = props.milpacArray; + + //Currently broken. Sypolt, pls fix. + //const uniqueNamesSet = new Set(); + + let returnArray = Array(billetBankObject.length) + .fill() + .map(() => []); + + //First, check the combat roster primaries for matching billet id's, then push them to the return array if match is found. + + for (let milpacIdCombat in milpacArray[0].combat.profiles) { + let name = milpacArray[0].combat.profiles[milpacIdCombat].realName; + let rank = milpacArray[0].combat.profiles[milpacIdCombat].rank.rankFull; + let primary = milpacArray[0].combat.profiles[milpacIdCombat].primary; + let fullName = rank + " " + name; + let primarySortKey = + milpacArray[0].combat.profiles[milpacIdCombat].primary.positionId; + + for (let index in billetBankObject) { + if (billetBankObject[index].includes(primary.positionId)) { + returnArray[index].push({ + fullName: fullName, + position: primary, + isPrimary: "true", + sortKey: primarySortKey, + itemKey: milpacIdCombat, + listKey: primarySortKey + milpacIdCombat, + }); + //uniqueNamesSet.add(fullName); + } + + //Next, check the combat roster secondaries for matching billet id's, then push to return array if match is found. + + for (let index2 in milpacArray[0].combat.profiles[milpacIdCombat] + .secondaries) { + let secondary = + milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2]; + let secondarySortKey = + milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2] + .positionId; + + if (!billetBankObject[index].includes(secondary.positionId)) { + continue; + } + + returnArray[index].push({ + fullName: fullName, + position: secondary, + isPrimary: "false", + sortKey: secondarySortKey, + itemKey: milpacIdCombat, + listKey: secondarySortKey + milpacIdCombat, + }); + //uniqueNamesSet.add(fullName); + } + } + } + + //After the Combat Roster, check the Reserves. + + for (let milpacIdReserve in milpacArray[0].reserve.profiles) { + let rName = milpacArray[0].reserve.profiles[milpacIdReserve].realName; + let rRank = milpacArray[0].reserve.profiles[milpacIdReserve].rank.rankFull; + let rPrimary = milpacArray[0].reserve.profiles[milpacIdReserve].primary; + let rFullName = rRank + " " + rName; + let rPrimarySortKey = + milpacArray[0].reserve.profiles[milpacIdReserve].primary.positionId; + + //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({ + fullName: rFullName, + position: rPrimary, + isPrimary: "true", + sortKey: rPrimarySortKey, + itemKey: milpacIdReserve, + listKey: rPrimarySortKey + milpacIdReserve, + }); + //uniqueNamesSet.add(rFullName); + } + + //Check the Reserve secondaries, then push to return array if match is found. + + for (let rIndex in milpacArray[0].reserve.profiles[milpacIdReserve] + .secondaries) { + let rSecondary = + milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex]; + let rSecondarySortKey = + milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex] + .positionId; + + if (!billetBankObject[index].includes(rSecondary.positionId)) { + continue; + } + + 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; + }); + } + } + + return ( +
+ +
+ ); +} + +export default MilpacParse; diff --git a/client/app/test/page.css b/client/app/test/page.css new file mode 100644 index 0000000..1ae39a9 --- /dev/null +++ b/client/app/test/page.css @@ -0,0 +1,241 @@ +.DepartmentContainer { + margin: auto; + min-width: 30%; + max-width: 30%; +} + +@media only screen and (max-width: 1000px) { + .DepartmentContainer { + min-width: 50%; + max-width: 95%; + } +} + +.p-nav-primary { + position: sticky; + top: 0; + z-index: 400; + background-color: #2e2e2e; + margin-bottom: 1.2em; +} + +.p-nav { + display: block; + overflow-wrap: break-word; +} + +.p-nav-logo { + align-self: center; + box-sizing: border-box; + display: block; + max-width: 220px; + line-height: 21px; + padding: 3px; +} + +.loading-container { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + min-height: 60vh; + flex-direction: column; +} + +.gif-spinner-wrapper { + position: relative; +} + +.spinner { + border: 0.5em solid #f3f3f3; + border-top: 0.5em solid #ebc729; + border-radius: 50%; + width: 11em; + /* Make this larger than the GIF */ + height: 11em; + /* Make this larger than the GIF */ + animation: spin 2s linear infinite; + position: absolute; + top: 30%; + left: 30%; + z-index: 1; + margin: -4em 0 0 -4.5em; + /* Half of width and height */ +} + +.p-loading-png { + width: 8em; + height: 8em; + position: relative; + z-index: 2; + transform: translatex(-7%); +} + +.loading-subtitle { + color: #f1f1f1; + font-size: x-large; + font-weight: bold; + padding: 1em; +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} + +.cache-time { + color: #ebc729; + font-weight: bold; + margin-left: 20px; +} + +.error-container { + display: flex; + justify-content: center; + align-items: flex-start; + height: 100%; + min-height: 100vh; +} + +.p-nav-scroller { + display: flex; + align-items: center; + justify-content: center; +} + +.p-nav-png { + max-width: 220px; + max-height: 37.7167px; + flex: 1 1 auto; +} + +.p-nav-opposite { + text-align: right; + flex: 1 1 auto; + margin: 5px; +} + +.p-nav-opposite-link { + color: #f1f1f1; + font-weight: bold; +} + +.p-nav-png { + width: 220px; + height: 37.7167px; +} + +.p-nav-info p { + display: flex; + align-items: center; +} + +/* Mobile layout */ +@media (max-width: 768px) { + .p-nav-scroller { + flex-direction: column; + align-items: center; + justify-content: center; + /* Center-align items vertically */ + } + + .p-nav-info p { + margin-left: 0; + margin-top: 10px; + /* Add some space between the logo and the text */ + } +} + +.Title { + color: #f1f1f1; + font-size: x-large; + font-weight: bold; + border-width: 1px; + border-style: solid; + border-image: linear-gradient(to right, #ebc729, transparent) 1 0%; + border-top: transparent; +} + +@media only screen and (max-width: 1000px) { + .Title { + border-image: none; + border-color: #ebc729; + border-left: transparent; + border-right: transparent; + } +} + +/* This is a very hack-y way to make the borders look proper on mobile browsers. This is because the border image property does not appear to be properly supported with IOS' Safari */ + +.Subtitle { + color: #f1f1f1; + font-size: larger; + font-weight: bold; + padding-top: 15px; + padding-bottom: 15px; +} + +/*.Title:hover { + text-decoration: none; + cursor: pointer; +} */ + +.HeaderContainer { + display: flex; +} + +.Counter { + font-size: smaller; + padding-top: 20px; + padding-bottom: 15px; + margin-left: auto; +} + +.ItemList table { + width: 100%; + margin-left: auto; + margin-right: auto; +} + +.ItemList thead { + display: none; +} + +.ItemList td { + padding-bottom: 7px; + padding-left: 10px; + width: 50%; +} + +.Collapsible__trigger { + display: block; + position: relative; +} + +.Collapsible__trigger:after { + content: none; + position: absolute; + right: 0px; + top: 0px; + display: block; + transition: transform 300ms; + transform: rotateZ(90deg); + + /* 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%; +} + +.Collapsible__trigger.is-open::after { + transform: rotateZ(180deg); + position: absolute; + right: 0px; + top: 0px; + + /* 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%; +} diff --git a/client/app/test/page.jsx b/client/app/test/page.jsx index 3d60884..f919052 100644 --- a/client/app/test/page.jsx +++ b/client/app/test/page.jsx @@ -3,9 +3,10 @@ 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"; -//import "../globals.css"; +import "./page.css"; +import "../globals.css"; export const metadata = { title: "Active Duty Roster", @@ -25,5 +26,46 @@ export default async function ActiveDutyRoster() { console.log(milpacArray); console.log(rosterGroups); - return

Hello there!

; + return ( +
+
+
+ +
+
+
+ {/* note: bBGroup = Billet Bank Group */} + + + + + + + + +
+
+ ); } From c3399de509a4b94a7e2b696d290f947d2745c53c Mon Sep 17 00:00:00 2001 From: Vercin-G <97210222+Vercin-G@users.noreply.github.com> Date: Mon, 21 Jul 2025 15:23:29 -0600 Subject: [PATCH 08/11] Code Restructure and initial implementation --- client/app/test/modules/AdrListEntry.jsx | 20 +-- client/app/test/modules/ArrayMap.jsx | 27 ++-- client/app/test/modules/MilpacParse.jsx | 180 ++++++++++++----------- client/app/test/page.jsx | 21 ++- 4 files changed, 128 insertions(+), 120 deletions(-) diff --git a/client/app/test/modules/AdrListEntry.jsx b/client/app/test/modules/AdrListEntry.jsx index a979b2a..edb5c7e 100644 --- a/client/app/test/modules/AdrListEntry.jsx +++ b/client/app/test/modules/AdrListEntry.jsx @@ -1,21 +1,17 @@ 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}
-
- -
+
+
{rosterGroups[selector].groupTitle}
+
); } diff --git a/client/app/test/modules/ArrayMap.jsx b/client/app/test/modules/ArrayMap.jsx index 8a24947..4d73aad 100644 --- a/client/app/test/modules/ArrayMap.jsx +++ b/client/app/test/modules/ArrayMap.jsx @@ -7,30 +7,29 @@ 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/test/modules/MilpacParse.jsx b/client/app/test/modules/MilpacParse.jsx index a7526be..24430e8 100644 --- a/client/app/test/modules/MilpacParse.jsx +++ b/client/app/test/modules/MilpacParse.jsx @@ -7,15 +7,19 @@ 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; + console.log(rosterGroups); + //Currently broken. Sypolt, pls fix. //const uniqueNamesSet = new Set(); - let returnArray = Array(billetBankObject.length) - .fill() - .map(() => []); + let returnArray = []; + + // let returnArray = Array(rosterGroups.length) + // .fill() + // .map(() => []); //First, check the combat roster primaries for matching billet id's, then push them to the return array if match is found. @@ -27,13 +31,13 @@ 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, }); @@ -42,90 +46,92 @@ function MilpacParse(props) { //Next, check the combat roster secondaries for matching billet id's, then push to return array if match is found. - for (let index2 in milpacArray[0].combat.profiles[milpacIdCombat] - .secondaries) { - let secondary = - milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2]; - let secondarySortKey = - milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2] - .positionId; - - if (!billetBankObject[index].includes(secondary.positionId)) { - continue; - } - - returnArray[index].push({ - fullName: fullName, - position: secondary, - isPrimary: "false", - sortKey: secondarySortKey, - itemKey: milpacIdCombat, - listKey: secondarySortKey + milpacIdCombat, - }); - //uniqueNamesSet.add(fullName); - } + // for (let index2 in milpacArray[0].combat.profiles[milpacIdCombat] + // .secondaries) { + // let secondary = + // milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2]; + // let secondarySortKey = + // milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2] + // .positionId; + + // if (!rosterGroups[index].positionId.includes(secondary.positionId)) { + // continue; + // } + + // returnArray[index].push({ + // fullName: fullName, + // position: secondary, + // isPrimary: "false", + // sortKey: secondarySortKey, + // itemKey: milpacIdCombat, + // listKey: secondarySortKey + milpacIdCombat, + // }); + // //uniqueNamesSet.add(fullName); + // } } } //After the Combat Roster, check the Reserves. - for (let milpacIdReserve in milpacArray[0].reserve.profiles) { - let rName = milpacArray[0].reserve.profiles[milpacIdReserve].realName; - let rRank = milpacArray[0].reserve.profiles[milpacIdReserve].rank.rankFull; - let rPrimary = milpacArray[0].reserve.profiles[milpacIdReserve].primary; - let rFullName = rRank + " " + rName; - let rPrimarySortKey = - milpacArray[0].reserve.profiles[milpacIdReserve].primary.positionId; - - //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({ - fullName: rFullName, - position: rPrimary, - isPrimary: "true", - sortKey: rPrimarySortKey, - itemKey: milpacIdReserve, - listKey: rPrimarySortKey + milpacIdReserve, - }); - //uniqueNamesSet.add(rFullName); - } - - //Check the Reserve secondaries, then push to return array if match is found. - - for (let rIndex in milpacArray[0].reserve.profiles[milpacIdReserve] - .secondaries) { - let rSecondary = - milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex]; - let rSecondarySortKey = - milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex] - .positionId; - - if (!billetBankObject[index].includes(rSecondary.positionId)) { - continue; - } - - 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; - }); - } - } + // for (let milpacIdReserve in milpacArray[0].reserve.profiles) { + // let rName = milpacArray[0].reserve.profiles[milpacIdReserve].realName; + // let rRank = milpacArray[0].reserve.profiles[milpacIdReserve].rank.rankFull; + // let rPrimary = milpacArray[0].reserve.profiles[milpacIdReserve].primary; + // let rFullName = rRank + " " + rName; + // let rPrimarySortKey = + // milpacArray[0].reserve.profiles[milpacIdReserve].primary.positionId; + + // //Check the Reserve primaries, then push to return array if match is found. + + // for (let index in rosterGroups) { + // if (rosterGroups[index].positionId.includes(rPrimary.positionId)) { + // returnArray[index].push({ + // fullName: rFullName, + // position: rPrimary, + // isPrimary: "true", + // sortKey: rPrimarySortKey, + // itemKey: milpacIdReserve, + // listKey: rPrimarySortKey + milpacIdReserve, + // }); + // //uniqueNamesSet.add(rFullName); + // } + + // //Check the Reserve secondaries, then push to return array if match is found. + + // for (let rIndex in milpacArray[0].reserve.profiles[milpacIdReserve] + // .secondaries) { + // let rSecondary = + // milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex]; + // let rSecondarySortKey = + // milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex] + // .positionId; + + // if (!rosterGroups[index].positionId.includes(rSecondary.positionId)) { + // continue; + // } + + // 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.sort((a, b) => { + const aIndex = a.sortKey; + const bIndex = b.sortKey; + return aIndex - bIndex; + }); + // } + // } + + console.log(returnArray); return (
diff --git a/client/app/test/page.jsx b/client/app/test/page.jsx index f919052..468befd 100644 --- a/client/app/test/page.jsx +++ b/client/app/test/page.jsx @@ -23,8 +23,7 @@ export default async function ActiveDutyRoster() { const milpacArray = [{ combat, reserve }]; const rosterGroups = groups; - console.log(milpacArray); - console.log(rosterGroups); + const firstBattGroups = [2, 3, 4, 5, 6]; return (
@@ -56,15 +55,23 @@ export default async function ActiveDutyRoster() {
- {/* note: bBGroup = Billet Bank Group */} - - - + {/* */} +
+
First Battalion
+ {firstBattGroups.map((selector) => ( + + ))} +
+ {/* - + */}
); From 28131a9491000e8cfbba8d2394e90efe9711fe77 Mon Sep 17 00:00:00 2001 From: Vercin-G <97210222+Vercin-G@users.noreply.github.com> Date: Mon, 21 Jul 2025 15:42:18 -0600 Subject: [PATCH 09/11] Make Subtitles (and counters) Great Again! --- client/app/test/modules/AdrListEntry.jsx | 2 +- client/app/test/modules/ArrayMap.jsx | 8 -------- client/app/test/modules/MilpacParse.jsx | 16 ++++++++++++---- client/app/test/page.css | 8 ++++++++ 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/client/app/test/modules/AdrListEntry.jsx b/client/app/test/modules/AdrListEntry.jsx index edb5c7e..38f6862 100644 --- a/client/app/test/modules/AdrListEntry.jsx +++ b/client/app/test/modules/AdrListEntry.jsx @@ -7,10 +7,10 @@ function AdrListEntry(props) { return (
-
{rosterGroups[selector].groupTitle}
); diff --git a/client/app/test/modules/ArrayMap.jsx b/client/app/test/modules/ArrayMap.jsx index 4d73aad..262f801 100644 --- a/client/app/test/modules/ArrayMap.jsx +++ b/client/app/test/modules/ArrayMap.jsx @@ -14,14 +14,6 @@ function ArrayMap(props) { {inputArray.map((item, index) => ( - {/* - {/* - - */}
+ {/*
{props.headerTitles[index]} - Unit Strength: {inputArray[index].length}
+ + {item.fullName} + + {item.position.positionTitle}
- - {item.fullName} - - {item.position.positionTitle}
- {props.headerTitles[index]} - - Unit Strength: {inputArray[index].length} -
diff --git a/client/app/test/modules/MilpacParse.jsx b/client/app/test/modules/MilpacParse.jsx index 24430e8..7891a63 100644 --- a/client/app/test/modules/MilpacParse.jsx +++ b/client/app/test/modules/MilpacParse.jsx @@ -13,7 +13,7 @@ function MilpacParse(props) { console.log(rosterGroups); //Currently broken. Sypolt, pls fix. - //const uniqueNamesSet = new Set(); + const uniqueNamesSet = new Set(); let returnArray = []; @@ -41,7 +41,7 @@ function MilpacParse(props) { 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. @@ -134,8 +134,16 @@ function MilpacParse(props) { console.log(returnArray); return ( -
- +
+
+
{props.subtitle}
+
+ Unit Strength: {uniqueNamesSet.size} +
+
+
+ +
); } diff --git a/client/app/test/page.css b/client/app/test/page.css index 1ae39a9..73d1241 100644 --- a/client/app/test/page.css +++ b/client/app/test/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; +} From e194be19ad38d684604cfc0022ca8afb84af54c9 Mon Sep 17 00:00:00 2001 From: Vercin-G <97210222+Vercin-G@users.noreply.github.com> Date: Mon, 21 Jul 2025 16:47:43 -0600 Subject: [PATCH 10/11] Abstract to Battalion level units. --- client/app/test/modules/AdrListEntry.jsx | 2 + client/app/test/modules/MilpacParse.jsx | 146 +++++++++++------------ client/app/test/page.jsx | 40 +++++-- 3 files changed, 97 insertions(+), 91 deletions(-) diff --git a/client/app/test/modules/AdrListEntry.jsx b/client/app/test/modules/AdrListEntry.jsx index 38f6862..e106148 100644 --- a/client/app/test/modules/AdrListEntry.jsx +++ b/client/app/test/modules/AdrListEntry.jsx @@ -1,3 +1,5 @@ +//Honestly, I could probably just delete this file. + import React from "react"; import MilpacParse from "./MilpacParse"; diff --git a/client/app/test/modules/MilpacParse.jsx b/client/app/test/modules/MilpacParse.jsx index 7891a63..0dc8960 100644 --- a/client/app/test/modules/MilpacParse.jsx +++ b/client/app/test/modules/MilpacParse.jsx @@ -12,15 +12,10 @@ function MilpacParse(props) { console.log(rosterGroups); - //Currently broken. Sypolt, pls fix. const uniqueNamesSet = new Set(); let returnArray = []; - // let returnArray = Array(rosterGroups.length) - // .fill() - // .map(() => []); - //First, check the combat roster primaries for matching billet id's, then push them to the return array if match is found. for (let milpacIdCombat in milpacArray[0].combat.profiles) { @@ -46,90 +41,85 @@ function MilpacParse(props) { //Next, check the combat roster secondaries for matching billet id's, then push to return array if match is found. - // for (let index2 in milpacArray[0].combat.profiles[milpacIdCombat] - // .secondaries) { - // let secondary = - // milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2]; - // let secondarySortKey = - // milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2] - // .positionId; - - // if (!rosterGroups[index].positionId.includes(secondary.positionId)) { - // continue; - // } - - // returnArray[index].push({ - // fullName: fullName, - // position: secondary, - // isPrimary: "false", - // sortKey: secondarySortKey, - // itemKey: milpacIdCombat, - // listKey: secondarySortKey + milpacIdCombat, - // }); - // //uniqueNamesSet.add(fullName); - // } + for (let index2 in milpacArray[0].combat.profiles[milpacIdCombat] + .secondaries) { + let secondary = + milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2]; + let secondarySortKey = + milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2] + .positionId; + + 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); + } + } } } //After the Combat Roster, check the Reserves. - // for (let milpacIdReserve in milpacArray[0].reserve.profiles) { - // let rName = milpacArray[0].reserve.profiles[milpacIdReserve].realName; - // let rRank = milpacArray[0].reserve.profiles[milpacIdReserve].rank.rankFull; - // let rPrimary = milpacArray[0].reserve.profiles[milpacIdReserve].primary; - // let rFullName = rRank + " " + rName; - // let rPrimarySortKey = - // milpacArray[0].reserve.profiles[milpacIdReserve].primary.positionId; - - // //Check the Reserve primaries, then push to return array if match is found. - - // for (let index in rosterGroups) { - // if (rosterGroups[index].positionId.includes(rPrimary.positionId)) { - // returnArray[index].push({ - // fullName: rFullName, - // position: rPrimary, - // isPrimary: "true", - // sortKey: rPrimarySortKey, - // itemKey: milpacIdReserve, - // listKey: rPrimarySortKey + milpacIdReserve, - // }); - // //uniqueNamesSet.add(rFullName); - // } - - // //Check the Reserve secondaries, then push to return array if match is found. - - // for (let rIndex in milpacArray[0].reserve.profiles[milpacIdReserve] - // .secondaries) { - // let rSecondary = - // milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex]; - // let rSecondarySortKey = - // milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex] - // .positionId; - - // if (!rosterGroups[index].positionId.includes(rSecondary.positionId)) { - // continue; - // } - - // 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 + for (let milpacIdReserve in milpacArray[0].reserve.profiles) { + let rName = milpacArray[0].reserve.profiles[milpacIdReserve].realName; + let rRank = milpacArray[0].reserve.profiles[milpacIdReserve].rank.rankFull; + let rPrimary = milpacArray[0].reserve.profiles[milpacIdReserve].primary; + let rFullName = rRank + " " + rName; + let rPrimarySortKey = + milpacArray[0].reserve.profiles[milpacIdReserve].primary.positionId; + + //Check the Reserve primaries, then push to return array if match is found. + + for (let index in rosterGroups) { + if (rosterGroups[index].positionId == rPrimary.positionId) { + returnArray.push({ + fullName: rFullName, + position: rPrimary, + isPrimary: "true", + sortKey: rosterGroups[index].positionDisplayOrder, + itemKey: milpacIdReserve, + listKey: rPrimarySortKey + milpacIdReserve, + }); + uniqueNamesSet.add(rFullName); + } + + //Check the Reserve secondaries, then push to return array if match is found. + + for (let rIndex in milpacArray[0].reserve.profiles[milpacIdReserve] + .secondaries) { + let rSecondary = + milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex]; + let rSecondarySortKey = + milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex] + .positionId; + + 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); + } + } + // 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.sort((a, b) => { const aIndex = a.sortKey; const bIndex = b.sortKey; return aIndex - bIndex; }); - // } - // } console.log(returnArray); diff --git a/client/app/test/page.jsx b/client/app/test/page.jsx index 468befd..3903b7e 100644 --- a/client/app/test/page.jsx +++ b/client/app/test/page.jsx @@ -23,8 +23,20 @@ export default async function ActiveDutyRoster() { const milpacArray = [{ combat, reserve }]; const rosterGroups = groups; - const firstBattGroups = [2, 3, 4, 5, 6]; - + 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 (
@@ -55,17 +67,19 @@ export default async function ActiveDutyRoster() {
- {/* */} -
-
First Battalion
- {firstBattGroups.map((selector) => ( - - ))} -
+ {units.map((unit) => ( +
+
{unit.title}
+ {unit.selectors.map((selector) => ( + + ))} +
+ ))} {/* From d88e41726d655c346fd4390d29e4e4d6ff6c3261 Mon Sep 17 00:00:00 2001 From: Vercin-G <97210222+Vercin-G@users.noreply.github.com> Date: Mon, 21 Jul 2025 16:49:33 -0600 Subject: [PATCH 11/11] Merge with ADR proper --- client/app/adr/modules/AdrListEntry.jsx | 22 +- client/app/adr/modules/ArrayMap.jsx | 27 +-- client/app/adr/modules/MilpacParse.jsx | 100 ++++----- client/app/adr/page.css | 8 + client/app/adr/page.jsx | 39 +++- client/app/test/loading.jsx | 18 -- client/app/test/modules/AdrListEntry.jsx | 21 -- client/app/test/modules/ArrayBuilder.js | 11 - client/app/test/modules/ArrayMap.jsx | 32 --- client/app/test/modules/MilpacParse.jsx | 141 ------------- client/app/test/page.css | 249 ----------------------- client/app/test/page.jsx | 92 --------- 12 files changed, 112 insertions(+), 648 deletions(-) delete mode 100644 client/app/test/loading.jsx delete mode 100644 client/app/test/modules/AdrListEntry.jsx delete mode 100644 client/app/test/modules/ArrayBuilder.js delete mode 100644 client/app/test/modules/ArrayMap.jsx delete mode 100644 client/app/test/modules/MilpacParse.jsx delete mode 100644 client/app/test/page.css delete mode 100644 client/app/test/page.jsx 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/test/loading.jsx b/client/app/test/loading.jsx deleted file mode 100644 index 1da2465..0000000 --- a/client/app/test/loading.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import "./page.css"; - -export default function Loading() { - return ( -
-
-
- {/*This gif is about 150kb. Kinda big, relatively speaking. An Svg may be desired in the furture */} - Loading -
-
Loading...
-
- ); -} diff --git a/client/app/test/modules/AdrListEntry.jsx b/client/app/test/modules/AdrListEntry.jsx deleted file mode 100644 index e106148..0000000 --- a/client/app/test/modules/AdrListEntry.jsx +++ /dev/null @@ -1,21 +0,0 @@ -//Honestly, I could probably just delete this file. - -import React from "react"; -import MilpacParse from "./MilpacParse"; - -function AdrListEntry(props) { - const rosterGroups = props.rosterGroups.groups; - const selector = props.rGSelector; - - return ( -
- -
- ); -} - -export default AdrListEntry; diff --git a/client/app/test/modules/ArrayBuilder.js b/client/app/test/modules/ArrayBuilder.js deleted file mode 100644 index 094b05a..0000000 --- a/client/app/test/modules/ArrayBuilder.js +++ /dev/null @@ -1,11 +0,0 @@ -//This is included as a dev tool to generate bulk billet list entries in sequential order. run this outside of cavApps. -let countString = ""; -let i = 629; -let stopper = 644; - -do { - countString = `${countString},'${i}'`; - i++; -} while (i <= stopper); - -console.log(countString); diff --git a/client/app/test/modules/ArrayMap.jsx b/client/app/test/modules/ArrayMap.jsx deleted file mode 100644 index 262f801..0000000 --- a/client/app/test/modules/ArrayMap.jsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from "react"; - -/*This function is probably the most complicated code in the ADR. Essentially, it takes inputArray and headerTitles, and iterates through the first layer of inputArray's arrays -which in this case is the battalion level. At the battalion level, it creates a table row for each company, adding the company title (defined in BilletBank.js) and unit strength counter. -After the title and counter are created for the company level, the lists themselves for each company are created, which are the second layer of arrays. The lists themselves contain -milpac link, name and rank, and position title.*/ - -function ArrayMap(props) { - let inputArray = props.inputArray; - console.log(inputArray); - - return ( -
- {props.headerTitles[index]} - - Unit Strength: {inputArray[index].length} -
+ + {item.fullName} + + {item.position.positionTitle}
- - {item.fullName} - - {item.position.positionTitle}
- - {inputArray.map((item, index) => ( - - - - - - - ))} - -
- - {item.fullName} - - {item.position.positionTitle}
- ); -} - -export default ArrayMap; diff --git a/client/app/test/modules/MilpacParse.jsx b/client/app/test/modules/MilpacParse.jsx deleted file mode 100644 index 0dc8960..0000000 --- a/client/app/test/modules/MilpacParse.jsx +++ /dev/null @@ -1,141 +0,0 @@ -import React from "react"; -import ArrayMap from "./ArrayMap"; - -/*Milpac Parse is used to compare the API response (milpacArray) against desired position ID's (billetBankObject). If for example, a person is a Milpacs Clerk and billetBankObject -is set to check for Milpacs Clerks, Milpac Parse will search for matching entries within the API resonse. If there is someone that matches, they are pushed to an output array. (returnArray) -This particular instance of milpacArray is designed to parse an entire object for matching entries, i.e. It will parse all of First Battalion, and push out an array -for each company within first battalion if asked to do so.*/ - -function MilpacParse(props) { - const rosterGroups = props.rosterGroups; - let milpacArray = props.milpacArray; - - console.log(rosterGroups); - - 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. - - for (let milpacIdCombat in milpacArray[0].combat.profiles) { - let name = milpacArray[0].combat.profiles[milpacIdCombat].realName; - let rank = milpacArray[0].combat.profiles[milpacIdCombat].rank.rankFull; - let primary = milpacArray[0].combat.profiles[milpacIdCombat].primary; - let fullName = rank + " " + name; - let primarySortKey = - milpacArray[0].combat.profiles[milpacIdCombat].primary.positionId; - - for (let index in rosterGroups) { - if (rosterGroups[index].positionId == primary.positionId) { - returnArray.push({ - fullName: fullName, - position: primary, - isPrimary: "true", - sortKey: rosterGroups[index].positionDisplayOrder, - itemKey: milpacIdCombat, - listKey: primarySortKey + milpacIdCombat, - }); - uniqueNamesSet.add(fullName); - } - - //Next, check the combat roster secondaries for matching billet id's, then push to return array if match is found. - - for (let index2 in milpacArray[0].combat.profiles[milpacIdCombat] - .secondaries) { - let secondary = - milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2]; - let secondarySortKey = - milpacArray[0].combat.profiles[milpacIdCombat].secondaries[index2] - .positionId; - - 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); - } - } - } - } - - //After the Combat Roster, check the Reserves. - - for (let milpacIdReserve in milpacArray[0].reserve.profiles) { - let rName = milpacArray[0].reserve.profiles[milpacIdReserve].realName; - let rRank = milpacArray[0].reserve.profiles[milpacIdReserve].rank.rankFull; - let rPrimary = milpacArray[0].reserve.profiles[milpacIdReserve].primary; - let rFullName = rRank + " " + rName; - let rPrimarySortKey = - milpacArray[0].reserve.profiles[milpacIdReserve].primary.positionId; - - //Check the Reserve primaries, then push to return array if match is found. - - for (let index in rosterGroups) { - if (rosterGroups[index].positionId == rPrimary.positionId) { - returnArray.push({ - fullName: rFullName, - position: rPrimary, - isPrimary: "true", - sortKey: rosterGroups[index].positionDisplayOrder, - itemKey: milpacIdReserve, - listKey: rPrimarySortKey + milpacIdReserve, - }); - uniqueNamesSet.add(rFullName); - } - - //Check the Reserve secondaries, then push to return array if match is found. - - for (let rIndex in milpacArray[0].reserve.profiles[milpacIdReserve] - .secondaries) { - let rSecondary = - milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex]; - let rSecondarySortKey = - milpacArray[0].reserve.profiles[milpacIdReserve].secondaries[rIndex] - .positionId; - - 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); - } - } - - // 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.sort((a, b) => { - const aIndex = a.sortKey; - const bIndex = b.sortKey; - return aIndex - bIndex; - }); - - console.log(returnArray); - - return ( -
-
-
{props.subtitle}
-
- Unit Strength: {uniqueNamesSet.size} -
-
-
- -
-
- ); -} - -export default MilpacParse; diff --git a/client/app/test/page.css b/client/app/test/page.css deleted file mode 100644 index 73d1241..0000000 --- a/client/app/test/page.css +++ /dev/null @@ -1,249 +0,0 @@ -.DepartmentContainer { - margin: auto; - min-width: 30%; - max-width: 30%; -} - -@media only screen and (max-width: 1000px) { - .DepartmentContainer { - min-width: 50%; - max-width: 95%; - } -} - -.p-nav-primary { - position: sticky; - top: 0; - z-index: 400; - background-color: #2e2e2e; - margin-bottom: 1.2em; -} - -.p-nav { - display: block; - overflow-wrap: break-word; -} - -.p-nav-logo { - align-self: center; - box-sizing: border-box; - display: block; - max-width: 220px; - line-height: 21px; - padding: 3px; -} - -.loading-container { - display: flex; - justify-content: center; - align-items: center; - height: 100%; - min-height: 60vh; - flex-direction: column; -} - -.gif-spinner-wrapper { - position: relative; -} - -.spinner { - border: 0.5em solid #f3f3f3; - border-top: 0.5em solid #ebc729; - border-radius: 50%; - width: 11em; - /* Make this larger than the GIF */ - height: 11em; - /* Make this larger than the GIF */ - animation: spin 2s linear infinite; - position: absolute; - top: 30%; - left: 30%; - z-index: 1; - margin: -4em 0 0 -4.5em; - /* Half of width and height */ -} - -.p-loading-png { - width: 8em; - height: 8em; - position: relative; - z-index: 2; - transform: translatex(-7%); -} - -.loading-subtitle { - color: #f1f1f1; - font-size: x-large; - font-weight: bold; - padding: 1em; -} - -@keyframes spin { - 0% { - transform: rotate(0deg); - } - - 100% { - transform: rotate(360deg); - } -} - -.cache-time { - color: #ebc729; - font-weight: bold; - margin-left: 20px; -} - -.error-container { - display: flex; - justify-content: center; - align-items: flex-start; - height: 100%; - min-height: 100vh; -} - -.p-nav-scroller { - display: flex; - align-items: center; - justify-content: center; -} - -.p-nav-png { - max-width: 220px; - max-height: 37.7167px; - flex: 1 1 auto; -} - -.p-nav-opposite { - text-align: right; - flex: 1 1 auto; - margin: 5px; -} - -.p-nav-opposite-link { - color: #f1f1f1; - font-weight: bold; -} - -.p-nav-png { - width: 220px; - height: 37.7167px; -} - -.p-nav-info p { - display: flex; - align-items: center; -} - -/* Mobile layout */ -@media (max-width: 768px) { - .p-nav-scroller { - flex-direction: column; - align-items: center; - justify-content: center; - /* Center-align items vertically */ - } - - .p-nav-info p { - margin-left: 0; - margin-top: 10px; - /* Add some space between the logo and the text */ - } -} - -.Title { - color: #f1f1f1; - font-size: x-large; - font-weight: bold; - border-width: 1px; - border-style: solid; - border-image: linear-gradient(to right, #ebc729, transparent) 1 0%; - border-top: transparent; -} - -@media only screen and (max-width: 1000px) { - .Title { - border-image: none; - border-color: #ebc729; - border-left: transparent; - border-right: transparent; - } -} - -/* This is a very hack-y way to make the borders look proper on mobile browsers. This is because the border image property does not appear to be properly supported with IOS' Safari */ - -.Subtitle { - color: #f1f1f1; - font-size: larger; - font-weight: bold; - padding-top: 15px; - padding-bottom: 15px; -} - -/*.Title:hover { - text-decoration: none; - cursor: pointer; -} */ - -.HeaderContainer { - display: flex; -} - -.Counter { - font-size: smaller; - padding-top: 20px; - padding-bottom: 15px; - margin-left: auto; -} - -.ItemList table { - width: 100%; - margin-left: auto; - margin-right: auto; -} - -.ItemList thead { - display: none; -} - -.ItemList td { - padding-bottom: 7px; - padding-left: 10px; - width: 50%; -} - -.Collapsible__trigger { - display: block; - position: relative; -} - -.Collapsible__trigger:after { - content: none; - position: absolute; - right: 0px; - top: 0px; - display: block; - transition: transform 300ms; - transform: rotateZ(90deg); - - /* 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%; -} - -.Collapsible__trigger.is-open::after { - transform: rotateZ(180deg); - position: absolute; - right: 0px; - top: 0px; - - /* 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/test/page.jsx b/client/app/test/page.jsx deleted file mode 100644 index 3903b7e..0000000 --- a/client/app/test/page.jsx +++ /dev/null @@ -1,92 +0,0 @@ -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"; -import "../globals.css"; - -export const metadata = { - title: "Active Duty Roster", -}; - -export default async function ActiveDutyRoster() { - 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 ( -
-
-
- -
-
-
- {units.map((unit) => ( -
-
{unit.title}
- {unit.selectors.map((selector) => ( - - ))} -
- ))} - {/* - - - - - */} -
-
- ); -}