Fix header not reflecting logged-in state after login

- Add useSnapshot from Valtio to make Header reactive to state changes
- Replace accountState references with accountSnap for reactive updates
- Add missing router import for navigation methods
- Fix router.reload() to router.refresh() for Next.js 13+
- Create AccountStateInitializer component to load auth from cookies
- Add initializer to root layout to ensure state is set on page load

The header now properly updates to show user avatar and authenticated menu when logging in.

🤖 Generated with Claude Code (https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Justin Edmund 2025-09-02 23:17:01 -07:00
parent f205e8fed0
commit 9b60134933
3191 changed files with 78 additions and 22 deletions

View file

@ -12,6 +12,7 @@ import Providers from '../components/Providers'
import Header from '../components/Header'
import UpdateToastClient from '../components/UpdateToastClient'
import VersionHydrator from '../components/VersionHydrator'
import AccountStateInitializer from '~components/AccountStateInitializer'
// Generate static params for all locales
export function generateStaticParams() {
@ -67,6 +68,7 @@ export default async function LocaleLayout({
<body className={goalking.className}>
<NextIntlClientProvider messages={messages}>
<Providers>
<AccountStateInitializer />
<Header />
<VersionHydrator version={version} />
<UpdateToastClient initialVersion={version} />

View file

@ -0,0 +1,48 @@
'use client'
import { useEffect } from 'react'
import { getCookie } from 'cookies-next'
import { accountState } from '~utils/accountState'
import { setHeaders } from '~utils/userToken'
export default function AccountStateInitializer() {
useEffect(() => {
const accountCookie = getCookie('account')
const userCookie = getCookie('user')
if (accountCookie && userCookie) {
try {
const accountData = JSON.parse(accountCookie as string)
const userData = JSON.parse(userCookie as string)
if (accountData && accountData.token) {
console.log(`Logged in as user "${accountData.username}"`)
// Set headers for API calls
setHeaders()
// Update account state
accountState.account.authorized = true
accountState.account.user = {
id: accountData.userId,
username: accountData.username,
role: accountData.role,
granblueId: '',
avatar: {
picture: userData.avatar.picture,
element: userData.avatar.element,
},
gender: userData.gender,
language: userData.language,
theme: userData.theme,
bahamut: userData.bahamut || false,
}
}
} catch (error) {
console.error('Error parsing account cookies:', error)
}
}
}, [])
return null
}

View file

@ -2,6 +2,8 @@
import React, { useState } from 'react'
import { deleteCookie, getCookie } from 'cookies-next'
import { useTranslations } from 'next-intl'
import { useRouter } from '~/i18n/navigation'
import { useSnapshot } from 'valtio'
import classNames from 'classnames'
import clonedeep from 'lodash.clonedeep'
import Link from 'next/link'
@ -36,10 +38,14 @@ import styles from './index.module.scss'
const Header = () => {
// Localization
const t = useTranslations('common')
const router = useRouter()
// Locale
const locale = (getCookie('NEXT_LOCALE') as string) || 'en'
// Subscribe to account state changes
const accountSnap = useSnapshot(accountState)
// State management
const [alertOpen, setAlertOpen] = useState(false)
const [loginModalOpen, setLoginModalOpen] = useState(false)
@ -95,7 +101,7 @@ const Header = () => {
if (key !== 'language') accountState[key] = resetState[key]
})
router.reload()
router.refresh()
return false
}
@ -112,8 +118,8 @@ const Header = () => {
// Methods: Rendering
const profileImage = () => {
const user = accountState.account.user
if (accountState.account.authorized && user) {
const user = accountSnap.account.user
if (accountSnap.account.authorized && user) {
return (
<img
alt={user.username}
@ -126,7 +132,7 @@ const Header = () => {
} else {
return (
<img
alt={t('no_user')}
alt={t('header.anonymous')}
className={`profile anonymous`}
srcSet={`/profile/npc.png,
/profile/npc@2x.png 2x`}
@ -163,18 +169,18 @@ const Header = () => {
const settingsModal = (
<>
{accountState.account.user && (
{accountSnap.account.user && (
<AccountModal
open={settingsModalOpen}
username={accountState.account.user.username}
picture={accountState.account.user.avatar.picture}
gender={accountState.account.user.gender}
language={accountState.account.user.language}
theme={accountState.account.user.theme}
role={accountState.account.user.role}
username={accountSnap.account.user.username}
picture={accountSnap.account.user.avatar.picture}
gender={accountSnap.account.user.gender}
language={accountSnap.account.user.language}
theme={accountSnap.account.user.theme}
role={accountSnap.account.user.role}
bahamutMode={
accountState.account.user.role === 9
? accountState.account.user.bahamut
accountSnap.account.user.role === 9
? accountSnap.account.user.bahamut
: false
}
onOpenChange={setSettingsModalOpen}
@ -194,12 +200,12 @@ const Header = () => {
// Rendering: Compositing
const authorizedLeftItems = (
<>
{accountState.account.user && (
{accountSnap.account.user && (
<>
<DropdownMenuGroup>
<DropdownMenuItem onClick={closeLeftMenu}>
<Link
href={`/${accountState.account.user.username}` || ''}
href={`/${accountSnap.account.user.username}` || ''}
>
<span>{t('menu.profile')}</span>
</Link>
@ -214,8 +220,8 @@ const Header = () => {
)
const leftMenuItems = (
<>
{accountState.account.authorized &&
accountState.account.user &&
{accountSnap.account.authorized &&
accountSnap.account.user &&
authorizedLeftItems}
<DropdownMenuGroup>
@ -286,15 +292,15 @@ const Header = () => {
const authorizedRightItems = (
<>
{accountState.account.user && (
{accountSnap.account.user && (
<>
<DropdownMenuGroup>
<DropdownMenuLabel>
{`@${accountState.account.user.username}`}
{`@${accountSnap.account.user.username}`}
</DropdownMenuLabel>
<DropdownMenuItem onClick={closeRightMenu}>
<Link
href={`/${accountState.account.user.username}` || ''}
href={`/${accountSnap.account.user.username}` || ''}
>
<span>{t('menu.profile')}</span>
</Link>
@ -347,7 +353,7 @@ const Header = () => {
const rightMenuItems = (
<>
{accountState.account.authorized && accountState.account.user
{accountSnap.account.authorized && accountSnap.account.user
? authorizedRightItems
: unauthorizedRightItems}
</>
@ -379,7 +385,7 @@ const Header = () => {
return (
<>
{accountState.account.user?.bahamut && (
{accountSnap.account.user?.bahamut && (
<div className={styles.bahamut}>
<BahamutIcon />
<p>Bahamut Mode is active</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 KiB

Some files were not shown because too many files have changed in this diff Show more