Переглянути джерело

Schedule interview FE

pull/97/head
Ermin Bronja 3 роки тому
джерело
коміт
cdd95aca82

+ 2
- 1
src/assets/styles/components/_patterns.scss Переглянути файл

@@ -267,7 +267,8 @@
display: flex;
}

.pattern-details-card-sub-card-add-email input {
.pattern-details-card-sub-card-add-email input,
.pattern-details-card-sub-card-add-email select {
margin-right: 18px;
flex: 50;
box-sizing: border-box;

+ 88
- 24
src/pages/PatternsPage/PatternDetailsPage.js Переглянути файл

@@ -7,24 +7,89 @@ import { useParams } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { setPatternReq } from "../../store/actions/pattern/patternActions";
import { selectPattern } from "../../store/selectors/patternSelectors";
import {
clearNotSentEmailsArray,
scheduleAppointmentReq,
} from "../../store/actions/scheduleAppointment/scheduleAppointmentActions";
import { selectNotSentEmails } from "../../store/selectors/scheduleAppointmentSelectors";
import { setPatternApplicantsReq } from "../../store/actions/patternApplicants/patternApplicantsActions";
import { selectPatternApplicants } from "../../store/selectors/patternApplicants";
import { PATTERNS_PAGE } from "../../constants/pages";
import { useHistory } from "react-router-dom";

const PatternDetailsPage = () => {
const [emails, setEmails] = useState([]);
const [email, setEmail] = useState("");
const pattern = useSelector(selectPattern);
const patternApplicants = useSelector(selectPatternApplicants);
const notSentEmails = useSelector(selectNotSentEmails);
const [selectedPatternApplicants, setSelectedPatternApplicants] = useState(
[]
);
const { id } = useParams();
const dispatch = useDispatch();
const regex = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/
const history = useHistory();

const navigateToPatternsPage = () => {
history.push(PATTERNS_PAGE);
};

useEffect(() => {
setSelectedPatternApplicants(patternApplicants);
}, [patternApplicants]);

useEffect(() => {
dispatch(setPatternApplicantsReq({ id }));
}, []);

useEffect(() => {
dispatch(setPatternReq({ id }));
}, []);

useEffect(() => {
if (patternApplicants.length > 0) {
setEmail(patternApplicants[0].email);
}
}, [patternApplicants]);

useEffect(() => {
const arrOfApplicants = [];
for (let i = 0; i < patternApplicants.length; i++) {
let s = 0;
for (let j = 0; j < emails.length; j++) {
if (patternApplicants[i].email === emails[j]) s = 1;
}

if (s === 0) arrOfApplicants.push(patternApplicants[i]);
}

setSelectedPatternApplicants(arrOfApplicants);
if (arrOfApplicants.length > 0) {
setEmail(arrOfApplicants[0].email);
}
}, [emails]);

useEffect(() => {
dispatch(clearNotSentEmailsArray());
}, []);

const addNewEmailHandler = () => {
if (email.length === 0) return;
if(selectedPatternApplicants.length === 0) return;
setEmails((oldState) => [...oldState, email]);
setEmail("");
};

const scheduleAppointmentHandler = () => {
dispatch(
scheduleAppointmentReq({
emails,
patternId: id,
handleApiResponseSuccess: navigateToPatternsPage,
})
);
};

return (
<>
{!pattern && (
@@ -51,7 +116,7 @@ const PatternDetailsPage = () => {
</div>
<div className="pattern-details-card-sub-card">
<div className="pattern-details-card-sub-card-title">
<p>Screening test</p>
<p>{pattern.selectionLevel.name}</p>
</div>
<div className="pattern-details-card-sub-card-emails">
{emails &&
@@ -68,39 +133,34 @@ const PatternDetailsPage = () => {

<div className="pattern-details-card-sub-card">
<div className="pattern-details-card-sub-card-title">
<p>Screening test</p>
<p>{pattern.selectionLevel.name}</p>
</div>
<div className="pattern-details-card-sub-card-add-email">
<input
type="text"
onChange={(e) => setEmail(e.target.value)}
value={email}
placeholder="ex. petar.petrovic@mail.com"
/>
<button
onClick={addNewEmailHandler}
disabled={!regex.test(email)}
>
<select onChange={(e) => setEmail(e.target.value)}>
{selectedPatternApplicants.length > 0 &&
selectedPatternApplicants.map((applicant) => (
<option
key={applicant.applicantId}
value={applicant.email}
>
{applicant.firstName + " " + applicant.lastName}
</option>
))}
</select>
<button onClick={addNewEmailHandler}>
<img src={plusIcon} alt="plus" />
</button>
</div>
</div>

{notSentEmails && notSentEmails.map((x) => <p key={x}>{x}</p>)}

<div className="pattern-details-card-sub-card">
<div className="pattern-details-card-sub-card-title">
<p>Teskt poruke</p>
</div>
<div className="pattern-details-card-sub-card-message-pattern">
<textarea
disabled
// value={`Postovani,

// Ovom prilikom Vas obavestavamo da je datum Screening testa zakazan za [selected Date]

// Srdacan pozdrav,
// Diligent HR Team`}
value={pattern.message}
></textarea>
<textarea disabled value={pattern.message}></textarea>
</div>
</div>

@@ -108,7 +168,11 @@ const PatternDetailsPage = () => {
<Link className="ad-details-buttons-link" to="/patterns">
Nazad na sve šablone
</Link>
<IconButton className="c-btn c-btn--primary add-ad-btn">
<IconButton
disabled={emails.length === 0}
className="c-btn c-btn--primary add-ad-btn"
onClick={scheduleAppointmentHandler}
>
<img
style={{
marginRight: "5px",

+ 2
- 0
src/request/apiEndpoints.js Переглянути файл

@@ -44,9 +44,11 @@ export default {
patterns: {
allPatterns: base + "/patterns",
patternById: base + "/patterns/:id",
patternApplicantsById: base + "/patterns/corresponding-pattern-applicants/:id",
filteredPatterns: base + "/patterns/filter",
createPattern: base + "/patterns",
updatePattern: base + "/patterns/:id",
scheduleAppointment: base + "/patterns/schedule-interview"
},
stats: {
stats: base + "/stats",

+ 7
- 1
src/request/patternsRequest.js Переглянути файл

@@ -5,6 +5,8 @@ export const getAllPatterns = () =>
getRequest(apiEndpoints.patterns.allPatterns);
export const getPatternById = (id) =>
getRequest(apiEndpoints.patterns.patternById.replace(":id", id));
export const getPatternApplicantsById = (id) =>
getRequest(apiEndpoints.patterns.patternApplicantsById.replace(":id", id));
export const getFilteredPatterns = (payload) => {
let selectionLevelsQuery = "";
for (let i = 0; i < payload.selectionLevels.length; i++) {
@@ -13,7 +15,9 @@ export const getFilteredPatterns = (payload) => {
return getRequest(
apiEndpoints.patterns.filteredPatterns +
`?fromDate=${
payload.fromDate === null ? "" : new Date(payload.fromDate).toISOString()
payload.fromDate === null
? ""
: new Date(payload.fromDate).toISOString()
}&toDate=${
payload.toDate === null ? "" : new Date(payload.toDate).toISOString()
}&${selectionLevelsQuery}`
@@ -26,3 +30,5 @@ export const updatePatternRequest = (payload) =>
apiEndpoints.patterns.updatePattern.replace(":id", payload.id),
payload
);
export const scheduleAppointmentRequest = (payload) =>
postRequest(apiEndpoints.patterns.scheduleAppointment, payload);

+ 17
- 0
src/store/actions/patternApplicants/patternApplicantsActionConstants.js Переглянути файл

@@ -0,0 +1,17 @@
import {
createFetchType,
createSuccessType,
createErrorType,
} from "../actionHelpers";

const FETCH_PATTERN_APPLICANTS_SCOPE = "FETCH_PATTERN_APPLICANTS";

export const FETCH_PATTERN_APPLICANTS_REQ = createFetchType(
FETCH_PATTERN_APPLICANTS_SCOPE
);
export const FETCH_PATTERN_APPLICANTS_ERR = createErrorType(
FETCH_PATTERN_APPLICANTS_SCOPE
);
export const FETCH_PATTERN_APPLICANTS_SUCCESS = createSuccessType(
FETCH_PATTERN_APPLICANTS_SCOPE
);

+ 20
- 0
src/store/actions/patternApplicants/patternApplicantsActions.js Переглянути файл

@@ -0,0 +1,20 @@
import {
FETCH_PATTERN_APPLICANTS_REQ,
FETCH_PATTERN_APPLICANTS_ERR,
FETCH_PATTERN_APPLICANTS_SUCCESS,
} from "./patternApplicantsActionConstants";

export const setPatternApplicantsReq = (payload) => ({
type: FETCH_PATTERN_APPLICANTS_REQ,
payload,
});

export const setPatternApplicantsError = (payload) => ({
type: FETCH_PATTERN_APPLICANTS_ERR,
payload,
});

export const setPatternApplicants = (payload) => ({
type: FETCH_PATTERN_APPLICANTS_SUCCESS,
payload,
});

+ 14
- 0
src/store/actions/scheduleAppointment/scheduleAppointmentActionConstants.js Переглянути файл

@@ -0,0 +1,14 @@
import {
createFetchType,
createSuccessType,
createErrorType,
} from "../actionHelpers";
const SCHEDULE_APPOINTMENT_SCOPE = "SCHEDULE_APPOINTMENT";
export const SCHEDULE_APPOINTMENT_REQ = createFetchType(SCHEDULE_APPOINTMENT_SCOPE);
export const SCHEDULE_APPOINTMENT_ERR = createErrorType(SCHEDULE_APPOINTMENT_SCOPE);
export const SCHEDULE_APPOINTMENT_SUCCESS = createSuccessType(SCHEDULE_APPOINTMENT_SCOPE);

export const CLEAR_NOT_SENT_EMAILS_ARRAY = "CLEAR_NOT_SENT_EMAILS_ARRAY";

+ 25
- 0
src/store/actions/scheduleAppointment/scheduleAppointmentActions.js Переглянути файл

@@ -0,0 +1,25 @@
import {
SCHEDULE_APPOINTMENT_REQ,
SCHEDULE_APPOINTMENT_ERR,
SCHEDULE_APPOINTMENT_SUCCESS,
CLEAR_NOT_SENT_EMAILS_ARRAY,
} from "./scheduleAppointmentActionConstants";

export const scheduleAppointmentReq = (payload) => ({
type: SCHEDULE_APPOINTMENT_REQ,
payload,
});

export const scheduleAppointmentError = (payload) => ({
type: SCHEDULE_APPOINTMENT_ERR,
payload,
});

export const scheduleAppointment = (payload) => ({
type: SCHEDULE_APPOINTMENT_SUCCESS,
payload,
});

export const clearNotSentEmailsArray = () => ({
type: CLEAR_NOT_SENT_EMAILS_ARRAY,
});

+ 6
- 2
src/store/reducers/index.js Переглянути файл

@@ -24,6 +24,8 @@ import createPatternReducer from "./pattern/createPatternReducer";
import updatePatternReducer from "./pattern/updatePatternReducer";
import statsReducer from "./stats/statsReducer";
import scheduleReducer from "./schedule/scheduleReducer";
import scheduleAppointmentReducer from "./pattern/scheduleAppointmentReducer";
import patternApplicantsReducer from "./pattern/patternApplicantsReducer";
import archiveActiveAdReducer from "./ad/archiveActiveAdReducer";
import registerReducer from "./register/registerReducer";

@@ -53,6 +55,8 @@ export default combineReducers({
createPattern: createPatternReducer,
updatePattern: updatePatternReducer,
stats: statsReducer,
schedule:scheduleReducer,
register: registerReducer
schedule: scheduleReducer,
register: registerReducer,
scheduleAppointment: scheduleAppointmentReducer,
patternApplicants: patternApplicantsReducer,
});

+ 26
- 0
src/store/reducers/pattern/patternApplicantsReducer.js Переглянути файл

@@ -0,0 +1,26 @@
import createReducer from "../../utils/createReducer";
import {
FETCH_PATTERN_APPLICANTS_SUCCESS,
FETCH_PATTERN_APPLICANTS_ERR,
} from "../../actions/patternApplicants/patternApplicantsActionConstants";

const initialState = {
patternApplicants: [],
errorMessage: "",
};

export default createReducer(
{
[FETCH_PATTERN_APPLICANTS_SUCCESS]: setStatePatternApplicants,
[FETCH_PATTERN_APPLICANTS_ERR]: setStateErrorMessage,
},
initialState
);

function setStatePatternApplicants(state, action) {
return { ...state, patternApplicants: action.payload };
}

function setStateErrorMessage(state, action) {
return { ...state, errorMessage: action.payload };
}

+ 41
- 0
src/store/reducers/pattern/scheduleAppointmentReducer.js Переглянути файл

@@ -0,0 +1,41 @@
import {
SCHEDULE_APPOINTMENT_SUCCESS,
SCHEDULE_APPOINTMENT_ERR,
CLEAR_NOT_SENT_EMAILS_ARRAY,
} from "../../actions/scheduleAppointment/scheduleAppointmentActionConstants";
import createReducer from "../../utils/createReducer";

const initialState = {
notSentEmails: null,
errorMessage: "",
};

export default createReducer(
{
[SCHEDULE_APPOINTMENT_SUCCESS]: setStateScheduleAppointment,
[SCHEDULE_APPOINTMENT_ERR]: setScheduleAppointmentErrorMessage,
[CLEAR_NOT_SENT_EMAILS_ARRAY]: setNotSentEmailsArrayNull,
},
initialState
);

function setStateScheduleAppointment(state, action) {
return {
...state,
notSentEmails: action.payload ? [...action.payload.notSentEmails] : null,
};
}

function setScheduleAppointmentErrorMessage(state, action) {
return {
...state,
errorMessage: action.payload,
};
}

function setNotSentEmailsArrayNull(state) {
return {
...state,
notSentEmails: null,
};
}

+ 35
- 0
src/store/saga/patternsSaga.js Переглянути файл

@@ -3,7 +3,9 @@ import {
createPatternRequest,
getAllPatterns,
getFilteredPatterns,
getPatternApplicantsById,
getPatternById,
scheduleAppointmentRequest,
updatePatternRequest,
} from "../../request/patternsRequest";
import {
@@ -32,6 +34,10 @@ import { authScopeStringGetHelper } from "../../util/helpers/authScopeHelpers";
import { JWT_TOKEN } from "../../constants/localStorage";
import { addHeaderToken } from "../../request";
import { rejectErrorCodeHelper } from "../../util/helpers/rejectErrorCodeHelper";
import { SCHEDULE_APPOINTMENT_REQ } from "../actions/scheduleAppointment/scheduleAppointmentActionConstants";
import { scheduleAppointment } from "../actions/scheduleAppointment/scheduleAppointmentActions";
import { FETCH_PATTERN_APPLICANTS_REQ } from "../actions/patternApplicants/patternApplicantsActionConstants";
import { setPatternApplicants } from "../actions/patternApplicants/patternApplicantsActions";

export function* getPatterns() {
try {
@@ -51,6 +57,18 @@ export function* getPattern({ payload }) {
}
}

export function* getPatternApplicants({ payload }) {
try {
const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);
yield call(addHeaderToken, JwtToken);
const result = yield call(getPatternApplicantsById, payload.id);
yield put(setPatternApplicants(result.data));
} catch (error) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(setPatternError(errorMessage));
}
}

export function* filterPatterns({ payload }) {
try {
const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);
@@ -88,12 +106,29 @@ export function* updatePatternSaga({ payload }) {
}
}

export function* scheduleAppointmentSaga({ payload }) {
try {
const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);
yield call(addHeaderToken, JwtToken);
const { data } = yield call(scheduleAppointmentRequest, payload);
yield put(scheduleAppointment(data));
if (payload.handleApiResponseSuccess) {
yield call(payload.handleApiResponseSuccess);
}
} catch (error) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(setFilteredPatternsError(errorMessage));
}
}

export default function* adsSaga() {
yield all([
takeLatest(FETCH_PATTERNS_REQ, getPatterns),
takeLatest(FETCH_PATTERN_REQ, getPattern),
takeLatest(FETCH_PATTERN_APPLICANTS_REQ, getPatternApplicants),
takeLatest(FETCH_FILTERED_PATTERNS_REQ, filterPatterns),
takeLatest(CREATE_PATTERN_REQ, createPatternSaga),
takeLatest(UPDATE_PATTERN_REQ, updatePatternSaga),
takeLatest(SCHEDULE_APPOINTMENT_REQ, scheduleAppointmentSaga),
]);
}

+ 13
- 0
src/store/selectors/patternApplicants.js Переглянути файл

@@ -0,0 +1,13 @@
import { createSelector } from "@reduxjs/toolkit";

export const patternApplicantsSelector = (state) => state.patternApplicants;

export const selectPatternApplicants = createSelector(
patternApplicantsSelector,
(state) => state.patternApplicants
);

export const selectPatternApplicantsError = createSelector(
patternApplicantsSelector,
(state) => state.errorMessage
);

+ 13
- 0
src/store/selectors/scheduleAppointmentSelectors.js Переглянути файл

@@ -0,0 +1,13 @@
import { createSelector } from "@reduxjs/toolkit";

export const scheduleAppointmentSelector = (state) => state.scheduleAppointment;

export const selectNotSentEmails = createSelector(
scheduleAppointmentSelector,
(state) => state.notSentEmails
);

export const selectScheduleAppointmentError = createSelector(
scheduleAppointmentSelector,
(state) => state.errorMessage
);

Завантаження…
Відмінити
Зберегти