Skip to content

Commit

Permalink
feat(messages): Initial implementation of the messages feature
Browse files Browse the repository at this point in the history
Closes #13
  • Loading branch information
barnslig committed Jan 22, 2022
1 parent e6085da commit 7788d94
Show file tree
Hide file tree
Showing 22 changed files with 851 additions and 8 deletions.
2 changes: 1 addition & 1 deletion app/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ module.exports = {
},
},

setupFilesAfterEnv: ["<rootDir>/src/setupTests.ts"],
setupFilesAfterEnv: ["<rootDir>/src/setupTests.tsx"],
};
16 changes: 16 additions & 0 deletions app/lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
"defaultMessage": "Hygiene",
"description": "parameter label"
},
"DZHDmU": {
"defaultMessage": "Nachrichten",
"description": "main nav messages page item label"
},
"Ejhsxh": {
"defaultMessage": "Ein Fehler ist aufgetreten!",
"description": "unknown error snack"
Expand Down Expand Up @@ -79,6 +83,10 @@
"defaultMessage": "Crew-Moral",
"description": "parameter label"
},
"Vdokz/": {
"defaultMessage": "Es gibt noch keine Nachrichten",
"description": "messages page no messages yet title"
},
"WHOfrR": {
"defaultMessage": "Setze Charakter",
"description": "qr code action label"
Expand Down Expand Up @@ -107,6 +115,10 @@
"defaultMessage": "Diversity Puzzle Trails",
"description": "main page title"
},
"eYC0U9": {
"defaultMessage": "Nachrichten",
"description": "messages page title"
},
"f0maUH": {
"defaultMessage": "Um an einem Spiel teilzunehmen ist ein Spiel-Code erforderlich. Bitte tippe diesen hier ein:",
"description": "start code page description"
Expand Down Expand Up @@ -135,6 +147,10 @@
"defaultMessage": "An einem Spiel teilnehmen",
"description": "start code page title"
},
"nwAgUn": {
"defaultMessage": "Schau doch später nochmal vorbei.",
"description": "messages page no messages yet description"
},
"qPHCvM": {
"defaultMessage": "Spielstand",
"description": "global parameter card title"
Expand Down
14 changes: 13 additions & 1 deletion app/src/app/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ProgressBar from "@badrap/bar-of-progress";
import useLocation, { BaseLocationHook } from "wouter/use-location";

import useGameId from "../common/hooks/useGameId";
import config from "../config";

/**
* Wrap `React.lazy()` and return the factory as well for preloading the component
Expand All @@ -17,6 +18,7 @@ const lazyWithPreload = <T extends React.ComponentType<any>>(

const CodePage = lazyWithPreload(() => import("./pages/CodePage"));
const IndexPage = lazyWithPreload(() => import("./pages/IndexPage"));
const MessagesPage = lazyWithPreload(() => import("./pages/MessagesPage"));
const ScannerPage = lazyWithPreload(() => import("./pages/ScannerPage"));
const StartPage = lazyWithPreload(() => import("./pages/StartPage"));

Expand All @@ -37,6 +39,10 @@ const routeFactories = [
path: "/start/:gameId?",
factory: StartPage.factory,
},
{
path: "/messages",
factory: MessagesPage.factory,
},
];

/**
Expand Down Expand Up @@ -84,7 +90,13 @@ const AppRouter = () => {
<Route path="/start/:gameId?">
{({ gameId }) => <StartPage.Component gameId={gameId} />}
</Route>

{config.featureMessages ? (
<Route path="/messages">
{gameId ? <MessagesPage.Component /> : <Redirect to="/start" />}
</Route>
) : (
<></>
)}
{/* Redirect to index page on 404 */}
<Route>
<Redirect to="/" />
Expand Down
29 changes: 29 additions & 0 deletions app/src/app/MainNav.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { screen } from "@testing-library/react";
import * as React from "react";
import userEvent from "@testing-library/user-event";

