330 lines
9.2 KiB
JavaScript
330 lines
9.2 KiB
JavaScript
import { duration, utc } from "moment";
|
|
import React, { Component } from "react";
|
|
import DatePicker from "react-datepicker";
|
|
import { connect } from "react-redux";
|
|
import { Redirect } from "react-router-dom";
|
|
import {
|
|
Container,
|
|
Dropdown,
|
|
Form,
|
|
Header,
|
|
Label,
|
|
Message,
|
|
TextArea
|
|
} from "semantic-ui-react";
|
|
|
|
import {
|
|
setFormEmployeeUUID,
|
|
setFormPriceUUID,
|
|
setFormShiftStartTime,
|
|
setFormShiftDuration,
|
|
setFormShiftNote,
|
|
setClearCShiftState,
|
|
setFormShiftDates
|
|
} from "../../../actions/cShift/reducer.actions";
|
|
import { createMultipleCShiftRequest } from "../../../actions/cShift/saga.actions";
|
|
import Error from "../../Shared/Error";
|
|
|
|
import "react-datepicker/dist/react-datepicker.css";
|
|
import "./shiftStartTimeOverrides.css";
|
|
|
|
const CShiftDurationOptions = [];
|
|
for (let min = 60; min <= 480; min += 30) {
|
|
let displayText = duration(min, "minutes").humanize();
|
|
if (min % 60) {
|
|
displayText = duration(Math.floor(min / 60), "hours").humanize();
|
|
displayText += ` and ${duration(min % 60, "minutes").humanize()}`;
|
|
}
|
|
CShiftDurationOptions.push({
|
|
key: min,
|
|
value: min,
|
|
text: displayText
|
|
});
|
|
}
|
|
|
|
class ClientAddShiftForm extends Component {
|
|
componentWillMount = () => {
|
|
this.props.dispatch(setClearCShiftState());
|
|
};
|
|
|
|
changeSelectedEmployee = (e, { value }) => {
|
|
if (value !== this.props.employeeUUID) {
|
|
this.props.dispatch(setFormPriceUUID(""));
|
|
}
|
|
this.props.dispatch(setFormEmployeeUUID(value));
|
|
};
|
|
|
|
changeSelectedPrice = (e, { value }) => {
|
|
this.props.dispatch(setFormPriceUUID(value));
|
|
};
|
|
|
|
/**
|
|
* change handler for shift start time selector.
|
|
* @param momentTime - instance of moment (but we only care about the time)
|
|
*/
|
|
changeShiftStartTime = momentTime => {
|
|
this.props.dispatch(setFormShiftStartTime(momentTime));
|
|
};
|
|
|
|
changeShiftDuration = (e, { value }) => {
|
|
this.props.dispatch(setFormShiftDuration(value));
|
|
};
|
|
|
|
changeShiftNote = event => {
|
|
this.props.dispatch(setFormShiftNote(event.target.value));
|
|
};
|
|
|
|
/**
|
|
* change handler for shift date selector
|
|
* @param momentDate - instance of moment (but we only care about the day)
|
|
*/
|
|
handleSelectDate = momentDate => {
|
|
const shiftDatesCopy = { ...this.props.shiftDates };
|
|
const key = momentDate.format("YYYY-MM-DD");
|
|
if (shiftDatesCopy.hasOwnProperty(key)) {
|
|
delete shiftDatesCopy[key];
|
|
} else {
|
|
shiftDatesCopy[key] = momentDate;
|
|
}
|
|
this.props.dispatch(setFormShiftDates(shiftDatesCopy));
|
|
};
|
|
|
|
onSubmitShifts = event => {
|
|
event.preventDefault();
|
|
// change this into interable cshift post request bodies
|
|
const { priceUUID, startTime, duration, note, shiftDates } = this.props;
|
|
const postRequestBodies = [];
|
|
for (let shiftDateString in shiftDates) {
|
|
const dynamicStartTime = utc(startTime);
|
|
const startDate = shiftDates[shiftDateString];
|
|
dynamicStartTime.set({
|
|
year: startDate.get("year"),
|
|
month: startDate.get("month"),
|
|
date: startDate.get("date")
|
|
});
|
|
const dynamicEndTime = utc(dynamicStartTime);
|
|
dynamicEndTime.add(duration, "minutes");
|
|
postRequestBodies.push({
|
|
get_price_uuid: priceUUID,
|
|
set_start: dynamicStartTime.format(),
|
|
set_end: dynamicEndTime.format(),
|
|
description: note ? note : undefined
|
|
});
|
|
}
|
|
this.props.dispatch(createMultipleCShiftRequest(postRequestBodies));
|
|
};
|
|
|
|
render() {
|
|
const {
|
|
isSendingCShiftRequest,
|
|
cShiftRequestErrors,
|
|
cShiftRequestSuccess,
|
|
selfUser,
|
|
employeeUUID,
|
|
priceUUID,
|
|
startTime,
|
|
duration,
|
|
note,
|
|
shiftDates
|
|
} = this.props;
|
|
|
|
if (!selfUser.client) {
|
|
return <Redirect to="/" />;
|
|
}
|
|
|
|
const employeeChoices = selfUser.client.employees
|
|
.filter(employee => !employee.deleted && !!employee.approved)
|
|
.map(({ uuid, provider }) => ({
|
|
key: uuid,
|
|
value: uuid,
|
|
text: provider.email
|
|
}));
|
|
|
|
const priceChoices = [];
|
|
if (employeeUUID) {
|
|
const employee = selfUser.client.employees.find(emp => {
|
|
return emp && emp.uuid === employeeUUID;
|
|
});
|
|
priceChoices.push(
|
|
...employee.prices
|
|
.filter(price => !price.deleted)
|
|
.map(({ amount, uuid, work_type }) => ({
|
|
key: uuid,
|
|
value: uuid,
|
|
text: `${work_type.label} ($${amount}/hr)`,
|
|
content: (
|
|
<Header>
|
|
<Label
|
|
circular
|
|
empty
|
|
style={{
|
|
backgroundColor: work_type.color,
|
|
borderColor: work_type.color
|
|
}}
|
|
/>
|
|
{work_type.label}
|
|
<Header.Subheader
|
|
style={{ paddingLeft: "2em" }}
|
|
content={`Hourly Rate: ${amount}`}
|
|
/>
|
|
</Header>
|
|
)
|
|
}))
|
|
);
|
|
}
|
|
|
|
const selectedShiftDates = Object.keys(shiftDates).map(
|
|
key => shiftDates[key]
|
|
);
|
|
return (
|
|
<ClientAddShiftFormView
|
|
isSendingCShiftRequest={isSendingCShiftRequest}
|
|
cShiftRequestErrors={cShiftRequestErrors}
|
|
cShiftRequestSuccess={!!cShiftRequestSuccess.length}
|
|
user={selfUser}
|
|
employeeChoices={employeeChoices}
|
|
priceChoices={priceChoices}
|
|
employeeUUID={employeeUUID}
|
|
priceUUID={priceUUID}
|
|
startTime={startTime}
|
|
duration={duration}
|
|
note={note}
|
|
selectedShiftDates={selectedShiftDates}
|
|
changeSelectedEmployee={this.changeSelectedEmployee}
|
|
changeSelectedPrice={this.changeSelectedPrice}
|
|
changeShiftStartTime={this.changeShiftStartTime}
|
|
changeShiftDuration={this.changeShiftDuration}
|
|
changeShiftNote={this.changeShiftNote}
|
|
handleSelectDate={this.handleSelectDate}
|
|
onSubmitShifts={this.onSubmitShifts}
|
|
/>
|
|
);
|
|
}
|
|
}
|
|
|
|
function mapStateToProps(state) {
|
|
return { ...state.cShift, selfUser: state.user.selfUser };
|
|
}
|
|
|
|
const ClientAddShiftFormView = ({
|
|
isSendingCShiftRequest,
|
|
cShiftRequestErrors,
|
|
cShiftRequestSuccess,
|
|
user,
|
|
employeeChoices,
|
|
priceChoices,
|
|
employeeUUID,
|
|
priceUUID,
|
|
startTime,
|
|
duration,
|
|
note,
|
|
selectedShiftDates,
|
|
changeSelectedEmployee,
|
|
changeSelectedPrice,
|
|
changeShiftStartTime,
|
|
changeShiftDuration,
|
|
changeShiftNote,
|
|
handleSelectDate,
|
|
onSubmitShifts
|
|
}) => (
|
|
<Container>
|
|
<Header>Schedule Shifts</Header>
|
|
<Form
|
|
loading={isSendingCShiftRequest}
|
|
onSubmit={onSubmitShifts}
|
|
error={!!cShiftRequestErrors.length}
|
|
success={!!cShiftRequestSuccess}
|
|
>
|
|
<Form.Group widths="equal">
|
|
<Form.Field>
|
|
<label>Employee</label>
|
|
<Dropdown
|
|
onChange={changeSelectedEmployee}
|
|
options={employeeChoices}
|
|
placeholder="Select employee"
|
|
selection
|
|
fluid
|
|
search
|
|
noResultsMessage="No approved employees found."
|
|
value={employeeUUID}
|
|
/>
|
|
</Form.Field>
|
|
<Form.Field>
|
|
<label>Price</label>
|
|
<Dropdown
|
|
onChange={changeSelectedPrice}
|
|
options={priceChoices}
|
|
placeholder="Select price"
|
|
selection
|
|
fluid
|
|
search
|
|
disabled={!employeeUUID}
|
|
noResultsMessage="No prices for given employee."
|
|
value={priceUUID}
|
|
/>
|
|
</Form.Field>
|
|
<Form.Field>
|
|
<label>Shift Start Time</label>
|
|
<DatePicker
|
|
selected={startTime}
|
|
onChange={changeShiftStartTime}
|
|
showTimeSelect
|
|
showTimeSelectOnly
|
|
timeIntervals={30}
|
|
dateFormat="LT Z"
|
|
timeFormat="hh:mm"
|
|
placeholderText="Select shift start time"
|
|
/>
|
|
</Form.Field>
|
|
<Form.Field>
|
|
<label>Shift Duration</label>
|
|
<Dropdown
|
|
onChange={changeShiftDuration}
|
|
options={CShiftDurationOptions}
|
|
placeholder="Select duration"
|
|
selection
|
|
fluid
|
|
value={duration}
|
|
/>
|
|
</Form.Field>
|
|
</Form.Group>
|
|
<Form.Field>
|
|
<label>Note</label>
|
|
<TextArea
|
|
placeholder="Employee notes"
|
|
value={note}
|
|
onChange={changeShiftNote}
|
|
/>
|
|
</Form.Field>
|
|
<Form.Field style={{ textAlign: "center" }}>
|
|
<label>Dates</label>
|
|
<DatePicker
|
|
inline
|
|
onSelect={handleSelectDate}
|
|
highlightDates={selectedShiftDates}
|
|
monthsShown={2}
|
|
// https://github.com/Hacker0x01/react-datepicker/pull/1360
|
|
peekNextMonth={false} // this is broken? Fixed in PR 1360
|
|
minDate={utc(new Date()).add(1, "day")}
|
|
maxDate={utc(new Date())
|
|
.add(1, "month")
|
|
.endOf("month")}
|
|
/>
|
|
</Form.Field>
|
|
{!!cShiftRequestErrors.length && (
|
|
<Error header="" error={cShiftRequestErrors[0]} />
|
|
)}
|
|
<Message success>
|
|
<Message.Header>Add Shift successful!</Message.Header>
|
|
<p>Shifts successfully scheduled.</p>
|
|
{!!cShiftRequestSuccess && (
|
|
<Redirect to="/user/profile/client/shifts" />
|
|
)}
|
|
</Message>
|
|
<Form.Button>Schedule Shift</Form.Button>
|
|
</Form>
|
|
</Container>
|
|
);
|
|
|
|
export default connect(mapStateToProps)(ClientAddShiftForm);
|