Skip to content

Commit

Permalink
WIP: Separate app into workspaces
Browse files Browse the repository at this point in the history
Signed-off-by: Johannes Loher <[email protected]>
  • Loading branch information
ghost91- committed Jul 1, 2024
1 parent 4e0ceff commit 3f6d294
Show file tree
Hide file tree
Showing 171 changed files with 17,591 additions and 25,946 deletions.
3 changes: 0 additions & 3 deletions .eslintignore

This file was deleted.

7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build
/build-server
build
dist
*.tsbuildinfo

# misc
.DS_Store
Expand Down
3 changes: 0 additions & 3 deletions .prettierignore

This file was deleted.

1 change: 1 addition & 0 deletions apps/client/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build
11 changes: 11 additions & 0 deletions apps/client/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import config from "@eop/eslint-config/type-checked";
import react from "eslint-plugin-react/configs/recommended.js";
import tseslint from "typescript-eslint";

export default tseslint.config(
{ ignores: ["build/"] },
{ languageOptions: { parserOptions: { project: "./tsconfig.json" } } },
{ settings: { react: { version: "detect" } } },
react,
...config,
);
94 changes: 94 additions & 0 deletions apps/client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"name": "@eop/client",
"type": "module",
"version": "0.23.0",
"main": "src/client/index.tsx",
"scripts": {
"build": "react-scripts build",
"start": "react-scripts start",
"test": "react-scripts test",
"lint": "eslint .",
"fixlint": "eslint . --fix",
"checkformat": "prettier . --check",
"format": "prettier . --write"
},
"dependencies": {
"@eop/cornucopia-cards": "*",
"@eop/shared": "*",
"@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/react-fontawesome": "^0.2.0",
"bootstrap": "^4.6.0",
"jointjs": "^3.7.7",
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-countdown-circle-timer": "^3.2.1",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
"react-map-interaction": "^2.1.0",
"react-nl2br": "^1.0.4",
"react-router-dom": "^5.3.1",
"reactstrap": "^8.10.1",
"reactstrap-confirm": "^1.3.2"
},
"devDependencies": {
"@eop/eslint-config": "*",
"@eop/prettier-config": "*",
"@eop/typescript-config": "*",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^12.1.5",
"@testing-library/user-event": "^14.5.2",
"@types/backbone": "^1.4.19",
"@types/react": "^17.0.43",
"@types/react-dom": "^17.0.14",
"@types/react-helmet": "^6.1.11",
"@types/react-router-dom": "^5.3.3",
"eslint-plugin-react": "^7.34.3",
"nock": "^13.3.8",
"prettier": "^3.3.2",
"react-scripts": "^5.0.1",
"typescript": "^4.8.4",
"typescript-eslint": "^8.0.0-alpha.37"
},
"overrides": {
"autoprefixer": "10.4.5"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}",
"!<rootDir>/node_modules/",
"!src/serviceWorker.js",
"!src/components/board/board.ignoretest.js",
"!src/jointjs/shapes.js",
"!src/index.tsx"
],
"coverageThreshold": {
"global": {
"branches": 5,
"functions": 5,
"lines": 5,
"statements": 5
}
},
"coverageReporters": [
"text",
"lcov"
]
},
"private": true
}
3 changes: 3 additions & 0 deletions apps/client/prettier.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import config from '@eop/prettier-config';

export default config;
File renamed without changes.
2 changes: 1 addition & 1 deletion public/index.html → apps/client/public/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
Expand Down
File renamed without changes
File renamed without changes.
File renamed without changes.
33 changes: 33 additions & 0 deletions apps/client/src/components/banner/banner.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import Banner from "./banner";