import config from "../config";
import MainNav from "./MainNav";
import render from "../common/testing/render";

it("renders correctly", () => {
const { container } = render(<MainNav />);
expect(container.firstChild).toMatchSnapshot();
});

it("sets the location on click", () => {
render(<MainNav />);

expect(window.location.pathname).toEqual("/");

if (config.featureMessages) {
userEvent.click(screen.getByText(/Nachrichten/));
expect(window.location.pathname).toEqual("/messages");
}

userEvent.click(screen.getByText(/Scanner/));
expect(window.location.pathname).toEqual("/scan");

userEvent.click(screen.getByText(/Status/));
expect(window.location.pathname).toEqual("/");
});
21 changes: 18 additions & 3 deletions app/src/app/MainNav.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { Paper, BottomNavigation, BottomNavigationAction } from "@mui/material";
import { Home } from "@mui/icons-material";
import * as React from "react";
import { ChatBubble, Home } from "@mui/icons-material";
import { FormattedMessage } from "react-intl";
import { Paper, BottomNavigation, BottomNavigationAction } from "@mui/material";
import { useLocation } from "wouter";
import * as React from "react";

import QrCodeScanner from "../common/icons/QrCodeScanner";

import config from "../config";

type MainNavProps = {};

const MainNav = (props: MainNavProps) => {
Expand Down Expand Up @@ -47,6 +50,18 @@ const MainNav = (props: MainNavProps) => {
}
icon={<QrCodeScanner />}
/>
{config.featureMessages && (
<BottomNavigationAction
value="/messages"
label={
<FormattedMessage
defaultMessage="Nachrichten"
description="main nav messages page item label"
/>
}
icon={<ChatBubble />}
/>
)}
</BottomNavigation>
</Paper>
);
Expand Down
86 changes: 86 additions & 0 deletions app/src/app/__snapshots__/MainNav.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders correctly 1`] = `
<nav
class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation8 css-avw9ge-MuiPaper-root"
>
<div
class="MuiBottomNavigation-root css-16lloyr-MuiBottomNavigation-root"
>
<button
class="MuiButtonBase-root MuiBottomNavigationAction-root Mui-selected css-1ee5err-MuiButtonBase-root-MuiBottomNavigationAction-root"
tabindex="0"
type="button"
>
<svg
aria-hidden="true"
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-i4bv87-MuiSvgIcon-root"
data-testid="HomeIcon"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"
/>
</svg>
<span
class="MuiBottomNavigationAction-label Mui-selected css-imwso6-MuiBottomNavigationAction-label"
>
Status
</span>
<span
class="MuiTouchRipple-root css-8je8zh-MuiTouchRipple-root"
/>
</button>
<button
class="MuiButtonBase-root MuiBottomNavigationAction-root css-1ee5err-MuiButtonBase-root-MuiBottomNavigationAction-root"
tabindex="0"
type="button"
>
<svg
aria-hidden="true"
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-i4bv87-MuiSvgIcon-root"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M9.5 6.5v3h-3v-3h3M11 5H5v6h6V5zm-1.5 9.5v3h-3v-3h3M11 13H5v6h6v-6zm6.5-6.5v3h-3v-3h3M19 5h-6v6h6V5zm-6 8h1.5v1.5H13V13zm1.5 1.5H16V16h-1.5v-1.5zM16 13h1.5v1.5H16V13zm-3 3h1.5v1.5H13V16zm1.5 1.5H16V19h-1.5v-1.5zM16 16h1.5v1.5H16V16zm1.5-1.5H19V16h-1.5v-1.5zm0 3H19V19h-1.5v-1.5zM22 7h-2V4h-3V2h5v5zm0 15v-5h-2v3h-3v2h5zM2 22h5v-2H4v-3H2v5zM2 2v5h2V4h3V2H2z"
/>
</svg>
<span
class="MuiBottomNavigationAction-label css-imwso6-MuiBottomNavigationAction-label"
>
Scanner
</span>
<span
class="MuiTouchRipple-root css-8je8zh-MuiTouchRipple-root"
/>
</button>
<button
class="MuiButtonBase-root MuiBottomNavigationAction-root css-1ee5err-MuiButtonBase-root-MuiBottomNavigationAction-root"
tabindex="0"
type="button"
>
<svg
aria-hidden="true"
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-i4bv87-MuiSvgIcon-root"
data-testid="ChatBubbleIcon"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"
/>
</svg>
<span
class="MuiBottomNavigationAction-label css-imwso6-MuiBottomNavigationAction-label"
>
Nachrichten
</span>
<span
class="MuiTouchRipple-root css-8je8zh-MuiTouchRipple-root"
/>
</button>
</div>
</nav>
`;
41 changes: 41 additions & 0 deletions app/src/app/pages/MessagesPage.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { rest } from "msw";
import { screen, waitFor } from "@testing-library/react";
import * as React from "react";

import { server } from "../../mocks/server";
import MessagesPage from "./MessagesPage";
import render from "../../common/testing/render";

it("renders a loading screen", () => {
render(<MessagesPage />);

expect(screen.getByRole("progressbar")).toBeInTheDocument();
});

it("renders messages", async () => {
const { container } = render(<MessagesPage />);

await waitFor(() => expect(screen.getByText(/Test 123/)).toBeInTheDocument());
expect(container.firstChild).toMatchSnapshot();
});

it("renders no messages yet hero message", async () => {
server.use(
rest.get("/games/:gameId/messages", (req, res, ctx) => {
return res(
ctx.json({
data: [],
})
);
})
);

const { container } = render(<MessagesPage />);

await waitFor(() =>
expect(
screen.getByText(/Es gibt noch keine Nachrichten/)
).toBeInTheDocument()
);
expect(container.firstChild).toMatchSnapshot();
});
80 changes: 80 additions & 0 deletions app/src/app/pages/MessagesPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {
AppBar,
Toolbar,
Typography,
Box,
Container,
LinearProgress,
} from "@mui/material";
import { FormattedMessage } from "react-intl";
import * as React from "react";

import MainNav from "../MainNav";
import MessageCard from "../../common/components/MessageCard";
import useMessages from "../../common/hooks/api/useMessages";
import { Message } from "../../common/types/Message";
import HeroMessage from "../../common/components/HeroMessage";

const MessagesPage = () => {
const { data: messages } = useMessages();

// Scroll to the bottom after (new) messages are rendered
React.useEffect(() => {
const $html = document.documentElement;
$html.scrollTop = $html.scrollHeight;
}, [messages]);

/**
* Whether the API has returned zero messages
*/
const hasNoMessages = messages && messages.data.length === 0;

return (
<div>
<AppBar position="fixed">
<Toolbar>
<Typography component="h1" sx={{ flexGrow: 1 }} variant="h6">
<FormattedMessage
defaultMessage="Nachrichten"
description="messages page title"
/>
</Typography>
</Toolbar>
</AppBar>
<MainNav />
<Box
component="main"
paddingBottom={7}
paddingTop={10}
sx={{ display: "flex", alignItems: "flex-end", minHeight: "100vh" }}
>
{hasNoMessages ? (
<HeroMessage
title={
<FormattedMessage
defaultMessage="Es gibt noch keine Nachrichten"
description="messages page no messages yet title"
/>
}
description={
<FormattedMessage
defaultMessage="Schau doch später nochmal vorbei."
description="messages page no messages yet description"
/>
}
/>
) : messages ? (
<Container maxWidth="sm">
{messages.data.map((msg: Message) => (
<MessageCard key={msg.id} message={msg} />
))}
</Container>
) : (
<LinearProgress sx={{ width: "100%" }} />
)}
</Box>
</div>
);
};

export default MessagesPage;
Loading

0 comments on commit 7788d94

Please sign in to comment.