Skip to content

Commit

Permalink
nearly complete operative selection
Browse files Browse the repository at this point in the history
  • Loading branch information
jaaimino committed Oct 29, 2024
1 parent ec1f4a1 commit 0bf58cc
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 31 deletions.
38 changes: 30 additions & 8 deletions src/pages/dashboard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import { useAPI, useRequest } from "../../hooks/use-api";
import { ActionIcon, Card, Container, Group, LoadingOverlay, SimpleGrid, Stack, Tabs, Title } from "@mantine/core";
import OperativeCard from "../../components/operative-card";
import React from "react";
import { IconEdit, IconListCheck, IconMinus, IconPlus, IconRefresh, IconUserShare } from "@tabler/icons-react";
import { IconEdit, IconListCheck, IconMinus, IconPlus, IconRefresh } from "@tabler/icons-react";
import useAuth from "../../hooks/use-auth";
import { useAppContext } from "../../hooks/app-context";
import { useLocalStorage } from "@mantine/hooks";
import { debounce, groupBy } from "lodash";
import PloyCards from "../../components/ploy-cards";
import EquipmentCards from "../../components/equipment-cards";
import TacOpCards from "../../components/tacop-cards";
import { SelectOperativesModal } from "./modals";
import { modals } from "@mantine/modals";

