diff --git a/public/css/edu-purge.css b/public/css/edu-purge.css index 4d59fc11f..c8f7c907f 100644 --- a/public/css/edu-purge.css +++ b/public/css/edu-purge.css @@ -3912,7 +3912,6 @@ html>body #ajax-indicator { text-align: center; height: 70px; box-sizing: border-box; - min-width: 780px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; diff --git a/src/forge/Component/AddMember.jsx b/src/forge/Component/AddMember.jsx index 0548e52da..f927850c8 100644 --- a/src/forge/Component/AddMember.jsx +++ b/src/forge/Component/AddMember.jsx @@ -4,7 +4,7 @@ import axios from 'axios'; import { getImageUrl } from 'educoder'; const { Option } = AutoComplete; -function AddMember({getID,login}){ +function AddMember({getID,login,showNotification}){ const [ id , setID ] = useState(undefined); const [ source , setSource ] = useState(undefined); const [ searchKey , setSearchKey ] = useState(undefined); @@ -45,7 +45,7 @@ function AddMember({getID,login}){ src={getImageUrl(`/${item && item.image_url}`)} alt="" /> - + {item.username} ({item.login}) @@ -66,7 +66,12 @@ function AddMember({getID,login}){ }; function addCollaborator(){ - getID && getID(id); + if(source && source.length>0){ + getID && getID(id); + setSearchKey(undefined); + }else{ + showNotification("请选择存在的用户!"); + } } return( diff --git a/src/forge/Head/AddProjectModal.jsx b/src/forge/Head/AddProjectModal.jsx new file mode 100644 index 000000000..8e3073e30 --- /dev/null +++ b/src/forge/Head/AddProjectModal.jsx @@ -0,0 +1,84 @@ +import React, { useState , forwardRef, useEffect } from 'react'; +import { Form , Modal , Input , Radio } from 'antd'; +import Axios from 'axios'; + +export default Form.create()( + forwardRef((props)=>{ + const { getFieldDecorator, validateFields , setFieldsValue } = props && props.form; + const [ visible , setVisible ] = useState(false); + + useEffect(()=>{ + if(!visible){ + setFieldsValue({ + code:undefined, + role:"developer" + }) + } + },[visible]) + + function onOk() { + validateFields((error,values)=>{ + if(!error){ + const url = `/applied_projects.json`; + Axios.post(url,{ + applied_project:{ + ...values + } + }).then(result=>{ + if(result && result.data){ + setVisible(false); + props.showNotification("申请加入项目成功,等待审核!"); + } + }).catch(error=>{}) + } + }) + } + function checkValue(rule, value, callback){ + if(!value){ + callback(); + } + if(value.length < 6 || value.length > 6){ + callback("请输入6位数的邀请码"); + } + callback(); + } + + return( + + setVisible(false)} + > +
+ + {getFieldDecorator("code",{ + rules:[ + {required:true,message:"请输入6位项目邀请码"}, + {validator:checkValue} + ] + })( + + )} + + + {getFieldDecorator("role",{ + rules:[{required:true,message:"请选择角色"}] + })( + + 管理员 + 开发者 + 报告者 + + )} + +
+
+ setVisible(true)}>加入项目 +
+ ) + }) +) \ No newline at end of file diff --git a/src/forge/Head/Header.js b/src/forge/Head/Header.js index 9b19a5c50..0ea38b41b 100644 --- a/src/forge/Head/Header.js +++ b/src/forge/Head/Header.js @@ -2,13 +2,11 @@ import React, { Component } from 'react'; import AccountProfile from "../../modules/user/AccountProfile"; import { getImageUrl } from 'educoder' import axios from 'axios'; -import { Modal, Input, message, notification , Dropdown , Menu } from 'antd'; +import { Input , notification , Dropdown , Menu } from 'antd'; import LoginDialog from '../../modules/login/LoginDialog'; -import GotoQQgroup from '../../modal/GotoQQgroup' - +import AddProjectModal from './AddProjectModal'; import '../../modules/tpm/TPMIndex.css'; -import logo from '../../modules/tpm/images/logo.png'; import './header.scss'; const $ = window.$ @@ -33,11 +31,9 @@ class NewHeader extends Component { Checkboxteachertype: false, Checkboxteachingtype: false, code_notice: false, - checked_notice: false, RadioGroupvalue: undefined, submitapplications: false, isRender: false, - showSearchOpentype: false, showTrial: false, setevaluatinghides: false, occupation: 0, @@ -45,7 +41,6 @@ class NewHeader extends Component { headtypesonClickbool: false, headtypess: "/", settings: null, - goshowqqgtounp: false, visiblemyss: false, openSearch:false, } @@ -93,10 +88,11 @@ class NewHeader extends Component { }, 300) }} > - this.onGlobalSearch(value,item)} autoFocus={true} + style={{width:"260px"}} /> ) @@ -130,43 +126,7 @@ class NewHeader extends Component { } } - submitsubmitapplications = () => { - let { - submitapplicationssum, - submitapplicationsvaluedata - } = this.state; - this.setState({ - submitapplications: false, - RadioGroupvalue: undefined - }) - if (submitapplicationssum === 0) { - if (submitapplicationsvaluedata !== undefined) { - window.location.href = "/courses/" + submitapplicationsvaluedata; - } - } else if (submitapplicationssum === 1) { - if (submitapplicationsvaluedata !== undefined) { - window.location.href = "/projects/" + submitapplicationsvaluedata; - } - } - } - hidesubmitapplications = () => { - this.setState({ - Addcoursestypes: false, - tojoinitemtype: false, - tojoinclasstitle: undefined, - rolearr: ["", ""], - Checkboxteacherchecked: false, - Checkboxstudentchecked: false, - Checkboxteachingchecked: false, - Checkboxteachertype: false, - Checkboxteachingtype: false, - code_notice: false, - checked_notice: false, - submitapplications: false, - RadioGroupvalue: undefined - }) - } educoderlogin = () => { //登录账号 this.setState({ @@ -205,23 +165,6 @@ class NewHeader extends Component { }; - hidetojoinclass = () => { - this.setState({ - tojoinclasstype: false, - tojoinitemtype: false, - tojoinclasstitle: undefined, - rolearr: ["", ""], - Checkboxteacherchecked: false, - Checkboxstudentchecked: false, - Checkboxteachingchecked: false, - Checkboxteachertype: false, - Checkboxteachingtype: false, - code_notice: false, - checked_notice: false, - RadioGroupvalue: undefined - }) - } - // 关闭 cancelModulationModels = () => { this.setState({ isRenders: false }) @@ -313,14 +256,6 @@ class NewHeader extends Component { } } - - // 处理弹框 - setgoshowqqgtounp = (bool) => { - this.setState({ - goshowqqgtounp: bool - }) - } - addMenu=(list)=>{ return( list && list.length >0 && @@ -333,10 +268,29 @@ class NewHeader extends Component { ) }) } + ) } + renderMenu=(personal)=>{ + const { current_user } = this.props; + return( + + + {current_user && current_user.username} + + { + personal && personal.length > 0 && personal.map((item,key)=>{ + return( +
  • {item.name}
  • + ) + }) + } + this.educoderloginysl()}>退出 +
    + ) + } render() { const { match} = this.props; @@ -345,17 +299,12 @@ class NewHeader extends Component { tojoinitemtype, tojoinclasstitle, code_notice, - checked_notice, AccountProfiletype, - submitapplications, - submitapplicationsvalue, user, isRender, - showSearchOpentype, headtypesonClickbool, headtypess, settings, - goshowqqgtounp, openSearch, } = this.state; /*用户名称 用户头像url*/ @@ -452,11 +401,6 @@ class NewHeader extends Component { {...this.props} {...this.state} /> : ""} - { - goshowqqgtounp === true ? - this.setgoshowqqgtounp(bool)}> - :"" - } { settings && settings.nav_logo_url ? @@ -522,32 +466,6 @@ class NewHeader extends Component { } :"" } - -
    -
    - -
    -
    - {!user || (user && !user.login) ? @@ -558,25 +476,11 @@ class NewHeader extends Component { } : -
    - - - + + + 头像 -
      -
    • {this.props.current_user.username}
    • - { - settings && settings.personal && settings.personal.length > 0 && settings.personal.map((item,key)=>{ - return( -
    • {item.name}
    • - ) - }) - } -
    • - this.educoderloginysl()}>退出 -
    • -
    -
    + } diff --git a/src/forge/Head/header.scss b/src/forge/Head/header.scss index 0ae8f48e2..a2c11b7a1 100644 --- a/src/forge/Head/header.scss +++ b/src/forge/Head/header.scss @@ -1,7 +1,6 @@ .dropdownFlex{ display:flex; - padding:5px; background:#fff; border-radius: 3px; .ant-menu-vertical > .ant-menu-item{ @@ -9,11 +8,57 @@ height: 35px; line-height: 35px; margin:0px; + &.ant-menu-item-selected{ + background-color: #fff; + a{color: rgba(0, 0, 0, 0.65)!important;} + } + &.ant-menu-item-active{ + a{color: #4cacff!important;} + } } .ant-menu-vertical{ border:none; } } +.currentImg{ + width: 34px; + height: 34px; + border-radius: 50%; + margin-left: 30px; +} +.currentMenu{ + width: 120px; + text-align: center; + padding:0px; + li{ + height: 40px; + line-height: 40px; + padding:0px; + cursor: default; + &:hover{ + background-color: #fff; + } + &:first-child{ + border-bottom: 1px solid #eee; + } + &:last-child{ + border-top: 1px solid #eee; + a{ + border-radius: 0px 0px 4px 4px; + } + } + a{ + padding:0px; + margin:0px; + display: block; + color: #666; + &:hover{ + color: #fff; + background: #4CACFF; + } + } + } +} .newFooter { position: absolute; @@ -65,4 +110,13 @@ } } } +} +.inviteForm{ + .ant-form-item{ + margin-right: 0px; + } + .ant-form-item-label{ + width: 110px; + text-align: right; + } } \ No newline at end of file diff --git a/src/forge/Main/CoderDepot.jsx b/src/forge/Main/CoderDepot.jsx index adda25c54..b1c384652 100644 --- a/src/forge/Main/CoderDepot.jsx +++ b/src/forge/Main/CoderDepot.jsx @@ -239,9 +239,11 @@ function CoderDepot(props){ } }) } - let n = fileInfo && fileInfo.name; const mdFlag = n && n.substring(n.length-3,n.length) === ".md"; + + const { current_user } = props; + const fileOperate = type === "dir" && projectDetail && projectDetail.type !== 2 && (projectDetail.permission !=="Reporter" || (current_user && current_user.admin)); return( @@ -311,7 +313,7 @@ function CoderDepot(props){ } urlLink(`/projects/${owner}/${projectsId}/issues/new`)} >+ 任务 - { type === "dir" && projectDetail.type !== 2 && + { fileOperate && diff --git a/src/forge/Main/Detail.js b/src/forge/Main/Detail.js index 61b2df722..505cf1d8a 100644 --- a/src/forge/Main/Detail.js +++ b/src/forge/Main/Detail.js @@ -1,8 +1,9 @@ import React, { Component } from 'react'; -import { Spin, Tooltip } from 'antd'; +import { Spin, Tooltip , message } from 'antd'; import { Link, Route, Switch } from 'react-router-dom'; -import { Content } from '../Component/layout'; +import { Content , FlexAJ } from '../Component/layout'; import DetailBanner from './sub/DetailBanner'; +import Invite from './sub/Invite'; import '../css/index.scss' import './list.css'; @@ -389,6 +390,15 @@ class Detail extends Component { }) } + textFunc = (forked_from_project_id,fork_info)=>{ + return forked_from_project_id && fork_info ? +
    + forked from + {fork_info.fork_project_user_name} + / + {fork_info.fork_form_name} +
    : "" + } render() { @@ -406,16 +416,6 @@ class Detail extends Component { const { state } = this.props.history.location; - const text = ( - projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ? - - forked from - {projectDetail.fork_info.fork_project_user_name} - / - {projectDetail.fork_info.fork_form_name} - : "" - ); - const common = { getDetail: this.getDetail, changeOpenDevops:this.changeOpenDevops, @@ -425,7 +425,7 @@ class Detail extends Component {
    -
    +

    {project && project.author && @@ -435,15 +435,7 @@ class Detail extends Component { / {project && project.name} - { - projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ? - - - - - : "" - } + { projectDetail && projectDetail.type && projectDetail.type !== 0 ? projectDetail.type === 2 ? @@ -516,6 +508,19 @@ class Detail extends Component { }

    + +
    + { + projectDetail && projectDetail.forked_from_project_id && projectDetail.fork_info ? + this.textFunc(projectDetail.forked_from_project_id,projectDetail.fork_info) + :"" + } +
    + { + projectDetail && projectDetail.invite_code && + + } +
    { firstSync ? "" : + 邀请码: {code} + 可以通过邀请码邀请成员加入项目
    点击复制邀请码。

    } placement={"bottom"}> + jsCopy("#devitecode")}> +
    +
    + ) +} +export default Invite; \ No newline at end of file diff --git a/src/forge/Notice/Apply.jsx b/src/forge/Notice/Apply.jsx new file mode 100644 index 000000000..3c77edfaa --- /dev/null +++ b/src/forge/Notice/Apply.jsx @@ -0,0 +1,114 @@ +import React, { useEffect , useState } from 'react'; +import Axios from 'axios'; +import { Pagination , Spin , Popconfirm }from 'antd'; +import { Link } from 'react-router-dom'; +import { getImageUrl } from 'educoder'; +import Nodata from '../Nodata'; +import { FlexAJ } from '../Component/layout'; + +const limit = 15; +function Apply(props) { + const username = props.match.params.username; + const [ list , setList ] = useState(undefined); + const [ page , setPage ] = useState(1); + const [ total , setTotal ] = useState(0); + const [ isSpin , setIsSpin ] = useState(true); + + useEffect(()=>{ + if(username){ + setIsSpin(true); + getList(); + } + },[username]) + + function getList() { + const url = `/users/${username}/applied_projects.json`; + Axios.get(url).then(result=>{ + if(result){ + setList(result.data.applied_projects); + setTotal(result.data.total_count); + setIsSpin(false); + } + }).catch(error=>{}) + } + + // 接受 + function acceptDivert(id){ + const url = `/users/${username}/applied_projects/${id}/accept.json`; + Axios.post(url).then(result=>{ + if(result && result.data){ + getList(); + props && props.deleteEvent("apply",1); + } + }).catch(error=>{}) + } + + // 拒绝 + function revertDivert(id){ + const url = `/users/${username}/applied_projects/${id}/refuse.json`; + Axios.post(url).then(result=>{ + if(result && result.data){ + getList(); + props && props.deleteEvent("apply",1); + } + }).catch(error=>{}) + } + return( +
    + +
    + { + list && list.length > 0 ? +
      + { + list.map((i,k)=>{ + return( +
    • + +
      +

      + {i.user && i.user.name} + {i.time_ago} +

      + +

      申请以【{i.role === "developer" ?"开发者":i.role === "manager" ? "管理者":"报告者"}】身份加入【{i.project && i.project.name}】项目。是否同意?

      + { + i.status === "common" && + + acceptDivert(i.id)}> + 同意 + + revertDivert(i.id)}> + 拒绝 + + + } + { + i.status === "accepted" && 已接受 + } + { + i.status === "refused" && 已拒绝 + } +
      +
      +
    • + ) + }) + } +
    + : + "" + } + {list && list.length === 0 && } + { + total > limit && +
    + {setPage(p)}}/> +
    + } +
    +
    +
    + ) +} +export default Apply; \ No newline at end of file diff --git a/src/forge/Notice/Index.jsx b/src/forge/Notice/Index.jsx index d9d04d59e..94c63804e 100644 --- a/src/forge/Notice/Index.jsx +++ b/src/forge/Notice/Index.jsx @@ -6,6 +6,10 @@ import Loadable from "react-loadable"; import Loading from "../../Loading"; import { Route, Switch } from "react-router-dom"; +const Apply = Loadable({ + loader: () => import("./Apply"), + loading: Loading, +}); const Notify = Loadable({ loader: () => import("./Notify"), loading: Loading, @@ -18,38 +22,62 @@ function Index(props){ const username = props.match.params.username; const pathname = props.history.location.pathname; const user = props.user; - const undo_messages = props.undo_messages; const [ menu , setMenu ] = useState("notify"); - const [ messages , setMessages ] = useState(0); - const [ transferProjects , setTransferProjects ] = useState(0); + const [ messagesCount , setMessagesCount ] = useState(0); + const [ transferCount , setTransferCount ] = useState(0); + const [ applyCount , setApplyCount ] = useState(0); + + const [ flag , setFlag ] = useState(true); + const { current_user } = props; + + useEffect(()=>{ + if((username && current_user && (current_user.login !== username))){ + props.history.push(`/users/${username}`); + } + },[current_user,username]) useEffect(()=>{ if(user){ - setTransferProjects(user.undo_transfer_projects); + setTransferCount(user.undo_transfer_projects); + setApplyCount(user.undo_join_projects); + setMessagesCount(user.undo_messages); } - if(undo_messages){ - setMessages(undo_messages); - } - },[user,undo_messages]) + },[user]) useEffect(()=>{ if(pathname && username){ if(pathname === `/users/${username}/notice`){ setMenu("notify"); + changeNum(user.undo_messages); } if(pathname === `/users/${username}/notice/undo`){ setMenu("undo"); } + if(pathname === `/users/${username}/notice/apply`){ + setMenu("apply"); + } } - },[pathname]) - - function fetchUser(){ - props && props.fetchUser(); - } + },[pathname,user]) function changeNum(){ - fetchUser(); + if(flag){ + messagesCount && props.deleteUndoEvent(messagesCount); + setFlag(false); + } + } + + function deleteEvent(type,count) { + let c = count; + if(type==="apply"){ + setApplyCount(applyCount-count); + }else if(type==="undo"){ + setTransferCount(applyCount-count); + }else{ + setMessagesCount(0); + c = messagesCount; + } + (c || c===0) && props.deleteUndoEvent(c); } return ( @@ -58,27 +86,39 @@ function Index(props){
  • 通知 - {messages ? {messages}:""} + {messagesCount ? {messagesCount}:""}
  • 接收仓库 - {transferProjects ? {transferProjects}:""} + {transferCount ? {transferCount}:""} + +
  • +
  • + + 成员申请 + {applyCount ? {applyCount}:""}
  • + { + return ; + }} + > { - return ; + return ; }} > { - return ; + return ; }} > diff --git a/src/forge/Notice/Index.scss b/src/forge/Notice/Index.scss index a50c34131..b00e18a5a 100644 --- a/src/forge/Notice/Index.scss +++ b/src/forge/Notice/Index.scss @@ -26,7 +26,7 @@ min-width: 23px; text-align: center; background-color: #ffe4b3; - margin-top: 19px; + margin-top: 27px; margin-left: 10px; display: block; } diff --git a/src/forge/Notice/Notify.jsx b/src/forge/Notice/Notify.jsx index c68271b38..761366d3d 100644 --- a/src/forge/Notice/Notify.jsx +++ b/src/forge/Notice/Notify.jsx @@ -13,6 +13,10 @@ function Notify(props){ const [ total , setTotal ] = useState(0); const [ isSpin , setIsSpin ] = useState(true); + useEffect(()=>{ + props && props.deleteEvent("notify",0); + },[]) + useEffect(()=>{ if(username){ setIsSpin(true); @@ -43,7 +47,7 @@ function Notify(props){ return

    取消转移【{project && project.name}】仓库

    case 'common': return

    正在将【{project && project.name}】仓库转移给【{owner && owner.name}】

    - case 'successed': + case 'successed': return

    {project && project.name}】仓库成功转移给【{owner && owner.name}】

    default: return

    拒绝转移【{project && project.name}】仓库

    @@ -53,42 +57,56 @@ function Notify(props){ } } + function renderApplyStatus(status,applied) { + let { project } = applied; + if(status){ + switch(status){ + case 'successed': + return

    已通过你加入【{project && project.name}】项目的申请

    + default: + return

    已拒绝你加入【{project && project.name}】项目的申请

    + } + }else{ + return "" + } + } + return(
    { - list && list.length > 0 ? -
      - { - list.map((i,k)=>{ - return( -
    • - -
      -

      - {i.applied_user && i.applied_user.name} - {i.time_ago} -

      - {renderStatus(i.status,i.applied)} -
      -
    • - ) - }) - } -
    - : - "" - } + list && list.length > 0 ? +
      + { + list.map((i,k)=>{ + return( +
    • + +
      +

      + {i.applied_user && i.applied_user.name} + {i.time_ago} +

      + { i.applied_type === "AppliedProject" ? renderApplyStatus(i.status,i.applied):renderStatus(i.status,i.applied)} +
      +
    • + ) + }) + } +
    + : + "" + } + {list && list.length === 0 && } + { + total > limit && +
    + {setPage(p)}}/> +
    + }
    - {list && list.length === 0 && } - { - total > limit && -
    - {setPage(p)}}/> -
    - }
    ) } diff --git a/src/forge/Notice/UndoEvent.jsx b/src/forge/Notice/UndoEvent.jsx index 68557a9e9..c8c579dc1 100644 --- a/src/forge/Notice/UndoEvent.jsx +++ b/src/forge/Notice/UndoEvent.jsx @@ -42,7 +42,7 @@ function UndoEvent(props){ Axios.post(url).then(result=>{ if(result && result.data){ getList(); - props && props.fetchUser(); + props && props.deleteEvent("undo",1); } }).catch(error=>{}) } @@ -53,7 +53,7 @@ function UndoEvent(props){ Axios.post(url).then(result=>{ if(result && result.data){ getList(); - props && props.fetchUser(); + props && props.deleteEvent("undo",1); } }).catch(error=>{}) } diff --git a/src/forge/Settings/Collaborator.js b/src/forge/Settings/Collaborator.js index 4ae292633..0b94eee5b 100644 --- a/src/forge/Settings/Collaborator.js +++ b/src/forge/Settings/Collaborator.js @@ -34,7 +34,7 @@ function Collaborator(props){ } { nav === "1" ? - + : } diff --git a/src/forge/Team/Group/Setting/GroupMemberSetting.jsx b/src/forge/Team/Group/Setting/GroupMemberSetting.jsx index 847dd6ef4..a0d8ec781 100644 --- a/src/forge/Team/Group/Setting/GroupMemberSetting.jsx +++ b/src/forge/Team/Group/Setting/GroupMemberSetting.jsx @@ -146,7 +146,7 @@ export default ((props) => { <span>团队成员管理</span> - <AddMember getID={getID}/> + <AddMember getID={getID} showNotification={props.showNotification}/>
    diff --git a/src/forge/users/Index.scss b/src/forge/users/Index.scss index 71d06226e..fa8bc2949 100644 --- a/src/forge/users/Index.scss +++ b/src/forge/users/Index.scss @@ -104,6 +104,7 @@ $flex:flex; margin:10px 0px; word-break: break-all; text-align: justify; + font-size: 16px; } .focusBox,.infoBox{ width: 100%!important; diff --git a/src/forge/users/Infos.js b/src/forge/users/Infos.js index a415b3d58..9b292d2eb 100644 --- a/src/forge/users/Infos.js +++ b/src/forge/users/Infos.js @@ -66,7 +66,6 @@ class Infos extends Component { project_type: undefined, route_type: undefined, undo_events:0, - undo_messages:0, menuKey:"0" }; } @@ -124,20 +123,14 @@ class Infos extends Component { }); const { current_user } = this.props; const { username } = this.props.match.params; - const { pathname } = this.props.location; - const { notice } = this.state; let url = `/users/${username || (current_user && current_user.login)}.json`; axios.get(url).then((result) => { let e = result.data && result.data.undo_events; - let p = result.data && result.data.undo_messages; - let n = notice || pathname === `/users/${username}/notice` ; this.setState({ user: result.data, isSpin: false, - undo_events:n ? (e-p) : e, - undo_messages:0, - notice:n + undo_events:e }); }) .catch((error) => { @@ -161,7 +154,6 @@ class Infos extends Component { this.setState({ route_type: undefined, project_type:"notice", - notice:true },()=>{ this.props.history.push(`/users/${user && user.login}/notice`); this.fetchUser(); @@ -190,10 +182,19 @@ class Infos extends Component { resetUserInfo && resetUserInfo(); } + // 修改待办事项右侧的数量 + deleteUndoEvent=(count)=>{ + let { undo_events } = this.state; + let undo = undo_events - count; + this.setState({ + undo_events:undo + }) + } + render() { - const { current_user, mygetHelmetapi , resetUserInfo } = this.props; + const { current_user } = this.props; const { username } = this.props.match.params; - const { user, isSpin, project_type, route_type , undo_events , undo_messages , menuKey } = this.state; + const { user, isSpin, route_type , undo_events , menuKey } = this.state; return (
    @@ -213,7 +214,7 @@ class Infos extends Component { -
    +
    {user && user.username}
    @@ -306,7 +307,7 @@ class Infos extends Component { { - return ; + return ; }} > {}) }