/* * << * Davinci * == * Copyright (C) 2016 - 2017 EDP * == * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * >> */ import React, { useMemo, useEffect, useState, ReactElement, useCallback, useRef, useImperativeHandle } from 'react' import classnames from 'classnames' import { connect } from 'react-redux' import { Row, Col, Tooltip, Popconfirm, Icon, Modal, Button } from 'antd' import saga from './sagas' import reducer from './reducer' import { compose } from 'redux' import { makeSelectLoginUser } from '../App/selectors' import { makeSelectProjects, makeSelectSearchProject, makeSelectStarUserList, makeSelectCollectProjects } from './selectors' import { ProjectActions } from './actions' import injectReducer from 'utils/injectReducer' import { createStructuredSelector } from 'reselect' import injectSaga from 'utils/injectSaga' import ProjectsForm from './component/ProjectForm' import reducerOrganization from '../Organizations/reducer' import { IOrganization } from '../Organizations/types' import sagaOrganization from '../Organizations/sagas' import { OrganizationActions } from '../Organizations/actions' import { makeSelectOrganizations } from '../Organizations/selectors' import { checkNameUniqueAction } from '../App/actions' import ComponentPermission from '../Account/components/checkMemberPermission' import Star from 'components/StarPanel/Star' import HistoryStack from '../Organizations/component/historyStack' import { RouteComponentWithParams } from 'utils/types' import { IProject, IProjectFormFieldProps, IProjectsProps, projectType, IProjectType, IToolbarProps, projectTypeSmall } from './types' import { FormComponentProps } from 'antd/lib/form/Form' import { uuid } from 'app/utils/util' import { useResize } from './hooks/useResize' import ProjectItem from './component/ProjectItem' const StarUserModal = Star.StarUser const historyStack = new HistoryStack() const styles = require('../Organizations/Project.less') function enhanceInput(props, ref) { const inputRef = useRef(null) useImperativeHandle(ref, () => ({})) return } const EnhanceInput = React.forwardRef(enhanceInput) const Toolbar: React.FC = React.memo( ({ pType, setPType, setKeywords, searchKeywords, showProForm }) => { const searchRef = useRef(null) const documentWidth = useResize() const checkoutType = useCallback( (type) => { return () => { if (setPType) { setPType(type) } } }, [pType] ) const menus = useMemo(() => { const types = ['all', 'join', 'create', 'favorite', 'history'] return types.map((t: IProjectType) => { const classNames = classnames({ [styles.selectMenu]: pType === t, [styles.menuitem]: true }) return (

{documentWidth <= 1200 ? projectTypeSmall[t] : projectType[t]}

) }) }, [pType, documentWidth]) const getKeywords = useCallback( (e) => { setKeywords(e.target.value) }, [setKeywords] ) const addPro = useCallback( (e) => { if (showProForm) { showProForm('add', {}, e) } }, [showProForm] ) return (
{menus}
) } ) function stopPPG(e: React.MouseEvent) { if (e) { e.stopPropagation() } return } const Projects: React.FC = React.memo( ({ projects, onLoadProjects, onLoadOrganizations, organizations, loginUser, onLoadCollectProjects, collectProjects, history, onAddProject, onCheckUniqueName, onTransferProject, onDeleteProject, onClickCollectProjects, starUserList, onStarProject, onGetProjectStarUser, onEditProject }) => { const [formKey, setFormKey] = useState(() => uuid(8, 16)) const [projectType, setProjectType] = useState('all') const [formVisible, setFormVisible] = useState(false) const [formType, setFormType] = useState('add') const [currentPro, setCurrentPro] = useState({}) const [modalLoading, setModalLoading] = useState(false) const [searchKeywords, setKeywords] = useState('') const [starModalVisble, setStarModalVisble] = useState(false) const onCloseStarModal = useCallback(() => { setStarModalVisble(false) }, [starModalVisble]) const getStarProjectUserList = useCallback( (id) => () => { if (onGetProjectStarUser) { onGetProjectStarUser(id) } setStarModalVisble(true) }, [setStarModalVisble, onGetProjectStarUser] ) let proForm: FormComponentProps = null useEffect(() => { window.localStorage.setItem('inDataService', '') }, []) useEffect(() => { if (onLoadProjects) { onLoadProjects() } if (onLoadOrganizations) { onLoadOrganizations() } if (onLoadCollectProjects) { onLoadCollectProjects() } }, ['nf']) useEffect(() => { if (projects) { historyStack.init(projects) } }, [projects]) const loginUserId = useMemo(() => { return loginUser && loginUser.id }, [loginUser]) const checkoutFormVisible = useCallback(() => { setFormVisible(true) }, [formVisible]) const hideProForm = useCallback(() => { setFormVisible(false) }, [formVisible]) const deletePro = useCallback( (proId: number, isFavorite: boolean) => { if (onDeleteProject) { onDeleteProject(proId, () => { if (isFavorite) { if (onLoadCollectProjects) { onLoadCollectProjects() } } if (onLoadProjects) { onLoadProjects() } }) } }, [formVisible] ) const favoritePro = useCallback( (proId: number, isFavorite: boolean) => { if (onClickCollectProjects) { onClickCollectProjects(isFavorite, proId, () => { if (onLoadCollectProjects) { onLoadCollectProjects() } if (onLoadProjects) { onLoadProjects() } }) } }, [formVisible] ) const showProForm = useCallback( (formType, project: IProject, e: React.MouseEvent) => { stopPPG(e) setFormVisible(true) setCurrentPro(project) setFormType(formType) }, [formVisible, formType, currentPro] ) const onModalOk = useCallback(() => { proForm.form.validateFieldsAndScroll( (err, values: IProjectFormFieldProps) => { if (!err) { setModalLoading(true) if (formType === 'add') { onAddProject( { ...values, visibility: values.visibility === 'true' ? true : false, pic: `${Math.ceil(Math.random() * 19)}` }, () => { hideProForm() onLoadProjects() setModalLoading(false) const newFormKey = uuid(8, 16) setFormKey(newFormKey) } ) } else { onEditProject( { ...values, ...{ orgId: Number(values.orgId) } }, () => { hideProForm() onLoadProjects() setModalLoading(false) const newFormKey = uuid(8, 16) setFormKey(newFormKey) } ) } } } ) }, [formVisible, formType, setFormKey]) const onTransfer = useCallback(() => { proForm.form.validateFieldsAndScroll((err, values) => { if (!err) { setModalLoading(true) const { id, orgId } = values onTransferProject(id, Number(orgId)) hideProForm() const newFormKey = uuid(8, 16) setFormKey(newFormKey) } }) }, [formVisible, setFormKey]) const checkNameUnique = useCallback( (rule, value = '', callback) => { const fieldsValue = proForm.form.getFieldsValue() const { orgId, id } = fieldsValue onCheckUniqueName( 'project', { name: value, orgId, id }, () => { callback() }, (err) => { callback(err) } ) }, [formVisible] ) const getProjectsBySearch = useMemo(() => { const { proIdList } = historyStack.getAll() function filterByKeyword(arr: IProject[]) { return ( Array.isArray(arr) && arr.filter( (pro: IProject) => pro.name.toUpperCase().indexOf(searchKeywords.toUpperCase()) > -1 ) ) } function filterByProjectType(arr: IProject[]) { if (Array.isArray(arr)) { switch (projectType) { case 'create': return arr.filter( (pro) => pro.createBy && pro.createBy.id === loginUserId ) case 'join': return arr.filter( (pro) => pro.createBy && pro.createBy.id !== loginUserId ) case 'favorite': return arr.filter((pro) => pro.isFavorites) case 'history': return proIdList.reduce((iteratee, pid) => { const pl = arr.find((pro) => pro.id === pid) if (pl) { iteratee.push(pl) } return iteratee }, []) case 'all': return arr default: return [] } } } function pushForkTagProjects(arr: IProject[]) { const favoriteProjectsId = Array.isArray(collectProjects) && collectProjects.length > 0 && collectProjects.map((col) => col.id) return Array.isArray(arr) ? arr.map((pro) => { return favoriteProjectsId.includes && favoriteProjectsId.includes(pro.id) ? { ...pro, isFavorites: true } : pro }) : [] } return compose( filterByProjectType, filterByKeyword, pushForkTagProjects )(projects) }, [projects, projectType, searchKeywords, loginUserId, collectProjects]) const ProjectItems: ReactElement[] = useMemo(() => { const items = Array.isArray(projects) ? getProjectsBySearch.map((pro: IProject, index) => { const { pic, name, description, createBy, isStar, isFavorites, id, starNum, orgId } = pro const isMimePro = !!(createBy && createBy.id === loginUserId) const getTagType = (function(mime, favorite) { const tagType = [] if (mime) { tagType.push({ text: '创建', color: '#108EE9' }) } else { tagType.push({ text: '参与', color: '#FA8C15' }) } return tagType })(isMimePro, isFavorites) const starProject = (id) => () => { onStarProject(id, () => { if (onLoadProjects) { onLoadProjects() } }) } const toProject = () => { history.push(`/project/${id}`) saveHistory(pro) } const saveHistory = (pro) => historyStack.pushNode(pro) const currentOrganization: IOrganization = organizations.find( (org) => org.id === orgId ) const CreateButton = ComponentPermission( currentOrganization, '' )(Icon) const isHistoryType = !!(projectType && projectType === 'history') const favoriteProject = (e: React.MouseEvent) => { const { id, isFavorites } = pro stopPPG(e) if (favoritePro) { favoritePro(id, isFavorites) } } const transferPro = (e: React.MouseEvent) => { stopPPG(e) if (showProForm) { showProForm('transfer', pro, e) } } const editPro = (e: React.MouseEvent) => { stopPPG(e) if (showProForm) { showProForm('edit', pro, e) } } const deleteProject = (e: React.MouseEvent) => { const { id, isFavorites } = pro if (deletePro) { deletePro(id, isFavorites) } stopPPG(e) } const { Favorite, Transfer, Edit, Delete } = (function() { const favoriteClassName = classnames({ [styles.ft16]: true, [styles.mainColor]: isFavorites }) const themeFavorite = isFavorites ? 'filled' : 'outlined' const Favorite = !isMimePro ? ( ) : ( [] ) const Transfer = ( ) const Edit = ( ) const Delete = ( ) return { Edit, Favorite, Transfer, Delete } })() return (
{!isHistoryType ? Edit : ''} {Favorite} {!isHistoryType ? Transfer : ''} {!isHistoryType ? Delete : ''}
) }) : [] return items }, [ getProjectsBySearch, projectType, projects, onLoadProjects, onStarProject, onGetProjectStarUser, loginUserId, organizations ]) return (
{projects ? ( projects.length > 0 ? (
{ProjectItems}
) : (

无项目

) ) : ( '' )}
{ proForm = ref }} />
) } ) const mapStateToProps = createStructuredSelector({ projects: makeSelectProjects(), loginUser: makeSelectLoginUser(), starUserList: makeSelectStarUserList(), organizations: makeSelectOrganizations(), searchProject: makeSelectSearchProject(), collectProjects: makeSelectCollectProjects() }) export function mapDispatchToProps(dispatch) { return { onLoadProjects: () => dispatch(ProjectActions.loadProjects()), onSearchProject: (param) => dispatch(ProjectActions.searchProject(param)), onLoadProjectDetail: (id) => dispatch(ProjectActions.loadProjectDetail(id)), onLoadCollectProjects: () => dispatch(ProjectActions.loadCollectProjects()), onLoadOrganizations: () => dispatch(OrganizationActions.loadOrganizations()), onGetProjectStarUser: (id) => dispatch(ProjectActions.getProjectStarUser(id)), onStarProject: (id, resolve) => dispatch(ProjectActions.unStarProject(id, resolve)), onTransferProject: (id, orgId) => dispatch(ProjectActions.transferProject(id, orgId)), onDeleteProject: (id, resolve) => dispatch(ProjectActions.deleteProject(id, resolve)), onAddProject: (project, resolve) => dispatch(ProjectActions.addProject(project, resolve)), onEditProject: (project, resolve) => dispatch(ProjectActions.editProject(project, resolve)), onCheckUniqueName: (pathname, data, resolve, reject) => dispatch(checkNameUniqueAction(pathname, data, resolve, reject)), onClickCollectProjects: (isFavorite, proId, result) => dispatch(ProjectActions.clickCollectProjects(isFavorite, proId, result)) } } const withConnect = connect(mapStateToProps, mapDispatchToProps) const withReducer = injectReducer({ key: 'project', reducer }) const withSaga = injectSaga({ key: 'project', saga }) const withOrganizationReducer = injectReducer({ key: 'organization', reducer: reducerOrganization }) const withOrganizationSaga = injectSaga({ key: 'organization', saga: sagaOrganization }) export default compose( withReducer, withOrganizationReducer, withSaga, withOrganizationSaga, withConnect )(Projects)