Skip to content

Commit 1bda11a

Browse files
committed
added bug report frontend
1 parent fcd2598 commit 1bda11a

File tree

7 files changed

+338
-125
lines changed

7 files changed

+338
-125
lines changed

client/src/App.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import UnitCreator from './views/ContentCreator/UnitCreator/UnitCreator';
1919
import UploadBlocks from './views/UploadBlocks/UploadBlocks';
2020
import ForgetPassword from './views/TeacherLogin/ForgetPassword';
2121
import ResetPassword from './views/TeacherLogin/ResetPassword';
22+
import BugReport from './views/BugReport/BugReport'
2223

2324
const App = () => {
2425
let history = useHistory();
@@ -82,6 +83,9 @@ const App = () => {
8283
<Route exact path='/addblocks'>
8384
<UploadBlocks history={history} />
8485
</Route>
86+
<Route exact path='/bugreport'>
87+
<BugReport history={history} />
88+
</Route>
8589

8690
<Route component={NotFound} />
8791
</Switch>

client/src/Utils/requests.js

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -457,21 +457,45 @@ export const resetPassword = async (code, password, passwordConfirmation) =>
457457
});
458458

459459
export const getBlockImage = async (url) => {
460-
const config ={header: {
461-
Authorization: `Bearer ${getToken()}`,
462-
},
463-
responseType: 'arraybuffer',
460+
const config = {
461+
header: {
462+
Authorization: `Bearer ${getToken()}`,
463+
},
464+
responseType: 'arraybuffer',
464465
};
465466

466467
let res = [];
467-
try{
468+
try {
468469
const path = `${server}${url}`;
469470
const response = await axios.get(path, config);
470-
res.data = "data:" + response.headers["content-type"] + ";base64," + Buffer.from(response.data).toString('base64');
471-
}
472-
catch(e){
471+
res.data =
472+
'data:' +
473+
response.headers['content-type'] +
474+
';base64,' +
475+
Buffer.from(response.data).toString('base64');
476+
} catch (e) {
473477
console.log(e);
474478
res.err = 'Unable to get block image';
475479
}
476480
return res;
477-
}
481+
};
482+
483+
export const submitBugReport = async (
484+
description,
485+
steps,
486+
name,
487+
email,
488+
systemInfo
489+
) =>
490+
makeRequest({
491+
method: POST,
492+
path: `${server}/bug-report`,
493+
data: {
494+
description,
495+
steps,
496+
name,
497+
email,
498+
systemInfo,
499+
},
500+
error: 'Unable to submit bug-report',
501+
});
Lines changed: 111 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,122 @@
11
import React from 'react';
2-
import './NavBar.less'
2+
import './NavBar.less';
33
import config from './NavBarConfig.json';
4-
import Logo from "../../assets/casmm_logo.png";
5-
import { Link, useHistory } from "react-router-dom";
6-
import {Menu, Dropdown} from 'antd';
7-
import {DownOutlined} from '@ant-design/icons';
8-
import { getUser, removeUserSession } from "../../Utils/AuthRequests";
4+
import Logo from '../../assets/casmm_logo.png';
5+
import { Link, useHistory } from 'react-router-dom';
6+
import { Menu, Dropdown } from 'antd';
7+
import { DownOutlined } from '@ant-design/icons';
8+
import { getUser, removeUserSession } from '../../Utils/AuthRequests';
99

1010
export default function NavBar(props) {
11-
const {isMentor, isStudent, isContentCreator } = props;
12-
const user = getUser();
13-
let currentRoute = window.location.pathname;
14-
let profile = "";
15-
let history = useHistory();
16-
let routes = config.routes;
11+
const { isMentor, isStudent, isContentCreator } = props;
12+
const user = getUser();
13+
let currentRoute = window.location.pathname;
14+
let profile = '';
15+
let history = useHistory();
16+
let routes = config.routes;
1717

18-
if (isMentor) {
19-
profile = "isMentor"
20-
} else if (isStudent) {
21-
profile = "isStudent"
22-
} else if (isContentCreator) {
23-
profile = "isContentCreator"
24-
} else {
25-
profile = "defaultUser"
26-
}
18+
if (isMentor) {
19+
profile = 'isMentor';
20+
} else if (isStudent) {
21+
profile = 'isStudent';
22+
} else if (isContentCreator) {
23+
profile = 'isContentCreator';
24+
} else {
25+
profile = 'defaultUser';
26+
}
2727

28-
const handleLogout = () => {
29-
removeUserSession();
30-
history.push('/');
31-
};
28+
const handleLogout = () => {
29+
removeUserSession();
30+
history.push('/');
31+
};
3232

33-
const handleRouteChange = (route) => {
34-
history.push(route);
35-
}
33+
const handleRouteChange = (route) => {
34+
history.push(route);
35+
};
3636

37-
const shouldShowRoute = (route) => {
38-
if (currentRoute === routes[route]) return false;
39-
return config.users[profile].includes(route);
40-
}
37+
const shouldShowRoute = (route) => {
38+
if (currentRoute === routes[route]) return false;
39+
return config.users[profile].includes(route);
40+
};
4141

42-
const menu =
43-
<Menu>
44-
{ shouldShowRoute("Home") ? <Menu.Item key="0" onClick={() => handleRouteChange(routes.Home)}>
45-
<i className="fa fa-home"/>
46-
&nbsp; Home
47-
</Menu.Item> : null }
48-
{/*{ shouldShowRoute("AccountInfo") ? <Menu.Item key="0" onClick={() => handleRouteChange(routes.AccountInfo)}>*/}
49-
{/* <i className="fa fa-user-circle"/>*/}
50-
{/* &nbsp; Account Info*/}
51-
{/*</Menu.Item> : null}*/}
52-
{ shouldShowRoute("Dashboard") ? <Menu.Item key="1" onClick={() => handleRouteChange(routes.Dashboard)}>
53-
<i className="fa fa-home"/>
54-
&nbsp; Dashboard
55-
</Menu.Item> : null }
56-
{ shouldShowRoute("ContentCreatorDashboard") ? <Menu.Item key="1" onClick={() => handleRouteChange(routes.ContentCreatorDashboard)}>
57-
<i className="fa fa-home"/>
58-
&nbsp; Dashboard
59-
</Menu.Item> : null }
60-
{ shouldShowRoute("Sandbox") ? <Menu.Item key="1" onClick={() => handleRouteChange(routes.Sandbox)}>
61-
<i className="fa fa-window-maximize"/>
62-
&nbsp; Sandbox
63-
</Menu.Item> : null }
64-
{ shouldShowRoute("TeacherLogin") ? <Menu.Item key="2" onClick={() => handleRouteChange(routes.TeacherLogin)}>
65-
<i className="fa fa-sign-in-alt"/>
66-
&nbsp; User Login
67-
</Menu.Item> : null }
68-
{ shouldShowRoute("About") ? <Menu.Item key="3" onClick={() => handleRouteChange(routes.About)}>
69-
<i className="fa fa-info-circle"/>
70-
&nbsp; About
71-
</Menu.Item> : null }
72-
{ shouldShowRoute("SignOut") ? <Menu.Item key="2" onClick={() => handleLogout()}>
73-
<i className="fa fa-sign-out-alt"/>
74-
&nbsp; Sign Out
75-
</Menu.Item> : null }
76-
</Menu>
42+
const menu = (
43+
<Menu>
44+
{shouldShowRoute('Home') ? (
45+
<Menu.Item key='0' onClick={() => handleRouteChange(routes.Home)}>
46+
<i className='fa fa-home' />
47+
&nbsp; Home
48+
</Menu.Item>
49+
) : null}
50+
{/*{ shouldShowRoute("AccountInfo") ? <Menu.Item key="0" onClick={() => handleRouteChange(routes.AccountInfo)}>*/}
51+
{/* <i className="fa fa-user-circle"/>*/}
52+
{/* &nbsp; Account Info*/}
53+
{/*</Menu.Item> : null}*/}
54+
{shouldShowRoute('Dashboard') ? (
55+
<Menu.Item key='1' onClick={() => handleRouteChange(routes.Dashboard)}>
56+
<i className='fa fa-home' />
57+
&nbsp; Dashboard
58+
</Menu.Item>
59+
) : null}
60+
{shouldShowRoute('ContentCreatorDashboard') ? (
61+
<Menu.Item
62+
key='1'
63+
onClick={() => handleRouteChange(routes.ContentCreatorDashboard)}
64+
>
65+
<i className='fa fa-home' />
66+
&nbsp; Dashboard
67+
</Menu.Item>
68+
) : null}
69+
{shouldShowRoute('Sandbox') ? (
70+
<Menu.Item key='1' onClick={() => handleRouteChange(routes.Sandbox)}>
71+
<i className='fa fa-window-maximize' />
72+
&nbsp; Sandbox
73+
</Menu.Item>
74+
) : null}
75+
{shouldShowRoute('TeacherLogin') ? (
76+
<Menu.Item
77+
key='2'
78+
onClick={() => handleRouteChange(routes.TeacherLogin)}
79+
>
80+
<i className='fa fa-sign-in-alt' />
81+
&nbsp; User Login
82+
</Menu.Item>
83+
) : null}
84+
{shouldShowRoute('About') ? (
85+
<Menu.Item key='3' onClick={() => handleRouteChange(routes.About)}>
86+
<i className='fa fa-info-circle' />
87+
&nbsp; About
88+
</Menu.Item>
89+
) : null}
90+
{shouldShowRoute('BugReport') ? (
91+
<Menu.Item key='2' onClick={() => handleRouteChange(routes.BugReport)}>
92+
<i className='fa fa-calendar-times' />
93+
&nbsp; Report a Bug
94+
</Menu.Item>
95+
) : null}
96+
{shouldShowRoute('SignOut') ? (
97+
<Menu.Item key='3' onClick={() => handleLogout()}>
98+
<i className='fa fa-sign-out-alt' />
99+
&nbsp; Sign Out
100+
</Menu.Item>
101+
) : null}
102+
</Menu>
103+
);
77104

78-
return (
79-
<span id="navBar">
80-
<Link id='link' to={isMentor ? "/dashboard" : "/"}>
81-
<img src={Logo} id='casmm-logo' alt='logo'/>
82-
</Link>
83-
<div id="dropdown-menu">
84-
<Dropdown overlay={menu} trigger={['click']}>
85-
<button className="ant-dropdown-link" onClick={e => e.preventDefault()}>
86-
{isMentor ? user.username : "Menu"} <DownOutlined/>
87-
</button>
88-
</Dropdown>
89-
</div>
90-
</span>
91-
)
105+
return (
106+
<span id='navBar'>
107+
<Link id='link' to={isMentor ? '/dashboard' : '/'}>
108+
<img src={Logo} id='casmm-logo' alt='logo' />
109+
</Link>
110+
<div id='dropdown-menu'>
111+
<Dropdown overlay={menu} trigger={['click']}>
112+
<button
113+
className='ant-dropdown-link'
114+
onClick={(e) => e.preventDefault()}
115+
>
116+
{isMentor ? user.username : 'Menu'} <DownOutlined />
117+
</button>
118+
</Dropdown>
119+
</div>
120+
</span>
121+
);
92122
}

client/src/components/NavBar/NavBarConfig.json

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,18 @@
77
"Dashboard": "/dashboard",
88
"SignOut": "/",
99
"AccountInfo": "/account",
10-
"ContentCreatorDashboard":"/ccdashboard"
10+
"ContentCreatorDashboard": "/ccdashboard",
11+
"BugReport": "/bugreport"
1112
},
1213
"users": {
1314
"defaultUser": ["Home", "TeacherLogin", "Sandbox", "About"],
14-
"isMentor": ["Dashboard", "AccountInfo", "SignOut"],
15+
"isMentor": ["Dashboard", "AccountInfo", "SignOut", "BugReport"],
1516
"isStudent": ["SignOut"],
16-
"isContentCreator":["ContentCreatorDashboard","AccountInfo", "About", "SignOut"]
17+
"isContentCreator": [
18+
"ContentCreatorDashboard",
19+
"AccountInfo",
20+
"SignOut",
21+
"BugReport"
22+
]
1723
}
18-
}
24+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import React, { useState } from 'react';
2+
import { Form, Input, Button, message, Alert } from 'antd';
3+
import { submitBugReport } from '../../Utils/requests';
4+
import NavBar from '../../components/NavBar/NavBar';
5+
6+
const BugReport = ({ history }) => {
7+
const [description, setDescription] = useState('');
8+
const [steps, setSteps] = useState('');
9+
const [name, setName] = useState('');
10+
const [email, setEmail] = useState('');
11+
12+
const handleSubmit = async () => {
13+
let systemInfo = navigator.userAgent;
14+
let screenSize = ` Screen (${window.screen.height}, ${window.screen.width})`;
15+
systemInfo += screenSize;
16+
17+
const res = await submitBugReport(
18+
description,
19+
steps,
20+
name,
21+
email,
22+
systemInfo
23+
);
24+
if (res.err) {
25+
message.error(res.err);
26+
} else {
27+
message.success('Successfully submitted bug report!');
28+
history.push('/');
29+
}
30+
};
31+
32+
return (
33+
<div className='container nav-padding'>
34+
<NavBar />
35+
<div id='forgot-pass-wrapper' style={{ marginTop: '0px' }}>
36+
<div id='forgot-pass-title'>Report a Bug</div>
37+
<Form id='forgot-pass-form' onFinish={handleSubmit}>
38+
<Form.Item id='form-label' label='Contect name'>
39+
<Input
40+
onChange={(e) => setName(e.target.value)}
41+
value={name}
42+
type='text'
43+
placeholder='Enter your name'
44+
required
45+
/>
46+
</Form.Item>
47+
<Form.Item id='form-label' label='Contect Email'>
48+
<Input
49+
onChange={(e) => setEmail(e.target.value)}
50+
value={email}
51+
type='email'
52+
placeholder='Enter your email'
53+
required
54+
/>
55+
</Form.Item>
56+
<Form.Item id='form-label' label='Description of the bug'>
57+
<Input.TextArea
58+
onChange={(e) => setDescription(e.target.value)}
59+
value={description}
60+
type='text'
61+
placeholder='Enter description'
62+
required
63+
autoComplete='off'
64+
/>
65+
</Form.Item>
66+
<Form.Item id='form-label' label='Steps to reproduce the bug'>
67+
<Input.TextArea
68+
onChange={(e) => setSteps(e.target.value)}
69+
value={steps}
70+
type='text'
71+
placeholder='Enter steps to reproduce the bug'
72+
required
73+
autoComplete='off'
74+
/>
75+
</Form.Item>
76+
<Form.Item>
77+
<Button type='primary' htmlType='submit' size='large'>
78+
Submit
79+
</Button>
80+
</Form.Item>
81+
</Form>
82+
</div>
83+
</div>
84+
);
85+
};
86+
87+
export default BugReport;

0 commit comments

Comments
 (0)