Skip to content

Commit fcb1d8d

Browse files
chqy24gondzo
authored andcommitted
challenge 30056131 -- SELECT SERVICE PACKAGE
1 parent cbd6177 commit fcb1d8d

File tree

7 files changed

+259
-34
lines changed

7 files changed

+259
-34
lines changed

.env

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
GOOGLE_API_KEY=AIzaSyCrL-O319wNJK8kk8J_JAYsWgu6yo5YsDI
2-
REACT_APP_API_BASE_PATH=https://kb-dsp-server-dev.herokuapp.com
2+
REACT_APP_API_BASE_PATH=http://localhost:3500
33
REACT_APP_AUTH0_CLIENT_ID=3CGKzjS2nVSqHxHHE64RhvvKY6e0TYpK
44
REACT_APP_AUTH0_CLIENT_DOMAIN=dronetest.auth0.com
5-
REACT_APP_SOCKET_URL=https://kb-dsp-server-dev.herokuapp.com
5+
REACT_APP_SOCKET_URL=http://localhost:3500

src/routes/MissionPlanner/components/MissionMap/MissionMap.jsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,22 +86,22 @@ export class MissionMap extends Component {
8686

8787
handleMapLoad(map) {
8888
this.map = map;
89-
if (map ) {
90-
if ( this.props.markers.length > 0 ) {
91-
this.fitMapToBounds(map, this.props.markers);
92-
} else {
93-
navigator.geolocation.getCurrentPosition((pos) => {
94-
map.panTo({
95-
lat: pos.coords.latitude,
96-
lng: pos.coords.longitude,
97-
});
98-
},
89+
if (map) {
90+
if (this.props.markers.length > 0) {
91+
this.fitMapToBounds(map, this.props.markers);
92+
} else {
93+
navigator.geolocation.getCurrentPosition((pos) => {
94+
map.panTo({
95+
lat: pos.coords.latitude,
96+
lng: pos.coords.longitude,
97+
});
98+
},
9999
null,
100100
{timeout: 60000}
101101
);
102+
}
102103
}
103104
}
104-
}
105105

106106
render() {
107107
return (
Lines changed: 162 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,173 @@
1-
import React, {PropTypes} from 'react';
1+
import React, {PropTypes, Component} from 'react';
22
import CSSModules from 'react-css-modules';
3+
import Modal from 'react-modal';
4+
import {browserHistory} from 'react-router';
35
import SelectDropdown from 'components/SelectDropdown';
6+
import Button from 'components/Button';
47
import styles from './MyRequestHeader.scss';
58

6-
export const MyRequestHeader = ({onStatusChange, statusValue}) => (
7-
<div styleName="my-request-header">
8-
<h1 styleName="title">My Request Status</h1>
9-
<SelectDropdown
10-
options={[
11-
{value: 'all', label: 'Show all requests'},
12-
{value: 'in-progress', label: 'Show In Progress'},
13-
{value: 'cancelled', label: 'Show Cancelled'},
14-
{value: 'completed', label: 'Show Completed'},
15-
{value: 'rejected', label: 'Show Rejected'},
16-
{value: 'pending', label: 'Show Pending'},
17-
{value: 'scheduled', label: 'Show Scheduled'},
18-
]}
19-
value={statusValue}
20-
onChange={onStatusChange}
21-
/>
22-
</div>
23-
);
9+
const customStyles = {
10+
overlay: {
11+
position: 'fixed',
12+
top: 0,
13+
left: 0,
14+
right: 0,
15+
bottom: 0,
16+
backgroundColor: 'rgba(9, 9, 9, 0.58)',
17+
zIndex: '9999',
18+
},
19+
content: {
20+
top: '50%',
21+
left: '50%',
22+
right: 'auto',
23+
bottom: 'auto',
24+
marginRight: '-50%',
25+
transform: 'translate(-50%, -50%)',
26+
padding: '0px',
27+
width: '417px',
28+
borderRadius: '10px',
29+
zIndex: '99999',
30+
border: 'none',
31+
},
32+
};
33+
34+
class MyRequestHeader extends Component {
35+
constructor() {
36+
super();
37+
38+
this.state = {
39+
openModal: false,
40+
};
41+
42+
this.clickCreate = this.clickCreate.bind(this);
43+
this.closeModal = this.closeModal.bind(this);
44+
this.selectPackage = this.selectPackage.bind(this);
45+
this.confirmPackage = this.confirmPackage.bind(this);
46+
}
47+
48+
clickCreate() {
49+
const {searchPackages} = this.props;
50+
this.setState({
51+
openModal: true,
52+
}, () => {
53+
searchPackages().then(() => {
54+
this.setState({
55+
searchError: false,
56+
});
57+
}).catch(() => {
58+
this.setState({
59+
searchError: true,
60+
});
61+
});
62+
});
63+
}
64+
65+
closeModal() {
66+
this.setState({
67+
openModal: false,
68+
});
69+
}
70+
71+
selectPackage(i) {
72+
this.setState({
73+
selectedPackage: i,
74+
});
75+
}
76+
77+
confirmPackage() {
78+
const {availablePackages} = this.props;
79+
this.setState({
80+
openModal: false,
81+
}, () => {
82+
browserHistory.push(`/service-request/${availablePackages[this.state.selectedPackage].id}`);
83+
});
84+
}
85+
86+
render() {
87+
const {onStatusChange, statusValue, availablePackages} = this.props;
88+
return (
89+
<div styleName="my-request-header">
90+
<h1 styleName="title">My Request Status</h1>
91+
<div styleName="right-group">
92+
<Button className={styles['create-btn']} onClick={this.clickCreate}>
93+
Create Request
94+
</Button>
95+
<SelectDropdown
96+
options={[
97+
{value: 'all', label: 'Show all requests'},
98+
{value: 'in-progress', label: 'Show In Progress'},
99+
{value: 'cancelled', label: 'Show Cancelled'},
100+
{value: 'completed', label: 'Show Completed'},
101+
{value: 'rejected', label: 'Show Rejected'},
102+
{value: 'pending', label: 'Show Pending'},
103+
{value: 'scheduled', label: 'Show Scheduled'},
104+
]}
105+
value={statusValue}
106+
onChange={onStatusChange}
107+
/>
108+
</div>
109+
<Modal
110+
isOpen={this.state.openModal}
111+
onRequestClose={this.closeModal}
112+
style={customStyles}
113+
shouldCloseOnOverlayClick
114+
contentLabel='available-pacages'
115+
>
116+
<div styleName="modal-wrap">
117+
<div styleName="modal-title">
118+
Select a package
119+
</div>
120+
<div styleName="modal-body">
121+
{
122+
availablePackages.length > 0 ?
123+
(
124+
<ul>
125+
{
126+
availablePackages.map((p, i) => (
127+
<li
128+
key={i}
129+
onClick={() => this.selectPackage(i)}
130+
styleName={this.state.selectedPackage === i ? 'selected' : null}
131+
>
132+
{p.name}
133+
</li>
134+
))
135+
}
136+
</ul>
137+
) :
138+
(
139+
<div styleName={this.state.searchError ? 'error' : null}>
140+
{
141+
this.state.searchError ?
142+
'An error occured when searching packages' :
143+
'No available packages for now.'
144+
}
145+
</div>
146+
)
147+
}
148+
</div>
149+
{
150+
availablePackages.length > 0 ?
151+
(
152+
<div styleName="modal-foot">
153+
<Button onClick={this.confirmPackage}>
154+
Confirm
155+
</Button>
156+
</div>
157+
) : null
158+
}
159+
</div>
160+
</Modal>
161+
</div>
162+
);
163+
}
164+
}
24165

25166
MyRequestHeader.propTypes = {
26167
onStatusChange: PropTypes.func.isRequired,
27168
statusValue: PropTypes.string.isRequired,
169+
availablePackages: PropTypes.array.isRequired,
170+
searchPackages: PropTypes.func.isRequired,
28171
};
29172

30173
export default CSSModules(MyRequestHeader, styles);

src/routes/MyRequestStatus/components/MyRequestHeader/MyRequestHeader.scss

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
:global{
2+
.ReactModal__Body--open{
3+
overflow: hidden;
4+
}
5+
}
16
.my-request-header {
27
align-items: center;
38
border-bottom: 1px solid #d5d5d5;
@@ -38,3 +43,48 @@
3843
width: 12px;
3944
}
4045
}
46+
.right-group{
47+
display: flex;
48+
align-items: center;
49+
}
50+
.create-btn{
51+
margin-right:20px;
52+
}
53+
.modal-wrap{
54+
padding: 0;
55+
ul{
56+
list-style: none;
57+
padding:0;
58+
margin:0;
59+
}
60+
li{
61+
padding: 6px;
62+
border: 1px solid #ddd;
63+
margin-bottom: 10px;
64+
cursor: pointer;
65+
}
66+
.selected{
67+
background-color: #315b95;
68+
color: #fff;
69+
}
70+
}
71+
.modal-title{
72+
background-color: #1e526c;
73+
padding: 12px;
74+
color: #fff;
75+
font-size: 16px;
76+
}
77+
.modal-body{
78+
padding: 20px;
79+
max-height: 300px;
80+
overflow:auto;
81+
}
82+
83+
.modal-foot{
84+
padding: 8px 20px;
85+
text-align: right;
86+
border-top: 1px solid #ddd;
87+
}
88+
.error{
89+
color:red;
90+
}

src/routes/MyRequestStatus/components/MyRequestStatusView.jsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import MyRequestHeader from './MyRequestHeader';
55
import MyRequestTable from './MyRequestTable';
66
import styles from './MyRequestStatusView.scss';
77

8-
export const MyRequestStatusView = ({requests, load, filterByStatus}) => (
8+
export const MyRequestStatusView = ({requests, load, filterByStatus, searchPackages, availablePackages}) => (
99
<div styleName="my-request-status-view">
1010
<Breadcrumb
1111
items={[
@@ -14,7 +14,12 @@ export const MyRequestStatusView = ({requests, load, filterByStatus}) => (
1414
]}
1515
/>
1616
<div styleName="wrap">
17-
<MyRequestHeader onStatusChange={(value) => load(value)} statusValue={filterByStatus} />
17+
<MyRequestHeader
18+
onStatusChange={(value) => load(value)}
19+
statusValue={filterByStatus}
20+
searchPackages={searchPackages}
21+
availablePackages={availablePackages}
22+
/>
1823
<div styleName="panel">
1924
<MyRequestTable requests={requests} />
2025
</div>
@@ -26,6 +31,8 @@ MyRequestStatusView.propTypes = {
2631
requests: MyRequestTable.propTypes.requests,
2732
load: PropTypes.func.isRequired,
2833
filterByStatus: PropTypes.string.isRequired,
34+
searchPackages: PropTypes.func.isRequired,
35+
availablePackages: PropTypes.array.isRequired,
2936
};
3037

3138
export default CSSModules(MyRequestStatusView, styles);

src/routes/MyRequestStatus/modules/MyRequestStatus.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import APIService from 'services/APIService';
55
// Constants
66
// ------------------------------------
77
export const LOADED = 'MyRequestStatus/LOADED';
8+
export const PACKAGES_LOADED = 'MyRequestStatus/PACKAGES_LOADED';
89

910
// ------------------------------------
1011
// Actions
@@ -28,16 +29,28 @@ export const load = (filterByStatus = 'all') => async(dispatch) => {
2829
});
2930
};
3031

32+
export const searchPackages = () => (dispatch) => APIService.searchPackages({limit: -1}).then(({items}) => {
33+
dispatch({
34+
type: PACKAGES_LOADED,
35+
payload: {
36+
availablePackages: items,
37+
},
38+
});
39+
});
40+
3141
export const actions = {
3242
load,
43+
searchPackages,
3344
};
3445

3546
// ------------------------------------
3647
// Reducer
3748
// ------------------------------------
3849
export default handleActions({
3950
[LOADED]: (state, {payload: {requests, filterByStatus}}) => ({...state, requests, filterByStatus}),
51+
[PACKAGES_LOADED]: (state, {payload}) => ({...state, ...payload}),
4052
}, {
4153
filterByStatus: 'all',
4254
requests: [],
55+
availablePackages: [],
4356
});

src/services/APIService.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,4 +462,16 @@ export default class APIService {
462462
.end()
463463
.then((res) => res.body);
464464
}
465+
466+
/**
467+
* search packages
468+
* @param {Object} params the search critiria
469+
*/
470+
static searchPackages(params) {
471+
return request
472+
.get(`${config.api.basePath}/api/v1/packages`)
473+
.query(params)
474+
.end()
475+
.then((res) => res.body);
476+
}
465477
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy