Compare commits

...

15 Commits

Author SHA1 Message Date
Senad Uka
d4bd965365 Upstream sync 2018-06-01 10:26:45 +02:00
GotPPay
bf3f372ab4 password fix, overlay dialog fix 2018-05-31 19:08:48 +02:00
Senad Uka
182cde9fbb Upstream sync 2018-05-31 18:24:49 +02:00
Senad Uka
04debaf3e9 Upstream sync 2018-05-30 08:52:10 +02:00
Senad Uka
8e52651172 Upstream sync 2018-05-29 17:02:50 +02:00
Senad Uka
3969863cbf Upstream sync 2018-05-28 15:28:19 +02:00
Senad Uka
372b3883a0 Upstream sync 2018-05-26 16:36:01 +02:00
Senad Uka
11fe5f1c61 Upstream sync 2018-05-25 09:10:32 +02:00
Senad Uka
659160676c Upstream sync 2018-05-22 12:41:39 +02:00
Senad Uka
92785d17a1 Upstream sync 2018-05-21 18:55:30 +02:00
Senad Uka
adf2ba8232 Upstream sync 2018-05-17 19:02:54 +02:00
Senad Uka
c993a194a6 upstream sync 2018-05-16 18:41:24 +02:00
Senad Uka
961a9f1448 Merge pull request #1 from senaduka/add-child-error-dialog-fix
fix typo with error message
2018-05-11 11:49:18 +02:00
GotPPay
0cff9ccae9 fix typo with error message 2018-05-11 11:45:06 +02:00
Senad Uka
1fdce51b72 Upstream sync 2018-05-11 09:10:18 +02:00
41 changed files with 5270 additions and 821 deletions

863
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -57,18 +57,22 @@
"react": "^15.5.4",
"react-cookie": "^2.1.2",
"react-data-components": "^1.1.1",
"react-dialog": "^1.0.2",
"react-dom": "^15.5.4",
"react-draggable": "^3.0.5",
"react-draggable": "^2.2.6",
"react-geosuggest": "^2.5.0",
"react-geosuggest-sw": "^1.4.13",
"react-google-maps": "^7.2.0",
"react-helmet": "^5.1.3",
"react-hot-loader": "^3.0.0-beta.6",
"react-imgix": "^7.1.1",
"react-input-mask": "^2.0.1",
"react-jquery-datatables": "^0.7.1",
"react-materialui-notifications": "^0.5.1",
"react-onclickoutside": "^5.10.0",
"react-places-autocomplete": "^5.4.2",
"react-redux": "^5.0.5",
"react-resizable": "^1.7.1",
"react-router": "^3.0.4",
"react-router-redux": "^4.0.8",
"react-tap-event-plugin": "^2.0.1",

View File

