diff --git a/src/components/auth/appInfo/AppInfo.jsx b/src/components/auth/appInfo/AppInfo.jsx
index 7f7c92b..9f7217a 100644
--- a/src/components/auth/appInfo/AppInfo.jsx
+++ b/src/components/auth/appInfo/AppInfo.jsx
@@ -4,6 +4,7 @@ import { FormattedMessage as Message } from 'react-intl';
import { Button } from 'components/ui/form';
import { LangMenu } from 'components/langMenu';
+import { FooterMenu } from 'components/footerMenu';
import styles from './appInfo.scss';
import messages from './AppInfo.intl.json';
@@ -39,6 +40,7 @@ export default class AppInfo extends Component {
+
diff --git a/src/components/auth/appInfo/appInfo.scss b/src/components/auth/appInfo/appInfo.scss
index eac2921..e74cab7 100644
--- a/src/components/auth/appInfo/appInfo.scss
+++ b/src/components/auth/appInfo/appInfo.scss
@@ -56,4 +56,6 @@
bottom: 10px;
left: 0;
right: 0;
+ text-align: center;
+ line-height: 1.5;
}
diff --git a/src/components/contact/ContactForm.jsx b/src/components/contact/ContactForm.jsx
new file mode 100644
index 0000000..a710194
--- /dev/null
+++ b/src/components/contact/ContactForm.jsx
@@ -0,0 +1,78 @@
+import React, { Component, PropTypes } from 'react';
+
+import classNames from 'classnames';
+import { FormattedMessage as Message } from 'react-intl';
+
+import { Input, TextArea, Button, Form, FormModel } from 'components/ui/form';
+import site from 'services/api/site';
+import icons from 'components/ui/icons.scss';
+
+import styles from './contactForm.scss';
+import messages from './contactForm.intl.json';
+
+export default class ContactForm extends Component {
+ static displayName = 'ContactForm';
+
+ static propTypes = {
+ onClose: PropTypes.func.isRequired
+ };
+
+ form = new FormModel();
+
+ render() {
+ const {onClose} = this.props;
+ const {form} = this;
+
+ return (
+
+ );
+ }
+
+ onSubmit = () => {
+ site.contact(this.form.serialize())
+ .then(this.props.onClose)
+ .catch((resp) => {
+ if (resp.errors) {
+ this.form.setErrors(resp.errors);
+ }
+
+ return Promise.reject(resp);
+ })
+ ;
+ };
+}
diff --git a/src/components/contact/contactForm.intl.json b/src/components/contact/contactForm.intl.json
new file mode 100644
index 0000000..3705e6e
--- /dev/null
+++ b/src/components/contact/contactForm.intl.json
@@ -0,0 +1,7 @@
+{
+ "title": "Contact Us",
+ "subject": "Subject",
+ "email": "E-mail",
+ "message": "Message",
+ "send": "Send"
+}
diff --git a/src/components/contact/contactForm.scss b/src/components/contact/contactForm.scss
new file mode 100644
index 0000000..713d93f
--- /dev/null
+++ b/src/components/contact/contactForm.scss
@@ -0,0 +1,31 @@
+.contactForm {
+}
+
+.header {
+ position: relative;
+ margin: -30px;
+ margin-bottom: 0;
+
+ padding: 10px 10px 0;
+ border-bottom: 1px solid #D6D6D6;
+ background: #F5F5F5;
+}
+
+.title {
+ color: #444;
+ font-size: 30px;
+ line-height: 68px;
+ text-align: center;
+}
+
+.close {
+ position: absolute;
+ right: 10px;
+ top: 10px;
+ cursor: pointer;
+}
+
+.footer {
+ margin: -30px;
+ margin-top: 0;
+}
diff --git a/src/components/footerMenu/FooterMenu.jsx b/src/components/footerMenu/FooterMenu.jsx
new file mode 100644
index 0000000..444a544
--- /dev/null
+++ b/src/components/footerMenu/FooterMenu.jsx
@@ -0,0 +1,43 @@
+import React, { Component, PropTypes } from 'react';
+
+import { Link } from 'react-router';
+import { FormattedMessage as Message } from 'react-intl';
+
+import styles from './footerMenu.scss';
+import messages from './footerMenu.intl.json';
+
+export default class FooterMenu extends Component {
+ static displayName = 'FooterMenu';
+
+ static propTypes = {
+ skin: PropTypes.oneOf(['light', 'dark']),
+ createPopup: PropTypes.func.isRequired
+ };
+
+ render() {
+ return (
+
+ );
+ }
+
+ onContact = (event) => {
+ event.preventDefault();
+ this.props.createPopup();
+ };
+}
+
+import { connect } from 'react-redux';
+import ContactForm from 'components/contact/ContactForm';
+import { create as createPopup } from 'components/ui/popup/actions';
+
+export default connect(null, {
+ createPopup: () => createPopup(ContactForm)
+})(FooterMenu);
diff --git a/src/components/footerMenu/footerMenu.intl.json b/src/components/footerMenu/footerMenu.intl.json
new file mode 100644
index 0000000..be3af35
--- /dev/null
+++ b/src/components/footerMenu/footerMenu.intl.json
@@ -0,0 +1,4 @@
+{
+ "rules": "Rules",
+ "contactUs": "Contact Us"
+}
diff --git a/src/components/footerMenu/footerMenu.scss b/src/components/footerMenu/footerMenu.scss
new file mode 100644
index 0000000..0e7d8da
--- /dev/null
+++ b/src/components/footerMenu/footerMenu.scss
@@ -0,0 +1,16 @@
+.footerMenu {
+ font-size: 12px;
+ color: #666;
+
+ a {
+ color: #666;
+ border-bottom: 1px dotted #666;
+ text-decoration: none;
+ transition: .25s;
+
+ &:hover {
+ border-bottom-color: #777;
+ color: #777;
+ }
+ }
+}
diff --git a/src/components/footerMenu/index.js b/src/components/footerMenu/index.js
new file mode 100644
index 0000000..dcc7ed7
--- /dev/null
+++ b/src/components/footerMenu/index.js
@@ -0,0 +1,5 @@
+import FooterMenu from './FooterMenu';
+
+export {
+ FooterMenu
+};
diff --git a/src/components/profile/changeEmail/ChangeEmail.jsx b/src/components/profile/changeEmail/ChangeEmail.jsx
index 264e500..4584aef 100644
--- a/src/components/profile/changeEmail/ChangeEmail.jsx
+++ b/src/components/profile/changeEmail/ChangeEmail.jsx
@@ -165,6 +165,7 @@ export default class ChangeEmail extends Component {
{this[`renderStep${step}`]({
email,
code,
+ isCodeSpecified,
form,
isActiveStep: step === activeStep
})}
diff --git a/src/components/ui/form/TextArea.jsx b/src/components/ui/form/TextArea.jsx
new file mode 100644
index 0000000..a724c67
--- /dev/null
+++ b/src/components/ui/form/TextArea.jsx
@@ -0,0 +1,81 @@
+import React, { PropTypes } from 'react';
+
+import classNames from 'classnames';
+
+import { uniqueId } from 'functions';
+
+import styles from './form.scss';
+import FormInputComponent from './FormInputComponent';
+
+export default class TextArea extends FormInputComponent {
+ static displayName = 'TextArea';
+
+ static propTypes = {
+ placeholder: PropTypes.oneOfType([
+ PropTypes.shape({
+ id: PropTypes.string
+ }),
+ PropTypes.string
+ ]),
+ label: PropTypes.oneOfType([
+ PropTypes.shape({
+ id: PropTypes.string
+ }),
+ PropTypes.string
+ ]),
+ error: PropTypes.string,
+ skin: PropTypes.oneOf(['dark', 'light']),
+ color: PropTypes.oneOf(['green', 'blue', 'red', 'lightViolet', 'darkBlue', 'violet'])
+ };
+
+ render() {
+ let { color = 'green', skin = 'dark', label } = this.props;
+
+ const props = {
+ type: 'text',
+ ...this.props
+ };
+
+ if (label) {
+ if (!props.id) {
+ props.id = uniqueId('textarea');
+ }
+
+ label = this.formatMessage(label);
+
+ label = (
+
+ );
+ }
+
+ props.placeholder = this.formatMessage(props.placeholder);
+
+ return (
+
+ {label}
+
+
+
+ {this.renderError()}
+
+ );
+ }
+
+ getValue() {
+ return this.el.value;
+ }
+
+ focus() {
+ this.el.focus();
+ setTimeout(this.el.focus.bind(this.el), 10);
+ }
+}
diff --git a/src/components/ui/form/form.scss b/src/components/ui/form/form.scss
index 5396bd6..fc4bd64 100644
--- a/src/components/ui/form/form.scss
+++ b/src/components/ui/form/form.scss
@@ -153,6 +153,17 @@
}
}
+.textAreaContainer {
+ height: auto;
+}
+
+.textArea {
+ height: 150px;
+ padding: 5px 10px;
+ resize: vertical;
+ position: relative;
+}
+
@include input-theme('green', $green);
@include input-theme('blue', $blue);
@include input-theme('red', $red);
diff --git a/src/components/ui/form/index.js b/src/components/ui/form/index.js
index f2eb656..512d66f 100644
--- a/src/components/ui/form/index.js
+++ b/src/components/ui/form/index.js
@@ -1,4 +1,5 @@
import Input from './Input';
+import TextArea from './TextArea';
import Checkbox from './Checkbox';
import Button from './Button';
import Form from './Form';
@@ -6,6 +7,7 @@ import FormModel from './FormModel';
export {
Input,
+ TextArea,
Button,
Checkbox,
Form,
diff --git a/src/components/ui/popup/popup.scss b/src/components/ui/popup/popup.scss
index c8329a7..45f3138 100644
--- a/src/components/ui/popup/popup.scss
+++ b/src/components/ui/popup/popup.scss
@@ -10,9 +10,11 @@
background: rgba(255, 255, 255, 0.8);
text-align: center;
- vertical-align: middle;
white-space: nowrap;
+ overflow-x: hidden;
+ overflow-y: auto;
+
&:before {
content: '';
display: inline-block;
@@ -25,6 +27,8 @@
.popup {
display: inline-block;
white-space: normal;
+ text-align: left;
+ vertical-align: middle;
width: 400px;
max-width: 90%;
diff --git a/src/i18n/en.json b/src/i18n/en.json
index cad9db9..0dfb641 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -57,6 +57,13 @@
"components.auth.register.termsOfService": "terms of service",
"components.auth.register.yourEmail": "Your E-mail",
"components.auth.register.yourNickname": "Your nickname",
+ "components.contact.email": "E-mail",
+ "components.contact.message": "Message",
+ "components.contact.send": "Send",
+ "components.contact.subject": "Subject",
+ "components.contact.title": "Contact Us",
+ "components.footerMenu.contactUs": "Contact Us",
+ "components.footerMenu.rules": "Rules",
"components.langMenu.siteLanguage": "Site language",
"components.profile.accountDescription": "Ely.by account allows you to get access to many Minecraft resources. Please, take care of your account safety. Use secure password and change it regularly.",
"components.profile.accountPreferencesTitle": "Ely.by account preferences",
diff --git a/src/i18n/ru.json b/src/i18n/ru.json
index 5178511..501fc8a 100644
--- a/src/i18n/ru.json
+++ b/src/i18n/ru.json
@@ -57,6 +57,13 @@
"components.auth.register.termsOfService": "правилами сервиса",
"components.auth.register.yourEmail": "Ваш E-mail",
"components.auth.register.yourNickname": "Желаемый ник",
+ "components.contact.email": "E-mail",
+ "components.contact.message": "Сообщение",
+ "components.contact.send": "Отправить",
+ "components.contact.subject": "Тема",
+ "components.contact.title": "Обратная связь",
+ "components.footerMenu.contactUs": "Обратная связь",
+ "components.footerMenu.rules": "Правила сайта",
"components.langMenu.siteLanguage": "Язык сайта",
"components.profile.accountDescription": "Благодаря аккаунту Ely.by вы можете получить доступ ко многим ресурсам, связанным с Minecraft. Берегите свой аккаунт, используйте надёжный пароль и регулярно его меняйте.",
"components.profile.accountPreferencesTitle": "Настройки аккаунта Ely.by",
diff --git a/src/pages/index/IndexPage.jsx b/src/pages/index/IndexPage.jsx
index ed6c213..122bdc9 100644
--- a/src/pages/index/IndexPage.jsx
+++ b/src/pages/index/IndexPage.jsx
@@ -1,7 +1,5 @@
import React, { Component } from 'react';
-import { connect } from 'react-redux';
-
import ProfilePage from 'pages/profile/ProfilePage';
import Profile from 'components/profile/Profile';
@@ -17,6 +15,8 @@ class IndexPage extends Component {
}
}
+import { connect } from 'react-redux';
+
export default connect((state) => ({
user: state.user
}))(IndexPage);
diff --git a/src/pages/profile/ProfilePage.jsx b/src/pages/profile/ProfilePage.jsx
index 817de01..ee81507 100644
--- a/src/pages/profile/ProfilePage.jsx
+++ b/src/pages/profile/ProfilePage.jsx
@@ -1,5 +1,7 @@
import React, { Component, PropTypes } from 'react';
+import { FooterMenu } from 'components/footerMenu';
+
import styles from './profile.scss';
class ProfilePage extends Component {
@@ -27,6 +29,10 @@ class ProfilePage extends Component {
return (
{this.props.children}
+
+
+
+
);
}
diff --git a/src/pages/profile/profile.scss b/src/pages/profile/profile.scss
index 3d6c38b..9ce0df4 100644
--- a/src/pages/profile/profile.scss
+++ b/src/pages/profile/profile.scss
@@ -1,3 +1,11 @@
.container {
margin-top: 55px;
}
+
+.footer {
+ text-align: center;
+ position: fixed;
+ bottom: 10px;
+ width: 100%;
+ left: 0;
+}
diff --git a/src/services/api/site.js b/src/services/api/site.js
new file mode 100644
index 0000000..d9004ab
--- /dev/null
+++ b/src/services/api/site.js
@@ -0,0 +1,14 @@
+import request from 'services/request';
+
+export default {
+ contact({
+ subject = '',
+ email = '',
+ message = ''
+ }) {
+ return request.post(
+ '/api/site/contact',
+ {subject, email, message}
+ );
+ }
+};