style global activities

This commit is contained in:
zmagod 2017-08-22 13:20:06 +02:00
parent 685cb42aac
commit 3a2a1205e3
11 changed files with 190 additions and 54 deletions

View file

@ -4,6 +4,7 @@ export const GET_LIST_OF_TEAMS = "GET_LIST_OF_TEAMS";
// activities // activities
export const GLOBAL_ACTIVITIES_DATA = "GLOBAL_ACTIVITIES_DATA"; export const GLOBAL_ACTIVITIES_DATA = "GLOBAL_ACTIVITIES_DATA";
export const DESTROY_GLOBAL_ACTIVITIES_DATA = "DESTROY_GLOBAL_ACTIVITIES_DATA";
// users // users
export const SET_CURRENT_USER = "SET_CURRENT_USER"; export const SET_CURRENT_USER = "SET_CURRENT_USER";

View file

@ -3,3 +3,7 @@ export const WHITE_COLOR = "#fff";
export const BORDER_GRAY_COLOR = "#d2d2d2"; export const BORDER_GRAY_COLOR = "#d2d2d2";
export const WILD_SAND_COLOR = "#f5f5f5"; export const WILD_SAND_COLOR = "#f5f5f5";
export const MYSTIC_COLOR = "#eaeff2"; export const MYSTIC_COLOR = "#eaeff2";
export const COLOR_CONCRETE = "#f2f2f2";
export const COLOR_MINE_SHAFT = "#333"
export const COLOR_BLACK = "#000";
export const COLOR_GRAY_LIGHT_YADCF = "#ccc";

View file

