Skip to content

Commit

Permalink
Improving Anonymous account workflow (#506)
Browse files Browse the repository at this point in the history
  • Loading branch information
antoinejaussoin authored Mar 25, 2023
1 parent f80c96b commit 64e8e9d
Show file tree
Hide file tree
Showing 23 changed files with 229 additions and 156 deletions.
4 changes: 3 additions & 1 deletion backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ db().then(() => {

if (user) {
res.status(200).send(user.toJson());
} else {
} else if (!config.DISABLE_ANONYMOUS_LOGIN) {
const anonUser = await registerAnonymousUser(
generateUsername() + '^' + v4(),
v4()
Expand All @@ -353,6 +353,8 @@ db().then(() => {
} else {
res.status(401).send('Not logged in');
}
} else {
res.status(403).send('Cannot login anonymously');
}
});

Expand Down
117 changes: 7 additions & 110 deletions frontend/src/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,15 @@
import { useEffect, useCallback, lazy, Suspense } from 'react';
import {
useNavigate,
Routes,
Route,
useLocation,
useMatch,
} from 'react-router-dom';
import { useEffect, lazy, Suspense } from 'react';
import { Routes, Route, useLocation } from 'react-router-dom';
import { trackPageView } from './track';
import styled from '@emotion/styled';
import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
import IconButton from '@mui/material/IconButton';
import Typography from '@mui/material/Typography';
import MenuIcon from '@mui/icons-material/Menu';
import AccountMenu from './auth/AccountMenu';
import useIsCompatibleBrowser from './hooks/useIsCompatibleBrowser';
import OutdatedBrowser from './components/OutdatedBrowser';
import useIsInitialised from './auth/useIsInitialised';
import useUser from './auth/useUser';
import { HomeOutlined } from '@mui/icons-material';
import ProPill from './components/ProPill';
import { CodeSplitLoader } from './CodeSplitLoader';
import useSidePanel from './views/panel/useSidePanel';
import { Alert, AlertTitle, Button, Hidden } from '@mui/material';
import { Alert, AlertTitle } from '@mui/material';
import useBackendCapabilities from './global/useBackendCapabilities';
import useIsPro from 'auth/useIsPro';
import ProButton from 'components/ProButton';
import { useTranslation } from 'react-i18next';
import { Welcome } from 'views/Welcome';
import { Header } from 'views/layout/Header';

const Home = lazy(() => import('./views/Home'));
const Game = lazy(() => import('./views/Game'));
Expand All @@ -40,28 +22,18 @@ const SubscribePageOuter = lazy(
);
const ResetPasswordPage = lazy(() => import('./views/Reset'));
const ValidatePage = lazy(() => import('./views/Validate'));
const Invite = lazy(() => import('./views/layout/Invite'));
const Panel = lazy(() => import('./views/Panel'));
const EncryptionDoc = lazy(() => import('./views/home/Encryption'));
const AdminPage = lazy(() => import('./views/admin/AdminPage'));
const Demo = lazy(() => import('./views/Demo'));

const Title = styled(Typography)`
color: white;
`;

function App() {
const navigate = useNavigate();
const backend = useBackendCapabilities();
const isCompatible = useIsCompatibleBrowser();
const { toggle: togglePanel } = useSidePanel();
const isInitialised = useIsInitialised();
const user = useUser();
const isPro = useIsPro();
const displayGoPro = !isPro && user && user.accountType !== 'anonymous';
const goToHome = useCallback(() => navigate('/'), [navigate]);

const location = useLocation();
const isOnGamePage = !!useMatch('game/:gameId/*');

const { t } = useTranslation();

// Tracks page views on every location change
Expand All @@ -87,58 +59,7 @@ function App() {
administration panel.
</Alert>
) : null}
<AppBar position="sticky">
<Toolbar>
<IconButton
color="inherit"
aria-label="Menu"
onClick={togglePanel}
size="large"
data-cy="side-panel-toggle"
>
<MenuIcon />
</IconButton>
<HomeButton>
<IconButton
color="inherit"
aria-label="Home"
onClick={goToHome}
size="large"
>
<HomeOutlined />
</IconButton>
</HomeButton>
<MainTitle
variant="h6"
color="inherit"
onClick={goToHome}
data-cy="header-home-button"
>
Retrospected&nbsp;
</MainTitle>
<ProPillContainer>
<ProPill small />
</ProPillContainer>
{displayGoPro ? (
<Hidden mdDown>
<GoProContainer>
<ProButton>
<Button variant="contained" color="secondary">
⭐️ Go Pro!
</Button>
</ProButton>
</GoProContainer>
</Hidden>
) : null}
<Spacer />
{isOnGamePage ? <Invite /> : null}
{isInitialised ? (
<AccountMenu />
) : (
<Initialising>{t('Main.loading')}</Initialising>
)}
</Toolbar>
</AppBar>
<Header />
<Suspense fallback={<CodeSplitLoader />}>
<Routes>
<Route path="/" element={user ? <Home /> : <Welcome />} />
Expand All @@ -162,28 +83,4 @@ function App() {
);
}

const MainTitle = styled(Title)`
cursor: pointer;
margin-right: 10px;
@media screen and (max-width: 600px) {
display: none;
}
`;

const HomeButton = styled.div`
margin-right: 10px;
`;

const ProPillContainer = styled.div``;

const GoProContainer = styled.div`
margin-left: 20px;
`;

const Initialising = styled.div``;

const Spacer = styled.div`
flex: 1;
`;

export default App;
19 changes: 18 additions & 1 deletion frontend/src/auth/AccountMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ import UserContext from './Context';
import Avatar from '../components/Avatar';
import { useMatch, useNavigate } from 'react-router-dom';
import { Key, Logout, Star } from '@mui/icons-material';
import { colors, Divider, ListItemIcon, ListItemText } from '@mui/material';
import {
Chip,
colors,
Divider,
ListItemIcon,
ListItemText,
} from '@mui/material';
import AccountCircle from '@mui/icons-material/AccountCircle';
import useIsAdmin from './useIsAdmin';
import { useTranslation } from 'react-i18next';
Expand Down Expand Up @@ -74,6 +80,11 @@ const AccountMenu = () => {
>
<Avatar user={user} />
<DisplayName>{user.name}</DisplayName>
<ChipContainer>
{user.accountType === 'anonymous' ? (
<Chip color="secondary" label="Anonymous" />
) : null}
</ChipContainer>
<AccountCircle fontSize={'large'} />
</AvatarContainer>
{menuAnchor.current ? (
Expand Down Expand Up @@ -160,4 +171,10 @@ const DisplayName = styled.div`
overflow: hidden;
`;

const ChipContainer = styled.div`
@media screen and (max-width: 700px) {
display: none;
}
`;

export default AccountMenu;
21 changes: 12 additions & 9 deletions frontend/src/auth/modal/LoginContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,26 @@ import { Alert } from '@mui/material';
import styled from '@emotion/styled';

interface LoginContentProps {
allowAnonymous?: boolean;
onClose: () => void;
}

export default function LoginContent({
onClose,
allowAnonymous = true,
}: LoginContentProps) {
export default function LoginContent({ onClose }: LoginContentProps) {
const { any } = useOAuthAvailabilities();
const { disableAnonymous, disablePasswords } = useBackendCapabilities();
const hasNoSocialMediaAuth = !any;
const hasNoWayOfLoggingIn =
hasNoSocialMediaAuth && disableAnonymous && disablePasswords;
const hasNoWayOtherThanAnonymous = hasNoSocialMediaAuth && disablePasswords;
const { t } = useTranslation();
const { setUser } = useContext(UserContext);

if (hasNoWayOfLoggingIn) {
<Alert severity="error">{t('AuthCommon.noAuthWarning')}</Alert>;
}

return (
<>
{hasNoWayOfLoggingIn ? (
{hasNoWayOtherThanAnonymous ? (
<Alert severity="error">{t('AuthCommon.noAuthWarning')}</Alert>
) : (
<>
Expand All @@ -37,9 +38,11 @@ export default function LoginContent({
{!hasNoSocialMediaAuth ? (
<SocialAuth onClose={onClose} onUser={setUser} />
) : null}
<Separator>
<span>{t('AuthCommon.or')}</span>
</Separator>
{!hasNoSocialMediaAuth && !disablePasswords ? (
<Separator>
<span>{t('AuthCommon.or')}</span>
</Separator>
) : null}
{!disablePasswords ? (
<AccountAuth onClose={onClose} onUser={setUser} />
) : null}
Expand Down
19 changes: 13 additions & 6 deletions frontend/src/components/LanguagePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import { Flag } from './Flag';
interface LanguagePickerProps {
value: string;
variant?: 'outlined' | 'standard' | 'filled';
small?: boolean;
onChange: (value: string) => void;
}

const LanguagePicker = ({
value,
variant = 'standard',
small,
onChange,
}: LanguagePickerProps) => {
const handleSelect = useCallback(
Expand All @@ -29,6 +31,9 @@ const LanguagePicker = ({
value={value}
onChange={handleSelect}
variant={variant}
small={small}
size={small ? 'small' : 'medium'}
disableUnderline={small}
data-cy="language-picker"
>
{languages.map((language) => (
Expand All @@ -39,19 +44,21 @@ const LanguagePicker = ({
>
<LanguageItem>
<Flag country={language.iso} />
<Names>
<Name>{language.name}</Name>
<EnglishName>{language.englishName}</EnglishName>
</Names>
{!small ? (
<Names>
<Name>{language.name}</Name>
<EnglishName>{language.englishName}</EnglishName>
</Names>
) : null}
</LanguageItem>
</MenuItem>
))}
</StyledSelect>
);
};

const StyledSelect = styled(Select)`
width: 250px;
const StyledSelect = styled(Select)<{ small?: boolean }>`
width: ${(props) => (props.small ? '100px' : '250px;')};
`;

const LanguageItem = styled.div`
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/translations/locales/ar-SA.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
},
"Home": {
"welcome": "مرحبا، {{name}}",
"howDoesThatWork": "كيف يعمل ذلك؟"
"anonWarning": "أنت تستخدم حساب مجهول. قد ترغب في تسجيل الدخول للتأكد من أن البيانات الخاصة بك يمكن استرجاعها عند استخدام جهاز آخر.",
"howDoesThatWork": "كيف يعمل ذلك؟",
"login": "تسجيل الدخول"
},
"PreviousGame": {
"createdBy": "تم إنشاؤها بواسطة",
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/translations/locales/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
},
"Home": {
"welcome": "Willkommen, {{name}}",
"howDoesThatWork": "Wie funktioniert das?"
"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"
},
"PreviousGame": {
"createdBy": "Erstellt von",
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/translations/locales/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
},
"Home": {
"welcome": "Welcome, {{name}}",
"howDoesThatWork": "How does that work?"
"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"
},
"PreviousGame": {
"createdBy": "Created by",
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/translations/locales/es-ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
},
"Home": {
"welcome": "Bienvenido, {{name}}",
"howDoesThatWork": "¿Cómo funciona esto?"
"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"
},
"PreviousGame": {
"createdBy": "Creado por",
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/translations/locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
},
"Home": {
"welcome": "Bienvenue, {{name}}",
"howDoesThatWork": "Comment cela fonctionne-t-il ?"
"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"
},
"PreviousGame": {
"createdBy": "Créé par",
Expand Down Expand Up @@ -293,7 +295,7 @@
"cancelButton": "Non merci"
},
"AccountPage": {
"convertTitle": "Convertir en vrai compte",
"convertTitle": "Convertir votre compte anonyme",
"noEmptyNameError": "Vous ne pouvez pas choisir un nom d'affichage vide. Veuillez réessayer.",
"anonymousError": "Les comptes anonymes ne peuvent avoir accès à leur profil (puisqu'ils n'en ont pas).",
"convertWarning": "Vous utilisez un compte anonyme. Ne perdez pas vos données et convertissez votre compte anonyme vers un vrai compte. Connectez-vous avec votre compte Google, GitHub, Twitter ou créez un compte avec mot de passe, et nous fusionnerons automatiquement vos données.",
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/translations/locales/hu-HU.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
},
"Home": {
"welcome": "Isten hozott, {{name}}",
"howDoesThatWork": "Hogyan működik?"
"anonWarning": "",
"howDoesThatWork": "Hogyan működik?",
"login": ""
},
"PreviousGame": {
"createdBy": "Készítette",
Expand Down
Loading

0 comments on commit 64e8e9d

Please sign in to comment.