Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit cd42c7d

Browse files
Merge pull request #78 from topcoder-platform/dev
[PROD] Release 1.0.3
2 parents 2a7fb16 + ff10976 commit cd42c7d

File tree

14 files changed

+154
-22
lines changed

14 files changed

+154
-22
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.container {
22
margin-bottom: 7px;
33
line-height: 17px;
4+
font-weight: bold;
45
}

src/constants/workPeriods.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export const API_REQUIRED_FIELDS = [
4242
"endDate",
4343
"memberRate",
4444
"status",
45+
"billingAccountId",
4546
"workPeriods.id",
4647
"workPeriods.projectId",
4748
"workPeriods.userHandle",
@@ -128,6 +129,7 @@ export const API_CHALLENGE_PAYMENT_STATUS_MAP = {
128129
export const URL_QUERY_PARAM_MAP = new Map([
129130
["startDate", "startDate"],
130131
["paymentStatuses", "status"],
132+
["alertOptions", "alert"],
131133
["onlyFailedPayments", "onlyFailed"],
132134
["userHandle", "user"],
133135
["criteria", "by"],
@@ -149,6 +151,8 @@ export const REASON_DISABLED_MESSAGE_MAP = {
149151
"Billing Account is not set for the Resource Booking",
150152
[REASON_DISABLED.NO_DAYS_TO_PAY_FOR]: "There are no days to pay for",
151153
[REASON_DISABLED.NO_MEMBER_RATE]: "Member Rate should be greater than 0",
154+
[REASON_DISABLED.NOT_ALLOW_FUTURE_WEEK]:
155+
"Not allowed processing payments for the future weeks",
152156
};
153157

154158
export const ALERT_MESSAGE_MAP = {

src/constants/workPeriods/alerts.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export const BA_NOT_ASSIGNED = "BA_NOT_ASSIGNED";
2+
export const ONBOARDING_WEEK = "ONBOARDING_WEEK";
23
export const LAST_BOOKING_WEEK = "LAST_BOOKING_WEEK";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export const NO_BILLING_ACCOUNT = "NO_BILLING_ACCOUNT";
22
export const NO_DAYS_TO_PAY_FOR = "NO_DAYS_TO_PAY_FOR";
33
export const NO_MEMBER_RATE = "NO_MEMBER_RATE";
4+
export const NOT_ALLOW_FUTURE_WEEK = "NOT_ALLOW_FUTURE_WEEK";

src/routes/WorkPeriods/components/PeriodFilters/index.jsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ import CheckboxList from "components/CheckboxList";
88
import SearchHandleField from "components/SearchHandleField";
99
import SidebarSection from "components/SidebarSection";
1010
import Toggle from "components/Toggle";
11-
import { PAYMENT_STATUS } from "constants/workPeriods";
11+
import { PAYMENT_STATUS, ALERT } from "constants/workPeriods";
1212
import { getWorkPeriodsFilters } from "store/selectors/workPeriods";
1313
import {
1414
resetWorkPeriodsFilters,
1515
setWorkPeriodsPaymentStatuses,
16+
setAlertOption,
1617
setWorkPeriodsUserHandle,
1718
toggleShowFailedPaymentsOnly,
1819
} from "store/actions/workPeriods";
@@ -35,7 +36,8 @@ import styles from "./styles.module.scss";
3536
const PeriodFilters = ({ className }) => {
3637
const dispatch = useDispatch();
3738
const filters = useSelector(getWorkPeriodsFilters);
38-
const { onlyFailedPayments, paymentStatuses, userHandle } = filters;
39+
const { onlyFailedPayments, paymentStatuses, alertOptions, userHandle } =
40+
filters;
3941

4042
const onToggleFailedPayments = useCallback(
4143
(on) => {
@@ -61,6 +63,14 @@ const PeriodFilters = ({ className }) => {
6163
[dispatch]
6264
);
6365

66+
const onAlertOptionsChange = useCallback(
67+
(option) => {
68+
dispatch(setAlertOption(option));
69+
dispatch(updateQueryFromState());
70+
},
71+
[dispatch]
72+
);
73+
6474
const onClearFilter = useCallback(() => {
6575
dispatch(resetWorkPeriodsFilters());
6676
dispatch(updateQueryFromState());
@@ -113,6 +123,14 @@ const PeriodFilters = ({ className }) => {
113123
onChange={onToggleFailedPayments}
114124
/>
115125
</div>
126+
<SidebarSection label="Misc Filters">
127+
<CheckboxList
128+
name="alert_option[]"
129+
onChange={onAlertOptionsChange}
130+
options={ALERT_OPTIONS}
131+
value={alertOptions}
132+
/>
133+
</SidebarSection>
116134
<div className={styles.buttons}>
117135
<Button className={styles.button} size="small" onClick={onClearFilter}>
118136
Clear Filter
@@ -134,4 +152,10 @@ const PAYMENT_STATUS_OPTIONS = [
134152
{ value: PAYMENT_STATUS.NO_DAYS, label: "No Days" },
135153
];
136154

155+
const ALERT_OPTIONS = [
156+
{ value: ALERT.BA_NOT_ASSIGNED, label: "No BA Assigned" },
157+
{ value: ALERT.ONBOARDING_WEEK, label: "Onboarding Week" },
158+
{ value: ALERT.LAST_BOOKING_WEEK, label: "Last Booking Week" },
159+
];
160+
137161
export default memo(PeriodFilters);

src/routes/WorkPeriods/components/PeriodFilters/styles.module.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
justify-content: space-between;
1010
align-items: center;
1111
margin-top: 6px;
12+
margin-bottom: 26px;
1213
}
1314

1415
.buttons {

src/routes/WorkPeriods/components/PeriodListHead/index.jsx

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1-
import React, { useCallback } from "react";
1+
import React, { useCallback, useMemo } from "react";
22
import { useDispatch, useSelector } from "react-redux";
3+
import Tooltip from "components/Tooltip";
34
import cn from "classnames";
5+
import moment from "moment";
46
import Checkbox from "components/Checkbox";
57
import SortingControl from "components/SortingControl";
6-
import { SORT_BY } from "constants/workPeriods";
78
import {
9+
SORT_BY,
10+
REASON_DISABLED,
11+
REASON_DISABLED_MESSAGE_MAP,
12+
} from "constants/workPeriods";
13+
import {
14+
getWorkPeriodsDateRange,
815
getWorkPeriodsIsSelectedVisible,
916
getWorkPeriodsSorting,
1017
} from "store/selectors/workPeriods";
@@ -24,6 +31,7 @@ import styles from "./styles.module.scss";
2431
const PeriodListHead = () => {
2532
const sorting = useSelector(getWorkPeriodsSorting);
2633
const isSelectedVisible = useSelector(getWorkPeriodsIsSelectedVisible);
34+
const periodsDateRange = useSelector(getWorkPeriodsDateRange);
2735
const dispatch = useDispatch();
2836
const { criteria, order } = sorting;
2937

@@ -39,16 +47,40 @@ const PeriodListHead = () => {
3947
dispatch(toggleWorkingPeriodsVisible());
4048
}, [dispatch]);
4149

50+
const reasonsDisabled = useMemo(() => {
51+
if (periodsDateRange[0].isAfter(moment())) {
52+
return REASON_DISABLED.NOT_ALLOW_FUTURE_WEEK;
53+
}
54+
return null;
55+
}, [periodsDateRange]);
56+
57+
const reasonsDisabledElement = useMemo(
58+
() => (
59+
<div className={styles.tooltipContent}>
60+
{reasonsDisabled && REASON_DISABLED_MESSAGE_MAP[reasonsDisabled]}
61+
</div>
62+
),
63+
[reasonsDisabled]
64+
);
65+
4266
return (
4367
<tr className={styles.container}>
4468
<th>
4569
<div className={styles.colHead}>
46-
<Checkbox
47-
size="small"
48-
name={"visible_periods_selected"}
49-
onChange={onToggleVisible}
50-
checked={isSelectedVisible}
51-
/>
70+
<Tooltip
71+
content={reasonsDisabledElement}
72+
isDisabled={!reasonsDisabled}
73+
strategy="fixed"
74+
targetClassName={styles.checkboxContainer}
75+
>
76+
<Checkbox
77+
size="small"
78+
isDisabled={!!reasonsDisabled}
79+
name={"visible_periods_selected"}
80+
onChange={onToggleVisible}
81+
checked={isSelectedVisible}
82+
/>
83+
</Tooltip>
5284
</div>
5385
</th>
5486
{HEAD_CELLS.map(({ id, className, label, disableSort }) => (

src/services/workPeriods.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import axios, { CancelToken } from "./axios";
22
import {
33
API_CHALLENGE_PAYMENT_STATUS,
4-
API_QUERY_PARAM_NAMES,
54
JOBS_API_URL,
65
PAYMENTS_API_URL,
76
PROJECTS_API_URL,
@@ -100,10 +99,9 @@ export const fetchWorkPeriods = (rbId, source) => {
10099
export const fetchResourceBookings = (params) => {
101100
const source = CancelToken.source();
102101
return [
103-
axios.get(
104-
`${RB_API_URL}?${buildRequestQuery(params, API_QUERY_PARAM_NAMES)}`,
105-
{ cancelToken: source.token }
106-
),
102+
axios.get(`${RB_API_URL}?${buildRequestQuery(params)}`, {
103+
cancelToken: source.token,
104+
}),
107105
source,
108106
];
109107
};

src/store/actionTypes/workPeriods.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const WP_SET_PAGE_SIZE = "WP_SET_PAGE_SIZE";
2020
export const WP_SET_DATE_RANGE = "WP_SET_DATE_RANGE";
2121
export const WP_SET_PAYMENT_DATA = "WP_SET_PAYMENT_DATA";
2222
export const WP_SET_PAYMENT_STATUSES = "WP_SET_PAYMENT_STATUSES";
23+
export const WP_SET_ALERT_OPTION = "WP_SET_ALERT_OPTION";
2324
export const WP_SET_PERIOD_DATA_PENDING = "WP_SET_PERIOD_DATA_PENDING";
2425
export const WP_SET_PERIOD_DATA_SUCCESS = "WP_SET_PERIOD_DATA_SUCCESS";
2526
export const WP_SET_PERIOD_DATA_ERROR = "WP_SET_PERIOD_DATA_ERROR";

src/store/actions/workPeriods.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,17 @@ export const setWorkPeriodsPaymentStatuses = (paymentStatuses) => ({
265265
payload: paymentStatuses,
266266
});
267267

268+
/**
269+
* Creates an action denoting the changing of alert option
270+
*
271+
* @param {Object} paymentStatuses object with working periods' payment statuses
272+
* @returns {Object}
273+
*/
274+
export const setAlertOption = (option) => ({
275+
type: ACTION_TYPE.WP_SET_ALERT_OPTION,
276+
payload: option,
277+
});
278+
268279
/**
269280
* Creates an action denoting the changing of working periods' topcoder handle.
270281
*

src/store/reducers/workPeriods.js

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const initFilters = () => ({
4242
dateRange: getWeekByDate(moment()),
4343
onlyFailedPayments: false,
4444
paymentStatuses: {}, // all disabled by default
45+
alertOptions: {},
4546
userHandle: "",
4647
});
4748

@@ -141,7 +142,7 @@ const actionHandlers = {
141142
periodEnd
142143
);
143144
periodsData[period.id] = periodData;
144-
let reasonsDisabled = findReasonsDisabled(period);
145+
let reasonsDisabled = findReasonsDisabled(period, dateRange);
145146
if (reasonsDisabled) {
146147
periodsDisabledMap.set(period.id, reasonsDisabled);
147148
}
@@ -556,6 +557,17 @@ const actionHandlers = {
556557
pageNumber: 1,
557558
},
558559
}),
560+
[ACTION_TYPE.WP_SET_ALERT_OPTION]: (state, alertOptions) => ({
561+
...state,
562+
filters: {
563+
...state.filters,
564+
alertOptions: updateOptionMap(state.filters.alertOptions, alertOptions),
565+
},
566+
pagination: {
567+
...state.pagination,
568+
pageNumber: 1,
569+
},
570+
}),
559571
[ACTION_TYPE.WP_SET_USER_HANDLE]: (state, userHandle) => {
560572
if (userHandle === state.filters.userHandle) {
561573
return state;
@@ -944,6 +956,34 @@ function updateStateFromQuery(queryStr, state) {
944956
filters.paymentStatuses = queryPaymentStatuses;
945957
updateFilters = true;
946958
}
959+
960+
// checking alert option
961+
let hasSameOption = true;
962+
const filtersAlertOptions = filters.alertOptions;
963+
const queryAlertOptions = {};
964+
const alertOptionsStr = params.alertOptions;
965+
if (alertOptionsStr) {
966+
for (let option of alertOptionsStr.split(",")) {
967+
option = option.toUpperCase();
968+
if (option in ALERT) {
969+
queryAlertOptions[option] = true;
970+
if (!filtersAlertOptions[option]) {
971+
hasSameOption = false;
972+
}
973+
}
974+
}
975+
}
976+
for (let option in filtersAlertOptions) {
977+
if (!filtersAlertOptions[option]) {
978+
hasSameOption = false;
979+
break;
980+
}
981+
}
982+
if (!hasSameOption) {
983+
filters.alertOptions = queryAlertOptions;
984+
updateFilters = true;
985+
}
986+
947987
// chacking only failed payments flag
948988
const onlyFailedFlag = params.onlyFailedPayments?.slice(0, 1);
949989
const onlyFailedPayments = onlyFailedFlag === "y";

src/store/thunks/workPeriods.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ export const loadWorkPeriodsPage = async (dispatch, getState) => {
113113
["workPeriods.userHandle"]: userHandle,
114114
["workPeriods.startDate"]: startDate.format(DATE_FORMAT_API),
115115
["workPeriods.paymentStatus"]: paymentStatuses,
116+
["billingAccountId"]: filters.alertOptions.BA_NOT_ASSIGNED ? 0 : null,
117+
["workPeriods.isFirstWeek"]: filters.alertOptions.ONBOARDING_WEEK
118+
? true
119+
: null,
120+
["workPeriods.isLastWeek"]: filters.alertOptions.LAST_BOOKING_WEEK
121+
? true
122+
: null,
116123
["workPeriods.payments.status"]: onlyFailedPayments
117124
? API_CHALLENGE_PAYMENT_STATUS.FAILED
118125
: null,

src/utils/misc.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,11 @@ export function updateOptionMap(oldOptions, newOptions) {
116116
* that are not numbers and are falsy are ignored.
117117
*
118118
* @param {Object} params query parameters object
119-
* @param {string[]} paramNames array of valid query parameter names
120119
* @returns {string} query string
121120
*/
122-
export const buildRequestQuery = (params, paramNames) => {
121+
export const buildRequestQuery = (params) => {
123122
const queryParams = [];
124-
for (const paramName of paramNames) {
123+
for (const paramName in params) {
125124
const paramValue = params[paramName];
126125
if (
127126
!(paramName in params) ||

src/utils/workPeriods.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,16 @@ export function createPeriodAlerts(period, periodEnd) {
6363
* payment processing.
6464
*
6565
* @param {Object} period working period object
66+
* @param {Array} dateRange date range array
6667
* @returns {?string[]}
6768
*/
68-
export function findReasonsDisabled(period) {
69+
export function findReasonsDisabled(period, dateRange) {
6970
const reasons = [];
71+
if (dateRange && dateRange.length > 0) {
72+
if (dateRange[0].isAfter(moment())) {
73+
reasons.push(REASON_DISABLED.NOT_ALLOW_FUTURE_WEEK);
74+
}
75+
}
7076
if (!period.billingAccountId) {
7177
reasons.push(REASON_DISABLED.NO_BILLING_ACCOUNT);
7278
}
@@ -111,13 +117,19 @@ export function removeValueImmutable(items, value) {
111117
*/
112118
export function makeUrlQuery(state) {
113119
const { filters, pagination, sorting } = state;
114-
const { dateRange, onlyFailedPayments, paymentStatuses, userHandle } =
115-
filters;
120+
const {
121+
dateRange,
122+
onlyFailedPayments,
123+
paymentStatuses,
124+
alertOptions,
125+
userHandle,
126+
} = filters;
116127
const { pageNumber, pageSize } = pagination;
117128
const { criteria, order } = sorting;
118129
const params = {
119130
startDate: dateRange[0].format(DATE_FORMAT_API),
120131
paymentStatuses: Object.keys(paymentStatuses).join(",").toLowerCase(),
132+
alertOptions: Object.keys(alertOptions).join(",").toLowerCase(),
121133
onlyFailedPayments: onlyFailedPayments ? "y" : "",
122134
userHandle: encodeURIComponent(userHandle),
123135
criteria: criteria.toLowerCase(),

0 commit comments

Comments
 (0)