describe("Banner", () => {
const envBackup = process.env;

afterEach(() => (process.env = envBackup));

it("should render link if env var is defined", async () => {
// given
process.env.REACT_APP_EOP_BANNER_TEXT = "This is a banner text";
render(<Banner />);

// when
const banner = await screen.findByText("This is a banner text");

// then
expect(banner).toBeInTheDocument();
});

it("should not render link if env var is not defined", () => {
// given
process.env.REACT_APP_EOP_BANNER_TEXT = "";
render(<Banner />);

// when
const banner = screen.queryByText("This is a banner text");

// then
expect(banner).not.toBeInTheDocument();
});
});
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import React from 'react';
import {
API_PORT,
DEFAULT_GAME_MODE,
DEFAULT_TURN_DURATION,
ModelType,
} from '@eop/shared';
import { render, screen } from '@testing-library/react';
import Board from './board';
import { DEFAULT_TURN_DURATION, ModelType } from '../../../utils/constants';
import { DEFAULT_GAME_MODE } from '../../../utils/GameMode';
import type { GameState } from '../../../game/gameState';
import type { Ctx } from 'boardgame.io';
import React from 'react';
import nock from 'nock';

import { API_PORT } from '../../../utils/serverConfig';
import Board from './board';

import type { GameState } from '@eop/shared';
import type { Ctx } from 'boardgame.io';

const baseUrl = `${window.location.protocol}//${window.location.hostname}:${API_PORT}`;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import type { BoardProps as BoardgameIOBoardProps } from 'boardgame.io/react';
import React, { FC, useCallback, useEffect, useState } from 'react';
import Model from '../model/model';
import Deck from '../deck/deck';
import Sidebar from '../sidebar/sidebar';
import Threatbar from '../threatbar/threatbar';
import ImageModel from '../imagemodel/imagemodel';
import Timer from '../timer/timer';
import './board.css';
import request from 'superagent';
import Status from '../status/status';
import { getDealtCard } from '../../../utils/utils';
import { ModelType, SPECTATOR } from '../../../utils/constants';
import LicenseAttribution from '../license/licenseAttribution';
import { API_PORT } from '../../../utils/serverConfig';
import PrivacyEnhancedModel from '../privacyEnhancedModel/privacyEnhancedModel';
import Imprint from '../footer/imprint';
import Privacy from '../footer/privacy';
import Banner from '../banner/banner';
import type { GameState } from '../../../game/gameState';
import type { ThreatDragonModel } from '../../../types/ThreatDragonModel';
import { API_PORT, getDealtCard, ModelType, SPECTATOR } from "@eop/shared";
import type { BoardProps as BoardgameIOBoardProps } from "boardgame.io/react";
import React, { FC, useCallback, useEffect, useState } from "react";
import request from "superagent";

import Banner from "../banner/banner";
import Deck from "../deck/deck";
import Imprint from "../footer/imprint";
import Privacy from "../footer/privacy";
import ImageModel from "../imagemodel/imagemodel";
import LicenseAttribution from "../license/licenseAttribution";
import Model from "../model/model";
import PrivacyEnhancedModel from "../privacyEnhancedModel/privacyEnhancedModel";
import Sidebar from "../sidebar/sidebar";
import Status from "../status/status";
import Threatbar from "../threatbar/threatbar";
import Timer from "../timer/timer";

import "./board.css";

import type { GameState, ThreatDragonModel } from "@eop/shared";

type BoardProps = Pick<
BoardgameIOBoardProps<GameState>,
'G' | 'ctx' | 'matchID' | 'moves' | 'playerID' | 'credentials'
"G" | "ctx" | "matchID" | "moves" | "playerID" | "credentials"
>;

