diff --git a/api/src/controllers/issues.ts b/api/src/controllers/issues.ts index cd7d12b..da274e6 100644 --- a/api/src/controllers/issues.ts +++ b/api/src/controllers/issues.ts @@ -19,7 +19,8 @@ router.get( router.post( '/issues', catchErrors(async (req, res) => { - const issue = await createEntity(Issue, req.body); + const listPosition = await calculateListPosition(req.body); + const issue = await createEntity(Issue, { ...req.body, listPosition }); res.respond({ issue }); }), ); @@ -40,4 +41,15 @@ router.delete( }), ); +const calculateListPosition = async (newIssue: Issue): Promise => { + const issues = await Issue.find({ + where: { projectId: newIssue.projectId, status: newIssue.status }, + }); + const listPositions = issues.map(({ listPosition }) => listPosition); + if (listPositions.length > 0) { + return Math.min(...listPositions) - 1; + } + return 1; +}; + export default router; diff --git a/api/src/entities/Issue.ts b/api/src/entities/Issue.ts index 4f30a81..f02d88b 100644 --- a/api/src/entities/Issue.ts +++ b/api/src/entities/Issue.ts @@ -23,6 +23,7 @@ class Issue extends BaseEntity { type: [is.required(), is.oneOf(Object.values(IssueType))], status: [is.required(), is.oneOf(Object.values(IssueStatus))], priority: [is.required(), is.oneOf(Object.values(IssuePriority))], + listPosition: is.required(), reporterId: is.required(), }; @@ -71,6 +72,9 @@ class Issue extends BaseEntity { ) project: Project; + @Column('integer') + projectId: number; + @OneToMany( () => Comment, comment => comment.issue, diff --git a/client/.eslintrc.json b/client/.eslintrc.json index f2469b4..b2c5d12 100644 --- a/client/.eslintrc.json +++ b/client/.eslintrc.json @@ -28,6 +28,7 @@ "import/no-cycle": 0, "react/no-array-index-key": 0, "react/forbid-prop-types": 0, + "react/prop-types": [2, { "skipUndeclared": true }], "react/state-in-constructor": 0, "react/jsx-props-no-spreading": 0, "jsx-a11y/click-events-have-key-events": 0 diff --git a/client/package-lock.json b/client/package-lock.json index 740e5c4..3fb75f5 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -2733,6 +2733,11 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "deepmerge": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", + "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==" + }, "default-gateway": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", @@ -4179,6 +4184,32 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, + "formik": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/formik/-/formik-2.0.8.tgz", + "integrity": "sha512-PxC9G6EvLdJzMv7z+bsvpI/Euplv2vVgTQebD5yNza4t3fiMBB+iD90VOVTLCyH5Pnv3bljsZiKsIqGp/UNKKg==", + "requires": { + "deepmerge": "^2.1.1", + "hoist-non-react-statics": "^3.3.0", + "lodash": "^4.17.14", + "lodash-es": "^4.17.14", + "react-fast-compare": "^2.0.1", + "scheduler": "^0.17.0", + "tiny-warning": "^1.0.2", + "tslib": "^1.10.0" + }, + "dependencies": { + "scheduler": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.17.0.tgz", + "integrity": "sha512-7rro8Io3tnCPuY4la/NuI5F2yfESpnfZyT6TtkXnSWVkcu0BCDJ+8gk5ozUaFaxpIyNuWAPXrH0yFcSi28fnDA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + } + } + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -6309,6 +6340,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, + "lodash-es": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz", + "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==" + }, "log-symbols": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", @@ -7845,6 +7881,11 @@ "scheduler": "^0.18.0" } }, + "react-fast-compare": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", + "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" + }, "react-is": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", @@ -9459,8 +9500,7 @@ "tslib": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, "tty-browserify": { "version": "0.0.0", diff --git a/client/package.json b/client/package.json index 7465ca1..6eec5a0 100644 --- a/client/package.json +++ b/client/package.json @@ -40,6 +40,7 @@ "axios": "^0.19.0", "color": "^3.1.2", "core-js": "^3.4.7", + "formik": "^2.0.8", "history": "^4.10.1", "jwt-decode": "^2.2.0", "lodash": "^4.17.15", diff --git a/client/src/App/NavbarLeft/index.jsx b/client/src/App/NavbarLeft/index.jsx deleted file mode 100644 index 013ab9e..0000000 --- a/client/src/App/NavbarLeft/index.jsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; - -import { Icon } from 'shared/components'; -import { NavLeft, LogoLink, StyledLogo, Bottom, Item, ItemText } from './Styles'; - -const NavbarLeft = () => ( - - - - - - - Search - - - - Create - - - - - Help - - - -); - -export default NavbarLeft; diff --git a/client/src/App/Routes.jsx b/client/src/App/Routes.jsx index efffb48..a94f506 100644 --- a/client/src/App/Routes.jsx +++ b/client/src/App/Routes.jsx @@ -3,24 +3,17 @@ import { Router, Switch, Route, Redirect } from 'react-router-dom'; import history from 'browserHistory'; import PageError from 'shared/components/PageError'; - -import Project from 'components/Project'; - -import NavbarLeft from './NavbarLeft'; +import Project from 'Project'; import Authenticate from './Authenticate'; -import { Main } from './AppStyles'; const Routes = () => ( -
- - - - - - - -
+ + + + + +
); diff --git a/client/src/App/App.jsx b/client/src/App/index.jsx similarity index 100% rename from client/src/App/App.jsx rename to client/src/App/index.jsx diff --git a/client/src/Project/Board/IssueDetails/Type/Styles.js b/client/src/Project/Board/IssueDetails/Type/Styles.js deleted file mode 100644 index 0743340..0000000 --- a/client/src/Project/Board/IssueDetails/Type/Styles.js +++ /dev/null @@ -1,38 +0,0 @@ -import styled from 'styled-components'; - -import { color, font, mixin } from 'shared/utils/styles'; -import { Button } from 'shared/components'; - -export const TypeButton = styled(Button)` - text-transform: uppercase; - letter-spacing: 0.5px; - color: ${color.textMedium}; - ${font.size(13)} -`; - -export const TypeDropdown = styled.div` - padding-bottom: 6px; -`; - -export const TypeTitle = styled.div` - padding: 10px 0 7px 12px; - text-transform: uppercase; - color: ${color.textMedium}; - ${font.size(12)} -`; - -export const Type = styled.div` - display: flex; - align-items: center; - padding: 7px 12px; - ${mixin.clickable} - &:hover { - background: ${color.backgroundLight}; - } -`; - -export const TypeLabel = styled.div` - padding: 0 5px 0 7px; - text-transform: capitalize; - ${font.size(15)} -`; diff --git a/client/src/Project/Board/IssueDetails/Type/index.jsx b/client/src/Project/Board/IssueDetails/Type/index.jsx deleted file mode 100644 index 4980b6e..0000000 --- a/client/src/Project/Board/IssueDetails/Type/index.jsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { IssueType } from 'shared/constants/issues'; -import { IssueTypeIcon, Tooltip } from 'shared/components'; -import { TypeButton, TypeDropdown, TypeTitle, Type, TypeLabel } from './Styles'; - -const propTypes = { - issue: PropTypes.object.isRequired, - updateIssue: PropTypes.func.isRequired, -}; - -const ProjectBoardIssueDetailsType = ({ issue, updateIssue }) => ( - ( - }> - {`${issue.type}-${issue.id}`} - - )} - renderContent={() => ( - - Change issue type - {Object.values(IssueType).map(type => ( - updateIssue({ type })}> - - {type} - - ))} - - )} - /> -); - -ProjectBoardIssueDetailsType.propTypes = propTypes; - -export default ProjectBoardIssueDetailsType; diff --git a/client/src/Project/Board/Lists/Issue/index.jsx b/client/src/Project/Board/Lists/Issue/index.jsx index 6118a87..6d5493f 100644 --- a/client/src/Project/Board/Lists/Issue/index.jsx +++ b/client/src/Project/Board/Lists/Issue/index.jsx @@ -22,7 +22,7 @@ const ProjectBoardListsIssue = ({ projectUsers, issue, index }) => { {(provided, snapshot) => ( { - const match = useRouteMatch(); - const history = useHistory(); +const ProjectBoard = ({ project, updateLocalIssuesArray }) => { const [filters, setFilters] = useState(defaultFilters); - return ( <>
@@ -36,26 +29,6 @@ const ProjectBoard = ({ project, fetchProject, updateLocalIssuesArray }) => { setFilters={setFilters} /> - ( - history.push(match.url)} - renderContent={modal => ( - - )} - /> - )} - /> ); }; diff --git a/client/src/Project/IssueCreateForm/Styles.js b/client/src/Project/IssueCreateForm/Styles.js new file mode 100644 index 0000000..6be61d7 --- /dev/null +++ b/client/src/Project/IssueCreateForm/Styles.js @@ -0,0 +1,39 @@ +import styled from 'styled-components'; + +import { color, font } from 'shared/utils/styles'; +import { Button, Form } from 'shared/components'; + +export const FormElement = styled(Form.Element)` + padding: 20px 40px; +`; + +export const FormHeading = styled.div` + padding-bottom: 15px; + ${font.size(20)} +`; + +export const SelectItem = styled.div` + display: flex; + align-items: center; + margin-right: 15px; + ${props => props.withBottomMargin && `margin-bottom: 5px;`} +`; + +export const SelectItemLabel = styled.div` + padding: 0 3px 0 6px; +`; + +export const Divider = styled.div` + margin-top: 22px; + border-top: 1px solid ${color.borderLightest}; +`; + +export const Actions = styled.div` + display: flex; + justify-content: flex-end; + padding-top: 30px; +`; + +export const ActionButton = styled(Button)` + margin-left: 10px; +`; diff --git a/client/src/Project/IssueCreateForm/index.jsx b/client/src/Project/IssueCreateForm/index.jsx new file mode 100644 index 0000000..eb2c352 --- /dev/null +++ b/client/src/Project/IssueCreateForm/index.jsx @@ -0,0 +1,169 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { + IssueType, + IssueStatus, + IssuePriority, + IssueTypeCopy, + IssuePriorityCopy, +} from 'shared/constants/issues'; +import toast from 'shared/utils/toast'; +import useApi from 'shared/hooks/api'; +import { Form, IssueTypeIcon, Icon, Avatar, IssuePriorityIcon } from 'shared/components'; +import { + FormHeading, + FormElement, + SelectItem, + SelectItemLabel, + Divider, + Actions, + ActionButton, +} from './Styles'; + +const propTypes = { + project: PropTypes.object.isRequired, + fetchProject: PropTypes.func.isRequired, + modalClose: PropTypes.func.isRequired, +}; + +const ProjectIssueCreateForm = ({ project, fetchProject, modalClose }) => { + const [{ isCreating }, createIssue] = useApi.post('/issues'); + + const typeOptions = Object.values(IssueType).map(type => ({ + value: type, + label: IssueTypeCopy[type], + })); + + const priorityOptions = Object.values(IssuePriority).map(priority => ({ + value: priority, + label: IssuePriorityCopy[priority], + })); + + const userOptions = project.users.map(user => ({ value: user.id, label: user.name })); + + const renderType = ({ value: type }) => ( + + + {IssueTypeCopy[type]} + + ); + + const renderPriority = ({ value: priority }) => ( + + + {IssuePriorityCopy[priority]} + + ); + + const renderUser = ({ value: userId, removeOptionValue }) => { + const user = project.users.find(({ id }) => id === userId); + return ( + removeOptionValue && removeOptionValue()} + > + + {user.name} + {removeOptionValue && } + + ); + }; + + return ( +
{ + try { + await createIssue({ + ...values, + projectId: project.id, + users: values.userIds.map(id => ({ id })), + }); + await fetchProject(); + modalClose(); + } catch (error) { + if (error.data.fields) { + form.setErrors(error.data.fields); + } else { + toast.error(error); + } + } + }} + > + + Create issue + + + + + + + + + + Create Issue + + + Cancel + + + +
+ ); +}; + +ProjectIssueCreateForm.propTypes = propTypes; + +export default ProjectIssueCreateForm; diff --git a/client/src/Project/Board/IssueDetails/Comments/BodyForm/Styles.js b/client/src/Project/IssueDetails/Comments/BodyForm/Styles.js similarity index 100% rename from client/src/Project/Board/IssueDetails/Comments/BodyForm/Styles.js rename to client/src/Project/IssueDetails/Comments/BodyForm/Styles.js diff --git a/client/src/Project/Board/IssueDetails/Comments/BodyForm/index.jsx b/client/src/Project/IssueDetails/Comments/BodyForm/index.jsx similarity index 100% rename from client/src/Project/Board/IssueDetails/Comments/BodyForm/index.jsx rename to client/src/Project/IssueDetails/Comments/BodyForm/index.jsx diff --git a/client/src/Project/Board/IssueDetails/Comments/Comment/Styles.js b/client/src/Project/IssueDetails/Comments/Comment/Styles.js similarity index 100% rename from client/src/Project/Board/IssueDetails/Comments/Comment/Styles.js rename to client/src/Project/IssueDetails/Comments/Comment/Styles.js diff --git a/client/src/Project/Board/IssueDetails/Comments/Comment/index.jsx b/client/src/Project/IssueDetails/Comments/Comment/index.jsx similarity index 100% rename from client/src/Project/Board/IssueDetails/Comments/Comment/index.jsx rename to client/src/Project/IssueDetails/Comments/Comment/index.jsx diff --git a/client/src/Project/Board/IssueDetails/Comments/Create/ProTip/Style.js b/client/src/Project/IssueDetails/Comments/Create/ProTip/Styles.js similarity index 100% rename from client/src/Project/Board/IssueDetails/Comments/Create/ProTip/Style.js rename to client/src/Project/IssueDetails/Comments/Create/ProTip/Styles.js diff --git a/client/src/Project/Board/IssueDetails/Comments/Create/ProTip/index.jsx b/client/src/Project/IssueDetails/Comments/Create/ProTip/index.jsx similarity index 95% rename from client/src/Project/Board/IssueDetails/Comments/Create/ProTip/index.jsx rename to client/src/Project/IssueDetails/Comments/Create/ProTip/index.jsx index 1e1c08b..f33ca22 100644 --- a/client/src/Project/Board/IssueDetails/Comments/Create/ProTip/index.jsx +++ b/client/src/Project/IssueDetails/Comments/Create/ProTip/index.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { KeyCodes } from 'shared/constants/keyCodes'; import { isFocusedElementEditable } from 'shared/utils/dom'; -import { Tip, TipLetter } from './Style'; +import { Tip, TipLetter } from './Styles'; const propTypes = { setFormOpen: PropTypes.func.isRequired, diff --git a/client/src/Project/Board/IssueDetails/Comments/Create/Style.js b/client/src/Project/IssueDetails/Comments/Create/Styles.js similarity index 100% rename from client/src/Project/Board/IssueDetails/Comments/Create/Style.js rename to client/src/Project/IssueDetails/Comments/Create/Styles.js diff --git a/client/src/Project/Board/IssueDetails/Comments/Create/index.jsx b/client/src/Project/IssueDetails/Comments/Create/index.jsx similarity index 99% rename from client/src/Project/Board/IssueDetails/Comments/Create/index.jsx rename to client/src/Project/IssueDetails/Comments/Create/index.jsx index 41f7a5f..a2ed31a 100644 --- a/client/src/Project/Board/IssueDetails/Comments/Create/index.jsx +++ b/client/src/Project/IssueDetails/Comments/Create/index.jsx @@ -6,7 +6,7 @@ import useApi from 'shared/hooks/api'; import toast from 'shared/utils/toast'; import BodyForm from '../BodyForm'; import ProTip from './ProTip'; -import { Create, UserAvatar, Right, FakeTextarea } from './Style'; +import { Create, UserAvatar, Right, FakeTextarea } from './Styles'; const propTypes = { issueId: PropTypes.number.isRequired, diff --git a/client/src/Project/Board/IssueDetails/Comments/Styles.js b/client/src/Project/IssueDetails/Comments/Styles.js similarity index 100% rename from client/src/Project/Board/IssueDetails/Comments/Styles.js rename to client/src/Project/IssueDetails/Comments/Styles.js diff --git a/client/src/Project/Board/IssueDetails/Comments/index.jsx b/client/src/Project/IssueDetails/Comments/index.jsx similarity index 100% rename from client/src/Project/Board/IssueDetails/Comments/index.jsx rename to client/src/Project/IssueDetails/Comments/index.jsx diff --git a/client/src/Project/Board/IssueDetails/Dates/Styles.js b/client/src/Project/IssueDetails/Dates/Styles.js similarity index 100% rename from client/src/Project/Board/IssueDetails/Dates/Styles.js rename to client/src/Project/IssueDetails/Dates/Styles.js diff --git a/client/src/Project/Board/IssueDetails/Dates/index.jsx b/client/src/Project/IssueDetails/Dates/index.jsx similarity index 100% rename from client/src/Project/Board/IssueDetails/Dates/index.jsx rename to client/src/Project/IssueDetails/Dates/index.jsx diff --git a/client/src/Project/Board/IssueDetails/Delete.jsx b/client/src/Project/IssueDetails/Delete.jsx similarity index 100% rename from client/src/Project/Board/IssueDetails/Delete.jsx rename to client/src/Project/IssueDetails/Delete.jsx diff --git a/client/src/Project/Board/IssueDetails/Description/Styles.js b/client/src/Project/IssueDetails/Description/Styles.js similarity index 100% rename from client/src/Project/Board/IssueDetails/Description/Styles.js rename to client/src/Project/IssueDetails/Description/Styles.js diff --git a/client/src/Project/Board/IssueDetails/Description/index.jsx b/client/src/Project/IssueDetails/Description/index.jsx similarity index 62% rename from client/src/Project/Board/IssueDetails/Description/index.jsx rename to client/src/Project/IssueDetails/Description/index.jsx index ceddb71..4eaabba 100644 --- a/client/src/Project/Board/IssueDetails/Description/index.jsx +++ b/client/src/Project/IssueDetails/Description/index.jsx @@ -1,4 +1,4 @@ -import React, { useRef, useState } from 'react'; +import React, { useState } from 'react'; import PropTypes from 'prop-types'; import { getTextContentsFromHtmlString } from 'shared/utils/html'; @@ -11,34 +11,30 @@ const propTypes = { }; const ProjectBoardIssueDetailsDescription = ({ issue, updateIssue }) => { - const $editorRef = useRef(); - const [isPresenting, setPresenting] = useState(true); + const [value, setValue] = useState(issue.description); + const [isEditing, setEditing] = useState(false); const renderPresentingMode = () => isDescriptionEmpty(issue.description) ? ( - setPresenting(false)}>Add a description... + setEditing(true)}>Add a description... ) : ( - setPresenting(false)} /> + setEditing(true)} /> ); const renderEditingMode = () => ( <> - ($editorRef.current = editor)} - /> + - @@ -47,7 +43,7 @@ const ProjectBoardIssueDetailsDescription = ({ issue, updateIssue }) => { return ( <> Description - {isPresenting ? renderPresentingMode() : renderEditingMode()} + {isEditing ? renderEditingMode() : renderPresentingMode()} ); }; diff --git a/client/src/Project/Board/IssueDetails/Feedback/Styles.js b/client/src/Project/IssueDetails/Feedback/Styles.js similarity index 100% rename from client/src/Project/Board/IssueDetails/Feedback/Styles.js rename to client/src/Project/IssueDetails/Feedback/Styles.js diff --git a/client/src/Project/Board/IssueDetails/Feedback/assets/feedback.png b/client/src/Project/IssueDetails/Feedback/assets/feedback.png similarity index 100% rename from client/src/Project/Board/IssueDetails/Feedback/assets/feedback.png rename to client/src/Project/IssueDetails/Feedback/assets/feedback.png diff --git a/client/src/Project/Board/IssueDetails/Feedback/index.jsx b/client/src/Project/IssueDetails/Feedback/index.jsx similarity index 100% rename from client/src/Project/Board/IssueDetails/Feedback/index.jsx rename to client/src/Project/IssueDetails/Feedback/index.jsx diff --git a/client/src/Project/Board/IssueDetails/Loader.jsx b/client/src/Project/IssueDetails/Loader.jsx similarity index 100% rename from client/src/Project/Board/IssueDetails/Loader.jsx rename to client/src/Project/IssueDetails/Loader.jsx diff --git a/client/src/Project/Board/IssueDetails/Priority/Styles.js b/client/src/Project/IssueDetails/Priority/Styles.js similarity index 93% rename from client/src/Project/Board/IssueDetails/Priority/Styles.js rename to client/src/Project/IssueDetails/Priority/Styles.js index 73bae5b..d5c1434 100644 --- a/client/src/Project/Board/IssueDetails/Priority/Styles.js +++ b/client/src/Project/IssueDetails/Priority/Styles.js @@ -18,7 +18,6 @@ export const Priority = styled.div` `; export const Label = styled.div` - text-transform: capitalize; padding: 0 3px 0 8px; ${font.size(14.5)} `; diff --git a/client/src/Project/Board/IssueDetails/Priority/index.jsx b/client/src/Project/IssueDetails/Priority/index.jsx similarity index 84% rename from client/src/Project/Board/IssueDetails/Priority/index.jsx rename to client/src/Project/IssueDetails/Priority/index.jsx index 77a0ec9..863eb24 100644 --- a/client/src/Project/Board/IssueDetails/Priority/index.jsx +++ b/client/src/Project/IssueDetails/Priority/index.jsx @@ -1,14 +1,11 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { invert } from 'lodash'; -import { IssuePriority } from 'shared/constants/issues'; +import { IssuePriority, IssuePriorityCopy } from 'shared/constants/issues'; import { Select, IssuePriorityIcon } from 'shared/components'; import { Priority, Label } from './Styles'; import { SectionTitle } from '../Styles'; -const IssuePriorityCopy = invert(IssuePriority); - const propTypes = { issue: PropTypes.object.isRequired, updateIssue: PropTypes.func.isRequired, @@ -18,13 +15,14 @@ const ProjectBoardIssueDetailsPriority = ({ issue, updateIssue }) => { const renderPriorityItem = (priority, isValue) => ( - + ); return ( <> Priority ({ diff --git a/client/src/Project/Board/IssueDetails/Styles.js b/client/src/Project/IssueDetails/Styles.js similarity index 100% rename from client/src/Project/Board/IssueDetails/Styles.js rename to client/src/Project/IssueDetails/Styles.js diff --git a/client/src/Project/Board/IssueDetails/Title/Styles.js b/client/src/Project/IssueDetails/Title/Styles.js similarity index 100% rename from client/src/Project/Board/IssueDetails/Title/Styles.js rename to client/src/Project/IssueDetails/Title/Styles.js diff --git a/client/src/Project/Board/IssueDetails/Title/index.jsx b/client/src/Project/IssueDetails/Title/index.jsx similarity index 100% rename from client/src/Project/Board/IssueDetails/Title/index.jsx rename to client/src/Project/IssueDetails/Title/index.jsx diff --git a/client/src/Project/Board/IssueDetails/Tracking/Styles.js b/client/src/Project/IssueDetails/Tracking/Styles.js similarity index 100% rename from client/src/Project/Board/IssueDetails/Tracking/Styles.js rename to client/src/Project/IssueDetails/Tracking/Styles.js diff --git a/client/src/Project/Board/IssueDetails/Tracking/index.jsx b/client/src/Project/IssueDetails/Tracking/index.jsx similarity index 100% rename from client/src/Project/Board/IssueDetails/Tracking/index.jsx rename to client/src/Project/IssueDetails/Tracking/index.jsx diff --git a/client/src/Project/IssueDetails/Type/Styles.js b/client/src/Project/IssueDetails/Type/Styles.js new file mode 100644 index 0000000..21c3d28 --- /dev/null +++ b/client/src/Project/IssueDetails/Type/Styles.js @@ -0,0 +1,21 @@ +import styled from 'styled-components'; + +import { color, font } from 'shared/utils/styles'; +import { Button } from 'shared/components'; + +export const TypeButton = styled(Button)` + text-transform: uppercase; + letter-spacing: 0.5px; + color: ${color.textMedium}; + ${font.size(13)} +`; + +export const Type = styled.div` + display: flex; + align-items: center; +`; + +export const TypeLabel = styled.div` + padding: 0 5px 0 7px; + ${font.size(15)} +`; diff --git a/client/src/Project/IssueDetails/Type/index.jsx b/client/src/Project/IssueDetails/Type/index.jsx new file mode 100644 index 0000000..9d4a167 --- /dev/null +++ b/client/src/Project/IssueDetails/Type/index.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { IssueType, IssueTypeCopy } from 'shared/constants/issues'; +import { IssueTypeIcon, Select } from 'shared/components'; +import { TypeButton, Type, TypeLabel } from './Styles'; + +const propTypes = { + issue: PropTypes.object.isRequired, + updateIssue: PropTypes.func.isRequired, +}; + +const ProjectBoardIssueDetailsType = ({ issue, updateIssue }) => ( + updateIssue({ userIds, users: userIds.map(getUserById) }); }} renderValue={({ value, removeOptionValue }) => - renderUserValue(getUserById(value), true, removeOptionValue) + renderUser(getUserById(value), true, removeOptionValue) } - renderOption={({ value }) => renderUserOption(getUserById(value))} + renderOption={({ value }) => renderUser(getUserById(value), false)} /> ); @@ -60,12 +54,13 @@ const ProjectBoardIssueDetailsUsers = ({ issue, updateIssue, projectUsers }) => <> Reporter