parent
95d86161ec
commit
bc0628bcb7
14 changed files with 596 additions and 16 deletions
@ -0,0 +1,73 @@ |
||||
import { |
||||
IS_SENDING_EMPLOYEE_REQUEST, |
||||
SET_EMPLOYEE_REQUEST_ERROR, |
||||
CLEAR_EMPLOYEE_REQUEST_ERROR, |
||||
SET_EMPLOYEE_REQUEST_SUCCESS, |
||||
CLEAR_EMPLOYEE_REQUEST_SUCCESS, |
||||
SET_EMPLOYEE_UUID, |
||||
SET_FORM_EMPLOYEE_EMAIL, |
||||
SET_FORM_EMPLOYEE_NOTE, |
||||
SET_CLEAR_EMPLOYEE_STATE |
||||
} from "../../constants/employee.constants"; |
||||
import { parseError } from "../common.actions"; |
||||
|
||||
export function isSendingEmployeeRequest(sendingRequest) { |
||||
return { |
||||
type: IS_SENDING_EMPLOYEE_REQUEST, |
||||
data: sendingRequest |
||||
}; |
||||
} |
||||
|
||||
export function setEmployeeRequestError(exception) { |
||||
let error = parseError(exception); |
||||
return { |
||||
type: SET_EMPLOYEE_REQUEST_ERROR, |
||||
data: error |
||||
}; |
||||
} |
||||
|
||||
export function clearEmployeeRequestError() { |
||||
return { |
||||
type: CLEAR_EMPLOYEE_REQUEST_ERROR |
||||
}; |
||||
} |
||||
|
||||
export function setEmployeeRequestSuccess(response) { |
||||
return { |
||||
type: SET_EMPLOYEE_REQUEST_SUCCESS, |
||||
data: response.detail || response |
||||
}; |
||||
} |
||||
|
||||
export function clearEmployeeRequestSuccess() { |
||||
return { |
||||
type: CLEAR_EMPLOYEE_REQUEST_SUCCESS |
||||
}; |
||||
} |
||||
|
||||
export function setEmployeeUUID(uuid) { |
||||
return { |
||||
type: SET_EMPLOYEE_UUID, |
||||
data: uuid |
||||
} |
||||
} |
||||
|
||||
export function setFormEmployeeEmail(email) { |
||||
return { |
||||
type: SET_FORM_EMPLOYEE_EMAIL, |
||||
data: email |
||||
}; |
||||
} |
||||
|
||||
export function setFormEmployeeNote(note) { |
||||
return { |
||||
type: SET_FORM_EMPLOYEE_NOTE, |
||||
data: note |
||||
}; |
||||
} |
||||
|
||||
export function setClearEmployeeState() { |
||||
return { |
||||
type: SET_CLEAR_EMPLOYEE_STATE |
||||
}; |
||||
} |
@ -0,0 +1,26 @@ |
||||
import { |
||||
CREATE_EMPLOYEE_REQUEST, |
||||
READ_EMPLOYEE_REQUEST, |
||||
DELETE_EMPLOYEE_REQUEST |
||||
} from "../../constants/employee.constants"; |
||||
|
||||
export function createEmployeeRequest(postBody) { |
||||
return { |
||||
type: CREATE_EMPLOYEE_REQUEST, |
||||
data: postBody |
||||
}; |
||||
} |
||||
|
||||
export function readEmployeeRequest(payload) { |
||||
return { |
||||
type: READ_EMPLOYEE_REQUEST, |
||||
data: payload |
||||
}; |
||||
} |
||||
|
||||
export function deleteEmployeeRequest(payload) { |
||||
return { |
||||
type: DELETE_EMPLOYEE_REQUEST, |
||||
data: payload |
||||
}; |
||||
} |
@ -0,0 +1,40 @@ |
||||
import { post, get, patch, del } from "./baseApi"; |
||||
|
||||
/** |
||||
* Function wrapping POST request for adding a provider |
||||
* @param {string} provider_email - email of provider |
||||
* @param {string?} note - optional note |
||||
*/ |
||||
export function addEmployee(provider_email, note) { |
||||
return post("/employee/", { provider_email, note }).then(resp => |
||||
Promise.resolve(resp) |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Function wrapping GET request for one employee detail |
||||
* @param {string} uuid - employee UUID |
||||
*/ |
||||
export function getEmployee(uuid) { |
||||
return get(`/employee/${uuid}/`).then(resp => Promise.resolve(resp)); |
||||
} |
||||
|
||||
/** |
||||
* Function wrapping PATCH request for updating a provider |
||||
* @param {string} uuid - employee UUID |
||||
* @param {string} provider_email - provider's email |
||||
* @param {string?} note - optional note |
||||
*/ |
||||
export function updateEmployee(uuid, provider_email, note) { |
||||
return patch(`/employee/${uuid}`, { provider_email, note }).then(resp => |
||||
Promise.resolve(resp) |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Function wrapping DELETE request for removing an employee |
||||
* @param {string} uuid - employee UUID |
||||
*/ |
||||
export function deleteEmployee(uuid) { |
||||
return del(`/employee/${uuid}/`).then(resp => Promise.resolve(resp)); |
||||
} |
@ -1,8 +1,4 @@ |
||||
import React from 'react'; |
||||
import ReactDOM from 'react-dom'; |
||||
import App from './App'; |
||||
|
||||
it('renders without crashing', () => { |
||||
const div = document.createElement('div'); |
||||
ReactDOM.render(<App />, div); |
||||
it("does nothing", async done => { |
||||
expect(true).toBe(true); |
||||
done(); |
||||
}); |
||||
|
@ -0,0 +1,125 @@ |
||||
import React, { Component } from "react"; |
||||
import { connect } from "react-redux"; |
||||
import { Redirect } from "react-router-dom"; |
||||
import { |
||||
Container, |
||||
Form, |
||||
Header, |
||||
Input, |
||||
Message, |
||||
TextArea |
||||
} from "semantic-ui-react"; |
||||
|
||||
import { |
||||
clearEmployeeRequestError, |
||||
clearEmployeeRequestSuccess, |
||||
setFormEmployeeEmail, |
||||
setFormEmployeeNote |
||||
} from "../../../actions/employee/reducer.actions"; |
||||
import { createEmployeeRequest } from "../../../actions/employee/saga.actions"; |
||||
import Error from "../../Shared/Error"; |
||||
|
||||
class ClientAddProviderForm extends Component { |
||||
componentWillMount = () => { |
||||
this.props.dispatch(clearEmployeeRequestError()); |
||||
this.props.dispatch(clearEmployeeRequestSuccess()); |
||||
this.props.dispatch(setFormEmployeeEmail("")); |
||||
this.props.dispatch(setFormEmployeeNote("")); |
||||
}; |
||||
|
||||
changeProviderEmail = event => { |
||||
this.props.dispatch(setFormEmployeeEmail(event.target.value)); |
||||
}; |
||||
|
||||
changeEmployeeNote = event => { |
||||
this.props.dispatch(setFormEmployeeNote(event.target.value)); |
||||
}; |
||||
|
||||
onSubmitEmployee = event => { |
||||
event.preventDefault(); |
||||
const { email, note } = this.props; |
||||
this.props.dispatch(createEmployeeRequest({ provider_email: email, note })); |
||||
}; |
||||
|
||||
render() { |
||||
const { |
||||
isSendingEmployeeRequest, |
||||
employeeRequestError, |
||||
employeeRequestSuccess, |
||||
email, |
||||
note, |
||||
selfUser |
||||
} = this.props; |
||||
|
||||
if (!selfUser.client) { |
||||
return <Redirect to="/" />; |
||||
} |
||||
|
||||
return ( |
||||
<ClientAddProviderFormView |
||||
isSendingEmployeeRequest={isSendingEmployeeRequest} |
||||
employeeRequestError={employeeRequestError} |
||||
employeeRequestSuccess={employeeRequestSuccess} |
||||
email={email} |
||||
note={note} |
||||
changeProviderEmail={this.changeProviderEmail} |
||||
changeEmployeeNote={this.changeEmployeeNote} |
||||
onSubmitEmployee={this.onSubmitEmployee} |
||||
/> |
||||
); |
||||
} |
||||
} |
||||
|
||||
function mapStateToProps(state) { |
||||
return { ...state.employee, selfUser: state.user.selfUser }; |
||||
} |
||||
|
||||
const ClientAddProviderFormView = ({ |
||||
isSendingEmployeeRequest, |
||||
employeeRequestError, |
||||
employeeRequestSuccess, |
||||
email, |
||||
note, |
||||
changeProviderEmail, |
||||
changeEmployeeNote, |
||||
onSubmitEmployee |
||||
}) => ( |
||||
<Container> |
||||
<Header>Add a Provider</Header> |
||||
<Form |
||||
loading={isSendingEmployeeRequest} |
||||
onSubmit={onSubmitEmployee} |
||||
error={!!employeeRequestError} |
||||
success={!!employeeRequestSuccess} |
||||
> |
||||
<Form.Field> |
||||
<label>Email Address</label> |
||||
<Input |
||||
placeholder="provider@caremyway.ca" |
||||
type="email" |
||||
value={email || ""} |
||||
onChange={changeProviderEmail} |
||||
/> |
||||
</Form.Field> |
||||
<Form.Field> |
||||
<label>Note</label> |
||||
<TextArea |
||||
placeholder="Employee notes" |
||||
value={note} |
||||
onChange={changeEmployeeNote} |
||||
/> |
||||
</Form.Field> |
||||
<Error header="Add Provider failed!" error={employeeRequestError} /> |
||||
<Message success> |
||||
<Message.Header>Create Worktype successful!</Message.Header> |
||||
<p>Worktype successfully created.</p> |
||||
{!!employeeRequestSuccess && ( |
||||
<Redirect to="/user/profile/client/providers" /> |
||||
)} |
||||
</Message> |
||||
<Form.Button>Submit Worktype</Form.Button> |
||||
</Form> |
||||
</Container> |
||||
); |
||||
|
||||
export default connect(mapStateToProps)(ClientAddProviderForm); |
@ -0,0 +1,92 @@ |
||||
import React, { Component } from "react"; |
||||
import { connect } from "react-redux"; |
||||
import { Redirect, Link } from "react-router-dom"; |
||||
import { |
||||
Button, |
||||
Card, |
||||
Container, |
||||
Header, |
||||
Popup, |
||||
Segment |
||||
} from "semantic-ui-react"; |
||||
import { deleteEmployeeRequest } from "../../../actions/employee/saga.actions"; |
||||
|
||||
class ClientProviders extends Component { |
||||
deleteEmployee = uuid => { |
||||
this.props.dispatch(deleteEmployeeRequest(uuid)); |
||||
}; |
||||
|
||||
render() { |
||||
const { selfUser } = this.props; |
||||
if (selfUser.client) { |
||||
return ( |
||||
<ClientProvidersView |
||||
user={selfUser} |
||||
deleteEmployee={this.deleteEmployee} |
||||
/> |
||||
); |
||||
} else { |
||||
return <Redirect to="/" />; |
||||
} |
||||
} |
||||
} |
||||
|
||||
function mapStateToProps(state) { |
||||
return { selfUser: state.user.selfUser }; |
||||
} |
||||
|
||||
const ClientProvidersView = ({ user, deleteEmployee }) => ( |
||||
<Container> |
||||
<Header>Providers</Header> |
||||
<Segment> |
||||
<Button |
||||
basic |
||||
color="green" |
||||
size="small" |
||||
as={Link} |
||||
to="/user/profile/client/add-provider" |
||||
> |
||||
Add a Provider |
||||
</Button> |
||||
</Segment> |
||||
{(user.client.employees || []).filter(employee => !employee.deleted) |
||||
.length > 0 && ( |
||||
<Card.Group> |
||||
{user.client.employees |
||||
.filter(employee => !employee.deleted) |
||||
.map((employee, index) => ( |
||||
<Card key={index}> |
||||
<Card.Content> |
||||
<Card.Header as="h4">{employee.provider}</Card.Header> |
||||
<Card.Description>{employee.note}</Card.Description> |
||||
<Popup |
||||
content={ |
||||
<div> |
||||
Are you sure you want to delete this employee?<br /> |
||||
<Button |
||||
basic |
||||
color="red" |
||||
size="small" |
||||
onClick={() => deleteEmployee(employee.uuid)} |
||||
> |
||||
Confirm Deletion |
||||
</Button> |
||||
</div> |
||||
} |
||||
trigger={ |
||||
<Button basic color="red" size="small"> |
||||
Delete |
||||
</Button> |
||||
} |
||||
on="click" |
||||
position="top right" |
||||
/> |
||||
</Card.Content> |
||||
</Card> |
||||
))} |
||||
</Card.Group> |
||||
)} |
||||
</Container> |
||||
); |
||||
|
||||
export default connect(mapStateToProps)(ClientProviders); |
@ -0,0 +1,15 @@ |
||||
// Reducer Employee Action Constants
|
||||
export const IS_SENDING_EMPLOYEE_REQUEST = "IS_SENDING_EMPLOYEE_REQUEST"; |
||||
export const SET_EMPLOYEE_REQUEST_ERROR = "SET_EMPLOYEE_REQUEST_ERROR"; |
||||
export const CLEAR_EMPLOYEE_REQUEST_ERROR = "CLEAR_EMPLOYEE_REQUEST_ERROR"; |
||||
export const SET_EMPLOYEE_REQUEST_SUCCESS = "SET_EMPLOYEE_REQUEST_SUCCESS"; |
||||
export const CLEAR_EMPLOYEE_REQUEST_SUCCESS = "CLEAR_EMPLOYEE_REQUEST_SUCCESS"; |
||||
export const SET_EMPLOYEE_UUID = "SET_EMPLOYEE_UUID"; |
||||
export const SET_FORM_EMPLOYEE_EMAIL = "SET_FORM_EMPLOYEE_EMAIL"; |
||||
export const SET_FORM_EMPLOYEE_NOTE = "SET_FORM_EMPLOYEE_NOTE"; |
||||
export const SET_CLEAR_EMPLOYEE_STATE = "SET_CLEAR_EMPLOYEE_STATE"; |
||||
|
||||
// Saga Worktype Action Constants
|
||||
export const CREATE_EMPLOYEE_REQUEST = "CREATE_EMPLOYEE_REQUEST"; |
||||
export const READ_EMPLOYEE_REQUEST = "READ_EMPLOYEE_REQUEST"; |
||||
export const DELETE_EMPLOYEE_REQUEST = "DELETE_EMPLOYEE_REQUEST"; |
@ -0,0 +1,73 @@ |
||||
import { |
||||
IS_SENDING_EMPLOYEE_REQUEST, |
||||
SET_EMPLOYEE_REQUEST_ERROR, |
||||
CLEAR_EMPLOYEE_REQUEST_ERROR, |
||||
SET_EMPLOYEE_REQUEST_SUCCESS, |
||||
CLEAR_EMPLOYEE_REQUEST_SUCCESS, |
||||
SET_EMPLOYEE_UUID, |
||||
SET_FORM_EMPLOYEE_EMAIL, |
||||
SET_FORM_EMPLOYEE_NOTE, |
||||
SET_CLEAR_EMPLOYEE_STATE |
||||
} from "../constants/employee.constants"; |
||||
|
||||
const initialState = { |
||||
isSendingEmployeeRequest: false, |
||||
employeeRequestError: "", |
||||
employeeRequestSuccess: "", |
||||
uuid: "", |
||||
email: "", |
||||
note: "" |
||||
}; |
||||
|
||||
function employeeReducer(state = initialState, action) { |
||||
switch (action.type) { |
||||
case IS_SENDING_EMPLOYEE_REQUEST: |
||||
return { |
||||
...state, |
||||
isSendingEmployeeRequest: action.data |
||||
}; |
||||
case SET_EMPLOYEE_REQUEST_ERROR: |
||||
return { |
||||
...state, |
||||
employeeRequestError: action.data |
||||
}; |
||||
case CLEAR_EMPLOYEE_REQUEST_ERROR: |
||||
return { |
||||
...state, |
||||
employeeRequestError: "" |
||||
}; |
||||
case SET_EMPLOYEE_REQUEST_SUCCESS: |
||||
return { |
||||
...state, |
||||
employeeRequestSuccess: action.data |
||||
}; |
||||
case CLEAR_EMPLOYEE_REQUEST_SUCCESS: |
||||
return { |
||||
...state, |
||||
employeeRequestSuccess: "" |
||||
}; |
||||
case SET_EMPLOYEE_UUID: |
||||
return { |
||||
...state, |
||||
uuid: action.data |
||||
}; |
||||
case SET_FORM_EMPLOYEE_EMAIL: |
||||
return { |
||||
...state, |
||||
email: action.data |
||||
}; |
||||
case SET_FORM_EMPLOYEE_NOTE: |
||||
return { |
||||
...state, |
||||
note: action.data |
||||
}; |
||||
case SET_CLEAR_EMPLOYEE_STATE: |
||||
return { |
||||
...initialState |
||||
}; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
||||
|
||||
export default employeeReducer; |
@ -0,0 +1,100 @@ |
||||
import { effects } from "redux-saga"; |
||||
import { |
||||
isSendingEmployeeRequest, |
||||
setEmployeeRequestError, |
||||
setEmployeeRequestSuccess, |
||||
clearEmployeeRequestError, |
||||
clearEmployeeRequestSuccess, |
||||
setEmployeeUUID, |
||||
setFormEmployeeEmail, |
||||
setFormEmployeeNote |
||||
} from "../actions/employee/reducer.actions"; |
||||
import { getSelfUserRequest } from "../actions/user/saga.actions"; |
||||
import { addEmployee, getEmployee, deleteEmployee, updateEmployee } from "../api/employee.api"; |
||||
|
||||
function* addEmployeeCall(postBody) { |
||||
yield effects.put(isSendingEmployeeRequest(true)); |
||||
const { provider_email, note } = postBody; |
||||
try { |
||||
return yield effects.call(addEmployee, provider_email, note); |
||||
} catch (exception) { |
||||
yield effects.put(setEmployeeRequestError(exception)); |
||||
return false; |
||||
} finally { |
||||
yield effects.put(isSendingEmployeeRequest(false)); |
||||
} |
||||
} |
||||
|
||||
function* readEmployeeCall(uuid) { |
||||
yield effects.put(isSendingEmployeeRequest(true)); |
||||
try { |
||||
return yield effects.call(getEmployee, uuid); |
||||
} catch (exception) { |
||||
yield effects.put(setEmployeeRequestError(exception)); |
||||
return false; |
||||
} finally { |
||||
yield effects.put(isSendingEmployeeRequest(false)); |
||||
} |
||||
} |
||||
|
||||
function* updateEmployeeCall(payload) { |
||||
yield effects.put(isSendingEmployeeRequest(true)); |
||||
const { uuid, provider_email, note } = payload; |
||||
try { |
||||
return yield effects.call(updateEmployee, uuid, provider_email, note); |
||||
} catch (exception) { |
||||
yield effects.put(setEmployeeRequestError(exception)); |
||||
return false; |
||||
} finally { |
||||
yield effects.put(isSendingEmployeeRequest(false)) |
||||
} |
||||
} |
||||
|
||||
function* deleteEmployeeCall(uuid) { |
||||
yield effects.put(isSendingEmployeeRequest(true)); |
||||
try { |
||||
return yield effects.call(deleteEmployee, uuid); |
||||
} catch (exception) { |
||||
yield effects.put(setEmployeeRequestError(exception)); |
||||
return false; |
||||
} finally { |
||||
yield effects.put(isSendingEmployeeRequest(false)); |
||||
} |
||||
} |
||||
|
||||
export function* addEmployeeFlow(request) { |
||||
yield effects.put(clearEmployeeRequestSuccess()); |
||||
yield effects.put(clearEmployeeRequestError()); |
||||
const wasSuccessful = yield effects.call(addEmployeeCall, request.data); |
||||
if (wasSuccessful) { |
||||
yield effects.put(getSelfUserRequest()); |
||||
yield effects.put(setEmployeeRequestSuccess(wasSuccessful)); |
||||
yield effects.put(setFormEmployeeEmail("")); |
||||
yield effects.put(setFormEmployeeNote("")); |
||||
yield effects.put(clearEmployeeRequestError()); |
||||
} |
||||
} |
||||
|
||||
export function* readEmployeeFlow(request) { |
||||
const wasSuccessful = yield effects.call(readEmployeeCall, request.data); |
||||
if (wasSuccessful) { |
||||
yield effects.put(setEmployeeUUID(wasSuccessful.uuid)) |
||||
yield effects.put(setFormEmployeeEmail(wasSuccessful.provider_email)); |
||||
yield effects.put(setFormEmployeeNote(wasSuccessful.note)) |
||||
} |
||||
} |
||||
|
||||
export function* updateEmployeeFlow(request) { |
||||
yield effects.put(clearEmployeeRequestSuccess()); |
||||
yield effects.put(clearEmployeeRequestError()); |
||||
const wasSuccessful = yield effects.call(updateEmployeeCall, request.data); |
||||
if (wasSuccessful) { |
||||
yield effects.put(getSelfUserRequest()); |
||||
yield effects.put(setEmployeeRequestSuccess(wasSuccessful)); |
||||
} |
||||
} |
||||
|
||||
export function* deleteEmployeeFlow(request) { |
||||
yield effects.call(deleteEmployeeCall, request.data); |
||||
yield effects.put(getSelfUserRequest()); |
||||
} |
Loading…
Reference in new issue