fix: Comprehensive authentication and UI fixes
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:
@@ -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
|
||||
|
||||
@@ -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 }}
|
||||
/>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user