added provider users approve clients functionality

This commit is contained in:
Alexander Wong 2018-01-21 18:20:41 -07:00
parent bc0628bcb7
commit e6ee51f481
No known key found for this signature in database
GPG Key ID: EBFE6371FA6A79DC
14 changed files with 356 additions and 11 deletions

View File

@ -0,0 +1,42 @@
import {
IS_SENDING_EMPLOYER_REQUEST,
SET_EMPLOYER_REQUEST_ERROR,
CLEAR_EMPLOYER_REQUEST_ERROR,
SET_EMPLOYER_REQUEST_SUCCESS,
CLEAR_EMPLOYER_REQUEST_SUCCESS
} from "../../constants/employer.constants";
import { parseError } from "../common.actions";
export function isSendingEmployerRequest(sendingRequest) {
return {
type: IS_SENDING_EMPLOYER_REQUEST,
data: sendingRequest
};
}
export function setEmployerRequestError(exception) {
let error = parseError(exception);
return {
type: SET_EMPLOYER_REQUEST_ERROR,
data: error
};
}
export function clearEmployerRequestError() {
return {
type: CLEAR_EMPLOYER_REQUEST_ERROR
};
}
export function setEmployerRequestSuccess(response) {
return {
type: SET_EMPLOYER_REQUEST_SUCCESS,
data: response.detail || response
};
}
export function clearEmployerRequestSuccess() {
return {
type: CLEAR_EMPLOYER_REQUEST_SUCCESS
};
}

View File

@ -0,0 +1,8 @@
import { UPDATE_EMPLOYER_REQUEST } from "../../constants/employer.constants";
export function updateEmployerRequest(payload) {
return {
type: UPDATE_EMPLOYER_REQUEST,
data: payload
};
}

12
src/api/employer.api.js Normal file
View File

@ -0,0 +1,12 @@
import { put } from "./baseApi";
/**
* Function wrapping PATCH request for updating employer information
* @param {string} uuid - employer UUID
* @param {boolean} approved - whether or not to approve employment relationship
*/
export function updateEmployer(uuid, approved) {
return put(`/employer/${uuid}/`, { approved }).then(resp =>
Promise.resolve(resp)
);
}

View File