@@ -2340,19 +2340,19 @@ html.static.boxed {
@font-face {
font-family: 'Lato';
src: url(/assets/./fonts/646474e48f4c1ea783f43ac5e41fd111.woff2) format("woff2"), url(/assets/./fonts/374df2a818582454b6e6832804e52f86.woff) format("woff");
src: url(/fonts/lato/lato-regular-webfont.woff2) format("woff2"), url(/fonts/lato/lato-regular-webfont.woff) format("woff");
font-weight: bold;
font-style: normal; }
@font-face {
font-family: 'Lato';
src: url(/assets/./fonts/5fa6d7ddc0a0d53311752343d7176d70.woff2) format("woff2"), url(/assets/./fonts/c53136193516ed2d4fac337d1dc6965a.woff) format("woff");
src: url(/assets/./fonts/lato/lato-bolditalic-webfont.woff2) format("woff2"), url(/assets/./fonts/lato/lato-bolditalic-webfont.woff) format("woff");
font-weight: bold;
font-style: italic; }
@font-face {
font-family: 'Lato';
src: url(/assets/./fonts/9bcf055a732c0b22d2279ba79e20c577.woff2) format("woff2"), url(/assets/./fonts/c8eef482ac448a91ecca9d008634c044.woff) format("woff");
src: url(/assets/./fonts/lato/lato-italic-webfont.woff2) format("woff2"), url(/assets/./fonts/lato/lato-italic-webfont.woff) format("woff");
font-weight: normal;
font-style: italic; }

View File

@@ -8,6 +8,10 @@ import { Router, hashHistory, browserHistory } from 'react-router';
import { syncHistoryWithStore, routerMiddleware } from 'react-router-redux';
import reducers from './reducers';
import Instance from './components/Connection';
import {
loggedUser,
visitReporter,
} from 'utils/authorization';
const middleware = routerMiddleware(hashHistory);
const store = createStore(
@@ -29,8 +33,8 @@ const isFunction = (functionToCheck) => {
};
const requireAuth = (nextState, replace, next) => {
if (nextState.location.pathname === '/login' || nextState.location.pathname === '/sign-up' || (nextState.location.pathname.indexOf('/ride') > -1 && nextState.params.ride_uuid !== undefined && nextState.params.user_uuid !== undefined)
|| (!isFunction(replace) && (replace.location.pathname === '/login' || replace.location.pathname === '/sign-up' || (replace.location.pathname.indexOf('/ride') > -1 && replace.params.ride_uuid !== undefined && replace.params.user_uuid !== undefined)))) {
if (nextState.location.pathname === '/login' || nextState.location.pathname === '/sign-up' || nextState.location.pathname.toLowerCase() === '/selfregister' || (nextState.location.pathname.indexOf('/ride') > -1 && nextState.params.ride_uuid !== undefined && nextState.params.user_uuid !== undefined)
|| (!isFunction(replace) && (replace.location.pathname === '/login' || replace.location.pathname === '/sign-up' || nextState.location.pathname.toLowerCase() === '/selfRegister' || (replace.location.pathname.indexOf('/ride') > -1 && replace.params.ride_uuid !== undefined && replace.params.user_uuid !== undefined)))) {
next();
}
@@ -55,7 +59,15 @@ const rootRoute = {
onChange: requireAuth,
onEnter: requireAuth,
component: require('./containers/App'),
indexRoute: { onEnter: (nextState, replace) => replace('/app/table/rides') },
indexRoute: {
onEnter: (nextState, replace) => {
if (loggedUser.anyOf(visitReporter)) {
replace('/app/form/visit/' + loggedUser.useruuid)
} else {
replace('/app/table/rides');
}
}
},
childRoutes: [
require('./routes/app'),
require('./routes/404'),
@@ -65,6 +77,7 @@ const rootRoute = {
require('./routes/lockScreen'),
require('./routes/login'),
require('./routes/signUp'),
require('./routes/selfRegister'),
require('./routes/fullscreen'),
require('./routes/ride'),
require('./routes/ready'),

View File

@@ -6,6 +6,9 @@ const Instance = () => {
const apiUrl = process.env.NODE_ENV === 'production'
? 'https://portal-api.bcbsinstitute.com'
: 'https://portal-api.dev.bcbsinstitute.com';
// const apiUrl = 'http://localhost:5100';
window.localStorage.setItem('App', '8a266a40-ed2e-4be2-bdfc-459a507bf02e');
let instance = axios.create({
@@ -61,11 +64,25 @@ const Instance = () => {
return setToken(token);
};
const getAPIUrl = (url) => {
if (!url) {
return instance;
} else {
const token = getCookie('token');
return axios.create({
baseURL: url,
timeout: 60000,
headers: { App: window.localStorage.getItem('App'), Token: `Bearer ${token}`, Token: `Bearer ${token}` },
});
}
}
const getRawConn = () => {
const token = getCookie('token');
if (token && token !== null && token !== '') {
return instance;
}
window.location.href = '/#/login';
return null;
};
@@ -80,6 +97,7 @@ const Instance = () => {
getConnection,
setToken,
getRawConn,
getAPIUrl,
};
};

View File

@@ -4,6 +4,13 @@ import MenuItem from 'material-ui/MenuItem';
import IconButton from 'material-ui/IconButton/IconButton';
import { hashHistory } from 'react-router';
import {
loggedUser,
planScheduler,
providerScheduler,
visitReporter,
} from 'utils/authorization';
const ImgIconButtonStyle = {
width: '60px',
height: '60px'
@@ -28,6 +35,7 @@ class NavRightList extends React.Component {
handleChange = (event, value) => {
hashHistory.push(value);
}
componentDidMount() {
const user = JSON.parse(localStorage.getItem('loggedUser'));
if (user) {
@@ -40,6 +48,8 @@ class NavRightList extends React.Component {
<ul className="list-unstyled float-right">
<li>
<IconMenu
iconButtonElement={<IconButton style={ImgIconButtonStyle}><img src="assets/images/ic_account_circle_white_48dp_1x.png" alt="" className="rounded-circle img30_30" /></IconButton>}
@@ -48,20 +58,35 @@ class NavRightList extends React.Component {
targetOrigin={{ horizontal: 'right', vertical: 'top' }}
menuStyle={{ minWidth: '150px' }}
>
<MenuItem
onTouchTap={(e) => this.handleChange(e, `/app/authorizedusers/${this.state.useruuid}`)}
primaryText="Profile"
style={{ fontSize: '14px', lineHeight: '48px' }}
innerDivStyle={listItemStyle}
leftIcon={<i className="material-icons">account_circle</i>}
/>
<MenuItem
onTouchTap={(e) => this.handleChange(e, `/app/form/steppers/${this.state.useruuid}`)}
primaryText="Book Ride"
innerDivStyle={listItemStyle}
style={{ fontSize: '14px', lineHeight: '48px' }}
leftIcon={<i className="material-icons">mode_edit</i>}
/>
{!loggedUser.anyOf(visitReporter) &&
<MenuItem
onTouchTap={(e) => this.handleChange(e, `/app/authorizedusers/${this.state.useruuid}`)}
primaryText="Profile"
style={{ fontSize: '14px', lineHeight: '48px' }}
innerDivStyle={listItemStyle}
leftIcon={<i className="material-icons">account_circle</i>}
/>
}
{loggedUser.anyOf(visitReporter) &&
<MenuItem
onTouchTap={(e) => this.handleChange(e, `/app/form/visit/${this.state.useruuid}`)}
primaryText="Create Visit"
innerDivStyle={listItemStyle}
style={{ fontSize: '14px', lineHeight: '48px' }}
leftIcon={<i className="material-icons">mode_edit</i>}
/>
}
{!loggedUser.anyOf(visitReporter) &&
<MenuItem
onTouchTap={(e) => this.handleChange(e, `/app/form/steppers/${this.state.useruuid}`)}
primaryText="Book Ride"
innerDivStyle={listItemStyle}
style={{ fontSize: '14px', lineHeight: '48px' }}
leftIcon={<i className="material-icons">mode_edit</i>}
/>
}
<MenuItem
onTouchTap={(e) => this.handleChange(e, `/login`)}
primaryText="Log Out"

View File

@@ -0,0 +1,97 @@
import React, { Component } from 'react';
import FlatButton from 'material-ui/FlatButton';
import MaterialDialog from 'material-ui/Dialog';
import Dialog from './draggable-dialog';
import './draggable-dialog/css/index.css';
const defaultDialogHeight = 100; //px
const dialogHeightPerLine = 25; //px
export class ValidationErrorsInfoDialog extends React.Component {
constructor(props) {
super(props)
this.props = props;
this.state = {
open: this.props.open,
title: "Errors",
}
}
componentWillReceiveProps(newProps) {
let title = this.state.title;
if (newProps.errorTitle) {
title = newProps.errorTitle;
}
this.setState({ open: newProps.open, title: title });
}
handleOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
this.props.onDismiss();
};
render() {
const actions = [
<FlatButton
label="Dismiss"
primary={true}
onClick={this.handleClose}
/>,
];
const dialogContent = (
this.props.errorMessages.map(errorMessage => {
const oneValidationMessage = (<span><a>{errorMessage.message}</a><br /></span>);
const oneValidationMessageWithTab = (<span><li style={{ marginLeft: 2 + "em" }}>{errorMessage.message}</li></span>);
if (errorMessage.field_name === "password-tab") {
return oneValidationMessageWithTab;
} else {
return oneValidationMessage;
}
})
)
const draggableDialog =
(<Dialog
title={this.props.title ? this.props.title : 'Error'}
isDraggable={true}
buttons={actions}
hasCloseIcon={false}
modal={this.props.modal ? this.props.modal : false}
height={defaultDialogHeight + this.props.errorMessages.length * dialogHeightPerLine}>
{dialogContent}
</Dialog>
)
const normalDialog =
(<MaterialDialog
open={this.state.open}
title={this.props.title ? this.props.title : 'Error'}
onBackdropClick={()=>{console.log("Backdrop")}}
actions={actions}>
{dialogContent}
</MaterialDialog>
)
return (
<div className="container">
{this.state.open && this.props.draggable && draggableDialog }
{this.state.open && !this.props.draggable && normalDialog}
</div>
);
}
}
module.exports = ValidationErrorsInfoDialog;

View File

@@ -0,0 +1,18 @@
import React from "react";
import PropTypes from "prop-types";
class DialogBody extends React.Component {
render() {
return (
<div className="ui-dialog-content" style={{ "overflowY": "auto" }}>
{this.props.children}
</div>
);
}
}
DialogBody.propTypes = {
children: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
};
export default DialogBody;

View File

@@ -0,0 +1,43 @@
import React from "react";
import PropTypes from "prop-types";
import cs from "classnames";
const DialogFooter = (props) => {
const buttons = props.buttons;
if (!buttons || buttons.length == 0) {
return false;
}
const dialogButtons = buttons.map(function (button, index) {
if (React.isValidElement(button)) {
return button;
}
const { text, onClick, className } = button;
return (
<button
key={`button-${index}`}
type="button"
className={cs("button", className)}
onClick={onClick}>
{text}
</button>
);
}, this);
return (
<div className="ui-dialog-buttonpane">
<div className="ui-dialog-buttonset">
{dialogButtons}
</div>
</div>
);
};
DialogFooter.propTypes = {
buttons: PropTypes.array,
onClose: PropTypes.func.isRequired
};
export default DialogFooter;

View File

@@ -0,0 +1,65 @@
import React from "react";
import PropTypes from "prop-types";
const DialogTitle = ({ title, hasCloseIcon, onClose, allowMinimize, isMinimized, onMinimize, allowMaximize, isMaximized, onMaximize, onRestore }) => {
let closeIcon;
if (hasCloseIcon !== false) {
closeIcon = (
<i className="icon icon-close" onClick={onClose}></i>
);
}
let minimizeIcon;
if (allowMinimize) {
if (isMinimized) {
minimizeIcon = (
<i className="icon icon-restore" onClick={onRestore}></i>
);
} else {
minimizeIcon = (
<i className="icon icon-minimize" onClick={onMinimize}></i>
);
}
}
let maximizeIcon;
if (allowMaximize) {
if (isMaximized) {
maximizeIcon = (
<i className="icon icon-restore" onClick={onRestore}></i>
);
} else {
maximizeIcon = (
<i className="icon icon-maximize" onClick={onMaximize}></i>
);
}
}
return (
<header className="ui-dialog-titlebar">
<div className="title">
{title}
</div>
<div className="action-items">
{minimizeIcon}
{maximizeIcon}
{closeIcon}
</div>
</header>
);
};
DialogTitle.propTypes = {
hasCloseIcon: PropTypes.bool,
allowMinimize: PropTypes.bool,
allowMaximize: PropTypes.bool,
isMinimized: PropTypes.bool,
isMaximized: PropTypes.bool,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
onClose: PropTypes.func.isRequired,
onMinimize: PropTypes.func,
onMaximize: PropTypes.func,
onRestore: PropTypes.func
};
export default DialogTitle;

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

View File

@@ -0,0 +1,167 @@
body {
width: 100%;
min-height: 700px;
}
a {
cursor: pointer;
text-decoration: underline;
}
.ui-dialog-overlay {
background: #aaaaaa;
opacity: .3;
filter: Alpha(Opacity=30);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
}
.ui-dialog {
position: fixed;
top: 50%;
left: 50%;
outline: 0 none;
padding: 0 !important;;
z-index: 101;
background-color: white;
border: 1px solid #f6f6f6;
}
.ui-dialog.maximized{
position: fixed;
top: 0;
left: 0;
width: 100% !important;
height: 100% !important;
}
.ui-dialog.minimized{
position: fixed;
bottom: 0;
right: 0;
}
.ui-dialog .ui-dialog-titlebar {
position: relative;
font-size: 1em;
border-radius: 3px;
padding: 0.5em;
height: 35px;
/*border-bottom: 1px solid #f6f6f6;*/
}
.ui-dialog.react-draggable .ui-dialog-titlebar{
cursor: move;
}
.ui-dialog.react-draggable .ui-dialog-content{
cursor: move;
}
.ui-dialog.react-draggable .ui-dialog-buttonpane {
cursor: move;
}
.ui-dialog .ui-dialog-titlebar .action-items {
float: right;
position: relative;
}
.ui-dialog .ui-dialog-titlebar .title {
float: left;
margin-right: .5em;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
font-size: 1.3125em;
font-weight: 500;
line-height: 0.2em;
padding : 24px 0px 0px 19px;
}
.icon {
width: 24px;
height: 24px;
display: block;
float: left;
margin: 5px;
cursor: pointer;
background-size: cover;
}
.icon.icon-close {
width: 20px;
height: 20px;
background-image: url("./img/close.png");
}
.icon.icon-minimize {
background-image: url("./img/minimize.png");
}
.icon.icon-maximize {
background-image: url("./img/maximize.png");
}
.icon.icon-restore {
background-image: url("./img/restore.png");
}
.ui-dialog .ui-dialog-content {
background: none repeat scroll 0 0 transparent;
border: 0 none;
overflow: auto;
position: relative;
font-size: 1rem;
font-weight: 400;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
line-height: 1.5em;
color:rgba(0, 0, 0, 0.54);
padding : 24px 24px 24px 24px;
}
.ui-dialog .ui-dialog-buttonpane {
position: absolute;
width: 100%;
bottom: 0;
text-align: right;
border-width: 1px 0 0 0;
/*border-top: 1px solid #f6f6f6;*/
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{
padding: 0.5em;
}
.ui-dialog .ui-dialog-buttonpane button {
margin: 0 .5em 0 .5em;
cursor: pointer;
background-color: #f6f6f6;
padding: 0.5em 1em;
outline: none;
border: 1px solid #CCCCCC;
border-radius: 3px;
}
.ui-dialog .ui-dialog-buttonpane button:hover{
background-color: #CCCCCC;
border: 1px solid #BBBBBB;
}
.ui-dialog .react-resizable-handle {
position: absolute;
width: 20px;
height: 20px;
bottom: 0;
right: 0;
background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+');
background-position: bottom right;
padding: 0 3px 3px 0;
background-repeat: no-repeat;
background-origin: content-box;
box-sizing: border-box;
cursor: se-resize;
}

View File

@@ -0,0 +1,171 @@
import React from "react";
import PropTypes from "prop-types";
import cs from "classnames";
import Draggable from "react-draggable";
import { Resizable } from "react-resizable";
import DialogTitle from "./DialogTitle";
import DialogBody from "./DialogBody";
import DialogFooter from "./DialogFooter";
import EventStack from "active-event-stack";
class Dialog extends React.Component {
constructor(props) {
super(props);
this.state = {
height: props.height,
width: props.width,
isMinimized: false,
isMaximized: false
};
}
componentWillMount() {
/**
* This is done in the componentWillMount instead of the componentDidMount
* because this way, a modal that is a child of another will have register
* for events after its parent
*/
this.eventToken = EventStack.addListenable([
["keydown", this.handleGlobalKeydown]
]);
}
componentWillUnmount = () => {
EventStack.removeListenable(this.eventToken);
}
handleGlobalKeydown = (e) => {
if (this.props.closeOnEscape && e.keyCode == 27) {
e.stopPropagation();
this.onClose();
}
return false;
}
onClose = () => {
if (this.props.onClose) {
this.props.onClose();
}
}
onMinimize = () => {
this.setState({ isMinimized: true, isMaximized: false });
}
onMaximize = () => {
this.setState({ isMinimized: false, isMaximized: true });
}
onRestore = () => {
this.setState({ isMinimized: false, isMaximized: false });
}
onResize = (event, { element, size }) => {
this.setState({ width: size.width, height: size.height });
}
getDialogTitle = () => {
return (
<DialogTitle
title={this.props.title}
hasCloseIcon={this.props.hasCloseIcon}
allowMinimize={this.props.allowMinimize}
allowMaximize={this.props.allowMaximize}
isMinimized={this.state.isMinimized}
isMaximized={this.state.isMaximized}
onMinimize={this.onMinimize}
onMaximize={this.onMaximize}
onRestore={this.onRestore}
onClose={this.onClose}
/>
);
}
render() {
const { height, width, isMinimized, isMaximized } = this.state;
const { modal, isDraggable, isResizable, buttons, children, position } = this.props;
const { x = -width / 2, y = -height / 2 } = position;
let dialog = (
<div style={{ height: height, width, transform: `translate(${x}px, ${y}px)` }} className={cs("ui-dialog", { "minimized": isMinimized, "maximized": isMaximized })}>
{this.getDialogTitle()}
{
!isMinimized && <DialogBody>{children}</DialogBody>
}
{
!isMinimized && <DialogFooter buttons={buttons} onClose={this.onClose}></DialogFooter>
}
</div>
);
if (!isMinimized && !isMaximized && isResizable) {
dialog = (
<Resizable className="box" height={height} width={width} onResize={this.onResize}>
{dialog}
</Resizable>
);
}
if (!isMinimized && !isMaximized && isDraggable !== false) {
dialog = (
<Draggable handle=".ui-dialog" bounds="body" defaultPosition={{ x, y }}>
{dialog}
</Draggable>
);
}
return (
<div
className={cs("ui-dialog-container", { "": modal })}>
{dialog}
{modal && <div className="ui-dialog-overlay"></div>}
</div>
);
}
}
Dialog.propTypes = {
height: PropTypes.number,
width: PropTypes.number,
modal: PropTypes.bool,
position: PropTypes.shape({
x: PropTypes.number,
y: PropTypes.number
}),
hasCloseIcon: PropTypes.bool,
allowMinimize: PropTypes.bool,
allowMaximize: PropTypes.bool,
isResizable: PropTypes.bool,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
closeOnEscape: PropTypes.bool,
onClose: PropTypes.func,
children: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.element]).isRequired,
buttons: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.shape({
text: PropTypes.string,
onClick: PropTypes.func
})),
PropTypes.arrayOf(PropTypes.element)
])
};
Dialog.defaultProps = {
height: 200,
width: 600,
modal: false,
closeOnEscape: true,
isDraggable: false,
isResizable: false,
title: '',
hasCloseIcon: true,
allowMinimize: false,
allowMaximize: false,
onClose: null,
buttons: null,
position: { x: -250, y: -150 }
};
export default Dialog;

View File

@@ -7,6 +7,7 @@ import {
loggedUser,
planScheduler,
providerScheduler,
visitReporter,
} from 'utils/authorization';
class SidebarContent extends React.Component {
@@ -66,7 +67,6 @@ class SidebarContent extends React.Component {
$subUl.stop().slideToggle(slideTime);
});
// HighlightActiveItems
const $links = $nav.find('a');
const currentLocation = hashHistory.getCurrentLocation();
@@ -101,52 +101,73 @@ class SidebarContent extends React.Component {
return (
<ul className="nav" ref={(c) => { this.nav = c; }}>
<li>
<FlatButton href="#/app/form"><i className="nav-icon material-icons cyan-text text-lighter-4">directions_car</i><span className="nav-text">Rides</span></FlatButton>
<ul>
<li><FlatButton className="prepend-icon" href={"#/app/form/steppers/" + this.state.user.useruuid}><span>Book Rides</span></FlatButton></li>
<li><FlatButton className="prepend-icon" href="#/app/table/rides"><span>Manage Rides</span></FlatButton></li>
</ul>
</li>
<li>
<FlatButton href="#/app/chart"><i className="nav-icon material-icons">people_outline</i><span className="nav-text">Members</span></FlatButton>
<ul>
<li><FlatButton className="prepend-icon" href="#/app/page/eligibility"><span>Verify Eligibility</span></FlatButton></li>
<li><FlatButton className="prepend-icon" href="#/app/table/members"><span>Manage Members</span></FlatButton></li>
</ul>
</li>
{loggedUser.anyOf(visitReporter) &&
<li>
<FlatButton href="#/app/chart"><i className="nav-icon material-icons">schedule</i><span className="nav-text">Visits</span></FlatButton>
<ul>
<li><FlatButton className="prepend-icon" href={"#/app/form/visit/" + this.state.user.useruuid}><span>Add Visit</span></FlatButton></li>
</ul>
</li>
}
<li>
<FlatButton href="#/app/table/visits"><i className="nav-icon material-icons">schedule</i><span className="nav-text">Visits</span></FlatButton>
</li>
{/* <li>
<FlatButton href="#/app/table/message"><i className="nav-icon material-icons">mail_outline</i><span className="nav-text">Message Center</span></FlatButton>
</li> */}
<li>
<FlatButton href="#/app/chart"><i className="nav-icon material-icons">settings</i><span className="nav-text">Manage</span></FlatButton>
<ul>
{!loggedUser.anyOf(planScheduler, providerScheduler) &&
{!loggedUser.anyOf(visitReporter) &&
<li>
<FlatButton href="#/app/form"><i className="nav-icon material-icons cyan-text text-lighter-4">directions_car</i><span className="nav-text">Rides</span></FlatButton>
<ul>
<li><FlatButton className="prepend-icon" href={"#/app/form/steppers/" + this.state.user.useruuid}><span>Book Rides</span></FlatButton></li>
<li><FlatButton className="prepend-icon" href="#/app/table/rides"><span>Manage Rides</span></FlatButton></li>
</ul>
</li>
}
{!loggedUser.anyOf(visitReporter) &&
<li>
<FlatButton href="#/app/chart"><i className="nav-icon material-icons">people_outline</i><span className="nav-text">Members</span></FlatButton>
<ul>
<li><FlatButton className="prepend-icon" href="#/app/page/eligibility"><span>Verify Eligibility</span></FlatButton></li>
<li><FlatButton className="prepend-icon" href="#/app/table/members"><span>Manage Members</span></FlatButton></li>
</ul>
</li>
}
{!loggedUser.anyOf(visitReporter) &&
<li>
<FlatButton href="#/app/chart"><i className="nav-icon material-icons">schedule</i><span className="nav-text">Visits</span></FlatButton>
<ul>
<li><FlatButton className="prepend-icon" href={"#/app/form/visit/" + this.state.user.useruuid}><span>Create Visit</span></FlatButton></li>
<li> <FlatButton className="prepend-icon" href="#/app/table/visits"><span className="nav-text">Manage Visits</span></FlatButton></li>
</ul>
</li>
}
{!loggedUser.anyOf(visitReporter) &&
<li>
<FlatButton href="#/app/chart"><i className="nav-icon material-icons">settings</i><span className="nav-text">Manage</span></FlatButton>
<ul>
{!loggedUser.anyOf(planScheduler, providerScheduler) &&
<li>
<FlatButton href="#/app/table/authorizedusers"><i className="nav-icon material-icons">people</i><span className="nav-text">Authorized Users</span></FlatButton>
</li>
}
<li>
<FlatButton href="#/app/table/authorizedusers"><i className="nav-icon material-icons">people</i><span className="nav-text">Authorized Users</span></FlatButton>
<FlatButton href="#/app/table/organizations"><i className="nav-icon material-icons">assignment</i><span className="nav-text">Organizations</span></FlatButton>
</li>
}
<li>
<FlatButton href="#/app/table/organizations"><i className="nav-icon material-icons">assignment</i><span className="nav-text">Organizations</span></FlatButton>
</li>
<li>
<FlatButton href="#/app/table/provider"><i className="nav-icon material-icons">local_hospital</i><span className="nav-text">Participating Providers</span></FlatButton>
</li>
<li>
<FlatButton href={"#/app/authorizedusers/" + this.state.user.useruuid}><i className="nav-icon material-icons">account_circle</i><span className="nav-text">Profile</span></FlatButton>
</li>
{/* <li>
<FlatButton href="#/app/dashboard"><i className="nav-icon material-icons">equalizer</i><span className="nav-text">Reports</span></FlatButton>
</li> */}
</ul>
</li>
<li>
<FlatButton href="#/app/table/provider"><i className="nav-icon material-icons">local_hospital</i><span className="nav-text">Participating Providers</span></FlatButton>
</li>
<li>
<FlatButton href={"#/app/authorizedusers/" + this.state.user.useruuid}><i className="nav-icon material-icons">account_circle</i><span className="nav-text">Profile</span></FlatButton>
</li>
{/* <li>
<FlatButton href="#/app/dashboard"><i className="nav-icon material-icons">equalizer</i><span className="nav-text">Reports</span></FlatButton>
</li> */}
</ul>
</li>
}
<li className="nav-divider" />
<li><FlatButton className="prepend-icon" href={"#/login"}><span>Log Out</span></FlatButton></li>
</ul>
);
}

View File

@@ -5,6 +5,10 @@ import Footer from 'components/Footer';
import Notifications from 'components/Notifications';
import Notification from 'components/Shared/Notification';
import GeolocationService from './Geolocation';
import {
loggedUser,
visitReporter,
} from 'utils/authorization';
class MainApp extends React.Component {
constructor(props) {
@@ -53,8 +57,9 @@ class MainApp extends React.Component {
<Footer />
</div>
</section>
<Notifications user={this.state.user} onRideUpdate={this.handleRide} />
{/* <Notification user={this.state.user} onRideUpdate={this.handleRide} /> */}
{!loggedUser.anyOf(visitReporter) &&
<Notifications user={this.state.user} onRideUpdate={this.handleRide} />
}
</div>
);
}

View File

@@ -115,6 +115,7 @@ export class NEMTLocation extends React.Component {
long: 0
},
providers: [],
locations: [],
currentSelection: {
id: 0,
name: "",
@@ -125,6 +126,7 @@ export class NEMTLocation extends React.Component {
saved: false,
},
inputValue: "",
locationValue: "",
addLocation: false,
searchAddresses: [],
addLocationText: '',
@@ -143,7 +145,15 @@ export class NEMTLocation extends React.Component {
id: '',
name: '',
address: '',
}
},
centerLocation: {
lat: 0,
long: 0,
name: '',
address: '',
},
searchingProvider: false,
providerList: [],
}
this.addCustomLabel = this.addCustomLabel.bind(this);
@@ -164,6 +174,8 @@ export class NEMTLocation extends React.Component {
this.updateLocation = this.updateLocation.bind(this);
this.handleGetClosestPlace = this.handleGetClosestPlace.bind(this);
this.updateLocationValue = this.updateLocationValue.bind(this);
this.handleAutoCompleteLocation = this.handleAutoCompleteLocation.bind(this);
// this.updateLocation().then(console.log);
@@ -184,50 +196,71 @@ export class NEMTLocation extends React.Component {
}
geoSuccess = (position) => {
let lat = 0;
let long = 0;
if (this.state.centerLocation.lat !== 0 && this.state.centerLocation.long !== 0) {
lat = this.state.centerLocation.lat;
long = this.state.centerLocation.long;
} else {
const geo = GeolocationService.GetCoordinates();
lat = geo.lat;
long = geo.long;
}
const geo = GeolocationService.GetCoordinates();
// self.updateLocation().then(p => {
let lat = geo.lat;
let long = geo.long;
if ((lat === undefined || long === undefined) || (lat === 0 || long === 0)) {
lat = 41.886406;
long = -87.624225;
}
this.locateNearby(lat, long)
}
locateNearby = (lat, long) => {
if (lat === 0 || long === 0) {
this.setState(Object.assign(this.state, { nearbyPlaces: [], providers: [], providerList: [] }));
if ((lat === undefined || long === undefined) || (lat === 0 || long === 0)) {
lat = 41.886406;
long = -87.624225;
}
if (this.state.locationType === 'provider') {
Instance.getRawConn().get(`/v1/nemt/provider/participating?sort=distance&lat=${lat}&long=${long}`).then(res => {
let url = `/v1/nemt/provider?lat=${lat}&long=${long}&limit=50&sortby=distance`
Instance.getRawConn().get(url).then(res => {
let nearByPlaces = [];
let providers = res.data.map(p => {
const streetNumber = p.address.street_address_1.split(' ')[0]
let clickResult = {
id: p.muk_id,
address: `${p.address.street_address_1}, ${p.address.city}, ${p.address.state} (${p.address.zipcode})`,
lat: p.address.lat,
lng: p.address.long,
name: p.name,
type: "provider",
raw: p,
street_number: streetNumber,
street: p.address.street_address_1.replace(streetNumber, '').trim(),
city: p.address.city,
state: p.address.state,
zipcode: p.address.zipcode.substring(0, 5),
country: p.address.country,
saved: false,
}
clickResult.address = `${clickResult.street_number} ${clickResult.street}, ${clickResult.city}`
if (res.data.resultStatus === 'SUCCESS') {
let providers = res.data.providers.map(p => {
const streetNumber = p.streetName_1.split(' ')[0]
let clickResult = {
id: p.mukId,
muk_id: p.mukId,
address: `${p.streetName_1}, ${p.cityName}, ${p.state} (${p.zipCode.substr(0, 5)})`,
lat: parseFloat(p.latitude),
lng: parseFloat(p.longitude),
name: p.providerName,
type: 'provider',
raw: p,
street_number: streetNumber,
street: p.streetName_1.replace(streetNumber, '').trim(),
city: p.cityName,
state: p.state,
zipcode: p.zipCode.substr(0, 5),
country: p.country,
saved: false,
}
var listItem = (<ListItem primaryText={p.name} secondaryText={clickResult.address} key={p.muk_id} rightIcon={<MapsLocalHospital />} onClick={(event) => this.handlePlaceChanged(clickResult)} />)
nearByPlaces.push(listItem);
p.providerText = `${p.name} - ${p.address.street_address_1}, ${p.address.city}, ${p.address.state} (${p.address.zipcode}) (${p.address.phone_number})`
return p;
});
if (p.fivePartKeyGroups.length > 0) {
clickResult.npi = p.fivePartKeyGroups[0].providerNum;
}
this.setState(Object.assign(this.state, { nearbyPlaces: nearByPlaces, providers: providers }));
var listItem = (<ListItem primaryText={p.providerName} secondaryText={clickResult.address} key={p.mukId} rightIcon={<MapsLocalHospital />} onClick={(event) => this.handlePlaceChanged(clickResult)} />)
nearByPlaces.push(listItem);
p.providerText = `${p.providerName} - ${p.streetName_1}, ${p.cityName}, ${p.state} (${p.zipCode.substr(0, 5)}) (${p.phoneNumber})`
p.muk_id = p.mukId
return p;
});
this.setState(Object.assign(this.state, { nearbyPlaces: nearByPlaces, providers: providers, providerList: nearByPlaces }));
}
});
} else {
var pyrmont = new google.maps.LatLng(lat, long);
@@ -305,14 +338,14 @@ export class NEMTLocation extends React.Component {
self.props.onPlaceChanged(name);
}
self.locateNearby(name.lat, name.lng);
//self.locateNearby(name.lat, name.lng);
let buttonText = name.name;
if (buttonText.length > self.state.textSize) {
buttonText = buttonText.substring(0, self.state.textSize);
buttonText += '...';
}
self.setState(Object.assign(self.state, { buttonValue: buttonText, inputValue: name.address }));
self.setState(Object.assign(self.state, { buttonValue: buttonText, inputValue: name.name, searchingProvider: false, providerList: [] }));
}).catch(console.error);
}
@@ -371,6 +404,16 @@ export class NEMTLocation extends React.Component {
objConf.currentSelection = objConf.address
objConf.buttonValue = objConf.address.name
objConf.inputValue = objConf.address.name
// let centerLocation = this.state.centerLocation;
// if ((centerLocation.lat === undefined || centerLocation.long === undefined) || (centerLocation.lat === 0 || centerLocation.long === 0)) {
// objConf.centerLocation = objConf.address
// objConf.locationValue = objConf.address.name
// if (objConf.address.lat !== 0 && objConf.address.lng !== 0) {
// this.locateNearby(objConf.address.lat, objConf.address.lng)
// }
// }
}
if (!objConf.buttonValue) {
@@ -382,16 +425,6 @@ export class NEMTLocation extends React.Component {
objConf.buttonValue += '...';
}
// if (self.state.user.useruuid === '') {
// if (objConf.data.user && objConf.data.user !== null && objConf.data.user.useruuid !== '') {
// let url = `/v1/nemt/users/member/` + objConf.data.user.useruuid
// instance.get(url).then(res => {
// let user = res.data;
// self.setState(Object.assign(self.state, { user: user }));
// }).catch(console.error);
// }
// }
this.setState(Object.assign(this.state, objConf));
if (this.state.type === "flat") {
@@ -434,13 +467,13 @@ export class NEMTLocation extends React.Component {
objConf.buttonValue += '...';
}
// if (self.state.user.useruuid === '' || self.state.user.useruuid !== objConf.data.user.useruuid) {
// if (objConf.data.user && objConf.data.user !== null && objConf.data.user.useruuid !== '') {
// let url = `/v1/nemt/users/member/` + objConf.data.user.useruuid
// instance.get(url).then(res => {
// let user = res.data;
// self.setState(Object.assign(self.state, { user: user }));
// }).catch(console.error);
// if (nextProps.address) {
// let centerLocation = this.state.centerLocation;
// if ((centerLocation.lat === undefined || centerLocation.long === undefined) || (centerLocation.lat === 0 || centerLocation.long === 0)) {
// objConf.centerLocation = nextProps.address
// objConf.locationValue = nextProps.address.name
// this.locateNearby(nextProps.address.lat, nextProps.address.lng)
// }
// }
@@ -461,7 +494,7 @@ export class NEMTLocation extends React.Component {
this.setState(Object.assign(this.state, { open: true }));
if (this.state.user.useruuid === '' || this.state.user.useruuid !== this.props.data.user.useruuid) {
if (this.props.data.user && this.props.data.user !== null && this.props.data.user.useruuid !== '') {
if (this.props.data.user && this.props.data.user.useruuid !== undefined && this.props.data.user !== null && this.props.data.user.useruuid !== '') {
let url = `/v1/nemt/users/member/` + this.props.data.user.useruuid
Instance.getRawConn().get(url).then(res => {
let user = res.data;
@@ -493,29 +526,111 @@ export class NEMTLocation extends React.Component {
this.locateNearby(41.886406, -87.624225);
}
updateTextSearch(searchText, dtSource, params) {
updateLocationValue(searchText, dtSource, params) {
let self = this;
self.setState(Object.assign(self.state, { inputValue: searchText }));
self.setState(Object.assign(self.state, { locationValue: searchText }));
if (searchText.length >= 3) {
let lat = self.state.geolocation.lat;
let long = self.state.geolocation.long;
if (lat === 0 || long === 0) {
let lat = 0;
let long = 0;
if (this.state.centerLocation.lat !== 0 && this.state.centerLocation.long !== 0) {
lat = this.state.centerLocation.lat;
long = this.state.centerLocation.long;
} else {
const geo = GeolocationService.GetCoordinates();
lat = geo.lat;
long = geo.long;
}
if ((lat === undefined || long === undefined) || (lat === 0 || long === 0)) {
lat = 41.886406;
long = -87.624225;
}
var location = new google.maps.LatLng(lat, long);
var request = {
location: location,
radius: '500',
input: searchText,
componentRestrictions: { country: 'us' },
};
const callback = (results, status) => {
if (status == google.maps.places.PlacesServiceStatus.OK) {
var googlePlaces = results.map(place => {
place.providerText = place.description;
place.muk_id = place.id;
place.saved = false;
return place;
});
self.setState(Object.assign(self.state, { locations: googlePlaces }));
}
}
service.getPlacePredictions(request, callback);
}
}
updateTextSearch(event) {
const searchText = event.target.value;
let self = this;
self.setState(Object.assign(self.state, { inputValue: searchText, searchingProvider: true }));
if (searchText.length === 0) {
self.setState(Object.assign(self.state, { searchingProvider: false }));
}
if (searchText.length >= 3) {
let lat = 0;
let long = 0;
if (this.state.centerLocation.lat !== 0 && this.state.centerLocation.long !== 0) {
lat = this.state.centerLocation.lat;
long = this.state.centerLocation.long;
} else {
const geo = GeolocationService.GetCoordinates();
lat = geo.lat;
long = geo.long;
}
if ((lat === undefined || long === undefined) || (lat === 0 || long === 0)) {
lat = 41.886406;
long = -87.624225;
}
if (self.state.locationType === 'provider') {
//let url = `/v1/nemt/provider?lat=${lat}&long=${long}&limit=20&name=${searchText}&sortby=distance`
let url = `/v1/nemt/provider/participating?lat=${lat}&long=${long}&query=${searchText}&sortby=distance`
let url = `/v1/nemt/provider?lat=${lat}&long=${long}&limit=50&name=${searchText}&sortby=distance`
Instance.getRawConn().get(encodeURI(url)).then(res => {
if (res.data.length > 0) {
let places = res.data.map(p => {
p.providerText = `${p.name} - ${p.address.street_address_1}, ${p.address.city}, ${p.address.state} (${p.address.zipcode}) (${p.address.phone_number})`
p.saved = false
return p;
})
self.setState(Object.assign(self.state, { providers: places }));
dtSource = self.state.providers;
if (res.data.resultStatus === 'SUCCESS') {
let providers = res.data.providers.map(p => {
const streetNumber = p.streetName_1.split(' ')[0]
p.providerText = `${p.providerName} - ${p.streetName_1}, ${p.cityName}, ${p.state} (${p.zipCode.substr(0, 5)}) (${p.phoneNumber})`
p.muk_id = p.mukId
let clickResult = {
id: p.mukId,
muk_id: p.mukId,
address: `${p.streetName_1}, ${p.cityName}, ${p.state} (${p.zipCode.substr(0, 5)})`,
lat: parseFloat(p.latitude),
lng: parseFloat(p.longitude),
name: p.providerName,
type: 'provider',
raw: p,
street_number: streetNumber,
street: p.streetName_1.replace(streetNumber, '').trim(),
city: p.cityName,
state: p.state,
zipcode: p.zipCode.substr(0, 5),
country: p.country,
saved: false,
}
if (p.fivePartKeyGroups.length > 0) {
clickResult.npi = p.fivePartKeyGroups[0].providerNum;
}
var listItem = (<ListItem primaryText={p.providerName} secondaryText={clickResult.address} key={p.mukId} rightIcon={<MapsLocalHospital />} onClick={(event) => this.handlePlaceChanged(clickResult)} />)
return listItem;
});
this.setState(Object.assign(this.state, { providerList: providers }));
}
});
} else {
@@ -552,42 +667,59 @@ export class NEMTLocation extends React.Component {
this.setState(Object.assign(this.state, { addLocationTextValue: providerSearch }));
if (providerSearch.length >= 3) {
const geo = GeolocationService.GetCoordinates();
let lat = geo.lat;
let long = geo.long;
if (lat === 0 || long === 0) {
let lat = 0;
let long = 0;
if (this.state.centerLocation.lat !== 0 && this.state.centerLocation.long !== 0) {
lat = this.state.centerLocation.lat;
long = this.state.centerLocation.long;
} else {
const geo = GeolocationService.GetCoordinates();
lat = geo.lat;
long = geo.long;
}
if ((lat === undefined || long === undefined) || (lat === 0 || long === 0)) {
lat = 41.886406;
long = -87.624225;
}
if (this.state.locationType === 'provider') {
let url = `/v1/nemt/provider/participating?lat=${lat}&long=${long}&query=${providerSearch}&sortby=distance`
let url = `/v1/nemt/provider?lat=${lat}&long=${long}&limit=50&name=${providerSearch}&sortby=distance`
Instance.getRawConn().get(encodeURI(url)).then(res => {
let places = res.data.map(p => {
const streetNumber = p.address.street_address_1.split(' ')[0]
p.providerText = `${p.name} - ${p.address.street_address_1}, ${p.address.city}, ${p.address.state} (${p.address.zipcode}) (${p.address.phone_number})`
let clickResult = {
id: p.muk_id,
address: `${p.address.street_address_1}, ${p.address.city}, ${p.address.state} (${p.address.zipcode})`,
lat: p.address.lat,
lng: p.address.long,
name: p.name,
type: "provider",
raw: p,
street_number: streetNumber,
street: p.address.street_address_1.replace(streetNumber, '').trim(),
city: p.address.city,
state: p.address.state,
zipcode: p.address.zipcode.substring(0, 5),
country: p.address.country,
saved: false,
}
clickResult.address = `${clickResult.street_number} ${clickResult.street}, ${clickResult.city}`
if (res.data.resultStatus === 'SUCCESS') {
let providers = res.data.providers.map(p => {
const streetNumber = p.streetName_1.split(' ')[0]
p.providerText = `${p.providerName} - ${p.streetName_1}, ${p.cityName}, ${p.state} (${p.zipCode.substr(0, 5)}) (${p.phoneNumber})`
p.muk_id = p.mukId
var listItem = (<ListItem value={p.muk_id} primaryText={p.name} secondaryText={clickResult.address} key={p.muk_id} rightIcon={<MapsLocalHospital />} onClick={(event) => this.handleSaveAddress(clickResult, this)} />)
return listItem;
});
let clickResult = {
id: p.mukId,
muk_id: p.mukId,
address: `${p.streetName_1}, ${p.cityName}, ${p.state} (${p.zipCode.substr(0, 5)})`,
lat: parseFloat(p.latitude),
lng: parseFloat(p.longitude),
name: p.providerName,
type: 'provider',
raw: p,
street_number: streetNumber,
street: p.streetName_1.replace(streetNumber, '').trim(),
city: p.cityName,
state: p.state,
zipcode: p.zipCode.substr(0, 5),
country: p.country,
saved: false,
}
this.setState(Object.assign(this.state, { searchAddresses: places }));
if (p.fivePartKeyGroups.length > 0) {
clickResult.npi = p.fivePartKeyGroups[0].providerNum;
}
var listItem = (<ListItem primaryText={p.providerName} secondaryText={clickResult.address} key={p.mukId} value={p.mukId} rightIcon={<MapsLocalHospital />} onClick={(event) => this.handleSaveAddress(clickResult)} />)
return listItem;
});
this.setState(Object.assign(this.state, { searchAddresses: providers }));
}
});
} else {
var location = new google.maps.LatLng(lat, long);
@@ -714,6 +846,68 @@ export class NEMTLocation extends React.Component {
}
}
handleAutoCompleteLocation = (location) => {
const self = this;
placeService.getDetails(location, (result, status) => {
if (status == google.maps.places.PlacesServiceStatus.OK) {
let clickResult = {
id: result.place_id,
placeId: result.place_id,
address: result.formatted_address ? result.formatted_address : result.vicinity,
lat: result.geometry.location.lat(),
lng: result.geometry.location.lng(),
name: result.name,
type: "google",
raw: result,
street_number: '',
street: '',
city: '',
state: '',
zipcode: '',
country: '',
saved: false,
}
result.address_components.forEach(a => {
a.types.forEach(c => {
switch (c) {
case "street_number":
clickResult.street_number = a.short_name;
break;
case "route":
clickResult.street = a.short_name;
break;
case "locality":
clickResult.city = a.short_name;
break;
case "administrative_area_level_1":
clickResult.state = a.short_name;
break;
case "country":
clickResult.country = a.short_name;
break;
case "postal_code":
clickResult.zipcode = a.short_name;
break;
}
}, this)
}, this);
clickResult.address = `${clickResult.street_number} ${clickResult.street}, ${clickResult.city}`
const centerLocation = {
lat: clickResult.lat,
long: clickResult.lng,
name: clickResult.name,
address: clickResult.address
}
self.setState(Object.assign(self.state, { centerLocation: centerLocation }));
self.locateNearby(clickResult.lat, clickResult.lng);
}
});
}
handleAutocomplete = (provider) => {
const sendInfo = (clickResult) => {
this.setState(Object.assign(this.state, { currentSelection: clickResult }));
@@ -733,24 +927,32 @@ export class NEMTLocation extends React.Component {
}
if (this.state.locationType === "provider") {
const streetNumber = provider.address.street_address_1.split(' ')[0]
const p = provider;
const streetNumber = p.streetName_1.split(' ')[0]
p.providerText = `${p.providerName} - ${p.streetName_1}, ${p.cityName}, ${p.state} (${p.zipCode.substr(0, 5)}) (${p.phoneNumber})`
p.muk_id = p.mukId
let clickResult = {
id: provider.muk_id,
address: `${provider.address.street_address_1}, ${provider.address.city}, ${provider.address.state} (${provider.address.zipcode})`,
lat: provider.address.lat,
lng: provider.address.long,
name: provider.name,
type: "provider",
raw: provider,
id: p.mukId,
muk_id: p.mukId,
address: `${p.streetName_1}, ${p.cityName}, ${p.state} (${p.zipCode.substr(0, 5)})`,
lat: parseFloat(p.latitude),
lng: parseFloat(p.longitude),
name: p.providerName,
type: 'provider',
raw: p,
street_number: streetNumber,
street: provider.address.street_address_1.replace(streetNumber, '').trim(),
city: provider.address.city,
state: provider.address.state,
zipcode: provider.address.zipcode.substring(0, 5),
country: provider.address.country,
street: p.streetName_1.replace(streetNumber, '').trim(),
city: p.cityName,
state: p.state,
zipcode: p.zipCode.substr(0, 5),
country: p.country,
saved: false,
}
clickResult.address = `${clickResult.street_number} ${clickResult.street}, ${clickResult.city}`
if (p.fivePartKeyGroups.length > 0) {
clickResult.npi = p.fivePartKeyGroups[0].providerNum;
}
sendInfo(clickResult);
} else {
@@ -840,42 +1042,51 @@ export class NEMTLocation extends React.Component {
handleCurrentLocation(e) {
const self = this;
const geo = GeolocationService.GetCoordinates();
// self.updateLocation().then(p => {
let lat = geo.lat;
let long = geo.long;
if (lat === 0 || long === 0) {
let lat = 0;
let long = 0;
if (this.state.centerLocation.lat !== 0 && this.state.centerLocation.long !== 0) {
lat = this.state.centerLocation.lat;
long = this.state.centerLocation.long;
} else {
const geo = GeolocationService.GetCoordinates();
lat = geo.lat;
long = geo.long;
}
if ((lat === undefined || long === undefined) || (lat === 0 || long === 0)) {
lat = 41.886406;
long = -87.624225;
}
if (self.state.locationType === 'provider') {
Instance.getRawConn().get(`/v1/nemt/provider/participating?sort=distance&lat=${lat}&long=${long}`).then(res => {
let url = `/v1/nemt/provider?lat=${lat}&long=${long}&limit=50&sortby=distance`
Instance.getRawConn().get(url).then(res => {
let listItem = (<ListItem primaryText="No location found" key="-1" leftIcon={<MapsNearMe />} onClick={self.handleCurrentLocation} />)
if (res.data.length > 0) {
const result = res.data[0];
const streetNumber = result.address.street_address_1.split(' ')[0]
if (res.data.resultStatus === 'SUCCESS') {
const p = res.data.providers[0];
const streetNumber = p.streetName_1.split(' ')[0]
let clickResult = {
id: result.muk_id,
address: `${result.address.street_address_1}, ${result.address.city}, ${result.address.state} (${result.address.zipcode})`,
lat: result.address.lat,
lng: result.address.long,
name: result.name,
type: "provider",
raw: result,
id: p.mukId,
address: `${p.streetName_1}, ${p.cityName}, ${p.state} (${p.zipCode.substr(0, 5)})`,
lat: parseFloat(p.latitude),
lng: parseFloat(p.longitude),
name: p.providerName,
type: 'provider',
raw: p,
street_number: streetNumber,
street: result.address.street_address_1.replace(streetNumber, '').trim(),
city: result.address.city,
state: result.address.state,
zipcode: result.address.zipcode.substring(0, 5),
country: result.address.country,
street: p.streetName_1.replace(streetNumber, '').trim(),
city: p.cityName,
state: p.state,
zipcode: p.zipCode.substr(0, 5),
country: p.country,
saved: false,
}
clickResult.address = `${clickResult.street_number} ${clickResult.street}, ${clickResult.city}`
if (p.fivePartKeyGroups.length > 0) {
clickResult.npi = p.fivePartKeyGroups[0].providerNum;
}
self.handlePlaceChanged(clickResult)
//listItem = (<ListItem primaryText={clickResult.name} secondaryText={clickResult.address} key={clickResult.muk_id} leftIcon={<MapsNearMe />} onClick={(event) => self.handlePlaceChanged(clickResult)} />)
}
//self.setState(Object.assign(self.state, { currentLocation: listItem }));
}).catch(console.error);
} else {
var location = new google.maps.LatLng(lat, long);
@@ -1129,13 +1340,16 @@ export class NEMTLocation extends React.Component {
{customAddresses}
<ListItem primaryText="Add Custom Shortcut" rightIcon={<ArrowDropRight />} leftIcon={<MapsLocalHospital />} onClick={(e) => this.handleAddAddress(e, 'custom')} />
</List>)
autosuggest = (<AutoComplete dataSourceConfig={datasourceConfig} dataSource={this.state.providers} filter={this.filterResults} maxSearchResults={5} onUpdateInput={this.updateTextSearch} fullWidth={true} floatingLabelText="Enter the Provider's name or address" onNewRequest={this.handleAutocomplete} searchText={this.state.inputValue} />)
autosuggest = (<TextField fullWidth={true} onChange={this.updateTextSearch} floatingLabelText={"Enter the Provider's name or address"} value={this.state.inputValue} />)
//autosuggest = (<AutoComplete dataSourceConfig={datasourceConfig} dataSource={this.state.providers} filter={this.filterResults} maxSearchResults={50} onUpdateInput={this.updateTextSearch} fullWidth={true} floatingLabelText="Enter the Provider's name or address" onNewRequest={this.handleAutocomplete} searchText={this.state.inputValue} />)
} else {
autosuggest = (<AutoComplete dataSourceConfig={datasourceConfig} dataSource={this.state.providers} filter={this.filterResults} maxSearchResults={5} onUpdateInput={this.updateTextSearch} fullWidth={true} floatingLabelText="Enter the Member's address or a nearby intersection or public place" onNewRequest={this.handleAutocomplete} searchText={this.state.inputValue} />)
autosuggest = (<TextField fullWidth={true} onChange={this.updateTextSearch} floatingLabelText={"Enter the Member's address or a nearby intersection or public place"} value={this.state.inputValue} />)
//autosuggest = (<AutoComplete dataSourceConfig={datasourceConfig} dataSource={this.state.providers} filter={this.filterResults} maxSearchResults={50} onUpdateInput={this.updateTextSearch} fullWidth={true} floatingLabelText="Enter the Member's address or a nearby intersection or public place" onNewRequest={this.handleAutocomplete} searchText={this.state.inputValue} />)
}
let listItem = (
<div className="" id="container">
<AutoComplete dataSourceConfig={datasourceConfig} dataSource={this.state.locations} filter={this.filterResults} maxSearchResults={50} onUpdateInput={this.updateLocationValue} fullWidth={true} floatingLabelText="Center Location" onNewRequest={this.handleAutoCompleteLocation} searchText={this.state.locationValue} />
{autosuggest}
<List>
{this.state.currentLocation}
@@ -1149,8 +1363,21 @@ export class NEMTLocation extends React.Component {
<List style={customListStyle}>
{this.state.nearbyPlaces}
</List>
</div >
</div>
)
if (this.state.searchingProvider) {
listItem = (
<div className="" id="container">
<AutoComplete dataSourceConfig={datasourceConfig} dataSource={this.state.locations} filter={this.filterResults} maxSearchResults={50} onUpdateInput={this.updateLocationValue} fullWidth={true} floatingLabelText="Center Location" onNewRequest={this.handleAutoCompleteLocation} searchText={this.state.locationValue} />
{autosuggest}
<List style={customListStyle}>
{this.state.providerList}
</List>
</div>
)
}
if (this.state.addLocation) {
listItem = (
<div className="" id="container">
@@ -1193,4 +1420,4 @@ export class NEMTLocation extends React.Component {
</div>
);
}
}
}

View File

@@ -6,6 +6,8 @@ module.exports = {
require('./routes/components'),
require('./routes/layouts'),
require('./routes/steppers'),
require('./routes/visitRide'),
require('./routes/visit'),
]);
});
}

View File

@@ -30,14 +30,19 @@ import Close from 'material-ui/svg-icons/navigation/close'
import CommunicationCall from 'material-ui/svg-icons/communication/call'
import Message from 'material-ui/svg-icons/communication/message'
import Instance from '../../../../../../../components/Connection';
import ValidationErrorsInfoDialog from '../../../../../../../components/Shared/ValidationErrorsInfoDialog';
import Checkbox from 'material-ui/Checkbox';
import Popover from 'material-ui/Popover';
const ADDRESS_TYPE_HOME = "home";
let DateTimeFormat;
const roundingTime = 1000 * 60 * 5; //5 minutes
DateTimeFormat = global.Intl.DateTimeFormat;
export class DialogExampleSimple extends React.Component {
state = {
open: true,
@@ -361,16 +366,18 @@ class VerticalNonLinear extends React.Component {
constructor(props) {
super(props);
let dateNow = new Date();
this.state = {
stepIndex: 0,
rideTypeValue: 0,
providerID: 0,
providerName: '',
visitDate: new Date(),
visitTime: new Date(),
visitTime: new Date(Math.round(dateNow.getTime() / roundingTime) * roundingTime),
pickupLocation: null,
pickupTime: new Date(),
pickupTimeReturn: new Date(),
pickupTime: new Date(Math.round(dateNow.getTime() / roundingTime) * roundingTime),
pickupTimeReturn: new Date(Math.round(dateNow.getTime() / roundingTime) * roundingTime),
pickupTimeReturnDisplayMode: 'none',
open: false,
message: 'Booking Ride',
@@ -398,6 +405,8 @@ class VerticalNonLinear extends React.Component {
},
return_time: new Date(),
pickupTimeHide: false,
showValidationErrors: false,
validationErrors: []
};
}
@@ -412,6 +421,16 @@ class VerticalNonLinear extends React.Component {
if (user.useruuid !== loggedUser.useruuid) {
Instance.getRawConn().get(`/v1/nemt/users/member/${user.useruuid}`)
.then(function (res) {
let userHomeAddress = null;
res.data.addresses.forEach(address => {
if (address.address_type === ADDRESS_TYPE_HOME) {
userHomeAddress = address;
}
});
if (userHomeAddress != null) {
userHomeAddress.name = "Home";
state.handlePickupChanged(userHomeAddress, state);
}
state.setState(Object.assign(state.state, { user: res.data, showUserSelection: true, userSelectionText: `${res.data.member} - ${res.data.name}` }));
})
.catch(err => {
@@ -432,10 +451,12 @@ class VerticalNonLinear extends React.Component {
}
});
let visitTime = new Date(new Date().getTime() + (1 * 60 * 60 * 1000));
let visitDate = visitTime;
let pickupTime = new Date(visitTime.getTime() - (0.5 * 60 * 60 * 1000));
let pickupTimeReturn = new Date(visitTime.getTime() - (0.5 * 60 * 60 * 1000));
let date = new Date();
let visitTime = new Date(Math.round((date.getTime() + (1 * 60 * 60 * 1000)) / roundingTime) * roundingTime);
let visitDate = date;
let pickupTime = new Date(Math.round((visitTime.getTime() - (0.5 * 60 * 60 * 1000)) / roundingTime) * roundingTime);
let pickupTimeReturn = new Date(Math.round((visitTime.getTime() - (0.5 * 60 * 60 * 1000)) / roundingTime) * roundingTime);
this.setState(Object.assign(this.state, {
visitDate: visitDate,
@@ -466,7 +487,8 @@ class VerticalNonLinear extends React.Component {
if (stepIndex === 3) {
self.handleTouchTap();
var requestRide = {
user_uuid: state.state.user.useruuid,
user_uuid: state.state.user ? state.state.user.useruuid : '',
user_consent: state.state.checked,
ride_type: "lyft",
origin: state.state.origin,
destination: state.state.destination,
@@ -480,6 +502,7 @@ class VerticalNonLinear extends React.Component {
eta: 0,
trip_type: state.state.trip_type,
return_time: state.state.return_time,
raw_provider: state.state.destination.raw,
};
if (self.state.eta.distance_miles) requestRide.distance = self.state.eta.distance_miles;
@@ -495,10 +518,21 @@ class VerticalNonLinear extends React.Component {
}
}
console.log(JSON.stringify(requestRide));
return false;
Instance.getRawConn().post('/v1/nemt/rides', requestRide).then(function (res) {
self.handleRequestClose(self);
window.location.href = '/#/app/page/map/' + res.data.ride_uuid;
}).catch(console.error);
}).catch(error => {
if (error.response.status === 422) {
//Unprocessable Entity (validation failed)
self.setState(Object.assign(self.state, {
showValidationErrors: true,
validationErrors: error.response.data.data
}));
}
});
}
}
};
@@ -535,10 +569,10 @@ class VerticalNonLinear extends React.Component {
handleDate(event, date, state) {
let self = state
let visitTime = new Date(date.getTime() + (1 * 60 * 60 * 1000));
let visitTime = new Date(Math.round((date.getTime() + (1 * 60 * 60 * 1000)) / roundingTime) * roundingTime);
let visitDate = date;
let pickupTime = new Date(visitTime.getTime() - (0.5 * 60 * 60 * 1000));
let pickupTimeReturn = new Date(visitTime.getTime() - (0.5 * 60 * 60 * 1000));
let pickupTime = new Date(Math.round((visitTime.getTime() - (0.5 * 60 * 60 * 1000)) / roundingTime) * roundingTime);
let pickupTimeReturn = new Date(Math.round((visitTime.getTime() - (0.5 * 60 * 60 * 1000)) / roundingTime) * roundingTime);
self.setState(Object.assign(self.state, {
visitDate: visitDate,
@@ -685,8 +719,10 @@ class VerticalNonLinear extends React.Component {
name: res.name,
lat: res.lat,
lng: res.lng,
address: res.address
address: res.address,
raw: res.raw,
}
const name = res.name;
if (self.state.origin && self.state.origin.lat && self.state.origin.lng) {
@@ -739,7 +775,7 @@ class VerticalNonLinear extends React.Component {
handlePickupChanged = (res, state) => {
let origin = {
id: res.id,
id: res.address_uuid ? res.address_uuid : res.id,
name: res.name,
lat: res.lat,
lng: res.lng,
@@ -785,6 +821,12 @@ class VerticalNonLinear extends React.Component {
}
handleValidationErrosDialogDismiss() {
this.setState(Object.assign(this.state, {
showValidationErrors: false
}));
}
render() {
// const { stepIndex } = this.state;
this.getLocation();
@@ -823,6 +865,18 @@ class VerticalNonLinear extends React.Component {
if (this.state.showUserSelection && this.state.users.length > 0) {
const handleAutocomplete = (u) => {
let userHomeAddress = null;
if (u.addresses && u.addresses.length > 0) {
u.addresses.forEach(address => {
if (address.address_type === ADDRESS_TYPE_HOME) {
userHomeAddress = address;
}
});
}
if (userHomeAddress != null) {
userHomeAddress.name = "Home";
state.handlePickupChanged(userHomeAddress, state);
}
state.setState(Object.assign(state.state, { user: u, userSelectionText: u.userdata }));
}
const datasourceConfig = { text: 'userdata', value: 'useruuid' }
@@ -848,6 +902,8 @@ class VerticalNonLinear extends React.Component {
<div className="box-body padding-xs">
<div style={{ maxWidth: 380, margin: 'auto' }}>
<ValidationErrorsInfoDialog title={'Errors'} open={this.state.showValidationErrors} draggable={true} modal={false} errorMessages={this.state.validationErrors} onDismiss={this.handleValidationErrosDialogDismiss.bind(this)} />
<Stepper
activeStep={this.state.stepIndex}
linear={false}

View File

@@ -0,0 +1,14 @@
import React from 'react';
import QueueAnim from 'rc-queue-anim';
import VerticalNonLinear from './VerticalNonLinear';
const Stepper = (props) => {
return (
<div className="container-fluid with-maxwidth chapter">
<QueueAnim type="bottom" className="ui-animate">
<div key="1"><VerticalNonLinear params={props.params} /></div>
</QueueAnim>
</div>
);
};
module.exports = Stepper;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
module.exports = {
path: 'visit/:uuid',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('./components/Steppers'));
});
}
};

View File

@@ -0,0 +1,14 @@
import React from 'react';
import QueueAnim from 'rc-queue-anim';
import VerticalNonLinear from './VerticalNonLinear';
const Stepper = (props) => {
return (
<div className="container-fluid with-maxwidth chapter">
<QueueAnim type="bottom" className="ui-animate">
<div key="1"><VerticalNonLinear params={props.params} /></div>
</QueueAnim>
</div>
);
};
module.exports = Stepper;

View File

@@ -0,0 +1,955 @@
import React, { Component } from 'react';
import {
Step,
Stepper,
StepButton,
StepContent,
} from 'material-ui/Stepper';
import RaisedButton from 'material-ui/RaisedButton';
import FlatButton from 'material-ui/FlatButton';
import QueueAnim from 'rc-queue-anim';
import { RadioButton, RadioButtonGroup } from 'material-ui/RadioButton';
import ActionFavorite from 'material-ui/svg-icons/action/favorite';
import ActionFavoriteBorder from 'material-ui/svg-icons/action/favorite-border';
import AutoComplete from 'material-ui/AutoComplete';
import SelectField from 'material-ui/SelectField';
import MenuItem from 'material-ui/MenuItem';
import { Tabs, Tab } from 'material-ui/Tabs';
// import Slider from 'material-ui/Slider';
import TimePicker from 'material-ui/TimePicker';
import DatePicker from 'material-ui/DatePicker';
import TextField from 'material-ui/TextField';
// import Toggle from 'material-ui/Toggle';
import Snackbar from 'material-ui/Snackbar';
import { NEMTLocation } from '../../../../../components/NEMTLocation';
import { request } from 'https';
import Divider from 'material-ui/Divider';
import Paper from 'material-ui/Paper';
import Dialog from 'material-ui/Dialog';
import Close from 'material-ui/svg-icons/navigation/close'
import CommunicationCall from 'material-ui/svg-icons/communication/call'
import Message from 'material-ui/svg-icons/communication/message'
import Instance from '../../../../../../../components/Connection';
import ValidationErrorsInfoDialog from '../../../../../../../components/Shared/ValidationErrorsInfoDialog';
import Checkbox from 'material-ui/Checkbox';
import Popover from 'material-ui/Popover';
import InputMask from 'react-input-mask';
let DateTimeFormat;
const roundingTime = 1000 * 60 * 5; //5 minutes
DateTimeFormat = global.Intl.DateTimeFormat;
class SignUp extends React.Component {
constructor(props) {
super(props);
this.props = props;
}
componentWillReceiveProps = (nextProps) => {
this.props = nextProps;
}
handleEmail = (event) => {
if (this.props.onUserChanged) {
const user = this.props.user;
user.email = event.target.value;
this.props.onUserChanged(user);
}
};
handlePhone = (event) => {
let phone = event.target.value;
if (phone.indexOf("+1") < 0 && phone.length == 10) {
phone = "+1" + phone;
phone = phone.substring(0, 12);
}
if (this.props.onUserChanged) {
const user = this.props.user;
user.phonenumber = event.target.value;
user.phonenumber = user.phonenumber.replace('(','').replace(')','').replace('-','').replace(' ','').trim();
this.props.onUserChanged(user);
}
};
render() {
return (
<form className="">
<fieldset>
{/* <div className="form-group"> */}
<TextField
floatingLabelText="First Name"
value={this.props.user.first}
disabled={true}
/>
<TextField
floatingLabelText="Last Name"
value={this.props.user.last}
disabled={true}
/>
<TextField
floatingLabelText="Email"
type="email"
value={this.props.user.email}
onChange={this.handleEmail}
/>
<SelectField
floatingLabelText="Gender"
value={this.props.user.gender}
disabled={true}
>
<MenuItem value={null} primaryText="" />
<MenuItem value={"M"} primaryText="Male" />
<MenuItem value={"F"} primaryText="Female" />
<MenuItem value={"U"} primaryText="Unknown" />
</SelectField>
<SelectField
style={{ maxWidth: 165 }}
floatingLabelText="Member Type"
value={"S"}
disabled={true}
>
<MenuItem value={null} primaryText="" />
<MenuItem value={"S"} primaryText="Subscriber" />
<MenuItem value={"D"} primaryText="Dependant" />
<MenuItem value={"U"} primaryText="Unknown" />
</SelectField>
<TextField
style={{ maxWidth: 165 }}
floatingLabelText="Member #"
value={this.props.user.member}
disabled={true}
/>
<DatePicker width="115" hintText="Birth Date" container="inline" style={{ width: 115 }}
value={this.props.user.birthdate} disabled={true} />
<TextField
style={{ maxWidth: 115 }}
ref="phone"
type="telephone"
floatingLabelText="Mobile Phone"
value={this.props.user.phonenumber}
onChange={this.handlePhone}
>
<InputMask mask="(999) 999-9999" maskChar={null} value={this.props.user.phonenumber} />
</TextField>
</fieldset>
</form>
);
}
}
export class AdditionalPassengerSelect extends React.Component {
state = {
open: false,
additionalPassenger:
{
passengerType: '',
seatType: '',
}
};
handleOpen = () => {
this.setState({ open: true });
};
handlePassengerTypeChange = (e, i, v, state) => {
this.setState({ additionalPassenger: { passengerType: v } });
};
handleSeatTypeChange = (e, i, v, state) => {
this.setState({ additionalPassenger: { seatType: v } });
};
handleClose = () => {
this.setState({ open: false });
};
render() {
const actions = [
<FlatButton
label="Add"
primary={true}
keyboardFocused={true}
onClick={this.handleClose}
/>,
<FlatButton
label="Cancel"
primary={false}
keyboardFocused={false}
onClick={this.handleClose}
/>,
];
return (
<div>
<RaisedButton style={{ fontSize: 5 }} label="+ Passenger" onClick={this.handleOpen} />
<Dialog
title="Add Passenger"
actions={actions}
modal={false}
open={this.state.open}
onRequestClose={this.handleClose}
>
<SelectField
floatingLabelText="Passenger Type"
value={this.state.additionalPassenger.passengerType}
onChange={(e, i, v) => this.handlePassengerTypeChange(e, i, v, this)}
autoWidth={true}
>
<MenuItem value={'Caregiver'} primaryText="Caregiver" />
<MenuItem value={'Companion'} primaryText="Companion" />
<MenuItem value={'Additional Patient'} primaryText="Additional Patient" />
</SelectField>
<SelectField
floatingLabelText="Seat Type"
value={this.state.additionalPassenger.seatType}
onChange={(e, i, v) => this.handleSeatTypeChange(e, i, v, this)}
autoWidth={true}
>
<MenuItem value={'Ambulatory'} primaryText="Ambulatory" />
<MenuItem value={'Stretcher'} primaryText="Stretcher" />
<MenuItem value={'Wheelchair'} primaryText="Wheelchair" />
</SelectField>
</Dialog>
</div>
);
}
}
const names = [
'Service Animal',
'Cane / Quad Cane',
'Electric Wheelchair',
'Oxygen Tank',
'Sign Language',
'White Cane',
'Leg Braces',
'Crutches',
'Manual Wheelchair',
'Prothesis',
'Walker',
];
export class MobilitySelect extends Component {
state = {
values: [],
};
handleChange = (event, index, values) => this.setState({ values });
menuItems(values) {
return names.map((name) => (
<MenuItem
key={name}
insetChildren={true}
checked={values && values.indexOf(name) > -1}
value={name}
primaryText={name}
autoWidth={false}
style={{ width: 215 }}
/>
));
}
render() {
const { values } = this.state;
return (
<SelectField
autoWidth={false}
style={{ width: 215 }}
multiple={true}
value={values}
floatingLabelText="Mobility Aids"
label="Mobility Aids"
onChange={this.handleChange}
>
{this.menuItems(values)}
</SelectField>
);
}
}
const selectStyles = {
customWidth: {
width: 35,
},
};
var tripType = 'To Visit';
var pickupTimeReturnDisplayMode = "none";
export class RideTypeSelect extends Component {
constructor(props) {
super(props);
this.props = props;
this.state = {
value: 'to_visit',
pickupTimeReturnDisplayMode: 'none',
pickupTimeHide: false,
};
}
componentDidMount() {
this.setState(Object.assign(this.state, { value: this.props.value }));
}
handleChange(event, index, value, state) {
let self = state
tripType = value;
switch (tripType) {
case 'from_visit':
pickupTimeReturnDisplayMode = "none"
self.setState(Object.assign(self.state, { pickupTimeReturnDisplayMode: 'none', value: 'from_visit', pickupTimeHide: false }));
break;
case 'from_visit_call':
pickupTimeReturnDisplayMode = "none"
self.setState(Object.assign(self.state, { pickupTimeReturnDisplayMode: 'none', value: 'from_visit_call', pickupTimeHide: true }));
break;
case 'to_visit':
pickupTimeReturnDisplayMode = "none"
self.setState(Object.assign(self.state, { pickupTimeReturnDisplayMode: 'none', value: 'to_visit', pickupTimeHide: false }));
break;
case 'roundtrip':
pickupTimeReturnDisplayMode = "block"
self.setState(Object.assign(self.state, { pickupTimeReturnDisplayMode: 'block', value: 'roundtrip', pickupTimeHide: false }));
break;
case 'roundtrip_call':
pickupTimeReturnDisplayMode = "none";
self.setState(Object.assign(self.state, { pickupTimeReturnDisplayMode: 'none', value: 'roundtrip_call', pickupTimeHide: false }));
break;
default:
self.setState(Object.assign(self.state, { pickupTimeReturnDisplayMode: 'block', value: 'roundtrip', pickupTimeHide: false }));
break;
}
if (this.props.handleChange) {
this.props.handleChange(event, index, { pickupTimeReturnDisplayMode: self.state.pickupTimeReturnDisplayMode, selectField: this.state.value, pickupTimeHide: this.state.pickupTimeHide });
}
}
render() {
return (
<div >
<SelectField
floatingLabelText="Trip Type"
value={this.state.value}
onChange={(e, i, v) => this.handleChange(e, i, v, this)}
autoWidth={false}
style={{ width: 230 }}
>
<MenuItem value={'to_visit'} primaryText="To Visit" />
<MenuItem value={'from_visit'} primaryText="From Visit" />
<MenuItem value={'from_visit_call'} primaryText="From Visit / Will Call" />
<MenuItem value={'roundtrip'} primaryText="Round Trip" />
<MenuItem value={'roundtrip_call'} primaryText="Round Trip / Will Call" />
</SelectField>
</div>
);
}
}
function disableWeekends(date) {
return date.getDay() === 0 || date.getDay() === 6;
}
const styles = {
padding: '12px 18px',
marginBottom: 12,
fontWeight: 400,
maxWidth: 250,
radioButton: {
marginTop: 6
},
checkbox: {
marginTop: 16, fontWeight: 100, fontSize: 10
},
};
function handleActive(tab) {
console.log(`A tab with this route property ${tab.props.route} was activated.`);
}
const
dataConfig = { text: 'text', value: 'value' };
/**
* A basic vertical non-linear implementation
*/
class VerticalNonLinear extends React.Component {
constructor(props) {
super(props);
let dateNow = new Date();
this.state = {
stepIndex: 0,
rideTypeValue: 0,
providerID: 0,
providerName: '',
visitDate: new Date(),
visitTime: new Date(Math.round(dateNow.getTime() / roundingTime) * roundingTime),
pickupLocation: null,
pickupTime: new Date(Math.round(dateNow.getTime() / roundingTime) * roundingTime),
pickupTimeReturn: new Date(Math.round(dateNow.getTime() / roundingTime) * roundingTime),
pickupTimeReturnDisplayMode: 'none',
open: false,
message: 'Booking Ride',
origin: {},
destination: {},
buttonPickupText: 'Member Address',
buttodDropOffText: 'Choose Drop-Off location',
buttonProviderText: 'Choose Provider',
user: null,
showUserSelection: true,
userSelectionText: '',
users: [],
visit_external_id: "",
notes: "",
pickupTimeReturnDisplayMode: "none",
eta: {
distance_miles: 0,
duration_seconds: 0,
formatted_time: 0,
showed: false,
},
trip_type: {
key: "to_visit",
value: ""
},
return_time: new Date(),
pickupTimeHide: false,
showValidationErrors: false,
validationErrors: [],
visit: {
visit_uuid: "",
visit_status: {
key: "",
value: ""
},
user: {
useruuid: "",
name: "",
first: "",
last: "",
gender: "",
member: "",
birthdate: new Date(),
email: "",
phonenumber: ""
},
visit_datetime: new Date(),
pickup_datetime: new Date(),
notes: "",
pickup_address_id: 33,
pickup: {
id: ""
},
provider: {
provider_uuid: "",
internal_id: "",
muk_id: "",
name: "",
address: {
street_address_1: "",
city: "",
state: "",
zipcode: "",
country: "",
lat: 0,
long: 0,
phone_number: ""
},
organization: {
id: "",
type: {
name: "",
key: ""
},
name: "",
main: false,
active: false,
blocked: false,
suspended: false,
contacts: [],
addresses: []
}
},
trip_type: {
key: "",
value: ""
},
visit_external_id: ""
}
};
this.handleUser = this.handleUser.bind(this);
this.handlePickupChanged = this.handlePickupChanged.bind(this);
}
componentDidMount() {
let self = this;
let visit = {
uuid: this.props.params.uuid
}
Instance.getRawConn().get(`/v1/nemt/visits/${visit.uuid}`)
.then(function (res) {
const visit = res.data;
visit.user.birthdate = new Date(visit.user.birthdate);
visit.visit_datetime = new Date(visit.visit_datetime);
if(visit.user.phonenumber && visit.user.phonenumber.length > 9) {
visit.user.phonenumber = visit.user.phonenumber.replace('+1', '').replace(' ', '').trim();
}
if (visit.user.addresses) {
visit.user.addresses.forEach(a => {
if (a.address_type === 'home') {
const origin = {
id: a.address_uuid,
name: a.address_type_name,
lat: a.lat,
lng: a.lng,
address: a.address
};
self.setState(Object.assign(self.state, { origin: origin, buttonPickupText: a.address_type_name }));
}
});
}
self.setState(Object.assign(self.state, { visit: visit, user: visit.user }));
})
.catch(err => {
if (err.response.status !== 422) {
console.error(err);
}
});
}
//for snackbar
handleTouchTap() {
this.setState(Object.assign(this.state, {
open: true,
}));
};
handleRequestClose(state) {
let self = state;
self.setState(Object.assign(self.state, {
open: false,
}));
};
handleNext(state) {
let self = state;
const { stepIndex } = self.state;
if (stepIndex < 4) {
self.setState(Object.assign(self.state, { stepIndex: stepIndex + 1 }));
if (stepIndex === 3) {
self.handleTouchTap();
const visitRide = {
visit: self.state.visit,
trip_type: self.state.trip_type,
pickup_time: self.state.pickupTime,
return_time: self.state.return_time,
notes: self.state.notes,
origin: self.state.origin,
user: self.state.visit.user,
};
if (self.diffMinutes(self.state.pickupTime, new Date()) > 10) {
visitRide.scheduled_pickup_range = {
range_ms: null,
timestamp_ms: new Date(self.state.pickupTime).getTime()
}
}
Instance.getRawConn().post(`/v1/nemt/visits/${self.state.visit.visit_uuid}/ride`, visitRide).then(function (res) {
window.location.href = '/#/app/page/map/' + res.data.ride_uuid;
}).catch(error => {
if (error.response.status === 422) {
self.setState(Object.assign(self.state, {
showValidationErrors: true,
validationErrors: error.response.data.data
}));
}
});
}
}
};
diffMinutes(dt2, dt1) {
var diff = (dt2.getTime() - dt1.getTime()) / 1000;
diff /= 60;
return Math.abs(Math.round(diff));
}
handlePrev(state) {
let self = state;
const { stepIndex } = self.state;
if (stepIndex > 0) {
self.setState(Object.assign(self.state, { stepIndex: stepIndex - 1 }));
}
};
handleChange(value, state) {
let self = state
self.setState(Object.assign(self.state, {
rideTypeValue: parseInt(value.target.defaultValue)
}));
};
handleDate(event, date, state) {
let self = state
let visitTime = new Date(Math.round((date.getTime() + (1 * 60 * 60 * 1000)) / roundingTime) * roundingTime);
let visitDate = date;
let pickupTime = new Date(Math.round((visitTime.getTime() - (0.5 * 60 * 60 * 1000)) / roundingTime) * roundingTime);
let pickupTimeReturn = new Date(Math.round((visitTime.getTime() - (0.5 * 60 * 60 * 1000)) / roundingTime) * roundingTime);
self.setState(Object.assign(self.state, {
visitDate: visitDate,
visitTime: visitTime,
pickupTime: pickupTime,
pickupTimeReturn: pickupTimeReturn,
}));
}
handleTime(value, date, state) {
let self = state;
self.setState(Object.assign(self.state, {
visitDate: date,
visitTime: date,
pickupTime: new Date(date.getTime() - (0.5 * 60 * 60 * 1000)),
pickupTimeReturn: new Date(date.getTime() - (0.5 * 60 * 60 * 1000)),
}));
}
handlePickupTime(value, date, state) {
let self = state;
console.log('Pickup Time', date);
self.setState(Object.assign(self.state, {
pickupTime: date,
pickupTimeReturn: date
}));
}
handlePickupTimeReturn(value, date, state) {
let self = state;
self.setState(Object.assign(self.state, {
return_time: date,
pickupTimeReturn: date,
pickupTimeReturnDisplayMode: 'block'
}));
}
handlePickup(value) {
console.log(value);
this.setState(Object.assign(this.state, {
pickupLocation: value.text
}));
};
handleNotes(e, value, state) {
let self = state
self.setState(Object.assign(self.state, {
notes: value
}));
}
handleChangeVisitType(event, index, value, state) {
let self = state;
let trip_type = {
key: value.selectField,
}
self.setState(Object.assign(self.state, { pickupTimeReturnDisplayMode: value.pickupTimeReturnDisplayMode, trip_type: trip_type, pickupTimeHide: value.pickupTimeHide }));
}
renderStepActions(step, state) {
let self = state;
return (
<div style={{ margin: '12px 0' }}>
{step !== 2 && (
<RaisedButton
label="Next"
disableTouchRipple
disableFocusRipple
primary
onTouchTap={() => self.handleNext(self)}
style={{ marginRight: 12 }}
/>
)}
{step === 2 && (
<RaisedButton
label="Confirm"
disableTouchRipple
disableFocusRipple
primary
onTouchTap={() => self.handleNext(self)}
style={{ marginRight: 12 }}
href=""
/>
)}
{step > 0 && (
<FlatButton
label="Back"
disableTouchRipple
disableFocusRipple
onTouchTap={() => self.handlePrev(self)}
/>
)}
</div>
);
}
handleValidationErrosDialogDismiss() {
this.setState(Object.assign(this.state, {
showValidationErrors: false
}));
}
handleUser(user) {
const visit = this.state.visit;
visit.user = user;
this.setState(Object.assign(this.state, { visit: visit }));
}
handlePickupChanged = (res) => {
let origin = {
id: res.address_uuid ? res.address_uuid : res.id,
name: res.name,
lat: res.lat,
lng: res.lng,
address: res.address
}
const name = res.name;
this.setState(Object.assign(this.state, {
buttonPickupText: name,
origin: origin
}));
}
render() {
const state = this;
let userSelection;
let pickupTimeSelector;
if (this.state.pickupTimeReturnDisplayMode !== 'none') {
pickupTimeSelector = (
<TimePicker
autoWidth={false}
style={{ width: 80, display: pickupTimeReturnDisplayMode }}
format="ampm"
underlineShow={true}
hintText="Choose Return Time"
floatingLabelText="Return Time"
value={this.state.pickupTimeReturn}
onChange={(e, d) => this.handlePickupTimeReturn(e, d, this)}
minutesStep={5}
/>)
}
let pickupTime = (<TimePicker
autoWidth={false}
style={{ width: 80 }}
format="ampm"
underlineShow={true}
hintText="Choose Pickup Time"
floatingLabelText="Pickup Time"
value={this.state.pickupTime}
onChange={(e, d) => this.handlePickupTime(e, d, this)}
minutesStep={5}
/>);
if (this.state.pickupTimeHide) pickupTime = null;
if (this.state.showUserSelection && this.state.users.length > 0) {
const handleAutocomplete = (u) => {
let userHomeAddress = null;
u.addresses.forEach(address => {
if (address.address_type === ADDRESS_TYPE_HOME) {
userHomeAddress = address;
}
});
if (userHomeAddress != null) {
userHomeAddress.name = "Home";
state.handlePickupChanged(userHomeAddress, state);
}
state.setState(Object.assign(state.state, { user: u, userSelectionText: u.userdata }));
}
const datasourceConfig = { text: 'userdata', value: 'useruuid' }
userSelection = (
<div>
<AutoComplete style={{ fontSize: '10' }} dataSourceConfig={datasourceConfig} dataSource={this.state.users} floatingLabelText="Choose Member" filter={(searchText, key) => (key.toLowerCase().indexOf(searchText.toLowerCase()) !== -1)} maxSearchResults={5} onNewRequest={handleAutocomplete} searchText={this.state.userSelectionText} />
</div>
);
} else if (this.state.showUserSelection && this.state.users.length === 0) {
userSelection = (<div style={{ fontSize: '10' }} >
<strong>Loading...</strong>
</div>);
} else {
userSelection = (<div >
<strong>{this.state.user.member}</strong> - {this.state.user.name}
</div>);
}
return (
<article className="article padding-sm-v">
<h2 className="article-title" style={{ paddingTop: 10, margin: 0 }} >Book Ride from Visit</h2>
<div className="box box-default">
<div className="box-body padding-xs">
<div style={{ maxWidth: 380, margin: 'auto' }}>
<ValidationErrorsInfoDialog open={this.state.showValidationErrors} draggable={true} errorMessages={this.state.validationErrors} onDismiss={this.handleValidationErrosDialogDismiss.bind(this)} />
<Stepper
activeStep={this.state.stepIndex}
linear={false}
orientation="vertical"
>
<Step>
<StepButton onClick={() => this.setState({ stepIndex: 0 })}>
Member
</StepButton>
<StepContent>
<form role="form">
<SignUp user={this.state.visit.user} onUserChanged={this.handleUser} />
<div className="divider" />
<NEMTLocation type="flat" floatingLabelText='Choose Member Location' hintText="Choose Member Location" data={this.state} title={"Member Address"} value={""} buttonvalue={this.state.buttonPickupText} onPlaceChanged={(provider) => this.handlePickupChanged(provider, this)} fontSize={12} loadSuggestion={true} address={this.state.origin} />
</form>
{this.renderStepActions(0, this)}
</StepContent>
</Step>
<Step>
<StepButton onClick={() => this.setState({ stepIndex: 1 })}>
Provider
</StepButton>
<StepContent>
<form role="form">
{this.state.visit.provider.name}<br />
{this.state.visit.provider.address.street_address_1}<br />
{this.state.visit.provider.address.city}, {this.state.visit.provider.address.state} ({this.state.visit.provider.address.zipcode.substr(0, 5)})
</form>
{this.renderStepActions(1, this)}
</StepContent>
</Step>
<Step>
<StepButton onClick={() => this.setState({ stepIndex: 2 })}>
Visit Details
</StepButton>
<StepContent>
<form role="form">
<div className="form-group">
<DatePicker formatDate={new DateTimeFormat('en-US', {
weekday: 'short',
day: 'numeric',
month: 'long',
year: 'numeric',
}).format} style={{ maxWidth: 80 }} hintText="Visit Date" floatingLabelText="Date" container="inline" onChange={(e, d) => this.handleDate(e, d, this)} shouldDisableDate={disableWeekends} value={this.state.visit.visit_datetime} disabled={true} />
<TimePicker
style={{ maxWidth: 80 }}
format="ampm"
hintText="Visit Time"
floatingLabelText="Time"
value={this.state.visit.visit_datetime}
onChange={(e, d) => this.handleTime(e, d, this)}
minutesStep={5} disabled={true}
/>
</div>
<div className="divider" />
<div className="form-group">
<TextField hintText="Visit External ID" disabled="true" floatingLabelText="External ID" onChange={(e, v) => this.handleExternalID(e, v, this)} value={this.state.visit.visit_external_id} disable={true} />
</div>
</form>
{/* <TabsSection /> */}
{this.renderStepActions(1, this)}
</StepContent>
</Step>
<Step>
<StepButton onClick={() => this.setState({ stepIndex: 3 })}>
Trip Details
</StepButton>
<StepContent>
<form>
<RideTypeSelect handleChange={(e, i, v) => this.handleChangeVisitType(e, i, v, this)} value={this.state.trip_type.key} />
{pickupTime}
{pickupTimeSelector}
<MobilitySelect />
<AdditionalPassengerSelect />
<TextField
underlineShow={true}
hintText="Notes for Driver"
floatingLabelText="Notes for Driver"
onChange={(e, v) => this.handleNotes(e, v, this)}
value={this.state.notes} multiLine={true}
maxlength={250}
rows={1}
/>
</form>
{this.renderStepActions(2, this)}
</StepContent>
</Step>
</Stepper>
</div>
<div style={{ maxWidth: 380, margin: 'auto' }}>
<div className="divider divider-xl" />
<div className="callout callout-info">
<p>Complete steps <strong>1 - 4</strong> to schedule your ride!</p>
</div>
</div>
</div>
</div>
<div>
<Snackbar
style={{ fontSize: '7' }}
open={this.state.open}
message={this.state.message}
// message="Booking Ride"
autoHideDuration={50000}
onRequestClose={() => this.handleRequestClose(this)}
/>
</div>
</article>
);
}
}
export default VerticalNonLinear;

View File

@@ -0,0 +1,8 @@
module.exports = {
path: 'visitride/:uuid',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('./components/Steppers'));
});
}
};

View File

@@ -11,6 +11,8 @@ import {
import moment from 'moment';
import Delete from 'material-ui/svg-icons/action/delete';
import IconButton from 'material-ui/IconButton';
import FlatButton from 'material-ui/FlatButton';
import Dialog from 'material-ui/Dialog';
import GoogleAddressComponent from './GoogleAddressComponent';
import ContactComponent from './ContactComponent';
@@ -463,7 +465,9 @@ class Organization extends React.Component {
"useruuid": "",
"name": "",
}
}
},
showErrorMessage : false,
errorMessage : ''
}
componentDidMount() {
@@ -597,11 +601,20 @@ class Organization extends React.Component {
self.setState(Object.assign(self.state, { organization: res.data }));
})
.catch(err => {
if (err.response.status === 422) {
location.href = '/#/app/table/organizations';
} else {
console.error(err);
let errorMessage = '';
switch(err.response.status){
case 403:
errorMessage = 'Not authorized to add child organization';
break;
case 422:
location.href = '/#/app/table/organizations';
break;
default:
errorMessage = 'Error adding child organization';
console.error(err);
}
this.setState(Object.assign(this.state, { showErrorMessage:true, errorMessage:errorMessage }));
});
}
@@ -613,10 +626,32 @@ class Organization extends React.Component {
this.getOrganization(organization.id);
}
handleDialogDismiss(){
this.setState(Object.assign(this.state, { showErrorMessage:false }));
}
render() {
const actions = [
<FlatButton
label="Dismiss"
primary={true}
onClick={this.handleDialogDismiss.bind(this)}
/>,
];
return (
<div className="container-fluid no-breadcrumbs page-dashboard">
<QueueAnim type="bottom" className="ui-animate">
<Dialog
title="Error"
actions={actions}
modal={false}
open={this.state.showErrorMessage}
onRequestClose={this.handleDialogDismiss.bind(this)}
>
{this.state.errorMessage}
</Dialog>
<Main organization={this.state.organization}
onAddressAdded={this.handleAddressAdded} onAddressRemoved={this.handleAddressRemoved}
onContactAdded={this.handleContactAdded} onContactRemoved={this.handleContactRemoved}

View File

@@ -14,6 +14,7 @@ import RaisedButton from 'material-ui/RaisedButton';
import SelectField from 'material-ui/SelectField';
import Checkbox from 'material-ui/Checkbox';
import Instance from '../../../../../../../components/Connection';
import ValidationErrorsInfoDialog from '../../../../../../../components/Shared/ValidationErrorsInfoDialog';
class SignUp extends React.Component {
constructor(props) {
@@ -34,7 +35,10 @@ class SignUp extends React.Component {
gender: null,
agreedTerms: false,
validated: false,
memberType:"S"
memberType:"S",
showValidationErrors: false,
validationErrors:[],
draggableDialog:false
}
componentDidMount = () => {
@@ -58,7 +62,11 @@ class SignUp extends React.Component {
"member": this.state.member,
"email": this.state.email,
"phonenumber": this.state.phonenumber,
"birthdate": this.state.birthdate.toISOString()
"birthdate": this.state.birthdate.toISOString(),
"consent" : this.state.agreedTerms,
"type": this.state.memberType,
"useruuid": "1234567"
// "eligibility": {
// "tracking_id": "1234567",
// "payer": {
@@ -99,9 +107,27 @@ class SignUp extends React.Component {
// alert('NO benefits found for this member');
// }
}).catch(function (err) {
console.log('Error to get eligibility: ', err);
alert('NO benefits found for this member');
this.handleRequestClose();
switch(err.response.status){
case 403:
//Forbidden (not eligible)
console.log(err.response.data);
let messageArray = [
{
message:err.response.data.message
}
]
state.setState(Object.assign(state.state, {showValidationErrors:true, validationErrors:messageArray, draggableDialog:false}))
break;
case 422:
//Unprocessable Entity (validation failed)
state.setState(Object.assign(state.state, {showValidationErrors:true, validationErrors:err.response.data.data, draggableDialog:true}))
break;
default:
console.log('Error to get eligibility: ', err);
alert('NO benefits found for this member');
this.handleRequestClose();
}
});
}
@@ -173,10 +199,15 @@ class SignUp extends React.Component {
this.setState(Object.assign(this.state, { validated: validated }));
}
handleValidationErrosDialogDismiss(){
this.setState(Object.assign(this.state, {showValidationErrors:false}));
}
render() {
return (
<form className="">
<fieldset>
<ValidationErrorsInfoDialog open = {this.state.showValidationErrors} errorMessages = {this.state.validationErrors} draggable={this.state.draggableDialog} onDismiss={this.handleValidationErrosDialogDismiss.bind(this)}/>
<div className="form-group">
<TextField
floatingLabelText="First Name"

View File

@@ -50,7 +50,6 @@ import FloatingActionButton from 'material-ui/FloatingActionButton';
import ContentAdd from 'material-ui/svg-icons/content/add';
import moment from 'moment';
import { Card, CardActions, CardHeader, CardMedia, CardTitle, CardText } from 'material-ui/Card';
import Draggable, { DraggableCore } from 'react-draggable'; // Both at the same time
import Imgix from 'react-imgix'
import Paper from 'material-ui/Paper';

View File

@@ -40,9 +40,11 @@ const getDTList = function (member) {
member.forEach((r, i) => {
list.push(
<tr key={r.useruuid}>
<td><a href={"/#/app/member/" + r.useruuid}>{r.name}</a></td>
<td></td>
<td><a>{r.name}</a></td>
<td>
<div>
<a href={"/#/app/member/" + r.useruuid}> Details </a> |
<ContactList data={{
driverMobile: r.mobile,
memberMobile: r.mobile,
@@ -280,6 +282,7 @@ class DatatableComponent extends React.Component {
<Table ref={(c) => this.example = c} className='display' cellSpacing='0' width='100%'>
<thead>
<tr>
<th> </th>
<th>Name</th>
<th>Action</th>
<th>Subscriber ID</th>

View File

@@ -38,18 +38,22 @@ const getDTList = function (member) {
let list = [];
member.forEach((r, i) => {
let bookRide = '';
if (r.trip_type.key === 'no_trip') {
bookRide = (<a href={`/#/app/form/visitride/${r.visit_uuid}`}>Book Ride</a>)
}
list.push(
<tr key={r.visit_uuid}>
<td>{moment(r.visit_datetime).format('MM/DD/YYYY - h:mm a')}</td>
<td><a href={""}>{r.provider.name}</a></td>
<td><a href={"/#/app/member/" + r.user.useruuid}>{r.user.name}</a></td>
<td>{bookRide}</td>
<td><RoadTripLink rides={r.rides} isOpened={false} currentRide={null} visit={r} onRideClick={handleRide} /></td>
<td><a href={"/#/app/member/" + r.user.useruuid}>{r.user.member}</a></td>
{/* <td>{r.visit_status.value}</td> */}
<td>{r.provider.id}</td>
<td>{r.provider.provider_uuid}</td>
<td>{r.visit_uuid}</td>
<td>{r.visit_external_id}</td>
<td> <a href={""}>{r.created_user.name} </a></td>
<td>{moment(r.created).format('MM/DD/YYYY - h:mm a')}</td>
<td>{moment(r.updated).format('MM/DD/YYYY - h:mm a')}</td>
@@ -104,7 +108,8 @@ class DatatableComponent extends React.Component {
},
columnDefs: [
{ targets: [-1, -3], className: 'dt-body-right mdl-data-table__cell--non-numeric' }
]
],
order: [[0, 'desc']]
});
state.decorateButtons();
state.decorateSelect();
@@ -232,11 +237,10 @@ class DatatableComponent extends React.Component {
<th>Visit Time</th>
<th>Provider</th>
<th>Member </th>
<th>Ride</th>
<th>Rides </th>
<th>Subscriber ID</th>
{/* <th>Status</th> */}
<th>Provider ID</th>
<th>Visit ID</th>
<th>External ID</th>
<th>Scheduler</th>

View File

@@ -8,6 +8,11 @@ import Dialog from 'material-ui/Dialog';
import Instance from '../../../components/Connection';
import {
loggedUser,
visitReporter,
} from 'utils/authorization';
class Login extends React.Component {
constructor(props) {
super(props);
@@ -74,11 +79,15 @@ class Login extends React.Component {
}).then(function (res) {
let auth = res.data;
state.setCookie('token', auth.token, auth.valid_time);
localStorage.setItem('loggedUser', JSON.stringify(auth.user));
Instance.setToken(auth.token);
localStorage.setItem('loggedUser', JSON.stringify(auth.user));
loggedUser.update();
location.href = '/#/';
if (loggedUser.anyOf(visitReporter)) {
location.href = '/#/app/form/visit/' + auth.user.useruuid;
} else {
location.href = '/#/app/table/rides';
}
}).catch(function (err) {
state.setState(Object.assign(state.state, {
message: (err.response.data.message),

View File

@@ -0,0 +1,307 @@
import React from 'react';
import { browserHistory, Redirect } from 'react-router';
import APPCONFIG from 'constants/Config';
import TextField from 'material-ui/TextField';
import QueueAnim from 'rc-queue-anim';
import AutoComplete from 'material-ui/AutoComplete';
import MenuItem from 'material-ui/MenuItem';
import SelectField from 'material-ui/SelectField';
import { Tabs, Tab } from 'material-ui/Tabs';
import Slider from 'material-ui/Slider';
import TimePicker from 'material-ui/TimePicker';
import DatePicker from 'material-ui/DatePicker';
import RaisedButton from 'material-ui/RaisedButton';
import Toggle from 'material-ui/Toggle';
import Snackbar from 'material-ui/Snackbar';
import Instance from '../../../components/Connection';
import Checkbox from 'material-ui/Checkbox';
import ValidationErrorsInfoDialog from '../../../components/Shared/ValidationErrorsInfoDialog';
class SignUp extends React.Component {
constructor(props) {
super(props);
this.props = props;
this.state = {
"provider_name": "",
"provider_npi": "",
"name": "",
"first": "",
"last": "",
"gender": "",
"member": "",
"email": "",
"phone_number": "",
"pass": "",
"birthdate": new Date(),
"validated": false,
"password_validated": false,
"passConfirmation": "",
"organizationType": { name: "", key: "provider", desc: "" },
showValidationErrors: false,
validationErrors: [],
agreedTerms:false,
}
this.buttonValidated = this.buttonValidated.bind(this);
this.handleFirst = this.handleFirst.bind(this);
this.handleLast = this.handleLast.bind(this);
this.handleEmail = this.handleEmail.bind(this);
this.handlePhone = this.handlePhone.bind(this);
this.handlePass = this.handlePass.bind(this);
this.handleConfirmationPass = this.handleConfirmationPass.bind(this);
this.handleProviderName = this.handleProviderName.bind(this);
this.handleProviderNPI = this.handleProviderNPI.bind(this);
this.clickEvent = this.clickEvent.bind(this);
}
componentDidMount = () => { }
getFormattedPhoneNumber(){
if(this.state.phone_number && this.state.phone_number.length > 0) {
return this.state.phone_number.replace('+1','').replace('(','').replace(')','').replace('-','').replace(' ','').trim()
}
return '';
}
isPhoneNumberFormatValid() {
let formattedNumber = this.getFormattedPhoneNumber();
return !isNaN(formattedNumber) && (formattedNumber.toString().length === 10);
}
buttonValidated = () => {
let validated = true;
if (!this.state.provider_name || this.state.provider_name === null || this.state.provider_name === "") validated = false;
if (!this.state.provider_npi || this.state.provider_npi === null || this.state.provider_npi === "") validated = false;
if (!this.state.email || this.state.email === null || this.state.email === "") validated = false;
if (!this.state.phone_number || this.state.phone_number === null || this.state.phone_number === "" || !this.isPhoneNumberFormatValid()) validated = false;
if (!this.state.first || this.state.first === null || this.state.first === "") validated = false;
if (!this.state.last || this.state.last === null || this.state.last === "") validated = false;
if (!this.state.pass || this.state.pass === null || this.state.pass === "") validated = false;
if (!this.state.passConfirmation || this.state.passConfirmation === null || this.state.passConfirmation === "") validated = false;
if (!this.state.agreedTerms) validated = false;
this.setState(Object.assign(this.state, { validated: validated }));
}
handleProviderName = (event) => {
this.setState(Object.assign(this.state, { provider_name: event.target.value }));
};
handleProviderNPI = (event) => {
this.setState(Object.assign(this.state, { provider_npi: event.target.value }));
};
handleFirst = (event) => {
this.setState(Object.assign(this.state, { first: event.target.value }));
};
handleLast = (event) => {
this.setState(Object.assign(this.state, { last: event.target.value }));
};
handleEmail = (event) => {
this.setState(Object.assign(this.state, { email: event.target.value }));
};
handlePhone = (event) => {
let phone = event.target.value;
if (phone.indexOf("+1") < 0 && phone.length == 10) {
phone = "+1" + phone;
phone = phone.substring(0, 12);
}
this.setState(Object.assign(this.state, { phone_number: phone }));
};
handlePass = (event) => {
this.setState(Object.assign(this.state, { pass: btoa(event.target.value) }));
};
handleConfirmationPass = (event) => {
this.setState(Object.assign(this.state, { passConfirmation: btoa(event.target.value) }));
};
handleChecked = (event, checked) => {
this.setState(Object.assign(this.state, { agreedTerms: checked }));
this.buttonValidated();
};
clickEvent = (event) => {
event.preventDefault();
if (this.state.passConfirmation !== this.state.pass){
this.setState(Object.assign(this.state, {
showValidationErrors: true,
validationErrors: [{message:'Confirmed password does not match password'}]
}));
return;
}
const state = this;
let user = {
"provider":
{
"org_name": this.state.provider_name,
"internal_id": this.state.provider_npi
},
"name": this.state.first + ' ' + this.state.last,
"first": this.state.first,
"last": this.state.last,
"email": this.state.email,
"phonenumber": this.state.phone_number,
"pass": this.state.pass,
};
Instance.setToken(null).post('/v1/selfregister/', user).then(function (res) {
localStorage.removeItem('loggedUser');
location.href = '/#/login';
}).catch(function (err) {
switch(err.response.status){
case 422:
//Unprocessable Entity (validation failed)
state.setState(Object.assign(state.state, {
showValidationErrors: true,
validationErrors: err.response.data.data
}));
break;
default:
state.setState(Object.assign(state.state, {
showValidationErrors: true,
validationErrors: [{message:"Error processing your request"}]
}));
}
});
}
handleValidationErrosDialogDismiss() {
this.setState(Object.assign(this.state, {
showValidationErrors: false
}));
}
render() {
return (
<div className="body-inner">
<div className="card bg-white">
<div className="card-content">
<section className="logo text-center">
<h1><a href="#/">CHMHub®</a></h1>
</section>
<form className="form-horizontal">
<fieldset>
<div className="form-group">
<TextField
floatingLabelText="Provider Organization Name"
fullWidth
onChange={this.handleProviderName}
onBlur={this.buttonValidated}
/>
</div>
<div className="form-group">
<TextField
floatingLabelText="Provider NPI"
type="number"
onChange={this.handleProviderNPI}
onBlur={this.buttonValidated}
/>
</div>
<div className="form-group">
<TextField
floatingLabelText="First Name"
fullWidth
onChange={this.handleFirst}
onBlur={this.buttonValidated}
/>
</div>
<div className="form-group">
<TextField
floatingLabelText="Last Name"
fullWidth
onChange={this.handleLast}
onBlur={this.buttonValidated}
/>
</div>
<div className="form-group">
<TextField
floatingLabelText="Your Work Email"
type="email"
fullWidth
onChange={this.handleEmail}
onBlur={this.buttonValidated}
/>
</div>
<div className="form-group">
<TextField
floatingLabelText="Your Mobile Phone"
type="telephone"
onChange={this.handlePhone}
onBlur={this.buttonValidated}
/>
</div>
<div className="form-group">
<TextField
floatingLabelText="Choose Password"
type="password"
onChange={this.handlePass}
onBlur={this.buttonValidated}
/>
<TextField
floatingLabelText="Verify Password"
type="password"
onChange={this.handleConfirmationPass}
onBlur={this.buttonValidated}
/>
</div>
<div className="divider" />
<div className="form-group">
<Checkbox
label="Member has consented to terms of use"
checked={this.state.agreedTerms}
onCheck={this.handleChecked}
/>
</div>
<div className="divider" />
<div className="form-group">
<p className="text-small">By clicking on sign up, you agree to <a href="javascript:;"><i>terms</i></a> and <a href="javascript:;"><i>privacy policy</i></a></p>
</div>
<ValidationErrorsInfoDialog open={this.state.showValidationErrors} errorMessages={this.state.validationErrors} onDismiss={this.handleValidationErrosDialogDismiss.bind(this)} />
</fieldset>
</form>
</div>
<div className="card-action no-border text-right">
<RaisedButton
label="Sign up"
primary={true}
onClick={this.clickEvent}
disabled={!this.state.validated}
/>
</div>
</div>
</div>
);
}
}
const Page = () => (
<div className="page-login">
<div className="main-body">
<QueueAnim type="bottom" className="ui-animate">
<div key="1">
<SignUp />
</div>
</QueueAnim>
</div>
</div>
);
module.exports = Page;

View File

@@ -0,0 +1,8 @@
module.exports = {
path: 'selfRegister',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('./components/SignUp'));
});
}
};

View File

@@ -47,7 +47,9 @@ class SignUp extends React.Component {
"role": { name: "", key: "SP", desc: "" },
"profiles": [],
"types": [],
"organizations": []
"organizations": [],
showValidationErrors : false,
validationErrors: []
}
this.buttonValidated = this.buttonValidated.bind(this);
@@ -226,12 +228,42 @@ class SignUp extends React.Component {
localStorage.removeItem('loggedUser');
location.href = '/#/login';
}).catch(function (err) {
alert('Error to log in: ' + err.message);
if (err.response.status === 422){
//Unprocessable Entity (validation failed)
state.setState(Object.assign(state.state, {
showValidationErrors:true,
validationErrors:err.response.data.data
}));
}else{
alert('Error to log in: ' + err.message);
}
console.error(err);
});
}
handleDismiss(){
this.setState(Object.assign(this.state, { showErrorMessage: false }));
}
render() {
let validationErrors = null;
if (this.state.showValidationErrors){
validationErrors = (
<ul>
{this.state.validationErrors.map(errorMessage=>{
const oneValidationMessage = (<li>{errorMessage.message}</li>);
const oneValidationMessageWithTab = (<span><li style={{marginLeft:2 + "em"}}>{errorMessage.message}</li></span>);
if (errorMessage.field_name === "password-tab"){
return oneValidationMessageWithTab;
} else{
return oneValidationMessage;
}
})}
</ul>
);
}
return (
<div className="body-inner">
@@ -334,6 +366,10 @@ class SignUp extends React.Component {
<div className="form-group">
<p className="text-small">By clicking on sign up, you agree to <a href="javascript:;"><i>terms</i></a> and <a href="javascript:;"><i>privacy policy</i></a></p>
</div>
<div className="divider" />
<div className="form-group">
{validationErrors}
</div>
</fieldset>
</form>
</div>

View File

@@ -14,5 +14,6 @@ export { default as providerScheduler } from './profiles/providerScheduler';
export { default as superAdmin } from './profiles/superAdmin';
export { default as support } from './profiles/support';
export { default as techsupportAdmin } from './profiles/techsupportAdmin';
export { default as visitReporter } from './profiles/visitReporter';
export default authorization;

View File

@@ -3,11 +3,11 @@ import { contains } from 'ramda';
import normalizeRoles from './normalizeRoles';
const loggedUser = JSON.parse(window.localStorage.getItem('loggedUser'));
const loggedUser = () => {
let user = JSON.parse(window.localStorage.getItem('loggedUser'));
if (loggedUser) {
loggedUser.anyOf = (...profiles) => {
const userRole = loggedUser.profiles[0];
const anyOf = (...profiles) => {
const userRole = user.profiles[0];
const userOrgType = userRole.organization.type.key;
const roles = normalizeRoles(profiles);
@@ -22,7 +22,18 @@ if (loggedUser) {
}
return false;
};
}
const update = () => {
user = JSON.parse(window.localStorage.getItem('loggedUser'));
return user;
}
return {
user,
anyOf: anyOf,
update: update,
}
}
export default loggedUser;
export default loggedUser();

View File

@@ -11,7 +11,7 @@ const normalizeRoles = (profiles) => {
}
if (roleKeys.length === 1) {
return profiles[roleKeys[0]].authorize;
return profiles[roleKeys[0]].roles;
}
const roles = profiles.reduce((result, profile) => {

View File

@@ -0,0 +1,7 @@
import authorization from '../authorization';
const visitReporter = authorization({
VIRPT: ['provider'],
});
export default visitReporter;