mirror of
				https://github.com/elyby/accounts-frontend.git
				synced 2025-05-31 14:11:58 +05:30 
			
		
		
		
	Merge branch 'profile'
This commit is contained in:
		
							
								
								
									
										83
									
								
								src/components/profile/Profile.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/components/profile/Profile.jsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | |||||||
|  | import React, { Component } from 'react'; | ||||||
|  |  | ||||||
|  | import { FormattedMessage as Message, FormattedRelative as Relative, FormattedHTMLMessage as HTMLMessage } from 'react-intl'; | ||||||
|  | import Helmet from 'react-helmet'; | ||||||
|  |  | ||||||
|  | import { userShape } from 'components/user/User'; | ||||||
|  |  | ||||||
|  | import ProfileField from './ProfileField'; | ||||||
|  | import styles from './profile.scss'; | ||||||
|  | import messages from './Profile.messages'; | ||||||
|  |  | ||||||
|  | export class Profile extends Component { | ||||||
|  |     static displayName = 'Profile'; | ||||||
|  |     static propTypes = { | ||||||
|  |         user: userShape | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     render() { | ||||||
|  |         const { user } = this.props; | ||||||
|  |  | ||||||
|  |         return ( | ||||||
|  |             <div className={styles.container}> | ||||||
|  |                 <Message {...messages.accountPreferencesTitle}> | ||||||
|  |                     {(pageTitle) => ( | ||||||
|  |                         <h2 className={styles.title}> | ||||||
|  |                             <Helmet title={pageTitle} /> | ||||||
|  |                             {pageTitle} | ||||||
|  |                         </h2> | ||||||
|  |                     )} | ||||||
|  |                 </Message> | ||||||
|  |  | ||||||
|  |                 <div className={styles.content}> | ||||||
|  |                     <div className={styles.description}> | ||||||
|  |                         <Message {...messages.accountDescription} /> | ||||||
|  |                     </div> | ||||||
|  |  | ||||||
|  |                     <div className={styles.options}> | ||||||
|  |                         <div className={styles.item}> | ||||||
|  |                             <h3 className={styles.optionsTitle}> | ||||||
|  |                                 <Message {...messages.personalData} /> | ||||||
|  |                             </h3> | ||||||
|  |                             <p className={styles.optionsDescription}> | ||||||
|  |                                 <Message {...messages.preferencesDescription} /> | ||||||
|  |                             </p> | ||||||
|  |                         </div> | ||||||
|  |  | ||||||
|  |                         <ProfileField | ||||||
|  |                             label={<Message {...messages.nickname} />} | ||||||
|  |                             value={user.username} | ||||||
|  |                             warningMessage={<Message {...messages.mojangPriorityWarning} />} | ||||||
|  |                         /> | ||||||
|  |  | ||||||
|  |                         <ProfileField | ||||||
|  |                             label={'E-mail'} | ||||||
|  |                             value={user.email} | ||||||
|  |                         /> | ||||||
|  |  | ||||||
|  |                         <ProfileField | ||||||
|  |                             label={<Message {...messages.password} />} | ||||||
|  |                             value={<Message {...messages.changedAt} values={{ | ||||||
|  |                                 at: (<Relative value={user.passwordChangedAt * 1000} />) | ||||||
|  |                             }} />} | ||||||
|  |                             warningMessage={user.shouldChangePassword ? ( | ||||||
|  |                                 <HTMLMessage {...messages.oldHashingAlgoWarning} /> | ||||||
|  |                             ) : ''} | ||||||
|  |                         /> | ||||||
|  |  | ||||||
|  |                         <ProfileField | ||||||
|  |                             label={<Message {...messages.twoFactorAuth} />} | ||||||
|  |                             value={<Message {...messages.disabled} />} | ||||||
|  |                         /> | ||||||
|  |  | ||||||
|  |                         <ProfileField | ||||||
|  |                             label={'UUID'} | ||||||
|  |                             value={user.uuid} | ||||||
|  |                             readonly | ||||||
|  |                         /> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								src/components/profile/Profile.messages.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/components/profile/Profile.messages.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | import { defineMessages } from 'react-intl'; | ||||||
|  |  | ||||||
|  | export default defineMessages({ | ||||||
|  |     accountPreferencesTitle: { | ||||||
|  |         id: 'accountPreferencesTitle', | ||||||
|  |         defaultMessage: 'Ely.by account preferences' | ||||||
|  |         // defaultMessage: 'Настройки аккаунта Ely.by' | ||||||
|  |     }, | ||||||
|  |     personalData: { | ||||||
|  |         id: 'personalData', | ||||||
|  |         defaultMessage: 'Personal data' | ||||||
|  |         // defaultMessage: 'Персональные данные' | ||||||
|  |     }, | ||||||
|  |     accountDescription: { | ||||||
|  |         id: 'accountDescription', | ||||||
|  |         defaultMessage: '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.' | ||||||
|  |         // defaultMessage: 'Благодаря аккаунту Ely.by вы можете получить доступ ко многим ресурсам, связанным с Minecraft. Берегите свой аккаунт, используйте надёжный пароль и регулярно его меняйте.' | ||||||
|  |     }, | ||||||
|  |     preferencesDescription: { | ||||||
|  |         id: 'preferencesDescription', | ||||||
|  |         defaultMessage: 'Here you can change the key preferences of your account. Please note that all actions must be confirmed by entering a password.' | ||||||
|  |         // defaultMessage: 'Здесь вы можете сменить ключевые параметры вашего аккаунта. Обратите внимание, что для всех действий необходимо подтверждение при помощи ввода пароля.' | ||||||
|  |     }, | ||||||
|  |     mojangPriorityWarning: { | ||||||
|  |         id: 'mojangPriorityWarning', | ||||||
|  |         defaultMessage: 'A Mojang account with the same nickname was found. According to project rules, account owner has the right to demand the restoration of control over nickname.' | ||||||
|  |         // defaultMessage: 'Найден аккаунт Mojang с таким же ником и, по правилам проекта, его владелец вправе потребовать восстановления контроля над ником.' | ||||||
|  |     }, | ||||||
|  |     oldHashingAlgoWarning: { | ||||||
|  |         id: 'oldHashingAlgoWarning', | ||||||
|  |         defaultMessage: 'Your was hashed with an old hashing algorithm.<br />Please, change password.' | ||||||
|  |         // defaultMessage: 'Для пароля применяется старый алгоритм хэширования<br />Пожалуйста, смените пароль.' | ||||||
|  |     }, | ||||||
|  |     changedAt: { | ||||||
|  |         id: 'changedAt', | ||||||
|  |         defaultMessage: 'Changed {at}' | ||||||
|  |         // defaultMessage: 'Изменен {at}' | ||||||
|  |     }, | ||||||
|  |     disabled: { | ||||||
|  |         id: 'disabled', | ||||||
|  |         defaultMessage: 'Disabled' | ||||||
|  |         // defaultMessage: 'Не включена' | ||||||
|  |     }, | ||||||
|  |     nickname: { | ||||||
|  |         id: 'nickname', | ||||||
|  |         defaultMessage: 'Nickname' | ||||||
|  |         // defaultMessage: 'Ник' | ||||||
|  |     }, | ||||||
|  |     password: { | ||||||
|  |         id: 'password', | ||||||
|  |         defaultMessage: 'Password' | ||||||
|  |         // defaultMessage: 'Пароль' | ||||||
|  |     }, | ||||||
|  |     twoFactorAuth: { | ||||||
|  |         id: 'twoFactorAuth', | ||||||
|  |         defaultMessage: 'Two factor auth' | ||||||
|  |         // defaultMessage: 'Двухфакторная аутентификация' | ||||||
|  |     } | ||||||
|  | }); | ||||||
							
								
								
									
										40
									
								
								src/components/profile/ProfileField.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/components/profile/ProfileField.jsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | import React, { Component, PropTypes } from 'react'; | ||||||
|  |  | ||||||
|  | import styles from './profile.scss'; | ||||||
|  |  | ||||||
|  | export default class ProfileField extends Component { | ||||||
|  |     static displayName = 'ProfileField'; | ||||||
|  |     static propTypes = { | ||||||
|  |         label: React.PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired, | ||||||
|  |         value: React.PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired, | ||||||
|  |         warningMessage: React.PropTypes.oneOfType([PropTypes.string, PropTypes.element]), | ||||||
|  |         readonly: PropTypes.bool | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     render() { | ||||||
|  |         const {label, value, warningMessage, readonly} = this.props; | ||||||
|  |  | ||||||
|  |         return ( | ||||||
|  |             <div className={styles.paramItem}> | ||||||
|  |                 <div className={styles.paramRow}> | ||||||
|  |                     <div className={styles.paramName}>{label}:</div> | ||||||
|  |                     <div className={styles.paramValue}>{value}</div> | ||||||
|  |  | ||||||
|  |                     {readonly ? '' : ( | ||||||
|  |                         <div className={styles.paramAction}> | ||||||
|  |                             <a href="#"> | ||||||
|  |                                 <span className={styles.paramEditIcon} /> | ||||||
|  |                             </a> | ||||||
|  |                         </div> | ||||||
|  |                     )} | ||||||
|  |                 </div> | ||||||
|  |  | ||||||
|  |                 {warningMessage ? ( | ||||||
|  |                     <div className={styles.paramMessage}> | ||||||
|  |                         {warningMessage} | ||||||
|  |                     </div> | ||||||
|  |                 ) : ''} | ||||||
|  |             </div> | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										126
									
								
								src/components/profile/profile.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/components/profile/profile.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | |||||||
|  | @import '~components/ui/fonts.scss'; | ||||||
|  | @import '~components/ui/colors.scss'; | ||||||
|  |  | ||||||
|  | .container { | ||||||
|  |     margin-top: 55px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .title { | ||||||
|  |     font-family: $font-family-title; | ||||||
|  |     font-size: 30px; | ||||||
|  |     margin-bottom: 12px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .content { | ||||||
|  |     display: flex; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .description { | ||||||
|  |     font-size: 14px; | ||||||
|  |     line-height: 1.4; | ||||||
|  |     color: #9a9a9a; | ||||||
|  |     width: 340px; | ||||||
|  |     padding: 12px 20px 0 0; | ||||||
|  |     box-sizing: border-box; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .options { | ||||||
|  |     background: #fff; | ||||||
|  |     flex-grow: 1; | ||||||
|  |     max-width: 416px; | ||||||
|  |     border-bottom: 10px solid #ddd8ce; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .optionsTitle { | ||||||
|  |     position: relative; | ||||||
|  |     font-size: 24px; | ||||||
|  |     font-family: $font-family-title; | ||||||
|  |     padding-bottom: 9px; | ||||||
|  |  | ||||||
|  |     &:after { | ||||||
|  |         content: ''; | ||||||
|  |         display: block; | ||||||
|  |  | ||||||
|  |         position: absolute; | ||||||
|  |         left: 0; | ||||||
|  |         bottom: 0; | ||||||
|  |         height: 3px; | ||||||
|  |         width: 86px; | ||||||
|  |  | ||||||
|  |         background: $green; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .optionsDescription { | ||||||
|  |     font-size: 13px; | ||||||
|  |     color: #9a9a9a; | ||||||
|  |     line-height: 1.25; | ||||||
|  |     margin-top: 25px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .item { | ||||||
|  |     padding: 30px; | ||||||
|  |     border-bottom: 1px solid #eee; | ||||||
|  |  | ||||||
|  |     &:last-child { | ||||||
|  |         border-bottom: none; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .paramItem { | ||||||
|  |     composes: item; | ||||||
|  |  | ||||||
|  |     $padding: 20px; | ||||||
|  |  | ||||||
|  |     padding-top: $padding; | ||||||
|  |     padding-bottom: $padding; | ||||||
|  |  | ||||||
|  |     color: #666666; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .paramRow { | ||||||
|  |     display: flex; | ||||||
|  |     align-items: baseline; | ||||||
|  |     flex-basis: 0; | ||||||
|  |     flex-grow: 1; | ||||||
|  |  | ||||||
|  |     font-size: 14px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .paramName { | ||||||
|  |     width: 125px; | ||||||
|  |     font-family: $font-family-title; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .paramValue { | ||||||
|  |     flex-grow: 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .uuidValue { | ||||||
|  |     composes: paramName; | ||||||
|  |     composes: paramValue; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .paramAction { | ||||||
|  |     text-align: center; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .paramEditIcon { | ||||||
|  |     composes: pencil from 'components/ui/icons.scss'; | ||||||
|  |  | ||||||
|  |     color: $light; | ||||||
|  |     transition: .4s; | ||||||
|  |  | ||||||
|  |     a:hover & { | ||||||
|  |         color: #444; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .paramMessage { | ||||||
|  |     padding: 10px 40px 0 0; | ||||||
|  |  | ||||||
|  |     color: $red; | ||||||
|  |     font-size: 11px; | ||||||
|  |     line-height: 1.2; | ||||||
|  | } | ||||||
| @@ -17,6 +17,7 @@ export default class User { | |||||||
|  |  | ||||||
|         const defaults = { |         const defaults = { | ||||||
|             id: null, |             id: null, | ||||||
|  |             uuid: null, | ||||||
|             token: '', |             token: '', | ||||||
|             username: '', |             username: '', | ||||||
|             email: '', |             email: '', | ||||||
| @@ -24,7 +25,8 @@ export default class User { | |||||||
|             goal: null, // the goal with wich user entered site |             goal: null, // the goal with wich user entered site | ||||||
|             isGuest: true, |             isGuest: true, | ||||||
|             isActive: true, |             isActive: true, | ||||||
|             shouldChangePassword: false |             shouldChangePassword: false, // TODO: нужно ещё пробросить причину необходимости смены | ||||||
|  |             passwordChangedAt: null | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         const user = Object.keys(defaults).reduce((user, key) => { |         const user = Object.keys(defaults).reduce((user, key) => { | ||||||
| @@ -51,10 +53,12 @@ export default class User { | |||||||
|  |  | ||||||
| export const userShape = PropTypes.shape({ | export const userShape = PropTypes.shape({ | ||||||
|     id: PropTypes.number, |     id: PropTypes.number, | ||||||
|  |     uuid: PropTypes.string, | ||||||
|     token: PropTypes.string, |     token: PropTypes.string, | ||||||
|     username: PropTypes.string, |     username: PropTypes.string, | ||||||
|     email: PropTypes.string, |     email: PropTypes.string, | ||||||
|     avatar: PropTypes.string, |     avatar: PropTypes.string, | ||||||
|     isGuest: PropTypes.bool.isRequired, |     isGuest: PropTypes.bool.isRequired, | ||||||
|     isActive: PropTypes.bool.isRequired |     isActive: PropTypes.bool.isRequired, | ||||||
|  |     passwordChangedAt: PropTypes.number | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -27,7 +27,7 @@ export default class LoggedInPanel extends Component { | |||||||
|  |  | ||||||
|         return ( |         return ( | ||||||
|             <div className={buttonGroups.horizontalGroup}> |             <div className={buttonGroups.horizontalGroup}> | ||||||
|                 <Link to="/profile" className={classNames(buttons.green, buttonGroups.item)}> |                 <Link to="/" className={classNames(buttons.green, buttonGroups.item)}> | ||||||
|                     <span className={styles.userIcon} /> |                     <span className={styles.userIcon} /> | ||||||
|                     <span className={styles.userName}>{user.username}</span> |                     <span className={styles.userName}>{user.username}</span> | ||||||
|                 </Link> |                 </Link> | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								src/icons/webfont/pencil.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/icons/webfont/pencil.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||||
|  | <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16"> | ||||||
|  | <path d="M13.5 0c1.381 0 2.5 1.119 2.5 2.5 0 0.563-0.186 1.082-0.5 1.5l-1 1-3.5-3.5 1-1c0.418-0.314 0.937-0.5 1.5-0.5zM1 11.5l-1 4.5 4.5-1 9.25-9.25-3.5-3.5-9.25 9.25zM11.181 5.681l-7 7-0.862-0.862 7-7 0.862 0.862z"></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 543 B | 
| @@ -2,20 +2,13 @@ import React, { Component } from 'react'; | |||||||
|  |  | ||||||
| import { connect } from 'react-redux'; | import { connect } from 'react-redux'; | ||||||
|  |  | ||||||
|  | import { Profile } from 'components/profile/Profile'; | ||||||
|  |  | ||||||
| class IndexPage extends Component { | class IndexPage extends Component { | ||||||
|     displayName = 'IndexPage'; |     displayName = 'IndexPage'; | ||||||
|  |  | ||||||
|     render() { |     render() { | ||||||
|         const {user, children} = this.props; |         return (<Profile {...this.props} />); | ||||||
|  |  | ||||||
|         return ( |  | ||||||
|             <div> |  | ||||||
|                 <h1> |  | ||||||
|                     Hello {user.username}! |  | ||||||
|                 </h1> |  | ||||||
|                 {children} |  | ||||||
|             </div> |  | ||||||
|         ); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user