Merge pull request #20 from rkheftan/fix/layout

fix: connect header and layout user info to api, fix setting api and …
This commit is contained in:
SajadMRjl
2025-08-17 12:33:58 +03:30
committed by GitHub
5 changed files with 102 additions and 37 deletions

View File

@@ -1,13 +1,14 @@
import { Box, IconButton, Typography } from '@mui/material';
import { Box, IconButton, Skeleton, Typography } from '@mui/material';
import { Icon } from '@rkheftan/harmony-ui';
import { More } from 'iconsax-react';
import type { User } from './type';
interface HeaderProps {
user: User;
loading: boolean;
}
export const Header: React.FC<HeaderProps> = ({ user }) => {
export const Header: React.FC<HeaderProps> = ({ user, loading }) => {
return (
<Box
sx={{
@@ -20,10 +21,14 @@ export const Header: React.FC<HeaderProps> = ({ user }) => {
>
<Box>
<Typography variant="body1">
{user.firstName + ' ' + user.lastName}
{loading ? (
<Skeleton variant="text" />
) : (
user.firstName + ' ' + user.lastName
)}
</Typography>
<Typography variant="body2" color="textSecondary">
{user.phoneNumber}
{loading ? <Skeleton variant="text" /> : user.phoneNumber}
</Typography>
</Box>

View File

@@ -6,6 +6,8 @@ import { Box, useMediaQuery, useTheme } from '@mui/material';
import { Header } from './Header';
import { useState } from 'react';
import { Toolbar } from './Toolbar';
import { useApi } from '@/hooks/useApi';
import { fetchProfile } from '@/features/profile/api/settingsApi';
import type { User } from './type';
export const Layout = () => {
@@ -14,11 +16,7 @@ export const Layout = () => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const [sideNavOpen, setSideNavOpen] = useState(false);
const [user] = useState<User>({
firstName: 'محمد حسین',
lastName: 'برزه گر',
phoneNumber: '09123456789',
});
const { data, loading } = useApi(fetchProfile, { immediate: true });
return (
<Box
@@ -46,16 +44,48 @@ export const Layout = () => {
isMobile={isMobile}
sideNavOpen={sideNavOpen}
setSideNavOpen={setSideNavOpen}
user={user}
loading={loading}
user={{
firstName: data?.firstName || '',
lastName: data?.lastName || '',
phoneNumber: data?.phoneNumber || '',
profileUrl: data?.profileImageUrl,
}}
/>
<Outlet />
<Box sx={{ flex: 1, overflowY: 'auto' }}>
<Outlet />
</Box>
</Box>
<SideNav
open={sideNavOpen}
onClose={() => setSideNavOpen(false)}
header={isMobile ? undefined : <Header user={user} />}
footer={isMobile ? <Header user={user} /> : undefined}
header={
isMobile ? undefined : (
<Header
loading={loading}
user={{
firstName: data?.firstName || '',
lastName: data?.lastName || '',
phoneNumber: data?.phoneNumber || '',
profileUrl: data?.profileImageUrl,
}}
/>
)
}
footer={
isMobile ? (
<Header
loading={loading}
user={{
firstName: data?.firstName || '',
lastName: data?.lastName || '',
phoneNumber: data?.phoneNumber || '',
profileUrl: data?.profileImageUrl,
}}
/>
) : undefined
}
navConfig={navItemConfigs}
activePath={location.pathname + location.hash}
selectedVariant="textOnly"

View File

@@ -3,18 +3,20 @@ import {
Box,
IconButton,
Toolbar as MuiToolbar,
Typography,
Skeleton,
} from '@mui/material';
import { Icon } from '@rkheftan/harmony-ui';
import { HambergerMenu, Menu } from 'iconsax-react';
import type { Dispatch, SetStateAction } from 'react';
import type { User } from './type';
import Logo from '../Logo';
interface ToolbarProps {
sideNavOpen: boolean;
setSideNavOpen: Dispatch<SetStateAction<boolean>>;
isMobile: boolean;
user: User;
loading: boolean;
}
export const Toolbar: React.FC<ToolbarProps> = ({
@@ -22,6 +24,7 @@ export const Toolbar: React.FC<ToolbarProps> = ({
setSideNavOpen,
isMobile,
user,
loading,
}) => {
return (
<MuiToolbar
@@ -52,20 +55,22 @@ export const Toolbar: React.FC<ToolbarProps> = ({
<Icon Component={HambergerMenu} />
</IconButton>
)}
{/* <Logo /> */}
<Typography variant="h6">LOGO placeholder</Typography>
<Logo />
</Box>
<Box
sx={{ display: 'flex', height: '100%', alignItems: 'center', gap: 1 }}
>
{isMobile && (
<Avatar
sx={{ width: 32, height: 32, fontSize: '14px' }}
src={user.profileUrl}
>
{user.firstName.charAt(0) + ' ' + user.lastName.charAt(0)}
</Avatar>
)}
{isMobile &&
(loading ? (
<Skeleton variant="circular" />
) : (
<Avatar
sx={{ width: 32, height: 32, fontSize: '14px' }}
src={user.profileUrl}
>
{user.firstName.charAt(0) + ' ' + user.lastName.charAt(0)}
</Avatar>
))}
<IconButton>
<Icon Component={Menu} variant="Bold" />
</IconButton>

View File

@@ -15,7 +15,7 @@ import {
import { type InfoRowData } from '../types/settingsType';
export async function fetchProfile() {
return apiClient.post<GetProfileApiResponse>('/Profile/GetProfile');
return apiClient.post<GetProfileApiResponse>('/Profile/GetProfile', {});
}
export async function saveProfile(payload: {

View File

@@ -1,15 +1,4 @@
import { Layout } from '@/components';
import {
AuthenticationPage,
ForgetPasswordPage,
UserCompletionPage,
} from '@/features/authorization';
import {
ActiveDevicesPage,
SecurityPage,
SettingPage,
UserInformationPage,
} from '@/features/profile';
import {
Calendar,
Devices,
@@ -23,9 +12,45 @@ import {
Sms,
type Icon,
} from 'iconsax-react';
import { type ReactNode } from 'react';
import { lazy, type ReactNode } from 'react';
import { Navigate } from 'react-router-dom';
const AuthenticationPage = lazy(() =>
import('@/features/authorization').then((module) => ({
default: module.AuthenticationPage,
})),
);
const UserCompletionPage = lazy(() =>
import('@/features/authorization').then((module) => ({
default: module.UserCompletionPage,
})),
);
const ForgetPasswordPage = lazy(() =>
import('@/features/authorization').then((module) => ({
default: module.ForgetPasswordPage,
})),
);
const UserInformationPage = lazy(() =>
import('@/features/profile').then((module) => ({
default: module.UserInformationPage,
})),
);
const SecurityPage = lazy(() =>
import('@/features/profile').then((module) => ({
default: module.SecurityPage,
})),
);
const ActiveDevicesPage = lazy(() =>
import('@/features/profile').then((module) => ({
default: module.ActiveDevicesPage,
})),
);
const SettingPage = lazy(() =>
import('@/features/profile').then((module) => ({
default: module.SettingPage,
})),
);
export interface RouteConfig {
path: string;
element?: ReactNode;