From 09c24b40df93cead15b40dd27aa3088fdbb02c8e Mon Sep 17 00:00:00 2001 From: Sven Kirschbaum Date: Sat, 10 Aug 2024 03:32:49 +0200 Subject: [PATCH] feat: Display character raid ids --- frontend/character-list/package-lock.json | 28 ++++++++ frontend/character-list/package.json | 3 + frontend/character-list/src/App.css | 21 ++++++ frontend/character-list/src/App.tsx | 79 +++++++++++++++++++---- frontend/character-list/src/constants.tsx | 28 ++++++++ 5 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 frontend/character-list/src/constants.tsx diff --git a/frontend/character-list/package-lock.json b/frontend/character-list/package-lock.json index 40c4c17..a81f514 100644 --- a/frontend/character-list/package-lock.json +++ b/frontend/character-list/package-lock.json @@ -14,12 +14,15 @@ "@mui/icons-material": "^5.15.17", "@mui/material": "^5.15.17", "@mui/x-data-grid": "7.12.0", + "luxon": "3.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-error-boundary": "4.0.13", "react-router": "6.26.0", "react-router-dom": "6.26.0" }, "devDependencies": { + "@types/luxon": "3.4.2", "@types/react": "^18.2.66", "@types/react-dom": "^18.2.22", "@typescript-eslint/eslint-plugin": "^8.0.0", @@ -1734,6 +1737,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==", + "dev": true + }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -3279,6 +3288,14 @@ "yallist": "^3.0.2" } }, + "node_modules/luxon": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", + "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==", + "engines": { + "node": ">=12" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3633,6 +3650,17 @@ "react": "^18.3.1" } }, + "node_modules/react-error-boundary": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz", + "integrity": "sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", diff --git a/frontend/character-list/package.json b/frontend/character-list/package.json index 69fd405..5091455 100644 --- a/frontend/character-list/package.json +++ b/frontend/character-list/package.json @@ -10,8 +10,10 @@ "preview": "vite preview" }, "dependencies": { + "luxon": "3.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-error-boundary": "4.0.13", "react-router": "6.26.0", "react-router-dom": "6.26.0", "@mui/material": "^5.15.17", @@ -22,6 +24,7 @@ "@mui/x-data-grid": "7.12.0" }, "devDependencies": { + "@types/luxon": "3.4.2", "@types/react": "^18.2.66", "@types/react-dom": "^18.2.22", "@typescript-eslint/eslint-plugin": "^8.0.0", diff --git a/frontend/character-list/src/App.css b/frontend/character-list/src/App.css index d0bc3b3..a5427e0 100644 --- a/frontend/character-list/src/App.css +++ b/frontend/character-list/src/App.css @@ -68,4 +68,25 @@ .color-faction-HORDE { color: #FF4545; +} + +.raid-status { + display: flex; + flex-direction: column; +} + +.instance-status { + +} + +.completion-none { + color: red; +} + +.completion-partial { + color: orange; +} + +.completion-full { + color: green; } \ No newline at end of file diff --git a/frontend/character-list/src/App.tsx b/frontend/character-list/src/App.tsx index a2016bc..9f8f2fa 100644 --- a/frontend/character-list/src/App.tsx +++ b/frontend/character-list/src/App.tsx @@ -12,8 +12,10 @@ import { } from "@mui/material"; import {DataGrid, GridColDef, GridFooter, GridFooterContainer, GridRowModel} from "@mui/x-data-grid"; import {createBrowserRouter, redirect, redirectDocument, RouterProvider} from "react-router-dom"; +import {ErrorBoundary} from "react-error-boundary"; +import {DIFFUCULTY_ABBREVIATIONS, RAID_ABBREVIATIONS, REGIONS, WEEKLY_RESET} from "./constants.tsx"; +import {DateTime} from "luxon"; -const REGIONS = ['eu', 'us', 'kr', 'tw'] const router = createBrowserRouter([ { Component: LoadingWrapper, @@ -81,14 +83,15 @@ function CharacterList() { const rows: GridRowModel[] = []; const columns: GridColDef[] = [ - { field: 'name', headerName: 'Name', width: 150, cellClassName: (params) => `color-class-${params.row.classId}`}, - { field: 'level', headerName: 'Level', width: 150 }, - { field: 'className', headerName: 'Class', width: 150, cellClassName: (params) => `color-class-${params.row.classId}`}, - { field: 'realm', headerName: 'Realm', width: 150 }, - { field: 'factionName', headerName: 'Faction', width: 150, cellClassName: (params) => `color-faction-${params.row.factionType}`}, - { field: 'race', headerName: 'Race', width: 150 }, - { field: 'gender', headerName: 'Gender', width: 150 }, - { field: 'account', headerName: 'Account Index'}, + { field: 'name', headerName: 'Name', headerAlign: 'center', cellClassName: (params) => `color-class-${params.row.classId}`}, + { field: 'level', headerName: 'Level', headerAlign: 'center' }, + { field: 'className', headerName: 'Class', headerAlign: 'center', cellClassName: (params) => `color-class-${params.row.classId}`}, + { field: 'realm', headerName: 'Realm', headerAlign: 'center' }, + { field: 'factionName', headerName: 'Faction', headerAlign: 'center', cellClassName: (params) => `color-faction-${params.row.factionType}`}, + { field: 'race', headerName: 'Race', headerAlign: 'center' }, + { field: 'gender', headerName: 'Gender', headerAlign: 'center' }, + { field: 'account', headerName: 'Account', headerAlign: 'center'}, + { field: 'raids', headerName: 'Raid IDs', headerAlign: 'center', renderCell: (params) => }, ]; data.profile.wow_accounts.forEach((account: any, accountIndex: number) => { @@ -105,24 +108,37 @@ function CharacterList() { factionType: character.faction.type, race: character.playable_race.name, gender: character.gender.name, + raids: data.raids[`${character.name.toLowerCase()}-${character.realm.slug}`], }); }); }); return ( 'auto'} + pageSizeOptions={[15]} slots={{ footer: Footer }} @@ -130,6 +146,47 @@ function CharacterList() { ); } +function RaidStatusWrapper(props: any) { + return ( + Error}> + + + ) +} + +function RaidStatus(props: {value: any}) { + if(!props.value) { + return ""; + } + + return ( +
+ {props.value.map((instance: any) => )} +
+ ); +} + +function InstanceStatus(props: {instance: any, modes: any}) { + return ( +
+ {RAID_ABBREVIATIONS[props.instance.id] || props.instance.name}: {props.modes.map((mode: any) => )} +
+ ) +} + +function ModeStatus(props: any) { + const routeParams = useParams() as {region: string}; + const region = routeParams.region.toUpperCase(); + + const name = DIFFUCULTY_ABBREVIATIONS[props.difficulty.type] || props.difficulty.name; + const killsThisWeek = props.progress.encounters.filter((encounter: any) => DateTime.fromMillis(encounter.last_kill_timestamp) > WEEKLY_RESET[region]).length; + + //Variant is either none, partial or full + const variant = killsThisWeek === props.progress.total_count ? 'full' : killsThisWeek > 0 ? 'partial' : 'none'; + + return {`${killsThisWeek}/${props.progress.total_count} ${name}`} ; +} + function Footer() { const {region} = useParams(); const navigate = useNavigate(); diff --git a/frontend/character-list/src/constants.tsx b/frontend/character-list/src/constants.tsx new file mode 100644 index 0000000..61ad1cd --- /dev/null +++ b/frontend/character-list/src/constants.tsx @@ -0,0 +1,28 @@ +import {DateTime} from "luxon"; + +export const REGIONS = ['eu', 'us', 'kr', 'tw'] +export const RAID_ABBREVIATIONS: {[key: number]: string} = { + 1200: 'VOTI', + 1208: 'ATSC', + 1207: 'ATDH', +} + +export const DIFFUCULTY_ABBREVIATIONS: {[key: string]: string} = { + 'LFR': 'LFR', + 'NORMAL': 'NHC', + 'HEROIC': 'HC', + 'MYTHIC': 'M', +} + +export const WEEKLY_RESET: {[key: string]: DateTime} = { + "EU": DateTime.utc().startOf('week').set({ weekday: 3, hour: 4, minute: 0, second: 0, millisecond: 0 }), + "US": DateTime.utc().startOf('week').set({ weekday: 2, hour: 15, minute: 0, second: 0, millisecond: 0 }), + "KR": DateTime.utc().startOf('week').set({ weekday: 3, hour: 22, minute: 0, second: 0, millisecond: 0 }), + "TW": DateTime.utc().startOf('week').set({ weekday: 3, hour: 22, minute: 0, second: 0, millisecond: 0 }), +} + +for (const REGION in WEEKLY_RESET) { + if(DateTime.utc() < WEEKLY_RESET[REGION]) { + WEEKLY_RESET[REGION] = WEEKLY_RESET[REGION].minus({weeks: 1}); + } +} \ No newline at end of file