mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
notifications: updating lastSeen when list is opened
This commit is contained in:
parent
a39d000ff2
commit
97590d88af
7 changed files with 88 additions and 4 deletions
|
@ -4,6 +4,8 @@ import { api, cleanResult } from '~/utils/api';
|
||||||
import {
|
import {
|
||||||
ApiGetNotificationSettingsResponse,
|
ApiGetNotificationSettingsResponse,
|
||||||
ApiGetNotificationsResponse,
|
ApiGetNotificationsResponse,
|
||||||
|
ApiUpdateNotificationSettingsResponse,
|
||||||
|
ApiUpdateNotificationSettingsRequest,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
export const apiGetNotificationSettings = () =>
|
export const apiGetNotificationSettings = () =>
|
||||||
|
@ -15,3 +17,13 @@ export const apiGetNotifications = () =>
|
||||||
api
|
api
|
||||||
.get<ApiGetNotificationsResponse>(API.NOTIFICATIONS.LIST)
|
.get<ApiGetNotificationsResponse>(API.NOTIFICATIONS.LIST)
|
||||||
.then(cleanResult);
|
.then(cleanResult);
|
||||||
|
|
||||||
|
export const apiUpdateNotificationSettings = (
|
||||||
|
settings: ApiUpdateNotificationSettingsRequest,
|
||||||
|
) =>
|
||||||
|
api
|
||||||
|
.post<ApiUpdateNotificationSettingsResponse>(
|
||||||
|
API.NOTIFICATIONS.SETTINGS,
|
||||||
|
settings,
|
||||||
|
)
|
||||||
|
.then(cleanResult);
|
||||||
|
|
|
@ -7,7 +7,11 @@ export interface ApiGetNotificationSettingsResponse {
|
||||||
last_seen?: string | null;
|
last_seen?: string | null;
|
||||||
last_date?: string | null;
|
last_date?: string | null;
|
||||||
}
|
}
|
||||||
|
export type ApiUpdateNotificationSettingsResponse =
|
||||||
|
ApiGetNotificationSettingsResponse;
|
||||||
|
|
||||||
|
export type ApiUpdateNotificationSettingsRequest =
|
||||||
|
Partial<ApiGetNotificationSettingsResponse>;
|
||||||
export interface ApiGetNotificationsResponse {
|
export interface ApiGetNotificationsResponse {
|
||||||
items?: NotificationItem[];
|
items?: NotificationItem[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
padding: $gap/2 $gap/2 $gap/4 $gap/2;
|
padding: $gap/2 $gap/2 $gap/4 $gap/2;
|
||||||
min-height: calc(1.3em * 3 + $gap);
|
min-height: calc(1.3em * 3 + $gap);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 40px auto;
|
grid-template-columns: 32px auto;
|
||||||
column-gap: 0;
|
column-gap: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC, useEffect } from 'react';
|
||||||
|
|
||||||
import { LoaderCircle } from '~/components/input/LoaderCircle';
|
import { LoaderCircle } from '~/components/input/LoaderCircle';
|
||||||
import { NotificationComment } from '~/components/notifications/NotificationComment';
|
import { NotificationComment } from '~/components/notifications/NotificationComment';
|
||||||
import { useNotificationsList } from '~/hooks/notifications/useNotificationsList';
|
import { useNotificationsList } from '~/hooks/notifications/useNotificationsList';
|
||||||
|
import { useNotifications } from '~/utils/providers/NotificationProvider';
|
||||||
|
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
|
|
||||||
|
@ -10,6 +11,11 @@ interface NotificationListProps {}
|
||||||
|
|
||||||
const NotificationList: FC<NotificationListProps> = () => {
|
const NotificationList: FC<NotificationListProps> = () => {
|
||||||
const { isLoading, items } = useNotificationsList();
|
const { isLoading, items } = useNotificationsList();
|
||||||
|
const { markAsRead } = useNotifications();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => markAsRead();
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <LoaderCircle />;
|
return <LoaderCircle />;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { isAfter, isValid, parse, parseISO } from 'date-fns';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { isAfter, isBefore, isEqual, isValid, parse, parseISO } from 'date-fns';
|
||||||
|
|
||||||
import { useAuth } from '../auth/useAuth';
|
import { useAuth } from '../auth/useAuth';
|
||||||
|
|
||||||
|
@ -13,6 +15,7 @@ export const useNotificationSettings = () => {
|
||||||
lastSeen,
|
lastSeen,
|
||||||
lastDate,
|
lastDate,
|
||||||
isLoading: isLoadingSettings,
|
isLoading: isLoadingSettings,
|
||||||
|
update,
|
||||||
} = useNotificationSettingsRequest();
|
} = useNotificationSettingsRequest();
|
||||||
|
|
||||||
const enabled = !isLoadingSettings && !settingsError && settingsEnabled;
|
const enabled = !isLoadingSettings && !settingsError && settingsEnabled;
|
||||||
|
@ -20,9 +23,21 @@ export const useNotificationSettings = () => {
|
||||||
const hasNew =
|
const hasNew =
|
||||||
enabled && !!lastDate && (!lastSeen || isAfter(lastDate, lastSeen));
|
enabled && !!lastDate && (!lastSeen || isAfter(lastDate, lastSeen));
|
||||||
|
|
||||||
|
const markAsRead = useCallback(() => {
|
||||||
|
if (
|
||||||
|
!lastDate ||
|
||||||
|
(lastSeen && (isEqual(lastSeen, lastDate) || isAfter(lastSeen, lastDate)))
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
update({ last_seen: lastDate.toISOString() });
|
||||||
|
}, [update, lastDate, lastSeen]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enabled,
|
enabled,
|
||||||
hasNew,
|
hasNew,
|
||||||
available: isUser,
|
available: isUser,
|
||||||
|
markAsRead,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,25 +1,68 @@
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { isValid, parseISO } from 'date-fns';
|
import { isValid, parseISO } from 'date-fns';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
|
|
||||||
import { apiGetNotificationSettings } from '~/api/notifications/settings';
|
import {
|
||||||
|
apiGetNotificationSettings,
|
||||||
|
apiUpdateNotificationSettings,
|
||||||
|
} from '~/api/notifications/settings';
|
||||||
|
import { ApiUpdateNotificationSettingsRequest } from '~/api/notifications/types';
|
||||||
import { API } from '~/constants/api';
|
import { API } from '~/constants/api';
|
||||||
|
import { getErrorMessage } from '~/utils/errors/getErrorMessage';
|
||||||
|
import { showErrorToast } from '~/utils/errors/showToast';
|
||||||
|
|
||||||
import { useAuth } from '../auth/useAuth';
|
import { useAuth } from '../auth/useAuth';
|
||||||
|
|
||||||
const refreshInterval = 60e3; // 1min
|
const refreshInterval = 60e3; // 1min
|
||||||
|
|
||||||
export const useNotificationSettingsRequest = () => {
|
export const useNotificationSettingsRequest = () => {
|
||||||
|
const [isUpdating, setIsUpdating] = useState(false);
|
||||||
|
const [updateError, setUpdateError] = useState('');
|
||||||
|
|
||||||
const { isUser } = useAuth();
|
const { isUser } = useAuth();
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
isValidating: isLoading,
|
isValidating: isLoading,
|
||||||
error,
|
error,
|
||||||
|
mutate,
|
||||||
} = useSWR(
|
} = useSWR(
|
||||||
isUser ? API.NOTIFICATIONS.SETTINGS : null,
|
isUser ? API.NOTIFICATIONS.SETTINGS : null,
|
||||||
async () => apiGetNotificationSettings(),
|
async () => apiGetNotificationSettings(),
|
||||||
{ refreshInterval },
|
{ refreshInterval },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const update = useCallback(
|
||||||
|
async (settings: ApiUpdateNotificationSettingsRequest) => {
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
setIsUpdating(true);
|
||||||
|
setUpdateError('');
|
||||||
|
|
||||||
|
mutate({ ...data, ...settings }, { revalidate: false });
|
||||||
|
|
||||||
|
const result = await apiUpdateNotificationSettings(settings);
|
||||||
|
|
||||||
|
mutate(result, { revalidate: false });
|
||||||
|
} catch (error) {
|
||||||
|
mutate(data, { revalidate: false });
|
||||||
|
|
||||||
|
const message = getErrorMessage(error);
|
||||||
|
if (message) {
|
||||||
|
setUpdateError(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
showErrorToast(error);
|
||||||
|
} finally {
|
||||||
|
setIsUpdating(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[data, mutate],
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isLoading,
|
isLoading,
|
||||||
error,
|
error,
|
||||||
|
@ -32,5 +75,8 @@ export const useNotificationSettingsRequest = () => {
|
||||||
? parseISO(data?.last_date)
|
? parseISO(data?.last_date)
|
||||||
: undefined,
|
: undefined,
|
||||||
enabled: !!data?.enabled && (data.flow || data.comments),
|
enabled: !!data?.enabled && (data.flow || data.comments),
|
||||||
|
update,
|
||||||
|
updateError,
|
||||||
|
isUpdating,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,7 @@ const defaultValue = {
|
||||||
available: false,
|
available: false,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
hasNew: false,
|
hasNew: false,
|
||||||
|
markAsRead: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const NotificationContext = createContext(defaultValue);
|
const NotificationContext = createContext(defaultValue);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue