You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

333 lines
9.3 KiB

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="/" />;
}
if (cShiftRequestSuccess) {
console.log(cShiftRequestSuccess);
}
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);