2018-04-23 04:10:46 +00:00
|
|
|
import { utc, ISO_8601, duration } from "moment";
|
2018-04-18 19:05:56 +00:00
|
|
|
import React, { Component } from "react";
|
|
|
|
import { connect } from "react-redux";
|
|
|
|
import { Redirect, Link } from "react-router-dom";
|
2018-04-23 00:23:43 +00:00
|
|
|
import {
|
|
|
|
Button,
|
|
|
|
Container,
|
2018-04-23 19:01:41 +00:00
|
|
|
Dropdown,
|
2018-04-23 00:23:43 +00:00
|
|
|
Header,
|
|
|
|
Item,
|
|
|
|
Segment,
|
2018-04-23 03:07:50 +00:00
|
|
|
Pagination,
|
2018-04-23 04:10:46 +00:00
|
|
|
Popup,
|
|
|
|
Loader,
|
2018-04-23 18:19:14 +00:00
|
|
|
Label,
|
|
|
|
List,
|
|
|
|
Message
|
2018-04-23 00:23:43 +00:00
|
|
|
} from "semantic-ui-react";
|
2018-04-23 19:01:41 +00:00
|
|
|
import {
|
|
|
|
setCShiftPage,
|
2018-04-23 21:44:23 +00:00
|
|
|
setCShiftApprovalFilter,
|
|
|
|
setCShiftCompletedFilter,
|
|
|
|
setCShiftProviderFilter,
|
|
|
|
setCShiftWorkTypeFilter
|
2018-04-23 19:01:41 +00:00
|
|
|
} from "../../../actions/cShift/reducer.actions";
|
2018-04-23 04:10:46 +00:00
|
|
|
import {
|
|
|
|
getCShiftsRequest,
|
|
|
|
deleteCShiftRequest
|
|
|
|
} from "../../../actions/cShift/saga.actions";
|
|
|
|
import { getEmployeeFromPrice, getPriceFromPrice } from "./ClientShiftShared";
|
2018-04-18 19:05:56 +00:00
|
|
|
|
|
|
|
class ClientShifts extends Component {
|
2018-04-23 00:23:43 +00:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
pageSize: 10 // client can't control this, but set here just in case
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillMount = () => {
|
|
|
|
this.props.dispatch(
|
|
|
|
getCShiftsRequest({
|
2018-04-23 19:01:41 +00:00
|
|
|
page: this.props.page,
|
|
|
|
approved: this.props.approvalFilter,
|
2018-04-23 21:44:23 +00:00
|
|
|
completed: this.props.completedFilter,
|
|
|
|
manage: this.props.providerFilter,
|
|
|
|
work_type: this.props.workTypeFilter,
|
2018-04-23 00:23:43 +00:00
|
|
|
page_size: this.state.pageSize
|
|
|
|
})
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
handlePaginationChange = (event, { activePage }) => {
|
|
|
|
this.props.dispatch(
|
|
|
|
getCShiftsRequest({
|
|
|
|
page: activePage,
|
2018-04-23 19:01:41 +00:00
|
|
|
approved: this.props.approvalFilter,
|
2018-04-23 21:44:23 +00:00
|
|
|
manage: this.props.providerFilter,
|
|
|
|
work_type: this.props.workTypeFilter,
|
2018-04-23 00:23:43 +00:00
|
|
|
page_size: this.state.pageSize
|
|
|
|
})
|
|
|
|
);
|
2018-04-23 19:01:41 +00:00
|
|
|
this.props.dispatch(setCShiftPage(activePage));
|
|
|
|
};
|
|
|
|
|
|
|
|
handleChangeApprovalFilter = (event, { value }) => {
|
|
|
|
this.props.dispatch(
|
|
|
|
getCShiftsRequest({
|
|
|
|
page: 1,
|
|
|
|
approved: value,
|
2018-04-23 21:44:23 +00:00
|
|
|
completed: this.props.completedFilter,
|
|
|
|
manage: this.props.providerFilter,
|
|
|
|
work_type: this.props.workTypeFilter,
|
2018-04-23 19:01:41 +00:00
|
|
|
page_size: this.state.pageSize
|
|
|
|
})
|
|
|
|
);
|
|
|
|
this.props.dispatch(setCShiftApprovalFilter(value));
|
|
|
|
this.props.dispatch(setCShiftPage(1));
|
2018-04-23 00:23:43 +00:00
|
|
|
};
|
|
|
|
|
2018-04-23 21:44:23 +00:00
|
|
|
handleChangeCompletedFilter = (event, { value }) => {
|
|
|
|
this.props.dispatch(
|
|
|
|
getCShiftsRequest({
|
|
|
|
page: 1,
|
|
|
|
approved: this.props.approvalFilter,
|
|
|
|
completed: value,
|
|
|
|
manage: this.props.providerFilter,
|
|
|
|
work_type: this.props.workTypeFilter,
|
|
|
|
page_size: this.state.pageSize
|
|
|
|
})
|
|
|
|
);
|
|
|
|
this.props.dispatch(setCShiftCompletedFilter(value));
|
|
|
|
this.props.dispatch(setCShiftPage(1));
|
|
|
|
};
|
|
|
|
|
|
|
|
handleChangeProviderFilter = (event, { value }) => {
|
|
|
|
this.props.dispatch(
|
|
|
|
getCShiftsRequest({
|
|
|
|
page: 1,
|
|
|
|
approved: this.props.approvalFilter,
|
|
|
|
completed: this.props.completedFilter,
|
|
|
|
manage: value,
|
|
|
|
work_type: this.props.workTypeFilter,
|
|
|
|
page_size: this.state.pageSize
|
|
|
|
})
|
|
|
|
);
|
|
|
|
this.props.dispatch(setCShiftProviderFilter(value));
|
|
|
|
this.props.dispatch(setCShiftPage(1));
|
|
|
|
};
|
|
|
|
|
2018-04-23 22:35:24 +00:00
|
|
|
handleChangeWorkTypeFilter = (event, { value }) => {
|
2018-04-23 21:44:23 +00:00
|
|
|
this.props.dispatch(
|
|
|
|
getCShiftsRequest({
|
|
|
|
page: 1,
|
|
|
|
approved: this.props.approvalFilter,
|
|
|
|
completed: this.props.completedFilter,
|
|
|
|
manage: this.props.manageFilter,
|
|
|
|
work_type: value,
|
|
|
|
page_size: this.state.pageSize
|
|
|
|
})
|
|
|
|
);
|
|
|
|
this.props.dispatch(setCShiftWorkTypeFilter(value));
|
|
|
|
this.props.dispatch(setCShiftPage(1));
|
2018-04-23 22:35:24 +00:00
|
|
|
};
|
2018-04-23 21:44:23 +00:00
|
|
|
|
2018-04-23 04:10:46 +00:00
|
|
|
deleteCShift = uuid => {
|
|
|
|
this.props.dispatch(deleteCShiftRequest(uuid));
|
|
|
|
};
|
|
|
|
|
2018-04-18 19:05:56 +00:00
|
|
|
render() {
|
2018-04-23 00:23:43 +00:00
|
|
|
const {
|
|
|
|
isSendingCShiftRequest,
|
|
|
|
cShiftRequestSuccess,
|
2018-04-23 19:01:41 +00:00
|
|
|
selfUser,
|
|
|
|
page,
|
2018-04-23 21:44:23 +00:00
|
|
|
approvalFilter,
|
|
|
|
completedFilter,
|
|
|
|
providerFilter,
|
|
|
|
workTypeFilter
|
2018-04-23 00:23:43 +00:00
|
|
|
} = this.props;
|
2018-04-23 19:01:41 +00:00
|
|
|
const { pageSize } = this.state;
|
2018-04-18 19:05:56 +00:00
|
|
|
if (selfUser.client) {
|
2018-04-23 00:23:43 +00:00
|
|
|
return (
|
|
|
|
<ClientShiftsView
|
|
|
|
isSendingCShiftRequest={isSendingCShiftRequest}
|
|
|
|
cShiftRequestSuccess={cShiftRequestSuccess}
|
|
|
|
page={page}
|
2018-04-23 19:01:41 +00:00
|
|
|
approvalFilter={approvalFilter}
|
2018-04-23 21:44:23 +00:00
|
|
|
completedFilter={completedFilter}
|
|
|
|
providerFilter={providerFilter}
|
|
|
|
workTypeFilter={workTypeFilter}
|
2018-04-23 00:23:43 +00:00
|
|
|
pageSize={pageSize}
|
|
|
|
user={selfUser}
|
|
|
|
handlePaginationChange={this.handlePaginationChange}
|
2018-04-23 19:01:41 +00:00
|
|
|
handleChangeApprovalFilter={this.handleChangeApprovalFilter}
|
2018-04-23 21:44:23 +00:00
|
|
|
handleChangeCompletedFilter={this.handleChangeCompletedFilter}
|
|
|
|
handleChangeProviderFilter={this.handleChangeProviderFilter}
|
|
|
|
handleChangeWorkTypeFilter={this.handleChangeWorkTypeFilter}
|
2018-04-23 04:10:46 +00:00
|
|
|
deleteCShift={this.deleteCShift}
|
2018-04-23 00:23:43 +00:00
|
|
|
/>
|
|
|
|
);
|
2018-04-18 19:05:56 +00:00
|
|
|
} else {
|
|
|
|
return <Redirect to="/" />;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function mapStateToProps(state) {
|
2018-04-23 00:23:43 +00:00
|
|
|
return { ...state.cShift, selfUser: state.user.selfUser };
|
2018-04-18 19:05:56 +00:00
|
|
|
}
|
|
|
|
|
2018-04-23 00:23:43 +00:00
|
|
|
const ClientShiftsView = ({
|
|
|
|
isSendingCShiftRequest,
|
|
|
|
cShiftRequestSuccess,
|
|
|
|
user,
|
|
|
|
page,
|
2018-04-23 19:01:41 +00:00
|
|
|
approvalFilter,
|
2018-04-23 21:44:23 +00:00
|
|
|
completedFilter,
|
|
|
|
providerFilter,
|
|
|
|
workTypeFilter,
|
2018-04-23 00:23:43 +00:00
|
|
|
pageSize,
|
2018-04-23 04:10:46 +00:00
|
|
|
handlePaginationChange,
|
2018-04-23 19:01:41 +00:00
|
|
|
handleChangeApprovalFilter,
|
2018-04-23 21:44:23 +00:00
|
|
|
handleChangeCompletedFilter,
|
|
|
|
handleChangeProviderFilter,
|
|
|
|
handleChangeWorkTypeFilter,
|
2018-04-23 04:10:46 +00:00
|
|
|
deleteCShift
|
2018-04-23 00:23:43 +00:00
|
|
|
}) => {
|
|
|
|
const { count = 0, results = [] } = cShiftRequestSuccess;
|
2018-04-23 19:01:41 +00:00
|
|
|
const approvedOptions = [
|
|
|
|
{ text: "Approved", value: true },
|
|
|
|
{ text: "Rejected", value: false },
|
2018-04-23 20:58:14 +00:00
|
|
|
{ text: "Pending", value: "" },
|
2018-04-23 19:01:41 +00:00
|
|
|
{ text: "All", value: null }
|
|
|
|
];
|
2018-04-23 21:44:23 +00:00
|
|
|
const completedOptions = [
|
|
|
|
{ text: "Completed", value: true },
|
|
|
|
{ text: "Incomplete", value: false },
|
|
|
|
{ text: "All", value: null }
|
|
|
|
];
|
|
|
|
const manageOptions = (user.client.employees || []).map(employee => {
|
|
|
|
const name =
|
|
|
|
`${employee.provider.first_name} ${employee.provider.last_name}`.trim() ||
|
|
|
|
"No Name";
|
|
|
|
return {
|
|
|
|
text: `${name} <${employee.provider.email}>`,
|
|
|
|
value: employee.uuid
|
|
|
|
};
|
|
|
|
});
|
|
|
|
manageOptions.push({ text: `All`, value: null });
|
|
|
|
const workTypeOptions = (user.client.work_types || []).map(workType => {
|
|
|
|
return {
|
|
|
|
text: `${workType.label}`,
|
|
|
|
value: workType.uuid,
|
|
|
|
label: (
|
|
|
|
<Label
|
|
|
|
circular
|
|
|
|
empty
|
|
|
|
style={{
|
|
|
|
backgroundColor: workType.color,
|
|
|
|
borderColor: workType.color
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
};
|
|
|
|
});
|
|
|
|
workTypeOptions.push({ text: `All`, value: null });
|
2018-04-23 20:58:14 +00:00
|
|
|
const OLD_PEOPLE_TIME_FORMAT = "dddd, MMMM Do YYYY, h:mm a ";
|
2018-04-23 00:23:43 +00:00
|
|
|
return (
|
|
|
|
<Container>
|
|
|
|
<Header>Shifts</Header>
|
2018-04-23 19:01:41 +00:00
|
|
|
<Segment.Group horizontal>
|
2018-04-23 22:35:24 +00:00
|
|
|
<Button
|
|
|
|
attached="left"
|
|
|
|
basic
|
|
|
|
color="green"
|
|
|
|
as={Link}
|
|
|
|
to="/user/profile/client/add-shift"
|
|
|
|
>
|
|
|
|
Schedule Shift
|
|
|
|
</Button>
|
2018-04-23 19:01:41 +00:00
|
|
|
<Segment>
|
2018-04-23 21:44:23 +00:00
|
|
|
{"Filter by Approval "}
|
2018-04-23 19:01:41 +00:00
|
|
|
<Dropdown
|
|
|
|
inline
|
2018-04-23 20:58:14 +00:00
|
|
|
placeholder={approvalFilter === null ? `All` : `Pending`}
|
2018-04-23 19:01:41 +00:00
|
|
|
options={approvedOptions}
|
|
|
|
onChange={handleChangeApprovalFilter}
|
|
|
|
value={approvalFilter}
|
|
|
|
/>
|
2018-04-23 21:44:23 +00:00
|
|
|
{" and Completed "}
|
|
|
|
<Dropdown
|
|
|
|
inline
|
|
|
|
placeholder="All"
|
|
|
|
options={completedOptions}
|
|
|
|
onChange={handleChangeCompletedFilter}
|
|
|
|
value={completedFilter}
|
|
|
|
/>
|
|
|
|
{" and Provider "}
|
|
|
|
<Dropdown
|
|
|
|
inline
|
|
|
|
placeholder="All"
|
|
|
|
options={manageOptions}
|
|
|
|
onChange={handleChangeProviderFilter}
|
|
|
|
value={providerFilter}
|
|
|
|
/>
|
|
|
|
{" and Work Type "}
|
|
|
|
<Dropdown
|
|
|
|
inline
|
|
|
|
placeholder="All"
|
|
|
|
options={workTypeOptions}
|
|
|
|
onChange={handleChangeWorkTypeFilter}
|
|
|
|
value={workTypeFilter}
|
|
|
|
/>
|
2018-04-23 19:01:41 +00:00
|
|
|
</Segment>
|
|
|
|
</Segment.Group>
|
2018-04-23 17:07:33 +00:00
|
|
|
{!!isSendingCShiftRequest && <Loader content="Loading" active />}
|
2018-04-23 00:23:43 +00:00
|
|
|
{!isSendingCShiftRequest &&
|
|
|
|
results.length > 0 && (
|
2018-04-23 03:07:50 +00:00
|
|
|
<Item.Group divided>
|
2018-04-23 04:10:46 +00:00
|
|
|
{results.map(result => {
|
2018-04-23 17:07:33 +00:00
|
|
|
const employee = getEmployeeFromPrice(result.price, user) || {};
|
|
|
|
const provider = employee.provider || {};
|
|
|
|
const price = getPriceFromPrice(result.price, user) || {};
|
2018-04-23 04:10:46 +00:00
|
|
|
const workType = price.work_type;
|
2018-04-23 18:19:14 +00:00
|
|
|
const checkedIn =
|
|
|
|
!!result.actual_start && utc(result.actual_start, ISO_8601);
|
|
|
|
const checkedOut =
|
|
|
|
!!result.actual_end && utc(result.actual_end, ISO_8601);
|
2018-04-23 04:10:46 +00:00
|
|
|
const min = duration(
|
|
|
|
utc(result.set_end, ISO_8601) - utc(result.set_start, ISO_8601),
|
|
|
|
"milliseconds"
|
|
|
|
).as("minutes");
|
2018-04-23 17:07:33 +00:00
|
|
|
let displayDuration = duration(min, "minutes").humanize();
|
2018-04-23 04:10:46 +00:00
|
|
|
if (min % 60) {
|
2018-04-23 17:07:33 +00:00
|
|
|
displayDuration = duration(
|
2018-04-23 04:10:46 +00:00
|
|
|
Math.floor(min / 60),
|
|
|
|
"hours"
|
|
|
|
).humanize();
|
2018-04-23 17:07:33 +00:00
|
|
|
displayDuration += ` and ${duration(
|
2018-04-23 04:10:46 +00:00
|
|
|
min % 60,
|
|
|
|
"minutes"
|
|
|
|
).humanize()}`;
|
|
|
|
}
|
2018-04-23 17:07:33 +00:00
|
|
|
const approved = !!result.approved;
|
|
|
|
const rejected = !result.approved && result.approved !== null;
|
|
|
|
const pending = result.approved === null;
|
2018-04-23 04:10:46 +00:00
|
|
|
return (
|
|
|
|
<Item key={result.uuid}>
|
|
|
|
<Item.Content>
|
|
|
|
<Item.Header>
|
|
|
|
<Label
|
|
|
|
circular
|
|
|
|
empty
|
|
|
|
style={{
|
|
|
|
backgroundColor: workType.color,
|
|
|
|
borderColor: workType.color
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
{workType.label}
|
|
|
|
</Item.Header>
|
2018-04-23 17:07:33 +00:00
|
|
|
<Item.Extra>
|
|
|
|
<Label
|
|
|
|
color={approved ? "green" : rejected ? "red" : "grey"}
|
|
|
|
tag
|
|
|
|
size="small"
|
|
|
|
>
|
|
|
|
{approved && "Approved"}
|
|
|
|
{pending && "Approval Pending"}
|
|
|
|
{rejected && "Rejected"}
|
|
|
|
</Label>
|
|
|
|
</Item.Extra>
|
2018-04-23 04:10:46 +00:00
|
|
|
<Item.Meta>
|
|
|
|
{"At " +
|
|
|
|
utc(result.set_start, ISO_8601)
|
|
|
|
.local(false)
|
2018-04-23 20:58:14 +00:00
|
|
|
.format(OLD_PEOPLE_TIME_FORMAT)}
|
2018-04-23 04:10:46 +00:00
|
|
|
</Item.Meta>
|
2018-04-23 17:07:33 +00:00
|
|
|
<Item.Meta>{displayDuration}</Item.Meta>
|
|
|
|
<Item.Meta>{`Rate $${price.amount}/hour`}</Item.Meta>
|
|
|
|
{/* <Item.Description>{result.description}</Item.Description> */}
|
2018-04-23 05:04:09 +00:00
|
|
|
{/* <code>{JSON.stringify(result, null, 2)}</code> */}
|
2018-04-23 17:07:33 +00:00
|
|
|
<Item.Description>
|
|
|
|
{`${provider.first_name} ${provider.last_name}`.trim() ||
|
|
|
|
"No Name!"}{" "}
|
|
|
|
<a href={"mailto:" + provider.email}>{provider.email}</a>
|
|
|
|
</Item.Description>
|
2018-04-23 04:10:46 +00:00
|
|
|
</Item.Content>
|
2018-04-23 18:19:14 +00:00
|
|
|
{!checkedIn && (
|
2018-04-23 04:10:46 +00:00
|
|
|
<Item.Extra>
|
|
|
|
<Button
|
|
|
|
primary
|
|
|
|
floated="right"
|
|
|
|
as={Link}
|
|
|
|
to={`/user/profile/client/edit-shift/${result.uuid}`}
|
|
|
|
>
|
|
|
|
Edit
|
|
|
|
</Button>
|
|
|
|
<Popup
|
|
|
|
content={
|
|
|
|
<div>
|
|
|
|
Are you sure you want to delete this shift?<br />
|
|
|
|
<Button
|
|
|
|
basic
|
|
|
|
color="red"
|
|
|
|
size="small"
|
|
|
|
onClick={() => deleteCShift(result.uuid)}
|
|
|
|
>
|
|
|
|
Confirm Deletion
|
|
|
|
</Button>
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
trigger={
|
|
|
|
<Button color="red" floated="right">
|
|
|
|
Delete
|
|
|
|
</Button>
|
|
|
|
}
|
|
|
|
on="click"
|
|
|
|
position="top right"
|
|
|
|
/>
|
|
|
|
</Item.Extra>
|
|
|
|
)}
|
2018-04-23 18:19:14 +00:00
|
|
|
{checkedIn && (
|
|
|
|
<Item.Content>
|
|
|
|
<Item.Description>
|
|
|
|
{result.description && (
|
|
|
|
<Message>{result.description}</Message>
|
|
|
|
)}
|
|
|
|
<strong>Provider</strong>
|
|
|
|
<List bulleted>
|
|
|
|
<List.Item>
|
|
|
|
{"Checked in at " +
|
|
|
|
checkedIn
|
|
|
|
.local(false)
|
2018-04-23 20:58:14 +00:00
|
|
|
.format(OLD_PEOPLE_TIME_FORMAT)}
|
2018-04-23 18:19:14 +00:00
|
|
|
</List.Item>
|
|
|
|
{checkedOut && (
|
|
|
|
<List.Item>
|
|
|
|
{"Checked out at " +
|
|
|
|
checkedOut
|
|
|
|
.local(false)
|
2018-04-23 20:58:14 +00:00
|
|
|
.format(OLD_PEOPLE_TIME_FORMAT)}
|
2018-04-23 18:19:14 +00:00
|
|
|
</List.Item>
|
|
|
|
)}
|
|
|
|
</List>
|
|
|
|
{result.chart && (
|
|
|
|
<Message>
|
|
|
|
<Message.Header>Chart</Message.Header>
|
|
|
|
{result.chart}
|
|
|
|
</Message>
|
|
|
|
)}
|
|
|
|
</Item.Description>
|
|
|
|
</Item.Content>
|
|
|
|
)}
|
2018-04-23 04:10:46 +00:00
|
|
|
</Item>
|
|
|
|
);
|
|
|
|
})}
|
2018-04-23 00:23:43 +00:00
|
|
|
</Item.Group>
|
|
|
|
)}
|
|
|
|
<div style={{ textAlign: "center" }}>
|
|
|
|
<Pagination
|
|
|
|
activePage={page}
|
|
|
|
onPageChange={handlePaginationChange}
|
|
|
|
totalPages={Math.ceil(count / pageSize)}
|
|
|
|
boundaryRange={1}
|
|
|
|
siblingRange={1}
|
|
|
|
size="mini"
|
|
|
|
firstItem={undefined}
|
|
|
|
lastItem={undefined}
|
|
|
|
prevItem={null}
|
|
|
|
nextItem={null}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</Container>
|
|
|
|
);
|
|
|
|
};
|
2018-04-18 19:05:56 +00:00
|
|
|
|
|
|
|
export default connect(mapStateToProps)(ClientShifts);
|