diff --git a/frontend/components/UserAvatar.tsx b/frontend/components/UserAvatar.tsx new file mode 100644 index 0000000..6325b0c --- /dev/null +++ b/frontend/components/UserAvatar.tsx @@ -0,0 +1,20 @@ +import { User } from 'lucide-react'; +import Avatar from 'boring-avatars'; +import { TokenContextType } from '@/types/user'; + +type Props = { + context: TokenContextType; +}; + +export default function PublicityChip({ context }: Props) { + return context.isSignedIn() ? ( + + ) : ( + + ); +} diff --git a/frontend/config/selection.ts b/frontend/config/selection.ts index 1fdda50..a4cf6d7 100644 --- a/frontend/config/selection.ts +++ b/frontend/config/selection.ts @@ -1,8 +1,14 @@ const roles = [{ uid: 'administrator' }, { uid: 'user' }]; + const memberRoles = [{ uid: 'manager' }, { uid: 'developer' }, { uid: 'reporter' }]; const categoricalPalette = ['#fba91e', '#6ea56c', '#3ac6e1', '#feda2f', '#f15f47', '#244470', '#9c80bb', '#f595a6']; +const locales = [ + { code: 'en', name: 'English' }, + { code: 'ja', name: '日本語' }, +]; + const priorities = [ { uid: 'critical', color: '#bb3e03', chartColor: '#bb3e03' }, { uid: 'high', color: '#ca6702', chartColor: '#ca6702' }, @@ -56,4 +62,14 @@ const testRunCaseStatus = [ { uid: 'skipped', color: 'primary', chartColor: '#805aab' }, ]; -export { roles, memberRoles, priorities, testTypes, automationStatus, templates, testRunStatus, testRunCaseStatus }; +export { + roles, + memberRoles, + locales, + priorities, + testTypes, + automationStatus, + templates, + testRunStatus, + testRunCaseStatus, +}; diff --git a/frontend/messages/en.json b/frontend/messages/en.json index d7ad3cc..0a287ad 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -27,7 +27,9 @@ "account": "Account", "signup": "Sign up", "signin": "Sign in", - "signout": "Sign out" + "signout": "Sign out", + "links": "Links", + "languages": "Languages" }, "Toast": { "need_signed_in": "You need signed in", diff --git a/frontend/messages/ja.json b/frontend/messages/ja.json index 37d01e4..9f2b7bc 100644 --- a/frontend/messages/ja.json +++ b/frontend/messages/ja.json @@ -27,7 +27,9 @@ "account": "アカウント", "signup": "新規登録", "signin": "サインイン", - "signout": "サインアウト" + "signout": "サインアウト", + "links": "リンク", + "languages": "言語" }, "Toast": { "need_signed_in": "サインインが必要です", diff --git a/frontend/src/app/[locale]/DropdownAccount.tsx b/frontend/src/app/[locale]/DropdownAccount.tsx index 0934701..a58b8b4 100644 --- a/frontend/src/app/[locale]/DropdownAccount.tsx +++ b/frontend/src/app/[locale]/DropdownAccount.tsx @@ -1,11 +1,11 @@ 'use client'; import { Button, DropdownTrigger, Dropdown, DropdownMenu, DropdownItem } from '@nextui-org/react'; -import { User, ChevronDown, PenTool, ArrowRightFromLine, ArrowRightToLine } from 'lucide-react'; +import { ChevronDown, PenTool, ArrowRightFromLine, ArrowRightToLine } from 'lucide-react'; import { useContext } from 'react'; import { TokenContext } from '@/utils/TokenProvider'; import { useRouter } from '@/src/navigation'; import { AccountDropDownMessages } from '@/types/user'; -import Avatar from 'boring-avatars'; +import UserAvatar from '@/components/UserAvatar'; type Props = { messages: AccountDropDownMessages; @@ -23,22 +23,11 @@ export default function DropdownAccount({ messages, locale, onItemPress }: Props router.push(`/`, { locale: locale }); }; - let userAvatar = context.isSignedIn() ? ( - - ) : ( - - ); - const signinItems = [ { uid: 'account', title: messages.account, - icon: userAvatar, + icon: , onPress: () => { router.push('/account', { locale: locale }); onItemPress(); @@ -79,7 +68,12 @@ export default function DropdownAccount({ messages, locale, onItemPress }: Props return ( - diff --git a/frontend/src/app/[locale]/DropdownLanguage.tsx b/frontend/src/app/[locale]/DropdownLanguage.tsx index 8ad3bef..e945caa 100644 --- a/frontend/src/app/[locale]/DropdownLanguage.tsx +++ b/frontend/src/app/[locale]/DropdownLanguage.tsx @@ -1,40 +1,24 @@ 'use client'; import { Button, DropdownTrigger, Dropdown, DropdownMenu, DropdownItem } from '@nextui-org/react'; import { Globe, ChevronDown } from 'lucide-react'; -import { usePathname } from 'next/navigation'; -import { useRouter } from '@/src/navigation'; +import { locales } from '@/config/selection'; -const locales = [ - { code: 'en', name: 'English' }, - { code: 'ja', name: '日本語' }, -]; - -export default function DropdownLanguage(params: { locale: string }) { - const router = useRouter(); - const pathname = usePathname(); - - async function changeLocale(nextLocale: string) { - let newPathname; - if (pathname.length < 4) { - // when root path - router.push('/', { locale: nextLocale }); - } else { - // when not root path, trim first "/en" from pathname = "/en/projects" - newPathname = pathname.slice(params.locale.length + 1); - router.push(newPathname, { locale: nextLocale }); - } - } +type Props = { + locale: string; + onChangeLocale: (code: string) => void; +}; +export default function DropdownLanguage({ locale, onChangeLocale }: Props) { return ( {locales.map((entry) => ( - changeLocale(entry.code)}> + onChangeLocale(entry.code)}> {entry.name} ))} diff --git a/frontend/src/app/[locale]/Header.tsx b/frontend/src/app/[locale]/Header.tsx index 477710a..0132fab 100644 --- a/frontend/src/app/[locale]/Header.tsx +++ b/frontend/src/app/[locale]/Header.tsx @@ -11,6 +11,8 @@ export default function Header(params: { locale: string }) { signUp: t('signup'), signIn: t('signin'), signOut: t('signout'), + links: t('links'), + languages: t('languages'), }; return ; diff --git a/frontend/src/app/[locale]/HeaderNavbarMenu.tsx b/frontend/src/app/[locale]/HeaderNavbarMenu.tsx index b111483..bc20449 100644 --- a/frontend/src/app/[locale]/HeaderNavbarMenu.tsx +++ b/frontend/src/app/[locale]/HeaderNavbarMenu.tsx @@ -1,7 +1,8 @@ 'use client'; import { useState, useContext } from 'react'; import { TokenContext } from '@/utils/TokenProvider'; -import { Link } from '@/src/navigation'; +import { Link, useRouter } from '@/src/navigation'; +import { usePathname } from 'next/navigation'; import Image from 'next/image'; import { Navbar, @@ -10,15 +11,18 @@ import { NavbarMenuToggle, NavbarBrand, NavbarItem, - NavbarMenuItem, Link as NextUiLink, Chip, + ListboxItem, + Listbox, } from '@nextui-org/react'; -import { MoveUpRight } from 'lucide-react'; +import { ArrowRightFromLine, ArrowRightToLine, File, Globe, MoveUpRight, PenTool } from 'lucide-react'; import { ThemeSwitch } from '@/components/theme-switch'; import { GithubIcon } from '@/components/icons'; +import { locales } from '@/config/selection'; import DropdownAccount from './DropdownAccount'; import DropdownLanguage from './DropdownLanguage'; +import UserAvatar from '@/components/UserAvatar'; type NabbarMenuMessages = { projects: string; @@ -28,6 +32,8 @@ type NabbarMenuMessages = { signUp: string; signIn: string; signOut: string; + links: string; + languages: string; }; type Props = { @@ -54,6 +60,20 @@ export default function HeaderNavbarMenu({ messages, locale }: Props) { }, ]; + const router = useRouter(); + const pathname = usePathname(); + async function changeLocale(nextLocale: string) { + let newPathname; + if (pathname.length < 4) { + // when root path + router.push('/', { locale: nextLocale }); + } else { + // when not root path, trim first "/en" from pathname = "/en/projects" + newPathname = pathname.slice(locale.length + 1); + router.push(newPathname, { locale: nextLocale }); + } + } + return ( @@ -115,44 +135,120 @@ export default function HeaderNavbarMenu({ messages, locale }: Props) {
{}} /> - +
setIsMenuOpen(!isMenuOpen)} />
- - setIsMenuOpen(false)} /> - - - - - {commonLinks.map((link) => - link.isExternal ? ( - - setIsMenuOpen(false)} - showAnchorIcon - anchorIcon={} - > - {messages.docs} - - - ) : ( - - setIsMenuOpen(false)} - > - {link.label} - - - ) +

{messages.links}

+ + {commonLinks.map((link) => + link.isExternal ? ( + } + onPress={() => { + router.push(link.href, { locale: locale }); + setIsMenuOpen(false); + }} + /> + ) : ( + } + onPress={() => { + router.push(link.href, { locale: locale }); + setIsMenuOpen(false); + }} + /> + ) + )} + + +

{messages.account}

+ {context.isSignedIn() ? ( + + } + onPress={() => { + router.push('/account', { locale: locale }); + setIsMenuOpen(false); + }} + /> + } + onPress={() => { + context.setToken(null); + context.removeTokenFromLocalStorage(); + router.push(`/`, { locale: locale }); + setIsMenuOpen(false); + }} + /> + + ) : ( + + } + title={messages.signIn} + onClick={() => { + router.push('/account/signin', { locale: locale }); + setIsMenuOpen(false); + }} + /> + } + onClick={() => { + router.push('/account/signup', { locale: locale }); + setIsMenuOpen(false); + }} + /> + )} +

{messages.languages}

+ + {locales.map((entry) => ( + } + title={entry.name} + onClick={() => { + changeLocale(entry.code); + setIsMenuOpen(false); + }} + /> + ))} +