NavBar.jsx 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  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 { useC2C, 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 { ENABLE_WEBCONFERENCE } from "../../utils/settings";
  12. import useLocalStorage from "../../hooks/useLocalStorage";
  13. import InfoModal from "./InfoModal";
  14. import LoadGameModal from "./LoadGameModal";
  15. import LoadSessionModal from "./LoadSessionModal";
  16. import ChangeGameModal from "./ChangeGameModal";
  17. import ExportModal from "./ExportModal";
  18. import SaveExportModal from "./SaveExportModal";
  19. import WelcomeModal from "./WelcomeModal";
  20. import useSession from "../../hooks/useSession";
  21. const StyledNavBar = styled.div.attrs(() => ({ className: "nav" }))`
  22. position: fixed;
  23. top: 0;
  24. width: 100%;
  25. z-index: 205;
  26. background-color: #19202ce0;
  27. box-shadow: 0px 3px 6px #00000029;
  28. color: var(--font-color);
  29. & .nav-center {
  30. display: relative;
  31. & h3 {
  32. position: absolute;
  33. top: 0;
  34. margin: 0;
  35. padding: 0 2em;
  36. background-color: var(--color-blueGrey);
  37. box-shadow: 0px 3px 6px #00000029;
  38. line-height: 90px;
  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 } = useC2C("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") {
  132. if (history.length > 0) {
  133. // Go to previous if exists
  134. history.goBack();
  135. } else {
  136. // Otherwise go to /games root
  137. history.push("/games");
  138. }
  139. return;
  140. }
  141. // If inside room, go back to that room
  142. if (match.path === "/room/:roomId/session/:sessionId") {
  143. history.push(`/room/${match.params.roomId}`);
  144. return;
  145. }
  146. }, [history, match.params.roomId, match.path]);
  147. const handleBackWithConfirm = React.useCallback(() => {
  148. confirmAlert({
  149. title: t("Confirmation"),
  150. message: t("Do you really want to quit game edition?"),
  151. buttons: [
  152. {
  153. label: t("Yes"),
  154. onClick: async () => {
  155. history.push("/studio");
  156. },
  157. },
  158. {
  159. label: t("No"),
  160. onClick: () => {},
  161. },
  162. ],
  163. });
  164. }, [history, t]);
  165. return (
  166. <>
  167. <StyledNavBar>
  168. <div className="nav-left">
  169. {!editMode && (
  170. <>
  171. <Touch
  172. onClick={handleBack}
  173. alt={t("Go back")}
  174. title={t("Go back")}
  175. icon={"chevron-left"}
  176. style={{ display: "inline" }}
  177. />
  178. {isMaster && (
  179. <>
  180. <Touch
  181. onClick={() => setShowChangeGameModal((prev) => !prev)}
  182. alt={t("Change game")}
  183. title={t("Change game")}
  184. icon="https://icongr.am/material/cards-playing-outline.svg?size=24&color=f9fbfa"
  185. />
  186. <ChangeGameModal
  187. show={showChangeGameModal}
  188. setShow={setShowChangeGameModal}
  189. />
  190. </>
  191. )}
  192. </>
  193. )}
  194. {editMode && (
  195. <Touch
  196. onClick={handleBackWithConfirm}
  197. alt={t("Go back to studio")}
  198. title={t("Go back to studio")}
  199. icon={"chevron-left"}
  200. style={{ display: "inline" }}
  201. />
  202. )}
  203. </div>
  204. <div className="nav-center">
  205. <h3>{translation.name ? translation.name : "Air Board Game"}</h3>
  206. </div>
  207. <div className="nav-right">
  208. {!editMode && (
  209. <>
  210. <UserList />
  211. <Touch
  212. onClick={() => {
  213. setShowLink(true);
  214. }}
  215. icon="add-user"
  216. title={t("Invite more player")}
  217. />
  218. {ENABLE_WEBCONFERENCE && isBeta && (
  219. <WebConferenceButton room={room} />
  220. )}
  221. </>
  222. )}
  223. <div className="spacer" />
  224. {(isMaster || editMode) && (
  225. <Touch
  226. onClick={() => setShowLoadGameModal((prev) => !prev)}
  227. alt={editMode ? t("Load game") : t("Load session")}
  228. title={editMode ? t("Load game") : t("Load session")}
  229. icon={"upload-to-cloud"}
  230. />
  231. )}
  232. <Touch
  233. onClick={() => setShowSaveGameModal((prev) => !prev)}
  234. alt={t("Save")}
  235. title={editMode ? t("Save game") : t("Save session")}
  236. icon={editMode ? "save" : "download"}
  237. />
  238. <div className="spacer" />
  239. <Touch
  240. onClick={() => setShowInfoModal((prev) => !prev)}
  241. alt={t("Help & info")}
  242. title={t("Help & info")}
  243. icon={"info"}
  244. />
  245. </div>
  246. </StyledNavBar>
  247. <InfoModal show={showInfoModal} setShow={setShowInfoModal} />
  248. {!editMode && (
  249. <WelcomeModal show={showLink} setShow={setShowLink} welcome={false} />
  250. )}
  251. {!editMode && (
  252. <LoadSessionModal
  253. show={showLoadGameModal}
  254. setShow={setShowLoadGameModal}
  255. edit={editMode}
  256. />
  257. )}
  258. {editMode && (
  259. <LoadGameModal
  260. show={showLoadGameModal}
  261. setShow={setShowLoadGameModal}
  262. edit={editMode}
  263. />
  264. )}
  265. {!editMode && (
  266. <ExportModal show={showSaveGameModal} setShow={setShowSaveGameModal} />
  267. )}
  268. {editMode && (
  269. <SaveExportModal
  270. show={showSaveGameModal}
  271. setShow={setShowSaveGameModal}
  272. />
  273. )}
  274. </>
  275. );
  276. };
  277. export default NavBar;