Skip to content

Commit

Permalink
Merge branch 'develop' into feat/redesign-synthesis
Browse files Browse the repository at this point in the history
  • Loading branch information
Baboo7 committed Jun 22, 2023
2 parents d635add + 51fca6d commit 2d813a3
Show file tree
Hide file tree
Showing 78 changed files with 1,992 additions and 904 deletions.
16 changes: 11 additions & 5 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@types/recharts": "^1.8.24",
"axios": "^0.25.0",
"date-fns": "^2.28.0",
"deepmerge": "^4.3.1",
"get-user-locale": "^2.2.1",
"i18next": "^22.4.14",
"lodash": "^4.17.21",
Expand Down Expand Up @@ -57,11 +58,16 @@
],
"rules": {
"no-use-before-define": "off",
"no-restricted-imports": ["error", {
"name": "axios",
"importNames": ["default"],
"message": "Please use `http`, the axios client configured in the request utils (src/utils/request)."
}],
"no-restricted-imports": [
"error",
{
"name": "axios",
"importNames": [
"default"
],
"message": "Please use `http`, the axios client configured in the request utils (src/utils/request)."
}
],
"@typescript-eslint/no-use-before-define": "off"
}
},
Expand Down
58 changes: 57 additions & 1 deletion packages/client/src/lib/array.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export { deepFreeze, sortBy, sumReducer, toArray };
import get from "lodash/get";

export { deepFreeze, indexArrayBy, sortBy, sumReducer, toArray };

