Skip to content

Commit 74eb072

Browse files
committed
refactor(tsx): convert RepoDetails view
1 parent 71d54cf commit 74eb072

File tree

2 files changed

+135
-101
lines changed

2 files changed

+135
-101
lines changed

src/ui/views/RepoDetails/Components/AddUser.jsx renamed to src/ui/views/RepoDetails/Components/AddUser.tsx

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React, { useState, useEffect } from 'react';
2-
import PropTypes from 'prop-types';
32
import InputLabel from '@material-ui/core/InputLabel';
43
import FormControl from '@material-ui/core/FormControl';
54
import FormHelperText from '@material-ui/core/FormHelperText';
@@ -18,18 +17,33 @@ import { addUser } from '../../../services/repo';
1817
import { getUsers } from '../../../services/user';
1918
import { PersonAdd } from '@material-ui/icons';
2019

21-
function AddUserDialog(props) {
22-
const repoName = props.repoName;
23-
const type = props.type;
24-
const refreshFn = props.refreshFn;
25-
const [username, setUsername] = useState('');
26-
const [data, setData] = useState([]);
27-
const [, setAuth] = useState(true);
28-
const [isLoading, setIsLoading] = useState(false);
29-
const [isError, setIsError] = useState(false);
30-
const [error, setError] = useState('');
31-
const [tip, setTip] = useState(false);
32-
const { onClose, open } = props;
20+
interface User {
21+
username: string;
22+
gitAccount: string;
23+
}
24+
25+
interface AddUserDialogProps {
26+
repoName: string;
27+
type: string;
28+
refreshFn: () => void;
29+
open: boolean;
30+
onClose: () => void;
31+
}
32+
33+
const AddUserDialog: React.FC<AddUserDialogProps> = ({
34+
repoName,
35+
type,
36+
refreshFn,
37+
open,
38+
onClose,
39+
}) => {
40+
const [username, setUsername] = useState<string>('');
41+
const [data, setData] = useState<User[]>([]);
42+
const [, setAuth] = useState<boolean>(true);
43+
const [isLoading, setIsLoading] = useState<boolean>(false);
44+
const [isError, setIsError] = useState<boolean>(false);
45+
const [error, setError] = useState<string>('');
46+
const [tip, setTip] = useState<boolean>(false);
3347

3448
const handleClose = () => {
3549
setError('');
@@ -41,8 +55,8 @@ function AddUserDialog(props) {
4155
refreshFn();
4256
};
4357

44-
const handleChange = (event) => {
45-
setUsername(event.target.value);
58+
const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => {
59+
setUsername(event.target.value as string);
4660
};
4761

4862
const add = async () => {
@@ -53,29 +67,24 @@ function AddUserDialog(props) {
5367
handleClose();
5468
} catch (e) {
5569
setIsLoading(false);
56-
if (e.message) {
57-
setError(JSON.stringify(e));
70+
if (e instanceof Error) {
71+
setError(e.message);
5872
} else {
59-
setError(e.toString());
73+
setError('An unknown error occurred');
6074
}
6175
}
6276
};
6377

64-
const inputStyle = {
78+
const inputStyle: React.CSSProperties = {
6579
width: '100%',
6680
};
6781

6882
useEffect(() => {
6983
getUsers(setIsLoading, setData, setAuth, setIsError, {});
70-
}, [props]);
84+
}, []);
7185

7286
if (isError) return <div>Something went wrong ...</div>;
7387

74-
let spinner;
75-
if (isLoading) {
76-
spinner = <CircularProgress />;
77-
}
78-
7988
return (
8089
<>
8190
<Snackbar
@@ -96,7 +105,9 @@ function AddUserDialog(props) {
96105
maxWidth='md'
97106
>
98107
<DialogTitle id='simple-dialog-title'>
99-
Add a user...<p>{error}</p> {spinner}
108+
Add a user...
109+
<p>{error}</p>
110+
{isLoading && <CircularProgress />}
100111
</DialogTitle>
101112
<Card>
102113
<CardBody>
@@ -134,20 +145,16 @@ function AddUserDialog(props) {
134145
</Dialog>
135146
</>
136147
);
137-
}
138-
139-
AddUserDialog.propTypes = {
140-
onClose: PropTypes.func.isRequired,
141-
open: PropTypes.bool.isRequired,
142-
refreshFn: PropTypes.func.isRequired,
143148
};
144149

145-
export default function AddUser(props) {
146-
const [open, setOpen] = React.useState(false);
150+
interface AddUserProps {
151+
repoName: string;
152+
type: string;
153+
refreshFn: () => void;
154+
}
147155

148-
const repoName = props.repoName;
149-
const type = props.type;
150-
const refreshFn = props.refreshFn;
156+
const AddUser: React.FC<AddUserProps> = ({ repoName, type, refreshFn }) => {
157+
const [open, setOpen] = useState<boolean>(false);
151158

152159
const handleClickOpen = () => {
153160
setOpen(true);
@@ -160,7 +167,7 @@ export default function AddUser(props) {
160167
return (
161168
<>
162169
<Button variant='outlined' color='success' onClick={handleClickOpen}>
163-
<PersonAdd></PersonAdd>
170+
<PersonAdd />
164171
</Button>
165172
<AddUserDialog
166173
repoName={repoName}
@@ -171,4 +178,6 @@ export default function AddUser(props) {
171178
/>
172179
</>
173180
);
174-
}
181+
};
182+
183+
export default AddUser;

src/ui/views/RepoDetails/RepoDetails.jsx renamed to src/ui/views/RepoDetails/RepoDetails.tsx

Lines changed: 87 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -21,45 +21,73 @@ import { UserContext } from '../../../context';
2121
import CodeActionButton from '../../components/CustomButtons/CodeActionButton';
2222
import { Box } from '@material-ui/core';
2323

24+
interface RepoData {
25+
project: string;
26+
name: string;
27+
proxyURL: string;
28+
url: string;
29+
users: {
30+
canAuthorise: string[];
31+
canPush: string[];
32+
};
33+
}
34+
35+
export interface UserContextType {
36+
user: {
37+
admin: boolean;
38+
};
39+
}
40+
2441
const useStyles = makeStyles((theme) => ({
2542
root: {
2643
'& .MuiTextField-root': {
2744
margin: theme.spacing(1),
2845
width: '100%',
2946
},
3047
},
48+
table: {
49+
minWidth: 650,
50+
},
3151
}));
3252

33-
export default function RepoDetails() {
53+
const RepoDetails: React.FC = () => {
3454
const navigate = useNavigate();
3555
const classes = useStyles();
36-
const [data, setData] = useState([]);
56+
const [data, setData] = useState<RepoData | null>(null);
3757
const [, setAuth] = useState(true);
3858
const [isLoading, setIsLoading] = useState(true);
3959
const [isError, setIsError] = useState(false);
40-
const { user } = useContext(UserContext);
41-
const { id: repoName } = useParams();
60+
const { user } = useContext<UserContextType>(UserContext);
61+
const { id: repoName } = useParams<{ id: string }>();
4262

4363
useEffect(() => {
44-
getRepo(setIsLoading, setData, setAuth, setIsError, repoName);
45-
}, []);
64+
if (repoName) {
65+
getRepo(setIsLoading, setData, setAuth, setIsError, repoName);
66+
}
67+
}, [repoName]);
4668

47-
const removeUser = async (userToRemove, action) => {
69+
const removeUser = async (userToRemove: string, action: 'authorise' | 'push') => {
70+
if (!repoName) return;
4871
await deleteUser(userToRemove, repoName, action);
4972
getRepo(setIsLoading, setData, setAuth, setIsError, repoName);
5073
};
5174

52-
const removeRepository = async (name) => {
75+
const removeRepository = async (name: string) => {
5376
await deleteRepo(name);
5477
navigate('/dashboard/repo', { replace: true });
5578
};
5679

57-
const refresh = () => getRepo(setIsLoading, setData, setAuth, setIsError, repoName);
80+
const refresh = () => {
81+
if (repoName) {
82+
getRepo(setIsLoading, setData, setAuth, setIsError, repoName);
83+
}
84+
};
5885

5986
if (isLoading) return <div>Loading...</div>;
6087
if (isError) return <div>Something went wrong ...</div>;
88+
if (!data) return <div>No repository data found</div>;
6189

62-
const { project: org, name, proxyURL } = data || {};
90+
const { project: org, name, proxyURL } = data;
6391
const cloneURL = `${proxyURL}/${org}/${name}.git`;
6492

6593
return (
@@ -74,7 +102,7 @@ export default function RepoDetails() {
74102
color='secondary'
75103
onClick={() => removeRepository(data.name)}
76104
>
77-
<Delete></Delete>
105+
<Delete />
78106
</Button>
79107
</div>
80108
)}
@@ -86,10 +114,11 @@ export default function RepoDetails() {
86114
<GridContainer>
87115
<GridItem xs={1} sm={1} md={1}>
88116
<img
89-
width={'75px'}
117+
width='75px'
90118
style={{ borderRadius: '5px' }}
91119
src={`https://github.com/${data.project}.png`}
92-
></img>
120+
alt={`${data.project} logo`}
121+
/>
93122
</GridItem>
94123
<GridItem xs={2} sm={2} md={2}>
95124
<FormLabel component='legend'>Organization</FormLabel>
@@ -130,11 +159,11 @@ export default function RepoDetails() {
130159
<GridContainer>
131160
<GridItem xs={12} sm={12} md={12}>
132161
<h3>
133-
<Visibility></Visibility> Reviewers
162+
<Visibility /> Reviewers
134163
</h3>
135164
{user.admin && (
136165
<div style={{ textAlign: 'right' }}>
137-
<AddUser repoName={repoName} type='authorise' refreshFn={refresh}></AddUser>
166+
<AddUser repoName={repoName || ''} type='authorise' refreshFn={refresh} />
138167
</div>
139168
)}
140169
<TableContainer component={Paper}>
@@ -146,73 +175,67 @@ export default function RepoDetails() {
146175
</TableRow>
147176
</TableHead>
148177
<TableBody>
149-
{data.users.canAuthorise.map((row) => {
150-
if (row)
151-
return (
152-
<TableRow key={row}>
153-
<TableCell align='left'>
154-
<a href={`/dashboard/admin/user/${row}`}>{row}</a>
155-
</TableCell>
156-
{user.admin && (
157-
<TableCell align='right' component='th' scope='row'>
158-
<Button
159-
variant='contained'
160-
color='secondary'
161-
onClick={() => removeUser(row, 'authorise')}
162-
>
163-
<RemoveCircle></RemoveCircle>
164-
</Button>
165-
</TableCell>
166-
)}
167-
</TableRow>
168-
);
169-
})}
178+
{data.users.canAuthorise.map((row) => (
179+
<TableRow key={row}>
180+
<TableCell align='left'>
181+
<a href={`/dashboard/user/${row}`}>{row}</a>
182+
</TableCell>
183+
{user.admin && (
184+
<TableCell align='right' component='th' scope='row'>
185+
<Button
186+
variant='contained'
187+
color='secondary'
188+
onClick={() => removeUser(row, 'authorise')}
189+
>
190+
<RemoveCircle />
191+
</Button>
192+
</TableCell>
193+
)}
194+
</TableRow>
195+
))}
170196
</TableBody>
171197
</Table>
172198
</TableContainer>
173199
</GridItem>
174200
</GridContainer>
201+
175202
<GridContainer>
176203
<GridItem xs={12} sm={12} md={12}>
177204
<h3>
178-
<Code></Code> Contributors
205+
<Code /> Contributors
179206
</h3>
180207
{user.admin && (
181208
<div style={{ textAlign: 'right' }}>
182-
<AddUser repoName={repoName} type='push' refreshFn={refresh} />
209+
<AddUser repoName={repoName || ''} type='push' refreshFn={refresh} />
183210
</div>
184211
)}
185212
<TableContainer component={Paper}>
186-
<Table className={classes.table} aria-label='simple table'>
213+
<Table className={classes.table} aria-label='contributors table'>
187214
<TableHead>
188215
<TableRow>
189216
<TableCell align='left'>Username</TableCell>
190217
{user.admin && <TableCell align='right'></TableCell>}
191218
</TableRow>
192219
</TableHead>
193220
<TableBody>
194-
{data.users.canPush.map((row) => {
195-
if (row) {
196-
return (
197-
<TableRow key={row}>
198-
<TableCell align='left'>
199-
<a href={`/dashboard/admin/user/${row}`}>{row}</a>
200-
</TableCell>
201-
{user.admin && (
202-
<TableCell align='right' component='th' scope='row'>
203-
<Button
204-
variant='contained'
205-
color='secondary'
206-
onClick={() => removeUser(row, 'push')}
207-
>
208-
<RemoveCircle></RemoveCircle>
209-
</Button>
210-
</TableCell>
211-
)}
212-
</TableRow>
213-
);
214-
}
215-
})}
221+
{data.users.canPush.map((row) => (
222+
<TableRow key={row}>
223+
<TableCell align='left'>
224+
<a href={`/dashboard/user/${row}`}>{row}</a>
225+
</TableCell>
226+
{user.admin && (
227+
<TableCell align='right' component='th' scope='row'>
228+
<Button
229+
variant='contained'
230+
color='secondary'
231+
onClick={() => removeUser(row, 'push')}
232+
>
233+
<RemoveCircle />
234+
</Button>
235+
</TableCell>
236+
)}
237+
</TableRow>
238+
))}
216239
</TableBody>
217240
</Table>
218241
</TableContainer>
@@ -223,4 +246,6 @@ export default function RepoDetails() {
223246
</GridItem>
224247
</GridContainer>
225248
);
226-
}
249+
};
250+
251+
export default RepoDetails;

0 commit comments

Comments
 (0)