mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
notifications: added tabs to notification screen
This commit is contained in:
parent
7135d06673
commit
f9e0ecdd0c
10 changed files with 148 additions and 21 deletions
25
src/components/input/LoaderScreen/index.tsx
Normal file
25
src/components/input/LoaderScreen/index.tsx
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { LoaderCircle } from '../LoaderCircle';
|
||||||
|
|
||||||
|
import styles from './styles.module.scss';
|
||||||
|
|
||||||
|
interface LoaderScreenProps {
|
||||||
|
className?: string;
|
||||||
|
align?: 'top' | 'middle';
|
||||||
|
}
|
||||||
|
|
||||||
|
const LoaderScreen: FC<LoaderScreenProps> = ({
|
||||||
|
className,
|
||||||
|
align = 'middle',
|
||||||
|
}) => (
|
||||||
|
<div
|
||||||
|
className={classNames(styles.screen, styles[`align-${align}`], className)}
|
||||||
|
>
|
||||||
|
<LoaderCircle size={32} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export { LoaderScreen };
|
14
src/components/input/LoaderScreen/styles.module.scss
Normal file
14
src/components/input/LoaderScreen/styles.module.scss
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
@import 'src/styles/variables';
|
||||||
|
|
||||||
|
.screen {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: $gap;
|
||||||
|
|
||||||
|
&.align-top {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ interface HorizontalMenuItemProps {
|
||||||
icon?: string;
|
icon?: string;
|
||||||
color?: 'green' | 'orange' | 'yellow';
|
color?: 'green' | 'orange' | 'yellow';
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
|
stretchy?: boolean;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ HorizontalMenu.Item = ({
|
||||||
children,
|
children,
|
||||||
isLoading,
|
isLoading,
|
||||||
active,
|
active,
|
||||||
|
stretchy,
|
||||||
onClick,
|
onClick,
|
||||||
}: PropsWithChildren<HorizontalMenuItemProps>) => {
|
}: PropsWithChildren<HorizontalMenuItemProps>) => {
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
|
@ -44,7 +46,11 @@ HorizontalMenu.Item = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(styles.item, { [styles.active]: active }, styles[color])}
|
className={classNames(
|
||||||
|
styles.item,
|
||||||
|
{ [styles.active]: active, [styles.stretchy]: stretchy },
|
||||||
|
styles[color],
|
||||||
|
)}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
{!!icon && <Icon icon={icon} size={24} />}
|
{!!icon && <Icon icon={icon} size={24} />}
|
||||||
|
|
|
@ -57,6 +57,11 @@
|
||||||
background: $warning_gradient;
|
background: $warning_gradient;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.stretchy {
|
||||||
|
flex: 1;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { FC, useCallback } from 'react';
|
import React, { FC, useCallback } from 'react';
|
||||||
|
|
||||||
|
import { Card } from '~/components/containers/Card';
|
||||||
import { Group } from '~/components/containers/Group';
|
import { Group } from '~/components/containers/Group';
|
||||||
import { Zone } from '~/components/containers/Zone';
|
import { Zone } from '~/components/containers/Zone';
|
||||||
import { Button } from '~/components/input/Button';
|
import { Button } from '~/components/input/Button';
|
||||||
|
@ -49,11 +50,16 @@ const NotificationSettingsForm: FC<NotificationSettingsFormProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Group>
|
<Group>
|
||||||
<Zone title="Уведомления">
|
<Card>
|
||||||
|
<InputRow className={styles.row} input={toggle('enabled')}>
|
||||||
|
Получать уведомления
|
||||||
|
</InputRow>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<div />
|
||||||
|
|
||||||
|
<Zone title="Типы уведомлений">
|
||||||
<Group>
|
<Group>
|
||||||
<InputRow className={styles.row} input={toggle('enabled')}>
|
|
||||||
Включены
|
|
||||||
</InputRow>
|
|
||||||
<InputRow
|
<InputRow
|
||||||
className={styles.row}
|
className={styles.row}
|
||||||
input={toggle('flow', !values.enabled)}
|
input={toggle('flow', !values.enabled)}
|
||||||
|
@ -70,7 +76,9 @@ const NotificationSettingsForm: FC<NotificationSettingsFormProps> = ({
|
||||||
</Group>
|
</Group>
|
||||||
</Zone>
|
</Zone>
|
||||||
|
|
||||||
<Zone title="Уведомления">
|
<div />
|
||||||
|
|
||||||
|
<Zone title="Способы доставки">
|
||||||
<Group>
|
<Group>
|
||||||
<InputRow
|
<InputRow
|
||||||
className={styles.row}
|
className={styles.row}
|
||||||
|
|
|
@ -1,25 +1,62 @@
|
||||||
import { VFC } from 'react';
|
import { useState, VFC } from 'react';
|
||||||
|
|
||||||
import { Padder } from '~/components/containers/Padder';
|
import { Group } from '~/components/containers/Group';
|
||||||
|
import { Button } from '~/components/input/Button';
|
||||||
|
import { Icon } from '~/components/input/Icon';
|
||||||
|
import { HorizontalMenu } from '~/components/menu/HorizontalMenu';
|
||||||
import { useStackContext } from '~/components/sidebar/SidebarStack';
|
import { useStackContext } from '~/components/sidebar/SidebarStack';
|
||||||
import { SidebarStackCard } from '~/components/sidebar/SidebarStackCard';
|
import { SidebarStackCard } from '~/components/sidebar/SidebarStackCard';
|
||||||
|
import { NotificationList } from '~/containers/notifications/NotificationList';
|
||||||
import { NotificationSettings } from '~/containers/notifications/NotificationSettings';
|
import { NotificationSettings } from '~/containers/notifications/NotificationSettings';
|
||||||
|
import { useNotificationSettings } from '~/hooks/notifications/useNotificationSettings';
|
||||||
|
|
||||||
|
import styles from './styles.module.scss';
|
||||||
|
|
||||||
interface ProfileSidebarNotificationsProps {}
|
interface ProfileSidebarNotificationsProps {}
|
||||||
|
|
||||||
|
enum Tabs {
|
||||||
|
List,
|
||||||
|
Settings,
|
||||||
|
}
|
||||||
|
|
||||||
const ProfileSidebarNotifications: VFC<
|
const ProfileSidebarNotifications: VFC<
|
||||||
ProfileSidebarNotificationsProps
|
ProfileSidebarNotificationsProps
|
||||||
> = () => {
|
> = () => {
|
||||||
const { closeAllTabs } = useStackContext();
|
const { closeAllTabs } = useStackContext();
|
||||||
|
const [tab, setTab] = useState(Tabs.List);
|
||||||
|
const { loading } = useNotificationSettings();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarStackCard
|
<SidebarStackCard width={400} onBackPress={closeAllTabs}>
|
||||||
width={400}
|
<div className={styles.grid}>
|
||||||
headerFeature="back"
|
<Group className={styles.head} horizontal>
|
||||||
title="Уведомления"
|
<HorizontalMenu className={styles.tabs}>
|
||||||
onBackPress={closeAllTabs}
|
<HorizontalMenu.Item
|
||||||
>
|
active={tab === Tabs.List}
|
||||||
<NotificationSettings />
|
isLoading={loading}
|
||||||
|
onClick={() => setTab(Tabs.List)}
|
||||||
|
stretchy
|
||||||
|
>
|
||||||
|
Уведомления
|
||||||
|
</HorizontalMenu.Item>
|
||||||
|
|
||||||
|
<HorizontalMenu.Item
|
||||||
|
active={tab === Tabs.Settings}
|
||||||
|
isLoading={loading}
|
||||||
|
onClick={() => setTab(Tabs.Settings)}
|
||||||
|
stretchy
|
||||||
|
>
|
||||||
|
Настройки
|
||||||
|
</HorizontalMenu.Item>
|
||||||
|
</HorizontalMenu>
|
||||||
|
|
||||||
|
<Button iconLeft="right" color="link" onClick={closeAllTabs} />
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<div className={styles.list}>
|
||||||
|
{tab === Tabs.List ? <NotificationList /> : <NotificationSettings />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</SidebarStackCard>
|
</SidebarStackCard>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
@import 'src/styles/variables';
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 4;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head {
|
||||||
|
@include row_shadow;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
padding: $gap;
|
||||||
|
flex: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
@include row_shadow;
|
||||||
|
|
||||||
|
overflow-y: auto;
|
||||||
|
flex: 1 1;
|
||||||
|
overflow: auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { FC, useEffect } from 'react';
|
import { FC, useEffect } from 'react';
|
||||||
|
|
||||||
import { LoaderCircle } from '~/components/input/LoaderCircle';
|
import { LoaderScreen } from '~/components/input/LoaderScreen';
|
||||||
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 { useNotifications } from '~/utils/providers/NotificationProvider';
|
||||||
|
@ -18,7 +18,7 @@ const NotificationList: FC<NotificationListProps> = () => {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <LoaderCircle />;
|
return <LoaderScreen align="top" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -14,13 +14,13 @@ export const useNotificationSettings = () => {
|
||||||
enabled: settingsEnabled,
|
enabled: settingsEnabled,
|
||||||
lastSeen,
|
lastSeen,
|
||||||
lastDate,
|
lastDate,
|
||||||
isLoading: isLoadingSettings,
|
isLoading,
|
||||||
update,
|
update,
|
||||||
refresh,
|
refresh,
|
||||||
settings,
|
settings,
|
||||||
} = useNotificationSettingsRequest();
|
} = useNotificationSettingsRequest();
|
||||||
|
|
||||||
const enabled = !isLoadingSettings && !settingsError && settingsEnabled;
|
const enabled = !isLoading && !settingsError && settingsEnabled;
|
||||||
|
|
||||||
const hasNew =
|
const hasNew =
|
||||||
enabled && !!lastDate && (!lastSeen || isAfter(lastDate, lastSeen));
|
enabled && !!lastDate && (!lastSeen || isAfter(lastDate, lastSeen));
|
||||||
|
@ -47,5 +47,6 @@ export const useNotificationSettings = () => {
|
||||||
markAsRead,
|
markAsRead,
|
||||||
refresh,
|
refresh,
|
||||||
update,
|
update,
|
||||||
|
loading: isLoading,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -66,7 +66,7 @@ export const useNotificationSettingsRequest = () => {
|
||||||
const refresh = useCallback(() => mutate(), [mutate]);
|
const refresh = useCallback(() => mutate(), [mutate]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isLoading,
|
isLoading: isLoading && !data,
|
||||||
error,
|
error,
|
||||||
lastSeen:
|
lastSeen:
|
||||||
data?.lastSeen && isValid(parseISO(data.lastSeen))
|
data?.lastSeen && isValid(parseISO(data.lastSeen))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue