@stack-spot/portal-components 2.26.0 → 2.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +628 -614
- package/dist/components/AnimatedHeight.d.ts +1 -1
- package/dist/components/AnimatedHeight.js +26 -26
- package/dist/components/AsyncContent.d.ts +1 -1
- package/dist/components/AsyncContent.js +1 -1
- package/dist/components/BannerWarning.d.ts +1 -1
- package/dist/components/BannerWarning.js +1 -1
- package/dist/components/Breadcrumb/index.d.ts +2 -2
- package/dist/components/Breadcrumb/index.js +1 -1
- package/dist/components/Breadcrumb/styled.js +31 -31
- package/dist/components/ButtonLoading.d.ts +1 -1
- package/dist/components/ButtonLoading.js +1 -1
- package/dist/components/ChatBot.d.ts +1 -1
- package/dist/components/ChatBot.js +1 -1
- package/dist/components/ContentValidateFilter.d.ts +1 -1
- package/dist/components/ContentValidateFilter.js +1 -1
- package/dist/components/FadingOverflow.d.ts +1 -1
- package/dist/components/FadingOverflow.js +69 -69
- package/dist/components/FileTreeView/More.d.ts +1 -1
- package/dist/components/FileTreeView/More.js +1 -1
- package/dist/components/FileTreeView/index.d.ts +1 -1
- package/dist/components/FileTreeView/index.js +1 -1
- package/dist/components/InfiniteScroll.d.ts +1 -1
- package/dist/components/InfiniteScroll.js +1 -1
- package/dist/components/InfoMaintenanceBanner.d.ts +1 -1
- package/dist/components/InfoMaintenanceBanner.js +2 -2
- package/dist/components/LazyMarkdown/BlockquoteMd.d.ts +1 -1
- package/dist/components/LazyMarkdown/BlockquoteMd.js +1 -1
- package/dist/components/LazyMarkdown/CodeViewer.d.ts +1 -1
- package/dist/components/LazyMarkdown/CodeViewer.js +76 -76
- package/dist/components/LazyMarkdown/Markdown.d.ts +1 -1
- package/dist/components/LazyMarkdown/Markdown.js +1 -1
- package/dist/components/LazyMarkdown/MarkdownButton.d.ts +1 -1
- package/dist/components/LazyMarkdown/MarkdownButton.js +1 -1
- package/dist/components/LazyMarkdown/Video.d.ts +1 -1
- package/dist/components/LazyMarkdown/Video.js +1 -1
- package/dist/components/LazyMarkdown/index.d.ts +1 -1
- package/dist/components/LazyMarkdown/index.js +1 -1
- package/dist/components/Placeholder.d.ts +3 -3
- package/dist/components/Placeholder.js +1 -1
- package/dist/components/ScrollView.js +16 -16
- package/dist/components/Select/BadgeItem.d.ts +1 -1
- package/dist/components/Select/BadgeItem.js +1 -1
- package/dist/components/Select/ClearInput.d.ts +1 -1
- package/dist/components/Select/ClearInput.js +1 -1
- package/dist/components/Select/CloseItem.d.ts +1 -1
- package/dist/components/Select/CloseItem.js +1 -1
- package/dist/components/Select/CreatableSelect.js +1 -1
- package/dist/components/Select/CustomMenu.d.ts +1 -1
- package/dist/components/Select/CustomMenu.js +1 -1
- package/dist/components/Select/LabelItem.d.ts +1 -1
- package/dist/components/Select/LabelItem.js +1 -1
- package/dist/components/Select/MultiValue.d.ts +1 -1
- package/dist/components/Select/MultiValue.js +1 -1
- package/dist/components/Select/SelectInfiniteScroll.d.ts +1 -1
- package/dist/components/Select/SelectInfiniteScroll.js +1 -1
- package/dist/components/Select/SelectSearch.d.ts +1 -1
- package/dist/components/Select/SelectSearch.js +1 -1
- package/dist/components/SelectionList.d.ts +1 -1
- package/dist/components/SelectionList.js +61 -61
- package/dist/components/StatusCircle.d.ts +1 -1
- package/dist/components/StatusCircle.js +6 -6
- package/dist/components/Stepper/Navigation.js +4 -4
- package/dist/components/Stepper/Step.js +3 -3
- package/dist/components/Stepper/Stepper.js +6 -6
- package/dist/components/Stepper/headers.js +22 -22
- package/dist/components/Table/HeaderItem.js +1 -1
- package/dist/components/Table/SettingsVerticalMenu.d.ts +1 -1
- package/dist/components/Table/SettingsVerticalMenu.js +1 -1
- package/dist/components/Table/StyledLinkTable.d.ts +1 -1
- package/dist/components/Table/StyledLinkTable.js +5 -5
- package/dist/components/Table/TableData.d.ts +1 -1
- package/dist/components/Table/TableData.js +25 -25
- package/dist/components/TimelineSection.d.ts +1 -1
- package/dist/components/TimelineSection.js +14 -14
- package/dist/components/error/ErrorFeedback.d.ts +1 -1
- package/dist/components/error/ErrorFeedback.js +35 -35
- package/dist/components/error/NotFound.d.ts +1 -1
- package/dist/components/error/NotFound.js +1 -1
- package/dist/components/error/UnderMaintenance.d.ts +1 -1
- package/dist/components/error/UnderMaintenance.js +1 -1
- package/dist/components/form/Form/Form.d.ts +1 -1
- package/dist/components/form/Form/Form.js +1 -1
- package/dist/components/form/Form/FormGroup.d.ts +2 -2
- package/dist/components/form/Form/FormGroup.js +1 -1
- package/dist/components/form/SearchInput.d.ts +1 -1
- package/dist/components/form/SearchInput.js +1 -1
- package/dist/components/form/Select/CustomSelect.d.ts +1 -1
- package/dist/components/form/Select/CustomSelect.js +1 -1
- package/dist/components/form/Select/DetailedSelect.d.ts +1 -1
- package/dist/components/form/Select/DetailedSelect.js +1 -1
- package/dist/components/form/Select/Select.d.ts +1 -1
- package/dist/components/form/Select/Select.js +1 -1
- package/dist/components/form/Select/styled.js +161 -161
- package/dist/components/form/Select/utils.js +1 -1
- package/dist/components/notification/NotificationComponent.d.ts +1 -1
- package/dist/components/notification/NotificationComponent.js +54 -54
- package/dist/components/notification/NotificationItem.d.ts +1 -1
- package/dist/components/notification/NotificationItem.d.ts.map +1 -1
- package/dist/components/notification/NotificationItem.js +4 -4
- package/dist/components/notification/NotificationItem.js.map +1 -1
- package/dist/components/notification/NotificationList.d.ts +1 -1
- package/dist/components/notification/NotificationList.js +43 -43
- package/dist/components/notification/NotificationPlaceholder.d.ts +1 -1
- package/dist/components/notification/NotificationPlaceholder.js +9 -9
- package/dist/components/notification/NotificationPlaceholder.js.map +1 -1
- package/dist/containers/NotificationsPage.d.ts +1 -1
- package/dist/containers/NotificationsPage.d.ts.map +1 -1
- package/dist/containers/NotificationsPage.js +24 -11
- package/dist/containers/NotificationsPage.js.map +1 -1
- package/dist/context/anchor.d.ts +1 -1
- package/dist/context/anchor.js +1 -1
- package/dist/context/loading.d.ts +1 -1
- package/dist/context/loading.js +1 -1
- package/dist/context/notification/context.d.ts +1 -1
- package/dist/context/notification/context.js +1 -1
- package/dist/context/notification/types.d.ts +1 -0
- package/dist/context/notification/types.d.ts.map +1 -1
- package/dist/hooks/date.js +1 -1
- package/dist/hooks/service-now.js +28 -28
- package/dist/svg/AI.d.ts +1 -1
- package/dist/svg/AI.js +1 -1
- package/dist/svg/CS.d.ts +1 -1
- package/dist/svg/CS.js +1 -1
- package/dist/svg/EDP.d.ts +1 -1
- package/dist/svg/EDP.js +1 -1
- package/dist/svg/Forbidden.d.ts +1 -1
- package/dist/svg/Forbidden.js +1 -1
- package/dist/svg/GenericPlaceholder.d.ts +1 -1
- package/dist/svg/GenericPlaceholder.js +1 -1
- package/dist/svg/HUB.d.ts +1 -1
- package/dist/svg/HUB.js +1 -1
- package/dist/svg/Logo.d.ts +1 -1
- package/dist/svg/Logo.js +1 -1
- package/dist/svg/MiniLogo.d.ts +1 -1
- package/dist/svg/MiniLogo.js +1 -1
- package/dist/svg/NotFound.d.ts +1 -1
- package/dist/svg/NotFound.js +1 -1
- package/dist/svg/ServerError.d.ts +1 -1
- package/dist/svg/ServerError.js +1 -1
- package/dist/svg/Unauthenticated.d.ts +1 -1
- package/dist/svg/Unauthenticated.js +1 -1
- package/package.json +80 -80
- package/readme.md +66 -66
- package/src/components/AnimatedHeight.tsx +174 -174
- package/src/components/AsyncContent.tsx +78 -78
- package/src/components/BannerWarning.tsx +91 -91
- package/src/components/Breadcrumb/index.tsx +76 -76
- package/src/components/Breadcrumb/styled.ts +37 -37
- package/src/components/ButtonLoading.tsx +29 -29
- package/src/components/ChatBot.tsx +82 -82
- package/src/components/ContentValidateFilter.tsx +15 -15
- package/src/components/FadingOverflow.tsx +265 -265
- package/src/components/FileTreeView/More.tsx +114 -114
- package/src/components/FileTreeView/index.tsx +186 -186
- package/src/components/InfiniteScroll.tsx +24 -24
- package/src/components/InfoMaintenanceBanner.tsx +29 -29
- package/src/components/LazyMarkdown/BlockquoteMd.tsx +107 -107
- package/src/components/LazyMarkdown/CodeViewer.tsx +161 -161
- package/src/components/LazyMarkdown/Markdown.tsx +122 -122
- package/src/components/LazyMarkdown/MarkdownButton.tsx +24 -24
- package/src/components/LazyMarkdown/Video.tsx +13 -13
- package/src/components/LazyMarkdown/index.tsx +21 -21
- package/src/components/Placeholder.tsx +118 -118
- package/src/components/ScrollView.tsx +57 -57
- package/src/components/Select/BadgeItem.tsx +58 -58
- package/src/components/Select/ClearInput.tsx +24 -24
- package/src/components/Select/CloseItem.tsx +38 -38
- package/src/components/Select/CreatableSelect.tsx +155 -155
- package/src/components/Select/CustomMenu.tsx +16 -16
- package/src/components/Select/LabelItem.tsx +8 -8
- package/src/components/Select/MultiValue.tsx +49 -49
- package/src/components/Select/SelectInfiniteScroll.tsx +82 -82
- package/src/components/Select/SelectSearch.tsx +195 -195
- package/src/components/Select/index.tsx +7 -7
- package/src/components/Select/types.ts +8 -8
- package/src/components/SelectionList.tsx +427 -427
- package/src/components/StatusCircle.tsx +67 -67
- package/src/components/Stepper/Navigation.tsx +97 -97
- package/src/components/Stepper/Step.tsx +30 -30
- package/src/components/Stepper/Stepper.tsx +113 -113
- package/src/components/Stepper/headers.tsx +64 -64
- package/src/components/Stepper/index.ts +3 -3
- package/src/components/Table/HeaderItem.tsx +52 -52
- package/src/components/Table/SettingsVerticalMenu.tsx +50 -50
- package/src/components/Table/StyledLinkTable.tsx +22 -22
- package/src/components/Table/TableData.tsx +251 -251
- package/src/components/Table/index.tsx +2 -2
- package/src/components/TimelineSection.tsx +66 -66
- package/src/components/error/ErrorFeedback.tsx +217 -217
- package/src/components/error/NotFound.tsx +24 -24
- package/src/components/error/UnderMaintenance.tsx +30 -30
- package/src/components/error/index.ts +4 -4
- package/src/components/form/Form/Form.tsx +101 -101
- package/src/components/form/Form/FormGroup.tsx +221 -221
- package/src/components/form/Form/index.ts +2 -2
- package/src/components/form/SearchInput.tsx +69 -69
- package/src/components/form/Select/CustomSelect.tsx +232 -232
- package/src/components/form/Select/DetailedSelect.tsx +85 -85
- package/src/components/form/Select/Select.tsx +67 -67
- package/src/components/form/Select/index.ts +4 -4
- package/src/components/form/Select/styled.ts +165 -165
- package/src/components/form/Select/types.ts +112 -112
- package/src/components/form/Select/utils.tsx +28 -28
- package/src/components/notification/NotificationComponent.tsx +340 -340
- package/src/components/notification/NotificationItem.tsx +337 -336
- package/src/components/notification/NotificationList.tsx +178 -178
- package/src/components/notification/NotificationPlaceholder.tsx +43 -43
- package/src/components/notification/types.ts +72 -72
- package/src/containers/NotificationsPage.tsx +119 -98
- package/src/context/anchor.tsx +37 -37
- package/src/context/loading.tsx +36 -36
- package/src/context/notification/LazyNotificationList.ts +103 -103
- package/src/context/notification/NotificationController.ts +104 -104
- package/src/context/notification/context.tsx +23 -23
- package/src/context/notification/hooks.ts +98 -98
- package/src/context/notification/types.ts +66 -65
- package/src/hooks/date.ts +31 -31
- package/src/hooks/keyboard.tsx +128 -128
- package/src/hooks/manual-render.tsx +10 -10
- package/src/hooks/service-now.tsx +233 -233
- package/src/hooks/text.tsx +30 -30
- package/src/hooks/title.tsx +28 -28
- package/src/hooks/use-effect-once.tsx +43 -43
- package/src/index.ts +19 -19
- package/src/notifications.ts +11 -11
- package/src/svg/AI.tsx +41 -41
- package/src/svg/CS.tsx +48 -48
- package/src/svg/EDP.tsx +31 -31
- package/src/svg/Forbidden.tsx +22 -22
- package/src/svg/GenericPlaceholder.tsx +20 -20
- package/src/svg/HUB.tsx +48 -48
- package/src/svg/Logo.tsx +16 -16
- package/src/svg/MiniLogo.tsx +12 -12
- package/src/svg/NotFound.tsx +16 -16
- package/src/svg/ServerError.tsx +33 -33
- package/src/svg/Unauthenticated.tsx +16 -16
- package/src/svg/index.ts +11 -11
- package/src/utils/accessibility.ts +135 -135
- package/src/utils/cookie.ts +73 -73
- package/src/utils/promise.ts +5 -5
- package/src/utils/read-file.ts +16 -16
- package/tsconfig.json +10 -10
|
@@ -1,340 +1,340 @@
|
|
|
1
|
-
import { Box, Button, Flex, IconBox, Text } from '@citric/core'
|
|
2
|
-
import { Bell, TimesMini } from '@citric/icons'
|
|
3
|
-
import { IconButton } from '@citric/ui'
|
|
4
|
-
import { listToClass, theme } from '@stack-spot/portal-theme'
|
|
5
|
-
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
6
|
-
import { ReactElement, useLayoutEffect, useRef, useState } from 'react'
|
|
7
|
-
import styled from 'styled-components'
|
|
8
|
-
import { AsyncContent, ErrorProps } from '../AsyncContent'
|
|
9
|
-
import { InfiniteScroll } from '../InfiniteScroll'
|
|
10
|
-
import { ScrollView } from '../ScrollView'
|
|
11
|
-
import { StatusCircle } from '../StatusCircle'
|
|
12
|
-
import { NotificationItem } from './NotificationItem'
|
|
13
|
-
import { GetTenantNotificationsResponse, NotificationTypeFilters, UnreadType } from './types'
|
|
14
|
-
|
|
15
|
-
interface Props {
|
|
16
|
-
hasUnreadNotification?: boolean,
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const ANIMATION_DURATION_MS = 300
|
|
20
|
-
const MAX_HEIGHT_TRANSITION = `max-height ease-in ${ANIMATION_DURATION_MS / 1000}s`
|
|
21
|
-
|
|
22
|
-
const NotificationsComponent = styled.div<{ $scroll?: boolean }>`
|
|
23
|
-
max-height: 0;
|
|
24
|
-
z-index: 2;
|
|
25
|
-
visibility: hidden;
|
|
26
|
-
position: absolute;
|
|
27
|
-
top: calc(var(--header-height) + 4px);
|
|
28
|
-
right: -270%;
|
|
29
|
-
opacity: 0;
|
|
30
|
-
width: 400px;
|
|
31
|
-
transition: ${MAX_HEIGHT_TRANSITION}, opacity ${ANIMATION_DURATION_MS}ms ease-in-out, visibility 0s ${ANIMATION_DURATION_MS}ms;
|
|
32
|
-
|
|
33
|
-
&.visible {
|
|
34
|
-
visibility: visible;
|
|
35
|
-
min-height: 400px;
|
|
36
|
-
opacity: 1;
|
|
37
|
-
transition: ${MAX_HEIGHT_TRANSITION}, opacity ${ANIMATION_DURATION_MS}ms ease-in-out;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.content {
|
|
41
|
-
border-radius: 4px;
|
|
42
|
-
border: 1px solid ${theme.color.light[400]};
|
|
43
|
-
box-shadow: 4px 4px 48px ${theme.color.danger.contrastText};
|
|
44
|
-
background-color: ${theme.color.light[300]};
|
|
45
|
-
overflow-y: ${({ $scroll }) => ($scroll ? 'auto' : 'hidden')};
|
|
46
|
-
overflow-x: hidden;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
&::after {
|
|
50
|
-
content: '';
|
|
51
|
-
position: absolute;
|
|
52
|
-
border-width: 8px 32px;
|
|
53
|
-
border-style: solid;
|
|
54
|
-
border-color: transparent;
|
|
55
|
-
bottom: 100%;
|
|
56
|
-
left: 74%;
|
|
57
|
-
margin-left: -5px;
|
|
58
|
-
transform: rotate(180deg);
|
|
59
|
-
border-top-color: ${theme.color.light[400]};
|
|
60
|
-
}
|
|
61
|
-
`
|
|
62
|
-
|
|
63
|
-
const Overlay = styled.div`
|
|
64
|
-
position: fixed;
|
|
65
|
-
top: 0;
|
|
66
|
-
left: 0;
|
|
67
|
-
width: 100%;
|
|
68
|
-
height: 100%;
|
|
69
|
-
background-color: ${theme.color.primary.contrastText};
|
|
70
|
-
opacity: 0.6;
|
|
71
|
-
z-index: 1;
|
|
72
|
-
`
|
|
73
|
-
|
|
74
|
-
const StyledBox = styled(Box)`
|
|
75
|
-
width: 100%;
|
|
76
|
-
> div:first-child{
|
|
77
|
-
width: 100%;
|
|
78
|
-
}
|
|
79
|
-
`
|
|
80
|
-
|
|
81
|
-
interface NotificationsFilterProps {
|
|
82
|
-
type?: NotificationTypeFilters,
|
|
83
|
-
onChangeFilterType: (type?: NotificationTypeFilters) => void,
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
interface NotificationFilterButtonProps extends NotificationsFilterProps {
|
|
87
|
-
ariaLabel: string,
|
|
88
|
-
label: string,
|
|
89
|
-
enumType: NotificationTypeFilters,
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* NotificationFilterButton component that renders a button to be used in quick filters for notifications.
|
|
94
|
-
*
|
|
95
|
-
* @param props the component's props {@link NotificationFilterButtonProps}.
|
|
96
|
-
*/
|
|
97
|
-
const NotificationFilterButton = (props: NotificationFilterButtonProps) => {
|
|
98
|
-
const { type, onChangeFilterType, ariaLabel, label, enumType } = props
|
|
99
|
-
return (<Button
|
|
100
|
-
appearance="text"
|
|
101
|
-
role="button"
|
|
102
|
-
aria-label={ariaLabel}
|
|
103
|
-
aria-pressed={type === enumType}
|
|
104
|
-
onClick={() => onChangeFilterType(enumType)}
|
|
105
|
-
sx={{ borderColor: type === enumType ? 'primary' : 'transparent' }}
|
|
106
|
-
>
|
|
107
|
-
<Text colorScheme="inverse" appearance="microtext1">
|
|
108
|
-
{label}
|
|
109
|
-
</Text>
|
|
110
|
-
</Button>
|
|
111
|
-
)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* NotificationsFilter component that renders the filter options for notifications.
|
|
116
|
-
*
|
|
117
|
-
* @param props the component's props {@link NotificationsFilterProps}.
|
|
118
|
-
*/
|
|
119
|
-
const NotificationsFilter = ({ type, onChangeFilterType }: NotificationsFilterProps) => {
|
|
120
|
-
const t = useTranslate(dictionary)
|
|
121
|
-
|
|
122
|
-
return (<Flex alignItems="center" sx={{ gap: '4px' }} my="5">
|
|
123
|
-
<Button
|
|
124
|
-
aria-pressed={!type}
|
|
125
|
-
appearance="text"
|
|
126
|
-
role="button"
|
|
127
|
-
aria-label={t.filterAll}
|
|
128
|
-
onClick={() => onChangeFilterType()}
|
|
129
|
-
sx={{ borderColor: !type ? 'primary' : 'transparent' }}
|
|
130
|
-
>
|
|
131
|
-
<Text colorScheme="inverse" appearance="microtext1">
|
|
132
|
-
{t.all}
|
|
133
|
-
</Text>
|
|
134
|
-
</Button>
|
|
135
|
-
<NotificationFilterButton
|
|
136
|
-
type={type} onChangeFilterType={onChangeFilterType}
|
|
137
|
-
ariaLabel={t.filterUnread} label={t.unread} enumType={UnreadType.Unread}
|
|
138
|
-
/>
|
|
139
|
-
<NotificationFilterButton
|
|
140
|
-
type={type} onChangeFilterType={onChangeFilterType}
|
|
141
|
-
ariaLabel={t.filterHigh} label={t.high} enumType={'HIGH'}
|
|
142
|
-
/>
|
|
143
|
-
<NotificationFilterButton
|
|
144
|
-
type={type} onChangeFilterType={onChangeFilterType}
|
|
145
|
-
ariaLabel={t.filterMedium} label={t.medium} enumType={'MEDIUM'}
|
|
146
|
-
/>
|
|
147
|
-
<NotificationFilterButton
|
|
148
|
-
type={type} onChangeFilterType={onChangeFilterType}
|
|
149
|
-
ariaLabel={t.filterLow} label={t.low} enumType={'LOW'}
|
|
150
|
-
/>
|
|
151
|
-
</Flex>)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
interface Props {
|
|
155
|
-
onMarkAsReadUnread: (notificationId: string, read: boolean, type: 'callToAction' | 'icon') => void,
|
|
156
|
-
notifications?: GetTenantNotificationsResponse[],
|
|
157
|
-
isLoading: boolean,
|
|
158
|
-
error?: any,
|
|
159
|
-
onClickViewNotifications: () => void,
|
|
160
|
-
onClickViewAll: () => void,
|
|
161
|
-
errorDetails: ErrorProps,
|
|
162
|
-
fetchNextPage: () => void,
|
|
163
|
-
hasNextPage: boolean,
|
|
164
|
-
type?: NotificationTypeFilters,
|
|
165
|
-
onUpdateType: (updatedType?: NotificationTypeFilters) => void,
|
|
166
|
-
placeholderComponent: ReactElement,
|
|
167
|
-
isSummary: boolean,
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// fixme: remove this component in the next major
|
|
171
|
-
/**
|
|
172
|
-
* NotificationComponent component that renders the notifications panel.
|
|
173
|
-
* It renders the notification icon and when clicked the notification modal is opened.
|
|
174
|
-
*
|
|
175
|
-
* @param props the component's props {@link Props}.
|
|
176
|
-
* @deprecated this functionality has been moved to the Layout library. This is now a property of the Header.
|
|
177
|
-
*/
|
|
178
|
-
export const NotificationComponent = ({
|
|
179
|
-
hasUnreadNotification, onMarkAsReadUnread, notifications, isLoading, error,
|
|
180
|
-
type, onUpdateType,
|
|
181
|
-
onClickViewNotifications, onClickViewAll, errorDetails, fetchNextPage, hasNextPage,
|
|
182
|
-
placeholderComponent, isSummary = false,
|
|
183
|
-
}: Props) => {
|
|
184
|
-
const t = useTranslate(dictionary)
|
|
185
|
-
const [visible, setVisible] = useState(false)
|
|
186
|
-
const seeAllButtonRef = useRef<HTMLButtonElement>(null)
|
|
187
|
-
|
|
188
|
-
const updateType = (updatedType?: NotificationTypeFilters) => {
|
|
189
|
-
onUpdateType(updatedType)
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
useLayoutEffect(() => {
|
|
193
|
-
const handleKeyDown = (event: KeyboardEvent) => {
|
|
194
|
-
if (event.key === 'Escape') {
|
|
195
|
-
const focusedElement = document.activeElement
|
|
196
|
-
const notificationItems = document.querySelectorAll('[id^="notificationItem-"]')
|
|
197
|
-
let isFocusedOnNotificationItem = false
|
|
198
|
-
|
|
199
|
-
notificationItems.forEach((item) => {
|
|
200
|
-
if (item.contains(focusedElement)) {
|
|
201
|
-
isFocusedOnNotificationItem = true
|
|
202
|
-
}
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
if (isFocusedOnNotificationItem) {
|
|
206
|
-
seeAllButtonRef?.current?.focus()
|
|
207
|
-
} else {
|
|
208
|
-
setVisible(false)
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
document.addEventListener('keydown', handleKeyDown)
|
|
214
|
-
|
|
215
|
-
return () => {
|
|
216
|
-
document.removeEventListener('keydown', handleKeyDown)
|
|
217
|
-
}
|
|
218
|
-
}, [])
|
|
219
|
-
|
|
220
|
-
return (<Flex sx={{ position: 'relative' }}>
|
|
221
|
-
<IconButton aria-label={t.openNotifications} onClick={() => {
|
|
222
|
-
onClickViewNotifications()
|
|
223
|
-
setVisible(!visible)
|
|
224
|
-
}} sx={{ border: 'none', bg: 'transparent' }} aria-expanded={visible}>
|
|
225
|
-
<IconBox size="md"
|
|
226
|
-
className="notificationsTour" >
|
|
227
|
-
<Bell />
|
|
228
|
-
</IconBox>
|
|
229
|
-
</IconButton>
|
|
230
|
-
{hasUnreadNotification && <Box sx={{ position: 'absolute', right: '2px' }} aria-label={t.hasUnread}>
|
|
231
|
-
<StatusCircle status={'danger'} />
|
|
232
|
-
</Box>}
|
|
233
|
-
|
|
234
|
-
{visible && <Overlay onClick={() => setVisible(false)} />}
|
|
235
|
-
|
|
236
|
-
<NotificationsComponent
|
|
237
|
-
className={listToClass(['notification-list', visible ? 'visible' : undefined])}
|
|
238
|
-
$scroll={true}
|
|
239
|
-
aria-hidden={!visible}
|
|
240
|
-
>
|
|
241
|
-
<Flex className="content" p={5} flexDirection="column" justifyContent="space-between">
|
|
242
|
-
<Flex w="100%">
|
|
243
|
-
<Flex justifyContent="space-between" w="100%" >
|
|
244
|
-
<Text appearance="h4">
|
|
245
|
-
{t.notifications}
|
|
246
|
-
</Text>
|
|
247
|
-
<IconButton onClick={() => setVisible(false)} aria-label={t.close}>
|
|
248
|
-
<IconBox size="xs">
|
|
249
|
-
<TimesMini />
|
|
250
|
-
</IconBox>
|
|
251
|
-
</IconButton>
|
|
252
|
-
</Flex>
|
|
253
|
-
|
|
254
|
-
<NotificationsFilter type={type} onChangeFilterType={updateType} />
|
|
255
|
-
<AsyncContent error={error} errorDetails={errorDetails} loading={isLoading}>
|
|
256
|
-
{notifications?.length ? <StyledBox>
|
|
257
|
-
<ScrollView id="scrollableNotifications" direction="vertical" style={{ maxHeight: 'calc(100vh - 300px)' }}>
|
|
258
|
-
<InfiniteScroll
|
|
259
|
-
dataLength={notifications?.length || 0}
|
|
260
|
-
next={fetchNextPage}
|
|
261
|
-
hasMore={hasNextPage}
|
|
262
|
-
scrollableTarget="scrollableNotifications"
|
|
263
|
-
>
|
|
264
|
-
<Flex sx={{ gap: '4px' }} mr="3" flexDirection="column">
|
|
265
|
-
{notifications?.map((item, index) => (
|
|
266
|
-
<NotificationItem
|
|
267
|
-
key={item.id}
|
|
268
|
-
notification={item}
|
|
269
|
-
id={`notificationItem-${index}`}
|
|
270
|
-
isSummary={isSummary}
|
|
271
|
-
onClickMarkReadUnread={(read, type) => onMarkAsReadUnread(item.id, read, type)}
|
|
272
|
-
/>
|
|
273
|
-
))}
|
|
274
|
-
</Flex>
|
|
275
|
-
</InfiniteScroll>
|
|
276
|
-
</ScrollView>
|
|
277
|
-
</StyledBox>
|
|
278
|
-
:
|
|
279
|
-
<>
|
|
280
|
-
{placeholderComponent}
|
|
281
|
-
</>
|
|
282
|
-
}
|
|
283
|
-
</AsyncContent>
|
|
284
|
-
</Flex>
|
|
285
|
-
|
|
286
|
-
<Flex w="100%" pt={3}>
|
|
287
|
-
<Button
|
|
288
|
-
ref={seeAllButtonRef}
|
|
289
|
-
size="sm"
|
|
290
|
-
sx={{ width: '100%' }} colorScheme="inverse" appearance="text"
|
|
291
|
-
onClick={() => {
|
|
292
|
-
setVisible(false)
|
|
293
|
-
onClickViewAll()
|
|
294
|
-
}}>
|
|
295
|
-
<Text appearance="microtext1">
|
|
296
|
-
{t.viewAll}
|
|
297
|
-
</Text>
|
|
298
|
-
</Button>
|
|
299
|
-
</Flex>
|
|
300
|
-
</Flex>
|
|
301
|
-
</NotificationsComponent>
|
|
302
|
-
</Flex >)
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const dictionary = {
|
|
306
|
-
en: {
|
|
307
|
-
notifications: 'Notifications',
|
|
308
|
-
all: 'All',
|
|
309
|
-
filterAll: 'Filter all notifications',
|
|
310
|
-
filterUnread: 'Filter unread notifications',
|
|
311
|
-
filterHigh: 'Filter high notifications',
|
|
312
|
-
filterMedium: 'Filter medium notifications',
|
|
313
|
-
filterLow: 'Filter low notifications',
|
|
314
|
-
unread: 'Unread',
|
|
315
|
-
high: 'High',
|
|
316
|
-
medium: 'Medium',
|
|
317
|
-
low: 'Low',
|
|
318
|
-
viewAll: 'View all notifications',
|
|
319
|
-
openNotifications: 'View notifications',
|
|
320
|
-
hasUnread: 'Has Unread notifications',
|
|
321
|
-
close: 'Close',
|
|
322
|
-
},
|
|
323
|
-
pt: {
|
|
324
|
-
notifications: 'Notificações',
|
|
325
|
-
all: 'Todos',
|
|
326
|
-
filterAll: 'Filtrar todas as notificações ',
|
|
327
|
-
filterUnread: 'Filtrar notificações não lidas',
|
|
328
|
-
filterHigh: 'Filtrar notificações criticidade alta',
|
|
329
|
-
filterMedium: 'Filtrar notificações criticidade média',
|
|
330
|
-
filterLow: 'Filtrar notificações criticidade baixa',
|
|
331
|
-
unread: 'Não lidas',
|
|
332
|
-
high: 'Alto',
|
|
333
|
-
medium: 'Médio',
|
|
334
|
-
low: 'Baixo',
|
|
335
|
-
viewAll: 'Ver todas as notificações',
|
|
336
|
-
openNotifications: 'Visualizar notificações',
|
|
337
|
-
hasUnread: 'Existem notificações não lidas',
|
|
338
|
-
close: 'Fechar',
|
|
339
|
-
},
|
|
340
|
-
} satisfies Dictionary
|
|
1
|
+
import { Box, Button, Flex, IconBox, Text } from '@citric/core'
|
|
2
|
+
import { Bell, TimesMini } from '@citric/icons'
|
|
3
|
+
import { IconButton } from '@citric/ui'
|
|
4
|
+
import { listToClass, theme } from '@stack-spot/portal-theme'
|
|
5
|
+
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
6
|
+
import { ReactElement, useLayoutEffect, useRef, useState } from 'react'
|
|
7
|
+
import styled from 'styled-components'
|
|
8
|
+
import { AsyncContent, ErrorProps } from '../AsyncContent'
|
|
9
|
+
import { InfiniteScroll } from '../InfiniteScroll'
|
|
10
|
+
import { ScrollView } from '../ScrollView'
|
|
11
|
+
import { StatusCircle } from '../StatusCircle'
|
|
12
|
+
import { NotificationItem } from './NotificationItem'
|
|
13
|
+
import { GetTenantNotificationsResponse, NotificationTypeFilters, UnreadType } from './types'
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
hasUnreadNotification?: boolean,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const ANIMATION_DURATION_MS = 300
|
|
20
|
+
const MAX_HEIGHT_TRANSITION = `max-height ease-in ${ANIMATION_DURATION_MS / 1000}s`
|
|
21
|
+
|
|
22
|
+
const NotificationsComponent = styled.div<{ $scroll?: boolean }>`
|
|
23
|
+
max-height: 0;
|
|
24
|
+
z-index: 2;
|
|
25
|
+
visibility: hidden;
|
|
26
|
+
position: absolute;
|
|
27
|
+
top: calc(var(--header-height) + 4px);
|
|
28
|
+
right: -270%;
|
|
29
|
+
opacity: 0;
|
|
30
|
+
width: 400px;
|
|
31
|
+
transition: ${MAX_HEIGHT_TRANSITION}, opacity ${ANIMATION_DURATION_MS}ms ease-in-out, visibility 0s ${ANIMATION_DURATION_MS}ms;
|
|
32
|
+
|
|
33
|
+
&.visible {
|
|
34
|
+
visibility: visible;
|
|
35
|
+
min-height: 400px;
|
|
36
|
+
opacity: 1;
|
|
37
|
+
transition: ${MAX_HEIGHT_TRANSITION}, opacity ${ANIMATION_DURATION_MS}ms ease-in-out;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.content {
|
|
41
|
+
border-radius: 4px;
|
|
42
|
+
border: 1px solid ${theme.color.light[400]};
|
|
43
|
+
box-shadow: 4px 4px 48px ${theme.color.danger.contrastText};
|
|
44
|
+
background-color: ${theme.color.light[300]};
|
|
45
|
+
overflow-y: ${({ $scroll }) => ($scroll ? 'auto' : 'hidden')};
|
|
46
|
+
overflow-x: hidden;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&::after {
|
|
50
|
+
content: '';
|
|
51
|
+
position: absolute;
|
|
52
|
+
border-width: 8px 32px;
|
|
53
|
+
border-style: solid;
|
|
54
|
+
border-color: transparent;
|
|
55
|
+
bottom: 100%;
|
|
56
|
+
left: 74%;
|
|
57
|
+
margin-left: -5px;
|
|
58
|
+
transform: rotate(180deg);
|
|
59
|
+
border-top-color: ${theme.color.light[400]};
|
|
60
|
+
}
|
|
61
|
+
`
|
|
62
|
+
|
|
63
|
+
const Overlay = styled.div`
|
|
64
|
+
position: fixed;
|
|
65
|
+
top: 0;
|
|
66
|
+
left: 0;
|
|
67
|
+
width: 100%;
|
|
68
|
+
height: 100%;
|
|
69
|
+
background-color: ${theme.color.primary.contrastText};
|
|
70
|
+
opacity: 0.6;
|
|
71
|
+
z-index: 1;
|
|
72
|
+
`
|
|
73
|
+
|
|
74
|
+
const StyledBox = styled(Box)`
|
|
75
|
+
width: 100%;
|
|
76
|
+
> div:first-child{
|
|
77
|
+
width: 100%;
|
|
78
|
+
}
|
|
79
|
+
`
|
|
80
|
+
|
|
81
|
+
interface NotificationsFilterProps {
|
|
82
|
+
type?: NotificationTypeFilters,
|
|
83
|
+
onChangeFilterType: (type?: NotificationTypeFilters) => void,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
interface NotificationFilterButtonProps extends NotificationsFilterProps {
|
|
87
|
+
ariaLabel: string,
|
|
88
|
+
label: string,
|
|
89
|
+
enumType: NotificationTypeFilters,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* NotificationFilterButton component that renders a button to be used in quick filters for notifications.
|
|
94
|
+
*
|
|
95
|
+
* @param props the component's props {@link NotificationFilterButtonProps}.
|
|
96
|
+
*/
|
|
97
|
+
const NotificationFilterButton = (props: NotificationFilterButtonProps) => {
|
|
98
|
+
const { type, onChangeFilterType, ariaLabel, label, enumType } = props
|
|
99
|
+
return (<Button
|
|
100
|
+
appearance="text"
|
|
101
|
+
role="button"
|
|
102
|
+
aria-label={ariaLabel}
|
|
103
|
+
aria-pressed={type === enumType}
|
|
104
|
+
onClick={() => onChangeFilterType(enumType)}
|
|
105
|
+
sx={{ borderColor: type === enumType ? 'primary' : 'transparent' }}
|
|
106
|
+
>
|
|
107
|
+
<Text colorScheme="inverse" appearance="microtext1">
|
|
108
|
+
{label}
|
|
109
|
+
</Text>
|
|
110
|
+
</Button>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* NotificationsFilter component that renders the filter options for notifications.
|
|
116
|
+
*
|
|
117
|
+
* @param props the component's props {@link NotificationsFilterProps}.
|
|
118
|
+
*/
|
|
119
|
+
const NotificationsFilter = ({ type, onChangeFilterType }: NotificationsFilterProps) => {
|
|
120
|
+
const t = useTranslate(dictionary)
|
|
121
|
+
|
|
122
|
+
return (<Flex alignItems="center" sx={{ gap: '4px' }} my="5">
|
|
123
|
+
<Button
|
|
124
|
+
aria-pressed={!type}
|
|
125
|
+
appearance="text"
|
|
126
|
+
role="button"
|
|
127
|
+
aria-label={t.filterAll}
|
|
128
|
+
onClick={() => onChangeFilterType()}
|
|
129
|
+
sx={{ borderColor: !type ? 'primary' : 'transparent' }}
|
|
130
|
+
>
|
|
131
|
+
<Text colorScheme="inverse" appearance="microtext1">
|
|
132
|
+
{t.all}
|
|
133
|
+
</Text>
|
|
134
|
+
</Button>
|
|
135
|
+
<NotificationFilterButton
|
|
136
|
+
type={type} onChangeFilterType={onChangeFilterType}
|
|
137
|
+
ariaLabel={t.filterUnread} label={t.unread} enumType={UnreadType.Unread}
|
|
138
|
+
/>
|
|
139
|
+
<NotificationFilterButton
|
|
140
|
+
type={type} onChangeFilterType={onChangeFilterType}
|
|
141
|
+
ariaLabel={t.filterHigh} label={t.high} enumType={'HIGH'}
|
|
142
|
+
/>
|
|
143
|
+
<NotificationFilterButton
|
|
144
|
+
type={type} onChangeFilterType={onChangeFilterType}
|
|
145
|
+
ariaLabel={t.filterMedium} label={t.medium} enumType={'MEDIUM'}
|
|
146
|
+
/>
|
|
147
|
+
<NotificationFilterButton
|
|
148
|
+
type={type} onChangeFilterType={onChangeFilterType}
|
|
149
|
+
ariaLabel={t.filterLow} label={t.low} enumType={'LOW'}
|
|
150
|
+
/>
|
|
151
|
+
</Flex>)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
interface Props {
|
|
155
|
+
onMarkAsReadUnread: (notificationId: string, read: boolean, type: 'callToAction' | 'icon') => void,
|
|
156
|
+
notifications?: GetTenantNotificationsResponse[],
|
|
157
|
+
isLoading: boolean,
|
|
158
|
+
error?: any,
|
|
159
|
+
onClickViewNotifications: () => void,
|
|
160
|
+
onClickViewAll: () => void,
|
|
161
|
+
errorDetails: ErrorProps,
|
|
162
|
+
fetchNextPage: () => void,
|
|
163
|
+
hasNextPage: boolean,
|
|
164
|
+
type?: NotificationTypeFilters,
|
|
165
|
+
onUpdateType: (updatedType?: NotificationTypeFilters) => void,
|
|
166
|
+
placeholderComponent: ReactElement,
|
|
167
|
+
isSummary: boolean,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// fixme: remove this component in the next major
|
|
171
|
+
/**
|
|
172
|
+
* NotificationComponent component that renders the notifications panel.
|
|
173
|
+
* It renders the notification icon and when clicked the notification modal is opened.
|
|
174
|
+
*
|
|
175
|
+
* @param props the component's props {@link Props}.
|
|
176
|
+
* @deprecated this functionality has been moved to the Layout library. This is now a property of the Header.
|
|
177
|
+
*/
|
|
178
|
+
export const NotificationComponent = ({
|
|
179
|
+
hasUnreadNotification, onMarkAsReadUnread, notifications, isLoading, error,
|
|
180
|
+
type, onUpdateType,
|
|
181
|
+
onClickViewNotifications, onClickViewAll, errorDetails, fetchNextPage, hasNextPage,
|
|
182
|
+
placeholderComponent, isSummary = false,
|
|
183
|
+
}: Props) => {
|
|
184
|
+
const t = useTranslate(dictionary)
|
|
185
|
+
const [visible, setVisible] = useState(false)
|
|
186
|
+
const seeAllButtonRef = useRef<HTMLButtonElement>(null)
|
|
187
|
+
|
|
188
|
+
const updateType = (updatedType?: NotificationTypeFilters) => {
|
|
189
|
+
onUpdateType(updatedType)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
useLayoutEffect(() => {
|
|
193
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
194
|
+
if (event.key === 'Escape') {
|
|
195
|
+
const focusedElement = document.activeElement
|
|
196
|
+
const notificationItems = document.querySelectorAll('[id^="notificationItem-"]')
|
|
197
|
+
let isFocusedOnNotificationItem = false
|
|
198
|
+
|
|
199
|
+
notificationItems.forEach((item) => {
|
|
200
|
+
if (item.contains(focusedElement)) {
|
|
201
|
+
isFocusedOnNotificationItem = true
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
if (isFocusedOnNotificationItem) {
|
|
206
|
+
seeAllButtonRef?.current?.focus()
|
|
207
|
+
} else {
|
|
208
|
+
setVisible(false)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
document.addEventListener('keydown', handleKeyDown)
|
|
214
|
+
|
|
215
|
+
return () => {
|
|
216
|
+
document.removeEventListener('keydown', handleKeyDown)
|
|
217
|
+
}
|
|
218
|
+
}, [])
|
|
219
|
+
|
|
220
|
+
return (<Flex sx={{ position: 'relative' }}>
|
|
221
|
+
<IconButton aria-label={t.openNotifications} onClick={() => {
|
|
222
|
+
onClickViewNotifications()
|
|
223
|
+
setVisible(!visible)
|
|
224
|
+
}} sx={{ border: 'none', bg: 'transparent' }} aria-expanded={visible}>
|
|
225
|
+
<IconBox size="md"
|
|
226
|
+
className="notificationsTour" >
|
|
227
|
+
<Bell />
|
|
228
|
+
</IconBox>
|
|
229
|
+
</IconButton>
|
|
230
|
+
{hasUnreadNotification && <Box sx={{ position: 'absolute', right: '2px' }} aria-label={t.hasUnread}>
|
|
231
|
+
<StatusCircle status={'danger'} />
|
|
232
|
+
</Box>}
|
|
233
|
+
|
|
234
|
+
{visible && <Overlay onClick={() => setVisible(false)} />}
|
|
235
|
+
|
|
236
|
+
<NotificationsComponent
|
|
237
|
+
className={listToClass(['notification-list', visible ? 'visible' : undefined])}
|
|
238
|
+
$scroll={true}
|
|
239
|
+
aria-hidden={!visible}
|
|
240
|
+
>
|
|
241
|
+
<Flex className="content" p={5} flexDirection="column" justifyContent="space-between">
|
|
242
|
+
<Flex w="100%">
|
|
243
|
+
<Flex justifyContent="space-between" w="100%" >
|
|
244
|
+
<Text appearance="h4">
|
|
245
|
+
{t.notifications}
|
|
246
|
+
</Text>
|
|
247
|
+
<IconButton onClick={() => setVisible(false)} aria-label={t.close}>
|
|
248
|
+
<IconBox size="xs">
|
|
249
|
+
<TimesMini />
|
|
250
|
+
</IconBox>
|
|
251
|
+
</IconButton>
|
|
252
|
+
</Flex>
|
|
253
|
+
|
|
254
|
+
<NotificationsFilter type={type} onChangeFilterType={updateType} />
|
|
255
|
+
<AsyncContent error={error} errorDetails={errorDetails} loading={isLoading}>
|
|
256
|
+
{notifications?.length ? <StyledBox>
|
|
257
|
+
<ScrollView id="scrollableNotifications" direction="vertical" style={{ maxHeight: 'calc(100vh - 300px)' }}>
|
|
258
|
+
<InfiniteScroll
|
|
259
|
+
dataLength={notifications?.length || 0}
|
|
260
|
+
next={fetchNextPage}
|
|
261
|
+
hasMore={hasNextPage}
|
|
262
|
+
scrollableTarget="scrollableNotifications"
|
|
263
|
+
>
|
|
264
|
+
<Flex sx={{ gap: '4px' }} mr="3" flexDirection="column">
|
|
265
|
+
{notifications?.map((item, index) => (
|
|
266
|
+
<NotificationItem
|
|
267
|
+
key={item.id}
|
|
268
|
+
notification={item}
|
|
269
|
+
id={`notificationItem-${index}`}
|
|
270
|
+
isSummary={isSummary}
|
|
271
|
+
onClickMarkReadUnread={(read, type) => onMarkAsReadUnread(item.id, read, type)}
|
|
272
|
+
/>
|
|
273
|
+
))}
|
|
274
|
+
</Flex>
|
|
275
|
+
</InfiniteScroll>
|
|
276
|
+
</ScrollView>
|
|
277
|
+
</StyledBox>
|
|
278
|
+
:
|
|
279
|
+
<>
|
|
280
|
+
{placeholderComponent}
|
|
281
|
+
</>
|
|
282
|
+
}
|
|
283
|
+
</AsyncContent>
|
|
284
|
+
</Flex>
|
|
285
|
+
|
|
286
|
+
<Flex w="100%" pt={3}>
|
|
287
|
+
<Button
|
|
288
|
+
ref={seeAllButtonRef}
|
|
289
|
+
size="sm"
|
|
290
|
+
sx={{ width: '100%' }} colorScheme="inverse" appearance="text"
|
|
291
|
+
onClick={() => {
|
|
292
|
+
setVisible(false)
|
|
293
|
+
onClickViewAll()
|
|
294
|
+
}}>
|
|
295
|
+
<Text appearance="microtext1">
|
|
296
|
+
{t.viewAll}
|
|
297
|
+
</Text>
|
|
298
|
+
</Button>
|
|
299
|
+
</Flex>
|
|
300
|
+
</Flex>
|
|
301
|
+
</NotificationsComponent>
|
|
302
|
+
</Flex >)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const dictionary = {
|
|
306
|
+
en: {
|
|
307
|
+
notifications: 'Notifications',
|
|
308
|
+
all: 'All',
|
|
309
|
+
filterAll: 'Filter all notifications',
|
|
310
|
+
filterUnread: 'Filter unread notifications',
|
|
311
|
+
filterHigh: 'Filter high notifications',
|
|
312
|
+
filterMedium: 'Filter medium notifications',
|
|
313
|
+
filterLow: 'Filter low notifications',
|
|
314
|
+
unread: 'Unread',
|
|
315
|
+
high: 'High',
|
|
316
|
+
medium: 'Medium',
|
|
317
|
+
low: 'Low',
|
|
318
|
+
viewAll: 'View all notifications',
|
|
319
|
+
openNotifications: 'View notifications',
|
|
320
|
+
hasUnread: 'Has Unread notifications',
|
|
321
|
+
close: 'Close',
|
|
322
|
+
},
|
|
323
|
+
pt: {
|
|
324
|
+
notifications: 'Notificações',
|
|
325
|
+
all: 'Todos',
|
|
326
|
+
filterAll: 'Filtrar todas as notificações ',
|
|
327
|
+
filterUnread: 'Filtrar notificações não lidas',
|
|
328
|
+
filterHigh: 'Filtrar notificações criticidade alta',
|
|
329
|
+
filterMedium: 'Filtrar notificações criticidade média',
|
|
330
|
+
filterLow: 'Filtrar notificações criticidade baixa',
|
|
331
|
+
unread: 'Não lidas',
|
|
332
|
+
high: 'Alto',
|
|
333
|
+
medium: 'Médio',
|
|
334
|
+
low: 'Baixo',
|
|
335
|
+
viewAll: 'Ver todas as notificações',
|
|
336
|
+
openNotifications: 'Visualizar notificações',
|
|
337
|
+
hasUnread: 'Existem notificações não lidas',
|
|
338
|
+
close: 'Fechar',
|
|
339
|
+
},
|
|
340
|
+
} satisfies Dictionary
|