1import { Button, Typography } from '@mui/material';
2import makeStyles from '@mui/styles/makeStyles';
3import { useRef, useState } from 'react';
4import { Link } from 'react-router';
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 const issueTitleInput = useRef<HTMLInputElement>(null);
75
76 function isFormValid() {
77 if (issueTitleInput.current) {
78 return issueTitleInput.current.value.length > 0;
79 } else {
80 return false;
81 }
82 }
83
84 function submitNewTitle() {
85 if (!isFormValid()) return;
86 if (bug.title === issueTitleInput.current?.value) {
87 cancelChange();
88 return;
89 }
90 setTitle({
91 variables: {
92 input: {
93 prefix: bug.id,
94 title: issueTitleInput.current!!.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={issueTitleInput}
121 label="Title"
122 variant="outlined"
123 fullWidth
124 margin="dense"
125 value={issueTitle}
126 onChange={(event: any) => setIssueTitle(event.target.value)}
127 />
128 <div className={classes.editButtonContainer}>
129 <Button
130 className={classes.saveButton}
131 size="small"
132 variant="contained"
133 onClick={() => submitNewTitle()}
134 disabled={issueTitle.length === 0}
135 >
136 Save
137 </Button>
138 <Button size="small" onClick={() => cancelChange()}>
139 Cancel
140 </Button>
141 </div>
142 </form>
143 );
144 }
145
146 function readonlyBugTitle() {
147 return (
148 <div className={classes.headerTitle}>
149 <div>
150 <span className={classes.readOnlyTitle}>{bug.title}</span>
151 <span className={classes.readOnlyId}>{bug.humanId}</span>
152 </div>
153 <IfLoggedIn>
154 {() => (
155 <div className={classes.editButtonContainer}>
156 <Button
157 size="small"
158 variant="contained"
159 onClick={() => setbugTitleEdition(!bugTitleEdition)}
160 >
161 Edit
162 </Button>
163 <Button
164 className={classes.greenButton}
165 size="small"
166 variant="contained"
167 component={Link}
168 to="/new"
169 >
170 New bug
171 </Button>
172 </div>
173 )}
174 </IfLoggedIn>
175 </div>
176 );
177 }
178
179 if (loading) return <div>Loading...</div>;
180 if (error) return <div>Error</div>;
181
182 return (
183 <div className={classes.header}>
184 {bugTitleEdition ? editableBugTitle() : readonlyBugTitle()}
185 <div className="classes.headerSubtitle">
186 <Typography color={'textSecondary'}>
187 <Author author={bug.author} className={classes.author} />
188 {' opened this bug '}
189 <Date date={bug.createdAt} />
190 </Typography>
191 </div>
192 </div>
193 );
194}
195
196export default BugTitleForm;