Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DSA Notifications #4376

Merged
merged 36 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
23e6633
create notifications collection and api resolver
nick-funk Oct 16, 2023
3b34ebd
create preliminary notifications tab
nick-funk Oct 17, 2023
b31f691
create preliminary notifications context
nick-funk Oct 18, 2023
0e0f441
rename logging function
nick-funk Oct 18, 2023
7236f07
post notifications for approve, reject, and feature
nick-funk Oct 18, 2023
b4cafca
create notification resolver
nick-funk Oct 18, 2023
c212ae4
define indices for notifications in INDEXES.md
nick-funk Oct 18, 2023
f4bbcfa
bring translations into notification context
nick-funk Oct 18, 2023
2148e7e
add optional title to notification models
nick-funk Oct 19, 2023
6c018c7
preliminarily style notifications
nick-funk Oct 19, 2023
b542c8b
show comment url in notifications with linked comment data
nick-funk Oct 19, 2023
b19296b
show the user box under notifications
nick-funk Oct 19, 2023
b168919
only show notifications tab if dsa features are enabled
nick-funk Oct 19, 2023
9441bf2
only show notifications tab in-stream when user is signed in
nick-funk Oct 19, 2023
2d5530c
style load more button for notifications paginations
nick-funk Oct 19, 2023
e107460
fix typo in creating approved comment notifications
nick-funk Oct 19, 2023
3106951
check if target user exists before creating notifications
nick-funk Oct 24, 2023
815b451
preliminarily hook up notification seen state resolvers
nick-funk Oct 24, 2023
00e7ddb
use bell icon for notifications
nick-funk Oct 25, 2023
310bedf
handle hasNewNotifications within the local relay state
nick-funk Oct 25, 2023
068cebd
update fixtures to handle new notification resolvers
nick-funk Oct 25, 2023
cd33c2b
preliminarily visualize seen state on notifications
nick-funk Oct 25, 2023
f182afb
use memo for notification seen state
nick-funk Oct 25, 2023
89608a2
add resolvers for DSA deports associated to a notification
nick-funk Oct 30, 2023
0071c52
add dsa notification details comments to schema
nick-funk Oct 30, 2023
a9ab148
update notification styles to better match figma designs
nick-funk Oct 30, 2023
da57277
add null/undefined check when setting lastSeenNotificationDate
nick-funk Oct 31, 2023
e9fcfc4
implement preliminary comment styling for stream notifications
nick-funk Nov 1, 2023
daa73ea
add title to notifications tab content area
nick-funk Nov 1, 2023
c879e5e
Merge branch 'feat/dsa-launch-pad' into feat/dsa-notifications
nick-funk Nov 2, 2023
c8cf99d
rename loader function for single DSA Report
nick-funk Nov 2, 2023
1f9b5d0
persist commentStatus onto notification
nick-funk Nov 2, 2023
990b952
rename `publicID` to `referenceID`
nick-funk Nov 3, 2023
13f8017
refactor notifications css for brevity
nick-funk Nov 6, 2023
14b6b1e
improve readability of lastSeenNotificationDate state logic
nick-funk Nov 6, 2023
2350c0b
allow DSA feature state be overridden by tests
nick-funk Nov 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions INDEXES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ The goal of this document is to date-mark the indexes you add to support the cha

If you are releasing, you can use this readme to check all the indexes prior to the release you are deploying and have a good idea of what indexes you might need to deploy to Mongo along with your release of a new Coral Docker image to kubernetes.

## 2023-10-18

```
db.notifications.createIndex({ tenantID: 1, id: 1 }, { unique: true });
```

- This index creates the uniqueness constraint for the `tenantID` and `id` fields on the notifications collection

```
db.notifications.createIndex({ tenantID: 1, ownerID: 1, createdAt: 1 });
```

- This index speeds up the retrieval of notifications by `tenantID`, `ownerID`, and `createdAt` which is the most common way of retrieving notifications for pagination in the notifications tab on the stream.

## 2023-03-28