@ -12,6 +12,7 @@ import UpdateWorkTypeForm from "./Worktype/UpdateWorkTypeForm";
import Worktypes from "./Worktype/Worktypes";
import ClientProviders from "./User/Client/ClientProviders";
import ClientAddProviderForm from "./User/Client/ClientAddProviderForm";
import ProviderClients from "./User/Provider/ProviderClients";
import CompleteRegistration from "./User/CompleteRegistration";
import EditProfile from "./User/EditProfile";
import Profile from "./User/Profile";
@ -71,6 +72,10 @@ class App extends Component {
path="/user/profile/client/add-provider"
component={ClientAddProviderForm}
/>
<PrivateRoute
path="/user/profile/provider/clients"
component={ProviderClients}
/>
<PrivateRoute path="/user/profile/edit" component={EditProfile} />
<PrivateRoute path="/user/profile" component={Profile} />
<Route path="/user/complete-registration" component={Profile} />

View File

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

View File

@ -111,13 +111,13 @@ const ClientAddProviderFormView = ({
</Form.Field>
<Error header="Add Provider failed!" error={employeeRequestError} />
<Message success>
<Message.Header>Create Worktype successful!</Message.Header>
<p>Worktype successfully created.</p>
<Message.Header>Create Provider successful!</Message.Header>
<p>Provider successfully created.</p>
{!!employeeRequestSuccess && (
<Redirect to="/user/profile/client/providers" />
)}
</Message>
<Form.Button>Submit Worktype</Form.Button>
<Form.Button>Submit Provider</Form.Button>
</Form>
</Container>
);

View File

@ -6,6 +6,8 @@ import {
Card,
Container,
Header,
Label,
List,
Popup,
Segment
} from "semantic-ui-react";
@ -57,8 +59,48 @@ const ClientProvidersView = ({ user, deleteEmployee }) => (
.map((employee, index) => (
<Card key={index}>
<Card.Content>
<Card.Header as="h4">{employee.provider}</Card.Header>
<Card.Description>{employee.note}</Card.Description>
{(employee.approved === null ||
employee.approved === false) && (
<div>
<Card.Header as="h4">{employee.provider}</Card.Header>
<Card.Description>{employee.note}</Card.Description>
</div>
)}
{employee.approved && (
<div>
<Card.Header as="h4">
{`${employee.provider.first_name} ${
employee.provider.last_name
}`.trim() || "No Name!"}
</Card.Header>
<Card.Description>
{employee.provider.userinfo && (
<List>
{employee.provider.userinfo.phone_number && (
<List.Item>
Phone Number:{" "}
{employee.provider.userinfo.phone_number}
</List.Item>
)}
</List>
)}
</Card.Description>
</div>
)}
<Label
attached="bottom right"
color={
employee.approved === null
? "grey"
: !!employee.approved ? "green" : "red"
}
>
{employee.approved === null
? "Pending"
: !!employee.approved ? "Approved" : "Ended"}
</Label>
</Card.Content>
<Card.Content extra>
<Popup
content={
<div>

View File

@ -0,0 +1,133 @@
import React, { Component } from "react";
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import {
Button,
Card,
Container,
Header,
Label,
List
} from "semantic-ui-react";
import { updateEmployerRequest } from "../../../actions/employer/saga.actions";
class ProviderClients extends Component {
updateEmployer = (uuid, approved) => {
this.props.dispatch(updateEmployerRequest({ uuid, approved }));
};
render() {
const { selfUser } = this.props;
if (selfUser.provider) {
return (
<ProviderClientsView
user={selfUser}
updateEmployer={this.updateEmployer}
/>
);
} else {
return <Redirect to="/" />;
}
}
}
function mapStateToProps(state) {
return { selfUser: state.user.selfUser };
}
const ProviderClientsView = ({ user, updateEmployer }) => (
<Container>
<Header>Clients</Header>
{(user.provider.employers || []).filter(employer => !employer.deleted)
.length > 0 && (
<Card.Group>
{user.provider.employers
.filter(employer => !employer.deleted)
.map((employer, index) => (
<Card key={index}>
<Card.Content>
{(employer.approved === null ||
employer.approved === false) && (
<div>
<Card.Header as="h4">
{employer.client.trim() || "No Name!"}
</Card.Header>
<Card.Description>{employer.note}</Card.Description>
</div>
)}
{employer.approved && (
<div>
<Card.Header as="h4">
{`${employer.client.first_name} ${
employer.client.last_name
}`.trim() || "No Name!"}
</Card.Header>
<Card.Description>
{employer.client.userinfo && (
<List>
{employer.client.userinfo.phone_number && (
<List.Item>
Phone Number:{" "}
{employer.client.userinfo.phone_number}
</List.Item>
)}
</List>
)}
</Card.Description>
</div>
)}
<Label
attached="bottom right"
color={
employer.approved === null
? "grey"
: !!employer.approved ? "green" : "red"
}
>
{employer.approved === null
? "Pending"
: !!employer.approved ? "Approved" : "Ended"}
</Label>
</Card.Content>
<Card.Content extra>
<Button.Group>
{!employer.approved && (
<Button
basic
color="green"
size="small"
onClick={() => updateEmployer(employer.uuid, true)}
>
Approve
</Button>
)}
{employer.approved === null && (
<Button
basic
color="red"
size="small"
onClick={() => updateEmployer(employer.uuid, false)}
>
Reject
</Button>
)}
{employer.approved && (
<Button
basic
color="red"
size="small"
onClick={() => updateEmployer(employer.uuid, false)}
>
End
</Button>
)}
</Button.Group>
</Card.Content>
</Card>
))}
</Card.Group>
)}
</Container>
);
export default connect(mapStateToProps)(ProviderClients);

View File

@ -9,7 +9,7 @@ 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
// Saga Employee 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";

View File

@ -0,0 +1,9 @@
// Reducer Employer Action Constants
export const IS_SENDING_EMPLOYER_REQUEST = "IS_SENDING_EMPLOYER_REQUEST";
export const SET_EMPLOYER_REQUEST_ERROR = "SET_EMPLOYER_REQUEST_ERROR";
export const CLEAR_EMPLOYER_REQUEST_ERROR = "CLEAR_EMPLOYER_REQUEST_ERROR";
export const SET_EMPLOYER_REQUEST_SUCCESS = "SET_EMPLOYER_REQUEST_SUCCESS";
export const CLEAR_EMPLOYER_REQUEST_SUCCESS = "CLEAR_EMPLOYER_REQUEST_SUCCESS";
// Saga Employer Action Constants
export const UPDATE_EMPLOYER_REQUEST = "UPDATE_EMPLOYER_REQUEST";

View File

@ -0,0 +1,47 @@
import {
IS_SENDING_EMPLOYER_REQUEST,
SET_EMPLOYER_REQUEST_ERROR,
CLEAR_EMPLOYER_REQUEST_ERROR,
SET_EMPLOYER_REQUEST_SUCCESS,
CLEAR_EMPLOYER_REQUEST_SUCCESS
} from "../constants/employer.constants";
const initialState = {
isSendingEmployerRequest: false,
employerRequestError: "",
employerRequestSuccess: ""
};
function employerReducer(state = initialState, action) {
switch (action.type) {
case IS_SENDING_EMPLOYER_REQUEST:
return {
...state,
isSendingEmployerRequest: action.data
};
case SET_EMPLOYER_REQUEST_ERROR:
return {
...state,
employerRequestError: action.data
};
case CLEAR_EMPLOYER_REQUEST_ERROR:
return {
...state,
employerRequestError: ""
};
case SET_EMPLOYER_REQUEST_SUCCESS:
return {
...state,
employerRequestSuccess: action.data
};
case CLEAR_EMPLOYER_REQUEST_SUCCESS:
return {
...state,
employerRequestSuccess: ""
};
default:
return state;
}
}
export default employerReducer;

View File

@ -10,7 +10,12 @@ import {
setFormEmployeeNote
} from "../actions/employee/reducer.actions";
import { getSelfUserRequest } from "../actions/user/saga.actions";
import { addEmployee, getEmployee, deleteEmployee, updateEmployee } from "../api/employee.api";
import {
addEmployee,
getEmployee,
deleteEmployee,
updateEmployee
} from "../api/employee.api";
function* addEmployeeCall(postBody) {
yield effects.put(isSendingEmployeeRequest(true));
@ -46,7 +51,7 @@ function* updateEmployeeCall(payload) {
yield effects.put(setEmployeeRequestError(exception));
return false;
} finally {
yield effects.put(isSendingEmployeeRequest(false))
yield effects.put(isSendingEmployeeRequest(false));
}
}
@ -78,9 +83,9 @@ export function* addEmployeeFlow(request) {
export function* readEmployeeFlow(request) {
const wasSuccessful = yield effects.call(readEmployeeCall, request.data);
if (wasSuccessful) {
yield effects.put(setEmployeeUUID(wasSuccessful.uuid))
yield effects.put(setEmployeeUUID(wasSuccessful.uuid));
yield effects.put(setFormEmployeeEmail(wasSuccessful.provider_email));
yield effects.put(setFormEmployeeNote(wasSuccessful.note))
yield effects.put(setFormEmployeeNote(wasSuccessful.note));
}
}

View File

@ -0,0 +1,34 @@
import { effects } from "redux-saga";
import {
isSendingEmployerRequest,
setEmployerRequestError,
setEmployerRequestSuccess,
clearEmployerRequestError,
clearEmployerRequestSuccess
} from "../actions/employer/reducer.actions";
import { getSelfUserRequest } from "../actions/user/saga.actions";
import { updateEmployer } from "../api/employer.api";
function* updateEmployerCall(payload) {
yield effects.put(isSendingEmployerRequest(true));
const { uuid, approved } = payload;
try {
return yield effects.call(updateEmployer, uuid, approved);
} catch (exception) {
yield effects.put(setEmployerRequestError(exception));
return false;
} finally {
yield effects.put(isSendingEmployerRequest(false));
}
}
export function* updateEmployerFlow(request) {
yield effects.put(clearEmployerRequestSuccess());
yield effects.put(clearEmployerRequestError());
const wasSuccessful = yield effects.call(updateEmployerCall, request.data);
if (wasSuccessful) {
yield effects.put(getSelfUserRequest());
yield effects.put(setEmployerRequestSuccess(wasSuccessful));
yield effects.put(clearEmployerRequestError());
}
}

View File

@ -57,6 +57,8 @@ import {
readEmployeeFlow,
deleteEmployeeFlow
} from "./employee.sagas";
import { UPDATE_EMPLOYER_REQUEST } from "../constants/employer.constants";
import { updateEmployerFlow } from "./employer.sagas";
export default function* rootSaga() {
yield takeLatest(SEND_REGISTER_REQUEST, registerUserFlow);
@ -80,4 +82,5 @@ export default function* rootSaga() {
yield takeLatest(CREATE_EMPLOYEE_REQUEST, addEmployeeFlow);
yield takeLatest(READ_EMPLOYEE_REQUEST, readEmployeeFlow);
yield takeLatest(DELETE_EMPLOYEE_REQUEST, deleteEmployeeFlow);
yield takeLatest(UPDATE_EMPLOYER_REQUEST, updateEmployerFlow);
}