1
0
Fork 0
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:
Fedor Katurov 2023-03-11 19:30:18 +06:00
parent a39d000ff2
commit 97590d88af
7 changed files with 88 additions and 4 deletions

View file

@ -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);

View file

@ -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[];
} }

View file

@ -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;
} }

View file

@ -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 />;

View file

@ -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,
}; };
}; };

View file

@ -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,
}; };
}; };

View file

@ -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);