From b31394a90ae57bf75379b61f5d3dc7fed4bf4029 Mon Sep 17 00:00:00 2001 From: Antoine Jaussoin Date: Tue, 28 Mar 2023 21:45:12 +0100 Subject: [PATCH] Prevent auto-connecting as anonymous (#514) --- backend/src/index.ts | 37 ++------ frontend/src/auth/AccountMenu.tsx | 3 +- frontend/src/auth/modal/LoginContent.tsx | 86 +++++++++++++++---- frontend/src/auth/modal/LoginModal.tsx | 2 +- frontend/src/components/EditableLabel.tsx | 14 +-- frontend/src/molecules/NameEditor.tsx | 34 ++++++++ frontend/src/translations/locales/ar-SA.json | 5 +- frontend/src/translations/locales/de-DE.json | 5 +- frontend/src/translations/locales/en-GB.json | 5 +- frontend/src/translations/locales/es-ES.json | 5 +- frontend/src/translations/locales/fr-FR.json | 5 +- frontend/src/translations/locales/hu-HU.json | 5 +- frontend/src/translations/locales/it-IT.json | 5 +- frontend/src/translations/locales/ja-JP.json | 5 +- frontend/src/translations/locales/nl-NL.json | 5 +- frontend/src/translations/locales/pl-PL.json | 5 +- frontend/src/translations/locales/pt-BR.json | 5 +- frontend/src/translations/locales/pt-PT.json | 5 +- frontend/src/translations/locales/uk-UA.json | 5 +- frontend/src/translations/locales/zh-CN.json | 5 +- frontend/src/translations/locales/zh-TW.json | 5 +- frontend/src/views/Demo.tsx | 25 +++++- frontend/src/views/Home.tsx | 11 ++- frontend/src/views/Welcome.tsx | 4 +- frontend/src/views/account/AccountPage.tsx | 29 ++----- frontend/src/views/game/board/Group.tsx | 1 + .../views/game/board/header/BoardHeader.tsx | 1 + frontend/src/views/game/board/post/Post.tsx | 2 + .../sections/template/ColumnEditor.tsx | 1 + integration/cypress/e2e/test.cy.ts | 21 ++--- 30 files changed, 220 insertions(+), 126 deletions(-) create mode 100644 frontend/src/molecules/NameEditor.tsx diff --git a/backend/src/index.ts b/backend/src/index.ts index 81154008f..8ee89c31c 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -59,7 +59,6 @@ import { getIdentityByUsername, associateUserWithAdWordsCampaign, TrackingInfo, - registerAnonymousUser, } from './db/actions/users.js'; import { isLicenced } from './security/is-licenced.js'; import rateLimit from 'express-rate-limit'; @@ -71,7 +70,6 @@ import { deleteAccount } from './db/actions/delete.js'; import { noop } from 'lodash-es'; import { createDemoSession } from './db/actions/demo.js'; import cookieParser from 'cookie-parser'; -import { generateUsername } from './common/random-username.js'; import { mergeAnonymous } from './db/actions/merge.js'; import aiRouter from './ai/router.js'; @@ -336,37 +334,18 @@ db().then(() => { app.get('/api/me', async (req, res) => { const user = await getUserViewFromRequest(req); - const trackingString: string = req.cookies['retro_aw']; - if (trackingString && user) { - const tracking: Partial = JSON.parse(trackingString); - // We don't await this because we don't want to block the response - associateUserWithAdWordsCampaign(user, tracking); - } if (user) { - res.status(200).send(user.toJson()); - } else if (!config.DISABLE_ANONYMOUS_LOGIN) { - const anonUser = await registerAnonymousUser( - generateUsername() + '^' + v4(), - v4() - ); - if (anonUser) { - const view = await getUserView(anonUser.id); - if (view) { - req.logIn( - { userId: anonUser.user.id, identityId: anonUser.id }, - () => { - res.status(200).send(view.toJson()); - } - ); - } else { - res.status(500).send('Could not get user view'); - } - } else { - res.status(401).send('Not logged in'); + const trackingString: string = req.cookies['retro_aw']; + if (trackingString) { + const tracking: Partial = JSON.parse(trackingString); + // We don't await this because we don't want to block the response + associateUserWithAdWordsCampaign(user, tracking); } + + res.status(200).send(user.toJson()); } else { - res.status(403).send('Cannot login anonymously'); + res.status(401).send('Not logged in'); } }); diff --git a/frontend/src/auth/AccountMenu.tsx b/frontend/src/auth/AccountMenu.tsx index a8554e9c7..5598c632e 100644 --- a/frontend/src/auth/AccountMenu.tsx +++ b/frontend/src/auth/AccountMenu.tsx @@ -53,7 +53,8 @@ const AccountMenu = () => { logout(); setUser(null); setMenuOpen(false); - }, [setUser]); + navigate('/'); + }, [setUser, navigate]); const handleAccount = useCallback(() => { navigate('/account'); diff --git a/frontend/src/auth/modal/LoginContent.tsx b/frontend/src/auth/modal/LoginContent.tsx index 50f88a214..2d1d67329 100644 --- a/frontend/src/auth/modal/LoginContent.tsx +++ b/frontend/src/auth/modal/LoginContent.tsx @@ -1,4 +1,4 @@ -import { useContext } from 'react'; +import { useCallback, useContext } from 'react'; import DialogContent from '@mui/material/DialogContent'; import { useTranslation } from 'react-i18next'; import UserContext from '../Context'; @@ -6,14 +6,22 @@ import SocialAuth from './SocialAuth'; import AccountAuth from './AccountAuth'; import useOAuthAvailabilities from '../../global/useOAuthAvailabilities'; import useBackendCapabilities from '../../global/useBackendCapabilities'; -import { Alert } from '@mui/material'; +import { Alert, Button } from '@mui/material'; 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'; interface LoginContentProps { + anonymous: boolean; onClose: () => void; } -export default function LoginContent({ onClose }: LoginContentProps) { +export default function LoginContent({ + anonymous, + onClose, +}: LoginContentProps) { const { any } = useOAuthAvailabilities(); const { disableAnonymous, disablePasswords } = useBackendCapabilities(); const hasNoSocialMediaAuth = !any; @@ -22,6 +30,23 @@ export default function LoginContent({ onClose }: LoginContentProps) { const hasNoWayOtherThanAnonymous = hasNoSocialMediaAuth && disablePasswords; const { t } = useTranslation(); const { setUser } = useContext(UserContext); + const [language] = useLanguage(); + + const handleAnonLogin = useCallback(async () => { + const user = await anonymousLogin('Anonymous User'); + if (!user) { + return; + } + trackEvent('register/anonymous'); + let updatedUser = await me(); + if (updatedUser?.language === null) { + updatedUser = await updateLanguage(language.locale); + } + setUser(updatedUser); + if (onClose) { + onClose(); + } + }, [setUser, onClose, language]); if (hasNoWayOfLoggingIn) { {t('AuthCommon.noAuthWarning')}; @@ -34,19 +59,34 @@ export default function LoginContent({ onClose }: LoginContentProps) { ) : ( <> - - {!hasNoSocialMediaAuth ? ( - - ) : null} - {!hasNoSocialMediaAuth && !disablePasswords ? ( - - {t('AuthCommon.or')} - - ) : null} - {!disablePasswords ? ( - - ) : null} - +
+ + {!hasNoSocialMediaAuth ? ( + + ) : null} + {!hasNoSocialMediaAuth && !disablePasswords ? ( + + {t('AuthCommon.or')} + + ) : null} + {!disablePasswords ? ( + + ) : null} + +
+ {anonymous ? ( +
+ +
+ ) : null}
)} @@ -96,3 +136,17 @@ const Container = styled.div` flex-direction: column; } `; + +const Main = styled.div``; + +const Footer = styled.div` + display: flex; + justify-content: flex-end; + + @media screen and (max-width: 1000px) { + border-top: 1px solid #ccc; + justify-content: center; + margin-top: 30px; + padding-top: 30px; + } +`; diff --git a/frontend/src/auth/modal/LoginModal.tsx b/frontend/src/auth/modal/LoginModal.tsx index 47e84e4e8..3b6cdab31 100644 --- a/frontend/src/auth/modal/LoginModal.tsx +++ b/frontend/src/auth/modal/LoginModal.tsx @@ -31,7 +31,7 @@ export default function LoginModal({ onClose={handleClose} hideBackdrop={!backdrop} > - + ); } diff --git a/frontend/src/components/EditableLabel.tsx b/frontend/src/components/EditableLabel.tsx index a5ac91680..375043c1a 100644 --- a/frontend/src/components/EditableLabel.tsx +++ b/frontend/src/components/EditableLabel.tsx @@ -11,6 +11,7 @@ interface EditableLabelProps extends CenteredProp { multiline?: boolean; label?: string; focused?: boolean; + wrap?: boolean; onChange: (value: string) => void; } @@ -25,6 +26,7 @@ const EditableLabel = ({ multiline, label, focused, + wrap = false, onChange, }: EditableLabelProps) => { const [editMode, setEditMode] = useState(false); @@ -98,11 +100,11 @@ const EditableLabel = ({ ) : readOnly ? ( - + {current || placeholder} ) : ( - + {current || placeholder} @@ -118,10 +120,12 @@ export default EditableLabel; const LabelContainer = styled.span``; -const ViewMode = styled.span` - display: inline-block; +const ViewMode = styled.span<{ wrap: boolean }>` + display: inline-flex; + flex-wrap: nowrap; + align-items: center; > span { - white-space: pre-wrap; + white-space: ${(props) => (props.wrap ? 'pre-wrap' : 'nowrap')}; line-height: 1.5; } diff --git a/frontend/src/molecules/NameEditor.tsx b/frontend/src/molecules/NameEditor.tsx new file mode 100644 index 000000000..b47cac702 --- /dev/null +++ b/frontend/src/molecules/NameEditor.tsx @@ -0,0 +1,34 @@ +import UserContext from 'auth/Context'; +import useUser from 'auth/useUser'; +import EditableLabel from 'components/EditableLabel'; +import { useSnackbar } from 'notistack'; +import { useCallback, useContext } from 'react'; +import { useTranslation } from 'react-i18next'; +import { updateUserName } from 'views/account/api'; + +export function NameEditor() { + const { enqueueSnackbar } = useSnackbar(); + const { t } = useTranslation(); + const user = useUser(); + const { setUser } = useContext(UserContext); + const handleEditName = useCallback( + async (name: string) => { + const trimmed = name.trim(); + if (!trimmed.length) { + enqueueSnackbar(t('AccountPage.noEmptyNameError'), { + variant: 'warning', + }); + } else { + const updatedUser = await updateUserName(name); + setUser(updatedUser); + } + }, + [setUser, enqueueSnackbar, t] + ); + + if (!user) { + return <>Stranger; + } + + return ; +} diff --git a/frontend/src/translations/locales/ar-SA.json b/frontend/src/translations/locales/ar-SA.json index fe1f13436..b63c49f37 100644 --- a/frontend/src/translations/locales/ar-SA.json +++ b/frontend/src/translations/locales/ar-SA.json @@ -23,7 +23,7 @@ "title": "مرحبًا! الرجاء تسجيل الدخول للبدء." }, "Home": { - "welcome": "مرحبا، {{name}}", + "welcome": "مرحباً،", "anonWarning": "أنت تستخدم حساب مجهول. قد ترغب في تسجيل الدخول للتأكد من أن البيانات الخاصة بك يمكن استرجاعها عند استخدام جهاز آخر.", "howDoesThatWork": "كيف يعمل ذلك؟", "login": "تسجيل الدخول", @@ -221,7 +221,8 @@ "ليس تماما", "جيد", "قوي" - ] + ], + "skipAndAnonLogin": "تخطي وتسجلي في مجهول" }, "AccountLogin": { "header": "كلمة المرور", diff --git a/frontend/src/translations/locales/de-DE.json b/frontend/src/translations/locales/de-DE.json index 1e4fb10d0..2abe819ca 100644 --- a/frontend/src/translations/locales/de-DE.json +++ b/frontend/src/translations/locales/de-DE.json @@ -23,7 +23,7 @@ "title": "Willkommen! Bitte melden Sie sich an, um zu starten." }, "Home": { - "welcome": "Willkommen, {{name}}", + "welcome": "Willkommen,", "anonWarning": "Du verwendest ein anonymes Konto. Du solltest dich einloggen, um sicherzustellen, dass deine Daten abgerufen werden können, wenn du ein anderes Gerät verwendest.", "howDoesThatWork": "Wie funktioniert das?", "login": "Anmelden", @@ -221,7 +221,8 @@ "nicht ganz", "gut", "stark" - ] + ], + "skipAndAnonLogin": "Überspringe und logge mich anonym ein" }, "AccountLogin": { "header": "Passwort", diff --git a/frontend/src/translations/locales/en-GB.json b/frontend/src/translations/locales/en-GB.json index f8f409384..a86013161 100644 --- a/frontend/src/translations/locales/en-GB.json +++ b/frontend/src/translations/locales/en-GB.json @@ -23,7 +23,7 @@ "title": "Welcome! Please login to start." }, "Home": { - "welcome": "Welcome, {{name}}", + "welcome": "Welcome,", "anonWarning": "You are using an Anonymous account. You might want to login to make sure your data can be retrieved when using another device.", "howDoesThatWork": "How does that work?", "login": "Login", @@ -221,7 +221,8 @@ "not quite", "good", "strong" - ] + ], + "skipAndAnonLogin": "Skip and log me in Anonymously" }, "AccountLogin": { "header": "Password", diff --git a/frontend/src/translations/locales/es-ES.json b/frontend/src/translations/locales/es-ES.json index 3bde88bd2..759c5f2ed 100644 --- a/frontend/src/translations/locales/es-ES.json +++ b/frontend/src/translations/locales/es-ES.json @@ -23,7 +23,7 @@ "title": "¡Bienvenido! Inicie sesión para empezar." }, "Home": { - "welcome": "Bienvenido, {{name}}", + "welcome": "Bienvenido,", "anonWarning": "Estás usando una cuenta anónima. Tal vez quieras iniciar sesión para asegurarte de que tus datos pueden ser recuperados cuando usas otro dispositivo.", "howDoesThatWork": "¿Cómo funciona esto?", "login": "Ingresar", @@ -221,7 +221,8 @@ "no muy bien", "bueno", "fuerte" - ] + ], + "skipAndAnonLogin": "Saltar y registrarme anónimamente" }, "AccountLogin": { "header": "Contraseña", diff --git a/frontend/src/translations/locales/fr-FR.json b/frontend/src/translations/locales/fr-FR.json index 7497f65cd..7012db160 100644 --- a/frontend/src/translations/locales/fr-FR.json +++ b/frontend/src/translations/locales/fr-FR.json @@ -23,7 +23,7 @@ "title": "Bienvenue! Veuillez vous connecter pour commencer." }, "Home": { - "welcome": "Bienvenue, {{name}}", + "welcome": "Bienvenue,", "anonWarning": "Vous utilisez un compte anonyme. Connectez-vous afin que vos données puissent être récupérées lorsque vous utilisez un autre appareil.", "howDoesThatWork": "Comment cela fonctionne-t-il ?", "login": "Connexion", @@ -221,7 +221,8 @@ "encore un effort", "suffisant", "excellent" - ] + ], + "skipAndAnonLogin": "Connectez-moi en mode anonyme à la place" }, "AccountLogin": { "header": "Mot de Passe", diff --git a/frontend/src/translations/locales/hu-HU.json b/frontend/src/translations/locales/hu-HU.json index 6c89cc792..3829821d5 100644 --- a/frontend/src/translations/locales/hu-HU.json +++ b/frontend/src/translations/locales/hu-HU.json @@ -23,7 +23,7 @@ "title": "" }, "Home": { - "welcome": "Isten hozott, {{name}}", + "welcome": "", "anonWarning": "", "howDoesThatWork": "Hogyan működik?", "login": "", @@ -221,7 +221,8 @@ "nem egészen", "jó", "erős" - ] + ], + "skipAndAnonLogin": "" }, "AccountLogin": { "header": "Jelszó", diff --git a/frontend/src/translations/locales/it-IT.json b/frontend/src/translations/locales/it-IT.json index 6087530cc..ad4bf9ddc 100644 --- a/frontend/src/translations/locales/it-IT.json +++ b/frontend/src/translations/locales/it-IT.json @@ -23,7 +23,7 @@ "title": "Benvenuto! Effettua il login per iniziare." }, "Home": { - "welcome": "Benvenuto, {{name}}", + "welcome": "Benvenuto,", "anonWarning": "Stai utilizzando un account anonimo. Potresti voler effettuare il login per assicurarsi che i tuoi dati possano essere recuperati quando usi un altro dispositivo.", "howDoesThatWork": "Come funziona quello?", "login": "Accedi", @@ -221,7 +221,8 @@ "non abbastanza", "buono", "forte" - ] + ], + "skipAndAnonLogin": "Salta e accedi in anonimo" }, "AccountLogin": { "header": "Password", diff --git a/frontend/src/translations/locales/ja-JP.json b/frontend/src/translations/locales/ja-JP.json index c2e4c88ae..7b3b97c07 100644 --- a/frontend/src/translations/locales/ja-JP.json +++ b/frontend/src/translations/locales/ja-JP.json @@ -23,7 +23,7 @@ "title": "ようこそ!ログインしてください。" }, "Home": { - "welcome": "ようこそ、 {{name}}", + "welcome": "ようこそ", "anonWarning": "匿名アカウントを使用しています。別のデバイスを使用しているときにデータを取得できることを確認するためにログインする場合があります。", "howDoesThatWork": "それはどのように機能しますか?", "login": "ログイン", @@ -221,7 +221,8 @@ "そうではありません", "良い", "強い" - ] + ], + "skipAndAnonLogin": "Skip and log me in Anonymously" }, "AccountLogin": { "header": "パスワード", diff --git a/frontend/src/translations/locales/nl-NL.json b/frontend/src/translations/locales/nl-NL.json index 661b8b9fd..288e1b7a6 100644 --- a/frontend/src/translations/locales/nl-NL.json +++ b/frontend/src/translations/locales/nl-NL.json @@ -23,7 +23,7 @@ "title": "Welkom! Gelieve in te loggen om te starten." }, "Home": { - "welcome": "Welkom, {{name}}", + "welcome": "Welkom,", "anonWarning": "Je gebruikt een anonieme account. Je kunt misschien inloggen om ervoor te zorgen dat je gegevens kunnen worden opgehaald wanneer je een ander apparaat gebruikt.", "howDoesThatWork": "Hoe werkt dat?", "login": "Aanmelden", @@ -221,7 +221,8 @@ "niet helemaal", "goed", "sterk" - ] + ], + "skipAndAnonLogin": "Sla me over en log me in Anoniem" }, "AccountLogin": { "header": "Wachtwoord", diff --git a/frontend/src/translations/locales/pl-PL.json b/frontend/src/translations/locales/pl-PL.json index 5b2ad9ca8..275791131 100644 --- a/frontend/src/translations/locales/pl-PL.json +++ b/frontend/src/translations/locales/pl-PL.json @@ -23,7 +23,7 @@ "title": "Witaj! Zaloguj się, aby rozpocząć." }, "Home": { - "welcome": "Witaj, {{name}}", + "welcome": "Witaj,", "anonWarning": "Używasz konta anonimowego. Możesz się zalogować, aby mieć pewność, że dane mogą być pobrane podczas korzystania z innego urządzenia.", "howDoesThatWork": "Jak to działa?", "login": "Logowanie", @@ -221,7 +221,8 @@ "nie całkiem", "dobry", "silny" - ] + ], + "skipAndAnonLogin": "Pomiń i zaloguj mnie anonimowo" }, "AccountLogin": { "header": "Hasło", diff --git a/frontend/src/translations/locales/pt-BR.json b/frontend/src/translations/locales/pt-BR.json index 46a443d30..c692a0a2a 100644 --- a/frontend/src/translations/locales/pt-BR.json +++ b/frontend/src/translations/locales/pt-BR.json @@ -23,7 +23,7 @@ "title": "Bem-vindo! Por favor, faça o login para começar." }, "Home": { - "welcome": "Bem-vindo, {{name}}", + "welcome": "Bem-vindo,", "anonWarning": "Você está usando uma conta anônima. Talvez você queira fazer login para garantir que seus dados possam ser recuperados usando outro dispositivo.", "howDoesThatWork": "Como funciona isso?", "login": "Conectar-se", @@ -221,7 +221,8 @@ "não é muito", "bom", "forte" - ] + ], + "skipAndAnonLogin": "Pular e iniciar sessão em Anônimo" }, "AccountLogin": { "header": "Palavra-passe", diff --git a/frontend/src/translations/locales/pt-PT.json b/frontend/src/translations/locales/pt-PT.json index 4c04ad149..0205ee6fd 100644 --- a/frontend/src/translations/locales/pt-PT.json +++ b/frontend/src/translations/locales/pt-PT.json @@ -23,7 +23,7 @@ "title": "Bem-vindo! Por favor, faça o login para começar." }, "Home": { - "welcome": "Bem-vindo, {{name}}", + "welcome": "Bem-vindo,", "anonWarning": "Você está usando uma conta anônima. Talvez você queira fazer login para garantir que seus dados possam ser recuperados usando outro dispositivo.", "howDoesThatWork": "Como funciona isso?", "login": "Conectar-se", @@ -221,7 +221,8 @@ "não é muito", "bom", "forte" - ] + ], + "skipAndAnonLogin": "Pular e iniciar sessão em Anônimo" }, "AccountLogin": { "header": "Palavra-passe", diff --git a/frontend/src/translations/locales/uk-UA.json b/frontend/src/translations/locales/uk-UA.json index bf9eadfbe..9d13bfb9e 100644 --- a/frontend/src/translations/locales/uk-UA.json +++ b/frontend/src/translations/locales/uk-UA.json @@ -23,7 +23,7 @@ "title": "Ласкаво просимо! Будь ласка, увійдіть, щоб почати." }, "Home": { - "welcome": "Ласкаво просимо, {{name}}", + "welcome": "Ласкаво просимо,", "anonWarning": "Ви використовуєте анонімний обліковий запис. Ви можете увійти в систему, щоб переконатися, що ваші дані можуть бути отримані при використанні іншого пристрою.", "howDoesThatWork": "Як це працює?", "login": "Логін", @@ -221,7 +221,8 @@ "не зовсім", "добре", "сильний" - ] + ], + "skipAndAnonLogin": "Пропустити і увійти до мене анонімно" }, "AccountLogin": { "header": "Пароль", diff --git a/frontend/src/translations/locales/zh-CN.json b/frontend/src/translations/locales/zh-CN.json index 09cb725d1..c35c70fe9 100644 --- a/frontend/src/translations/locales/zh-CN.json +++ b/frontend/src/translations/locales/zh-CN.json @@ -23,7 +23,7 @@ "title": "欢迎!请登录以开始" }, "Home": { - "welcome": "欢迎, {{name}}", + "welcome": "欢迎,", "anonWarning": "您正在使用匿名帐户。您可能想要登录以确保您的数据可以在使用其他设备时检索。", "howDoesThatWork": "这是如何运作的?", "login": "登录", @@ -221,7 +221,8 @@ "不好", "很好", "强度" - ] + ], + "skipAndAnonLogin": "匿名跳过并登录我" }, "AccountLogin": { "header": "密码", diff --git a/frontend/src/translations/locales/zh-TW.json b/frontend/src/translations/locales/zh-TW.json index 9edf9609b..bf292babc 100644 --- a/frontend/src/translations/locales/zh-TW.json +++ b/frontend/src/translations/locales/zh-TW.json @@ -23,7 +23,7 @@ "title": "" }, "Home": { - "welcome": "歡迎, {{name}}", + "welcome": "", "anonWarning": "", "howDoesThatWork": "這是如何運作的?", "login": "", @@ -221,7 +221,8 @@ "不完全的", "好的", "強的" - ] + ], + "skipAndAnonLogin": "" }, "AccountLogin": { "header": "密碼", diff --git a/frontend/src/views/Demo.tsx b/frontend/src/views/Demo.tsx index 425810d82..28ff67d31 100644 --- a/frontend/src/views/Demo.tsx +++ b/frontend/src/views/Demo.tsx @@ -1,7 +1,8 @@ import styled from '@emotion/styled'; import { colors } from '@mui/material'; -import { createDemoGame, me, updateLanguage } from 'api'; +import { anonymousLogin, createDemoGame, me, updateLanguage } from 'api'; import UserContext from 'auth/Context'; +import useUser from 'auth/useUser'; import { useContext, useEffect } from 'react'; import { useSearchParams } from 'react-router-dom'; import { trackEvent } from 'track'; @@ -9,11 +10,13 @@ import { Language } from 'translations/languages'; import { languages, useLanguage } from '../translations'; export default function Demo() { + const user = useUser(); const { setUser } = useContext(UserContext); let [searchParams] = useSearchParams(); const twoLetter = searchParams.get('lang'); const [currentLanguage, changeLanguage] = useLanguage(); const language = getLanguage(twoLetter || 'en'); + const alreadyLoggedIn = !!user; useEffect(() => { if (currentLanguage.locale !== language.locale) { @@ -21,6 +24,16 @@ export default function Demo() { } }, [language.locale, currentLanguage.locale, changeLanguage]); + useEffect(() => { + async function login() { + if (!alreadyLoggedIn) { + const user = await anonymousLogin('Demo User'); + setUser(user); + } + } + login(); + }, [alreadyLoggedIn, setUser]); + useEffect(() => { async function fetch() { trackEvent('register/demo'); @@ -35,10 +48,16 @@ export default function Demo() { window.location.href = `/game/${session.id}`; } } - if (language.locale === currentLanguage.locale) { + if (alreadyLoggedIn && language.locale === currentLanguage.locale) { fetch(); } - }, [language.locale, currentLanguage.locale, setUser, changeLanguage]); + }, [ + language.locale, + currentLanguage.locale, + setUser, + changeLanguage, + alreadyLoggedIn, + ]); return (

Preparing demo...

diff --git a/frontend/src/views/Home.tsx b/frontend/src/views/Home.tsx index fe5cc67f1..69e247d03 100644 --- a/frontend/src/views/Home.tsx +++ b/frontend/src/views/Home.tsx @@ -25,6 +25,7 @@ import { useTranslation } from 'react-i18next'; import ClosableAlert from 'components/ClosableAlert'; import SplitButton from 'components/SplitButton/SplitButton'; import SearchBar from './game/SearchBar'; +import { NameEditor } from 'molecules/NameEditor'; function Home() { const navigate = useNavigate(); @@ -96,7 +97,10 @@ function Home() { ) : null} - {t('Home.welcome', { name: user?.name || '' })} + + {t('Home.welcome')}  + + @@ -161,9 +165,12 @@ function Home() { } const MainHeader = styled.h1` + display: flex; + flex-wrap: wrap; + align-items: center; font-weight: 100; font-size: 4em; - @media screen and (max-width: 500px) { + @media screen and (max-width: 800px) { font-size: 2em; } `; diff --git a/frontend/src/views/Welcome.tsx b/frontend/src/views/Welcome.tsx index 2dea3d7bd..5e18406b4 100644 --- a/frontend/src/views/Welcome.tsx +++ b/frontend/src/views/Welcome.tsx @@ -9,7 +9,7 @@ export function Welcome() { {t('Welcome.title')} - + ); @@ -28,7 +28,7 @@ const Title = styled.h1` font-weight: 100; font-size: 4em; @media screen and (max-width: 700px) { - font-size: 2em; + font-size: 1.5em; } `; diff --git a/frontend/src/views/account/AccountPage.tsx b/frontend/src/views/account/AccountPage.tsx index 9669a5562..5cc18715d 100644 --- a/frontend/src/views/account/AccountPage.tsx +++ b/frontend/src/views/account/AccountPage.tsx @@ -14,11 +14,8 @@ import TrialPrompt from '../home/TrialPrompt'; import useFormatDate from '../../hooks/useFormatDate'; import { DeleteModal } from './delete/DeleteModal'; import useModal from '../../hooks/useModal'; -import EditableLabel from 'components/EditableLabel'; -import { useCallback, useContext, useEffect, useState } from 'react'; -import { updateAdmins, updateUserName } from './api'; -import UserContext from 'auth/Context'; -import { useSnackbar } from 'notistack'; +import { useCallback, useEffect, useState } from 'react'; +import { updateAdmins } from './api'; import LanguagePicker from 'components/LanguagePicker'; import { useLanguage } from 'translations'; import useBackendCapabilities from 'global/useBackendCapabilities'; @@ -26,18 +23,17 @@ import AdminsEditor from './AdminEditor'; import Tag from 'components/TagInput/Tag'; import LoginContent from 'auth/modal/LoginContent'; import { noop } from 'lodash'; +import { NameEditor } from 'molecules/NameEditor'; function AccountPage() { const url = usePortalUrl(); const user = useUser(); const [admins, setAdmins] = useState(null); const [language, setLanguage] = useLanguage(); - const { setUser } = useContext(UserContext); const isTrial = useIsTrial(); const formatDistanceToNow = useFormatDate(); const navigate = useNavigate(); const { t } = useTranslation(); - const { enqueueSnackbar } = useSnackbar(); const [deleteModalOpen, handleDeleteModalOpen, handleDeleteModalClose] = useModal(); const capabilities = useBackendCapabilities(); @@ -46,21 +42,6 @@ function AccountPage() { setAdmins(user?.planAdmins || null); }, [user]); - const handleEditName = useCallback( - async (name: string) => { - const trimmed = name.trim(); - if (!trimmed.length) { - enqueueSnackbar(t('AccountPage.noEmptyNameError'), { - variant: 'warning', - }); - } else { - const updatedUser = await updateUserName(name); - setUser(updatedUser); - } - }, - [setUser, enqueueSnackbar, t] - ); - const handleEditAdmins = useCallback((admins: string[]) => { setAdmins(admins); updateAdmins(admins); @@ -93,13 +74,13 @@ function AccountPage() {   - + {user.accountType === 'anonymous' ? (
{t('AccountPage.convertWarning')} - +
) : (
diff --git a/frontend/src/views/game/board/Group.tsx b/frontend/src/views/game/board/Group.tsx index b04265f86..d1df0fd6e 100644 --- a/frontend/src/views/game/board/Group.tsx +++ b/frontend/src/views/game/board/Group.tsx @@ -63,6 +63,7 @@ export default function Group({