added pShift scaffolding

This commit is contained in:
Alexander Wong 2018-04-22 23:04:09 -06:00
parent 2b15495072
commit 0fc6ac31f5
No known key found for this signature in database
GPG Key ID: E90E5D6448C2C663
13 changed files with 379 additions and 2 deletions

View File

@ -0,0 +1,49 @@
import {
IS_SENDING_PSHIFT_REQUEST,
SET_PSHIFT_REQUEST_SUCCESS,
SET_PSHIFT_REQUEST_ERROR,
CLEAR_PSHIFT_REQUEST_ERROR,
CLEAR_PSHIFT_REQUEST_SUCCESS,
SET_CLEAR_PSHIFT_STATE
} from "../../constants/pShift.constants";
import { parseError } from "../common.actions";
export function isSendingPShiftRequest(sendingRequest) {
return {
type: IS_SENDING_PSHIFT_REQUEST,
data: sendingRequest
};
}
export function setPShiftRequestSuccess(response) {
return {
type: SET_PSHIFT_REQUEST_SUCCESS,
data: response.detail || response
};
}
export function setPShiftRequestError(exception) {
let error = parseError(exception);
return {
type: SET_PSHIFT_REQUEST_ERROR,
data: error
};
}
export function clearPShiftRequestError() {
return {
type: CLEAR_PSHIFT_REQUEST_ERROR
};
}
export function clearPShiftRequestSuccess() {
return {
type: CLEAR_PSHIFT_REQUEST_SUCCESS
};
}
export function setClearPShiftState() {
return {
type: SET_CLEAR_PSHIFT_STATE
};
}

View File

@ -0,0 +1,8 @@
import { GET_PSHIFTS_REQUEST } from "../../constants/pShift.constants";
export function getPShiftsRequest(params) {
return {
type: GET_PSHIFTS_REQUEST,
data: params
};
}

5
src/api/pShift.api.js Normal file
View File

@ -0,0 +1,5 @@
import { get } from "./baseApi";
export function getPShifts(params) {
return get("/pshift/", params).then(resp => Promise.resolve(resp));
}

View File

@ -18,6 +18,7 @@ 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 ClientEditShiftForm from "./User/Client/ClientEditShiftForm";
import ProviderClients from "./User/Provider/ProviderClients"; import ProviderClients from "./User/Provider/ProviderClients";
import ProviderShifts from "./User/Provider/ProviderShifts";
import CompleteRegistration from "./User/CompleteRegistration"; import CompleteRegistration from "./User/CompleteRegistration";
import EditProfile from "./User/EditProfile"; import EditProfile from "./User/EditProfile";
import Profile from "./User/Profile"; import Profile from "./User/Profile";
@ -101,6 +102,10 @@ class App extends Component {
path="/user/profile/provider/clients" path="/user/profile/provider/clients"
component={ProviderClients} component={ProviderClients}
/> />
<PrivateRoute
path="/user/profile/provider/shifts"
component={ProviderShifts}
/>
<PrivateRoute path="/user/profile/edit" component={EditProfile} /> <PrivateRoute path="/user/profile/edit" component={EditProfile} />
<PrivateRoute path="/user/profile" component={Profile} /> <PrivateRoute path="/user/profile" component={Profile} />
<Route path="/user/complete-registration" component={Profile} /> <Route path="/user/complete-registration" component={Profile} />

View File

@ -83,6 +83,11 @@ const NavbarView = ({ isAuthenticated, dispatchLogoutRequest, selfUser }) => (
Clients Clients
</Dropdown.Item> </Dropdown.Item>
)} )}
{selfUser.provider && (
<Dropdown.Item as={Link} to="/user/profile/provider/shifts">
Shifts
</Dropdown.Item>
)}
<Dropdown.Item as={Link} to="/auth/settings"> <Dropdown.Item as={Link} to="/auth/settings">
Settings Settings
</Dropdown.Item> </Dropdown.Item>

View File

@ -154,7 +154,7 @@ const ClientShiftsView = ({
"/hour"} "/hour"}
</Item.Meta> </Item.Meta>
<Item.Description>{result.description}</Item.Description> <Item.Description>{result.description}</Item.Description>
<code>{JSON.stringify(result, null, 2)}</code> {/* <code>{JSON.stringify(result, null, 2)}</code> */}
<Item.Meta> <Item.Meta>
<a href={"mailto:" + employee.provider.email}> <a href={"mailto:" + employee.provider.email}>
{employee.provider.email} {employee.provider.email}

View File

