working edit cshift functionality
This commit is contained in:
parent
0950f264e8
commit
4f548d529f
|
@ -10,6 +10,7 @@ import {
|
||||||
SET_FORM_SHIFT_DURATION,
|
SET_FORM_SHIFT_DURATION,
|
||||||
SET_FORM_SHIFT_NOTE,
|
SET_FORM_SHIFT_NOTE,
|
||||||
SET_FORM_SHIFT_DATES,
|
SET_FORM_SHIFT_DATES,
|
||||||
|
SET_CSHIFT_UUID,
|
||||||
SET_CLEAR_CSHIFT_STATE
|
SET_CLEAR_CSHIFT_STATE
|
||||||
} from "../../constants/cShift.constants";
|
} from "../../constants/cShift.constants";
|
||||||
import { parseError } from "../common.actions";
|
import { parseError } from "../common.actions";
|
||||||
|
@ -43,7 +44,7 @@ export function setCShiftRequestErrors(exceptions) {
|
||||||
return {
|
return {
|
||||||
type: SET_CSHIFT_REQUEST_ERRORS,
|
type: SET_CSHIFT_REQUEST_ERRORS,
|
||||||
data: errors
|
data: errors
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearCShiftRequestError() {
|
export function clearCShiftRequestError() {
|
||||||
|
@ -107,6 +108,13 @@ export function setFormShiftDates(dates) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setCShiftUUID(uuid) {
|
||||||
|
return {
|
||||||
|
type: SET_CSHIFT_UUID,
|
||||||
|
data: uuid
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function setClearCShiftState() {
|
export function setClearCShiftState() {
|
||||||
return {
|
return {
|
||||||
type: SET_CLEAR_CSHIFT_STATE
|
type: SET_CLEAR_CSHIFT_STATE
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import {
|
import {
|
||||||
CREATE_MULTIPLE_CSHIFT_REQUEST,
|
CREATE_MULTIPLE_CSHIFT_REQUEST,
|
||||||
GET_CSHIFTS_REQUEST
|
GET_CSHIFTS_REQUEST,
|
||||||
|
GET_CSHIFT_REQUEST,
|
||||||
|
EDIT_CSHIFT_REQUEST
|
||||||
} from "../../constants/cShift.constants";
|
} from "../../constants/cShift.constants";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,3 +22,17 @@ export function getCShiftsRequest(params) {
|
||||||
data: params
|
data: params
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCShiftRequest(payload) {
|
||||||
|
return {
|
||||||
|
type: GET_CSHIFT_REQUEST,
|
||||||
|
data: payload
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editCShiftRequest(payload) {
|
||||||
|
return {
|
||||||
|
type: EDIT_CSHIFT_REQUEST,
|
||||||
|
data: payload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { get, post } from "./baseApi";
|
import { get, put, post } from "./baseApi";
|
||||||
|
|
||||||
export function createCShifts(postBodies) {
|
export function createCShifts(postBodies) {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
|
@ -15,3 +15,11 @@ export function createCShifts(postBodies) {
|
||||||
export function getCShifts(params) {
|
export function getCShifts(params) {
|
||||||
return get("/cshift/", params).then(resp => Promise.resolve(resp));
|
return get("/cshift/", params).then(resp => Promise.resolve(resp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCShift(uuid, params) {
|
||||||
|
return get(`/cshift/${uuid}/`, params).then(resp => Promise.resolve(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editCShift(uuid, payload) {
|
||||||
|
return put(`/cshift/${uuid}/`, payload).then(resp => Promise.resolve(resp));
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import UpdatePriceForm from "./User/Client/UpdatePriceForm";
|
||||||
import ClientAddProviderForm from "./User/Client/ClientAddProviderForm";
|
import ClientAddProviderForm from "./User/Client/ClientAddProviderForm";
|
||||||
import ClientShifts from "./User/Client/ClientShifts";
|
import ClientShifts from "./User/Client/ClientShifts";
|
||||||
import ClientAddShiftForm from "./User/Client/ClientAddShiftForm";
|
import ClientAddShiftForm from "./User/Client/ClientAddShiftForm";
|
||||||
|
import ClientEditShiftForm from "./User/Client/ClientEditShiftForm";
|
||||||
import ProviderClients from "./User/Provider/ProviderClients";
|
import ProviderClients from "./User/Provider/ProviderClients";
|
||||||
import CompleteRegistration from "./User/CompleteRegistration";
|
import CompleteRegistration from "./User/CompleteRegistration";
|
||||||
import EditProfile from "./User/EditProfile";
|
import EditProfile from "./User/EditProfile";
|
||||||
|
@ -92,6 +93,10 @@ class App extends Component {
|
||||||
path="/user/profile/client/add-shift"
|
path="/user/profile/client/add-shift"
|
||||||
component={ClientAddShiftForm}
|
component={ClientAddShiftForm}
|
||||||
/>
|
/>
|
||||||
|
<PrivateRoute
|
||||||
|
path="/user/profile/client/edit-shift/:shiftUUID"
|
||||||
|
component={ClientEditShiftForm}
|
||||||
|
/>
|
||||||
<PrivateRoute
|
<PrivateRoute
|
||||||
path="/user/profile/provider/clients"
|
path="/user/profile/provider/clients"
|
||||||
component={ProviderClients}
|
component={ProviderClients}
|
||||||
|
|
|
@ -1,17 +1,8 @@
|
||||||
import { duration, utc } from "moment";
|
import { utc } from "moment";
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import DatePicker from "react-datepicker";
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Redirect } from "react-router-dom";
|
import { Redirect } from "react-router-dom";
|
||||||
import {
|
import { Header, Label } from "semantic-ui-react";
|
||||||
Container,
|
|
||||||
Dropdown,
|
|
||||||
Form,
|
|
||||||
Header,
|
|
||||||
Label,
|
|
||||||
Message,
|
|
||||||
TextArea
|
|
||||||
} from "semantic-ui-react";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
setFormEmployeeUUID,
|
setFormEmployeeUUID,
|
||||||
|
@ -23,24 +14,7 @@ import {
|
||||||
setFormShiftDates
|
setFormShiftDates
|
||||||
} from "../../../actions/cShift/reducer.actions";
|
} from "../../../actions/cShift/reducer.actions";
|
||||||
import { createMultipleCShiftRequest } from "../../../actions/cShift/saga.actions";
|
import { createMultipleCShiftRequest } from "../../../actions/cShift/saga.actions";
|
||||||
import Error from "../../Shared/Error";
|
import { ClientShiftFormView } from "./ClientShiftFormView";
|
||||||
|
|
||||||
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 {
|
class ClientAddShiftForm extends Component {
|
||||||
componentWillMount = () => {
|
componentWillMount = () => {
|
||||||
|
@ -177,7 +151,7 @@ class ClientAddShiftForm extends Component {
|
||||||
key => shiftDates[key]
|
key => shiftDates[key]
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<ClientAddShiftFormView
|
<ClientShiftFormView
|
||||||
isSendingCShiftRequest={isSendingCShiftRequest}
|
isSendingCShiftRequest={isSendingCShiftRequest}
|
||||||
cShiftRequestErrors={cShiftRequestErrors}
|
cShiftRequestErrors={cShiftRequestErrors}
|
||||||
cShiftRequestSuccess={!!cShiftRequestSuccess.length}
|
cShiftRequestSuccess={!!cShiftRequestSuccess.length}
|
||||||
|
@ -206,124 +180,4 @@ function mapStateToProps(state) {
|
||||||
return { ...state.cShift, selfUser: state.user.selfUser };
|
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);
|
export default connect(mapStateToProps)(ClientAddShiftForm);
|
||||||
|
|
237
src/components/User/Client/ClientEditShiftForm.jsx
Normal file
237
src/components/User/Client/ClientEditShiftForm.jsx
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
import { utc, duration, ISO_8601 } from "moment";
|
||||||
|
import React, { Component } from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { Redirect } from "react-router-dom";
|
||||||
|
import { Header, Label, Loader } from "semantic-ui-react";
|
||||||
|
|
||||||
|
import {
|
||||||
|
setFormEmployeeUUID,
|
||||||
|
setFormPriceUUID,
|
||||||
|
setFormShiftStartTime,
|
||||||
|
setFormShiftDuration,
|
||||||
|
setFormShiftNote,
|
||||||
|
setClearCShiftState,
|
||||||
|
setFormShiftDates,
|
||||||
|
setCShiftUUID
|
||||||
|
} from "../../../actions/cShift/reducer.actions";
|
||||||
|
import {
|
||||||
|
getCShiftRequest,
|
||||||
|
editCShiftRequest
|
||||||
|
} from "../../../actions/cShift/saga.actions";
|
||||||
|
import { ClientShiftFormView } from "./ClientShiftFormView";
|
||||||
|
import { getEmployeeFromPrice } from "./ClientShiftShared";
|
||||||
|
|
||||||
|
class ClientEditShiftForm extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
const { cShiftRequestSuccess, selfUser } = this.props;
|
||||||
|
if (selfUser.client && cShiftRequestSuccess.uuid) {
|
||||||
|
const employee = getEmployeeFromPrice(
|
||||||
|
cShiftRequestSuccess.price,
|
||||||
|
selfUser
|
||||||
|
);
|
||||||
|
const startTime = utc(cShiftRequestSuccess.set_start, ISO_8601).local();
|
||||||
|
const endTime = utc(cShiftRequestSuccess.set_end, ISO_8601).local();
|
||||||
|
this.props.dispatch(setCShiftUUID(cShiftRequestSuccess.uuid));
|
||||||
|
this.props.dispatch(setFormShiftDates([startTime]));
|
||||||
|
this.props.dispatch(setFormShiftStartTime(startTime));
|
||||||
|
this.props.dispatch(
|
||||||
|
setFormShiftDuration(
|
||||||
|
duration(endTime - startTime, "milliseconds").as("minutes")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
this.props.dispatch(setFormEmployeeUUID(employee.uuid));
|
||||||
|
this.props.dispatch(setFormShiftNote(cShiftRequestSuccess.description));
|
||||||
|
this.props.dispatch(setFormPriceUUID(cShiftRequestSuccess.price));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 => {
|
||||||
|
this.props.dispatch(setFormShiftDates([momentDate]));
|
||||||
|
};
|
||||||
|
|
||||||
|
onSubmitShifts = event => {
|
||||||
|
event.preventDefault();
|
||||||
|
// change this into interable cshift post request bodies
|
||||||
|
const {
|
||||||
|
cShiftUUID,
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log({ ...postRequestBodies[0], uuid: cShiftUUID })
|
||||||
|
this.props.dispatch(
|
||||||
|
editCShiftRequest({ ...postRequestBodies[0], uuid: cShiftUUID })
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
isSendingCShiftRequest,
|
||||||
|
cShiftRequestErrors,
|
||||||
|
cShiftRequestSuccess,
|
||||||
|
selfUser,
|
||||||
|
employeeUUID,
|
||||||
|
priceUUID,
|
||||||
|
startTime,
|
||||||
|
duration,
|
||||||
|
note,
|
||||||
|
shiftDates,
|
||||||
|
cShiftUUID
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
if (!selfUser.client) {
|
||||||
|
return <Redirect to="/" />;
|
||||||
|
}
|
||||||
|
if (cShiftUUID === true) {
|
||||||
|
return <Redirect to="/user/profile/client/shifts" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const employeeChoices = selfUser.client.employees
|
||||||
|
// TODO: ugly edit of state changed employee
|
||||||
|
.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 (
|
||||||
|
<ClientShiftFormView
|
||||||
|
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}
|
||||||
|
isEditing={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state) {
|
||||||
|
return { ...state.cShift, selfUser: state.user.selfUser };
|
||||||
|
}
|
||||||
|
|
||||||
|
class EditClientShiftWrapper extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.props.dispatch(setClearCShiftState());
|
||||||
|
this.props.dispatch(
|
||||||
|
getCShiftRequest({ uuid: this.props.match.params.shiftUUID })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { cShiftRequestSuccess } = this.props;
|
||||||
|
if (cShiftRequestSuccess.uuid) {
|
||||||
|
return <ClientEditShiftForm {...this.props} />;
|
||||||
|
} else {
|
||||||
|
return <Loader />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(EditClientShiftWrapper);
|
159
src/components/User/Client/ClientShiftFormView.jsx
Normal file
159
src/components/User/Client/ClientShiftFormView.jsx
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
import { utc, duration } from "moment";
|
||||||
|
import React from "react";
|
||||||
|
import DatePicker from "react-datepicker";
|
||||||
|
import { Redirect } from "react-router-dom";
|
||||||
|
import {
|
||||||
|
Container,
|
||||||
|
Dropdown,
|
||||||
|
Form,
|
||||||
|
Header,
|
||||||
|
Message,
|
||||||
|
TextArea
|
||||||
|
} from "semantic-ui-react";
|
||||||
|
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ClientShiftFormView = ({
|
||||||
|
isSendingCShiftRequest,
|
||||||
|
cShiftRequestErrors,
|
||||||
|
cShiftRequestSuccess,
|
||||||
|
user,
|
||||||
|
employeeChoices,
|
||||||
|
priceChoices,
|
||||||
|
employeeUUID,
|
||||||
|
priceUUID,
|
||||||
|
startTime,
|
||||||
|
duration,
|
||||||
|
note,
|
||||||
|
selectedShiftDates,
|
||||||
|
changeSelectedEmployee,
|
||||||
|
changeSelectedPrice,
|
||||||
|
changeShiftStartTime,
|
||||||
|
changeShiftDuration,
|
||||||
|
changeShiftNote,
|
||||||
|
handleSelectDate,
|
||||||
|
onSubmitShifts,
|
||||||
|
isEditing = false
|
||||||
|
}) => (
|
||||||
|
<Container>
|
||||||
|
<Header>
|
||||||
|
{!isEditing && "Schedule Shifts"}
|
||||||
|
{isEditing && "Edit Shift"}
|
||||||
|
</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>
|
||||||
|
{!isEditing && "Schedule Shifts"}
|
||||||
|
{isEditing && "Edit Shift"}
|
||||||
|
</Form.Button>
|
||||||
|
</Form>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default ClientShiftFormView;
|
13
src/components/User/Client/ClientShiftShared.js
Normal file
13
src/components/User/Client/ClientShiftShared.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
export const getEmployeeFromPrice = (priceUUID, selfUser) => {
|
||||||
|
const employees = selfUser && selfUser.client && selfUser.client.employees;
|
||||||
|
let matchEmployee = null;
|
||||||
|
employees.forEach(employee => {
|
||||||
|
const priceMatch = employee.prices.filter(price => {
|
||||||
|
return price.uuid === priceUUID;
|
||||||
|
});
|
||||||
|
if (priceMatch.length > 0) {
|
||||||
|
matchEmployee = employee;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return matchEmployee;
|
||||||
|
};
|
|
@ -7,7 +7,8 @@ import {
|
||||||
Header,
|
Header,
|
||||||
Item,
|
Item,
|
||||||
Segment,
|
Segment,
|
||||||
Pagination
|
Pagination,
|
||||||
|
Loader
|
||||||
} from "semantic-ui-react";
|
} from "semantic-ui-react";
|
||||||
import { getCShiftsRequest } from "../../../actions/cShift/saga.actions";
|
import { getCShiftsRequest } from "../../../actions/cShift/saga.actions";
|
||||||
|
|
||||||
|
@ -91,15 +92,29 @@ const ClientShiftsView = ({
|
||||||
Schedule a Shift
|
Schedule a Shift
|
||||||
</Button>
|
</Button>
|
||||||
</Segment>
|
</Segment>
|
||||||
|
{!!isSendingCShiftRequest && <Loader content="Loading" />}
|
||||||
{!isSendingCShiftRequest &&
|
{!isSendingCShiftRequest &&
|
||||||
results.length > 0 && (
|
results.length > 0 && (
|
||||||
<Item.Group>
|
<Item.Group divided>
|
||||||
{results.map(result => (
|
{results.map(result => (
|
||||||
<Item key={result.uuid}>
|
<Item key={result.uuid}>
|
||||||
<Item.Content>
|
<Item.Content>
|
||||||
<Item.Header content={result.uuid} />
|
<Item.Header content={result.uuid} />
|
||||||
<code>{JSON.stringify(result, null, 2)}</code>
|
<code>{JSON.stringify(result, null, 2)}</code>
|
||||||
</Item.Content>
|
</Item.Content>
|
||||||
|
<Item.Extra>
|
||||||
|
<Button
|
||||||
|
primary
|
||||||
|
floated="right"
|
||||||
|
as={Link}
|
||||||
|
to={`/user/profile/client/edit-shift/${result.uuid}`}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</Button>
|
||||||
|
<Button color="red" floated="right">
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</Item.Extra>
|
||||||
</Item>
|
</Item>
|
||||||
))}
|
))}
|
||||||
</Item.Group>
|
</Item.Group>
|
||||||
|
|
|
@ -10,8 +10,11 @@ export const SET_FORM_SHIFT_START_TIME = "SET_FORM_SHIFT_START_TIME";
|
||||||
export const SET_FORM_SHIFT_DURATION = "SET_FORM_SHIFT_DURATION";
|
export const SET_FORM_SHIFT_DURATION = "SET_FORM_SHIFT_DURATION";
|
||||||
export const SET_FORM_SHIFT_NOTE = "SET_FORM_SHIFT_NOTE";
|
export const SET_FORM_SHIFT_NOTE = "SET_FORM_SHIFT_NOTE";
|
||||||
export const SET_FORM_SHIFT_DATES = "SET_FORM_SHIFT_DATES";
|
export const SET_FORM_SHIFT_DATES = "SET_FORM_SHIFT_DATES";
|
||||||
|
export const SET_CSHIFT_UUID = "SET_CSHIFT_UUID";
|
||||||
export const SET_CLEAR_CSHIFT_STATE = "SET_CLEAR_CSHIFT_STATE";
|
export const SET_CLEAR_CSHIFT_STATE = "SET_CLEAR_CSHIFT_STATE";
|
||||||
|
|
||||||
// Saga CShift Action Constants
|
// Saga CShift Action Constants
|
||||||
export const CREATE_MULTIPLE_CSHIFT_REQUEST = "CREATE_MULTIPLE_CSHIFT_REQUEST";
|
export const CREATE_MULTIPLE_CSHIFT_REQUEST = "CREATE_MULTIPLE_CSHIFT_REQUEST";
|
||||||
export const GET_CSHIFTS_REQUEST = "GET_CSHIFTS_REQUEST";
|
export const GET_CSHIFTS_REQUEST = "GET_CSHIFTS_REQUEST";
|
||||||
|
export const GET_CSHIFT_REQUEST = "GET_CSHIFT_REQUEST";
|
||||||
|
export const EDIT_CSHIFT_REQUEST = "EDIT_CSHIFT_REQUEST";
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
SET_FORM_SHIFT_DURATION,
|
SET_FORM_SHIFT_DURATION,
|
||||||
SET_FORM_SHIFT_NOTE,
|
SET_FORM_SHIFT_NOTE,
|
||||||
SET_FORM_SHIFT_DATES,
|
SET_FORM_SHIFT_DATES,
|
||||||
|
SET_CSHIFT_UUID,
|
||||||
SET_CLEAR_CSHIFT_STATE
|
SET_CLEAR_CSHIFT_STATE
|
||||||
} from "../constants/cShift.constants";
|
} from "../constants/cShift.constants";
|
||||||
|
|
||||||
|
@ -22,7 +23,8 @@ const initialState = {
|
||||||
startTime: null, // When does the shift begin? moment instance
|
startTime: null, // When does the shift begin? moment instance
|
||||||
duration: "", // Duration of shift in minutes
|
duration: "", // Duration of shift in minutes
|
||||||
note: "", // Optional note
|
note: "", // Optional note
|
||||||
shiftDates: {} // Dates, map of "YYYY-MM-DD" > moment instance
|
shiftDates: {}, // Dates, map of "YYYY-MM-DD" > moment instance
|
||||||
|
cShiftUUID: ""
|
||||||
};
|
};
|
||||||
|
|
||||||
function cShiftReducer(state = initialState, action) {
|
function cShiftReducer(state = initialState, action) {
|
||||||
|
@ -82,6 +84,11 @@ function cShiftReducer(state = initialState, action) {
|
||||||
...state,
|
...state,
|
||||||
shiftDates: action.data
|
shiftDates: action.data
|
||||||
};
|
};
|
||||||
|
case SET_CSHIFT_UUID:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
cShiftUUID: action.data
|
||||||
|
};
|
||||||
case SET_CLEAR_CSHIFT_STATE:
|
case SET_CLEAR_CSHIFT_STATE:
|
||||||
return {
|
return {
|
||||||
...initialState
|
...initialState
|
||||||
|
|
|
@ -11,9 +11,15 @@ import {
|
||||||
setFormShiftDates,
|
setFormShiftDates,
|
||||||
setFormShiftDuration,
|
setFormShiftDuration,
|
||||||
setFormShiftNote,
|
setFormShiftNote,
|
||||||
setFormShiftStartTime
|
setFormShiftStartTime,
|
||||||
|
setCShiftUUID
|
||||||
} from "../actions/cShift/reducer.actions";
|
} from "../actions/cShift/reducer.actions";
|
||||||
import { createCShifts, getCShifts } from "../api/cShift.api";
|
import {
|
||||||
|
createCShifts,
|
||||||
|
getCShifts,
|
||||||
|
getCShift,
|
||||||
|
editCShift
|
||||||
|
} from "../api/cShift.api";
|
||||||
|
|
||||||
function* createCShiftsCall(postBodies) {
|
function* createCShiftsCall(postBodies) {
|
||||||
yield effects.put(isSendingCShiftRequest(true));
|
yield effects.put(isSendingCShiftRequest(true));
|
||||||
|
@ -48,6 +54,32 @@ function* getCShiftsCall(params) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* getCShiftCall({ uuid, params }) {
|
||||||
|
yield effects.put(isSendingCShiftRequest(true));
|
||||||
|
try {
|
||||||
|
return yield effects.call(getCShift, uuid, params);
|
||||||
|
} catch (exception) {
|
||||||
|
yield effects.put(setCShiftRequestError(exception));
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
yield effects.put(isSendingCShiftRequest(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function* editCShiftCall(payload) {
|
||||||
|
yield effects.put(isSendingCShiftRequest(true));
|
||||||
|
try {
|
||||||
|
const edit = yield effects.call(editCShift, payload.uuid, payload);
|
||||||
|
yield effects.put(setCShiftUUID(true));
|
||||||
|
return edit;
|
||||||
|
} catch (exception) {
|
||||||
|
yield effects.put(setCShiftRequestError(exception));
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
yield effects.put(isSendingCShiftRequest(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function* createCShiftsFlow(request) {
|
export function* createCShiftsFlow(request) {
|
||||||
yield effects.put(clearCShiftRequestSuccess());
|
yield effects.put(clearCShiftRequestSuccess());
|
||||||
yield effects.put(clearCShiftRequestError());
|
yield effects.put(clearCShiftRequestError());
|
||||||
|
@ -78,3 +110,20 @@ export function* getCShiftsFlow(request) {
|
||||||
yield effects.put(setCShiftRequestSuccess(isSuccessful));
|
yield effects.put(setCShiftRequestSuccess(isSuccessful));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function* getCShiftFlow(request) {
|
||||||
|
yield effects.put(clearCShiftRequestSuccess());
|
||||||
|
yield effects.put(clearCShiftRequestError());
|
||||||
|
const wasSuccessful = yield effects.call(getCShiftCall, request.data);
|
||||||
|
if (wasSuccessful) {
|
||||||
|
yield effects.put(setCShiftRequestSuccess(wasSuccessful));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* editCShiftFlow(request) {
|
||||||
|
yield effects.put(clearCShiftRequestError());
|
||||||
|
const wasSuccessful = yield effects.call(editCShiftCall, request.data);
|
||||||
|
if (wasSuccessful) {
|
||||||
|
yield effects.put(setCShiftRequestSuccess(wasSuccessful));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -71,9 +71,16 @@ import {
|
||||||
} from "./price.sagas";
|
} from "./price.sagas";
|
||||||
import {
|
import {
|
||||||
CREATE_MULTIPLE_CSHIFT_REQUEST,
|
CREATE_MULTIPLE_CSHIFT_REQUEST,
|
||||||
GET_CSHIFTS_REQUEST
|
GET_CSHIFTS_REQUEST,
|
||||||
|
GET_CSHIFT_REQUEST,
|
||||||
|
EDIT_CSHIFT_REQUEST
|
||||||
} from "../constants/cShift.constants";
|
} from "../constants/cShift.constants";
|
||||||
import { createCShiftsFlow, getCShiftsFlow } from "./cShift.sagas";
|
import {
|
||||||
|
createCShiftsFlow,
|
||||||
|
getCShiftsFlow,
|
||||||
|
getCShiftFlow,
|
||||||
|
editCShiftFlow
|
||||||
|
} from "./cShift.sagas";
|
||||||
|
|
||||||
export default function* rootSaga() {
|
export default function* rootSaga() {
|
||||||
yield takeLatest(SEND_REGISTER_REQUEST, registerUserFlow);
|
yield takeLatest(SEND_REGISTER_REQUEST, registerUserFlow);
|
||||||
|
@ -103,4 +110,6 @@ export default function* rootSaga() {
|
||||||
yield takeLatest(DELETE_PRICE_REQUEST, deletePriceFlow);
|
yield takeLatest(DELETE_PRICE_REQUEST, deletePriceFlow);
|
||||||
yield takeLatest(CREATE_MULTIPLE_CSHIFT_REQUEST, createCShiftsFlow);
|
yield takeLatest(CREATE_MULTIPLE_CSHIFT_REQUEST, createCShiftsFlow);
|
||||||
yield takeLatest(GET_CSHIFTS_REQUEST, getCShiftsFlow);
|
yield takeLatest(GET_CSHIFTS_REQUEST, getCShiftsFlow);
|
||||||
|
yield takeLatest(GET_CSHIFT_REQUEST, getCShiftFlow);
|
||||||
|
yield takeLatest(EDIT_CSHIFT_REQUEST, editCShiftFlow);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user