Skip to content

Commit

Permalink
[CORL-1150] Discussions Tab (#3050)
Browse files Browse the repository at this point in the history
* feat: Added Site.topStories edge

* feat: Added User.ongoingDiscussions edge

* connect discussions tab to relay

* style discussions tab

* add message if no ongoing discussions

* style site name in story row

* fix: make line-heights relative

* add custom class hooks

* feat: condition display based on feature flag

* add target attribute to story links

* fix: expose some featureFlags

* fix: fixed sorting

* fix: copy fixes

Co-authored-by: tessalt <tessathornton@gmail.com>
Co-authored-by: Chi Vinh Le <vinh@vinh.tech>
  • Loading branch information
3 people committed Jul 30, 2020
1 parent 9a9c92d commit dfdea2b
Show file tree
Hide file tree
Showing 25 changed files with 886 additions and 48 deletions.
10 changes: 9 additions & 1 deletion src/core/client/stream/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import {

import Comments from "../tabs/Comments";
import Configure from "../tabs/Configure";
import Discussions from "../tabs/Discussions";
import Profile from "../tabs/Profile";
import TabBarQuery from "./TabBarQuery";

import styles from "./App.css";

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

export interface AppProps {
activeTab: TabValue;
Expand All @@ -38,6 +39,13 @@ const App: FunctionComponent<AppProps> = (props) => {
>
<Comments />
</TabPane>
<TabPane
className={CLASSES.discussionsTabPane.$root}
tabID="DISCUSSIONS"
data-testid="current-tab-pane"
>
<Discussions />
</TabPane>
<TabPane
className={CLASSES.myProfileTabPane.$root}
tabID="PROFILE"
Expand Down
2 changes: 1 addition & 1 deletion src/core/client/stream/App/SetActiveTabMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { createMutationContainer, LOCAL_ID } from "coral-framework/lib/relay";
import { SetMainTabEvent } from "coral-stream/events";

export interface SetActiveTabInput {
tab: "COMMENTS" | "PROFILE" | "%future added value";
tab: "COMMENTS" | "PROFILE" | "DISCUSSIONS" | "%future added value";
}

export type SetActiveTabMutation = (input: SetActiveTabInput) => Promise<void>;
Expand Down
29 changes: 28 additions & 1 deletion src/core/client/stream/App/TabBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import { Icon, MatchMedia, Tab, TabBar } from "coral-ui/components/v2";

import styles from "./TabBar.css";

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

export interface Props {
activeTab: TabValue;
onTabClick: (tab: TabValue) => void;
showProfileTab: boolean;
showDiscussionsTab: boolean;
showConfigureTab: boolean;
mode: "%future added value" | "COMMENTS" | "QA" | null;
}
Expand Down Expand Up @@ -69,6 +70,31 @@ const AppTabBar: FunctionComponent<Props> = (props) => {
)}
</Tab>

{props.showDiscussionsTab && (
<Tab
className={cn(CLASSES.tabBar.discussions, {
[CLASSES.tabBar.activeTab]: props.activeTab === "DISCUSSIONS",
[styles.smallTab]: !matches,
})}
tabID="DISCUSSIONS"
variant="streamPrimary"
localizationId="general-tabBar-aria-discussions"
>
{matches ? (
<Localized id="general-tabBar-discussionsTab">
<span>Discussions</span>
</Localized>
) : (
<div>
<Icon size="lg">list_alt</Icon>
<Localized id="general-tabBar-discussionsTab">
<div className={styles.smallText}>Discussions</div>
</Localized>
</div>
)}
</Tab>
)}

{props.showProfileTab && (
<Tab
className={cn(CLASSES.tabBar.myProfile, {
Expand All @@ -93,6 +119,7 @@ const AppTabBar: FunctionComponent<Props> = (props) => {
)}
</Tab>
)}

{props.showConfigureTab && (
<Tab
className={cn(CLASSES.tabBar.configure, {
Expand Down
89 changes: 53 additions & 36 deletions src/core/client/stream/App/TabBarContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import React, { Component } from "react";
import React, { FunctionComponent, useCallback, useMemo } from "react";
import { graphql } from "react-relay";

import {
withFragmentContainer,
withLocalStateContainer,
} from "coral-framework/lib/relay";
import { GQLSTORY_MODE } from "coral-framework/schema";
import { GQLFEATURE_FLAG, GQLSTORY_MODE } from "coral-framework/schema";
import { Ability, can } from "coral-stream/permissions";

import { TabBarContainer_settings } from "coral-stream/__generated__/TabBarContainer_settings.graphql";
import { TabBarContainer_story } from "coral-stream/__generated__/TabBarContainer_story.graphql";
import { TabBarContainer_viewer as ViewerData } from "coral-stream/__generated__/TabBarContainer_viewer.graphql";
import { TabBarContainerLocal as Local } from "coral-stream/__generated__/TabBarContainerLocal.graphql";
import { TabBarContainer_viewer } from "coral-stream/__generated__/TabBarContainer_viewer.graphql";
import { TabBarContainerLocal } from "coral-stream/__generated__/TabBarContainerLocal.graphql";

import {
SetActiveTabInput,
Expand All @@ -21,43 +22,54 @@ import TabBar from "./TabBar";

interface Props {
story: TabBarContainer_story | null;
viewer: ViewerData | null;
local: Local;
settings: TabBarContainer_settings | null;
viewer: TabBarContainer_viewer | null;
local: TabBarContainerLocal;
setActiveTab: SetActiveTabMutation;
}

export class TabBarContainer extends Component<Props> {
private handleSetActiveTab = (tab: SetActiveTabInput["tab"]) => {
void this.props.setActiveTab({ tab });
};
export const TabBarContainer: FunctionComponent<Props> = ({
local: { activeTab },
viewer,
story,
settings,
setActiveTab,
}) => {
const handleSetActiveTab = useCallback(
(tab: SetActiveTabInput["tab"]) => {
void setActiveTab({ tab });
},
[setActiveTab]
);

public render() {
const {
local: { activeTab },
viewer,
story,
} = this.props;
const showDiscussionsTab = useMemo(
() =>
!!viewer &&
!!settings &&
settings.featureFlags.includes(GQLFEATURE_FLAG.DISCUSSIONS),
[viewer, settings]
);

return (
<TabBar
mode={
this.props.story
? this.props.story.settings.mode
: GQLSTORY_MODE.COMMENTS
}
activeTab={activeTab}
showProfileTab={Boolean(viewer)}
showConfigureTab={
!!viewer &&
!!story &&
story.canModerate &&
can(viewer, Ability.CHANGE_STORY_CONFIGURATION)
}
onTabClick={this.handleSetActiveTab}
/>
);
}
}
const showConfigureTab = useMemo(
() =>
!!viewer &&
!!story &&
story.canModerate &&
can(viewer, Ability.CHANGE_STORY_CONFIGURATION),
[viewer, story]
);

return (
<TabBar
mode={story ? story.settings.mode : GQLSTORY_MODE.COMMENTS}
activeTab={activeTab}
showProfileTab={!!viewer}
showDiscussionsTab={showDiscussionsTab}
showConfigureTab={showConfigureTab}
onTabClick={handleSetActiveTab}
/>
);
};

const enhanced = withSetActiveTabMutation(
withLocalStateContainer(
Expand All @@ -81,6 +93,11 @@ const enhanced = withSetActiveTabMutation(
}
}
`,
settings: graphql`
fragment TabBarContainer_settings on Settings {
featureFlags
}
`,
})(TabBarContainer)
)
);
Expand Down
4 changes: 4 additions & 0 deletions src/core/client/stream/App/TabBarQuery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class TabBarQuery extends Component<Props> {
story(id: $storyID, url: $storyURL) {
...TabBarContainer_story
}
settings {
...TabBarContainer_settings
}
}
`}
variables={{
Expand All @@ -41,6 +44,7 @@ class TabBarQuery extends Component<Props> {

return (
<TabBarContainer
settings={(props && props.settings) || null}
story={(props && props.story) || null}
viewer={(props && props.viewer) || null}
/>
Expand Down
7 changes: 7 additions & 0 deletions src/core/client/stream/App/__snapshots__/App.spec.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ exports[`renders correctly 1`] = `
>
<CommentsPane />
</TabPane>
<TabPane
className="coral coral-discussions"
data-testid="current-tab-pane"
tabID="DISCUSSIONS"
>
<withContext(withLocalStateContainer(DiscussionsQuery)) />
</TabPane>
<TabPane
className="coral coral-myProfile"
data-testid="current-tab-pane"
Expand Down
24 changes: 24 additions & 0 deletions src/core/client/stream/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ const CLASSES = {
*/
myProfile: "coral coral-tabBar-tab coral-tabBar-myProfile",

discussions: "coral coral-tabBar-tab coral-tabBar-discussions",

/**
* configure is the button for the "Configure" tab.
*/
Expand Down Expand Up @@ -714,6 +716,10 @@ const CLASSES = {
$root: "coral coral-myProfile",
},

discussionsTabPane: {
$root: "coral coral-discussions",
},

/**
* myUsername is the username part of my profile.
*/
Expand Down Expand Up @@ -981,6 +987,24 @@ const CLASSES = {
},

moderateStream: "coral coral-general-moderateStreamLink",

discussions: {
$root: "coral coral-discussions",
mostActiveDiscussions: "coral coral-mostActiveDiscussions",
myOngoingDiscussions: "coral coral-myOngoingDiscussions",
header: "coral coral-discussions-header",
subHeader: "coral coral-discussions-subHeader",
discussionsList: "coral coral-discussions-list",
story: {
$root: "coral coral-discussions-story",
header: "coral coral-discussions-story-header",
commentsCount: "coral coral-discussions-story-commentsCount",
commentsCountIcon: "coral coral-discussions-story-commentsCountIcon",
date: "coral coral-discussions-story-date",
siteName: "coral coral-discussions-story-siteName",
},
viewHistoryButton: "coral coral-discussions-viewHistoryButton",
},
};

export default CLASSES;
85 changes: 85 additions & 0 deletions src/core/client/stream/tabs/Discussions/DiscussionsContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Localized } from "@fluent/react/compat";
import React, { FunctionComponent, useCallback } from "react";
import { graphql } from "react-relay";

import {
createMutation,
useMutation,
withFragmentContainer,
} from "coral-framework/lib/relay";
import CLASSES from "coral-stream/classes";
import UserBoxContainer from "coral-stream/common/UserBox";
import { Button, HorizontalGutter } from "coral-ui/components/v2";

import { DiscussionsContainer_settings } from "coral-stream/__generated__/DiscussionsContainer_settings.graphql";
import { DiscussionsContainer_story } from "coral-stream/__generated__/DiscussionsContainer_story.graphql";
import { DiscussionsContainer_viewer } from "coral-stream/__generated__/DiscussionsContainer_viewer.graphql";

import { commit } from "../../App/SetActiveTabMutation";
import MostActiveDiscussionsContainer from "./MostActiveDiscussionsContainer";
import MyOngoingDiscussionsContainer from "./MyOngoingDiscussionsContainer";

interface Props {
viewer: DiscussionsContainer_viewer;
settings: DiscussionsContainer_settings;
story: DiscussionsContainer_story;
}

const SetActiveTabMutation = createMutation("setActiveTab", commit);

const DiscussionsContainer: FunctionComponent<Props> = (props) => {
const setActiveTab = useMutation(SetActiveTabMutation);
const onFullHistoryClick = useCallback(
async () => await setActiveTab({ tab: "PROFILE" }),
[]
);
return (
<HorizontalGutter spacing={3} className={CLASSES.discussions.$root}>
<UserBoxContainer settings={props.settings} viewer={props.viewer} />
<MostActiveDiscussionsContainer site={props.story.site} />
<MyOngoingDiscussionsContainer
viewer={props.viewer}
currentSiteID={props.story.site.id}
settings={props.settings}
/>
<Localized id="discussions-viewFullHistory">
<Button
variant="outline"
color="stream"
onClick={onFullHistoryClick}
className={CLASSES.discussions.viewHistoryButton}
>
View full comment history
</Button>
</Localized>
</HorizontalGutter>
);
};

const enhanced = withFragmentContainer<Props>({
story: graphql`
fragment DiscussionsContainer_story on Story {
site {
id
...MostActiveDiscussionsContainer_site
}
}
`,
viewer: graphql`
fragment DiscussionsContainer_viewer on User {
...MyOngoingDiscussionsContainer_viewer
...UserBoxContainer_viewer
}
`,
settings: graphql`
fragment DiscussionsContainer_settings on Settings {
...MyOngoingDiscussionsContainer_settings
...UserBoxContainer_settings
organization {
name
}
}
`,
})(DiscussionsContainer);

export default enhanced;
19 changes: 19 additions & 0 deletions src/core/client/stream/tabs/Discussions/DiscussionsHeader.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.root {
border-bottom: 2px solid var(--palette-grey-200);
padding-bottom: var(--spacing-2);
font-family: var(--font-family-primary);
}

.header {
font-weight: var(--font-weight-primary-bold);
font-size: var(--font-size-4);
line-height: 1;
color: var(--palette-text-900);
margin: 0;
}

.subHeader {
color: var(--palette-text-100);
font-size: var(--font-size-2);
line-height: 1.285;
}

0 comments on commit dfdea2b

Please sign in to comment.