fix: dashboard api calls, multi profile fetch

This commit is contained in:
Sajad Mirjalili
2025-08-21 14:51:56 +03:30
parent 4d84a29bda
commit 16fa6615c9
24 changed files with 656 additions and 679 deletions

View File

@@ -12,12 +12,13 @@ import { DeviceMessage, Logout } from 'iconsax-react';
import { CardContainer } from '@/components/CardContainer';
import { PageWrapper } from '../components/PageWrapper';
import { Icon } from '@rkheftan/harmony-ui';
import { fetchProfile, deleteSessions } from '../api/settingsApi';
import { deleteSessions } from '../api/settingsApi';
import { type ApiSession } from '../types/settingsApiType';
import { useApi } from '@/hooks/useApi';
import { formatDate } from '@/utils/formatSessionDate';
import { type Device } from '../types/settingsType';
import { useToast } from '@rkheftan/harmony-ui';
import { useProfile } from '../hooks/useProfile';
export function ActiveDevicesPage() {
const { t, i18n } = useTranslation('setting');
@@ -27,50 +28,56 @@ export function ActiveDevicesPage() {
const isXsup = useMediaQuery(theme.breakpoints.up('xs'));
const showToast = useToast();
const {
data: profileData,
loading: isLoading,
error: fetchError,
} = useApi(fetchProfile, { immediate: true });
const { isLoadingProfile, refetchProfile } = useProfile();
const {
data: terminateData,
loading: isTerminating,
execute: executeTerminateAll,
} = useApi(deleteSessions);
const { loading: isTerminating, execute: executeTerminate } =
useApi(deleteSessions);
useEffect(() => {
if (profileData?.success && profileData.activeSessions) {
const { sessions, currentKey } = profileData.activeSessions;
const formattedDevices = sessions.map((session: ApiSession) => ({
id: session.key,
timeAndDate: formatDate(session.created, i18n.language, t),
deviceModel: `${session.deviceOs} ${session.deviceName}`,
ip: session.ipAddress,
current: session.key === currentKey,
}));
const loadProfile = async () => {
const profileData = await refetchProfile();
const sortedDevices = formattedDevices.sort((a, b) => {
if (a.current && !b.current) return -1;
if (!a.current && b.current) return 1;
return 0;
});
if (!profileData) return;
setDevices(sortedDevices);
}
}, [profileData, i18n.language, t]);
if (profileData.success) {
if (!profileData.activeSessions) return;
useEffect(() => {
if (terminateData?.success) {
setDevices((prev) => prev.filter((d) => d.current));
}
}, [terminateData]);
const { sessions, currentKey } = profileData.activeSessions;
const formattedDevices = sessions.map((session: ApiSession) => ({
id: session.key,
timeAndDate: formatDate(session.created, i18n.language, t),
deviceModel: `${session.deviceOs} ${session.deviceName}`,
ip: session.ipAddress,
current: session.key === currentKey,
}));
const sortedDevices = formattedDevices.sort((a, b) => {
if (a.current && !b.current) return -1;
if (!a.current && b.current) return 1;
return 0;
});
setDevices(sortedDevices);
} else {
showToast({
message: profileData.message || t('message.serverError'),
severity: 'error',
});
}
};
loadProfile();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleDeleteDevice = async (id: string) => {
if (loadingDeleteIds.includes(id)) return;
setLoadingDeleteIds((prev) => [...prev, id]);
try {
const { data } = await deleteSessions({ keys: [id] });
const data = await executeTerminate({ keys: [id] });
if (!data) return;
if (data.success) {
setDevices((prevDevices) => prevDevices.filter((d) => d.id !== id));
showToast({ message: t('active.successDelete'), severity: 'success' });
@@ -80,11 +87,6 @@ export function ActiveDevicesPage() {
severity: 'error',
});
}
} catch (error: unknown) {
showToast({
message: t('active.deleteFailed'),
severity: 'error',
});
} finally {
setLoadingDeleteIds((prev) =>
prev.filter((loadingId) => loadingId !== id),
@@ -92,17 +94,22 @@ export function ActiveDevicesPage() {
}
};
const handleTerminateAllOtherSessions = () => {
const handleTerminateAllOtherSessions = async () => {
const otherSessionKeys = devices.filter((d) => !d.current).map((d) => d.id);
if (otherSessionKeys.length > 0) {
executeTerminateAll({ keys: otherSessionKeys });
}
};
const terminateData = await executeTerminate({ keys: otherSessionKeys });
const getErrorMessage = (error: unknown): string | null => {
if (!error) return null;
if (error instanceof Error) return error.message;
return String(error);
if (!terminateData) return;
if (terminateData?.success) {
setDevices((prev) => prev.filter((d) => d.current));
} else {
showToast({
message: terminateData.message || t('active.deleteFailed'),
severity: 'error',
});
}
}
};
return (
@@ -124,7 +131,7 @@ export function ActiveDevicesPage() {
flexGrow: 0,
width: 'auto',
}}
disabled={isLoading || isTerminating}
disabled={isLoadingProfile || isTerminating}
>
{isTerminating
? t('active.deleting')
@@ -132,7 +139,7 @@ export function ActiveDevicesPage() {
</Button>
}
>
{isLoading ? (
{isLoadingProfile ? (
<Box
sx={{
display: 'flex',
@@ -144,12 +151,6 @@ export function ActiveDevicesPage() {
>
<CircularProgress />
</Box>
) : fetchError ? (
<Box sx={{ textAlign: 'center', p: 4 }}>
<Typography color="error.main">
{getErrorMessage(fetchError)}
</Typography>
</Box>
) : (
<Box
sx={{