1import React, { useState } from 'react';
2import { Link } from 'react-router-dom';
3
4import { Button, makeStyles, Typography } from '@material-ui/core';
5
6import { TimelineDocument } from '../../pages/bug/TimelineQuery.generated';
7import IfLoggedIn from '../IfLoggedIn/IfLoggedIn';
8import Author from 'src/components/Author';
9import Date from 'src/components/Date';
10import { BugFragment } from 'src/pages/bug/Bug.generated';
11
12import BugTitleInput from './BugTitleInput';
13import { useSetTitleMutation } from './SetTitle.generated';
14
15/**
16 * Css in JS styles
17 */
18const useStyles = makeStyles((theme) => ({
19 header: {
20 display: 'flex',
21 flexDirection: 'column',
22 },
23 headerTitle: {
24 display: 'flex',
25 flexDirection: 'row',
26 justifyContent: 'space-between',
27 },
28 readOnlyTitle: {
29 ...theme.typography.h5,
30 },
31 readOnlyId: {
32 ...theme.typography.subtitle1,
33 marginLeft: theme.spacing(1),
34 },
35 editButtonContainer: {
36 display: 'flex',
37 flexDirection: 'row',
38 justifyContent: 'flex-start',
39 alignItems: 'center',
40 minWidth: 200,
41 marginLeft: theme.spacing(2),
42 },
43 greenButton: {
44 marginLeft: theme.spacing(1),
45 backgroundColor: theme.palette.success.main,
46 color: theme.palette.success.contrastText,
47 '&:hover': {
48 backgroundColor: theme.palette.success.dark,
49 color: theme.palette.primary.contrastText,
50 },
51 },
52 saveButton: {
53 marginRight: theme.spacing(1),
54 },
55 author: {
56 fontWeight: 'bold',
57 color: theme.palette.text.secondary,
58 },
59}));
60
61interface Props {
62 bug: BugFragment;
63}
64
65/**
66 * Component for bug title change
67 * @param bug Selected bug in list page
68 */
69function BugTitleForm({ bug }: Props) {
70 const [bugTitleEdition, setbugTitleEdition] = useState(false);
71 const [setTitle, { loading, error }] = useSetTitleMutation();
72 const [issueTitle, setIssueTitle] = useState(bug.title);
73 const classes = useStyles();
74 let issueTitleInput: any;
75
76 function isFormValid() {
77 if (issueTitleInput) {
78 return issueTitleInput.value.length > 0;
79 } else {
80 return false;
81 }
82 }
83
84 function submitNewTitle() {
85 if (!isFormValid()) return;
86 if (bug.title === issueTitleInput.value) {
87 cancelChange();
88 return;
89 }
90 setTitle({
91 variables: {
92 input: {
93 prefix: bug.humanId,
94 title: issueTitleInput.value,
95 },
96 },
97 refetchQueries: [
98 // TODO: update the cache instead of refetching
99 {
100 query: TimelineDocument,
101 variables: {
102 id: bug.id,
103 first: 100,
104 },
105 },
106 ],
107 awaitRefetchQueries: true,
108 }).then(() => setbugTitleEdition(false));
109 }
110
111 function cancelChange() {
112 setIssueTitle(bug.title);
113 setbugTitleEdition(false);
114 }
115
116 function editableBugTitle() {
117 return (
118 <form className={classes.headerTitle}>
119 <BugTitleInput
120 inputRef={(node) => {
121 issueTitleInput = node;
122 }}
123 label="Title"
124 variant="outlined"
125 fullWidth
126 margin="dense"
127 value={issueTitle}
128 onChange={(event: any) => setIssueTitle(event.target.value)}
129 />
130 <div className={classes.editButtonContainer}>
131 <Button
132 className={classes.saveButton}
133 size="small"
134 variant="contained"
135 onClick={() => submitNewTitle()}
136 disabled={issueTitle.length === 0}
137 >
138 Save
139 </Button>
140 <Button size="small" onClick={() => cancelChange()}>
141 Cancel
142 </Button>
143 </div>
144 </form>
145 );
146 }
147
148 function readonlyBugTitle() {
149 return (
150 <div className={classes.headerTitle}>
151 <div>
152 <span className={classes.readOnlyTitle}>{bug.title}</span>
153 <span className={classes.readOnlyId}>{bug.humanId}</span>
154 </div>
155 <IfLoggedIn>
156 {() => (
157 <div className={classes.editButtonContainer}>
158 <Button
159 size="small"
160 variant="contained"
161 onClick={() => setbugTitleEdition(!bugTitleEdition)}
162 >
163 Edit
164 </Button>
165 <Button
166 className={classes.greenButton}
167 size="small"
168 variant="contained"
169 component={Link}
170 to="/new"
171 >
172 New bug
173 </Button>
174 </div>
175 )}
176 </IfLoggedIn>
177 </div>
178 );
179 }
180
181 if (loading) return <div>Loading...</div>;
182 if (error) return <div>Error</div>;
183
184 return (
185 <div className={classes.header}>
186 {bugTitleEdition ? editableBugTitle() : readonlyBugTitle()}
187 <div className="classes.headerSubtitle">
188 <Typography color={'textSecondary'}>
189 <Author author={bug.author} className={classes.author} />
190 {' opened this bug '}
191 <Date date={bug.createdAt} />
192 </Typography>
193 </div>
194 </div>
195 );
196}
197
198export default BugTitleForm;