Skip to content

Commit

Permalink
feat(tracks): Added ability for users to view completed campaign & ch…
Browse files Browse the repository at this point in the history
…aracter tracks and clocks
  • Loading branch information
scottbenton committed Mar 17, 2024
1 parent e04b748 commit 3e70cc8
Show file tree
Hide file tree
Showing 20 changed files with 731 additions and 562 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Added ability to add extra experience points past 30 (Ironsworn)
- Added the ability to delete Rolls from the log (AnnB)
- Added ability for GMs to remove other players and their characters from campaigns
- Added the ability for users to view completed campaign & character tracks and clocks

### Bug Fixes

Expand Down
59 changes: 39 additions & 20 deletions src/components/features/ProgressTrack/ProgressTrack.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { Box, Button, ButtonBase, Link, Typography } from "@mui/material";
import { Box, Button, ButtonBase, Chip, Link, Typography } from "@mui/material";
import { useEffect, useId, useState } from "react";
import { ProgressTrackTick } from "./ProgressTrackTick";
import MinusIcon from "@mui/icons-material/Remove";
import PlusIcon from "@mui/icons-material/Add";
import { DIFFICULTY, PROGRESS_TRACKS, TRACK_TYPES } from "types/Track.type";
import {
DIFFICULTY,
PROGRESS_TRACKS,
TRACK_STATUS,
TRACK_TYPES,
} from "types/Track.type";
import CompleteIcon from "@mui/icons-material/Check";
import DieIcon from "@mui/icons-material/Casino";
import { useConfirm } from "material-ui-confirm";
Expand Down Expand Up @@ -32,6 +37,7 @@ const trackMoveIdSystemValues: GameSystemChooser<{

export interface ProgressTracksProps {
trackType?: PROGRESS_TRACKS;
status?: TRACK_STATUS;
label?: string;
difficulty?: DIFFICULTY;
description?: string;
Expand All @@ -41,6 +47,7 @@ export interface ProgressTracksProps {
onDelete?: () => void;
onEdit?: () => void;
hideDifficultyLabel?: boolean;
hideRollButton?: boolean;
}

const getDifficultyLabel = (difficulty: DIFFICULTY): string => {
Expand Down Expand Up @@ -79,6 +86,7 @@ export function ProgressTrack(props: ProgressTracksProps) {
const {
trackType,
label,
status,
description,
difficulty,
max,
Expand All @@ -87,6 +95,7 @@ export function ProgressTrack(props: ProgressTracksProps) {
onDelete,
onEdit,
hideDifficultyLabel,
hideRollButton,
} = props;

const trackMoveIds = useGameSystemValue(trackMoveIdSystemValues);
Expand Down Expand Up @@ -176,25 +185,35 @@ export function ProgressTrack(props: ProgressTracksProps) {
</Typography>
)}
{(label || onEdit) && (
<Typography
variant={"h6"}
component={"p"}
id={labelId}
color={(theme) => theme.palette.text.primary}
fontFamily={(theme) => theme.fontFamilyTitle}
>
{label + " "}
{onEdit && (
<Link
color={"inherit"}
component={"button"}
<Box display={"flex"} alignItems={"center"}>
<Typography
variant={"h6"}
component={"p"}
id={labelId}
color={(theme) => theme.palette.text.primary}
fontFamily={(theme) => theme.fontFamilyTitle}
>
{label + " "}
{onEdit && (
<Link
color={"inherit"}
component={"button"}
sx={{ ml: 2 }}
onClick={() => onEdit()}
>
Edit
</Link>
)}
</Typography>
{status === TRACK_STATUS.COMPLETED && (
<Chip
label={"Completed"}
color={"success"}
sx={{ ml: 2 }}
onClick={() => onEdit()}
>
Edit
</Link>
size={"small"}
/>
)}
</Typography>
</Box>
)}
{description && (
<Typography
Expand Down Expand Up @@ -328,7 +347,7 @@ export function ProgressTrack(props: ProgressTracksProps) {
Complete Track
</Button>
)}
{trackType && (
{trackType && !hideRollButton && (
<Button
color={"inherit"}
onClick={handleRollClick}
Expand Down
198 changes: 79 additions & 119 deletions src/components/features/ProgressTrack/ProgressTrackList.tsx
Original file line number Diff line number Diff line change
@@ -1,146 +1,106 @@
import { Button, Stack } from "@mui/material";
import {
ProgressTrack as IProgressTrack,
TRACK_SECTION_PROGRESS_TRACKS,
} from "types/Track.type";
import { Button, Checkbox, FormControlLabel } from "@mui/material";
import { TRACK_SECTION_PROGRESS_TRACKS } from "types/Track.type";
import { EditOrCreateTrackDialog } from "./EditOrCreateTrackDialog";
import { ProgressTrack } from "./ProgressTrack";
import { SectionHeading } from "components/shared/SectionHeading";
import { EmptyState } from "components/shared/EmptyState";
import { useState } from "react";
import { useStore } from "stores/store";
import { ProgressTracks } from "./ProgressTracks";

export interface ProgressTrackListProps {
trackType: TRACK_SECTION_PROGRESS_TRACKS;
tracks?: { [trackId: string]: IProgressTrack };
typeLabel: string;
handleAdd?: (newTrack: IProgressTrack) => Promise<boolean | void>;
handleUpdateValue: (
trackId: string,
value: number
) => Promise<boolean | void>;
handleDeleteTrack?: (trackId: string) => Promise<boolean | void>;
handleUpdateTrack?: (
trackId: string,
track: IProgressTrack
) => Promise<boolean | void>;
headingBreakContainer?: boolean;
readOnly?: boolean;
isCampaign?: boolean;
}

export function ProgressTrackList(props: ProgressTrackListProps) {
const {
tracks = {},
trackType,
typeLabel,
handleAdd,
handleUpdateValue,
handleDeleteTrack,
handleUpdateTrack,
headingBreakContainer,
} = props;
const { trackType, typeLabel, headingBreakContainer, readOnly, isCampaign } =
props;

const orderedTrackIds = tracks
? Object.keys(tracks).sort((trackId1, trackId2) => {
const track1 = tracks[trackId1];
const track2 = tracks[trackId2];

return track2.createdDate.getTime() - track1.createdDate.getTime();
})
: [];

const [addTrackDialogOpen, setAddTrackDialogOpen] = useState<boolean>(false);
const [currentlyEditingTrackId, setCurrentlyEditingTrackId] =
useState<string>();
const setLoadCompletedTracks = useStore((store) =>
isCampaign
? store.campaigns.currentCampaign.tracks.setLoadCompletedTracks
: store.characters.currentCharacter.tracks.setLoadCompletedTracks
);
const [showCompletedTracks, setShowCompletedTracks] = useState(false);
const toggleShowCompletedTracks = (value: boolean) => {
if (value) {
setLoadCompletedTracks();
}
setShowCompletedTracks(value);
};

const currentlyEditingTrack =
currentlyEditingTrackId && tracks
? tracks[currentlyEditingTrackId]
: undefined;
const addCampaignProgressTrack = useStore(
(store) => store.campaigns.currentCampaign.tracks.addTrack
);
const addCharacterProgressTrack = useStore(
(store) => store.characters.currentCharacter.tracks.addTrack
);

const [addTrackDialogOpen, setAddTrackDialogOpen] = useState(false);
return (
<>
<EditOrCreateTrackDialog
open={addTrackDialogOpen}
handleClose={() => setAddTrackDialogOpen(false)}
trackType={trackType}
trackTypeName={`${typeLabel}`}
handleTrack={(track) =>
handleAdd ? handleAdd(track) : new Promise((res) => res(true))
}
/>

{handleUpdateTrack &&
currentlyEditingTrack &&
currentlyEditingTrackId && (
<EditOrCreateTrackDialog
open={!!currentlyEditingTrack}
handleClose={() => setCurrentlyEditingTrackId(undefined)}
trackType={
currentlyEditingTrack.type as TRACK_SECTION_PROGRESS_TRACKS
{!readOnly && (
<EditOrCreateTrackDialog
open={addTrackDialogOpen}
handleClose={() => setAddTrackDialogOpen(false)}
trackType={trackType}
trackTypeName={`${typeLabel}`}
handleTrack={(track) => {
if (isCampaign) {
return addCampaignProgressTrack(track);
} else {
return addCharacterProgressTrack(track);
}
trackTypeName={`${typeLabel}`}
initialTrack={currentlyEditingTrack}
handleTrack={(track) =>
currentlyEditingTrack
? handleUpdateTrack(currentlyEditingTrackId, track)
: new Promise((res) => res(true))
}
/>
)}
}}
/>
)}

<SectionHeading
label={`${typeLabel}s`}
action={
handleAdd && (
<Button
color={"inherit"}
onClick={() => setAddTrackDialogOpen(true)}
>
Add {typeLabel}
</Button>
)
<>
<FormControlLabel
control={
<Checkbox
checked={showCompletedTracks}
onChange={(evt, checked) =>
toggleShowCompletedTracks(checked)
}
/>
}
label={`Show Completed ${typeLabel}s`}
/>
{!readOnly && (
<Button
color={"inherit"}
onClick={() => setAddTrackDialogOpen(true)}
>
Add {typeLabel}
</Button>
)}
</>
}
breakContainer={headingBreakContainer}
/>
<Stack
mt={2}
spacing={4}
mb={4}
sx={(theme) => ({
px: headingBreakContainer ? 0 : 2,
[theme.breakpoints.up("md")]: {
px: headingBreakContainer ? 0 : 3,
},
})}
>
{Array.isArray(orderedTrackIds) && orderedTrackIds.length > 0 ? (
orderedTrackIds.map((trackId, index) => (
<ProgressTrack
key={index}
trackType={trackType}
label={tracks[trackId].label}
description={tracks[trackId].description}
difficulty={tracks[trackId].difficulty}
value={tracks[trackId].value}
onValueChange={(value) => handleUpdateValue(trackId, value)}
onDelete={
handleDeleteTrack
? () => {
handleDeleteTrack(trackId);
}
: undefined
}
max={40}
onEdit={
handleUpdateTrack
? () => setCurrentlyEditingTrackId(trackId)
: undefined
}
/>
))
) : (
<EmptyState message={`No ${typeLabel}s found`} />
)}
</Stack>
<ProgressTracks
isCampaign={isCampaign}
trackType={trackType}
typeLabel={typeLabel}
headingBreakContainer={headingBreakContainer}
readOnly={readOnly}
/>
{showCompletedTracks && (
<ProgressTracks
isCampaign={isCampaign}
isCompleted
trackType={trackType}
typeLabel={typeLabel}
headingBreakContainer={headingBreakContainer}
readOnly={readOnly}
/>
)}
</>
);
}
Loading

0 comments on commit 3e70cc8

Please sign in to comment.