Skip to content

Commit 4efd307

Browse files
committed
login menu when unauthn
1 parent 0b1909e commit 4efd307

File tree

5 files changed

+107
-66
lines changed

5 files changed

+107
-66
lines changed

frontend/public/locales/en/translation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"share": "Share",
3535
"copied": "Copied!",
3636
"login": "Login",
37+
"twitchLogin": "Twitch Login",
3738
"logout": "Logout",
3839
"all": "All",
3940
"categories": "Categories",

frontend/public/locales/es/translation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"share": "Compartir",
3535
"copied": "¡Copiado!",
3636
"login": "Iniciar sesión",
37+
"twitchLogin": "Iniciar sesión en Twitch",
3738
"logout": "Cerrar sesión",
3839
"all": "Todo",
3940
"categories": "Categorías",

frontend/src/components/LanguageToggle.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useState } from 'react'
22
import { useTranslation } from 'react-i18next'
33
import { IconChevronDown } from '@tabler/icons-react'
4-
import { Group, Image, Menu, UnstyledButton } from '@mantine/core'
4+
import { Group, Image, Menu, Text, UnstyledButton } from '@mantine/core'
55
import classes from './LanguageToggle.module.css'
66

77
const languages = [
@@ -20,10 +20,10 @@ export default function LanguageToggle() {
2020
}
2121

2222
const items = languages.map((item) => (
23-
<Menu.Item onClick={() => handleLanguageChange(item.value)} key={item.value} lang={item.value}>
23+
<Menu.Item w={'100%'} onClick={() => handleLanguageChange(item.value)} key={item.value} lang={item.value}>
2424
<Group>
2525
<Image src={item.image} style={{ width: '16px', height: '16px' }} alt={item.label} />
26-
{item.label}
26+
<Text size="sm">{item.label}</Text>
2727
</Group>
2828
</Menu.Item>
2929
))
@@ -40,12 +40,12 @@ export default function LanguageToggle() {
4040
>
4141
<Group gap={8}>
4242
<Image src={selected.image} style={{ width: '22px', height: '22px' }} />
43-
{selected.label}
43+
<Text size="sm">{selected.label}</Text>
4444
</Group>
4545
<IconChevronDown size={16} stroke={2} />
4646
</UnstyledButton>
4747
</Menu.Target>
48-
<Menu.Dropdown>{items}</Menu.Dropdown>
48+
<Menu.Dropdown w={200}>{items}</Menu.Dropdown>
4949
</Menu>
5050
)
5151
}

frontend/src/components/Layout/Layout.module.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,10 @@
156156
border-radius: 9000px;
157157
width: 100%;
158158
}
159+
160+
.twitchLogin {
161+
background-color: hsla(264, 100%, 72%, 0.35);
162+
}
163+
.twitchLogin:hover {
164+
background-color: hsla(264, 100%, 72%, 0.6);
165+
}

frontend/src/components/Layout/Layout.tsx

