diff --git a/src/components/ActionsMenu/index.jsx b/src/components/ActionsMenu/index.jsx
index ab08abe..4eb6940 100644
--- a/src/components/ActionsMenu/index.jsx
+++ b/src/components/ActionsMenu/index.jsx
@@ -3,6 +3,7 @@ import PT from "prop-types";
 import cn from "classnames";
 import { usePopper } from "react-popper";
 import Button from "components/Button";
+import Tooltip from "components/Tooltip";
 import IconArrowDown from "../../assets/images/icon-arrow-down-narrow.svg";
 import { useClickOutside } from "utils/hooks";
 import { negate, stopPropagation } from "utils/misc";
@@ -39,48 +40,6 @@ const ActionsMenu = ({
     setIsOpen(negate);
   }, []);
 
-  const onItemClick = useCallback(
-    (event) => {
-      let index = +event.target.dataset.actionIndex;
-      let item = items[index];
-      if (!item || item.disabled || item.separator) {
-        return;
-      }
-      closeMenu();
-      item.action?.();
-    },
-    [items, closeMenu]
-  );
-
-  const menuItems = useMemo(
-    () =>
-      items.map((item, index) => {
-        if (item.hidden) {
-          return null;
-        } else if (item.separator) {
-          return <div key={index} className={compStyles.separator} />;
-        } else {
-          return (
-            <div
-              key={index}
-              data-action-index={index}
-              onClick={onItemClick}
-              role="button"
-              tabIndex={0}
-              className={cn(
-                compStyles.item,
-                { [compStyles.itemDisabled]: item.disabled },
-                item.className
-              )}
-            >
-              {item.label}
-            </div>
-          );
-        }
-      }),
-    [items, onItemClick]
-  );
-
   return (
     <div
       className={compStyles.container}
@@ -104,8 +63,8 @@ const ActionsMenu = ({
       </Button>
       {isOpen && (
         <Menu
-          items={menuItems}
-          onClickOutside={closeMenu}
+          close={closeMenu}
+          items={items}
           referenceElement={referenceElement}
           strategy={popupStrategy}
         />
@@ -123,6 +82,7 @@ ActionsMenu.propTypes = {
       label: PT.string,
       action: PT.func,
       separator: PT.bool,
+      disabled: PT.bool,
       hidden: PT.bool,
     })
   ),
@@ -138,7 +98,7 @@ export default ActionsMenu;
  * @param {Object} props component properties
  * @returns {JSX.Element}
  */
-const Menu = ({ items, onClickOutside, referenceElement, strategy }) => {
+const Menu = ({ close, items, referenceElement, strategy }) => {
   const [popperElement, setPopperElement] = useState(null);
   const [arrowElement, setArrowElement] = useState(null);
   const { styles, attributes } = usePopper(referenceElement, popperElement, {
@@ -180,7 +140,75 @@ const Menu = ({ items, onClickOutside, referenceElement, strategy }) => {
     ],
   });
 
-  useClickOutside(popperElement, onClickOutside, []);
+  const onClickItem = useCallback(
+    (event) => {
+      let targetData = event.target.dataset;
+      let index = +targetData.actionIndex;
+      let item = items[index];
+      if (!item || targetData.disabled || item.separator) {
+        return;
+      }
+      close();
+      item.action?.();
+    },
+    [close, items]
+  );
+
+  useClickOutside(popperElement, close, []);
+
+  const menuItems = useMemo(() => {
+    return items.map((item, index) => {
+      if (item.hidden) {
+        return null;
+      } else if (item.separator) {
+        return <div key={index} className={compStyles.separator} />;
+      } else {
+        let disabled = !!item.disabled;
+        let reasonsDisabled = Array.isArray(item.disabled)
+          ? item.disabled
+          : null;
+        let attrs = {
+          key: index,
+          "data-action-index": index,
+          onClick: onClickItem,
+          role: "button",
+          tabIndex: 0,
+          className: cn(
+            compStyles.item,
+            { [compStyles.itemDisabled]: disabled },
+            item.className
+          ),
+        };
+        if (disabled) {
+          attrs["data-disabled"] = true;
+        }
+        return (
+          <div {...attrs}>
+            {reasonsDisabled ? (
+              <Tooltip
+                content={
+                  reasonsDisabled.length === 1 ? (
+                    reasonsDisabled[0]
+                  ) : (
+                    <ul>
+                      {reasonsDisabled.map((text, index) => (
+                        <li key={index}>{text}</li>
+                      ))}
+                    </ul>
+                  )
+                }
+                strategy="fixed"
+              >
+                {item.label}
+              </Tooltip>
+            ) : (
+              item.label
+            )}
+          </div>
+        );
+      }
+    });
+  }, [items, onClickItem]);
 
   return (
     <div
@@ -189,7 +217,7 @@ const Menu = ({ items, onClickOutside, referenceElement, strategy }) => {
       style={styles.popper}
       {...attributes.popper}
     >
-      <div className={compStyles.items}>{items}</div>
+      <div className={compStyles.items}>{menuItems}</div>
       <div
         ref={setArrowElement}
         style={styles.arrow}
@@ -200,8 +228,17 @@ const Menu = ({ items, onClickOutside, referenceElement, strategy }) => {
 };
 
 Menu.propTypes = {
-  items: PT.array.isRequired,
-  onClickOutside: PT.func.isRequired,
+  close: PT.func.isRequired,
+  items: PT.arrayOf(
+    PT.shape({
+      label: PT.string,
+      action: PT.func,
+      checkDisabled: PT.func,
+      disabled: PT.bool,
+      separator: PT.bool,
+      hidden: PT.bool,
+    })
+  ),
   referenceElement: PT.object,
   strategy: PT.oneOf(["absolute", "fixed"]),
 };
diff --git a/src/components/ActionsMenu/styles.module.scss b/src/components/ActionsMenu/styles.module.scss
index 0346f39..e780ce5 100644
--- a/src/components/ActionsMenu/styles.module.scss
+++ b/src/components/ActionsMenu/styles.module.scss
@@ -71,9 +71,8 @@
 }
 
 .itemDisabled {
-  color: gray;
-  opacity: 0.6;
-  pointer-events: none;
+  color: #bbb;
+  cursor: default;
 }
 
 .hidden {
diff --git a/src/components/CurrencyField/index.jsx b/src/components/CurrencyField/index.jsx
new file mode 100644
index 0000000..eea33c9
--- /dev/null
+++ b/src/components/CurrencyField/index.jsx
@@ -0,0 +1,63 @@
+import React, { useCallback } from "react";
+import PT from "prop-types";
+import TextField from "components/TextField";
+
+/**
+ * Displays text field with optional label.
+ *
+ * @param {Object} props component properties
+ * @returns {JSX.Element}
+ */
+const CurrencyField = (props) => {
+  const { onChange } = props;
+
+  const onChangeValue = useCallback(
+    (value) => {
+      onChange(normalizeValue(value));
+    },
+    [onChange]
+  );
+
+  return <TextField {...props} onChange={onChangeValue} />;
+};
+
+CurrencyField.propTypes = {
+  className: PT.string,
+  error: PT.string,
+  id: PT.string,
+  isDisabled: PT.bool,
+  isTouched: PT.bool,
+  label: PT.string,
+  name: PT.string.isRequired,
+  onBlur: PT.func,
+  onChange: PT.func,
+  onFocus: PT.func,
+  size: PT.oneOf(["small", "medium"]),
+  value: PT.oneOfType([PT.number, PT.string]).isRequired,
+};
+
+export default CurrencyField;
+
+/**
+ * Returns normalized payment amount.
+ *
+ * @param {string} value peyment amount
+ * @returns {string}
+ */
+function normalizeValue(value) {
+  if (!value) {
+    return value;
+  }
+  value = value.trim();
+  let dotIndex = value.lastIndexOf(".");
+  if (isNaN(+value) || dotIndex < 0) {
+    return value;
+  }
+  if (dotIndex === 0) {
+    return "0" + value;
+  }
+  if (value.length - dotIndex > 3) {
+    return value.slice(0, dotIndex + 3);
+  }
+  return value;
+}
diff --git a/src/components/CurrencyField/styles.module.scss b/src/components/CurrencyField/styles.module.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/Page/index.jsx b/src/components/Page/index.jsx
index a9b51b0..bfedb09 100644
--- a/src/components/Page/index.jsx
+++ b/src/components/Page/index.jsx
@@ -15,7 +15,6 @@ import styles from "./styles.module.scss";
  */
 const Page = ({ className, children }) => (
   <div className={cn(styles.container, className)}>
-    {children}
     <ReduxToastr
       timeOut={TOAST_DEFAULT_TIMEOUT}
       position="top-right"
@@ -26,6 +25,7 @@ const Page = ({ className, children }) => (
       transitionIn="fadeIn"
       transitionOut="fadeOut"
     />
+    {children}
   </div>
 );
 
diff --git a/src/components/Page/styles.module.scss b/src/components/Page/styles.module.scss
index 49417bf..5616900 100644
--- a/src/components/Page/styles.module.scss
+++ b/src/components/Page/styles.module.scss
@@ -14,6 +14,7 @@
 
   @include desktop {
     flex-direction: row;
+    flex-wrap: wrap;
   }
 
   *,
diff --git a/src/components/TextField/index.jsx b/src/components/TextField/index.jsx
index 4f968b3..73f0b4c 100644
--- a/src/components/TextField/index.jsx
+++ b/src/components/TextField/index.jsx
@@ -1,6 +1,7 @@
 import React, { useCallback } from "react";
 import PT from "prop-types";
 import cn from "classnames";
+import ValidationError from "components/ValidationError";
 import styles from "./styles.module.scss";
 
 /**
@@ -11,9 +12,12 @@ import styles from "./styles.module.scss";
  */
 const TextField = ({
   className,
+  error,
+  errorClassName,
   id,
+  inputRef,
   isDisabled = false,
-  isValid = true,
+  isTouched = false,
   label,
   name,
   onBlur,
@@ -39,7 +43,7 @@ const TextField = ({
         {
           [styles.hasLabel]: !!label,
           [styles.disabled]: isDisabled,
-          [styles.invalid]: !isValid,
+          [styles.invalid]: !!error,
         },
         className
       )}
@@ -50,21 +54,30 @@ const TextField = ({
         disabled={isDisabled}
         id={id}
         name={name}
-        type="text"
-        value={value}
         onBlur={onBlur}
         onChange={onInputChange}
         onFocus={onFocus}
+        ref={inputRef}
+        type="text"
+        value={value}
       />
+      {isTouched && error && (
+        <ValidationError className={cn(styles.error, errorClassName)}>
+          {error}
+        </ValidationError>
+      )}
     </div>
   );
 };
 
 TextField.propTypes = {
   className: PT.string,
+  error: PT.string,
+  errorClassName: PT.string,
   id: PT.string,
+  inputRef: PT.oneOfType([PT.object, PT.func]),
   isDisabled: PT.bool,
-  isValid: PT.bool,
+  isTouched: PT.bool,
   label: PT.string,
   name: PT.string.isRequired,
   onBlur: PT.func,
diff --git a/src/components/TextField/styles.module.scss b/src/components/TextField/styles.module.scss
index f36534c..107f6e2 100644
--- a/src/components/TextField/styles.module.scss
+++ b/src/components/TextField/styles.module.scss
@@ -38,8 +38,8 @@
   }
 
   &.invalid {
-    input,
-    input:hover {
+    input.input,
+    input.input:hover {
       border-color: $error-color;
       color: $error-text-color;
     }
diff --git a/src/components/Tooltip/styles.module.scss b/src/components/Tooltip/styles.module.scss
index c0d1d6e..4b0a779 100644
--- a/src/components/Tooltip/styles.module.scss
+++ b/src/components/Tooltip/styles.module.scss
@@ -1,3 +1,6 @@
+@import "styles/variables";
+@import "styles/mixins";
+
 .container {
   position: relative;
   display: inline-flex;
@@ -14,8 +17,14 @@
   border-radius: 8px;
   padding: 10px 15px;
   line-height: 22px;
-  box-shadow: 0px 5px 25px #c6c6c6;
+  font-size: $font-size-px;
+  @include roboto-regular;
+  font-weight: normal;
+  letter-spacing: normal;
+  text-transform: none;
+  color: $text-color;
   background: #fff;
+  box-shadow: 0px 5px 25px #c6c6c6;
 
   ul {
     margin: 0;
diff --git a/src/components/ValidationError/styles.module.scss b/src/components/ValidationError/styles.module.scss
index da60411..38da73e 100644
--- a/src/components/ValidationError/styles.module.scss
+++ b/src/components/ValidationError/styles.module.scss
@@ -1,5 +1,5 @@
 .container {
-  margin: 10px 0;
+  margin: 10px 0 0;
   border: 1px solid #ffd5d1;
   padding: 9px 10px;
   min-height: 40px;
diff --git a/src/constants/workPeriods.js b/src/constants/workPeriods.js
index 6c28487..7d0078b 100644
--- a/src/constants/workPeriods.js
+++ b/src/constants/workPeriods.js
@@ -4,6 +4,7 @@ import * as ALERT from "./workPeriods/alerts";
 import * as API_CHALLENGE_PAYMENT_STATUS from "./workPeriods/apiChallengePaymentStatus";
 import * as API_PAYMENT_STATUS from "./workPeriods/apiPaymentStatus";
 import * as API_SORT_BY from "./workPeriods/apiSortBy";
+import * as ERROR_MESSAGE from "./workPeriods/errorMessage";
 import * as SORT_BY from "./workPeriods/sortBy";
 import * as SORT_ORDER from "./workPeriods/sortOrder";
 import * as PAYMENT_STATUS from "./workPeriods/paymentStatus";
@@ -14,6 +15,7 @@ export {
   API_CHALLENGE_PAYMENT_STATUS,
   API_PAYMENT_STATUS,
   API_SORT_BY,
+  ERROR_MESSAGE,
   SORT_BY,
   SORT_ORDER,
   PAYMENT_STATUS,
diff --git a/src/constants/workPeriods/errorMessage.js b/src/constants/workPeriods/errorMessage.js
new file mode 100644
index 0000000..e14e1b0
--- /dev/null
+++ b/src/constants/workPeriods/errorMessage.js
@@ -0,0 +1,2 @@
+export const AMOUNT_OUT_OF_BOUNDS =
+  "Amount should be greater than 0 and less than 100,000.";
diff --git a/src/routes/WorkPeriods/components/PaymentActions/index.jsx b/src/routes/WorkPeriods/components/PaymentActions/index.jsx
index 38742f0..de2a419 100644
--- a/src/routes/WorkPeriods/components/PaymentActions/index.jsx
+++ b/src/routes/WorkPeriods/components/PaymentActions/index.jsx
@@ -34,7 +34,10 @@ const PaymentActions = ({ className, daysPaid, daysWorked, payment }) => {
         action() {
           setIsOpenEditModal(true);
         },
-        disabled: paymentStatus === PAYMENT_STATUS.IN_PROGRESS,
+        disabled:
+          paymentStatus === PAYMENT_STATUS.IN_PROGRESS ||
+          paymentStatus === PAYMENT_STATUS.FAILED ||
+          paymentStatus === PAYMENT_STATUS.CANCELLED,
       },
       {
         label: "Cancel Payment",
diff --git a/src/routes/WorkPeriods/components/PaymentModalAdditional/index.jsx b/src/routes/WorkPeriods/components/PaymentModalAdditional/index.jsx
index 0838110..1920340 100644
--- a/src/routes/WorkPeriods/components/PaymentModalAdditional/index.jsx
+++ b/src/routes/WorkPeriods/components/PaymentModalAdditional/index.jsx
@@ -1,15 +1,15 @@
 import React, { useCallback, useEffect, useState } from "react";
+import { useDispatch } from "react-redux";
 import PT from "prop-types";
 import moment from "moment";
 import debounce from "lodash/debounce";
 import Modal from "components/Modal";
 import Spinner from "components/Spinner";
-import TextField from "components/TextField";
-import ValidationError from "components/ValidationError";
-import { makeToast } from "components/ToastrMessage";
-import { postWorkPeriodPayment } from "services/workPeriods";
+import CurrencyField from "components/CurrencyField";
+import { addWorkPeriodPayment } from "store/thunks/workPeriods";
 import { useUpdateEffect } from "utils/hooks";
 import { preventDefault, validateAmount } from "utils/misc";
+import { ERROR_MESSAGE } from "constants/workPeriods";
 import styles from "./styles.module.scss";
 
 /**
@@ -21,9 +21,10 @@ import styles from "./styles.module.scss";
  */
 const PaymentModalAdditional = ({ period, removeModal }) => {
   const [isModalOpen, setIsModalOpen] = useState(true);
-  const [amount, setAmount] = useState("0");
+  const [amount, setAmount] = useState("");
   const [isAmountValid, setIsAmountValid] = useState(true);
   const [isProcessing, setIsProcessing] = useState(false);
+  const dispatch = useDispatch();
 
   const onApprove = () => {
     let isAmountValid = validateAmount(amount);
@@ -37,10 +38,6 @@ const PaymentModalAdditional = ({ period, removeModal }) => {
     setIsModalOpen(false);
   }, []);
 
-  const onChangeAmount = useCallback((amount) => {
-    setAmount((amount || "").trim());
-  }, []);
-
   const validateAmountDebounced = useCallback(
     debounce(
       (amount) => {
@@ -61,23 +58,19 @@ const PaymentModalAdditional = ({ period, removeModal }) => {
     if (!isProcessing) {
       return;
     }
-    postWorkPeriodPayment({ workPeriodId: period.id, days: 0, amount })
-      .then(() => {
-        makeToast("Additional payment scheduled for resource", "success");
-        setIsModalOpen(false);
-      })
-      .catch((error) => {
-        makeToast(error.toString());
-      })
-      .finally(() => {
-        setIsProcessing(false);
-      });
-  }, [amount, isProcessing, period.id]);
+    (async function () {
+      let ok = await dispatch(
+        addWorkPeriodPayment(period.id, { days: 0, amount })
+      );
+      setIsModalOpen(!ok);
+      setIsProcessing(false);
+    })();
+  }, [amount, isProcessing, period.id, dispatch]);
 
   return (
     <Modal
       approveColor="primary"
-      approveDisabled={!isAmountValid || isProcessing}
+      approveDisabled={!amount || !isAmountValid || isProcessing}
       approveText="Process Payment"
       dismissText="Cancel"
       title="Additional Payment"
@@ -94,23 +87,19 @@ const PaymentModalAdditional = ({ period, removeModal }) => {
         <>
           <div className={styles.description}>
             Additional payment for Resource Booking &quot;{period.userHandle}
-            &quot; for week &quot;{moment(period.start).format("MM/DD")}
+            &quot; for the week &quot;{moment(period.start).format("MM/DD")}
             &nbsp;-&nbsp;{moment(period.end).format("MM/DD")}&quot;
           </div>
           <form className={styles.form} action="#" onSubmit={preventDefault}>
-            <TextField
+            <CurrencyField
               className={styles.amountField}
-              isValid={isAmountValid}
+              error={isAmountValid ? null : ERROR_MESSAGE.AMOUNT_OUT_OF_BOUNDS}
+              isTouched={true}
               label="Amount ($)"
               name={`payment_amount_${period.id}`}
+              onChange={setAmount}
               value={amount}
-              onChange={onChangeAmount}
             />
-            {!isAmountValid && (
-              <ValidationError className={styles.amountError}>
-                Amount should be greater than 0 and less than 100,000.
-              </ValidationError>
-            )}
           </form>
         </>
       )}
diff --git a/src/routes/WorkPeriods/components/PaymentModalEdit/index.jsx b/src/routes/WorkPeriods/components/PaymentModalEdit/index.jsx
index 6c93731..f2a2c4b 100644
--- a/src/routes/WorkPeriods/components/PaymentModalEdit/index.jsx
+++ b/src/routes/WorkPeriods/components/PaymentModalEdit/index.jsx
@@ -1,11 +1,11 @@
 import React, { useCallback, useEffect, useState } from "react";
+import { useDispatch } from "react-redux";
 import PT from "prop-types";
 import IntegerFieldHinted from "components/IntegerFieldHinted";
 import Modal from "components/Modal";
 import Spinner from "components/Spinner";
 import TextField from "components/TextField";
-import { makeToast } from "components/ToastrMessage";
-import { patchWorkPeriodPayment } from "services/workPeriods";
+import { updateWorkPeriodPayment } from "store/thunks/workPeriods";
 import { currencyFormatter } from "utils/formatters";
 import { preventDefault } from "utils/misc";
 import { CHALLENGE_PAYMENT_ACTIVE_STATUSES } from "constants/workPeriods";
@@ -22,6 +22,10 @@ const PaymentModalEdit = ({ daysPaid, daysWorked, payment, removeModal }) => {
   const [isModalOpen, setIsModalOpen] = useState(true);
   const [isProcessing, setIsProcessing] = useState(false);
   const [days, setDays] = useState(payment.days);
+  const dispatch = useDispatch();
+
+  const isChanged = days !== payment.days;
+  const { id: paymentId, workPeriodId: periodId } = payment;
 
   const maxDays =
     daysWorked -
@@ -41,27 +45,27 @@ const PaymentModalEdit = ({ daysPaid, daysWorked, payment, removeModal }) => {
     setIsModalOpen(false);
   }, []);
 
+  const onChangeDays = useCallback((days) => {
+    setDays(days);
+  }, []);
+
   useEffect(() => {
     if (!isProcessing) {
       return;
     }
-    patchWorkPeriodPayment(payment.id, { amount, days })
-      .then(() => {
-        makeToast("Payment was successfully updated", "success");
-        setIsModalOpen(false);
-      })
-      .catch((error) => {
-        makeToast(error.toString());
-      })
-      .finally(() => {
-        setIsProcessing(false);
-      });
-  }, [amount, days, isProcessing, payment.id]);
+    (async function () {
+      let ok = await dispatch(
+        updateWorkPeriodPayment(periodId, paymentId, { amount, days })
+      );
+      setIsModalOpen(!ok);
+      setIsProcessing(false);
+    })();
+  }, [amount, days, isProcessing, paymentId, periodId, dispatch]);
 
   return (
     <Modal
       approveColor="primary"
-      approveDisabled={isProcessing}
+      approveDisabled={!isChanged || isProcessing}
       approveText="Update"
       title="Edit Payment"
       controls={isProcessing ? null : undefined}
@@ -102,7 +106,7 @@ const PaymentModalEdit = ({ daysPaid, daysWorked, payment, removeModal }) => {
                 <td>
                   <IntegerFieldHinted
                     name="day_cnt"
-                    onChange={setDays}
+                    onChange={onChangeDays}
                     maxValue={maxDays}
                     minValue={1}
                     maxValueMessage="Cannot pay for more days than the user has worked for"
@@ -131,6 +135,7 @@ PaymentModalEdit.propTypes = {
     id: PT.string.isRequired,
     memberRate: PT.number.isRequired,
     status: PT.string.isRequired,
+    workPeriodId: PT.string.isRequired,
   }),
   removeModal: PT.func.isRequired,
 };
diff --git a/src/routes/WorkPeriods/components/PaymentModalEditAdditional/index.jsx b/src/routes/WorkPeriods/components/PaymentModalEditAdditional/index.jsx
index dca47d6..761fcc8 100644
--- a/src/routes/WorkPeriods/components/PaymentModalEditAdditional/index.jsx
+++ b/src/routes/WorkPeriods/components/PaymentModalEditAdditional/index.jsx
@@ -1,14 +1,14 @@
 import React, { useCallback, useEffect, useState } from "react";
+import { useDispatch } from "react-redux";
 import PT from "prop-types";
 import debounce from "lodash/debounce";
 import Modal from "components/Modal";
 import Spinner from "components/Spinner";
-import TextField from "components/TextField";
-import ValidationError from "components/ValidationError";
-import { makeToast } from "components/ToastrMessage";
-import { patchWorkPeriodPayment } from "services/workPeriods";
+import CurrencyField from "components/CurrencyField";
+import { updateWorkPeriodPayment } from "store/thunks/workPeriods";
 import { useUpdateEffect } from "utils/hooks";
 import { preventDefault, validateAmount } from "utils/misc";
+import { ERROR_MESSAGE } from "constants/workPeriods";
 import styles from "./styles.module.scss";
 
 /**
@@ -18,12 +18,16 @@ import styles from "./styles.module.scss";
  * @returns {JSX.Element}
  */
 const PaymentModalEditAdditional = ({ payment, removeModal }) => {
+  const paymentAmount = payment.amount + "";
   const [isModalOpen, setIsModalOpen] = useState(true);
-  const [amount, setAmount] = useState(payment.amount);
+  const [amount, setAmount] = useState(paymentAmount);
   const [isAmountValid, setIsAmountValid] = useState(true);
   const [isProcessing, setIsProcessing] = useState(false);
+  const dispatch = useDispatch();
 
-  const amountControlId = `edit_pmt_amt_${payment.id}`;
+  const isChanged = amount !== paymentAmount;
+  const { id: paymentId, workPeriodId: periodId } = payment;
+  const amountControlId = `edit_pmt_amt_${paymentId}`;
 
   const onApprove = () => {
     let isAmountValid = validateAmount(amount);
@@ -37,8 +41,8 @@ const PaymentModalEditAdditional = ({ payment, removeModal }) => {
     setIsModalOpen(false);
   }, []);
 
-  const onAmountChange = useCallback((amount) => {
-    setAmount((amount || "").trim());
+  const onChangeAmount = useCallback((amount) => {
+    setAmount(amount);
   }, []);
 
   const validateAmountDebounced = useCallback(
@@ -61,26 +65,23 @@ const PaymentModalEditAdditional = ({ payment, removeModal }) => {
     if (!isProcessing) {
       return;
     }
-    patchWorkPeriodPayment(payment.id, { amount })
-      .then(() => {
-        makeToast("Payment was successfully updated", "success");
-        setIsModalOpen(false);
-      })
-      .catch((error) => {
-        makeToast(error.toString());
-      })
-      .finally(() => {
-        setIsProcessing(false);
-      });
-  }, [amount, isProcessing, payment.id]);
+    (async function () {
+      let ok = await dispatch(
+        updateWorkPeriodPayment(periodId, paymentId, { amount })
+      );
+      setIsModalOpen(!ok);
+      setIsProcessing(false);
+    })();
+  }, [amount, isProcessing, paymentId, periodId, dispatch]);
 
   return (
     <Modal
       approveColor="primary"
-      approveDisabled={!isAmountValid || isProcessing}
+      approveDisabled={!isChanged || !isAmountValid || isProcessing}
       approveText="Update"
       title="Edit Additional Payment"
       controls={isProcessing ? null : undefined}
+      isDisabled={isProcessing}
       isOpen={isModalOpen}
       onApprove={onApprove}
       onClose={removeModal}
@@ -96,18 +97,16 @@ const PaymentModalEditAdditional = ({ payment, removeModal }) => {
                 <label htmlFor={amountControlId}>Amount:</label>
               </div>
               <div className={styles.fieldControl}>
-                <TextField
+                <CurrencyField
+                  error={
+                    isAmountValid ? null : ERROR_MESSAGE.AMOUNT_OUT_OF_BOUNDS
+                  }
                   id={amountControlId}
-                  isValid={isAmountValid}
+                  isTouched={isChanged}
                   name="edit_payment_amount"
-                  onChange={onAmountChange}
+                  onChange={onChangeAmount}
                   value={amount}
                 />
-                {!isAmountValid && (
-                  <ValidationError>
-                    Amount should be greater than 0 and less than 100,000.
-                  </ValidationError>
-                )}
               </div>
             </div>
           </form>
@@ -124,6 +123,7 @@ PaymentModalEditAdditional.propTypes = {
   payment: PT.shape({
     amount: PT.number.isRequired,
     id: PT.string.isRequired,
+    workPeriodId: PT.string.isRequired,
   }).isRequired,
   removeModal: PT.func.isRequired,
 };
diff --git a/src/routes/WorkPeriods/components/PeriodActions/index.jsx b/src/routes/WorkPeriods/components/PeriodActions/index.jsx
index b531657..9d3ba73 100644
--- a/src/routes/WorkPeriods/components/PeriodActions/index.jsx
+++ b/src/routes/WorkPeriods/components/PeriodActions/index.jsx
@@ -1,9 +1,14 @@
 import React, { useCallback, useMemo, useState } from "react";
 import PT from "prop-types";
 import cn from "classnames";
+import moment from "moment";
 import ActionsMenu from "components/ActionsMenu";
 import PaymentModalAdditional from "../PaymentModalAdditional";
 import PaymentModalUpdateBA from "../PaymentModalUpdateBA";
+import {
+  REASON_DISABLED,
+  REASON_DISABLED_MESSAGE_MAP,
+} from "constants/workPeriods";
 import styles from "./styles.module.scss";
 
 /**
@@ -32,6 +37,7 @@ const PeriodActions = ({ className, period, periodData }) => {
         action() {
           setIsOpenAddPaymentModal(true);
         },
+        disabled: checkDisabled(period),
       },
     ];
     if (payments?.length) {
@@ -40,10 +46,11 @@ const PeriodActions = ({ className, period, periodData }) => {
         action() {
           setIsOpenUpdateBAModal(true);
         },
+        disabled: false,
       });
     }
     return actions;
-  }, [payments]);
+  }, [period, payments]);
 
   return (
     <div className={cn(styles.container, className)}>
@@ -73,6 +80,7 @@ PeriodActions.propTypes = {
   className: PT.string,
   period: PT.shape({
     id: PT.string.isRequired,
+    billingAccountId: PT.number,
     start: PT.oneOfType([PT.number, PT.string]).isRequired,
     end: PT.oneOfType([PT.number, PT.string]).isRequired,
   }).isRequired,
@@ -82,3 +90,18 @@ PeriodActions.propTypes = {
 };
 
 export default PeriodActions;
+
+function checkDisabled(period) {
+  let reasonsDisabled = [];
+  if (moment(period.start).isAfter(Date.now())) {
+    reasonsDisabled.push(
+      REASON_DISABLED_MESSAGE_MAP[REASON_DISABLED.NOT_ALLOW_FUTURE_WEEK]
+    );
+  }
+  if (!period.billingAccountId) {
+    reasonsDisabled.push(
+      REASON_DISABLED_MESSAGE_MAP[REASON_DISABLED.NO_BILLING_ACCOUNT]
+    );
+  }
+  return reasonsDisabled.length ? reasonsDisabled : false;
+}
diff --git a/src/store/reducers/workPeriods.js b/src/store/reducers/workPeriods.js
index 13da1d7..b4312e4 100644
--- a/src/store/reducers/workPeriods.js
+++ b/src/store/reducers/workPeriods.js
@@ -133,12 +133,8 @@ const actionHandlers = {
     const dateRange = state.filters.dateRange;
     const periodStart = dateRange[0];
     const periodEnd = dateRange[1];
-    const periodStartValue = periodStart.valueOf();
-    const periodEndValue = periodEnd.valueOf();
     for (let period of periods) {
       periodsById[period.id] = true;
-      period.start = periodStartValue;
-      period.end = periodEndValue;
       let periodData = initPeriodData(period);
       let daysWorkedMax = computeDaysWorkedMax(
         period.bookingStart,
diff --git a/src/store/thunks/workPeriods.js b/src/store/thunks/workPeriods.js
index fc5f51d..4f848d2 100644
--- a/src/store/thunks/workPeriods.js
+++ b/src/store/thunks/workPeriods.js
@@ -36,6 +36,53 @@ import {
 import { RESOURCE_BOOKING_STATUS, WORK_PERIODS_PATH } from "constants/index.js";
 import { currencyFormatter } from "utils/formatters";
 
+/**
+ * A thunk that adds working period's payment and reloads working period data
+ * after some delay.
+ *
+ * @param {string} workPeriodId working period id
+ * @param {Object} data payment data
+ * @param {string|number} data.amount payment amount
+ * @param {number} data.days number of days for payment
+ * @param {string} [data.workPeriodId] working period id
+ * @param {number} [periodUpdateDelay] update delay for period data
+ * @returns {function}
+ */
+export const addWorkPeriodPayment =
+  (workPeriodId, data, periodUpdateDelay = SERVER_DATA_UPDATE_DELAY) =>
+  async (dispatch) => {
+    let errorMessage = null;
+    try {
+      let paymentData = await services.postWorkPeriodPayment({
+        ...data,
+        workPeriodId,
+      });
+      if ("error" in paymentData) {
+        errorMessage = paymentData.error.message;
+      }
+    } catch (error) {
+      errorMessage = error.toString();
+    }
+    if (errorMessage) {
+      makeToast(errorMessage);
+      return false;
+    }
+    [, errorMessage] = await dispatch(
+      loadWorkPeriodData(workPeriodId, periodUpdateDelay)
+    );
+    if (errorMessage) {
+      makeToast(
+        "Additional payment scheduled for resource " +
+          "but working period data was not reloaded.\n" +
+          errorMessage,
+        "warning"
+      );
+    } else {
+      makeToast("Additional payment scheduled for resource", "success");
+    }
+    return true;
+  };
+
 /**
  * A thunk that cancels specific working period payment, reloads WP data
  * and updates store's state after certain delay.
@@ -66,7 +113,12 @@ export const cancelWorkPeriodPayment =
       loadWorkPeriodData(periodId, periodUpdateDelay)
     );
     if (errorMessage) {
-      makeToast("Failed to reload working period data. " + errorMessage);
+      makeToast(
+        `Payment ${paymentData.amount} was marked as "cancelled" ` +
+          "but working period data wos not reloaded.\n" +
+          errorMessage,
+        "warning"
+      );
     } else if (periodData) {
       let userHandle = periodData.userHandle;
       let amount = null;
@@ -289,6 +341,50 @@ export const toggleWorkPeriodDetails =
     }
   };
 
+/**
+ * A thunk that updates working period's payment and reloads working period data
+ * after some delay.
+ *
+ * @param {string} periodId working period id
+ * @param {string} paymentId working period payment id
+ * @param {Object} data payment data
+ * @param {string|number} data.amount payment amount
+ * @param {number} [data.days] number of days for payment
+ * @param {number} [periodUpdateDelay] update delay for period data
+ * @returns {function}
+ */
+export const updateWorkPeriodPayment =
+  (periodId, paymentId, data, periodUpdateDelay = SERVER_DATA_UPDATE_DELAY) =>
+  async (dispatch) => {
+    let paymentData = null;
+    let errorMessage = null;
+    try {
+      paymentData = await services.patchWorkPeriodPayment(paymentId, data);
+      paymentData = normalizePaymentData(paymentData);
+    } catch (error) {
+      errorMessage = error.toString();
+    }
+    if (errorMessage) {
+      makeToast(errorMessage);
+      return false;
+    }
+    dispatch(actions.setWorkPeriodPaymentData(paymentData));
+    [, errorMessage] = await dispatch(
+      loadWorkPeriodData(periodId, periodUpdateDelay)
+    );
+    if (errorMessage) {
+      makeToast(
+        "Payment was successfully updated " +
+          "but working period data was not reloaded.\n" +
+          errorMessage,
+        "warning"
+      );
+    } else {
+      makeToast("Payment was successfully updated", "success");
+    }
+    return true;
+  };
+
 /**
  * A thunk that updates the billing accounts for all the payments from the
  * specific working period.
diff --git a/src/styles/toastr.scss b/src/styles/toastr.scss
index c707bbb..3589b5c 100644
--- a/src/styles/toastr.scss
+++ b/src/styles/toastr.scss
@@ -2,44 +2,45 @@
 @import "variables";
 
 .redux-toastr {
-  position: absolute;
+  flex: 0 0 auto;
+  z-index: 10000;
+  position: sticky;
   left: 0;
-  top: 0;
+  top: -4px;
   right: 0;
   margin: 0;
   border: none;
   padding: 0;
-  height: auto;
+  width: 100%;
+  height: 0;
   background: transparent;
+  overflow: visible;
 
   @include desktop {
-    left: $sidebar-width;
+    padding-left: $sidebar-width;
   }
 
   > div {
-    position: absolute;
-    left: 10px;
-    top: 24px;
-    right: 10px;
+    position: relative;
     margin: 0;
     border: none;
     padding: 0;
     height: auto;
     background: transparent;
+  }
+
+  .top-right {
+    z-index: 1000;
+    position: absolute;
+    left: 10px;
+    top: 24px;
+    right: 10px;
 
     @include desktop {
       left: 22px;
       top: 24px;
       right: 14px;
     }
-  }
-
-  .top-right {
-    z-index: 1000;
-    position: absolute;
-    left: 0;
-    top: 0;
-    right: 0;
 
     > div {
       margin-top: 10px;
diff --git a/src/utils/hooks.js b/src/utils/hooks.js
index bf25bac..0ccfc4c 100644
--- a/src/utils/hooks.js
+++ b/src/utils/hooks.js
@@ -50,3 +50,19 @@ export const useUpdateEffect = (effect, deps) => {
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, deps);
 };
+
+/**
+ * A hook that returns previously saved value before component updated.
+ *
+ * @param {*} value value to save
+ * @returns {*}
+ */
+export const usePrevious = (value) => {
+  const ref = useRef();
+
+  useEffect(() => {
+    ref.current = value;
+  });
+
+  return ref.current;
+};
diff --git a/src/utils/misc.js b/src/utils/misc.js
index cc49429..d421899 100644
--- a/src/utils/misc.js
+++ b/src/utils/misc.js
@@ -243,13 +243,5 @@ export const hoursToHumanReadableTime = (timeHrs) => {
  */
 export function validateAmount(value) {
   let amount = +value;
-  let valueStr = value + "";
-  return (
-    !isNaN(amount) &&
-    (amount.toFixed(0) === valueStr ||
-      amount.toFixed(1) === valueStr ||
-      amount.toFixed(2) === valueStr) &&
-    amount > 0 &&
-    amount < 1e5
-  );
+  return !isNaN(amount) && amount > 0 && amount < 1e5 && !value.endsWith(".");
 }
diff --git a/src/utils/workPeriods.js b/src/utils/workPeriods.js
index 7743cbd..bc1e3dc 100644
--- a/src/utils/workPeriods.js
+++ b/src/utils/workPeriods.js
@@ -168,6 +168,8 @@ export function normalizePeriodItems(items) {
       bookingEnd: item.endDate
         ? moment(item.endDate).format(DATE_FORMAT_ISO)
         : "",
+      start: workPeriod.startDate,
+      end: workPeriod.endDate,
       weeklyRate: item.memberRate,
       data: normalizePeriodData(workPeriod),
     });