@ -0,0 +1,166 @@
import { utc, ISO_8601, duration } from "moment";
import React, { Component } from "react";
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import {
Container,
Header,
Item,
Pagination,
Loader,
Label
} from "semantic-ui-react";
import {
getEmployerFromPrice,
getPriceFromPrice
} from "./ProviderShiftsShared";
import { getPShiftsRequest } from "../../../actions/pShift/saga.actions";
class ProviderShifts extends Component {
constructor(props) {
super(props);
this.state = {
page: 1,
pageSize: 10 // client can't control this, but set here just in case
};
}
componentWillMount = () => {
this.props.dispatch(
getPShiftsRequest({
page: this.state.page,
page_size: this.state.pageSize
})
);
};
handlePaginationChange = (event, { activePage }) => {
this.props.dispatch(
getPShiftsRequest({
page: activePage,
page_size: this.state.pageSize
})
);
this.setState({ page: activePage });
};
render() {
const {
isSendingPShiftRequest,
pShiftRequestSuccess,
selfUser
} = this.props;
const { page, pageSize } = this.state;
if (selfUser.provider) {
return (
<ProviderShiftsView
isSendingPShiftRequest={isSendingPShiftRequest}
pShiftRequestSuccess={pShiftRequestSuccess}
page={page}
pageSize={pageSize}
user={selfUser}
handlePaginationChange={this.handlePaginationChange}
/>
);
} else {
return <Redirect to="/" />;
}
}
}
function mapStateToProps(state) {
return { ...state.pShift, selfUser: state.user.selfUser };
}
const ProviderShiftsView = ({
isSendingPShiftRequest,
pShiftRequestSuccess,
user,
page,
pageSize,
handlePaginationChange
}) => {
const { count = 0, results = [] } = pShiftRequestSuccess;
return (
<Container>
<Header>Shifts</Header>
{!!isSendingPShiftRequest && <Loader content="Loading" />}
{!isSendingPShiftRequest &&
results.length > 0 && (
<Item.Group divided>
{results.map(result => {
const employer = getEmployerFromPrice(result.price, user);
const price = getPriceFromPrice(result.price, user);
const workType = price.work_type;
const min = duration(
utc(result.set_end, ISO_8601) - utc(result.set_start, ISO_8601),
"milliseconds"
).as("minutes");
let displayText = duration(min, "minutes").humanize();
if (min % 60) {
displayText = duration(
Math.floor(min / 60),
"hours"
).humanize();
displayText += ` and ${duration(
min % 60,
"minutes"
).humanize()}`;
}
return (
<Item key={result.uuid}>
<Item.Content>
<Item.Header>
<Label
circular
empty
style={{
backgroundColor: workType.color,
borderColor: workType.color
}}
/>
{workType.label}
</Item.Header>
<Item.Meta>
{"At " +
utc(result.set_start, ISO_8601)
.local(false)
.format("dddd, MMMM Do YYYY, h:mm a Z") +
"; for " +
displayText +
"; rate $" +
price.amount +
"/hour"}
</Item.Meta>
<Item.Description>{result.description}</Item.Description>
{/* <code>{JSON.stringify(result, null, 2)}</code> */}
<Item.Meta>
<a href={"mailto:" + employer.client.email}>
{employer.client.email}
</a>
</Item.Meta>
</Item.Content>
</Item>
);
})}
</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>
);
};
export default connect(mapStateToProps)(ProviderShifts);

View File

@ -0,0 +1,42 @@
export const getEmployerFromPrice = (priceUUID, selfUser) => {
const employers =
selfUser && selfUser.provider && selfUser.provider.employers;
let matchEmployer = null;
employers.forEach(employer => {
const priceMatch = employer.prices.filter(price => {
return price.uuid === priceUUID;
});
if (priceMatch.length > 0) {
matchEmployer = employer;
}
});
return matchEmployer;
};
export const getWorkTypeFromPrice = (priceUUID, selfUser) => {
const employers =
selfUser && selfUser.provider && selfUser.provider.employers;
let matchWorkType = null;
employers.forEach(employer => {
employer.prices.forEach(price => {
if (price.uuid === priceUUID) {
matchWorkType = price.work_type;
}
});
});
return matchWorkType;
};
export const getPriceFromPrice = (priceUUID, selfUser) => {
const employers =
selfUser && selfUser.provider && selfUser.provider.employers;
let matchPrice = null;
employers.forEach(employer => {
employer.prices.forEach(price => {
if (price.uuid === priceUUID) {
matchPrice = price;
}
});
});
return matchPrice;
};

View File

@ -0,0 +1,10 @@
// Reducer PShift Action Constants
export const IS_SENDING_PSHIFT_REQUEST = "IS_SENDING_PSHIFT_REQUEST";
export const SET_PSHIFT_REQUEST_ERROR = "SET_PSHIFT_REQUEST_ERROR";
export const CLEAR_PSHIFT_REQUEST_ERROR = "CLEAR_PSHIFT_REQUEST_ERROR";
export const SET_PSHIFT_REQUEST_SUCCESS = "SET_PSHIFT_REQUEST_SUCCESS";
export const CLEAR_PSHIFT_REQUEST_SUCCESS = "CLEAR_PSHIFT_REQUEST_SUCCESS";
export const SET_CLEAR_PSHIFT_STATE = "SET_CLEAR_PSHIFT_STATE";
// Saga PShift Action Constants
export const GET_PSHIFTS_REQUEST = "GET_PSHIFTS_REQUEST";

View File

@ -6,6 +6,7 @@ import employeeReducer from "./employeeReducer";
// import employerReducer from "./employerReducer"; // unused // import employerReducer from "./employerReducer"; // unused
import priceReducer from "./priceReducer"; import priceReducer from "./priceReducer";
import cShiftReducer from "./cShiftReducer"; import cShiftReducer from "./cShiftReducer";
import pShiftReducer from "./pShiftReducer";
const reducer = combineReducers({ const reducer = combineReducers({
auth: authReducer, auth: authReducer,
@ -14,7 +15,8 @@ const reducer = combineReducers({
employee: employeeReducer, employee: employeeReducer,
// employer: employerReducer // unused // employer: employerReducer // unused
price: priceReducer, price: priceReducer,
cShift: cShiftReducer cShift: cShiftReducer,
pShift: pShiftReducer
}); });
export default reducer; export default reducer;

View File

@ -0,0 +1,52 @@
import {
IS_SENDING_PSHIFT_REQUEST,
SET_PSHIFT_REQUEST_ERROR,
SET_PSHIFT_REQUEST_SUCCESS,
CLEAR_PSHIFT_REQUEST_ERROR,
CLEAR_PSHIFT_REQUEST_SUCCESS,
SET_CLEAR_PSHIFT_STATE
} from "../constants/pShift.constants";
const initialState = {
isSendingPShiftRequest: false,
pShiftRequestError: "",
pShiftRequestSuccess: ""
};
function pShiftReducer(state = initialState, action) {
switch (action.type) {
case IS_SENDING_PSHIFT_REQUEST:
return {
...state,
isSendingPShiftRequest: action.data
};
case SET_PSHIFT_REQUEST_ERROR:
return {
...state,
pShiftRequestError: action.data
};
case CLEAR_PSHIFT_REQUEST_ERROR:
return {
...state,
pShiftRequestError: ""
};
case SET_PSHIFT_REQUEST_SUCCESS:
return {
...state,
pShiftRequestSuccess: action.data
};
case CLEAR_PSHIFT_REQUEST_SUCCESS:
return {
...state,
pShiftRequestSuccess: ""
};
case SET_CLEAR_PSHIFT_STATE:
return {
...initialState
};
default:
return { ...state };
}
}
export default pShiftReducer;

View File

@ -83,6 +83,8 @@ import {
editCShiftFlow, editCShiftFlow,
deleteCShiftFlow deleteCShiftFlow
} from "./cShift.sagas"; } from "./cShift.sagas";
import { GET_PSHIFTS_REQUEST } from "../constants/pShift.constants";
import { getPShiftsFlow } from "./pShift.sagas";
export default function* rootSaga() { export default function* rootSaga() {
yield takeLatest(SEND_REGISTER_REQUEST, registerUserFlow); yield takeLatest(SEND_REGISTER_REQUEST, registerUserFlow);
@ -115,4 +117,5 @@ export default function* rootSaga() {
yield takeLatest(GET_CSHIFT_REQUEST, getCShiftFlow); yield takeLatest(GET_CSHIFT_REQUEST, getCShiftFlow);
yield takeLatest(EDIT_CSHIFT_REQUEST, editCShiftFlow); yield takeLatest(EDIT_CSHIFT_REQUEST, editCShiftFlow);
yield takeLatest(DELETE_CSHIFT_REQUEST, deleteCShiftFlow); yield takeLatest(DELETE_CSHIFT_REQUEST, deleteCShiftFlow);
yield takeLatest(GET_PSHIFTS_REQUEST, getPShiftsFlow);
} }

30
src/sagas/pShift.sagas.js Normal file
View File

@ -0,0 +1,30 @@
import { effects } from "redux-saga";
import {
isSendingPShiftRequest,
setPShiftRequestError,
setPShiftRequestSuccess,
clearPShiftRequestError,
clearPShiftRequestSuccess
} from "../actions/pShift/reducer.actions";
import { getPShifts } from "../api/pShift.api";
function* getPShiftsCall(params) {
yield effects.put(isSendingPShiftRequest(true));
try {
return yield effects.call(getPShifts, params);
} catch (exception) {
yield effects.put(setPShiftRequestError(exception));
return false;
} finally {
yield effects.put(isSendingPShiftRequest(false));
}
}
export function* getPShiftsFlow(request) {
yield effects.put(clearPShiftRequestSuccess());
yield effects.put(clearPShiftRequestError());
const wasSuccessful = yield effects.call(getPShiftsCall, request.data);
if (wasSuccessful) {
yield effects.put(setPShiftRequestSuccess(wasSuccessful));
}
}