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

Modals and DashAlert state #737

Merged
merged 16 commits into from
Mar 5, 2017
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
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
26 changes: 11 additions & 15 deletions src/universal/components/Dashboard/DashModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ const DashModal = (props) => {
isClosing,
onBackdropClick,
position,
modalContext,
modalLayout,
styles
} = props;
const backdropStyles = css(
styles.backdrop,
position && styles[position],
modalContext && styles[modalContext]
modalLayout && styles[modalLayout]
);
const modalStyles = css(
styles.modal,
Expand Down Expand Up @@ -47,17 +47,14 @@ DashModal.propTypes = {

// NOTE: Use 'fixed' to show over 'viewport'.
// Default styles use 'fixed' and 'viewport' values.
// Use 'absolute' to show over 'main'.
// Use 'absolute' to show over 'main' or 'mainHasNotificationBar'.
// SEE: ui.modalLayout for options

position: PropTypes.oneOf([
'absolute',
'fixed'
]),
modalContext: PropTypes.oneOf([
'main',
'meetingInProgress',
'viewport'
]),
modalLayout: PropTypes.oneOf(ui.modalLayout),
styles: PropTypes.object
};

Expand Down Expand Up @@ -107,19 +104,19 @@ const styleThunk = (theme, props) => ({
animationName: animateOut
},

viewport: {
left: 0
},

main: {
[ui.modalLayoutMain]: {
left: ui.dashSidebarWidth
},

meetingInProgress: {
[ui.modalLayoutMainWithBar]: {
left: ui.dashSidebarWidth,
top: ui.dashNotificationBarHeight
},

[ui.modalLayoutViewport]: {
left: 0
},

absolute: {
position: 'absolute'
},
Expand All @@ -137,7 +134,6 @@ const styleThunk = (theme, props) => ({
modal: {
background: '#fff',
border: `.125rem solid ${appTheme.palette.mid30a}`,
// boxShadow: `0 0 0 .25rem ${appTheme.palette.mid30a}, ${ui.modalBoxShadow}`,
boxShadow: ui.modalBoxShadow,
borderRadius: ui.modalBorderRadius,
padding: '1.25rem',
Expand Down
5 changes: 3 additions & 2 deletions src/universal/components/DashboardWrapper/DashboardWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import DashLayoutContainer from 'universal/containers/DashLayoutContainer/DashLa
import Helmet from 'react-helmet';

const DashboardWrapper = (props) => {
const {children, location, title} = props;
const {children, dispatch, location, title} = props;
return (
<DashLayoutContainer>
<DashLayoutContainer dispatch={dispatch}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont pass dispatch to containers, mapStateToProps gives it to em anyways

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ackernaut is this necessary?

<Helmet title={title}/>
<DashSidebar isUserSettings={title === 'User Settings'} location={location} />
{children}
Expand All @@ -16,6 +16,7 @@ const DashboardWrapper = (props) => {

DashboardWrapper.propTypes = {
children: PropTypes.any,
dispatch: PropTypes.func.isRequired,
location: PropTypes.string,
title: PropTypes.string
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {cashay} from 'cashay';
import DashLayout from 'universal/components/Dashboard/DashLayout';
import {TEAM} from 'universal/subscriptions/constants';
import {TRIAL_EXPIRES_SOON, TRIAL_EXPIRED} from 'universal/utils/constants';
import {notificationBarPresent} from 'universal/modules/notifications/ducks/notificationDuck';

const resolveActiveMeetings = (teams) => {
if (teams !== resolveActiveMeetings.teams) {
Expand Down Expand Up @@ -53,7 +54,8 @@ const mapStateToProps = (state) => {
activeMeetings: resolveActiveMeetings(teams),
tms: state.auth.obj.tms,
userId: state.auth.sub,
trialNotification
trialNotification,
hasNotificationBar: state.notifications.hasNotificationBar
};
};

Expand All @@ -69,11 +71,16 @@ export default class DashLayoutContainer extends Component {
static propTypes = {
activeMeetings: PropTypes.array,
children: PropTypes.any,
dispatch: PropTypes.func.isRequired,
tms: PropTypes.array,
trialNotification: PropTypes.object
// userId: PropTypes.string
};

componentWillMount() {
this.maybeSetBar(this.props);
}

componentDidMount() {
const {tms} = this.props;
subToAllTeams(tms);
Expand All @@ -84,12 +91,30 @@ export default class DashLayoutContainer extends Component {
if (this.props.tms !== nextProps.tms) {
subToAllTeams(nextProps.tms);
}
this.maybeSetBar(nextProps);
}

maybeSetBar(props) {
const {
activeMeetings,
trialNotification,
hasNotificationBar
} = props;
const shouldHaveBar = activeMeetings.length > 0 || trialNotification.type;
if (shouldHaveBar !== hasNotificationBar) {
this.props.dispatch(notificationBarPresent(shouldHaveBar));
}
};

render() {
const {activeMeetings, children, trialNotification} = this.props;
const {activeMeetings, children, dispatch, trialNotification} = this.props;
return (
<DashLayout activeMeetings={activeMeetings} children={children} trialNotification={trialNotification}/>
<DashLayout
activeMeetings={activeMeetings}
children={children}
dispatch={dispatch}
trialNotification={trialNotification}
/>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import HTML5Backend from 'react-dnd-html5-backend';
const NewTeam = (props) => {
const {dispatch, params: {newOrg}} = props;
return (
<DashboardWrapper title="User Dashboard">
<DashboardWrapper dispatch={dispatch} title="User Dashboard">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ackernaut can we get rid of this?

<NewTeamFormContainer dispatch={dispatch} newOrgRoute={Boolean(newOrg)}/>
</DashboardWrapper>
);
Expand Down
25 changes: 25 additions & 0 deletions src/universal/modules/notifications/ducks/notificationDuck.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const NOTIFICATION_BAR_PRESENT = 'notifications/NOTIFICATION_BAR_PRESENT';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does this bar appear? all dashboards? meeting? i think we may wanna refactor it into a dashboard duck. we already have an entity called notifications & having a notifications duck that doesnt pertain to it is gonna get confusing.


const initialState = {
hasNotificationBar: false
};

export default function reducer(state = initialState, action = {}) {
switch (action.type) {
case NOTIFICATION_BAR_PRESENT: {
return {
...state,
hasNotificationBar: action.payload.hasNotificationBar,
};
}
default:
return state;
}
}

export const notificationBarPresent = (hasNotificationBar) => ({
type: NOTIFICATION_BAR_PRESENT,
payload: {
hasNotificationBar
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import IconLink from 'universal/components/IconLink/IconLink';
import Type from 'universal/components/Type/Type';
import {withRouter} from 'react-router';
import portal from 'react-portal-hoc';
import ui from 'universal/styles/ui';

const MeetingInProgressModal = (props) => {
const {closeAfter, isClosing, teamId, teamName, router} = props;
const {closeAfter, isClosing, modalLayout, teamId, teamName, router} = props;
const handleClick = () => {
router.push(`/meeting/${teamId}`);
};
return (
<DashModal position="absolute" modalContext="meetingInProgress" isClosing={isClosing} closeAfter={closeAfter}>
<DashModal position="absolute" modalLayout={modalLayout} isClosing={isClosing} closeAfter={closeAfter}>
<Type align="center" bold marginBottom="1.5rem" scale="s7" colorPalette="cool">
Oh, hi there!
</Type>
Expand All @@ -36,6 +37,7 @@ const MeetingInProgressModal = (props) => {
MeetingInProgressModal.propTypes = {
closeAfter: PropTypes.number,
isClosing: PropTypes.bool,
modalLayout: PropTypes.oneOf(ui.modalLayout),
router: PropTypes.object,
teamId: PropTypes.string,
teamName: PropTypes.string
Expand Down
20 changes: 17 additions & 3 deletions src/universal/modules/teamDashboard/components/Team/Team.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {Link, withRouter} from 'react-router';
import DashboardAvatars from 'universal/components/DashboardAvatars/DashboardAvatars';
import MeetingInProgressModal from '../MeetingInProgressModal/MeetingInProgressModal';
import UnpaidTeamModalContainer from 'universal/modules/teamDashboard/containers/UnpaidTeamModal/UnpaidTeamModalContainer';
import ui from 'universal/styles/ui';

const faIconStyle = {
fontSize: '14px',
Expand Down Expand Up @@ -65,17 +66,29 @@ const settingsLinks = (teamId) => {
const initialValues = {teamName: ''};

const Team = (props) => {
const {children, router, team, teamMembers} = props;
const {children, hasNotificationBar, router, team, teamMembers} = props;
const {id: teamId, name: teamName, isPaid} = team;
const hasActiveMeeting = Boolean(team && team.meetingId);
const hasOverlay = hasActiveMeeting || !isPaid;
const isSettings = router.isActive(`/team/${teamId}/settings`, false);
initialValues.teamName = teamName;
const DashHeaderInfoTitle = isSettings ? <EditTeamName initialValues={initialValues} teamName={teamName} teamId={teamId}/> : teamName;
const modalLayout = hasNotificationBar ? ui.modalLayoutMainWithBar : ui.modalLayoutMain;
return (
<DashMain>
<MeetingInProgressModal isOpen={hasActiveMeeting} teamId={teamId} teamName={teamName} key={teamId}/>
<UnpaidTeamModalContainer isOpen={!isPaid} teamId={teamId} teamName={teamName}/>
<MeetingInProgressModal
isOpen={hasActiveMeeting}
modalLayout={modalLayout}
teamId={teamId}
teamName={teamName}
key={teamId}
/>
<UnpaidTeamModalContainer
isOpen={!isPaid}
teamId={teamId}
modalLayout={modalLayout}
teamName={teamName}
/>
<DashHeader hasOverlay={hasOverlay}>
<DashHeaderInfo title={DashHeaderInfoTitle}>
{isSettings ? settingsLinks(teamId) : standardLinks(teamId)}
Expand All @@ -91,6 +104,7 @@ const Team = (props) => {

Team.propTypes = {
children: PropTypes.any,
hasNotificationBar: PropTypes.bool,
router: PropTypes.object,
team: PropTypes.object.isRequired,
teamMembers: PropTypes.array.isRequired,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import React, {PropTypes} from 'react';
import {DashModal} from 'universal/components/Dashboard';
import IconLink from 'universal/components/IconLink/IconLink';
import Type from 'universal/components/Type/Type';
import ui from 'universal/styles/ui';

const UnpaidTeamModal = (props) => {
const {isClosing, closeAfter, problem, solution, isALeader, handleClick} = props;
const {isClosing, closeAfter, modalLayout, problem, solution, isALeader, handleClick} = props;
return (
<DashModal position="absolute" modalContext="main" isClosing={isClosing} closeAfter={closeAfter}>
<DashModal position="absolute" modalLayout={modalLayout} isClosing={isClosing} closeAfter={closeAfter}>
<Type align="center" bold marginBottom="1.5rem" scale="s7" colorPalette="cool">
Oh dear...
</Type>
Expand Down Expand Up @@ -35,6 +36,7 @@ UnpaidTeamModal.propTypes = {
handleClick: PropTypes.func,
isALeader: PropTypes.bool,
isClosing: PropTypes.bool,
modalLayout: PropTypes.oneOf(ui.modalLayout),
router: PropTypes.object,
orgId: PropTypes.string,
problem: PropTypes.string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ query {

const mapStateToProps = (state, props) => {
const {teamId} = props.params;
const {hasNotificationBar} = state.notifications;
const teamContainer = cashay.query(teamContainerSub, {
op: 'teamContainer',
key: teamId,
Expand All @@ -37,21 +38,23 @@ const mapStateToProps = (state, props) => {
});
const {team, teamMembers} = teamContainer.data;
return {
hasNotificationBar,
team,
teamMembers
};
};

const TeamContainer = (props) => {
const {children, team, teamMembers} = props;
const {children, dispatch, hasNotificationBar, team, teamMembers} = props;
const readyEnough = team.id;
return (
<DashboardWrapper title="Team Dashboard">
<DashboardWrapper dispatch={dispatch} title="Team Dashboard">
{readyEnough ?
<Team
children={children}
hasNotificationBar={hasNotificationBar}
team={team}
teamMembers={teamMembers}
children={children}
/> :
<LoadingView/>
}
Expand All @@ -61,6 +64,8 @@ const TeamContainer = (props) => {

TeamContainer.propTypes = {
children: PropTypes.any.isRequired,
dispatch: PropTypes.func.isRequired,
hasNotificationBar: PropTypes.bool,
team: PropTypes.object.isRequired,
teamMembers: PropTypes.array.isRequired,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@ import {DragDropContext as dragDropContext} from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';

const UserDashboard = (props) => {
const {children, location: {pathname}} = props;
const {children, dispatch, location: {pathname}} = props;
const title = pathname === '/me' ? 'User Dashboard' : 'User Settings';
return (
<DashboardWrapper location={pathname} title={title}>
<DashboardWrapper dispatch={dispatch} location={pathname} title={title}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

necessary?

{children}
</DashboardWrapper>
);
};

UserDashboard.propTypes = {
children: PropTypes.any,
dispatch: PropTypes.func.isRequired,
location: PropTypes.object
};

Expand Down
2 changes: 2 additions & 0 deletions src/universal/redux/makeReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {reducer as storageReducer} from 'redux-storage-whitelist-fn';
import storageMerger from 'universal/redux/storageMerger';
import makeRootReducer from 'universal/redux/rootDuck';
import menuReducer from 'universal/modules/menu/ducks/menuDuck';
import notificationReducer from 'universal/modules/notifications/ducks/notificationDuck';

const {SET_SUBMIT_SUCCEEDED} = actionTypes;

Expand Down Expand Up @@ -35,6 +36,7 @@ const appReducers = {
[DEFAULT_AUTH_REDUCER_NAME]: auth,
cashay: cashayReducer,
form: formReducer.plugin(formPlugin),
notifications: notificationReducer,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's refactor to 'dashboard' or something similar so we don't confuse the notification bar with notifications

menu: menuReducer,
toasts,
};
Expand Down
13 changes: 13 additions & 0 deletions src/universal/styles/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ const iconSizeAvatar = '21px'; // FontAwesome 1.5x
const iconSize2x = '28px'; // FontAwesome 2x
const iconSize3x = '42px'; // FontAwesome 3x

// Modals
const MODAL_LAYOUT_MAIN = 'main';
const MODAL_LAYOUT_MAIN_WITH_BAR = 'mainHasNotificationBar';
const MODAL_LAYOUT_VIEWPORT = 'viewport';

// Transitions
const transitionFastest = '100ms ease-in';
const transitionFaster = '200ms ease-in';
Expand Down Expand Up @@ -330,6 +335,14 @@ const ui = {
modalBorderRadius: borderRadiusLarge,
modalBoxShadow: '0 .25rem .5rem 0 rgba(0, 0, 0, .35)',
modalButtonSize: BUTTON_SIZE_MEDIUM,
modalLayoutMain: MODAL_LAYOUT_MAIN,
modalLayoutMainWithBar: MODAL_LAYOUT_MAIN_WITH_BAR,
modalLayoutViewport: MODAL_LAYOUT_VIEWPORT,
modalLayout: [
MODAL_LAYOUT_MAIN,
MODAL_LAYOUT_MAIN_WITH_BAR,
MODAL_LAYOUT_VIEWPORT
],

// Notifications
// ---------------------------------------------------------------------------
Expand Down