Ivan - Add responsive style and full-width mode [skip ci]

This commit is contained in:
ivan 2017-02-15 02:52:14 -03:00
parent dbfbd0cf80
commit d85d76f20e
19 changed files with 250 additions and 52 deletions

View File

@ -3,6 +3,7 @@ import _ from 'lodash';
import classNames from 'classnames'; import classNames from 'classnames';
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { browserHistory } from 'react-router'; import { browserHistory } from 'react-router';
import DocumentTitle from 'react-document-title';
import ModalContainer from 'app-components/modal-container'; import ModalContainer from 'app-components/modal-container';
@ -33,12 +34,14 @@ class App extends React.Component {
render() { render() {
return ( return (
<DocumentTitle title={this.props.config.title}>
<div className={this.getClass()}> <div className={this.getClass()}>
<div className="application__content"> <div className="application__content">
{React.cloneElement(this.props.children, {})} {React.cloneElement(this.props.children, {})}
</div> </div>
<ModalContainer /> <ModalContainer />
</div> </div>
</DocumentTitle>
); );
} }
@ -46,7 +49,8 @@ class App extends React.Component {
let classes = { let classes = {
'application': true, 'application': true,
'application_modal-opened': (this.props.modal.opened), 'application_modal-opened': (this.props.modal.opened),
'application_full-width': (this.props.config.layout === 'full-width' && !_.includes(this.props.location.pathname, '/admin')) 'application_full-width': (this.props.config.layout === 'full-width' && !_.includes(this.props.location.pathname, '/admin')),
'application_user-system': (this.props.config['user-system-enabled'])
}; };
return classNames(classes); return classNames(classes);

View File

@ -25,10 +25,12 @@
} }
} }
&--content {
position: relative;
}
&-footer { &-footer {
height: 40px; height: 40px;
//position: fixed;
//bottom: 0;
&--powered { &--powered {
padding-top: 9px; padding-top: 9px;
@ -37,14 +39,122 @@
} }
.main-home-page { .main-home-page {
width: 1100px;
margin: 0 auto; margin: 0 auto;
.widget {
background-color: $very-light-grey;
}
} }
.main-signup-page { .signup-widget {
background-color: $very-light-grey;
}
.signup-widget__captcha { .dashboard {
margin-left: 290px;
.widget {
background-color: transparent;
}
&__menu {
margin-left: -5px;
margin-top: -20px;
padding: 0;
background-color: $very-light-grey;
height: 100%;
position: absolute;
.menu__list {
background-color: transparent;
height: 100%;
position: relative;
}
.menu__header {
border-top-left-radius: 0;
border-top-right-radius: 0;
background-color: $secondary-blue;
text-align: right;
}
}
&__content {
margin-top: -10px;
}
@media screen and (max-width: 992px) {
.dashboard__menu {
position: static;
}
}
}
&__widget {
background-color: $very-light-grey;
}
@media screen and (max-width: 467px) {
.input {
width: 250px;
}
}
&.application_user-system {
.main-layout {
background-color: white;
}
.main-home-page {
&__login-widget {
position: absolute;
}
&__portal-wrapper {
margin-left: 360px;
padding-left: 15px;
padding-right: 15px;
}
@media screen and (max-width: 992px) {
.main-home-page {
&__login-widget,
&__portal-wrapper {
float: none;
width: initial;
margin-left: 0;
position: static;
}
}
}
}
}
@media screen and (max-width: 379px) {
.main-home-page {
.widget {
min-width: 313px !important;
width: initial !important;
}
}
}
}
&_user-system {
@media screen and (max-width: 379px) {
.main-home-page {
.widget {
min-width: initial;
width: 283px;
}
} }
} }
} }