type OnlyNumberKeys<T> = keyof {
[K in keyof T as T[K] extends number ? K : never]: T[K];
Expand Down Expand Up @@ -34,3 +36,57 @@ const toArray = <T>(val: T | T[]): T[] => {
const isArraySafe = <T>(val: T | T[]): val is T[] => {
return val && Array.isArray(val);
};

/**
* Create an object from an array where items are indexed by the specified key.
* @example
* const arr = [{ id: 1, name: "John"}, { id: 2, name: "Doe"}];
* indexArrayBy(arr, "name");
* // => { "John": { id: 1, name: "John"}, "Doe": { id: 2, name: "Doe"} }
*/
const indexArrayBy = <
T extends Record<string | number | symbol, any>,
U extends DeepPath<T>
>(
arr: T[],
key: U
): Record<T[U], T> => {
return Object.fromEntries(arr.map((item) => [get(item, key), item]));
};

type DeepPath<T extends Record<string | number, any>> = DeepPathRecursive<
T,
keyof T,
"",
[1, 2, 3]
>;

type DeepPathRecursive<
T extends Record<string | number, any>,
TKey extends keyof T,
TPrefix extends string,
TRecursion extends any[]
> = TKey extends TemplatableTypes
? Head<TRecursion> extends never
? `${TPrefix}${TKey}`
: T[TKey] extends number | string
? `${TPrefix}${TKey}`
: T[TKey] extends Record<string | number, any>
? DeepPathRecursive<
T[TKey],
keyof T[TKey],
`${TPrefix}${TKey}.`,
Tail<TRecursion>
>
: ""
: "";

type TemplatableTypes = string | number | bigint | boolean | null | undefined;

type Head<T extends any[]> = T extends [infer THead, ...infer _]
? THead
: never;

type Tail<T extends any[]> = T extends [infer _, ...infer TTail]
? TTail
: never;
5 changes: 5 additions & 0 deletions packages/client/src/lib/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export {
formatProduction,
formatProductionGw,
formatResource,
formatUserName,
};

function formatBudget(value?: number) {
Expand Down Expand Up @@ -52,3 +53,7 @@ function formatNumber(value?: number, options: Intl.NumberFormatOptions = {}) {
? new Intl.NumberFormat(userLocale, options).format(value)
: "";
}

function formatUserName(user: { firstName: string; lastName: string }): string {
return `${user.firstName} ${user.lastName}`;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Button } from "@mui/material";
import RocketLaunchIcon from "@mui/icons-material/RocketLaunch";
import { useState } from "react";
import { useMutation, useQueryClient } from "react-query";
import { IGame, ITeamWithPlayers } from "../../../../../utils/types";
import { SuccessAlert } from "../../../../alert";
import { useNavigate } from "react-router-dom";
import { hasGameStarted } from "../../utils";
import { Button } from "../../../../common/components/Button";
import { Dialog } from "../../../../common/components/Dialog";
import { Typography } from "../../../../common/components/Typography";
import { NO_TEAM } from "../../../../common/constants/teams";
Expand Down Expand Up @@ -65,7 +65,7 @@ export default function Launch({ game }: { game: IGameWithTeams }) {
const playersWithoutTeams = hasPlayersWithoutTeam(game.teams);

const navigate = useNavigate();
const mutation = useMutation<Response, { message: string }, any>(
const launchGameMutation = useMutation<Response, { message: string }, any>(
() => {
const path = `/api/games/${game.id}`;
return http.put(path, { status: "playing" });
Expand All @@ -80,7 +80,7 @@ export default function Launch({ game }: { game: IGameWithTeams }) {

const launchGame = () => {
if (!hasGameStarted(game.status)) {
mutation.mutate({ status: true });
launchGameMutation.mutate({ status: true });
}
setSuccessDialogOpen(false);
};
Expand All @@ -97,12 +97,10 @@ export default function Launch({ game }: { game: IGameWithTeams }) {

return (
<div>
{mutation.isSuccess && <SuccessAlert />}
{launchGameMutation.isSuccess && <SuccessAlert />}
<Button
disabled={playersQuery.isLoading}
loading={playersQuery.isLoading || launchGameMutation.isLoading}
onClick={handleLaunchGame}
variant="contained"
color="secondary"
>
<RocketLaunchIcon sx={{ height: "1rem" }} />
{!hasGameStarted(game.status) ? "Animer" : "Rejoindre"}
Expand All @@ -112,7 +110,12 @@ export default function Launch({ game }: { game: IGameWithTeams }) {
handleClose={() => setSuccessDialogOpen(false)}
actions={
<>
<Button onClick={() => setSuccessDialogOpen(false)}>Annuler</Button>
<Button
type="secondary"
onClick={() => setSuccessDialogOpen(false)}
>
Annuler
</Button>
<Button onClick={launchGame}>Continuer</Button>
</>
}
Expand All @@ -128,7 +131,9 @@ export default function Launch({ game }: { game: IGameWithTeams }) {
handleClose={() => setErrorDialogOpen(false)}
actions={
<>
<Button onClick={() => setErrorDialogOpen(false)}> Fermer</Button>
<Button type="secondary" onClick={() => setErrorDialogOpen(false)}>
Fermer
</Button>
</>
}
>
Expand Down
43 changes: 43 additions & 0 deletions packages/client/src/modules/common/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Button as ButtonLib, CircularProgress } from "@mui/material";
import { useMemo } from "react";

export { Button };

interface ButtonProps {
type?: "primary" | "secondary";
loading?: boolean;
onClick: () => void | Promise<void>;
children: React.ReactNode;
}

function Button({
type = "primary",
loading = false,
onClick,
children,
}: ButtonProps) {
const buttonProps = useMemo(() => {
if (type === "primary") {
return {
color: "secondary",
variant: "contained",
};
}
return {
color: "primary",
};
}, [type]);
const loaderColor = useMemo(
() => (type === "primary" ? "primary" : "secondary"),
[type]
);

return (
<ButtonLib {...(buttonProps as any)} disabled={loading} onClick={onClick}>
{loading && (
<CircularProgress color={loaderColor} size={16} sx={{ mr: 1 }} />
)}
{children}
</ButtonLib>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Button } from "./Button";
17 changes: 11 additions & 6 deletions packages/client/src/modules/persona/persona.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
computeMetals,
PhysicalResourceNeedDatum,
} from "../play/gameEngines/resourcesEngine";
import { TeamAction } from "../../utils/types";
import { ProductionAction, TeamAction } from "../../utils/types";

export { buildInitialPersona };
export type { Persona };
Expand All @@ -28,10 +28,11 @@ interface Persona {
metals: PhysicalResourceNeedDatum[];
}

const buildInitialPersona: (
const buildInitialPersona = (
personalization: PersoForm,
teamActions: TeamAction[]
) => Persona = (personalization: PersoForm, teamActions: TeamAction[]) => {
teamActions: TeamAction[],
productionActionById: Record<number, ProductionAction>
): Persona => {
const formattedPersonalization = fillPersonalization(personalization);
const intermediateValues = computeIntermediateValues(
formattedPersonalization
Expand All @@ -48,8 +49,12 @@ const buildInitialPersona: (
consumption as ConsumptionDatum[]
);

const materials = computeMaterials(production, teamActions);
const metals = computeMetals(production, teamActions);
const materials = computeMaterials(
production,
teamActions,
productionActionById
);
const metals = computeMetals(production, teamActions, productionActionById);

const persona: Persona = {
budget: 13.7,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { emphasizeText } from "../../../common/utils";
import { synthesisConstants } from "../../playerActions/constants/synthesis";
import { Icon } from "../../../common/components/Icon";
import { useTeamValues } from "../../context/playContext";
import { ITeamWithPlayers } from "../../../../utils/types";
import { ITeam } from "../../../../utils/types";
import { getDaysTo2050 } from "../../../../lib/time";

export { SynthesisRecap, SynthesisBudget, SynthesisCarbon };

function SynthesisRecap({ team }: { team: ITeamWithPlayers }) {
function SynthesisRecap({ team }: { team: ITeam }) {
return (
<Box>
<SynthesisBudget team={team} />
Expand All @@ -20,7 +20,7 @@ function SynthesisRecap({ team }: { team: ITeamWithPlayers }) {
);
}

function SynthesisBudget({ team }: { team: ITeamWithPlayers | null }) {
function SynthesisBudget({ team }: { team: ITeam | null }) {
const daysTo2050 = getDaysTo2050();
const { getTeamById } = useTeamValues();
const teamValues = getTeamById(team?.id);
Expand Down Expand Up @@ -51,7 +51,7 @@ function SynthesisBudget({ team }: { team: ITeamWithPlayers | null }) {
);
}

function SynthesisCarbon({ team }: { team: ITeamWithPlayers | null }) {
function SynthesisCarbon({ team }: { team: ITeam | null }) {
const { getTeamById } = useTeamValues();
const teamValues = getTeamById(team?.id);
const teamCarbonFootprintInKgPerDay = teamValues?.carbonFootprint || 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import sumBy from "lodash/sumBy";
import React from "react";

import { Typography } from "../../../common/components/Typography";
import { useCurrentStep } from "../../context/playContext";
import { useCurrentStep, usePlay } from "../../context/playContext";
import { Icon } from "../../../common/components/Icon";
import { computeTeamActionStats } from "../../utils/production";
import { TeamAction } from "../../../../utils/types";
Expand All @@ -26,11 +26,12 @@ function TeamActionsRecap({
showCredibility?: boolean;
}) {
const currentStep = useCurrentStep();
const { productionActionById } = usePlay();

const energyNameToEnergyStats = Object.fromEntries(
teamActions.map((teamAction) => [
teamAction.action.name,
computeTeamActionStats(teamAction),
productionActionById[teamAction.actionId].name,
computeTeamActionStats(teamAction, productionActionById),
])
);

Expand Down Expand Up @@ -78,7 +79,7 @@ function TeamActionsRecap({
<Box style={{ gap: "4px" }} display="flex" flexDirection="column">
{teamActions.map((teamAction) => (
<EnergyListItem
key={teamAction.action.name}
key={productionActionById[teamAction.actionId].name}
teamAction={teamAction}
showCredibility={showCredibility}
/>
Expand All @@ -96,12 +97,13 @@ function EnergyListItem({
showCredibility?: boolean;
}) {
const theme = useTheme();
const { productionActionById } = usePlay();

if (!teamAction) {
return null;
}

const stats = computeTeamActionStats(teamAction);
const stats = computeTeamActionStats(teamAction, productionActionById);
const color = teamAction.isTouched ? theme.palette.secondary.main : "white";

return (
Expand All @@ -121,7 +123,12 @@ function EnergyListItem({
</div>
)}
<Typography>
{t(`production.energy.${teamAction.action.name}.name`)} :
{t(
`production.energy.${
productionActionById[teamAction.actionId].name
}.name`
)}
:
</Typography>
</Box>

Expand Down
Loading

0 comments on commit 2d813a3

Please sign in to comment.