const Board: FC<BoardProps> = ({
Expand All @@ -35,14 +35,14 @@ const Board: FC<BoardProps> = ({
}) => {
const initialNames = Array.from<string>({
length: ctx.numPlayers,
}).fill('No Name');
}).fill("No Name");

const [names, setNames] = useState(initialNames);

const [model, setModel] = useState<ThreatDragonModel | undefined>(undefined);
const apiBase =
process.env.NODE_ENV === 'production'
? '/api'
process.env.NODE_ENV === "production"
? "/api"
: `${window.location.protocol}//${window.location.hostname}:${API_PORT}`;

const updateName = useCallback((index: number, name: string) => {
Expand All @@ -65,25 +65,29 @@ const Board: FC<BoardProps> = ({
console.error(err);
}
} else {
console.error('Credentials are missing.');
console.error("Credentials are missing.");
}
},
[apiBase, matchID, playerID, credentials],
);

const updateNames = useCallback(async () => {
// TODO: Type with zod and consider using react-query.
const playersResponse = await apiGetRequest('players');
for (const player of playersResponse?.body.players ?? []) {
if (typeof player.name !== 'undefined') {
const playersResponse = await apiGetRequest("players");
for (const player of (
playersResponse?.body as
| { players: { id: number; name: string }[] }
| undefined
)?.players ?? []) {
if (typeof player.name !== "undefined") {
updateName(player.id, player.name);
}
}
}, [apiGetRequest, updateName]);

const updateModel = useCallback(async () => {
// TODO: Type with zod and consider using react-query.
const modelResponse = await apiGetRequest('model');
const modelResponse = await apiGetRequest("model");

const model = modelResponse?.body as ThreatDragonModel | undefined;

Expand All @@ -93,23 +97,23 @@ const Board: FC<BoardProps> = ({
// consider using react-query instead
useEffect(() => {
if (G.modelType !== ModelType.IMAGE) {
updateModel();
void updateModel();
}
}, [G.modelType, updateModel]);

useEffect(() => {
updateNames();
void updateNames();
}, [updateNames]);

const current = playerID === ctx.currentPlayer;

const isInThreatStage =
!!ctx.activePlayers &&
!!playerID &&
ctx.activePlayers?.[playerID] === 'threats';
ctx.activePlayers?.[playerID] === "threats";

const isSpectator = !playerID;
const isFirstPlayerInThreatStage = ctx.activePlayers?.[0] === 'threats';
const isFirstPlayerInThreatStage = ctx.activePlayers?.[0] === "threats";

const shouldShowTimer =
isInThreatStage || (isSpectator && isFirstPlayerInThreatStage);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { FC, PropsWithChildren, useState } from 'react';
import { Button, ButtonProps } from 'reactstrap';
import { copyToClipboard } from '../../utils/utils';
import { faCopy, faCheck, faTimes } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React, { FC, PropsWithChildren, useState } from "react";
import { Button, ButtonProps } from "reactstrap";
import { copyToClipboard } from "../../utils/utils";
import { faCopy, faCheck, faTimes } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";

type CopyButtonProps = PropsWithChildren<
Pick<ButtonProps, 'color' | 'active' | 'block' | 'disabled' | 'size'> & {
Pick<ButtonProps, "color" | "active" | "block" | "disabled" | "size"> & {
text: string;
}
>;
Expand All @@ -22,11 +22,11 @@ const CopyButton: FC<CopyButtonProps> = ({
const handleClick = async () => {
try {
await copyToClipboard(text);
setColor('success');
setColor("success");
setIcon(faCheck);
} catch {
//If the copy fails, maybe alert the user somehow
setColor('danger');
setColor("danger");
setIcon(faTimes);
} finally {
setTimeout(() => {
Expand All @@ -37,7 +37,7 @@ const CopyButton: FC<CopyButtonProps> = ({
};

return (
<Button color={color} onClick={handleClick} {...props}>
<Button color={color} onClick={() => void handleClick()} {...props}>
{/* @ts-expect-error @fortawesome/react-fontawesome uses an older version of @fortawesome/fontawesome-svg-core (1.3.0), which makes the types incompatible. It still works correctly at runtime. */}
<FontAwesomeIcon icon={icon} fixedWidth /> {children}
</Button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { DEFAULT_GAME_MODE } from '@eop/shared';
import React from 'react';
import ReactDOM from 'react-dom';

import DealtCard from './dealtcard';
import { DEFAULT_GAME_MODE } from '../../../utils/GameMode';

it('renders without crashing', () => {
const div = document.createElement('div');
Expand Down
Loading

0 comments on commit 3f6d294

Please sign in to comment.