Lines changed: 93 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
IconBrandTwitch,
4242
IconUsers,
4343
IconBrandGithub,
44+
IconUser,
4445
} from '@tabler/icons'
4546
import useAuthenticatedUser, { logUserOut } from 'src/hooks/auth/useAuthenticatedUser'
4647
import { useQueryClient } from '@tanstack/react-query'
@@ -60,7 +61,7 @@ import { EMOTES } from 'src/assets/img/emotes'
6061
import { ErrorPage } from 'src/components/ErrorPage/ErrorPage'
6162
import HttpStatus from 'src/utils/httpStatus'
6263
import BroadcasterTokenButton from 'src/components/BroadcasterTokenModal'
63-
import { checkAuthorization, redirectToBroadcasterAuthLogin } from 'src/services/authorization'
64+
import { checkAuthorization, redirectToBroadcasterAuthLogin, redirectToUserAuthLogin } from 'src/services/authorization'
6465
import BroadcasterTokenModal from 'src/components/BroadcasterTokenModal'
6566
import banner from 'src/assets/img/banner-la-clipassa.png'
6667
import homeBackground from 'src/assets/img/background-la-clipassa.jpg'
@@ -87,7 +88,8 @@ export default function Layout({ children }: LayoutProps) {
8788
const { user, isAuthenticating } = useAuthenticatedUser()
8889
const { colorScheme } = useMantineColorScheme() // TODO: app logo useffect
8990
const { burgerOpened, setBurgerOpened } = useUISlice()
90-
const [broadcasterTokenOpened, { open: openBroadcasterToken, close: closeBroadcasterToken }] = useDisclosure(false)
91+
const [broadcasterTokenModalOpened, { open: openBroadcasterTokenModal, close: closeBroadcasterTokenModal }] =
92+
useDisclosure(false)
9193
const notificationIdRef = useRef<string | null>(null)
9294
const swRegistrationRef = useRef<ServiceWorkerRegistration | null>(null)
9395

@@ -219,7 +221,7 @@ export default function Layout({ children }: LayoutProps) {
219221
ui.setIsLoggingOut(false)
220222
}
221223

222-
function renderAvatarOrLogin() {
224+
function renderUserMenuButton() {
223225
if (ui.isLoggingOut || isAuthenticating)
224226
return (
225227
<Group gap={'md'} align="center">
@@ -228,18 +230,30 @@ export default function Layout({ children }: LayoutProps) {
228230
{ui.isLoggingOut && <Text>{t('layout.loggingOut')}</Text>}
229231
</Group>
230232
)
231-
return user ? (
233+
234+
return (
232235
<UnstyledButton className={cx(styles.user, { [styles.userActive as string]: userMenuOpened })}>
233236
<Group gap={'xs'} m={4} align="center">
234-
<Avatar alt={user.displayName} radius="xl" size={28} src={withBaseURL(user.profileImage)} />
235-
<Text className={styles.displayName} fw={500} size="sm">
236-
{user.displayName}
237-
</Text>
237+
{user ? (
238+
<Avatar alt={user.displayName} radius="xl" size={28} src={withBaseURL(user.profileImage)} />
239+
) : (
240+
<>
241+
<Avatar radius="xl" size={28}>
242+
<IconUser size={16} />
243+
</Avatar>
244+
<Text className={styles.displayName} fw={500} size="sm">
245+
{t('common.login')}
246+
</Text>
247+
</>
248+
)}
249+
{user && (
250+
<Text className={styles.displayName} fw={500} size="sm">
251+
{user.displayName}
252+
</Text>
253+
)}
238254
<IconChevronDown size={12} stroke={1.5} />
239255
</Group>
240256
</UnstyledButton>
241-
) : (
242-
<LoginButton />
243257
)
244258
}
245259

@@ -254,7 +268,7 @@ export default function Layout({ children }: LayoutProps) {
254268
<Banner />
255269
<AppShell
256270
style={{
257-
height: `calc(100% - var(--header-height) - var(--footer-height))`,
271+
height: 'calc(100% - var(--header-height) - var(--footer-height))',
258272
}}
259273
className={styles.appShell}
260274
header={{ height: 'var(--header-height)' }}
@@ -306,65 +320,83 @@ export default function Layout({ children }: LayoutProps) {
306320
width={220}
307321
position="bottom-end"
308322
onClose={() => setUserMenuOpened(false)}
309-
onOpen={() => {
310-
if (user) setUserMenuOpened(true)
311-
}}
312-
disabled={!user}
323+
onOpen={() => setUserMenuOpened(true)}
313324
>
314-
<Menu.Target>{renderAvatarOrLogin()}</Menu.Target>
325+
<Menu.Target>{renderUserMenuButton()}</Menu.Target>
315326
<Menu.Dropdown classNames={{ dropdown: styles.menuDropdown }}>
316327
<Group justify="center">
317328
<LanguageToggle />
318329
</Group>
319330
<Menu.Divider />
320331
<Menu.Label>{t('common.theme')}</Menu.Label>
321332
<ThemeSwitcher />
322-
{checkAuthorization({ user, requiredRole: 'ADMIN' }).authorized && (
323-
<>
324-
<Menu.Divider />
325-
<Menu.Label>Admin</Menu.Label>
326-
<Menu.Item
327-
component="a"
328-
color={
329-
window.location.href.includes(uiPath('/admin/users-management'))
330-
? 'var(--mantine-primary-color-6)'
331-
: 'inherit'
332-
}
333-
leftSection={<IconUsers size={14} stroke={1.5} />}
334-
onClick={() => navigate(uiPath('/admin/users-management'))}
335-
>
336-
{t('layout.userManagement')}
337-
</Menu.Item>
338-
</>
339-
)}
333+
334+
{user
335+
? checkAuthorization({ user, requiredRole: 'ADMIN' }).authorized && (
336+
<>
337+
<Menu.Divider />
338+
<Menu.Label>Admin</Menu.Label>
339+
<Menu.Item
340+
component="a"
341+
color={
342+
window.location.href.includes(uiPath('/admin/users-management'))
343+
? 'var(--mantine-primary-color-6)'
344+
: 'inherit'
345+
}
346+
leftSection={<IconUsers size={14} stroke={1.5} />}
347+
onClick={() => navigate(uiPath('/admin/users-management'))}
348+
>
349+
{t('layout.userManagement')}
350+
</Menu.Item>
351+
</>
352+
)
353+
: null}
354+
340355
<Menu.Divider />
341356
<Menu.Item
342357
leftSection={<IconBrandGithub size={14} stroke={1.5} />}
343358
onClick={() => window.open('https://github.com/caliecode/la-clipasa', '_blank')}
344359
>
345360
{t('layout.contribute')}
346361
</Menu.Item>
347-
<Menu.Divider />
348-
<Menu.Label>Settings</Menu.Label>
349-
<Menu.Item leftSection={<IconSettings size={14} stroke={1.5} />}>
350-
{t('layout.accountSettings')}
351-
</Menu.Item>
352-
<Menu.Item
353-
leftSection={<IconDeviceDesktopAnalytics size={14} stroke={1.5} />}
354-
onClick={() => navigate(uiPath('/settings/sessions'))}
355-
>
356-
{t('layout.sessionManagement')}
357-
</Menu.Item>
358-
<Menu.Item
359-
onClick={() => openBroadcasterToken()}
360-
leftSection={<IconBrandTwitch size={14} stroke={1.5} />}
361-
>
362-
{t('layout.broadcasterToken')}
363-
</Menu.Item>
364-
<Menu.Divider />
365-
<Menu.Item leftSection={<IconLogout size={14} stroke={1.5} />} onClick={onLogout}>
366-
Logout
367-
</Menu.Item>
362+
363+
{user ? (
364+
<>
365+
<Menu.Divider />
366+
<Menu.Label>Settings</Menu.Label>
367+
<Menu.Item leftSection={<IconSettings size={14} stroke={1.5} />}>
368+
{t('layout.accountSettings')}
369+
</Menu.Item>
370+
<Menu.Item
371+
leftSection={<IconDeviceDesktopAnalytics size={14} stroke={1.5} />}
372+
onClick={() => navigate(uiPath('/settings/sessions'))}
373+
>
374+
{t('layout.sessionManagement')}
375+
</Menu.Item>
376+
<Menu.Item
377+
onClick={() => openBroadcasterTokenModal()}
378+
leftSection={<IconBrandTwitch size={14} stroke={1.5} />}
379+
>
380+
{t('layout.broadcasterToken')}
381+
</Menu.Item>
382+
<Menu.Divider />
383+
<Menu.Item leftSection={<IconLogout size={14} stroke={1.5} />} onClick={onLogout}>
384+
{t('common.logout')}
385+
</Menu.Item>
386+
</>
387+
) : (
388+
<>
389+
<Menu.Divider />
390+
<Menu.Item
391+
leftSection={<IconBrandTwitch size={14} stroke={1.5} />}
392+
className={styles.twitchLogin}
393+
onClick={redirectToUserAuthLogin}
394+
>
395+
{t('common.twitchLogin')}
396+
</Menu.Item>
397+
</>
398+
)}
399+
368400
<Menu.Label c="dimmed" style={{ display: 'none' }}>
369401
Version: {import.meta.env.VITE_BUILD_VERSION} (1)
370402
</Menu.Label>
@@ -425,8 +457,8 @@ export default function Layout({ children }: LayoutProps) {
425457
</Drawer>
426458
{/* <AppShell.Aside p="md">Aside</AppShell.Aside> */}
427459
<BroadcasterTokenModal
428-
isOpen={broadcasterTokenOpened}
429-
onClose={closeBroadcasterToken}
460+
isOpen={broadcasterTokenModalOpened}
461+
onClose={closeBroadcasterTokenModal}
430462
onConfirm={() => redirectToBroadcasterAuthLogin()}
431463
/>
432464
<AppShell.Footer className={styles.footer}>
@@ -497,13 +529,13 @@ function Banner() {
497529
alt="la clipasa"
498530
src={banner}
499531
onClick={() => navigate('/')}
500-
className={`showOnLargeOnly`}
532+
className={styles.showOnLargeOnly}
501533
style={{
502534
cursor: 'pointer',
503535
height: 'var(--banner-height)',
504536
width: '100%',
505537
backgroundImage: `url(${banner})`,
506-
animation: `slideIn 0.3s ease-in-out`,
538+
animation: 'slideIn 0.3s ease-in-out',
507539
}}
508540
/>
509541
)
@@ -515,9 +547,9 @@ function LiveAvatar({ streamTitle }) {
515547
return (
516548
<Group align="center">
517549
<Tooltip label={streamTitle}>
518-
<a href={`https://www.twitch.tv/caliebre`} target="_blank" rel="noopener noreferrer">
550+
<a href="https://www.twitch.tv/caliebre" target="_blank" rel="noopener noreferrer">
519551
<div style={{ position: 'relative' }}>
520-
<img src={broadcasterIcon} alt={`caliebre`} height={40} width={40} className={styles.avatar} />
552+
<img src={broadcasterIcon} alt="caliebre" height={40} width={40} className={styles.avatar} />
521553
<Badge className={styles.liveBadge} variant="filled" radius={5} size="xs">
522554
LIVE
523555
</Badge>

0 commit comments

Comments
 (0)