hensei-web/components/Party/index.tsx

270 lines
7.2 KiB
TypeScript

import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useRouter } from "next/router";
import { useSnapshot } from "valtio";
import { getCookie } from "cookies-next";
import clonedeep from "lodash.clonedeep";
import PartySegmentedControl from "~components/PartySegmentedControl";
import PartyDetails from "~components/PartyDetails";
import WeaponGrid from "~components/WeaponGrid";
import SummonGrid from "~components/SummonGrid";
import CharacterGrid from "~components/CharacterGrid";
import api from "~utils/api";
import { appState, initialAppState } from "~utils/appState";
import { GridType, TeamElement } from "~utils/enums";
import "./index.scss";
// Props
interface Props {
new?: boolean;
team?: Party;
raids: Raid[][];
pushHistory?: (path: string) => void;
}
const Party = (props: Props) => {
// Cookies
const cookie = getCookie("account");
const accountData: AccountCookie = cookie
? JSON.parse(cookie as string)
: null;
const headers = useMemo(() => {
return accountData
? { headers: { Authorization: `Bearer ${accountData.token}` } }
: {};
}, [accountData]);
// Set up router
const router = useRouter();
// Set up states
const { party } = useSnapshot(appState);
const [currentTab, setCurrentTab] = useState<GridType>(GridType.Weapon);
// Reset state on first load
useEffect(() => {
const resetState = clonedeep(initialAppState);
appState.grid = resetState.grid;
if (props.team) storeParty(props.team);
}, []);
// Methods: Creating a new party
async function createParty(extra: boolean = false) {
let body = {
party: {
...(accountData && { user_id: accountData.userId }),
extra: extra,
},
};
return await api.endpoints.parties.create(body, headers);
}
// Methods: Updating the party's details
function checkboxChanged(event: React.ChangeEvent<HTMLInputElement>) {
appState.party.extra = event.target.checked;
if (party.id) {
api.endpoints.parties.update(
party.id,
{
party: { extra: event.target.checked },
},
headers
);
}
}
function updateDetails(name?: string, description?: string, raid?: Raid) {
if (
appState.party.name !== name ||
appState.party.description !== description ||
appState.party.raid?.id !== raid?.id
) {
if (appState.party.id)
api.endpoints.parties
.update(
appState.party.id,
{
party: {
name: name,
description: description,
raid_id: raid?.id,
},
},
headers
)
.then(() => {
appState.party.name = name;
appState.party.description = description;
appState.party.raid = raid;
appState.party.updated_at = party.updated_at;
});
}
}
// Deleting the party
function deleteTeam(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
if (appState.party.editable && appState.party.id) {
api.endpoints.parties
.destroy({ id: appState.party.id, params: headers })
.then(() => {
// Push to route
router.push("/");
// Clean state
const resetState = clonedeep(initialAppState);
Object.keys(resetState).forEach((key) => {
appState[key] = resetState[key];
});
// Set party to be editable
appState.party.editable = true;
})
.catch((error) => {
console.error(error);
});
}
}
// Methods: Storing party data
const storeParty = function (party: Party) {
// Store the important party and state-keeping values
appState.party.name = party.name;
appState.party.description = party.description;
appState.party.raid = party.raid;
appState.party.updated_at = party.updated_at;
appState.party.job = party.job;
appState.party.jobSkills = party.job_skills;
appState.party.id = party.id;
appState.party.extra = party.extra;
appState.party.user = party.user;
appState.party.favorited = party.favorited;
appState.party.created_at = party.created_at;
appState.party.updated_at = party.updated_at;
// Populate state
storeCharacters(party.characters);
storeWeapons(party.weapons);
storeSummons(party.summons);
};
const storeCharacters = (list: Array<GridCharacter>) => {
list.forEach((object: GridCharacter) => {
if (object.position != null)
appState.grid.characters[object.position] = object;
});
};
const storeWeapons = (list: Array<GridWeapon>) => {
list.forEach((gridObject: GridWeapon) => {
if (gridObject.mainhand) {
appState.grid.weapons.mainWeapon = gridObject;
appState.party.element = gridObject.object.element;
} else if (!gridObject.mainhand && gridObject.position != null) {
appState.grid.weapons.allWeapons[gridObject.position] = gridObject;
}
});
};
const storeSummons = (list: Array<GridSummon>) => {
list.forEach((gridObject: GridSummon) => {
if (gridObject.main) appState.grid.summons.mainSummon = gridObject;
else if (gridObject.friend)
appState.grid.summons.friendSummon = gridObject;
else if (
!gridObject.main &&
!gridObject.friend &&
gridObject.position != null
)
appState.grid.summons.allSummons[gridObject.position] = gridObject;
});
};
// Methods: Navigating with segmented control
function segmentClicked(event: React.ChangeEvent<HTMLInputElement>) {
switch (event.target.value) {
case "class":
setCurrentTab(GridType.Class);
break;
case "characters":
setCurrentTab(GridType.Character);
break;
case "weapons":
setCurrentTab(GridType.Weapon);
break;
case "summons":
setCurrentTab(GridType.Summon);
break;
default:
break;
}
}
// Render: JSX components
const navigation = (
<PartySegmentedControl
selectedTab={currentTab}
onClick={segmentClicked}
onCheckboxChange={checkboxChanged}
/>
);
const weaponGrid = (
<WeaponGrid
new={props.new || false}
weapons={props.team?.weapons}
createParty={createParty}
pushHistory={props.pushHistory}
/>
);
const summonGrid = (
<SummonGrid
new={props.new || false}
summons={props.team?.summons}
createParty={createParty}
pushHistory={props.pushHistory}
/>
);
const characterGrid = (
<CharacterGrid
new={props.new || false}
characters={props.team?.characters}
createParty={createParty}
pushHistory={props.pushHistory}
/>
);
const currentGrid = () => {
switch (currentTab) {
case GridType.Character:
return characterGrid;
case GridType.Weapon:
return weaponGrid;
case GridType.Summon:
return summonGrid;
}
};
return (
<div>
{navigation}
<section id="Party">{currentGrid()}</section>
{
<PartyDetails
editable={party.editable}
updateCallback={updateDetails}
deleteCallback={deleteTeam}
/>
}
</div>
);
};
export default Party;