NavBar.jsx 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. import React from "react";
  2. import styled from "styled-components";
  3. import { useTranslation } from "react-i18next";
  4. import { useHistory, useRouteMatch } from "react-router-dom";
  5. import { confirmAlert } from "react-confirm-alert";
  6. import { useWire, useBoardConfig } from "react-sync-board";
  7. import UserList from "../../users/UserList";
  8. import Touch from "../../ui/Touch";
  9. import WebConferenceButton from "../../webconf/WebConferenceButton";
  10. import { getBestTranslationFromConfig } from "../../utils/api";
  11. import useLocalStorage from "../../hooks/useLocalStorage";
  12. import InfoModal from "./InfoModal";
  13. import LoadGameModal from "./LoadGameModal";
  14. import LoadSessionModal from "./LoadSessionModal";
  15. import ChangeGameModal from "./ChangeGameModal";
  16. import ExportModal from "./ExportModal";
  17. import SaveExportModal from "./SaveExportModal";
  18. import WelcomeModal from "./WelcomeModal";
  19. import useSession from "../../hooks/useSession";
  20. const StyledNavBar = styled.div.attrs(() => ({ className: "nav" }))`
  21. position: fixed;
  22. top: 0;
  23. width: 100%;
  24. z-index: 205;
  25. background-color: #19202ce0;
  26. box-shadow: 0px 3px 6px #00000029;
  27. color: var(--font-color);
  28. & .nav-center {
  29. display: relative;
  30. & h3 {
  31. position: absolute;
  32. top: 0;
  33. margin: 0;
  34. padding: 0 2em;
  35. background-color: ${({ edit }) =>
  36. edit ? "var(--color-primary)" : "var(--color-blueGrey)"};
  37. box-shadow: 0px 3px 6px #00000029;
  38. line-height: 80px;
  39. letter-spacing: 0px;
  40. font-size: 24px;
  41. text-transform: uppercase;
  42. transform: perspective(280px) rotateX(-20deg);
  43. }
  44. }
  45. & .nav-right,
  46. & .nav-center,
  47. & .nav-left {
  48. align-items: center;
  49. }
  50. & .nav-left {
  51. & > div {
  52. padding-right: 1em;
  53. }
  54. padding-left: 40px;
  55. justify-content: flex-start;
  56. }
  57. & .nav-right {
  58. justify-content: flex-end;
  59. padding-right: 1em;
  60. gap: 1em;
  61. }
  62. & .spacer {
  63. flex: 1;
  64. max-width: 1em;
  65. }
  66. @media screen and (max-width: 640px) {
  67. & .nav-left {
  68. flex: 1;
  69. padding-left: 5px;
  70. & > div {
  71. padding-right: 2px;
  72. }
  73. }
  74. & .nav-center h3 {
  75. position: relative;
  76. padding: 0;
  77. background-color: transparent;
  78. box-shadow: none;
  79. line-height: 1.2em;
  80. font-size: 1.2em;
  81. transform: none;
  82. }
  83. & .nav-right {
  84. display: none;
  85. }
  86. & .spacer {
  87. flex: 0;
  88. }
  89. & {
  90. flex-direction: row;
  91. }
  92. & .save {
  93. display: none;
  94. }
  95. & .info {
  96. margin: 0;
  97. padding: 0;
  98. width: 24px;
  99. height: 24px;
  100. }
  101. & .help {
  102. margin: 0;
  103. padding: 0;
  104. width: 24px;
  105. height: 24px;
  106. }
  107. & h3 {
  108. font-size: 1.2em;
  109. }
  110. }
  111. `;
  112. const NavBar = ({ editMode }) => {
  113. const { t, i18n } = useTranslation();
  114. const { sessionId: room } = useSession();
  115. const [boardConfig] = useBoardConfig();
  116. const { isMaster } = useWire("board");
  117. const history = useHistory();
  118. const match = useRouteMatch();
  119. const [showLoadGameModal, setShowLoadGameModal] = React.useState(false);
  120. const [showSaveGameModal, setShowSaveGameModal] = React.useState(false);
  121. const [showChangeGameModal, setShowChangeGameModal] = React.useState(false);
  122. const [showInfoModal, setShowInfoModal] = React.useState(false);
  123. const [showLink, setShowLink] = React.useState(false);
  124. const [isBeta] = useLocalStorage("isBeta", false);
  125. const translation = React.useMemo(
  126. () => getBestTranslationFromConfig(boardConfig, i18n.languages),
  127. [boardConfig, i18n.languages]
  128. );
  129. const handleBack = React.useCallback(() => {
  130. // If inside session
  131. if (match.path === "/session/:sessionId" && history.length > 2) {
  132. // Go to previous if exists
  133. // Previous can be home or studio
  134. // Yes history should be greater than 2 for any reason...
  135. history.goBack();
  136. return;
  137. }
  138. // If inside room, go back to that room
  139. if (match.path === "/room/:roomId/session/:sessionId") {
  140. history.push(`/room/${match.params.roomId}`);
  141. return;
  142. }
  143. // Otherwise, go back to home
  144. history.push("/games");
  145. }, [history, match.params.roomId, match.path]);
  146. const handleBackWithConfirm = React.useCallback(() => {
  147. confirmAlert({
  148. title: t("Confirmation"),
  149. message: t("Do you really want to quit game edition?"),
  150. buttons: [
  151. {
  152. label: t("Yes"),
  153. onClick: async () => {
  154. history.push("/studio");
  155. },
  156. },
  157. {
  158. label: t("No"),
  159. onClick: () => {},
  160. },
  161. ],
  162. });
  163. }, [history, t]);
  164. return (
  165. <>
  166. <StyledNavBar edit={editMode}>
  167. <div className="nav-left">
  168. {!editMode && (
  169. <>
  170. <Touch
  171. onClick={handleBack}
  172. alt={t("Go back")}
  173. title={t("Go back")}
  174. icon={"chevron-left"}
  175. style={{ display: "inline" }}
  176. />
  177. {isMaster && (
  178. <>
  179. <Touch
  180. onClick={() => setShowChangeGameModal((prev) => !prev)}
  181. alt={t("Change game")}
  182. title={t("Change game")}
  183. icon="https://icongr.am/material/cards-playing-outline.svg?size=24&color=f9fbfa"
  184. />
  185. <ChangeGameModal
  186. show={showChangeGameModal}
  187. setShow={setShowChangeGameModal}
  188. />
  189. </>
  190. )}
  191. </>
  192. )}
  193. {editMode && (
  194. <Touch
  195. onClick={handleBackWithConfirm}
  196. alt={t("Go back to studio")}
  197. title={t("Go back to studio")}
  198. icon={"chevron-left"}
  199. style={{ display: "inline" }}
  200. />
  201. )}
  202. </div>
  203. <div className="nav-center">
  204. <h3>{translation.name ? translation.name : "Air Board Game"}</h3>
  205. </div>
  206. <div className="nav-right">
  207. {!editMode && (
  208. <>
  209. <UserList />
  210. <Touch
  211. onClick={() => {
  212. setShowLink(true);
  213. }}
  214. icon="add-user"
  215. title={t("Invite more player")}
  216. />
  217. <WebConferenceButton room={room} />
  218. </>
  219. )}
  220. <div className="spacer" />
  221. {(isMaster || editMode) && (
  222. <Touch
  223. onClick={() => setShowLoadGameModal((prev) => !prev)}
  224. alt={editMode ? t("Load game") : t("Load session")}
  225. title={editMode ? t("Load game") : t("Load session")}
  226. icon={"upload-to-cloud"}
  227. />
  228. )}
  229. <Touch
  230. onClick={() => setShowSaveGameModal((prev) => !prev)}
  231. alt={t("Save")}
  232. title={editMode ? t("Save game") : t("Save session")}
  233. icon={editMode ? "save" : "download"}
  234. />
  235. <div className="spacer" />
  236. <Touch
  237. onClick={() => setShowInfoModal((prev) => !prev)}
  238. alt={t("Help & info")}
  239. title={t("Help & info")}
  240. icon={"info"}
  241. />
  242. </div>
  243. </StyledNavBar>
  244. <InfoModal show={showInfoModal} setShow={setShowInfoModal} />
  245. {!editMode && (
  246. <WelcomeModal show={showLink} setShow={setShowLink} welcome={false} />
  247. )}
  248. {!editMode && (
  249. <LoadSessionModal
  250. show={showLoadGameModal}
  251. setShow={setShowLoadGameModal}
  252. edit={editMode}
  253. />
  254. )}
  255. {editMode && (
  256. <LoadGameModal
  257. show={showLoadGameModal}
  258. setShow={setShowLoadGameModal}
  259. edit={editMode}
  260. />
  261. )}
  262. {!editMode && (
  263. <ExportModal show={showSaveGameModal} setShow={setShowSaveGameModal} />
  264. )}
  265. {editMode && (
  266. <SaveExportModal
  267. show={showSaveGameModal}
  268. setShow={setShowSaveGameModal}
  269. />
  270. )}
  271. </>
  272. );
  273. };
  274. export default NavBar;