```
Expand Down
12 changes: 12 additions & 0 deletions client/src/core/client/stream/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, { FunctionComponent } from "react";

import { useCoralContext } from "coral-framework/lib/bootstrap/CoralContext";
import CLASSES from "coral-stream/classes";
import NotificationsQuery from "coral-stream/tabs/Notifications/NotificationsQuery";
import { HorizontalGutter, TabContent, TabPane } from "coral-ui/components/v2";

import Comments from "../tabs/Comments";
Expand All @@ -18,10 +19,12 @@ type TabValue = "COMMENTS" | "PROFILE" | "DISCUSSIONS" | "%future added value";

export interface AppProps {
activeTab: TabValue;
dsaFeaturesEnabled: boolean;
}

const App: FunctionComponent<AppProps> = (props) => {
const { browserInfo } = useCoralContext();

return (
<Localized id="general-commentsEmbedSection" attrs={{ "aria-label": true }}>
<HorizontalGutter
Expand Down Expand Up @@ -68,6 +71,15 @@ const App: FunctionComponent<AppProps> = (props) => {
>
<Configure />
</TabPane>
{props.dsaFeaturesEnabled && (
<TabPane
className={CLASSES.notificationsTabPane.$root}
tabID="NOTIFICATIONS"
data-testid="current-tab-pane"
>
<NotificationsQuery />
</TabPane>
)}
</TabContent>
</div>
</HorizontalGutter>
Expand Down
14 changes: 8 additions & 6 deletions client/src/core/client/stream/App/AppContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,18 @@ interface Props {
}

const AppContainer: FunctionComponent<Props> = ({ disableListeners }) => {
const [{ activeTab }] = useLocal<AppContainerLocal>(graphql`
fragment AppContainerLocal on Local {
activeTab
}
`);
const [{ activeTab, dsaFeaturesEnabled }] =
useLocal<AppContainerLocal>(graphql`
fragment AppContainerLocal on Local {
activeTab
dsaFeaturesEnabled
}
`);
return (
<>
{disableListeners ? null : listeners}
<RefreshTokenHandler />
<App activeTab={activeTab} />
<App activeTab={activeTab} dsaFeaturesEnabled={!!dsaFeaturesEnabled} />
</>
);
};
Expand Down
9 changes: 5 additions & 4 deletions client/src/core/client/stream/App/TabBar.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
.smallTab {
padding-top: var(--spacing-3);
padding-bottom: var(--spacing-3);
padding-left: var(--spacing-3);
padding-right: var(--spacing-3);
padding: var(--spacing-3);
}

.condensedTab {
padding: var(--spacing-2);
}

.configureTab {
Expand Down
34 changes: 33 additions & 1 deletion client/src/core/client/stream/App/TabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import useGetMessage from "coral-framework/lib/i18n/useGetMessage";
import { GQLSTORY_MODE } from "coral-framework/schema";
import CLASSES from "coral-stream/classes";
import {
ActiveNotificationBellIcon,
CogIcon,
ConversationChatIcon,
ConversationQuestionWarningIcon,
MessagesBubbleSquareIcon,
NotificationBellIcon,
RatingStarIcon,
SingleNeutralCircleIcon,
SvgIcon,
Expand All @@ -17,14 +19,21 @@ import { MatchMedia, Tab, TabBar } from "coral-ui/components/v2";

import styles from "./TabBar.css";

type TabValue = "COMMENTS" | "PROFILE" | "DISCUSSIONS" | "%future added value";
type TabValue =
| "COMMENTS"
| "PROFILE"
| "DISCUSSIONS"
| "NOTIFICATIONS"
| "%future added value";

export interface Props {
activeTab: TabValue;
onTabClick: (tab: TabValue) => void;
showProfileTab: boolean;
showDiscussionsTab: boolean;
showConfigureTab: boolean;
showNotificationsTab: boolean;
hasNewNotifications: boolean;
mode:
| "COMMENTS"
| "QA"
Expand Down Expand Up @@ -155,6 +164,29 @@ const AppTabBar: FunctionComponent<Props> = (props) => {
)}
</Tab>
)}

{props.showNotificationsTab && (
<Tab
className={cn(CLASSES.tabBar.notifications, {
[CLASSES.tabBar.activeTab]: props.activeTab === "NOTIFICATIONS",
[styles.condensedTab]: matches,
[styles.smallTab]: !matches,
})}
tabID="NOTIFICATIONS"
variant="streamPrimary"
>
<div>
<SvgIcon
size="md"
Icon={
props.hasNewNotifications
? ActiveNotificationBellIcon
: NotificationBellIcon
}
></SvgIcon>
</div>
</Tab>
)}
</TabBar>
)}
</MatchMedia>
Expand Down
20 changes: 15 additions & 5 deletions client/src/core/client/stream/App/TabBarContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@ export const TabBarContainer: FunctionComponent<Props> = ({
settings,
setActiveTab,
}) => {
const [{ activeTab }] = useLocal<TabBarContainerLocal>(graphql`
fragment TabBarContainerLocal on Local {
activeTab
}
`);
const [{ activeTab, dsaFeaturesEnabled, hasNewNotifications }] =
useLocal<TabBarContainerLocal>(graphql`
fragment TabBarContainerLocal on Local {
activeTab
dsaFeaturesEnabled
hasNewNotifications
}
`);
const handleSetActiveTab = useCallback(
(tab: SetActiveTabInput["tab"]) => {
void setActiveTab({ tab });
Expand All @@ -59,13 +62,20 @@ export const TabBarContainer: FunctionComponent<Props> = ({
[viewer, story]
);

const showNotificationsTab = useMemo(
() => !!viewer && !!dsaFeaturesEnabled,
[viewer, dsaFeaturesEnabled]
);

return (
<TabBar
mode={story ? story.settings.mode : GQLSTORY_MODE.COMMENTS}
activeTab={activeTab}
showProfileTab={!!viewer}
showDiscussionsTab={showDiscussionsTab}
showConfigureTab={showConfigureTab}
showNotificationsTab={showNotificationsTab}
hasNewNotifications={!!hasNewNotifications}
onTabClick={handleSetActiveTab}
/>
);
Expand Down
23 changes: 17 additions & 6 deletions client/src/core/client/stream/App/TabBarQuery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,23 @@ import ErrorReporterSetUserContainer from "./ErrorReporterSetUserContainer";
import TabBarContainer from "./TabBarContainer";

const TabBarQuery: FunctionComponent = () => {
const [{ storyID, storyURL }] = useLocal<TabBarQueryLocal>(graphql`
fragment TabBarQueryLocal on Local {
storyID
storyURL
}
`);
const [{ storyID, storyURL, hasNewNotifications }, setLocal] =
useLocal<TabBarQueryLocal>(graphql`
fragment TabBarQueryLocal on Local {
storyID
storyURL
hasNewNotifications
}
`);

return (
<QueryRenderer<QueryTypes>
query={graphql`
query TabBarQuery($storyID: ID, $storyURL: String) {
viewer {
...TabBarContainer_viewer
...ErrorReporterSetUserContainer_viewer
hasNewNotifications
}
story(id: $storyID, url: $storyURL) {
...TabBarContainer_story
Expand All @@ -46,6 +50,13 @@ const TabBarQuery: FunctionComponent = () => {
<ErrorReporterSetUserContainer viewer={props.viewer} />
) : null;

if (hasNewNotifications === null) {
setLocal({
hasNewNotifications:
props && props.viewer ? props.viewer.hasNewNotifications : false,
});
}

return (
<>
{ErrorReporterSetUser}
Expand Down
6 changes: 6 additions & 0 deletions client/src/core/client/stream/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ const CLASSES = {
configure: "coral coral-tabBar-tab coral-tabBar-configure",

activeTab: "coral-tabBar-tab-active",

notifications: "coral coral-tabBar-tab coral-tabBar-notifications",
},

/**
Expand Down Expand Up @@ -142,6 +144,10 @@ const CLASSES = {
settings: "coral coral-tabBarSecondary-tab coral-tabBarMyProfile-settings",
},

tabBarNotifications: {
loadMore: "coral coral-tabBarNotifications-loadMore",
},

/**
* createComment is the comment creation box where a user can write a comment.
*/
Expand Down
2 changes: 2 additions & 0 deletions client/src/core/client/stream/local/initLocalState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,5 +179,7 @@ export const createInitLocalState: (options: Options) => InitLocalState =

const dsaFeaturesEnabled = staticConfig?.dsaFeaturesEnabled ?? false;
localRecord.setValue(dsaFeaturesEnabled, "dsaFeaturesEnabled");

localRecord.setValue(null, "hasNewNotifications");
});
};
2 changes: 2 additions & 0 deletions client/src/core/client/stream/local/local.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,6 @@ extend type Local {
refreshStream: Boolean

dsaFeaturesEnabled: Boolean

hasNewNotifications: Boolean
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.toggle {
padding: 0;
margin-bottom: var(--spacing-1);

border-style: none;

background-color: transparent;

color: var(--palette-primary-300);
font-family: var(--font-family-primary);
font-style: normal;
font-weight: var(--font-weight-primary-bold);
font-size: var(--font-size-2);

&:hover,
&.mouseHover {
color: var(--palette-primary-200);
}
&:active,
&.active {
color: var(--palette-primary-400);
}
}

.content {
border-left-style: solid;
border-left-width: 2px;
border-left-color: var(--palette-grey-400);

padding-left: var(--spacing-3);
}

.timestamp {
font-family: var(--font-family-primary);
font-style: normal;
font-weight: var(--font-weight-primary-semi-bold);
font-size: var(--font-size-2);
color: var(--palette-grey-500);
}

.storyTitle {
font-family: var(--font-family-primary);
font-style: normal;
font-weight: var(--font-weight-primary-semi-bold);
font-size: var(--font-size-2);
color: var(--palette-text-900);
}
Loading