export default function Dashboard() {
const { user: userData } = useAuth();
Expand All @@ -23,6 +25,31 @@ export default function Dashboard() {
const killteam = roster?.killteam;
const isNarrativeEquipment = (equip) => equip.eqid.includes('BS-') || equip.eqid.includes('BH-');
const groupedEquipment = groupBy(roster?.rostereqs?.filter(equip => !isNarrativeEquipment(equip)), 'eqcategory');
const handleUpdateOperatives = React.useCallback((operatives) => {
console.log(operatives);
// const updatedOperative = {
// ...operative,
// hidden: checked ? 0 : 1
// }
// setRoster({
// ...roster,
// operatives: roster.operatives?.map((op) => op.rosteropid === operative.rosteropid ? updatedOperative : op)
// });
// api.request(`/rosteroperative.php`, {
// method: "POST",
// body: JSON.stringify(updatedOperative)
// })
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [roster]);
const handleShowSelectOperatives = React.useCallback(() => {
modals.open({
modalId: "select-operatives",
size: "xl",
title: <Title order={2}>Select Operatives</Title>,
children: <SelectOperativesModal roster={roster} onClose={handleUpdateOperatives} />
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [roster]);
// eslint-disable-next-line react-hooks/exhaustive-deps
const handleSaveUpdateRoster = React.useCallback(debounce((newRoster) => {
api.request(`/roster.php`, {
Expand Down Expand Up @@ -163,12 +190,7 @@ export default function Dashboard() {
{
icon: <IconListCheck />,
text: "Select Operatives",
onClick: () => { }
},
{
icon: <IconUserShare />,
text: "Add Opponent",
onClick: () => { }
onClick: () => handleShowSelectOperatives()
},
{
icon: <IconEdit />,
Expand All @@ -192,7 +214,7 @@ export default function Dashboard() {
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [canEdit]);
}, [canEdit, handleShowSelectOperatives, handleUpdateOperatives]);
if (isFetchinigTeam) {
return (<LoadingOverlay visible={isFetchinigTeam} />);
}
Expand Down
91 changes: 91 additions & 0 deletions src/pages/dashboard/modals/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Stack, Button, Group, Checkbox, Title, Text, Image, SimpleGrid, Paper, Tabs, Box } from '@mantine/core';
import { useLocalStorage } from '@mantine/hooks';
import { modals } from '@mantine/modals';
import React from 'react';
import { DEFAULT_SETTINGS } from '../../settings';
import { API_PATH } from '../../../hooks/use-api';
import { IconCrosshair, IconSwords } from '@tabler/icons-react';

function MiniOperativeCard(props) {
const { operative, onChange = () => { } } = props;
const [settings] = useLocalStorage({ key: 'settings', defaultValue: DEFAULT_SETTINGS });
return (
<Paper withBorder p="sm" style={{ cursor: 'pointer' }} onClick={() => onChange(operative, !!operative.hidden)}>
<Stack gap={5}>
<Group>
<Checkbox.Indicator checked={!operative.hidden} />
<Title textWrap="pretty" order={4}>{settings.opnamefirst === "y" ? operative.opname : operative.optype || operative.opname}</Title>
</Group>
<SimpleGrid cols={{ base: 2 }} spacing="xs">
{settings.display === "card" && <Image
h="100%"
fit="cover"
style={{ objectPosition: "top" }}
radius="md"
src={operative.rosteropid ? `${API_PATH}/operativeportrait.php?roid=${operative.rosteropid}` : `https://ktdash.app/img/portraits/${operative.factionid}/${operative.killteamid}/${operative.fireteamid}/${operative.opid}.jpg`}
/>}
<Stack gap={5}>
<Text>{(settings.opnamefirst === "y" || !operative.optype) ? operative.optype : operative.opname}</Text>
{operative.weapons.map((weapon) => (
<span>
{weapon.weptype === "M" ?
<IconSwords size={20} /> : <IconCrosshair size={20} />}
<span style={{ marginLeft: '5px' }}>{weapon.wepname}</span>
</span>
))}
</Stack>
</SimpleGrid>
</Stack>
</Paper>
);
}

export function SelectOperativesModal(props) {
const { onClose = () => {}, roster } = props;

const [ operatives, setOperatives ] = React.useState(roster.operatives || []);

const handleUpdateRoster = () => {
onClose(operatives);
modals.close("select-operatives");
};

const handleUpdateOperative = (operative, checked) => {
setOperatives(operatives?.map((op) => op.rosteropid === operative.rosteropid ? { ...op, hidden: checked ? 0 : 1 } : op))
}

return (
<>
<Tabs defaultValue="operatives">
<Tabs.List grow>
<Tabs.Tab value="operatives">
Operatives
</Tabs.Tab>
<Tabs.Tab value="composition">
Team Composition
</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="operatives">
<form
onSubmit={handleUpdateRoster}
>
<Stack pt="md">
{operatives.map((operative) => (
<MiniOperativeCard operative={operative} onChange={handleUpdateOperative} />
))}
<Group justify="flex-end">
<Button variant="default" onClick={() => modals.close("select-operatives")}>Cancel</Button>
<Button type="submit">Save</Button>
</Group>
</Stack>
</form>
</Tabs.Panel>
<Tabs.Panel value="composition">
<Box pt="md">
<div dangerouslySetInnerHTML={{ __html: `${roster?.killteam?.killteamcomp}` }} />
</Box>
</Tabs.Panel>
</Tabs>
</>
);
}
41 changes: 27 additions & 14 deletions src/pages/roster/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { API_PATH, useAPI, useRequest } from "../../hooks/use-api";
import { Container, Group, Image, LoadingOverlay, SimpleGrid, Stack, Text, Title } from "@mantine/core";
import OperativeCard from "../../components/operative-card";
import React from "react";
import { IconCards, IconCopy, IconEdit, IconPhoto, IconPlus, IconPrinter, IconTrash } from "@tabler/icons-react";
import { IconCards, IconCopy, IconEdit, IconListCheck, IconPhoto, IconPlus, IconPrinter, IconTrash } from "@tabler/icons-react";
import useAuth from "../../hooks/use-auth";
import { useAppContext } from "../../hooks/app-context";
import { useLocalStorage } from "@mantine/hooks";
Expand All @@ -20,6 +20,14 @@ export default function Roster() {
const [, setDashboardrosterId] = useLocalStorage({ key: 'dashboardrosterid' });
const [, navigate] = useLocation();
const canEdit = userData?.username === roster?.username;
const showTeamComp = () =>
modals.open({
size: "lg",
title: 'Team Composition',
children: (
<div dangerouslySetInnerHTML={{ __html: `${roster?.killteam?.killteamcomp}` }} />
),
});
const handleUpdateRoster = (roster) => {
api.request("/roster.php", {
method: "POST",
Expand Down Expand Up @@ -51,7 +59,7 @@ export default function Roster() {
notifications.show({
title: 'Added',
message: `Successfully added ${operative.opname}.`,
})
})
setRoster({
...roster,
operatives: [...roster?.operatives, data]
Expand Down Expand Up @@ -82,7 +90,7 @@ export default function Roster() {
notifications.show({
title: 'Updated',
message: `Successfully updated ${operative.opname}.`,
})
})
setRoster({
...roster,
operatives: roster.operatives?.map((op) => op.rosteropid === data.rosteropid ? data : op)
Expand All @@ -107,7 +115,7 @@ export default function Roster() {
notifications.show({
title: 'Deleted',
message: `Successfully deleted ${operative.opname}.`,
})
})
setRoster({
...roster,
operatives: [...roster?.operatives?.filter((op) => op.rosteropid !== operative.rosteropid)]
Expand Down Expand Up @@ -185,18 +193,23 @@ export default function Roster() {
setDashboardrosterId(roster?.rosterid);
navigate('/dashboard')
}
}] : []),
{
icon: <IconPhoto />,
text: "Photo Gallery",
onClick: () => {}
},
{
icon: <IconCopy />,
text: "Duplicate",
onClick: () => {}
},
...(canEdit ? [
icon: <IconListCheck />,
text: "Team Composition",
onClick: () => showTeamComp()
}] : []),
{
icon: <IconPhoto />,
text: "Photo Gallery",
onClick: () => { }
},
{
icon: <IconCopy />,
text: "Duplicate",
onClick: () => { }
},
...(canEdit ? [
{
icon: <IconPrinter />,
text: "Print",
Expand Down
40 changes: 31 additions & 9 deletions src/pages/team/index.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,53 @@
import { useRoute } from "wouter";
import { useRequest } from "../../hooks/use-api";
import { Button, Container, Image, LoadingOverlay, SimpleGrid, Stack, Tabs, Text, Title } from "@mantine/core";
import { Container, Image, LoadingOverlay, SimpleGrid, Stack, Tabs, Text, Title } from "@mantine/core";
import OperativeCard from "../../components/operative-card";
import { modals } from '@mantine/modals';
import { groupBy } from "lodash";
import PloyCards from "../../components/ploy-cards";
import EquipmentCards from "../../components/equipment-cards";
import TacOpCards from "../../components/tacop-cards";
import { IconListCheck } from "@tabler/icons-react";
import React from "react";
import { useAppContext } from "../../hooks/app-context";

export default function Faction() {
const { appState, setAppState } = useAppContext();
const [, params] = useRoute("/fa/:factionId/kt/:killteamId");
const { data: killteam, isFetching: isFetchinigTeam } = useRequest(`/killteam.php?fa=${params?.factionId}&kt=${params?.killteamId}`);
if (isFetchinigTeam) {
return (<LoadingOverlay visible={isFetchinigTeam} />);
}
if (!killteam) {
return;
}
const showTeamComp = () =>
modals.open({
size: "lg",
title: 'Team Composition',
children: (
<div dangerouslySetInnerHTML={{ __html: `${killteam.killteamcomp}` }} />
<div dangerouslySetInnerHTML={{ __html: `${killteam?.killteamcomp}` }} />
),
});
React.useEffect(() => {
setAppState({
...appState,
contextActions: [
{
icon: <IconListCheck />,
text: "Team Composition",
onClick: () => showTeamComp()
}
]
});
return () => {
setAppState({
...appState,
contextActions: []
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [killteam]);
if (isFetchinigTeam) {
return (<LoadingOverlay visible={isFetchinigTeam} />);
}
if (!killteam) {
return;
}
const isNarrativeEquipment = (equip) => equip.eqid.includes('BS-') || equip.eqid.includes('BH-');
const groupedEquipment = groupBy(killteam.equipments.filter(equip => !isNarrativeEquipment(equip)), 'eqcategory');
return (
Expand All @@ -39,7 +62,6 @@ export default function Faction() {
<Text>
<div dangerouslySetInnerHTML={{ __html: `${killteam.description}` }} />
</Text>
<Button onClick={showTeamComp}>Team Composition</Button>
</Stack>
</SimpleGrid>
<Tabs defaultValue="operatives">
Expand Down

0 comments on commit 0bf58cc

Please sign in to comment.