diff --git a/src/App/src/App.tsx b/src/App/src/App.tsx index 8c28e0de1..8720b5414 100644 --- a/src/App/src/App.tsx +++ b/src/App/src/App.tsx @@ -14,7 +14,7 @@ function App() { const dispatch = useAppDispatch(); // Select state from Redux store - const { userName, imageGenerationEnabled, showChatHistory } = useAppSelector(state => state.app); + const { imageGenerationEnabled, showChatHistory } = useAppSelector(state => state.app); const { conversationId, conversationTitle, messages, isLoading, generationStatus, historyRefreshTrigger } = useAppSelector(state => state.chat); const { pendingBrief, confirmedBrief, selectedProducts, availableProducts, generatedContent } = useAppSelector(state => state.content); @@ -44,7 +44,6 @@ function App() {
{/* Header */} dispatch(toggleChatHistory())} /> diff --git a/src/App/src/components/AppHeader.tsx b/src/App/src/components/AppHeader.tsx index dd7205737..1bc00d24f 100644 --- a/src/App/src/components/AppHeader.tsx +++ b/src/App/src/components/AppHeader.tsx @@ -6,7 +6,6 @@ import React from 'react'; import { Text, - Avatar, Button, Tooltip, tokens, @@ -16,15 +15,14 @@ import { History24Filled, } from '@fluentui/react-icons'; import ContosoLogo from '../styles/images/contoso.svg'; +import LoginButton from './LoginButton'; interface AppHeaderProps { - userName: string; showChatHistory: boolean; onToggleChatHistory: () => void; } export const AppHeader = React.memo(function AppHeader({ - userName, showChatHistory, onToggleChatHistory, }: AppHeaderProps) { @@ -53,11 +51,7 @@ export const AppHeader = React.memo(function AppHeader({ aria-label={showChatHistory ? 'Hide chat history' : 'Show chat history'} /> - +
); diff --git a/src/App/src/components/LoginButton.tsx b/src/App/src/components/LoginButton.tsx new file mode 100644 index 000000000..0753b6a44 --- /dev/null +++ b/src/App/src/components/LoginButton.tsx @@ -0,0 +1,133 @@ +import React, { useCallback } from 'react'; +import { + Avatar, + Menu, + MenuTrigger, + MenuPopover, + MenuList, + MenuItem, + Button, + makeStyles, + tokens, +} from '@fluentui/react-components'; +import { Person20Regular, SignOut24Regular } from '@fluentui/react-icons'; +import { useAppSelector } from '../store/hooks'; + +const useStyles = makeStyles({ + userButton: { + minWidth: 'auto', + paddingLeft: tokens.spacingHorizontalXS, + paddingRight: tokens.spacingHorizontalXS, + }, + menuItem: { + paddingLeft: tokens.spacingHorizontalM, + paddingRight: tokens.spacingHorizontalM, + }, + userInfo: { + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-start', + gap: tokens.spacingVerticalXXS, + }, + userName: { + fontWeight: tokens.fontWeightSemibold, + fontSize: tokens.fontSizeBase200, + }, + userEmail: { + fontSize: tokens.fontSizeBase100, + color: tokens.colorNeutralForeground2, + }, +}); + +const getUserInitials = (name: string | undefined): string => { + if (!name) return 'U'; + const cleanName = name.replace(/\s*\([^)]*\)/g, '').trim(); + if (!cleanName) return 'U'; + const parts = cleanName.split(/\s+/).filter(Boolean); + if (parts.length >= 2) { + return (parts[0][0] + parts[1][0]).toUpperCase(); + } + return cleanName.charAt(0).toUpperCase(); +}; + +const LoginButton: React.FC = () => { + const styles = useStyles(); + const userName = useAppSelector(state => state.app.userName); + const userId = useAppSelector(state => state.app.userId); + const userEmail = useAppSelector(state => state.app.userEmail); + const isAuthenticated = Boolean(userId && userId !== 'anonymous'); + + const login = useCallback(() => { + window.location.href = '/.auth/login/aad'; + }, []); + + const logout = useCallback(() => { + const logoutUrl = '/.auth/logout?post_logout_redirect_uri=' + encodeURIComponent('/'); + window.location.href = logoutUrl; + }, []); + + const displayName = isAuthenticated ? userName || userId || 'User' : 'User'; + + if (!isAuthenticated) { + return ( +