diff --git a/backend/src/common/types.ts b/backend/src/common/types.ts index 9e89be644..dabdae257 100644 --- a/backend/src/common/types.ts +++ b/backend/src/common/types.ts @@ -248,7 +248,10 @@ export type ColumnDefinitionType = | 'cargo' | 'island' | 'wind' - | 'rock'; + | 'rock' + | 'mad' + | 'sad' + | 'glad'; export type StripeLocales = | 'ar-AR' diff --git a/docs/docs/self-hosting/optionals.md b/docs/docs/self-hosting/optionals.md index 85cf4188c..4b66dc142 100644 --- a/docs/docs/self-hosting/optionals.md +++ b/docs/docs/self-hosting/optionals.md @@ -119,6 +119,7 @@ services: FRONTEND_GIPHY_API_KEY: '' # Optional, can be obtained here: https://developers.giphy.com/ FRONTEND_DEFAULT_LANGUAGE: 'en-GB' # Set the default language for new users FRONTEND_MARKETING_ROOT: 'https://www.retrospected.com' # URL of the marketing website + FRONTEND_AI_FEEDBACK_URL: 'http://' # URL of a freeform feedback form for AI feedback # -- Do Not Change -- BACKEND_HOST: backend # This should be the name of the backend service diff --git a/frontend/.env b/frontend/.env index 808fa5753..913a3b3ef 100644 --- a/frontend/.env +++ b/frontend/.env @@ -1,7 +1,11 @@ +# Do not fill any of these values except VITE_VERSION +# use the .env.local file instead + VITE_VERSION=$npm_package_version VITE_STRIPE_KEY= VITE_GIPHY_API_KEY= -VITE_MARKETING_ROOT=http://localhost:3001 +VITE_MARKETING_ROOT= VITE_GOOGLE_ANALYTICS_ID= VITE_GOOGLE_AD_WORDS_ID= VITE_GOOGLE_AD_WORDS_CONVERSION_ID= +VITE_AI_FEEDBACK_URL= \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html index 639ae3ecf..4346a25db 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -77,11 +77,14 @@ .loader { font-size: 5rem; font-weight: bold; + padding: 0; + margin: 0; + display: flex; } @keyframes blink { 50% { color: transparent } } - .loader__dot { animation: 1s blink infinite } + .loader__dot { animation: 1s blink infinite; padding: 0; margin: 0; display: block; } .loader__dot:nth-child(2) { animation-delay: 250ms } .loader__dot:nth-child(3) { animation-delay: 500ms } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 670443a9e..404cf33b2 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -14,11 +14,12 @@ import { Suspense } from 'react'; import { CodeSplitLoader } from './CodeSplitLoader'; import QuotaManager from './auth/QuotaManager'; import { ConfirmProvider } from 'material-ui-confirm'; +import { FullScreenLoader } from 'components/loaders/FullScreenLoader'; function App() { return ( - - + + }> - - + + ); } diff --git a/frontend/src/Layout.tsx b/frontend/src/Layout.tsx index 8a0a4383d..5ba6b1a26 100644 --- a/frontend/src/Layout.tsx +++ b/frontend/src/Layout.tsx @@ -3,13 +3,13 @@ import { Routes, Route, useLocation } from 'react-router-dom'; import { trackPageView } from './track'; import useIsCompatibleBrowser from './hooks/useIsCompatibleBrowser'; import OutdatedBrowser from './components/OutdatedBrowser'; -import useUser from './auth/useUser'; import { CodeSplitLoader } from './CodeSplitLoader'; import { Alert, AlertTitle } from '@mui/material'; import useBackendCapabilities from './global/useBackendCapabilities'; import { useTranslation } from 'react-i18next'; import { Welcome } from 'views/Welcome'; import { Header } from 'views/layout/Header'; +import useUser from 'state/user/useUser'; const Home = lazy(() => import('./views/Home')); const Game = lazy(() => import('./views/Game')); diff --git a/frontend/src/auth/AccountMenu.tsx b/frontend/src/auth/AccountMenu.tsx index 5598c632e..0b8b2f08d 100644 --- a/frontend/src/auth/AccountMenu.tsx +++ b/frontend/src/auth/AccountMenu.tsx @@ -1,13 +1,12 @@ -import { useCallback, useState, useRef, useContext } from 'react'; +import { useCallback, useState, useRef } from 'react'; import styled from '@emotion/styled'; import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; import Button from '@mui/material/Button'; import AccountIcon from '@mui/icons-material/AccountCircle'; -import useUser from './useUser'; +import useUser from '../state/user/useUser'; import LoginModal from './modal/LoginModal'; import { logout } from '../api'; -import UserContext from './Context'; import Avatar from '../components/Avatar'; import { useMatch, useNavigate } from 'react-router-dom'; import { Key, Logout, Star } from '@mui/icons-material'; @@ -21,10 +20,11 @@ import { import AccountCircle from '@mui/icons-material/AccountCircle'; import useIsAdmin from './useIsAdmin'; import { useTranslation } from 'react-i18next'; +import { useSetUser } from 'state/user/useSetUser'; const AccountMenu = () => { const { t } = useTranslation(); - const { setUser } = useContext(UserContext); + const setUser = useSetUser(); const [modalOpened, setModalOpen] = useState(false); const [menuOpen, setMenuOpen] = useState(false); const menuAnchor = useRef(null); @@ -79,20 +79,18 @@ const AccountMenu = () => { ref={menuAnchor} data-cy="account-menu" > - {user.name} {user.accountType === 'anonymous' ? ( ) : null} - - - + {menuAnchor.current ? ( @@ -180,10 +178,4 @@ const ChipContainer = styled.div` } `; -const AccountCircleContainer = styled.div` - @media screen and (max-width: 800px) { - display: none; - } -`; - export default AccountMenu; diff --git a/frontend/src/auth/AuthProvider.tsx b/frontend/src/auth/AuthProvider.tsx index ce1ba13b0..7e5892307 100644 --- a/frontend/src/auth/AuthProvider.tsx +++ b/frontend/src/auth/AuthProvider.tsx @@ -1,14 +1,10 @@ -import { useState, useEffect, useCallback, PropsWithChildren } from 'react'; -import Context from './Context'; -import { FullUser } from 'common'; -import { me } from '../api'; +import { useEffect, PropsWithChildren } from 'react'; import { setScope } from '../track'; +import useUser from 'state/user/useUser'; export default function AuthProvider({ children }: PropsWithChildren<{}>) { - const [user, setUser] = useState(null); - const [initialised, setInitialised] = useState(false); - - const handleUser = useCallback((user: FullUser | null) => { + const user = useUser(); + useEffect(() => { setScope((scope) => { if (scope && user) { scope.setUser({ @@ -18,20 +14,7 @@ export default function AuthProvider({ children }: PropsWithChildren<{}>) { }); } }); - setUser(user); - }, []); - - useEffect(() => { - async function getUser() { - setUser(await me()); - setInitialised(true); - } - getUser(); - }, []); + }, [user]); - return ( - - {children} - - ); + return <>{children}; } diff --git a/frontend/src/auth/Context.tsx b/frontend/src/auth/Context.tsx deleted file mode 100644 index e500f3300..000000000 --- a/frontend/src/auth/Context.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createContext } from 'react'; -import { FullUser } from 'common'; - -interface UserContextProps { - user: FullUser | null; - initialised: boolean; - setUser: (user: FullUser | null) => void; -} - -const UserContext = createContext({ - user: null, - initialised: false, - setUser: (_: FullUser | null) => {}, -}); - -export default UserContext; diff --git a/frontend/src/auth/QuotaManager.tsx b/frontend/src/auth/QuotaManager.tsx index 1d901d1f5..211b02524 100644 --- a/frontend/src/auth/QuotaManager.tsx +++ b/frontend/src/auth/QuotaManager.tsx @@ -2,7 +2,7 @@ import { Quota } from 'common'; import React, { useEffect } from 'react'; import { atom, useRecoilState } from 'recoil'; import { getQuota } from '../views/account/api'; -import useUser from './useUser'; +import useUser from '../state/user/useUser'; import { getItem } from '../utils/localStorage'; export const LOCAL_STORAGE_POSTS_KEY = 'posts'; diff --git a/frontend/src/auth/modal/LoginContent.tsx b/frontend/src/auth/modal/LoginContent.tsx index 2d1d67329..46c10f88c 100644 --- a/frontend/src/auth/modal/LoginContent.tsx +++ b/frontend/src/auth/modal/LoginContent.tsx @@ -1,7 +1,6 @@ -import { useCallback, useContext } from 'react'; +import { useCallback } from 'react'; import DialogContent from '@mui/material/DialogContent'; import { useTranslation } from 'react-i18next'; -import UserContext from '../Context'; import SocialAuth from './SocialAuth'; import AccountAuth from './AccountAuth'; import useOAuthAvailabilities from '../../global/useOAuthAvailabilities'; @@ -11,7 +10,8 @@ import styled from '@emotion/styled'; import { anonymousLogin, me, updateLanguage } from 'api'; import { trackEvent } from 'track'; import { useLanguage } from 'translations'; -import { Login } from '@mui/icons-material'; +import { NoAccounts } from '@mui/icons-material'; +import { useSetUser } from 'state/user/useSetUser'; interface LoginContentProps { anonymous: boolean; @@ -29,7 +29,7 @@ export default function LoginContent({ hasNoSocialMediaAuth && disableAnonymous && disablePasswords; const hasNoWayOtherThanAnonymous = hasNoSocialMediaAuth && disablePasswords; const { t } = useTranslation(); - const { setUser } = useContext(UserContext); + const setUser = useSetUser(); const [language] = useLanguage(); const handleAnonLogin = useCallback(async () => { @@ -80,7 +80,7 @@ export default function LoginContent({ onClick={handleAnonLogin} variant="text" color="secondary" - startIcon={} + startIcon={} data-cy="login-anonymous" > {t('AuthCommon.skipAndAnonLogin')} diff --git a/frontend/src/auth/modal/account/Register.tsx b/frontend/src/auth/modal/account/Register.tsx index ed4bdde1c..8e0a919c2 100644 --- a/frontend/src/auth/modal/account/Register.tsx +++ b/frontend/src/auth/modal/account/Register.tsx @@ -1,11 +1,4 @@ -import { - Suspense, - useCallback, - useState, - useMemo, - lazy, - useContext, -} from 'react'; +import { Suspense, useCallback, useState, useMemo, lazy } from 'react'; import Button from '@mui/material/Button'; import { Alert } from '@mui/material'; import { useLanguage } from '../../../translations'; @@ -13,11 +6,11 @@ import Wrapper from './../Wrapper'; import Input from '../../../components/Input'; import { Person, Email, VpnKey } from '@mui/icons-material'; import { register } from '../../../api'; -import UserContext from '../../Context'; import useBackendCapabilities from 'global/useBackendCapabilities'; import { useTranslation } from 'react-i18next'; import { validate } from 'email/validate'; import { trackEvent } from 'track'; +import { useSetUser } from 'state/user/useSetUser'; type RegisterProps = { onClose: () => void; @@ -35,7 +28,7 @@ const Register = ({ onClose, onCancel }: RegisterProps) => { const [passwordScore, setPasswordScore] = useState(0); const [generalError, setGeneralError] = useState(null); const [isSuccessful, setIsSuccessful] = useState(false); - const { setUser } = useContext(UserContext); + const setUser = useSetUser(); const { disablePasswordRegistration } = useBackendCapabilities(); const validEmail = useMemo(() => { diff --git a/frontend/src/auth/useDisplayMarketing.ts b/frontend/src/auth/useDisplayMarketing.ts index 3be8f66c5..eb557c914 100644 --- a/frontend/src/auth/useDisplayMarketing.ts +++ b/frontend/src/auth/useDisplayMarketing.ts @@ -1,5 +1,5 @@ import { useLocation } from 'react-router-dom'; -import useUser from './useUser'; +import useUser from '../state/user/useUser'; export default function useDisplayMarketing(): boolean { const location = useLocation(); diff --git a/frontend/src/auth/useIsAdmin.ts b/frontend/src/auth/useIsAdmin.ts index 99077f021..95440906f 100644 --- a/frontend/src/auth/useIsAdmin.ts +++ b/frontend/src/auth/useIsAdmin.ts @@ -1,5 +1,5 @@ import useBackendCapabilities from '../global/useBackendCapabilities'; -import useUser from './useUser'; +import useUser from '../state/user/useUser'; export default function useIsAdmin() { const user = useUser(); diff --git a/frontend/src/auth/useIsInitialised.ts b/frontend/src/auth/useIsInitialised.ts deleted file mode 100644 index db37b65d3..000000000 --- a/frontend/src/auth/useIsInitialised.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { useContext } from 'react'; -import UserContext from './Context'; - -function useIsInitialised(): boolean { - const { initialised } = useContext(UserContext); - - return initialised; -} - -export default useIsInitialised; diff --git a/frontend/src/auth/useIsPro.ts b/frontend/src/auth/useIsPro.ts index a352af0fb..35ff1339e 100644 --- a/frontend/src/auth/useIsPro.ts +++ b/frontend/src/auth/useIsPro.ts @@ -1,5 +1,5 @@ import useBackendCapabilities from '../global/useBackendCapabilities'; -import useUser from './useUser'; +import useUser from '../state/user/useUser'; export default function useIsPro() { const user = useUser(); diff --git a/frontend/src/auth/useIsTrial.ts b/frontend/src/auth/useIsTrial.ts index 1f26db39d..b7119a5aa 100644 --- a/frontend/src/auth/useIsTrial.ts +++ b/frontend/src/auth/useIsTrial.ts @@ -1,4 +1,4 @@ -import useUser from './useUser'; +import useUser from '../state/user/useUser'; export default function useIsTrial() { const user = useUser(); diff --git a/frontend/src/common/types.ts b/frontend/src/common/types.ts index 9e89be644..dabdae257 100644 --- a/frontend/src/common/types.ts +++ b/frontend/src/common/types.ts @@ -248,7 +248,10 @@ export type ColumnDefinitionType = | 'cargo' | 'island' | 'wind' - | 'rock'; + | 'rock' + | 'mad' + | 'sad' + | 'glad'; export type StripeLocales = | 'ar-AR' diff --git a/frontend/src/components/Page.tsx b/frontend/src/components/Page.tsx index 6c1467a5a..cd6ab9c5b 100644 --- a/frontend/src/components/Page.tsx +++ b/frontend/src/components/Page.tsx @@ -1,11 +1,11 @@ import styled from '@emotion/styled'; export const Page = styled.main` - margin: 50px; + margin: 0px 50px 50px 50px; @media screen and (max-width: 600px) { margin: 10px; margin-bottom: 80px; - margin-top: 30px; + margin-top: 0px; } margin-bottom: 80px; `; diff --git a/frontend/src/components/ProPill.tsx b/frontend/src/components/ProPill.tsx index 27aabdcce..3c1b16971 100644 --- a/frontend/src/components/ProPill.tsx +++ b/frontend/src/components/ProPill.tsx @@ -3,7 +3,7 @@ import { colors } from '@mui/material'; import { Star } from '@mui/icons-material'; import useIsPro from '../auth/useIsPro'; import useIsTrial from '../auth/useIsTrial'; -import useUser from '../auth/useUser'; +import useUser from '../state/user/useUser'; interface ProPillProps { small?: boolean; diff --git a/frontend/src/components/loaders/FullScreenLoader.tsx b/frontend/src/components/loaders/FullScreenLoader.tsx new file mode 100644 index 000000000..81015c996 --- /dev/null +++ b/frontend/src/components/loaders/FullScreenLoader.tsx @@ -0,0 +1,51 @@ +import styled from '@emotion/styled'; + +export function FullScreenLoader() { + return ( + + + R. + . + . + + + ); +} + +const Container = styled.div` + background-color: #673ab7; + height: 100%; + width: 100%; + position: fixed; + top: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif; +`; + +const Loader = styled.div` + font-size: 5rem; + font-weight: bold; + display: flex; + margin: 0; + padding: 0; + @keyframes blink { + 50% { + color: transparent; + } + } + > span { + animation: 1s blink infinite; + display: block; + margin: 0; + } + > span:nth-child(2) { + animation-delay: 250ms; + } + > span:nth-child(3) { + animation-delay: 500ms; + } +`; diff --git a/frontend/src/hooks/usePreviousSessions.ts b/frontend/src/hooks/usePreviousSessions.ts index 1f98c609f..0a90adab5 100644 --- a/frontend/src/hooks/usePreviousSessions.ts +++ b/frontend/src/hooks/usePreviousSessions.ts @@ -1,5 +1,5 @@ import { SessionMetadata } from 'common'; -import useUser from '../auth/useUser'; +import useUser from '../state/user/useUser'; import { fetchPreviousSessions } from '../api'; import { useState, useEffect, useCallback } from 'react'; diff --git a/frontend/src/hooks/useQuota.ts b/frontend/src/hooks/useQuota.ts index dc075b6f5..db800eb94 100644 --- a/frontend/src/hooks/useQuota.ts +++ b/frontend/src/hooks/useQuota.ts @@ -6,7 +6,7 @@ import { DEFAULT_QUOTA, LOCAL_STORAGE_POSTS_KEY, } from '../auth/QuotaManager'; -import useUser from '../auth/useUser'; +import useUser from '../state/user/useUser'; import { setItem } from '../utils/localStorage'; type QuotaResult = { diff --git a/frontend/src/molecules/NameEditor.tsx b/frontend/src/molecules/NameEditor.tsx index b47cac702..c2f54cba5 100644 --- a/frontend/src/molecules/NameEditor.tsx +++ b/frontend/src/molecules/NameEditor.tsx @@ -1,16 +1,16 @@ -import UserContext from 'auth/Context'; -import useUser from 'auth/useUser'; +import useUser from 'state/user/useUser'; import EditableLabel from 'components/EditableLabel'; import { useSnackbar } from 'notistack'; -import { useCallback, useContext } from 'react'; +import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { updateUserName } from 'views/account/api'; +import { useSetUser } from 'state/user/useSetUser'; export function NameEditor() { const { enqueueSnackbar } = useSnackbar(); const { t } = useTranslation(); const user = useUser(); - const { setUser } = useContext(UserContext); + const setUser = useSetUser(); const handleEditName = useCallback( async (name: string) => { const trimmed = name.trim(); diff --git a/frontend/src/state/columns.ts b/frontend/src/state/columns.ts index d35f668fe..81632d834 100644 --- a/frontend/src/state/columns.ts +++ b/frontend/src/state/columns.ts @@ -2,14 +2,14 @@ import { ColumnDefinition, ColumnDefinitionType } from 'common'; import { v4 } from 'uuid'; import keyBy from 'lodash/keyBy'; import { ColumnSettings, Template, TranslationFunction } from './types'; -import { getTemplate } from './templates'; +import { getTemplateColumns } from './templates'; import isEqual from 'lodash/isEqual'; export function buildDefaults( template: Template, translations: TranslationFunction ): ColumnSettings[] { - const base = getTemplate(template, translations); + const base = getTemplateColumns(template, translations); return base; } @@ -153,6 +153,24 @@ export const getTemplateColumnByType = label: t('PostBoard.rockQuestion'), type: 'rock', }, + { + color: '#FFCDD2', + icon: 'rage', + label: t('PostBoard.madQuestion'), + type: 'mad', + }, + { + color: '#FFECB3', + icon: 'disappointed', + label: t('PostBoard.sadQuestion'), + type: 'sad', + }, + { + color: '#C8E6C9', + icon: 'blush', + label: t('PostBoard.gladQuestion'), + type: 'glad', + }, ] as ColumnSettings[], (x) => x.type ); diff --git a/frontend/src/state/templates.ts b/frontend/src/state/templates.tsx similarity index 63% rename from frontend/src/state/templates.ts rename to frontend/src/state/templates.tsx index ef05c4387..bf2f74408 100644 --- a/frontend/src/state/templates.ts +++ b/frontend/src/state/templates.tsx @@ -5,27 +5,41 @@ import { TranslationFunction, } from './types'; import { getTemplateColumnByType } from './columns'; +import { Bookmark } from '@mui/icons-material'; export function getAllTemplates(t: TranslationFunction): TemplateDefinition[] { return [ { type: 'default', name: t('Template.default')!, + icon: , + }, + { + type: 'well-not-well-ideas', + name: t('Template.wellNotWellIdeas')!, + icon: , }, { type: 'well-not-well', name: t('Template.wellNotWell')!, + icon: , + }, + { + type: 'mad-sad-glad', + name: t('Template.madSadGlad')!, + icon: , }, { type: 'start-stop-continue', name: t('Template.startStopContinue')!, + icon: , }, - { type: 'four-l', name: t('Template.fourLs')! }, - { type: 'sailboat', name: t('Template.sailboat')! }, + { type: 'four-l', name: t('Template.fourLs')!, icon: }, + { type: 'sailboat', name: t('Template.sailboat')!, icon: }, ]; } -export function getTemplate( +export function getTemplateColumns( template: Template, translations: TranslationFunction ): ColumnSettings[] { @@ -33,10 +47,14 @@ export function getTemplate( switch (template) { case 'default': return [dic('well'), dic('notWell'), dic('ideas')]; + case 'well-not-well-ideas': + return [dic('well'), dic('notWell'), dic('ideas')]; case 'well-not-well': return [dic('well'), dic('notWell')]; case 'start-stop-continue': return [dic('start'), dic('stop'), dic('continue')]; + case 'mad-sad-glad': + return [dic('mad'), dic('sad'), dic('glad')]; case 'four-l': return [dic('liked'), dic('learned'), dic('lacked'), dic('longedFor')]; case 'sailboat': diff --git a/frontend/src/state/types.ts b/frontend/src/state/types.ts index fe59363f3..d9a3bd99e 100644 --- a/frontend/src/state/types.ts +++ b/frontend/src/state/types.ts @@ -11,13 +11,16 @@ export interface ColumnSettings { export type Template = | 'default' | 'well-not-well' + | 'well-not-well-ideas' | 'start-stop-continue' | 'four-l' - | 'sailboat'; + | 'sailboat' + | 'mad-sad-glad'; export interface TemplateDefinition { type: Template; name: string; + icon: React.ReactNode; } export type TranslationFunction = TFunction, undefined>; diff --git a/frontend/src/state/user/useSetUser.ts b/frontend/src/state/user/useSetUser.ts new file mode 100644 index 000000000..b07c540b5 --- /dev/null +++ b/frontend/src/state/user/useSetUser.ts @@ -0,0 +1,7 @@ +import { useSetRecoilState } from 'recoil'; +import { userState } from './user-state'; + +export function useSetUser() { + const setUser = useSetRecoilState(userState); + return setUser; +} diff --git a/frontend/src/auth/useUser.ts b/frontend/src/state/user/useUser.ts similarity index 56% rename from frontend/src/auth/useUser.ts rename to frontend/src/state/user/useUser.ts index 35252d9ba..be76620f1 100644 --- a/frontend/src/auth/useUser.ts +++ b/frontend/src/state/user/useUser.ts @@ -1,10 +1,9 @@ -import { useContext } from 'react'; -import UserContext from './Context'; import { FullUser } from 'common'; +import { useRecoilValue } from 'recoil'; +import { userState } from './user-state'; function useUser(): FullUser | null { - const { user } = useContext(UserContext); - + const user = useRecoilValue(userState); return user; } @@ -14,9 +13,9 @@ interface UseUserMetadataReturn { } export function useUserMetadata(): UseUserMetadataReturn { - const { user, initialised } = useContext(UserContext); + const user = useUser(); - return { user, initialised }; + return { user, initialised: true }; } export default useUser; diff --git a/frontend/src/state/user/user-state.ts b/frontend/src/state/user/user-state.ts new file mode 100644 index 000000000..c3fb38797 --- /dev/null +++ b/frontend/src/state/user/user-state.ts @@ -0,0 +1,16 @@ +import { me } from 'api'; +import { FullUser } from 'common'; +import { atom, selector } from 'recoil'; + +const userDefaults = selector({ + key: 'user-defaults', + get: async () => { + const user = await me(); + return user; + }, +}); + +export const userState = atom({ + key: 'user', + default: userDefaults, +}); diff --git a/frontend/src/testing/index.tsx b/frontend/src/testing/index.tsx index b648ff26e..940f57cef 100644 --- a/frontend/src/testing/index.tsx +++ b/frontend/src/testing/index.tsx @@ -1,4 +1,4 @@ -import { PropsWithChildren, useEffect, useState } from 'react'; +import { PropsWithChildren, useEffect } from 'react'; import { render, RenderOptions, RenderResult } from '@testing-library/react'; import { FullUser, Session, defaultOptions } from 'common'; import { @@ -7,9 +7,33 @@ import { DroppableProvided, DroppableStateSnapshot, } from '@hello-pangea/dnd'; -import UserContext from '../auth/Context'; import useSession from '../views/game/useSession'; import { RecoilRoot } from 'recoil'; +import { userState } from 'state/user/user-state'; + +const user: FullUser = { + id: 'John Doe', + name: 'John Doe', + photo: null, + accountType: 'anonymous', + language: 'en-GB', + username: 'johndoe', + email: 'john@doe.com', + pro: false, + stripeId: null, + subscriptionsId: null, + currency: null, + plan: null, + planOwner: null, + planOwnerEmail: null, + planAdmins: null, + domain: null, + ownPlan: null, + ownSubscriptionsId: null, + trial: null, + canDeleteSession: false, + identityId: 'John Doe Identity', +}; export const initialSession: Session = { id: 'test-session', @@ -35,7 +59,7 @@ export const initialSession: Session = { export function AllTheProviders({ children }: PropsWithChildren<{}>) { return ( - + snap.set(userState, user)}> {children} ); @@ -43,64 +67,15 @@ export function AllTheProviders({ children }: PropsWithChildren<{}>) { export default function Inner({ children }: PropsWithChildren<{}>) { const { receiveBoard } = useSession(); - const [user, setUser] = useState({ - id: 'John Doe', - name: 'John Doe', - photo: null, - accountType: 'anonymous', - language: 'en-GB', - username: 'johndoe', - email: 'john@doe.com', - pro: false, - stripeId: null, - subscriptionsId: null, - currency: null, - plan: null, - planOwner: null, - planOwnerEmail: null, - planAdmins: null, - domain: null, - ownPlan: null, - ownSubscriptionsId: null, - trial: null, - canDeleteSession: false, - identityId: 'John Doe Identity', - }); + useEffect(() => { receiveBoard(initialSession); - setUser({ - id: 'John Doe', - name: 'John Doe', - photo: null, - accountType: 'anonymous', - language: 'en-GB', - username: 'johndoe', - email: 'john@doe.com', - pro: false, - stripeId: null, - subscriptionsId: null, - currency: null, - plan: null, - planOwner: null, - planOwnerEmail: null, - planAdmins: null, - domain: null, - ownPlan: null, - ownSubscriptionsId: null, - trial: null, - canDeleteSession: false, - identityId: 'John Doe Identity', - }); }, [receiveBoard]); return ( {}}> {(dropProvided: DroppableProvided, _: DroppableStateSnapshot) => ( -
- - {children} - -
+
{children}
)}
diff --git a/frontend/src/translations/LanguageProvider.tsx b/frontend/src/translations/LanguageProvider.tsx index 5ef780076..a23cd6a18 100644 --- a/frontend/src/translations/LanguageProvider.tsx +++ b/frontend/src/translations/LanguageProvider.tsx @@ -1,5 +1,5 @@ import { useEffect, PropsWithChildren } from 'react'; -import useUser from '../auth/useUser'; +import useUser from '../state/user/useUser'; import { useTranslation } from 'react-i18next'; export default function LanguageProvider({ children }: PropsWithChildren<{}>) { diff --git a/frontend/src/translations/locales/ar-SA.json b/frontend/src/translations/locales/ar-SA.json index 3bd1887a0..e5feca2d3 100644 --- a/frontend/src/translations/locales/ar-SA.json +++ b/frontend/src/translations/locales/ar-SA.json @@ -80,7 +80,8 @@ "postCategory": "إعدادات النشر", "postCategorySub": "تعيين القواعد حول ما يمكن للمستخدم أن يفعله عند إنشاء أو عرض مشاركة", "customTemplateCategory": "قالب العمود", - "customTemplateCategorySub": "تعيين عدد الأعمدة وخصائصها", + "customTemplateCategorySub": "حدد قالب وقم بتخصيص الأعمدة الخاصة بك", + "customTemplateAddColumn": "إضافة عمود جديد", "startButton": "بدء الجلسة", "editButton": "تحديث", "maxUpVotes": "الحد الاقصى للتصويتات", @@ -132,6 +133,9 @@ "islandQuestion": "الجزيرة", "windQuestion": "الريح", "rockQuestion": "الصخور", + "madQuestion": "مجنون", + "sadQuestion": "حزين", + "gladQuestion": "سعيد", "disconnected": "لقد تم فصلك عن الدورة الحالية.", "reconnect": "إعادة الاتصال", "notLoggedIn": "لم تقم بتسجيل الدخول. يمكنك عرض هذه الجلسة كمتفرج، ولكن يجب تسجيل الدخول للمشاركة.", @@ -169,9 +173,11 @@ "Template": { "default": "الافتراضي", "wellNotWell": "حسنا / غير جيد", + "wellNotWellIdeas": "جيد/غير جيد/أفكار", "startStopContinue": "بدء / إيقاف / متابعة", "fourLs": "أربعة لترات", - "sailboat": "زورق بحري" + "sailboat": "زورق بحري", + "madSadGlad": "مجنون / حزين / سعيد" }, "Clients": { "header": "الضيوف الحاضرين معنا الآن:", @@ -222,7 +228,7 @@ "جيد", "قوي" ], - "skipAndAnonLogin": "تخطي وتسجلي في مجهول" + "skipAndAnonLogin": "استخدام مجهول" }, "AccountLogin": { "header": "كلمة المرور", @@ -501,6 +507,7 @@ "• ما هي أفضل الممارسات لأثر رجعي على شبكة الإنترنت؟", "كيف يمكنني أن أجعل رجعي أكثر متعة؟", "كيف يمكنني جعلها أكثر انخراطاً؟" - ] + ], + "feedback": "ترك بعض الملاحظات" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/de-DE.json b/frontend/src/translations/locales/de-DE.json index f866a8e76..760fc52a4 100644 --- a/frontend/src/translations/locales/de-DE.json +++ b/frontend/src/translations/locales/de-DE.json @@ -80,7 +80,8 @@ "postCategory": "Beitragseinstellungen", "postCategorySub": "Stelle ein, wie Nutzer mit Beiträgen interagieren können", "customTemplateCategory": "Spaltenkonfiguration", - "customTemplateCategorySub": "Setzen Sie die Anzahl an Spalten und deren Eigenschaften", + "customTemplateCategorySub": "Wählen Sie eine Vorlage aus und passen Sie Ihre Spalten an", + "customTemplateAddColumn": "Neue Spalte hinzufügen", "startButton": "Spiel starten!", "editButton": "Aktualisieren", "maxUpVotes": "Max. Positiv-Stimmen", @@ -132,6 +133,9 @@ "islandQuestion": "Insel", "windQuestion": "Wind", "rockQuestion": "Fels", + "madQuestion": "Wahnsinnig", + "sadQuestion": "Traurig", + "gladQuestion": "Glad", "disconnected": "Sie wurden von der aktuellen Sitzung getrennt.", "reconnect": "Neu verbinden", "notLoggedIn": "Sie sind nicht eingeloggt. Sie können diese Sitzung als Zuschauer betrachten, müssen sich aber einloggen, um daran teilzunehmen.", @@ -169,9 +173,11 @@ "Template": { "default": "Standard", "wellNotWell": "Gut / Nicht Gut", + "wellNotWellIdeas": "Gut / Nicht gut / Ideen", "startStopContinue": "Start / Stop / Weiter", "fourLs": "Vier Ls", - "sailboat": "Segelboot" + "sailboat": "Segelboot", + "madSadGlad": "Wahnsinnig / Traurig / Glad" }, "Clients": { "header": "Mit dabei sind:", @@ -222,7 +228,7 @@ "gut", "stark" ], - "skipAndAnonLogin": "Überspringe und logge mich anonym ein" + "skipAndAnonLogin": "Anonym verwenden" }, "AccountLogin": { "header": "Passwort", @@ -501,6 +507,7 @@ "Was sind die besten Praktiken für eine Online-Retrospektive?", "Wie kann ich meine Retrospektive noch mehr Spaß machen?", "Wie kann ich ihn engagierter gestalten?" - ] + ], + "feedback": "Feedback hinterlassen" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/en-GB.json b/frontend/src/translations/locales/en-GB.json index 7474c5823..e90fd6352 100644 --- a/frontend/src/translations/locales/en-GB.json +++ b/frontend/src/translations/locales/en-GB.json @@ -80,7 +80,8 @@ "postCategory": "Post settings", "postCategorySub": "Set the rules about what a user can do when creating or viewing a post", "customTemplateCategory": "Column Template", - "customTemplateCategorySub": "Set the number of columns and their characteristics", + "customTemplateCategorySub": "Select a template and customize your columns", + "customTemplateAddColumn": "Add a new column", "startButton": "Start the session", "editButton": "Update", "maxUpVotes": "Max Up-Votes", @@ -132,6 +133,9 @@ "islandQuestion": "Island", "windQuestion": "Wind", "rockQuestion": "Rock", + "madQuestion": "Mad", + "sadQuestion": "Sad", + "gladQuestion": "Glad", "disconnected": "You have been disconnected from the current session.", "reconnect": "Reconnect", "notLoggedIn": "You are not logged in. You can view this session as a spectator, but must login to participate.", @@ -169,9 +173,11 @@ "Template": { "default": "Default", "wellNotWell": "Well / Not Well", + "wellNotWellIdeas": "Well / Not Well / Ideas", "startStopContinue": "Start / Stop / Continue", "fourLs": "Four Ls", - "sailboat": "Sailboat" + "sailboat": "Sailboat", + "madSadGlad": "Mad / Sad / Glad" }, "Clients": { "header": "Participants:", @@ -222,7 +228,7 @@ "good", "strong" ], - "skipAndAnonLogin": "Skip and log me in Anonymously" + "skipAndAnonLogin": "Use Anonymously" }, "AccountLogin": { "header": "Password", @@ -501,6 +507,7 @@ "What are the best practices for an online retrospective?", "How can I make my retrospective more fun?", "How can I make it more engaging?" - ] + ], + "feedback": "Leave some feedback" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/es-ES.json b/frontend/src/translations/locales/es-ES.json index 051e18f26..499aa183e 100644 --- a/frontend/src/translations/locales/es-ES.json +++ b/frontend/src/translations/locales/es-ES.json @@ -80,7 +80,8 @@ "postCategory": "Ajustes de publicación", "postCategorySub": "Establecer las reglas sobre lo que un usuario puede hacer al crear o ver un mensaje", "customTemplateCategory": "Plantilla de columna", - "customTemplateCategorySub": "Establecer el número de columnas y sus características", + "customTemplateCategorySub": "Seleccione una plantilla y personalice sus columnas", + "customTemplateAddColumn": "Añadir una nueva columna", "startButton": "Iniciar la sesión", "editButton": "Actualizar", "maxUpVotes": "Máximo de votos", @@ -132,6 +133,9 @@ "islandQuestion": "Isla", "windQuestion": "Viento", "rockQuestion": "Roca", + "madQuestion": "Loco", + "sadQuestion": "Triste", + "gladQuestion": "Glaciar", "disconnected": "Has sido desconectado de la sesión actual.", "reconnect": "Volver a conectar", "notLoggedIn": "No estás conectado. Puedes ver esta sesión como un espectador, pero debes iniciar sesión para participar.", @@ -169,9 +173,11 @@ "Template": { "default": "Por defecto", "wellNotWell": "Bueno / No Bueno", + "wellNotWellIdeas": "Bueno / No Bueno / Ideas", "startStopContinue": "Inicio / Parar / Continuar", "fourLs": "Cuatro Ls", - "sailboat": "Barco de vela" + "sailboat": "Barco de vela", + "madSadGlad": "Loco / Triste / Glad" }, "Clients": { "header": "Acompañenos amablemente en este momento:", @@ -222,7 +228,7 @@ "bueno", "fuerte" ], - "skipAndAnonLogin": "Saltar y registrarme anónimamente" + "skipAndAnonLogin": "Usar anónimamente" }, "AccountLogin": { "header": "Contraseña", @@ -501,6 +507,7 @@ "¿Cuáles son las mejores prácticas para una retrospectiva en línea?", "¿Cómo puedo hacer que mi retrospectiva sea más divertida?", "¿Cómo puedo hacerla más interesante?" - ] + ], + "feedback": "Dejar algunos comentarios" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/fr-FR.json b/frontend/src/translations/locales/fr-FR.json index 9bdb9e46a..5b9f24c1a 100644 --- a/frontend/src/translations/locales/fr-FR.json +++ b/frontend/src/translations/locales/fr-FR.json @@ -80,7 +80,8 @@ "postCategory": "Options des posts", "postCategorySub": "Règles concernant ce qu'un utilisateur peut faire sur un post", "customTemplateCategory": "Colonnes personalisées", - "customTemplateCategorySub": "Définir le nombre de colonnes et leurs caractéristiques", + "customTemplateCategorySub": "Sélectionnez un modèle et personnalisez vos colonnes", + "customTemplateAddColumn": "Ajouter une nouvelle colonne", "startButton": "Lancez la session", "editButton": "Mettre à jour", "maxUpVotes": "Nb de votes max (positifs)", @@ -109,7 +110,7 @@ "allowReorderingHelp": "Permettre aux utilisateurs de réorganiser l'ordre des posts", "blurCards": "Flouter", "blurCardsHelp": "Les posts sont floutés, jusqu'à ce qu'un modérateur révèle les posts", - "template": "Règles prédéfinies", + "template": "Modèles", "templateHelp": "Sélectionnez un jeu de colonnes prédéfini", "numberOfColumns": "Nombre de colonnes", "numberOfColumnsHelp": "Réglez le nombre de colonnes", @@ -132,6 +133,9 @@ "islandQuestion": "Île", "windQuestion": "Vent", "rockQuestion": "Rocher", + "madQuestion": "Furieux", + "sadQuestion": "Malheureux", + "gladQuestion": "Joyeux", "disconnected": "Vous avez été déconnecté de la session.", "reconnect": "Se reconnecter", "notLoggedIn": "Vous n'êtes pas connecté. Vous pouvez regarder cette session en tant que spectateur, mais vous devez vous connecter pour participer.", @@ -169,9 +173,11 @@ "Template": { "default": "Par défaut", "wellNotWell": "Bien / Pas Bien", + "wellNotWellIdeas": "Bien / Pas Bien / Idées", "startStopContinue": "Commencer / Arrêter / Continuer", "fourLs": "Les 4 A", - "sailboat": "Bateau" + "sailboat": "Bateau", + "madSadGlad": "Furieux / Malheureux / Joyeux" }, "Clients": { "header": "Participants :", @@ -222,7 +228,7 @@ "suffisant", "excellent" ], - "skipAndAnonLogin": "Connectez-moi en mode anonyme à la place" + "skipAndAnonLogin": "Utiliser anonymement" }, "AccountLogin": { "header": "Mot de Passe", @@ -501,6 +507,7 @@ "Quelles sont les meilleurs pratiques quant aux rétrospectives en ligne ?", "Comment puis-je rendre ma rétrospective plus amusante?", "Comment puis-je la rendre plus engageante ?" - ] + ], + "feedback": "Donnez-nous votre avis !" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/hu-HU.json b/frontend/src/translations/locales/hu-HU.json index 9a48566bb..4350131e3 100644 --- a/frontend/src/translations/locales/hu-HU.json +++ b/frontend/src/translations/locales/hu-HU.json @@ -80,7 +80,8 @@ "postCategory": "Hozzászólás beállításai", "postCategorySub": "Állítsa be a szabályokat arra vonatkozóan, hogy a felhasználó mit tehet bejegyzés létrehozásakor vagy megtekintésekor", "customTemplateCategory": "Oszlop sablon", - "customTemplateCategorySub": "Állítsa be az oszlopok számát és jellemzőit", + "customTemplateCategorySub": "", + "customTemplateAddColumn": "", "startButton": "Indítsa el a munkamenetet", "editButton": "Frissítés", "maxUpVotes": "Max fel-szavazatok", @@ -132,6 +133,9 @@ "islandQuestion": "sziget", "windQuestion": "Szél", "rockQuestion": "Szikla", + "madQuestion": "", + "sadQuestion": "", + "gladQuestion": "", "disconnected": "Lekapcsolták az aktuális munkamenetről.", "reconnect": "Csatlakozzon újra", "notLoggedIn": "Nincs bejelentkezve. Ezt az ülést nézőként tekintheti meg, de a részvételhez be kell jelentkeznie.", @@ -169,9 +173,11 @@ "Template": { "default": "Alapértelmezett", "wellNotWell": "Hát / Nem jól", + "wellNotWellIdeas": "", "startStopContinue": "Indítás / Leállítás / Folytatás", "fourLs": "Négy Ls", - "sailboat": "Vitorlás" + "sailboat": "Vitorlás", + "madSadGlad": "" }, "Clients": { "header": "Jelenleg itt van:", @@ -501,6 +507,7 @@ "", "", "" - ] + ], + "feedback": "" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/it-IT.json b/frontend/src/translations/locales/it-IT.json index 93f96aad3..3e7498f9b 100644 --- a/frontend/src/translations/locales/it-IT.json +++ b/frontend/src/translations/locales/it-IT.json @@ -80,7 +80,8 @@ "postCategory": "Impostazioni del Post", "postCategorySub": "Imposta le azioni che l'utente può fare quando crea o vede un post ", "customTemplateCategory": "Template di Colonna", - "customTemplateCategorySub": "Imposta il numero di colonne e le sue caratteristiche", + "customTemplateCategorySub": "Seleziona un modello e personalizza le tue colonne", + "customTemplateAddColumn": "Aggiungi una nuova colonna", "startButton": "Fai partire il gioco!", "editButton": "Aggiorna", "maxUpVotes": "Numero massimo di \"mi piace\"", @@ -132,6 +133,9 @@ "islandQuestion": "Isola", "windQuestion": "Vento", "rockQuestion": "Roccia", + "madQuestion": "Pazzo", + "sadQuestion": "Triste", + "gladQuestion": "Felice", "disconnected": "Ti sei disconnesso/a dalla sessione corrente.", "reconnect": "Riconnesso", "notLoggedIn": "Non sei autenticato. Puoi assistere a questa sessione come spettatore ma non puoi partecipare", @@ -169,9 +173,11 @@ "Template": { "default": "Predefinito", "wellNotWell": "Ok / Non Ok", + "wellNotWellIdeas": "Bene / Non Bene / Idee", "startStopContinue": "Inizia / Stop / Continua", "fourLs": "Quattro Ls", - "sailboat": "Barca a Vela" + "sailboat": "Barca a Vela", + "madSadGlad": "Pazzo / Triste / Felice" }, "Clients": { "header": "Partecipanti:", @@ -222,7 +228,7 @@ "buono", "forte" ], - "skipAndAnonLogin": "Salta e accedi in anonimo" + "skipAndAnonLogin": "Usa Anonimo" }, "AccountLogin": { "header": "Password", @@ -501,6 +507,7 @@ "Quali sono le migliori pratiche per una retrospettiva online?", "Come posso rendere la mia retrospettiva più divertente?", "Come posso renderlo più coinvolgente?" - ] + ], + "feedback": "Lascia qualche feedback" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/ja-JP.json b/frontend/src/translations/locales/ja-JP.json index b63d6de5a..481704846 100644 --- a/frontend/src/translations/locales/ja-JP.json +++ b/frontend/src/translations/locales/ja-JP.json @@ -80,7 +80,8 @@ "postCategory": "投稿設定", "postCategorySub": "投稿を作成または表示する際にユーザができることに関するルールを設定します", "customTemplateCategory": "列テンプレート", - "customTemplateCategorySub": "列数とその特性を設定します", + "customTemplateCategorySub": "テンプレートを選択し、列をカスタマイズします", + "customTemplateAddColumn": "新しい列を追加", "startButton": "セッションを開始", "editButton": "更新", "maxUpVotes": "最大投票数", @@ -132,6 +133,9 @@ "islandQuestion": "島", "windQuestion": "風", "rockQuestion": "岩", + "madQuestion": "マッド", + "sadQuestion": "悲しいです", + "gladQuestion": "うれしいです", "disconnected": "現在のセッションから切断されました。", "reconnect": "再接続", "notLoggedIn": "ログインしていません。このセッションは観戦者として表示できますが、参加するにはログインする必要があります。", @@ -169,9 +173,11 @@ "Template": { "default": "デフォルト", "wellNotWell": "よくない/よくない", + "wellNotWellIdeas": "よく/よくない/アイデア", "startStopContinue": "開始 / 停止 / 続ける", "fourLs": "4 Ls", - "sailboat": "帆船" + "sailboat": "帆船", + "madSadGlad": "マッド/悲しい/うれしいです" }, "Clients": { "header": "現在の参加者", @@ -222,7 +228,7 @@ "良い", "強い" ], - "skipAndAnonLogin": "Skip and log me in Anonymously" + "skipAndAnonLogin": "匿名で使用" }, "AccountLogin": { "header": "パスワード", @@ -501,6 +507,7 @@ "オンライン振り返りのためのベストプラクティスは何ですか?", "回顧展をもっと楽しくするにはどうしたらいいですか?", "どうすればもっと魅力的になれますか?" - ] + ], + "feedback": "いくつかのフィードバックを残す" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/nl-NL.json b/frontend/src/translations/locales/nl-NL.json index 255f8979f..8c9da187a 100644 --- a/frontend/src/translations/locales/nl-NL.json +++ b/frontend/src/translations/locales/nl-NL.json @@ -80,7 +80,8 @@ "postCategory": "Retropunten instellingen", "postCategorySub": "Instellen regels wat een gebruiker kan doen wanneer hij reageert op een retropunt", "customTemplateCategory": "Kolommen template", - "customTemplateCategorySub": "Instellen aantal kolommen en hun specificaties", + "customTemplateCategorySub": "Selecteer een sjabloon en pas uw kolommen aan", + "customTemplateAddColumn": "Nieuwe kolom toevoegen", "startButton": "Start de sessie", "editButton": "Vernieuwen", "maxUpVotes": "Maximum up-votes", @@ -132,6 +133,9 @@ "islandQuestion": "Eiland", "windQuestion": "Wind", "rockQuestion": "Steen", + "madQuestion": "Gekke", + "sadQuestion": "Triest", + "gladQuestion": "Blij", "disconnected": "Je huidige sessie is verbroken", "reconnect": "Opnieuw verbinden", "notLoggedIn": "Je bent niet ingelogd. Je kan de sessie bekijken als toeschouwer maar moet inloggen om deel te nemen.", @@ -169,9 +173,11 @@ "Template": { "default": "Standaard", "wellNotWell": "Goed / Niet goed", + "wellNotWellIdeas": "Goed / Niet Goed / Ideeën", "startStopContinue": "Start / Stop / Blijven doen", "fourLs": "De 4 L'en", - "sailboat": "Zeilboot" + "sailboat": "Zeilboot", + "madSadGlad": "Moeilijk / droog / blij" }, "Clients": { "header": "Deelnemers:", @@ -222,7 +228,7 @@ "goed", "sterk" ], - "skipAndAnonLogin": "Sla me over en log me in Anoniem" + "skipAndAnonLogin": "Anoniem gebruiken" }, "AccountLogin": { "header": "Wachtwoord", @@ -501,6 +507,7 @@ "Wat zijn de beste praktijken voor een online-retrospectie?", "Hoe kan ik mijn retrospectief leuker maken?", "Hoe kan ik het aantrekkelijker maken?" - ] + ], + "feedback": "Laat feedback achter" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/pl-PL.json b/frontend/src/translations/locales/pl-PL.json index 37035b878..61e8439ef 100644 --- a/frontend/src/translations/locales/pl-PL.json +++ b/frontend/src/translations/locales/pl-PL.json @@ -80,7 +80,8 @@ "postCategory": "Ustawienia postów", "postCategorySub": "Ustaw reguły co użytkownik może zrobić podczas tworzenia lub przeglądania wpisu", "customTemplateCategory": "Szablon kolumny", - "customTemplateCategorySub": "Ustaw liczbę kolumn i ich właściwości", + "customTemplateCategorySub": "Wybierz szablon i dostosuj swoje kolumny", + "customTemplateAddColumn": "Dodaj nową kolumnę", "startButton": "Rozpocznij sesję", "editButton": "Aktualizuj", "maxUpVotes": "Maksymalna liczba głosów", @@ -132,6 +133,9 @@ "islandQuestion": "Wyspa", "windQuestion": "Wiatr", "rockQuestion": "Skała", + "madQuestion": "Szalony", + "sadQuestion": "Smutny", + "gladQuestion": "Wspaniały", "disconnected": "Zostałeś odłączony od bieżącej sesji.", "reconnect": "Połącz ponownie", "notLoggedIn": "Nie jesteś zalogowany. Możesz zobaczyć tę sesję jako obserwator, ale musisz się zalogować, aby wziąć udział.", @@ -169,9 +173,11 @@ "Template": { "default": "Domyślny", "wellNotWell": "Dobra / Niedobrze", + "wellNotWellIdeas": "Dobra / Niedobra / Pomysły", "startStopContinue": "Rozpocznij / Zatrzymaj / Kontynuuj", "fourLs": "Cztery litery", - "sailboat": "Łódka żaglowca" + "sailboat": "Łódka żaglowca", + "madSadGlad": "Szalony / Smutny / Glad" }, "Clients": { "header": "Są dziś z nami:", @@ -222,7 +228,7 @@ "dobry", "silny" ], - "skipAndAnonLogin": "Pomiń i zaloguj mnie anonimowo" + "skipAndAnonLogin": "Użyj anonimowo" }, "AccountLogin": { "header": "Hasło", @@ -501,6 +507,7 @@ "Jakie są najlepsze praktyki w zakresie retrospektywnego stosowania internetu?", "Jak mogę sprawić, by moja retrospektywność była bardziej zabawna?", "Jak mogę sprawić, by był bardziej zaangażowany?" - ] + ], + "feedback": "Pozostaw trochę opinii" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/pt-BR.json b/frontend/src/translations/locales/pt-BR.json index d0c41781f..4ba03688a 100644 --- a/frontend/src/translations/locales/pt-BR.json +++ b/frontend/src/translations/locales/pt-BR.json @@ -80,7 +80,8 @@ "postCategory": "Configurações de postagem", "postCategorySub": "Defina as regras sobre o que um usuário pode fazer ao criar ou visualizar uma postagem", "customTemplateCategory": "Modelo de coluna", - "customTemplateCategorySub": "Define o número de colunas e suas características", + "customTemplateCategorySub": "Selecione um modelo e personalize suas colunas", + "customTemplateAddColumn": "Adicione uma nova coluna", "startButton": "Iniciar a sessão", "editButton": "Atualização", "maxUpVotes": "Máximo de Votos Atuais", @@ -132,6 +133,9 @@ "islandQuestion": "Ilha", "windQuestion": "Vento", "rockQuestion": "Pedras", + "madQuestion": "Louco", + "sadQuestion": "Triste", + "gladQuestion": "Feliz", "disconnected": "Você foi desconectado da sessão atual.", "reconnect": "Reconectar", "notLoggedIn": "Você não está conectado. Você pode ver esta sessão como um espectador, mas precisa fazer o login para participar.", @@ -169,9 +173,11 @@ "Template": { "default": "Padrão", "wellNotWell": "Bem / Não Bom", + "wellNotWellIdeas": "Bem / Não Bem / Ideias", "startStopContinue": "Iniciar / Parar / Continuar", "fourLs": "Quatro Ls", - "sailboat": "Veleiro" + "sailboat": "Veleiro", + "madSadGlad": "Maluco / Triste / Desagradável" }, "Clients": { "header": "Participando conosco agora:", @@ -222,7 +228,7 @@ "bom", "forte" ], - "skipAndAnonLogin": "Pular e iniciar sessão em Anônimo" + "skipAndAnonLogin": "Usar anonimamente" }, "AccountLogin": { "header": "Palavra-passe", @@ -501,6 +507,7 @@ "Quais são as melhores práticas para um retrocesso na Internet?", "Como posso fazer meu retrospectivo mais divertido?", "Como posso fazer isso mais envolvente?" - ] + ], + "feedback": "Deixe alguns comentários" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/pt-PT.json b/frontend/src/translations/locales/pt-PT.json index 24d5a336a..55889c041 100644 --- a/frontend/src/translations/locales/pt-PT.json +++ b/frontend/src/translations/locales/pt-PT.json @@ -80,7 +80,8 @@ "postCategory": "Configurações de postagem", "postCategorySub": "Defina as regras sobre o que um usuário pode fazer ao criar ou visualizar uma postagem", "customTemplateCategory": "Modelo de coluna", - "customTemplateCategorySub": "Define o número de colunas e suas características", + "customTemplateCategorySub": "Selecione um modelo e personalize suas colunas", + "customTemplateAddColumn": "Adicione uma nova coluna", "startButton": "Iniciar a sessão", "editButton": "Atualização", "maxUpVotes": "Máximo de Votos Atuais", @@ -132,6 +133,9 @@ "islandQuestion": "Ilha", "windQuestion": "Vento", "rockQuestion": "Pedras", + "madQuestion": "Louco", + "sadQuestion": "Triste", + "gladQuestion": "Feliz", "disconnected": "Você foi desconectado da sessão atual.", "reconnect": "Reconectar", "notLoggedIn": "Você não está conectado. Você pode ver esta sessão como um espectador, mas precisa fazer o login para participar.", @@ -169,9 +173,11 @@ "Template": { "default": "Padrão", "wellNotWell": "Bem / Não Bom", + "wellNotWellIdeas": "Bem / Não Bem / Ideias", "startStopContinue": "Iniciar / Parar / Continuar", "fourLs": "Quatro Ls", - "sailboat": "Veleiro" + "sailboat": "Veleiro", + "madSadGlad": "Maluco / Triste / Desagradável" }, "Clients": { "header": "Participantes:", @@ -222,7 +228,7 @@ "bom", "forte" ], - "skipAndAnonLogin": "Pular e iniciar sessão em Anônimo" + "skipAndAnonLogin": "Usar anonimamente" }, "AccountLogin": { "header": "Palavra-passe", @@ -501,6 +507,7 @@ "Quais são as melhores práticas para um retrocesso na Internet?", "Como posso fazer meu retrospectivo mais divertido?", "Como posso fazer isso mais envolvente?" - ] + ], + "feedback": "Deixe alguns comentários" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/uk-UA.json b/frontend/src/translations/locales/uk-UA.json index 48849da17..3e27528d4 100644 --- a/frontend/src/translations/locales/uk-UA.json +++ b/frontend/src/translations/locales/uk-UA.json @@ -80,7 +80,8 @@ "postCategory": "Налаштування повідомлень", "postCategorySub": "Встановіть правила щодо того, що може робити користувач при створенні чи перегляді допису", "customTemplateCategory": "Шаблон стовпця", - "customTemplateCategorySub": "Встановіть кількість стовпців і їх символів", + "customTemplateCategorySub": "Виберіть шаблон і налаштуйте стовпці", + "customTemplateAddColumn": "Додати новий стовпець", "startButton": "Почати сесію", "editButton": "Оновити", "maxUpVotes": "Максимальна кількість голосів", @@ -132,6 +133,9 @@ "islandQuestion": "Острів", "windQuestion": "Вітер", "rockQuestion": "Скеля", + "madQuestion": "Злість", + "sadQuestion": "Сум", + "gladQuestion": "Ґлейд", "disconnected": "Вас відключено від поточної сесії.", "reconnect": "Перепід'єднатись", "notLoggedIn": "Ви не ввійшли. Ви можете переглядати цю сесію в якості глядача, але повинні увійти, щоб брати участь.", @@ -169,9 +173,11 @@ "Template": { "default": "Типово", "wellNotWell": "Коалі/не дуже добре", + "wellNotWellIdeas": "Колода / не є / деї", "startStopContinue": "Почати / Зупинити / продовжити", "fourLs": "Чотири Ли", - "sailboat": "Сильний човен" + "sailboat": "Сильний човен", + "madSadGlad": "Божевільний / сумний / Сміх" }, "Clients": { "header": "Учасники:", @@ -222,7 +228,7 @@ "добре", "сильний" ], - "skipAndAnonLogin": "Пропустити і увійти до мене анонімно" + "skipAndAnonLogin": "Використовувати анонімно" }, "AccountLogin": { "header": "Пароль", @@ -501,6 +507,7 @@ "Які найкращі практики є онлайн-ретроспективу?", "Як я можу зробити свою ретроспективу більш веселою?", "Як зробити його більш захоплюючим?" - ] + ], + "feedback": "Залишити відгук" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/zh-CN.json b/frontend/src/translations/locales/zh-CN.json index 74a9f16d1..b173cae41 100644 --- a/frontend/src/translations/locales/zh-CN.json +++ b/frontend/src/translations/locales/zh-CN.json @@ -80,7 +80,8 @@ "postCategory": "帖子设置", "postCategorySub": "设置用户在创建或查看帖子时可以做什么的规则", "customTemplateCategory": "列模板", - "customTemplateCategorySub": "设置列数及其特性", + "customTemplateCategorySub": "选择模板并自定义您的列", + "customTemplateAddColumn": "添加新列", "startButton": "开始会话", "editButton": "更新", "maxUpVotes": "最大向上投票数", @@ -132,6 +133,9 @@ "islandQuestion": "岛", "windQuestion": "向导", "rockQuestion": "摇动", + "madQuestion": "马德", + "sadQuestion": "悲伤的", + "gladQuestion": "格拉德文", "disconnected": "您已与当前会话断开连接。", "reconnect": "重新连接", "notLoggedIn": "您尚未登录。您可以将此会话视为旁观者,但必须登录才能参与。", @@ -169,9 +173,11 @@ "Template": { "default": "默认设置", "wellNotWell": "好的 / 不好", + "wellNotWellIdeas": "好的/不好的/想法的", "startStopContinue": "开始/停止/继续", "fourLs": "四指示灯", - "sailboat": "帆船" + "sailboat": "帆船", + "madSadGlad": "坏的 / 沙德 / Glad" }, "Clients": { "header": "已加入我们的:", @@ -222,7 +228,7 @@ "很好", "强度" ], - "skipAndAnonLogin": "匿名跳过并登录我" + "skipAndAnonLogin": "匿名使用" }, "AccountLogin": { "header": "密码", @@ -501,6 +507,7 @@ "网上回顾的最佳做法是什么?", "如何使我的回顾更加有趣?", "我如何才能使它更多地参与?" - ] + ], + "feedback": "留下一些反馈" } } \ No newline at end of file diff --git a/frontend/src/translations/locales/zh-TW.json b/frontend/src/translations/locales/zh-TW.json index 688dd49fe..23388f0b7 100644 --- a/frontend/src/translations/locales/zh-TW.json +++ b/frontend/src/translations/locales/zh-TW.json @@ -80,7 +80,8 @@ "postCategory": "帖子設置", "postCategorySub": "設置用戶在創建或查看帖子時可以做什麼的規則", "customTemplateCategory": "列模板", - "customTemplateCategorySub": "設置列數及其特徵", + "customTemplateCategorySub": "", + "customTemplateAddColumn": "", "startButton": "開始會話", "editButton": "更新", "maxUpVotes": "最大投票數", @@ -132,6 +133,9 @@ "islandQuestion": "島", "windQuestion": "風", "rockQuestion": "岩石", + "madQuestion": "", + "sadQuestion": "", + "gladQuestion": "", "disconnected": "您已與當前會話斷開連接。", "reconnect": "重新連接", "notLoggedIn": "您尚未登錄。您可以作為旁觀者查看此會話,但必須登錄才能參與。", @@ -169,9 +173,11 @@ "Template": { "default": "默認", "wellNotWell": "好/不好", + "wellNotWellIdeas": "", "startStopContinue": "開始/停止/繼續", "fourLs": "四個 L", - "sailboat": "帆船" + "sailboat": "帆船", + "madSadGlad": "" }, "Clients": { "header": "已加入我們的:", @@ -501,6 +507,7 @@ "", "", "" - ] + ], + "feedback": "" } } \ No newline at end of file diff --git a/frontend/src/translations/useLanguage.ts b/frontend/src/translations/useLanguage.ts index f6450d3f5..7d337d67f 100644 --- a/frontend/src/translations/useLanguage.ts +++ b/frontend/src/translations/useLanguage.ts @@ -1,10 +1,11 @@ -import { useCallback, useContext, useMemo } from 'react'; +import { useCallback, useMemo } from 'react'; import languages, { Language } from './languages'; import { useTranslation } from 'react-i18next'; import { updateLanguage } from 'api'; -import UserContext from 'auth/Context'; import { trackEvent } from 'track'; import { TrackingEvent } from 'common'; +import useUser from 'state/user/useUser'; +import { useSetUser } from 'state/user/useSetUser'; type UseLanguageResult = [ language: Language, @@ -13,7 +14,8 @@ type UseLanguageResult = [ export default function useLanguage(): UseLanguageResult { const { i18n } = useTranslation(); - const { user, setUser } = useContext(UserContext); + const user = useUser(); + const setUser = useSetUser(); const hasUser = !!user; const locale = i18n.language; diff --git a/frontend/src/utils/getConfig.ts b/frontend/src/utils/getConfig.ts index 69c069190..9931b89c6 100644 --- a/frontend/src/utils/getConfig.ts +++ b/frontend/src/utils/getConfig.ts @@ -8,6 +8,7 @@ interface Config { DEFAULT_LANGUAGE: string; VERSION: string; MARKETING_ROOT: string; + AI_FEEDBACK_URL: string; } const ALL_KEYS: (keyof Config)[] = [ @@ -20,6 +21,7 @@ const ALL_KEYS: (keyof Config)[] = [ 'DEFAULT_LANGUAGE', 'VERSION', 'MARKETING_ROOT', + 'AI_FEEDBACK_URL', ]; declare global { @@ -31,7 +33,10 @@ declare global { window.__env__ = window.__env__ || {}; function getKey(key: keyof Config): string { - if (import.meta.env[`VITE_${key}`]) { + if ( + (import.meta.env.DEV || key === 'VERSION') && + import.meta.env[`VITE_${key}`] + ) { return import.meta.env[`VITE_${key}`] || ''; } const winObj = window.__env__[key]; diff --git a/frontend/src/views/Demo.tsx b/frontend/src/views/Demo.tsx index 28ff67d31..1ca38a8b5 100644 --- a/frontend/src/views/Demo.tsx +++ b/frontend/src/views/Demo.tsx @@ -1,17 +1,17 @@ import styled from '@emotion/styled'; import { colors } from '@mui/material'; import { anonymousLogin, createDemoGame, me, updateLanguage } from 'api'; -import UserContext from 'auth/Context'; -import useUser from 'auth/useUser'; -import { useContext, useEffect } from 'react'; +import useUser from 'state/user/useUser'; +import { useEffect } from 'react'; import { useSearchParams } from 'react-router-dom'; import { trackEvent } from 'track'; import { Language } from 'translations/languages'; import { languages, useLanguage } from '../translations'; +import { useSetUser } from 'state/user/useSetUser'; export default function Demo() { const user = useUser(); - const { setUser } = useContext(UserContext); + const setUser = useSetUser(); let [searchParams] = useSearchParams(); const twoLetter = searchParams.get('lang'); const [currentLanguage, changeLanguage] = useLanguage(); diff --git a/frontend/src/views/Home.tsx b/frontend/src/views/Home.tsx index 69e247d03..0c4eb05e3 100644 --- a/frontend/src/views/Home.tsx +++ b/frontend/src/views/Home.tsx @@ -15,7 +15,7 @@ import { trackAdWordsConversion, trackEvent } from './../track'; import { createGame, createEncryptedGame, deleteSession } from '../api'; import { Page } from '../components/Page'; import usePreviousSessions from '../hooks/usePreviousSessions'; -import useUser from '../auth/useUser'; +import useUser from '../state/user/useUser'; import shortid from 'shortid'; import { storeEncryptionKeyLocally } from '../crypto/crypto'; import ProButton from '../components/ProButton'; diff --git a/frontend/src/views/Panel.tsx b/frontend/src/views/Panel.tsx index 72b2c5d79..14cc6da12 100644 --- a/frontend/src/views/Panel.tsx +++ b/frontend/src/views/Panel.tsx @@ -36,6 +36,12 @@ function Panel() { + + Website + + Main Website + + Documentation import('react-password-strength-bar')); function ResetPasswordPage() { - const { setUser } = useContext(UserContext); + const setUser = useSetUser(); const navigate = useNavigate(); const location = useLocation(); const { t } = useTranslation(); diff --git a/frontend/src/views/Validate.tsx b/frontend/src/views/Validate.tsx index d4e278133..ce726e00d 100644 --- a/frontend/src/views/Validate.tsx +++ b/frontend/src/views/Validate.tsx @@ -3,12 +3,11 @@ import { useLocation, useNavigate } from 'react-router-dom'; import { useEffect } from 'react'; import { verifyEmail } from '../api'; import { Alert } from '@mui/material'; -import { useContext } from 'react'; -import UserContext from '../auth/Context'; import { useTranslation } from 'react-i18next'; +import { useSetUser } from 'state/user/useSetUser'; function ValidatePage() { - const { setUser } = useContext(UserContext); + const setUser = useSetUser(); const navigate = useNavigate(); const location = useLocation(); const { t } = useTranslation(); diff --git a/frontend/src/views/account/AccountPage.tsx b/frontend/src/views/account/AccountPage.tsx index 9aaa9d2cc..9bd61d0f8 100644 --- a/frontend/src/views/account/AccountPage.tsx +++ b/frontend/src/views/account/AccountPage.tsx @@ -1,7 +1,7 @@ import usePortalUrl from './usePortalUrl'; import Button from '@mui/material/Button'; import { Page } from '../../components/Page'; -import useUser from '../../auth/useUser'; +import useUser from '../../state/user/useUser'; import styled from '@emotion/styled'; import ProPill from '../../components/ProPill'; import { Alert } from '@mui/material'; diff --git a/frontend/src/views/account/delete/DeleteModal.tsx b/frontend/src/views/account/delete/DeleteModal.tsx index 8db0b33ba..c3ea3f5cc 100644 --- a/frontend/src/views/account/delete/DeleteModal.tsx +++ b/frontend/src/views/account/delete/DeleteModal.tsx @@ -15,17 +15,17 @@ import { colors, } from '@mui/material'; import { noop } from 'lodash'; -import { useCallback, useContext, useState } from 'react'; +import { useCallback, useState } from 'react'; import styled from '@emotion/styled'; import { DeleteAccountPayload, FullUser } from 'common'; import { deleteAccount, deleteUser, logout } from '../../../api'; -import UserContext from '../../../auth/Context'; import { useNavigate } from 'react-router'; import { useConfirm } from 'material-ui-confirm'; import { useSnackbar } from 'notistack'; import { useTranslation } from 'react-i18next'; import { trackEvent } from '../../../track'; -import useUser from 'auth/useUser'; +import useUser from 'state/user/useUser'; +import { useSetUser } from 'state/user/useSetUser'; type DeleteModalProps = { open: boolean; @@ -46,7 +46,7 @@ export function DeleteModal({ const [deleteVotes, setDeleteVotes] = useState(false); const currentUser = useUser(); const isOwnAccount = currentUser && currentUser.id === user.id; - const { setUser } = useContext(UserContext); + const setUser = useSetUser(); const { enqueueSnackbar } = useSnackbar(); const push = useNavigate(); const confirm = useConfirm(); diff --git a/frontend/src/views/account/usePortalUrl.ts b/frontend/src/views/account/usePortalUrl.ts index 4e1bc7cce..4cf2f3f60 100644 --- a/frontend/src/views/account/usePortalUrl.ts +++ b/frontend/src/views/account/usePortalUrl.ts @@ -1,6 +1,6 @@ import { getPortalUrl } from './api'; import { useEffect, useState } from 'react'; -import useUser from '../../auth/useUser'; +import useUser from '../../state/user/useUser'; export default function usePortalUrl(): string | null { const [url, setUrl] = useState(null); diff --git a/frontend/src/views/admin/AdminPage.tsx b/frontend/src/views/admin/AdminPage.tsx index 579b53fbd..b60e45510 100644 --- a/frontend/src/views/admin/AdminPage.tsx +++ b/frontend/src/views/admin/AdminPage.tsx @@ -1,7 +1,7 @@ import { Alert, Button, Checkbox } from '@mui/material'; import { DataGrid, GridColDef, GridRenderCellParams } from '@mui/x-data-grid'; import { FullUser } from 'common'; -import useUser from '../../auth/useUser'; +import useUser from '../../state/user/useUser'; import useStateFetch from '../../hooks/useStateFetch'; import { useCallback, useMemo, useState } from 'react'; import styled from '@emotion/styled'; diff --git a/frontend/src/views/game/board/Board.tsx b/frontend/src/views/game/board/Board.tsx index 9d0000f35..a5a905afe 100644 --- a/frontend/src/views/game/board/Board.tsx +++ b/frontend/src/views/game/board/Board.tsx @@ -186,8 +186,9 @@ function GameMode({ const Columns = styled.div<{ numberOfColumns: number }>` display: flex; margin-top: 30px; + margin-right: -20px; - @media screen and (max-width: ${(props) => props.numberOfColumns * 320 + 100}px) { + @media screen and (max-width: ${(props) => props.numberOfColumns * 340 + 100}px) { margin-top: 10px; flex-direction: column; diff --git a/frontend/src/views/game/board/header/BoardHeader.tsx b/frontend/src/views/game/board/header/BoardHeader.tsx index 4f9c0a912..2d670de8a 100644 --- a/frontend/src/views/game/board/header/BoardHeader.tsx +++ b/frontend/src/views/game/board/header/BoardHeader.tsx @@ -8,7 +8,7 @@ import useRemainingVotes from './useRemainingVotes'; import useCanReveal from './useCanReveal'; import EditableLabel from '../../../../components/EditableLabel'; import RemainingVotes from './RemainingVotes'; -import useUser from '../../../../auth/useUser'; +import useUser from '../../../../state/user/useUser'; import RevealButton from './RevealButton'; import ModifyOptions from './ModifyOptions'; import useCanModifyOptions from './useCanModifyOptions'; @@ -182,6 +182,7 @@ const Alerts = styled.div` `; const Header = styled.div` + margin-bottom: 50px; display: grid; justify-items: center; align-items: center; @@ -203,14 +204,12 @@ const Header = styled.div` } @media (max-width: 500px) { - grid-template-columns: 1fr; - grid-template-rows: auto auto auto auto; + grid-template-columns: 1fr 1fr 1fr; + grid-template-rows: auto auto; row-gap: 20px; grid-template-areas: - 'title' - 'left' - 'right' - 'votes'; + 'title title title' + 'left votes right'; } `; @@ -241,7 +240,7 @@ const LeftOptions = styled.div` } @media (max-width: 500px) { - justify-self: center; + margin-left: 10px; } `; @@ -251,8 +250,7 @@ const RightOptions = styled.div` justify-self: end; @media (max-width: 500px) { - justify-self: center; - margin-top: 10px; + margin-right: 10px; } `; diff --git a/frontend/src/views/game/board/header/LockSession.tsx b/frontend/src/views/game/board/header/LockSession.tsx index c6a2776ca..feef6883b 100644 --- a/frontend/src/views/game/board/header/LockSession.tsx +++ b/frontend/src/views/game/board/header/LockSession.tsx @@ -5,7 +5,7 @@ import DialogContent from '@mui/material/DialogContent'; import DialogContentText from '@mui/material/DialogContentText'; import DialogTitle from '@mui/material/DialogTitle'; import useMediaQuery from '@mui/material/useMediaQuery'; -import { colors } from '@mui/material'; +import { colors, IconButton } from '@mui/material'; import { Lock, VerifiedUser } from '@mui/icons-material'; import { useCallback, useState } from 'react'; import styled from '@emotion/styled'; @@ -27,6 +27,7 @@ function LockSession({ onLock }: LockSessionProps) { const { t } = useTranslation(); const { participants } = useParticipants(); const fullScreen = useMediaQuery('(max-width:600px)'); + const small = useMediaQuery('(max-width: 500px)'); const handleLock = useCallback(() => { if (session) { @@ -60,20 +61,32 @@ function LockSession({ onLock }: LockSessionProps) { return ( <> - + )} + + ) : ( + + )} void; @@ -26,6 +27,7 @@ function ModifyOptions({ const { t } = useTranslation(); const [open, setOpen] = useState(false); const { session } = useSession(); + const small = useMediaQuery('(max-width: 500px)'); const handleChange = useCallback( ( @@ -62,14 +64,20 @@ function ModifyOptions({ return ( <> - + {small ? ( + setOpen(true)} color="primary"> + + + ) : ( + + )} {open ? ( void; @@ -14,6 +15,7 @@ interface RevealButtonProps { function RevealButton({ onClick }: RevealButtonProps) { const { t } = useTranslation(); + const small = useMediaQuery('(max-width: 500px)'); const [revealDialogOpen, setRevealDialogOpen] = useState(false); const handleOpenDialog = useCallback(() => { setRevealDialogOpen(true); @@ -23,14 +25,20 @@ function RevealButton({ onClick }: RevealButtonProps) { }, []); return ( <> - + {small ? ( + + + + ) : ( + + )} navigate('/'), [navigate]); const { toggle: togglePanel } = useSidePanel(); - const isInitialised = useIsInitialised(); const isOnGamePage = !!useMatch('game/:gameId/*'); - const { t } = useTranslation(); return ( @@ -63,11 +59,7 @@ export function Header() { {user ? : null} {isOnGamePage ? : null} - {isInitialised ? ( - - ) : ( - {t('Main.loading')} - )} + ); @@ -102,8 +94,6 @@ const GoProContainer = styled.div` margin-left: 20px; `; -const Initialising = styled.div``; - const Spacer = styled.div` flex: 1; `; diff --git a/frontend/src/views/layout/ai/AiCoach.tsx b/frontend/src/views/layout/ai/AiCoach.tsx index a5bf535fa..2befbb62c 100644 --- a/frontend/src/views/layout/ai/AiCoach.tsx +++ b/frontend/src/views/layout/ai/AiCoach.tsx @@ -9,10 +9,11 @@ import { DialogTitle, } from '@mui/material'; import { requestConfig } from 'api/fetch'; -import useUser from 'auth/useUser'; +import useUser from 'state/user/useUser'; import { CoachMessage, CoachRole } from 'common'; import { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import config from 'utils/getConfig'; import { v4 } from 'uuid'; import { Chat } from './Chat'; @@ -21,6 +22,8 @@ type AiCoachProps = { onClose: () => void; }; +const feedbackUrl = config.AI_FEEDBACK_URL; + export function AiCoach({ open, onClose }: AiCoachProps) { const [messages, setMessages] = useState([]); const [thinking, setThinking] = useState(false); @@ -83,20 +86,26 @@ export function AiCoach({ open, onClose }: AiCoachProps) { - {disabled ? ( - {t('Ai.disabledAnonymous')} - ) : ( - {t('Ai.info')} - )} + {!disabled ? {t('Ai.info')} : null} - + + {feedbackUrl ? ( + + ) : ( + + )} + + ); @@ -107,3 +116,9 @@ const HeaderContainer = styled.div` align-items: center; gap: 20px; `; + +const Buttons = styled.div` + width: 100%; + display: flex; + justify-content: space-between; +`; diff --git a/frontend/src/views/layout/ai/Chat.tsx b/frontend/src/views/layout/ai/Chat.tsx index 0ce0d02fd..317297991 100644 --- a/frontend/src/views/layout/ai/Chat.tsx +++ b/frontend/src/views/layout/ai/Chat.tsx @@ -6,15 +6,27 @@ import ChatInput from './ChatInput'; import { keyframes } from '@emotion/react'; import { CoachMessage } from 'common'; import { Examples } from './Examples'; +import { Alert, Button } from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; type ChatProps = { messages: CoachMessage[]; thinking: boolean; disabled: boolean; onMessage: (content: string) => void; + onClose: () => void; }; -export function Chat({ messages, disabled, thinking, onMessage }: ChatProps) { +export function Chat({ + messages, + disabled, + thinking, + onClose, + onMessage, +}: ChatProps) { + const { t } = useTranslation(); + const navigate = useNavigate(); return (
@@ -27,7 +39,20 @@ export function Chat({ messages, disabled, thinking, onMessage }: ChatProps) { /> ))} {thinking ? } /> : null} - {messages.length === 0 ? ( + {disabled ? ( + + {t('Ai.disabledAnonymous')} + + + ) : null} + {!disabled && messages.length === 0 ? ( @@ -80,3 +105,12 @@ const Ellipsis = styled.div` content: ''; } `; + +const AlertContainer = styled.div` + display: flex; + gap: 40px; + flex-direction: column; + justify-content: center; + align-items: center; + height: 100%; +`; diff --git a/frontend/src/views/layout/ai/ChatMessage.tsx b/frontend/src/views/layout/ai/ChatMessage.tsx index 35142b433..bc8021d52 100644 --- a/frontend/src/views/layout/ai/ChatMessage.tsx +++ b/frontend/src/views/layout/ai/ChatMessage.tsx @@ -32,4 +32,5 @@ const MessageContent = styled.div<{ own: boolean }>` border-radius: 10px; background-color: ${(props) => (props.own ? colors.blue[400] : '#f0f0f0')}; color: ${(props) => (props.own ? 'white' : 'black')}; + line-height: 1.4rem; `; diff --git a/frontend/src/views/session-editor/SessionEditor.tsx b/frontend/src/views/session-editor/SessionEditor.tsx index 401812035..b5ae9a147 100644 --- a/frontend/src/views/session-editor/SessionEditor.tsx +++ b/frontend/src/views/session-editor/SessionEditor.tsx @@ -74,6 +74,7 @@ function SessionEditor({ fullWidth fullScreen={fullScreen} keepMounted={false} + maxWidth="md" > { +}: OptionItemProps) { return ( @@ -37,7 +37,7 @@ const OptionItem = ({ ); -}; +} const Container = styled.div` border: 1px solid ${colors.grey[200]}; @@ -78,5 +78,3 @@ const HeaderContainer = styled.div<{ wide: boolean }>` : ''} } `; - -export default OptionItem; diff --git a/frontend/src/views/session-editor/sections/posts/PostsSection.tsx b/frontend/src/views/session-editor/sections/posts/PostsSection.tsx index d07fc8e42..a4ad3390c 100644 --- a/frontend/src/views/session-editor/sections/posts/PostsSection.tsx +++ b/frontend/src/views/session-editor/sections/posts/PostsSection.tsx @@ -1,7 +1,7 @@ import { useCallback } from 'react'; import { SessionOptions } from 'common'; import SettingCategory from '../SettingCategory'; -import OptionItem from '../OptionItem'; +import { OptionItem } from '../OptionItem'; import { useTranslation } from 'react-i18next'; import BooleanOption from '../BooleanOption'; import MaxPostsSlider from './MaxPostsSlider'; diff --git a/frontend/src/views/session-editor/sections/template/TemplateEditor.tsx b/frontend/src/views/session-editor/sections/template/TemplateEditor.tsx index b1971a41e..1aff3cf66 100644 --- a/frontend/src/views/session-editor/sections/template/TemplateEditor.tsx +++ b/frontend/src/views/session-editor/sections/template/TemplateEditor.tsx @@ -2,19 +2,20 @@ import { useCallback } from 'react'; import { ColumnSettings } from '../../../../state/types'; import ColumnEditor from './ColumnEditor'; import { getTemplateColumnByType } from '../../../../state/columns'; -import IconButton from '@mui/material/IconButton'; import { trackEvent } from '../../../../track'; import { Add } from '@mui/icons-material'; import { useTranslation } from 'react-i18next'; +import { Button } from '@mui/material'; +import styled from '@emotion/styled'; const MAX_NUMBER_OF_COLUMNS = 5; -interface TemplateEditorProps { +type TemplateEditorProps = { columns: ColumnSettings[]; onChange: (columns: ColumnSettings[]) => void; -} +}; -function TemplateEditor({ columns, onChange }: TemplateEditorProps) { +export function TemplateEditor({ columns, onChange }: TemplateEditorProps) { const { t } = useTranslation(); const handleColumnChange = useCallback( (value: ColumnSettings, index: number) => { @@ -36,7 +37,7 @@ function TemplateEditor({ columns, onChange }: TemplateEditorProps) { [onChange, columns] ); return ( - <> + {columns.map((def, index) => ( ))} {columns.length < MAX_NUMBER_OF_COLUMNS ? ( - - - + ) : null} - + ); } -export default TemplateEditor; +const Container = styled.div` + @media screen and (min-width: 600px) { + min-height: 340px; + } +`; diff --git a/frontend/src/views/session-editor/sections/template/TemplateItem.tsx b/frontend/src/views/session-editor/sections/template/TemplateItem.tsx new file mode 100644 index 000000000..12e1d57fa --- /dev/null +++ b/frontend/src/views/session-editor/sections/template/TemplateItem.tsx @@ -0,0 +1,65 @@ +import styled from '@emotion/styled'; +import { useTranslation } from 'react-i18next'; +import { getTemplateColumns } from 'state'; +import { Template, TemplateDefinition } from 'state/types'; +import Icon from 'components/Icon/Icon'; +import { colors } from '@mui/material'; + +type TemplateItemProps = { + definition: TemplateDefinition; + selected: boolean; + onSelect: (template: Template) => void; +}; + +export function TemplateItem({ + definition, + selected, + onSelect, +}: TemplateItemProps) { + const { t } = useTranslation(); + const columns = getTemplateColumns(definition.type, t); + return ( + { + onSelect(definition.type); + }} + > + + {columns.map((col) => ( + + ))} + + {definition.name} + + ); +} + +const Item = styled.div<{ selected: boolean }>` + cursor: pointer; + display: flex; + flex-direction: column; + align-items: center; + padding: 10px; + border-radius: 5px; + box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px; + background-color: ${(p) => (p.selected ? colors.deepPurple[700] : null)}; + color: ${(p) => (p.selected ? colors.grey[50] : colors.grey[500])}; + min-width: 185px; + + :hover { + background-color: ${colors.deepPurple[50]}; + color: ${colors.grey[700]}; + } +`; + +const ItemIcon = styled.div` + width: 100%; + display: flex; + justify-content: space-around; +`; + +const ItemTitle = styled.div` + margin-top: 15px; + font-size: 0.8rem; +`; diff --git a/frontend/src/views/session-editor/sections/template/TemplatePicker.tsx b/frontend/src/views/session-editor/sections/template/TemplatePicker.tsx index 141769771..22681d166 100644 --- a/frontend/src/views/session-editor/sections/template/TemplatePicker.tsx +++ b/frontend/src/views/session-editor/sections/template/TemplatePicker.tsx @@ -1,38 +1,65 @@ -import { useCallback, useState } from 'react'; -import { Template } from '../../../../state/types'; -import { getAllTemplates } from '../../../../state/templates'; +import { + ColumnSettings, + Template, + TranslationFunction, +} from '../../../../state/types'; +import { + getAllTemplates, + getTemplateColumns, +} from '../../../../state/templates'; import { useTranslation } from 'react-i18next'; -import Select from '@mui/material/Select'; -import MenuItem from '@mui/material/MenuItem'; -import { SelectChangeEvent } from '@mui/material'; +import styled from '@emotion/styled'; +import { TemplateItem } from './TemplateItem'; interface TemplatePickerProps { + current: ColumnSettings[]; onSelect: (value: Template) => void; } -const TemplatePicker = ({ onSelect }: TemplatePickerProps) => { +export function TemplatePicker({ current, onSelect }: TemplatePickerProps) { const { t } = useTranslation(); - const [template, setTemplate] = useState