mirror of
https://github.com/Afilmory/afilmory
synced 2026-02-01 14:44:48 +00:00
refactor: improve header and user menu components with responsive plan badge
- Updated the Header component to conditionally render the PlanBadge for larger screens. - Enhanced the UserMenu component to display a loading state for the plan badge on mobile and link to the plan page when available. - Introduced new props in UserMenu for better plan management and localization support. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
@@ -52,13 +52,20 @@ export function Header() {
|
||||
{/* Right side - User Menu */}
|
||||
{user && (
|
||||
<div className="border-fill-tertiary/50 ml-2 sm:ml-auto flex items-center gap-3 border-l pl-2 sm:pl-4">
|
||||
<PlanBadge
|
||||
label={planLabel}
|
||||
isLoading={planQuery.isLoading}
|
||||
onClick={() => navigate('/plan')}
|
||||
labelKey="header.plan.badge"
|
||||
<div className="hidden md:block">
|
||||
<PlanBadge
|
||||
label={planLabel}
|
||||
isLoading={planQuery.isLoading}
|
||||
onClick={() => navigate('/plan')}
|
||||
labelKey="header.plan.badge"
|
||||
/>
|
||||
</div>
|
||||
<UserMenu
|
||||
user={user}
|
||||
planLabel={planLabel}
|
||||
planLabelKey="header.plan.badge"
|
||||
planLoading={planQuery.isLoading}
|
||||
/>
|
||||
<UserMenu user={user} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import { clsxm } from '@afilmory/utils'
|
||||
import { LogOut, Settings, User as UserIcon } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Link } from 'react-router'
|
||||
|
||||
import { usePageRedirect } from '~/hooks/usePageRedirect'
|
||||
@@ -16,12 +17,16 @@ import type { BetterAuthUser } from '~/modules/auth/types'
|
||||
|
||||
interface UserMenuProps {
|
||||
user: BetterAuthUser
|
||||
planLabel?: string | null
|
||||
planLabelKey?: I18nKeys
|
||||
planLoading?: boolean
|
||||
}
|
||||
|
||||
export function UserMenu({ user }: UserMenuProps) {
|
||||
export function UserMenu({ user, planLabel, planLabelKey = 'header.plan.badge', planLoading }: UserMenuProps) {
|
||||
const { logout } = usePageRedirect()
|
||||
const [isLoggingOut, setIsLoggingOut] = useState(false)
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const { t } = useTranslation()
|
||||
|
||||
const handleLogout = async () => {
|
||||
if (isLoggingOut) return
|
||||
@@ -84,6 +89,27 @@ export function UserMenu({ user }: UserMenuProps) {
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
{/* Plan badge for mobile */}
|
||||
{planLoading && (
|
||||
<DropdownMenuItem className="md:hidden" disabled>
|
||||
<div className="flex w-full items-center justify-between text-xs text-text-tertiary">
|
||||
<span className="font-medium uppercase tracking-wide">{t(planLabelKey)}</span>
|
||||
<span className="bg-fill/30 h-4 w-12 animate-pulse rounded" aria-hidden="true" />
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
||||
{!planLoading && planLabel && (
|
||||
<DropdownMenuItem className="md:hidden">
|
||||
<Link to="/plan" className="flex w-full items-center justify-between text-xs">
|
||||
<span className="text-text-tertiary font-medium uppercase tracking-wide">{t(planLabelKey)}</span>
|
||||
<span className="text-text font-semibold capitalize">{planLabel}</span>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
||||
{(planLoading || planLabel) && <DropdownMenuSeparator className="md:hidden" />}
|
||||
|
||||
<DropdownMenuItem icon={<UserIcon className="size-4" />}>
|
||||
<Link to="/settings/account">Account Settings</Link>
|
||||
</DropdownMenuItem>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FormError, Input, Label } from '@afilmory/ui'
|
||||
import { useStore } from '@tanstack/react-form'
|
||||
import type { FC, MutableRefObject } from 'react'
|
||||
import { useEffect } from 'react'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import type { useRegistrationForm } from '~/modules/auth/hooks/useRegistrationForm'
|
||||
@@ -34,14 +34,20 @@ export const WorkspaceStep: FC<WorkspaceStepProps> = ({
|
||||
const { t } = useTranslation()
|
||||
const slugValue = useStore(form.store, (state) => state.values.tenantSlug)
|
||||
const tenantNameValue = useStore(form.store, (state) => state.values.tenantName)
|
||||
const tenantNameAutofilledRef = useRef(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (tenantNameValue || !slugValue) {
|
||||
if (tenantNameAutofilledRef.current || !slugValue) {
|
||||
return
|
||||
}
|
||||
if (tenantNameValue) {
|
||||
tenantNameAutofilledRef.current = true
|
||||
return
|
||||
}
|
||||
const derivedName = titleCaseFromSlug(slugValue)
|
||||
if (derivedName) {
|
||||
form.setFieldValue('tenantName', () => derivedName)
|
||||
tenantNameAutofilledRef.current = true
|
||||
}
|
||||
}, [form, slugValue, tenantNameValue])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user