@ -1,6 +1,9 @@
import axios from "../../app/axios"; import axios from "../../app/axios";
import { ACTIVITIES_PATH } from "../../app/routes"; import { ACTIVITIES_PATH } from "../../app/routes";
import { GLOBAL_ACTIVITIES_DATA } from "../../app/action_types"; import {
GLOBAL_ACTIVITIES_DATA,
DESTROY_GLOBAL_ACTIVITIES_DATA
} from "../../app/action_types";
function addActivitiesData(data) { function addActivitiesData(data) {
return { return {
@ -9,9 +12,15 @@ function addActivitiesData(data) {
}; };
} }
export function getActivities(last_id = 0) { export function destroyActivities() {
return {
type: DESTROY_GLOBAL_ACTIVITIES_DATA
};
}
export function getActivities(lastId = 0) {
return dispatch => { return dispatch => {
let path = `${ACTIVITIES_PATH}?from=${last_id}`; const path = `${ACTIVITIES_PATH}?from=${lastId}`;
axios axios
.get(path, { withCredentials: true }) .get(path, { withCredentials: true })
.then(response => { .then(response => {

View file

@ -1,11 +1,34 @@
import React from "react"; import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { FormattedDate } from "react-intl"; import Moment from "react-moment";
import styled from "styled-components";
import { WHITE_COLOR } from "../../../app/constants/colors"
const StyledLi = styled.li`
margin-bottom: 1em;
`
const StyledSpan = styled.span`
display: inline;
padding: 5px 30px;
font-size: 1em;
font-weight: bold;
line-height: 1;
color: ${WHITE_COLOR};
white-space: nowrap;
vertical-align: baseline;
border-radius: .25em;
`;
const ActivityDateElement = ({ date }) => const ActivityDateElement = ({ date }) =>
<li className="data-element"> <StyledLi className="text-center">
<FormattedDate value={date} day="2-digit" month="2-digit" year="numeric" /> <StyledSpan className="label label-primary">
</li>; <Moment format="DD.MM.YYYY">
{date}
</Moment>
</StyledSpan>
</StyledLi>;
ActivityDateElement.propTypes = { ActivityDateElement.propTypes = {
date: PropTypes.instanceOf(Date).isRequired date: PropTypes.instanceOf(Date).isRequired

View file

@ -1,24 +1,54 @@
import React from "react"; import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { FormattedTime } from "react-intl"; import Moment from "react-moment";
import styled from "styled-components";
import {
WHITE_COLOR,
COLOR_CONCRETE,
BORDER_GRAY_COLOR
} from "../../../app/constants/colors";
const StyledLi = styled.li`
border-radius: .25em;
margin-bottom: 1em;
background-color: ${WHITE_COLOR};
border: 1px solid ${COLOR_CONCRETE};
`;
const TimeSpan = styled.span`
min-width: 150px;
display: table-cell;
vertical-align: middle;
border-top-left-radius: .25em;
border-bottom-left-radius: .25em;
border: 3px solid ${BORDER_GRAY_COLOR};
background-color: ${BORDER_GRAY_COLOR};
padding-left: 10px;
padding-right: 10px;
vertical-align: top;
`;
const TextSpan = styled.span`
display: table-cell;
padding: 3px 10px;
text-align: justify;
`
const ActivityElement = ({ activity }) => const ActivityElement = ({ activity }) =>
<li> <StyledLi>
<span> <TimeSpan>
<FormattedTime <Moment format="HH.mm">
value={activity.created_at} {activity.created_at}
hour="numeric" </Moment>
minute="numeric" </TimeSpan>
/> <TextSpan dangerouslySetInnerHTML={{ __html: activity.message }} />
</span> </StyledLi>;
<span dangerouslySetInnerHTML={{ __html: activity.message }} />
</li>;
ActivityElement.propTypes = { ActivityElement.propTypes = {
activity: PropTypes.shape({ activity: PropTypes.shape({
message: PropTypes.string.isRequired, message: PropTypes.string.isRequired,
created_at: PropTypes.string.isRequired created_at: PropTypes.string.isRequired
}) }).isRequired
}; };
export default ActivityElement; export default ActivityElement;

View file

@ -4,10 +4,46 @@ import PropTypes from "prop-types";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import { Modal, Button } from "react-bootstrap"; import { Modal, Button } from "react-bootstrap";
import _ from "lodash"; import _ from "lodash";
import styled from "styled-components";
import { getActivities } from "../../actions/ActivitiesActions"; import { getActivities } from "../../actions/ActivitiesActions";
import ActivityElement from "./ActivityElement"; import ActivityElement from "./ActivityElement";
import ActivityDateElement from "./ActivityDateElement"; import ActivityDateElement from "./ActivityDateElement";
import {
WHITE_COLOR,
COLOR_CONCRETE,
COLOR_MINE_SHAFT,
COLOR_GRAY_LIGHT_YADCF
} from "../../../app/constants/colors";
const StyledBottom = styled(Button)`
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
color: ${COLOR_MINE_SHAFT};
background-color: ${WHITE_COLOR};
border-color: ${COLOR_GRAY_LIGHT_YADCF};
`;
const StyledModalBody = styled(Modal.Body)`
background-color: ${COLOR_CONCRETE};
color: ${COLOR_MINE_SHAFT};;
`;
class GlobalActivitiesModal extends Component { class GlobalActivitiesModal extends Component {
constructor(props) { constructor(props) {
@ -52,13 +88,14 @@ class GlobalActivitiesModal extends Component {
addMoreButton() { addMoreButton() {
if (this.props.more) { if (this.props.more) {
return ( return (
<li> <li className="text-center">
<Button onClick={this.addMoreActivities}> <StyledBottom onClick={this.addMoreActivities}>
<FormattedMessage id="activities.more_activities" /> <FormattedMessage id="activities.more_activities" />
</Button> </StyledBottom>
</li> </li>
); );
} }
return "";
} }
render() { render() {
@ -69,12 +106,12 @@ class GlobalActivitiesModal extends Component {
<FormattedMessage id="activities.modal_title" /> <FormattedMessage id="activities.modal_title" />
</Modal.Title> </Modal.Title>
</Modal.Header> </Modal.Header>
<Modal.Body> <StyledModalBody>
<ul> <ul className="list-unstyled">
{this.displayActivities()} {this.displayActivities()}
{this.addMoreButton()} {this.addMoreButton()}
</ul> </ul>
</Modal.Body> </StyledModalBody>
<Modal.Footer> <Modal.Footer>
<Button onClick={this.props.onCloseModal}> <Button onClick={this.props.onCloseModal}>
<FormattedMessage id="general.close" /> <FormattedMessage id="general.close" />

View file

@ -8,7 +8,7 @@ import {
WHITE_COLOR, WHITE_COLOR,
BORDER_GRAY_COLOR BORDER_GRAY_COLOR
} from "../../app/constants/colors"; } from "../../app/constants/colors";
import { getActivities } from "../actions/ActivitiesActions"; import { getActivities, destroyActivities } from "../actions/ActivitiesActions";
import TeamSwitch from "./components/TeamSwitch"; import TeamSwitch from "./components/TeamSwitch";
import GlobalActivitiesModal from "./components/GlobalActivitiesModal"; import GlobalActivitiesModal from "./components/GlobalActivitiesModal";
import SearchDropdown from "./components/SearchDropdown"; import SearchDropdown from "./components/SearchDropdown";
@ -50,16 +50,29 @@ class Navigation extends Component {
} }
selectItemCallback(key, ev) { selectItemCallback(key, ev) {
if (key === 4) { switch (key) {
case 1:
window.location = "/";
break;
case 2:
window.location = "/protocols";
break;
case 3:
window.location = `/teams/${this.props.current_team.id}/repositories`;
break;
case 4:
ev.preventDefault(); ev.preventDefault();
this.setState({ showActivitesModal: !this.state.showActivitesModal }); this.setState({ showActivitesModal: !this.state.showActivitesModal });
// Call action creator to fetch activities from the server // Call action creator to fetch activities from the server
this.props.fetchActivities(); this.props.fetchActivities();
break;
default:
} }
} }
closeModalCallback() { closeModalCallback() {
this.setState({ showActivitesModal: false }); this.setState({ showActivitesModal: false });
this.props.destroyActivities();
} }
render() { render() {
@ -74,21 +87,16 @@ class Navigation extends Component {
</Navbar.Brand> </Navbar.Brand>
</Navbar.Header> </Navbar.Header>
<Nav> <Nav>
<NavItem onClick={() => (window.location = "/")}> <NavItem eventKey={1}>
<span className="glyphicon glyphicon-home" title="Home" /> <span className="glyphicon glyphicon-home" title="Home" />
</NavItem> </NavItem>
<NavItem onClick={() => (window.location = "/protocols")}> <NavItem eventKey={2}>
<span <span
className="glyphicon glyphicon-list-alt" className="glyphicon glyphicon-list-alt"
title="Protocol repositories" title="Protocol repositories"
/> />
</NavItem> </NavItem>
<NavItem <NavItem eventKey={3}>
eventKey={3}
onClick={() =>
(window.location = `/teams/${this.props.current_team
.id}/repositories`)}
>
<i <i
className="fa fa-cubes" className="fa fa-cubes"
aria-hidden="true" aria-hidden="true"
@ -121,6 +129,7 @@ class Navigation extends Component {
Navigation.propTypes = { Navigation.propTypes = {
fetchActivities: PropTypes.func.isRequired, fetchActivities: PropTypes.func.isRequired,
destroyActivities: PropTypes.func.isRequired,
current_team: PropTypes.shape({ current_team: PropTypes.shape({
id: PropTypes.number.isRequired, id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
@ -135,6 +144,9 @@ const mapStateToProps = ({ current_team }) => ({ current_team });
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
fetchActivities() { fetchActivities() {
dispatch(getActivities()); dispatch(getActivities());
},
destroyActivities() {
dispatch(destroyActivities());
} }
}); });

View file

@ -1,13 +1,13 @@
import { import {
GLOBAL_ACTIVITIES_DATA, GLOBAL_ACTIVITIES_DATA,
MORE_GLOBAL_ACTIVITIES DESTROY_GLOBAL_ACTIVITIES_DATA
} from "../../app/action_types"; } from "../../app/action_types";
export function globalActivities( const initialStateu = { more: true, activities: [] };
state = { more: true, activities: [] },
action export function globalActivities(state = initialStateu, action) {
) { switch (action.type) {
if (action.type === GLOBAL_ACTIVITIES_DATA) { case GLOBAL_ACTIVITIES_DATA:
return { return {
...state, ...state,
activities: [ activities: [
@ -16,6 +16,12 @@ export function globalActivities(
], ],
more: action.payload.global_activities.more more: action.payload.global_activities.more
}; };
} case DESTROY_GLOBAL_ACTIVITIES_DATA:
return {
...state,
...initialStateu
};
default:
return state; return state;
}
} }

View file

@ -6,3 +6,7 @@ body {
font-family: "Open Sans",Arial,Helvetica,sans-serif; font-family: "Open Sans",Arial,Helvetica,sans-serif;
font-size: 13px; font-size: 13px;
} }
.label-primary {
background-color: $color-theme-primary;
}

View file

@ -53,6 +53,7 @@
"glob": "^7.1.2", "glob": "^7.1.2",
"js-yaml": "^3.9.0", "js-yaml": "^3.9.0",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"moment": "^2.18.1",
"node-sass": "^4.5.3", "node-sass": "^4.5.3",
"path-complete-extname": "^0.1.0", "path-complete-extname": "^0.1.0",
"postcss-loader": "^2.0.6", "postcss-loader": "^2.0.6",
@ -65,6 +66,7 @@
"react-dom": "^15.6.1", "react-dom": "^15.6.1",
"react-intl": "^2.3.0", "react-intl": "^2.3.0",
"react-intl-redux": "^0.6.0", "react-intl-redux": "^0.6.0",
"react-moment": "^0.6.4",
"react-redux": "^5.0.5", "react-redux": "^5.0.5",
"react-router-bootstrap": "^0.24.2", "react-router-bootstrap": "^0.24.2",
"react-router-dom": "^4.1.2", "react-router-dom": "^4.1.2",

View file

@ -3596,6 +3596,10 @@ mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkd
dependencies: dependencies:
minimist "0.0.8" minimist "0.0.8"
moment@^2.18.1:
version "2.18.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f"
ms@2.0.0: ms@2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@ -4692,6 +4696,10 @@ react-intl@^2.3.0:
intl-relativeformat "^1.3.0" intl-relativeformat "^1.3.0"
invariant "^2.1.1" invariant "^2.1.1"
react-moment@^0.6.4:
version "0.6.4"
resolved "https://registry.yarnpkg.com/react-moment/-/react-moment-0.6.4.tgz#5e531d47ad7b0bff6f6b7175093e98659f5e667b"
react-overlays@^0.7.0: react-overlays@^0.7.0:
version "0.7.0" version "0.7.0"
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.7.0.tgz#531898ff566c7e5c7226ead2863b8cf9fbb5a981" resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.7.0.tgz#531898ff566c7e5c7226ead2863b8cf9fbb5a981"