fix: Comprehensive authentication and UI fixes
Some checks failed
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled

Authentication & Token Management:
- Add deviceId to token refresh flow (backend requires both refreshToken and deviceId)
- Fix React Strict Mode token clearing race condition with retry logic
- Improve AuthContext to handle all token state combinations properly
- Store deviceId in localStorage alongside tokens

UI/UX Improvements:
- Remove deprecated legacyBehavior from Next.js Link components
- Update primary theme color to WCAG AA compliant #7c3aed
- Fix nested button error in TabBar voice navigation
- Fix invalid Tabs value error in DynamicChildDashboard

Multi-Child Dashboard:
- Load all children into Redux store properly
- Fetch metrics for all children, not just selected one
- Remove mock data to prevent unauthorized API calls

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-05 16:10:11 +00:00
parent ee6b5cddee
commit d0b78181a3
11 changed files with 272 additions and 124 deletions

View File

@@ -49,19 +49,25 @@ export default function DynamicChildDashboard({
const children = useSelector((state: RootState) => childrenSelectors.selectAll(state));
const viewMode = useSelector(selectViewMode);
const selectedChild = useSelector(selectSelectedChild);
const [selectedTab, setSelectedTab] = useState<string>('');
// Initialize selectedTab with first available child ID
const [selectedTab, setSelectedTab] = useState<string>(() => {
if (selectedChild?.id) return selectedChild.id;
if (children.length > 0) return children[0].id;
return '';
});
// Initialize selected tab
useEffect(() => {
if (selectedChild?.id) {
if (selectedChild?.id && selectedTab !== selectedChild.id) {
setSelectedTab(selectedChild.id);
} else if (children.length > 0) {
} else if (!selectedTab && children.length > 0) {
const firstChildId = children[0].id;
setSelectedTab(firstChildId);
dispatch(selectChild(firstChildId));
onChildSelect(firstChildId);
}
}, [selectedChild, children, dispatch, onChildSelect]);
}, [selectedChild, children, dispatch, onChildSelect, selectedTab]);
const handleTabChange = (_event: React.SyntheticEvent, newValue: string) => {
setSelectedTab(newValue);
@@ -180,6 +186,11 @@ export default function DynamicChildDashboard({
// Tab view for 1-3 children
if (viewMode === 'tabs') {
// Don't render tabs if no children or no valid selectedTab
if (children.length === 0 || !selectedTab) {
return null;
}
return (
<Box>
<Tabs

View File

@@ -71,16 +71,16 @@ export const TabBar = () => {
label=""
value="voice"
showLabel={false}
icon={
<IconButton
onClick={(e) => {
e.stopPropagation();
const voiceButton = document.querySelector('[aria-label="voice input"]') as HTMLButtonElement;
if (voiceButton) {
voiceButton.click();
}
}}
icon={(
<Box
aria-label="voice command"
onClick={(e) => {
e.stopPropagation();
const voiceButton = document.querySelector('[aria-label="voice input"]') as HTMLButtonElement;
if (voiceButton) {
voiceButton.click();
}
}}
sx={{
bgcolor: '#FF69B4',
color: 'white',
@@ -89,11 +89,15 @@ export const TabBar = () => {
'&:hover': {
bgcolor: '#FF1493',
},
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '50%',
}}
>
<Mic />
</IconButton>
}
</Box>
)}
sx={{ minWidth: 80 }}
/>
);