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

Fixes for popups and pagination #43

Merged
merged 3 commits into from
Jun 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/components/Popup/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,27 @@ import PT from "prop-types";
import cn from "classnames";
import compStyles from "./styles.module.scss";

const Popup = ({ children, className, referenceElement }) => {
/**
* Displays a popup near the reference element.
*
* @param {Object} props component properties
* @param {any} [props.children] child nodes
* @param {string} [props.className] class name to be added to root element
* @param {Object} props.referenceElement reference element
* @param {'absolute'|'fixed'} [props.strategy] positioning strategy
* @returns {JSX.Element}
*/
const Popup = ({
children,
className,
referenceElement,
strategy = "absolute",
}) => {
const [popperElement, setPopperElement] = useState(null);
const [arrowElement, setArrowElement] = useState(null);
const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: "bottom",
strategy,
modifiers: [
{ name: "arrow", options: { element: arrowElement, padding: 10 } },
{ name: "offset", options: { offset: [0, 5] } },
Expand All @@ -33,6 +49,7 @@ Popup.propTypes = {
children: PT.node,
className: PT.string,
referenceElement: PT.object.isRequired,
strategy: PT.oneOf(["absolute", "fixed"]),
};

export default Popup;
11 changes: 9 additions & 2 deletions src/routes/WorkPeriods/components/PaymentError/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@ import styles from "./styles.module.scss";
* @param {string} [props.className] class name to be added to root element
* @param {Object} [props.errorDetails] error details object
* @param {boolean} [props.isImportant] whether the error deemed important
* @param {'absolute'|'fixed'} [props.popupStrategy] popup positioning strategy
* @returns {JSX.Element}
*/
const PaymentError = ({ className, errorDetails, isImportant = true }) => {
const PaymentError = ({
className,
errorDetails,
isImportant = true,
popupStrategy = "absolute",
}) => {
const [isShowPopup, setIsShowPopup] = useState(false);
const [refElem, setRefElem] = useState(null);
const containerRef = useRef(null);
Expand All @@ -42,7 +48,7 @@ const PaymentError = ({ className, errorDetails, isImportant = true }) => {
tabIndex={0}
/>
{isShowPopup && errorDetails && (
<Popup referenceElement={refElem}>
<Popup referenceElement={refElem} strategy={popupStrategy}>
<PaymentErrorDetails details={errorDetails} />
</Popup>
)}
Expand All @@ -54,6 +60,7 @@ PaymentError.propTypes = {
className: PT.string,
errorDetails: PT.object,
isImportant: PT.bool,
popupStrategy: PT.oneOf(["absolute", "fixed"]),
};

export default PaymentError;
12 changes: 10 additions & 2 deletions src/routes/WorkPeriods/components/PaymentTotal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,16 @@ import styles from "./styles.module.scss";
* @param {Array} [props.payments] an array with payments information
* @param {number} props.paymentTotal total paid sum
* @param {number} props.daysPaid number of paid days
* @param {'absolute'|'fixed'} [props.popupStrategy] popup positioning strategy
* @returns {JSX.Element}
*/
const PaymentTotal = ({ className, payments, paymentTotal, daysPaid }) => {
const PaymentTotal = ({
className,
payments,
paymentTotal,
daysPaid,
popupStrategy = "absolute",
}) => {
const [isShowPopup, setIsShowPopup] = useState(false);
const [refElem, setRefElem] = useState(null);
const containerRef = useRef(null);
Expand Down Expand Up @@ -56,7 +63,7 @@ const PaymentTotal = ({ className, payments, paymentTotal, daysPaid }) => {
<span className={styles.daysPaid}>({daysPaid})</span>
</span>
{hasPayments && isShowPopup && (
<Popup referenceElement={refElem}>
<Popup referenceElement={refElem} strategy={popupStrategy}>
<PaymentsList payments={payments} />
</Popup>
)}
Expand All @@ -69,6 +76,7 @@ PaymentTotal.propTypes = {
payments: PT.array,
paymentTotal: PT.number.isRequired,
daysPaid: PT.number.isRequired,
popupStrategy: PT.oneOf(["absolute", "fixed"]),
};

export default PaymentTotal;
2 changes: 2 additions & 0 deletions src/routes/WorkPeriods/components/PeriodItem/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,15 @@ const PeriodItem = ({
className={styles.paymentError}
errorDetails={data.paymentErrorLast}
isImportant={data.paymentStatus !== PAYMENT_STATUS.COMPLETED}
popupStrategy="fixed"
/>
)}
<PaymentTotal
className={styles.paymentTotalContainer}
daysPaid={data.daysPaid}
payments={data.payments}
paymentTotal={data.paymentTotal}
popupStrategy="fixed"
/>
</td>
<td>
Expand Down
13 changes: 7 additions & 6 deletions src/store/actions/workPeriods.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as ACTION_TYPE from "store/actionTypes/workPeriods";
let nextErrorId = 1;

/**
* Creates an action denoting the start of loading specific challenge page.
* Creates an action denoting the start of loading specific working period page.
*
* @param {Object} cancelSource object that can be used to cancel network request
* @returns {Object}
Expand All @@ -17,14 +17,15 @@ export const loadWorkPeriodsPagePending = (cancelSource) => ({
/**
* Creates an action denoting the saving of fetched working periods' page.
*
* @param {Array} periods array of challenge objects
* @param {number} totalCount total number of periods for current filters' state
* @param {number} pageCount total number of pages
* @param {Object} payload action payload
* @param {Array} payload.periods array of working period objects
* @param {number} payload.totalCount total number of periods for current filters' state
* @param {number} payload.pageCount total number of pages
* @returns {Object}
*/
export const loadWorkPeriodsPageSuccess = (periods, totalCount, pageCount) => ({
export const loadWorkPeriodsPageSuccess = (payload) => ({
type: ACTION_TYPE.WP_LOAD_PAGE_SUCCESS,
payload: { periods, totalCount, pageCount },
payload,
});

/**
Expand Down
4 changes: 4 additions & 0 deletions src/store/reducers/workPeriods.js
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,10 @@ const actionHandlers = {
...filters,
onlyFailedPayments: on,
},
pagination: {
...state.pagination,
pageNumber: 1,
},
};
},
[ACTION_TYPE.WP_TOGGLE_PERIOD]: (state, periodId) => {
Expand Down
19 changes: 12 additions & 7 deletions src/store/thunks/workPeriods.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const loadWorkPeriodsPage = async (dispatch, getState) => {

// For parameter description see:
// https://topcoder-platform.github.io/taas-apis/#/ResourceBookings/get_resourceBookings
const params = {
const [promise, cancelSource] = services.fetchResourceBookings({
fields: API_FIELDS_QUERY,
page: pagination.pageNumber,
perPage: pagination.pageSize,
Expand All @@ -75,11 +75,10 @@ export const loadWorkPeriodsPage = async (dispatch, getState) => {
["workPeriods.userHandle"]: userHandle,
["workPeriods.startDate"]: startDate.format(DATE_FORMAT_API),
["workPeriods.paymentStatus"]: paymentStatuses,
};
if (onlyFailedPayments) {
params["workPeriods.payments.status"] = API_CHALLENGE_PAYMENT_STATUS.FAILED;
}
const [promise, cancelSource] = services.fetchResourceBookings(params);
["workPeriods.payments.status"]: onlyFailedPayments
? API_CHALLENGE_PAYMENT_STATUS.FAILED
: null,
});
dispatch(actions.loadWorkPeriodsPagePending(cancelSource));
let totalCount, periods, pageCount;
try {
Expand All @@ -95,7 +94,13 @@ export const loadWorkPeriodsPage = async (dispatch, getState) => {
}
return;
}
dispatch(actions.loadWorkPeriodsPageSuccess(periods, totalCount, pageCount));
dispatch(
actions.loadWorkPeriodsPageSuccess({
periods,
totalCount,
pageCount,
})
);
};

/**
Expand Down
2 changes: 1 addition & 1 deletion src/styles/mixins/_screenSizes.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import 'variables/screenSizes';
@import "variables/screenSizes";

// There's no need for phone() mixin for phone and larger screens to exist
// because styles for these screens are simply added without media queries.
Expand Down
8 changes: 4 additions & 4 deletions src/styles/variables/_screenSizes.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ $screen-codes: phone tablet desktop desktop-lg;

// This map defines minimum screen widths for different devices.
$screen-sizes: (
'phone': 320px,
'tablet': 768px,
'desktop': 1280px,
"phone": 320px,
"tablet": 768px,
"desktop": 1280px,
);

// Media queries' mixins will use minimum screen widths from this map.
Expand All @@ -20,7 +20,7 @@ $screen-min-px: ();
$screen-min-px: map-merge(
$screen-min-px,
(
'desktop-lg': 1920px,
"desktop-lg": 1920px,
)
);

Expand Down