View File

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import {connect} from 'react-redux';
import CreateTicketForm from 'app/main/dashboard/dashboard-create-ticket/create-ticket-form'; import CreateTicketForm from 'app/main/dashboard/dashboard-create-ticket/create-ticket-form';
import Widget from 'core-components/widget'; import Widget from 'core-components/widget';
@ -29,11 +30,16 @@ class DashboardCreateTicketPage extends React.Component {
getClass() { getClass() {
let classes = { let classes = {
'dashboard-create-ticket-page': true, 'dashboard-create-ticket-page': true,
'dashboard-create-ticket-page_wrapped': (this.props.location.pathname === '/create-ticket') 'dashboard-create-ticket-page_wrapped': (this.props.location.pathname === '/create-ticket'),
'col-md-10 col-md-offset-1': (!this.props.config['user-system-enabled'])
}; };
return classNames(classes); return classNames(classes);
} }
} }
export default DashboardCreateTicketPage; export default connect((store) => {
return {
config: store.config
};
})(DashboardCreateTicketPage);

View File

@ -24,19 +24,19 @@ class DashboardEditProfilePage extends React.Component {
render() { render() {
return ( return (
<div className="edit-profile-page"> <div className="edit-profile-page">
<Header title="Edit Profile" description="what ever" /> <Header title={i18n('EDIT_PROFILE')} description={i18n('EDIT_PROFILE_VIEW_DESCRIPTION')} />
<div className="edit-profile-page__title">Edit Email</div> <div className="edit-profile-page__title">{i18n('EDIT_EMAIL')}</div>
<Form loading={this.state.loadingEmail} onSubmit={this.onSubmitEditEmail.bind(this)}> <Form loading={this.state.loadingEmail} onSubmit={this.onSubmitEditEmail.bind(this)}>
<FormField name="newEmail" label="New Email" field="input" validation="EMAIL" fieldProps={{size:'large'}} required/> <FormField name="newEmail" label="New Email" field="input" validation="EMAIL" fieldProps={{size:'large'}} required/>
<SubmitButton>CHANGE EMAIL</SubmitButton> <SubmitButton>{i18n('CHANGE_EMAIL')}</SubmitButton>
{this.renderMessageEmail()} {this.renderMessageEmail()}
</Form> </Form>
<div className="edit-profile-page__title">Edit password</div> <div className="edit-profile-page__title">{i18n('EDIT_PASSWORD')}</div>
<Form loading={this.state.loadingPass} onSubmit={this.onSubmitEditPassword.bind(this)}> <Form loading={this.state.loadingPass} onSubmit={this.onSubmitEditPassword.bind(this)}>
<FormField name="oldPassword" label="Old Password" field="input" validation="PASSWORD" fieldProps={{password:true, size:'large'}} required/> <FormField name="oldPassword" label={i18n('OLD_PASSWORD')} field="input" validation="PASSWORD" fieldProps={{password:true, size:'large'}} required/>
<FormField name="password" label="New Password" field="input" validation="PASSWORD" fieldProps={{password:true, size:'large'}} required/> <FormField name="password" label={i18n('NEW_PASSWORD')} field="input" validation="PASSWORD" fieldProps={{password:true, size:'large'}} required/>
<FormField name="repeatNewPassword" label="Repeat New Password" field="input" validation="REPEAT_PASSWORD" fieldProps={{password:true ,size:'large'}} required/> <FormField name="repeatNewPassword" label={i18n('REPEAT_NEW_PASSWORD')} field="input" validation="REPEAT_PASSWORD" fieldProps={{password:true ,size:'large'}} required/>
<SubmitButton>CHANGE PASSWORD</SubmitButton> <SubmitButton>{i18n('CHANGE_PASSWORD')}</SubmitButton>
{this.renderMessagePass()} {this.renderMessagePass()}
</Form> </Form>
</div> </div>

View File

@ -1,11 +1,14 @@
@import '../../../../scss/vars'; @import '../../../../scss/vars';
.edit-profile-page { .edit-profile-page {
&__title { &__title {
color: $dark-grey; color: $dark-grey;
font-size: 20px; font-size: 20px;
text-align: left; text-align: left;
margin-bottom: 20px;
} }
&__message { &__message {
margin-top: 20px; margin-top: 20px;
margin-bottom: 20px; margin-bottom: 20px;

View File

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import classNames from 'classnames';
import DashboardMenu from 'app/main/dashboard/dashboard-menu'; import DashboardMenu from 'app/main/dashboard/dashboard-menu';
import Widget from 'core-components/widget'; import Widget from 'core-components/widget';
@ -9,8 +10,10 @@ class DashboardLayout extends React.Component {
render() { render() {
return (this.props.session.logged) ? ( return (this.props.session.logged) ? (
<div className="dashboard"> <div className="dashboard">
<div className="dashboard__menu col-md-3"><DashboardMenu location={this.props.location} /></div> <div className={this.getDashboardMenuClass()}>
<div className="dashboard__content col-md-9"> <DashboardMenu location={this.props.location} />
</div>
<div className={this.getDashboardContentClass()}>
<Widget> <Widget>
{this.props.children} {this.props.children}
</Widget> </Widget>
@ -18,10 +21,32 @@ class DashboardLayout extends React.Component {
</div> </div>
) : null; ) : null;
} }
getDashboardMenuClass() {
let classes = {
'dashboard__menu': true,
'col-md-3': (this.props.config.layout === 'boxed'),
'col-md-2': (this.props.config.layout === 'full-width')
};
return classNames(classes);
}
getDashboardContentClass() {
let classes = {
'dashboard__content': true,
'col-md-9': (this.props.config.layout === 'boxed'),
'col-md-10': (this.props.config.layout === 'full-width'),
'col-md-offset-2': (this.props.config.layout === 'full-width')
};
return classNames(classes);
}
} }
export default connect((store) => { export default connect((store) => {
return { return {
session: store.session session: store.session,
config: store.config
}; };
})(DashboardLayout); })(DashboardLayout);

View File

@ -76,7 +76,8 @@ class DashboardListArticlesPage extends React.Component {
getClass() { getClass() {
let classes = { let classes = {
'dashboard-list-articles-page': true, 'dashboard-list-articles-page': true,
'dashboard-list-articles-page_wrapped': (this.props.location.pathname == '/articles') 'dashboard-list-articles-page_wrapped': (this.props.location.pathname == '/articles'),
'col-md-10 col-md-offset-1': (!this.props.config['user-system-enabled'])
}; };
return classNames(classes); return classNames(classes);
@ -124,6 +125,7 @@ class DashboardListArticlesPage extends React.Component {
export default connect((store) => { export default connect((store) => {
return { return {
config: store.config,
topics: store.articles.topics, topics: store.articles.topics,
loading: store.articles.loading loading: store.articles.loading
}; };

View File

@ -24,7 +24,7 @@ class DashboardMenu extends React.Component {
getProps() { getProps() {
return { return {
header: 'Dashboard', header: i18n('DASHBOARD'),
items: this.getMenuItems(), items: this.getMenuItems(),
selectedIndex: this.getSelectedIndex(), selectedIndex: this.getSelectedIndex(),
onItemClick: this.onItemClick.bind(this), onItemClick: this.onItemClick.bind(this),

View File

@ -1,5 +1,7 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames';
import {browserHistory} from 'react-router'; import {browserHistory} from 'react-router';
import {connect} from 'react-redux';
import i18n from 'lib-app/i18n'; import i18n from 'lib-app/i18n';
import API from 'lib-app/api-call'; import API from 'lib-app/api-call';
@ -25,7 +27,7 @@ class MainCheckTicketPage extends React.Component {
render() { render() {
return ( return (
<div className="main-check-ticket-page"> <div className={this.getClass()}>
<Widget> <Widget>
<Header title={i18n('CHECK_TICKET')} description={i18n('VIEW_TICKET_DESCRIPTION')} /> <Header title={i18n('CHECK_TICKET')} description={i18n('VIEW_TICKET_DESCRIPTION')} />
<Form {...this.getFormProps()}> <Form {...this.getFormProps()}>
@ -47,6 +49,15 @@ class MainCheckTicketPage extends React.Component {
); );
} }
getClass() {
let classes = {
'main-check-ticket-page': true,
'col-md-10 col-md-offset-1': (!this.props.config['user-system-enabled'])
};
return classNames(classes);
}
getFormProps() { getFormProps() {
return { return {
className: 'main-check-ticket-page__form', className: 'main-check-ticket-page__form',
@ -92,4 +103,8 @@ class MainCheckTicketPage extends React.Component {
} }
} }
export default MainCheckTicketPage; export default connect((store) => {
return {
config: store.config
};
})(MainCheckTicketPage);

View File

@ -17,8 +17,4 @@
&__message { &__message {
margin-top: 18px; margin-top: 18px;
} }
&_password {
width: 324px;
}
} }

View File

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import {connect} from 'react-redux' import {connect} from 'react-redux';
import classNames from 'classnames';
import i18n from 'lib-app/i18n'; import i18n from 'lib-app/i18n';
@ -14,7 +15,7 @@ class MainHomePage extends React.Component {
<div className="main-home-page"> <div className="main-home-page">
{this.renderMessage()} {this.renderMessage()}
{(this.props.config['user-system-enabled']) ? this.renderLoginWidget() : null} {(this.props.config['user-system-enabled']) ? this.renderLoginWidget() : null}
<div className={(this.props.config['user-system-enabled']) ? 'col-md-8' : 'col-md-12'}> <div className={this.getPortalClass()}>
<MainHomePagePortal type={((this.props.config['user-system-enabled']) ? 'default' : 'complete')}/> <MainHomePagePortal type={((this.props.config['user-system-enabled']) ? 'default' : 'complete')}/>
</div> </div>
</div> </div>
@ -34,7 +35,7 @@ class MainHomePage extends React.Component {
renderLoginWidget() { renderLoginWidget() {
return ( return (
<div className="col-md-4"> <div className="col-md-4 main-home-page__login-widget">
<MainHomePageLoginWidget /> <MainHomePageLoginWidget />
</div> </div>
); );
@ -55,6 +56,16 @@ class MainHomePage extends React.Component {
</Message> </Message>
); );
} }
getPortalClass() {
let classes = {
'main-home-page__portal-wrapper': true,
'col-md-8': (this.props.config['user-system-enabled'] && this.props.config['layout'] === 'boxed'),
'col-md-10 col-md-offset-1' : (!this.props.config['user-system-enabled'])
};
return classNames(classes);
}
} }
export default connect((store) => { export default connect((store) => {

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux' import {connect} from 'react-redux';
import i18n from 'lib-app/i18n'; import i18n from 'lib-app/i18n';
import ConfigActions from 'actions/config-actions'; import ConfigActions from 'actions/config-actions';
@ -32,7 +32,7 @@ class MainLayoutHeader extends React.Component {
result = ( result = (
<div className="main-layout-header__login-links"> <div className="main-layout-header__login-links">
<Button type="clean" route={{to:'/'}}>{i18n('LOG_IN')}</Button> <Button type="clean" route={{to:'/'}}>{i18n('LOG_IN')}</Button>
{(this.props.config['registration'] === true) ? <Button type="clean" route={{to:'/signup'}}>{i18n('SIGN_UP')}</Button> : null} {(this.props.config['registration']) ? <Button type="clean" route={{to:'/signup'}}>{i18n('SIGN_UP')}</Button> : null}
</div> </div>
); );
} }

View File

@ -4,7 +4,6 @@ import _ from 'lodash';
import i18n from 'lib-app/i18n'; import i18n from 'lib-app/i18n';
import API from 'lib-app/api-call'; import API from 'lib-app/api-call';
import SessionStore from 'lib-app/session-store';
import Captcha from 'app/main/captcha'; import Captcha from 'app/main/captcha';
import SubmitButton from 'core-components/submit-button'; import SubmitButton from 'core-components/submit-button';
@ -12,7 +11,7 @@ import Message from 'core-components/message';
import Form from 'core-components/form'; import Form from 'core-components/form';
import FormField from 'core-components/form-field'; import FormField from 'core-components/form-field';
import Widget from 'core-components/widget'; import Widget from 'core-components/widget';
import Header from 'core-components/header';
class MainSignUpPageWidget extends React.Component { class MainSignUpPageWidget extends React.Component {
@ -28,7 +27,8 @@ class MainSignUpPageWidget extends React.Component {
render() { render() {
return ( return (
<div className="main-signup-page"> <div className="main-signup-page">
<Widget className="signup-widget col-md-6 col-md-offset-3" title="Register"> <Widget className="signup-widget col-md-6 col-md-offset-3">
<Header title={i18n('SIGN_UP')} description={i18n('SIGN_UP_VIEW_DESCRIPTION')} />
<Form {...this.getFormProps()}> <Form {...this.getFormProps()}>
<div className="signup-widget__inputs"> <div className="signup-widget__inputs">
<FormField {...this.getInputProps()} label="Full Name" name="name" validation="NAME" required/> <FormField {...this.getInputProps()} label="Full Name" name="name" validation="NAME" required/>

View File

@ -15,7 +15,7 @@
} }
&__captcha { &__captcha {
margin: 10px 84px 20px; margin: 10px auto 20px;
height: 78px; height: 78px;
width: 304px; width: 304px;
} }

View File

@ -5,7 +5,6 @@
border-radius: 4px; border-radius: 4px;
text-align: center; text-align: center;
padding: 20px; padding: 20px;
min-width: 324px;
min-height: 361px; min-height: 361px;
&--title { &--title {
@ -15,3 +14,15 @@
margin-bottom: 20px; margin-bottom: 20px;
} }
} }
@media screen and (min-width: 379px) {
.widget {
min-width: 324px;
}
}
@media screen and (max-width: 409px) {
.widget {
min-width: 313px;
margin-left: -11px;
}
}

View File

@ -11,8 +11,8 @@ module.exports = [
'reCaptchaKey': '6LfM5CYTAAAAAGLz6ctpf-hchX2_l0Ge-Bn-n8wS', 'reCaptchaKey': '6LfM5CYTAAAAAGLz6ctpf-hchX2_l0Ge-Bn-n8wS',
'reCaptchaPrivate': 'LALA', 'reCaptchaPrivate': 'LALA',
'url': 'http://www.opensupports.com/support', 'url': 'http://www.opensupports.com/support',
'title': 'OpenSupports Support Center', 'title': 'Support Center',
'layout': 'full-width', 'layout': 'boxed',
'time-zone': 3, 'time-zone': 3,
'no-reply-email': 'shitr@post.com', 'no-reply-email': 'shitr@post.com',
'smtp-host': 'localhost', 'smtp-host': 'localhost',
@ -38,8 +38,8 @@ module.exports = [
status: 'success', status: 'success',
data: { data: {
'language': 'en', 'language': 'en',
'title': '', 'title': 'Support Center',
'layout': 'full-width', 'layout': 'boxed',
'reCaptchaKey': '6LfM5CYTAAAAAGLz6ctpf-hchX2_l0Ge-Bn-n8wS', 'reCaptchaKey': '6LfM5CYTAAAAAGLz6ctpf-hchX2_l0Ge-Bn-n8wS',
'maintenance-mode': false, 'maintenance-mode': false,
'departments': [ 'departments': [

View File

@ -12,6 +12,7 @@ export default {
'FORGOT_PASSWORD': 'Forgot your password?', 'FORGOT_PASSWORD': 'Forgot your password?',
'RECOVER_PASSWORD': 'Recover Password', 'RECOVER_PASSWORD': 'Recover Password',
'RECOVER_SENT': 'An email with recover instructions has been sent.', 'RECOVER_SENT': 'An email with recover instructions has been sent.',
'OLD_PASSWORD': 'Old password',
'NEW_PASSWORD': 'New password', 'NEW_PASSWORD': 'New password',
'REPEAT_NEW_PASSWORD': 'Repeat new password', 'REPEAT_NEW_PASSWORD': 'Repeat new password',
'BACK_LOGIN_FORM': 'Back to login form', 'BACK_LOGIN_FORM': 'Back to login form',
@ -82,6 +83,10 @@ export default {
'UN_BAN': 'Disable ban', 'UN_BAN': 'Disable ban',
'BAN_NEW_EMAIL': 'Ban new email', 'BAN_NEW_EMAIL': 'Ban new email',
'BAN_EMAIL': 'Ban email', 'BAN_EMAIL': 'Ban email',
'EDIT_EMAIL': 'Edit email',
'EDIT_PASSWORD': 'Edit password',
'CHANGE_EMAIL': 'Change email',
'CHANGE_PASSWORD': 'Change password',
'NAME': 'Name', 'NAME': 'Name',
'SIGNUP_DATE': 'Sign up date', 'SIGNUP_DATE': 'Sign up date',
'SEARCH_USERS': 'Search users...', 'SEARCH_USERS': 'Search users...',
@ -243,6 +248,8 @@ export default {
'REGISTRATION_DISABLED': 'Registration has been disabled', 'REGISTRATION_DISABLED': 'Registration has been disabled',
'REGISTRATION_ENABLED': 'Registration has been enabled', 'REGISTRATION_ENABLED': 'Registration has been enabled',
'ADD_API_KEY_DESCRIPTION': 'Insert the name and a registration api key be generated.', 'ADD_API_KEY_DESCRIPTION': 'Insert the name and a registration api key be generated.',
'SIGN_UP_VIEW_DESCRIPTION': 'Here you can create an account for our support center. It is required for send tickets and see documentation.',
'EDIT_PROFILE_VIEW_DESCRIPTION': 'Here you can edit your user by changing your email or your password.',
//ERRORS //ERRORS
'EMAIL_OR_PASSWORD': 'Email or password invalid', 'EMAIL_OR_PASSWORD': 'Email or password invalid',

View File

@ -58,6 +58,10 @@ class SessionStore {
this.setItem('departments', JSON.stringify(configs.departments)); this.setItem('departments', JSON.stringify(configs.departments));
this.setItem('allowedLanguages', JSON.stringify(configs.allowedLanguages)); this.setItem('allowedLanguages', JSON.stringify(configs.allowedLanguages));
this.setItem('supportedLanguages', JSON.stringify(configs.supportedLanguages)); this.setItem('supportedLanguages', JSON.stringify(configs.supportedLanguages));
this.setItem('layout', configs.layout);
this.setItem('title', configs.title);
this.setItem('registration', configs.registration);
this.setItem('user-system-enabled', configs['user-system-enabled']);
} }
getConfigs() { getConfigs() {
@ -66,7 +70,11 @@ class SessionStore {
reCaptchaKey: this.getItem('reCaptchaKey'), reCaptchaKey: this.getItem('reCaptchaKey'),
departments: this.getDepartments(), departments: this.getDepartments(),
allowedLanguages: JSON.parse(this.getItem('allowedLanguages')), allowedLanguages: JSON.parse(this.getItem('allowedLanguages')),
supportedLanguages: JSON.parse(this.getItem('supportedLanguages')) supportedLanguages: JSON.parse(this.getItem('supportedLanguages')),
layout: this.getItem('layout'),
registration: this.getItem('registration'),
title: this.getItem('title'),
['user-system-enabled']: this.getItem('user-system-enabled')
}; };
} }

View File

@ -43,7 +43,7 @@ $font-size--xl: 32px;
} }
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
backgroundr: transparent; background: transparent;
} }
&:hover { &:hover {