fix: dashboard api calls, multi profile fetch
This commit is contained in:
@@ -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={{
|
||||
|
||||
Reference in New Issue
Block a user