From 75fbcbda9b17e96a43b5be153050cc89d3598516 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 16 Aug 2023 13:09:55 +0200
Subject: [PATCH 001/118] add routes

---
 src/ROUTES.js                        |  6 ++++++
 src/libs/Navigation/linkingConfig.js | 15 +++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/src/ROUTES.js b/src/ROUTES.js
index 6c0365e40568..0427a5fdce2e 100644
--- a/src/ROUTES.js
+++ b/src/ROUTES.js
@@ -14,6 +14,9 @@ const SETTINGS_PERSONAL_DETAILS = 'settings/profile/personal-details';
 const SETTINGS_CONTACT_METHODS = 'settings/profile/contact-methods';
 const SETTINGS_STATUS = 'settings/profile/status';
 const SETTINGS_STATUS_SET = 'settings/profile/status/set';
+const SETTINGS_STATUS_CLEAR_AFTER = 'settings/profile/status/clear-after';
+const SETTINGS_STATUS_CLEAR_AFTER_CUSTOM = 'settings/profile/status/clear-after/custom';
+const SETTINGS_STATUS_CLEAR_AFTER_TIME = 'settings/profile/status/clear-after/time';
 
 export default {
     BANK_ACCOUNT: 'bank-account',
@@ -62,6 +65,9 @@ export default {
     SETTINGS_2FA_SUCCESS: 'settings/security/two-factor-auth/success',
     SETTINGS_STATUS,
     SETTINGS_STATUS_SET,
+    SETTINGS_STATUS_CLEAR_AFTER,
+    SETTINGS_STATUS_CLEAR_AFTER_CUSTOM,
+    SETTINGS_STATUS_CLEAR_AFTER_TIME,
     NEW_GROUP: 'new/group',
     NEW_CHAT: 'new/chat',
     NEW_TASK,
diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js
index dcc4f77fde73..b7f42470870d 100644
--- a/src/libs/Navigation/linkingConfig.js
+++ b/src/libs/Navigation/linkingConfig.js
@@ -184,6 +184,21 @@ export default {
                                 path: ROUTES.SETTINGS_STATUS_SET,
                                 exact: true,
                             },
+                            Settings_Status_Clear_After: {
+                                path: ROUTES.SETTINGS_STATUS_CLEAR_AFTER,
+                            },
+                            Settings_Status_Clear_After_Custom: {
+                                path: ROUTES.SETTINGS_STATUS_CLEAR_AFTER_CUSTOM,
+                            },
+                            Settings_Status_Clear_After_Time: {
+                                path: ROUTES.SETTINGS_STATUS_CLEAR_AFTER_TIME,
+                            },
+                            Settings_Status_SetTime: {
+                                path: ROUTES.SETTINGS_STATUS_SET_TIME,
+                            },
+                            Settings_Status_SetData: {
+                                path: ROUTES.SETTINGS_STATUS_SET_DATE,
+                            },
                             Workspace_Initial: {
                                 path: ROUTES.WORKSPACE_INITIAL,
                             },

From cd8dd15f404a42e705f1ae2ebfa5ac40e2c9c160 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 16 Aug 2023 13:11:34 +0200
Subject: [PATCH 002/118] add disableIsFocusStyle feature to
 BaseSelectionListRadio

---
 .../SelectionListRadio/BaseSelectionListRadio.js      |  1 +
 src/components/SelectionListRadio/RadioListItem.js    | 11 ++++++++---
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/components/SelectionListRadio/BaseSelectionListRadio.js b/src/components/SelectionListRadio/BaseSelectionListRadio.js
index 4daacb184ea1..e9e832f05664 100644
--- a/src/components/SelectionListRadio/BaseSelectionListRadio.js
+++ b/src/components/SelectionListRadio/BaseSelectionListRadio.js
@@ -165,6 +165,7 @@ function BaseSelectionListRadio(props) {
                 item={item}
                 isFocused={isFocused}
                 onSelectRow={props.onSelectRow}
+                disableIsFocusStyle={props.disableInitialFocusOptionStyle}
             />
         );
     };
diff --git a/src/components/SelectionListRadio/RadioListItem.js b/src/components/SelectionListRadio/RadioListItem.js
index c5c4b3aeaf2c..d15a78cb9ed3 100644
--- a/src/components/SelectionListRadio/RadioListItem.js
+++ b/src/components/SelectionListRadio/RadioListItem.js
@@ -18,15 +18,20 @@ const propTypes = {
 
     /** Callback to fire when the item is pressed */
     onSelectRow: PropTypes.func,
+
+    /** Whether to disable the isFocused style */
+    disableIsFocusStyle: PropTypes.bool,
 };
 
 const defaultProps = {
     item: {},
     isFocused: false,
     onSelectRow: () => {},
+    disableIsFocusStyle: false,
 };
 
 function RadioListItem(props) {
+  const isFocused = !props.disableIsFocusStyle && props.isFocused
     return (
         <PressableWithFeedback
             onPress={() => props.onSelectRow(props.item)}
@@ -36,14 +41,14 @@ function RadioListItem(props) {
             hoverStyle={styles.hoveredComponentBG}
             focusStyle={styles.hoveredComponentBG}
         >
-            <View style={[styles.flex1, styles.justifyContentBetween, styles.sidebarLinkInner, styles.optionRow, props.isFocused && styles.sidebarLinkActive]}>
+            <View style={[styles.flex1, styles.justifyContentBetween, styles.sidebarLinkInner, styles.optionRow, isFocused && styles.sidebarLinkActive]}>
                 <View style={[styles.flex1, styles.alignItemsStart]}>
-                    <Text style={[styles.optionDisplayName, props.isFocused ? styles.sidebarLinkActiveText : styles.sidebarLinkText, props.item.isSelected && styles.sidebarLinkTextBold]}>
+                    <Text style={[styles.optionDisplayName, isFocused ? styles.sidebarLinkActiveText : styles.sidebarLinkText, props.item.isSelected && styles.sidebarLinkTextBold]}>
                         {props.item.text}
                     </Text>
 
                     {Boolean(props.item.alternateText) && (
-                        <Text style={[props.isFocused ? styles.sidebarLinkActiveText : styles.sidebarLinkText, styles.optionAlternateText, styles.textLabelSupporting]}>
+                        <Text style={[isFocused ? styles.sidebarLinkActiveText : styles.sidebarLinkText, styles.optionAlternateText, styles.textLabelSupporting]}>
                             {props.item.alternateText}
                         </Text>
                     )}

From 3ecbaaf93889a19406abe7d5d8d7c7daaf818a27 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 16 Aug 2023 13:13:05 +0200
Subject: [PATCH 003/118] add translations

---
 src/languages/en.js | 8 ++++++++
 src/languages/es.js | 8 ++++++++
 2 files changed, 16 insertions(+)

diff --git a/src/languages/en.js b/src/languages/en.js
index 09651e6ec05e..7e787be1913c 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -874,6 +874,14 @@ export default {
         clearStatus: 'Clear status',
         save: 'Save',
         message: 'Message',
+        timePeriods: {
+          never: 'Never',
+          thirtyMinutes: 'Thirty minutes',
+          oneHour: 'One hour',
+          afterToday: 'After today',
+          afterWeek: 'After week',
+          custom: 'Custom',
+        }
     },
     stepCounter: ({step, total, text}) => {
         let result = `Step ${step}`;
diff --git a/src/languages/es.js b/src/languages/es.js
index fa920c84ce35..c67a91897db7 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -878,6 +878,14 @@ export default {
         clearStatus: 'Borrar estado',
         save: 'Guardar',
         message: 'Mensaje',
+        timePeriods: {
+            never: 'Nunca',
+            thirtyMinutes: 'Treinta minutos',
+            oneHour: 'Una hora',
+            afterToday: 'Después de hoy',
+            afterWeek: 'Después de una semana',
+            custom: 'Personalizado',
+        },
     },
     stepCounter: ({step, total, text}) => {
         let result = `Paso ${step}`;

From 244147e147f86d28bf73a7f706ad393d79f3248c Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 16 Aug 2023 13:15:42 +0200
Subject: [PATCH 004/118] extend dateUtils

---
 src/libs/DateUtils.js | 90 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index 6be627dc643d..aaa9f41310dd 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -205,6 +205,87 @@ function getDateStringFromISOTimestamp(isoTimestamp) {
     return dateString;
 }
 
+/**
+ * @returns {string} example: 2023-05-16
+ */
+function getThirtyMinutesFromNow() {
+    return moment().add(30, 'minutes').format('YYYY-MM-DD HH:mm:ss');
+}
+
+function getOneHourFromNow() {
+    return moment().add(1, 'hours').format('YYYY-MM-DD HH:mm:ss');
+}
+
+/**
+ * @returns {string} example: 2023-05-16
+ */
+function getEndOfToday() {
+    return moment().endOf('day').format('YYYY-MM-DD HH:mm:ss');
+}
+
+/**
+ * @returns {string} example: 2023-05-16
+ */
+function getEndOfWeekFromNow() {
+    return moment().add(7, 'days').format('YYYY-MM-DD HH:mm:ss');
+}
+
+/**
+ * @returns {string} example: 2023-05-16
+ * it's kind of 'newer' date
+ */
+function getOneHundredYearsFromNow() {
+    return moment().endOf(100, 'years').format('YYYY-MM-DD HH:mm:ss');
+}
+
+/**
+ * @param {string} time
+ * @returns {string} example: 2023-05-16
+ * it's kind of 'newer' date
+ */
+function extractDate(time) {
+    return moment(time).format('YYYY-MM-DD');
+}
+
+/**
+ * @param {string} dateTimeString
+ * @returns {string} example: 2023-05-16
+ * it's kind of 'newer' date
+ */
+function extractTime(dateTimeString) {
+    return moment(dateTimeString).format('HH:mm');
+}
+
+/**
+ * @param {string} dateTimeString
+ * @returns {string} example: 2023-05-16
+ * it's kind of 'newer' date
+ */
+function formatDateTo12Hour(dateTimeString) {
+    if (!dateTimeString) return '';
+    return moment(dateTimeString).format('YYYY-MM-DD hh:mm:ss A');
+}
+
+// /**
+//  * @returns {string} example: 2023-05-16
+//  */
+function getDateBasedFromType(type) {
+    switch (type) {
+        case CONST.CUSTOM_STATUS_TYPES.THIRTY_MINUTES:
+            return getThirtyMinutesFromNow();
+        case CONST.CUSTOM_STATUS_TYPES.ONE_HOUR:
+            return getOneHourFromNow();
+        case CONST.CUSTOM_STATUS_TYPES.AFTER_TODAY:
+            return getEndOfToday();
+        case CONST.CUSTOM_STATUS_TYPES.AFTER_WEEK:
+            return getEndOfWeekFromNow();
+        case CONST.CUSTOM_STATUS_TYPES.NEVER:
+            return getOneHundredYearsFromNow();
+        default:
+            return '';
+    }
+}
+
 /**
  * @namespace DateUtils
  */
@@ -220,6 +301,15 @@ const DateUtils = {
     getDBTime,
     subtractMillisecondsFromDateTime,
     getDateStringFromISOTimestamp,
+    getThirtyMinutesFromNow,
+    getEndOfToday,
+    getEndOfWeekFromNow,
+    getOneHundredYearsFromNow,
+    getDateBasedFromType,
+    getOneHourFromNow,
+    extractDate,
+    extractTime,
+    formatDateTo12Hour,
 };
 
 export default DateUtils;

From b6125582777998b043b518789789ba179ed9168a Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 16 Aug 2023 13:17:27 +0200
Subject: [PATCH 005/118] add new field for draftCustomStatus in Onyx

---
 src/libs/actions/FormActions.js | 10 +++++++++-
 src/libs/actions/User.js        |  2 +-
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/libs/actions/FormActions.js b/src/libs/actions/FormActions.js
index 2a4e1dbd5d27..9372e32fd733 100644
--- a/src/libs/actions/FormActions.js
+++ b/src/libs/actions/FormActions.js
@@ -32,4 +32,12 @@ function setDraftValues(formID, draftValues) {
     Onyx.merge(`${formID}Draft`, draftValues);
 }
 
-export {setIsLoading, setErrors, setErrorFields, setDraftValues};
+/**
+ * @param {String} formID
+ * @param {Object} draftValues
+ */
+function cleanDraftValues(formID) {
+    Onyx.merge(`${formID}Draft`, null);
+}
+
+export {setIsLoading, setErrors, setErrorFields, setDraftValues, cleanDraftValues};
diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js
index 7f7078c45379..6bd0583d8d05 100644
--- a/src/libs/actions/User.js
+++ b/src/libs/actions/User.js
@@ -876,7 +876,7 @@ function updateDraftCustomStatus(status) {
  *
  */
 function clearDraftCustomStatus() {
-    Onyx.merge(ONYXKEYS.CUSTOM_STATUS_DRAFT, {text: '', emojiCode: '', clearAfter: ''});
+    Onyx.merge(ONYXKEYS.CUSTOM_STATUS_DRAFT, {text: '', emojiCode: '', clearAfter: '', customDateTemporary: ''});
 }
 
 export {

From f774e8e68f2ab9b31aaa8c337b6bc363fb7c5adc Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 16 Aug 2023 13:18:12 +0200
Subject: [PATCH 006/118] use proper data for title on StatusPage

---
 .../settings/Profile/CustomStatus/StatusPage.js | 17 ++++++++++++++---
 src/styles/styles.js                            | 12 +++++++++++-
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index c239f9e45f2d..ec189e2bbc59 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -20,6 +20,7 @@ import styles from '../../../../styles/styles';
 import compose from '../../../../libs/compose';
 import ONYXKEYS from '../../../../ONYXKEYS';
 import ROUTES from '../../../../ROUTES';
+import DateUtils from '../../../../libs/DateUtils';
 
 const propTypes = {
     ...withCurrentUserPersonalDetailsPropTypes,
@@ -31,16 +32,20 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
     const currentUserStatusText = lodashGet(currentUserPersonalDetails, 'status.text', '');
     const draftEmojiCode = lodashGet(draftStatus, 'emojiCode');
     const draftText = lodashGet(draftStatus, 'text');
+    const draftClearAfter = lodashGet(draftStatus, 'clearAfter');
 
     const defaultEmoji = draftEmojiCode || currentUserEmojiCode;
     const defaultText = draftEmojiCode ? draftText : currentUserStatusText;
     const customStatus = draftEmojiCode ? `${draftEmojiCode} ${draftText}` : `${currentUserEmojiCode || ''} ${currentUserStatusText || ''}`;
+    
     const hasDraftStatus = !!draftEmojiCode || !!draftText;
+    const formattedClearAfter = DateUtils.formatDateTo12Hour(lodashGet(currentUserPersonalDetails, 'status.clearAfter', ''));
+    const formattedClearAfterDraft = DateUtils.formatDateTo12Hour(draftClearAfter);
+    const customClearAfter = draftClearAfter ? formattedClearAfterDraft : formattedClearAfter ||'';
 
     const updateStatus = useCallback(() => {
-        const endOfDay = moment().endOf('day').toDate();
-        User.updateCustomStatus({text: defaultText, emojiCode: defaultEmoji, clearAfter: endOfDay.toISOString()});
-
+        const endOfDay = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss');
+        User.updateCustomStatus({text: defaultText, emojiCode: defaultEmoji, clearAfter: endOfDay});
         User.clearDraftCustomStatus();
         Navigation.goBack(ROUTES.SETTINGS_PROFILE);
     }, [defaultText, defaultEmoji]);
@@ -83,6 +88,12 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                 inputID="test"
                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_SET)}
             />
+            <MenuItemWithTopDescription
+                title={customClearAfter}
+                description="Clear after"
+                shouldShowRightIcon
+                onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
+            />
 
             {(!!currentUserEmojiCode || !!currentUserStatusText) && (
                 <MenuItem
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 581410e0e5a5..e4580e7900ea 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3642,7 +3642,17 @@ const styles = {
     willChangeTransform: {
         willChange: 'transform',
     },
-
+    statusClearAfter: {
+        flexDirection: 'row',
+        justifyContent: 'space-between',
+        width: '100%',
+        paddingHorizontal: 20,
+    },
+    statusClearAfterContent: {
+        borderBottomWidth: 1,
+        borderColor: themeColors.border,
+        paddingVertical: 12,
+    },
     emojiPickerButtonDropdown: {
         justifyContent: 'center',
         backgroundColor: themeColors.activeComponentBG,

From 5f5233a03278f1297e239e3c08a35f5e936c570d Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 16 Aug 2023 14:43:59 +0200
Subject: [PATCH 007/118] WIP StatusClearAfterPage

---
 src/ONYXKEYS.js                               |   1 +
 .../AppNavigator/ModalStackNavigators.js      |   7 +
 .../CustomStatus/StatusClearAfterPage.js      | 145 ++++++++++++++++++
 3 files changed, 153 insertions(+)
 create mode 100644 src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js

diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js
index a99a09063561..a7b148212ece 100755
--- a/src/ONYXKEYS.js
+++ b/src/ONYXKEYS.js
@@ -225,6 +225,7 @@ export default {
         SETTINGS_STATUS_SET_FORM: 'settingsStatusSetForm',
         SETTINGS_STATUS_CLEAR_AFTER_FORM: 'settingsStatusClearAfterForm',
         SETTINGS_STATUS_SET_CLEAR_AFTER_FORM: 'settingsStatusSetClearAfterForm',
+        SETTINGS_STATUS_CLEAR_DATE_FORM: 'settingsStatusClearDateForm',
     },
 
     // Whether we should show the compose input or not
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
index 8a489afb035e..ee9488884f29 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
@@ -529,6 +529,13 @@ const SettingsModalStackNavigator = createModalStackNavigator([
         },
         name: 'Settings_Status_Set',
     },
+    {
+        getComponent: () => {
+            const SettingsStatusClearAfter = require('../../../pages/settings/Profile/CustomStatus/StatusClearAfterPage').default;
+            return SettingsStatusClearAfter;
+        },
+        name: 'Settings_Status_Clear_After',
+    },
     {
         getComponent: () => {
             const WorkspaceInitialPage = require('../../../pages/workspace/WorkspaceInitialPage').default;
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
new file mode 100644
index 000000000000..4a30e98c87d1
--- /dev/null
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -0,0 +1,145 @@
+import React, {useEffect, useState, useCallback, useMemo} from 'react';
+import {View} from 'react-native';
+import _ from 'lodash';
+import {withOnyx} from 'react-native-onyx';
+import lodashGet from 'lodash/get';
+import ScreenWrapper from '../../../../components/ScreenWrapper';
+import Form from '../../../../components/Form';
+import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
+import ROUTES from '../../../../ROUTES';
+import Navigation from '../../../../libs/Navigation/Navigation';
+import styles from '../../../../styles/styles';
+import Text from '../../../../components/Text';
+import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription';
+import SelectionListRadio from '../../../../components/SelectionListRadio';
+import useLocalize from '../../../../hooks/useLocalize';
+import ONYXKEYS from '../../../../ONYXKEYS';
+import CONST from '../../../../CONST';
+import * as User from '../../../../libs/actions/User';
+import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
+import compose from '../../../../libs/compose';
+import DateUtils from '../../../../libs/DateUtils';
+import withCurrentUserPersonalDetails from '../../../../components/withCurrentUserPersonalDetails';
+
+const defaultProps = {};
+
+const propTypes = {};
+
+function StatusClearAfterPage({currentUserPersonalDetails, customStatus, ...props}) {
+    const localize = useLocalize();
+    const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
+
+    const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
+    const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
+    const [draftPeriod, setDraftPeriod] = useState((clearAfter && !draftClearAfter) || draftClearAfter ? CONST.CUSTOM_STATUS_TYPES.CUSTOM : CONST.CUSTOM_STATUS_TYPES.AFTER_TODAY);
+
+    const localesToThemes = useMemo(
+        () =>
+            _.map(CONST.CUSTOM_STATUS_TYPES, (value, key) => ({
+                value,
+                text: localize.translate(`statusPage.timePeriods.${value}`),
+                keyForList: key,
+                isSelected: draftPeriod === value,
+            })),
+        [draftPeriod],
+    );
+
+    const onSubmit = () => {
+        let calculatedDraftDate = '';
+        if (draftPeriod === CONST.CUSTOM_STATUS_TYPES.CUSTOM) {
+            calculatedDraftDate = customDateTemporary || draftClearAfter;
+        } else {
+            const selectedRange = localesToThemes.find((item) => item.isSelected);
+            calculatedDraftDate = DateUtils.getDateBasedFromType(selectedRange.value);
+        }
+
+        User.updateDraftCustomStatus({clearAfter: calculatedDraftDate});
+        Navigation.goBack(ROUTES.SETTINGS_STATUS);
+    };
+
+    const updateMode = useCallback((mode) => {
+        if (mode.value === CONST.CUSTOM_STATUS_TYPES.CUSTOM) {
+            User.updateDraftCustomStatus({customDateTemporary: DateUtils.getOneHourFromNow()});
+        }
+        setDraftPeriod(mode.value);
+    }, []);
+
+    useEffect(() => {
+        if ((clearAfter && !draftClearAfter) || draftClearAfter) {
+            User.updateDraftCustomStatus({customDateTemporary: (clearAfter && !draftClearAfter) || draftClearAfter});
+            return;
+        }
+        // value by default is CONST.CUSTOM_STATUS_TYPES.AFTER_TODAY
+        User.updateDraftCustomStatus({customDate: DateUtils.getEndOfToday()});
+    }, []);
+
+    const customStatusDate = DateUtils.extractDate(customDateTemporary || draftClearAfter || clearAfter);
+    const customStatusTime = DateUtils.extractTime(customDateTemporary || draftClearAfter || clearAfter);
+    return (
+        <ScreenWrapper>
+            <HeaderWithBackButton
+                title="Status"
+                onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS)}
+            />
+            <Text style={[styles.textNormal, styles.mh5, styles.mv4]}>When should we clear your status?</Text>
+            <Form
+                formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_CLEAR_AFTER_FORM}
+                onCloseButtonPress={() => {}}
+                onBackButtonPress={() => {}}
+                submitButtonText="Save"
+                onSubmit={onSubmit}
+                style={[{flexGrow: 1}]}
+                scrollContextEnabled={false}
+            >
+                <View style={{flexGrow: 1}}>
+                    <SelectionListRadio
+                        sections={[{data: localesToThemes, indexOffset: 0}]}
+                        onSelectRow={updateMode}
+                        disableInitialFocusOptionStyle
+                        wrapperStyle={{flex: null}}
+                    />
+
+                    {draftPeriod === CONST.CUSTOM_STATUS_TYPES.CUSTOM && (
+                        <>
+                            <MenuItemWithTopDescription
+                                title={customStatusDate}
+                                description="Clear after"
+                                shouldShowRightIcon
+                                onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_CUSTOM)}
+                            />
+                            <MenuItemWithTopDescription
+                                title={customStatusTime}
+                                description="Clear after"
+                                shouldShowRightIcon
+                                onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_TIME)}
+                            />
+                        </>
+                    )}
+                </View>
+            </Form>
+        </ScreenWrapper>
+    );
+}
+
+StatusClearAfterPage.displayName = 'StatusClearAfterPage';
+StatusClearAfterPage.propTypes = propTypes;
+StatusClearAfterPage.defaultProps = defaultProps;
+
+export default compose(
+    withCurrentUserPersonalDetails,
+    withLocalize,
+    withOnyx({
+        timePeriodType: {
+            key: `${ONYXKEYS.FORMS.SETTINGS_STATUS_SET_CLEAR_AFTER_FORM}Draft`,
+        },
+        clearDateForm: {
+            key: `${ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_DATE_FORM}Draft`,
+        },
+        customStatus: {
+            key: ONYXKEYS.CUSTOM_STATUS_DRAFT,
+        },
+        preferredLocale: {
+            key: ONYXKEYS.NVP_PREFERRED_LOCALE,
+        },
+    }),
+)(StatusClearAfterPage);

From 76f5a67b0017f1716fdd84826c174b1354ecd18d Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 16 Aug 2023 14:46:42 +0200
Subject: [PATCH 008/118] add style property into BaseSelectionListRadio

---
 src/components/SelectionListRadio/BaseSelectionListRadio.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/SelectionListRadio/BaseSelectionListRadio.js b/src/components/SelectionListRadio/BaseSelectionListRadio.js
index e9e832f05664..95c3e79b87fa 100644
--- a/src/components/SelectionListRadio/BaseSelectionListRadio.js
+++ b/src/components/SelectionListRadio/BaseSelectionListRadio.js
@@ -215,7 +215,7 @@ function BaseSelectionListRadio(props) {
         >
             <SafeAreaConsumer>
                 {({safeAreaPaddingBottomStyle}) => (
-                    <View style={[styles.flex1, !props.isKeyboardShown && safeAreaPaddingBottomStyle]}>
+                    <View style={[styles.flex1, props.wrapperStyle, !props.isKeyboardShown && safeAreaPaddingBottomStyle]}>
                         {shouldShowTextInput && (
                             <View style={[styles.ph5, styles.pb3]}>
                                 <TextInput

From 9053f53e5692414108507bef1ba6b6a1fb115e64 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 16 Aug 2023 14:49:43 +0200
Subject: [PATCH 009/118] WIP SettingsStatusCustomClearAfter

---
 .../AppNavigator/ModalStackNavigators.js      |  7 ++
 .../CustomStatus/CustomClearAfterPage.js      | 92 +++++++++++++++++++
 2 files changed, 99 insertions(+)
 create mode 100644 src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js

diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
index ee9488884f29..ae8d5dafa0d6 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
@@ -536,6 +536,13 @@ const SettingsModalStackNavigator = createModalStackNavigator([
         },
         name: 'Settings_Status_Clear_After',
     },
+    {
+        getComponent: () => {
+            const SettingsStatusCustomClearAfter = require('../../../pages/settings/Profile/CustomStatus/CustomClearAfterPage').default;
+            return SettingsStatusCustomClearAfter;
+        },
+        name: 'Settings_Status_Clear_After_Custom',
+    },
     {
         getComponent: () => {
             const WorkspaceInitialPage = require('../../../pages/workspace/WorkspaceInitialPage').default;
diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
new file mode 100644
index 000000000000..a67f4b360ffe
--- /dev/null
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -0,0 +1,92 @@
+import moment from 'moment';
+import PropTypes from 'prop-types';
+import React from 'react';
+import {withOnyx} from 'react-native-onyx';
+import lodashGet from 'lodash/get';
+import ONYXKEYS from '../../../../ONYXKEYS';
+import ROUTES from '../../../../ROUTES';
+import Form from '../../../../components/Form';
+import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
+import NewDatePicker from '../../../../components/NewDatePicker';
+import ScreenWrapper from '../../../../components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
+import Navigation from '../../../../libs/Navigation/Navigation';
+import * as User from '../../../../libs/actions/User';
+import compose from '../../../../libs/compose';
+import styles from '../../../../styles/styles';
+import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
+import DateUtils from '../../../../libs/DateUtils';
+
+const propTypes = {
+    /* Onyx Props */
+
+    /** User's private personal details */
+    privatePersonalDetails: PropTypes.shape({
+        dob: PropTypes.string,
+    }),
+
+    ...withLocalizePropTypes,
+};
+
+const defaultProps = {
+    privatePersonalDetails: {
+        dob: '',
+    },
+};
+
+function CustomClearAfterPage({translate, customStatus, clearDateForm, personalDetails}) {
+    usePrivatePersonalDetails();
+    const cleanAfter = lodashGet(personalDetails, 'status.cleanAfter', '');
+    const defaultValue = cleanAfter || DateUtils.extractDate(customStatus?.customDateTemporary);
+
+
+    const onSubmit = (v) => {
+        User.updateDraftCustomStatus({customDateTemporary: v.dob});
+        Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
+    };
+
+    return (
+        <ScreenWrapper includeSafeAreaPaddingBottom={false}>
+            <HeaderWithBackButton
+                title={translate('common.dob')}
+                onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
+            />
+            <Form
+                style={[styles.flexGrow1, styles.ph5]}
+                formID={ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_DATE_FORM}
+            
+                // onSubmit={PersonalDetails.updateDateOfBirth}
+                onSubmit={onSubmit}
+                submitButtonText={translate('common.save')}
+                enabledWhenOffline
+                shouldUseDefaultValue
+            >
+                <NewDatePicker
+                    inputID="dob"
+                    label={translate('common.date')}
+                    defaultValue={defaultValue}
+                    minDate={moment().toDate()}
+                />
+            </Form>
+        </ScreenWrapper>
+    );
+}
+
+CustomClearAfterPage.propTypes = propTypes;
+CustomClearAfterPage.defaultProps = defaultProps;
+CustomClearAfterPage.displayName = 'CustomClearAfterPage';
+
+export default compose(
+    withLocalize,
+    withOnyx({
+        privatePersonalDetails: {
+            key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS,
+        },
+        customStatus: {
+            key: ONYXKEYS.CUSTOM_STATUS_DRAFT,
+        },
+        clearDateForm: {
+            key: `${ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_DATE_FORM}Draft`,
+        },
+    }),
+)(CustomClearAfterPage);

From dbfde80e6f987252a3d0b53fc27a193c0b26bf2e Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 21 Aug 2023 17:34:44 +0200
Subject: [PATCH 010/118] lint

---
 .../SelectionListRadio/RadioListItem.js       |    2 +-
 src/languages/en.js                           |   12 +-
 src/languages/es.js                           | 2361 +++++++++--------
 .../Profile/CustomStatus/StatusPage.js        |    3 +-
 4 files changed, 1189 insertions(+), 1189 deletions(-)

diff --git a/src/components/SelectionListRadio/RadioListItem.js b/src/components/SelectionListRadio/RadioListItem.js
index a538bf713b11..ab1272e50910 100644
--- a/src/components/SelectionListRadio/RadioListItem.js
+++ b/src/components/SelectionListRadio/RadioListItem.js
@@ -35,7 +35,7 @@ const defaultProps = {
 };
 
 function RadioListItem(props) {
-  const isFocused = !props.disableIsFocusStyle && props.isFocused
+    const isFocused = !props.disableIsFocusStyle && props.isFocused;
     return (
         <PressableWithFeedback
             onPress={() => props.onSelectRow(props.item)}
diff --git a/src/languages/en.js b/src/languages/en.js
index a6b16d3d089c..094487369f8a 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -895,12 +895,12 @@ export default {
         save: 'Save',
         message: 'Message',
         timePeriods: {
-          never: 'Never',
-          thirtyMinutes: 'Thirty minutes',
-          oneHour: 'One hour',
-          afterToday: 'After today',
-          afterWeek: 'After week',
-          custom: 'Custom',
+            never: 'Never',
+            thirtyMinutes: 'Thirty minutes',
+            oneHour: 'One hour',
+            afterToday: 'After today',
+            afterWeek: 'After week',
+            custom: 'Custom',
         },
         untilTomorrow: 'Until tomorrow',
         untilTime: ({time}) => `Until ${time}`,
diff --git a/src/languages/es.js b/src/languages/es.js
index ecbc13c65648..37ef60152c6c 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -905,7 +905,7 @@ export default {
             afterToday: 'Después de hoy',
             afterWeek: 'Después de una semana',
             custom: 'Personalizado',
-        untilTomorrow: 'Hasta mañana',
+            untilTomorrow: 'Hasta mañana',
         },
         untilTime: ({time}) => {
             // Check for HH:MM AM/PM format and starts with '01:'
@@ -923,1198 +923,1199 @@ export default {
             // Default case
             return `Hasta ${time}`;
         },
-    stepCounter: ({step, total, text}) => {
-        let result = `Paso ${step}`;
+        stepCounter: ({step, total, text}) => {
+            let result = `Paso ${step}`;
 
-        if (total) {
-            result = `${result} de ${total}`;
-        }
+            if (total) {
+                result = `${result} de ${total}`;
+            }
 
-        if (text) {
-            result = `${result}: ${text}`;
-        }
-        return result;
-    },
-    bankAccount: {
-        accountNumber: 'Número de cuenta',
-        routingNumber: 'Número de ruta',
-        addBankAccount: 'Añadir cuenta bancaria',
-        chooseAnAccount: 'Elige una cuenta',
-        connectOnlineWithPlaid: 'Conéctate a Plaid online',
-        connectManually: 'Conectar manualmente',
-        desktopConnection: 'Para conectarse con Chase, Wells Fargo, Capital One o Bank of America, haga clic aquí para completar este proceso en un navegador.',
-        yourDataIsSecure: 'Tus datos están seguros',
-        toGetStarted: 'Añade una cuenta bancaria y emite tarjetas corporativas, reembolsa gastos y cobra y paga facturas, todo desde un mismo lugar.',
-        plaidBodyCopy: 'Ofrezca a sus empleados una forma más sencilla de pagar - y recuperar - los gastos de la empresa.',
-        checkHelpLine: 'Su número de ruta y número de cuenta se pueden encontrar en un cheque de la cuenta bancaria.',
-        validateAccountError:
-            'Para terminar de configurar tu cuenta bancaria, debes validar tu cuenta de Expensify. Por favor, revisa tu correo electrónico para validar tu cuenta y vuelve aquí para continuar.',
-        hasPhoneLoginError:
-            'Para añadir una cuenta bancaria verificada, asegúrate de que tu nombre de usuario principal sea un correo electrónico válido y vuelve a intentarlo. Puedes añadir tu número de teléfono como nombre de usuario secundario.',
-        hasBeenThrottledError: 'Se produjo un error al intentar añadir tu cuenta bancaria. Por favor, espera unos minutos e inténtalo de nuevo.',
-        hasCurrencyError:
-            '¡Ups! Parece que la moneda de tu espacio de trabajo está configurada en una moneda diferente a USD. Para continuar, por favor configúrala en USD e inténtalo nuevamente.',
-        error: {
-            noBankAccountAvailable: 'Lo sentimos, no hay ninguna cuenta bancaria disponible',
-            noBankAccountSelected: 'Por favor, elige una cuenta bancaria',
-            taxID: 'Por favor, introduce un número de identificación fiscal válido',
-            website: 'Por favor, introduce un sitio web válido',
-            zipCode: 'Por favor, introduce un código postal válido',
-            phoneNumber: 'Por favor, introduce un teléfono válido',
-            companyName: 'Por favor, introduce un nombre comercial legal válido',
-            addressCity: 'Por favor, introduce una ciudad válida',
-            addressStreet: 'Por favor, introduce una calle de dirección válida que no sea un apartado postal',
-            addressState: 'Por favor, selecciona un estado',
-            incorporationDateFuture: 'La fecha de incorporación no puede ser futura',
-            incorporationState: 'Por favor, selecciona una estado válido',
-            industryCode: 'Por favor, introduce un código de clasificación de industria válido',
-            restrictedBusiness: 'Por favor, confirma que la empresa no está en la lista de negocios restringidos',
-            routingNumber: 'Por favor, introduce un número de ruta válido',
-            accountNumber: 'Por favor, introduce un número de cuenta válido',
-            routingAndAccountNumberCannotBeSame: 'El número de ruta y el número de cuenta no pueden ser iguales',
-            companyType: 'Por favor, selecciona un tipo de compañía válido',
-            tooManyAttempts:
-                'Debido a la gran cantidad de intentos de inicio de sesión, esta opción se ha desactivado temporalmente durante 24 horas. Vuelve a intentarlo más tarde o introduce los detalles manualmente.',
-            address: 'Por favor, introduce una dirección válida',
-            dob: 'Por favor, selecciona una fecha de nacimiento válida',
-            age: 'Debe ser mayor de 18 años',
-            ssnLast4: 'Por favor, introduce los últimos 4 dígitos del número de seguridad social',
-            firstName: 'Por favor, introduce el nombre',
-            lastName: 'Por favor, introduce los apellidos',
-            noDefaultDepositAccountOrDebitCardAvailable: 'Por favor, añade una cuenta bancaria para depósitos o una tarjeta de débito',
-            validationAmounts: 'Los importes de validación que introduciste son incorrectos. Por favor, comprueba tu cuenta bancaria e inténtalo de nuevo.',
-        },
-    },
-    addPersonalBankAccountPage: {
-        enterPassword: 'Escribe tu contraseña de Expensify',
-        alreadyAdded: 'Esta cuenta ya ha sido añadida.',
-        chooseAccountLabel: 'Cuenta',
-        successTitle: '¡Cuenta bancaria personal añadida!',
-        successMessage: 'Enhorabuena, tu cuenta bancaria está lista para recibir reembolsos.',
-    },
-    attachmentView: {
-        unknownFilename: 'Archivo desconocido',
-        passwordRequired: 'Por favor, introduce tu contraseña',
-        passwordIncorrect: 'Contraseña incorrecta. Por favor, inténtalo de nuevo.',
-        failedToLoadPDF: 'Hubo un error al intentar cargar el PDF.',
-        pdfPasswordForm: {
-            title: 'PDF protegido con contraseña',
-            infoText: 'Este PDF esta protegido con contraseña.',
-            beforeLinkText: 'Por favor',
-            linkText: 'introduce la contraseña',
-            afterLinkText: 'para verlo.',
-            formLabel: 'Ver PDF',
-        },
-    },
-    messages: {
-        errorMessageInvalidPhone: `Por favor, introduce un número de teléfono válido sin paréntesis o guiones. Si reside fuera de Estados Unidos, por favor incluye el prefijo internacional (p. ej. ${CONST.EXAMPLE_PHONE_NUMBER}).`,
-        errorMessageInvalidEmail: 'Email inválido',
-        userIsAlreadyMemberOfWorkspace: ({login, workspace}) => `${login} ya es miembro de ${workspace}`,
-    },
-    onfidoStep: {
-        acceptTerms: 'Al continuar con la solicitud para activar su billetera Expensify, confirma que ha leído, comprende y acepta ',
-        facialScan: 'Política y lanzamiento de la exploración facial de Onfido',
-        tryAgain: 'Intentar otra vez',
-        verifyIdentity: 'Verificar identidad',
-        genericError: 'Hubo un error al procesar este paso. Inténtalo de nuevo.',
-        cameraPermissionsNotGranted: 'No has habilitado los permisos para acceder a la cámara',
-        cameraRequestMessage: 'No has habilitado los permisos para acceder a la cámara. Necesitamos acceso para completar la verificaciôn.',
-        originalDocumentNeeded: 'Por favor, sube una imagen original de tu identificación en lugar de una captura de pantalla o imagen escaneada.',
-        documentNeedsBetterQuality:
-            'Parece que tu identificación esta dañado o le faltan características de seguridad. Por favor, sube una imagen de tu documento sin daños y que se vea completamente.',
-        imageNeedsBetterQuality: 'Hay un problema con la calidad de la imagen de tu identificación. Por favor, sube una nueva imagen donde el identificación se vea con claridad.',
-        selfieIssue: 'Hay un problema con tu selfie/video. Por favor, sube un nuevo selfie/video grabado en el momento',
-        selfieNotMatching: 'Tu selfie/video no concuerda con tu identificación. Por favor, sube un nuevo selfie/video donde se vea tu cara con claridad.',
-        selfieNotLive: 'Tu selfie/video no parece ser un selfie/video en vivo. Por favor, sube un selfie/video a tiempo real.',
-    },
-    additionalDetailsStep: {
-        headerTitle: 'Detalles adicionales',
-        helpText: 'Necesitamos confirmar la siguiente información antes de que podamos procesar el pago.',
-        helpTextIdologyQuestions: 'Tenemos que preguntarte unas preguntas más para terminar de verificar tu identidad',
-        helpLink: 'Obtén más información sobre por qué necesitamos esto.',
-        legalFirstNameLabel: 'Primer nombre legal',
-        legalMiddleNameLabel: 'Segundo nombre legal',
-        legalLastNameLabel: 'Apellidos legales',
-        selectAnswer: 'Selecciona una respuesta.',
-        ssnFull9Error: 'Por favor, introduce los 9 dígitos de un número de seguridad social válido',
-        needSSNFull9: 'Estamos teniendo problemas para verificar tu número de seguridad social. Introduce los 9 dígitos del número de seguridad social.',
-        weCouldNotVerify: 'No se pudo verificar',
-        pleaseFixIt: 'Corrige esta información antes de continuar.',
-        failedKYCTextBefore: 'No se ha podido verificar correctamente tu identidad. Vuelve a intentarlo más tarde y comunicate con ',
-        failedKYCTextAfter: ' si tienes alguna pregunta.',
-    },
-    termsStep: {
-        headerTitle: 'Condiciones y tarifas',
-        haveReadAndAgree: 'He leído y acepto recibir ',
-        electronicDisclosures: 'divulgaciones electrónicas',
-        agreeToThe: 'Estoy de acuerdo con la ',
-        walletAgreement: 'Acuerdo de billetera',
-        enablePayments: 'Habilitar pagos',
-        feeAmountZero: '$0',
-        monthlyFee: 'Cuota mensual',
-        inactivity: 'Inactividad',
-        electronicFundsInstantFee: '1.5%',
-        noOverdraftOrCredit: 'Sin función de sobregiro / crédito',
-        electronicFundsWithdrawal: 'Retiro electrónico de fondos',
-        standard: 'Estándar',
-        shortTermsForm: {
-            expensifyPaymentsAccount: 'La billetera Expensify es emitida por The Bancorp Bank.',
-            perPurchase: 'Por compra',
-            atmWithdrawal: 'Retiro de cajero automático',
-            cashReload: 'Recarga de efectivo',
-            inNetwork: 'en la red',
-            outOfNetwork: 'fuera de la red',
-            atmBalanceInquiry: 'Consulta de saldo de cajero automático',
-            inOrOutOfNetwork: '(dentro o fuera de la red)',
-            customerService: 'Servicio al cliente',
-            automatedOrLive: '(agente automatizado o en vivo)',
-            afterTwelveMonths: '(después de 12 meses sin transacciones)',
-            weChargeOneFee: 'Cobramos un tipo de tarifa.',
-            fdicInsurance: 'Sus fondos son elegibles para el seguro de la FDIC.',
-            generalInfo: 'Para obtener información general sobre cuentas prepagas, visite',
-            conditionsDetails: 'Encuentra detalles y condiciones para todas las tarifas y servicios visitando',
-            conditionsPhone: 'o llamando al +1 833-400-0904.',
-            instant: '(instantáneo)',
-            electronicFundsInstantFeeMin: '(mínimo $0.25)',
-        },
-        longTermsForm: {
-            listOfAllFees: 'Una lista de todas las tarifas de la billetera Expensify',
-            typeOfFeeHeader: 'Tipo de tarifa',
-            feeAmountHeader: 'Importe de la tarifa',
-            moreDetailsHeader: 'Más detalles',
-            openingAccountTitle: 'Abrir una cuenta',
-            openingAccountDetails: 'No hay tarifa para abrir una cuenta.',
-            monthlyFeeDetails: 'No hay tarifa mensual.',
-            customerServiceTitle: 'Servicio al cliente',
-            customerServiceDetails: 'No hay tarifas de servicio al cliente.',
-            inactivityDetails: 'No hay tarifa de inactividad.',
-            sendingFundsTitle: 'Enviar fondos a otro titular de cuenta',
-            sendingFundsDetails: 'No se aplica ningún cargo por enviar fondos a otro titular de cuenta utilizando su saldo cuenta bancaria o tarjeta de débito',
-            electronicFundsStandardDetails:
-                'No hay cargo por transferir fondos desde su billetera Expensify ' +
-                'a su cuenta bancaria utilizando la opción estándar. Esta transferencia generalmente se completa en' +
-                '1-3 negocios días.',
-            electronicFundsInstantDetails:
-                'Hay una tarifa para transferir fondos desde su billetera Expensify a ' +
-                'su tarjeta de débito vinculada utilizando la opción de transferencia instantánea. Esta transferencia ' +
-                'generalmente se completa dentro de varios minutos. La tarifa es el 1.5% del monto de la ' +
-                'transferencia (con una tarifa mínima de $ 0.25). ',
-            fdicInsuranceBancorp:
-                'Sus fondos son elegibles para el seguro de la FDIC. Sus fondos se mantendrán en o ' +
-                'transferido a The Bancorp Bank, una institución asegurada por la FDIC. Una vez allí, sus fondos ' +
-                'están asegurados a $ 250,000 por la FDIC en caso de que The Bancorp Bank quiebre. Ver',
-            fdicInsuranceBancorp2: 'para detalles.',
-            contactExpensifyPayments: 'Comuníquese con Expensify Payments llamando al + 1833-400-0904, por correoelectrónico a',
-            contactExpensifyPayments2: 'o inicie sesión en',
-            generalInformation: 'Para obtener información general sobre cuentas prepagas, visite',
-            generalInformation2: 'Si tiene una queja sobre una cuenta prepaga, llame al Consumer Financial Oficina de Protección al 1-855-411-2372 o visite',
-            printerFriendlyView: 'Ver versión para imprimir',
-            automated: 'Automatizado',
-            liveAgent: 'Agente en vivo',
-            instant: 'Instantáneo',
-            electronicFundsInstantFeeMin: 'Mínimo $0.25',
-        },
-    },
-    activateStep: {
-        headerTitle: 'Habilitar pagos',
-        activatedTitle: '¡Billetera  activada!',
-        activatedMessage: 'Felicidades, tu Billetera está configurada y lista para hacer pagos.',
-        checkBackLaterTitle: 'Un momento...',
-        checkBackLaterMessage: 'Todavía estamos revisando tu información. Por favor, vuelva más tarde.',
-        continueToPayment: 'Continuar al pago',
-        continueToTransfer: 'Continuar a la transferencia',
-    },
-    companyStep: {
-        headerTitle: 'Información de la empresa',
-        subtitle: '¡Ya casi estamos! Por motivos de seguridad, necesitamos confirmar la siguiente información:',
-        legalBusinessName: 'Nombre comercial legal',
-        companyWebsite: 'Página web de la empresa',
-        taxIDNumber: 'Número de identificación fiscal',
-        taxIDNumberPlaceholder: '9 dígitos',
-        companyType: 'Tipo de empresa',
-        incorporationDate: 'Fecha de incorporación',
-        incorporationState: 'Estado de incorporación',
-        industryClassificationCode: 'Código de clasificación industrial',
-        confirmCompanyIsNot: 'Confirmo que esta empresa no está en el',
-        listOfRestrictedBusinesses: 'lista de negocios restringidos',
-        incorporationDatePlaceholder: 'Fecha de inicio (aaaa-mm-dd)',
-        incorporationTypes: {
-            LLC: 'LLC',
-            CORPORATION: 'Corp',
-            PARTNERSHIP: 'Sociedad',
-            COOPERATIVE: 'Cooperativa',
-            SOLE_PROPRIETORSHIP: 'Propietario único',
-            OTHER: 'Otra',
-        },
-    },
-    requestorStep: {
-        headerTitle: 'Información personal',
-        subtitle: 'Dé más información sobre tí.',
-        learnMore: 'Más información',
-        isMyDataSafe: '¿Están seguros mis datos?',
-        onFidoConditions: 'Al continuar con la solicitud de añadir esta cuenta bancaria, confirma que ha leído, entiende y acepta ',
-        isControllingOfficer: 'Estoy autorizado a utilizar la cuenta bancaria de mi compañía para gastos de empresa',
-        isControllingOfficerError: 'Debe ser un oficial controlador con autorización para operar la cuenta bancaria de la compañía',
-    },
-    validationStep: {
-        headerTitle: 'Validar cuenta bancaria',
-        buttonText: 'Finalizar configuración',
-        maxAttemptsReached: 'Se ha inhabilitado la validación de esta cuenta bancaria debido a demasiados intentos incorrectos.',
-        description:
-            'Uno o dos días después de añadir tu cuenta a Expensify, te enviaremos tres (3) transacciones a tu cuenta. Tienen un nombre de comerciante similar a "Expensify, Inc. Validation".',
-        descriptionCTA: 'Introduce el importe de cada transacción en los campos siguientes. Ejemplo: 1.51.',
-        reviewingInfo: '¡Gracias! Estamos revisando tu información y nos comunicaremos contigo en breve. Consulta el chat con Concierge ',
-        forNextSteps: ' para conocer los próximos pasos para terminar de configurar tu cuenta bancaria.',
-        letsChatCTA: 'Sí, vamos a chatear',
-        letsChatText: 'Gracias. Necesitamos tu ayuda para verificar la información, pero podemos hacerlo rápidamente a través del chat. ¿Estás listo?',
-        letsChatTitle: '¡Vamos a chatear!',
-        enable2FATitle: 'Evita fraudes, activa la autenticación de dos factores!',
-        enable2FAText:
-            'Tu seguridad es importante para nosotros. Por favor, configura ahora la autenticación de dos factores. Eso nos permitirá disputar las transacciones de la Tarjeta Expensify y reducirá tu riesgo de fraude.',
-        secureYourAccount: 'Asegura tu cuenta',
-    },
-    beneficialOwnersStep: {
-        additionalInformation: 'Información adicional',
-        checkAllThatApply: 'Marca todos los que apliquen, en caso de que ninguno aplique dejar en blanco.',
-        iOwnMoreThan25Percent: 'Soy dueño de mas de 25% de ',
-        someoneOwnsMoreThan25Percent: 'Otra persona es dueña de mas de 25% de ',
-        additionalOwner: 'Beneficiario efectivo adicional',
-        removeOwner: 'Eliminar este beneficiario efectivo',
-        addAnotherIndividual: 'Añadir otra persona que es dueña de mas de 25% de ',
-        agreement: 'Acuerdo:',
-        termsAndConditions: 'Términos y condiciones',
-        certifyTrueAndAccurate: 'Certifico que la información dada es correcta',
-        error: {
-            certify: 'Debe certificar que la información es verdadera y precisa',
-        },
-    },
-    reimbursementAccountLoadingAnimation: {
-        oneMoment: 'Un momento',
-        explanationLine: 'Estamos verificando tu información y podrás continuar con los siguientes pasos en unos momentos.',
-    },
-    session: {
-        offlineMessageRetry: 'Parece que estás desconectado. Por favor, comprueba tu conexión e inténtalo de nuevo.',
-    },
-    workspace: {
-        common: {
-            card: 'Tarjetas',
-            workspace: 'Espacio de trabajo',
-            edit: 'Editar espacio de trabajo',
-            delete: 'Eliminar espacio de trabajo',
-            settings: 'Configuración',
-            reimburse: 'Reembolsos',
-            bills: 'Pagar facturas',
-            invoices: 'Enviar facturas',
-            travel: 'Viajes',
-            members: 'Miembros',
-            bankAccount: 'Cuenta bancaria',
-            connectBankAccount: 'Conectar cuenta bancaria',
-            testTransactions: 'Transacciones de prueba',
-            issueAndManageCards: 'Emitir y gestionar tarjetas',
-            reconcileCards: 'Reconciliar tarjetas',
-            settlementFrequency: 'Frecuencia de liquidación',
-            deleteConfirmation: '¿Estás seguro de que quieres eliminar este espacio de trabajo?',
-            unavailable: 'Espacio de trabajo no disponible',
-            memberNotFound: 'Miembro no encontrado. Para invitar a un nuevo miembro al espacio de trabajo, por favor, utiliza el botón Invitar que está arriba.',
-            notAuthorized: `No tienes acceso a esta página. ¿Estás tratando de unirte al espacio de trabajo? Comunícate con el propietario de este espacio de trabajo para que pueda añadirte como miembro. ¿Necesitas algo más? Comunícate con ${CONST.EMAIL.CONCIERGE}`,
-            goToRoom: ({roomName}) => `Ir a la sala ${roomName}`,
-        },
-        emptyWorkspace: {
-            title: 'Crear un nuevo espacio de trabajo',
-            subtitle: 'En los espacios de trabajo es donde puedes chatear con tu equipo, reembolsar gastos, emitir tarjetas, enviar y pagar facturas y mas — todo en un mismo lugar',
-            features: {
-                trackAndCollect: 'Organiza recibos',
-                companyCards: 'Tarjetas de crédito corporativas',
-                reimbursements: 'Reembolsos fáciles',
-            },
-        },
-        new: {
-            newWorkspace: 'Nuevo espacio de trabajo',
-            getTheExpensifyCardAndMore: 'Consigue la Tarjeta Expensify y más',
-        },
-        people: {
-            genericFailureMessage: 'Se ha producido un error al intentar eliminar a un usuario del espacio de trabajo. Por favor, inténtalo más tarde.',
-            removeMembersPrompt: '¿Estás seguro que quieres eliminar a los miembros seleccionados de tu espacio de trabajo?',
-            removeMembersTitle: 'Eliminar miembros',
-            selectAll: 'Seleccionar todo',
-            error: {
-                genericAdd: 'Ha ocurrido un problema al añadir el miembro al espacio de trabajo.',
-                cannotRemove: 'No puedes eliminarte ni a ti mismo ni al dueño del espacio de trabajo.',
-                genericRemove: 'Ha ocurrido un problema al eliminar al miembro del espacio de trabajo.',
-            },
-        },
-        card: {
-            header: 'Desbloquea Tarjetas Expensify gratis',
-            headerWithEcard: '¡Tus tarjetas están listas!',
-            noVBACopy: 'Conecta una cuenta bancaria para emitir tarjetas Expensify a los miembros de tu espacio de trabajo y accede a estos increíbles beneficios y más:',
-            VBANoECardCopy:
-                'Añade tu correo electrónico de trabajo para emitir Tarjetas Expensify ilimitadas para los miembros de tu espacio de trabajo y acceder a todas estas increíbles ventajas:',
-            VBAWithECardCopy: 'Acceda a estos increíbles beneficios y más:',
-            benefit1: 'Hasta un 4% de devolución en tus gastos',
-            benefit2: 'Tarjetas digitales y físicas',
-            benefit3: 'Sin responsabilidad personal',
-            benefit4: 'Límites personalizables',
-            addWorkEmail: 'Añadir correo electrónico de trabajo',
-            checkingDomain: '¡Un momento! Estamos todavía trabajando para habilitar tu Tarjeta Expensify. Vuelve aquí en unos minutos.',
-        },
-        reimburse: {
-            captureReceipts: 'Captura recibos',
-            fastReimbursementsHappyMembers: '¡Reembolsos rápidos = miembros felices!',
-            kilometers: 'Kilómetros',
-            miles: 'Millas',
-            viewAllReceipts: 'Ver todos los recibos',
-            reimburseReceipts: 'Reembolsar recibos',
-            trackDistance: 'Medir distancia',
-            trackDistanceCopy: 'Configura la tarifa y unidad usadas para medir distancias.',
-            trackDistanceRate: 'Tarifa',
-            trackDistanceUnit: 'Unidad',
-            unlockNextDayReimbursements: 'Desbloquea reembolsos diarios',
-            captureNoVBACopyBeforeEmail: 'Pide a los miembros de tu espacio de trabajo que envíen recibos a ',
-            captureNoVBACopyAfterEmail: ' y descarga la App de Expensify para controlar tus gastos en efectivo sobre la marcha.',
-            unlockNoVBACopy: 'Conecta una cuenta bancaria para reembolsar online a los miembros de tu espacio de trabajo.',
-            fastReimbursementsVBACopy: '¡Todo listo para reembolsar recibos desde tu cuenta bancaria!',
-            updateCustomUnitError: 'Los cambios no han podido ser guardados. El espacio de trabajo ha sido modificado mientras estabas desconectado. Por favor, inténtalo de nuevo.',
-            invalidRateError: 'Por favor, introduce una tarifa válida',
-        },
-        bills: {
-            manageYourBills: 'Gestiona tus facturas',
-            askYourVendorsBeforeEmail: 'Pide a tus proveedores que envíen sus facturas a ',
-            askYourVendorsAfterEmail: ' y las escanearemos para que las pagues.',
-            viewAllBills: 'Ver facturas recibidas',
-            unlockOnlineBillPayment: 'Desbloquea el pago de facturas online',
-            unlockNoVBACopy: '¡Conecta tu cuenta bancaria para pagar tus facturas online de manera gratuita!',
-            hassleFreeBills: '¡Facturas sin complicaciones!',
-            VBACopy: '¡Todo listo para realizar pagos desde tu cuenta bancaria!',
-        },
-        invoices: {
-            invoiceClientsAndCustomers: 'Emite facturas a tus clientes',
-            invoiceFirstSectionCopy: 'Envía facturas detalladas y profesionales directamente a tus clientes desde la app de Expensify.',
-            viewAllInvoices: 'Ver facturas emitidas',
-            unlockOnlineInvoiceCollection: 'Desbloquea el cobro de facturas online',
-            unlockNoVBACopy: 'Conecta tu cuenta bancaria para recibir pagos online de facturas - por transferencia o con tarjeta - directamente en tu cuenta.',
-            moneyBackInAFlash: '¡Tu dinero de vuelta en un momento!',
-            unlockVBACopy: '¡Todo listo para recibir pagos por transferencia o con tarjeta!',
-            viewUnpaidInvoices: 'Ver facturas emitidas pendientes',
-            sendInvoice: 'Enviar factura',
-        },
-        travel: {
-            unlockConciergeBookingTravel: 'Desbloquea la reserva de viajes con Concierge',
-            noVBACopy: 'Conecta tu cuenta bancaria para permitir a los miembros de tu espacio de trabajo reservar sus vuelos, hoteles y coches empezando una conversación con Concierge.',
-            packYourBags: '¡Haz las maletas!',
-            VBACopy: '¡Miembros con la tarjeta Expensify pueden hablar con Concierge para reservar viajes!',
-            bookTravelWithConcierge: 'Reserva viajes con Concierge',
-        },
-        invite: {
-            invitePeople: 'Invitar nuevos miembros',
-            genericFailureMessage: 'Se produjo un error al invitar al usuario al espacio de trabajo. Vuelva a intentarlo..',
-            pleaseEnterValidLogin: `Asegúrese de que el correo electrónico o el número de teléfono sean válidos (p. ej. ${CONST.EXAMPLE_PHONE_NUMBER}).`,
-        },
-        inviteMessage: {
-            inviteMessageTitle: 'Añadir un mensaje',
-            inviteMessagePrompt: 'Añadir un mensaje para hacer tu invitación destacar',
-            personalMessagePrompt: 'Mensaje',
-            inviteNoMembersError: 'Por favor, selecciona al menos un miembro a invitar',
-            genericFailureMessage: 'Se produjo un error al invitar al usuario al espacio de trabajo. Vuelva a intentarlo..',
-            welcomeNote: ({workspaceName}) =>
-                `¡Has sido invitado a ${workspaceName}! Descargue la aplicación móvil Expensify en use.expensify.com/download para comenzar a rastrear sus gastos.`,
-        },
-        editor: {
-            nameInputLabel: 'Nombre',
-            nameInputHelpText: 'Este es el nombre que verás en tu espacio de trabajo.',
-            nameIsRequiredError: 'Debes definir un nombre para tu espacio de trabajo.',
-            nameIsTooLongError: `El nombre de su espacio de trabajo no puede tener más de ${CONST.WORKSPACE_NAME_CHARACTER_LIMIT} caracteres.`,
-            currencyInputLabel: 'Moneda por defecto',
-            currencyInputHelpText: 'Todas los gastos en este espacio de trabajo serán convertidos a esta moneda.',
-            currencyInputDisabledText: 'La moneda predeterminada no se puede cambiar porque este espacio de trabajo está vinculado a una cuenta bancaria en USD.',
-            save: 'Guardar',
-            genericFailureMessage: 'Se produjo un error al guardar el espacio de trabajo. Por favor, inténtalo de nuevo.',
-            avatarUploadFailureMessage: 'No se pudo subir el avatar. Por favor, inténtalo de nuevo.',
+            if (text) {
+                result = `${result}: ${text}`;
+            }
+            return result;
         },
         bankAccount: {
-            continueWithSetup: 'Continuar con la configuración',
-            youreAlmostDone:
-                'Casi has acabado de configurar tu cuenta bancaria, que te permitirá emitir tarjetas corporativas, reembolsar gastos y cobrar pagar facturas, todo desde la misma cuenta bancaria.',
-            streamlinePayments: 'Optimiza pagos',
-            oneMoreThing: '¡Una cosa más!',
-            allSet: '¡Todo listo!',
-            accountDescriptionNoCards:
-                'Esta cuenta bancaria se utilizará para reembolsar gastos y cobrar y pagar facturas, todo desde la misma cuenta.\n\nPor favor, añade un correo electrónico de trabajo como tu nombre de usuario secundario para activar la Tarjeta Expensify.',
-            accountDescriptionWithCards: 'Esta cuenta bancaria se utilizará para emitir tarjetas corporativas, reembolsar gastos y cobrar y pagar facturas, todo desde la misma cuenta.',
-            addWorkEmail: 'Añadir correo electrónico de trabajo',
-            letsFinishInChat: '¡Continuemos en el chat!',
-            almostDone: '¡Casi listo!',
-            disconnectBankAccount: 'Desconectar cuenta bancaria',
-            noLetsStartOver: 'No, empecemos de nuevo',
-            startOver: 'Empezar de nuevo',
-            yesDisconnectMyBankAccount: 'Sí, desconecta mi cuenta bancaria',
-            yesStartOver: 'Sí, empezar de nuevo',
-            disconnectYour: 'Desconecta tu cuenta bancaria de ',
-            bankAccountAnyTransactions: '. Los reembolsos pendientes serán completados sin problemas.',
-            clearProgress: 'Empezar de nuevo descartará lo completado hasta ahora.',
-            areYouSure: '¿Estás seguro?',
-            workspaceCurrency: 'Moneda del espacio de trabajo',
-            updateCurrencyPrompt:
-                'Parece que tu espacio de trabajo está configurado actualmente en una moneda diferente a USD. Por favor, haz clic en el botón de abajo para actualizar tu moneda a USD ahora.',
-            updateToUSD: 'Actualizar a USD',
-        },
-    },
-    getAssistancePage: {
-        title: 'Obtener ayuda',
-        subtitle: '¡Estamos aquí para ayudarte!',
-        description: 'Elige una de las siguientes opciones:',
-        chatWithConcierge: 'Chatear con Concierge',
-        scheduleSetupCall: 'Concertar una llamada',
-        questionMarkButtonTooltip: 'Obtén ayuda de nuestro equipo',
-        exploreHelpDocs: 'Explorar la documentación de ayuda',
-    },
-    emojiPicker: {
-        skinTonePickerLabel: 'Elige el tono de piel por defecto',
-        headers: {
-            frequentlyUsed: 'Usado frecuentemente',
-            smileysAndEmotion: 'Emoticonos y emociones',
-            peopleAndBody: 'Personas y Cuerpo',
-            animalsAndNature: 'Animales y naturaleza',
-            foodAndDrink: 'Alimentos y bebidas',
-            travelAndPlaces: 'Viajes y lugares',
-            activities: 'Actividades',
-            objects: 'Objetos',
-            symbols: 'Símbolos',
-            flags: 'Banderas',
-        },
-    },
-    newRoomPage: {
-        newRoom: 'Nueva sala de chat',
-        roomName: 'Nombre de la sala',
-        visibility: 'Visibilidad',
-        restrictedDescription: 'Sólo las personas en tu espacio de trabajo pueden encontrar esta sala',
-        privateDescription: 'Sólo las personas que están invitadas a esta sala pueden encontrarla',
-        publicDescription: 'Cualquier persona puede unirse a esta sala',
-        public_announceDescription: 'Cualquier persona puede unirse a esta sala',
-        createRoom: 'Crea una sala de chat',
-        roomAlreadyExistsError: 'Ya existe una sala con este nombre',
-        roomNameReservedError: ({reservedName}) => `${reservedName} es el nombre una sala por defecto de todos los espacios de trabajo. Por favor, elige otro nombre.`,
-        roomNameInvalidError: 'Los nombres de las salas solo pueden contener minúsculas, números y guiones',
-        pleaseEnterRoomName: 'Por favor, escribe el nombre de una sala',
-        pleaseSelectWorkspace: 'Por favor, selecciona un espacio de trabajo',
-        renamedRoomAction: ({oldName, newName}) => ` cambió el nombre de la sala de ${oldName} a ${newName}`,
-        roomRenamedTo: ({newName}) => `Sala renombrada a ${newName}`,
-        social: 'social',
-        selectAWorkspace: 'Seleccionar un espacio de trabajo',
-        growlMessageOnRenameError: 'No se ha podido cambiar el nombre del espacio de trabajo, por favor, comprueba tu conexión e inténtalo de nuevo.',
-        visibilityOptions: {
-            restricted: 'Restringida',
-            private: 'Privada',
-            public: 'Público',
-            public_announce: 'Anuncio Público',
-        },
-    },
-    newTaskPage: {
-        assignTask: 'Asignar tarea',
-        assignMe: 'Asignar a mí mismo',
-        confirmTask: 'Confirmar tarea',
-        confirmError: 'Por favor, introduce un título y selecciona un destino de tarea.',
-        descriptionOptional: 'Descripción (opcional)',
-        shareSomewhere: 'Compartir en algún lugar',
-        pleaseEnterTaskName: 'Por favor, introduce un título',
-        pleaseEnterTaskDestination: 'Por favor, selecciona con quién deseas compartir.',
-    },
-    task: {
-        task: 'Tarea',
-        title: 'Título',
-        description: 'Descripción',
-        assignee: 'Usuario asignado',
-        completed: 'Completada',
+            accountNumber: 'Número de cuenta',
+            routingNumber: 'Número de ruta',
+            addBankAccount: 'Añadir cuenta bancaria',
+            chooseAnAccount: 'Elige una cuenta',
+            connectOnlineWithPlaid: 'Conéctate a Plaid online',
+            connectManually: 'Conectar manualmente',
+            desktopConnection: 'Para conectarse con Chase, Wells Fargo, Capital One o Bank of America, haga clic aquí para completar este proceso en un navegador.',
+            yourDataIsSecure: 'Tus datos están seguros',
+            toGetStarted: 'Añade una cuenta bancaria y emite tarjetas corporativas, reembolsa gastos y cobra y paga facturas, todo desde un mismo lugar.',
+            plaidBodyCopy: 'Ofrezca a sus empleados una forma más sencilla de pagar - y recuperar - los gastos de la empresa.',
+            checkHelpLine: 'Su número de ruta y número de cuenta se pueden encontrar en un cheque de la cuenta bancaria.',
+            validateAccountError:
+                'Para terminar de configurar tu cuenta bancaria, debes validar tu cuenta de Expensify. Por favor, revisa tu correo electrónico para validar tu cuenta y vuelve aquí para continuar.',
+            hasPhoneLoginError:
+                'Para añadir una cuenta bancaria verificada, asegúrate de que tu nombre de usuario principal sea un correo electrónico válido y vuelve a intentarlo. Puedes añadir tu número de teléfono como nombre de usuario secundario.',
+            hasBeenThrottledError: 'Se produjo un error al intentar añadir tu cuenta bancaria. Por favor, espera unos minutos e inténtalo de nuevo.',
+            hasCurrencyError:
+                '¡Ups! Parece que la moneda de tu espacio de trabajo está configurada en una moneda diferente a USD. Para continuar, por favor configúrala en USD e inténtalo nuevamente.',
+            error: {
+                noBankAccountAvailable: 'Lo sentimos, no hay ninguna cuenta bancaria disponible',
+                noBankAccountSelected: 'Por favor, elige una cuenta bancaria',
+                taxID: 'Por favor, introduce un número de identificación fiscal válido',
+                website: 'Por favor, introduce un sitio web válido',
+                zipCode: 'Por favor, introduce un código postal válido',
+                phoneNumber: 'Por favor, introduce un teléfono válido',
+                companyName: 'Por favor, introduce un nombre comercial legal válido',
+                addressCity: 'Por favor, introduce una ciudad válida',
+                addressStreet: 'Por favor, introduce una calle de dirección válida que no sea un apartado postal',
+                addressState: 'Por favor, selecciona un estado',
+                incorporationDateFuture: 'La fecha de incorporación no puede ser futura',
+                incorporationState: 'Por favor, selecciona una estado válido',
+                industryCode: 'Por favor, introduce un código de clasificación de industria válido',
+                restrictedBusiness: 'Por favor, confirma que la empresa no está en la lista de negocios restringidos',
+                routingNumber: 'Por favor, introduce un número de ruta válido',
+                accountNumber: 'Por favor, introduce un número de cuenta válido',
+                routingAndAccountNumberCannotBeSame: 'El número de ruta y el número de cuenta no pueden ser iguales',
+                companyType: 'Por favor, selecciona un tipo de compañía válido',
+                tooManyAttempts:
+                    'Debido a la gran cantidad de intentos de inicio de sesión, esta opción se ha desactivado temporalmente durante 24 horas. Vuelve a intentarlo más tarde o introduce los detalles manualmente.',
+                address: 'Por favor, introduce una dirección válida',
+                dob: 'Por favor, selecciona una fecha de nacimiento válida',
+                age: 'Debe ser mayor de 18 años',
+                ssnLast4: 'Por favor, introduce los últimos 4 dígitos del número de seguridad social',
+                firstName: 'Por favor, introduce el nombre',
+                lastName: 'Por favor, introduce los apellidos',
+                noDefaultDepositAccountOrDebitCardAvailable: 'Por favor, añade una cuenta bancaria para depósitos o una tarjeta de débito',
+                validationAmounts: 'Los importes de validación que introduciste son incorrectos. Por favor, comprueba tu cuenta bancaria e inténtalo de nuevo.',
+            },
+        },
+        addPersonalBankAccountPage: {
+            enterPassword: 'Escribe tu contraseña de Expensify',
+            alreadyAdded: 'Esta cuenta ya ha sido añadida.',
+            chooseAccountLabel: 'Cuenta',
+            successTitle: '¡Cuenta bancaria personal añadida!',
+            successMessage: 'Enhorabuena, tu cuenta bancaria está lista para recibir reembolsos.',
+        },
+        attachmentView: {
+            unknownFilename: 'Archivo desconocido',
+            passwordRequired: 'Por favor, introduce tu contraseña',
+            passwordIncorrect: 'Contraseña incorrecta. Por favor, inténtalo de nuevo.',
+            failedToLoadPDF: 'Hubo un error al intentar cargar el PDF.',
+            pdfPasswordForm: {
+                title: 'PDF protegido con contraseña',
+                infoText: 'Este PDF esta protegido con contraseña.',
+                beforeLinkText: 'Por favor',
+                linkText: 'introduce la contraseña',
+                afterLinkText: 'para verlo.',
+                formLabel: 'Ver PDF',
+            },
+        },
         messages: {
-            completed: 'tarea completada',
-            canceled: 'tarea cancelada',
-            reopened: 'tarea reabrir',
-            error: 'No tiene permiso para realizar la acción solicitada.',
-        },
-        markAsDone: 'Marcar como completada',
-        markAsIncomplete: 'Marcar como incompleta',
-        assigneeError: 'Hubo un error al asignar esta tarea, inténtalo con otro usuario.',
-    },
-    statementPage: {
-        generatingPDF: 'Estamos generando tu PDF ahora mismo. ¡Por favor, vuelve más tarde!',
-    },
-    keyboardShortcutModal: {
-        title: 'Atajos de teclado',
-        subtitle: 'Ahorra tiempo con estos atajos de teclado:',
-        shortcuts: {
-            openShortcutDialog: 'Abre el cuadro de diálogo de métodos abreviados de teclado',
-            escape: 'Diálogos de escape',
-            search: 'Abrir diálogo de búsqueda',
-            newGroup: 'Nueva pantalla de grupo',
-            copy: 'Copiar comentario',
-        },
-    },
-    guides: {
-        screenShare: 'Compartir pantalla',
-        screenShareRequest: 'Expensify te está invitando a compartir la pantalla',
-    },
-    genericErrorPage: {
-        title: '¡Uh-oh, algo salió mal!',
-        body: {
-            helpTextMobile: 'Intenta cerrar y volver a abrir la aplicación o cambiar a la',
-            helpTextWeb: 'web.',
-            helpTextConcierge: 'Si el problema persiste, comunícate con',
-        },
-        refresh: 'Actualizar',
-    },
-    fileDownload: {
-        success: {
-            title: '!Descargado!',
-            message: 'Archivo descargado correctamente',
-        },
-        generalError: {
-            title: 'Error en la descarga',
-            message: 'No se puede descargar el archivo adjunto',
-        },
-        permissionError: {
-            title: 'Permiso para acceder al almacenamiento',
-            message: 'Expensify no puede guardar los archivos adjuntos sin permiso para acceder al almacenamiento. Haz click en Configuración para actualizar los permisos.',
-        },
-    },
-    desktopApplicationMenu: {
-        mainMenu: 'Nuevo Expensify',
-        about: 'Sobre Nuevo Expensify',
-        update: 'Actualizar Nuevo Expensify',
-        checkForUpdates: 'Buscar actualizaciones',
-        toggleDevTools: 'Ver herramientas de desarrollo',
-        viewShortcuts: 'Ver atajos de teclado',
-        services: 'Servicios',
-        hide: 'Ocultar Nuevo Expensify',
-        hideOthers: 'Ocultar otros',
-        showAll: 'Mostrar todos',
-        quit: 'Salir de Nuevo Expensify',
-        fileMenu: 'Archivo',
-        closeWindow: 'Cerrar ventana',
-        editMenu: 'Editar',
-        undo: 'Deshacer',
-        redo: 'Rehacer',
-        cut: 'Cortar',
-        copy: 'Copiar',
-        paste: 'Pegar',
-        pasteAndMatchStyle: 'Pegar adaptando el estilo',
-        pasteAsPlainText: 'Pegar como texto sin formato',
-        delete: 'Eliminar',
-        selectAll: 'Seleccionar todo',
-        speechSubmenu: 'Voz',
-        startSpeaking: 'Empezar a hablar',
-        stopSpeaking: 'Dejar de Hablar',
-        viewMenu: 'Ver',
-        reload: 'Cargar de nuevo',
-        forceReload: 'Forzar recarga',
-        resetZoom: 'Tamaño real',
-        zoomIn: 'Acercar',
-        zoomOut: 'Alejar',
-        togglefullscreen: 'Alternar pantalla completa',
-        historyMenu: 'Historial',
-        back: 'Atrás',
-        forward: 'Adelante',
-        windowMenu: 'Ventana',
-        minimize: 'Minimizar',
-        zoom: 'Zoom',
-        front: 'Traer todo al frente',
-        helpMenu: 'Ayuda',
-        learnMore: 'Más información',
-        documentation: 'Documentación',
-        communityDiscussions: 'Debates de la comunidad',
-        searchIssues: 'Buscar problemas',
-    },
-    historyMenu: {
-        forward: 'Adelante',
-        back: 'Atrás',
-    },
-    checkForUpdatesModal: {
-        available: {
-            title: 'Actualización disponible',
-            message: 'La nueva versión estará disponible dentro de poco. Te notificaremos cuando esté lista.',
-            soundsGood: 'Suena bien',
-        },
-        notAvailable: {
-            title: 'Actualización no disponible',
-            message: 'No existe ninguna actualización disponible! Inténtalo de nuevo más tarde.',
-            okay: 'Vale',
+            errorMessageInvalidPhone: `Por favor, introduce un número de teléfono válido sin paréntesis o guiones. Si reside fuera de Estados Unidos, por favor incluye el prefijo internacional (p. ej. ${CONST.EXAMPLE_PHONE_NUMBER}).`,
+            errorMessageInvalidEmail: 'Email inválido',
+            userIsAlreadyMemberOfWorkspace: ({login, workspace}) => `${login} ya es miembro de ${workspace}`,
+        },
+        onfidoStep: {
+            acceptTerms: 'Al continuar con la solicitud para activar su billetera Expensify, confirma que ha leído, comprende y acepta ',
+            facialScan: 'Política y lanzamiento de la exploración facial de Onfido',
+            tryAgain: 'Intentar otra vez',
+            verifyIdentity: 'Verificar identidad',
+            genericError: 'Hubo un error al procesar este paso. Inténtalo de nuevo.',
+            cameraPermissionsNotGranted: 'No has habilitado los permisos para acceder a la cámara',
+            cameraRequestMessage: 'No has habilitado los permisos para acceder a la cámara. Necesitamos acceso para completar la verificaciôn.',
+            originalDocumentNeeded: 'Por favor, sube una imagen original de tu identificación en lugar de una captura de pantalla o imagen escaneada.',
+            documentNeedsBetterQuality:
+                'Parece que tu identificación esta dañado o le faltan características de seguridad. Por favor, sube una imagen de tu documento sin daños y que se vea completamente.',
+            imageNeedsBetterQuality: 'Hay un problema con la calidad de la imagen de tu identificación. Por favor, sube una nueva imagen donde el identificación se vea con claridad.',
+            selfieIssue: 'Hay un problema con tu selfie/video. Por favor, sube un nuevo selfie/video grabado en el momento',
+            selfieNotMatching: 'Tu selfie/video no concuerda con tu identificación. Por favor, sube un nuevo selfie/video donde se vea tu cara con claridad.',
+            selfieNotLive: 'Tu selfie/video no parece ser un selfie/video en vivo. Por favor, sube un selfie/video a tiempo real.',
+        },
+        additionalDetailsStep: {
+            headerTitle: 'Detalles adicionales',
+            helpText: 'Necesitamos confirmar la siguiente información antes de que podamos procesar el pago.',
+            helpTextIdologyQuestions: 'Tenemos que preguntarte unas preguntas más para terminar de verificar tu identidad',
+            helpLink: 'Obtén más información sobre por qué necesitamos esto.',
+            legalFirstNameLabel: 'Primer nombre legal',
+            legalMiddleNameLabel: 'Segundo nombre legal',
+            legalLastNameLabel: 'Apellidos legales',
+            selectAnswer: 'Selecciona una respuesta.',
+            ssnFull9Error: 'Por favor, introduce los 9 dígitos de un número de seguridad social válido',
+            needSSNFull9: 'Estamos teniendo problemas para verificar tu número de seguridad social. Introduce los 9 dígitos del número de seguridad social.',
+            weCouldNotVerify: 'No se pudo verificar',
+            pleaseFixIt: 'Corrige esta información antes de continuar.',
+            failedKYCTextBefore: 'No se ha podido verificar correctamente tu identidad. Vuelve a intentarlo más tarde y comunicate con ',
+            failedKYCTextAfter: ' si tienes alguna pregunta.',
+        },
+        termsStep: {
+            headerTitle: 'Condiciones y tarifas',
+            haveReadAndAgree: 'He leído y acepto recibir ',
+            electronicDisclosures: 'divulgaciones electrónicas',
+            agreeToThe: 'Estoy de acuerdo con la ',
+            walletAgreement: 'Acuerdo de billetera',
+            enablePayments: 'Habilitar pagos',
+            feeAmountZero: '$0',
+            monthlyFee: 'Cuota mensual',
+            inactivity: 'Inactividad',
+            electronicFundsInstantFee: '1.5%',
+            noOverdraftOrCredit: 'Sin función de sobregiro / crédito',
+            electronicFundsWithdrawal: 'Retiro electrónico de fondos',
+            standard: 'Estándar',
+            shortTermsForm: {
+                expensifyPaymentsAccount: 'La billetera Expensify es emitida por The Bancorp Bank.',
+                perPurchase: 'Por compra',
+                atmWithdrawal: 'Retiro de cajero automático',
+                cashReload: 'Recarga de efectivo',
+                inNetwork: 'en la red',
+                outOfNetwork: 'fuera de la red',
+                atmBalanceInquiry: 'Consulta de saldo de cajero automático',
+                inOrOutOfNetwork: '(dentro o fuera de la red)',
+                customerService: 'Servicio al cliente',
+                automatedOrLive: '(agente automatizado o en vivo)',
+                afterTwelveMonths: '(después de 12 meses sin transacciones)',
+                weChargeOneFee: 'Cobramos un tipo de tarifa.',
+                fdicInsurance: 'Sus fondos son elegibles para el seguro de la FDIC.',
+                generalInfo: 'Para obtener información general sobre cuentas prepagas, visite',
+                conditionsDetails: 'Encuentra detalles y condiciones para todas las tarifas y servicios visitando',
+                conditionsPhone: 'o llamando al +1 833-400-0904.',
+                instant: '(instantáneo)',
+                electronicFundsInstantFeeMin: '(mínimo $0.25)',
+            },
+            longTermsForm: {
+                listOfAllFees: 'Una lista de todas las tarifas de la billetera Expensify',
+                typeOfFeeHeader: 'Tipo de tarifa',
+                feeAmountHeader: 'Importe de la tarifa',
+                moreDetailsHeader: 'Más detalles',
+                openingAccountTitle: 'Abrir una cuenta',
+                openingAccountDetails: 'No hay tarifa para abrir una cuenta.',
+                monthlyFeeDetails: 'No hay tarifa mensual.',
+                customerServiceTitle: 'Servicio al cliente',
+                customerServiceDetails: 'No hay tarifas de servicio al cliente.',
+                inactivityDetails: 'No hay tarifa de inactividad.',
+                sendingFundsTitle: 'Enviar fondos a otro titular de cuenta',
+                sendingFundsDetails: 'No se aplica ningún cargo por enviar fondos a otro titular de cuenta utilizando su saldo cuenta bancaria o tarjeta de débito',
+                electronicFundsStandardDetails:
+                    'No hay cargo por transferir fondos desde su billetera Expensify ' +
+                    'a su cuenta bancaria utilizando la opción estándar. Esta transferencia generalmente se completa en' +
+                    '1-3 negocios días.',
+                electronicFundsInstantDetails:
+                    'Hay una tarifa para transferir fondos desde su billetera Expensify a ' +
+                    'su tarjeta de débito vinculada utilizando la opción de transferencia instantánea. Esta transferencia ' +
+                    'generalmente se completa dentro de varios minutos. La tarifa es el 1.5% del monto de la ' +
+                    'transferencia (con una tarifa mínima de $ 0.25). ',
+                fdicInsuranceBancorp:
+                    'Sus fondos son elegibles para el seguro de la FDIC. Sus fondos se mantendrán en o ' +
+                    'transferido a The Bancorp Bank, una institución asegurada por la FDIC. Una vez allí, sus fondos ' +
+                    'están asegurados a $ 250,000 por la FDIC en caso de que The Bancorp Bank quiebre. Ver',
+                fdicInsuranceBancorp2: 'para detalles.',
+                contactExpensifyPayments: 'Comuníquese con Expensify Payments llamando al + 1833-400-0904, por correoelectrónico a',
+                contactExpensifyPayments2: 'o inicie sesión en',
+                generalInformation: 'Para obtener información general sobre cuentas prepagas, visite',
+                generalInformation2: 'Si tiene una queja sobre una cuenta prepaga, llame al Consumer Financial Oficina de Protección al 1-855-411-2372 o visite',
+                printerFriendlyView: 'Ver versión para imprimir',
+                automated: 'Automatizado',
+                liveAgent: 'Agente en vivo',
+                instant: 'Instantáneo',
+                electronicFundsInstantFeeMin: 'Mínimo $0.25',
+            },
         },
-        error: {
-            title: 'Comprobación fallida',
-            message: 'No hemos podido comprobar si existe una actualización. Inténtalo de nuevo más tarde!',
-        },
-    },
-    report: {
-        genericCreateReportFailureMessage: 'Error inesperado al crear el chat. Por favor, inténtalo más tarde',
-        genericAddCommentFailureMessage: 'Error inesperado al añadir el comentario. Por favor, inténtalo más tarde',
-        noActivityYet: 'Sin actividad todavía',
-    },
-    chronos: {
-        oooEventSummaryFullDay: ({summary, dayCount, date}) => `${summary} por ${dayCount} ${dayCount === 1 ? 'día' : 'días'} hasta el ${date}`,
-        oooEventSummaryPartialDay: ({summary, timePeriod, date}) => `${summary} de ${timePeriod} del ${date}`,
-    },
-    footer: {
-        features: 'Características',
-        expenseManagement: 'Gestión de Gastos',
-        spendManagement: 'Control de Gastos',
-        expenseReports: 'Informes de Gastos',
-        companyCreditCard: 'Tarjeta de Crédito Corporativa',
-        receiptScanningApp: 'Aplicación de Escaneado de Recibos',
-        billPay: 'Pago de Facturas',
-        invoicing: 'Facturación',
-        CPACard: 'Tarjeta Para Contables',
-        payroll: 'Nómina',
-        travel: 'Viajes',
-        resources: 'Recursos',
-        expensifyApproved: 'ExpensifyApproved!',
-        pressKit: 'Kit de Prensa',
-        support: 'Soporte',
-        expensifyHelp: 'ExpensifyHelp',
-        community: 'Comunidad',
-        privacy: 'Privacidad',
-        learnMore: 'Más Información',
-        aboutExpensify: 'Acerca de Expensify',
-        blog: 'Blog',
-        jobs: 'Empleo',
-        expensifyOrg: 'Expensify.org',
-        investorRelations: 'Relaciones Con Los Inversores',
-        getStarted: 'Comenzar',
-        createAccount: 'Crear Una Cuenta Nueva',
-        logIn: 'Conectarse',
-    },
-    allStates: {
-        AK: {
-            stateISO: 'AK',
-            stateName: 'Alaska',
-        },
-        AL: {
-            stateISO: 'AL',
-            stateName: 'Alabama',
-        },
-        AR: {
-            stateISO: 'AR',
-            stateName: 'Arkansas',
-        },
-        AZ: {
-            stateISO: 'AZ',
-            stateName: 'Arizona',
-        },
-        CA: {
-            stateISO: 'CA',
-            stateName: 'California',
-        },
-        CO: {
-            stateISO: 'CO',
-            stateName: 'Colorado',
-        },
-        CT: {
-            stateISO: 'CT',
-            stateName: 'Connecticut',
-        },
-        DE: {
-            stateISO: 'DE',
-            stateName: 'Delaware',
-        },
-        FL: {
-            stateISO: 'FL',
-            stateName: 'Florida',
-        },
-        GA: {
-            stateISO: 'GA',
-            stateName: 'Georgia',
-        },
-        HI: {
-            stateISO: 'HI',
-            stateName: 'Hawái',
-        },
-        IA: {
-            stateISO: 'IA',
-            stateName: 'Iowa',
-        },
-        ID: {
-            stateISO: 'ID',
-            stateName: 'Idaho',
-        },
-        IL: {
-            stateISO: 'IL',
-            stateName: 'Illinois',
-        },
-        IN: {
-            stateISO: 'IN',
-            stateName: 'Indiana',
-        },
-        KS: {
-            stateISO: 'KS',
-            stateName: 'Kansas',
-        },
-        KY: {
-            stateISO: 'KY',
-            stateName: 'Kentucky',
-        },
-        LA: {
-            stateISO: 'LA',
-            stateName: 'Luisiana',
-        },
-        MA: {
-            stateISO: 'MA',
-            stateName: 'Massachusetts',
-        },
-        MD: {
-            stateISO: 'MD',
-            stateName: 'Maryland',
-        },
-        ME: {
-            stateISO: 'ME',
-            stateName: 'Maine',
-        },
-        MI: {
-            stateISO: 'MI',
-            stateName: 'Míchigan',
-        },
-        MN: {
-            stateISO: 'MN',
-            stateName: 'Minnesota',
-        },
-        MO: {
-            stateISO: 'MO',
-            stateName: 'Misuri',
+        activateStep: {
+            headerTitle: 'Habilitar pagos',
+            activatedTitle: '¡Billetera  activada!',
+            activatedMessage: 'Felicidades, tu Billetera está configurada y lista para hacer pagos.',
+            checkBackLaterTitle: 'Un momento...',
+            checkBackLaterMessage: 'Todavía estamos revisando tu información. Por favor, vuelva más tarde.',
+            continueToPayment: 'Continuar al pago',
+            continueToTransfer: 'Continuar a la transferencia',
+        },
+        companyStep: {
+            headerTitle: 'Información de la empresa',
+            subtitle: '¡Ya casi estamos! Por motivos de seguridad, necesitamos confirmar la siguiente información:',
+            legalBusinessName: 'Nombre comercial legal',
+            companyWebsite: 'Página web de la empresa',
+            taxIDNumber: 'Número de identificación fiscal',
+            taxIDNumberPlaceholder: '9 dígitos',
+            companyType: 'Tipo de empresa',
+            incorporationDate: 'Fecha de incorporación',
+            incorporationState: 'Estado de incorporación',
+            industryClassificationCode: 'Código de clasificación industrial',
+            confirmCompanyIsNot: 'Confirmo que esta empresa no está en el',
+            listOfRestrictedBusinesses: 'lista de negocios restringidos',
+            incorporationDatePlaceholder: 'Fecha de inicio (aaaa-mm-dd)',
+            incorporationTypes: {
+                LLC: 'LLC',
+                CORPORATION: 'Corp',
+                PARTNERSHIP: 'Sociedad',
+                COOPERATIVE: 'Cooperativa',
+                SOLE_PROPRIETORSHIP: 'Propietario único',
+                OTHER: 'Otra',
+            },
         },
-        MS: {
-            stateISO: 'MS',
-            stateName: 'Misisipi',
+        requestorStep: {
+            headerTitle: 'Información personal',
+            subtitle: 'Dé más información sobre tí.',
+            learnMore: 'Más información',
+            isMyDataSafe: '¿Están seguros mis datos?',
+            onFidoConditions: 'Al continuar con la solicitud de añadir esta cuenta bancaria, confirma que ha leído, entiende y acepta ',
+            isControllingOfficer: 'Estoy autorizado a utilizar la cuenta bancaria de mi compañía para gastos de empresa',
+            isControllingOfficerError: 'Debe ser un oficial controlador con autorización para operar la cuenta bancaria de la compañía',
+        },
+        validationStep: {
+            headerTitle: 'Validar cuenta bancaria',
+            buttonText: 'Finalizar configuración',
+            maxAttemptsReached: 'Se ha inhabilitado la validación de esta cuenta bancaria debido a demasiados intentos incorrectos.',
+            description:
+                'Uno o dos días después de añadir tu cuenta a Expensify, te enviaremos tres (3) transacciones a tu cuenta. Tienen un nombre de comerciante similar a "Expensify, Inc. Validation".',
+            descriptionCTA: 'Introduce el importe de cada transacción en los campos siguientes. Ejemplo: 1.51.',
+            reviewingInfo: '¡Gracias! Estamos revisando tu información y nos comunicaremos contigo en breve. Consulta el chat con Concierge ',
+            forNextSteps: ' para conocer los próximos pasos para terminar de configurar tu cuenta bancaria.',
+            letsChatCTA: 'Sí, vamos a chatear',
+            letsChatText: 'Gracias. Necesitamos tu ayuda para verificar la información, pero podemos hacerlo rápidamente a través del chat. ¿Estás listo?',
+            letsChatTitle: '¡Vamos a chatear!',
+            enable2FATitle: 'Evita fraudes, activa la autenticación de dos factores!',
+            enable2FAText:
+                'Tu seguridad es importante para nosotros. Por favor, configura ahora la autenticación de dos factores. Eso nos permitirá disputar las transacciones de la Tarjeta Expensify y reducirá tu riesgo de fraude.',
+            secureYourAccount: 'Asegura tu cuenta',
+        },
+        beneficialOwnersStep: {
+            additionalInformation: 'Información adicional',
+            checkAllThatApply: 'Marca todos los que apliquen, en caso de que ninguno aplique dejar en blanco.',
+            iOwnMoreThan25Percent: 'Soy dueño de mas de 25% de ',
+            someoneOwnsMoreThan25Percent: 'Otra persona es dueña de mas de 25% de ',
+            additionalOwner: 'Beneficiario efectivo adicional',
+            removeOwner: 'Eliminar este beneficiario efectivo',
+            addAnotherIndividual: 'Añadir otra persona que es dueña de mas de 25% de ',
+            agreement: 'Acuerdo:',
+            termsAndConditions: 'Términos y condiciones',
+            certifyTrueAndAccurate: 'Certifico que la información dada es correcta',
+            error: {
+                certify: 'Debe certificar que la información es verdadera y precisa',
+            },
         },
-        MT: {
-            stateISO: 'MT',
-            stateName: 'Montana',
+        reimbursementAccountLoadingAnimation: {
+            oneMoment: 'Un momento',
+            explanationLine: 'Estamos verificando tu información y podrás continuar con los siguientes pasos en unos momentos.',
+        },
+        session: {
+            offlineMessageRetry: 'Parece que estás desconectado. Por favor, comprueba tu conexión e inténtalo de nuevo.',
+        },
+        workspace: {
+            common: {
+                card: 'Tarjetas',
+                workspace: 'Espacio de trabajo',
+                edit: 'Editar espacio de trabajo',
+                delete: 'Eliminar espacio de trabajo',
+                settings: 'Configuración',
+                reimburse: 'Reembolsos',
+                bills: 'Pagar facturas',
+                invoices: 'Enviar facturas',
+                travel: 'Viajes',
+                members: 'Miembros',
+                bankAccount: 'Cuenta bancaria',
+                connectBankAccount: 'Conectar cuenta bancaria',
+                testTransactions: 'Transacciones de prueba',
+                issueAndManageCards: 'Emitir y gestionar tarjetas',
+                reconcileCards: 'Reconciliar tarjetas',
+                settlementFrequency: 'Frecuencia de liquidación',
+                deleteConfirmation: '¿Estás seguro de que quieres eliminar este espacio de trabajo?',
+                unavailable: 'Espacio de trabajo no disponible',
+                memberNotFound: 'Miembro no encontrado. Para invitar a un nuevo miembro al espacio de trabajo, por favor, utiliza el botón Invitar que está arriba.',
+                notAuthorized: `No tienes acceso a esta página. ¿Estás tratando de unirte al espacio de trabajo? Comunícate con el propietario de este espacio de trabajo para que pueda añadirte como miembro. ¿Necesitas algo más? Comunícate con ${CONST.EMAIL.CONCIERGE}`,
+                goToRoom: ({roomName}) => `Ir a la sala ${roomName}`,
+            },
+            emptyWorkspace: {
+                title: 'Crear un nuevo espacio de trabajo',
+                subtitle: 'En los espacios de trabajo es donde puedes chatear con tu equipo, reembolsar gastos, emitir tarjetas, enviar y pagar facturas y mas — todo en un mismo lugar',
+                features: {
+                    trackAndCollect: 'Organiza recibos',
+                    companyCards: 'Tarjetas de crédito corporativas',
+                    reimbursements: 'Reembolsos fáciles',
+                },
+            },
+            new: {
+                newWorkspace: 'Nuevo espacio de trabajo',
+                getTheExpensifyCardAndMore: 'Consigue la Tarjeta Expensify y más',
+            },
+            people: {
+                genericFailureMessage: 'Se ha producido un error al intentar eliminar a un usuario del espacio de trabajo. Por favor, inténtalo más tarde.',
+                removeMembersPrompt: '¿Estás seguro que quieres eliminar a los miembros seleccionados de tu espacio de trabajo?',
+                removeMembersTitle: 'Eliminar miembros',
+                selectAll: 'Seleccionar todo',
+                error: {
+                    genericAdd: 'Ha ocurrido un problema al añadir el miembro al espacio de trabajo.',
+                    cannotRemove: 'No puedes eliminarte ni a ti mismo ni al dueño del espacio de trabajo.',
+                    genericRemove: 'Ha ocurrido un problema al eliminar al miembro del espacio de trabajo.',
+                },
+            },
+            card: {
+                header: 'Desbloquea Tarjetas Expensify gratis',
+                headerWithEcard: '¡Tus tarjetas están listas!',
+                noVBACopy: 'Conecta una cuenta bancaria para emitir tarjetas Expensify a los miembros de tu espacio de trabajo y accede a estos increíbles beneficios y más:',
+                VBANoECardCopy:
+                    'Añade tu correo electrónico de trabajo para emitir Tarjetas Expensify ilimitadas para los miembros de tu espacio de trabajo y acceder a todas estas increíbles ventajas:',
+                VBAWithECardCopy: 'Acceda a estos increíbles beneficios y más:',
+                benefit1: 'Hasta un 4% de devolución en tus gastos',
+                benefit2: 'Tarjetas digitales y físicas',
+                benefit3: 'Sin responsabilidad personal',
+                benefit4: 'Límites personalizables',
+                addWorkEmail: 'Añadir correo electrónico de trabajo',
+                checkingDomain: '¡Un momento! Estamos todavía trabajando para habilitar tu Tarjeta Expensify. Vuelve aquí en unos minutos.',
+            },
+            reimburse: {
+                captureReceipts: 'Captura recibos',
+                fastReimbursementsHappyMembers: '¡Reembolsos rápidos = miembros felices!',
+                kilometers: 'Kilómetros',
+                miles: 'Millas',
+                viewAllReceipts: 'Ver todos los recibos',
+                reimburseReceipts: 'Reembolsar recibos',
+                trackDistance: 'Medir distancia',
+                trackDistanceCopy: 'Configura la tarifa y unidad usadas para medir distancias.',
+                trackDistanceRate: 'Tarifa',
+                trackDistanceUnit: 'Unidad',
+                unlockNextDayReimbursements: 'Desbloquea reembolsos diarios',
+                captureNoVBACopyBeforeEmail: 'Pide a los miembros de tu espacio de trabajo que envíen recibos a ',
+                captureNoVBACopyAfterEmail: ' y descarga la App de Expensify para controlar tus gastos en efectivo sobre la marcha.',
+                unlockNoVBACopy: 'Conecta una cuenta bancaria para reembolsar online a los miembros de tu espacio de trabajo.',
+                fastReimbursementsVBACopy: '¡Todo listo para reembolsar recibos desde tu cuenta bancaria!',
+                updateCustomUnitError: 'Los cambios no han podido ser guardados. El espacio de trabajo ha sido modificado mientras estabas desconectado. Por favor, inténtalo de nuevo.',
+                invalidRateError: 'Por favor, introduce una tarifa válida',
+            },
+            bills: {
+                manageYourBills: 'Gestiona tus facturas',
+                askYourVendorsBeforeEmail: 'Pide a tus proveedores que envíen sus facturas a ',
+                askYourVendorsAfterEmail: ' y las escanearemos para que las pagues.',
+                viewAllBills: 'Ver facturas recibidas',
+                unlockOnlineBillPayment: 'Desbloquea el pago de facturas online',
+                unlockNoVBACopy: '¡Conecta tu cuenta bancaria para pagar tus facturas online de manera gratuita!',
+                hassleFreeBills: '¡Facturas sin complicaciones!',
+                VBACopy: '¡Todo listo para realizar pagos desde tu cuenta bancaria!',
+            },
+            invoices: {
+                invoiceClientsAndCustomers: 'Emite facturas a tus clientes',
+                invoiceFirstSectionCopy: 'Envía facturas detalladas y profesionales directamente a tus clientes desde la app de Expensify.',
+                viewAllInvoices: 'Ver facturas emitidas',
+                unlockOnlineInvoiceCollection: 'Desbloquea el cobro de facturas online',
+                unlockNoVBACopy: 'Conecta tu cuenta bancaria para recibir pagos online de facturas - por transferencia o con tarjeta - directamente en tu cuenta.',
+                moneyBackInAFlash: '¡Tu dinero de vuelta en un momento!',
+                unlockVBACopy: '¡Todo listo para recibir pagos por transferencia o con tarjeta!',
+                viewUnpaidInvoices: 'Ver facturas emitidas pendientes',
+                sendInvoice: 'Enviar factura',
+            },
+            travel: {
+                unlockConciergeBookingTravel: 'Desbloquea la reserva de viajes con Concierge',
+                noVBACopy: 'Conecta tu cuenta bancaria para permitir a los miembros de tu espacio de trabajo reservar sus vuelos, hoteles y coches empezando una conversación con Concierge.',
+                packYourBags: '¡Haz las maletas!',
+                VBACopy: '¡Miembros con la tarjeta Expensify pueden hablar con Concierge para reservar viajes!',
+                bookTravelWithConcierge: 'Reserva viajes con Concierge',
+            },
+            invite: {
+                invitePeople: 'Invitar nuevos miembros',
+                genericFailureMessage: 'Se produjo un error al invitar al usuario al espacio de trabajo. Vuelva a intentarlo..',
+                pleaseEnterValidLogin: `Asegúrese de que el correo electrónico o el número de teléfono sean válidos (p. ej. ${CONST.EXAMPLE_PHONE_NUMBER}).`,
+            },
+            inviteMessage: {
+                inviteMessageTitle: 'Añadir un mensaje',
+                inviteMessagePrompt: 'Añadir un mensaje para hacer tu invitación destacar',
+                personalMessagePrompt: 'Mensaje',
+                inviteNoMembersError: 'Por favor, selecciona al menos un miembro a invitar',
+                genericFailureMessage: 'Se produjo un error al invitar al usuario al espacio de trabajo. Vuelva a intentarlo..',
+                welcomeNote: ({workspaceName}) =>
+                    `¡Has sido invitado a ${workspaceName}! Descargue la aplicación móvil Expensify en use.expensify.com/download para comenzar a rastrear sus gastos.`,
+            },
+            editor: {
+                nameInputLabel: 'Nombre',
+                nameInputHelpText: 'Este es el nombre que verás en tu espacio de trabajo.',
+                nameIsRequiredError: 'Debes definir un nombre para tu espacio de trabajo.',
+                nameIsTooLongError: `El nombre de su espacio de trabajo no puede tener más de ${CONST.WORKSPACE_NAME_CHARACTER_LIMIT} caracteres.`,
+                currencyInputLabel: 'Moneda por defecto',
+                currencyInputHelpText: 'Todas los gastos en este espacio de trabajo serán convertidos a esta moneda.',
+                currencyInputDisabledText: 'La moneda predeterminada no se puede cambiar porque este espacio de trabajo está vinculado a una cuenta bancaria en USD.',
+                save: 'Guardar',
+                genericFailureMessage: 'Se produjo un error al guardar el espacio de trabajo. Por favor, inténtalo de nuevo.',
+                avatarUploadFailureMessage: 'No se pudo subir el avatar. Por favor, inténtalo de nuevo.',
+            },
+            bankAccount: {
+                continueWithSetup: 'Continuar con la configuración',
+                youreAlmostDone:
+                    'Casi has acabado de configurar tu cuenta bancaria, que te permitirá emitir tarjetas corporativas, reembolsar gastos y cobrar pagar facturas, todo desde la misma cuenta bancaria.',
+                streamlinePayments: 'Optimiza pagos',
+                oneMoreThing: '¡Una cosa más!',
+                allSet: '¡Todo listo!',
+                accountDescriptionNoCards:
+                    'Esta cuenta bancaria se utilizará para reembolsar gastos y cobrar y pagar facturas, todo desde la misma cuenta.\n\nPor favor, añade un correo electrónico de trabajo como tu nombre de usuario secundario para activar la Tarjeta Expensify.',
+                accountDescriptionWithCards: 'Esta cuenta bancaria se utilizará para emitir tarjetas corporativas, reembolsar gastos y cobrar y pagar facturas, todo desde la misma cuenta.',
+                addWorkEmail: 'Añadir correo electrónico de trabajo',
+                letsFinishInChat: '¡Continuemos en el chat!',
+                almostDone: '¡Casi listo!',
+                disconnectBankAccount: 'Desconectar cuenta bancaria',
+                noLetsStartOver: 'No, empecemos de nuevo',
+                startOver: 'Empezar de nuevo',
+                yesDisconnectMyBankAccount: 'Sí, desconecta mi cuenta bancaria',
+                yesStartOver: 'Sí, empezar de nuevo',
+                disconnectYour: 'Desconecta tu cuenta bancaria de ',
+                bankAccountAnyTransactions: '. Los reembolsos pendientes serán completados sin problemas.',
+                clearProgress: 'Empezar de nuevo descartará lo completado hasta ahora.',
+                areYouSure: '¿Estás seguro?',
+                workspaceCurrency: 'Moneda del espacio de trabajo',
+                updateCurrencyPrompt:
+                    'Parece que tu espacio de trabajo está configurado actualmente en una moneda diferente a USD. Por favor, haz clic en el botón de abajo para actualizar tu moneda a USD ahora.',
+                updateToUSD: 'Actualizar a USD',
+            },
         },
-        NC: {
-            stateISO: 'NC',
-            stateName: 'Carolina del Norte',
+        getAssistancePage: {
+            title: 'Obtener ayuda',
+            subtitle: '¡Estamos aquí para ayudarte!',
+            description: 'Elige una de las siguientes opciones:',
+            chatWithConcierge: 'Chatear con Concierge',
+            scheduleSetupCall: 'Concertar una llamada',
+            questionMarkButtonTooltip: 'Obtén ayuda de nuestro equipo',
+            exploreHelpDocs: 'Explorar la documentación de ayuda',
+        },
+        emojiPicker: {
+            skinTonePickerLabel: 'Elige el tono de piel por defecto',
+            headers: {
+                frequentlyUsed: 'Usado frecuentemente',
+                smileysAndEmotion: 'Emoticonos y emociones',
+                peopleAndBody: 'Personas y Cuerpo',
+                animalsAndNature: 'Animales y naturaleza',
+                foodAndDrink: 'Alimentos y bebidas',
+                travelAndPlaces: 'Viajes y lugares',
+                activities: 'Actividades',
+                objects: 'Objetos',
+                symbols: 'Símbolos',
+                flags: 'Banderas',
+            },
         },
-        ND: {
-            stateISO: 'ND',
-            stateName: 'Dakota del Norte',
+        newRoomPage: {
+            newRoom: 'Nueva sala de chat',
+            roomName: 'Nombre de la sala',
+            visibility: 'Visibilidad',
+            restrictedDescription: 'Sólo las personas en tu espacio de trabajo pueden encontrar esta sala',
+            privateDescription: 'Sólo las personas que están invitadas a esta sala pueden encontrarla',
+            publicDescription: 'Cualquier persona puede unirse a esta sala',
+            public_announceDescription: 'Cualquier persona puede unirse a esta sala',
+            createRoom: 'Crea una sala de chat',
+            roomAlreadyExistsError: 'Ya existe una sala con este nombre',
+            roomNameReservedError: ({reservedName}) => `${reservedName} es el nombre una sala por defecto de todos los espacios de trabajo. Por favor, elige otro nombre.`,
+            roomNameInvalidError: 'Los nombres de las salas solo pueden contener minúsculas, números y guiones',
+            pleaseEnterRoomName: 'Por favor, escribe el nombre de una sala',
+            pleaseSelectWorkspace: 'Por favor, selecciona un espacio de trabajo',
+            renamedRoomAction: ({oldName, newName}) => ` cambió el nombre de la sala de ${oldName} a ${newName}`,
+            roomRenamedTo: ({newName}) => `Sala renombrada a ${newName}`,
+            social: 'social',
+            selectAWorkspace: 'Seleccionar un espacio de trabajo',
+            growlMessageOnRenameError: 'No se ha podido cambiar el nombre del espacio de trabajo, por favor, comprueba tu conexión e inténtalo de nuevo.',
+            visibilityOptions: {
+                restricted: 'Restringida',
+                private: 'Privada',
+                public: 'Público',
+                public_announce: 'Anuncio Público',
+            },
         },
-        NE: {
-            stateISO: 'NE',
-            stateName: 'Nebraska',
+        newTaskPage: {
+            assignTask: 'Asignar tarea',
+            assignMe: 'Asignar a mí mismo',
+            confirmTask: 'Confirmar tarea',
+            confirmError: 'Por favor, introduce un título y selecciona un destino de tarea.',
+            descriptionOptional: 'Descripción (opcional)',
+            shareSomewhere: 'Compartir en algún lugar',
+            pleaseEnterTaskName: 'Por favor, introduce un título',
+            pleaseEnterTaskDestination: 'Por favor, selecciona con quién deseas compartir.',
+        },
+        task: {
+            task: 'Tarea',
+            title: 'Título',
+            description: 'Descripción',
+            assignee: 'Usuario asignado',
+            completed: 'Completada',
+            messages: {
+                completed: 'tarea completada',
+                canceled: 'tarea cancelada',
+                reopened: 'tarea reabrir',
+                error: 'No tiene permiso para realizar la acción solicitada.',
+            },
+            markAsDone: 'Marcar como completada',
+            markAsIncomplete: 'Marcar como incompleta',
+            assigneeError: 'Hubo un error al asignar esta tarea, inténtalo con otro usuario.',
+        },
+        statementPage: {
+            generatingPDF: 'Estamos generando tu PDF ahora mismo. ¡Por favor, vuelve más tarde!',
+        },
+        keyboardShortcutModal: {
+            title: 'Atajos de teclado',
+            subtitle: 'Ahorra tiempo con estos atajos de teclado:',
+            shortcuts: {
+                openShortcutDialog: 'Abre el cuadro de diálogo de métodos abreviados de teclado',
+                escape: 'Diálogos de escape',
+                search: 'Abrir diálogo de búsqueda',
+                newGroup: 'Nueva pantalla de grupo',
+                copy: 'Copiar comentario',
+            },
         },
-        NH: {
-            stateISO: 'NH',
-            stateName: 'Nuevo Hampshire',
-        },
-        NJ: {
-            stateISO: 'NJ',
-            stateName: 'Nueva Jersey',
-        },
-        NM: {
-            stateISO: 'NM',
-            stateName: 'Nuevo México',
-        },
-        NV: {
-            stateISO: 'NV',
-            stateName: 'Nevada',
-        },
-        NY: {
-            stateISO: 'NY',
-            stateName: 'Nueva York',
-        },
-        OH: {
-            stateISO: 'OH',
-            stateName: 'Ohio',
-        },
-        OK: {
-            stateISO: 'OK',
-            stateName: 'Oklahoma',
-        },
-        OR: {
-            stateISO: 'OR',
-            stateName: 'Oregón',
-        },
-        PA: {
-            stateISO: 'PA',
-            stateName: 'Pensilvania',
-        },
-        PR: {
-            stateISO: 'PR',
-            stateName: 'Puerto Rico',
-        },
-        RI: {
-            stateISO: 'RI',
-            stateName: 'Rhode Island',
-        },
-        SC: {
-            stateISO: 'SC',
-            stateName: 'Carolina del Sur',
-        },
-        SD: {
-            stateISO: 'SD',
-            stateName: 'Dakota del Sur',
-        },
-        TN: {
-            stateISO: 'TN',
-            stateName: 'Tennessee',
-        },
-        TX: {
-            stateISO: 'TX',
-            stateName: 'Texas',
-        },
-        UT: {
-            stateISO: 'UT',
-            stateName: 'Utah',
-        },
-        VA: {
-            stateISO: 'VA',
-            stateName: 'Virginia',
-        },
-        VT: {
-            stateISO: 'VT',
-            stateName: 'Vermont',
-        },
-        WA: {
-            stateISO: 'WA',
-            stateName: 'Washington',
-        },
-        WI: {
-            stateISO: 'WI',
-            stateName: 'Wisconsin',
-        },
-        WV: {
-            stateISO: 'WV',
-            stateName: 'Virginia Occidental',
-        },
-        WY: {
-            stateISO: 'WY',
-            stateName: 'Wyoming',
-        },
-        DC: {
-            stateISO: 'DC',
-            stateName: 'Distrito de Columbia',
-        },
-    },
-    allCountries: {
-        AF: 'Afganistán',
-        AL: 'Albania',
-        DE: 'Alemania',
-        AD: 'Andorra',
-        AO: 'Angola',
-        AI: 'Anguila',
-        AQ: 'Antártida',
-        AG: 'Antigua y Barbuda',
-        SA: 'Arabia Saudita',
-        DZ: 'Argelia',
-        AR: 'Argentina',
-        AM: 'Armenia',
-        AW: 'Aruba',
-        AU: 'Australia',
-        AT: 'Austria',
-        AZ: 'Azerbaiyán',
-        BS: 'Bahamas',
-        BH: 'Bahrein',
-        BD: 'Bangladesh',
-        BB: 'Barbados',
-        BE: 'Bélgica',
-        BZ: 'Belice',
-        BJ: 'Benin',
-        BT: 'Bhután',
-        BY: 'Bielorrusia',
-        MM: 'Birmania',
-        BO: 'Bolivia',
-        BQ: 'Bonaire, San Eustaquio y Saba',
-        BA: 'Bosnia y Herzegovina',
-        BW: 'Botsuana',
-        BR: 'Brazil',
-        BN: 'Brunéi',
-        BG: 'Bulgaria',
-        BF: 'Burkina Faso',
-        BI: 'Burundi',
-        CV: 'Cabo Verde',
-        KH: 'Camboya',
-        CM: 'Camerún',
-        CA: 'Canadá',
-        TD: 'Chad',
-        CL: 'Chile',
-        CN: 'China',
-        CY: 'Chipre',
-        VA: 'Ciudad del Vaticano',
-        CO: 'Colombia',
-        KM: 'Comoras',
-        KP: 'Corea del Norte',
-        KR: 'Corea del Sur',
-        CI: 'Costa de Marfil',
-        CR: 'Costa Rica',
-        HR: 'Croacia',
-        CU: 'Cuba',
-        CW: 'Curazao',
-        DK: 'Dinamarca',
-        DM: 'Dominica',
-        EC: 'Ecuador',
-        EG: 'Egipto',
-        SV: 'El Salvador',
-        AE: 'Emiratos Árabes Unidos',
-        ER: 'Eritrea',
-        SK: 'Eslovaquia',
-        SI: 'Eslovenia',
-        ES: 'España',
-        US: 'Estados Unidos de América',
-        EE: 'Estonia',
-        ET: 'Etiopía',
-        PH: 'Filipinas',
-        FI: 'Finlandia',
-        FJ: 'Fiyi',
-        FR: 'Francia',
-        GA: 'Gabón',
-        GM: 'Gambia',
-        GE: 'Georgia',
-        GH: 'Ghana',
-        GI: 'Gibraltar',
-        GD: 'Granada',
-        GR: 'Greece',
-        GL: 'Groenlandia',
-        GP: 'Guadeloupe',
-        GU: 'Guam',
-        GT: 'Guatemala',
-        GF: 'Guayana Francesa',
-        GG: 'Guernsey',
-        GN: 'Guinea',
-        GQ: 'Guinea Ecuatorial',
-        GW: 'Guinea-Bissau',
-        GY: 'Guyana',
-        HT: 'Haiti',
-        HN: 'Honduras',
-        HK: 'Hong Kong',
-        HU: 'Hungría',
-        IN: 'India',
-        ID: 'Indonesia',
-        IQ: 'Irak',
-        IR: 'Irán',
-        IE: 'Irlanda',
-        AC: 'Isla Ascensión',
-        IM: 'Isla de Man',
-        CX: 'Isla de Navidad',
-        NF: 'Isla Norfolk',
-        IS: 'Islandia',
-        BM: 'Islas Bermudas',
-        KY: 'Islas Caimán',
-        CC: 'Islas Cocos (Keeling)',
-        CK: 'Islas Cook',
-        AX: 'Islas de Åland',
-        FO: 'Islas Feroe',
-        GS: 'Islas Georgias del Sur y Sandwich del Sur',
-        MV: 'Islas Maldivas',
-        FK: 'Islas Malvinas',
-        MP: 'Islas Marianas del Norte',
-        MH: 'Islas Marshall',
-        PN: 'Islas Pitcairn',
-        SB: 'Islas Salomón',
-        TC: 'Islas Turcas y Caicos',
-        UM: 'Islas Ultramarinas Menores de Estados Unidos',
-        VG: 'Islas Vírgenes Británicas',
-        VI: 'Islas Vírgenes de los Estados Unidos',
-        IL: 'Israel',
-        IT: 'Italia',
-        JM: 'Jamaica',
-        JP: 'Japón',
-        JE: 'Jersey',
-        JO: 'Jordania',
-        KZ: 'Kazajistán',
-        KE: 'Kenia',
-        KG: 'Kirguistán',
-        KI: 'Kiribati',
-        XK: 'Kosovo',
-        KW: 'Kuwait',
-        LA: 'Laos',
-        LS: 'Lesoto',
-        LV: 'Letonia',
-        LB: 'Líbano',
-        LR: 'Liberia',
-        LY: 'Libia',
-        LI: 'Liechtenstein',
-        LT: 'Lituania',
-        LU: 'Luxemburgo',
-        MO: 'Macao',
-        MK: 'Macedônia',
-        MG: 'Madagascar',
-        MY: 'Malasia',
-        MW: 'Malawi',
-        ML: 'Mali',
-        MT: 'Malta',
-        MA: 'Marruecos',
-        MQ: 'Martinica',
-        MR: 'Mauritania',
-        MU: 'Mauritius',
-        YT: 'Mayotte',
-        MX: 'México',
-        FM: 'Micronesia',
-        MD: 'Moldavia',
-        MC: 'Mónaco',
-        MN: 'Mongolia',
-        ME: 'Montenegro',
-        MS: 'Montserrat',
-        MZ: 'Mozambique',
-        NA: 'Namibia',
-        NR: 'Nauru',
-        NP: 'Nepal',
-        NI: 'Nicaragua',
-        NE: 'Niger',
-        NG: 'Nigeria',
-        NU: 'Niue',
-        NO: 'Noruega',
-        NC: 'Nueva Caledonia',
-        NZ: 'Nueva Zealand',
-        OM: 'Omán',
-        NL: 'Países Bajos',
-        PK: 'Pakistán',
-        PW: 'Palau',
-        PS: 'Palestina',
-        PA: 'Panamá',
-        PG: 'Papúa Nueva Guinea',
-        PY: 'Paraguay',
-        PE: 'Perú',
-        PF: 'Polinesia Francesa',
-        PL: 'Polonia',
-        PT: 'Portugal',
-        PR: 'Puerto Rico',
-        QA: 'Qatar',
-        GB: 'Reino Unido',
-        CF: 'República Centroafricana',
-        CZ: 'República Checa',
-        SS: 'República de Sudán del Sur',
-        CG: 'República del Congo',
-        CD: 'República Democrática del Congo',
-        DO: 'República Dominicana',
-        RE: 'Reunión',
-        RW: 'Ruanda',
-        RO: 'Rumanía',
-        RU: 'Rusia',
-        EH: 'Sahara Occidental',
-        WS: 'Samoa',
-        AS: 'Samoa Americana',
-        BL: 'San Bartolomé',
-        KN: 'San Cristóbal y Nieves',
-        SM: 'San Marino',
-        MF: 'San Martín (Francia)',
-        PM: 'San Pedro y Miquelón',
-        VC: 'San Vicente y las Granadinas',
-        SH: 'Santa Elena',
-        LC: 'Santa Lucía',
-        ST: 'Santo Tomé y Príncipe',
-        SN: 'Senegal',
-        RS: 'Serbia',
-        SC: 'Seychelles',
-        SL: 'Sierra Leona',
-        SG: 'Singapur',
-        SX: 'Sint Maarten',
-        SY: 'Siria',
-        SO: 'Somalia',
-        LK: 'Sri Lanka',
-        ZA: 'Sudáfrica',
-        SD: 'Sudán',
-        SE: 'Suecia',
-        CH: 'Suiza',
-        SR: 'Surinám',
-        SJ: 'Svalbard y Jan Mayen',
-        SZ: 'Swazilandia',
-        TH: 'Tailandia',
-        TW: 'Taiwán',
-        TZ: 'Tanzania',
-        TJ: 'Tayikistán',
-        IO: 'Territorio Británico del Océano Índico',
-        TF: 'Territorios Australes y Antárticas Franceses',
-        TL: 'Timor Oriental',
-        TG: 'Togo',
-        TK: 'Tokelau',
-        TO: 'Tonga',
-        TT: 'Trinidad y Tobago',
-        TA: 'Tristán de Acuña',
-        TN: 'Tunez',
-        TM: 'Turkmenistán',
-        TR: 'Turquía',
-        TV: 'Tuvalu',
-        UA: 'Ucrania',
-        UG: 'Uganda',
-        UY: 'Uruguay',
-        UZ: 'Uzbekistan',
-        VU: 'Vanuatu',
-        VE: 'Venezuela',
-        VN: 'Vietnam',
-        WF: 'Wallis y Futuna',
-        YE: 'Yemen',
-        DJ: 'Yibuti',
-        ZM: 'Zambia',
-        ZW: 'Zimbabue',
-    },
-    accessibilityHints: {
-        navigateToChatsList: 'Vuelve a la lista de chats',
-        chatWelcomeMessage: 'Mensaje de bienvenida al chat',
-        navigatesToChat: 'Navega a un chat',
-        newMessageLineIndicator: 'Indicador de nueva línea de mensaje',
-        chatMessage: 'mensaje de chat',
-        lastChatMessagePreview: 'Vista previa del último mensaje del chat',
-        workspaceName: 'Nombre del espacio de trabajo',
-        chatUserDisplayNames: 'Nombres de los usuarios del chat',
-        scrollToNewestMessages: 'Desplázate a los mensajes más recientes',
-        prestyledText: 'texto preestilizado',
-        viewAttachment: 'Ver archivo adjunto',
-    },
-    parentReportAction: {
-        deletedMessage: '[Mensaje eliminado]',
-        deletedRequest: '[Pedido eliminado]',
-        hiddenMessage: '[Mensaje oculto]',
-    },
-    threads: {
-        replies: 'Respuestas',
-        reply: 'Respuesta',
-        from: 'De',
-        in: 'en',
-        parentNavigationSummary: ({rootReportName, workspaceName}) => `De ${rootReportName}${workspaceName ? ` en ${workspaceName}` : ''}`,
-    },
-    qrCodes: {
-        copyUrlToClipboard: 'Copiar URL al portapapeles',
-        copied: '¡Copiado!',
-    },
-    moderation: {
-        flagDescription: 'Todos los mensajes marcados se enviarán a un moderador para su revisión.',
-        chooseAReason: 'Elige abajo un motivo para reportarlo:',
-        spam: 'Spam',
-        spamDescription: 'Promoción fuera de tema no solicitada',
-        inconsiderate: 'Desconsiderado',
-        inconsiderateDescription: 'Frase insultante o irrespetuosa, con intenciones cuestionables',
-        intimidation: 'Intimidación',
-        intimidationDescription: 'Persigue agresivamente una agenda sobre objeciones válidas',
-        bullying: 'Bullying',
-        bullyingDescription: 'Apunta a un individuo para obtener obediencia',
-        harassment: 'Acoso',
-        harassmentDescription: 'Comportamiento racista, misógino u otro comportamiento discriminatorio',
-        assault: 'Agresion',
-        assaultDescription: 'Ataque emocional específicamente dirigido con la intención de hacer daño',
-        flaggedContent: 'Este mensaje ha sido marcado por violar las reglas de nuestra comunidad y el contenido se ha ocultado.',
-        hideMessage: 'Ocultar mensaje',
-        revealMessage: 'Revelar mensaje',
-        levelOneResult: 'Envia una advertencia anónima y el mensaje es reportado para revisión.',
-        levelTwoResult: 'Mensaje ocultado del canal, más advertencia anónima y mensaje reportado para revisión.',
-        levelThreeResult: 'Mensaje eliminado del canal, más advertencia anónima y mensaje reportado para revisión.',
-    },
-    distance: {
-        addStop: 'Agregar parada',
-        address: 'Dirección',
-        waypointEditor: 'Editor de puntos de ruta',
-        waypointDescription: {
-            start: 'Comienzo',
-            finish: 'Final',
-            stop: 'Parada',
-        },
-        mapPending: {
-            title: 'Mapa pendiente',
-            subtitle: 'El mapa se generará cuando vuelvas a estar en línea',
-            onlineSubtitle: 'Un momento mientras configuramos el mapa',
+        guides: {
+            screenShare: 'Compartir pantalla',
+            screenShareRequest: 'Expensify te está invitando a compartir la pantalla',
         },
-        errors: {
-            selectSuggestedAddress: 'Por favor, selecciona una dirección sugerida',
+        genericErrorPage: {
+            title: '¡Uh-oh, algo salió mal!',
+            body: {
+                helpTextMobile: 'Intenta cerrar y volver a abrir la aplicación o cambiar a la',
+                helpTextWeb: 'web.',
+                helpTextConcierge: 'Si el problema persiste, comunícate con',
+            },
+            refresh: 'Actualizar',
+        },
+        fileDownload: {
+            success: {
+                title: '!Descargado!',
+                message: 'Archivo descargado correctamente',
+            },
+            generalError: {
+                title: 'Error en la descarga',
+                message: 'No se puede descargar el archivo adjunto',
+            },
+            permissionError: {
+                title: 'Permiso para acceder al almacenamiento',
+                message: 'Expensify no puede guardar los archivos adjuntos sin permiso para acceder al almacenamiento. Haz click en Configuración para actualizar los permisos.',
+            },
+        },
+        desktopApplicationMenu: {
+            mainMenu: 'Nuevo Expensify',
+            about: 'Sobre Nuevo Expensify',
+            update: 'Actualizar Nuevo Expensify',
+            checkForUpdates: 'Buscar actualizaciones',
+            toggleDevTools: 'Ver herramientas de desarrollo',
+            viewShortcuts: 'Ver atajos de teclado',
+            services: 'Servicios',
+            hide: 'Ocultar Nuevo Expensify',
+            hideOthers: 'Ocultar otros',
+            showAll: 'Mostrar todos',
+            quit: 'Salir de Nuevo Expensify',
+            fileMenu: 'Archivo',
+            closeWindow: 'Cerrar ventana',
+            editMenu: 'Editar',
+            undo: 'Deshacer',
+            redo: 'Rehacer',
+            cut: 'Cortar',
+            copy: 'Copiar',
+            paste: 'Pegar',
+            pasteAndMatchStyle: 'Pegar adaptando el estilo',
+            pasteAsPlainText: 'Pegar como texto sin formato',
+            delete: 'Eliminar',
+            selectAll: 'Seleccionar todo',
+            speechSubmenu: 'Voz',
+            startSpeaking: 'Empezar a hablar',
+            stopSpeaking: 'Dejar de Hablar',
+            viewMenu: 'Ver',
+            reload: 'Cargar de nuevo',
+            forceReload: 'Forzar recarga',
+            resetZoom: 'Tamaño real',
+            zoomIn: 'Acercar',
+            zoomOut: 'Alejar',
+            togglefullscreen: 'Alternar pantalla completa',
+            historyMenu: 'Historial',
+            back: 'Atrás',
+            forward: 'Adelante',
+            windowMenu: 'Ventana',
+            minimize: 'Minimizar',
+            zoom: 'Zoom',
+            front: 'Traer todo al frente',
+            helpMenu: 'Ayuda',
+            learnMore: 'Más información',
+            documentation: 'Documentación',
+            communityDiscussions: 'Debates de la comunidad',
+            searchIssues: 'Buscar problemas',
+        },
+        historyMenu: {
+            forward: 'Adelante',
+            back: 'Atrás',
+        },
+        checkForUpdatesModal: {
+            available: {
+                title: 'Actualización disponible',
+                message: 'La nueva versión estará disponible dentro de poco. Te notificaremos cuando esté lista.',
+                soundsGood: 'Suena bien',
+            },
+            notAvailable: {
+                title: 'Actualización no disponible',
+                message: 'No existe ninguna actualización disponible! Inténtalo de nuevo más tarde.',
+                okay: 'Vale',
+            },
+            error: {
+                title: 'Comprobación fallida',
+                message: 'No hemos podido comprobar si existe una actualización. Inténtalo de nuevo más tarde!',
+            },
+        },
+        report: {
+            genericCreateReportFailureMessage: 'Error inesperado al crear el chat. Por favor, inténtalo más tarde',
+            genericAddCommentFailureMessage: 'Error inesperado al añadir el comentario. Por favor, inténtalo más tarde',
+            noActivityYet: 'Sin actividad todavía',
+        },
+        chronos: {
+            oooEventSummaryFullDay: ({summary, dayCount, date}) => `${summary} por ${dayCount} ${dayCount === 1 ? 'día' : 'días'} hasta el ${date}`,
+            oooEventSummaryPartialDay: ({summary, timePeriod, date}) => `${summary} de ${timePeriod} del ${date}`,
+        },
+        footer: {
+            features: 'Características',
+            expenseManagement: 'Gestión de Gastos',
+            spendManagement: 'Control de Gastos',
+            expenseReports: 'Informes de Gastos',
+            companyCreditCard: 'Tarjeta de Crédito Corporativa',
+            receiptScanningApp: 'Aplicación de Escaneado de Recibos',
+            billPay: 'Pago de Facturas',
+            invoicing: 'Facturación',
+            CPACard: 'Tarjeta Para Contables',
+            payroll: 'Nómina',
+            travel: 'Viajes',
+            resources: 'Recursos',
+            expensifyApproved: 'ExpensifyApproved!',
+            pressKit: 'Kit de Prensa',
+            support: 'Soporte',
+            expensifyHelp: 'ExpensifyHelp',
+            community: 'Comunidad',
+            privacy: 'Privacidad',
+            learnMore: 'Más Información',
+            aboutExpensify: 'Acerca de Expensify',
+            blog: 'Blog',
+            jobs: 'Empleo',
+            expensifyOrg: 'Expensify.org',
+            investorRelations: 'Relaciones Con Los Inversores',
+            getStarted: 'Comenzar',
+            createAccount: 'Crear Una Cuenta Nueva',
+            logIn: 'Conectarse',
+        },
+        allStates: {
+            AK: {
+                stateISO: 'AK',
+                stateName: 'Alaska',
+            },
+            AL: {
+                stateISO: 'AL',
+                stateName: 'Alabama',
+            },
+            AR: {
+                stateISO: 'AR',
+                stateName: 'Arkansas',
+            },
+            AZ: {
+                stateISO: 'AZ',
+                stateName: 'Arizona',
+            },
+            CA: {
+                stateISO: 'CA',
+                stateName: 'California',
+            },
+            CO: {
+                stateISO: 'CO',
+                stateName: 'Colorado',
+            },
+            CT: {
+                stateISO: 'CT',
+                stateName: 'Connecticut',
+            },
+            DE: {
+                stateISO: 'DE',
+                stateName: 'Delaware',
+            },
+            FL: {
+                stateISO: 'FL',
+                stateName: 'Florida',
+            },
+            GA: {
+                stateISO: 'GA',
+                stateName: 'Georgia',
+            },
+            HI: {
+                stateISO: 'HI',
+                stateName: 'Hawái',
+            },
+            IA: {
+                stateISO: 'IA',
+                stateName: 'Iowa',
+            },
+            ID: {
+                stateISO: 'ID',
+                stateName: 'Idaho',
+            },
+            IL: {
+                stateISO: 'IL',
+                stateName: 'Illinois',
+            },
+            IN: {
+                stateISO: 'IN',
+                stateName: 'Indiana',
+            },
+            KS: {
+                stateISO: 'KS',
+                stateName: 'Kansas',
+            },
+            KY: {
+                stateISO: 'KY',
+                stateName: 'Kentucky',
+            },
+            LA: {
+                stateISO: 'LA',
+                stateName: 'Luisiana',
+            },
+            MA: {
+                stateISO: 'MA',
+                stateName: 'Massachusetts',
+            },
+            MD: {
+                stateISO: 'MD',
+                stateName: 'Maryland',
+            },
+            ME: {
+                stateISO: 'ME',
+                stateName: 'Maine',
+            },
+            MI: {
+                stateISO: 'MI',
+                stateName: 'Míchigan',
+            },
+            MN: {
+                stateISO: 'MN',
+                stateName: 'Minnesota',
+            },
+            MO: {
+                stateISO: 'MO',
+                stateName: 'Misuri',
+            },
+            MS: {
+                stateISO: 'MS',
+                stateName: 'Misisipi',
+            },
+            MT: {
+                stateISO: 'MT',
+                stateName: 'Montana',
+            },
+            NC: {
+                stateISO: 'NC',
+                stateName: 'Carolina del Norte',
+            },
+            ND: {
+                stateISO: 'ND',
+                stateName: 'Dakota del Norte',
+            },
+            NE: {
+                stateISO: 'NE',
+                stateName: 'Nebraska',
+            },
+            NH: {
+                stateISO: 'NH',
+                stateName: 'Nuevo Hampshire',
+            },
+            NJ: {
+                stateISO: 'NJ',
+                stateName: 'Nueva Jersey',
+            },
+            NM: {
+                stateISO: 'NM',
+                stateName: 'Nuevo México',
+            },
+            NV: {
+                stateISO: 'NV',
+                stateName: 'Nevada',
+            },
+            NY: {
+                stateISO: 'NY',
+                stateName: 'Nueva York',
+            },
+            OH: {
+                stateISO: 'OH',
+                stateName: 'Ohio',
+            },
+            OK: {
+                stateISO: 'OK',
+                stateName: 'Oklahoma',
+            },
+            OR: {
+                stateISO: 'OR',
+                stateName: 'Oregón',
+            },
+            PA: {
+                stateISO: 'PA',
+                stateName: 'Pensilvania',
+            },
+            PR: {
+                stateISO: 'PR',
+                stateName: 'Puerto Rico',
+            },
+            RI: {
+                stateISO: 'RI',
+                stateName: 'Rhode Island',
+            },
+            SC: {
+                stateISO: 'SC',
+                stateName: 'Carolina del Sur',
+            },
+            SD: {
+                stateISO: 'SD',
+                stateName: 'Dakota del Sur',
+            },
+            TN: {
+                stateISO: 'TN',
+                stateName: 'Tennessee',
+            },
+            TX: {
+                stateISO: 'TX',
+                stateName: 'Texas',
+            },
+            UT: {
+                stateISO: 'UT',
+                stateName: 'Utah',
+            },
+            VA: {
+                stateISO: 'VA',
+                stateName: 'Virginia',
+            },
+            VT: {
+                stateISO: 'VT',
+                stateName: 'Vermont',
+            },
+            WA: {
+                stateISO: 'WA',
+                stateName: 'Washington',
+            },
+            WI: {
+                stateISO: 'WI',
+                stateName: 'Wisconsin',
+            },
+            WV: {
+                stateISO: 'WV',
+                stateName: 'Virginia Occidental',
+            },
+            WY: {
+                stateISO: 'WY',
+                stateName: 'Wyoming',
+            },
+            DC: {
+                stateISO: 'DC',
+                stateName: 'Distrito de Columbia',
+            },
+        },
+        allCountries: {
+            AF: 'Afganistán',
+            AL: 'Albania',
+            DE: 'Alemania',
+            AD: 'Andorra',
+            AO: 'Angola',
+            AI: 'Anguila',
+            AQ: 'Antártida',
+            AG: 'Antigua y Barbuda',
+            SA: 'Arabia Saudita',
+            DZ: 'Argelia',
+            AR: 'Argentina',
+            AM: 'Armenia',
+            AW: 'Aruba',
+            AU: 'Australia',
+            AT: 'Austria',
+            AZ: 'Azerbaiyán',
+            BS: 'Bahamas',
+            BH: 'Bahrein',
+            BD: 'Bangladesh',
+            BB: 'Barbados',
+            BE: 'Bélgica',
+            BZ: 'Belice',
+            BJ: 'Benin',
+            BT: 'Bhután',
+            BY: 'Bielorrusia',
+            MM: 'Birmania',
+            BO: 'Bolivia',
+            BQ: 'Bonaire, San Eustaquio y Saba',
+            BA: 'Bosnia y Herzegovina',
+            BW: 'Botsuana',
+            BR: 'Brazil',
+            BN: 'Brunéi',
+            BG: 'Bulgaria',
+            BF: 'Burkina Faso',
+            BI: 'Burundi',
+            CV: 'Cabo Verde',
+            KH: 'Camboya',
+            CM: 'Camerún',
+            CA: 'Canadá',
+            TD: 'Chad',
+            CL: 'Chile',
+            CN: 'China',
+            CY: 'Chipre',
+            VA: 'Ciudad del Vaticano',
+            CO: 'Colombia',
+            KM: 'Comoras',
+            KP: 'Corea del Norte',
+            KR: 'Corea del Sur',
+            CI: 'Costa de Marfil',
+            CR: 'Costa Rica',
+            HR: 'Croacia',
+            CU: 'Cuba',
+            CW: 'Curazao',
+            DK: 'Dinamarca',
+            DM: 'Dominica',
+            EC: 'Ecuador',
+            EG: 'Egipto',
+            SV: 'El Salvador',
+            AE: 'Emiratos Árabes Unidos',
+            ER: 'Eritrea',
+            SK: 'Eslovaquia',
+            SI: 'Eslovenia',
+            ES: 'España',
+            US: 'Estados Unidos de América',
+            EE: 'Estonia',
+            ET: 'Etiopía',
+            PH: 'Filipinas',
+            FI: 'Finlandia',
+            FJ: 'Fiyi',
+            FR: 'Francia',
+            GA: 'Gabón',
+            GM: 'Gambia',
+            GE: 'Georgia',
+            GH: 'Ghana',
+            GI: 'Gibraltar',
+            GD: 'Granada',
+            GR: 'Greece',
+            GL: 'Groenlandia',
+            GP: 'Guadeloupe',
+            GU: 'Guam',
+            GT: 'Guatemala',
+            GF: 'Guayana Francesa',
+            GG: 'Guernsey',
+            GN: 'Guinea',
+            GQ: 'Guinea Ecuatorial',
+            GW: 'Guinea-Bissau',
+            GY: 'Guyana',
+            HT: 'Haiti',
+            HN: 'Honduras',
+            HK: 'Hong Kong',
+            HU: 'Hungría',
+            IN: 'India',
+            ID: 'Indonesia',
+            IQ: 'Irak',
+            IR: 'Irán',
+            IE: 'Irlanda',
+            AC: 'Isla Ascensión',
+            IM: 'Isla de Man',
+            CX: 'Isla de Navidad',
+            NF: 'Isla Norfolk',
+            IS: 'Islandia',
+            BM: 'Islas Bermudas',
+            KY: 'Islas Caimán',
+            CC: 'Islas Cocos (Keeling)',
+            CK: 'Islas Cook',
+            AX: 'Islas de Åland',
+            FO: 'Islas Feroe',
+            GS: 'Islas Georgias del Sur y Sandwich del Sur',
+            MV: 'Islas Maldivas',
+            FK: 'Islas Malvinas',
+            MP: 'Islas Marianas del Norte',
+            MH: 'Islas Marshall',
+            PN: 'Islas Pitcairn',
+            SB: 'Islas Salomón',
+            TC: 'Islas Turcas y Caicos',
+            UM: 'Islas Ultramarinas Menores de Estados Unidos',
+            VG: 'Islas Vírgenes Británicas',
+            VI: 'Islas Vírgenes de los Estados Unidos',
+            IL: 'Israel',
+            IT: 'Italia',
+            JM: 'Jamaica',
+            JP: 'Japón',
+            JE: 'Jersey',
+            JO: 'Jordania',
+            KZ: 'Kazajistán',
+            KE: 'Kenia',
+            KG: 'Kirguistán',
+            KI: 'Kiribati',
+            XK: 'Kosovo',
+            KW: 'Kuwait',
+            LA: 'Laos',
+            LS: 'Lesoto',
+            LV: 'Letonia',
+            LB: 'Líbano',
+            LR: 'Liberia',
+            LY: 'Libia',
+            LI: 'Liechtenstein',
+            LT: 'Lituania',
+            LU: 'Luxemburgo',
+            MO: 'Macao',
+            MK: 'Macedônia',
+            MG: 'Madagascar',
+            MY: 'Malasia',
+            MW: 'Malawi',
+            ML: 'Mali',
+            MT: 'Malta',
+            MA: 'Marruecos',
+            MQ: 'Martinica',
+            MR: 'Mauritania',
+            MU: 'Mauritius',
+            YT: 'Mayotte',
+            MX: 'México',
+            FM: 'Micronesia',
+            MD: 'Moldavia',
+            MC: 'Mónaco',
+            MN: 'Mongolia',
+            ME: 'Montenegro',
+            MS: 'Montserrat',
+            MZ: 'Mozambique',
+            NA: 'Namibia',
+            NR: 'Nauru',
+            NP: 'Nepal',
+            NI: 'Nicaragua',
+            NE: 'Niger',
+            NG: 'Nigeria',
+            NU: 'Niue',
+            NO: 'Noruega',
+            NC: 'Nueva Caledonia',
+            NZ: 'Nueva Zealand',
+            OM: 'Omán',
+            NL: 'Países Bajos',
+            PK: 'Pakistán',
+            PW: 'Palau',
+            PS: 'Palestina',
+            PA: 'Panamá',
+            PG: 'Papúa Nueva Guinea',
+            PY: 'Paraguay',
+            PE: 'Perú',
+            PF: 'Polinesia Francesa',
+            PL: 'Polonia',
+            PT: 'Portugal',
+            PR: 'Puerto Rico',
+            QA: 'Qatar',
+            GB: 'Reino Unido',
+            CF: 'República Centroafricana',
+            CZ: 'República Checa',
+            SS: 'República de Sudán del Sur',
+            CG: 'República del Congo',
+            CD: 'República Democrática del Congo',
+            DO: 'República Dominicana',
+            RE: 'Reunión',
+            RW: 'Ruanda',
+            RO: 'Rumanía',
+            RU: 'Rusia',
+            EH: 'Sahara Occidental',
+            WS: 'Samoa',
+            AS: 'Samoa Americana',
+            BL: 'San Bartolomé',
+            KN: 'San Cristóbal y Nieves',
+            SM: 'San Marino',
+            MF: 'San Martín (Francia)',
+            PM: 'San Pedro y Miquelón',
+            VC: 'San Vicente y las Granadinas',
+            SH: 'Santa Elena',
+            LC: 'Santa Lucía',
+            ST: 'Santo Tomé y Príncipe',
+            SN: 'Senegal',
+            RS: 'Serbia',
+            SC: 'Seychelles',
+            SL: 'Sierra Leona',
+            SG: 'Singapur',
+            SX: 'Sint Maarten',
+            SY: 'Siria',
+            SO: 'Somalia',
+            LK: 'Sri Lanka',
+            ZA: 'Sudáfrica',
+            SD: 'Sudán',
+            SE: 'Suecia',
+            CH: 'Suiza',
+            SR: 'Surinám',
+            SJ: 'Svalbard y Jan Mayen',
+            SZ: 'Swazilandia',
+            TH: 'Tailandia',
+            TW: 'Taiwán',
+            TZ: 'Tanzania',
+            TJ: 'Tayikistán',
+            IO: 'Territorio Británico del Océano Índico',
+            TF: 'Territorios Australes y Antárticas Franceses',
+            TL: 'Timor Oriental',
+            TG: 'Togo',
+            TK: 'Tokelau',
+            TO: 'Tonga',
+            TT: 'Trinidad y Tobago',
+            TA: 'Tristán de Acuña',
+            TN: 'Tunez',
+            TM: 'Turkmenistán',
+            TR: 'Turquía',
+            TV: 'Tuvalu',
+            UA: 'Ucrania',
+            UG: 'Uganda',
+            UY: 'Uruguay',
+            UZ: 'Uzbekistan',
+            VU: 'Vanuatu',
+            VE: 'Venezuela',
+            VN: 'Vietnam',
+            WF: 'Wallis y Futuna',
+            YE: 'Yemen',
+            DJ: 'Yibuti',
+            ZM: 'Zambia',
+            ZW: 'Zimbabue',
+        },
+        accessibilityHints: {
+            navigateToChatsList: 'Vuelve a la lista de chats',
+            chatWelcomeMessage: 'Mensaje de bienvenida al chat',
+            navigatesToChat: 'Navega a un chat',
+            newMessageLineIndicator: 'Indicador de nueva línea de mensaje',
+            chatMessage: 'mensaje de chat',
+            lastChatMessagePreview: 'Vista previa del último mensaje del chat',
+            workspaceName: 'Nombre del espacio de trabajo',
+            chatUserDisplayNames: 'Nombres de los usuarios del chat',
+            scrollToNewestMessages: 'Desplázate a los mensajes más recientes',
+            prestyledText: 'texto preestilizado',
+            viewAttachment: 'Ver archivo adjunto',
+        },
+        parentReportAction: {
+            deletedMessage: '[Mensaje eliminado]',
+            deletedRequest: '[Pedido eliminado]',
+            hiddenMessage: '[Mensaje oculto]',
+        },
+        threads: {
+            replies: 'Respuestas',
+            reply: 'Respuesta',
+            from: 'De',
+            in: 'en',
+            parentNavigationSummary: ({rootReportName, workspaceName}) => `De ${rootReportName}${workspaceName ? ` en ${workspaceName}` : ''}`,
+        },
+        qrCodes: {
+            copyUrlToClipboard: 'Copiar URL al portapapeles',
+            copied: '¡Copiado!',
+        },
+        moderation: {
+            flagDescription: 'Todos los mensajes marcados se enviarán a un moderador para su revisión.',
+            chooseAReason: 'Elige abajo un motivo para reportarlo:',
+            spam: 'Spam',
+            spamDescription: 'Promoción fuera de tema no solicitada',
+            inconsiderate: 'Desconsiderado',
+            inconsiderateDescription: 'Frase insultante o irrespetuosa, con intenciones cuestionables',
+            intimidation: 'Intimidación',
+            intimidationDescription: 'Persigue agresivamente una agenda sobre objeciones válidas',
+            bullying: 'Bullying',
+            bullyingDescription: 'Apunta a un individuo para obtener obediencia',
+            harassment: 'Acoso',
+            harassmentDescription: 'Comportamiento racista, misógino u otro comportamiento discriminatorio',
+            assault: 'Agresion',
+            assaultDescription: 'Ataque emocional específicamente dirigido con la intención de hacer daño',
+            flaggedContent: 'Este mensaje ha sido marcado por violar las reglas de nuestra comunidad y el contenido se ha ocultado.',
+            hideMessage: 'Ocultar mensaje',
+            revealMessage: 'Revelar mensaje',
+            levelOneResult: 'Envia una advertencia anónima y el mensaje es reportado para revisión.',
+            levelTwoResult: 'Mensaje ocultado del canal, más advertencia anónima y mensaje reportado para revisión.',
+            levelThreeResult: 'Mensaje eliminado del canal, más advertencia anónima y mensaje reportado para revisión.',
+        },
+        distance: {
+            addStop: 'Agregar parada',
+            address: 'Dirección',
+            waypointEditor: 'Editor de puntos de ruta',
+            waypointDescription: {
+                start: 'Comienzo',
+                finish: 'Final',
+                stop: 'Parada',
+            },
+            mapPending: {
+                title: 'Mapa pendiente',
+                subtitle: 'El mapa se generará cuando vuelvas a estar en línea',
+                onlineSubtitle: 'Un momento mientras configuramos el mapa',
+            },
+            errors: {
+                selectSuggestedAddress: 'Por favor, selecciona una dirección sugerida',
+            },
+        },
+        countrySelectorModal: {
+            placeholderText: 'Buscar para ver opciones',
+        },
+        stateSelectorModal: {
+            placeholderText: 'Buscar para ver opciones',
         },
-    },
-    countrySelectorModal: {
-        placeholderText: 'Buscar para ver opciones',
-    },
-    stateSelectorModal: {
-        placeholderText: 'Buscar para ver opciones',
     },
 };
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index e708b53708b1..28a2332db221 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -37,11 +37,10 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
     const defaultEmoji = draftEmojiCode || currentUserEmojiCode;
     const defaultText = draftEmojiCode ? draftText : currentUserStatusText;
     const customStatus = draftEmojiCode ? `${draftEmojiCode} ${draftText}` : `${currentUserEmojiCode || ''} ${currentUserStatusText || ''}`;
-    
     const hasDraftStatus = !!draftEmojiCode || !!draftText;
     const formattedClearAfter = DateUtils.formatDateTo12Hour(lodashGet(currentUserPersonalDetails, 'status.clearAfter', ''));
     const formattedClearAfterDraft = DateUtils.formatDateTo12Hour(draftClearAfter);
-    const customClearAfter = draftClearAfter ? formattedClearAfterDraft : formattedClearAfter ||'';
+    const customClearAfter = draftClearAfter ? formattedClearAfterDraft : formattedClearAfter || '';
 
     const updateStatus = useCallback(() => {
         const endOfDay = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss');

From 243c7e3d40c461ca56e289af361de80082da8fd2 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 22 Aug 2023 10:40:25 +0200
Subject: [PATCH 011/118] add SetTimePage

---
 src/languages/en.js                           |  8 +-
 src/languages/es.js                           | 10 +--
 src/libs/DateUtils.js                         | 44 +++++++++-
 .../AppNavigator/ModalStackNavigators.js      |  7 ++
 .../Profile/CustomStatus/SetTimePage.js       | 85 +++++++++++++++++++
 .../CustomStatus/StatusClearAfterPage.js      | 48 ++++++-----
 6 files changed, 172 insertions(+), 30 deletions(-)
 create mode 100644 src/pages/settings/Profile/CustomStatus/SetTimePage.js

diff --git a/src/languages/en.js b/src/languages/en.js
index 094487369f8a..586fafd9276f 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -896,10 +896,10 @@ export default {
         message: 'Message',
         timePeriods: {
             never: 'Never',
-            thirtyMinutes: 'Thirty minutes',
-            oneHour: 'One hour',
-            afterToday: 'After today',
-            afterWeek: 'After week',
+            thirtyMinutes: '30 minutes',
+            oneHour: '1 hour',
+            afterToday: 'Today',
+            afterWeek: 'A week',
             custom: 'Custom',
         },
         untilTomorrow: 'Until tomorrow',
diff --git a/src/languages/es.js b/src/languages/es.js
index 37ef60152c6c..1315d02de363 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -900,13 +900,13 @@ export default {
         message: 'Mensaje',
         timePeriods: {
             never: 'Nunca',
-            thirtyMinutes: 'Treinta minutos',
-            oneHour: 'Una hora',
-            afterToday: 'Después de hoy',
-            afterWeek: 'Después de una semana',
+            thirtyMinutes: '30 minutos',
+            oneHour: '1 hora',
+            afterToday: 'Hoy',
+            afterWeek: 'Una semana',
             custom: 'Personalizado',
-            untilTomorrow: 'Hasta mañana',
         },
+        untilTomorrow: 'Hasta mañana',
         untilTime: ({time}) => {
             // Check for HH:MM AM/PM format and starts with '01:'
             if (CONST.REGEX.TIME_STARTS_01.test(time)) {
diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index 27c5e9397fb5..ac0537fc05d4 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -253,7 +253,15 @@ function extractDate(time) {
  * it's kind of 'newer' date
  */
 function extractTime(dateTimeString) {
-    return moment(dateTimeString).format('HH:mm');
+    return moment(dateTimeString).format('hh:mm');
+}
+/**
+ * @param {string} dateTimeString
+ * @returns {string} example: 2023-05-16
+ * it's kind of 'newer' date
+ */
+function extractTime12Hour(dateTimeString) {
+    return moment(dateTimeString).format('hh:mm A');
 }
 
 /**
@@ -284,7 +292,7 @@ function getDateBasedFromType(type) {
         default:
             return '';
     }
-  }
+}
 
 /**
  * receive date like 2020-05-16 05:34:14 and format it to show in string like "Until 05:34 PM"
@@ -319,6 +327,36 @@ function getStatusUntilDate(inputDate) {
     return translateLocal('statusPage.untilTime', {time: input.format('YYYY-MM-DD hh:mm A')});
 }
 
+/**
+ * Update the hour and minute of a date.
+ *
+ * @param {string} time - Time in "hh:mm A" format (like "10:55 AM").
+ * @param {string} date - Date in "YYYY-MM-DD HH:mm:ss" format.
+ *
+ * @returns {string} - Date with updated time in "YYYY-MM-DD HH:mm:ss" format.
+ */
+function setTimeOrDefaultToTomorrow(time, date) {
+    const dateToUse = date ? moment(date) : moment().endOf('day');
+
+    // Split the time into hour, minute, and period (AM/PM)
+    const [hour, minute, period] = time.match(/(\d+):(\d+) (\w\w)/).slice(1);
+
+    // Adjust the hour based on the period
+    let adjustedHour = parseInt(hour, 10);
+    if (period === 'PM' && adjustedHour !== 12) {
+        adjustedHour += 12;
+    } else if (period === 'AM' && adjustedHour === 12) {
+        adjustedHour = 0; // For 12 AM, set to 00
+    }
+
+    // Set the hour, minute, and second
+    dateToUse.hour(adjustedHour);
+    dateToUse.minute(minute);
+    dateToUse.second(0); // Reset seconds to zero
+
+    return dateToUse.format('YYYY-MM-DD HH:mm:ss');
+}
+
 /**
  * @namespace DateUtils
  */
@@ -344,6 +382,8 @@ const DateUtils = {
     extractTime,
     formatDateTo12Hour,
     getStatusUntilDate,
+    extractTime12Hour,
+    setTimeOrDefaultToTomorrow,
 };
 
 export default DateUtils;
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
index 63c83d9951b5..9480dc4aeae2 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
@@ -550,6 +550,13 @@ const SettingsModalStackNavigator = createModalStackNavigator([
         },
         name: 'Settings_Status_Clear_After_Custom',
     },
+    {
+        getComponent: () => {
+            const Settings_Status_Clear_After_Time = require('../../../pages/settings/Profile/CustomStatus/SetTimePage').default;
+            return Settings_Status_Clear_After_Time;
+        },
+        name: 'Settings_Status_Clear_After_Time',
+    },
     {
         getComponent: () => {
             const WorkspaceInitialPage = require('../../../pages/workspace/WorkspaceInitialPage').default;
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
new file mode 100644
index 000000000000..18f707ea22f2
--- /dev/null
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -0,0 +1,85 @@
+import PropTypes from 'prop-types';
+import React, {useCallback} from 'react';
+import {withOnyx} from 'react-native-onyx';
+import lodashGet from 'lodash/get';
+import withCurrentUserPersonalDetails from '../../../../components/withCurrentUserPersonalDetails';
+import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator';
+import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
+import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
+import ScreenWrapper from '../../../../components/ScreenWrapper';
+import TimePicker from '../../../../components/TimePicker';
+import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
+import Navigation from '../../../../libs/Navigation/Navigation';
+import * as User from '../../../../libs/actions/User';
+import DateUtils from '../../../../libs/DateUtils';
+import compose from '../../../../libs/compose';
+import ONYXKEYS from '../../../../ONYXKEYS';
+import ROUTES from '../../../../ROUTES';
+
+const propTypes = {
+    /** User's private personal details */
+    privatePersonalDetails: PropTypes.shape({
+        dob: PropTypes.string,
+    }),
+
+    ...withLocalizePropTypes,
+};
+
+const defaultProps = {
+    privatePersonalDetails: {
+        dob: '',
+    },
+};
+
+function SetTimePage({translate, privatePersonalDetails, customStatus, currentUserPersonalDetails}) {
+    usePrivatePersonalDetails();
+
+    const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
+    const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
+    const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
+
+    const onSubmitButtonPress = useCallback((time, amPmValue) => {
+        const timeToUse = DateUtils.setTimeOrDefaultToTomorrow(`${time} ${amPmValue}`, customDateTemporary);
+
+        User.updateDraftCustomStatus({customDateTemporary: timeToUse});
+        Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
+    }, [customDateTemporary]);
+
+
+    if (lodashGet(privatePersonalDetails, 'isLoading', true)) {
+        return <FullscreenLoadingIndicator />;
+    }
+
+    const customStatusTime = DateUtils.extractTime(customDateTemporary || draftClearAfter || clearAfter);
+
+    return (
+        <ScreenWrapper includeSafeAreaPaddingBottom={false}>
+            <HeaderWithBackButton
+                title={translate('common.dob')}
+                onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
+            />
+            <TimePicker
+                inputID="timePicker"
+                defaultValue={customStatusTime}
+                onSubmitButtonPress={onSubmitButtonPress}
+            />
+        </ScreenWrapper>
+    );
+}
+
+SetTimePage.propTypes = propTypes;
+SetTimePage.defaultProps = defaultProps;
+SetTimePage.displayName = 'SetTimePage';
+
+export default compose(
+    withCurrentUserPersonalDetails,
+    withLocalize,
+    withOnyx({
+        privatePersonalDetails: {
+            key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS,
+        },
+        customStatus: {
+            key: ONYXKEYS.CUSTOM_STATUS_DRAFT,
+        },
+    }),
+)(SetTimePage);
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 4a30e98c87d1..9b208f9c3d14 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -16,16 +16,21 @@ import useLocalize from '../../../../hooks/useLocalize';
 import ONYXKEYS from '../../../../ONYXKEYS';
 import CONST from '../../../../CONST';
 import * as User from '../../../../libs/actions/User';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
+import withLocalize from '../../../../components/withLocalize';
 import compose from '../../../../libs/compose';
 import DateUtils from '../../../../libs/DateUtils';
-import withCurrentUserPersonalDetails from '../../../../components/withCurrentUserPersonalDetails';
+import withCurrentUserPersonalDetails, { withCurrentUserPersonalDetailsDefaultProps } from '../../../../components/withCurrentUserPersonalDetails';
+import personalDetailsPropType from '../../../personalDetailsPropType';
 
-const defaultProps = {};
+const defaultProps = {
+  ...withCurrentUserPersonalDetailsDefaultProps,
+};
 
-const propTypes = {};
+const propTypes = {
+  currentUserPersonalDetails: personalDetailsPropType,
+};
 
-function StatusClearAfterPage({currentUserPersonalDetails, customStatus, ...props}) {
+function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const localize = useLocalize();
     const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
 
@@ -53,28 +58,33 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus, ...prop
             calculatedDraftDate = DateUtils.getDateBasedFromType(selectedRange.value);
         }
 
-        User.updateDraftCustomStatus({clearAfter: calculatedDraftDate});
+        User.updateDraftCustomStatus({clearAfter: calculatedDraftDate, customDateTemporary: calculatedDraftDate});
         Navigation.goBack(ROUTES.SETTINGS_STATUS);
     };
 
-    const updateMode = useCallback((mode) => {
-        if (mode.value === CONST.CUSTOM_STATUS_TYPES.CUSTOM) {
-            User.updateDraftCustomStatus({customDateTemporary: DateUtils.getOneHourFromNow()});
-        }
-        setDraftPeriod(mode.value);
-    }, []);
+    const updateMode = useCallback(
+        (mode) => {
+            if (mode.value === draftPeriod) return;
+            User.updateDraftCustomStatus({
+                customDateTemporary: mode.value === CONST.CUSTOM_STATUS_TYPES.CUSTOM ? DateUtils.getOneHourFromNow() : DateUtils.getDateBasedFromType(mode.value),
+            });
+            setDraftPeriod(mode.value);
+        },
+        [draftPeriod],
+    );
 
     useEffect(() => {
-        if ((clearAfter && !draftClearAfter) || draftClearAfter) {
-            User.updateDraftCustomStatus({customDateTemporary: (clearAfter && !draftClearAfter) || draftClearAfter});
-            return;
-        }
-        // value by default is CONST.CUSTOM_STATUS_TYPES.AFTER_TODAY
-        User.updateDraftCustomStatus({customDate: DateUtils.getEndOfToday()});
+        User.updateDraftCustomStatus({
+            customDateTemporary: clearAfter,
+            clearAfter,
+        });
+
+    // eslint-disable-next-line react-hooks/exhaustive-deps
     }, []);
 
     const customStatusDate = DateUtils.extractDate(customDateTemporary || draftClearAfter || clearAfter);
-    const customStatusTime = DateUtils.extractTime(customDateTemporary || draftClearAfter || clearAfter);
+    const customStatusTime = DateUtils.extractTime12Hour(customDateTemporary || clearAfter);
+
     return (
         <ScreenWrapper>
             <HeaderWithBackButton

From 1f51af152159b2887e1e2c0f370e3af979b8de2b Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 22 Aug 2023 10:41:01 +0200
Subject: [PATCH 012/118] use correct clearAfter for saving

---
 src/pages/settings/Profile/CustomStatus/StatusPage.js | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 28a2332db221..d9ec14f3fc7c 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -30,6 +30,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
     const localize = useLocalize();
     const currentUserEmojiCode = lodashGet(currentUserPersonalDetails, 'status.emojiCode', '');
     const currentUserStatusText = lodashGet(currentUserPersonalDetails, 'status.text', '');
+    const currentUserClearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
     const draftEmojiCode = lodashGet(draftStatus, 'emojiCode');
     const draftText = lodashGet(draftStatus, 'text');
     const draftClearAfter = lodashGet(draftStatus, 'clearAfter');
@@ -44,11 +45,11 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
     const updateStatus = useCallback(() => {
         const endOfDay = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss');
-        User.updateCustomStatus({text: defaultText, emojiCode: defaultEmoji, clearAfter: endOfDay});
+        User.updateCustomStatus({text: defaultText, emojiCode: defaultEmoji, clearAfter: draftClearAfter || endOfDay || currentUserClearAfter});
 
         User.clearDraftCustomStatus();
         Navigation.goBack(ROUTES.SETTINGS_PROFILE);
-    }, [defaultText, defaultEmoji]);
+    }, [defaultText, defaultEmoji, currentUserClearAfter, draftClearAfter]);
 
     const clearStatus = () => {
         User.clearCustomStatus();

From 55ecba368119bdc4d69ce9c2779aa2b971c3c9bc Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 23 Aug 2023 15:47:41 +0200
Subject: [PATCH 013/118] add styles to AmountTextInput

---
 src/components/AmountTextInput.js | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/src/components/AmountTextInput.js b/src/components/AmountTextInput.js
index 8472ef271be0..de2296bd3833 100644
--- a/src/components/AmountTextInput.js
+++ b/src/components/AmountTextInput.js
@@ -25,12 +25,24 @@ const propTypes = {
 
     /** Function to call when selection in text input is changed */
     onSelectionChange: PropTypes.func,
+
+    /** Function to call when key is pressed in text input */
+    onKeyPress: PropTypes.func,
+
+    /** Style for the input */
+    style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
+    
+    /** Style for the container */
+    containerStyles: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
 };
 
 const defaultProps = {
     forwardedRef: undefined,
     selection: undefined,
     onSelectionChange: () => {},
+    onKeyPress: () => {},
+    style: {},
+    containerStyles: {},
 };
 
 function AmountTextInput(props) {
@@ -39,7 +51,7 @@ function AmountTextInput(props) {
             disableKeyboard
             autoGrow
             hideFocusedState
-            inputStyle={[styles.iouAmountTextInput, styles.p0, styles.noLeftBorderRadius, styles.noRightBorderRadius]}
+            inputStyle={[styles.iouAmountTextInput, styles.p0, styles.noLeftBorderRadius, styles.noRightBorderRadius, props.style]}
             textInputContainerStyles={[styles.borderNone, styles.noLeftBorderRadius, styles.noRightBorderRadius]}
             onChangeText={props.onChangeAmount}
             ref={props.forwardedRef}
@@ -50,6 +62,8 @@ function AmountTextInput(props) {
             selection={props.selection}
             onSelectionChange={props.onSelectionChange}
             accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
+            onKeyPress={props.onKeyPress}
+            containerStyles={props.containerStyles}
         />
     );
 }

From 7cc9a4b172afc415becb645a4a9b0528e9154aef Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 23 Aug 2023 15:48:22 +0200
Subject: [PATCH 014/118] add isDisabledLongPress to button

---
 src/components/Button/index.js | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/components/Button/index.js b/src/components/Button/index.js
index a850a43d2fb0..c0ea547a0aaa 100644
--- a/src/components/Button/index.js
+++ b/src/components/Button/index.js
@@ -120,6 +120,9 @@ const propTypes = {
     /** A ref to forward the button */
     // eslint-disable-next-line react/forbid-prop-types
     forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({current: PropTypes.object})]),
+
+    /** Whether the long press is disabled */
+    isDisabledLongPress: PropTypes.bool,
 };
 
 const defaultProps = {
@@ -155,6 +158,7 @@ const defaultProps = {
     nativeID: '',
     accessibilityLabel: '',
     forwardedRef: undefined,
+    isDisabledLongPress: false,
 };
 
 class Button extends Component {
@@ -269,6 +273,7 @@ class Button extends Component {
                     return this.props.onPress(e);
                 }}
                 onLongPress={(e) => {
+                    if (this.props.isDisabledLongPress) return;
                     if (this.props.shouldEnableHapticFeedback) {
                         HapticFeedback.longPress();
                     }

From c150adfd0146b8a151660914039df037aaedf243 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 23 Aug 2023 15:49:10 +0200
Subject: [PATCH 015/118] update BigNumberPad

---
 src/components/BigNumberPad.js | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/components/BigNumberPad.js b/src/components/BigNumberPad.js
index 06dbc1aa34ac..60b8f1fc176e 100644
--- a/src/components/BigNumberPad.js
+++ b/src/components/BigNumberPad.js
@@ -17,12 +17,16 @@ const propTypes = {
     /** Used to locate this view from native classes. */
     nativeID: PropTypes.string,
 
+    /** Whether long press is disabled */
+    isDisabledLongPress: PropTypes.bool,
+
     ...withLocalizePropTypes,
 };
 
 const defaultProps = {
     longPressHandlerStateChanged: () => {},
     nativeID: 'numPadView',
+    isDisabledLongPress: false,
 };
 
 const padNumbers = [
@@ -83,6 +87,7 @@ function BigNumberPad(props) {
                                     props.longPressHandlerStateChanged(false);
                                 }}
                                 onMouseDown={(e) => e.preventDefault()}
+                                isDisabledLongPress={props.isDisabledLongPress}
                             />
                         );
                     })}

From b6c34cb4fee0adf0e5715c83d695ffcd8ca3f97f Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 23 Aug 2023 15:49:50 +0200
Subject: [PATCH 016/118] create TimePicker

---
 src/components/TimePicker.js | 417 +++++++++++++++++++++++++++++++++++
 src/libs/DateUtils.js        |  19 ++
 2 files changed, 436 insertions(+)
 create mode 100644 src/components/TimePicker.js

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
new file mode 100644
index 000000000000..8195d88fcddc
--- /dev/null
+++ b/src/components/TimePicker.js
@@ -0,0 +1,417 @@
+import React, {useEffect, useState, useCallback, useRef, useMemo} from 'react';
+import {View} from 'react-native';
+import PropTypes from 'prop-types';
+import lodashGet from 'lodash/get';
+import _ from 'underscore';
+import styles from '../styles/styles';
+import themeColors from '../styles/themes/default';
+import BigNumberPad from './BigNumberPad';
+import Button from './Button';
+import AmountTextInput from './AmountTextInput';
+import * as DeviceCapabilities from '../libs/DeviceCapabilities';
+import useLocalize from '../hooks/useLocalize';
+// import CONST from '../../../CONST';
+import CONST from '../CONST';
+import DateUtils from '../libs/DateUtils';
+import Text from './Text';
+import useKeyboardShortcut from '../hooks/useKeyboardShortcut';
+
+const propTypes = {
+    /** Refs forwarded to the TextInputWithCurrencySymbol */
+    forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({current: PropTypes.instanceOf(React.Component)})]),
+
+    /** Fired when submit button pressed, saves the given amount and navigates to the next page */
+    onSubmitButtonPress: PropTypes.func,
+
+    /** Default value for the inputs */
+    defaultValue: PropTypes.string,
+};
+
+const defaultProps = {
+    forwardedRef: null,
+    onSubmitButtonPress: () => {},
+    defaultValue: '',
+};
+
+const AMOUNT_VIEW_ID = 'amountView';
+const NUM_PAD_CONTAINER_VIEW_ID = 'numPadContainerView';
+const NUM_PAD_VIEW_ID = 'numPadView';
+
+function formatHour(hourText) {
+    // // If the integer value of hour is greater than 12, return the second digit with a leading 0
+
+    // return twoDigitHour;
+    const hourNumber = parseInt(hourText, 10);
+
+    // If the integer value of hour is greater than 12, subtract 10
+    const adjustedHour = hourNumber > 12 ? hourNumber - 10 : hourNumber;
+
+    // Convert to a string and pad with a 0 if needed
+    return adjustedHour.toString().padStart(2, '0');
+}
+
+function insertAtPosition(originalString, newSubstring, selectionPositionFrom, selectionPositionTo, fn) {
+    // Check for invalid positions
+    if (selectionPositionFrom < 0 || selectionPositionTo < 0 || selectionPositionFrom > originalString.length || selectionPositionTo > originalString.length) {
+        return;
+    }
+
+    // If the positions are the same, it means we're inserting at a point
+    if (selectionPositionFrom === selectionPositionTo) {
+        if (selectionPositionFrom === originalString.length) {
+            if (typeof fn === 'function') fn();
+            return originalString; // If the insertion point is at the end, simply return the original string
+        }
+        return originalString.slice(0, selectionPositionFrom) + newSubstring + originalString.slice(selectionPositionFrom);
+    }
+
+    // Replace the selected range
+    return originalString.slice(0, selectionPositionFrom) + newSubstring + originalString.slice(selectionPositionTo);
+}
+
+function decreaseBothSelectionByOne({start, end}) {
+    if (start === 0) {
+        return {start: 0, end: 0};
+    }
+    return {start: start - 1, end: end - 1};
+}
+
+function replaceWithZeroAtPosition(originalString, position) {
+    if (position === 0 || position > 2) {
+        return originalString;
+    }
+    return `${originalString.slice(0, position - 1)}0${originalString.slice(position)}`;
+}
+function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
+    const {translate, numberFormat} = useLocalize();
+
+    const [hours, setHours] = useState(DateUtils.parseTimeTo12HourFormat(defaultValue).hour);
+    const [minute, setMinute] = useState(DateUtils.parseTimeTo12HourFormat(defaultValue).minute);
+    const [selectionHour, setSelectionHour] = useState({start: 0, end: 0});
+    const [selectionMinute, setSelectionMinute] = useState({start: 0, end: 0});
+
+    const [amPmValue, setAmPmValue] = useState('AM');
+
+    const hourInputRef = useRef(null);
+    const minuteInputRef = useRef(null);
+
+    /**
+     * Submit amount and navigate to a proper page
+     *
+     */
+    const submitAndNavigateToNextPage = useCallback(() => {
+        onSubmitButtonPress(`${hours}:${minute}`, amPmValue);
+    }, [hours, minute, onSubmitButtonPress, amPmValue]);
+
+    const focusMinuteInputOnFirstCharacter = useCallback(() => {
+        minuteInputRef.current.focus();
+        setSelectionMinute({start: 0, end: 0});
+    }, []);
+    const focusHourInputIfNeeded = useCallback(({nativeEvent}, forceFocus = false) => {
+        const keyValue = lodashGet(nativeEvent, 'key', '');
+        if (!forceFocus && keyValue !== 'Backspace') return;
+
+        hourInputRef.current.focus();
+    }, []);
+
+    const handleHourChange = (text) => {
+        let filteredText;
+        if (selectionHour.start !== selectionHour.end) {
+            filteredText = text.replace(/[^0-9]/g, '').slice(0, 2);
+        } else {
+            filteredText = text.replace(/[^0-9]/g, '');
+        }
+        let newHour = hours;
+        let newSelection = selectionHour.start;
+        if (selectionHour.start !== selectionHour.end) {
+            if (filteredText.length === 1 && filteredText <= 1) {
+                newHour = `${filteredText}0`;
+                newSelection = 1;
+            } else {
+                newHour = `${formatHour(filteredText)}`;
+                newSelection = 2;
+                focusMinuteInputOnFirstCharacter();
+            }
+        } else if (selectionHour.start === 0) {
+            const formattedText = `${filteredText[0]}${filteredText[2] || 0}`;
+            if (formattedText > 12) {
+                newHour = `0${formattedText[1]}`;
+                newSelection = 2;
+                focusMinuteInputOnFirstCharacter();
+            } else {
+                newHour = `${formattedText[0]}${formattedText[1]}`;
+                newSelection = 1;
+            }
+        } else if (selectionHour.start === 1) {
+            // if we remove value
+            if (filteredText.length < 2) {
+                newHour = `0${text}`;
+                newSelection = 0;
+            } else if (text[1] > 2) {
+                newHour = `0${text[1]}`;
+                newSelection = 2;
+                focusMinuteInputOnFirstCharacter();
+            } else {
+                newHour = `${text[0]}${text[1]}`;
+                newSelection = 2;
+                focusMinuteInputOnFirstCharacter();
+            }
+        } else if (selectionHour.start === 2 && selectionHour.end === 2) {
+            if (filteredText.length < 2) {
+                newHour = `${text}0`;
+                newSelection = 1;
+            } else {
+                focusMinuteInputOnFirstCharacter();
+            }
+        }
+
+        setHours(newHour);
+        setSelectionHour({start: newSelection, end: newSelection});
+    };
+
+    const handleMinutesChange = (text) => {
+        const filteredText = text.replace(/[^0-9]/g, '');
+
+        let newMinute = minute;
+        let newSelection = selectionMinute.start;
+        if (selectionMinute.start !== selectionMinute.end) {
+            if (filteredText.length === 1 && filteredText > 5) {
+                newMinute = `0${filteredText}`;
+                newSelection = 2;
+            } else if (filteredText.length === 1 && filteredText <= 5) {
+                newMinute = `${filteredText}0`;
+                newSelection = 1;
+            } else {
+                newMinute = `${filteredText.slice(0, 2)}`;
+                newSelection = 2;
+            }
+        } else if (selectionMinute.start === 0) {
+            const formattedText = `${filteredText[0]}${filteredText[2] || 0}`;
+            if (text[0] >= 6) {
+                newMinute = `0${formattedText[1]}`;
+                newSelection = 2;
+            } else {
+                newMinute = `${formattedText[0]}${formattedText[1]}`;
+                newSelection = 1;
+            }
+        } else if (selectionMinute.start === 1) {
+            //   //if we remove value
+            if (filteredText.length < 2) {
+                newMinute = `0${text}`;
+                newSelection = 0;
+            } else {
+                newMinute = `${text[0]}${text[1]}`;
+                newSelection = 2;
+            }
+        } else if (filteredText.length < 2) {
+            newMinute = `${text}0`;
+            newSelection = 1;
+        }
+
+        setMinute(newMinute);
+        setSelectionMinute({start: newSelection, end: newSelection});
+    };
+
+    /**
+     * Update amount with number or Backspace pressed for BigNumberPad.
+     * Validate new amount with decimal number regex up to 6 digits and 2 decimal digit to enable Next button
+     *
+     * @param {String} key
+     */
+    const updateAmountNumberPad = useCallback(
+        (key) => {
+            const isHourFocused = hourInputRef.current.isFocused();
+            const isMinuteFocused = minuteInputRef.current.isFocused();
+            if (!isHourFocused && !isMinuteFocused) {
+                hourInputRef.current.focus();
+                setTimeout(() => setSelectionHour({start: 0, end: 0}), 10);
+            }
+
+            if (key === '.') return;
+            if (key === '<' || key === 'Backspace') {
+                if (isHourFocused) {
+                    const newHour = replaceWithZeroAtPosition(hours, selectionHour.start);
+                    setHours(newHour);
+                    setSelectionHour(decreaseBothSelectionByOne(selectionHour));
+                } else if (isMinuteFocused) {
+                    if (selectionMinute.start === 0) {
+                        focusHourInputIfNeeded(_, true);
+                    }
+                    const newMinute = replaceWithZeroAtPosition(minute, selectionMinute.start);
+                    setMinute(newMinute);
+                    setSelectionMinute(decreaseBothSelectionByOne(selectionMinute));
+                }
+                return;
+            }
+            const trimmedKey = key.replace(/[^0-9]/g, '');
+            if (isHourFocused) {
+                handleHourChange(insertAtPosition(hours, trimmedKey, selectionHour.start, selectionHour.end));
+            } else if (isMinuteFocused) {
+                handleMinutesChange(insertAtPosition(minute, trimmedKey, selectionMinute.start, selectionMinute.end));
+            }
+        },
+        // eslint-disable-next-line react-hooks/exhaustive-deps
+        [minute, hours, selectionHour, selectionMinute],
+    );
+
+    useEffect(() => minuteInputRef.current.focus, []);
+
+    const arrowConfig = useMemo(
+        () => ({
+            shouldPreventDefault: false,
+        }),
+        [],
+    );
+
+    const arrowLeftCallback = useCallback(() => {
+        const isMinuteFocused = minuteInputRef.current.isFocused();
+        if (isMinuteFocused && selectionMinute.start === 0) {
+            focusHourInputIfNeeded(_, true);
+        }
+    }, [selectionHour, selectionMinute]);
+    const arrowRightCallback = useCallback(() => {
+        const isHourFocused = hourInputRef.current.isFocused();
+
+        if (isHourFocused && selectionHour.start === 2) {
+            focusMinuteInputOnFirstCharacter();
+        }
+    }, [selectionHour, selectionMinute]);
+
+    useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_LEFT, arrowLeftCallback, arrowConfig);
+    useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_RIGHT, arrowRightCallback, arrowConfig);
+    // useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS., arrowRightCallback, arrowConfig);
+
+    const handleFocusOnBackspace = useCallback(
+        (e) => {
+            if (selectionMinute.start !== 0 || e.key === 'Backspace') return;
+            focusHourInputIfNeeded(e);
+        },
+        [selectionMinute.start],
+    );
+
+    return (
+        <>
+            <View
+                nativeID={AMOUNT_VIEW_ID}
+                style={[styles.flex1, styles.flexRow, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}
+            >
+                <AmountTextInput
+                    formattedAmount={hours}
+                    onChangeAmount={handleHourChange}
+                    placeholder={numberFormat(0)}
+                    ref={(ref) => {
+                        if (typeof forwardedRef === 'function') {
+                            forwardedRef({refHour: ref, minuteRef: minuteInputRef.current});
+                        } else if (forwardedRef && _.has(forwardedRef, 'current')) {
+                            // eslint-disable-next-line no-param-reassign
+                            forwardedRef.current = {hourRef: ref, minuteRef: minuteInputRef.current};
+                        }
+                        hourInputRef.current = ref;
+                    }}
+                    maxLength={2}
+                    onSelectionChange={(e) => {
+                        setSelectionHour(e.nativeEvent.selection);
+                    }}
+                    selection={selectionHour}
+                    style={{
+                        fontSize: 69,
+                        minWidth: 56,
+                    }}
+                    containerStyles={[{height: 100}]}
+                />
+                <Text style={{fontSize: 69}}>:</Text>
+                <AmountTextInput
+                    onKeyPress={handleFocusOnBackspace}
+                    autofocus
+                    formattedAmount={minute}
+                    onChangeAmount={handleMinutesChange}
+                    placeholder={numberFormat(0)}
+                    ref={(ref) => {
+                        if (typeof forwardedRef === 'function') {
+                            forwardedRef({refHour: hourInputRef.current, minuteRef: ref});
+                        } else if (forwardedRef && _.has(forwardedRef, 'current')) {
+                            // eslint-disable-next-line no-param-reassign
+                            minuteInputRef.current = {hourRef: hourInputRef.current, minuteInputRef: ref};
+                        }
+                        minuteInputRef.current = ref;
+                    }}
+                    maxLength={2}
+                    onSelectionChange={(e) => {
+                        setSelectionMinute(e.nativeEvent.selection);
+                    }}
+                    selection={selectionMinute}
+                    style={{
+                        fontSize: 69,
+                        minWidth: 56,
+                    }}
+                    containerStyles={[{height: 100}]}
+                />
+            </View>
+            <View style={{flexDirection: 'row', height: 40, alignItems: 'center', justifyContent: 'center'}}>
+                <Button
+                    shouldEnableHapticFeedback
+                    innerStyles={[
+                        {
+                            width: 100,
+                        },
+                        amPmValue !== 'AM' ? {backgroundColor: themeColors.componentBG} : {},
+                    ]}
+                    text="AM"
+                    onLongPress={() => {}}
+                    onPress={() => {
+                        setAmPmValue('AM');
+                    }}
+                    onPressOut={() => {}}
+                    onMouseDown={(e) => e.preventDefault()}
+                />
+                <Button
+                    shouldEnableHapticFeedback
+                    innerStyles={[
+                        {
+                            width: 100,
+                        },
+                        amPmValue !== 'PM' ? {backgroundColor: themeColors.componentBG} : {},
+                    ]}
+                    text="PM"
+                    onLongPress={() => {}}
+                    onPress={() => {
+                        setAmPmValue('PM');
+                    }}
+                    onPressOut={() => {}}
+                    onMouseDown={(e) => e.preventDefault()}
+                />
+            </View>
+            <View
+                style={[styles.w100, styles.justifyContentEnd, styles.pageWrapper]}
+                nativeID={NUM_PAD_CONTAINER_VIEW_ID}
+            >
+                {DeviceCapabilities.canUseTouchScreen() ? (
+                    <BigNumberPad
+                        nativeID={NUM_PAD_VIEW_ID}
+                        numberPressed={updateAmountNumberPad}
+                        isDisabledLongPress
+                    />
+                ) : null}
+                <Button
+                    success
+                    style={[styles.w100, styles.mt5]}
+                    onPress={submitAndNavigateToNextPage}
+                    pressOnEnter
+                    text={translate('common.save')}
+                />
+            </View>
+        </>
+    );
+}
+
+TimePicker.propTypes = propTypes;
+TimePicker.defaultProps = defaultProps;
+TimePicker.displayName = 'TimePicker';
+
+export default React.forwardRef((props, ref) => (
+    <TimePicker
+        // eslint-disable-next-line react/jsx-props-no-spreading
+        {...props}
+        forwardedRef={ref}
+    />
+));
diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index ac0537fc05d4..8d39cd698399 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -357,6 +357,24 @@ function setTimeOrDefaultToTomorrow(time, date) {
     return dateToUse.format('YYYY-MM-DD HH:mm:ss');
 }
 
+function parseTimeTo12HourFormat(datetime) {
+  if(!datetime) {
+    return {
+      hour: '',
+      minute: '',
+      period: ''
+    }
+  }
+  const parsedTime = moment(datetime, 'YYYY-MM-DD HH:mm:ss');
+  
+  return {
+      hour: parsedTime.format('hh'), // Hour in 12-hour format
+      minute: parsedTime.format('mm'), // Minute
+      period: parsedTime.format('A') // AM or PM
+  };
+}
+
+
 /**
  * @namespace DateUtils
  */
@@ -384,6 +402,7 @@ const DateUtils = {
     getStatusUntilDate,
     extractTime12Hour,
     setTimeOrDefaultToTomorrow,
+    parseTimeTo12HourFormat,
 };
 
 export default DateUtils;

From f81217f76e732a08b043b6dca93692489e222aee Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 23 Aug 2023 16:37:21 +0200
Subject: [PATCH 017/118] lint

---
 src/components/AmountTextInput.js             |   2 +-
 src/components/TimePicker.js                  | 180 +++++++++---------
 src/libs/DateUtils.js                         |  27 ++-
 .../Profile/CustomStatus/SetTimePage.js       |  20 +-
 .../CustomStatus/StatusClearAfterPage.js      |   8 +-
 src/styles/styles.js                          |  20 ++
 6 files changed, 139 insertions(+), 118 deletions(-)

diff --git a/src/components/AmountTextInput.js b/src/components/AmountTextInput.js
index de2296bd3833..d9a1b2db20a2 100644
--- a/src/components/AmountTextInput.js
+++ b/src/components/AmountTextInput.js
@@ -31,7 +31,7 @@ const propTypes = {
 
     /** Style for the input */
     style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
-    
+
     /** Style for the container */
     containerStyles: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
 };
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 8195d88fcddc..16ec0a4fce3e 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -10,7 +10,6 @@ import Button from './Button';
 import AmountTextInput from './AmountTextInput';
 import * as DeviceCapabilities from '../libs/DeviceCapabilities';
 import useLocalize from '../hooks/useLocalize';
-// import CONST from '../../../CONST';
 import CONST from '../CONST';
 import DateUtils from '../libs/DateUtils';
 import Text from './Text';
@@ -268,6 +267,7 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
         if (isMinuteFocused && selectionMinute.start === 0) {
             focusHourInputIfNeeded(_, true);
         }
+        // eslint-disable-next-line react-hooks/exhaustive-deps
     }, [selectionHour, selectionMinute]);
     const arrowRightCallback = useCallback(() => {
         const isHourFocused = hourInputRef.current.isFocused();
@@ -275,111 +275,109 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
         if (isHourFocused && selectionHour.start === 2) {
             focusMinuteInputOnFirstCharacter();
         }
+        // eslint-disable-next-line react-hooks/exhaustive-deps
     }, [selectionHour, selectionMinute]);
 
     useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_LEFT, arrowLeftCallback, arrowConfig);
     useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_RIGHT, arrowRightCallback, arrowConfig);
-    // useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS., arrowRightCallback, arrowConfig);
 
     const handleFocusOnBackspace = useCallback(
         (e) => {
             if (selectionMinute.start !== 0 || e.key === 'Backspace') return;
             focusHourInputIfNeeded(e);
         },
+        // eslint-disable-next-line react-hooks/exhaustive-deps
         [selectionMinute.start],
     );
 
+    const { styleForAM, styleForPM } = useMemo(() => {
+      const computedStyleForAM = amPmValue !== 'AM' ? { backgroundColor: themeColors.componentBG } : {};
+      const computedStyleForPM = amPmValue !== 'PM' ? { backgroundColor: themeColors.componentBG } : {};
+  
+      return {
+          styleForAM: [styles.timePickerWidth100, computedStyleForAM],
+          styleForPM: [styles.timePickerWidth100, computedStyleForPM]
+      };
+  }, [amPmValue]);
+  
+
     return (
         <>
-            <View
-                nativeID={AMOUNT_VIEW_ID}
-                style={[styles.flex1, styles.flexRow, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}
-            >
-                <AmountTextInput
-                    formattedAmount={hours}
-                    onChangeAmount={handleHourChange}
-                    placeholder={numberFormat(0)}
-                    ref={(ref) => {
-                        if (typeof forwardedRef === 'function') {
-                            forwardedRef({refHour: ref, minuteRef: minuteInputRef.current});
-                        } else if (forwardedRef && _.has(forwardedRef, 'current')) {
-                            // eslint-disable-next-line no-param-reassign
-                            forwardedRef.current = {hourRef: ref, minuteRef: minuteInputRef.current};
-                        }
-                        hourInputRef.current = ref;
-                    }}
-                    maxLength={2}
-                    onSelectionChange={(e) => {
-                        setSelectionHour(e.nativeEvent.selection);
-                    }}
-                    selection={selectionHour}
-                    style={{
-                        fontSize: 69,
-                        minWidth: 56,
-                    }}
-                    containerStyles={[{height: 100}]}
-                />
-                <Text style={{fontSize: 69}}>:</Text>
-                <AmountTextInput
-                    onKeyPress={handleFocusOnBackspace}
-                    autofocus
-                    formattedAmount={minute}
-                    onChangeAmount={handleMinutesChange}
-                    placeholder={numberFormat(0)}
-                    ref={(ref) => {
-                        if (typeof forwardedRef === 'function') {
-                            forwardedRef({refHour: hourInputRef.current, minuteRef: ref});
-                        } else if (forwardedRef && _.has(forwardedRef, 'current')) {
-                            // eslint-disable-next-line no-param-reassign
-                            minuteInputRef.current = {hourRef: hourInputRef.current, minuteInputRef: ref};
-                        }
-                        minuteInputRef.current = ref;
-                    }}
-                    maxLength={2}
-                    onSelectionChange={(e) => {
-                        setSelectionMinute(e.nativeEvent.selection);
-                    }}
-                    selection={selectionMinute}
-                    style={{
-                        fontSize: 69,
-                        minWidth: 56,
-                    }}
-                    containerStyles={[{height: 100}]}
-                />
-            </View>
-            <View style={{flexDirection: 'row', height: 40, alignItems: 'center', justifyContent: 'center'}}>
-                <Button
-                    shouldEnableHapticFeedback
-                    innerStyles={[
-                        {
-                            width: 100,
-                        },
-                        amPmValue !== 'AM' ? {backgroundColor: themeColors.componentBG} : {},
-                    ]}
-                    text="AM"
-                    onLongPress={() => {}}
-                    onPress={() => {
-                        setAmPmValue('AM');
-                    }}
-                    onPressOut={() => {}}
-                    onMouseDown={(e) => e.preventDefault()}
-                />
-                <Button
-                    shouldEnableHapticFeedback
-                    innerStyles={[
-                        {
-                            width: 100,
-                        },
-                        amPmValue !== 'PM' ? {backgroundColor: themeColors.componentBG} : {},
-                    ]}
-                    text="PM"
-                    onLongPress={() => {}}
-                    onPress={() => {
-                        setAmPmValue('PM');
-                    }}
-                    onPressOut={() => {}}
-                    onMouseDown={(e) => e.preventDefault()}
-                />
+            <View style={[styles.flex1, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}>
+                <View
+                    nativeID={AMOUNT_VIEW_ID}
+                    style={[styles.flexRow, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}
+                >
+                    <AmountTextInput
+                        formattedAmount={hours}
+                        onChangeAmount={handleHourChange}
+                        placeholder={numberFormat(0)}
+                        ref={(ref) => {
+                            if (typeof forwardedRef === 'function') {
+                                forwardedRef({refHour: ref, minuteRef: minuteInputRef.current});
+                            } else if (forwardedRef && _.has(forwardedRef, 'current')) {
+                                // eslint-disable-next-line no-param-reassign
+                                forwardedRef.current = {hourRef: ref, minuteRef: minuteInputRef.current};
+                            }
+                            hourInputRef.current = ref;
+                        }}
+                        maxLength={2}
+                        onSelectionChange={(e) => {
+                            setSelectionHour(e.nativeEvent.selection);
+                        }}
+                        selection={selectionHour}
+                        style={styles.timePickerInput}
+                        containerStyles={[styles.timePickerHeight100]}
+                    />
+                    <Text style={styles.timePickerSemiDot}>:</Text>
+                    <AmountTextInput
+                        onKeyPress={handleFocusOnBackspace}
+                        autofocus
+                        formattedAmount={minute}
+                        onChangeAmount={handleMinutesChange}
+                        placeholder={numberFormat(0)}
+                        ref={(ref) => {
+                            if (typeof forwardedRef === 'function') {
+                                forwardedRef({refHour: hourInputRef.current, minuteRef: ref});
+                            } else if (forwardedRef && _.has(forwardedRef, 'current')) {
+                                // eslint-disable-next-line no-param-reassign
+                                minuteInputRef.current = {hourRef: hourInputRef.current, minuteInputRef: ref};
+                            }
+                            minuteInputRef.current = ref;
+                        }}
+                        maxLength={2}
+                        onSelectionChange={(e) => {
+                            setSelectionMinute(e.nativeEvent.selection);
+                        }}
+                        selection={selectionMinute}
+                        style={styles.timePickerInput}
+                        containerStyles={[styles.timePickerWidth100]}
+                    />
+                </View>
+                <View style={styles.timePickerSwitcherContainer}>
+                    <Button
+                        shouldEnableHapticFeedback
+                        innerStyles={styleForAM}
+                        text="AM"
+                        onLongPress={() => {}}
+                        onPress={() => {
+                            setAmPmValue('AM');
+                        }}
+                        onPressOut={() => {}}
+                        onMouseDown={(e) => e.preventDefault()}
+                    />
+                    <Button
+                        shouldEnableHapticFeedback
+                        innerStyles={styleForPM}
+                        text="PM"
+                        onLongPress={() => {}}
+                        onPress={() => {
+                            setAmPmValue('PM');
+                        }}
+                        onPressOut={() => {}}
+                        onMouseDown={(e) => e.preventDefault()}
+                    />
+                </View>
             </View>
             <View
                 style={[styles.w100, styles.justifyContentEnd, styles.pageWrapper]}
diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index 8d39cd698399..a40eeb28c70b 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -358,22 +358,21 @@ function setTimeOrDefaultToTomorrow(time, date) {
 }
 
 function parseTimeTo12HourFormat(datetime) {
-  if(!datetime) {
-    return {
-      hour: '',
-      minute: '',
-      period: ''
+    if (!datetime) {
+        return {
+            hour: '',
+            minute: '',
+            period: '',
+        };
     }
-  }
-  const parsedTime = moment(datetime, 'YYYY-MM-DD HH:mm:ss');
-  
-  return {
-      hour: parsedTime.format('hh'), // Hour in 12-hour format
-      minute: parsedTime.format('mm'), // Minute
-      period: parsedTime.format('A') // AM or PM
-  };
-}
+    const parsedTime = moment(datetime, 'YYYY-MM-DD HH:mm:ss');
 
+    return {
+        hour: parsedTime.format('hh'), // Hour in 12-hour format
+        minute: parsedTime.format('mm'), // Minute
+        period: parsedTime.format('A'), // AM or PM
+    };
+}
 
 /**
  * @namespace DateUtils
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 18f707ea22f2..c4411f5a7e53 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -2,6 +2,8 @@ import PropTypes from 'prop-types';
 import React, {useCallback} from 'react';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
+import RNTimePicker from '@react-native-community/datetimepicker';
+import {View} from 'react-native';
 import withCurrentUserPersonalDetails from '../../../../components/withCurrentUserPersonalDetails';
 import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator';
 import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
@@ -38,19 +40,21 @@ function SetTimePage({translate, privatePersonalDetails, customStatus, currentUs
     const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
     const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
 
-    const onSubmitButtonPress = useCallback((time, amPmValue) => {
-        const timeToUse = DateUtils.setTimeOrDefaultToTomorrow(`${time} ${amPmValue}`, customDateTemporary);
-
-        User.updateDraftCustomStatus({customDateTemporary: timeToUse});
-        Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
-    }, [customDateTemporary]);
+    const onSubmitButtonPress = useCallback(
+        (time, amPmValue) => {
+            const timeToUse = DateUtils.setTimeOrDefaultToTomorrow(`${time} ${amPmValue}`, customDateTemporary);
 
+            User.updateDraftCustomStatus({customDateTemporary: timeToUse});
+            Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
+        },
+        [customDateTemporary],
+    );
 
     if (lodashGet(privatePersonalDetails, 'isLoading', true)) {
         return <FullscreenLoadingIndicator />;
     }
 
-    const customStatusTime = DateUtils.extractTime(customDateTemporary || draftClearAfter || clearAfter);
+    // const customStatusTime = DateUtils.extractTime(customDateTemporary || draftClearAfter || clearAfter);
 
     return (
         <ScreenWrapper includeSafeAreaPaddingBottom={false}>
@@ -60,7 +64,7 @@ function SetTimePage({translate, privatePersonalDetails, customStatus, currentUs
             />
             <TimePicker
                 inputID="timePicker"
-                defaultValue={customStatusTime}
+                defaultValue={customDateTemporary || draftClearAfter || clearAfter}
                 onSubmitButtonPress={onSubmitButtonPress}
             />
         </ScreenWrapper>
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 9b208f9c3d14..b1b40e3fbbbe 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -19,15 +19,15 @@ import * as User from '../../../../libs/actions/User';
 import withLocalize from '../../../../components/withLocalize';
 import compose from '../../../../libs/compose';
 import DateUtils from '../../../../libs/DateUtils';
-import withCurrentUserPersonalDetails, { withCurrentUserPersonalDetailsDefaultProps } from '../../../../components/withCurrentUserPersonalDetails';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps} from '../../../../components/withCurrentUserPersonalDetails';
 import personalDetailsPropType from '../../../personalDetailsPropType';
 
 const defaultProps = {
-  ...withCurrentUserPersonalDetailsDefaultProps,
+    ...withCurrentUserPersonalDetailsDefaultProps,
 };
 
 const propTypes = {
-  currentUserPersonalDetails: personalDetailsPropType,
+    currentUserPersonalDetails: personalDetailsPropType,
 };
 
 function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
@@ -79,7 +79,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
             clearAfter,
         });
 
-    // eslint-disable-next-line react-hooks/exhaustive-deps
+        // eslint-disable-next-line react-hooks/exhaustive-deps
     }, []);
 
     const customStatusDate = DateUtils.extractDate(customDateTemporary || draftClearAfter || clearAfter);
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 3db02979e612..868614ab564f 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3772,6 +3772,26 @@ const styles = {
         fontSize: variables.fontSizeNormal,
         marginRight: 4,
     },
+
+    timePickerInput: {
+        fontSize: 69,
+        minWidth: 56,
+    },
+    timePickerWidth100: {
+        width: 100,
+    },
+    timePickerHeight100: {
+        height: 100,
+    },
+    timePickerSemiDot: {
+        fontSize: 69,
+    },
+    timePickerSwitcherContainer: {
+        flexDirection: 'row',
+        alignItems: 'flex-start',
+        justifyContent: 'center',
+        marginTop: 40,
+    },
 };
 
 export default styles;

From be5ed562994b9a76f6cfa6c88d935d8a452dcb8e Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 23 Aug 2023 17:13:42 +0200
Subject: [PATCH 018/118] add ItemSeparatorComponent to BaseSelectionListRadio

---
 src/CONST.js                                               | 4 ++++
 .../SelectionListRadio/selectionListRadioPropTypes.js      | 1 +
 src/components/TimePicker.js                               | 6 +++---
 .../settings/Profile/CustomStatus/StatusClearAfterPage.js  | 2 ++
 src/styles/styles.js                                       | 7 +++++++
 5 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/src/CONST.js b/src/CONST.js
index e7d2fa6f4d03..2b85a9c9bfa6 100755
--- a/src/CONST.js
+++ b/src/CONST.js
@@ -2564,6 +2564,10 @@ const CONST = {
             NAVIGATE: 'NAVIGATE',
         },
     },
+    TIME_PERIOD: {
+      AM: 'AM',
+      PM: 'PM',
+    }
 };
 
 export default CONST;
diff --git a/src/components/SelectionListRadio/selectionListRadioPropTypes.js b/src/components/SelectionListRadio/selectionListRadioPropTypes.js
index 14e41b195d7b..8a2658dad3a4 100644
--- a/src/components/SelectionListRadio/selectionListRadioPropTypes.js
+++ b/src/components/SelectionListRadio/selectionListRadioPropTypes.js
@@ -83,6 +83,7 @@ const defaultProps = {
     onScroll: () => {},
     onScrollBeginDrag: () => {},
     headerMessage: '',
+    scrollEnabled: true,
 };
 
 export {propTypes, radioListItemPropTypes, defaultProps};
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 16ec0a4fce3e..13cddbdc1e61 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -291,8 +291,8 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
     );
 
     const { styleForAM, styleForPM } = useMemo(() => {
-      const computedStyleForAM = amPmValue !== 'AM' ? { backgroundColor: themeColors.componentBG } : {};
-      const computedStyleForPM = amPmValue !== 'PM' ? { backgroundColor: themeColors.componentBG } : {};
+      const computedStyleForAM = amPmValue !== CONST.TIME_PERIOD.AM ? { backgroundColor: themeColors.componentBG } : {};
+      const computedStyleForPM = amPmValue !== CONST.TIME_PERIOD.PM ? { backgroundColor: themeColors.componentBG } : {};
   
       return {
           styleForAM: [styles.timePickerWidth100, computedStyleForAM],
@@ -351,7 +351,7 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
                         }}
                         selection={selectionMinute}
                         style={styles.timePickerInput}
-                        containerStyles={[styles.timePickerWidth100]}
+                        containerStyles={[styles.timePickerHeight100]}
                     />
                 </View>
                 <View style={styles.timePickerSwitcherContainer}>
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index b1b40e3fbbbe..7b4d77ec330f 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -107,6 +107,8 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                         onSelectRow={updateMode}
                         disableInitialFocusOptionStyle
                         wrapperStyle={{flex: null}}
+                        scrollEnabled={false}
+                        useSeparator
                     />
 
                     {draftPeriod === CONST.CUSTOM_STATUS_TYPES.CUSTOM && (
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 868614ab564f..f780f865f527 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -1,5 +1,6 @@
 import {defaultStyles as defaultPickerStyles} from 'react-native-picker-select/src/styles';
 import lodashClamp from 'lodash/clamp';
+import { StyleSheet } from 'react-native';
 import fontFamily from './fontFamily';
 import addOutlineWidth from './addOutlineWidth';
 import themeColors from './themes/default';
@@ -3792,6 +3793,12 @@ const styles = {
         justifyContent: 'center',
         marginTop: 40,
     },
+    selectionListRadioSeparator: {
+      height: StyleSheet.hairlineWidth,
+      backgroundColor: themeColors.border,
+      marginHorizontal: 20,
+
+    }
 };
 
 export default styles;

From 72d6c0ec57baaee43b3cddb1f6502622b5be29e7 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 23 Aug 2023 21:55:48 +0200
Subject: [PATCH 019/118] add containerStyle for MenuItem

---
 src/components/MenuItem.js                    |  1 +
 .../CustomStatus/CustomClearAfterPage.js      | 19 ++++++++-----------
 .../CustomStatus/StatusClearAfterPage.js      | 14 ++++++++++----
 3 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js
index e284244f694c..3de423b68272 100644
--- a/src/components/MenuItem.js
+++ b/src/components/MenuItem.js
@@ -124,6 +124,7 @@ const MenuItem = React.forwardRef((props, ref) => {
                     onSecondaryInteraction={props.onSecondaryInteraction}
                     style={({pressed}) => [
                         props.style,
+                        props.containerStyle,
                         !props.interactive && styles.cursorDefault,
                         StyleUtils.getButtonBackgroundColorStyle(getButtonState(props.focused || isHovered, pressed, props.success, props.disabled, props.interactive), true),
                         (isHovered || pressed) && props.hoverAndPressStyle,
diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index a67f4b360ffe..75cdcd9d89d0 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -3,19 +3,18 @@ import PropTypes from 'prop-types';
 import React from 'react';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import ROUTES from '../../../../ROUTES';
-import Form from '../../../../components/Form';
+import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
 import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
 import NewDatePicker from '../../../../components/NewDatePicker';
 import ScreenWrapper from '../../../../components/ScreenWrapper';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
+import Form from '../../../../components/Form';
+import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
 import Navigation from '../../../../libs/Navigation/Navigation';
 import * as User from '../../../../libs/actions/User';
 import compose from '../../../../libs/compose';
 import styles from '../../../../styles/styles';
-import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
-import DateUtils from '../../../../libs/DateUtils';
+import ONYXKEYS from '../../../../ONYXKEYS';
+import ROUTES from '../../../../ROUTES';
 
 const propTypes = {
     /* Onyx Props */
@@ -34,11 +33,11 @@ const defaultProps = {
     },
 };
 
-function CustomClearAfterPage({translate, customStatus, clearDateForm, personalDetails}) {
+function CustomClearAfterPage({translate, customStatus, personalDetails}) {
     usePrivatePersonalDetails();
     const cleanAfter = lodashGet(personalDetails, 'status.cleanAfter', '');
-    const defaultValue = cleanAfter || DateUtils.extractDate(customStatus?.customDateTemporary);
-
+    const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
+    const defaultValue = cleanAfter || customDateTemporary;
 
     const onSubmit = (v) => {
         User.updateDraftCustomStatus({customDateTemporary: v.dob});
@@ -54,8 +53,6 @@ function CustomClearAfterPage({translate, customStatus, clearDateForm, personalD
             <Form
                 style={[styles.flexGrow1, styles.ph5]}
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_DATE_FORM}
-            
-                // onSubmit={PersonalDetails.updateDateOfBirth}
                 onSubmit={onSubmit}
                 submitButtonText={translate('common.save')}
                 enabledWhenOffline
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 7b4d77ec330f..34822f775695 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -3,6 +3,7 @@ import {View} from 'react-native';
 import _ from 'lodash';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
 import ScreenWrapper from '../../../../components/ScreenWrapper';
 import Form from '../../../../components/Form';
 import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
@@ -28,6 +29,11 @@ const defaultProps = {
 
 const propTypes = {
     currentUserPersonalDetails: personalDetailsPropType,
+    customStatus: PropTypes.shape({
+        clearAfter: PropTypes.string,
+        customDateTemporary: PropTypes.string,
+
+    }),
 };
 
 function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
@@ -94,14 +100,12 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
             <Text style={[styles.textNormal, styles.mh5, styles.mv4]}>When should we clear your status?</Text>
             <Form
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_CLEAR_AFTER_FORM}
-                onCloseButtonPress={() => {}}
-                onBackButtonPress={() => {}}
                 submitButtonText="Save"
                 onSubmit={onSubmit}
-                style={[{flexGrow: 1}]}
+                style={styles.flexGrow1}
                 scrollContextEnabled={false}
             >
-                <View style={{flexGrow: 1}}>
+                <View style={styles.flexGrow1}>
                     <SelectionListRadio
                         sections={[{data: localesToThemes, indexOffset: 0}]}
                         onSelectRow={updateMode}
@@ -117,12 +121,14 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                                 title={customStatusDate}
                                 description="Clear after"
                                 shouldShowRightIcon
+                                containerStyle={styles.pr2}
                                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_CUSTOM)}
                             />
                             <MenuItemWithTopDescription
                                 title={customStatusTime}
                                 description="Clear after"
                                 shouldShowRightIcon
+                                containerStyle={styles.pr2}
                                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_TIME)}
                             />
                         </>

From 33b23b93fa06f6d3b81ae606352da3281d384c76 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 23 Aug 2023 21:59:37 +0200
Subject: [PATCH 020/118] add separator component

---
 src/CONST.js                                  |  6 ++---
 .../BaseSelectionListRadio.js                 | 24 ++++++++++++++++--
 src/components/TimePicker.js                  | 25 ++++++++++---------
 .../CustomStatus/StatusClearAfterPage.js      |  3 +--
 .../Profile/CustomStatus/StatusPage.js        |  7 +++---
 5 files changed, 42 insertions(+), 23 deletions(-)

diff --git a/src/CONST.js b/src/CONST.js
index 2b85a9c9bfa6..fff39d67dc76 100755
--- a/src/CONST.js
+++ b/src/CONST.js
@@ -2565,9 +2565,9 @@ const CONST = {
         },
     },
     TIME_PERIOD: {
-      AM: 'AM',
-      PM: 'PM',
-    }
+        AM: 'AM',
+        PM: 'PM',
+    },
 };
 
 export default CONST;
diff --git a/src/components/SelectionListRadio/BaseSelectionListRadio.js b/src/components/SelectionListRadio/BaseSelectionListRadio.js
index bab20e35adb4..d46a7cc5d50a 100644
--- a/src/components/SelectionListRadio/BaseSelectionListRadio.js
+++ b/src/components/SelectionListRadio/BaseSelectionListRadio.js
@@ -1,7 +1,8 @@
-import React, {useEffect, useRef, useState} from 'react';
+import React, {useEffect, useMemo, useRef, useState} from 'react';
 import {View} from 'react-native';
 import _ from 'underscore';
 import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
 import SectionList from '../SectionList';
 import Text from '../Text';
 import styles from '../../styles/styles';
@@ -18,6 +19,18 @@ import withKeyboardState, {keyboardStatePropTypes} from '../withKeyboardState';
 const propTypes = {
     ...keyboardStatePropTypes,
     ...selectionListRadioPropTypes,
+
+    /** Whether to disable the scroll for the scroll */
+    scrollEnabled: PropTypes.bool,
+
+    /** Whether to show the separator between items */
+    useSeparator: PropTypes.bool,
+};
+
+const defaultProps = {
+    ...selectionListRadioDefaultProps,
+
+    useSeparator: false,
 };
 
 function BaseSelectionListRadio(props) {
@@ -205,6 +218,11 @@ function BaseSelectionListRadio(props) {
         shouldBubble: () => !flattenedSections.allOptions[focusedIndex],
     });
 
+    const separatorComponent = useMemo(() => {
+        const separatorStyle = [styles.selectionListRadioSeparator, props.separatorStyle];
+        return () => (props.useSeparator ? <View style={separatorStyle} /> : null);
+    }, [props.separatorStyle, props.useSeparator]);
+
     return (
         <ArrowKeyFocusManager
             disabledIndexes={flattenedSections.disabledOptionsIndexes}
@@ -265,6 +283,8 @@ function BaseSelectionListRadio(props) {
                                 scrollToIndex(focusedIndex, false);
                                 firstLayoutRef.current = false;
                             }}
+                            scrollEnabled={props.scrollEnabled}
+                            ItemSeparatorComponent={separatorComponent}
                         />
                     </View>
                 )}
@@ -275,6 +295,6 @@ function BaseSelectionListRadio(props) {
 
 BaseSelectionListRadio.displayName = 'BaseSelectionListRadio';
 BaseSelectionListRadio.propTypes = propTypes;
-BaseSelectionListRadio.defaultProps = selectionListRadioDefaultProps;
+BaseSelectionListRadio.defaultProps = defaultProps;
 
 export default withKeyboardState(BaseSelectionListRadio);
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 13cddbdc1e61..b9e5b8b748b4 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -89,7 +89,7 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
     const [selectionHour, setSelectionHour] = useState({start: 0, end: 0});
     const [selectionMinute, setSelectionMinute] = useState({start: 0, end: 0});
 
-    const [amPmValue, setAmPmValue] = useState('AM');
+    const [amPmValue, setAmPmValue] = useState(DateUtils.getTimePeriod(defaultValue));
 
     const hourInputRef = useRef(null);
     const minuteInputRef = useRef(null);
@@ -253,7 +253,9 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
         [minute, hours, selectionHour, selectionMinute],
     );
 
-    useEffect(() => minuteInputRef.current.focus, []);
+    useEffect(() => {
+        minuteInputRef.current.focus();
+    }, []);
 
     const arrowConfig = useMemo(
         () => ({
@@ -290,16 +292,15 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
         [selectionMinute.start],
     );
 
-    const { styleForAM, styleForPM } = useMemo(() => {
-      const computedStyleForAM = amPmValue !== CONST.TIME_PERIOD.AM ? { backgroundColor: themeColors.componentBG } : {};
-      const computedStyleForPM = amPmValue !== CONST.TIME_PERIOD.PM ? { backgroundColor: themeColors.componentBG } : {};
-  
-      return {
-          styleForAM: [styles.timePickerWidth100, computedStyleForAM],
-          styleForPM: [styles.timePickerWidth100, computedStyleForPM]
-      };
-  }, [amPmValue]);
-  
+    const {styleForAM, styleForPM} = useMemo(() => {
+        const computedStyleForAM = amPmValue !== CONST.TIME_PERIOD.AM ? {backgroundColor: themeColors.componentBG} : {};
+        const computedStyleForPM = amPmValue !== CONST.TIME_PERIOD.PM ? {backgroundColor: themeColors.componentBG} : {};
+
+        return {
+            styleForAM: [styles.timePickerWidth100, computedStyleForAM],
+            styleForPM: [styles.timePickerWidth100, computedStyleForPM],
+        };
+    }, [amPmValue]);
 
     return (
         <>
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 34822f775695..84c4aa69bf93 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -32,7 +32,6 @@ const propTypes = {
     customStatus: PropTypes.shape({
         clearAfter: PropTypes.string,
         customDateTemporary: PropTypes.string,
-
     }),
 };
 
@@ -60,7 +59,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
         if (draftPeriod === CONST.CUSTOM_STATUS_TYPES.CUSTOM) {
             calculatedDraftDate = customDateTemporary || draftClearAfter;
         } else {
-            const selectedRange = localesToThemes.find((item) => item.isSelected);
+            const selectedRange = _.find(localesToThemes, (item) => item.isSelected);
             calculatedDraftDate = DateUtils.getDateBasedFromType(selectedRange.value);
         }
 
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index d9ec14f3fc7c..18ece2b6f526 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -38,10 +38,9 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
     const defaultEmoji = draftEmojiCode || currentUserEmojiCode;
     const defaultText = draftEmojiCode ? draftText : currentUserStatusText;
     const customStatus = draftEmojiCode ? `${draftEmojiCode} ${draftText}` : `${currentUserEmojiCode || ''} ${currentUserStatusText || ''}`;
-    const hasDraftStatus = !!draftEmojiCode || !!draftText;
-    const formattedClearAfter = DateUtils.formatDateTo12Hour(lodashGet(currentUserPersonalDetails, 'status.clearAfter', ''));
-    const formattedClearAfterDraft = DateUtils.formatDateTo12Hour(draftClearAfter);
-    const customClearAfter = draftClearAfter ? formattedClearAfterDraft : formattedClearAfter || '';
+    const hasDraftStatus =
+        !!draftEmojiCode || !!draftText || ((!!draftEmojiCode || !!currentUserEmojiCode) && !!draftClearAfter && !DateUtils.areDatesIdentical(draftClearAfter, currentUserClearAfter));
+    const customClearAfter = DateUtils.formatDateTo12Hour(draftClearAfter || currentUserClearAfter);
 
     const updateStatus = useCallback(() => {
         const endOfDay = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss');

From 992b4fcbf6308d9e146369ca7f47bdff9a432c4a Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 23 Aug 2023 22:39:30 +0200
Subject: [PATCH 021/118] add translations

---
 src/languages/en.js                                        | 3 +++
 src/languages/es.js                                        | 3 +++
 .../settings/Profile/CustomStatus/StatusClearAfterPage.js  | 7 ++++---
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/languages/en.js b/src/languages/en.js
index 586fafd9276f..32f6b462097e 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -904,6 +904,9 @@ export default {
         },
         untilTomorrow: 'Until tomorrow',
         untilTime: ({time}) => `Until ${time}`,
+        date: 'Date',
+        time: 'Time',
+        clearAfter: 'Clear after',
     },
     stepCounter: ({step, total, text}) => {
         let result = `Step ${step}`;
diff --git a/src/languages/es.js b/src/languages/es.js
index 1315d02de363..76a99f50e434 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -923,6 +923,9 @@ export default {
             // Default case
             return `Hasta ${time}`;
         },
+        date: 'Fecha',
+        time: 'Hora',
+        clearAfter: 'Borrar después',
         stepCounter: ({step, total, text}) => {
             let result = `Paso ${step}`;
 
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 84c4aa69bf93..2446907dfeb8 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -51,7 +51,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 keyForList: key,
                 isSelected: draftPeriod === value,
             })),
-        [draftPeriod],
+        [draftPeriod, localize],
     );
 
     const onSubmit = () => {
@@ -103,6 +103,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 onSubmit={onSubmit}
                 style={styles.flexGrow1}
                 scrollContextEnabled={false}
+                submitButtonStyle={styles.mh3}
             >
                 <View style={styles.flexGrow1}>
                     <SelectionListRadio
@@ -118,14 +119,14 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                         <>
                             <MenuItemWithTopDescription
                                 title={customStatusDate}
-                                description="Clear after"
+                                description={localize.translate('statusPage.date')}
                                 shouldShowRightIcon
                                 containerStyle={styles.pr2}
                                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_CUSTOM)}
                             />
                             <MenuItemWithTopDescription
                                 title={customStatusTime}
-                                description="Clear after"
+                                description={localize.translate('statusPage.time')}
                                 shouldShowRightIcon
                                 containerStyle={styles.pr2}
                                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_TIME)}

From f532d244968e703987184a203784fbf69314edba Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 23 Aug 2023 22:40:16 +0200
Subject: [PATCH 022/118] add buttonStyle in Form

---
 src/components/Form.js                      |  6 ++++++
 src/components/FormAlertWithSubmitButton.js |  8 +++++--
 src/components/TimePicker.js                | 24 +++++++++++++--------
 src/styles/styles.js                        | 11 +++++-----
 4 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/src/components/Form.js b/src/components/Form.js
index eb6945f6ec78..b60678382041 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -82,6 +82,9 @@ const propTypes = {
     /** Information about the network */
     network: networkPropTypes.isRequired,
 
+    /** Style for the button */
+    submitButtonStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
+
     ...withLocalizePropTypes,
 };
 
@@ -99,6 +102,7 @@ const defaultProps = {
     footerContent: null,
     style: [],
     validate: () => ({}),
+    submitButtonStyle: {}
 };
 
 function Form(props) {
@@ -397,6 +401,7 @@ function Form(props) {
                         containerStyles={[styles.mh0, styles.mt5, styles.flex1]}
                         enabledWhenOffline={props.enabledWhenOffline}
                         isSubmitActionDangerous={props.isSubmitActionDangerous}
+                        buttonStyle={props.submitButtonStyle}
                         disablePressOnEnter
                     />
                 )}
@@ -419,6 +424,7 @@ function Form(props) {
             props.isSubmitActionDangerous,
             props.isSubmitButtonVisible,
             props.submitButtonText,
+            props.submitButtonStyle,
         ],
     );
 
diff --git a/src/components/FormAlertWithSubmitButton.js b/src/components/FormAlertWithSubmitButton.js
index 9c941fa9b967..ca9494af236c 100644
--- a/src/components/FormAlertWithSubmitButton.js
+++ b/src/components/FormAlertWithSubmitButton.js
@@ -46,6 +46,9 @@ const propTypes = {
 
     /** Custom content to display in the footer after submit button */
     footerContent: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
+
+    /** Style for the button */
+    buttonStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
 };
 
 const defaultProps = {
@@ -59,6 +62,7 @@ const defaultProps = {
     disablePressOnEnter: false,
     isSubmitActionDangerous: false,
     footerContent: null,
+    buttonStyle: {},
 };
 
 function FormAlertWithSubmitButton(props) {
@@ -79,7 +83,7 @@ function FormAlertWithSubmitButton(props) {
                             success
                             isDisabled
                             text={props.buttonText}
-                            style={buttonMarginStyle}
+                            style={[buttonMarginStyle, props.buttonStyle]}
                             danger={props.isSubmitActionDangerous}
                         />
                     ) : (
@@ -87,7 +91,7 @@ function FormAlertWithSubmitButton(props) {
                             success
                             pressOnEnter={!props.disablePressOnEnter}
                             text={props.buttonText}
-                            style={buttonMarginStyle}
+                            style={[buttonMarginStyle, props.buttonStyle]}
                             onPress={props.onSubmit}
                             isDisabled={props.isDisabled}
                             isLoading={props.isLoading}
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index b9e5b8b748b4..27a8401a2e51 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -93,6 +93,7 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
 
     const hourInputRef = useRef(null);
     const minuteInputRef = useRef(null);
+    const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen();
 
     /**
      * Submit amount and navigate to a proper page
@@ -302,6 +303,17 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
         };
     }, [amPmValue]);
 
+    const numberPad = useCallback(() => {
+        if (!canUseTouchScreen) return null;
+        return (
+            <BigNumberPad
+                nativeID={NUM_PAD_VIEW_ID}
+                numberPressed={updateAmountNumberPad}
+                isDisabledLongPress
+            />
+        );
+    }, [canUseTouchScreen, updateAmountNumberPad]);
+
     return (
         <>
             <View style={[styles.flex1, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}>
@@ -362,7 +374,7 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
                         text="AM"
                         onLongPress={() => {}}
                         onPress={() => {
-                            setAmPmValue('AM');
+                            setAmPmValue(CONST.TIME_PERIOD.AM);
                         }}
                         onPressOut={() => {}}
                         onMouseDown={(e) => e.preventDefault()}
@@ -373,7 +385,7 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
                         text="PM"
                         onLongPress={() => {}}
                         onPress={() => {
-                            setAmPmValue('PM');
+                            setAmPmValue(CONST.TIME_PERIOD.PM);
                         }}
                         onPressOut={() => {}}
                         onMouseDown={(e) => e.preventDefault()}
@@ -384,13 +396,7 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
                 style={[styles.w100, styles.justifyContentEnd, styles.pageWrapper]}
                 nativeID={NUM_PAD_CONTAINER_VIEW_ID}
             >
-                {DeviceCapabilities.canUseTouchScreen() ? (
-                    <BigNumberPad
-                        nativeID={NUM_PAD_VIEW_ID}
-                        numberPressed={updateAmountNumberPad}
-                        isDisabledLongPress
-                    />
-                ) : null}
+                {numberPad()}
                 <Button
                     success
                     style={[styles.w100, styles.mt5]}
diff --git a/src/styles/styles.js b/src/styles/styles.js
index f780f865f527..4a8677958cfe 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -1,6 +1,6 @@
 import {defaultStyles as defaultPickerStyles} from 'react-native-picker-select/src/styles';
 import lodashClamp from 'lodash/clamp';
-import { StyleSheet } from 'react-native';
+import {StyleSheet} from 'react-native';
 import fontFamily from './fontFamily';
 import addOutlineWidth from './addOutlineWidth';
 import themeColors from './themes/default';
@@ -3794,11 +3794,10 @@ const styles = {
         marginTop: 40,
     },
     selectionListRadioSeparator: {
-      height: StyleSheet.hairlineWidth,
-      backgroundColor: themeColors.border,
-      marginHorizontal: 20,
-
-    }
+        height: StyleSheet.hairlineWidth,
+        backgroundColor: themeColors.border,
+        marginHorizontal: 20,
+    },
 };
 
 export default styles;

From 9e8e850e422571feafd4edeb4c74dbf9932eff96 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 23 Aug 2023 22:42:26 +0200
Subject: [PATCH 023/118] create areDatesIdentical and getTimePeriod

---
 src/libs/DateUtils.js | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index a40eeb28c70b..0fda6f324c5c 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -287,8 +287,6 @@ function getDateBasedFromType(type) {
             return getEndOfToday();
         case CONST.CUSTOM_STATUS_TYPES.AFTER_WEEK:
             return getEndOfWeekFromNow();
-        case CONST.CUSTOM_STATUS_TYPES.NEVER:
-            return getOneHundredYearsFromNow();
         default:
             return '';
     }
@@ -374,6 +372,27 @@ function parseTimeTo12HourFormat(datetime) {
     };
 }
 
+/**
+ * @param {String} dateStr
+ * @returns {String}
+ * @example
+ */
+function getTimePeriod(dateStr) {
+    return moment(dateStr).format('A');
+}
+
+/**
+ * @param {String} dateParam1
+ * @param {String} dateParam2
+ * @returns {Boolean}
+ */
+function areDatesIdentical(dateParam1, dateParam2) {
+    const date1 = moment(dateParam1);
+    const date2 = moment(dateParam2);
+
+    return date1.isSame(date2);
+}
+
 /**
  * @namespace DateUtils
  */
@@ -402,6 +421,8 @@ const DateUtils = {
     extractTime12Hour,
     setTimeOrDefaultToTomorrow,
     parseTimeTo12HourFormat,
+    areDatesIdentical,
+    getTimePeriod,
 };
 
 export default DateUtils;

From b8da3bbf3851bffabc304917f909b0e9922aaf07 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 23 Aug 2023 23:06:43 +0200
Subject: [PATCH 024/118] fix BaseSelectionList after merge

---
 src/ONYXKEYS.ts                                              | 1 +
 src/components/SelectionList/BaseSelectionList.js            | 5 ++++-
 src/components/SelectionList/RadioListItem.js                | 3 ++-
 src/libs/DateUtils.js                                        | 2 +-
 .../settings/Profile/CustomStatus/StatusClearAfterPage.js    | 4 ++--
 5 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index d4d2ab1f90a6..f097cacb41ea 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -275,6 +275,7 @@ const ONYXKEYS = {
         SETTINGS_STATUS_SET_FORM: 'settingsStatusSetForm',
         SETTINGS_STATUS_CLEAR_AFTER_FORM: 'settingsStatusClearAfterForm',
         SETTINGS_STATUS_SET_CLEAR_AFTER_FORM: 'settingsStatusSetClearAfterForm',
+        SETTINGS_STATUS_CLEAR_DATE_FORM: 'settingsStatusClearDateForm',
     },
 } as const;
 
diff --git a/src/components/SelectionList/BaseSelectionList.js b/src/components/SelectionList/BaseSelectionList.js
index c7244093396e..716c94520536 100644
--- a/src/components/SelectionList/BaseSelectionList.js
+++ b/src/components/SelectionList/BaseSelectionList.js
@@ -50,6 +50,8 @@ function BaseSelectionList({
     showScrollIndicator = false,
     showLoadingPlaceholder = false,
     isKeyboardShown = false,
+    wrapperStyle = {},
+    disableInitialFocusOptionStyle = false,
 }) {
     const {translate} = useLocalize();
     const firstLayoutRef = useRef(true);
@@ -264,6 +266,7 @@ function BaseSelectionList({
                 isFocused={isFocused}
                 isDisabled={isDisabled}
                 onSelectRow={() => selectRow(item, index)}
+                disableIsFocusStyle={disableInitialFocusOptionStyle}
             />
         );
     };
@@ -304,7 +307,7 @@ function BaseSelectionList({
         >
             <SafeAreaConsumer>
                 {({safeAreaPaddingBottomStyle}) => (
-                    <View style={[styles.flex1, !isKeyboardShown && safeAreaPaddingBottomStyle]}>
+                    <View style={[styles.flex1, !isKeyboardShown && safeAreaPaddingBottomStyle, wrapperStyle]}>
                         {shouldShowTextInput && (
                             <View style={[styles.ph5, styles.pb3]}>
                                 <TextInput
diff --git a/src/components/SelectionList/RadioListItem.js b/src/components/SelectionList/RadioListItem.js
index 92e3e84b66c8..f35f05561fc5 100644
--- a/src/components/SelectionList/RadioListItem.js
+++ b/src/components/SelectionList/RadioListItem.js
@@ -8,7 +8,8 @@ import * as Expensicons from '../Icon/Expensicons';
 import themeColors from '../../styles/themes/default';
 import {radioListItemPropTypes} from './selectionListPropTypes';
 
-function RadioListItem({item, isFocused = false, isDisabled = false, onSelectRow}) {
+function RadioListItem({item, isFocused: isFocusedProp = false, isDisabled = false, onSelectRow, disableInitialFocusOptionStyle = false}) {
+    const isFocused = disableInitialFocusOptionStyle && isFocusedProp;
     return (
         <PressableWithFeedback
             onPress={() => onSelectRow(item)}
diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index 85c1539deb26..20cec65d5167 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -18,7 +18,7 @@ import {
     isAfter,
     isSameYear,
 } from 'date-fns';
-
+import moment from 'moment';
 import _ from 'underscore';
 import Onyx from 'react-native-onyx';
 import ONYXKEYS from '../ONYXKEYS';
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 2446907dfeb8..e1d69d009c2e 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -12,7 +12,7 @@ import Navigation from '../../../../libs/Navigation/Navigation';
 import styles from '../../../../styles/styles';
 import Text from '../../../../components/Text';
 import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription';
-import SelectionListRadio from '../../../../components/SelectionListRadio';
+import SelectionList from '../../../../components/SelectionList';
 import useLocalize from '../../../../hooks/useLocalize';
 import ONYXKEYS from '../../../../ONYXKEYS';
 import CONST from '../../../../CONST';
@@ -106,7 +106,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 submitButtonStyle={styles.mh3}
             >
                 <View style={styles.flexGrow1}>
-                    <SelectionListRadio
+                    <SelectionList
                         sections={[{data: localesToThemes, indexOffset: 0}]}
                         onSelectRow={updateMode}
                         disableInitialFocusOptionStyle

From 8a2af6fa2401bba82bd9860dce863f23b164302a Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 24 Aug 2023 09:12:41 +0200
Subject: [PATCH 025/118] remove stale time

---
 .../settings/Profile/CustomStatus/StatusClearAfterPage.js | 8 ++++----
 src/pages/settings/Profile/CustomStatus/StatusPage.js     | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index e1d69d009c2e..25439c0f74a8 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -38,9 +38,9 @@ const propTypes = {
 function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const localize = useLocalize();
     const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
-
     const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
     const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
+
     const [draftPeriod, setDraftPeriod] = useState((clearAfter && !draftClearAfter) || draftClearAfter ? CONST.CUSTOM_STATUS_TYPES.CUSTOM : CONST.CUSTOM_STATUS_TYPES.AFTER_TODAY);
 
     const localesToThemes = useMemo(
@@ -80,15 +80,15 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
 
     useEffect(() => {
         User.updateDraftCustomStatus({
-            customDateTemporary: clearAfter,
-            clearAfter,
+            customDateTemporary: draftClearAfter || clearAfter,
+            clearAfter: draftClearAfter || clearAfter,
         });
 
         // eslint-disable-next-line react-hooks/exhaustive-deps
     }, []);
 
     const customStatusDate = DateUtils.extractDate(customDateTemporary || draftClearAfter || clearAfter);
-    const customStatusTime = DateUtils.extractTime12Hour(customDateTemporary || clearAfter);
+    const customStatusTime = DateUtils.extractTime12Hour(customDateTemporary || draftClearAfter || clearAfter);
 
     return (
         <ScreenWrapper>
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 18ece2b6f526..c80ac2912353 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -90,7 +90,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
             />
             <MenuItemWithTopDescription
                 title={customClearAfter}
-                description="Clear after"
+                description={localize.translate('statusPage.clearAfter')}
                 shouldShowRightIcon
                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
             />

From ff8334c5d6e627bf69a4dead3c17d2e9415f6d6d Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 24 Aug 2023 09:54:06 +0200
Subject: [PATCH 026/118] disable scroll

---
 src/components/Form.js                        |    2 +-
 .../SelectionList/BaseSelectionList.js        |    2 +
 src/components/TimePicker.js                  |   16 +-
 src/languages/es.js                           | 2360 ++++++++---------
 4 files changed, 1188 insertions(+), 1192 deletions(-)

diff --git a/src/components/Form.js b/src/components/Form.js
index b60678382041..33ea23ec6366 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -102,7 +102,7 @@ const defaultProps = {
     footerContent: null,
     style: [],
     validate: () => ({}),
-    submitButtonStyle: {}
+    submitButtonStyle: {},
 };
 
 function Form(props) {
diff --git a/src/components/SelectionList/BaseSelectionList.js b/src/components/SelectionList/BaseSelectionList.js
index 716c94520536..d1c0807fcabd 100644
--- a/src/components/SelectionList/BaseSelectionList.js
+++ b/src/components/SelectionList/BaseSelectionList.js
@@ -52,6 +52,7 @@ function BaseSelectionList({
     isKeyboardShown = false,
     wrapperStyle = {},
     disableInitialFocusOptionStyle = false,
+    scrollEnabled = true,
 }) {
     const {translate} = useLocalize();
     const firstLayoutRef = useRef(true);
@@ -378,6 +379,7 @@ function BaseSelectionList({
                                         scrollToIndex(focusedIndex, false);
                                         firstLayoutRef.current = false;
                                     }}
+                                    scrollEnabled={scrollEnabled}
                                 />
                             </>
                         )}
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 27a8401a2e51..b5c0e096f1a5 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -87,7 +87,7 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
     const [hours, setHours] = useState(DateUtils.parseTimeTo12HourFormat(defaultValue).hour);
     const [minute, setMinute] = useState(DateUtils.parseTimeTo12HourFormat(defaultValue).minute);
     const [selectionHour, setSelectionHour] = useState({start: 0, end: 0});
-    const [selectionMinute, setSelectionMinute] = useState({start: 0, end: 0});
+    const [selectionMinute, setSelectionMinute] = useState({start: 2, end: 2}); // we focus it by default so need  to have selection on the end
 
     const [amPmValue, setAmPmValue] = useState(DateUtils.getTimePeriod(defaultValue));
 
@@ -107,12 +107,6 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
         minuteInputRef.current.focus();
         setSelectionMinute({start: 0, end: 0});
     }, []);
-    const focusHourInputIfNeeded = useCallback(({nativeEvent}, forceFocus = false) => {
-        const keyValue = lodashGet(nativeEvent, 'key', '');
-        if (!forceFocus && keyValue !== 'Backspace') return;
-
-        hourInputRef.current.focus();
-    }, []);
 
     const handleHourChange = (text) => {
         let filteredText;
@@ -235,7 +229,7 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
                     setSelectionHour(decreaseBothSelectionByOne(selectionHour));
                 } else if (isMinuteFocused) {
                     if (selectionMinute.start === 0) {
-                        focusHourInputIfNeeded(_, true);
+                        hourInputRef.current.focus();
                     }
                     const newMinute = replaceWithZeroAtPosition(minute, selectionMinute.start);
                     setMinute(newMinute);
@@ -268,7 +262,7 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
     const arrowLeftCallback = useCallback(() => {
         const isMinuteFocused = minuteInputRef.current.isFocused();
         if (isMinuteFocused && selectionMinute.start === 0) {
-            focusHourInputIfNeeded(_, true);
+            hourInputRef.current.focus();
         }
         // eslint-disable-next-line react-hooks/exhaustive-deps
     }, [selectionHour, selectionMinute]);
@@ -286,8 +280,8 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
 
     const handleFocusOnBackspace = useCallback(
         (e) => {
-            if (selectionMinute.start !== 0 || e.key === 'Backspace') return;
-            focusHourInputIfNeeded(e);
+            if (selectionMinute.start !== 0 || e.key !== 'Backspace') return;
+            hourInputRef.current.focus();
         },
         // eslint-disable-next-line react-hooks/exhaustive-deps
         [selectionMinute.start],
diff --git a/src/languages/es.js b/src/languages/es.js
index 7e81f578b22a..0d0ba2df1605 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -937,1201 +937,1201 @@ export default {
         date: 'Fecha',
         time: 'Hora',
         clearAfter: 'Borrar después',
-        stepCounter: ({step, total, text}) => {
-            let result = `Paso ${step}`;
+    },
+    stepCounter: ({step, total, text}) => {
+        let result = `Paso ${step}`;
 
-            if (total) {
-                result = `${result} de ${total}`;
-            }
+        if (total) {
+            result = `${result} de ${total}`;
+        }
 
-            if (text) {
-                result = `${result}: ${text}`;
-            }
-            return result;
-        },
-        bankAccount: {
-            accountNumber: 'Número de cuenta',
-            routingNumber: 'Número de ruta',
-            addBankAccount: 'Añadir cuenta bancaria',
-            chooseAnAccount: 'Elige una cuenta',
-            connectOnlineWithPlaid: 'Conéctate a Plaid online',
-            connectManually: 'Conectar manualmente',
-            desktopConnection: 'Para conectarse con Chase, Wells Fargo, Capital One o Bank of America, haga clic aquí para completar este proceso en un navegador.',
-            yourDataIsSecure: 'Tus datos están seguros',
-            toGetStarted: 'Añade una cuenta bancaria y emite tarjetas corporativas, reembolsa gastos y cobra y paga facturas, todo desde un mismo lugar.',
-            plaidBodyCopy: 'Ofrezca a sus empleados una forma más sencilla de pagar - y recuperar - los gastos de la empresa.',
-            checkHelpLine: 'Su número de ruta y número de cuenta se pueden encontrar en un cheque de la cuenta bancaria.',
-            validateAccountError:
-                'Para terminar de configurar tu cuenta bancaria, debes validar tu cuenta de Expensify. Por favor, revisa tu correo electrónico para validar tu cuenta y vuelve aquí para continuar.',
-            hasPhoneLoginError:
-                'Para añadir una cuenta bancaria verificada, asegúrate de que tu nombre de usuario principal sea un correo electrónico válido y vuelve a intentarlo. Puedes añadir tu número de teléfono como nombre de usuario secundario.',
-            hasBeenThrottledError: 'Se produjo un error al intentar añadir tu cuenta bancaria. Por favor, espera unos minutos e inténtalo de nuevo.',
-            hasCurrencyError:
-                '¡Ups! Parece que la moneda de tu espacio de trabajo está configurada en una moneda diferente a USD. Para continuar, por favor configúrala en USD e inténtalo nuevamente.',
+        if (text) {
+            result = `${result}: ${text}`;
+        }
+        return result;
+    },
+    bankAccount: {
+        accountNumber: 'Número de cuenta',
+        routingNumber: 'Número de ruta',
+        addBankAccount: 'Añadir cuenta bancaria',
+        chooseAnAccount: 'Elige una cuenta',
+        connectOnlineWithPlaid: 'Conéctate a Plaid online',
+        connectManually: 'Conectar manualmente',
+        desktopConnection: 'Para conectarse con Chase, Wells Fargo, Capital One o Bank of America, haga clic aquí para completar este proceso en un navegador.',
+        yourDataIsSecure: 'Tus datos están seguros',
+        toGetStarted: 'Añade una cuenta bancaria y emite tarjetas corporativas, reembolsa gastos y cobra y paga facturas, todo desde un mismo lugar.',
+        plaidBodyCopy: 'Ofrezca a sus empleados una forma más sencilla de pagar - y recuperar - los gastos de la empresa.',
+        checkHelpLine: 'Su número de ruta y número de cuenta se pueden encontrar en un cheque de la cuenta bancaria.',
+        validateAccountError:
+            'Para terminar de configurar tu cuenta bancaria, debes validar tu cuenta de Expensify. Por favor, revisa tu correo electrónico para validar tu cuenta y vuelve aquí para continuar.',
+        hasPhoneLoginError:
+            'Para añadir una cuenta bancaria verificada, asegúrate de que tu nombre de usuario principal sea un correo electrónico válido y vuelve a intentarlo. Puedes añadir tu número de teléfono como nombre de usuario secundario.',
+        hasBeenThrottledError: 'Se produjo un error al intentar añadir tu cuenta bancaria. Por favor, espera unos minutos e inténtalo de nuevo.',
+        hasCurrencyError:
+            '¡Ups! Parece que la moneda de tu espacio de trabajo está configurada en una moneda diferente a USD. Para continuar, por favor configúrala en USD e inténtalo nuevamente.',
+        error: {
+            noBankAccountAvailable: 'Lo sentimos, no hay ninguna cuenta bancaria disponible',
+            noBankAccountSelected: 'Por favor, elige una cuenta bancaria',
+            taxID: 'Por favor, introduce un número de identificación fiscal válido',
+            website: 'Por favor, introduce un sitio web válido',
+            zipCode: 'Por favor, introduce un código postal válido',
+            phoneNumber: 'Por favor, introduce un teléfono válido',
+            companyName: 'Por favor, introduce un nombre comercial legal válido',
+            addressCity: 'Por favor, introduce una ciudad válida',
+            addressStreet: 'Por favor, introduce una calle de dirección válida que no sea un apartado postal',
+            addressState: 'Por favor, selecciona un estado',
+            incorporationDateFuture: 'La fecha de incorporación no puede ser futura',
+            incorporationState: 'Por favor, selecciona una estado válido',
+            industryCode: 'Por favor, introduce un código de clasificación de industria válido',
+            restrictedBusiness: 'Por favor, confirma que la empresa no está en la lista de negocios restringidos',
+            routingNumber: 'Por favor, introduce un número de ruta válido',
+            accountNumber: 'Por favor, introduce un número de cuenta válido',
+            routingAndAccountNumberCannotBeSame: 'El número de ruta y el número de cuenta no pueden ser iguales',
+            companyType: 'Por favor, selecciona un tipo de compañía válido',
+            tooManyAttempts:
+                'Debido a la gran cantidad de intentos de inicio de sesión, esta opción se ha desactivado temporalmente durante 24 horas. Vuelve a intentarlo más tarde o introduce los detalles manualmente.',
+            address: 'Por favor, introduce una dirección válida',
+            dob: 'Por favor, selecciona una fecha de nacimiento válida',
+            age: 'Debe ser mayor de 18 años',
+            ssnLast4: 'Por favor, introduce los últimos 4 dígitos del número de seguridad social',
+            firstName: 'Por favor, introduce el nombre',
+            lastName: 'Por favor, introduce los apellidos',
+            noDefaultDepositAccountOrDebitCardAvailable: 'Por favor, añade una cuenta bancaria para depósitos o una tarjeta de débito',
+            validationAmounts: 'Los importes de validación que introduciste son incorrectos. Por favor, comprueba tu cuenta bancaria e inténtalo de nuevo.',
+        },
+    },
+    addPersonalBankAccountPage: {
+        enterPassword: 'Escribe tu contraseña de Expensify',
+        alreadyAdded: 'Esta cuenta ya ha sido añadida.',
+        chooseAccountLabel: 'Cuenta',
+        successTitle: '¡Cuenta bancaria personal añadida!',
+        successMessage: 'Enhorabuena, tu cuenta bancaria está lista para recibir reembolsos.',
+    },
+    attachmentView: {
+        unknownFilename: 'Archivo desconocido',
+        passwordRequired: 'Por favor, introduce tu contraseña',
+        passwordIncorrect: 'Contraseña incorrecta. Por favor, inténtalo de nuevo.',
+        failedToLoadPDF: 'Hubo un error al intentar cargar el PDF.',
+        pdfPasswordForm: {
+            title: 'PDF protegido con contraseña',
+            infoText: 'Este PDF esta protegido con contraseña.',
+            beforeLinkText: 'Por favor',
+            linkText: 'introduce la contraseña',
+            afterLinkText: 'para verlo.',
+            formLabel: 'Ver PDF',
+        },
+    },
+    messages: {
+        errorMessageInvalidPhone: `Por favor, introduce un número de teléfono válido sin paréntesis o guiones. Si reside fuera de Estados Unidos, por favor incluye el prefijo internacional (p. ej. ${CONST.EXAMPLE_PHONE_NUMBER}).`,
+        errorMessageInvalidEmail: 'Email inválido',
+        userIsAlreadyMemberOfWorkspace: ({login, workspace}) => `${login} ya es miembro de ${workspace}`,
+    },
+    onfidoStep: {
+        acceptTerms: 'Al continuar con la solicitud para activar su billetera Expensify, confirma que ha leído, comprende y acepta ',
+        facialScan: 'Política y lanzamiento de la exploración facial de Onfido',
+        tryAgain: 'Intentar otra vez',
+        verifyIdentity: 'Verificar identidad',
+        genericError: 'Hubo un error al procesar este paso. Inténtalo de nuevo.',
+        cameraPermissionsNotGranted: 'No has habilitado los permisos para acceder a la cámara',
+        cameraRequestMessage: 'No has habilitado los permisos para acceder a la cámara. Necesitamos acceso para completar la verificaciôn.',
+        originalDocumentNeeded: 'Por favor, sube una imagen original de tu identificación en lugar de una captura de pantalla o imagen escaneada.',
+        documentNeedsBetterQuality:
+            'Parece que tu identificación esta dañado o le faltan características de seguridad. Por favor, sube una imagen de tu documento sin daños y que se vea completamente.',
+        imageNeedsBetterQuality: 'Hay un problema con la calidad de la imagen de tu identificación. Por favor, sube una nueva imagen donde el identificación se vea con claridad.',
+        selfieIssue: 'Hay un problema con tu selfie/video. Por favor, sube un nuevo selfie/video grabado en el momento',
+        selfieNotMatching: 'Tu selfie/video no concuerda con tu identificación. Por favor, sube un nuevo selfie/video donde se vea tu cara con claridad.',
+        selfieNotLive: 'Tu selfie/video no parece ser un selfie/video en vivo. Por favor, sube un selfie/video a tiempo real.',
+    },
+    additionalDetailsStep: {
+        headerTitle: 'Detalles adicionales',
+        helpText: 'Necesitamos confirmar la siguiente información antes de que podamos procesar el pago.',
+        helpTextIdologyQuestions: 'Tenemos que preguntarte unas preguntas más para terminar de verificar tu identidad',
+        helpLink: 'Obtén más información sobre por qué necesitamos esto.',
+        legalFirstNameLabel: 'Primer nombre legal',
+        legalMiddleNameLabel: 'Segundo nombre legal',
+        legalLastNameLabel: 'Apellidos legales',
+        selectAnswer: 'Selecciona una respuesta.',
+        ssnFull9Error: 'Por favor, introduce los 9 dígitos de un número de seguridad social válido',
+        needSSNFull9: 'Estamos teniendo problemas para verificar tu número de seguridad social. Introduce los 9 dígitos del número de seguridad social.',
+        weCouldNotVerify: 'No se pudo verificar',
+        pleaseFixIt: 'Corrige esta información antes de continuar.',
+        failedKYCTextBefore: 'No se ha podido verificar correctamente tu identidad. Vuelve a intentarlo más tarde y comunicate con ',
+        failedKYCTextAfter: ' si tienes alguna pregunta.',
+    },
+    termsStep: {
+        headerTitle: 'Condiciones y tarifas',
+        haveReadAndAgree: 'He leído y acepto recibir ',
+        electronicDisclosures: 'divulgaciones electrónicas',
+        agreeToThe: 'Estoy de acuerdo con la ',
+        walletAgreement: 'Acuerdo de billetera',
+        enablePayments: 'Habilitar pagos',
+        feeAmountZero: '$0',
+        monthlyFee: 'Cuota mensual',
+        inactivity: 'Inactividad',
+        electronicFundsInstantFee: '1.5%',
+        noOverdraftOrCredit: 'Sin función de sobregiro / crédito',
+        electronicFundsWithdrawal: 'Retiro electrónico de fondos',
+        standard: 'Estándar',
+        shortTermsForm: {
+            expensifyPaymentsAccount: 'La billetera Expensify es emitida por The Bancorp Bank.',
+            perPurchase: 'Por compra',
+            atmWithdrawal: 'Retiro de cajero automático',
+            cashReload: 'Recarga de efectivo',
+            inNetwork: 'en la red',
+            outOfNetwork: 'fuera de la red',
+            atmBalanceInquiry: 'Consulta de saldo de cajero automático',
+            inOrOutOfNetwork: '(dentro o fuera de la red)',
+            customerService: 'Servicio al cliente',
+            automatedOrLive: '(agente automatizado o en vivo)',
+            afterTwelveMonths: '(después de 12 meses sin transacciones)',
+            weChargeOneFee: 'Cobramos un tipo de tarifa.',
+            fdicInsurance: 'Sus fondos son elegibles para el seguro de la FDIC.',
+            generalInfo: 'Para obtener información general sobre cuentas prepagas, visite',
+            conditionsDetails: 'Encuentra detalles y condiciones para todas las tarifas y servicios visitando',
+            conditionsPhone: 'o llamando al +1 833-400-0904.',
+            instant: '(instantáneo)',
+            electronicFundsInstantFeeMin: '(mínimo $0.25)',
+        },
+        longTermsForm: {
+            listOfAllFees: 'Una lista de todas las tarifas de la billetera Expensify',
+            typeOfFeeHeader: 'Tipo de tarifa',
+            feeAmountHeader: 'Importe de la tarifa',
+            moreDetailsHeader: 'Más detalles',
+            openingAccountTitle: 'Abrir una cuenta',
+            openingAccountDetails: 'No hay tarifa para abrir una cuenta.',
+            monthlyFeeDetails: 'No hay tarifa mensual.',
+            customerServiceTitle: 'Servicio al cliente',
+            customerServiceDetails: 'No hay tarifas de servicio al cliente.',
+            inactivityDetails: 'No hay tarifa de inactividad.',
+            sendingFundsTitle: 'Enviar fondos a otro titular de cuenta',
+            sendingFundsDetails: 'No se aplica ningún cargo por enviar fondos a otro titular de cuenta utilizando su saldo cuenta bancaria o tarjeta de débito',
+            electronicFundsStandardDetails:
+                'No hay cargo por transferir fondos desde su billetera Expensify ' +
+                'a su cuenta bancaria utilizando la opción estándar. Esta transferencia generalmente se completa en' +
+                '1-3 negocios días.',
+            electronicFundsInstantDetails:
+                'Hay una tarifa para transferir fondos desde su billetera Expensify a ' +
+                'su tarjeta de débito vinculada utilizando la opción de transferencia instantánea. Esta transferencia ' +
+                'generalmente se completa dentro de varios minutos. La tarifa es el 1.5% del monto de la ' +
+                'transferencia (con una tarifa mínima de $ 0.25). ',
+            fdicInsuranceBancorp:
+                'Sus fondos son elegibles para el seguro de la FDIC. Sus fondos se mantendrán en o ' +
+                'transferido a The Bancorp Bank, una institución asegurada por la FDIC. Una vez allí, sus fondos ' +
+                'están asegurados a $ 250,000 por la FDIC en caso de que The Bancorp Bank quiebre. Ver',
+            fdicInsuranceBancorp2: 'para detalles.',
+            contactExpensifyPayments: 'Comuníquese con Expensify Payments llamando al + 1833-400-0904, por correoelectrónico a',
+            contactExpensifyPayments2: 'o inicie sesión en',
+            generalInformation: 'Para obtener información general sobre cuentas prepagas, visite',
+            generalInformation2: 'Si tiene una queja sobre una cuenta prepaga, llame al Consumer Financial Oficina de Protección al 1-855-411-2372 o visite',
+            printerFriendlyView: 'Ver versión para imprimir',
+            automated: 'Automatizado',
+            liveAgent: 'Agente en vivo',
+            instant: 'Instantáneo',
+            electronicFundsInstantFeeMin: 'Mínimo $0.25',
+        },
+    },
+    activateStep: {
+        headerTitle: 'Habilitar pagos',
+        activatedTitle: '¡Billetera  activada!',
+        activatedMessage: 'Felicidades, tu Billetera está configurada y lista para hacer pagos.',
+        checkBackLaterTitle: 'Un momento...',
+        checkBackLaterMessage: 'Todavía estamos revisando tu información. Por favor, vuelva más tarde.',
+        continueToPayment: 'Continuar al pago',
+        continueToTransfer: 'Continuar a la transferencia',
+    },
+    companyStep: {
+        headerTitle: 'Información de la empresa',
+        subtitle: '¡Ya casi estamos! Por motivos de seguridad, necesitamos confirmar la siguiente información:',
+        legalBusinessName: 'Nombre comercial legal',
+        companyWebsite: 'Página web de la empresa',
+        taxIDNumber: 'Número de identificación fiscal',
+        taxIDNumberPlaceholder: '9 dígitos',
+        companyType: 'Tipo de empresa',
+        incorporationDate: 'Fecha de incorporación',
+        incorporationState: 'Estado de incorporación',
+        industryClassificationCode: 'Código de clasificación industrial',
+        confirmCompanyIsNot: 'Confirmo que esta empresa no está en el',
+        listOfRestrictedBusinesses: 'lista de negocios restringidos',
+        incorporationDatePlaceholder: 'Fecha de inicio (aaaa-mm-dd)',
+        incorporationTypes: {
+            LLC: 'LLC',
+            CORPORATION: 'Corp',
+            PARTNERSHIP: 'Sociedad',
+            COOPERATIVE: 'Cooperativa',
+            SOLE_PROPRIETORSHIP: 'Propietario único',
+            OTHER: 'Otra',
+        },
+    },
+    requestorStep: {
+        headerTitle: 'Información personal',
+        subtitle: 'Dé más información sobre tí.',
+        learnMore: 'Más información',
+        isMyDataSafe: '¿Están seguros mis datos?',
+        onFidoConditions: 'Al continuar con la solicitud de añadir esta cuenta bancaria, confirma que ha leído, entiende y acepta ',
+        isControllingOfficer: 'Estoy autorizado a utilizar la cuenta bancaria de mi compañía para gastos de empresa',
+        isControllingOfficerError: 'Debe ser un oficial controlador con autorización para operar la cuenta bancaria de la compañía',
+    },
+    validationStep: {
+        headerTitle: 'Validar cuenta bancaria',
+        buttonText: 'Finalizar configuración',
+        maxAttemptsReached: 'Se ha inhabilitado la validación de esta cuenta bancaria debido a demasiados intentos incorrectos.',
+        description:
+            'Uno o dos días después de añadir tu cuenta a Expensify, te enviaremos tres (3) transacciones a tu cuenta. Tienen un nombre de comerciante similar a "Expensify, Inc. Validation".',
+        descriptionCTA: 'Introduce el importe de cada transacción en los campos siguientes. Ejemplo: 1.51.',
+        reviewingInfo: '¡Gracias! Estamos revisando tu información y nos comunicaremos contigo en breve. Consulta el chat con Concierge ',
+        forNextSteps: ' para conocer los próximos pasos para terminar de configurar tu cuenta bancaria.',
+        letsChatCTA: 'Sí, vamos a chatear',
+        letsChatText: 'Gracias. Necesitamos tu ayuda para verificar la información, pero podemos hacerlo rápidamente a través del chat. ¿Estás listo?',
+        letsChatTitle: '¡Vamos a chatear!',
+        enable2FATitle: 'Evita fraudes, activa la autenticación de dos factores!',
+        enable2FAText:
+            'Tu seguridad es importante para nosotros. Por favor, configura ahora la autenticación de dos factores. Eso nos permitirá disputar las transacciones de la Tarjeta Expensify y reducirá tu riesgo de fraude.',
+        secureYourAccount: 'Asegura tu cuenta',
+    },
+    beneficialOwnersStep: {
+        additionalInformation: 'Información adicional',
+        checkAllThatApply: 'Marca todos los que apliquen, en caso de que ninguno aplique dejar en blanco.',
+        iOwnMoreThan25Percent: 'Soy dueño de mas de 25% de ',
+        someoneOwnsMoreThan25Percent: 'Otra persona es dueña de mas de 25% de ',
+        additionalOwner: 'Beneficiario efectivo adicional',
+        removeOwner: 'Eliminar este beneficiario efectivo',
+        addAnotherIndividual: 'Añadir otra persona que es dueña de mas de 25% de ',
+        agreement: 'Acuerdo:',
+        termsAndConditions: 'Términos y condiciones',
+        certifyTrueAndAccurate: 'Certifico que la información dada es correcta',
+        error: {
+            certify: 'Debe certificar que la información es verdadera y precisa',
+        },
+    },
+    reimbursementAccountLoadingAnimation: {
+        oneMoment: 'Un momento',
+        explanationLine: 'Estamos verificando tu información y podrás continuar con los siguientes pasos en unos momentos.',
+    },
+    session: {
+        offlineMessageRetry: 'Parece que estás desconectado. Por favor, comprueba tu conexión e inténtalo de nuevo.',
+    },
+    workspace: {
+        common: {
+            card: 'Tarjetas',
+            workspace: 'Espacio de trabajo',
+            edit: 'Editar espacio de trabajo',
+            delete: 'Eliminar espacio de trabajo',
+            settings: 'Configuración',
+            reimburse: 'Reembolsos',
+            bills: 'Pagar facturas',
+            invoices: 'Enviar facturas',
+            travel: 'Viajes',
+            members: 'Miembros',
+            bankAccount: 'Cuenta bancaria',
+            connectBankAccount: 'Conectar cuenta bancaria',
+            testTransactions: 'Transacciones de prueba',
+            issueAndManageCards: 'Emitir y gestionar tarjetas',
+            reconcileCards: 'Reconciliar tarjetas',
+            settlementFrequency: 'Frecuencia de liquidación',
+            deleteConfirmation: '¿Estás seguro de que quieres eliminar este espacio de trabajo?',
+            unavailable: 'Espacio de trabajo no disponible',
+            memberNotFound: 'Miembro no encontrado. Para invitar a un nuevo miembro al espacio de trabajo, por favor, utiliza el botón Invitar que está arriba.',
+            notAuthorized: `No tienes acceso a esta página. ¿Estás tratando de unirte al espacio de trabajo? Comunícate con el propietario de este espacio de trabajo para que pueda añadirte como miembro. ¿Necesitas algo más? Comunícate con ${CONST.EMAIL.CONCIERGE}`,
+            goToRoom: ({roomName}) => `Ir a la sala ${roomName}`,
+        },
+        emptyWorkspace: {
+            title: 'Crear un nuevo espacio de trabajo',
+            subtitle: 'En los espacios de trabajo es donde puedes chatear con tu equipo, reembolsar gastos, emitir tarjetas, enviar y pagar facturas y mas — todo en un mismo lugar',
+            features: {
+                trackAndCollect: 'Organiza recibos',
+                companyCards: 'Tarjetas de crédito corporativas',
+                reimbursements: 'Reembolsos fáciles',
+            },
+        },
+        new: {
+            newWorkspace: 'Nuevo espacio de trabajo',
+            getTheExpensifyCardAndMore: 'Consigue la Tarjeta Expensify y más',
+        },
+        people: {
+            genericFailureMessage: 'Se ha producido un error al intentar eliminar a un usuario del espacio de trabajo. Por favor, inténtalo más tarde.',
+            removeMembersPrompt: '¿Estás seguro que quieres eliminar a los miembros seleccionados de tu espacio de trabajo?',
+            removeMembersTitle: 'Eliminar miembros',
+            selectAll: 'Seleccionar todo',
             error: {
-                noBankAccountAvailable: 'Lo sentimos, no hay ninguna cuenta bancaria disponible',
-                noBankAccountSelected: 'Por favor, elige una cuenta bancaria',
-                taxID: 'Por favor, introduce un número de identificación fiscal válido',
-                website: 'Por favor, introduce un sitio web válido',
-                zipCode: 'Por favor, introduce un código postal válido',
-                phoneNumber: 'Por favor, introduce un teléfono válido',
-                companyName: 'Por favor, introduce un nombre comercial legal válido',
-                addressCity: 'Por favor, introduce una ciudad válida',
-                addressStreet: 'Por favor, introduce una calle de dirección válida que no sea un apartado postal',
-                addressState: 'Por favor, selecciona un estado',
-                incorporationDateFuture: 'La fecha de incorporación no puede ser futura',
-                incorporationState: 'Por favor, selecciona una estado válido',
-                industryCode: 'Por favor, introduce un código de clasificación de industria válido',
-                restrictedBusiness: 'Por favor, confirma que la empresa no está en la lista de negocios restringidos',
-                routingNumber: 'Por favor, introduce un número de ruta válido',
-                accountNumber: 'Por favor, introduce un número de cuenta válido',
-                routingAndAccountNumberCannotBeSame: 'El número de ruta y el número de cuenta no pueden ser iguales',
-                companyType: 'Por favor, selecciona un tipo de compañía válido',
-                tooManyAttempts:
-                    'Debido a la gran cantidad de intentos de inicio de sesión, esta opción se ha desactivado temporalmente durante 24 horas. Vuelve a intentarlo más tarde o introduce los detalles manualmente.',
-                address: 'Por favor, introduce una dirección válida',
-                dob: 'Por favor, selecciona una fecha de nacimiento válida',
-                age: 'Debe ser mayor de 18 años',
-                ssnLast4: 'Por favor, introduce los últimos 4 dígitos del número de seguridad social',
-                firstName: 'Por favor, introduce el nombre',
-                lastName: 'Por favor, introduce los apellidos',
-                noDefaultDepositAccountOrDebitCardAvailable: 'Por favor, añade una cuenta bancaria para depósitos o una tarjeta de débito',
-                validationAmounts: 'Los importes de validación que introduciste son incorrectos. Por favor, comprueba tu cuenta bancaria e inténtalo de nuevo.',
-            },
-        },
-        addPersonalBankAccountPage: {
-            enterPassword: 'Escribe tu contraseña de Expensify',
-            alreadyAdded: 'Esta cuenta ya ha sido añadida.',
-            chooseAccountLabel: 'Cuenta',
-            successTitle: '¡Cuenta bancaria personal añadida!',
-            successMessage: 'Enhorabuena, tu cuenta bancaria está lista para recibir reembolsos.',
-        },
-        attachmentView: {
-            unknownFilename: 'Archivo desconocido',
-            passwordRequired: 'Por favor, introduce tu contraseña',
-            passwordIncorrect: 'Contraseña incorrecta. Por favor, inténtalo de nuevo.',
-            failedToLoadPDF: 'Hubo un error al intentar cargar el PDF.',
-            pdfPasswordForm: {
-                title: 'PDF protegido con contraseña',
-                infoText: 'Este PDF esta protegido con contraseña.',
-                beforeLinkText: 'Por favor',
-                linkText: 'introduce la contraseña',
-                afterLinkText: 'para verlo.',
-                formLabel: 'Ver PDF',
-            },
+                genericAdd: 'Ha ocurrido un problema al añadir el miembro al espacio de trabajo.',
+                cannotRemove: 'No puedes eliminarte ni a ti mismo ni al dueño del espacio de trabajo.',
+                genericRemove: 'Ha ocurrido un problema al eliminar al miembro del espacio de trabajo.',
+            },
+        },
+        card: {
+            header: 'Desbloquea Tarjetas Expensify gratis',
+            headerWithEcard: '¡Tus tarjetas están listas!',
+            noVBACopy: 'Conecta una cuenta bancaria para emitir tarjetas Expensify a los miembros de tu espacio de trabajo y accede a estos increíbles beneficios y más:',
+            VBANoECardCopy:
+                'Añade tu correo electrónico de trabajo para emitir Tarjetas Expensify ilimitadas para los miembros de tu espacio de trabajo y acceder a todas estas increíbles ventajas:',
+            VBAWithECardCopy: 'Acceda a estos increíbles beneficios y más:',
+            benefit1: 'Hasta un 4% de devolución en tus gastos',
+            benefit2: 'Tarjetas digitales y físicas',
+            benefit3: 'Sin responsabilidad personal',
+            benefit4: 'Límites personalizables',
+            addWorkEmail: 'Añadir correo electrónico de trabajo',
+            checkingDomain: '¡Un momento! Estamos todavía trabajando para habilitar tu Tarjeta Expensify. Vuelve aquí en unos minutos.',
+        },
+        reimburse: {
+            captureReceipts: 'Captura recibos',
+            fastReimbursementsHappyMembers: '¡Reembolsos rápidos = miembros felices!',
+            kilometers: 'Kilómetros',
+            miles: 'Millas',
+            viewAllReceipts: 'Ver todos los recibos',
+            reimburseReceipts: 'Reembolsar recibos',
+            trackDistance: 'Medir distancia',
+            trackDistanceCopy: 'Configura la tarifa y unidad usadas para medir distancias.',
+            trackDistanceRate: 'Tarifa',
+            trackDistanceUnit: 'Unidad',
+            unlockNextDayReimbursements: 'Desbloquea reembolsos diarios',
+            captureNoVBACopyBeforeEmail: 'Pide a los miembros de tu espacio de trabajo que envíen recibos a ',
+            captureNoVBACopyAfterEmail: ' y descarga la App de Expensify para controlar tus gastos en efectivo sobre la marcha.',
+            unlockNoVBACopy: 'Conecta una cuenta bancaria para reembolsar online a los miembros de tu espacio de trabajo.',
+            fastReimbursementsVBACopy: '¡Todo listo para reembolsar recibos desde tu cuenta bancaria!',
+            updateCustomUnitError: 'Los cambios no han podido ser guardados. El espacio de trabajo ha sido modificado mientras estabas desconectado. Por favor, inténtalo de nuevo.',
+            invalidRateError: 'Por favor, introduce una tarifa válida',
+        },
+        bills: {
+            manageYourBills: 'Gestiona tus facturas',
+            askYourVendorsBeforeEmail: 'Pide a tus proveedores que envíen sus facturas a ',
+            askYourVendorsAfterEmail: ' y las escanearemos para que las pagues.',
+            viewAllBills: 'Ver facturas recibidas',
+            unlockOnlineBillPayment: 'Desbloquea el pago de facturas online',
+            unlockNoVBACopy: '¡Conecta tu cuenta bancaria para pagar tus facturas online de manera gratuita!',
+            hassleFreeBills: '¡Facturas sin complicaciones!',
+            VBACopy: '¡Todo listo para realizar pagos desde tu cuenta bancaria!',
+        },
+        invoices: {
+            invoiceClientsAndCustomers: 'Emite facturas a tus clientes',
+            invoiceFirstSectionCopy: 'Envía facturas detalladas y profesionales directamente a tus clientes desde la app de Expensify.',
+            viewAllInvoices: 'Ver facturas emitidas',
+            unlockOnlineInvoiceCollection: 'Desbloquea el cobro de facturas online',
+            unlockNoVBACopy: 'Conecta tu cuenta bancaria para recibir pagos online de facturas - por transferencia o con tarjeta - directamente en tu cuenta.',
+            moneyBackInAFlash: '¡Tu dinero de vuelta en un momento!',
+            unlockVBACopy: '¡Todo listo para recibir pagos por transferencia o con tarjeta!',
+            viewUnpaidInvoices: 'Ver facturas emitidas pendientes',
+            sendInvoice: 'Enviar factura',
+        },
+        travel: {
+            unlockConciergeBookingTravel: 'Desbloquea la reserva de viajes con Concierge',
+            noVBACopy: 'Conecta tu cuenta bancaria para permitir a los miembros de tu espacio de trabajo reservar sus vuelos, hoteles y coches empezando una conversación con Concierge.',
+            packYourBags: '¡Haz las maletas!',
+            VBACopy: '¡Miembros con la tarjeta Expensify pueden hablar con Concierge para reservar viajes!',
+            bookTravelWithConcierge: 'Reserva viajes con Concierge',
+        },
+        invite: {
+            invitePeople: 'Invitar nuevos miembros',
+            genericFailureMessage: 'Se produjo un error al invitar al usuario al espacio de trabajo. Vuelva a intentarlo..',
+            pleaseEnterValidLogin: `Asegúrese de que el correo electrónico o el número de teléfono sean válidos (p. ej. ${CONST.EXAMPLE_PHONE_NUMBER}).`,
+        },
+        inviteMessage: {
+            inviteMessageTitle: 'Añadir un mensaje',
+            inviteMessagePrompt: 'Añadir un mensaje para hacer tu invitación destacar',
+            personalMessagePrompt: 'Mensaje',
+            inviteNoMembersError: 'Por favor, selecciona al menos un miembro a invitar',
+            genericFailureMessage: 'Se produjo un error al invitar al usuario al espacio de trabajo. Vuelva a intentarlo..',
+            welcomeNote: ({workspaceName}) =>
+                `¡Has sido invitado a ${workspaceName}! Descargue la aplicación móvil Expensify en use.expensify.com/download para comenzar a rastrear sus gastos.`,
+        },
+        editor: {
+            nameInputLabel: 'Nombre',
+            nameInputHelpText: 'Este es el nombre que verás en tu espacio de trabajo.',
+            nameIsRequiredError: 'Debes definir un nombre para tu espacio de trabajo.',
+            nameIsTooLongError: `El nombre de su espacio de trabajo no puede tener más de ${CONST.WORKSPACE_NAME_CHARACTER_LIMIT} caracteres.`,
+            currencyInputLabel: 'Moneda por defecto',
+            currencyInputHelpText: 'Todas los gastos en este espacio de trabajo serán convertidos a esta moneda.',
+            currencyInputDisabledText: 'La moneda predeterminada no se puede cambiar porque este espacio de trabajo está vinculado a una cuenta bancaria en USD.',
+            save: 'Guardar',
+            genericFailureMessage: 'Se produjo un error al guardar el espacio de trabajo. Por favor, inténtalo de nuevo.',
+            avatarUploadFailureMessage: 'No se pudo subir el avatar. Por favor, inténtalo de nuevo.',
         },
+        bankAccount: {
+            continueWithSetup: 'Continuar con la configuración',
+            youreAlmostDone:
+                'Casi has acabado de configurar tu cuenta bancaria, que te permitirá emitir tarjetas corporativas, reembolsar gastos y cobrar pagar facturas, todo desde la misma cuenta bancaria.',
+            streamlinePayments: 'Optimiza pagos',
+            oneMoreThing: '¡Una cosa más!',
+            allSet: '¡Todo listo!',
+            accountDescriptionNoCards:
+                'Esta cuenta bancaria se utilizará para reembolsar gastos y cobrar y pagar facturas, todo desde la misma cuenta.\n\nPor favor, añade un correo electrónico de trabajo como tu nombre de usuario secundario para activar la Tarjeta Expensify.',
+            accountDescriptionWithCards: 'Esta cuenta bancaria se utilizará para emitir tarjetas corporativas, reembolsar gastos y cobrar y pagar facturas, todo desde la misma cuenta.',
+            addWorkEmail: 'Añadir correo electrónico de trabajo',
+            letsFinishInChat: '¡Continuemos en el chat!',
+            almostDone: '¡Casi listo!',
+            disconnectBankAccount: 'Desconectar cuenta bancaria',
+            noLetsStartOver: 'No, empecemos de nuevo',
+            startOver: 'Empezar de nuevo',
+            yesDisconnectMyBankAccount: 'Sí, desconecta mi cuenta bancaria',
+            yesStartOver: 'Sí, empezar de nuevo',
+            disconnectYour: 'Desconecta tu cuenta bancaria de ',
+            bankAccountAnyTransactions: '. Los reembolsos pendientes serán completados sin problemas.',
+            clearProgress: 'Empezar de nuevo descartará lo completado hasta ahora.',
+            areYouSure: '¿Estás seguro?',
+            workspaceCurrency: 'Moneda del espacio de trabajo',
+            updateCurrencyPrompt:
+                'Parece que tu espacio de trabajo está configurado actualmente en una moneda diferente a USD. Por favor, haz clic en el botón de abajo para actualizar tu moneda a USD ahora.',
+            updateToUSD: 'Actualizar a USD',
+        },
+    },
+    getAssistancePage: {
+        title: 'Obtener ayuda',
+        subtitle: '¡Estamos aquí para ayudarte!',
+        description: 'Elige una de las siguientes opciones:',
+        chatWithConcierge: 'Chatear con Concierge',
+        scheduleSetupCall: 'Concertar una llamada',
+        questionMarkButtonTooltip: 'Obtén ayuda de nuestro equipo',
+        exploreHelpDocs: 'Explorar la documentación de ayuda',
+    },
+    emojiPicker: {
+        skinTonePickerLabel: 'Elige el tono de piel por defecto',
+        headers: {
+            frequentlyUsed: 'Usado frecuentemente',
+            smileysAndEmotion: 'Emoticonos y emociones',
+            peopleAndBody: 'Personas y Cuerpo',
+            animalsAndNature: 'Animales y naturaleza',
+            foodAndDrink: 'Alimentos y bebidas',
+            travelAndPlaces: 'Viajes y lugares',
+            activities: 'Actividades',
+            objects: 'Objetos',
+            symbols: 'Símbolos',
+            flags: 'Banderas',
+        },
+    },
+    newRoomPage: {
+        newRoom: 'Nueva sala de chat',
+        roomName: 'Nombre de la sala',
+        visibility: 'Visibilidad',
+        restrictedDescription: 'Sólo las personas en tu espacio de trabajo pueden encontrar esta sala',
+        privateDescription: 'Sólo las personas que están invitadas a esta sala pueden encontrarla',
+        publicDescription: 'Cualquier persona puede unirse a esta sala',
+        public_announceDescription: 'Cualquier persona puede unirse a esta sala',
+        createRoom: 'Crea una sala de chat',
+        roomAlreadyExistsError: 'Ya existe una sala con este nombre',
+        roomNameReservedError: ({reservedName}) => `${reservedName} es el nombre una sala por defecto de todos los espacios de trabajo. Por favor, elige otro nombre.`,
+        roomNameInvalidError: 'Los nombres de las salas solo pueden contener minúsculas, números y guiones',
+        pleaseEnterRoomName: 'Por favor, escribe el nombre de una sala',
+        pleaseSelectWorkspace: 'Por favor, selecciona un espacio de trabajo',
+        renamedRoomAction: ({oldName, newName}) => ` cambió el nombre de la sala de ${oldName} a ${newName}`,
+        roomRenamedTo: ({newName}) => `Sala renombrada a ${newName}`,
+        social: 'social',
+        selectAWorkspace: 'Seleccionar un espacio de trabajo',
+        growlMessageOnRenameError: 'No se ha podido cambiar el nombre del espacio de trabajo, por favor, comprueba tu conexión e inténtalo de nuevo.',
+        visibilityOptions: {
+            restricted: 'Restringida',
+            private: 'Privada',
+            public: 'Público',
+            public_announce: 'Anuncio Público',
+        },
+    },
+    newTaskPage: {
+        assignTask: 'Asignar tarea',
+        assignMe: 'Asignar a mí mismo',
+        confirmTask: 'Confirmar tarea',
+        confirmError: 'Por favor, introduce un título y selecciona un destino de tarea.',
+        descriptionOptional: 'Descripción (opcional)',
+        shareSomewhere: 'Compartir en algún lugar',
+        pleaseEnterTaskName: 'Por favor, introduce un título',
+        pleaseEnterTaskDestination: 'Por favor, selecciona con quién deseas compartir.',
+    },
+    task: {
+        task: 'Tarea',
+        title: 'Título',
+        description: 'Descripción',
+        assignee: 'Usuario asignado',
+        completed: 'Completada',
         messages: {
-            errorMessageInvalidPhone: `Por favor, introduce un número de teléfono válido sin paréntesis o guiones. Si reside fuera de Estados Unidos, por favor incluye el prefijo internacional (p. ej. ${CONST.EXAMPLE_PHONE_NUMBER}).`,
-            errorMessageInvalidEmail: 'Email inválido',
-            userIsAlreadyMemberOfWorkspace: ({login, workspace}) => `${login} ya es miembro de ${workspace}`,
-        },
-        onfidoStep: {
-            acceptTerms: 'Al continuar con la solicitud para activar su billetera Expensify, confirma que ha leído, comprende y acepta ',
-            facialScan: 'Política y lanzamiento de la exploración facial de Onfido',
-            tryAgain: 'Intentar otra vez',
-            verifyIdentity: 'Verificar identidad',
-            genericError: 'Hubo un error al procesar este paso. Inténtalo de nuevo.',
-            cameraPermissionsNotGranted: 'No has habilitado los permisos para acceder a la cámara',
-            cameraRequestMessage: 'No has habilitado los permisos para acceder a la cámara. Necesitamos acceso para completar la verificaciôn.',
-            originalDocumentNeeded: 'Por favor, sube una imagen original de tu identificación en lugar de una captura de pantalla o imagen escaneada.',
-            documentNeedsBetterQuality:
-                'Parece que tu identificación esta dañado o le faltan características de seguridad. Por favor, sube una imagen de tu documento sin daños y que se vea completamente.',
-            imageNeedsBetterQuality: 'Hay un problema con la calidad de la imagen de tu identificación. Por favor, sube una nueva imagen donde el identificación se vea con claridad.',
-            selfieIssue: 'Hay un problema con tu selfie/video. Por favor, sube un nuevo selfie/video grabado en el momento',
-            selfieNotMatching: 'Tu selfie/video no concuerda con tu identificación. Por favor, sube un nuevo selfie/video donde se vea tu cara con claridad.',
-            selfieNotLive: 'Tu selfie/video no parece ser un selfie/video en vivo. Por favor, sube un selfie/video a tiempo real.',
-        },
-        additionalDetailsStep: {
-            headerTitle: 'Detalles adicionales',
-            helpText: 'Necesitamos confirmar la siguiente información antes de que podamos procesar el pago.',
-            helpTextIdologyQuestions: 'Tenemos que preguntarte unas preguntas más para terminar de verificar tu identidad',
-            helpLink: 'Obtén más información sobre por qué necesitamos esto.',
-            legalFirstNameLabel: 'Primer nombre legal',
-            legalMiddleNameLabel: 'Segundo nombre legal',
-            legalLastNameLabel: 'Apellidos legales',
-            selectAnswer: 'Selecciona una respuesta.',
-            ssnFull9Error: 'Por favor, introduce los 9 dígitos de un número de seguridad social válido',
-            needSSNFull9: 'Estamos teniendo problemas para verificar tu número de seguridad social. Introduce los 9 dígitos del número de seguridad social.',
-            weCouldNotVerify: 'No se pudo verificar',
-            pleaseFixIt: 'Corrige esta información antes de continuar.',
-            failedKYCTextBefore: 'No se ha podido verificar correctamente tu identidad. Vuelve a intentarlo más tarde y comunicate con ',
-            failedKYCTextAfter: ' si tienes alguna pregunta.',
-        },
-        termsStep: {
-            headerTitle: 'Condiciones y tarifas',
-            haveReadAndAgree: 'He leído y acepto recibir ',
-            electronicDisclosures: 'divulgaciones electrónicas',
-            agreeToThe: 'Estoy de acuerdo con la ',
-            walletAgreement: 'Acuerdo de billetera',
-            enablePayments: 'Habilitar pagos',
-            feeAmountZero: '$0',
-            monthlyFee: 'Cuota mensual',
-            inactivity: 'Inactividad',
-            electronicFundsInstantFee: '1.5%',
-            noOverdraftOrCredit: 'Sin función de sobregiro / crédito',
-            electronicFundsWithdrawal: 'Retiro electrónico de fondos',
-            standard: 'Estándar',
-            shortTermsForm: {
-                expensifyPaymentsAccount: 'La billetera Expensify es emitida por The Bancorp Bank.',
-                perPurchase: 'Por compra',
-                atmWithdrawal: 'Retiro de cajero automático',
-                cashReload: 'Recarga de efectivo',
-                inNetwork: 'en la red',
-                outOfNetwork: 'fuera de la red',
-                atmBalanceInquiry: 'Consulta de saldo de cajero automático',
-                inOrOutOfNetwork: '(dentro o fuera de la red)',
-                customerService: 'Servicio al cliente',
-                automatedOrLive: '(agente automatizado o en vivo)',
-                afterTwelveMonths: '(después de 12 meses sin transacciones)',
-                weChargeOneFee: 'Cobramos un tipo de tarifa.',
-                fdicInsurance: 'Sus fondos son elegibles para el seguro de la FDIC.',
-                generalInfo: 'Para obtener información general sobre cuentas prepagas, visite',
-                conditionsDetails: 'Encuentra detalles y condiciones para todas las tarifas y servicios visitando',
-                conditionsPhone: 'o llamando al +1 833-400-0904.',
-                instant: '(instantáneo)',
-                electronicFundsInstantFeeMin: '(mínimo $0.25)',
-            },
-            longTermsForm: {
-                listOfAllFees: 'Una lista de todas las tarifas de la billetera Expensify',
-                typeOfFeeHeader: 'Tipo de tarifa',
-                feeAmountHeader: 'Importe de la tarifa',
-                moreDetailsHeader: 'Más detalles',
-                openingAccountTitle: 'Abrir una cuenta',
-                openingAccountDetails: 'No hay tarifa para abrir una cuenta.',
-                monthlyFeeDetails: 'No hay tarifa mensual.',
-                customerServiceTitle: 'Servicio al cliente',
-                customerServiceDetails: 'No hay tarifas de servicio al cliente.',
-                inactivityDetails: 'No hay tarifa de inactividad.',
-                sendingFundsTitle: 'Enviar fondos a otro titular de cuenta',
-                sendingFundsDetails: 'No se aplica ningún cargo por enviar fondos a otro titular de cuenta utilizando su saldo cuenta bancaria o tarjeta de débito',
-                electronicFundsStandardDetails:
-                    'No hay cargo por transferir fondos desde su billetera Expensify ' +
-                    'a su cuenta bancaria utilizando la opción estándar. Esta transferencia generalmente se completa en' +
-                    '1-3 negocios días.',
-                electronicFundsInstantDetails:
-                    'Hay una tarifa para transferir fondos desde su billetera Expensify a ' +
-                    'su tarjeta de débito vinculada utilizando la opción de transferencia instantánea. Esta transferencia ' +
-                    'generalmente se completa dentro de varios minutos. La tarifa es el 1.5% del monto de la ' +
-                    'transferencia (con una tarifa mínima de $ 0.25). ',
-                fdicInsuranceBancorp:
-                    'Sus fondos son elegibles para el seguro de la FDIC. Sus fondos se mantendrán en o ' +
-                    'transferido a The Bancorp Bank, una institución asegurada por la FDIC. Una vez allí, sus fondos ' +
-                    'están asegurados a $ 250,000 por la FDIC en caso de que The Bancorp Bank quiebre. Ver',
-                fdicInsuranceBancorp2: 'para detalles.',
-                contactExpensifyPayments: 'Comuníquese con Expensify Payments llamando al + 1833-400-0904, por correoelectrónico a',
-                contactExpensifyPayments2: 'o inicie sesión en',
-                generalInformation: 'Para obtener información general sobre cuentas prepagas, visite',
-                generalInformation2: 'Si tiene una queja sobre una cuenta prepaga, llame al Consumer Financial Oficina de Protección al 1-855-411-2372 o visite',
-                printerFriendlyView: 'Ver versión para imprimir',
-                automated: 'Automatizado',
-                liveAgent: 'Agente en vivo',
-                instant: 'Instantáneo',
-                electronicFundsInstantFeeMin: 'Mínimo $0.25',
-            },
-        },
-        activateStep: {
-            headerTitle: 'Habilitar pagos',
-            activatedTitle: '¡Billetera  activada!',
-            activatedMessage: 'Felicidades, tu Billetera está configurada y lista para hacer pagos.',
-            checkBackLaterTitle: 'Un momento...',
-            checkBackLaterMessage: 'Todavía estamos revisando tu información. Por favor, vuelva más tarde.',
-            continueToPayment: 'Continuar al pago',
-            continueToTransfer: 'Continuar a la transferencia',
-        },
-        companyStep: {
-            headerTitle: 'Información de la empresa',
-            subtitle: '¡Ya casi estamos! Por motivos de seguridad, necesitamos confirmar la siguiente información:',
-            legalBusinessName: 'Nombre comercial legal',
-            companyWebsite: 'Página web de la empresa',
-            taxIDNumber: 'Número de identificación fiscal',
-            taxIDNumberPlaceholder: '9 dígitos',
-            companyType: 'Tipo de empresa',
-            incorporationDate: 'Fecha de incorporación',
-            incorporationState: 'Estado de incorporación',
-            industryClassificationCode: 'Código de clasificación industrial',
-            confirmCompanyIsNot: 'Confirmo que esta empresa no está en el',
-            listOfRestrictedBusinesses: 'lista de negocios restringidos',
-            incorporationDatePlaceholder: 'Fecha de inicio (aaaa-mm-dd)',
-            incorporationTypes: {
-                LLC: 'LLC',
-                CORPORATION: 'Corp',
-                PARTNERSHIP: 'Sociedad',
-                COOPERATIVE: 'Cooperativa',
-                SOLE_PROPRIETORSHIP: 'Propietario único',
-                OTHER: 'Otra',
-            },
-        },
-        requestorStep: {
-            headerTitle: 'Información personal',
-            subtitle: 'Dé más información sobre tí.',
-            learnMore: 'Más información',
-            isMyDataSafe: '¿Están seguros mis datos?',
-            onFidoConditions: 'Al continuar con la solicitud de añadir esta cuenta bancaria, confirma que ha leído, entiende y acepta ',
-            isControllingOfficer: 'Estoy autorizado a utilizar la cuenta bancaria de mi compañía para gastos de empresa',
-            isControllingOfficerError: 'Debe ser un oficial controlador con autorización para operar la cuenta bancaria de la compañía',
-        },
-        validationStep: {
-            headerTitle: 'Validar cuenta bancaria',
-            buttonText: 'Finalizar configuración',
-            maxAttemptsReached: 'Se ha inhabilitado la validación de esta cuenta bancaria debido a demasiados intentos incorrectos.',
-            description:
-                'Uno o dos días después de añadir tu cuenta a Expensify, te enviaremos tres (3) transacciones a tu cuenta. Tienen un nombre de comerciante similar a "Expensify, Inc. Validation".',
-            descriptionCTA: 'Introduce el importe de cada transacción en los campos siguientes. Ejemplo: 1.51.',
-            reviewingInfo: '¡Gracias! Estamos revisando tu información y nos comunicaremos contigo en breve. Consulta el chat con Concierge ',
-            forNextSteps: ' para conocer los próximos pasos para terminar de configurar tu cuenta bancaria.',
-            letsChatCTA: 'Sí, vamos a chatear',
-            letsChatText: 'Gracias. Necesitamos tu ayuda para verificar la información, pero podemos hacerlo rápidamente a través del chat. ¿Estás listo?',
-            letsChatTitle: '¡Vamos a chatear!',
-            enable2FATitle: 'Evita fraudes, activa la autenticación de dos factores!',
-            enable2FAText:
-                'Tu seguridad es importante para nosotros. Por favor, configura ahora la autenticación de dos factores. Eso nos permitirá disputar las transacciones de la Tarjeta Expensify y reducirá tu riesgo de fraude.',
-            secureYourAccount: 'Asegura tu cuenta',
-        },
-        beneficialOwnersStep: {
-            additionalInformation: 'Información adicional',
-            checkAllThatApply: 'Marca todos los que apliquen, en caso de que ninguno aplique dejar en blanco.',
-            iOwnMoreThan25Percent: 'Soy dueño de mas de 25% de ',
-            someoneOwnsMoreThan25Percent: 'Otra persona es dueña de mas de 25% de ',
-            additionalOwner: 'Beneficiario efectivo adicional',
-            removeOwner: 'Eliminar este beneficiario efectivo',
-            addAnotherIndividual: 'Añadir otra persona que es dueña de mas de 25% de ',
-            agreement: 'Acuerdo:',
-            termsAndConditions: 'Términos y condiciones',
-            certifyTrueAndAccurate: 'Certifico que la información dada es correcta',
-            error: {
-                certify: 'Debe certificar que la información es verdadera y precisa',
-            },
-        },
-        reimbursementAccountLoadingAnimation: {
-            oneMoment: 'Un momento',
-            explanationLine: 'Estamos verificando tu información y podrás continuar con los siguientes pasos en unos momentos.',
-        },
-        session: {
-            offlineMessageRetry: 'Parece que estás desconectado. Por favor, comprueba tu conexión e inténtalo de nuevo.',
-        },
-        workspace: {
-            common: {
-                card: 'Tarjetas',
-                workspace: 'Espacio de trabajo',
-                edit: 'Editar espacio de trabajo',
-                delete: 'Eliminar espacio de trabajo',
-                settings: 'Configuración',
-                reimburse: 'Reembolsos',
-                bills: 'Pagar facturas',
-                invoices: 'Enviar facturas',
-                travel: 'Viajes',
-                members: 'Miembros',
-                bankAccount: 'Cuenta bancaria',
-                connectBankAccount: 'Conectar cuenta bancaria',
-                testTransactions: 'Transacciones de prueba',
-                issueAndManageCards: 'Emitir y gestionar tarjetas',
-                reconcileCards: 'Reconciliar tarjetas',
-                settlementFrequency: 'Frecuencia de liquidación',
-                deleteConfirmation: '¿Estás seguro de que quieres eliminar este espacio de trabajo?',
-                unavailable: 'Espacio de trabajo no disponible',
-                memberNotFound: 'Miembro no encontrado. Para invitar a un nuevo miembro al espacio de trabajo, por favor, utiliza el botón Invitar que está arriba.',
-                notAuthorized: `No tienes acceso a esta página. ¿Estás tratando de unirte al espacio de trabajo? Comunícate con el propietario de este espacio de trabajo para que pueda añadirte como miembro. ¿Necesitas algo más? Comunícate con ${CONST.EMAIL.CONCIERGE}`,
-                goToRoom: ({roomName}) => `Ir a la sala ${roomName}`,
-            },
-            emptyWorkspace: {
-                title: 'Crear un nuevo espacio de trabajo',
-                subtitle: 'En los espacios de trabajo es donde puedes chatear con tu equipo, reembolsar gastos, emitir tarjetas, enviar y pagar facturas y mas — todo en un mismo lugar',
-                features: {
-                    trackAndCollect: 'Organiza recibos',
-                    companyCards: 'Tarjetas de crédito corporativas',
-                    reimbursements: 'Reembolsos fáciles',
-                },
-            },
-            new: {
-                newWorkspace: 'Nuevo espacio de trabajo',
-                getTheExpensifyCardAndMore: 'Consigue la Tarjeta Expensify y más',
-            },
-            people: {
-                genericFailureMessage: 'Se ha producido un error al intentar eliminar a un usuario del espacio de trabajo. Por favor, inténtalo más tarde.',
-                removeMembersPrompt: '¿Estás seguro que quieres eliminar a los miembros seleccionados de tu espacio de trabajo?',
-                removeMembersTitle: 'Eliminar miembros',
-                selectAll: 'Seleccionar todo',
-                error: {
-                    genericAdd: 'Ha ocurrido un problema al añadir el miembro al espacio de trabajo.',
-                    cannotRemove: 'No puedes eliminarte ni a ti mismo ni al dueño del espacio de trabajo.',
-                    genericRemove: 'Ha ocurrido un problema al eliminar al miembro del espacio de trabajo.',
-                },
-            },
-            card: {
-                header: 'Desbloquea Tarjetas Expensify gratis',
-                headerWithEcard: '¡Tus tarjetas están listas!',
-                noVBACopy: 'Conecta una cuenta bancaria para emitir tarjetas Expensify a los miembros de tu espacio de trabajo y accede a estos increíbles beneficios y más:',
-                VBANoECardCopy:
-                    'Añade tu correo electrónico de trabajo para emitir Tarjetas Expensify ilimitadas para los miembros de tu espacio de trabajo y acceder a todas estas increíbles ventajas:',
-                VBAWithECardCopy: 'Acceda a estos increíbles beneficios y más:',
-                benefit1: 'Hasta un 4% de devolución en tus gastos',
-                benefit2: 'Tarjetas digitales y físicas',
-                benefit3: 'Sin responsabilidad personal',
-                benefit4: 'Límites personalizables',
-                addWorkEmail: 'Añadir correo electrónico de trabajo',
-                checkingDomain: '¡Un momento! Estamos todavía trabajando para habilitar tu Tarjeta Expensify. Vuelve aquí en unos minutos.',
-            },
-            reimburse: {
-                captureReceipts: 'Captura recibos',
-                fastReimbursementsHappyMembers: '¡Reembolsos rápidos = miembros felices!',
-                kilometers: 'Kilómetros',
-                miles: 'Millas',
-                viewAllReceipts: 'Ver todos los recibos',
-                reimburseReceipts: 'Reembolsar recibos',
-                trackDistance: 'Medir distancia',
-                trackDistanceCopy: 'Configura la tarifa y unidad usadas para medir distancias.',
-                trackDistanceRate: 'Tarifa',
-                trackDistanceUnit: 'Unidad',
-                unlockNextDayReimbursements: 'Desbloquea reembolsos diarios',
-                captureNoVBACopyBeforeEmail: 'Pide a los miembros de tu espacio de trabajo que envíen recibos a ',
-                captureNoVBACopyAfterEmail: ' y descarga la App de Expensify para controlar tus gastos en efectivo sobre la marcha.',
-                unlockNoVBACopy: 'Conecta una cuenta bancaria para reembolsar online a los miembros de tu espacio de trabajo.',
-                fastReimbursementsVBACopy: '¡Todo listo para reembolsar recibos desde tu cuenta bancaria!',
-                updateCustomUnitError: 'Los cambios no han podido ser guardados. El espacio de trabajo ha sido modificado mientras estabas desconectado. Por favor, inténtalo de nuevo.',
-                invalidRateError: 'Por favor, introduce una tarifa válida',
-            },
-            bills: {
-                manageYourBills: 'Gestiona tus facturas',
-                askYourVendorsBeforeEmail: 'Pide a tus proveedores que envíen sus facturas a ',
-                askYourVendorsAfterEmail: ' y las escanearemos para que las pagues.',
-                viewAllBills: 'Ver facturas recibidas',
-                unlockOnlineBillPayment: 'Desbloquea el pago de facturas online',
-                unlockNoVBACopy: '¡Conecta tu cuenta bancaria para pagar tus facturas online de manera gratuita!',
-                hassleFreeBills: '¡Facturas sin complicaciones!',
-                VBACopy: '¡Todo listo para realizar pagos desde tu cuenta bancaria!',
-            },
-            invoices: {
-                invoiceClientsAndCustomers: 'Emite facturas a tus clientes',
-                invoiceFirstSectionCopy: 'Envía facturas detalladas y profesionales directamente a tus clientes desde la app de Expensify.',
-                viewAllInvoices: 'Ver facturas emitidas',
-                unlockOnlineInvoiceCollection: 'Desbloquea el cobro de facturas online',
-                unlockNoVBACopy: 'Conecta tu cuenta bancaria para recibir pagos online de facturas - por transferencia o con tarjeta - directamente en tu cuenta.',
-                moneyBackInAFlash: '¡Tu dinero de vuelta en un momento!',
-                unlockVBACopy: '¡Todo listo para recibir pagos por transferencia o con tarjeta!',
-                viewUnpaidInvoices: 'Ver facturas emitidas pendientes',
-                sendInvoice: 'Enviar factura',
-            },
-            travel: {
-                unlockConciergeBookingTravel: 'Desbloquea la reserva de viajes con Concierge',
-                noVBACopy: 'Conecta tu cuenta bancaria para permitir a los miembros de tu espacio de trabajo reservar sus vuelos, hoteles y coches empezando una conversación con Concierge.',
-                packYourBags: '¡Haz las maletas!',
-                VBACopy: '¡Miembros con la tarjeta Expensify pueden hablar con Concierge para reservar viajes!',
-                bookTravelWithConcierge: 'Reserva viajes con Concierge',
-            },
-            invite: {
-                invitePeople: 'Invitar nuevos miembros',
-                genericFailureMessage: 'Se produjo un error al invitar al usuario al espacio de trabajo. Vuelva a intentarlo..',
-                pleaseEnterValidLogin: `Asegúrese de que el correo electrónico o el número de teléfono sean válidos (p. ej. ${CONST.EXAMPLE_PHONE_NUMBER}).`,
-            },
-            inviteMessage: {
-                inviteMessageTitle: 'Añadir un mensaje',
-                inviteMessagePrompt: 'Añadir un mensaje para hacer tu invitación destacar',
-                personalMessagePrompt: 'Mensaje',
-                inviteNoMembersError: 'Por favor, selecciona al menos un miembro a invitar',
-                genericFailureMessage: 'Se produjo un error al invitar al usuario al espacio de trabajo. Vuelva a intentarlo..',
-                welcomeNote: ({workspaceName}) =>
-                    `¡Has sido invitado a ${workspaceName}! Descargue la aplicación móvil Expensify en use.expensify.com/download para comenzar a rastrear sus gastos.`,
-            },
-            editor: {
-                nameInputLabel: 'Nombre',
-                nameInputHelpText: 'Este es el nombre que verás en tu espacio de trabajo.',
-                nameIsRequiredError: 'Debes definir un nombre para tu espacio de trabajo.',
-                nameIsTooLongError: `El nombre de su espacio de trabajo no puede tener más de ${CONST.WORKSPACE_NAME_CHARACTER_LIMIT} caracteres.`,
-                currencyInputLabel: 'Moneda por defecto',
-                currencyInputHelpText: 'Todas los gastos en este espacio de trabajo serán convertidos a esta moneda.',
-                currencyInputDisabledText: 'La moneda predeterminada no se puede cambiar porque este espacio de trabajo está vinculado a una cuenta bancaria en USD.',
-                save: 'Guardar',
-                genericFailureMessage: 'Se produjo un error al guardar el espacio de trabajo. Por favor, inténtalo de nuevo.',
-                avatarUploadFailureMessage: 'No se pudo subir el avatar. Por favor, inténtalo de nuevo.',
-            },
-            bankAccount: {
-                continueWithSetup: 'Continuar con la configuración',
-                youreAlmostDone:
-                    'Casi has acabado de configurar tu cuenta bancaria, que te permitirá emitir tarjetas corporativas, reembolsar gastos y cobrar pagar facturas, todo desde la misma cuenta bancaria.',
-                streamlinePayments: 'Optimiza pagos',
-                oneMoreThing: '¡Una cosa más!',
-                allSet: '¡Todo listo!',
-                accountDescriptionNoCards:
-                    'Esta cuenta bancaria se utilizará para reembolsar gastos y cobrar y pagar facturas, todo desde la misma cuenta.\n\nPor favor, añade un correo electrónico de trabajo como tu nombre de usuario secundario para activar la Tarjeta Expensify.',
-                accountDescriptionWithCards: 'Esta cuenta bancaria se utilizará para emitir tarjetas corporativas, reembolsar gastos y cobrar y pagar facturas, todo desde la misma cuenta.',
-                addWorkEmail: 'Añadir correo electrónico de trabajo',
-                letsFinishInChat: '¡Continuemos en el chat!',
-                almostDone: '¡Casi listo!',
-                disconnectBankAccount: 'Desconectar cuenta bancaria',
-                noLetsStartOver: 'No, empecemos de nuevo',
-                startOver: 'Empezar de nuevo',
-                yesDisconnectMyBankAccount: 'Sí, desconecta mi cuenta bancaria',
-                yesStartOver: 'Sí, empezar de nuevo',
-                disconnectYour: 'Desconecta tu cuenta bancaria de ',
-                bankAccountAnyTransactions: '. Los reembolsos pendientes serán completados sin problemas.',
-                clearProgress: 'Empezar de nuevo descartará lo completado hasta ahora.',
-                areYouSure: '¿Estás seguro?',
-                workspaceCurrency: 'Moneda del espacio de trabajo',
-                updateCurrencyPrompt:
-                    'Parece que tu espacio de trabajo está configurado actualmente en una moneda diferente a USD. Por favor, haz clic en el botón de abajo para actualizar tu moneda a USD ahora.',
-                updateToUSD: 'Actualizar a USD',
-            },
-        },
-        getAssistancePage: {
-            title: 'Obtener ayuda',
-            subtitle: '¡Estamos aquí para ayudarte!',
-            description: 'Elige una de las siguientes opciones:',
-            chatWithConcierge: 'Chatear con Concierge',
-            scheduleSetupCall: 'Concertar una llamada',
-            questionMarkButtonTooltip: 'Obtén ayuda de nuestro equipo',
-            exploreHelpDocs: 'Explorar la documentación de ayuda',
-        },
-        emojiPicker: {
-            skinTonePickerLabel: 'Elige el tono de piel por defecto',
-            headers: {
-                frequentlyUsed: 'Usado frecuentemente',
-                smileysAndEmotion: 'Emoticonos y emociones',
-                peopleAndBody: 'Personas y Cuerpo',
-                animalsAndNature: 'Animales y naturaleza',
-                foodAndDrink: 'Alimentos y bebidas',
-                travelAndPlaces: 'Viajes y lugares',
-                activities: 'Actividades',
-                objects: 'Objetos',
-                symbols: 'Símbolos',
-                flags: 'Banderas',
-            },
-        },
-        newRoomPage: {
-            newRoom: 'Nueva sala de chat',
-            roomName: 'Nombre de la sala',
-            visibility: 'Visibilidad',
-            restrictedDescription: 'Sólo las personas en tu espacio de trabajo pueden encontrar esta sala',
-            privateDescription: 'Sólo las personas que están invitadas a esta sala pueden encontrarla',
-            publicDescription: 'Cualquier persona puede unirse a esta sala',
-            public_announceDescription: 'Cualquier persona puede unirse a esta sala',
-            createRoom: 'Crea una sala de chat',
-            roomAlreadyExistsError: 'Ya existe una sala con este nombre',
-            roomNameReservedError: ({reservedName}) => `${reservedName} es el nombre una sala por defecto de todos los espacios de trabajo. Por favor, elige otro nombre.`,
-            roomNameInvalidError: 'Los nombres de las salas solo pueden contener minúsculas, números y guiones',
-            pleaseEnterRoomName: 'Por favor, escribe el nombre de una sala',
-            pleaseSelectWorkspace: 'Por favor, selecciona un espacio de trabajo',
-            renamedRoomAction: ({oldName, newName}) => ` cambió el nombre de la sala de ${oldName} a ${newName}`,
-            roomRenamedTo: ({newName}) => `Sala renombrada a ${newName}`,
-            social: 'social',
-            selectAWorkspace: 'Seleccionar un espacio de trabajo',
-            growlMessageOnRenameError: 'No se ha podido cambiar el nombre del espacio de trabajo, por favor, comprueba tu conexión e inténtalo de nuevo.',
-            visibilityOptions: {
-                restricted: 'Restringida',
-                private: 'Privada',
-                public: 'Público',
-                public_announce: 'Anuncio Público',
-            },
-        },
-        newTaskPage: {
-            assignTask: 'Asignar tarea',
-            assignMe: 'Asignar a mí mismo',
-            confirmTask: 'Confirmar tarea',
-            confirmError: 'Por favor, introduce un título y selecciona un destino de tarea.',
-            descriptionOptional: 'Descripción (opcional)',
-            shareSomewhere: 'Compartir en algún lugar',
-            pleaseEnterTaskName: 'Por favor, introduce un título',
-            pleaseEnterTaskDestination: 'Por favor, selecciona con quién deseas compartir.',
-        },
-        task: {
-            task: 'Tarea',
-            title: 'Título',
-            description: 'Descripción',
-            assignee: 'Usuario asignado',
-            completed: 'Completada',
-            messages: {
-                completed: 'tarea completada',
-                canceled: 'tarea cancelada',
-                reopened: 'tarea reabrir',
-                error: 'No tiene permiso para realizar la acción solicitada.',
-            },
-            markAsDone: 'Marcar como completada',
-            markAsIncomplete: 'Marcar como incompleta',
-            assigneeError: 'Hubo un error al asignar esta tarea, inténtalo con otro usuario.',
-        },
-        statementPage: {
-            generatingPDF: 'Estamos generando tu PDF ahora mismo. ¡Por favor, vuelve más tarde!',
-        },
-        keyboardShortcutModal: {
-            title: 'Atajos de teclado',
-            subtitle: 'Ahorra tiempo con estos atajos de teclado:',
-            shortcuts: {
-                openShortcutDialog: 'Abre el cuadro de diálogo de métodos abreviados de teclado',
-                escape: 'Diálogos de escape',
-                search: 'Abrir diálogo de búsqueda',
-                newGroup: 'Nueva pantalla de grupo',
-                copy: 'Copiar comentario',
-            },
+            completed: 'tarea completada',
+            canceled: 'tarea cancelada',
+            reopened: 'tarea reabrir',
+            error: 'No tiene permiso para realizar la acción solicitada.',
+        },
+        markAsDone: 'Marcar como completada',
+        markAsIncomplete: 'Marcar como incompleta',
+        assigneeError: 'Hubo un error al asignar esta tarea, inténtalo con otro usuario.',
+    },
+    statementPage: {
+        generatingPDF: 'Estamos generando tu PDF ahora mismo. ¡Por favor, vuelve más tarde!',
+    },
+    keyboardShortcutModal: {
+        title: 'Atajos de teclado',
+        subtitle: 'Ahorra tiempo con estos atajos de teclado:',
+        shortcuts: {
+            openShortcutDialog: 'Abre el cuadro de diálogo de métodos abreviados de teclado',
+            escape: 'Diálogos de escape',
+            search: 'Abrir diálogo de búsqueda',
+            newGroup: 'Nueva pantalla de grupo',
+            copy: 'Copiar comentario',
+        },
+    },
+    guides: {
+        screenShare: 'Compartir pantalla',
+        screenShareRequest: 'Expensify te está invitando a compartir la pantalla',
+    },
+    genericErrorPage: {
+        title: '¡Uh-oh, algo salió mal!',
+        body: {
+            helpTextMobile: 'Intenta cerrar y volver a abrir la aplicación o cambiar a la',
+            helpTextWeb: 'web.',
+            helpTextConcierge: 'Si el problema persiste, comunícate con',
+        },
+        refresh: 'Actualizar',
+    },
+    fileDownload: {
+        success: {
+            title: '!Descargado!',
+            message: 'Archivo descargado correctamente',
+        },
+        generalError: {
+            title: 'Error en la descarga',
+            message: 'No se puede descargar el archivo adjunto',
+        },
+        permissionError: {
+            title: 'Permiso para acceder al almacenamiento',
+            message: 'Expensify no puede guardar los archivos adjuntos sin permiso para acceder al almacenamiento. Haz click en Configuración para actualizar los permisos.',
+        },
+    },
+    desktopApplicationMenu: {
+        mainMenu: 'Nuevo Expensify',
+        about: 'Sobre Nuevo Expensify',
+        update: 'Actualizar Nuevo Expensify',
+        checkForUpdates: 'Buscar actualizaciones',
+        toggleDevTools: 'Ver herramientas de desarrollo',
+        viewShortcuts: 'Ver atajos de teclado',
+        services: 'Servicios',
+        hide: 'Ocultar Nuevo Expensify',
+        hideOthers: 'Ocultar otros',
+        showAll: 'Mostrar todos',
+        quit: 'Salir de Nuevo Expensify',
+        fileMenu: 'Archivo',
+        closeWindow: 'Cerrar ventana',
+        editMenu: 'Editar',
+        undo: 'Deshacer',
+        redo: 'Rehacer',
+        cut: 'Cortar',
+        copy: 'Copiar',
+        paste: 'Pegar',
+        pasteAndMatchStyle: 'Pegar adaptando el estilo',
+        pasteAsPlainText: 'Pegar como texto sin formato',
+        delete: 'Eliminar',
+        selectAll: 'Seleccionar todo',
+        speechSubmenu: 'Voz',
+        startSpeaking: 'Empezar a hablar',
+        stopSpeaking: 'Dejar de Hablar',
+        viewMenu: 'Ver',
+        reload: 'Cargar de nuevo',
+        forceReload: 'Forzar recarga',
+        resetZoom: 'Tamaño real',
+        zoomIn: 'Acercar',
+        zoomOut: 'Alejar',
+        togglefullscreen: 'Alternar pantalla completa',
+        historyMenu: 'Historial',
+        back: 'Atrás',
+        forward: 'Adelante',
+        windowMenu: 'Ventana',
+        minimize: 'Minimizar',
+        zoom: 'Zoom',
+        front: 'Traer todo al frente',
+        helpMenu: 'Ayuda',
+        learnMore: 'Más información',
+        documentation: 'Documentación',
+        communityDiscussions: 'Debates de la comunidad',
+        searchIssues: 'Buscar problemas',
+    },
+    historyMenu: {
+        forward: 'Adelante',
+        back: 'Atrás',
+    },
+    checkForUpdatesModal: {
+        available: {
+            title: 'Actualización disponible',
+            message: 'La nueva versión estará disponible dentro de poco. Te notificaremos cuando esté lista.',
+            soundsGood: 'Suena bien',
+        },
+        notAvailable: {
+            title: 'Actualización no disponible',
+            message: 'No existe ninguna actualización disponible! Inténtalo de nuevo más tarde.',
+            okay: 'Vale',
         },
-        guides: {
-            screenShare: 'Compartir pantalla',
-            screenShareRequest: 'Expensify te está invitando a compartir la pantalla',
+        error: {
+            title: 'Comprobación fallida',
+            message: 'No hemos podido comprobar si existe una actualización. Inténtalo de nuevo más tarde!',
+        },
+    },
+    report: {
+        genericCreateReportFailureMessage: 'Error inesperado al crear el chat. Por favor, inténtalo más tarde',
+        genericAddCommentFailureMessage: 'Error inesperado al añadir el comentario. Por favor, inténtalo más tarde',
+        noActivityYet: 'Sin actividad todavía',
+    },
+    chronos: {
+        oooEventSummaryFullDay: ({summary, dayCount, date}) => `${summary} por ${dayCount} ${dayCount === 1 ? 'día' : 'días'} hasta el ${date}`,
+        oooEventSummaryPartialDay: ({summary, timePeriod, date}) => `${summary} de ${timePeriod} del ${date}`,
+    },
+    footer: {
+        features: 'Características',
+        expenseManagement: 'Gestión de Gastos',
+        spendManagement: 'Control de Gastos',
+        expenseReports: 'Informes de Gastos',
+        companyCreditCard: 'Tarjeta de Crédito Corporativa',
+        receiptScanningApp: 'Aplicación de Escaneado de Recibos',
+        billPay: 'Pago de Facturas',
+        invoicing: 'Facturación',
+        CPACard: 'Tarjeta Para Contables',
+        payroll: 'Nómina',
+        travel: 'Viajes',
+        resources: 'Recursos',
+        expensifyApproved: 'ExpensifyApproved!',
+        pressKit: 'Kit de Prensa',
+        support: 'Soporte',
+        expensifyHelp: 'ExpensifyHelp',
+        community: 'Comunidad',
+        privacy: 'Privacidad',
+        learnMore: 'Más Información',
+        aboutExpensify: 'Acerca de Expensify',
+        blog: 'Blog',
+        jobs: 'Empleo',
+        expensifyOrg: 'Expensify.org',
+        investorRelations: 'Relaciones Con Los Inversores',
+        getStarted: 'Comenzar',
+        createAccount: 'Crear Una Cuenta Nueva',
+        logIn: 'Conectarse',
+    },
+    allStates: {
+        AK: {
+            stateISO: 'AK',
+            stateName: 'Alaska',
+        },
+        AL: {
+            stateISO: 'AL',
+            stateName: 'Alabama',
+        },
+        AR: {
+            stateISO: 'AR',
+            stateName: 'Arkansas',
+        },
+        AZ: {
+            stateISO: 'AZ',
+            stateName: 'Arizona',
+        },
+        CA: {
+            stateISO: 'CA',
+            stateName: 'California',
+        },
+        CO: {
+            stateISO: 'CO',
+            stateName: 'Colorado',
+        },
+        CT: {
+            stateISO: 'CT',
+            stateName: 'Connecticut',
+        },
+        DE: {
+            stateISO: 'DE',
+            stateName: 'Delaware',
+        },
+        FL: {
+            stateISO: 'FL',
+            stateName: 'Florida',
+        },
+        GA: {
+            stateISO: 'GA',
+            stateName: 'Georgia',
+        },
+        HI: {
+            stateISO: 'HI',
+            stateName: 'Hawái',
+        },
+        IA: {
+            stateISO: 'IA',
+            stateName: 'Iowa',
+        },
+        ID: {
+            stateISO: 'ID',
+            stateName: 'Idaho',
+        },
+        IL: {
+            stateISO: 'IL',
+            stateName: 'Illinois',
+        },
+        IN: {
+            stateISO: 'IN',
+            stateName: 'Indiana',
+        },
+        KS: {
+            stateISO: 'KS',
+            stateName: 'Kansas',
+        },
+        KY: {
+            stateISO: 'KY',
+            stateName: 'Kentucky',
+        },
+        LA: {
+            stateISO: 'LA',
+            stateName: 'Luisiana',
+        },
+        MA: {
+            stateISO: 'MA',
+            stateName: 'Massachusetts',
+        },
+        MD: {
+            stateISO: 'MD',
+            stateName: 'Maryland',
+        },
+        ME: {
+            stateISO: 'ME',
+            stateName: 'Maine',
+        },
+        MI: {
+            stateISO: 'MI',
+            stateName: 'Míchigan',
+        },
+        MN: {
+            stateISO: 'MN',
+            stateName: 'Minnesota',
+        },
+        MO: {
+            stateISO: 'MO',
+            stateName: 'Misuri',
         },
-        genericErrorPage: {
-            title: '¡Uh-oh, algo salió mal!',
-            body: {
-                helpTextMobile: 'Intenta cerrar y volver a abrir la aplicación o cambiar a la',
-                helpTextWeb: 'web.',
-                helpTextConcierge: 'Si el problema persiste, comunícate con',
-            },
-            refresh: 'Actualizar',
+        MS: {
+            stateISO: 'MS',
+            stateName: 'Misisipi',
         },
-        fileDownload: {
-            success: {
-                title: '!Descargado!',
-                message: 'Archivo descargado correctamente',
-            },
-            generalError: {
-                title: 'Error en la descarga',
-                message: 'No se puede descargar el archivo adjunto',
-            },
-            permissionError: {
-                title: 'Permiso para acceder al almacenamiento',
-                message: 'Expensify no puede guardar los archivos adjuntos sin permiso para acceder al almacenamiento. Haz click en Configuración para actualizar los permisos.',
-            },
+        MT: {
+            stateISO: 'MT',
+            stateName: 'Montana',
         },
-        desktopApplicationMenu: {
-            mainMenu: 'Nuevo Expensify',
-            about: 'Sobre Nuevo Expensify',
-            update: 'Actualizar Nuevo Expensify',
-            checkForUpdates: 'Buscar actualizaciones',
-            toggleDevTools: 'Ver herramientas de desarrollo',
-            viewShortcuts: 'Ver atajos de teclado',
-            services: 'Servicios',
-            hide: 'Ocultar Nuevo Expensify',
-            hideOthers: 'Ocultar otros',
-            showAll: 'Mostrar todos',
-            quit: 'Salir de Nuevo Expensify',
-            fileMenu: 'Archivo',
-            closeWindow: 'Cerrar ventana',
-            editMenu: 'Editar',
-            undo: 'Deshacer',
-            redo: 'Rehacer',
-            cut: 'Cortar',
-            copy: 'Copiar',
-            paste: 'Pegar',
-            pasteAndMatchStyle: 'Pegar adaptando el estilo',
-            pasteAsPlainText: 'Pegar como texto sin formato',
-            delete: 'Eliminar',
-            selectAll: 'Seleccionar todo',
-            speechSubmenu: 'Voz',
-            startSpeaking: 'Empezar a hablar',
-            stopSpeaking: 'Dejar de Hablar',
-            viewMenu: 'Ver',
-            reload: 'Cargar de nuevo',
-            forceReload: 'Forzar recarga',
-            resetZoom: 'Tamaño real',
-            zoomIn: 'Acercar',
-            zoomOut: 'Alejar',
-            togglefullscreen: 'Alternar pantalla completa',
-            historyMenu: 'Historial',
-            back: 'Atrás',
-            forward: 'Adelante',
-            windowMenu: 'Ventana',
-            minimize: 'Minimizar',
-            zoom: 'Zoom',
-            front: 'Traer todo al frente',
-            helpMenu: 'Ayuda',
-            learnMore: 'Más información',
-            documentation: 'Documentación',
-            communityDiscussions: 'Debates de la comunidad',
-            searchIssues: 'Buscar problemas',
-        },
-        historyMenu: {
-            forward: 'Adelante',
-            back: 'Atrás',
-        },
-        checkForUpdatesModal: {
-            available: {
-                title: 'Actualización disponible',
-                message: 'La nueva versión estará disponible dentro de poco. Te notificaremos cuando esté lista.',
-                soundsGood: 'Suena bien',
-            },
-            notAvailable: {
-                title: 'Actualización no disponible',
-                message: 'No existe ninguna actualización disponible! Inténtalo de nuevo más tarde.',
-                okay: 'Vale',
-            },
-            error: {
-                title: 'Comprobación fallida',
-                message: 'No hemos podido comprobar si existe una actualización. Inténtalo de nuevo más tarde!',
-            },
+        NC: {
+            stateISO: 'NC',
+            stateName: 'Carolina del Norte',
         },
-        report: {
-            genericCreateReportFailureMessage: 'Error inesperado al crear el chat. Por favor, inténtalo más tarde',
-            genericAddCommentFailureMessage: 'Error inesperado al añadir el comentario. Por favor, inténtalo más tarde',
-            noActivityYet: 'Sin actividad todavía',
-        },
-        chronos: {
-            oooEventSummaryFullDay: ({summary, dayCount, date}) => `${summary} por ${dayCount} ${dayCount === 1 ? 'día' : 'días'} hasta el ${date}`,
-            oooEventSummaryPartialDay: ({summary, timePeriod, date}) => `${summary} de ${timePeriod} del ${date}`,
-        },
-        footer: {
-            features: 'Características',
-            expenseManagement: 'Gestión de Gastos',
-            spendManagement: 'Control de Gastos',
-            expenseReports: 'Informes de Gastos',
-            companyCreditCard: 'Tarjeta de Crédito Corporativa',
-            receiptScanningApp: 'Aplicación de Escaneado de Recibos',
-            billPay: 'Pago de Facturas',
-            invoicing: 'Facturación',
-            CPACard: 'Tarjeta Para Contables',
-            payroll: 'Nómina',
-            travel: 'Viajes',
-            resources: 'Recursos',
-            expensifyApproved: 'ExpensifyApproved!',
-            pressKit: 'Kit de Prensa',
-            support: 'Soporte',
-            expensifyHelp: 'ExpensifyHelp',
-            community: 'Comunidad',
-            privacy: 'Privacidad',
-            learnMore: 'Más Información',
-            aboutExpensify: 'Acerca de Expensify',
-            blog: 'Blog',
-            jobs: 'Empleo',
-            expensifyOrg: 'Expensify.org',
-            investorRelations: 'Relaciones Con Los Inversores',
-            getStarted: 'Comenzar',
-            createAccount: 'Crear Una Cuenta Nueva',
-            logIn: 'Conectarse',
-        },
-        allStates: {
-            AK: {
-                stateISO: 'AK',
-                stateName: 'Alaska',
-            },
-            AL: {
-                stateISO: 'AL',
-                stateName: 'Alabama',
-            },
-            AR: {
-                stateISO: 'AR',
-                stateName: 'Arkansas',
-            },
-            AZ: {
-                stateISO: 'AZ',
-                stateName: 'Arizona',
-            },
-            CA: {
-                stateISO: 'CA',
-                stateName: 'California',
-            },
-            CO: {
-                stateISO: 'CO',
-                stateName: 'Colorado',
-            },
-            CT: {
-                stateISO: 'CT',
-                stateName: 'Connecticut',
-            },
-            DE: {
-                stateISO: 'DE',
-                stateName: 'Delaware',
-            },
-            FL: {
-                stateISO: 'FL',
-                stateName: 'Florida',
-            },
-            GA: {
-                stateISO: 'GA',
-                stateName: 'Georgia',
-            },
-            HI: {
-                stateISO: 'HI',
-                stateName: 'Hawái',
-            },
-            IA: {
-                stateISO: 'IA',
-                stateName: 'Iowa',
-            },
-            ID: {
-                stateISO: 'ID',
-                stateName: 'Idaho',
-            },
-            IL: {
-                stateISO: 'IL',
-                stateName: 'Illinois',
-            },
-            IN: {
-                stateISO: 'IN',
-                stateName: 'Indiana',
-            },
-            KS: {
-                stateISO: 'KS',
-                stateName: 'Kansas',
-            },
-            KY: {
-                stateISO: 'KY',
-                stateName: 'Kentucky',
-            },
-            LA: {
-                stateISO: 'LA',
-                stateName: 'Luisiana',
-            },
-            MA: {
-                stateISO: 'MA',
-                stateName: 'Massachusetts',
-            },
-            MD: {
-                stateISO: 'MD',
-                stateName: 'Maryland',
-            },
-            ME: {
-                stateISO: 'ME',
-                stateName: 'Maine',
-            },
-            MI: {
-                stateISO: 'MI',
-                stateName: 'Míchigan',
-            },
-            MN: {
-                stateISO: 'MN',
-                stateName: 'Minnesota',
-            },
-            MO: {
-                stateISO: 'MO',
-                stateName: 'Misuri',
-            },
-            MS: {
-                stateISO: 'MS',
-                stateName: 'Misisipi',
-            },
-            MT: {
-                stateISO: 'MT',
-                stateName: 'Montana',
-            },
-            NC: {
-                stateISO: 'NC',
-                stateName: 'Carolina del Norte',
-            },
-            ND: {
-                stateISO: 'ND',
-                stateName: 'Dakota del Norte',
-            },
-            NE: {
-                stateISO: 'NE',
-                stateName: 'Nebraska',
-            },
-            NH: {
-                stateISO: 'NH',
-                stateName: 'Nuevo Hampshire',
-            },
-            NJ: {
-                stateISO: 'NJ',
-                stateName: 'Nueva Jersey',
-            },
-            NM: {
-                stateISO: 'NM',
-                stateName: 'Nuevo México',
-            },
-            NV: {
-                stateISO: 'NV',
-                stateName: 'Nevada',
-            },
-            NY: {
-                stateISO: 'NY',
-                stateName: 'Nueva York',
-            },
-            OH: {
-                stateISO: 'OH',
-                stateName: 'Ohio',
-            },
-            OK: {
-                stateISO: 'OK',
-                stateName: 'Oklahoma',
-            },
-            OR: {
-                stateISO: 'OR',
-                stateName: 'Oregón',
-            },
-            PA: {
-                stateISO: 'PA',
-                stateName: 'Pensilvania',
-            },
-            PR: {
-                stateISO: 'PR',
-                stateName: 'Puerto Rico',
-            },
-            RI: {
-                stateISO: 'RI',
-                stateName: 'Rhode Island',
-            },
-            SC: {
-                stateISO: 'SC',
-                stateName: 'Carolina del Sur',
-            },
-            SD: {
-                stateISO: 'SD',
-                stateName: 'Dakota del Sur',
-            },
-            TN: {
-                stateISO: 'TN',
-                stateName: 'Tennessee',
-            },
-            TX: {
-                stateISO: 'TX',
-                stateName: 'Texas',
-            },
-            UT: {
-                stateISO: 'UT',
-                stateName: 'Utah',
-            },
-            VA: {
-                stateISO: 'VA',
-                stateName: 'Virginia',
-            },
-            VT: {
-                stateISO: 'VT',
-                stateName: 'Vermont',
-            },
-            WA: {
-                stateISO: 'WA',
-                stateName: 'Washington',
-            },
-            WI: {
-                stateISO: 'WI',
-                stateName: 'Wisconsin',
-            },
-            WV: {
-                stateISO: 'WV',
-                stateName: 'Virginia Occidental',
-            },
-            WY: {
-                stateISO: 'WY',
-                stateName: 'Wyoming',
-            },
-            DC: {
-                stateISO: 'DC',
-                stateName: 'Distrito de Columbia',
-            },
+        ND: {
+            stateISO: 'ND',
+            stateName: 'Dakota del Norte',
         },
-        allCountries: {
-            AF: 'Afganistán',
-            AL: 'Albania',
-            DE: 'Alemania',
-            AD: 'Andorra',
-            AO: 'Angola',
-            AI: 'Anguila',
-            AQ: 'Antártida',
-            AG: 'Antigua y Barbuda',
-            SA: 'Arabia Saudita',
-            DZ: 'Argelia',
-            AR: 'Argentina',
-            AM: 'Armenia',
-            AW: 'Aruba',
-            AU: 'Australia',
-            AT: 'Austria',
-            AZ: 'Azerbaiyán',
-            BS: 'Bahamas',
-            BH: 'Bahrein',
-            BD: 'Bangladesh',
-            BB: 'Barbados',
-            BE: 'Bélgica',
-            BZ: 'Belice',
-            BJ: 'Benin',
-            BT: 'Bhután',
-            BY: 'Bielorrusia',
-            MM: 'Birmania',
-            BO: 'Bolivia',
-            BQ: 'Bonaire, San Eustaquio y Saba',
-            BA: 'Bosnia y Herzegovina',
-            BW: 'Botsuana',
-            BR: 'Brazil',
-            BN: 'Brunéi',
-            BG: 'Bulgaria',
-            BF: 'Burkina Faso',
-            BI: 'Burundi',
-            CV: 'Cabo Verde',
-            KH: 'Camboya',
-            CM: 'Camerún',
-            CA: 'Canadá',
-            TD: 'Chad',
-            CL: 'Chile',
-            CN: 'China',
-            CY: 'Chipre',
-            VA: 'Ciudad del Vaticano',
-            CO: 'Colombia',
-            KM: 'Comoras',
-            KP: 'Corea del Norte',
-            KR: 'Corea del Sur',
-            CI: 'Costa de Marfil',
-            CR: 'Costa Rica',
-            HR: 'Croacia',
-            CU: 'Cuba',
-            CW: 'Curazao',
-            DK: 'Dinamarca',
-            DM: 'Dominica',
-            EC: 'Ecuador',
-            EG: 'Egipto',
-            SV: 'El Salvador',
-            AE: 'Emiratos Árabes Unidos',
-            ER: 'Eritrea',
-            SK: 'Eslovaquia',
-            SI: 'Eslovenia',
-            ES: 'España',
-            US: 'Estados Unidos de América',
-            EE: 'Estonia',
-            ET: 'Etiopía',
-            PH: 'Filipinas',
-            FI: 'Finlandia',
-            FJ: 'Fiyi',
-            FR: 'Francia',
-            GA: 'Gabón',
-            GM: 'Gambia',
-            GE: 'Georgia',
-            GH: 'Ghana',
-            GI: 'Gibraltar',
-            GD: 'Granada',
-            GR: 'Greece',
-            GL: 'Groenlandia',
-            GP: 'Guadeloupe',
-            GU: 'Guam',
-            GT: 'Guatemala',
-            GF: 'Guayana Francesa',
-            GG: 'Guernsey',
-            GN: 'Guinea',
-            GQ: 'Guinea Ecuatorial',
-            GW: 'Guinea-Bissau',
-            GY: 'Guyana',
-            HT: 'Haiti',
-            HN: 'Honduras',
-            HK: 'Hong Kong',
-            HU: 'Hungría',
-            IN: 'India',
-            ID: 'Indonesia',
-            IQ: 'Irak',
-            IR: 'Irán',
-            IE: 'Irlanda',
-            AC: 'Isla Ascensión',
-            IM: 'Isla de Man',
-            CX: 'Isla de Navidad',
-            NF: 'Isla Norfolk',
-            IS: 'Islandia',
-            BM: 'Islas Bermudas',
-            KY: 'Islas Caimán',
-            CC: 'Islas Cocos (Keeling)',
-            CK: 'Islas Cook',
-            AX: 'Islas de Åland',
-            FO: 'Islas Feroe',
-            GS: 'Islas Georgias del Sur y Sandwich del Sur',
-            MV: 'Islas Maldivas',
-            FK: 'Islas Malvinas',
-            MP: 'Islas Marianas del Norte',
-            MH: 'Islas Marshall',
-            PN: 'Islas Pitcairn',
-            SB: 'Islas Salomón',
-            TC: 'Islas Turcas y Caicos',
-            UM: 'Islas Ultramarinas Menores de Estados Unidos',
-            VG: 'Islas Vírgenes Británicas',
-            VI: 'Islas Vírgenes de los Estados Unidos',
-            IL: 'Israel',
-            IT: 'Italia',
-            JM: 'Jamaica',
-            JP: 'Japón',
-            JE: 'Jersey',
-            JO: 'Jordania',
-            KZ: 'Kazajistán',
-            KE: 'Kenia',
-            KG: 'Kirguistán',
-            KI: 'Kiribati',
-            XK: 'Kosovo',
-            KW: 'Kuwait',
-            LA: 'Laos',
-            LS: 'Lesoto',
-            LV: 'Letonia',
-            LB: 'Líbano',
-            LR: 'Liberia',
-            LY: 'Libia',
-            LI: 'Liechtenstein',
-            LT: 'Lituania',
-            LU: 'Luxemburgo',
-            MO: 'Macao',
-            MK: 'Macedônia',
-            MG: 'Madagascar',
-            MY: 'Malasia',
-            MW: 'Malawi',
-            ML: 'Mali',
-            MT: 'Malta',
-            MA: 'Marruecos',
-            MQ: 'Martinica',
-            MR: 'Mauritania',
-            MU: 'Mauritius',
-            YT: 'Mayotte',
-            MX: 'México',
-            FM: 'Micronesia',
-            MD: 'Moldavia',
-            MC: 'Mónaco',
-            MN: 'Mongolia',
-            ME: 'Montenegro',
-            MS: 'Montserrat',
-            MZ: 'Mozambique',
-            NA: 'Namibia',
-            NR: 'Nauru',
-            NP: 'Nepal',
-            NI: 'Nicaragua',
-            NE: 'Niger',
-            NG: 'Nigeria',
-            NU: 'Niue',
-            NO: 'Noruega',
-            NC: 'Nueva Caledonia',
-            NZ: 'Nueva Zealand',
-            OM: 'Omán',
-            NL: 'Países Bajos',
-            PK: 'Pakistán',
-            PW: 'Palau',
-            PS: 'Palestina',
-            PA: 'Panamá',
-            PG: 'Papúa Nueva Guinea',
-            PY: 'Paraguay',
-            PE: 'Perú',
-            PF: 'Polinesia Francesa',
-            PL: 'Polonia',
-            PT: 'Portugal',
-            PR: 'Puerto Rico',
-            QA: 'Qatar',
-            GB: 'Reino Unido',
-            CF: 'República Centroafricana',
-            CZ: 'República Checa',
-            SS: 'República de Sudán del Sur',
-            CG: 'República del Congo',
-            CD: 'República Democrática del Congo',
-            DO: 'República Dominicana',
-            RE: 'Reunión',
-            RW: 'Ruanda',
-            RO: 'Rumanía',
-            RU: 'Rusia',
-            EH: 'Sahara Occidental',
-            WS: 'Samoa',
-            AS: 'Samoa Americana',
-            BL: 'San Bartolomé',
-            KN: 'San Cristóbal y Nieves',
-            SM: 'San Marino',
-            MF: 'San Martín (Francia)',
-            PM: 'San Pedro y Miquelón',
-            VC: 'San Vicente y las Granadinas',
-            SH: 'Santa Elena',
-            LC: 'Santa Lucía',
-            ST: 'Santo Tomé y Príncipe',
-            SN: 'Senegal',
-            RS: 'Serbia',
-            SC: 'Seychelles',
-            SL: 'Sierra Leona',
-            SG: 'Singapur',
-            SX: 'Sint Maarten',
-            SY: 'Siria',
-            SO: 'Somalia',
-            LK: 'Sri Lanka',
-            ZA: 'Sudáfrica',
-            SD: 'Sudán',
-            SE: 'Suecia',
-            CH: 'Suiza',
-            SR: 'Surinám',
-            SJ: 'Svalbard y Jan Mayen',
-            SZ: 'Swazilandia',
-            TH: 'Tailandia',
-            TW: 'Taiwán',
-            TZ: 'Tanzania',
-            TJ: 'Tayikistán',
-            IO: 'Territorio Británico del Océano Índico',
-            TF: 'Territorios Australes y Antárticas Franceses',
-            TL: 'Timor Oriental',
-            TG: 'Togo',
-            TK: 'Tokelau',
-            TO: 'Tonga',
-            TT: 'Trinidad y Tobago',
-            TA: 'Tristán de Acuña',
-            TN: 'Tunez',
-            TM: 'Turkmenistán',
-            TR: 'Turquía',
-            TV: 'Tuvalu',
-            UA: 'Ucrania',
-            UG: 'Uganda',
-            UY: 'Uruguay',
-            UZ: 'Uzbekistan',
-            VU: 'Vanuatu',
-            VE: 'Venezuela',
-            VN: 'Vietnam',
-            WF: 'Wallis y Futuna',
-            YE: 'Yemen',
-            DJ: 'Yibuti',
-            ZM: 'Zambia',
-            ZW: 'Zimbabue',
-        },
-        accessibilityHints: {
-            navigateToChatsList: 'Vuelve a la lista de chats',
-            chatWelcomeMessage: 'Mensaje de bienvenida al chat',
-            navigatesToChat: 'Navega a un chat',
-            newMessageLineIndicator: 'Indicador de nueva línea de mensaje',
-            chatMessage: 'mensaje de chat',
-            lastChatMessagePreview: 'Vista previa del último mensaje del chat',
-            workspaceName: 'Nombre del espacio de trabajo',
-            chatUserDisplayNames: 'Nombres de los usuarios del chat',
-            scrollToNewestMessages: 'Desplázate a los mensajes más recientes',
-            prestyledText: 'texto preestilizado',
-            viewAttachment: 'Ver archivo adjunto',
-        },
-        parentReportAction: {
-            deletedMessage: '[Mensaje eliminado]',
-            deletedRequest: '[Pedido eliminado]',
-            hiddenMessage: '[Mensaje oculto]',
-        },
-        threads: {
-            replies: 'Respuestas',
-            reply: 'Respuesta',
-            from: 'De',
-            in: 'en',
-            parentNavigationSummary: ({rootReportName, workspaceName}) => `De ${rootReportName}${workspaceName ? ` en ${workspaceName}` : ''}`,
-        },
-        qrCodes: {
-            copyUrlToClipboard: 'Copiar URL al portapapeles',
-            copied: '¡Copiado!',
-        },
-        moderation: {
-            flagDescription: 'Todos los mensajes marcados se enviarán a un moderador para su revisión.',
-            chooseAReason: 'Elige abajo un motivo para reportarlo:',
-            spam: 'Spam',
-            spamDescription: 'Promoción fuera de tema no solicitada',
-            inconsiderate: 'Desconsiderado',
-            inconsiderateDescription: 'Frase insultante o irrespetuosa, con intenciones cuestionables',
-            intimidation: 'Intimidación',
-            intimidationDescription: 'Persigue agresivamente una agenda sobre objeciones válidas',
-            bullying: 'Bullying',
-            bullyingDescription: 'Apunta a un individuo para obtener obediencia',
-            harassment: 'Acoso',
-            harassmentDescription: 'Comportamiento racista, misógino u otro comportamiento discriminatorio',
-            assault: 'Agresion',
-            assaultDescription: 'Ataque emocional específicamente dirigido con la intención de hacer daño',
-            flaggedContent: 'Este mensaje ha sido marcado por violar las reglas de nuestra comunidad y el contenido se ha ocultado.',
-            hideMessage: 'Ocultar mensaje',
-            revealMessage: 'Revelar mensaje',
-            levelOneResult: 'Envia una advertencia anónima y el mensaje es reportado para revisión.',
-            levelTwoResult: 'Mensaje ocultado del canal, más advertencia anónima y mensaje reportado para revisión.',
-            levelThreeResult: 'Mensaje eliminado del canal, más advertencia anónima y mensaje reportado para revisión.',
-        },
-        distance: {
-            addStop: 'Agregar parada',
-            address: 'Dirección',
-            waypointEditor: 'Editor de puntos de ruta',
-            waypointDescription: {
-                start: 'Comienzo',
-                finish: 'Final',
-                stop: 'Parada',
-            },
-            mapPending: {
-                title: 'Mapa pendiente',
-                subtitle: 'El mapa se generará cuando vuelvas a estar en línea',
-                onlineSubtitle: 'Un momento mientras configuramos el mapa',
-            },
-            errors: {
-                selectSuggestedAddress: 'Por favor, selecciona una dirección sugerida',
-            },
+        NE: {
+            stateISO: 'NE',
+            stateName: 'Nebraska',
         },
-        countrySelectorModal: {
-            placeholderText: 'Buscar para ver opciones',
+        NH: {
+            stateISO: 'NH',
+            stateName: 'Nuevo Hampshire',
+        },
+        NJ: {
+            stateISO: 'NJ',
+            stateName: 'Nueva Jersey',
+        },
+        NM: {
+            stateISO: 'NM',
+            stateName: 'Nuevo México',
+        },
+        NV: {
+            stateISO: 'NV',
+            stateName: 'Nevada',
+        },
+        NY: {
+            stateISO: 'NY',
+            stateName: 'Nueva York',
+        },
+        OH: {
+            stateISO: 'OH',
+            stateName: 'Ohio',
+        },
+        OK: {
+            stateISO: 'OK',
+            stateName: 'Oklahoma',
+        },
+        OR: {
+            stateISO: 'OR',
+            stateName: 'Oregón',
+        },
+        PA: {
+            stateISO: 'PA',
+            stateName: 'Pensilvania',
+        },
+        PR: {
+            stateISO: 'PR',
+            stateName: 'Puerto Rico',
+        },
+        RI: {
+            stateISO: 'RI',
+            stateName: 'Rhode Island',
+        },
+        SC: {
+            stateISO: 'SC',
+            stateName: 'Carolina del Sur',
+        },
+        SD: {
+            stateISO: 'SD',
+            stateName: 'Dakota del Sur',
+        },
+        TN: {
+            stateISO: 'TN',
+            stateName: 'Tennessee',
+        },
+        TX: {
+            stateISO: 'TX',
+            stateName: 'Texas',
+        },
+        UT: {
+            stateISO: 'UT',
+            stateName: 'Utah',
+        },
+        VA: {
+            stateISO: 'VA',
+            stateName: 'Virginia',
+        },
+        VT: {
+            stateISO: 'VT',
+            stateName: 'Vermont',
+        },
+        WA: {
+            stateISO: 'WA',
+            stateName: 'Washington',
+        },
+        WI: {
+            stateISO: 'WI',
+            stateName: 'Wisconsin',
+        },
+        WV: {
+            stateISO: 'WV',
+            stateName: 'Virginia Occidental',
+        },
+        WY: {
+            stateISO: 'WY',
+            stateName: 'Wyoming',
+        },
+        DC: {
+            stateISO: 'DC',
+            stateName: 'Distrito de Columbia',
+        },
+    },
+    allCountries: {
+        AF: 'Afganistán',
+        AL: 'Albania',
+        DE: 'Alemania',
+        AD: 'Andorra',
+        AO: 'Angola',
+        AI: 'Anguila',
+        AQ: 'Antártida',
+        AG: 'Antigua y Barbuda',
+        SA: 'Arabia Saudita',
+        DZ: 'Argelia',
+        AR: 'Argentina',
+        AM: 'Armenia',
+        AW: 'Aruba',
+        AU: 'Australia',
+        AT: 'Austria',
+        AZ: 'Azerbaiyán',
+        BS: 'Bahamas',
+        BH: 'Bahrein',
+        BD: 'Bangladesh',
+        BB: 'Barbados',
+        BE: 'Bélgica',
+        BZ: 'Belice',
+        BJ: 'Benin',
+        BT: 'Bhután',
+        BY: 'Bielorrusia',
+        MM: 'Birmania',
+        BO: 'Bolivia',
+        BQ: 'Bonaire, San Eustaquio y Saba',
+        BA: 'Bosnia y Herzegovina',
+        BW: 'Botsuana',
+        BR: 'Brazil',
+        BN: 'Brunéi',
+        BG: 'Bulgaria',
+        BF: 'Burkina Faso',
+        BI: 'Burundi',
+        CV: 'Cabo Verde',
+        KH: 'Camboya',
+        CM: 'Camerún',
+        CA: 'Canadá',
+        TD: 'Chad',
+        CL: 'Chile',
+        CN: 'China',
+        CY: 'Chipre',
+        VA: 'Ciudad del Vaticano',
+        CO: 'Colombia',
+        KM: 'Comoras',
+        KP: 'Corea del Norte',
+        KR: 'Corea del Sur',
+        CI: 'Costa de Marfil',
+        CR: 'Costa Rica',
+        HR: 'Croacia',
+        CU: 'Cuba',
+        CW: 'Curazao',
+        DK: 'Dinamarca',
+        DM: 'Dominica',
+        EC: 'Ecuador',
+        EG: 'Egipto',
+        SV: 'El Salvador',
+        AE: 'Emiratos Árabes Unidos',
+        ER: 'Eritrea',
+        SK: 'Eslovaquia',
+        SI: 'Eslovenia',
+        ES: 'España',
+        US: 'Estados Unidos de América',
+        EE: 'Estonia',
+        ET: 'Etiopía',
+        PH: 'Filipinas',
+        FI: 'Finlandia',
+        FJ: 'Fiyi',
+        FR: 'Francia',
+        GA: 'Gabón',
+        GM: 'Gambia',
+        GE: 'Georgia',
+        GH: 'Ghana',
+        GI: 'Gibraltar',
+        GD: 'Granada',
+        GR: 'Greece',
+        GL: 'Groenlandia',
+        GP: 'Guadeloupe',
+        GU: 'Guam',
+        GT: 'Guatemala',
+        GF: 'Guayana Francesa',
+        GG: 'Guernsey',
+        GN: 'Guinea',
+        GQ: 'Guinea Ecuatorial',
+        GW: 'Guinea-Bissau',
+        GY: 'Guyana',
+        HT: 'Haiti',
+        HN: 'Honduras',
+        HK: 'Hong Kong',
+        HU: 'Hungría',
+        IN: 'India',
+        ID: 'Indonesia',
+        IQ: 'Irak',
+        IR: 'Irán',
+        IE: 'Irlanda',
+        AC: 'Isla Ascensión',
+        IM: 'Isla de Man',
+        CX: 'Isla de Navidad',
+        NF: 'Isla Norfolk',
+        IS: 'Islandia',
+        BM: 'Islas Bermudas',
+        KY: 'Islas Caimán',
+        CC: 'Islas Cocos (Keeling)',
+        CK: 'Islas Cook',
+        AX: 'Islas de Åland',
+        FO: 'Islas Feroe',
+        GS: 'Islas Georgias del Sur y Sandwich del Sur',
+        MV: 'Islas Maldivas',
+        FK: 'Islas Malvinas',
+        MP: 'Islas Marianas del Norte',
+        MH: 'Islas Marshall',
+        PN: 'Islas Pitcairn',
+        SB: 'Islas Salomón',
+        TC: 'Islas Turcas y Caicos',
+        UM: 'Islas Ultramarinas Menores de Estados Unidos',
+        VG: 'Islas Vírgenes Británicas',
+        VI: 'Islas Vírgenes de los Estados Unidos',
+        IL: 'Israel',
+        IT: 'Italia',
+        JM: 'Jamaica',
+        JP: 'Japón',
+        JE: 'Jersey',
+        JO: 'Jordania',
+        KZ: 'Kazajistán',
+        KE: 'Kenia',
+        KG: 'Kirguistán',
+        KI: 'Kiribati',
+        XK: 'Kosovo',
+        KW: 'Kuwait',
+        LA: 'Laos',
+        LS: 'Lesoto',
+        LV: 'Letonia',
+        LB: 'Líbano',
+        LR: 'Liberia',
+        LY: 'Libia',
+        LI: 'Liechtenstein',
+        LT: 'Lituania',
+        LU: 'Luxemburgo',
+        MO: 'Macao',
+        MK: 'Macedônia',
+        MG: 'Madagascar',
+        MY: 'Malasia',
+        MW: 'Malawi',
+        ML: 'Mali',
+        MT: 'Malta',
+        MA: 'Marruecos',
+        MQ: 'Martinica',
+        MR: 'Mauritania',
+        MU: 'Mauritius',
+        YT: 'Mayotte',
+        MX: 'México',
+        FM: 'Micronesia',
+        MD: 'Moldavia',
+        MC: 'Mónaco',
+        MN: 'Mongolia',
+        ME: 'Montenegro',
+        MS: 'Montserrat',
+        MZ: 'Mozambique',
+        NA: 'Namibia',
+        NR: 'Nauru',
+        NP: 'Nepal',
+        NI: 'Nicaragua',
+        NE: 'Niger',
+        NG: 'Nigeria',
+        NU: 'Niue',
+        NO: 'Noruega',
+        NC: 'Nueva Caledonia',
+        NZ: 'Nueva Zealand',
+        OM: 'Omán',
+        NL: 'Países Bajos',
+        PK: 'Pakistán',
+        PW: 'Palau',
+        PS: 'Palestina',
+        PA: 'Panamá',
+        PG: 'Papúa Nueva Guinea',
+        PY: 'Paraguay',
+        PE: 'Perú',
+        PF: 'Polinesia Francesa',
+        PL: 'Polonia',
+        PT: 'Portugal',
+        PR: 'Puerto Rico',
+        QA: 'Qatar',
+        GB: 'Reino Unido',
+        CF: 'República Centroafricana',
+        CZ: 'República Checa',
+        SS: 'República de Sudán del Sur',
+        CG: 'República del Congo',
+        CD: 'República Democrática del Congo',
+        DO: 'República Dominicana',
+        RE: 'Reunión',
+        RW: 'Ruanda',
+        RO: 'Rumanía',
+        RU: 'Rusia',
+        EH: 'Sahara Occidental',
+        WS: 'Samoa',
+        AS: 'Samoa Americana',
+        BL: 'San Bartolomé',
+        KN: 'San Cristóbal y Nieves',
+        SM: 'San Marino',
+        MF: 'San Martín (Francia)',
+        PM: 'San Pedro y Miquelón',
+        VC: 'San Vicente y las Granadinas',
+        SH: 'Santa Elena',
+        LC: 'Santa Lucía',
+        ST: 'Santo Tomé y Príncipe',
+        SN: 'Senegal',
+        RS: 'Serbia',
+        SC: 'Seychelles',
+        SL: 'Sierra Leona',
+        SG: 'Singapur',
+        SX: 'Sint Maarten',
+        SY: 'Siria',
+        SO: 'Somalia',
+        LK: 'Sri Lanka',
+        ZA: 'Sudáfrica',
+        SD: 'Sudán',
+        SE: 'Suecia',
+        CH: 'Suiza',
+        SR: 'Surinám',
+        SJ: 'Svalbard y Jan Mayen',
+        SZ: 'Swazilandia',
+        TH: 'Tailandia',
+        TW: 'Taiwán',
+        TZ: 'Tanzania',
+        TJ: 'Tayikistán',
+        IO: 'Territorio Británico del Océano Índico',
+        TF: 'Territorios Australes y Antárticas Franceses',
+        TL: 'Timor Oriental',
+        TG: 'Togo',
+        TK: 'Tokelau',
+        TO: 'Tonga',
+        TT: 'Trinidad y Tobago',
+        TA: 'Tristán de Acuña',
+        TN: 'Tunez',
+        TM: 'Turkmenistán',
+        TR: 'Turquía',
+        TV: 'Tuvalu',
+        UA: 'Ucrania',
+        UG: 'Uganda',
+        UY: 'Uruguay',
+        UZ: 'Uzbekistan',
+        VU: 'Vanuatu',
+        VE: 'Venezuela',
+        VN: 'Vietnam',
+        WF: 'Wallis y Futuna',
+        YE: 'Yemen',
+        DJ: 'Yibuti',
+        ZM: 'Zambia',
+        ZW: 'Zimbabue',
+    },
+    accessibilityHints: {
+        navigateToChatsList: 'Vuelve a la lista de chats',
+        chatWelcomeMessage: 'Mensaje de bienvenida al chat',
+        navigatesToChat: 'Navega a un chat',
+        newMessageLineIndicator: 'Indicador de nueva línea de mensaje',
+        chatMessage: 'mensaje de chat',
+        lastChatMessagePreview: 'Vista previa del último mensaje del chat',
+        workspaceName: 'Nombre del espacio de trabajo',
+        chatUserDisplayNames: 'Nombres de los usuarios del chat',
+        scrollToNewestMessages: 'Desplázate a los mensajes más recientes',
+        prestyledText: 'texto preestilizado',
+        viewAttachment: 'Ver archivo adjunto',
+    },
+    parentReportAction: {
+        deletedMessage: '[Mensaje eliminado]',
+        deletedRequest: '[Pedido eliminado]',
+        hiddenMessage: '[Mensaje oculto]',
+    },
+    threads: {
+        replies: 'Respuestas',
+        reply: 'Respuesta',
+        from: 'De',
+        in: 'en',
+        parentNavigationSummary: ({rootReportName, workspaceName}) => `De ${rootReportName}${workspaceName ? ` en ${workspaceName}` : ''}`,
+    },
+    qrCodes: {
+        copyUrlToClipboard: 'Copiar URL al portapapeles',
+        copied: '¡Copiado!',
+    },
+    moderation: {
+        flagDescription: 'Todos los mensajes marcados se enviarán a un moderador para su revisión.',
+        chooseAReason: 'Elige abajo un motivo para reportarlo:',
+        spam: 'Spam',
+        spamDescription: 'Promoción fuera de tema no solicitada',
+        inconsiderate: 'Desconsiderado',
+        inconsiderateDescription: 'Frase insultante o irrespetuosa, con intenciones cuestionables',
+        intimidation: 'Intimidación',
+        intimidationDescription: 'Persigue agresivamente una agenda sobre objeciones válidas',
+        bullying: 'Bullying',
+        bullyingDescription: 'Apunta a un individuo para obtener obediencia',
+        harassment: 'Acoso',
+        harassmentDescription: 'Comportamiento racista, misógino u otro comportamiento discriminatorio',
+        assault: 'Agresion',
+        assaultDescription: 'Ataque emocional específicamente dirigido con la intención de hacer daño',
+        flaggedContent: 'Este mensaje ha sido marcado por violar las reglas de nuestra comunidad y el contenido se ha ocultado.',
+        hideMessage: 'Ocultar mensaje',
+        revealMessage: 'Revelar mensaje',
+        levelOneResult: 'Envia una advertencia anónima y el mensaje es reportado para revisión.',
+        levelTwoResult: 'Mensaje ocultado del canal, más advertencia anónima y mensaje reportado para revisión.',
+        levelThreeResult: 'Mensaje eliminado del canal, más advertencia anónima y mensaje reportado para revisión.',
+    },
+    distance: {
+        addStop: 'Agregar parada',
+        address: 'Dirección',
+        waypointEditor: 'Editor de puntos de ruta',
+        waypointDescription: {
+            start: 'Comienzo',
+            finish: 'Final',
+            stop: 'Parada',
+        },
+        mapPending: {
+            title: 'Mapa pendiente',
+            subtitle: 'El mapa se generará cuando vuelvas a estar en línea',
+            onlineSubtitle: 'Un momento mientras configuramos el mapa',
         },
-        stateSelectorModal: {
-            placeholderText: 'Buscar para ver opciones',
+        errors: {
+            selectSuggestedAddress: 'Por favor, selecciona una dirección sugerida',
         },
     },
+    countrySelectorModal: {
+        placeholderText: 'Buscar para ver opciones',
+    },
+    stateSelectorModal: {
+        placeholderText: 'Buscar para ver opciones',
+    },
     demos: {
         saastr: {
             signInWelcome: '¡Bienvenido a SaaStr! Entra y empieza a establecer contactos.',

From 0562cafa9e1e5d99d38d997cadef731655e69748 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 24 Aug 2023 15:07:47 +0200
Subject: [PATCH 027/118] clean

---
 src/components/TimePicker.js                  |  1 -
 src/libs/DateUtils.js                         | 38 ++++++++++++-------
 .../Profile/CustomStatus/SetTimePage.js       |  4 --
 .../CustomStatus/StatusClearAfterPage.js      | 22 +++++++++--
 .../Profile/CustomStatus/StatusPage.js        | 31 +++++++++++----
 5 files changed, 68 insertions(+), 28 deletions(-)

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index b5c0e096f1a5..9afbc2b18fa5 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -1,7 +1,6 @@
 import React, {useEffect, useState, useCallback, useRef, useMemo} from 'react';
 import {View} from 'react-native';
 import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
 import _ from 'underscore';
 import styles from '../styles/styles';
 import themeColors from '../styles/themes/default';
diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index 20cec65d5167..a6e865666c66 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -316,14 +316,6 @@ function getEndOfWeekFromNow() {
     return moment().add(7, 'days').format('YYYY-MM-DD HH:mm:ss');
 }
 
-/**
- * @returns {string} example: 2023-05-16
- * it's kind of 'newer' date
- */
-function getOneHundredYearsFromNow() {
-    return moment().endOf(100, 'years').format('YYYY-MM-DD HH:mm:ss');
-}
-
 /**
  * @param {string} time
  * @returns {string} example: 2023-05-16
@@ -357,12 +349,13 @@ function extractTime12Hour(dateTimeString) {
  */
 function formatDateTo12Hour(dateTimeString) {
     if (!dateTimeString) return '';
-    return moment(dateTimeString).format('YYYY-MM-DD hh:mm:ss A');
+    return moment(dateTimeString).format('YYYY-MM-DD hh:mm A');
 }
 
-// /**
-//  * @returns {string} example: 2023-05-16
-//  */
+/**
+ * @param {string} type - one of the values from CONST.CUSTOM_STATUS_TYPES
+ * @returns {string} example: 2023-05-16
+ */
 function getDateBasedFromType(type) {
     switch (type) {
         case CONST.CUSTOM_STATUS_TYPES.THIRTY_MINUTES:
@@ -373,11 +366,30 @@ function getDateBasedFromType(type) {
             return getEndOfToday();
         case CONST.CUSTOM_STATUS_TYPES.AFTER_WEEK:
             return getEndOfWeekFromNow();
+        case CONST.CUSTOM_STATUS_TYPES.NEVER:
+            return CONST.CUSTOM_STATUS_TYPES.NEVER;
         default:
             return '';
     }
 }
 
+/**
+ * @param {string} data - one of the values from CONST.CUSTOM_STATUS_TYPES or data in format YYYY-MM-DD HH:mm
+ * @returns {string} example: 2023-05-16 11:10 PM or 'Today'
+ */
+function getDateForTitleBasedFromType(data) {
+    const {translateLocal} = Localize;
+    switch (data) {
+        case getEndOfToday():
+            return translateLocal('statusPage.timePeriods.afterToday');
+        case CONST.CUSTOM_STATUS_TYPES.NEVER:
+        case '':
+            return translateLocal('statusPage.timePeriods.never');
+        default:
+            return formatDateTo12Hour(data);
+    }
+}
+
 /**
  * receive date like 2020-05-16 05:34:14 and format it to show in string like "Until 05:34 PM"
  *
@@ -501,7 +513,6 @@ const DateUtils = {
     getThirtyMinutesFromNow,
     getEndOfToday,
     getEndOfWeekFromNow,
-    getOneHundredYearsFromNow,
     getDateBasedFromType,
     getOneHourFromNow,
     extractDate,
@@ -513,6 +524,7 @@ const DateUtils = {
     parseTimeTo12HourFormat,
     areDatesIdentical,
     getTimePeriod,
+    getDateForTitleBasedFromType,
 };
 
 export default DateUtils;
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index c4411f5a7e53..9153f75d316a 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -2,8 +2,6 @@ import PropTypes from 'prop-types';
 import React, {useCallback} from 'react';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
-import RNTimePicker from '@react-native-community/datetimepicker';
-import {View} from 'react-native';
 import withCurrentUserPersonalDetails from '../../../../components/withCurrentUserPersonalDetails';
 import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator';
 import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
@@ -54,8 +52,6 @@ function SetTimePage({translate, privatePersonalDetails, customStatus, currentUs
         return <FullscreenLoadingIndicator />;
     }
 
-    // const customStatusTime = DateUtils.extractTime(customDateTemporary || draftClearAfter || clearAfter);
-
     return (
         <ScreenWrapper includeSafeAreaPaddingBottom={false}>
             <HeaderWithBackButton
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 25439c0f74a8..a41178ec5efd 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -35,14 +35,30 @@ const propTypes = {
     }),
 };
 
+/**
+ * @param {string} data - one of the values from CONST.CUSTOM_STATUS_TYPES or data in format YYYY-MM-DD HH:mm
+ * @returns {string}
+ */
+function getDateBasedFromType(data) {
+    switch (data) {
+        case DateUtils.getEndOfToday():
+            return CONST.CUSTOM_STATUS_TYPES.AFTER_TODAY;
+        case CONST.CUSTOM_STATUS_TYPES.NEVER:
+        case '':
+            return CONST.CUSTOM_STATUS_TYPES.NEVER;
+        case false:
+            return CONST.CUSTOM_STATUS_TYPES.AFTER_TODAY;
+        default:
+            return CONST.CUSTOM_STATUS_TYPES.CUSTOM;
+    }
+}
+
 function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const localize = useLocalize();
     const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
     const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
     const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
-
-    const [draftPeriod, setDraftPeriod] = useState((clearAfter && !draftClearAfter) || draftClearAfter ? CONST.CUSTOM_STATUS_TYPES.CUSTOM : CONST.CUSTOM_STATUS_TYPES.AFTER_TODAY);
-
+    const [draftPeriod, setDraftPeriod] = useState(getDateBasedFromType(clearAfter || draftClearAfter));
     const localesToThemes = useMemo(
         () =>
             _.map(CONST.CUSTOM_STATUS_TYPES, (value, key) => ({
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index c80ac2912353..88c40bd023d9 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -2,7 +2,6 @@ import React, {useMemo, useCallback, useEffect} from 'react';
 import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
-import moment from 'moment';
 import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../../../../components/withCurrentUserPersonalDetails';
 import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription';
 import StaticHeaderPageLayout from '../../../../components/StaticHeaderPageLayout';
@@ -17,10 +16,11 @@ import MobileBackgroundImage from '../../../../../assets/images/money-stack.svg'
 import themeColors from '../../../../styles/themes/default';
 import useLocalize from '../../../../hooks/useLocalize';
 import styles from '../../../../styles/styles';
+import DateUtils from '../../../../libs/DateUtils';
 import compose from '../../../../libs/compose';
 import ONYXKEYS from '../../../../ONYXKEYS';
 import ROUTES from '../../../../ROUTES';
-import DateUtils from '../../../../libs/DateUtils';
+import CONST from '../../../../CONST';
 
 const propTypes = {
     ...withCurrentUserPersonalDetailsPropTypes,
@@ -37,22 +37,39 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
     const defaultEmoji = draftEmojiCode || currentUserEmojiCode;
     const defaultText = draftEmojiCode ? draftText : currentUserStatusText;
-    const customStatus = draftEmojiCode ? `${draftEmojiCode} ${draftText}` : `${currentUserEmojiCode || ''} ${currentUserStatusText || ''}`;
+    const areAllValuesEmpty = !draftEmojiCode && !draftText && !currentUserEmojiCode && !currentUserStatusText;
+    const statusEmojiWithMessage = draftEmojiCode ? `${draftEmojiCode} ${draftText}` : `${currentUserEmojiCode || ''} ${currentUserStatusText || ''}`;
+    const customStatus = areAllValuesEmpty ? '' : statusEmojiWithMessage;
     const hasDraftStatus =
         !!draftEmojiCode || !!draftText || ((!!draftEmojiCode || !!currentUserEmojiCode) && !!draftClearAfter && !DateUtils.areDatesIdentical(draftClearAfter, currentUserClearAfter));
-    const customClearAfter = DateUtils.formatDateTo12Hour(draftClearAfter || currentUserClearAfter);
+    const customClearAfter = useMemo(() => {
+        const dataToShow = draftClearAfter || currentUserClearAfter;
+        return DateUtils.getDateForTitleBasedFromType(dataToShow);
+    }, [draftClearAfter, currentUserClearAfter]);
 
     const updateStatus = useCallback(() => {
-        const endOfDay = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss');
-        User.updateCustomStatus({text: defaultText, emojiCode: defaultEmoji, clearAfter: draftClearAfter || endOfDay || currentUserClearAfter});
+        let clearAfter = '';
+        if (draftClearAfter !== CONST.CUSTOM_STATUS_TYPES.NEVER) {
+            clearAfter = draftClearAfter || currentUserClearAfter;
+        }
+        User.updateCustomStatus({text: defaultText, emojiCode: defaultEmoji, clearAfter});
 
         User.clearDraftCustomStatus();
         Navigation.goBack(ROUTES.SETTINGS_PROFILE);
     }, [defaultText, defaultEmoji, currentUserClearAfter, draftClearAfter]);
 
+    useEffect(() => {
+        if (currentUserEmojiCode || currentUserClearAfter || draftClearAfter) return
+        User.updateDraftCustomStatus({clearAfter: DateUtils.getEndOfToday()});
+    }, []);
     const clearStatus = () => {
         User.clearCustomStatus();
-        User.clearDraftCustomStatus();
+        User.updateDraftCustomStatus({
+            text: '',
+            emojiCode: '',
+            clearAfter: DateUtils.getEndOfToday(),
+            customDateTemporary: '',
+        });
     };
 
     const footerComponent = useMemo(

From e3fa10a82ad4c7a77cf974d9e056727ea670d960 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 24 Aug 2023 16:59:20 +0200
Subject: [PATCH 028/118] clean

---
 .../settings/Profile/CustomStatus/CustomClearAfterPage.js  | 4 ++--
 src/pages/settings/Profile/CustomStatus/SetTimePage.js     | 4 ++--
 .../settings/Profile/CustomStatus/StatusClearAfterPage.js  | 7 +++++--
 src/pages/settings/Profile/CustomStatus/StatusPage.js      | 4 +++-
 src/pages/settings/Profile/CustomStatus/StatusSetPage.js   | 5 ++++-
 5 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index 75cdcd9d89d0..0b56a073faf5 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -47,7 +47,7 @@ function CustomClearAfterPage({translate, customStatus, personalDetails}) {
     return (
         <ScreenWrapper includeSafeAreaPaddingBottom={false}>
             <HeaderWithBackButton
-                title={translate('common.dob')}
+                title={translate('statusPage.date')}
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
             />
             <Form
@@ -60,7 +60,7 @@ function CustomClearAfterPage({translate, customStatus, personalDetails}) {
             >
                 <NewDatePicker
                     inputID="dob"
-                    label={translate('common.date')}
+                    label={translate('statusPage.date')}
                     defaultValue={defaultValue}
                     minDate={moment().toDate()}
                 />
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 9153f75d316a..3950e91dc6fa 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -53,9 +53,9 @@ function SetTimePage({translate, privatePersonalDetails, customStatus, currentUs
     }
 
     return (
-        <ScreenWrapper includeSafeAreaPaddingBottom={false}>
+        <ScreenWrapper>
             <HeaderWithBackButton
-                title={translate('common.dob')}
+                title={translate('statusPage.time')}
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
             />
             <TimePicker
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index a41178ec5efd..35a8af8823bb 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -107,7 +107,10 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const customStatusTime = DateUtils.extractTime12Hour(customDateTemporary || draftClearAfter || clearAfter);
 
     return (
-        <ScreenWrapper>
+        <ScreenWrapper
+            includeSafeAreaPaddingBottom={false}
+            shouldEnableMaxHeight
+        >
             <HeaderWithBackButton
                 title="Status"
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS)}
@@ -119,7 +122,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 onSubmit={onSubmit}
                 style={styles.flexGrow1}
                 scrollContextEnabled={false}
-                submitButtonStyle={styles.mh3}
+                submitButtonStyle={styles.mh5}
             >
                 <View style={styles.flexGrow1}>
                     <SelectionList
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 88c40bd023d9..26d7b18aa523 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -59,9 +59,10 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
     }, [defaultText, defaultEmoji, currentUserClearAfter, draftClearAfter]);
 
     useEffect(() => {
-        if (currentUserEmojiCode || currentUserClearAfter || draftClearAfter) return
+        if (currentUserEmojiCode || currentUserClearAfter || draftClearAfter) return;
         User.updateDraftCustomStatus({clearAfter: DateUtils.getEndOfToday()});
     }, []);
+
     const clearStatus = () => {
         User.clearCustomStatus();
         User.updateDraftCustomStatus({
@@ -79,6 +80,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                     success
                     text={localize.translate('statusPage.save')}
                     onPress={updateStatus}
+                    innerStyles={[styles.mb6]}
                 />
             ) : null,
         [hasDraftStatus, localize, updateStatus],
diff --git a/src/pages/settings/Profile/CustomStatus/StatusSetPage.js b/src/pages/settings/Profile/CustomStatus/StatusSetPage.js
index 7074ce45a7bb..04629f208ce7 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusSetPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusSetPage.js
@@ -47,7 +47,10 @@ function StatusSetPage({draftStatus, currentUserPersonalDetails}) {
     };
 
     return (
-        <ScreenWrapper>
+        <ScreenWrapper
+            includeSafeAreaPaddingBottom={false}
+            shouldEnableMaxHeight
+        >
             <HeaderWithBackButton
                 title={translate('statusPage.status')}
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS)}

From 76dc73fc9d729b0aec48349d3c78c14d1076e43f Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 24 Aug 2023 17:29:59 +0200
Subject: [PATCH 029/118] exhaustive-deps

---
 src/pages/settings/Profile/CustomStatus/StatusPage.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 26d7b18aa523..274f7e436caa 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -61,6 +61,8 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
     useEffect(() => {
         if (currentUserEmojiCode || currentUserClearAfter || draftClearAfter) return;
         User.updateDraftCustomStatus({clearAfter: DateUtils.getEndOfToday()});
+
+        // eslint-disable-next-line react-hooks/exhaustive-deps
     }, []);
 
     const clearStatus = () => {

From dbf4f4e55d9821d0d79cfe6002c01f895dfc08dd Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Sun, 27 Aug 2023 14:45:12 +0200
Subject: [PATCH 030/118] do more comments

---
 src/libs/DateUtils.js                         | 29 +++++++++----------
 .../CustomStatus/StatusClearAfterPage.js      | 10 +++----
 2 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index a6e865666c66..0e8b65bbe6c9 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -292,25 +292,28 @@ function getDateStringFromISOTimestamp(isoTimestamp) {
 }
 
 /**
- * @returns {string} example: 2023-05-16
+ * @returns {string} example: 2023-05-16 05:34:14
  */
 function getThirtyMinutesFromNow() {
     return moment().add(30, 'minutes').format('YYYY-MM-DD HH:mm:ss');
 }
 
+/**
+ * @returns {string} example: 2023-05-16 05:34:14
+ */
 function getOneHourFromNow() {
     return moment().add(1, 'hours').format('YYYY-MM-DD HH:mm:ss');
 }
 
 /**
- * @returns {string} example: 2023-05-16
+ * @returns {string} example: 2023-05-16 05:34:14
  */
 function getEndOfToday() {
     return moment().endOf('day').format('YYYY-MM-DD HH:mm:ss');
 }
 
 /**
- * @returns {string} example: 2023-05-16
+ * @returns {string} example: 2023-05-16 05:34:14
  */
 function getEndOfWeekFromNow() {
     return moment().add(7, 'days').format('YYYY-MM-DD HH:mm:ss');
@@ -319,7 +322,6 @@ function getEndOfWeekFromNow() {
 /**
  * @param {string} time
  * @returns {string} example: 2023-05-16
- * it's kind of 'newer' date
  */
 function extractDate(time) {
     return moment(time).format('YYYY-MM-DD');
@@ -327,16 +329,14 @@ function extractDate(time) {
 
 /**
  * @param {string} dateTimeString
- * @returns {string} example: 2023-05-16
- * it's kind of 'newer' date
+ * @returns {string} example: 11:10
  */
 function extractTime(dateTimeString) {
     return moment(dateTimeString).format('hh:mm');
 }
 /**
  * @param {string} dateTimeString
- * @returns {string} example: 2023-05-16
- * it's kind of 'newer' date
+ * @returns {string} example: 11:10 PM
  */
 function extractTime12Hour(dateTimeString) {
     return moment(dateTimeString).format('hh:mm A');
@@ -344,8 +344,7 @@ function extractTime12Hour(dateTimeString) {
 
 /**
  * @param {string} dateTimeString
- * @returns {string} example: 2023-05-16
- * it's kind of 'newer' date
+ * @returns {string} example: 2023-05-16 11:10 PM
  */
 function formatDateTo12Hour(dateTimeString) {
     if (!dateTimeString) return '';
@@ -354,9 +353,9 @@ function formatDateTo12Hour(dateTimeString) {
 
 /**
  * @param {string} type - one of the values from CONST.CUSTOM_STATUS_TYPES
- * @returns {string} example: 2023-05-16
+ * @returns {string} example: 2023-05-16 11:10:00 or ''
  */
-function getDateBasedFromType(type) {
+function getDateFromStatusType(type) {
     switch (type) {
         case CONST.CUSTOM_STATUS_TYPES.THIRTY_MINUTES:
             return getThirtyMinutesFromNow();
@@ -377,7 +376,7 @@ function getDateBasedFromType(type) {
  * @param {string} data - one of the values from CONST.CUSTOM_STATUS_TYPES or data in format YYYY-MM-DD HH:mm
  * @returns {string} example: 2023-05-16 11:10 PM or 'Today'
  */
-function getDateForTitleBasedFromType(data) {
+function getLocalizedTimePeriodDescription(data) {
     const {translateLocal} = Localize;
     switch (data) {
         case getEndOfToday():
@@ -513,7 +512,7 @@ const DateUtils = {
     getThirtyMinutesFromNow,
     getEndOfToday,
     getEndOfWeekFromNow,
-    getDateBasedFromType,
+    getDateFromStatusType,
     getOneHourFromNow,
     extractDate,
     extractTime,
@@ -524,7 +523,7 @@ const DateUtils = {
     parseTimeTo12HourFormat,
     areDatesIdentical,
     getTimePeriod,
-    getDateForTitleBasedFromType,
+    getLocalizedTimePeriodDescription,
 };
 
 export default DateUtils;
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 35a8af8823bb..26ac8b2637c5 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -39,7 +39,7 @@ const propTypes = {
  * @param {string} data - one of the values from CONST.CUSTOM_STATUS_TYPES or data in format YYYY-MM-DD HH:mm
  * @returns {string}
  */
-function getDateBasedFromType(data) {
+function getInitialDateBasedFromStatusType(data) {
     switch (data) {
         case DateUtils.getEndOfToday():
             return CONST.CUSTOM_STATUS_TYPES.AFTER_TODAY;
@@ -58,7 +58,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
     const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
     const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
-    const [draftPeriod, setDraftPeriod] = useState(getDateBasedFromType(clearAfter || draftClearAfter));
+    const [draftPeriod, setDraftPeriod] = useState(getInitialDateBasedFromStatusType(clearAfter || draftClearAfter));
     const localesToThemes = useMemo(
         () =>
             _.map(CONST.CUSTOM_STATUS_TYPES, (value, key) => ({
@@ -73,10 +73,10 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const onSubmit = () => {
         let calculatedDraftDate = '';
         if (draftPeriod === CONST.CUSTOM_STATUS_TYPES.CUSTOM) {
-            calculatedDraftDate = customDateTemporary || draftClearAfter;
+            calculatedDraftDate = customDateTemporary;
         } else {
             const selectedRange = _.find(localesToThemes, (item) => item.isSelected);
-            calculatedDraftDate = DateUtils.getDateBasedFromType(selectedRange.value);
+            calculatedDraftDate = DateUtils.getDateFromStatusType(selectedRange.value);
         }
 
         User.updateDraftCustomStatus({clearAfter: calculatedDraftDate, customDateTemporary: calculatedDraftDate});
@@ -87,7 +87,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
         (mode) => {
             if (mode.value === draftPeriod) return;
             User.updateDraftCustomStatus({
-                customDateTemporary: mode.value === CONST.CUSTOM_STATUS_TYPES.CUSTOM ? DateUtils.getOneHourFromNow() : DateUtils.getDateBasedFromType(mode.value),
+                customDateTemporary: mode.value === CONST.CUSTOM_STATUS_TYPES.CUSTOM ? DateUtils.getOneHourFromNow() : DateUtils.getDateFromStatusType(mode.value),
             });
             setDraftPeriod(mode.value);
         },

From a140ac2ecb2286ee7ee6031d4ca1d1780f135023 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 29 Aug 2023 10:22:52 +0200
Subject: [PATCH 031/118] remove getDateForTitleBasedFromType

---
 src/pages/settings/Profile/CustomStatus/StatusPage.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 28b027007f7a..b87f6198f173 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -44,7 +44,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
         !!draftEmojiCode || !!draftText || ((!!draftEmojiCode || !!currentUserEmojiCode) && !!draftClearAfter && !DateUtils.areDatesIdentical(draftClearAfter, currentUserClearAfter));
     const customClearAfter = useMemo(() => {
         const dataToShow = draftClearAfter || currentUserClearAfter;
-        return DateUtils.getDateForTitleBasedFromType(dataToShow);
+        return DateUtils.getLocalizedTimePeriodDescription(dataToShow);
     }, [draftClearAfter, currentUserClearAfter]);
 
     const navigateBackToSettingsPage = useCallback(() => Navigation.goBack(ROUTES.SETTINGS_PROFILE, false, true), []);

From 6eaf9f5a9def3fe2d0fbb9ba6883370c4a2c7e8c Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 30 Aug 2023 17:17:00 +0200
Subject: [PATCH 032/118] add FormHelpMessage for MenuItem

---
 src/components/MenuItem.js |  9 +++++++++
 src/styles/styles.js       | 10 ++++++++++
 2 files changed, 19 insertions(+)

diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js
index 3de423b68272..756f3e177aad 100644
--- a/src/components/MenuItem.js
+++ b/src/components/MenuItem.js
@@ -1,6 +1,7 @@
 import _ from 'underscore';
 import React from 'react';
 import {View} from 'react-native';
+import FormHelpMessage from './FormHelpMessage';
 import Text from './Text';
 import styles from '../styles/styles';
 import themeColors from '../styles/themes/default';
@@ -123,6 +124,7 @@ const MenuItem = React.forwardRef((props, ref) => {
                     onPressOut={ControlSelection.unblock}
                     onSecondaryInteraction={props.onSecondaryInteraction}
                     style={({pressed}) => [
+                        props.errorText ? styles.pb8 : {},
                         props.style,
                         props.containerStyle,
                         !props.interactive && styles.cursorDefault,
@@ -312,6 +314,13 @@ const MenuItem = React.forwardRef((props, ref) => {
                                 )}
                                 {props.shouldShowSelectedState && <SelectCircle isChecked={props.isSelected} />}
                             </View>
+                            {Boolean(props.errorText) && (
+                                <FormHelpMessage
+                                    isError={true}
+                                    message={props.errorText}
+                                    style={[styles.menuItemError]}
+                                />
+                            )}
                         </>
                     )}
                 </PressableWithSecondaryInteraction>
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 1c522874fc31..45bf5707934f 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3918,6 +3918,16 @@ const styles = {
         height: 30,
         width: '100%',
     },
+
+    menuItemError: {
+      position: 'absolute',
+      bottom: -4,
+      left: 20,
+      right: 20,
+      paddingTop: 4,
+      borderTopWidth: 1,
+      borderColor: 'red'
+    }
 };
 
 export default styles;

From 45b070b562d02240a18c9acd74355bf88ec9bcbd Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 30 Aug 2023 17:35:14 +0200
Subject: [PATCH 033/118] add brickRoadIndicator for status page

---
 .../Profile/CustomStatus/StatusPage.js        | 28 ++++++++++++++-----
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index b87f6198f173..64d3365497e2 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -49,15 +49,17 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
     const navigateBackToSettingsPage = useCallback(() => Navigation.goBack(ROUTES.SETTINGS_PROFILE, false, true), []);
     const updateStatus = useCallback(() => {
-        let clearAfter = '';
-        if (draftClearAfter !== CONST.CUSTOM_STATUS_TYPES.NEVER) {
-            clearAfter = draftClearAfter || currentUserClearAfter;
-        }
-        User.updateCustomStatus({text: defaultText, emojiCode: defaultEmoji, clearAfter});
+        const clearAfterTime = draftClearAfter || currentUserClearAfter;
+        if (DateUtils.hasDateExpired(clearAfterTime)) return;
+        User.updateCustomStatus({
+            text: defaultText,
+            emojiCode: defaultEmoji,
+            clearAfter: clearAfterTime !== CONST.CUSTOM_STATUS_TYPES.NEVER ? clearAfterTime : '',
+        });
 
         User.clearDraftCustomStatus();
         Navigation.goBack(ROUTES.SETTINGS_PROFILE);
-    }, [defaultText, defaultEmoji, currentUserClearAfter, draftClearAfter]);
+    }, [defaultText, defaultEmoji, currentUserClearAfter, draftClearAfter, isValidClearAfterDate]);
 
     useEffect(() => {
         if (currentUserEmojiCode || currentUserClearAfter || draftClearAfter) return;
@@ -86,9 +88,18 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                     innerStyles={[styles.mb6]}
                 />
             ) : null,
-        [hasDraftStatus, localize, updateStatus],
+        [hasDraftStatus, localize, updateStatus, isValidClearAfterDate],
     );
 
+    
+    const isValidClearAfterDate = useMemo(() => {
+      const clearAfterTime = draftClearAfter || currentUserClearAfter;
+      if (clearAfterTime === CONST.CUSTOM_STATUS_TYPES.NEVER) return true;
+      
+      return !DateUtils.hasDateExpired(clearAfterTime);
+    }, [draftClearAfter, currentUserClearAfter]);
+    
+    const brickRoadIndicator = () => isValidClearAfterDate ? null : CONST.BRICK_INDICATOR.ERROR;
     useEffect(() => () => User.clearDraftCustomStatus(), []);
 
     return (
@@ -107,6 +118,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                 title={customStatus}
                 description={localize.translate('statusPage.status')}
                 shouldShowRightIcon
+                containerStyle={styles.pr2}
                 inputID="test"
                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_SET)}
             />
@@ -115,6 +127,8 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                 description={localize.translate('statusPage.clearAfter')}
                 shouldShowRightIcon
                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
+                containerStyle={styles.pr2}
+                brickRoadIndicator={brickRoadIndicator}
             />
 
             {(!!currentUserEmojiCode || !!currentUserStatusText) && (

From 67a83ee08ba6c9307203281a9921964410a099b6 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 30 Aug 2023 17:40:54 +0200
Subject: [PATCH 034/118] add error handling for time picker

---
 src/components/TimePicker.js                  | 37 ++++++++++++-------
 .../Profile/CustomStatus/StatusPage.js        | 13 +++----
 src/styles/styles.js                          |  4 ++
 3 files changed, 33 insertions(+), 21 deletions(-)

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 9afbc2b18fa5..bcb128eeb5f6 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -13,6 +13,7 @@ import CONST from '../CONST';
 import DateUtils from '../libs/DateUtils';
 import Text from './Text';
 import useKeyboardShortcut from '../hooks/useKeyboardShortcut';
+import FormHelpMessage from './FormHelpMessage';
 
 const propTypes = {
     /** Refs forwarded to the TextInputWithCurrencySymbol */
@@ -22,13 +23,14 @@ const propTypes = {
     onSubmitButtonPress: PropTypes.func,
 
     /** Default value for the inputs */
-    defaultValue: PropTypes.string,
+    value: PropTypes.string,
 };
 
 const defaultProps = {
     forwardedRef: null,
     onSubmitButtonPress: () => {},
-    defaultValue: '',
+    onInputChange: () => {},
+    value: '',
 };
 
 const AMOUNT_VIEW_ID = 'amountView';
@@ -80,15 +82,15 @@ function replaceWithZeroAtPosition(originalString, position) {
     }
     return `${originalString.slice(0, position - 1)}0${originalString.slice(position)}`;
 }
-function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
-    const {translate, numberFormat} = useLocalize();
 
-    const [hours, setHours] = useState(DateUtils.parseTimeTo12HourFormat(defaultValue).hour);
-    const [minute, setMinute] = useState(DateUtils.parseTimeTo12HourFormat(defaultValue).minute);
+function TimePicker({forwardedRef, onSubmitButtonPress, value, errorText, onInputChange}) {
+    const {translate, numberFormat} = useLocalize();
+    const [hours, setHours] = useState(DateUtils.parseTimeTo12HourFormat(value).hour);
+    const [minute, setMinute] = useState(DateUtils.parseTimeTo12HourFormat(value).minute);
     const [selectionHour, setSelectionHour] = useState({start: 0, end: 0});
     const [selectionMinute, setSelectionMinute] = useState({start: 2, end: 2}); // we focus it by default so need  to have selection on the end
 
-    const [amPmValue, setAmPmValue] = useState(DateUtils.getTimePeriod(defaultValue));
+    const [amPmValue, setAmPmValue] = useState(DateUtils.getTimePeriod(value));
 
     const hourInputRef = useRef(null);
     const minuteInputRef = useRef(null);
@@ -307,6 +309,12 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
         );
     }, [canUseTouchScreen, updateAmountNumberPad]);
 
+    useEffect(() => {
+        if (!_.isFunction(onInputChange)) return;
+        onInputChange(`${hours}:${minute} ${amPmValue}`);
+    }, [hours, minute, amPmValue]);
+
+
     return (
         <>
             <View style={[styles.flex1, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}>
@@ -360,6 +368,14 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
                         containerStyles={[styles.timePickerHeight100]}
                     />
                 </View>
+                {!!errorText ? (
+                    <FormHelpMessage
+                        isError={!!errorText}
+                        message={errorText}
+                    />
+                ) : (
+                    <View style={styles.formHelperMessage} />
+                )}
                 <View style={styles.timePickerSwitcherContainer}>
                     <Button
                         shouldEnableHapticFeedback
@@ -390,13 +406,6 @@ function TimePicker({forwardedRef, onSubmitButtonPress, defaultValue}) {
                 nativeID={NUM_PAD_CONTAINER_VIEW_ID}
             >
                 {numberPad()}
-                <Button
-                    success
-                    style={[styles.w100, styles.mt5]}
-                    onPress={submitAndNavigateToNextPage}
-                    pressOnEnter
-                    text={translate('common.save')}
-                />
             </View>
         </>
     );
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 64d3365497e2..ece851f84e6b 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -91,15 +91,14 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
         [hasDraftStatus, localize, updateStatus, isValidClearAfterDate],
     );
 
-    
     const isValidClearAfterDate = useMemo(() => {
-      const clearAfterTime = draftClearAfter || currentUserClearAfter;
-      if (clearAfterTime === CONST.CUSTOM_STATUS_TYPES.NEVER) return true;
-      
-      return !DateUtils.hasDateExpired(clearAfterTime);
+        const clearAfterTime = draftClearAfter || currentUserClearAfter;
+        if (clearAfterTime === CONST.CUSTOM_STATUS_TYPES.NEVER) return true;
+
+        return !DateUtils.hasDateExpired(clearAfterTime);
     }, [draftClearAfter, currentUserClearAfter]);
-    
-    const brickRoadIndicator = () => isValidClearAfterDate ? null : CONST.BRICK_INDICATOR.ERROR;
+
+    const brickRoadIndicator = useMemo(() => (isValidClearAfterDate ? null : CONST.BRICK_INDICATOR.ERROR), [isValidClearAfterDate]);
     useEffect(() => () => User.clearDraftCustomStatus(), []);
 
     return (
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 45bf5707934f..76e0e8bc2e27 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3927,6 +3927,10 @@ const styles = {
       paddingTop: 4,
       borderTopWidth: 1,
       borderColor: 'red'
+    },
+
+    formHelperMessage: {
+      height: 32
     }
 };
 

From 793d02acf5a445a43138592a31913d560172b1dc Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 30 Aug 2023 18:02:57 +0200
Subject: [PATCH 035/118] add time validation for StatusClearAfterPage

---
 src/CONST.ts                                  |  3 +
 src/ONYXKEYS.ts                               |  1 +
 src/languages/en.js                           |  1 +
 src/languages/es.js                           |  1 +
 src/libs/DateUtils.js                         | 45 +++++++-------
 src/libs/ValidationUtils.js                   | 60 ++++++++++++++++++-
 .../CustomStatus/CustomClearAfterPage.js      | 19 +++++-
 .../Profile/CustomStatus/SetTimePage.js       | 49 ++++++++++-----
 .../CustomStatus/StatusClearAfterPage.js      | 45 +++++++++++++-
 9 files changed, 186 insertions(+), 38 deletions(-)

diff --git a/src/CONST.ts b/src/CONST.ts
index f227d3efba62..29767b919509 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -2608,6 +2608,9 @@ const CONST = {
         SAASTR: 'SaaStrDemoSetup',
         SBE: 'SbeDemoSetup',
     },
+    BRICK_INDICATOR: {
+      ERROR: 'error'
+    }
 } as const;
 
 export default CONST;
diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index b67124b5e1cd..304c8f546259 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -279,6 +279,7 @@ const ONYXKEYS = {
         SETTINGS_STATUS_CLEAR_AFTER_FORM: 'settingsStatusClearAfterForm',
         SETTINGS_STATUS_SET_CLEAR_AFTER_FORM: 'settingsStatusSetClearAfterForm',
         SETTINGS_STATUS_CLEAR_DATE_FORM: 'settingsStatusClearDateForm',
+        SETTINGS_STATUS_SET_TIME_FORM: 'settingsStatusSetTIMEForm',
     },
 } as const;
 
diff --git a/src/languages/en.js b/src/languages/en.js
index 5d8accf5b2cb..f477069e3e1a 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -106,6 +106,7 @@ export default {
             fieldRequired: 'This field is required.',
             characterLimit: ({limit}) => `Exceeds the maximum length of ${limit} characters`,
             dateInvalid: 'Please select a valid date',
+            timeInvalid: 'Please select a valid time',
             invalidCharacter: 'Invalid character',
         },
         comma: 'comma',
diff --git a/src/languages/es.js b/src/languages/es.js
index f971bab302c0..0e6822cecc9d 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -105,6 +105,7 @@ export default {
             fieldRequired: 'Este campo es obligatorio.',
             characterLimit: ({limit}) => `Supera el límite de ${limit} caracteres`,
             dateInvalid: 'Por favor, selecciona una fecha válida',
+            timeInvalid: 'Por favor, selecciona una hora válida',
             invalidCharacter: 'Carácter invalido',
         },
         comma: 'la coma',
diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index 0e8b65bbe6c9..af2b39508b08 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -430,27 +430,21 @@ function getStatusUntilDate(inputDate) {
  *
  * @returns {string} - Date with updated time in "YYYY-MM-DD HH:mm:ss" format.
  */
-function setTimeOrDefaultToTomorrow(time, date) {
-    const dateToUse = date ? moment(date) : moment().endOf('day');
-
-    // Split the time into hour, minute, and period (AM/PM)
-    const [hour, minute, period] = time.match(/(\d+):(\d+) (\w\w)/).slice(1);
-
-    // Adjust the hour based on the period
-    let adjustedHour = parseInt(hour, 10);
-    if (period === 'PM' && adjustedHour !== 12) {
-        adjustedHour += 12;
-    } else if (period === 'AM' && adjustedHour === 12) {
-        adjustedHour = 0; // For 12 AM, set to 00
-    }
+const combineDateAndTime = (inputTime, inputDateTime) => {
+    // Parse the time from the input
+    const parsedTime = moment(inputTime, 'hh:mm A');
 
-    // Set the hour, minute, and second
-    dateToUse.hour(adjustedHour);
-    dateToUse.minute(minute);
-    dateToUse.second(0); // Reset seconds to zero
+    // Create a moment object from the input date-time (or just date)
+    const parsedDateTime = moment(inputDateTime, inputDateTime.includes(':') ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD');
 
-    return dateToUse.format('YYYY-MM-DD HH:mm:ss');
-}
+    // Set the hour and minute from the time input to the date from the date-time input
+    parsedDateTime.set({
+        hour: parsedTime.get('hour'),
+        minute: parsedTime.get('minute'),
+    });
+
+    return parsedDateTime.format('YYYY-MM-DD HH:mm:ss');
+};
 
 function parseTimeTo12HourFormat(datetime) {
     if (!datetime) {
@@ -490,6 +484,16 @@ function areDatesIdentical(dateParam1, dateParam2) {
     return date1.isSame(date2);
 }
 
+/**
+ * @param {String} dateString
+ * @returns {Boolean}
+ */
+function hasDateExpired(dateString) {
+    const validUntil = moment().add(1, 'minutes');
+    const dateToCheck = moment(dateString);
+    return dateToCheck.isBefore(validUntil);
+}
+
 /**
  * @namespace DateUtils
  */
@@ -519,11 +523,12 @@ const DateUtils = {
     formatDateTo12Hour,
     getStatusUntilDate,
     extractTime12Hour,
-    setTimeOrDefaultToTomorrow,
     parseTimeTo12HourFormat,
     areDatesIdentical,
     getTimePeriod,
     getLocalizedTimePeriodDescription,
+    hasDateExpired,
+    combineDateAndTime,
 };
 
 export default DateUtils;
diff --git a/src/libs/ValidationUtils.js b/src/libs/ValidationUtils.js
index 81b91e2101be..fbf6795c1510 100644
--- a/src/libs/ValidationUtils.js
+++ b/src/libs/ValidationUtils.js
@@ -1,4 +1,4 @@
-import {subYears, addYears, startOfDay, endOfMonth, isAfter, isBefore, isValid, isWithinInterval, isSameDay, format} from 'date-fns';
+import {subYears, addYears, addMinutes, startOfDay, endOfMonth, isAfter, isBefore, isValid, isWithinInterval, isSam, parse, set, format} from 'date-fns';
 import _ from 'underscore';
 import {URL_REGEX_WITH_REQUIRED_PROTOCOL} from 'expensify-common/lib/Url';
 import {parsePhoneNumber} from 'awesome-phonenumber';
@@ -248,6 +248,31 @@ function getAgeRequirementError(date, minimumAge, maximumAge) {
     return ['privatePersonalDetails.error.dateShouldBeAfter', {dateString: format(longAgoDate, CONST.DATE.FNS_FORMAT_STRING)}];
 }
 
+/**
+ * Validate that given date is not expired more than two minutes.
+ *
+ * @param {String} inputDate
+ * @returns {String|Array}
+ */
+function isExpiredData(inputDate) {
+    const currentDate = new Date();
+    const parsedDate = new Date(inputDate + 'T00:00:00'); // set time to 00:00:00 for accurate comparison
+
+    // If input date is not valid, return an error
+    if (!isValid(parsedDate)) {
+        return 'common.error.dateInvalid';
+    }
+
+    // Clear time for currentDate so comparison is based solely on the date
+    currentDate.setHours(0, 0, 0, 0);
+
+    if (parsedDate < currentDate) {
+        return 'common.error.dateInvalid';
+    }
+
+    return '';
+}
+
 /**
  * Similar to backend, checks whether a website has a valid URL or not.
  * http/https/ftp URL scheme required.
@@ -456,6 +481,37 @@ function isValidAccountRoute(accountID) {
     return CONST.REGEX.NUMBER.test(accountID) && accountID > 0;
 }
 
+const isTimeAtLeastOneMinuteInFuture = (inputTime = '', inputDateTime = '') => {
+    if (!inputTime) return false;
+      // Parse the hour and minute from the time input
+      const [hourStr, minuteStr, period] = inputTime.split(/[:\s]+/);
+      let hour = parseInt(hourStr, 10);
+  
+      // Convert 12-hour format to 24-hour format
+      if (period.toUpperCase() === "PM" && hour !== 12) {
+          hour += 12;
+      } else if (period.toUpperCase() === "AM" && hour === 12) {
+          hour = 0;
+      }
+  
+      const minute = parseInt(minuteStr, 10);
+  
+      // Check if the inputDateTime contains a time portion or is just a date
+      const dateTimeFormat = inputDateTime.includes(':') ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd';
+      
+      // Parse the input date and time (or just date) accordingly
+      const parsedInputDateTime = parse(inputDateTime, dateTimeFormat, new Date());
+  
+      // Set the hour and minute from the time input to the date from the date-time input
+      const combinedDate = set(parsedInputDateTime, { hours: hour, minutes: minute });
+  
+      // Get current date and time
+      const now = new Date();
+  
+      // Check if the combinedDate is at least one minute later than the current date and time
+      return isAfter(combinedDate, addMinutes(now, 1));
+};
+
 export {
     meetsMinimumAgeRequirement,
     meetsMaximumAgeRequirement,
@@ -489,4 +545,6 @@ export {
     doesContainReservedWord,
     isNumeric,
     isValidAccountRoute,
+    isExpiredData,
+    isTimeAtLeastOneMinuteInFuture,
 };
diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index 0b56a073faf5..0551486b110f 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -1,3 +1,4 @@
+import { useCallback } from 'react';
 import moment from 'moment';
 import PropTypes from 'prop-types';
 import React from 'react';
@@ -11,6 +12,8 @@ import Form from '../../../../components/Form';
 import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
 import Navigation from '../../../../libs/Navigation/Navigation';
 import * as User from '../../../../libs/actions/User';
+import * as ValidationUtils from '../../../../libs/ValidationUtils';
+import DateUtils from '../../../../libs/DateUtils';
 import compose from '../../../../libs/compose';
 import styles from '../../../../styles/styles';
 import ONYXKEYS from '../../../../ONYXKEYS';
@@ -44,6 +47,19 @@ function CustomClearAfterPage({translate, customStatus, personalDetails}) {
         Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
     };
 
+        const validate = useCallback((values) => {
+          const requiredFields = ['dob'];
+          const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields);
+          const dateError = ValidationUtils.isExpiredData(values.dob);
+  
+          if (values.dob && dateError) {
+              errors.dob = dateError;
+          }
+  
+          return errors;
+      }, []);
+  
+
     return (
         <ScreenWrapper includeSafeAreaPaddingBottom={false}>
             <HeaderWithBackButton
@@ -55,13 +71,14 @@ function CustomClearAfterPage({translate, customStatus, personalDetails}) {
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_DATE_FORM}
                 onSubmit={onSubmit}
                 submitButtonText={translate('common.save')}
+                validate={validate}
                 enabledWhenOffline
                 shouldUseDefaultValue
             >
                 <NewDatePicker
                     inputID="dob"
                     label={translate('statusPage.date')}
-                    defaultValue={defaultValue}
+                    defaultValue={DateUtils.extractDate(defaultValue)}
                     minDate={moment().toDate()}
                 />
             </Form>
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 3950e91dc6fa..fd512c2e9280 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -8,13 +8,17 @@ import withLocalize, {withLocalizePropTypes} from '../../../../components/withLo
 import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
 import ScreenWrapper from '../../../../components/ScreenWrapper';
 import TimePicker from '../../../../components/TimePicker';
+import Form from '../../../../components/Form';
 import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
+import useLocalize from '../../../../hooks/useLocalize';
 import Navigation from '../../../../libs/Navigation/Navigation';
 import * as User from '../../../../libs/actions/User';
 import DateUtils from '../../../../libs/DateUtils';
+import * as ValidationUtils from '../../../../libs/ValidationUtils';
 import compose from '../../../../libs/compose';
 import ONYXKEYS from '../../../../ONYXKEYS';
 import ROUTES from '../../../../ROUTES';
+import styles from '../../../../styles/styles';
 
 const propTypes = {
     /** User's private personal details */
@@ -33,36 +37,51 @@ const defaultProps = {
 
 function SetTimePage({translate, privatePersonalDetails, customStatus, currentUserPersonalDetails}) {
     usePrivatePersonalDetails();
-
+    const localize = useLocalize();
     const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
     const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
     const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
 
-    const onSubmitButtonPress = useCallback(
-        (time, amPmValue) => {
-            const timeToUse = DateUtils.setTimeOrDefaultToTomorrow(`${time} ${amPmValue}`, customDateTemporary);
+    const onSubmit = ({timePicker}, amPmValue) => {
+        const timeToUse = DateUtils.combineDateAndTime(`${timePicker} ${amPmValue}`, customDateTemporary);
 
-            User.updateDraftCustomStatus({customDateTemporary: timeToUse});
-            Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
-        },
-        [customDateTemporary],
-    );
+        User.updateDraftCustomStatus({customDateTemporary: timeToUse});
+        Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
+    };
+    const validate = (v) => {
+        const error = {};
+
+        if (!ValidationUtils.isTimeAtLeastOneMinuteInFuture(v.timePicker, customDateTemporary || draftClearAfter || clearAfter)) {
+            error.timePicker = localize.translate('common.error.timeInvalid');
+        }
+
+        return error;
+    };
 
     if (lodashGet(privatePersonalDetails, 'isLoading', true)) {
         return <FullscreenLoadingIndicator />;
     }
 
     return (
-        <ScreenWrapper>
+        <ScreenWrapper includeSafeAreaPaddingBottom={false}>
             <HeaderWithBackButton
                 title={translate('statusPage.time')}
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
             />
-            <TimePicker
-                inputID="timePicker"
-                defaultValue={customDateTemporary || draftClearAfter || clearAfter}
-                onSubmitButtonPress={onSubmitButtonPress}
-            />
+            <Form
+                style={[styles.flexGrow1, styles.ph5]}
+                formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_TIME_FORM}
+                onSubmit={onSubmit}
+                submitButtonText={'SAVE'}
+                validate={validate}
+                enabledWhenOffline
+                shouldUseDefaultValue
+            >
+                <TimePicker
+                    inputID="timePicker"
+                    defaultValue={customDateTemporary || draftClearAfter || clearAfter}
+                />
+            </Form>
         </ScreenWrapper>
     );
 }
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 26ac8b2637c5..1380f5defc4b 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -4,6 +4,7 @@ import _ from 'lodash';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
 import PropTypes from 'prop-types';
+import moment from 'moment';
 import ScreenWrapper from '../../../../components/ScreenWrapper';
 import Form from '../../../../components/Form';
 import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
@@ -53,6 +54,42 @@ function getInitialDateBasedFromStatusType(data) {
     }
 }
 
+const useValidateCustomDate = (data) => {
+    const localize = useLocalize();
+    const [customDateError, setCustomDateError] = useState('');
+    const [customTimeError, setCustomTimeError] = useState('');
+
+    const validate = () => {
+        const inputData = moment(data, 'YYYY-MM-DD HH:mm:ss');
+        const currentDate = moment().startOf('day');
+        const currentDateTimePlus2 = moment().add(1, 'minutes');
+
+        // Date validation
+        if (inputData.isBefore(currentDate)) {
+            setCustomDateError(localize.translate('common.error.dateInvalid'));
+        } else {
+            setCustomDateError('');
+        }
+
+        // Time validation
+        if (inputData.isBefore(currentDateTimePlus2)) {
+            setCustomTimeError(localize.translate('common.error.timeInvalid'));
+        } else {
+            setCustomTimeError('');
+        }
+    };
+
+    useEffect(() => {
+        validate();
+    }, [data]);
+
+    const triggerValidation = () => {
+        validate();
+    };
+
+    return {customDateError, customTimeError, triggerValidation};
+};
+
 function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const localize = useLocalize();
     const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
@@ -70,15 +107,19 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
         [draftPeriod, localize],
     );
 
+    const {customDateError, customTimeError, triggerValidation} = useValidateCustomDate(customDateTemporary);
+
     const onSubmit = () => {
+        triggerValidation();
+        if (customDateError || customTimeError) return;
         let calculatedDraftDate = '';
         if (draftPeriod === CONST.CUSTOM_STATUS_TYPES.CUSTOM) {
+            // calculatedDraftDate = customDateTemporary || draftClearAfter;
             calculatedDraftDate = customDateTemporary;
         } else {
             const selectedRange = _.find(localesToThemes, (item) => item.isSelected);
             calculatedDraftDate = DateUtils.getDateFromStatusType(selectedRange.value);
         }
-
         User.updateDraftCustomStatus({clearAfter: calculatedDraftDate, customDateTemporary: calculatedDraftDate});
         Navigation.goBack(ROUTES.SETTINGS_STATUS);
     };
@@ -142,6 +183,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                                 shouldShowRightIcon
                                 containerStyle={styles.pr2}
                                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_CUSTOM)}
+                                errorText={customDateError}
                             />
                             <MenuItemWithTopDescription
                                 title={customStatusTime}
@@ -149,6 +191,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                                 shouldShowRightIcon
                                 containerStyle={styles.pr2}
                                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_TIME)}
+                                errorText={customTimeError}
                             />
                         </>
                     )}

From 3395f1b409a8924b264c4c30ce85776f031d4579 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 31 Aug 2023 11:26:48 +0200
Subject: [PATCH 036/118] add submitButtonContainerStyle

---
 src/components/Form.js                        |  2 +-
 src/components/ScreenWrapper/index.js         |  2 +-
 src/components/StaticHeaderPageLayout.js      |  4 ++-
 src/components/TimePicker.js                  |  2 +-
 .../CustomStatus/CustomClearAfterPage.js      | 33 ++++++++-----------
 .../Profile/CustomStatus/SetTimePage.js       | 13 +++++---
 .../CustomStatus/StatusClearAfterPage.js      |  4 +--
 7 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/src/components/Form.js b/src/components/Form.js
index 33ea23ec6366..f61c2a404418 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -398,7 +398,7 @@ function Form(props) {
                                 focusInput.focus();
                             }
                         }}
-                        containerStyles={[styles.mh0, styles.mt5, styles.flex1]}
+                        containerStyles={[styles.mh0, styles.mt5, styles.flex1, props.submitButtonContainerStyle]}
                         enabledWhenOffline={props.enabledWhenOffline}
                         isSubmitActionDangerous={props.isSubmitActionDangerous}
                         buttonStyle={props.submitButtonStyle}
diff --git a/src/components/ScreenWrapper/index.js b/src/components/ScreenWrapper/index.js
index ebdd79f586e1..1a3b79d3f03a 100644
--- a/src/components/ScreenWrapper/index.js
+++ b/src/components/ScreenWrapper/index.js
@@ -106,7 +106,7 @@ class ScreenWrapper extends React.Component {
 
                     return (
                         <View
-                            style={styles.flex1}
+                            style={[styles.flex1, this.props.containerStyle]}
                             // eslint-disable-next-line react/jsx-props-no-spreading
                             {...(this.props.environment === CONST.ENVIRONMENT.DEV ? this.panResponder.panHandlers : {})}
                         >
diff --git a/src/components/StaticHeaderPageLayout.js b/src/components/StaticHeaderPageLayout.js
index f97e42329942..72299171c637 100644
--- a/src/components/StaticHeaderPageLayout.js
+++ b/src/components/StaticHeaderPageLayout.js
@@ -10,6 +10,7 @@ import themeColors from '../styles/themes/default';
 import * as StyleUtils from '../styles/StyleUtils';
 import useWindowDimensions from '../hooks/useWindowDimensions';
 import FixedFooter from './FixedFooter';
+import useNetwork from '../hooks/useNetwork';
 
 const propTypes = {
     ...headerWithBackButtonPropTypes,
@@ -31,6 +32,7 @@ const defaultProps = {
 
 function StaticHeaderPageLayout({backgroundColor, children, image: Image, footer, imageContainerStyle, style, ...propsToPassToHeader}) {
     const {windowHeight} = useWindowDimensions();
+    const {isOffline} = useNetwork();
 
     const {titleColor, iconFill} = useMemo(() => {
         const isColorfulBackground = backgroundColor !== themeColors.appBG;
@@ -55,7 +57,7 @@ function StaticHeaderPageLayout({backgroundColor, children, image: Image, footer
                         titleColor={titleColor}
                         iconFill={iconFill}
                     />
-                    <View style={[styles.flex1, StyleUtils.getBackgroundColorStyle(themeColors.appBG)]}>
+                    <View style={[styles.flex1, StyleUtils.getBackgroundColorStyle(themeColors.appBG), !isOffline ? safeAreaPaddingBottomStyle : {}]}>
                         <ScrollView
                             contentContainerStyle={[safeAreaPaddingBottomStyle, style]}
                             showsVerticalScrollIndicator={false}
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index bcb128eeb5f6..d95669229750 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -314,7 +314,6 @@ function TimePicker({forwardedRef, onSubmitButtonPress, value, errorText, onInpu
         onInputChange(`${hours}:${minute} ${amPmValue}`);
     }, [hours, minute, amPmValue]);
 
-
     return (
         <>
             <View style={[styles.flex1, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}>
@@ -372,6 +371,7 @@ function TimePicker({forwardedRef, onSubmitButtonPress, value, errorText, onInpu
                     <FormHelpMessage
                         isError={!!errorText}
                         message={errorText}
+                        containerMessageStyle={styles.flex0}
                     />
                 ) : (
                     <View style={styles.formHelperMessage} />
diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index 0551486b110f..dd891366fe8f 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -1,4 +1,4 @@
-import { useCallback } from 'react';
+import {useCallback} from 'react';
 import moment from 'moment';
 import PropTypes from 'prop-types';
 import React from 'react';
@@ -9,7 +9,6 @@ import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
 import NewDatePicker from '../../../../components/NewDatePicker';
 import ScreenWrapper from '../../../../components/ScreenWrapper';
 import Form from '../../../../components/Form';
-import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
 import Navigation from '../../../../libs/Navigation/Navigation';
 import * as User from '../../../../libs/actions/User';
 import * as ValidationUtils from '../../../../libs/ValidationUtils';
@@ -36,29 +35,25 @@ const defaultProps = {
     },
 };
 
-function CustomClearAfterPage({translate, customStatus, personalDetails}) {
-    usePrivatePersonalDetails();
-    const cleanAfter = lodashGet(personalDetails, 'status.cleanAfter', '');
+function CustomClearAfterPage({translate, customStatus}) {
     const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
-    const defaultValue = cleanAfter || customDateTemporary;
 
     const onSubmit = (v) => {
         User.updateDraftCustomStatus({customDateTemporary: v.dob});
         Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
     };
 
-        const validate = useCallback((values) => {
-          const requiredFields = ['dob'];
-          const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields);
-          const dateError = ValidationUtils.isExpiredData(values.dob);
-  
-          if (values.dob && dateError) {
-              errors.dob = dateError;
-          }
-  
-          return errors;
-      }, []);
-  
+    const validate = useCallback((values) => {
+        const requiredFields = ['dob'];
+        const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields);
+        const dateError = ValidationUtils.isExpiredData(values.dob);
+
+        if (values.dob && dateError) {
+            errors.dob = dateError;
+        }
+
+        return errors;
+    }, []);
 
     return (
         <ScreenWrapper includeSafeAreaPaddingBottom={false}>
@@ -78,7 +73,7 @@ function CustomClearAfterPage({translate, customStatus, personalDetails}) {
                 <NewDatePicker
                     inputID="dob"
                     label={translate('statusPage.date')}
-                    defaultValue={DateUtils.extractDate(defaultValue)}
+                    defaultValue={DateUtils.extractDate(customDateTemporary)}
                     minDate={moment().toDate()}
                 />
             </Form>
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index fd512c2e9280..b8b4d6f680d1 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -1,5 +1,6 @@
 import PropTypes from 'prop-types';
 import React, {useCallback} from 'react';
+import {View } from 'react-native';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
 import withCurrentUserPersonalDetails from '../../../../components/withCurrentUserPersonalDetails';
@@ -51,7 +52,7 @@ function SetTimePage({translate, privatePersonalDetails, customStatus, currentUs
     const validate = (v) => {
         const error = {};
 
-        if (!ValidationUtils.isTimeAtLeastOneMinuteInFuture(v.timePicker, customDateTemporary || draftClearAfter || clearAfter)) {
+        if (!ValidationUtils.isTimeAtLeastOneMinuteInFuture(v.timePicker, customDateTemporary)) {
             error.timePicker = localize.translate('common.error.timeInvalid');
         }
 
@@ -61,7 +62,6 @@ function SetTimePage({translate, privatePersonalDetails, customStatus, currentUs
     if (lodashGet(privatePersonalDetails, 'isLoading', true)) {
         return <FullscreenLoadingIndicator />;
     }
-
     return (
         <ScreenWrapper includeSafeAreaPaddingBottom={false}>
             <HeaderWithBackButton
@@ -69,18 +69,21 @@ function SetTimePage({translate, privatePersonalDetails, customStatus, currentUs
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
             />
             <Form
-                style={[styles.flexGrow1, styles.ph5]}
+                style={[styles.flexGrow1]}
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_TIME_FORM}
                 onSubmit={onSubmit}
-                submitButtonText={'SAVE'}
+                submitButtonText={translate('common.save')}
+                submitButtonContainerStyle={[styles.mt0, styles.flex0, styles.mh4]}
                 validate={validate}
                 enabledWhenOffline
                 shouldUseDefaultValue
             >
+            <View style={styles.flex1}>
                 <TimePicker
                     inputID="timePicker"
-                    defaultValue={customDateTemporary || draftClearAfter || clearAfter}
+                    defaultValue={customDateTemporary}
                 />
+            </View>
             </Form>
         </ScreenWrapper>
     );
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 1380f5defc4b..113cb465fb09 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -144,8 +144,8 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
         // eslint-disable-next-line react-hooks/exhaustive-deps
     }, []);
 
-    const customStatusDate = DateUtils.extractDate(customDateTemporary || draftClearAfter || clearAfter);
-    const customStatusTime = DateUtils.extractTime12Hour(customDateTemporary || draftClearAfter || clearAfter);
+    const customStatusDate = DateUtils.extractDate(customDateTemporary);
+    const customStatusTime = DateUtils.extractTime12Hour(customDateTemporary);
 
     return (
         <ScreenWrapper

From 8c628699dd7d08285d3fd31f446151e2ecdf67fb Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 31 Aug 2023 11:55:01 +0200
Subject: [PATCH 037/118] add containerMessageStyle for FormHelpMessage

---
 src/components/FormHelpMessage.js                     | 8 ++++++--
 src/pages/settings/Profile/CustomStatus/StatusPage.js | 1 -
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/components/FormHelpMessage.js b/src/components/FormHelpMessage.js
index df8befe5af30..fe8ae10e1da4 100644
--- a/src/components/FormHelpMessage.js
+++ b/src/components/FormHelpMessage.js
@@ -22,6 +22,9 @@ const propTypes = {
 
     /** Container style props */
     style: stylePropTypes,
+
+    /** Container text style props */
+    containerMessageStyle: stylePropTypes
 };
 
 const defaultProps = {
@@ -29,6 +32,7 @@ const defaultProps = {
     children: null,
     isError: true,
     style: [],
+    containerMessageStyle: {}
 };
 
 function FormHelpMessage(props) {
@@ -38,14 +42,14 @@ function FormHelpMessage(props) {
 
     const translatedMessage = Localize.translateIfPhraseKey(props.message);
     return (
-        <View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2, styles.mb1, ...props.style]}>
+        <View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2, styles.mb1, ...props.style,  styles.justifyContentCenter]}>
             {props.isError && (
                 <Icon
                     src={Expensicons.DotIndicator}
                     fill={colors.red}
                 />
             )}
-            <View style={[styles.flex1, props.isError && styles.ml2]}>
+            <View style={[styles.flex1, props.isError && styles.ml2, props.containerMessageStyle]}>
                 {props.children || <Text style={[props.isError ? styles.formError : styles.formHelp, styles.mb0]}>{translatedMessage}</Text>}
             </View>
         </View>
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index ece851f84e6b..d09ffaa1b042 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -85,7 +85,6 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                     success
                     text={localize.translate('statusPage.save')}
                     onPress={updateStatus}
-                    innerStyles={[styles.mb6]}
                 />
             ) : null,
         [hasDraftStatus, localize, updateStatus, isValidClearAfterDate],

From 4ec08efa40d65f9d1c0a44f9b4a73a2d0d19cce8 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 31 Aug 2023 14:25:14 +0200
Subject: [PATCH 038/118] lint

---
 src/CONST.ts                                  |  4 +-
 src/components/AmountTextInput.js             |  3 -
 src/components/Button/index.js                |  4 --
 src/components/Form.js                        |  6 +-
 src/components/FormHelpMessage.js             |  6 +-
 src/components/MenuItem.js                    |  2 +-
 src/components/TimePicker.js                  | 30 +++++-----
 src/libs/DateUtils.js                         | 27 +++++----
 src/libs/ValidationUtils.js                   | 58 +++++++++----------
 .../CustomStatus/CustomClearAfterPage.js      |  3 +-
 .../Profile/CustomStatus/SetTimePage.js       | 28 ++++-----
 .../CustomStatus/StatusClearAfterPage.js      |  1 +
 .../Profile/CustomStatus/StatusPage.js        | 18 +++---
 src/styles/styles.js                          | 18 +++---
 14 files changed, 101 insertions(+), 107 deletions(-)

diff --git a/src/CONST.ts b/src/CONST.ts
index 29767b919509..338d69edc93c 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -2609,8 +2609,8 @@ const CONST = {
         SBE: 'SbeDemoSetup',
     },
     BRICK_INDICATOR: {
-      ERROR: 'error'
-    }
+        ERROR: 'error',
+    },
 } as const;
 
 export default CONST;
diff --git a/src/components/AmountTextInput.js b/src/components/AmountTextInput.js
index 19b28121c92a..649ff86ce81b 100644
--- a/src/components/AmountTextInput.js
+++ b/src/components/AmountTextInput.js
@@ -27,9 +27,6 @@ const propTypes = {
     /** Function to call when selection in text input is changed */
     onSelectionChange: PropTypes.func,
 
-    /** Function to call when key is pressed in text input */
-    onKeyPress: PropTypes.func,
-
     /** Style for the input */
     style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
 
diff --git a/src/components/Button/index.js b/src/components/Button/index.js
index a053ddc108ee..eb0f79744a74 100644
--- a/src/components/Button/index.js
+++ b/src/components/Button/index.js
@@ -117,10 +117,6 @@ const propTypes = {
 
     /** Accessibility label for the component */
     accessibilityLabel: PropTypes.string,
-
-    // eslint-disable-next-line react/forbid-prop-types
-    forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({current: PropTypes.object})]),
-    
     /** Whether the long press is disabled */
     isDisabledLongPress: PropTypes.bool,
 
diff --git a/src/components/Form.js b/src/components/Form.js
index f61c2a404418..8e650eaacf84 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -85,6 +85,8 @@ const propTypes = {
     /** Style for the button */
     submitButtonStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
 
+    submitButtonContainerStyles: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
+
     ...withLocalizePropTypes,
 };
 
@@ -103,6 +105,7 @@ const defaultProps = {
     style: [],
     validate: () => ({}),
     submitButtonStyle: {},
+    submitButtonContainerStyles: [],
 };
 
 function Form(props) {
@@ -398,7 +401,7 @@ function Form(props) {
                                 focusInput.focus();
                             }
                         }}
-                        containerStyles={[styles.mh0, styles.mt5, styles.flex1, props.submitButtonContainerStyle]}
+                        containerStyles={[styles.mh0, styles.mt5, styles.flex1, ...props.submitButtonContainerStyles]}
                         enabledWhenOffline={props.enabledWhenOffline}
                         isSubmitActionDangerous={props.isSubmitActionDangerous}
                         buttonStyle={props.submitButtonStyle}
@@ -417,6 +420,7 @@ function Form(props) {
             inputValues,
             submit,
             props.style,
+            props.submitButtonContainerStyles,
             children,
             props.formState,
             props.footerContent,
diff --git a/src/components/FormHelpMessage.js b/src/components/FormHelpMessage.js
index fe8ae10e1da4..b882b5f382a0 100644
--- a/src/components/FormHelpMessage.js
+++ b/src/components/FormHelpMessage.js
@@ -24,7 +24,7 @@ const propTypes = {
     style: stylePropTypes,
 
     /** Container text style props */
-    containerMessageStyle: stylePropTypes
+    containerMessageStyle: stylePropTypes,
 };
 
 const defaultProps = {
@@ -32,7 +32,7 @@ const defaultProps = {
     children: null,
     isError: true,
     style: [],
-    containerMessageStyle: {}
+    containerMessageStyle: {},
 };
 
 function FormHelpMessage(props) {
@@ -42,7 +42,7 @@ function FormHelpMessage(props) {
 
     const translatedMessage = Localize.translateIfPhraseKey(props.message);
     return (
-        <View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2, styles.mb1, ...props.style,  styles.justifyContentCenter]}>
+        <View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2, styles.mb1, ...props.style, styles.justifyContentCenter]}>
             {props.isError && (
                 <Icon
                     src={Expensicons.DotIndicator}
diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js
index 756f3e177aad..fce83034ffcd 100644
--- a/src/components/MenuItem.js
+++ b/src/components/MenuItem.js
@@ -316,7 +316,7 @@ const MenuItem = React.forwardRef((props, ref) => {
                             </View>
                             {Boolean(props.errorText) && (
                                 <FormHelpMessage
-                                    isError={true}
+                                    isError
                                     message={props.errorText}
                                     style={[styles.menuItemError]}
                                 />
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index d95669229750..471e4aa78b58 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -14,21 +14,25 @@ import DateUtils from '../libs/DateUtils';
 import Text from './Text';
 import useKeyboardShortcut from '../hooks/useKeyboardShortcut';
 import FormHelpMessage from './FormHelpMessage';
+import refPropTypes from './refPropTypes';
 
 const propTypes = {
     /** Refs forwarded to the TextInputWithCurrencySymbol */
-    forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({current: PropTypes.instanceOf(React.Component)})]),
-
-    /** Fired when submit button pressed, saves the given amount and navigates to the next page */
-    onSubmitButtonPress: PropTypes.func,
+    forwardedRef: refPropTypes,
 
     /** Default value for the inputs */
     value: PropTypes.string,
+
+    /** Form Error description */
+    errorText: PropTypes.string,
+
+    /** Callback to call when the input changes */
+    onInputChange: PropTypes.func,
 };
 
 const defaultProps = {
     forwardedRef: null,
-    onSubmitButtonPress: () => {},
+    errorText: '',
     onInputChange: () => {},
     value: '',
 };
@@ -83,8 +87,8 @@ function replaceWithZeroAtPosition(originalString, position) {
     return `${originalString.slice(0, position - 1)}0${originalString.slice(position)}`;
 }
 
-function TimePicker({forwardedRef, onSubmitButtonPress, value, errorText, onInputChange}) {
-    const {translate, numberFormat} = useLocalize();
+function TimePicker({forwardedRef, value, errorText, onInputChange}) {
+    const {numberFormat} = useLocalize();
     const [hours, setHours] = useState(DateUtils.parseTimeTo12HourFormat(value).hour);
     const [minute, setMinute] = useState(DateUtils.parseTimeTo12HourFormat(value).minute);
     const [selectionHour, setSelectionHour] = useState({start: 0, end: 0});
@@ -96,14 +100,6 @@ function TimePicker({forwardedRef, onSubmitButtonPress, value, errorText, onInpu
     const minuteInputRef = useRef(null);
     const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen();
 
-    /**
-     * Submit amount and navigate to a proper page
-     *
-     */
-    const submitAndNavigateToNextPage = useCallback(() => {
-        onSubmitButtonPress(`${hours}:${minute}`, amPmValue);
-    }, [hours, minute, onSubmitButtonPress, amPmValue]);
-
     const focusMinuteInputOnFirstCharacter = useCallback(() => {
         minuteInputRef.current.focus();
         setSelectionMinute({start: 0, end: 0});
@@ -310,8 +306,8 @@ function TimePicker({forwardedRef, onSubmitButtonPress, value, errorText, onInpu
     }, [canUseTouchScreen, updateAmountNumberPad]);
 
     useEffect(() => {
-        if (!_.isFunction(onInputChange)) return;
         onInputChange(`${hours}:${minute} ${amPmValue}`);
+        // eslint-disable-next-line react-hooks/exhaustive-deps
     }, [hours, minute, amPmValue]);
 
     return (
@@ -367,7 +363,7 @@ function TimePicker({forwardedRef, onSubmitButtonPress, value, errorText, onInpu
                         containerStyles={[styles.timePickerHeight100]}
                     />
                 </View>
-                {!!errorText ? (
+                {errorText ? (
                     <FormHelpMessage
                         isError={!!errorText}
                         message={errorText}
diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index af2b39508b08..7ac5466f1106 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -425,9 +425,8 @@ function getStatusUntilDate(inputDate) {
 /**
  * Update the hour and minute of a date.
  *
- * @param {string} time - Time in "hh:mm A" format (like "10:55 AM").
- * @param {string} date - Date in "YYYY-MM-DD HH:mm:ss" format.
- *
+ * @param {string} inputTime - Time in "hh:mm A" format (like "10:55 AM").
+ * @param {string} inputDateTime - Date in "YYYY-MM-DD HH:mm:ss" format.
  * @returns {string} - Date with updated time in "YYYY-MM-DD HH:mm:ss" format.
  */
 const combineDateAndTime = (inputTime, inputDateTime) => {
@@ -446,15 +445,20 @@ const combineDateAndTime = (inputTime, inputDateTime) => {
     return parsedDateTime.format('YYYY-MM-DD HH:mm:ss');
 };
 
-function parseTimeTo12HourFormat(datetime) {
-    if (!datetime) {
+/**
+ * @param {String} time
+ * @returns {Object}
+ * @example parseTimeTo12HourFormat('2023-08-29 11:10:00') // {hour: '11', minute: '10', period: 'AM'}
+ */
+function parseTimeTo12HourFormat(time) {
+    if (!time) {
         return {
-            hour: '',
-            minute: '',
-            period: '',
+            hour: '00',
+            minute: '01',
+            period: 'AM',
         };
     }
-    const parsedTime = moment(datetime, 'YYYY-MM-DD HH:mm:ss');
+    const parsedTime = moment(time, 'h:mm A');
 
     return {
         hour: parsedTime.format('hh'), // Hour in 12-hour format
@@ -466,10 +470,11 @@ function parseTimeTo12HourFormat(datetime) {
 /**
  * @param {String} dateStr
  * @returns {String}
- * @example
+ * @example getTimePeriod('11:10 PM') // 'PM'
  */
 function getTimePeriod(dateStr) {
-    return moment(dateStr).format('A');
+    const formattedDateStr = `2023-08-29 ${dateStr}`; // Assuming a random date for formatting
+    return moment(formattedDateStr, 'YYYY-MM-DD h:mm A').format('A');
 }
 
 /**
diff --git a/src/libs/ValidationUtils.js b/src/libs/ValidationUtils.js
index fbf6795c1510..968aaf20d26e 100644
--- a/src/libs/ValidationUtils.js
+++ b/src/libs/ValidationUtils.js
@@ -1,4 +1,4 @@
-import {subYears, addYears, addMinutes, startOfDay, endOfMonth, isAfter, isBefore, isValid, isWithinInterval, isSam, parse, set, format} from 'date-fns';
+import {subYears, addYears, addMinutes, startOfDay, endOfMonth, isAfter, isBefore, isValid, isWithinInterval, isSameDay, parse, set, format} from 'date-fns';
 import _ from 'underscore';
 import {URL_REGEX_WITH_REQUIRED_PROTOCOL} from 'expensify-common/lib/Url';
 import {parsePhoneNumber} from 'awesome-phonenumber';
@@ -256,7 +256,7 @@ function getAgeRequirementError(date, minimumAge, maximumAge) {
  */
 function isExpiredData(inputDate) {
     const currentDate = new Date();
-    const parsedDate = new Date(inputDate + 'T00:00:00'); // set time to 00:00:00 for accurate comparison
+    const parsedDate = new Date(`${inputDate}T00:00:00`); // set time to 00:00:00 for accurate comparison
 
     // If input date is not valid, return an error
     if (!isValid(parsedDate)) {
@@ -483,33 +483,33 @@ function isValidAccountRoute(accountID) {
 
 const isTimeAtLeastOneMinuteInFuture = (inputTime = '', inputDateTime = '') => {
     if (!inputTime) return false;
-      // Parse the hour and minute from the time input
-      const [hourStr, minuteStr, period] = inputTime.split(/[:\s]+/);
-      let hour = parseInt(hourStr, 10);
-  
-      // Convert 12-hour format to 24-hour format
-      if (period.toUpperCase() === "PM" && hour !== 12) {
-          hour += 12;
-      } else if (period.toUpperCase() === "AM" && hour === 12) {
-          hour = 0;
-      }
-  
-      const minute = parseInt(minuteStr, 10);
-  
-      // Check if the inputDateTime contains a time portion or is just a date
-      const dateTimeFormat = inputDateTime.includes(':') ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd';
-      
-      // Parse the input date and time (or just date) accordingly
-      const parsedInputDateTime = parse(inputDateTime, dateTimeFormat, new Date());
-  
-      // Set the hour and minute from the time input to the date from the date-time input
-      const combinedDate = set(parsedInputDateTime, { hours: hour, minutes: minute });
-  
-      // Get current date and time
-      const now = new Date();
-  
-      // Check if the combinedDate is at least one minute later than the current date and time
-      return isAfter(combinedDate, addMinutes(now, 1));
+    // Parse the hour and minute from the time input
+    const [hourStr, minuteStr, period] = inputTime.split(/[:\s]+/);
+    let hour = parseInt(hourStr, 10);
+
+    // Convert 12-hour format to 24-hour format
+    if (period.toUpperCase() === 'PM' && hour !== 12) {
+        hour += 12;
+    } else if (period.toUpperCase() === 'AM' && hour === 12) {
+        hour = 0;
+    }
+
+    const minute = parseInt(minuteStr, 10);
+
+    // Check if the inputDateTime contains a time portion or is just a date
+    const dateTimeFormat = inputDateTime.includes(':') ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd';
+
+    // Parse the input date and time (or just date) accordingly
+    const parsedInputDateTime = parse(inputDateTime, dateTimeFormat, new Date());
+
+    // Set the hour and minute from the time input to the date from the date-time input
+    const combinedDate = set(parsedInputDateTime, {hours: hour, minutes: minute});
+
+    // Get current date and time
+    const now = new Date();
+
+    // Check if the combinedDate is at least one minute later than the current date and time
+    return isAfter(combinedDate, addMinutes(now, 1));
 };
 
 export {
diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index dd891366fe8f..bad9551d2ec9 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -1,7 +1,6 @@
-import {useCallback} from 'react';
+import React, {useCallback} from 'react';
 import moment from 'moment';
 import PropTypes from 'prop-types';
-import React from 'react';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
 import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index b8b4d6f680d1..69ef3b73d054 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -1,9 +1,8 @@
+import React from 'react';
 import PropTypes from 'prop-types';
-import React, {useCallback} from 'react';
-import {View } from 'react-native';
+import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
-import withCurrentUserPersonalDetails from '../../../../components/withCurrentUserPersonalDetails';
 import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator';
 import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
 import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
@@ -36,15 +35,13 @@ const defaultProps = {
     },
 };
 
-function SetTimePage({translate, privatePersonalDetails, customStatus, currentUserPersonalDetails}) {
+function SetTimePage({translate, privatePersonalDetails, customStatus}) {
     usePrivatePersonalDetails();
     const localize = useLocalize();
-    const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
     const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
-    const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
 
-    const onSubmit = ({timePicker}, amPmValue) => {
-        const timeToUse = DateUtils.combineDateAndTime(`${timePicker} ${amPmValue}`, customDateTemporary);
+    const onSubmit = ({timePicker}) => {
+        const timeToUse = DateUtils.combineDateAndTime(timePicker, customDateTemporary);
 
         User.updateDraftCustomStatus({customDateTemporary: timeToUse});
         Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
@@ -73,17 +70,17 @@ function SetTimePage({translate, privatePersonalDetails, customStatus, currentUs
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_TIME_FORM}
                 onSubmit={onSubmit}
                 submitButtonText={translate('common.save')}
-                submitButtonContainerStyle={[styles.mt0, styles.flex0, styles.mh4]}
+                submitButtonContainerStyles={[styles.mt0, styles.flex0, styles.mh4]}
                 validate={validate}
                 enabledWhenOffline
                 shouldUseDefaultValue
             >
-            <View style={styles.flex1}>
-                <TimePicker
-                    inputID="timePicker"
-                    defaultValue={customDateTemporary}
-                />
-            </View>
+                <View style={styles.flex1}>
+                    <TimePicker
+                        inputID="timePicker"
+                        defaultValue={DateUtils.extractTime12Hour(customDateTemporary)}
+                    />
+                </View>
             </Form>
         </ScreenWrapper>
     );
@@ -94,7 +91,6 @@ SetTimePage.defaultProps = defaultProps;
 SetTimePage.displayName = 'SetTimePage';
 
 export default compose(
-    withCurrentUserPersonalDetails,
     withLocalize,
     withOnyx({
         privatePersonalDetails: {
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 113cb465fb09..ab04f706697c 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -81,6 +81,7 @@ const useValidateCustomDate = (data) => {
 
     useEffect(() => {
         validate();
+        // eslint-disable-next-line react-hooks/exhaustive-deps
     }, [data]);
 
     const triggerValidation = () => {
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index d09ffaa1b042..03a37b0b1c8d 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -47,6 +47,13 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
         return DateUtils.getLocalizedTimePeriodDescription(dataToShow);
     }, [draftClearAfter, currentUserClearAfter]);
 
+    const isValidClearAfterDate = useMemo(() => {
+        const clearAfterTime = draftClearAfter || currentUserClearAfter;
+        if (clearAfterTime === CONST.CUSTOM_STATUS_TYPES.NEVER) return true;
+
+        return !DateUtils.hasDateExpired(clearAfterTime);
+    }, [draftClearAfter, currentUserClearAfter]);
+
     const navigateBackToSettingsPage = useCallback(() => Navigation.goBack(ROUTES.SETTINGS_PROFILE, false, true), []);
     const updateStatus = useCallback(() => {
         const clearAfterTime = draftClearAfter || currentUserClearAfter;
@@ -59,7 +66,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
         User.clearDraftCustomStatus();
         Navigation.goBack(ROUTES.SETTINGS_PROFILE);
-    }, [defaultText, defaultEmoji, currentUserClearAfter, draftClearAfter, isValidClearAfterDate]);
+    }, [defaultText, defaultEmoji, currentUserClearAfter, draftClearAfter]);
 
     useEffect(() => {
         if (currentUserEmojiCode || currentUserClearAfter || draftClearAfter) return;
@@ -80,7 +87,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
     const footerComponent = useMemo(
         () =>
-            hasDraftStatus ? (
+            hasDraftStatus && isValidClearAfterDate ? (
                 <Button
                     success
                     text={localize.translate('statusPage.save')}
@@ -90,13 +97,6 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
         [hasDraftStatus, localize, updateStatus, isValidClearAfterDate],
     );
 
-    const isValidClearAfterDate = useMemo(() => {
-        const clearAfterTime = draftClearAfter || currentUserClearAfter;
-        if (clearAfterTime === CONST.CUSTOM_STATUS_TYPES.NEVER) return true;
-
-        return !DateUtils.hasDateExpired(clearAfterTime);
-    }, [draftClearAfter, currentUserClearAfter]);
-
     const brickRoadIndicator = useMemo(() => (isValidClearAfterDate ? null : CONST.BRICK_INDICATOR.ERROR), [isValidClearAfterDate]);
     useEffect(() => () => User.clearDraftCustomStatus(), []);
 
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 76e0e8bc2e27..6752a68cbcda 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3920,18 +3920,18 @@ const styles = {
     },
 
     menuItemError: {
-      position: 'absolute',
-      bottom: -4,
-      left: 20,
-      right: 20,
-      paddingTop: 4,
-      borderTopWidth: 1,
-      borderColor: 'red'
+        position: 'absolute',
+        bottom: -4,
+        left: 20,
+        right: 20,
+        paddingTop: 4,
+        borderTopWidth: 1,
+        borderColor: 'red',
     },
 
     formHelperMessage: {
-      height: 32
-    }
+        height: 32,
+    },
 };
 
 export default styles;

From ddf7b70b5e777f6b71773b207335fad046cffb9e Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 31 Aug 2023 14:41:53 +0200
Subject: [PATCH 039/118] flex reset

---
 src/components/TimePicker.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 471e4aa78b58..80c7f3aeea3b 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -367,7 +367,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                     <FormHelpMessage
                         isError={!!errorText}
                         message={errorText}
-                        containerMessageStyle={styles.flex0}
+                        containerMessageStyle={styles.flexReset}
                     />
                 ) : (
                     <View style={styles.formHelperMessage} />

From 0afb8f12fff4e4e9e0e7dc77d5282345c11d8e96 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 31 Aug 2023 14:47:43 +0200
Subject: [PATCH 040/118] remove duplicates after merge

---
 src/styles/styles.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/styles/styles.js b/src/styles/styles.js
index 7dd4f3014610..50387d45cb19 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -1,7 +1,6 @@
 import {defaultStyles as defaultPickerStyles} from 'react-native-picker-select/src/styles';
 import {StyleSheet} from 'react-native';
 import lodashClamp from 'lodash/clamp';
-import {StyleSheet} from 'react-native';
 import fontFamily from './fontFamily';
 import addOutlineWidth from './addOutlineWidth';
 import themeColors from './themes/default';

From 4742fa90550a3ef77b111ed524de4e758a2c72c9 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 31 Aug 2023 15:00:58 +0200
Subject: [PATCH 041/118] remove error dot and underline

---
 src/components/FormHelpMessage.js                      |  8 ++++++--
 src/components/MenuItem.js                             |  1 +
 .../Profile/CustomStatus/StatusClearAfterPage.js       | 10 ++++++++++
 src/styles/styles.js                                   |  2 --
 4 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/src/components/FormHelpMessage.js b/src/components/FormHelpMessage.js
index b882b5f382a0..91a8e73ea374 100644
--- a/src/components/FormHelpMessage.js
+++ b/src/components/FormHelpMessage.js
@@ -25,12 +25,16 @@ const propTypes = {
 
     /** Container text style props */
     containerMessageStyle: stylePropTypes,
+
+    /** Whether to show dot indicator */
+    withDot: PropTypes.bool,
 };
 
 const defaultProps = {
     message: '',
     children: null,
     isError: true,
+    withDot: true,
     style: [],
     containerMessageStyle: {},
 };
@@ -43,13 +47,13 @@ function FormHelpMessage(props) {
     const translatedMessage = Localize.translateIfPhraseKey(props.message);
     return (
         <View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2, styles.mb1, ...props.style, styles.justifyContentCenter]}>
-            {props.isError && (
+            {props.isError && props.withDot && (
                 <Icon
                     src={Expensicons.DotIndicator}
                     fill={colors.red}
                 />
             )}
-            <View style={[styles.flex1, props.isError && styles.ml2, props.containerMessageStyle]}>
+            <View style={[styles.flex1, props.isError && props.withDot ? styles.ml2 : {}, props.containerMessageStyle]}>
                 {props.children || <Text style={[props.isError ? styles.formError : styles.formHelp, styles.mb0]}>{translatedMessage}</Text>}
             </View>
         </View>
diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js
index fce83034ffcd..cef2f2020f22 100644
--- a/src/components/MenuItem.js
+++ b/src/components/MenuItem.js
@@ -317,6 +317,7 @@ const MenuItem = React.forwardRef((props, ref) => {
                             {Boolean(props.errorText) && (
                                 <FormHelpMessage
                                     isError
+                                    withDot={false}
                                     message={props.errorText}
                                     style={[styles.menuItemError]}
                                 />
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index ab04f706697c..aa6c6271a593 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -110,6 +110,14 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
 
     const {customDateError, customTimeError, triggerValidation} = useValidateCustomDate(customDateTemporary);
 
+    const {brickDateIndicator, brickTimeIndicator} = useMemo(
+        () => ({
+            brickDateIndicator: customDateError ? CONST.BRICK_INDICATOR.ERROR : null,
+            brickTimeIndicator: customTimeError ? CONST.BRICK_INDICATOR.ERROR : null,
+        }),
+        [customTimeError, customDateError],
+    );
+
     const onSubmit = () => {
         triggerValidation();
         if (customDateError || customTimeError) return;
@@ -185,6 +193,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                                 containerStyle={styles.pr2}
                                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_CUSTOM)}
                                 errorText={customDateError}
+                                brickRoadIndicator={brickDateIndicator}
                             />
                             <MenuItemWithTopDescription
                                 title={customStatusTime}
@@ -193,6 +202,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                                 containerStyle={styles.pr2}
                                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_TIME)}
                                 errorText={customTimeError}
+                                brickRoadIndicator={brickTimeIndicator}
                             />
                         </>
                     )}
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 50387d45cb19..7d314cccffed 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3936,8 +3936,6 @@ const styles = {
         left: 20,
         right: 20,
         paddingTop: 4,
-        borderTopWidth: 1,
-        borderColor: 'red',
     },
 
     formHelperMessage: {

From 33bb5246b5e5599feb56443464caa1474cd9c975 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 31 Aug 2023 15:29:57 +0200
Subject: [PATCH 042/118] adjust error styles

---
 src/components/MenuItem.js | 2 +-
 src/styles/styles.js       | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js
index cef2f2020f22..b742b587c823 100644
--- a/src/components/MenuItem.js
+++ b/src/components/MenuItem.js
@@ -124,7 +124,7 @@ const MenuItem = React.forwardRef((props, ref) => {
                     onPressOut={ControlSelection.unblock}
                     onSecondaryInteraction={props.onSecondaryInteraction}
                     style={({pressed}) => [
-                        props.errorText ? styles.pb8 : {},
+                        props.errorText ? styles.pb5 : {},
                         props.style,
                         props.containerStyle,
                         !props.interactive && styles.cursorDefault,
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 7d314cccffed..e6ce58c2b61d 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3935,7 +3935,6 @@ const styles = {
         bottom: -4,
         left: 20,
         right: 20,
-        paddingTop: 4,
     },
 
     formHelperMessage: {

From a0b89d1c480b405e71453aab7268da39e8c344f3 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 31 Aug 2023 20:55:50 +0200
Subject: [PATCH 043/118] update validation

---
 .../Profile/CustomStatus/StatusPage.js        | 33 +++++++++++--------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 03a37b0b1c8d..7f122e4fc93a 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -1,4 +1,4 @@
-import React, {useMemo, useCallback, useEffect} from 'react';
+import React, {useMemo, useCallback, useEffect, useState} from 'react';
 import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
@@ -28,6 +28,7 @@ const propTypes = {
 
 function StatusPage({draftStatus, currentUserPersonalDetails}) {
     const localize = useLocalize();
+    const [brickRoadIndicator, setBrickRoadIndicator] = useState('');
     const currentUserEmojiCode = lodashGet(currentUserPersonalDetails, 'status.emojiCode', '');
     const currentUserStatusText = lodashGet(currentUserPersonalDetails, 'status.text', '');
     const currentUserClearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
@@ -47,7 +48,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
         return DateUtils.getLocalizedTimePeriodDescription(dataToShow);
     }, [draftClearAfter, currentUserClearAfter]);
 
-    const isValidClearAfterDate = useMemo(() => {
+    const isValidClearAfterDate = useCallback(() => {
         const clearAfterTime = draftClearAfter || currentUserClearAfter;
         if (clearAfterTime === CONST.CUSTOM_STATUS_TYPES.NEVER) return true;
 
@@ -57,7 +58,11 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
     const navigateBackToSettingsPage = useCallback(() => Navigation.goBack(ROUTES.SETTINGS_PROFILE, false, true), []);
     const updateStatus = useCallback(() => {
         const clearAfterTime = draftClearAfter || currentUserClearAfter;
-        if (DateUtils.hasDateExpired(clearAfterTime)) return;
+        if (DateUtils.hasDateExpired(clearAfterTime)) {
+            setBrickRoadIndicator(isValidClearAfterDate() ? null : CONST.BRICK_INDICATOR.ERROR);
+            return;
+        }
+
         User.updateCustomStatus({
             text: defaultText,
             emojiCode: defaultEmoji,
@@ -66,14 +71,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
         User.clearDraftCustomStatus();
         Navigation.goBack(ROUTES.SETTINGS_PROFILE);
-    }, [defaultText, defaultEmoji, currentUserClearAfter, draftClearAfter]);
-
-    useEffect(() => {
-        if (currentUserEmojiCode || currentUserClearAfter || draftClearAfter) return;
-        User.updateDraftCustomStatus({clearAfter: DateUtils.getEndOfToday()});
-
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, []);
+    }, [defaultText, defaultEmoji, currentUserClearAfter, draftClearAfter, isValidClearAfterDate]);
 
     const clearStatus = () => {
         User.clearCustomStatus();
@@ -87,7 +85,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
     const footerComponent = useMemo(
         () =>
-            hasDraftStatus && isValidClearAfterDate ? (
+            hasDraftStatus && isValidClearAfterDate() ? (
                 <Button
                     success
                     text={localize.translate('statusPage.save')}
@@ -97,8 +95,15 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
         [hasDraftStatus, localize, updateStatus, isValidClearAfterDate],
     );
 
-    const brickRoadIndicator = useMemo(() => (isValidClearAfterDate ? null : CONST.BRICK_INDICATOR.ERROR), [isValidClearAfterDate]);
-    useEffect(() => () => User.clearDraftCustomStatus(), []);
+    useEffect(() => setBrickRoadIndicator(isValidClearAfterDate() ? null : CONST.BRICK_INDICATOR.ERROR), [isValidClearAfterDate]);
+    useEffect(() => {
+        if (!currentUserEmojiCode && !currentUserClearAfter && !draftClearAfter) {
+            User.updateDraftCustomStatus({clearAfter: DateUtils.getEndOfToday()});
+        }
+
+        return () => User.clearDraftCustomStatus();
+        // eslint-disable-next-line react-hooks/exhaustive-deps
+    }, []);
 
     return (
         <StaticHeaderPageLayout

From fab3f10ad4d5925a6228423cd300bff8a8b1f877 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Fri, 1 Sep 2023 11:05:11 +0200
Subject: [PATCH 044/118] update translation

---
 src/languages/en.js                                           | 3 ++-
 src/languages/es.js                                           | 3 ++-
 src/pages/settings/Profile/CustomStatus/SetTimePage.js        | 2 +-
 .../settings/Profile/CustomStatus/StatusClearAfterPage.js     | 4 ++--
 4 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/languages/en.js b/src/languages/en.js
index c9e942ba73e3..6f2669c5fb03 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -106,7 +106,8 @@ export default {
             fieldRequired: 'This field is required.',
             characterLimit: ({limit}) => `Exceeds the maximum length of ${limit} characters`,
             dateInvalid: 'Please select a valid date',
-            timeInvalid: 'Please select a valid time',
+            invalidDateShouldBeFuture: "It should be today's date or a future date.",
+            invalidTimeShouldBeFuture: 'It should be at least one minute in the future.',
             invalidCharacter: 'Invalid character',
         },
         comma: 'comma',
diff --git a/src/languages/es.js b/src/languages/es.js
index 05619919019b..88faba857d82 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -105,7 +105,8 @@ export default {
             fieldRequired: 'Este campo es obligatorio.',
             characterLimit: ({limit}) => `Supera el límite de ${limit} caracteres`,
             dateInvalid: 'Por favor, selecciona una fecha válida',
-            timeInvalid: 'Por favor, selecciona una hora válida',
+            invalidDateShouldBeFuture: "Debe ser la fecha de hoy o una fecha futura.",
+            invalidTimeShouldBeFuture: "Debe ser al menos un minuto en el futuro.",
             invalidCharacter: 'Carácter invalido',
         },
         comma: 'la coma',
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 69ef3b73d054..52ebb21ab79c 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -50,7 +50,7 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
         const error = {};
 
         if (!ValidationUtils.isTimeAtLeastOneMinuteInFuture(v.timePicker, customDateTemporary)) {
-            error.timePicker = localize.translate('common.error.timeInvalid');
+            error.timePicker = localize.translate('common.error.invalidTimeShouldBeFuture');
         }
 
         return error;
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index aa6c6271a593..15761eccbe42 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -66,14 +66,14 @@ const useValidateCustomDate = (data) => {
 
         // Date validation
         if (inputData.isBefore(currentDate)) {
-            setCustomDateError(localize.translate('common.error.dateInvalid'));
+            setCustomDateError(localize.translate('common.error.invalidDateShouldBeFuture'));
         } else {
             setCustomDateError('');
         }
 
         // Time validation
         if (inputData.isBefore(currentDateTimePlus2)) {
-            setCustomTimeError(localize.translate('common.error.timeInvalid'));
+            setCustomTimeError(localize.translate('common.error.invalidTimeShouldBeFuture'));
         } else {
             setCustomTimeError('');
         }

From 1cb9425b095e4ce7d036c36911fa40630b4c3a2c Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Fri, 1 Sep 2023 19:18:31 +0200
Subject: [PATCH 045/118] tide up the comments for time utils

---
 src/components/BigNumberPad.js                |  6 +-
 src/components/Button/index.js                |  7 ++-
 src/components/Form.js                        |  5 +-
 src/components/FormAlertWithSubmitButton.js   |  6 ++
 src/components/FormHelpMessage.js             |  8 +--
 src/components/MenuItem.js                    |  3 +-
 src/components/TimePicker.js                  | 33 +++++-----
 src/languages/en.js                           |  3 +
 src/languages/es.js                           |  7 ++-
 src/libs/DateUtils.js                         | 62 ++++++++-----------
 src/libs/Permissions.js                       |  2 +-
 src/libs/ValidationUtils.js                   | 14 +++--
 .../CustomStatus/CustomClearAfterPage.js      | 17 +----
 .../Profile/CustomStatus/SetTimePage.js       | 43 +++++--------
 .../CustomStatus/StatusClearAfterPage.js      | 22 ++++---
 src/styles/styles.js                          | 11 +++-
 src/styles/utilities/spacing.js               |  4 ++
 17 files changed, 132 insertions(+), 121 deletions(-)

diff --git a/src/components/BigNumberPad.js b/src/components/BigNumberPad.js
index 661ca2cd07f0..d6b56d00eac3 100644
--- a/src/components/BigNumberPad.js
+++ b/src/components/BigNumberPad.js
@@ -19,7 +19,7 @@ const propTypes = {
     nativeID: PropTypes.string,
 
     /** Whether long press is disabled */
-    isDisabledLongPress: PropTypes.bool,
+    isLongPressDisabled: PropTypes.bool,
 
     ...withLocalizePropTypes,
 };
@@ -27,7 +27,7 @@ const propTypes = {
 const defaultProps = {
     longPressHandlerStateChanged: () => {},
     nativeID: 'numPadView',
-    isDisabledLongPress: false,
+    isLongPressDisabled: false,
 };
 
 const padNumbers = [
@@ -90,7 +90,7 @@ function BigNumberPad(props) {
                                     props.longPressHandlerStateChanged(false);
                                 }}
                                 onMouseDown={(e) => e.preventDefault()}
-                                isDisabledLongPress={props.isDisabledLongPress}
+                                isLongPressDisabled={props.isLongPressDisabled}
                             />
                         );
                     })}
diff --git a/src/components/Button/index.js b/src/components/Button/index.js
index eb0f79744a74..98488d23ca23 100644
--- a/src/components/Button/index.js
+++ b/src/components/Button/index.js
@@ -117,8 +117,9 @@ const propTypes = {
 
     /** Accessibility label for the component */
     accessibilityLabel: PropTypes.string,
+
     /** Whether the long press is disabled */
-    isDisabledLongPress: PropTypes.bool,
+    isLongPressDisabled: PropTypes.bool,
 
     /** A ref to forward the button */
     forwardedRef: refPropTypes,
@@ -157,7 +158,7 @@ const defaultProps = {
     nativeID: '',
     accessibilityLabel: '',
     forwardedRef: undefined,
-    isDisabledLongPress: false,
+    isLongPressDisabled: false,
 };
 
 class Button extends Component {
@@ -272,7 +273,7 @@ class Button extends Component {
                     return this.props.onPress(e);
                 }}
                 onLongPress={(e) => {
-                    if (this.props.isDisabledLongPress) return;
+                    if (this.props.isLongPressDisabled) return;
                     if (this.props.shouldEnableHapticFeedback) {
                         HapticFeedback.longPress();
                     }
diff --git a/src/components/Form.js b/src/components/Form.js
index 8e650eaacf84..0217070f699b 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -18,6 +18,7 @@ import stylePropTypes from '../styles/stylePropTypes';
 import {withNetwork} from './OnyxProvider';
 import networkPropTypes from './networkPropTypes';
 import Visibility from '../libs/Visibility';
+import * as StyleUtils from '../styles/StyleUtils';
 
 const propTypes = {
     /** A unique Onyx key identifying the form */
@@ -404,7 +405,8 @@ function Form(props) {
                         containerStyles={[styles.mh0, styles.mt5, styles.flex1, ...props.submitButtonContainerStyles]}
                         enabledWhenOffline={props.enabledWhenOffline}
                         isSubmitActionDangerous={props.isSubmitActionDangerous}
-                        buttonStyle={props.submitButtonStyle}
+                        buttonStyle={{...StyleUtils.parseStyleAsArray(props.submitButtonStyle)}}
+                        useSmallerSubmitButtonSize={props.useSmallerSubmitButtonSize}
                         disablePressOnEnter
                     />
                 )}
@@ -429,6 +431,7 @@ function Form(props) {
             props.isSubmitButtonVisible,
             props.submitButtonText,
             props.submitButtonStyle,
+            props.useSmallerSubmitButtonSize,
         ],
     );
 
diff --git a/src/components/FormAlertWithSubmitButton.js b/src/components/FormAlertWithSubmitButton.js
index ca9494af236c..f0bd49a98cb0 100644
--- a/src/components/FormAlertWithSubmitButton.js
+++ b/src/components/FormAlertWithSubmitButton.js
@@ -49,6 +49,9 @@ const propTypes = {
 
     /** Style for the button */
     buttonStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
+
+    /** Whether to use a smaller submit button size */
+    useSmallerSubmitButtonSize: PropTypes.bool,
 };
 
 const defaultProps = {
@@ -61,6 +64,7 @@ const defaultProps = {
     enabledWhenOffline: false,
     disablePressOnEnter: false,
     isSubmitActionDangerous: false,
+    useSmallerSubmitButtonSize: false,
     footerContent: null,
     buttonStyle: {},
 };
@@ -85,6 +89,7 @@ function FormAlertWithSubmitButton(props) {
                             text={props.buttonText}
                             style={[buttonMarginStyle, props.buttonStyle]}
                             danger={props.isSubmitActionDangerous}
+                            medium={props.useSmallerSubmitButtonSize}
                         />
                     ) : (
                         <Button
@@ -96,6 +101,7 @@ function FormAlertWithSubmitButton(props) {
                             isDisabled={props.isDisabled}
                             isLoading={props.isLoading}
                             danger={props.isSubmitActionDangerous}
+                            medium={props.useSmallerSubmitButtonSize}
                         />
                     )}
                     {props.footerContent}
diff --git a/src/components/FormHelpMessage.js b/src/components/FormHelpMessage.js
index 91a8e73ea374..13e56f63784a 100644
--- a/src/components/FormHelpMessage.js
+++ b/src/components/FormHelpMessage.js
@@ -27,14 +27,14 @@ const propTypes = {
     containerMessageStyle: stylePropTypes,
 
     /** Whether to show dot indicator */
-    withDot: PropTypes.bool,
+    shouldShowRedDotIndicator: PropTypes.bool,
 };
 
 const defaultProps = {
     message: '',
     children: null,
     isError: true,
-    withDot: true,
+    shouldShowRedDotIndicator: true,
     style: [],
     containerMessageStyle: {},
 };
@@ -47,13 +47,13 @@ function FormHelpMessage(props) {
     const translatedMessage = Localize.translateIfPhraseKey(props.message);
     return (
         <View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2, styles.mb1, ...props.style, styles.justifyContentCenter]}>
-            {props.isError && props.withDot && (
+            {props.isError && props.shouldShowRedDotIndicator && (
                 <Icon
                     src={Expensicons.DotIndicator}
                     fill={colors.red}
                 />
             )}
-            <View style={[styles.flex1, props.isError && props.withDot ? styles.ml2 : {}, props.containerMessageStyle]}>
+            <View style={[styles.flex1, props.isError && props.shouldShowRedDotIndicator ? styles.ml2 : {}, props.containerMessageStyle]}>
                 {props.children || <Text style={[props.isError ? styles.formError : styles.formHelp, styles.mb0]}>{translatedMessage}</Text>}
             </View>
         </View>
diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js
index b742b587c823..b0803b1966bd 100644
--- a/src/components/MenuItem.js
+++ b/src/components/MenuItem.js
@@ -92,6 +92,7 @@ const MenuItem = React.forwardRef((props, ref) => {
             props.interactive && props.disabled ? {...styles.userSelectNone} : undefined,
             styles.ltr,
             isDeleted ? styles.offlineFeedback.deleted : undefined,
+            props.titleTextStyle,
         ],
         props.titleStyle,
     );
@@ -317,7 +318,7 @@ const MenuItem = React.forwardRef((props, ref) => {
                             {Boolean(props.errorText) && (
                                 <FormHelpMessage
                                     isError
-                                    withDot={false}
+                                    shouldShowRedDotIndicator={false}
                                     message={props.errorText}
                                     style={[styles.menuItemError]}
                                 />
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 80c7f3aeea3b..d79a2df6633f 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -2,19 +2,20 @@ import React, {useEffect, useState, useCallback, useRef, useMemo} from 'react';
 import {View} from 'react-native';
 import PropTypes from 'prop-types';
 import _ from 'underscore';
-import styles from '../styles/styles';
 import themeColors from '../styles/themes/default';
+import styles from '../styles/styles';
+import FormHelpMessage from './FormHelpMessage';
+import AmountTextInput from './AmountTextInput';
 import BigNumberPad from './BigNumberPad';
+import refPropTypes from './refPropTypes';
 import Button from './Button';
-import AmountTextInput from './AmountTextInput';
+import Text from './Text';
 import * as DeviceCapabilities from '../libs/DeviceCapabilities';
-import useLocalize from '../hooks/useLocalize';
-import CONST from '../CONST';
 import DateUtils from '../libs/DateUtils';
-import Text from './Text';
+import useWindowDimensions from '../hooks/useWindowDimensions';
 import useKeyboardShortcut from '../hooks/useKeyboardShortcut';
-import FormHelpMessage from './FormHelpMessage';
-import refPropTypes from './refPropTypes';
+import useLocalize from '../hooks/useLocalize';
+import CONST from '../CONST';
 
 const propTypes = {
     /** Refs forwarded to the TextInputWithCurrencySymbol */
@@ -42,7 +43,7 @@ const NUM_PAD_CONTAINER_VIEW_ID = 'numPadContainerView';
 const NUM_PAD_VIEW_ID = 'numPadView';
 
 function formatHour(hourText) {
-    // // If the integer value of hour is greater than 12, return the second digit with a leading 0
+    // If the integer value of hour is greater than 12, return the second digit with a leading 0
 
     // return twoDigitHour;
     const hourNumber = parseInt(hourText, 10);
@@ -89,6 +90,8 @@ function replaceWithZeroAtPosition(originalString, position) {
 
 function TimePicker({forwardedRef, value, errorText, onInputChange}) {
     const {numberFormat} = useLocalize();
+    const {isExtraSmallScreenHeight} = useWindowDimensions();
+    const localize = useLocalize();
     const [hours, setHours] = useState(DateUtils.parseTimeTo12HourFormat(value).hour);
     const [minute, setMinute] = useState(DateUtils.parseTimeTo12HourFormat(value).minute);
     const [selectionHour, setSelectionHour] = useState({start: 0, end: 0});
@@ -311,11 +314,11 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
     }, [hours, minute, amPmValue]);
 
     return (
-        <>
+        <View style={styles.flex1}>
             <View style={[styles.flex1, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}>
                 <View
                     nativeID={AMOUNT_VIEW_ID}
-                    style={[styles.flexRow, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}
+                    style={[styles.flexRow, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter, styles.timeInputsContainer]}
                 >
                     <AmountTextInput
                         formattedAmount={hours}
@@ -376,7 +379,8 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                     <Button
                         shouldEnableHapticFeedback
                         innerStyles={styleForAM}
-                        text="AM"
+                        medium={isExtraSmallScreenHeight}
+                        text={localize.translate('common.am')}
                         onLongPress={() => {}}
                         onPress={() => {
                             setAmPmValue(CONST.TIME_PERIOD.AM);
@@ -387,7 +391,8 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                     <Button
                         shouldEnableHapticFeedback
                         innerStyles={styleForPM}
-                        text="PM"
+                        medium={isExtraSmallScreenHeight}
+                        text={localize.translate('common.pm')}
                         onLongPress={() => {}}
                         onPress={() => {
                             setAmPmValue(CONST.TIME_PERIOD.PM);
@@ -398,12 +403,12 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                 </View>
             </View>
             <View
-                style={[styles.w100, styles.justifyContentEnd, styles.pageWrapper]}
+                style={[styles.pageWrapper, styles.pb0, styles.mb12]}
                 nativeID={NUM_PAD_CONTAINER_VIEW_ID}
             >
                 {numberPad()}
             </View>
-        </>
+        </View>
     );
 }
 
diff --git a/src/languages/en.js b/src/languages/en.js
index ce11e71df8ef..f048390b5bdb 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -165,6 +165,8 @@ export default {
         distance: 'Distance',
         recent: 'Recent',
         all: 'All',
+        am: 'AM',
+        pm: 'PM',
     },
     location: {
         useCurrent: 'Use current location',
@@ -935,6 +937,7 @@ export default {
         date: 'Date',
         time: 'Time',
         clearAfter: 'Clear after',
+        whenClearStatus: 'When should we clear your status?',
     },
     stepCounter: ({step, total, text}) => {
         let result = `Step ${step}`;
diff --git a/src/languages/es.js b/src/languages/es.js
index ca5c4c7bd184..ec017c02f79e 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -105,8 +105,8 @@ export default {
             fieldRequired: 'Este campo es obligatorio.',
             characterLimit: ({limit}) => `Supera el límite de ${limit} caracteres`,
             dateInvalid: 'Por favor, selecciona una fecha válida',
-            invalidDateShouldBeFuture: "Debe ser la fecha de hoy o una fecha futura.",
-            invalidTimeShouldBeFuture: "Debe ser al menos un minuto en el futuro.",
+            invalidDateShouldBeFuture: 'Debe ser la fecha de hoy o una fecha futura.',
+            invalidTimeShouldBeFuture: 'Debe ser al menos un minuto en el futuro.',
             invalidCharacter: 'Carácter invalido',
         },
         comma: 'la coma',
@@ -164,6 +164,8 @@ export default {
         distance: 'Distancia',
         recent: 'Reciente',
         all: 'Todo',
+        am: 'AM',
+        pm: 'PM',
     },
     location: {
         useCurrent: 'Usar ubicación actual',
@@ -954,6 +956,7 @@ export default {
         date: 'Fecha',
         time: 'Hora',
         clearAfter: 'Borrar después',
+        whenClearStatus: "¿Cuándo deberíamos borrar tu estado?",
     },
     stepCounter: ({step, total, text}) => {
         let result = `Paso ${step}`;
diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index 7ac5466f1106..a7575fcbff4b 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -320,20 +320,13 @@ function getEndOfWeekFromNow() {
 }
 
 /**
- * @param {string} time
+ * @param {string} dateTime
  * @returns {string} example: 2023-05-16
  */
-function extractDate(time) {
-    return moment(time).format('YYYY-MM-DD');
+function extractDate(dateTime) {
+    return moment(dateTime).format('YYYY-MM-DD');
 }
 
-/**
- * @param {string} dateTimeString
- * @returns {string} example: 11:10
- */
-function extractTime(dateTimeString) {
-    return moment(dateTimeString).format('hh:mm');
-}
 /**
  * @param {string} dateTimeString
  * @returns {string} example: 11:10 PM
@@ -346,7 +339,7 @@ function extractTime12Hour(dateTimeString) {
  * @param {string} dateTimeString
  * @returns {string} example: 2023-05-16 11:10 PM
  */
-function formatDateTo12Hour(dateTimeString) {
+function formatDateTimeTo12Hour(dateTimeString) {
     if (!dateTimeString) return '';
     return moment(dateTimeString).format('YYYY-MM-DD hh:mm A');
 }
@@ -373,7 +366,7 @@ function getDateFromStatusType(type) {
 }
 
 /**
- * @param {string} data - one of the values from CONST.CUSTOM_STATUS_TYPES or data in format YYYY-MM-DD HH:mm
+ * @param {string} data - either a value from CONST.CUSTOM_STATUS_TYPES or a dateTime string in the format YYYY-MM-DD HH:mm
  * @returns {string} example: 2023-05-16 11:10 PM or 'Today'
  */
 function getLocalizedTimePeriodDescription(data) {
@@ -385,7 +378,7 @@ function getLocalizedTimePeriodDescription(data) {
         case '':
             return translateLocal('statusPage.timePeriods.never');
         default:
-            return formatDateTo12Hour(data);
+            return formatDateTimeTo12Hour(data);
     }
 }
 
@@ -423,15 +416,15 @@ function getStatusUntilDate(inputDate) {
 }
 
 /**
- * Update the hour and minute of a date.
+ * Update the time for a given date.
  *
- * @param {string} inputTime - Time in "hh:mm A" format (like "10:55 AM").
+ * @param {string} updatedTime - Time in "hh:mm A" format (like "10:55 AM").
  * @param {string} inputDateTime - Date in "YYYY-MM-DD HH:mm:ss" format.
  * @returns {string} - Date with updated time in "YYYY-MM-DD HH:mm:ss" format.
  */
-const combineDateAndTime = (inputTime, inputDateTime) => {
+const combineDateAndTime = (updatedTime, inputDateTime) => {
     // Parse the time from the input
-    const parsedTime = moment(inputTime, 'hh:mm A');
+    const parsedTime = moment(updatedTime, 'hh:mm A');
 
     // Create a moment object from the input date-time (or just date)
     const parsedDateTime = moment(inputDateTime, inputDateTime.includes(':') ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD');
@@ -446,19 +439,19 @@ const combineDateAndTime = (inputTime, inputDateTime) => {
 };
 
 /**
- * @param {String} time
+ * @param {String} dateTime // 'YYYY-MM-DD HH:mm:ss'
  * @returns {Object}
  * @example parseTimeTo12HourFormat('2023-08-29 11:10:00') // {hour: '11', minute: '10', period: 'AM'}
  */
-function parseTimeTo12HourFormat(time) {
-    if (!time) {
+function parseTimeTo12HourFormat(dateTime) {
+    if (!dateTime) {
         return {
             hour: '00',
             minute: '01',
             period: 'AM',
         };
     }
-    const parsedTime = moment(time, 'h:mm A');
+    const parsedTime = moment(dateTime, 'h:mm A');
 
     return {
         hour: parsedTime.format('hh'), // Hour in 12-hour format
@@ -468,34 +461,34 @@ function parseTimeTo12HourFormat(time) {
 }
 
 /**
- * @param {String} dateStr
+ * @param {String} timeString
  * @returns {String}
  * @example getTimePeriod('11:10 PM') // 'PM'
  */
-function getTimePeriod(dateStr) {
-    const formattedDateStr = `2023-08-29 ${dateStr}`; // Assuming a random date for formatting
-    return moment(formattedDateStr, 'YYYY-MM-DD h:mm A').format('A');
+function getTimePeriod(timeString) {
+    const formattedDateString = `2023-08-29 ${timeString}`; // Assuming a random date for formatting
+    return moment(formattedDateString, 'YYYY-MM-DD h:mm A').format('A');
 }
 
 /**
- * @param {String} dateParam1
- * @param {String} dateParam2
+ * @param {String} dateTimeStringFirst // YYYY-MM-DD HH:mm:ss
+ * @param {String} dateTimeStringSecond // YYYY-MM-DD HH:mm:ss
  * @returns {Boolean}
  */
-function areDatesIdentical(dateParam1, dateParam2) {
-    const date1 = moment(dateParam1);
-    const date2 = moment(dateParam2);
+function areDatesIdentical(dateTimeStringFirst, dateTimeStringSecond) {
+    const date1 = moment(dateTimeStringFirst);
+    const date2 = moment(dateTimeStringSecond);
 
     return date1.isSame(date2);
 }
 
 /**
- * @param {String} dateString
+ * @param {String} dateTimeString
  * @returns {Boolean}
  */
-function hasDateExpired(dateString) {
+function hasDateExpired(dateTimeString) {
     const validUntil = moment().add(1, 'minutes');
-    const dateToCheck = moment(dateString);
+    const dateToCheck = moment(dateTimeString);
     return dateToCheck.isBefore(validUntil);
 }
 
@@ -524,8 +517,7 @@ const DateUtils = {
     getDateFromStatusType,
     getOneHourFromNow,
     extractDate,
-    extractTime,
-    formatDateTo12Hour,
+    formatDateTimeTo12Hour,
     getStatusUntilDate,
     extractTime12Hour,
     parseTimeTo12HourFormat,
diff --git a/src/libs/Permissions.js b/src/libs/Permissions.js
index 7f52c41ad0fd..0391a6714889 100644
--- a/src/libs/Permissions.js
+++ b/src/libs/Permissions.js
@@ -91,7 +91,7 @@ function canUseScanReceipts(betas) {
  * @returns {Boolean}
  */
 function canUseCustomStatus(betas) {
-    return _.contains(betas, CONST.BETAS.CUSTOM_STATUS) || canUseAllBetas(betas);
+    return '_.contains(betas, CONST.BETAS.CUSTOM_STATUS) || canUseAllBetas(betas)';
 }
 
 /**
diff --git a/src/libs/ValidationUtils.js b/src/libs/ValidationUtils.js
index 968aaf20d26e..40fc438bcbe8 100644
--- a/src/libs/ValidationUtils.js
+++ b/src/libs/ValidationUtils.js
@@ -249,12 +249,12 @@ function getAgeRequirementError(date, minimumAge, maximumAge) {
 }
 
 /**
- * Validate that given date is not expired more than two minutes.
+ * Validate that given date is not in the past.
  *
  * @param {String} inputDate
- * @returns {String|Array}
+ * @returns {String}
  */
-function isExpiredData(inputDate) {
+function getDatePassedError(inputDate) {
     const currentDate = new Date();
     const parsedDate = new Date(`${inputDate}T00:00:00`); // set time to 00:00:00 for accurate comparison
 
@@ -481,6 +481,12 @@ function isValidAccountRoute(accountID) {
     return CONST.REGEX.NUMBER.test(accountID) && accountID > 0;
 }
 
+/**
+ * Checks if the time input is at least one minute in the future.
+ * @param {String} inputTime
+ * @param {String} inputDateTime
+ * @returns {Boolean}
+ * */
 const isTimeAtLeastOneMinuteInFuture = (inputTime = '', inputDateTime = '') => {
     if (!inputTime) return false;
     // Parse the hour and minute from the time input
@@ -545,6 +551,6 @@ export {
     doesContainReservedWord,
     isNumeric,
     isValidAccountRoute,
-    isExpiredData,
+    getDatePassedError,
     isTimeAtLeastOneMinuteInFuture,
 };
diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index bad9551d2ec9..ba71aa65d177 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -1,6 +1,5 @@
 import React, {useCallback} from 'react';
 import moment from 'moment';
-import PropTypes from 'prop-types';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
 import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
@@ -18,22 +17,9 @@ import ONYXKEYS from '../../../../ONYXKEYS';
 import ROUTES from '../../../../ROUTES';
 
 const propTypes = {
-    /* Onyx Props */
-
-    /** User's private personal details */
-    privatePersonalDetails: PropTypes.shape({
-        dob: PropTypes.string,
-    }),
-
     ...withLocalizePropTypes,
 };
 
-const defaultProps = {
-    privatePersonalDetails: {
-        dob: '',
-    },
-};
-
 function CustomClearAfterPage({translate, customStatus}) {
     const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
 
@@ -45,7 +31,7 @@ function CustomClearAfterPage({translate, customStatus}) {
     const validate = useCallback((values) => {
         const requiredFields = ['dob'];
         const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields);
-        const dateError = ValidationUtils.isExpiredData(values.dob);
+        const dateError = ValidationUtils.getDatePassedError(values.dob);
 
         if (values.dob && dateError) {
             errors.dob = dateError;
@@ -81,7 +67,6 @@ function CustomClearAfterPage({translate, customStatus}) {
 }
 
 CustomClearAfterPage.propTypes = propTypes;
-CustomClearAfterPage.defaultProps = defaultProps;
 CustomClearAfterPage.displayName = 'CustomClearAfterPage';
 
 export default compose(
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 52ebb21ab79c..56bf875d1564 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -1,5 +1,4 @@
 import React from 'react';
-import PropTypes from 'prop-types';
 import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
@@ -10,6 +9,7 @@ import ScreenWrapper from '../../../../components/ScreenWrapper';
 import TimePicker from '../../../../components/TimePicker';
 import Form from '../../../../components/Form';
 import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
+import useWindowDimensions from '../../../../hooks/useWindowDimensions';
 import useLocalize from '../../../../hooks/useLocalize';
 import Navigation from '../../../../libs/Navigation/Navigation';
 import * as User from '../../../../libs/actions/User';
@@ -21,22 +21,12 @@ import ROUTES from '../../../../ROUTES';
 import styles from '../../../../styles/styles';
 
 const propTypes = {
-    /** User's private personal details */
-    privatePersonalDetails: PropTypes.shape({
-        dob: PropTypes.string,
-    }),
-
     ...withLocalizePropTypes,
 };
 
-const defaultProps = {
-    privatePersonalDetails: {
-        dob: '',
-    },
-};
-
 function SetTimePage({translate, privatePersonalDetails, customStatus}) {
     usePrivatePersonalDetails();
+    const {isExtraSmallScreenHeight} = useWindowDimensions();
     const localize = useLocalize();
     const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
 
@@ -65,29 +55,30 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
                 title={translate('statusPage.time')}
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
             />
-            <Form
-                style={[styles.flexGrow1]}
-                formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_TIME_FORM}
-                onSubmit={onSubmit}
-                submitButtonText={translate('common.save')}
-                submitButtonContainerStyles={[styles.mt0, styles.flex0, styles.mh4]}
-                validate={validate}
-                enabledWhenOffline
-                shouldUseDefaultValue
-            >
-                <View style={styles.flex1}>
+            <View style={styles.flex1}>
+                <Form
+                    style={[styles.flexGrow1]}
+                    formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_TIME_FORM}
+                    onSubmit={onSubmit}
+                    submitButtonText={translate('common.save')}
+                    submitButtonContainerStyles={[styles.mt0, styles.flex0, styles.mh4]}
+                    validate={validate}
+                    enabledWhenOffline
+                    shouldUseDefaultValue
+                    useSmallerSubmitButtonSize={isExtraSmallScreenHeight}
+                >
                     <TimePicker
                         inputID="timePicker"
                         defaultValue={DateUtils.extractTime12Hour(customDateTemporary)}
+                        style={styles.flexGrow1}
                     />
-                </View>
-            </Form>
+                </Form>
+            </View>
         </ScreenWrapper>
     );
 }
 
 SetTimePage.propTypes = propTypes;
-SetTimePage.defaultProps = defaultProps;
 SetTimePage.displayName = 'SetTimePage';
 
 export default compose(
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 15761eccbe42..04aad6af7742 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -37,10 +37,10 @@ const propTypes = {
 };
 
 /**
- * @param {string} data - one of the values from CONST.CUSTOM_STATUS_TYPES or data in format YYYY-MM-DD HH:mm
+ * @param {string} data -  either a value from CONST.CUSTOM_STATUS_TYPES or a dateTime string in the format YYYY-MM-DD HH:mm
  * @returns {string}
  */
-function getInitialDateBasedFromStatusType(data) {
+function getSelectedStatusType(data) {
     switch (data) {
         case DateUtils.getEndOfToday():
             return CONST.CUSTOM_STATUS_TYPES.AFTER_TODAY;
@@ -96,7 +96,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
     const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
     const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
-    const [draftPeriod, setDraftPeriod] = useState(getInitialDateBasedFromStatusType(clearAfter || draftClearAfter));
+    const [draftPeriod, setDraftPeriod] = useState(getSelectedStatusType(clearAfter || draftClearAfter));
     const localesToThemes = useMemo(
         () =>
             _.map(CONST.CUSTOM_STATUS_TYPES, (value, key) => ({
@@ -110,10 +110,10 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
 
     const {customDateError, customTimeError, triggerValidation} = useValidateCustomDate(customDateTemporary);
 
-    const {brickDateIndicator, brickTimeIndicator} = useMemo(
+    const {redBrickDateIndicator, redBrickTimeIndicator} = useMemo(
         () => ({
-            brickDateIndicator: customDateError ? CONST.BRICK_INDICATOR.ERROR : null,
-            brickTimeIndicator: customTimeError ? CONST.BRICK_INDICATOR.ERROR : null,
+            redBrickDateIndicator: customDateError ? CONST.BRICK_INDICATOR.ERROR : null,
+            redBrickTimeIndicator: customTimeError ? CONST.BRICK_INDICATOR.ERROR : null,
         }),
         [customTimeError, customDateError],
     );
@@ -123,7 +123,6 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
         if (customDateError || customTimeError) return;
         let calculatedDraftDate = '';
         if (draftPeriod === CONST.CUSTOM_STATUS_TYPES.CUSTOM) {
-            // calculatedDraftDate = customDateTemporary || draftClearAfter;
             calculatedDraftDate = customDateTemporary;
         } else {
             const selectedRange = _.find(localesToThemes, (item) => item.isSelected);
@@ -173,8 +172,9 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 style={styles.flexGrow1}
                 scrollContextEnabled={false}
                 submitButtonStyle={styles.mh5}
+                enabledWhenOffline
             >
-                <View style={styles.flexGrow1}>
+                <View>
                     <SelectionList
                         sections={[{data: localesToThemes, indexOffset: 0}]}
                         onSelectRow={updateMode}
@@ -193,7 +193,8 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                                 containerStyle={styles.pr2}
                                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_CUSTOM)}
                                 errorText={customDateError}
-                                brickRoadIndicator={brickDateIndicator}
+                                titleTextStyle={styles.flex1}
+                                brickRoadIndicator={redBrickDateIndicator}
                             />
                             <MenuItemWithTopDescription
                                 title={customStatusTime}
@@ -202,7 +203,8 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                                 containerStyle={styles.pr2}
                                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_TIME)}
                                 errorText={customTimeError}
-                                brickRoadIndicator={brickTimeIndicator}
+                                titleTextStyle={styles.flex1}
+                                brickRoadIndicator={redBrickTimeIndicator}
                             />
                         </>
                     )}
diff --git a/src/styles/styles.js b/src/styles/styles.js
index e6ce58c2b61d..98f9ab193618 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3902,7 +3902,9 @@ const styles = {
 
     timePickerInput: {
         fontSize: 69,
+        maxHeight: 70,
         minWidth: 56,
+        alignSelf: 'center',
     },
     timePickerWidth100: {
         width: 100,
@@ -3912,12 +3914,15 @@ const styles = {
     },
     timePickerSemiDot: {
         fontSize: 69,
+        maxHeight: 70,
+    },
+    timeInputsContainer: {
+        maxHeight: 70,
     },
     timePickerSwitcherContainer: {
         flexDirection: 'row',
         alignItems: 'flex-start',
         justifyContent: 'center',
-        marginTop: 40,
     },
     selectionListRadioSeparator: {
         height: StyleSheet.hairlineWidth,
@@ -3940,6 +3945,10 @@ const styles = {
     formHelperMessage: {
         height: 32,
     },
+
+    timePickerInputExtraSmall: {
+        fontSize: 50,
+    },
 };
 
 export default styles;
diff --git a/src/styles/utilities/spacing.js b/src/styles/utilities/spacing.js
index 47b523d89ac2..9d657d9023a4 100644
--- a/src/styles/utilities/spacing.js
+++ b/src/styles/utilities/spacing.js
@@ -237,6 +237,10 @@ export default {
         marginBottom: 32,
     },
 
+    mb12: {
+        marginBottom: 48,
+    },
+
     mb15: {
         marginBottom: 60,
     },

From e4283bcdf9aba608c596c61c21dc4c8ffeb76b14 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Sun, 3 Sep 2023 17:33:35 +0200
Subject: [PATCH 046/118] add more comments for TimePicker

---
 src/CONST.ts                 |  1 +
 src/components/Form.js       |  2 +-
 src/components/TimePicker.js | 29 +++++++++++++++++++++++++----
 src/languages/es.js          |  2 +-
 src/libs/Permissions.js      |  2 +-
 src/styles/styles.js         |  5 -----
 6 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/src/CONST.ts b/src/CONST.ts
index 261528537c69..cc4afd0287bb 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -2627,6 +2627,7 @@ const CONST = {
     BRICK_INDICATOR: {
         ERROR: 'error',
     },
+    COLON: ':'
 } as const;
 
 export default CONST;
diff --git a/src/components/Form.js b/src/components/Form.js
index 0217070f699b..841d0e607e02 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -405,7 +405,7 @@ function Form(props) {
                         containerStyles={[styles.mh0, styles.mt5, styles.flex1, ...props.submitButtonContainerStyles]}
                         enabledWhenOffline={props.enabledWhenOffline}
                         isSubmitActionDangerous={props.isSubmitActionDangerous}
-                        buttonStyle={{...StyleUtils.parseStyleAsArray(props.submitButtonStyle)}}
+                        buttonStyle={props.submitButtonStyle}
                         useSmallerSubmitButtonSize={props.useSmallerSubmitButtonSize}
                         disablePressOnEnter
                     />
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index d79a2df6633f..4ac620e3442f 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -108,8 +108,11 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
         setSelectionMinute({start: 0, end: 0});
     }, []);
 
+    // This function receive value from hour input and validate it
+    // The valid format is HH(from 00 to 12). If the user input 9, it will be 09. If user try to change 09 to 19 it would skip the first character
     const handleHourChange = (text) => {
         let filteredText;
+        // Remove non-numeric characters and limit to 3 digits. The third digit will appear when input has 01 and you type 2 => 201
         if (selectionHour.start !== selectionHour.end) {
             filteredText = text.replace(/[^0-9]/g, '').slice(0, 2);
         } else {
@@ -117,16 +120,22 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
         }
         let newHour = hours;
         let newSelection = selectionHour.start;
+
+        // Case when user selects and replaces the text.
         if (selectionHour.start !== selectionHour.end) {
+            // If the first digit is <= 1, append 0 at the end.
             if (filteredText.length === 1 && filteredText <= 1) {
                 newHour = `${filteredText}0`;
                 newSelection = 1;
             } else {
+                // Format the hour and move focus to minute input.
                 newHour = `${formatHour(filteredText)}`;
                 newSelection = 2;
                 focusMinuteInputOnFirstCharacter();
             }
+            // Case when the cursor is at the start.
         } else if (selectionHour.start === 0) {
+            // Handle cases where the hour would be > 12.
             const formattedText = `${filteredText[0]}${filteredText[2] || 0}`;
             if (formattedText > 12) {
                 newHour = `0${formattedText[1]}`;
@@ -137,10 +146,12 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                 newSelection = 1;
             }
         } else if (selectionHour.start === 1) {
-            // if we remove value
+            // Case when the cursor is at the second position.
             if (filteredText.length < 2) {
+                // If we remove a value, prepend 0.
                 newHour = `0${text}`;
                 newSelection = 0;
+                // If the second digit is > 2, replace the hour with 0 and the second digit.
             } else if (text[1] > 2) {
                 newHour = `0${text[1]}`;
                 newSelection = 2;
@@ -151,6 +162,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                 focusMinuteInputOnFirstCharacter();
             }
         } else if (selectionHour.start === 2 && selectionHour.end === 2) {
+            // Case when the cursor is at the end and no text is selected.
             if (filteredText.length < 2) {
                 newHour = `${text}0`;
                 newSelection = 1;
@@ -163,15 +175,21 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
         setSelectionHour({start: newSelection, end: newSelection});
     };
 
+    // This function receive value from minute input and validate it
+    // The valid format is MM(from 00 to 59). If the user input 9, it will be 09. If user try to change 09 to 99 it would skip the character
     const handleMinutesChange = (text) => {
+        // Remove non-numeric characters.
         const filteredText = text.replace(/[^0-9]/g, '');
 
         let newMinute = minute;
         let newSelection = selectionMinute.start;
+        // Case when user selects and replaces the text.
         if (selectionMinute.start !== selectionMinute.end) {
+            // If the first digit is > 5, prepend 0.
             if (filteredText.length === 1 && filteredText > 5) {
                 newMinute = `0${filteredText}`;
                 newSelection = 2;
+                // If the first digit is <= 5, append 0 at the end.
             } else if (filteredText.length === 1 && filteredText <= 5) {
                 newMinute = `${filteredText}0`;
                 newSelection = 1;
@@ -180,6 +198,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                 newSelection = 2;
             }
         } else if (selectionMinute.start === 0) {
+            // Case when the cursor is at the start.
             const formattedText = `${filteredText[0]}${filteredText[2] || 0}`;
             if (text[0] >= 6) {
                 newMinute = `0${formattedText[1]}`;
@@ -189,7 +208,8 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                 newSelection = 1;
             }
         } else if (selectionMinute.start === 1) {
-            //   //if we remove value
+            // Case when the cursor is at the second position.
+            // If we remove a value, prepend 0.
             if (filteredText.length < 2) {
                 newMinute = `0${text}`;
                 newSelection = 0;
@@ -198,6 +218,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                 newSelection = 2;
             }
         } else if (filteredText.length < 2) {
+            // Case when the cursor is at the end and no text is selected.
             newMinute = `${text}0`;
             newSelection = 1;
         }
@@ -318,7 +339,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
             <View style={[styles.flex1, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}>
                 <View
                     nativeID={AMOUNT_VIEW_ID}
-                    style={[styles.flexRow, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter, styles.timeInputsContainer]}
+                    style={[styles.flexRow, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}
                 >
                     <AmountTextInput
                         formattedAmount={hours}
@@ -341,7 +362,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                         style={styles.timePickerInput}
                         containerStyles={[styles.timePickerHeight100]}
                     />
-                    <Text style={styles.timePickerSemiDot}>:</Text>
+                    <Text style={styles.timePickerSemiDot}>{CONST.COLON}</Text>
                     <AmountTextInput
                         onKeyPress={handleFocusOnBackspace}
                         autofocus
diff --git a/src/languages/es.js b/src/languages/es.js
index ec017c02f79e..8d5cf43cf6e9 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -956,7 +956,7 @@ export default {
         date: 'Fecha',
         time: 'Hora',
         clearAfter: 'Borrar después',
-        whenClearStatus: "¿Cuándo deberíamos borrar tu estado?",
+        whenClearStatus: '¿Cuándo deberíamos borrar tu estado?',
     },
     stepCounter: ({step, total, text}) => {
         let result = `Paso ${step}`;
diff --git a/src/libs/Permissions.js b/src/libs/Permissions.js
index 0391a6714889..7f52c41ad0fd 100644
--- a/src/libs/Permissions.js
+++ b/src/libs/Permissions.js
@@ -91,7 +91,7 @@ function canUseScanReceipts(betas) {
  * @returns {Boolean}
  */
 function canUseCustomStatus(betas) {
-    return '_.contains(betas, CONST.BETAS.CUSTOM_STATUS) || canUseAllBetas(betas)';
+    return _.contains(betas, CONST.BETAS.CUSTOM_STATUS) || canUseAllBetas(betas);
 }
 
 /**
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 98f9ab193618..ebd7a50250e3 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3902,7 +3902,6 @@ const styles = {
 
     timePickerInput: {
         fontSize: 69,
-        maxHeight: 70,
         minWidth: 56,
         alignSelf: 'center',
     },
@@ -3914,10 +3913,6 @@ const styles = {
     },
     timePickerSemiDot: {
         fontSize: 69,
-        maxHeight: 70,
-    },
-    timeInputsContainer: {
-        maxHeight: 70,
     },
     timePickerSwitcherContainer: {
         flexDirection: 'row',

From ce90d1b18cd6f9f42a6cea5e9b78c5b6aaf12ae5 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 4 Sep 2023 12:03:21 +0200
Subject: [PATCH 047/118] fix form button

---
 src/components/TimePicker.js                           | 2 +-
 src/pages/settings/Profile/CustomStatus/SetTimePage.js | 2 +-
 src/styles/styles.js                                   | 3 +++
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 4ac620e3442f..2e81b820bcb2 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -424,7 +424,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                 </View>
             </View>
             <View
-                style={[styles.pageWrapper, styles.pb0, styles.mb12]}
+                style={[styles.pageWrapper, styles.pb0]}
                 nativeID={NUM_PAD_CONTAINER_VIEW_ID}
             >
                 {numberPad()}
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 56bf875d1564..fe64db19e724 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -61,7 +61,7 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
                     formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_TIME_FORM}
                     onSubmit={onSubmit}
                     submitButtonText={translate('common.save')}
-                    submitButtonContainerStyles={[styles.mt0, styles.flex0, styles.mh4]}
+                    submitButtonContainerStyles={[styles.flex0, styles.justifyContentStart, styles.mh5, styles.setTimeFormButtonContainer]}
                     validate={validate}
                     enabledWhenOffline
                     shouldUseDefaultValue
diff --git a/src/styles/styles.js b/src/styles/styles.js
index ebd7a50250e3..7b7d10e4b5c3 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3944,6 +3944,9 @@ const styles = {
     timePickerInputExtraSmall: {
         fontSize: 50,
     },
+    setTimeFormButtonContainer: {
+      minHeight: 54
+    }
 };
 
 export default styles;

From 2f7de9166b84a2fa088237360e3e2e7f596579c6 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 4 Sep 2023 16:15:58 +0200
Subject: [PATCH 048/118] update time picker styles

---
 src/components/TimePicker.js | 2 +-
 src/styles/styles.js         | 8 ++++++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 2e81b820bcb2..796cdb50f4f0 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -339,7 +339,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
             <View style={[styles.flex1, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}>
                 <View
                     nativeID={AMOUNT_VIEW_ID}
-                    style={[styles.flexRow, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}
+                    style={[styles.flexRow, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter, styles.timePickerInputsContainer]}
                 >
                     <AmountTextInput
                         formattedAmount={hours}
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 7b7d10e4b5c3..d1993a99d47d 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3913,6 +3913,7 @@ const styles = {
     },
     timePickerSemiDot: {
         fontSize: 69,
+        height: 84,
     },
     timePickerSwitcherContainer: {
         flexDirection: 'row',
@@ -3945,8 +3946,11 @@ const styles = {
         fontSize: 50,
     },
     setTimeFormButtonContainer: {
-      minHeight: 54
-    }
+        minHeight: 54,
+    },
+    timePickerInputsContainer: {
+        maxHeight: 70,
+    },
 };
 
 export default styles;

From 3038c646bc08371f33d97f25e52d2c8e06d1cb7a Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 4 Sep 2023 16:55:00 +0200
Subject: [PATCH 049/118] remove unused styleUtils

---
 src/components/Form.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/components/Form.js b/src/components/Form.js
index 841d0e607e02..a2a643695408 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -18,7 +18,6 @@ import stylePropTypes from '../styles/stylePropTypes';
 import {withNetwork} from './OnyxProvider';
 import networkPropTypes from './networkPropTypes';
 import Visibility from '../libs/Visibility';
-import * as StyleUtils from '../styles/StyleUtils';
 
 const propTypes = {
     /** A unique Onyx key identifying the form */

From 4f438f47ec2df5b9045d216c262b10a87bb9c17f Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 5 Sep 2023 09:56:02 +0200
Subject: [PATCH 050/118] BRICK_ROAD_INDICATOR_STATUS

---
 src/CONST.ts                                         |  3 ---
 src/components/TimePicker.js                         |  4 ++--
 src/libs/DateUtils.js                                | 12 ++++++------
 .../Profile/CustomStatus/StatusClearAfterPage.js     |  4 ++--
 .../settings/Profile/CustomStatus/StatusPage.js      |  4 ++--
 5 files changed, 12 insertions(+), 15 deletions(-)

diff --git a/src/CONST.ts b/src/CONST.ts
index 10fcb4e015df..4bbf5e81ad0a 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -2627,9 +2627,6 @@ const CONST = {
         SAASTR: 'SaaStrDemoSetup',
         SBE: 'SbeDemoSetup',
     },
-    BRICK_INDICATOR: {
-        ERROR: 'error',
-    },
     COLON: ':',
     MAPBOX: {
         PADDING: 50,
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 796cdb50f4f0..1047ea64e973 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -92,8 +92,8 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
     const {numberFormat} = useLocalize();
     const {isExtraSmallScreenHeight} = useWindowDimensions();
     const localize = useLocalize();
-    const [hours, setHours] = useState(DateUtils.parseTimeTo12HourFormat(value).hour);
-    const [minute, setMinute] = useState(DateUtils.parseTimeTo12HourFormat(value).minute);
+    const [hours, setHours] = useState(DateUtils.get12HourTimeObjectFromDate(value).hour);
+    const [minute, setMinute] = useState(DateUtils.get12HourTimeObjectFromDate(value).minute);
     const [selectionHour, setSelectionHour] = useState({start: 0, end: 0});
     const [selectionMinute, setSelectionMinute] = useState({start: 2, end: 2}); // we focus it by default so need  to have selection on the end
 
diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index a7575fcbff4b..14b47f39368d 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -320,11 +320,11 @@ function getEndOfWeekFromNow() {
 }
 
 /**
- * @param {string} dateTime
+ * @param {string} dateTimeString
  * @returns {string} example: 2023-05-16
  */
-function extractDate(dateTime) {
-    return moment(dateTime).format('YYYY-MM-DD');
+function extractDate(dateTimeString) {
+    return moment(dateTimeString).format('YYYY-MM-DD');
 }
 
 /**
@@ -441,9 +441,9 @@ const combineDateAndTime = (updatedTime, inputDateTime) => {
 /**
  * @param {String} dateTime // 'YYYY-MM-DD HH:mm:ss'
  * @returns {Object}
- * @example parseTimeTo12HourFormat('2023-08-29 11:10:00') // {hour: '11', minute: '10', period: 'AM'}
+ * @example get12HourTimeObjectFromDate('2023-08-29 11:10:00') // {hour: '11', minute: '10', period: 'AM'}
  */
-function parseTimeTo12HourFormat(dateTime) {
+function get12HourTimeObjectFromDate(dateTime) {
     if (!dateTime) {
         return {
             hour: '00',
@@ -520,7 +520,7 @@ const DateUtils = {
     formatDateTimeTo12Hour,
     getStatusUntilDate,
     extractTime12Hour,
-    parseTimeTo12HourFormat,
+    get12HourTimeObjectFromDate,
     areDatesIdentical,
     getTimePeriod,
     getLocalizedTimePeriodDescription,
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 04aad6af7742..acc670cca388 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -112,8 +112,8 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
 
     const {redBrickDateIndicator, redBrickTimeIndicator} = useMemo(
         () => ({
-            redBrickDateIndicator: customDateError ? CONST.BRICK_INDICATOR.ERROR : null,
-            redBrickTimeIndicator: customTimeError ? CONST.BRICK_INDICATOR.ERROR : null,
+            redBrickDateIndicator: customDateError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : null,
+            redBrickTimeIndicator: customTimeError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : null,
         }),
         [customTimeError, customDateError],
     );
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 7f122e4fc93a..4e0045e749e6 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -59,7 +59,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
     const updateStatus = useCallback(() => {
         const clearAfterTime = draftClearAfter || currentUserClearAfter;
         if (DateUtils.hasDateExpired(clearAfterTime)) {
-            setBrickRoadIndicator(isValidClearAfterDate() ? null : CONST.BRICK_INDICATOR.ERROR);
+            setBrickRoadIndicator(isValidClearAfterDate() ? null : CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR);
             return;
         }
 
@@ -95,7 +95,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
         [hasDraftStatus, localize, updateStatus, isValidClearAfterDate],
     );
 
-    useEffect(() => setBrickRoadIndicator(isValidClearAfterDate() ? null : CONST.BRICK_INDICATOR.ERROR), [isValidClearAfterDate]);
+    useEffect(() => setBrickRoadIndicator(isValidClearAfterDate() ? null : CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR), [isValidClearAfterDate]);
     useEffect(() => {
         if (!currentUserEmojiCode && !currentUserClearAfter && !draftClearAfter) {
             User.updateDraftCustomStatus({clearAfter: DateUtils.getEndOfToday()});

From 9f63519ea513094badb98111f47eb16a17bcccbf Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 25 Sep 2023 15:03:13 +0200
Subject: [PATCH 051/118] fix after merge

---
 src/components/Form.js                                       | 2 +-
 .../settings/Profile/CustomStatus/CustomClearAfterPage.js    | 5 ++++-
 .../settings/Profile/CustomStatus/StatusClearAfterPage.js    | 1 +
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/components/Form.js b/src/components/Form.js
index 7eaf957b66d8..5e72435f0150 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -457,7 +457,7 @@ function Form(props) {
                         containerStyles={[styles.mh0, styles.mt5, styles.flex1, ...props.submitButtonContainerStyles]}
                         enabledWhenOffline={props.enabledWhenOffline}
                         isSubmitActionDangerous={props.isSubmitActionDangerous}
-                        buttonStyle={props.submitButtonStyle}
+                        buttonStyles={[props.submitButtonStyle]}
                         useSmallerSubmitButtonSize={props.useSmallerSubmitButtonSize}
                         disablePressOnEnter
                     />
diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index ba71aa65d177..070997b3016b 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -41,7 +41,10 @@ function CustomClearAfterPage({translate, customStatus}) {
     }, []);
 
     return (
-        <ScreenWrapper includeSafeAreaPaddingBottom={false}>
+        <ScreenWrapper
+            includeSafeAreaPaddingBottom={false}
+            testID={CustomClearAfterPage.displayName}
+        >
             <HeaderWithBackButton
                 title={translate('statusPage.date')}
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index acc670cca388..56d8e2eeb2df 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -159,6 +159,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
         <ScreenWrapper
             includeSafeAreaPaddingBottom={false}
             shouldEnableMaxHeight
+            testID={StatusClearAfterPage.displayName}
         >
             <HeaderWithBackButton
                 title="Status"

From 658a0efaa2cfc5cd45df159670cc2d424342a900 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 26 Sep 2023 15:06:47 +0200
Subject: [PATCH 052/118] fix routes

---
 src/ROUTES.ts | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 1065b525f83a..800931218587 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -72,6 +72,9 @@ export default {
     SETTINGS_2FA:                               'settings/security/two-factor-auth',
     SETTINGS_STATUS:                            'settings/profile/status',
     SETTINGS_STATUS_SET:                        'settings/profile/status/set',
+    SETTINGS_STATUS_CLEAR_AFTER:                'settings/profile/status/clear-after',
+    SETTINGS_STATUS_CLEAR_AFTER_CUSTOM:         'settings/profile/status/clear-after/custom',
+    SETTINGS_STATUS_CLEAR_AFTER_TIME:           'settings/profile/status/clear-after/time',
 
     NEW:                                        'new',
     NEW_CHAT:                                   'new/chat',

From 6e274610b23b9b04869205b8a73e68fb4f31d1d6 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 26 Sep 2023 15:08:00 +0200
Subject: [PATCH 053/118] add errorMessageStyle for the Form

---
 src/components/Form.js                      | 4 ++++
 src/components/FormAlertWithSubmitButton.js | 4 ++++
 src/components/FormAlertWrapper.js          | 5 ++++-
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/src/components/Form.js b/src/components/Form.js
index 5e72435f0150..613ab6383fdd 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -85,6 +85,9 @@ const propTypes = {
     /** Style for the button */
     submitButtonStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
 
+    /** Style for the error message for submit button*/
+    errorMessageStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
+
     submitButtonContainerStyles: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
 
     ...withLocalizePropTypes,
@@ -460,6 +463,7 @@ function Form(props) {
                         buttonStyles={[props.submitButtonStyle]}
                         useSmallerSubmitButtonSize={props.useSmallerSubmitButtonSize}
                         disablePressOnEnter
+                        errorMessageStyle={props.errorMessageStyle}
                     />
                 )}
             </FormSubmit>
diff --git a/src/components/FormAlertWithSubmitButton.js b/src/components/FormAlertWithSubmitButton.js
index c4e4eec9190f..bdb4285b56fb 100644
--- a/src/components/FormAlertWithSubmitButton.js
+++ b/src/components/FormAlertWithSubmitButton.js
@@ -53,6 +53,9 @@ const propTypes = {
 
     /** Whether to use a smaller submit button size */
     useSmallerSubmitButtonSize: PropTypes.bool,
+
+    /** Style for the error message for submit button*/
+    errorMessageStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
 };
 
 const defaultProps = {
@@ -80,6 +83,7 @@ function FormAlertWithSubmitButton(props) {
             isMessageHtml={props.isMessageHtml}
             message={props.message}
             onFixTheErrorsLinkPressed={props.onFixTheErrorsLinkPressed}
+            errorMessageStyle={props.errorMessageStyle}
         >
             {(isOffline) => (
                 <View>
diff --git a/src/components/FormAlertWrapper.js b/src/components/FormAlertWrapper.js
index 704d9b5a241c..5b2c05fbe36f 100644
--- a/src/components/FormAlertWrapper.js
+++ b/src/components/FormAlertWrapper.js
@@ -35,6 +35,9 @@ const propTypes = {
     /** Callback fired when the "fix the errors" link is pressed */
     onFixTheErrorsLinkPressed: PropTypes.func,
 
+    /** Style for the error message for submit button*/
+    errorMessageStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
+
     ...withLocalizePropTypes,
 };
 
@@ -73,7 +76,7 @@ function FormAlertWrapper(props) {
             {props.isAlertVisible && (
                 <FormHelpMessage
                     message={props.message}
-                    style={[styles.mb3]}
+                    style={[styles.mb3, props.errorMessageStyle]}
                 >
                     {children}
                 </FormHelpMessage>

From 68df0dedcbe9ba6f1989af25935c6a6f6e2824ce Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 26 Sep 2023 15:08:57 +0200
Subject: [PATCH 054/118] update validateDateTimeIsAtLeastOneMinuteInFuture

---
 src/libs/ValidationUtils.js | 38 +++++++++++++++++++++++++++++++++----
 1 file changed, 34 insertions(+), 4 deletions(-)

diff --git a/src/libs/ValidationUtils.js b/src/libs/ValidationUtils.js
index 0a515a142e42..6f8ada3e70f8 100644
--- a/src/libs/ValidationUtils.js
+++ b/src/libs/ValidationUtils.js
@@ -1,10 +1,11 @@
-import {subYears, addYears, addMinutes, startOfDay, endOfMonth, isAfter, isBefore, isValid, isWithinInterval, isSameDay, parse, set, format} from 'date-fns';
+import {subYears, addYears, addMinutes, startOfDay, endOfMonth, isAfter, isBefore, isValid, isWithinInterval, isSameDay, parse, set, format, parseISO} from 'date-fns';
 import _ from 'underscore';
 import {URL_REGEX_WITH_REQUIRED_PROTOCOL} from 'expensify-common/lib/Url';
 import {parsePhoneNumber} from 'awesome-phonenumber';
 import CONST from '../CONST';
 import * as CardUtils from './CardUtils';
 import * as LoginUtils from './LoginUtils';
+import DateUtils from './DateUtils';
 
 /**
  * Implements the Luhn Algorithm, a checksum formula used to validate credit card
@@ -483,16 +484,22 @@ function isValidAccountRoute(accountID) {
 
 /**
  * Checks if the time input is at least one minute in the future.
- * @param {String} inputTime
- * @param {String} inputDateTime
+ * @param {String} inputTime '12:00 PM'
+ * @param {String} inputDateTime '2023-09-27'
  * @returns {Boolean}
  * */
 const isTimeAtLeastOneMinuteInFuture = (inputTime = '', inputDateTime = '') => {
-    if (!inputTime) return false;
+    if (!inputTime) {
+        return false;
+    }
     // Parse the hour and minute from the time input
     const [hourStr, minuteStr, period] = inputTime.split(/[:\s]+/);
     let hour = parseInt(hourStr, 10);
 
+    if (hour === 0) {
+        return false;
+    }
+
     // Convert 12-hour format to 24-hour format
     if (period.toUpperCase() === 'PM' && hour !== 12) {
         hour += 12;
@@ -518,6 +525,28 @@ const isTimeAtLeastOneMinuteInFuture = (inputTime = '', inputDateTime = '') => {
     return isAfter(combinedDate, addMinutes(now, 1));
 };
 
+/**
+ * Validates that the date and time are at least one minute in the future.
+ * @param {String} data - A date and time string in 'YYYY-MM-DDTHH:mm:ss.sssZ' format
+ * @returns {Object} - An object containing the error messages for the date and time
+ */
+const validateDateTimeIsAtLeastOneMinuteInFuture = (data) => {
+    if (!data) {
+        return {
+            dateValidationErrorKey: '',
+            timeValidationErrorKey: '',
+        };
+    }
+    const parsedInputData = parseISO(data);
+
+    const dateValidationErrorKey = DateUtils.getDateValidationErrorKey(parsedInputData);
+    const timeValidationErrorKey = DateUtils.getTimeValidationErrorKey(parsedInputData);
+    return {
+        dateValidationErrorKey,
+        timeValidationErrorKey,
+    };
+};
+
 export {
     meetsMinimumAgeRequirement,
     meetsMaximumAgeRequirement,
@@ -553,4 +582,5 @@ export {
     getDatePassedError,
     isTimeAtLeastOneMinuteInFuture,
     isValidRecoveryCode,
+    validateDateTimeIsAtLeastOneMinuteInFuture,
 };

From b31c3fb7f32e143b10a3254012bbae516d43749b Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 26 Sep 2023 15:09:22 +0200
Subject: [PATCH 055/118] fix ScreenWrapper

---
 src/pages/settings/Profile/CustomStatus/SetTimePage.js | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index fe64db19e724..b0319f166426 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -50,7 +50,10 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
         return <FullscreenLoadingIndicator />;
     }
     return (
-        <ScreenWrapper includeSafeAreaPaddingBottom={false}>
+        <ScreenWrapper
+            includeSafeAreaPaddingBottom={false}
+            testID={SetTimePage.displayName}
+        >
             <HeaderWithBackButton
                 title={translate('statusPage.time')}
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
@@ -61,7 +64,8 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
                     formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_TIME_FORM}
                     onSubmit={onSubmit}
                     submitButtonText={translate('common.save')}
-                    submitButtonContainerStyles={[styles.flex0, styles.justifyContentStart, styles.mh5, styles.setTimeFormButtonContainer]}
+                    submitButtonContainerStyles={[styles.flex0, styles.justifyContentStart, styles.mh5, styles.setTimeFormButtonContainer, styles.pt3]}
+                    errorMessageStyle={styles.timePickerButtonErrorText}
                     validate={validate}
                     enabledWhenOffline
                     shouldUseDefaultValue

From 679ee5bf69f2f2013bdb7403108c0a598438c595 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 26 Sep 2023 15:13:00 +0200
Subject: [PATCH 056/118] fix rerenders in TimePicker

---
 src/components/TimePicker.js                  | 19 +++----
 .../CustomStatus/StatusClearAfterPage.js      | 52 +++++++++----------
 src/styles/StyleUtils.ts                      | 14 +++++
 src/styles/styles.js                          |  5 ++
 4 files changed, 50 insertions(+), 40 deletions(-)

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 1047ea64e973..18e5aafeccba 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -15,6 +15,7 @@ import DateUtils from '../libs/DateUtils';
 import useWindowDimensions from '../hooks/useWindowDimensions';
 import useKeyboardShortcut from '../hooks/useKeyboardShortcut';
 import useLocalize from '../hooks/useLocalize';
+import * as StyleUtils from '../styles/StyleUtils';
 import CONST from '../CONST';
 
 const propTypes = {
@@ -92,12 +93,12 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
     const {numberFormat} = useLocalize();
     const {isExtraSmallScreenHeight} = useWindowDimensions();
     const localize = useLocalize();
-    const [hours, setHours] = useState(DateUtils.get12HourTimeObjectFromDate(value).hour);
-    const [minute, setMinute] = useState(DateUtils.get12HourTimeObjectFromDate(value).minute);
+    const [hours, setHours] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).hour);
+    const [minute, setMinute] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).minute);
     const [selectionHour, setSelectionHour] = useState({start: 0, end: 0});
     const [selectionMinute, setSelectionMinute] = useState({start: 2, end: 2}); // we focus it by default so need  to have selection on the end
 
-    const [amPmValue, setAmPmValue] = useState(DateUtils.getTimePeriod(value));
+    const [amPmValue, setAmPmValue] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).period);
 
     const hourInputRef = useRef(null);
     const minuteInputRef = useRef(null);
@@ -308,15 +309,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
         [selectionMinute.start],
     );
 
-    const {styleForAM, styleForPM} = useMemo(() => {
-        const computedStyleForAM = amPmValue !== CONST.TIME_PERIOD.AM ? {backgroundColor: themeColors.componentBG} : {};
-        const computedStyleForPM = amPmValue !== CONST.TIME_PERIOD.PM ? {backgroundColor: themeColors.componentBG} : {};
-
-        return {
-            styleForAM: [styles.timePickerWidth100, computedStyleForAM],
-            styleForPM: [styles.timePickerWidth100, computedStyleForPM],
-        };
-    }, [amPmValue]);
+    const {styleForAM, styleForPM} = StyleUtils.getStatusAMandPMButtonStyle(amPmValue);
 
     const numberPad = useCallback(() => {
         if (!canUseTouchScreen) return null;
@@ -411,7 +404,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                     />
                     <Button
                         shouldEnableHapticFeedback
-                        innerStyles={styleForPM}
+                        innerStyles={[...styleForPM, styles.ml1]}
                         medium={isExtraSmallScreenHeight}
                         text={localize.translate('common.pm')}
                         onLongPress={() => {}}
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 56d8e2eeb2df..ac88b4836456 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -18,11 +18,13 @@ import useLocalize from '../../../../hooks/useLocalize';
 import ONYXKEYS from '../../../../ONYXKEYS';
 import CONST from '../../../../CONST';
 import * as User from '../../../../libs/actions/User';
+import * as ValidationUtils from '../../../../libs/ValidationUtils';
 import withLocalize from '../../../../components/withLocalize';
 import compose from '../../../../libs/compose';
 import DateUtils from '../../../../libs/DateUtils';
 import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps} from '../../../../components/withCurrentUserPersonalDetails';
 import personalDetailsPropType from '../../../personalDetailsPropType';
+import {parseISO} from 'date-fns';
 
 const defaultProps = {
     ...withCurrentUserPersonalDetailsDefaultProps,
@@ -58,37 +60,33 @@ const useValidateCustomDate = (data) => {
     const localize = useLocalize();
     const [customDateError, setCustomDateError] = useState('');
     const [customTimeError, setCustomTimeError] = useState('');
+    const validate = (inputData = data) => {
+        const {dateValidationErrorKey, timeValidationErrorKey} = ValidationUtils.validateDateTimeIsAtLeastOneMinuteInFuture(inputData);
 
-    const validate = () => {
-        const inputData = moment(data, 'YYYY-MM-DD HH:mm:ss');
-        const currentDate = moment().startOf('day');
-        const currentDateTimePlus2 = moment().add(1, 'minutes');
+        const dateError = dateValidationErrorKey ? localize.translate(dateValidationErrorKey) : '';
+        setCustomDateError(dateError);
 
-        // Date validation
-        if (inputData.isBefore(currentDate)) {
-            setCustomDateError(localize.translate('common.error.invalidDateShouldBeFuture'));
-        } else {
-            setCustomDateError('');
-        }
+        const timeError = timeValidationErrorKey ? localize.translate(timeValidationErrorKey) : '';
+        setCustomTimeError(timeError);
 
-        // Time validation
-        if (inputData.isBefore(currentDateTimePlus2)) {
-            setCustomTimeError(localize.translate('common.error.invalidTimeShouldBeFuture'));
-        } else {
-            setCustomTimeError('');
-        }
+        return {
+            dateError,
+            timeError,
+        };
     };
 
     useEffect(() => {
-        validate();
+        if (data) {
+            validate();
+        }
         // eslint-disable-next-line react-hooks/exhaustive-deps
     }, [data]);
 
-    const triggerValidation = () => {
-        validate();
+    const validateCustomDate = (inputData) => {
+        return validate(inputData);
     };
 
-    return {customDateError, customTimeError, triggerValidation};
+    return {customDateError, customTimeError, validateCustomDate};
 };
 
 function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
@@ -97,7 +95,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
     const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
     const [draftPeriod, setDraftPeriod] = useState(getSelectedStatusType(clearAfter || draftClearAfter));
-    const localesToThemes = useMemo(
+    const statusType = useMemo(
         () =>
             _.map(CONST.CUSTOM_STATUS_TYPES, (value, key) => ({
                 value,
@@ -108,7 +106,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
         [draftPeriod, localize],
     );
 
-    const {customDateError, customTimeError, triggerValidation} = useValidateCustomDate(customDateTemporary);
+    const {customDateError, customTimeError, validateCustomDate} = useValidateCustomDate(customDateTemporary);
 
     const {redBrickDateIndicator, redBrickTimeIndicator} = useMemo(
         () => ({
@@ -118,14 +116,14 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
         [customTimeError, customDateError],
     );
 
-    const onSubmit = () => {
-        triggerValidation();
-        if (customDateError || customTimeError) return;
+    const onSubmit = (v) => {
+        const {dateError, timeError} = validateCustomDate();
+        if (dateError || timeError) return;
         let calculatedDraftDate = '';
         if (draftPeriod === CONST.CUSTOM_STATUS_TYPES.CUSTOM) {
             calculatedDraftDate = customDateTemporary;
         } else {
-            const selectedRange = _.find(localesToThemes, (item) => item.isSelected);
+            const selectedRange = _.find(statusType, (item) => item.isSelected);
             calculatedDraftDate = DateUtils.getDateFromStatusType(selectedRange.value);
         }
         User.updateDraftCustomStatus({clearAfter: calculatedDraftDate, customDateTemporary: calculatedDraftDate});
@@ -177,7 +175,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
             >
                 <View>
                     <SelectionList
-                        sections={[{data: localesToThemes, indexOffset: 0}]}
+                        sections={[{data: statusType, indexOffset: 0}]}
                         onSelectRow={updateMode}
                         disableInitialFocusOptionStyle
                         wrapperStyle={{flex: null}}
diff --git a/src/styles/StyleUtils.ts b/src/styles/StyleUtils.ts
index 11ade02220ab..bc267a3d9e57 100644
--- a/src/styles/StyleUtils.ts
+++ b/src/styles/StyleUtils.ts
@@ -1216,6 +1216,19 @@ function getTransparentColor(color: string) {
     return `${color}00`;
 }
 
+/**
+ * Get the style for the AM and PM buttons in the TimePicker
+ */
+function getStatusAMandPMButtonStyle(amPmValue: string): {styleForAM: ViewStyle | CSSProperties; styleForPM: ViewStyle | CSSProperties} {
+    const computedStyleForAM: ViewStyle = amPmValue !== CONST.TIME_PERIOD.AM ? {backgroundColor: themeColors.componentBG} : {};
+    const computedStyleForPM: ViewStyle = amPmValue !== CONST.TIME_PERIOD.PM ? {backgroundColor: themeColors.componentBG} : {};
+
+    return {
+        styleForAM: [styles.timePickerWidth100, computedStyleForAM] as ViewStyle,
+        styleForPM: [styles.timePickerWidth100, computedStyleForPM] as ViewStyle,
+    };
+}
+
 export {
     getAvatarSize,
     getAvatarWidthStyle,
@@ -1293,4 +1306,5 @@ export {
     getDropDownButtonHeight,
     getAmountFontSizeAndLineHeight,
     getTransparentColor,
+    getStatusAMandPMButtonStyle,
 };
diff --git a/src/styles/styles.js b/src/styles/styles.js
index ae95f543d4aa..35e7a226c631 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -1,3 +1,4 @@
+import {StyleSheet} from 'react-native';
 import {defaultStyles as defaultPickerStyles} from 'react-native-picker-select/src/styles';
 import lodashClamp from 'lodash/clamp';
 import fontFamily from './fontFamily';
@@ -3728,6 +3729,10 @@ const styles = (theme) => ({
     timePickerInputsContainer: {
         maxHeight: 70,
     },
+    timePickerButtonErrorText: {
+        position: 'absolute',
+        top: -20,
+    },
 });
 
 // For now we need to export the styles function that takes the theme as an argument

From b92dee68692a618879795a83c768494e1fbc21a1 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 26 Sep 2023 15:50:25 +0200
Subject: [PATCH 057/118] migrate from moment to date-fns

---
 src/libs/DateUtils.js | 139 +++++++++++++++++++++++++++++++-----------
 1 file changed, 102 insertions(+), 37 deletions(-)

diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index d401d6d9556f..e16a7ed3b53b 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -17,8 +17,13 @@ import {
     isSameDay,
     isAfter,
     isSameYear,
+    addMinutes,
+    addHours,
+    addDays,
+    parse,
+    set,
+    isSameMinute,
 } from 'date-fns';
-import moment from 'moment';
 import _ from 'underscore';
 import Onyx from 'react-native-onyx';
 import ONYXKEYS from '../ONYXKEYS';
@@ -295,28 +300,32 @@ function getDateStringFromISOTimestamp(isoTimestamp) {
  * @returns {string} example: 2023-05-16 05:34:14
  */
 function getThirtyMinutesFromNow() {
-    return moment().add(30, 'minutes').format('YYYY-MM-DD HH:mm:ss');
+    const date = addMinutes(new Date(), 30);
+    return format(date, 'yyyy-MM-dd HH:mm:ss');
 }
 
 /**
  * @returns {string} example: 2023-05-16 05:34:14
  */
 function getOneHourFromNow() {
-    return moment().add(1, 'hours').format('YYYY-MM-DD HH:mm:ss');
+    const date = addHours(new Date(), 1);
+    return format(date, 'yyyy-MM-dd HH:mm:ss');
 }
 
 /**
  * @returns {string} example: 2023-05-16 05:34:14
  */
 function getEndOfToday() {
-    return moment().endOf('day').format('YYYY-MM-DD HH:mm:ss');
+    const date = endOfDay(new Date());
+    return format(date, 'yyyy-MM-dd HH:mm:ss');
 }
 
 /**
  * @returns {string} example: 2023-05-16 05:34:14
  */
 function getEndOfWeekFromNow() {
-    return moment().add(7, 'days').format('YYYY-MM-DD HH:mm:ss');
+    const date = addDays(new Date(), 7);
+    return format(date, 'yyyy-MM-dd HH:mm:ss');
 }
 
 /**
@@ -324,7 +333,14 @@ function getEndOfWeekFromNow() {
  * @returns {string} example: 2023-05-16
  */
 function extractDate(dateTimeString) {
-    return moment(dateTimeString).format('YYYY-MM-DD');
+    if (!dateTimeString) {
+        return '';
+    }
+    if (dateTimeString === 'never') {
+        return '';
+    }
+    const date = new Date(dateTimeString);
+    return format(date, 'yyyy-MM-dd');
 }
 
 /**
@@ -332,7 +348,11 @@ function extractDate(dateTimeString) {
  * @returns {string} example: 11:10 PM
  */
 function extractTime12Hour(dateTimeString) {
-    return moment(dateTimeString).format('hh:mm A');
+    if (!dateTimeString || dateTimeString === 'never') {
+        return '';
+    }
+    const date = new Date(dateTimeString);
+    return format(date, 'hh:mm a');
 }
 
 /**
@@ -340,8 +360,11 @@ function extractTime12Hour(dateTimeString) {
  * @returns {string} example: 2023-05-16 11:10 PM
  */
 function formatDateTimeTo12Hour(dateTimeString) {
-    if (!dateTimeString) return '';
-    return moment(dateTimeString).format('YYYY-MM-DD hh:mm A');
+    if (!dateTimeString) {
+        return '';
+    }
+    const date = new Date(dateTimeString);
+    return format(date, 'yyyy-MM-dd hh:mm a');
 }
 
 /**
@@ -421,44 +444,50 @@ function getStatusUntilDate(inputDate) {
  * Update the time for a given date.
  *
  * @param {string} updatedTime - Time in "hh:mm A" format (like "10:55 AM").
- * @param {string} inputDateTime - Date in "YYYY-MM-DD HH:mm:ss" format.
+ * @param {string} inputDateTime - Date in "YYYY-MM-DD HH:mm:ss" or "YYYY-MM-DD" format.
  * @returns {string} - Date with updated time in "YYYY-MM-DD HH:mm:ss" format.
  */
 const combineDateAndTime = (updatedTime, inputDateTime) => {
-    // Parse the time from the input
-    const parsedTime = moment(updatedTime, 'hh:mm A');
+    if (!updatedTime || !inputDateTime) {
+        return '';
+    }
 
-    // Create a moment object from the input date-time (or just date)
-    const parsedDateTime = moment(inputDateTime, inputDateTime.includes(':') ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD');
+    const parsedTime = parse(updatedTime, 'hh:mm a', new Date());
 
-    // Set the hour and minute from the time input to the date from the date-time input
-    parsedDateTime.set({
-        hour: parsedTime.get('hour'),
-        minute: parsedTime.get('minute'),
+    let parsedDateTime;
+    if (inputDateTime.includes(':')) {
+        // Check if it includes time
+        parsedDateTime = parse(inputDateTime, 'yyyy-MM-dd HH:mm:ss', new Date());
+    } else {
+        parsedDateTime = parse(inputDateTime, 'yyyy-MM-dd', new Date());
+    }
+
+    const updatedDateTime = set(parsedDateTime, {
+        hours: parsedTime.getHours(),
+        minutes: parsedTime.getMinutes(),
     });
 
-    return parsedDateTime.format('YYYY-MM-DD HH:mm:ss');
+    return format(updatedDateTime, 'yyyy-MM-dd HH:mm:ss');
 };
 
 /**
- * @param {String} dateTime // 'YYYY-MM-DD HH:mm:ss'
+ * @param {String} dateTime // 'HH:mm:ss'
  * @returns {Object}
- * @example get12HourTimeObjectFromDate('2023-08-29 11:10:00') // {hour: '11', minute: '10', period: 'AM'}
+ * @example get12HourTimeObjectFromDate('11:10:00') // {hour: '11', minute: '10', period: 'AM'}
  */
 function get12HourTimeObjectFromDate(dateTime) {
     if (!dateTime) {
         return {
-            hour: '00',
-            minute: '01',
-            period: 'AM',
+            hour: '12',
+            minute: '00',
+            period: 'PM',
         };
     }
-    const parsedTime = moment(dateTime, 'h:mm A');
-
+    const parsedTime = parse(dateTime, 'hh:mm a', new Date());
     return {
-        hour: parsedTime.format('hh'), // Hour in 12-hour format
-        minute: parsedTime.format('mm'), // Minute
-        period: parsedTime.format('A'), // AM or PM
+        hour: format(parsedTime, 'hh'),
+        minute: format(parsedTime, 'mm'),
+        period: format(parsedTime, 'a').toUpperCase(),
     };
 }
 
@@ -468,8 +497,8 @@ function get12HourTimeObjectFromDate(dateTime) {
  * @example getTimePeriod('11:10 PM') // 'PM'
  */
 function getTimePeriod(timeString) {
-    const formattedDateString = `2023-08-29 ${timeString}`; // Assuming a random date for formatting
-    return moment(formattedDateString, 'YYYY-MM-DD h:mm A').format('A');
+    const parts = timeString.split(' ');
+    return parts[1];
 }
 
 /**
@@ -478,10 +507,10 @@ function getTimePeriod(timeString) {
  * @returns {Boolean}
  */
 function areDatesIdentical(dateTimeStringFirst, dateTimeStringSecond) {
-    const date1 = moment(dateTimeStringFirst);
-    const date2 = moment(dateTimeStringSecond);
+    const date1 = parse(dateTimeStringFirst, 'yyyy-MM-dd HH:mm:ss', new Date());
+    const date2 = parse(dateTimeStringSecond, 'yyyy-MM-dd HH:mm:ss', new Date());
 
-    return date1.isSame(date2);
+    return isSameMinute(date1, date2);
 }
 
 /**
@@ -489,11 +518,45 @@ function areDatesIdentical(dateTimeStringFirst, dateTimeStringSecond) {
  * @returns {Boolean}
  */
 function hasDateExpired(dateTimeString) {
-    const validUntil = moment().add(1, 'minutes');
-    const dateToCheck = moment(dateTimeString);
-    return dateToCheck.isBefore(validUntil);
+    const validUntil = addMinutes(new Date(), 1);
+    const dateToCheck = parse(dateTimeString, 'yyyy-MM-dd HH:mm:ss', new Date());
+
+    return isBefore(dateToCheck, validUntil);
 }
 
+/**
+ * Checks if the input date is in the future compared to the reference date.
+ * @param {Date} inputDate - The date to validate.
+ * @param {Date} referenceDate - The date to compare against.
+ * @returns {string} - Returns an error key if validation fails, otherwise an empty string.
+ */
+const getDateValidationErrorKey = (inputDate) => {
+    // const startOfCurrentDay = new Date();
+    if (!inputDate) {
+        return '';
+    }
+    const currentYear = new Date().getFullYear();
+    const inputYear = inputDate.getFullYear();
+    if (inputYear < currentYear) {
+        return 'common.error.invalidDateShouldBeFuture';
+    }
+    return '';
+};
+
+/**
+ * Checks if the input time is at least one minute in the future compared to the reference time.
+ * @param {Date} inputTime - The time to validate.
+ * @param {Date} referenceTime - The time to compare against.
+ * @returns {string} - Returns an error key if validation fails, otherwise an empty string.
+ */
+const getTimeValidationErrorKey = (inputTime) => {
+    const startOfCurrentDay = addMinutes(new Date(), 1);
+    if (isBefore(inputTime, startOfCurrentDay)) {
+        return 'common.error.invalidTimeShouldBeFuture';
+    }
+    return '';
+};
+
 /**
  * @namespace DateUtils
  */
@@ -528,6 +591,8 @@ const DateUtils = {
     getLocalizedTimePeriodDescription,
     hasDateExpired,
     combineDateAndTime,
+    getDateValidationErrorKey,
+    getTimeValidationErrorKey,
 };
 
 export default DateUtils;

From 3653b911545e21c0f8183aa1f28d98780d3a3ac0 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 26 Sep 2023 15:51:20 +0200
Subject: [PATCH 058/118] lint

---
 src/components/Button/index.js                |  4 ++-
 src/components/Form.js                        |  4 ++-
 src/components/FormAlertWithSubmitButton.js   |  3 ++-
 src/components/FormAlertWrapper.js            |  3 ++-
 src/components/MenuItem.js                    |  2 +-
 src/components/TimePicker.js                  | 17 +++++++++----
 .../CustomStatus/StatusClearAfterPage.js      | 25 ++++++++++---------
 .../Profile/CustomStatus/StatusPage.js        |  4 ++-
 8 files changed, 39 insertions(+), 23 deletions(-)

diff --git a/src/components/Button/index.js b/src/components/Button/index.js
index c42ad0b98ff9..394a147bedcc 100644
--- a/src/components/Button/index.js
+++ b/src/components/Button/index.js
@@ -274,7 +274,9 @@ class Button extends Component {
                     return this.props.onPress(e);
                 }}
                 onLongPress={(e) => {
-                    if (this.props.isLongPressDisabled) return;
+                    if (this.props.isLongPressDisabled) {
+                        return;
+                    }
                     if (this.props.shouldEnableHapticFeedback) {
                         HapticFeedback.longPress();
                     }
diff --git a/src/components/Form.js b/src/components/Form.js
index 613ab6383fdd..5f2c58436963 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -85,7 +85,7 @@ const propTypes = {
     /** Style for the button */
     submitButtonStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
 
-    /** Style for the error message for submit button*/
+    /** Style for the error message for submit button */
     errorMessageStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
 
     submitButtonContainerStyles: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
@@ -106,6 +106,7 @@ const defaultProps = {
     shouldValidateOnBlur: true,
     footerContent: null,
     style: [],
+    errorMessageStyle: [],
     validate: () => ({}),
     submitButtonStyle: {},
     submitButtonContainerStyles: [],
@@ -488,6 +489,7 @@ function Form(props) {
             props.submitButtonText,
             props.submitButtonStyle,
             props.useSmallerSubmitButtonSize,
+            props.errorMessageStyle,
         ],
     );
 
diff --git a/src/components/FormAlertWithSubmitButton.js b/src/components/FormAlertWithSubmitButton.js
index bdb4285b56fb..728406ad5320 100644
--- a/src/components/FormAlertWithSubmitButton.js
+++ b/src/components/FormAlertWithSubmitButton.js
@@ -54,7 +54,7 @@ const propTypes = {
     /** Whether to use a smaller submit button size */
     useSmallerSubmitButtonSize: PropTypes.bool,
 
-    /** Style for the error message for submit button*/
+    /** Style for the error message for submit button */
     errorMessageStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
 };
 
@@ -71,6 +71,7 @@ const defaultProps = {
     useSmallerSubmitButtonSize: false,
     footerContent: null,
     buttonStyles: [],
+    errorMessageStyle: [],
 };
 
 function FormAlertWithSubmitButton(props) {
diff --git a/src/components/FormAlertWrapper.js b/src/components/FormAlertWrapper.js
index 5b2c05fbe36f..8bc15613723f 100644
--- a/src/components/FormAlertWrapper.js
+++ b/src/components/FormAlertWrapper.js
@@ -35,7 +35,7 @@ const propTypes = {
     /** Callback fired when the "fix the errors" link is pressed */
     onFixTheErrorsLinkPressed: PropTypes.func,
 
-    /** Style for the error message for submit button*/
+    /** Style for the error message for submit button */
     errorMessageStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
 
     ...withLocalizePropTypes,
@@ -43,6 +43,7 @@ const propTypes = {
 
 const defaultProps = {
     containerStyles: [],
+    errorMessageStyle: [],
     isAlertVisible: false,
     isMessageHtml: false,
     message: '',
diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js
index 85f9b33ca7e2..42638b861b0c 100644
--- a/src/components/MenuItem.js
+++ b/src/components/MenuItem.js
@@ -1,8 +1,8 @@
 import _ from 'underscore';
 import React, {useEffect, useMemo} from 'react';
 import {View} from 'react-native';
-import FormHelpMessage from './FormHelpMessage';
 import ExpensiMark from 'expensify-common/lib/ExpensiMark';
+import FormHelpMessage from './FormHelpMessage';
 import Text from './Text';
 import styles from '../styles/styles';
 import themeColors from '../styles/themes/default';
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 18e5aafeccba..30898edeae12 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -2,7 +2,6 @@ import React, {useEffect, useState, useCallback, useRef, useMemo} from 'react';
 import {View} from 'react-native';
 import PropTypes from 'prop-types';
 import _ from 'underscore';
-import themeColors from '../styles/themes/default';
 import styles from '../styles/styles';
 import FormHelpMessage from './FormHelpMessage';
 import AmountTextInput from './AmountTextInput';
@@ -65,7 +64,9 @@ function insertAtPosition(originalString, newSubstring, selectionPositionFrom, s
     // If the positions are the same, it means we're inserting at a point
     if (selectionPositionFrom === selectionPositionTo) {
         if (selectionPositionFrom === originalString.length) {
-            if (typeof fn === 'function') fn();
+            if (typeof fn === 'function') {
+                fn();
+            }
             return originalString; // If the insertion point is at the end, simply return the original string
         }
         return originalString.slice(0, selectionPositionFrom) + newSubstring + originalString.slice(selectionPositionFrom);
@@ -243,7 +244,9 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                 setTimeout(() => setSelectionHour({start: 0, end: 0}), 10);
             }
 
-            if (key === '.') return;
+            if (key === '.') {
+                return;
+            }
             if (key === '<' || key === 'Backspace') {
                 if (isHourFocused) {
                     const newHour = replaceWithZeroAtPosition(hours, selectionHour.start);
@@ -302,7 +305,9 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
 
     const handleFocusOnBackspace = useCallback(
         (e) => {
-            if (selectionMinute.start !== 0 || e.key !== 'Backspace') return;
+            if (selectionMinute.start !== 0 || e.key !== 'Backspace') {
+                return;
+            }
             hourInputRef.current.focus();
         },
         // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -312,7 +317,9 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
     const {styleForAM, styleForPM} = StyleUtils.getStatusAMandPMButtonStyle(amPmValue);
 
     const numberPad = useCallback(() => {
-        if (!canUseTouchScreen) return null;
+        if (!canUseTouchScreen) {
+            return null;
+        }
         return (
             <BigNumberPad
                 nativeID={NUM_PAD_VIEW_ID}
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index ac88b4836456..9916f0fee0a8 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -4,7 +4,6 @@ import _ from 'lodash';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
 import PropTypes from 'prop-types';
-import moment from 'moment';
 import ScreenWrapper from '../../../../components/ScreenWrapper';
 import Form from '../../../../components/Form';
 import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
@@ -24,7 +23,6 @@ import compose from '../../../../libs/compose';
 import DateUtils from '../../../../libs/DateUtils';
 import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps} from '../../../../components/withCurrentUserPersonalDetails';
 import personalDetailsPropType from '../../../personalDetailsPropType';
-import {parseISO} from 'date-fns';
 
 const defaultProps = {
     ...withCurrentUserPersonalDetailsDefaultProps,
@@ -60,8 +58,8 @@ const useValidateCustomDate = (data) => {
     const localize = useLocalize();
     const [customDateError, setCustomDateError] = useState('');
     const [customTimeError, setCustomTimeError] = useState('');
-    const validate = (inputData = data) => {
-        const {dateValidationErrorKey, timeValidationErrorKey} = ValidationUtils.validateDateTimeIsAtLeastOneMinuteInFuture(inputData);
+    const validate = () => {
+        const {dateValidationErrorKey, timeValidationErrorKey} = ValidationUtils.validateDateTimeIsAtLeastOneMinuteInFuture(data);
 
         const dateError = dateValidationErrorKey ? localize.translate(dateValidationErrorKey) : '';
         setCustomDateError(dateError);
@@ -76,15 +74,14 @@ const useValidateCustomDate = (data) => {
     };
 
     useEffect(() => {
-        if (data) {
-            validate();
+        if (!data) {
+            return;
         }
+        validate();
         // eslint-disable-next-line react-hooks/exhaustive-deps
     }, [data]);
 
-    const validateCustomDate = (inputData) => {
-        return validate(inputData);
-    };
+    const validateCustomDate = () => validate();
 
     return {customDateError, customTimeError, validateCustomDate};
 };
@@ -116,9 +113,11 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
         [customTimeError, customDateError],
     );
 
-    const onSubmit = (v) => {
+    const onSubmit = () => {
         const {dateError, timeError} = validateCustomDate();
-        if (dateError || timeError) return;
+        if (dateError || timeError) {
+            return;
+        }
         let calculatedDraftDate = '';
         if (draftPeriod === CONST.CUSTOM_STATUS_TYPES.CUSTOM) {
             calculatedDraftDate = customDateTemporary;
@@ -132,7 +131,9 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
 
     const updateMode = useCallback(
         (mode) => {
-            if (mode.value === draftPeriod) return;
+            if (mode.value === draftPeriod) {
+                return;
+            }
             User.updateDraftCustomStatus({
                 customDateTemporary: mode.value === CONST.CUSTOM_STATUS_TYPES.CUSTOM ? DateUtils.getOneHourFromNow() : DateUtils.getDateFromStatusType(mode.value),
             });
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index df366b13d3ac..f47e870e3401 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -51,7 +51,9 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
     const isValidClearAfterDate = useCallback(() => {
         const clearAfterTime = draftClearAfter || currentUserClearAfter;
-        if (clearAfterTime === CONST.CUSTOM_STATUS_TYPES.NEVER) return true;
+        if (clearAfterTime === CONST.CUSTOM_STATUS_TYPES.NEVER) {
+            return true;
+        }
 
         return !DateUtils.hasDateExpired(clearAfterTime);
     }, [draftClearAfter, currentUserClearAfter]);

From 9b44d8630ae5c6cdcda31da129c25ace415a4758 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 26 Sep 2023 17:35:50 +0200
Subject: [PATCH 059/118] fix after merge

---
 src/components/TimePicker.js                                    | 2 +-
 src/pages/settings/Profile/CustomStatus/SetTimePage.js          | 2 +-
 src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js | 2 +-
 src/styles/styles.js                                            | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 30898edeae12..d175da979afc 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -424,7 +424,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                 </View>
             </View>
             <View
-                style={[styles.pageWrapper, styles.pb0]}
+                style={[styles.pageWrapper, styles.pb4]}
                 nativeID={NUM_PAD_CONTAINER_VIEW_ID}
             >
                 {numberPad()}
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index b0319f166426..94d56c285b00 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -64,7 +64,7 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
                     formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_TIME_FORM}
                     onSubmit={onSubmit}
                     submitButtonText={translate('common.save')}
-                    submitButtonContainerStyles={[styles.flex0, styles.justifyContentStart, styles.mh5, styles.setTimeFormButtonContainer, styles.pt3]}
+                    submitButtonContainerStyles={[styles.flex0, styles.justifyContentStart, styles.mh5, styles.setTimeFormButtonContainer]}
                     errorMessageStyle={styles.timePickerButtonErrorText}
                     validate={validate}
                     enabledWhenOffline
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 9916f0fee0a8..aec549356230 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -91,7 +91,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
     const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
     const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
-    const [draftPeriod, setDraftPeriod] = useState(getSelectedStatusType(clearAfter || draftClearAfter));
+    const [draftPeriod, setDraftPeriod] = useState(getSelectedStatusType(draftClearAfter || clearAfter));
     const statusType = useMemo(
         () =>
             _.map(CONST.CUSTOM_STATUS_TYPES, (value, key) => ({
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 12ba2a0c8bca..db6aedaf5522 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3731,7 +3731,7 @@ const styles = (theme) => ({
     },
     timePickerButtonErrorText: {
         position: 'absolute',
-        top: -20,
+        top: -36,
     },
 
     walletCard: {

From f4cd77b6aacc32b322beb179749b04ed1e447ec7 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 26 Sep 2023 17:57:12 +0200
Subject: [PATCH 060/118] clean styles

---
 src/styles/styles.js | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/src/styles/styles.js b/src/styles/styles.js
index db6aedaf5522..2ae262e52f3d 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3463,17 +3463,6 @@ const styles = (theme) => ({
     willChangeTransform: {
         willChange: 'transform',
     },
-    statusClearAfter: {
-        flexDirection: 'row',
-        justifyContent: 'space-between',
-        width: '100%',
-        paddingHorizontal: 20,
-    },
-    statusClearAfterContent: {
-        borderBottomWidth: 1,
-        borderColor: theme.border,
-        paddingVertical: 12,
-    },
 
     dropDownButtonCartIconContainerPadding: {
         paddingRight: 0,

From a095fd01132bc09fb7adeae077a37eb35bbc0788 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 27 Sep 2023 16:20:10 +0200
Subject: [PATCH 061/118] add resetForm functionality for Form, add isDisabled

---
 src/components/Form.js | 34 ++++++++++++++++++++++++++++++----
 1 file changed, 30 insertions(+), 4 deletions(-)

diff --git a/src/components/Form.js b/src/components/Form.js
index 5f2c58436963..0c8cae8bdbd2 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -1,4 +1,4 @@
-import React, {useState, useEffect, useCallback, useMemo, useRef} from 'react';
+import React, {useState, useEffect, useCallback, useMemo, useRef, useImperativeHandle, forwardRef} from 'react';
 import lodashGet from 'lodash/get';
 import {Keyboard, ScrollView, StyleSheet} from 'react-native';
 import PropTypes from 'prop-types';
@@ -24,7 +24,7 @@ const propTypes = {
     formID: PropTypes.string.isRequired,
 
     /** Text to be displayed in the submit button */
-    submitButtonText: PropTypes.string.isRequired,
+    submitButtonText: PropTypes.string,
 
     /** Controls the submit button's visibility */
     isSubmitButtonVisible: PropTypes.bool,
@@ -110,9 +110,10 @@ const defaultProps = {
     validate: () => ({}),
     submitButtonStyle: {},
     submitButtonContainerStyles: [],
+    submitButtonText: '',
 };
 
-function Form(props) {
+const Form = forwardRef((props, forwardedRef) => {
     const [errors, setErrors] = useState({});
     const [inputValues, setInputValues] = useState({...props.draftValues});
     const formRef = useRef(null);
@@ -251,6 +252,30 @@ function Form(props) {
         onSubmit(inputValues);
     }, [props.formState, onSubmit, inputRefs, inputValues, onValidate, touchedInputs, props.network.isOffline, props.enabledWhenOffline]);
 
+    /**
+     * Resets the form
+     */
+    const resetForm = useCallback(
+        (optionalValue) => {
+            _.each(inputValues, (inputRef, inputID) => {
+                setInputValues((prevState) => {
+                    const copyPrevState = _.clone(prevState);
+
+                    touchedInputs.current[inputID] = false;
+                    copyPrevState[inputID] = optionalValue[inputID] || '';
+
+                    return copyPrevState;
+                });
+            });
+            setErrors({});
+        },
+        [props.draftValues, inputValues],
+    );
+
+    useImperativeHandle(forwardedRef, () => ({
+        resetForm,
+    }));
+
     /**
      * Loops over Form's children and automatically supplies Form props to them
      *
@@ -465,6 +490,7 @@ function Form(props) {
                         useSmallerSubmitButtonSize={props.useSmallerSubmitButtonSize}
                         disablePressOnEnter
                         errorMessageStyle={props.errorMessageStyle}
+                        isDisabled={props.isDisabled}
                     />
                 )}
             </FormSubmit>
@@ -540,7 +566,7 @@ function Form(props) {
             }
         </SafeAreaConsumer>
     );
-}
+});
 
 Form.displayName = 'Form';
 Form.propTypes = propTypes;

From 394dba685eebbbae467042973dfef30312994d64 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 27 Sep 2023 16:20:46 +0200
Subject: [PATCH 062/118] change combineDateAndTime

---
 .../EmojiPicker/EmojiPickerButtonDropdown.js         |  2 +-
 src/libs/DateUtils.js                                | 12 ++++++++++--
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
index 3023a9abf95c..0914830cce77 100644
--- a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
+++ b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
@@ -39,7 +39,7 @@ function EmojiPickerButtonDropdown(props) {
         <Tooltip text={props.translate('reportActionCompose.emoji')}>
             <PressableWithoutFeedback
                 ref={emojiPopoverAnchor}
-                style={styles.emojiPickerButtonDropdown}
+                style={[styles.emojiPickerButtonDropdown, props.style]}
                 disabled={props.isDisabled}
                 onPress={onPress}
                 nativeID="emojiDropdownButton"
diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index d2ef790ae749..f3a2210e8740 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -482,7 +482,7 @@ function getStatusUntilDate(inputDate) {
 /**
  * Update the time for a given date.
  *
- * @param {string} updatedTime - Time in "hh:mm A" format (like "10:55 AM").
+ * @param {string} updatedTime - Time in "hh:mm A" or "HH:mm:ss" or "yyyy-MM-dd HH:mm:ss" format.
  * @param {string} inputDateTime - Date in "YYYY-MM-DD HH:mm:ss" or "YYYY-MM-DD" format.
  * @returns {string} - Date with updated time in "YYYY-MM-DD HH:mm:ss" format.
  */
@@ -491,7 +491,14 @@ const combineDateAndTime = (updatedTime, inputDateTime) => {
         return '';
     }
 
-    const parsedTime = parse(updatedTime, 'hh:mm a', new Date());
+    let parsedTime;
+    if (updatedTime.includes('-')) {
+        // it's in "yyyy-MM-dd HH:mm:ss" format
+        parsedTime = parse(updatedTime, 'yyyy-MM-dd HH:mm:ss', new Date());
+    } else if (updatedTime.includes(':')) {
+        // it's in "hh:mm a" format
+        parsedTime = parse(updatedTime, 'hh:mm a', new Date());
+    }
 
     let parsedDateTime;
     if (inputDateTime.includes(':')) {
@@ -504,6 +511,7 @@ const combineDateAndTime = (updatedTime, inputDateTime) => {
     const updatedDateTime = set(parsedDateTime, {
         hours: parsedTime.getHours(),
         minutes: parsedTime.getMinutes(),
+        seconds: parsedTime.getSeconds(),
     });
 
     return format(updatedDateTime, 'yyyy-MM-dd HH:mm:ss');

From 041b7cb20b738326f82d615130f912be55da8413 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 27 Sep 2023 16:27:47 +0200
Subject: [PATCH 063/118] new design

---
 .../CustomStatus/CustomClearAfterPage.js      |   6 +-
 .../Profile/CustomStatus/SetTimePage.js       |  10 +-
 .../CustomStatus/StatusClearAfterPage.js      |  28 ++-
 .../Profile/CustomStatus/StatusPage.js        | 206 +++++++++++-------
 src/styles/styles.js                          |   1 -
 5 files changed, 148 insertions(+), 103 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index 070997b3016b..f820d415ce0d 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -21,10 +21,10 @@ const propTypes = {
 };
 
 function CustomClearAfterPage({translate, customStatus}) {
-    const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
+    const customClearAfter = lodashGet(customStatus, 'clearAfter', '');
 
     const onSubmit = (v) => {
-        User.updateDraftCustomStatus({customDateTemporary: v.dob});
+        User.updateDraftCustomStatus({clearAfter: DateUtils.combineDateAndTime(customClearAfter, v.dob)});
         Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
     };
 
@@ -61,7 +61,7 @@ function CustomClearAfterPage({translate, customStatus}) {
                 <NewDatePicker
                     inputID="dob"
                     label={translate('statusPage.date')}
-                    defaultValue={DateUtils.extractDate(customDateTemporary)}
+                    defaultValue={DateUtils.extractDate(customClearAfter)}
                     minDate={moment().toDate()}
                 />
             </Form>
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 94d56c285b00..1da7e96912dc 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -28,18 +28,18 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
     usePrivatePersonalDetails();
     const {isExtraSmallScreenHeight} = useWindowDimensions();
     const localize = useLocalize();
-    const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
+    const clearAfter = lodashGet(customStatus, 'clearAfter', '');
 
     const onSubmit = ({timePicker}) => {
-        const timeToUse = DateUtils.combineDateAndTime(timePicker, customDateTemporary);
+        const timeToUse = DateUtils.combineDateAndTime(timePicker, clearAfter);
 
-        User.updateDraftCustomStatus({customDateTemporary: timeToUse});
+        User.updateDraftCustomStatus({clearAfter: timeToUse});
         Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
     };
     const validate = (v) => {
         const error = {};
 
-        if (!ValidationUtils.isTimeAtLeastOneMinuteInFuture(v.timePicker, customDateTemporary)) {
+        if (!ValidationUtils.isTimeAtLeastOneMinuteInFuture(v.timePicker, clearAfter)) {
             error.timePicker = localize.translate('common.error.invalidTimeShouldBeFuture');
         }
 
@@ -73,7 +73,7 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
                 >
                     <TimePicker
                         inputID="timePicker"
-                        defaultValue={DateUtils.extractTime12Hour(customDateTemporary)}
+                        defaultValue={DateUtils.extractTime12Hour(clearAfter)}
                         style={styles.flexGrow1}
                     />
                 </Form>
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index aec549356230..a15192912567 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -32,7 +32,6 @@ const propTypes = {
     currentUserPersonalDetails: personalDetailsPropType,
     customStatus: PropTypes.shape({
         clearAfter: PropTypes.string,
-        customDateTemporary: PropTypes.string,
     }),
 };
 
@@ -90,7 +89,6 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const localize = useLocalize();
     const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
     const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
-    const customDateTemporary = lodashGet(customStatus, 'customDateTemporary', '');
     const [draftPeriod, setDraftPeriod] = useState(getSelectedStatusType(draftClearAfter || clearAfter));
     const statusType = useMemo(
         () =>
@@ -99,11 +97,12 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 text: localize.translate(`statusPage.timePeriods.${value}`),
                 keyForList: key,
                 isSelected: draftPeriod === value,
+                value,
             })),
         [draftPeriod, localize],
     );
 
-    const {customDateError, customTimeError, validateCustomDate} = useValidateCustomDate(customDateTemporary);
+    const {customDateError, customTimeError, validateCustomDate} = useValidateCustomDate(draftClearAfter);
 
     const {redBrickDateIndicator, redBrickTimeIndicator} = useMemo(
         () => ({
@@ -120,12 +119,12 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
         }
         let calculatedDraftDate = '';
         if (draftPeriod === CONST.CUSTOM_STATUS_TYPES.CUSTOM) {
-            calculatedDraftDate = customDateTemporary;
+            calculatedDraftDate = draftClearAfter;
         } else {
             const selectedRange = _.find(statusType, (item) => item.isSelected);
             calculatedDraftDate = DateUtils.getDateFromStatusType(selectedRange.value);
         }
-        User.updateDraftCustomStatus({clearAfter: calculatedDraftDate, customDateTemporary: calculatedDraftDate});
+        User.updateDraftCustomStatus({clearAfter: calculatedDraftDate});
         Navigation.goBack(ROUTES.SETTINGS_STATUS);
     };
 
@@ -134,25 +133,30 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
             if (mode.value === draftPeriod) {
                 return;
             }
-            User.updateDraftCustomStatus({
-                customDateTemporary: mode.value === CONST.CUSTOM_STATUS_TYPES.CUSTOM ? DateUtils.getOneHourFromNow() : DateUtils.getDateFromStatusType(mode.value),
-            });
             setDraftPeriod(mode.value);
+
+            if (mode.value === CONST.CUSTOM_STATUS_TYPES.CUSTOM) {
+                User.updateDraftCustomStatus({clearAfter: DateUtils.getOneHourFromNow()});
+            } else {
+                const selectedRange = _.find(statusType, (item) => item.value === mode.value);
+                const calculatedDraftDate = DateUtils.getDateFromStatusType(selectedRange.value);
+                User.updateDraftCustomStatus({clearAfter: calculatedDraftDate});
+                Navigation.goBack(ROUTES.SETTINGS_STATUS);
+            }
         },
         [draftPeriod],
     );
 
     useEffect(() => {
         User.updateDraftCustomStatus({
-            customDateTemporary: draftClearAfter || clearAfter,
             clearAfter: draftClearAfter || clearAfter,
         });
 
         // eslint-disable-next-line react-hooks/exhaustive-deps
     }, []);
 
-    const customStatusDate = DateUtils.extractDate(customDateTemporary);
-    const customStatusTime = DateUtils.extractTime12Hour(customDateTemporary);
+    const customStatusDate = DateUtils.extractDate(draftClearAfter);
+    const customStatusTime = DateUtils.extractTime12Hour(draftClearAfter);
 
     return (
         <ScreenWrapper
@@ -171,7 +175,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 onSubmit={onSubmit}
                 style={styles.flexGrow1}
                 scrollContextEnabled={false}
-                submitButtonStyle={styles.mh5}
+                isSubmitButtonVisible={false}
                 enabledWhenOffline
             >
                 <View>
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index f47e870e3401..1576f1d618b1 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -1,18 +1,15 @@
-import React, {useMemo, useCallback, useEffect, useState} from 'react';
+import React, {useMemo, useCallback, useEffect, useState, useRef} from 'react';
 import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
 import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../../../../components/withCurrentUserPersonalDetails';
 import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription';
-import HeaderPageLayout from '../../../../components/HeaderPageLayout';
 import * as Expensicons from '../../../../components/Icon/Expensicons';
 import withLocalize from '../../../../components/withLocalize';
 import MenuItem from '../../../../components/MenuItem';
-import Button from '../../../../components/Button';
 import Text from '../../../../components/Text';
 import Navigation from '../../../../libs/Navigation/Navigation';
 import * as User from '../../../../libs/actions/User';
-import MobileBackgroundImage from '../../../../../assets/images/money-stack.svg';
 import themeColors from '../../../../styles/themes/default';
 import useLocalize from '../../../../hooks/useLocalize';
 import styles from '../../../../styles/styles';
@@ -21,15 +18,28 @@ import compose from '../../../../libs/compose';
 import ONYXKEYS from '../../../../ONYXKEYS';
 import ROUTES from '../../../../ROUTES';
 import CONST from '../../../../CONST';
-import SCREENS from '../../../../SCREENS';
+import ScreenWrapper from '../../../../components/ScreenWrapper';
+import Form from '../../../../components/Form';
+import TextInput from '../../../../components/TextInput';
+import EmojiPickerButtonDropdown from '../../../../components/EmojiPicker/EmojiPickerButtonDropdown';
+import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
+
+const INPUT_IDS = {
+    EMOJI_CODE: 'emojiCode',
+    STATUS_TEXT: 'statusText',
+};
 
 const propTypes = {
     ...withCurrentUserPersonalDetailsPropTypes,
 };
 
+const initialEmoji = '💬';
+
 function StatusPage({draftStatus, currentUserPersonalDetails}) {
     const localize = useLocalize();
     const [brickRoadIndicator, setBrickRoadIndicator] = useState('');
+    const [isFormDirty, setFormDirty] = useState(false);
+    const formRef = useRef(null);
     const currentUserEmojiCode = lodashGet(currentUserPersonalDetails, 'status.emojiCode', '');
     const currentUserStatusText = lodashGet(currentUserPersonalDetails, 'status.text', '');
     const currentUserClearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
@@ -37,13 +47,9 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
     const draftText = lodashGet(draftStatus, 'text');
     const draftClearAfter = lodashGet(draftStatus, 'clearAfter');
 
-    const defaultEmoji = draftEmojiCode || currentUserEmojiCode;
-    const defaultText = draftEmojiCode ? draftText : currentUserStatusText;
-    const areAllValuesEmpty = !draftEmojiCode && !draftText && !currentUserEmojiCode && !currentUserStatusText;
-    const statusEmojiWithMessage = draftEmojiCode ? `${draftEmojiCode} ${draftText}` : `${currentUserEmojiCode || ''} ${currentUserStatusText || ''}`;
-    const customStatus = areAllValuesEmpty ? '' : statusEmojiWithMessage;
-    const hasDraftStatus =
-        !!draftEmojiCode || !!draftText || ((!!draftEmojiCode || !!currentUserEmojiCode) && !!draftClearAfter && !DateUtils.areDatesIdentical(draftClearAfter, currentUserClearAfter));
+    const defaultEmoji = draftEmojiCode || currentUserEmojiCode || initialEmoji;
+    const defaultText = draftText || currentUserStatusText;
+
     const customClearAfter = useMemo(() => {
         const dataToShow = draftClearAfter || currentUserClearAfter;
         return DateUtils.getLocalizedTimePeriodDescription(dataToShow);
@@ -59,100 +65,136 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
     }, [draftClearAfter, currentUserClearAfter]);
 
     const navigateBackToSettingsPage = useCallback(() => Navigation.goBack(ROUTES.SETTINGS_PROFILE, false, true), []);
-    const updateStatus = useCallback(() => {
-        const clearAfterTime = draftClearAfter || currentUserClearAfter;
-        if (DateUtils.hasDateExpired(clearAfterTime)) {
-            setBrickRoadIndicator(isValidClearAfterDate() ? null : CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR);
-            return;
-        }
+    const updateStatus = useCallback(
+        ({emojiCode, statusText}) => {
+            const clearAfterTime = draftClearAfter || currentUserClearAfter;
+            if (DateUtils.hasDateExpired(clearAfterTime)) {
+                setBrickRoadIndicator(isValidClearAfterDate() ? null : CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR);
+                return;
+            }
 
-        User.updateCustomStatus({
-            text: defaultText,
-            emojiCode: defaultEmoji,
-            clearAfter: clearAfterTime !== CONST.CUSTOM_STATUS_TYPES.NEVER ? clearAfterTime : '',
-        });
+            User.updateCustomStatus({
+                text: statusText,
+                emojiCode: emojiCode,
+                clearAfter: clearAfterTime !== CONST.CUSTOM_STATUS_TYPES.NEVER ? clearAfterTime : '',
+            });
 
-        User.clearDraftCustomStatus();
-        Navigation.goBack(ROUTES.SETTINGS_PROFILE);
-    }, [defaultText, defaultEmoji, currentUserClearAfter, draftClearAfter, isValidClearAfterDate]);
+            User.clearDraftCustomStatus();
+            Navigation.goBack(ROUTES.SETTINGS_PROFILE);
+        },
+        [currentUserClearAfter, draftClearAfter, isValidClearAfterDate],
+    );
 
     const clearStatus = () => {
         User.clearCustomStatus();
         User.updateDraftCustomStatus({
             text: '',
-            emojiCode: '',
+            emojiCode: initialEmoji,
             clearAfter: DateUtils.getEndOfToday(),
-            customDateTemporary: '',
         });
+        formRef.current.resetForm({[INPUT_IDS.EMOJI_CODE]: initialEmoji});
     };
 
-    const footerComponent = useMemo(
-        () =>
-            hasDraftStatus && isValidClearAfterDate() ? (
-                <Button
-                    success
-                    text={localize.translate('statusPage.save')}
-                    onPress={updateStatus}
-                />
-            ) : null,
-        [hasDraftStatus, localize, updateStatus, isValidClearAfterDate],
-    );
-
     useEffect(() => setBrickRoadIndicator(isValidClearAfterDate() ? null : CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR), [isValidClearAfterDate]);
+
     useEffect(() => {
         if (!currentUserEmojiCode && !currentUserClearAfter && !draftClearAfter) {
             User.updateDraftCustomStatus({clearAfter: DateUtils.getEndOfToday()});
+        } else {
+            User.updateDraftCustomStatus({clearAfter: currentUserClearAfter});
         }
 
         return () => User.clearDraftCustomStatus();
         // eslint-disable-next-line react-hooks/exhaustive-deps
     }, []);
 
+    const checkIfFormIsDirty = useCallback(
+        ({emojiCode, statusText}) => {
+            const isDirty = currentUserEmojiCode !== emojiCode || currentUserStatusText !== statusText || currentUserClearAfter !== draftClearAfter;
+            setFormDirty(isDirty);
+        },
+        [currentUserEmojiCode, currentUserStatusText, currentUserClearAfter, draftClearAfter],
+    );
+
+    useEffect(() => {
+        setFormDirty(!!brickRoadIndicator || currentUserClearAfter !== draftClearAfter);
+    }, [checkIfFormIsDirty, brickRoadIndicator]);
+
+
+    const validateForm = useCallback((v) => {
+      checkIfFormIsDirty(v);
+
+      if (brickRoadIndicator) {
+          return {clearAfter: ''};
+      }
+      return {};
+  }, [brickRoadIndicator, checkIfFormIsDirty]);
     return (
-        <HeaderPageLayout
-            title={localize.translate('statusPage.status')}
-            onBackButtonPress={navigateBackToSettingsPage}
-            headerContent={
-                <MobileBackgroundImage
-                    pointerEvents="none"
-                    style={styles.staticHeaderImage}
-                />
-            }
-            headerContainerStyles={[styles.staticHeaderImage]}
-            backgroundColor={themeColors.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.STATUS]}
-            footer={footerComponent}
+        <ScreenWrapper
+            testID={StatusPage.displayName}
+            includeSafeAreaPaddingBottom={false}
+            shouldEnableMaxHeight
         >
-            <View style={styles.m5}>
-                <Text style={[styles.textHeadline]}>{localize.translate('statusPage.setStatusTitle')}</Text>
-                <Text style={[styles.textNormal, styles.mt2]}>{localize.translate('statusPage.statusExplanation')}</Text>
-            </View>
-            <MenuItemWithTopDescription
-                title={customStatus}
-                description={localize.translate('statusPage.status')}
-                shouldShowRightIcon
-                containerStyle={styles.pr2}
-                inputID="test"
-                onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_SET)}
+            <HeaderWithBackButton
+                title={localize.translate('statusPage.status')}
+                onBackButtonPress={navigateBackToSettingsPage}
             />
-            <MenuItemWithTopDescription
-                title={customClearAfter}
-                description={localize.translate('statusPage.clearAfter')}
-                shouldShowRightIcon
-                onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
-                containerStyle={styles.pr2}
-                brickRoadIndicator={brickRoadIndicator}
-            />
-
-            {(!!currentUserEmojiCode || !!currentUserStatusText) && (
-                <MenuItem
-                    title={localize.translate('statusPage.clearStatus')}
-                    icon={Expensicons.Close}
-                    onPress={clearStatus}
-                    iconFill={themeColors.danger}
-                    wrapperStyle={[styles.cardMenuItem]}
-                />
-            )}
-        </HeaderPageLayout>
+            <Form
+                formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_FORM}
+                style={styles.flexGrow1}
+                ref={formRef}
+                submitButtonText={localize.translate('statusPage.save')}
+                submitButtonStyle={styles.mh5}
+                onSubmit={updateStatus}
+                validate={validateForm}
+                enabledWhenOffline
+                isDisabled={!isFormDirty}
+            >
+                <View style={styles.mh5}>
+                    <Text style={[styles.textHeadline]}>{localize.translate('statusPage.setStatusTitle')}</Text>
+                    <Text style={[styles.textNormal, styles.mt2]}>{localize.translate('statusPage.statusExplanation')}</Text>
+                </View>
+                <View style={[styles.mb2, styles.mt6]}>
+                    <View style={[styles.mb4, styles.ph5]}>
+                        <EmojiPickerButtonDropdown
+                            inputID={INPUT_IDS.EMOJI_CODE}
+                            accessibilityLabel={INPUT_IDS.EMOJI_CODE}
+                            accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
+                            defaultValue={defaultEmoji}
+                            style={styles.mb3}
+                        />
+                        <TextInput
+                            inputID={INPUT_IDS.STATUS_TEXT}
+                            label={localize.translate('statusPage.message')}
+                            accessibilityLabel={INPUT_IDS.STATUS_TEXT}
+                            accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
+                            defaultValue={defaultText}
+                            maxLength={CONST.STATUS_TEXT_MAX_LENGTH}
+                            autoFocus
+                            shouldDelayFocus
+                        />
+                    </View>
+                    <MenuItemWithTopDescription
+                        title={customClearAfter}
+                        description={localize.translate('statusPage.clearAfter')}
+                        shouldShowRightIcon
+                        onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
+                        containerStyle={styles.pr2}
+                        brickRoadIndicator={brickRoadIndicator}
+                    />
+
+                    {(!!currentUserEmojiCode || !!currentUserStatusText) && (
+                        <MenuItem
+                            title={localize.translate('statusPage.clearStatus')}
+                            icon={Expensicons.Trashcan}
+                            onPress={clearStatus}
+                            iconFill={themeColors.danger}
+                            wrapperStyle={[styles.cardMenuItem]}
+                        />
+                    )}
+                </View>
+            </Form>
+        </ScreenWrapper>
     );
 }
 
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 2ae262e52f3d..31ce23c06973 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -3490,7 +3490,6 @@ const styles = (theme) => ({
         alignItems: 'center',
         paddingLeft: 10,
         paddingRight: 4,
-        marginBottom: 32,
         alignSelf: 'flex-start',
     },
 

From 78bc2e5f6c02775d3a3798bb400cc02e663bed12 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 27 Sep 2023 16:52:43 +0200
Subject: [PATCH 064/118] delete StatusSetPage

---
 .../Profile/CustomStatus/StatusSetPage.js     | 102 ------------------
 1 file changed, 102 deletions(-)
 delete mode 100644 src/pages/settings/Profile/CustomStatus/StatusSetPage.js

diff --git a/src/pages/settings/Profile/CustomStatus/StatusSetPage.js b/src/pages/settings/Profile/CustomStatus/StatusSetPage.js
deleted file mode 100644
index 9d59ceff105d..000000000000
--- a/src/pages/settings/Profile/CustomStatus/StatusSetPage.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import React from 'react';
-import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
-import {withOnyx} from 'react-native-onyx';
-import Form from '../../../../components/Form';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import ROUTES from '../../../../ROUTES';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import compose from '../../../../libs/compose';
-import styles from '../../../../styles/styles';
-import useLocalize from '../../../../hooks/useLocalize';
-import CONST from '../../../../CONST';
-import EmojiPickerButtonDropdown from '../../../../components/EmojiPicker/EmojiPickerButtonDropdown';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import * as User from '../../../../libs/actions/User';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../../../../components/withCurrentUserPersonalDetails';
-import TextInput from '../../../../components/TextInput';
-
-const propTypes = {
-    /** The draft status of the user */
-    // eslint-disable-next-line react/require-default-props
-    draftStatus: PropTypes.shape({
-        /** The emoji code of the draft status */
-        emojiCode: PropTypes.string,
-        /** The text of the draft status */
-        text: PropTypes.string,
-    }),
-
-    ...withCurrentUserPersonalDetailsPropTypes,
-};
-
-const INPUT_IDS = {
-    EMOJI_CODE: 'emojiCode',
-    STATUS_TEXT: 'statusText',
-};
-
-function StatusSetPage({draftStatus, currentUserPersonalDetails}) {
-    const {translate} = useLocalize();
-    const defaultEmoji = lodashGet(draftStatus, 'emojiCode') || lodashGet(currentUserPersonalDetails, 'status.emojiCode', '💬');
-    const defaultText = lodashGet(draftStatus, 'text') || lodashGet(currentUserPersonalDetails, 'status.text', '');
-
-    const onSubmit = (value) => {
-        User.updateDraftCustomStatus({text: value.statusText.trim(), emojiCode: value.emojiCode});
-        Navigation.goBack(ROUTES.SETTINGS_STATUS);
-    };
-
-    return (
-        <ScreenWrapper
-            testID={StatusSetPage.displayName}
-            includeSafeAreaPaddingBottom={false}
-            shouldEnableMaxHeight
-        >
-            <HeaderWithBackButton
-                title={translate('statusPage.status')}
-                onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS)}
-            />
-            <Form
-                formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_FORM}
-                style={[styles.flexGrow1, styles.ph5]}
-                submitButtonText={translate('statusPage.save')}
-                onSubmit={onSubmit}
-                enabledWhenOffline
-            >
-                <View>
-                    <View style={[styles.mb4]}>
-                        <View style={[styles.mt1]}>
-                            <EmojiPickerButtonDropdown
-                                inputID={INPUT_IDS.EMOJI_CODE}
-                                accessibilityLabel={INPUT_IDS.EMOJI_CODE}
-                                defaultValue={defaultEmoji}
-                            />
-                        </View>
-                        <TextInput
-                            inputID={INPUT_IDS.STATUS_TEXT}
-                            label={translate('statusPage.message')}
-                            accessibilityLabel={INPUT_IDS.STATUS_TEXT}
-                            accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
-                            defaultValue={defaultText}
-                            maxLength={CONST.STATUS_TEXT_MAX_LENGTH}
-                            autoFocus
-                            shouldDelayFocus
-                        />
-                    </View>
-                </View>
-            </Form>
-        </ScreenWrapper>
-    );
-}
-
-StatusSetPage.displayName = 'StatusSetPage';
-StatusSetPage.propTypes = propTypes;
-
-export default compose(
-    withCurrentUserPersonalDetails,
-    withOnyx({
-        draftStatus: {
-            key: ONYXKEYS.CUSTOM_STATUS_DRAFT,
-        },
-    }),
-)(StatusSetPage);

From bd517b4f27e70d6b7dfd0fb12cf3367ef4f3fc5b Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 27 Sep 2023 17:13:27 +0200
Subject: [PATCH 065/118] lint

---
 src/components/Form.js                        |  3 ++-
 .../AppNavigator/ModalStackNavigators.js      |  1 -
 .../CustomStatus/StatusClearAfterPage.js      |  4 +---
 .../Profile/CustomStatus/StatusPage.js        | 22 ++++++++++---------
 4 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/src/components/Form.js b/src/components/Form.js
index 0c8cae8bdbd2..1b810c85fb73 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -269,7 +269,7 @@ const Form = forwardRef((props, forwardedRef) => {
             });
             setErrors({});
         },
-        [props.draftValues, inputValues],
+        [inputValues],
     );
 
     useImperativeHandle(forwardedRef, () => ({
@@ -516,6 +516,7 @@ const Form = forwardRef((props, forwardedRef) => {
             props.submitButtonStyle,
             props.useSmallerSubmitButtonSize,
             props.errorMessageStyle,
+            props.isDisabled,
         ],
     );
 
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
index a2990bd850c6..2ba799a93686 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
@@ -147,7 +147,6 @@ const SettingsModalStackNavigator = createModalStackNavigator({
     Settings_Add_Debit_Card: () => require('../../../pages/settings/Wallet/AddDebitCardPage').default,
     Settings_Add_Bank_Account: () => require('../../../pages/AddPersonalBankAccountPage').default,
     [SCREENS.SETTINGS.STATUS]: () => require('../../../pages/settings/Profile/CustomStatus/StatusPage').default,
-    Settings_Status_Set: () => require('../../../pages/settings/Profile/CustomStatus/StatusSetPage').default,
     Settings_Status_Clear_After: () => require('../../../pages/settings/Profile/CustomStatus/StatusClearAfterPage').default,
     Settings_Status_Clear_After_Custom: () => require('../../../pages/settings/Profile/CustomStatus/CustomClearAfterPage').default,
     Settings_Status_Clear_After_Time: () => require('../../../pages/settings/Profile/CustomStatus/SetTimePage').default,
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index a15192912567..48cdb69f7682 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -97,7 +97,6 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 text: localize.translate(`statusPage.timePeriods.${value}`),
                 keyForList: key,
                 isSelected: draftPeriod === value,
-                value,
             })),
         [draftPeriod, localize],
     );
@@ -144,7 +143,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 Navigation.goBack(ROUTES.SETTINGS_STATUS);
             }
         },
-        [draftPeriod],
+        [draftPeriod, statusType],
     );
 
     useEffect(() => {
@@ -184,7 +183,6 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                         onSelectRow={updateMode}
                         disableInitialFocusOptionStyle
                         wrapperStyle={{flex: null}}
-                        scrollEnabled={false}
                         useSeparator
                     />
 
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 6cead9fbd3bc..fc0a466c751f 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -75,7 +75,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
             User.updateCustomStatus({
                 text: statusText,
-                emojiCode: emojiCode,
+                emojiCode,
                 clearAfter: clearAfterTime !== CONST.CUSTOM_STATUS_TYPES.NEVER ? clearAfterTime : '',
             });
 
@@ -118,17 +118,19 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
     useEffect(() => {
         setFormDirty(!!brickRoadIndicator || currentUserClearAfter !== draftClearAfter);
-    }, [checkIfFormIsDirty, brickRoadIndicator]);
+    }, [currentUserClearAfter, draftClearAfter, brickRoadIndicator]);
 
+    const validateForm = useCallback(
+        (v) => {
+            checkIfFormIsDirty(v);
 
-    const validateForm = useCallback((v) => {
-      checkIfFormIsDirty(v);
-
-      if (brickRoadIndicator) {
-          return {clearAfter: ''};
-      }
-      return {};
-  }, [brickRoadIndicator, checkIfFormIsDirty]);
+            if (brickRoadIndicator) {
+                return {clearAfter: ''};
+            }
+            return {};
+        },
+        [brickRoadIndicator, checkIfFormIsDirty],
+    );
     return (
         <ScreenWrapper
             testID={StatusPage.displayName}

From b4166e63160af0f696924a4d70962b8b358e3dc2 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 27 Sep 2023 17:27:56 +0200
Subject: [PATCH 066/118] add translation

---
 src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 48cdb69f7682..2583168ff542 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -167,7 +167,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 title="Status"
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS)}
             />
-            <Text style={[styles.textNormal, styles.mh5, styles.mv4]}>When should we clear your status?</Text>
+            <Text style={[styles.textNormal, styles.mh5, styles.mv4]}>{localize.translate('statusPage.whenClearStatus')}</Text>
             <Form
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_CLEAR_AFTER_FORM}
                 submitButtonText="Save"

From c702bcea908875eb6eaf7c56c988c795d78b6b59 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 27 Sep 2023 18:14:12 +0200
Subject: [PATCH 067/118] fix validation

---
 src/pages/settings/Profile/CustomStatus/StatusPage.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index fc0a466c751f..d8dbc389d098 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -89,7 +89,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
         User.clearCustomStatus();
         User.updateDraftCustomStatus({
             text: '',
-            emojiCode: initialEmoji,
+            emojiCode: '',
             clearAfter: DateUtils.getEndOfToday(),
         });
         formRef.current.resetForm({[INPUT_IDS.EMOJI_CODE]: initialEmoji});
@@ -110,7 +110,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
     const checkIfFormIsDirty = useCallback(
         ({emojiCode, statusText}) => {
-            const isDirty = currentUserEmojiCode !== emojiCode || currentUserStatusText !== statusText || currentUserClearAfter !== draftClearAfter;
+            const isDirty = currentUserEmojiCode !== emojiCode || currentUserStatusText !== statusText || currentUserClearAfter !== draftClearAfter || initialEmoji === emojiCode;
             setFormDirty(isDirty);
         },
         [currentUserEmojiCode, currentUserStatusText, currentUserClearAfter, draftClearAfter],

From 741a97952d48f90438348e0e4f7f552c72ca28ca Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 27 Sep 2023 20:04:52 +0200
Subject: [PATCH 068/118] remove SelectionList

---
 .../CustomStatus/StatusClearAfterPage.js      | 25 ++++++++++++-------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 2583168ff542..fd6f9005362a 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -12,7 +12,7 @@ import Navigation from '../../../../libs/Navigation/Navigation';
 import styles from '../../../../styles/styles';
 import Text from '../../../../components/Text';
 import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription';
-import SelectionList from '../../../../components/SelectionList';
+import RadioListItem from '../../../../components/SelectionList/RadioListItem';
 import useLocalize from '../../../../hooks/useLocalize';
 import ONYXKEYS from '../../../../ONYXKEYS';
 import CONST from '../../../../CONST';
@@ -157,6 +157,20 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const customStatusDate = DateUtils.extractDate(draftClearAfter);
     const customStatusTime = DateUtils.extractTime12Hour(draftClearAfter);
 
+    const timePeriodOptions = useCallback(
+        () =>
+            statusType.map((item, index) => {
+                return (
+                    <RadioListItem
+                        item={item}
+                        key={index}
+                        onSelectRow={() => updateMode(item)}
+                    />
+                );
+            }),
+        [statusType, updateMode],
+    );
+
     return (
         <ScreenWrapper
             includeSafeAreaPaddingBottom={false}
@@ -178,14 +192,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 enabledWhenOffline
             >
                 <View>
-                    <SelectionList
-                        sections={[{data: statusType, indexOffset: 0}]}
-                        onSelectRow={updateMode}
-                        disableInitialFocusOptionStyle
-                        wrapperStyle={{flex: null}}
-                        useSeparator
-                    />
-
+                    {timePeriodOptions()}
                     {draftPeriod === CONST.CUSTOM_STATUS_TYPES.CUSTOM && (
                         <>
                             <MenuItemWithTopDescription

From 9d19aa50d2efe9f6cbc37a577c63b01a95168456 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 28 Sep 2023 09:53:11 +0200
Subject: [PATCH 069/118] fix style errors

---
 src/ROUTES.ts                                 |  6 ++---
 src/components/AmountTextInput.js             |  5 ++--
 .../EmojiPicker/EmojiPickerButtonDropdown.js  |  3 ++-
 src/components/Form.js                        |  3 ++-
 .../CustomStatus/StatusClearAfterPage.js      | 18 +++++++-------
 .../Profile/CustomStatus/StatusPage.js        | 24 +++++++++----------
 6 files changed, 30 insertions(+), 29 deletions(-)

diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index c4269af477dc..745179f981ca 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -93,9 +93,9 @@ export default {
     SETTINGS_2FA: 'settings/security/two-factor-auth',
     SETTINGS_STATUS: 'settings/profile/status',
     SETTINGS_STATUS_SET: 'settings/profile/status/set',
-    SETTINGS_STATUS_CLEAR_AFTER:                'settings/profile/status/clear-after',
-    SETTINGS_STATUS_CLEAR_AFTER_CUSTOM:         'settings/profile/status/clear-after/custom',
-    SETTINGS_STATUS_CLEAR_AFTER_TIME:           'settings/profile/status/clear-after/time',
+    SETTINGS_STATUS_CLEAR_AFTER: 'settings/profile/status/clear-after',
+    SETTINGS_STATUS_CLEAR_AFTER_CUSTOM: 'settings/profile/status/clear-after/custom',
+    SETTINGS_STATUS_CLEAR_AFTER_TIME: 'settings/profile/status/clear-after/time',
 
     NEW: 'new',
     NEW_CHAT: 'new/chat',
diff --git a/src/components/AmountTextInput.js b/src/components/AmountTextInput.js
index 649ff86ce81b..1107ffdf4adb 100644
--- a/src/components/AmountTextInput.js
+++ b/src/components/AmountTextInput.js
@@ -1,5 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
+import * as StyleUtils from '../styles/StyleUtils';
 import TextInput from './TextInput';
 import styles from '../styles/styles';
 import CONST from '../CONST';
@@ -52,7 +53,7 @@ function AmountTextInput(props) {
             disableKeyboard
             autoGrow
             hideFocusedState
-            inputStyle={[styles.iouAmountTextInput, styles.p0, styles.noLeftBorderRadius, styles.noRightBorderRadius, props.style]}
+            inputStyle={[styles.iouAmountTextInput, styles.p0, styles.noLeftBorderRadius, styles.noRightBorderRadius, ...StyleUtils.parseStyleAsArray(props.style)]}
             textInputContainerStyles={[styles.borderNone, styles.noLeftBorderRadius, styles.noRightBorderRadius]}
             onChangeText={props.onChangeAmount}
             ref={props.forwardedRef}
@@ -64,7 +65,7 @@ function AmountTextInput(props) {
             onSelectionChange={props.onSelectionChange}
             accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
             onKeyPress={props.onKeyPress}
-            containerStyles={props.containerStyles}
+            containerStyles={[...StyleUtils.parseStyleAsArray(props.containerStyles)]}
         />
     );
 }
diff --git a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
index 0914830cce77..a25d36e0409b 100644
--- a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
+++ b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
@@ -1,6 +1,7 @@
 import React, {useRef, useEffect} from 'react';
 import PropTypes from 'prop-types';
 import {View} from 'react-native';
+import _ from 'lodash';
 import styles from '../../styles/styles';
 import CONST from '../../CONST';
 import * as StyleUtils from '../../styles/StyleUtils';
@@ -29,7 +30,7 @@ function EmojiPickerButtonDropdown(props) {
     useEffect(() => EmojiPickerAction.resetEmojiPopoverAnchor, []);
 
     const onPress = () =>
-        EmojiPickerAction.showEmojiPicker(props.onModalHide, (emoji) => props.onInputChange(emoji), emojiPopoverAnchor.current, {
+        EmojiPickerAction.showEmojiPicker(props.onModalHide, (emoji) => props.onInputChange(_.isArray(emoji) ? emoji[0] : emoji), emojiPopoverAnchor.current, {
             horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
             vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
             shiftVertical: 4,
diff --git a/src/components/Form.js b/src/components/Form.js
index 1b810c85fb73..fb413bb80bfe 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -4,6 +4,7 @@ import {Keyboard, ScrollView, StyleSheet} from 'react-native';
 import PropTypes from 'prop-types';
 import _ from 'underscore';
 import {withOnyx} from 'react-native-onyx';
+import * as StyleUtils from '../styles/StyleUtils';
 import compose from '../libs/compose';
 import withLocalize, {withLocalizePropTypes} from './withLocalize';
 import * as FormActions from '../libs/actions/FormActions';
@@ -486,7 +487,7 @@ const Form = forwardRef((props, forwardedRef) => {
                         containerStyles={[styles.mh0, styles.mt5, styles.flex1, ...props.submitButtonContainerStyles]}
                         enabledWhenOffline={props.enabledWhenOffline}
                         isSubmitActionDangerous={props.isSubmitActionDangerous}
-                        buttonStyles={[props.submitButtonStyle]}
+                        buttonStyles={[...StyleUtils.parseStyleAsArray(props.submitButtonStyle)]}
                         useSmallerSubmitButtonSize={props.useSmallerSubmitButtonSize}
                         disablePressOnEnter
                         errorMessageStyle={props.errorMessageStyle}
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index fd6f9005362a..ecc9dbfed56c 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -159,15 +159,13 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
 
     const timePeriodOptions = useCallback(
         () =>
-            statusType.map((item, index) => {
-                return (
-                    <RadioListItem
-                        item={item}
-                        key={index}
-                        onSelectRow={() => updateMode(item)}
-                    />
-                );
-            }),
+            _.map(statusType, (item, index) => (
+                <RadioListItem
+                    item={item}
+                    key={`${index}+${item.value}`}
+                    onSelectRow={() => updateMode(item)}
+                />
+            )),
         [statusType, updateMode],
     );
 
@@ -186,7 +184,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_CLEAR_AFTER_FORM}
                 submitButtonText="Save"
                 onSubmit={onSubmit}
-                style={styles.flexGrow1}
+                style={[styles.flexGrow1, styles.mb4]}
                 scrollContextEnabled={false}
                 isSubmitButtonVisible={false}
                 enabledWhenOffline
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index d8dbc389d098..6d4032a24fef 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -3,26 +3,26 @@ import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
 import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../../../../components/withCurrentUserPersonalDetails';
+import EmojiPickerButtonDropdown from '../../../../components/EmojiPicker/EmojiPickerButtonDropdown';
 import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription';
+import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
 import * as Expensicons from '../../../../components/Icon/Expensicons';
+import ScreenWrapper from '../../../../components/ScreenWrapper';
 import withLocalize from '../../../../components/withLocalize';
-import Text from '../../../../components/Text';
+import TextInput from '../../../../components/TextInput';
 import MenuItem from '../../../../components/MenuItem';
+import Form from '../../../../components/Form';
+import Text from '../../../../components/Text';
 import Navigation from '../../../../libs/Navigation/Navigation';
 import * as User from '../../../../libs/actions/User';
-import themeColors from '../../../../styles/themes/default';
 import useLocalize from '../../../../hooks/useLocalize';
-import styles from '../../../../styles/styles';
 import DateUtils from '../../../../libs/DateUtils';
 import compose from '../../../../libs/compose';
+import themeColors from '../../../../styles/themes/default';
+import styles from '../../../../styles/styles';
 import ONYXKEYS from '../../../../ONYXKEYS';
 import ROUTES from '../../../../ROUTES';
 import CONST from '../../../../CONST';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import Form from '../../../../components/Form';
-import TextInput from '../../../../components/TextInput';
-import EmojiPickerButtonDropdown from '../../../../components/EmojiPicker/EmojiPickerButtonDropdown';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
 
 const INPUT_IDS = {
     EMOJI_CODE: 'emojiCode',
@@ -64,7 +64,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
         return !DateUtils.hasDateExpired(clearAfterTime);
     }, [draftClearAfter, currentUserClearAfter]);
 
-    const navigateBackToSettingsPage = useCallback(() => Navigation.goBack(ROUTES.SETTINGS_PROFILE, false, true), []);
+    const navigateBackToPreviousScreen = useCallback(() => Navigation.goBack(ROUTES.SETTINGS_PROFILE, false, true), []);
     const updateStatus = useCallback(
         ({emojiCode, statusText}) => {
             const clearAfterTime = draftClearAfter || currentUserClearAfter;
@@ -80,9 +80,9 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
             });
 
             User.clearDraftCustomStatus();
-            Navigation.goBack(ROUTES.SETTINGS_PROFILE);
+            navigateBackToPreviousScreen();
         },
-        [currentUserClearAfter, draftClearAfter, isValidClearAfterDate],
+        [currentUserClearAfter, draftClearAfter, isValidClearAfterDate, navigateBackToPreviousScreen],
     );
 
     const clearStatus = () => {
@@ -139,7 +139,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
         >
             <HeaderWithBackButton
                 title={localize.translate('statusPage.status')}
-                onBackButtonPress={navigateBackToSettingsPage}
+                onBackButtonPress={navigateBackToPreviousScreen}
             />
             <Form
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_FORM}

From f12461f9c7f137a1b86fbef97c5f40fd0c6ec099 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Fri, 29 Sep 2023 12:20:11 +0200
Subject: [PATCH 070/118] remove disabling

---
 src/components/Form.js                        |  2 --
 .../Profile/CustomStatus/StatusPage.js        | 31 ++++---------------
 2 files changed, 6 insertions(+), 27 deletions(-)

diff --git a/src/components/Form.js b/src/components/Form.js
index fb413bb80bfe..0711d098060d 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -491,7 +491,6 @@ const Form = forwardRef((props, forwardedRef) => {
                         useSmallerSubmitButtonSize={props.useSmallerSubmitButtonSize}
                         disablePressOnEnter
                         errorMessageStyle={props.errorMessageStyle}
-                        isDisabled={props.isDisabled}
                     />
                 )}
             </FormSubmit>
@@ -517,7 +516,6 @@ const Form = forwardRef((props, forwardedRef) => {
             props.submitButtonStyle,
             props.useSmallerSubmitButtonSize,
             props.errorMessageStyle,
-            props.isDisabled,
         ],
     );
 
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 6d4032a24fef..2018871422e4 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -38,7 +38,6 @@ const initialEmoji = '💬';
 function StatusPage({draftStatus, currentUserPersonalDetails}) {
     const localize = useLocalize();
     const [brickRoadIndicator, setBrickRoadIndicator] = useState('');
-    const [isFormDirty, setFormDirty] = useState(false);
     const formRef = useRef(null);
     const currentUserEmojiCode = lodashGet(currentUserPersonalDetails, 'status.emojiCode', '');
     const currentUserStatusText = lodashGet(currentUserPersonalDetails, 'status.text', '');
@@ -108,29 +107,12 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
         // eslint-disable-next-line react-hooks/exhaustive-deps
     }, []);
 
-    const checkIfFormIsDirty = useCallback(
-        ({emojiCode, statusText}) => {
-            const isDirty = currentUserEmojiCode !== emojiCode || currentUserStatusText !== statusText || currentUserClearAfter !== draftClearAfter || initialEmoji === emojiCode;
-            setFormDirty(isDirty);
-        },
-        [currentUserEmojiCode, currentUserStatusText, currentUserClearAfter, draftClearAfter],
-    );
-
-    useEffect(() => {
-        setFormDirty(!!brickRoadIndicator || currentUserClearAfter !== draftClearAfter);
-    }, [currentUserClearAfter, draftClearAfter, brickRoadIndicator]);
-
-    const validateForm = useCallback(
-        (v) => {
-            checkIfFormIsDirty(v);
-
-            if (brickRoadIndicator) {
-                return {clearAfter: ''};
-            }
-            return {};
-        },
-        [brickRoadIndicator, checkIfFormIsDirty],
-    );
+    const validateForm = useCallback(() => {
+        if (brickRoadIndicator) {
+            return {clearAfter: ''};
+        }
+        return {};
+    }, [brickRoadIndicator]);
     return (
         <ScreenWrapper
             testID={StatusPage.displayName}
@@ -150,7 +132,6 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                 onSubmit={updateStatus}
                 validate={validateForm}
                 enabledWhenOffline
-                isDisabled={!isFormDirty}
             >
                 <View style={styles.mh5}>
                     <Text style={[styles.textHeadline]}>{localize.translate('statusPage.setStatusTitle')}</Text>

From 318726591185e8271f8c1c5c0da105212dfd2388 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 4 Oct 2023 14:34:02 +0200
Subject: [PATCH 071/118] fix after merge

---
 .../settings/Profile/CustomStatus/StatusClearAfterPage.js     | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index ecc9dbfed56c..dbb8d7b73a65 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -12,7 +12,6 @@ import Navigation from '../../../../libs/Navigation/Navigation';
 import styles from '../../../../styles/styles';
 import Text from '../../../../components/Text';
 import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription';
-import RadioListItem from '../../../../components/SelectionList/RadioListItem';
 import useLocalize from '../../../../hooks/useLocalize';
 import ONYXKEYS from '../../../../ONYXKEYS';
 import CONST from '../../../../CONST';
@@ -23,6 +22,7 @@ import compose from '../../../../libs/compose';
 import DateUtils from '../../../../libs/DateUtils';
 import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps} from '../../../../components/withCurrentUserPersonalDetails';
 import personalDetailsPropType from '../../../personalDetailsPropType';
+import BaseListItem from '../../../../components/SelectionList/BaseListItem';
 
 const defaultProps = {
     ...withCurrentUserPersonalDetailsDefaultProps,
@@ -160,7 +160,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const timePeriodOptions = useCallback(
         () =>
             _.map(statusType, (item, index) => (
-                <RadioListItem
+                <BaseListItem
                     item={item}
                     key={`${index}+${item.value}`}
                     onSelectRow={() => updateMode(item)}

From 798da59e755b5627439b1ba8303c09c9838b8e44 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 11 Oct 2023 12:19:36 +0200
Subject: [PATCH 072/118] storybook: add error text for MenuItem

---
 src/stories/MenuItem.stories.js | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/stories/MenuItem.stories.js b/src/stories/MenuItem.stories.js
index 7046617fe2ae..73df9cb35366 100644
--- a/src/stories/MenuItem.stories.js
+++ b/src/stories/MenuItem.stories.js
@@ -128,6 +128,17 @@ BrickRoadIndicatorFailure.args = {
     brickRoadIndicator: 'error',
 };
 
+const ErrorMessage = Template.bind({});
+ErrorMessage.args = {
+    title: 'Alberta Bobbeth Charleson',
+    icon: Chase,
+    iconHeight: variables.iconSizeExtraLarge,
+    iconWidth: variables.iconSizeExtraLarge,
+    shouldShowRightIcon: true,
+    errorText: 'Error text which describes the error',
+    brickRoadIndicator: 'error',
+};
+
 export default story;
 export {
     Default,
@@ -141,4 +152,5 @@ export {
     BrickRoadIndicatorSuccess,
     BrickRoadIndicatorFailure,
     RightIconAndDescriptionWithLabel,
+    ErrorMessage,
 };

From 816af0883f0e883b894834c6dd6acdca7bbbd232 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 11 Oct 2023 12:22:39 +0200
Subject: [PATCH 073/118] ts

---
 src/libs/DateUtils.ts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts
index b3675a6f8242..3de65ddb7d8f 100644
--- a/src/libs/DateUtils.ts
+++ b/src/libs/DateUtils.ts
@@ -635,7 +635,6 @@ const DateUtils = {
     combineDateAndTime,
     getDateValidationErrorKey,
     getTimeValidationErrorKey,
-    setLocale,
     isToday,
     isTomorrow,
     isYesterday,

From a11b34347569d9f764564fc9f44967ea7b3ecfe7 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 16 Oct 2023 21:30:42 +0200
Subject: [PATCH 074/118] Simplified code

---
 src/components/TimePicker.js |  2 --
 src/libs/DateUtils.ts        | 21 +++++++++++----------
 src/libs/ValidationUtils.ts  | 26 +++++---------------------
 3 files changed, 16 insertions(+), 33 deletions(-)

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index d175da979afc..563040520ab5 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -44,8 +44,6 @@ const NUM_PAD_VIEW_ID = 'numPadView';
 
 function formatHour(hourText) {
     // If the integer value of hour is greater than 12, return the second digit with a leading 0
-
-    // return twoDigitHour;
     const hourNumber = parseInt(hourText, 10);
 
     // If the integer value of hour is greater than 12, subtract 10
diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts
index 3de65ddb7d8f..7b80cbe59bed 100644
--- a/src/libs/DateUtils.ts
+++ b/src/libs/DateUtils.ts
@@ -19,8 +19,9 @@ import {
     addHours,
     parse,
     set,
-    isSameMinute,
+    isSameSecond,
     isValid,
+    getDayOfYear,
 } from 'date-fns';
 import Onyx from 'react-native-onyx';
 import throttle from 'lodash/throttle';
@@ -512,9 +513,9 @@ const combineDateAndTime = (updatedTime: string, inputDateTime: string): string
 };
 
 /**
- * param {String} dateTime // 'HH:mm:ss'
+ * param {String} dateTime in 'HH:mm:ss' format
  * returns {Object}
- * example get12HourTimeObjectFromDate('11:10:00') // {hour: '11', minute: '10', period: 'AM'}
+ * example {hour: '11', minute: '10', period: 'AM'}
  */
 function get12HourTimeObjectFromDate(dateTime: string): {hour: string; minute: string; period: string} {
     if (!dateTime) {
@@ -551,7 +552,7 @@ function areDatesIdentical(dateTimeStringFirst: string, dateTimeStringSecond: st
     const date1 = parse(dateTimeStringFirst, 'yyyy-MM-dd HH:mm:ss', new Date());
     const date2 = parse(dateTimeStringSecond, 'yyyy-MM-dd HH:mm:ss', new Date());
 
-    return isSameMinute(date1, date2);
+    return isSameSecond(date1, date2);
 }
 
 /**
@@ -571,12 +572,12 @@ function hasDateExpired(dateTimeString: string): boolean {
  * param {Date} referenceDate - The date to compare against.
  * returns {string} - Returns an error key if validation fails, otherwise an empty string.
  */
-const getDateValidationErrorKey = (inputDate: Date): string => {
+const getDayValidationErrorKey = (inputDate: Date): string => {
     if (!inputDate) {
         return '';
     }
-    const currentYear = new Date().getFullYear();
-    const inputYear = inputDate.getFullYear();
+    const currentYear = getDayOfYear(new Date());
+    const inputYear = getDayOfYear(inputDate);
     if (inputYear < currentYear) {
         return 'common.error.invalidDateShouldBeFuture';
     }
@@ -590,8 +591,8 @@ const getDateValidationErrorKey = (inputDate: Date): string => {
  * returns {string} - Returns an error key if validation fails, otherwise an empty string.
  */
 const getTimeValidationErrorKey = (inputTime: Date): string => {
-    const startOfCurrentDay = addMinutes(new Date(), 1);
-    if (isBefore(inputTime, startOfCurrentDay)) {
+    const timeNowPlusOneMinute = addMinutes(new Date(), 1);
+    if (isBefore(inputTime, timeNowPlusOneMinute)) {
         return 'common.error.invalidTimeShouldBeFuture';
     }
     return '';
@@ -633,7 +634,7 @@ const DateUtils = {
     getLocalizedTimePeriodDescription,
     hasDateExpired,
     combineDateAndTime,
-    getDateValidationErrorKey,
+    getDayValidationErrorKey,
     getTimeValidationErrorKey,
     isToday,
     isTomorrow,
diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts
index 8984463f9c71..b2a5f0970d77 100644
--- a/src/libs/ValidationUtils.ts
+++ b/src/libs/ValidationUtils.ts
@@ -383,36 +383,20 @@ const isTimeAtLeastOneMinuteInFuture = (inputTime: string, inputDateTime: string
         return false;
     }
     // Parse the hour and minute from the time input
-    const [hourStr, minuteStr, period] = inputTime.split(/[:\s]+/);
-    let hour = parseInt(hourStr, 10);
+    const [hourStr] = inputTime.split(/[:\s]+/);
+    const hour = parseInt(hourStr, 10);
 
     if (hour === 0) {
         return false;
     }
 
-    // Convert 12-hour format to 24-hour format
-    if (period.toUpperCase() === 'PM' && hour !== 12) {
-        hour += 12;
-    } else if (period.toUpperCase() === 'AM' && hour === 12) {
-        hour = 0;
-    }
-
-    const minute = parseInt(minuteStr, 10);
-
-    // Check if the inputDateTime contains a time portion or is just a date
-    const dateTimeFormat = inputDateTime.includes(':') ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd';
-
-    // Parse the input date and time (or just date) accordingly
-    const parsedInputDateTime = parse(inputDateTime, dateTimeFormat, new Date());
-
-    // Set the hour and minute from the time input to the date from the date-time input
-    const combinedDate = set(parsedInputDateTime, {hours: hour, minutes: minute});
+    const combinedDate = DateUtils.combineDateAndTime(inputTime, inputDateTime);
 
     // Get current date and time
     const now = new Date();
 
     // Check if the combinedDate is at least one minute later than the current date and time
-    return isAfter(combinedDate, addMinutes(now, 1));
+    return isAfter(new Date(combinedDate), addMinutes(now, 1));
 };
 
 /**
@@ -429,7 +413,7 @@ const validateDateTimeIsAtLeastOneMinuteInFuture = (data: string): {dateValidati
     }
     const parsedInputData = parseISO(data);
 
-    const dateValidationErrorKey = DateUtils.getDateValidationErrorKey(parsedInputData);
+    const dateValidationErrorKey = DateUtils.getDayValidationErrorKey(parsedInputData);
     const timeValidationErrorKey = DateUtils.getTimeValidationErrorKey(parsedInputData);
     return {
         dateValidationErrorKey,

From eeae2530dd9a92a7a14a99e9a6a27b7432016d22 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 16 Oct 2023 22:15:41 +0200
Subject: [PATCH 075/118] fix after merge

---
 .../CustomStatus/CustomClearAfterPage.js      |  6 +--
 .../CustomStatus/StatusClearAfterPage.js      |  1 +
 src/styles/styles.ts                          | 51 ++++++++++++++++++-
 3 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index f820d415ce0d..d7db4618fbba 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -6,7 +6,7 @@ import withLocalize, {withLocalizePropTypes} from '../../../../components/withLo
 import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
 import NewDatePicker from '../../../../components/NewDatePicker';
 import ScreenWrapper from '../../../../components/ScreenWrapper';
-import Form from '../../../../components/Form';
+import FormProvider from '../../../../components/Form/FormProvider';
 import Navigation from '../../../../libs/Navigation/Navigation';
 import * as User from '../../../../libs/actions/User';
 import * as ValidationUtils from '../../../../libs/ValidationUtils';
@@ -49,7 +49,7 @@ function CustomClearAfterPage({translate, customStatus}) {
                 title={translate('statusPage.date')}
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
             />
-            <Form
+            <FormProvider
                 style={[styles.flexGrow1, styles.ph5]}
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_DATE_FORM}
                 onSubmit={onSubmit}
@@ -64,7 +64,7 @@ function CustomClearAfterPage({translate, customStatus}) {
                     defaultValue={DateUtils.extractDate(customClearAfter)}
                     minDate={moment().toDate()}
                 />
-            </Form>
+            </FormProvider>
         </ScreenWrapper>
     );
 }
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index dbb8d7b73a65..341d8a62d840 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -164,6 +164,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                     item={item}
                     key={`${index}+${item.value}`}
                     onSelectRow={() => updateMode(item)}
+                    showTooltip={false}
                 />
             )),
         [statusType, updateMode],
diff --git a/src/styles/styles.ts b/src/styles/styles.ts
index aed9eac08d9b..176bd8b19bb8 100644
--- a/src/styles/styles.ts
+++ b/src/styles/styles.ts
@@ -2,7 +2,7 @@
 import {LineLayerStyleProps} from '@rnmapbox/maps/src/utils/MapboxStyles';
 import lodashClamp from 'lodash/clamp';
 import {LineLayer} from 'react-map-gl';
-import {AnimatableNumericValue, Animated, ImageStyle, TextStyle, ViewStyle} from 'react-native';
+import {AnimatableNumericValue, Animated, ImageStyle, TextStyle, ViewStyle, StyleSheet} from 'react-native';
 import {CustomAnimation} from 'react-native-animatable';
 import {PickerStyle} from 'react-native-picker-select';
 import {MixedStyleDeclaration, MixedStyleRecord} from 'react-native-render-html';
@@ -3672,7 +3672,6 @@ const styles = (theme: ThemeDefault) =>
             alignItems: 'center',
             paddingLeft: 10,
             paddingRight: 4,
-            marginBottom: 32,
             alignSelf: 'flex-start',
         },
 
@@ -3881,10 +3880,58 @@ const styles = (theme: ThemeDefault) =>
             fontSize: variables.fontSizeNormal,
             marginRight: 4,
         },
+        timePickerInput: {
+            fontSize: 69,
+            minWidth: 56,
+            alignSelf: 'center',
+        },
+        timePickerWidth100: {
+            width: 100,
+        },
+        timePickerHeight100: {
+            height: 100,
+        },
+        timePickerSemiDot: {
+            fontSize: 69,
+            height: 84,
+        },
+        timePickerSwitcherContainer: {
+            flexDirection: 'row',
+            alignItems: 'flex-start',
+            justifyContent: 'center',
+        },
+        selectionListRadioSeparator: {
+            height: StyleSheet.hairlineWidth,
+            backgroundColor: theme.border,
+            marginHorizontal: 20,
+        },
+
         draggableTopBar: {
             height: 30,
             width: '100%',
         },
+        menuItemError: {
+            position: 'absolute',
+            bottom: -4,
+            left: 20,
+            right: 20,
+        },
+        formHelperMessage: {
+            height: 32,
+        },
+        timePickerInputExtraSmall: {
+            fontSize: 50,
+        },
+        setTimeFormButtonContainer: {
+            minHeight: 54,
+        },
+        timePickerInputsContainer: {
+            maxHeight: 70,
+        },
+        timePickerButtonErrorText: {
+            position: 'absolute',
+            top: -36,
+        },
 
         videoContainer: {
             ...flex.flex1,

From 20777520ddff3153e57c9d7008b4ef0d8ce9c680 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 16 Oct 2023 22:41:28 +0200
Subject: [PATCH 076/118] lint

---
 src/components/Form.js                                | 2 --
 src/libs/ValidationUtils.ts                           | 2 +-
 src/pages/settings/Profile/CustomStatus/StatusPage.js | 2 +-
 3 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/components/Form.js b/src/components/Form.js
index 326adc85dc92..67e67ed37690 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -4,7 +4,6 @@ import {Keyboard, ScrollView, StyleSheet} from 'react-native';
 import PropTypes from 'prop-types';
 import _ from 'underscore';
 import {withOnyx} from 'react-native-onyx';
-import * as StyleUtils from '../styles/StyleUtils';
 import compose from '../libs/compose';
 import withLocalize, {withLocalizePropTypes} from './withLocalize';
 import * as FormActions from '../libs/actions/FormActions';
@@ -485,7 +484,6 @@ const Form = forwardRef((props, forwardedRef) => {
                         containerStyles={[styles.mh0, styles.mt5, styles.flex1, ...props.submitButtonStyles]}
                         enabledWhenOffline={props.enabledWhenOffline}
                         isSubmitActionDangerous={props.isSubmitActionDangerous}
-                        buttonStyles={[...StyleUtils.parseStyleAsArray(props.submitButtonStyle)]}
                         useSmallerSubmitButtonSize={props.useSmallerSubmitButtonSize}
                         disablePressOnEnter
                         errorMessageStyle={props.errorMessageStyle}
diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts
index b2a5f0970d77..27ea042541b8 100644
--- a/src/libs/ValidationUtils.ts
+++ b/src/libs/ValidationUtils.ts
@@ -1,4 +1,4 @@
-import {subYears, addYears, addMinutes, startOfDay, endOfMonth, isAfter, isBefore, isValid, isWithinInterval, isSameDay, parse, set, format, parseISO} from 'date-fns';
+import {subYears, addYears, addMinutes, startOfDay, endOfMonth, isAfter, isBefore, isValid, isWithinInterval, isSameDay, parse, format, parseISO} from 'date-fns';
 import {URL_REGEX_WITH_REQUIRED_PROTOCOL} from 'expensify-common/lib/Url';
 import {parsePhoneNumber} from 'awesome-phonenumber';
 import isDate from 'lodash/isDate';
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 2018871422e4..4cbe5fbbf272 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -128,7 +128,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                 style={styles.flexGrow1}
                 ref={formRef}
                 submitButtonText={localize.translate('statusPage.save')}
-                submitButtonStyle={styles.mh5}
+                submitButtonStyles={[styles.mh5]}
                 onSubmit={updateStatus}
                 validate={validateForm}
                 enabledWhenOffline

From a7fb9018db517b61c0db4857dd5a183405ddb94d Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 23 Oct 2023 10:05:51 +0200
Subject: [PATCH 077/118] remove lodash import after merge

---
 src/components/EmojiPicker/EmojiPickerButtonDropdown.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
index 0dc300be2030..50002167f50e 100644
--- a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
+++ b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
@@ -1,7 +1,6 @@
 import React, {useRef, useEffect} from 'react';
 import PropTypes from 'prop-types';
 import {View} from 'react-native';
-import _ from 'lodash';
 import styles from '../../styles/styles';
 import CONST from '../../CONST';
 import * as StyleUtils from '../../styles/StyleUtils';

From 61ee723a567d695d81edd66307c43d1436dcea66 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 23 Oct 2023 13:50:18 +0200
Subject: [PATCH 078/118] fix styles after merge

---
 src/pages/settings/Profile/CustomStatus/SetTimePage.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 1da7e96912dc..1d6c01fab708 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -64,7 +64,7 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
                     formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_TIME_FORM}
                     onSubmit={onSubmit}
                     submitButtonText={translate('common.save')}
-                    submitButtonContainerStyles={[styles.flex0, styles.justifyContentStart, styles.mh5, styles.setTimeFormButtonContainer]}
+                    submitButtonStyles={[styles.flex0, styles.justifyContentStart, styles.mh5, styles.setTimeFormButtonContainer]}
                     errorMessageStyle={styles.timePickerButtonErrorText}
                     validate={validate}
                     enabledWhenOffline

From db63d34f121611e4ce5b025601a35320b96126aa Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 24 Oct 2023 10:40:26 +0200
Subject: [PATCH 079/118] fix colon positioning

---
 src/components/TimePicker.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 563040520ab5..b146a89d1d9d 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -337,7 +337,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
             <View style={[styles.flex1, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}>
                 <View
                     nativeID={AMOUNT_VIEW_ID}
-                    style={[styles.flexRow, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter, styles.timePickerInputsContainer]}
+                    style={[styles.flexRow, styles.w100, styles.justifyContentCenter, styles.timePickerInputsContainer]}
                 >
                     <AmountTextInput
                         formattedAmount={hours}

From 139e9cb2453dcd5b7617f224f352f9490c6689d3 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Fri, 27 Oct 2023 20:03:19 +0200
Subject: [PATCH 080/118] change time validation

---
 src/components/TimePicker.js | 37 ++++++++++++++++++++++++++++--------
 1 file changed, 29 insertions(+), 8 deletions(-)

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index b146a89d1d9d..224278a0d1a1 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -43,11 +43,14 @@ const NUM_PAD_CONTAINER_VIEW_ID = 'numPadContainerView';
 const NUM_PAD_VIEW_ID = 'numPadView';
 
 function formatHour(hourText) {
-    // If the integer value of hour is greater than 12, return the second digit with a leading 0
-    const hourNumber = parseInt(hourText, 10);
-
-    // If the integer value of hour is greater than 12, subtract 10
-    const adjustedHour = hourNumber > 12 ? hourNumber - 10 : hourNumber;
+    let adjustedHour = '00';
+    if (hourText > 12 && hourText <= 24) {
+        adjustedHour = String(hourText - 12);
+    } else if (hourText > 24) {
+        adjustedHour = `0${hourText[1]}`;
+    } else {
+        adjustedHour = hourText;
+    }
 
     // Convert to a string and pad with a 0 if needed
     return adjustedHour.toString().padStart(2, '0');
@@ -136,8 +139,15 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
             // Case when the cursor is at the start.
         } else if (selectionHour.start === 0) {
             // Handle cases where the hour would be > 12.
+
+            // when you entering text the filteredText would consist of three numbers
             const formattedText = `${filteredText[0]}${filteredText[2] || 0}`;
-            if (formattedText > 12) {
+            if (formattedText > 12 && formattedText <= 24) {
+                newHour = String(formattedText - 12).padStart(2, '0');
+                newSelection = 2;
+                focusMinuteInputOnFirstCharacter();
+                setAmPmValue(CONST.TIME_PERIOD.PM);
+            } else if (formattedText > 24) {
                 newHour = `0${formattedText[1]}`;
                 newSelection = 2;
                 focusMinuteInputOnFirstCharacter();
@@ -147,12 +157,19 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
             }
         } else if (selectionHour.start === 1) {
             // Case when the cursor is at the second position.
+            const formattedText = `${filteredText[0]}${filteredText[1]}`;
+
             if (filteredText.length < 2) {
                 // If we remove a value, prepend 0.
                 newHour = `0${text}`;
                 newSelection = 0;
                 // If the second digit is > 2, replace the hour with 0 and the second digit.
-            } else if (text[1] > 2) {
+            } else if (formattedText > 12 && formattedText <= 24) {
+                newHour = String(formattedText - 12).padStart(2, '0');
+                newSelection = 2;
+                focusMinuteInputOnFirstCharacter();
+                setAmPmValue(CONST.TIME_PERIOD.PM);
+            } else if (formattedText > 24) {
                 newHour = `0${text[1]}`;
                 newSelection = 2;
                 focusMinuteInputOnFirstCharacter();
@@ -435,10 +452,14 @@ TimePicker.propTypes = propTypes;
 TimePicker.defaultProps = defaultProps;
 TimePicker.displayName = 'TimePicker';
 
-export default React.forwardRef((props, ref) => (
+const TimePickerWithRef = React.forwardRef((props, ref) => (
     <TimePicker
         // eslint-disable-next-line react/jsx-props-no-spreading
         {...props}
         forwardedRef={ref}
     />
 ));
+
+TimePickerWithRef.displayName = 'TimePickerWithRef';
+
+export default TimePickerWithRef;

From 714161361c96da56cf7c298e11be8762c8f4aecf Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 30 Oct 2023 09:54:01 +0100
Subject: [PATCH 081/118] fix imports after merge

---
 src/components/TimePicker.js                  | 24 +++++-----
 .../CustomStatus/CustomClearAfterPage.js      | 30 ++++++------
 .../Profile/CustomStatus/SetTimePage.js       | 36 +++++++-------
 .../CustomStatus/StatusClearAfterPage.js      | 48 +++++++++----------
 src/styles/styles.ts                          |  2 +-
 5 files changed, 70 insertions(+), 70 deletions(-)

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 224278a0d1a1..fd7b754970b8 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -1,21 +1,21 @@
-import React, {useEffect, useState, useCallback, useRef, useMemo} from 'react';
-import {View} from 'react-native';
 import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {View} from 'react-native';
 import _ from 'underscore';
-import styles from '../styles/styles';
-import FormHelpMessage from './FormHelpMessage';
+import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import DateUtils from '@libs/DateUtils';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
 import AmountTextInput from './AmountTextInput';
 import BigNumberPad from './BigNumberPad';
-import refPropTypes from './refPropTypes';
 import Button from './Button';
+import FormHelpMessage from './FormHelpMessage';
+import refPropTypes from './refPropTypes';
 import Text from './Text';
-import * as DeviceCapabilities from '../libs/DeviceCapabilities';
-import DateUtils from '../libs/DateUtils';
-import useWindowDimensions from '../hooks/useWindowDimensions';
-import useKeyboardShortcut from '../hooks/useKeyboardShortcut';
-import useLocalize from '../hooks/useLocalize';
-import * as StyleUtils from '../styles/StyleUtils';
-import CONST from '../CONST';
 
 const propTypes = {
     /** Refs forwarded to the TextInputWithCurrencySymbol */
diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index d7db4618fbba..302a1f1fbbe1 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -1,20 +1,20 @@
-import React, {useCallback} from 'react';
+import lodashGet from 'lodash/get';
 import moment from 'moment';
+import React, {useCallback} from 'react';
 import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import NewDatePicker from '../../../../components/NewDatePicker';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import FormProvider from '../../../../components/Form/FormProvider';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import * as User from '../../../../libs/actions/User';
-import * as ValidationUtils from '../../../../libs/ValidationUtils';
-import DateUtils from '../../../../libs/DateUtils';
-import compose from '../../../../libs/compose';
-import styles from '../../../../styles/styles';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import ROUTES from '../../../../ROUTES';
+import FormProvider from '@components/Form/FormProvider';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import NewDatePicker from '@components/NewDatePicker';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import * as User from '@libs/actions/User';
+import compose from '@libs/compose';
+import DateUtils from '@libs/DateUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
 
 const propTypes = {
     ...withLocalizePropTypes,
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 1d6c01fab708..96bf21d3776a 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -1,24 +1,24 @@
+import lodashGet from 'lodash/get';
 import React from 'react';
 import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import TimePicker from '../../../../components/TimePicker';
-import Form from '../../../../components/Form';
-import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
-import useWindowDimensions from '../../../../hooks/useWindowDimensions';
-import useLocalize from '../../../../hooks/useLocalize';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import * as User from '../../../../libs/actions/User';
-import DateUtils from '../../../../libs/DateUtils';
-import * as ValidationUtils from '../../../../libs/ValidationUtils';
-import compose from '../../../../libs/compose';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import ROUTES from '../../../../ROUTES';
-import styles from '../../../../styles/styles';
+import ONYXKEYS from 'src/ONYXKEYS';
+import ROUTES from 'src/ROUTES';
+import Form from '@components/Form';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import TimePicker from '@components/TimePicker';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
+import usePrivatePersonalDetails from '@hooks/usePrivatePersonalDetails';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as User from '@libs/actions/User';
+import compose from '@libs/compose';
+import DateUtils from '@libs/DateUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
 
 const propTypes = {
     ...withLocalizePropTypes,
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 341d8a62d840..2bf6e588a5f4 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -1,28 +1,28 @@
-import React, {useEffect, useState, useCallback, useMemo} from 'react';
-import {View} from 'react-native';
 import _ from 'lodash';
-import {withOnyx} from 'react-native-onyx';
 import lodashGet from 'lodash/get';
 import PropTypes from 'prop-types';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import Form from '../../../../components/Form';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import ROUTES from '../../../../ROUTES';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import styles from '../../../../styles/styles';
-import Text from '../../../../components/Text';
-import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription';
-import useLocalize from '../../../../hooks/useLocalize';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import CONST from '../../../../CONST';
-import * as User from '../../../../libs/actions/User';
-import * as ValidationUtils from '../../../../libs/ValidationUtils';
-import withLocalize from '../../../../components/withLocalize';
-import compose from '../../../../libs/compose';
-import DateUtils from '../../../../libs/DateUtils';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps} from '../../../../components/withCurrentUserPersonalDetails';
-import personalDetailsPropType from '../../../personalDetailsPropType';
-import BaseListItem from '../../../../components/SelectionList/BaseListItem';
+import React, {useCallback, useEffect, useMemo, useState} from 'react';
+import {View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import FormProvider from '@components/Form/FormProvider';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import ScreenWrapper from '@components/ScreenWrapper';
+import BaseListItem from '@components/SelectionList/BaseListItem';
+import Text from '@components/Text';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps} from '@components/withCurrentUserPersonalDetails';
+import withLocalize from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
+import * as User from '@libs/actions/User';
+import compose from '@libs/compose';
+import DateUtils from '@libs/DateUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import styles from '@src/styles/styles';
 
 const defaultProps = {
     ...withCurrentUserPersonalDetailsDefaultProps,
@@ -181,7 +181,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS)}
             />
             <Text style={[styles.textNormal, styles.mh5, styles.mv4]}>{localize.translate('statusPage.whenClearStatus')}</Text>
-            <Form
+            <FormProvider
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_CLEAR_AFTER_FORM}
                 submitButtonText="Save"
                 onSubmit={onSubmit}
@@ -217,7 +217,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                         </>
                     )}
                 </View>
-            </Form>
+            </FormProvider>
         </ScreenWrapper>
     );
 }
diff --git a/src/styles/styles.ts b/src/styles/styles.ts
index ebc3589a649f..fa3bef1a0d65 100644
--- a/src/styles/styles.ts
+++ b/src/styles/styles.ts
@@ -2,7 +2,7 @@
 import {LineLayerStyleProps} from '@rnmapbox/maps/src/utils/MapboxStyles';
 import lodashClamp from 'lodash/clamp';
 import {LineLayer} from 'react-map-gl';
-import {AnimatableNumericValue, Animated, ImageStyle, TextStyle, ViewStyle, StyleSheet} from 'react-native';
+import {AnimatableNumericValue, Animated, ImageStyle, StyleSheet, TextStyle, ViewStyle} from 'react-native';
 import {CustomAnimation} from 'react-native-animatable';
 import {PickerStyle} from 'react-native-picker-select';
 import {MixedStyleDeclaration, MixedStyleRecord} from 'react-native-render-html';

From 3c24990af364f2a04d5374e9083c4c1c092ca1cd Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 30 Oct 2023 10:15:20 +0100
Subject: [PATCH 082/118] update translations

---
 src/languages/en.ts                              |  4 ++--
 src/languages/es.ts                              |  4 ++--
 .../settings/Profile/CustomStatus/SetTimePage.js | 16 ++++++++--------
 3 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/languages/en.ts b/src/languages/en.ts
index 9d0688031919..4488ace8f110 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -196,8 +196,8 @@ export default {
             characterLimit: ({limit}: CharacterLimitParams) => `Exceeds the maximum length of ${limit} characters`,
             characterLimitExceedCounter: ({length, limit}) => `Character limit exceeded (${length}/${limit})`,
             dateInvalid: 'Please select a valid date',
-            invalidDateShouldBeFuture: "It should be today's date or a future date.",
-            invalidTimeShouldBeFuture: 'It should be at least one minute in the future.',
+            invalidDateShouldBeFuture: 'Choose today or a future date.',
+            invalidTimeShouldBeFuture: 'Enter a time one minute ahead.',
             invalidCharacter: 'Invalid character',
             enterMerchant: 'Enter a merchant name',
             enterAmount: 'Enter an amount',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 573dc7143127..196069ddd596 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -186,8 +186,8 @@ export default {
             characterLimit: ({limit}: CharacterLimitParams) => `Supera el límite de ${limit} caracteres`,
             characterLimitExceedCounter: ({length, limit}) => `Se superó el límite de caracteres (${length}/${limit})`,
             dateInvalid: 'Por favor, selecciona una fecha válida',
-            invalidDateShouldBeFuture: 'Debe ser la fecha de hoy o una fecha futura.',
-            invalidTimeShouldBeFuture: 'Debe ser al menos un minuto en el futuro.',
+            invalidDateShouldBeFuture: 'Elige hoy o una fecha futura.',
+            invalidTimeShouldBeFuture: 'Introduce un tiempo un minuto adelante.',
             invalidCharacter: 'Carácter invalido',
             enterMerchant: 'Introduce un comerciante',
             enterAmount: 'Introduce un importe',
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 96bf21d3776a..e04d6100b52d 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -2,22 +2,22 @@ import lodashGet from 'lodash/get';
 import React from 'react';
 import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
-import ONYXKEYS from 'src/ONYXKEYS';
-import ROUTES from 'src/ROUTES';
-import Form from '@components/Form';
 import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
 import HeaderWithBackButton from '@components/HeaderWithBackButton';
 import ScreenWrapper from '@components/ScreenWrapper';
 import TimePicker from '@components/TimePicker';
-import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
-import useLocalize from '@hooks/useLocalize';
+import Form from '@components/Form';
 import usePrivatePersonalDetails from '@hooks/usePrivatePersonalDetails';
 import useWindowDimensions from '@hooks/useWindowDimensions';
+import useLocalize from '@hooks/useLocalize';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import Navigation from '@libs/Navigation/Navigation';
 import * as User from '@libs/actions/User';
-import compose from '@libs/compose';
 import DateUtils from '@libs/DateUtils';
-import Navigation from '@libs/Navigation/Navigation';
-import * as ValidationUtils from '@libs/ValidationUtils';
+import compose from '@libs/compose';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
 import styles from '@styles/styles';
 
 const propTypes = {

From b85dbc98217eabaf50ca8e4a1e56a3ca38901742 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 31 Oct 2023 10:31:51 +0100
Subject: [PATCH 083/118] run prettier

---
 .../Profile/CustomStatus/SetTimePage.js        | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index e04d6100b52d..80b47ed493be 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -2,23 +2,23 @@ import lodashGet from 'lodash/get';
 import React from 'react';
 import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
+import FormProvider from '@components/Form/FormProvider';
 import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
-import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
 import HeaderWithBackButton from '@components/HeaderWithBackButton';
 import ScreenWrapper from '@components/ScreenWrapper';
 import TimePicker from '@components/TimePicker';
-import Form from '@components/Form';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
 import usePrivatePersonalDetails from '@hooks/usePrivatePersonalDetails';
 import useWindowDimensions from '@hooks/useWindowDimensions';
-import useLocalize from '@hooks/useLocalize';
-import * as ValidationUtils from '@libs/ValidationUtils';
-import Navigation from '@libs/Navigation/Navigation';
 import * as User from '@libs/actions/User';
-import DateUtils from '@libs/DateUtils';
 import compose from '@libs/compose';
+import DateUtils from '@libs/DateUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
-import styles from '@styles/styles';
 
 const propTypes = {
     ...withLocalizePropTypes,
@@ -59,7 +59,7 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
             />
             <View style={styles.flex1}>
-                <Form
+                <FormProvider
                     style={[styles.flexGrow1]}
                     formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_TIME_FORM}
                     onSubmit={onSubmit}
@@ -76,7 +76,7 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
                         defaultValue={DateUtils.extractTime12Hour(clearAfter)}
                         style={styles.flexGrow1}
                     />
-                </Form>
+                </FormProvider>
             </View>
         </ScreenWrapper>
     );

From 8d3d44ab071123147da8b55f79854fab7319d47e Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 31 Oct 2023 11:17:01 +0100
Subject: [PATCH 084/118] fix after merge: replace FormProvider with Form

---
 src/libs/DateUtils.ts                                  | 2 +-
 src/pages/settings/Profile/CustomStatus/SetTimePage.js | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts
index 0a09549f1691..424a38677d60 100644
--- a/src/libs/DateUtils.ts
+++ b/src/libs/DateUtils.ts
@@ -454,7 +454,7 @@ function getStatusUntilDate(inputDate: string): string {
     return translateLocal('statusPage.untilTime', {time: format(input, `${CONST.DATE.FNS_FORMAT_STRING} ${CONST.DATE.LOCAL_TIME_FORMAT}`)});
 }
 
-/*
+/**
  * Update the time for a given date.
  *
  * param {string} updatedTime - Time in "hh:mm A" or "HH:mm:ss" or "yyyy-MM-dd HH:mm:ss" format.
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 80b47ed493be..9db1c4c08c27 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -2,7 +2,7 @@ import lodashGet from 'lodash/get';
 import React from 'react';
 import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
-import FormProvider from '@components/Form/FormProvider';
+import Form from '@components/Form';
 import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
 import HeaderWithBackButton from '@components/HeaderWithBackButton';
 import ScreenWrapper from '@components/ScreenWrapper';
@@ -59,7 +59,7 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
             />
             <View style={styles.flex1}>
-                <FormProvider
+                <Form
                     style={[styles.flexGrow1]}
                     formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_TIME_FORM}
                     onSubmit={onSubmit}
@@ -76,7 +76,7 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
                         defaultValue={DateUtils.extractTime12Hour(clearAfter)}
                         style={styles.flexGrow1}
                     />
-                </FormProvider>
+                </Form>
             </View>
         </ScreenWrapper>
     );

From 39198d41d9e1c14608530d50c3343af55640811f Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 2 Nov 2023 11:04:30 +0100
Subject: [PATCH 085/118] showSoftInputOnFocus

---
 src/components/TimePicker.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index fd7b754970b8..0cac76de227a 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -376,6 +376,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                         selection={selectionHour}
                         style={styles.timePickerInput}
                         containerStyles={[styles.timePickerHeight100]}
+                        showSoftInputOnFocus={false}
                     />
                     <Text style={styles.timePickerSemiDot}>{CONST.COLON}</Text>
                     <AmountTextInput
@@ -400,6 +401,7 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                         selection={selectionMinute}
                         style={styles.timePickerInput}
                         containerStyles={[styles.timePickerHeight100]}
+                        showSoftInputOnFocus={false}
                     />
                 </View>
                 {errorText ? (

From 752de6ab60c52e34d540b81ad350efedb07bdf89 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Fri, 3 Nov 2023 16:50:49 +0100
Subject: [PATCH 086/118] update translations

---
 src/languages/en.ts | 4 ++--
 src/languages/es.ts | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/languages/en.ts b/src/languages/en.ts
index b37d7b451644..564b9cccee81 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -196,8 +196,8 @@ export default {
             characterLimit: ({limit}: CharacterLimitParams) => `Exceeds the maximum length of ${limit} characters`,
             characterLimitExceedCounter: ({length, limit}) => `Character limit exceeded (${length}/${limit})`,
             dateInvalid: 'Please select a valid date',
-            invalidDateShouldBeFuture: 'Choose today or a future date.',
-            invalidTimeShouldBeFuture: 'Enter a time one minute ahead.',
+            invalidDateShouldBeFuture: 'Please choose today or a future date.',
+            invalidTimeShouldBeFuture: 'Please choose a time at least one minute ahead.',
             invalidCharacter: 'Invalid character',
             enterMerchant: 'Enter a merchant name',
             enterAmount: 'Enter an amount',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 8731be9fc610..52bb200fd2c8 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -186,8 +186,8 @@ export default {
             characterLimit: ({limit}: CharacterLimitParams) => `Supera el límite de ${limit} caracteres`,
             characterLimitExceedCounter: ({length, limit}) => `Se superó el límite de caracteres (${length}/${limit})`,
             dateInvalid: 'Por favor, selecciona una fecha válida',
-            invalidDateShouldBeFuture: 'Elige hoy o una fecha futura.',
-            invalidTimeShouldBeFuture: 'Introduce un tiempo un minuto adelante.',
+            invalidDateShouldBeFuture: 'Por favor elija una fecha igual o posterior a hoy',
+            invalidTimeShouldBeFuture: 'Por favor elija una hora al menos un minuto en el futuro',
             invalidCharacter: 'Carácter invalido',
             enterMerchant: 'Introduce un comerciante',
             enterAmount: 'Introduce un importe',

From 431b6e3744932065fe57113e07172fd5ce65afd8 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Sat, 4 Nov 2023 10:58:48 +0100
Subject: [PATCH 087/118] update spanish translation

---
 src/languages/es.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/languages/es.ts b/src/languages/es.ts
index 52bb200fd2c8..4d1e8d75d1c9 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -186,8 +186,8 @@ export default {
             characterLimit: ({limit}: CharacterLimitParams) => `Supera el límite de ${limit} caracteres`,
             characterLimitExceedCounter: ({length, limit}) => `Se superó el límite de caracteres (${length}/${limit})`,
             dateInvalid: 'Por favor, selecciona una fecha válida',
-            invalidDateShouldBeFuture: 'Por favor elija una fecha igual o posterior a hoy',
-            invalidTimeShouldBeFuture: 'Por favor elija una hora al menos un minuto en el futuro',
+            invalidDateShouldBeFuture: 'Por favor, elige una fecha igual o posterior a hoy',
+            invalidTimeShouldBeFuture: 'Por favor, elige una hora al menos un minuto en el futuro',
             invalidCharacter: 'Carácter invalido',
             enterMerchant: 'Introduce un comerciante',
             enterAmount: 'Introduce un importe',

From 1588913858ab1d8d7bcef0b6c0b882d5d95a3b01 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 8 Nov 2023 20:49:07 +0100
Subject: [PATCH 088/118] change validation + add focus

---
 src/components/FormHelpMessage.js             |   9 +-
 src/components/TimePicker.js                  | 116 +++++++++++-------
 src/libs/actions/FormActions.ts               |   6 +-
 .../Profile/CustomStatus/SetTimePage.js       |  43 ++-----
 src/styles/styles.ts                          |   5 +
 5 files changed, 91 insertions(+), 88 deletions(-)

diff --git a/src/components/FormHelpMessage.js b/src/components/FormHelpMessage.js
index 7e4d8a707126..369be4607ebc 100644
--- a/src/components/FormHelpMessage.js
+++ b/src/components/FormHelpMessage.js
@@ -3,6 +3,7 @@ import React from 'react';
 import {View} from 'react-native';
 import _ from 'underscore';
 import * as Localize from '@libs/Localize';
+import * as StyleUtils from '@styles/StyleUtils';
 import stylePropTypes from '@styles/stylePropTypes';
 import styles from '@styles/styles';
 import themeColors from '@styles/themes/default';
@@ -23,9 +24,6 @@ const propTypes = {
     /** Container style props */
     style: stylePropTypes,
 
-    /** Container text style props */
-    containerMessageStyle: stylePropTypes,
-
     /** Whether to show dot indicator */
     shouldShowRedDotIndicator: PropTypes.bool,
 };
@@ -36,7 +34,6 @@ const defaultProps = {
     isError: true,
     shouldShowRedDotIndicator: true,
     style: [],
-    containerMessageStyle: {},
 };
 
 function FormHelpMessage(props) {
@@ -46,14 +43,14 @@ function FormHelpMessage(props) {
 
     const translatedMessage = Localize.translateIfPhraseKey(props.message);
     return (
-        <View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2, styles.mb1, ...props.style, styles.justifyContentCenter]}>
+        <View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2, styles.mb1, StyleUtils.parseStyleAsArray(props.style), styles.justifyContentCenter]}>
             {props.isError && props.shouldShowRedDotIndicator && (
                 <Icon
                     src={Expensicons.DotIndicator}
                     fill={themeColors.danger}
                 />
             )}
-            <View style={[styles.flex1, props.isError && props.shouldShowRedDotIndicator ? styles.ml2 : {}, props.containerMessageStyle]}>
+            <View style={[styles.flex1, props.isError && props.shouldShowRedDotIndicator ? styles.ml2 : {}]}>
                 {props.children || <Text style={[props.isError ? styles.formError : styles.formHelp, styles.mb0]}>{translatedMessage}</Text>}
             </View>
         </View>
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 0cac76de227a..1bb4ed143e65 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -7,6 +7,7 @@ import useLocalize from '@hooks/useLocalize';
 import useWindowDimensions from '@hooks/useWindowDimensions';
 import DateUtils from '@libs/DateUtils';
 import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import * as ValidationUtils from '@libs/ValidationUtils';
 import styles from '@styles/styles';
 import * as StyleUtils from '@styles/StyleUtils';
 import CONST from '@src/CONST';
@@ -22,10 +23,10 @@ const propTypes = {
     forwardedRef: refPropTypes,
 
     /** Default value for the inputs */
-    value: PropTypes.string,
+    defaultValue: PropTypes.string,
 
-    /** Form Error description */
-    errorText: PropTypes.string,
+    /** Callback to call when the Save button is pressed  */
+    onSubmit: PropTypes.func.isRequired,
 
     /** Callback to call when the input changes */
     onInputChange: PropTypes.func,
@@ -33,9 +34,8 @@ const propTypes = {
 
 const defaultProps = {
     forwardedRef: null,
-    errorText: '',
     onInputChange: () => {},
-    value: '',
+    defaultValue: '',
 };
 
 const AMOUNT_VIEW_ID = 'amountView';
@@ -91,53 +91,49 @@ function replaceWithZeroAtPosition(originalString, position) {
     return `${originalString.slice(0, position - 1)}0${originalString.slice(position)}`;
 }
 
-function TimePicker({forwardedRef, value, errorText, onInputChange}) {
-    const {numberFormat} = useLocalize();
+function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
+    const {numberFormat, translate} = useLocalize();
     const {isExtraSmallScreenHeight} = useWindowDimensions();
-    const localize = useLocalize();
-    const [hours, setHours] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).hour);
-    const [minute, setMinute] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).minute);
+    const value = DateUtils.extractTime12Hour(defaultValue);
+    const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen();
+
+    const [isError, setError] = useState(false);
     const [selectionHour, setSelectionHour] = useState({start: 0, end: 0});
     const [selectionMinute, setSelectionMinute] = useState({start: 2, end: 2}); // we focus it by default so need  to have selection on the end
-
+    const [hours, setHours] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).hour);
+    const [minute, setMinute] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).minute);
     const [amPmValue, setAmPmValue] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).period);
 
     const hourInputRef = useRef(null);
     const minuteInputRef = useRef(null);
-    const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen();
 
     const focusMinuteInputOnFirstCharacter = useCallback(() => {
-        minuteInputRef.current.focus();
         setSelectionMinute({start: 0, end: 0});
+        minuteInputRef.current.focus();
     }, []);
 
+    const validate = (time) => {
+        const isValid = ValidationUtils.isTimeAtLeastOneMinuteInFuture(time, defaultValue);
+        setError(isValid);
+        return isValid;
+    };
+
     // This function receive value from hour input and validate it
     // The valid format is HH(from 00 to 12). If the user input 9, it will be 09. If user try to change 09 to 19 it would skip the first character
     const handleHourChange = (text) => {
-        let filteredText;
-        // Remove non-numeric characters and limit to 3 digits. The third digit will appear when input has 01 and you type 2 => 201
-        if (selectionHour.start !== selectionHour.end) {
-            filteredText = text.replace(/[^0-9]/g, '').slice(0, 2);
-        } else {
-            filteredText = text.replace(/[^0-9]/g, '');
+        const isOnlyNumericValue = /^\d+$/.test(text.trim());
+        // Skip if the user is pasting the text or use non numeric characters.
+        if (selectionHour.start !== selectionHour.end || !isOnlyNumericValue) {
+            return;
         }
+        // Remove non-numeric characters.
+        const filteredText = text.replace(/[^0-9]/g, '');
+
         let newHour = hours;
         let newSelection = selectionHour.start;
 
-        // Case when user selects and replaces the text.
-        if (selectionHour.start !== selectionHour.end) {
-            // If the first digit is <= 1, append 0 at the end.
-            if (filteredText.length === 1 && filteredText <= 1) {
-                newHour = `${filteredText}0`;
-                newSelection = 1;
-            } else {
-                // Format the hour and move focus to minute input.
-                newHour = `${formatHour(filteredText)}`;
-                newSelection = 2;
-                focusMinuteInputOnFirstCharacter();
-            }
-            // Case when the cursor is at the start.
-        } else if (selectionHour.start === 0) {
+        // Case when the cursor is at the start.
+        if (selectionHour.start === 0) {
             // Handle cases where the hour would be > 12.
 
             // when you entering text the filteredText would consist of three numbers
@@ -195,6 +191,12 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
     // This function receive value from minute input and validate it
     // The valid format is MM(from 00 to 59). If the user input 9, it will be 09. If user try to change 09 to 99 it would skip the character
     const handleMinutesChange = (text) => {
+        const isOnlyNumericValue = /^\d+$/.test(text.trim());
+        // Skip if the user is pasting the text or use non numeric characters.
+        if (selectionMinute.start !== selectionMinute.end || !isOnlyNumericValue) {
+            return;
+        }
+
         // Remove non-numeric characters.
         const filteredText = text.replace(/[^0-9]/g, '');
 
@@ -230,6 +232,8 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
             if (filteredText.length < 2) {
                 newMinute = `0${text}`;
                 newSelection = 0;
+                setSelectionHour({start: 2, end: 2});
+                hourInputRef.current.focus();
             } else {
                 newMinute = `${text[0]}${text[1]}`;
                 newSelection = 2;
@@ -349,12 +353,22 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
         // eslint-disable-next-line react-hooks/exhaustive-deps
     }, [hours, minute, amPmValue]);
 
+    const handleSubmit = () => {
+        const time = `${hours}:${minute} ${amPmValue}`;
+        const isValid = ValidationUtils.isTimeAtLeastOneMinuteInFuture(time, defaultValue);
+
+        setError(!isValid);
+        if (isValid) {
+            onSubmit(time);
+        }
+    };
+
     return (
         <View style={styles.flex1}>
             <View style={[styles.flex1, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}>
                 <View
                     nativeID={AMOUNT_VIEW_ID}
-                    style={[styles.flexRow, styles.w100, styles.justifyContentCenter, styles.timePickerInputsContainer]}
+                    style={[styles.flexRow, styles.w100, styles.justifyContentCenter, styles.timePickerInputsContainer, styles.mb8]}
                 >
                     <AmountTextInput
                         formattedAmount={hours}
@@ -404,23 +418,15 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                         showSoftInputOnFocus={false}
                     />
                 </View>
-                {errorText ? (
-                    <FormHelpMessage
-                        isError={!!errorText}
-                        message={errorText}
-                        containerMessageStyle={styles.flexReset}
-                    />
-                ) : (
-                    <View style={styles.formHelperMessage} />
-                )}
                 <View style={styles.timePickerSwitcherContainer}>
                     <Button
                         shouldEnableHapticFeedback
                         innerStyles={styleForAM}
                         medium={isExtraSmallScreenHeight}
-                        text={localize.translate('common.am')}
+                        text={translate('common.am')}
                         onLongPress={() => {}}
                         onPress={() => {
+                            validate();
                             setAmPmValue(CONST.TIME_PERIOD.AM);
                         }}
                         onPressOut={() => {}}
@@ -430,9 +436,10 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                         shouldEnableHapticFeedback
                         innerStyles={[...styleForPM, styles.ml1]}
                         medium={isExtraSmallScreenHeight}
-                        text={localize.translate('common.pm')}
+                        text={translate('common.pm')}
                         onLongPress={() => {}}
                         onPress={() => {
+                            validate();
                             setAmPmValue(CONST.TIME_PERIOD.PM);
                         }}
                         onPressOut={() => {}}
@@ -440,12 +447,29 @@ function TimePicker({forwardedRef, value, errorText, onInputChange}) {
                     />
                 </View>
             </View>
+            {isError ? (
+                <FormHelpMessage
+                    isError={isError}
+                    message={translate('common.error.invalidTimeShouldBeFuture')}
+                    style={styles.pl5}
+                />
+            ) : (
+                <View style={styles.formHelperMessage} />
+            )}
             <View
-                style={[styles.pageWrapper, styles.pb4]}
+                style={[styles.numberPadWrapper, styles.pb4]}
                 nativeID={NUM_PAD_CONTAINER_VIEW_ID}
             >
                 {numberPad()}
             </View>
+            <Button
+                success
+                medium={isExtraSmallScreenHeight}
+                style={[styles.mb5, styles.mh5]}
+                onPress={handleSubmit}
+                pressOnEnter
+                text={translate('common.save')}
+            />
         </View>
     );
 }
diff --git a/src/libs/actions/FormActions.ts b/src/libs/actions/FormActions.ts
index ecaf38dc44f2..ebd689e29078 100644
--- a/src/libs/actions/FormActions.ts
+++ b/src/libs/actions/FormActions.ts
@@ -23,4 +23,8 @@ function setDraftValues<T extends OnyxFormKeyWithoutDraft>(formID: T, draftValue
     Onyx.merge(`${formID}Draft`, draftValues);
 }
 
-export {setDraftValues, setErrorFields, setErrors, setIsLoading};
+function cleanDraftValues<T extends OnyxFormKeyWithoutDraft>(formID: T) {
+    Onyx.merge(`${formID}Draft`, null);
+}
+
+export {setDraftValues, setErrorFields, setErrors, setIsLoading, cleanDraftValues};
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 9db1c4c08c27..8c4007d39877 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -2,20 +2,16 @@ import lodashGet from 'lodash/get';
 import React from 'react';
 import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
-import Form from '@components/Form';
 import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
 import HeaderWithBackButton from '@components/HeaderWithBackButton';
 import ScreenWrapper from '@components/ScreenWrapper';
 import TimePicker from '@components/TimePicker';
 import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
-import useLocalize from '@hooks/useLocalize';
 import usePrivatePersonalDetails from '@hooks/usePrivatePersonalDetails';
-import useWindowDimensions from '@hooks/useWindowDimensions';
 import * as User from '@libs/actions/User';
 import compose from '@libs/compose';
 import DateUtils from '@libs/DateUtils';
 import Navigation from '@libs/Navigation/Navigation';
-import * as ValidationUtils from '@libs/ValidationUtils';
 import styles from '@styles/styles';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
@@ -26,32 +22,21 @@ const propTypes = {
 
 function SetTimePage({translate, privatePersonalDetails, customStatus}) {
     usePrivatePersonalDetails();
-    const {isExtraSmallScreenHeight} = useWindowDimensions();
-    const localize = useLocalize();
     const clearAfter = lodashGet(customStatus, 'clearAfter', '');
 
-    const onSubmit = ({timePicker}) => {
-        const timeToUse = DateUtils.combineDateAndTime(timePicker, clearAfter);
+    const onSubmit = (time) => {
+        const timeToUse = DateUtils.combineDateAndTime(time, clearAfter);
 
         User.updateDraftCustomStatus({clearAfter: timeToUse});
         Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
     };
-    const validate = (v) => {
-        const error = {};
-
-        if (!ValidationUtils.isTimeAtLeastOneMinuteInFuture(v.timePicker, clearAfter)) {
-            error.timePicker = localize.translate('common.error.invalidTimeShouldBeFuture');
-        }
-
-        return error;
-    };
 
     if (lodashGet(privatePersonalDetails, 'isLoading', true)) {
         return <FullscreenLoadingIndicator />;
     }
     return (
         <ScreenWrapper
-            includeSafeAreaPaddingBottom={false}
+            includeSafeAreaPaddingBottom
             testID={SetTimePage.displayName}
         >
             <HeaderWithBackButton
@@ -59,24 +44,12 @@ function SetTimePage({translate, privatePersonalDetails, customStatus}) {
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER)}
             />
             <View style={styles.flex1}>
-                <Form
-                    style={[styles.flexGrow1]}
-                    formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_TIME_FORM}
+                <TimePicker
+                    inputID="timePicker"
+                    defaultValue={clearAfter}
+                    style={styles.flexGrow1}
                     onSubmit={onSubmit}
-                    submitButtonText={translate('common.save')}
-                    submitButtonStyles={[styles.flex0, styles.justifyContentStart, styles.mh5, styles.setTimeFormButtonContainer]}
-                    errorMessageStyle={styles.timePickerButtonErrorText}
-                    validate={validate}
-                    enabledWhenOffline
-                    shouldUseDefaultValue
-                    useSmallerSubmitButtonSize={isExtraSmallScreenHeight}
-                >
-                    <TimePicker
-                        inputID="timePicker"
-                        defaultValue={DateUtils.extractTime12Hour(clearAfter)}
-                        style={styles.flexGrow1}
-                    />
-                </Form>
+                />
             </View>
         </ScreenWrapper>
     );
diff --git a/src/styles/styles.ts b/src/styles/styles.ts
index 4dc95129f9fe..0e0c8efd0a0c 100644
--- a/src/styles/styles.ts
+++ b/src/styles/styles.ts
@@ -2425,6 +2425,11 @@ const styles = (theme: ThemeColors) =>
             alignItems: 'center',
             padding: 20,
         },
+        numberPadWrapper: {
+            width: '100%',
+            alignItems: 'center',
+            paddingHorizontal: 20
+        },
 
         avatarSectionWrapper: {
             width: '100%',

From 274cea1f69da9aa8a985505ff4d90dd8ea8b307b Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 9 Nov 2023 09:54:28 +0100
Subject: [PATCH 089/118] fix focusing on hour input

---
 src/components/Button/index.js                |  6 +--
 src/components/FormHelpMessage.js             |  2 +-
 src/components/TimePicker.js                  | 37 +++++++------------
 .../Profile/CustomStatus/StatusPage.js        |  4 +-
 src/styles/styles.ts                          |  2 +-
 5 files changed, 21 insertions(+), 30 deletions(-)

diff --git a/src/components/Button/index.js b/src/components/Button/index.js
index dcf62e8a39ed..d761da576b64 100644
--- a/src/components/Button/index.js
+++ b/src/components/Button/index.js
@@ -296,9 +296,9 @@ function Button({
                 return onPress(event);
             }}
             onLongPress={(event) => {
-              if (isLongPressDisabled) {
-                return;
-            }
+                if (isLongPressDisabled) {
+                    return;
+                }
                 if (shouldEnableHapticFeedback) {
                     HapticFeedback.longPress();
                 }
diff --git a/src/components/FormHelpMessage.js b/src/components/FormHelpMessage.js
index 369be4607ebc..80e79bfa792b 100644
--- a/src/components/FormHelpMessage.js
+++ b/src/components/FormHelpMessage.js
@@ -3,9 +3,9 @@ import React from 'react';
 import {View} from 'react-native';
 import _ from 'underscore';
 import * as Localize from '@libs/Localize';
-import * as StyleUtils from '@styles/StyleUtils';
 import stylePropTypes from '@styles/stylePropTypes';
 import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
 import themeColors from '@styles/themes/default';
 import Icon from './Icon';
 import * as Expensicons from './Icon/Expensicons';
diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
index 1bb4ed143e65..2e8c1c90d93c 100644
--- a/src/components/TimePicker.js
+++ b/src/components/TimePicker.js
@@ -42,20 +42,6 @@ const AMOUNT_VIEW_ID = 'amountView';
 const NUM_PAD_CONTAINER_VIEW_ID = 'numPadContainerView';
 const NUM_PAD_VIEW_ID = 'numPadView';
 
-function formatHour(hourText) {
-    let adjustedHour = '00';
-    if (hourText > 12 && hourText <= 24) {
-        adjustedHour = String(hourText - 12);
-    } else if (hourText > 24) {
-        adjustedHour = `0${hourText[1]}`;
-    } else {
-        adjustedHour = hourText;
-    }
-
-    // Convert to a string and pad with a 0 if needed
-    return adjustedHour.toString().padStart(2, '0');
-}
-
 function insertAtPosition(originalString, newSubstring, selectionPositionFrom, selectionPositionTo, fn) {
     // Check for invalid positions
     if (selectionPositionFrom < 0 || selectionPositionTo < 0 || selectionPositionFrom > originalString.length || selectionPositionTo > originalString.length) {
@@ -293,7 +279,11 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
     );
 
     useEffect(() => {
-        minuteInputRef.current.focus();
+        // The first focus event on the input defaults to the end of the text. Subsequent focuses can occur at any position within the text input. Therefore, we need to ensure the hour input is focused correctly.
+        hourInputRef.current.focus();
+        setTimeout(() => {
+            minuteInputRef.current.focus();
+        }, 10);
     }, []);
 
     const arrowConfig = useMemo(
@@ -371,9 +361,11 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
                     style={[styles.flexRow, styles.w100, styles.justifyContentCenter, styles.timePickerInputsContainer, styles.mb8]}
                 >
                     <AmountTextInput
+                        placeholder={numberFormat(0)}
+                        maxLength={2}
                         formattedAmount={hours}
                         onChangeAmount={handleHourChange}
-                        placeholder={numberFormat(0)}
+                        role={CONST.ACCESSIBILITY_ROLE.TEXT}
                         ref={(ref) => {
                             if (typeof forwardedRef === 'function') {
                                 forwardedRef({refHour: ref, minuteRef: minuteInputRef.current});
@@ -383,22 +375,22 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
                             }
                             hourInputRef.current = ref;
                         }}
-                        maxLength={2}
                         onSelectionChange={(e) => {
                             setSelectionHour(e.nativeEvent.selection);
                         }}
-                        selection={selectionHour}
                         style={styles.timePickerInput}
                         containerStyles={[styles.timePickerHeight100]}
+                        selection={selectionHour}
                         showSoftInputOnFocus={false}
                     />
                     <Text style={styles.timePickerSemiDot}>{CONST.COLON}</Text>
                     <AmountTextInput
-                        onKeyPress={handleFocusOnBackspace}
-                        autofocus
+                        placeholder={numberFormat(0)}
+                        maxLength={2}
                         formattedAmount={minute}
+                        onKeyPress={handleFocusOnBackspace}
                         onChangeAmount={handleMinutesChange}
-                        placeholder={numberFormat(0)}
+                        role={CONST.ACCESSIBILITY_ROLE.TEXT}
                         ref={(ref) => {
                             if (typeof forwardedRef === 'function') {
                                 forwardedRef({refHour: hourInputRef.current, minuteRef: ref});
@@ -408,13 +400,12 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
                             }
                             minuteInputRef.current = ref;
                         }}
-                        maxLength={2}
                         onSelectionChange={(e) => {
                             setSelectionMinute(e.nativeEvent.selection);
                         }}
-                        selection={selectionMinute}
                         style={styles.timePickerInput}
                         containerStyles={[styles.timePickerHeight100]}
+                        selection={selectionMinute}
                         showSoftInputOnFocus={false}
                     />
                 </View>
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index b3cf662bcf2a..a4466e15f85b 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -142,15 +142,15 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                         <EmojiPickerButtonDropdown
                             inputID={INPUT_IDS.EMOJI_CODE}
                             accessibilityLabel={INPUT_IDS.EMOJI_CODE}
-                            accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
+                            role={CONST.ACCESSIBILITY_ROLE.TEXT}
                             defaultValue={defaultEmoji}
                             style={styles.mb3}
                         />
                         <TextInput
                             inputID={INPUT_IDS.STATUS_TEXT}
+                            role={CONST.ACCESSIBILITY_ROLE.TEXT}
                             label={localize.translate('statusPage.message')}
                             accessibilityLabel={INPUT_IDS.STATUS_TEXT}
-                            accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
                             defaultValue={defaultText}
                             maxLength={CONST.STATUS_TEXT_MAX_LENGTH}
                             autoFocus
diff --git a/src/styles/styles.ts b/src/styles/styles.ts
index 0e0c8efd0a0c..b864aaa5d64a 100644
--- a/src/styles/styles.ts
+++ b/src/styles/styles.ts
@@ -2428,7 +2428,7 @@ const styles = (theme: ThemeColors) =>
         numberPadWrapper: {
             width: '100%',
             alignItems: 'center',
-            paddingHorizontal: 20
+            paddingHorizontal: 20,
         },
 
         avatarSectionWrapper: {

From 3179d070ddeb2413649aed9c3476d7a9aeaba2d6 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 9 Nov 2023 10:10:23 +0100
Subject: [PATCH 090/118] remove cleanDraftValues

---
 src/libs/actions/FormActions.ts | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/src/libs/actions/FormActions.ts b/src/libs/actions/FormActions.ts
index ebd689e29078..ecaf38dc44f2 100644
--- a/src/libs/actions/FormActions.ts
+++ b/src/libs/actions/FormActions.ts
@@ -23,8 +23,4 @@ function setDraftValues<T extends OnyxFormKeyWithoutDraft>(formID: T, draftValue
     Onyx.merge(`${formID}Draft`, draftValues);
 }
 
-function cleanDraftValues<T extends OnyxFormKeyWithoutDraft>(formID: T) {
-    Onyx.merge(`${formID}Draft`, null);
-}
-
-export {setDraftValues, setErrorFields, setErrors, setIsLoading, cleanDraftValues};
+export {setDraftValues, setErrorFields, setErrors, setIsLoading};

From aba85d5d25df81c454a2669f0555a0b4dd26711a Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 9 Nov 2023 15:25:47 +0100
Subject: [PATCH 091/118] migrate to FormProvider

---
 .../settings/Profile/CustomStatus/StatusPage.js     | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index a4466e15f85b..2fa7a1c16c67 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -3,7 +3,8 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
 import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
 import EmojiPickerButtonDropdown from '@components/EmojiPicker/EmojiPickerButtonDropdown';
-import Form from '@components/Form';
+import FormProvider from '@components/Form/FormProvider';
+import InputWrapper from '@components/Form/InputWrapper';
 import HeaderWithBackButton from '@components/HeaderWithBackButton';
 import * as Expensicons from '@components/Icon/Expensicons';
 import MenuItem from '@components/MenuItem';
@@ -123,7 +124,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                 title={localize.translate('statusPage.status')}
                 onBackButtonPress={navigateBackToPreviousScreen}
             />
-            <Form
+            <FormProvider
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_FORM}
                 style={styles.flexGrow1}
                 ref={formRef}
@@ -139,14 +140,16 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                 </View>
                 <View style={[styles.mb2, styles.mt6]}>
                     <View style={[styles.mb4, styles.ph5]}>
-                        <EmojiPickerButtonDropdown
+                        <InputWrapper
+                            InputComponent={EmojiPickerButtonDropdown}
                             inputID={INPUT_IDS.EMOJI_CODE}
                             accessibilityLabel={INPUT_IDS.EMOJI_CODE}
                             role={CONST.ACCESSIBILITY_ROLE.TEXT}
                             defaultValue={defaultEmoji}
                             style={styles.mb3}
                         />
-                        <TextInput
+                        <InputWrapper
+                            InputComponent={TextInput}
                             inputID={INPUT_IDS.STATUS_TEXT}
                             role={CONST.ACCESSIBILITY_ROLE.TEXT}
                             label={localize.translate('statusPage.message')}
@@ -177,7 +180,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                         />
                     )}
                 </View>
-            </Form>
+            </FormProvider>
         </ScreenWrapper>
     );
 }

From b040910a35a4b697026f8f6701d3e81c0ea54bb2 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Thu, 9 Nov 2023 15:30:17 +0100
Subject: [PATCH 092/118] add resetForm to FormProvide

---
 src/components/Form/FormProvider.js | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/src/components/Form/FormProvider.js b/src/components/Form/FormProvider.js
index 92baa9727832..04f1ad8d5e16 100644
--- a/src/components/Form/FormProvider.js
+++ b/src/components/Form/FormProvider.js
@@ -1,6 +1,6 @@
 import lodashGet from 'lodash/get';
 import PropTypes from 'prop-types';
-import React, {createRef, useCallback, useMemo, useRef, useState} from 'react';
+import React, {createRef, forwardRef, useCallback, useImperativeHandle, useMemo, useRef, useState} from 'react';
 import {withOnyx} from 'react-native-onyx';
 import _ from 'underscore';
 import networkPropTypes from '@components/networkPropTypes';
@@ -99,7 +99,7 @@ function getInitialValueByType(valueType) {
     }
 }
 
-function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnChange, children, formState, network, enabledWhenOffline, onSubmit, ...rest}) {
+const FormProvider = forwardRef(({validate, formID, shouldValidateOnBlur, shouldValidateOnChange, children, formState, network, enabledWhenOffline, onSubmit, ...rest}, forwardedRef) => {
     const inputRefs = useRef({});
     const touchedInputs = useRef({});
     const [inputValues, setInputValues] = useState({});
@@ -202,6 +202,29 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC
         onSubmit(inputValues);
     }, [enabledWhenOffline, formState.isLoading, inputValues, network.isOffline, onSubmit, onValidate]);
 
+    /**
+     * Resets the form
+     */
+    const resetForm = useCallback(
+        (optionalValue) => {
+            _.each(inputValues, (inputRef, inputID) => {
+                setInputValues((prevState) => {
+                    const copyPrevState = _.clone(prevState);
+
+                    touchedInputs.current[inputID] = false;
+                    copyPrevState[inputID] = optionalValue[inputID] || '';
+
+                    return copyPrevState;
+                });
+            });
+            setErrors({});
+        },
+        [inputValues],
+    );
+    useImperativeHandle(forwardedRef, () => ({
+        resetForm,
+    }));
+
     const registerInput = useCallback(
         (inputID, propsToParse = {}) => {
             const newRef = inputRefs.current[inputID] || propsToParse.ref || createRef();
@@ -324,7 +347,7 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC
             </FormWrapper>
         </FormContext.Provider>
     );
-}
+});
 
 FormProvider.displayName = 'Form';
 FormProvider.propTypes = propTypes;

From 435c4d4a7008d39dbcc917ccdc376e5d846a8a37 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Fri, 10 Nov 2023 12:07:02 +0100
Subject: [PATCH 093/118] clean artifacts

---
 src/pages/settings/Profile/CustomStatus/StatusPage.js | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 437a24992f4c..b540cdc29488 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -97,7 +97,6 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
     useEffect(() => setBrickRoadIndicator(isValidClearAfterDate() ? null : CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR), [isValidClearAfterDate]);
 
-    // <<<<<<< HEAD
     useEffect(() => {
         if (!currentUserEmojiCode && !currentUserClearAfter && !draftClearAfter) {
             User.updateDraftCustomStatus({clearAfter: DateUtils.getEndOfToday()});
@@ -185,7 +184,6 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                             wrapperStyle={[styles.pl2]}
                         />
                     )}
-                    <View style={[styles.flexGrow1]} />
                 </View>
             </FormProvider>
         </HeaderPageLayout>

From 91b8be1e7f91e3a6df4f2ee88cd4705d982d6f42 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 13 Nov 2023 13:35:09 +0100
Subject: [PATCH 094/118] fix ios focus

---
 src/components/TimePicker/TimePicker.js       | 492 ++++++++++++++++++
 src/components/TimePicker/setSelection.ios.ts |  11 +
 src/components/TimePicker/setSelection.ts     |  22 +
 .../Profile/CustomStatus/SetTimePage.js       |   2 +-
 4 files changed, 526 insertions(+), 1 deletion(-)
 create mode 100644 src/components/TimePicker/TimePicker.js
 create mode 100644 src/components/TimePicker/setSelection.ios.ts
 create mode 100644 src/components/TimePicker/setSelection.ts

diff --git a/src/components/TimePicker/TimePicker.js b/src/components/TimePicker/TimePicker.js
new file mode 100644
index 000000000000..3b9f70bbfb25
--- /dev/null
+++ b/src/components/TimePicker/TimePicker.js
@@ -0,0 +1,492 @@
+import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {View} from 'react-native';
+import _ from 'underscore';
+import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import DateUtils from '@libs/DateUtils';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
+import AmountTextInput from '../AmountTextInput';
+import BigNumberPad from '../BigNumberPad';
+import Button from '../Button';
+import FormHelpMessage from '../FormHelpMessage';
+import refPropTypes from '../refPropTypes';
+import Text from '../Text';
+import setSelection from './setSelection';
+
+const propTypes = {
+    /** Refs forwarded to the TextInputWithCurrencySymbol */
+    forwardedRef: refPropTypes,
+
+    /** Default value for the inputs */
+    defaultValue: PropTypes.string,
+
+    /** Callback to call when the Save button is pressed  */
+    onSubmit: PropTypes.func.isRequired,
+
+    /** Callback to call when the input changes */
+    onInputChange: PropTypes.func,
+};
+
+const defaultProps = {
+    forwardedRef: null,
+    onInputChange: () => {},
+    defaultValue: '',
+};
+
+const AMOUNT_VIEW_ID = 'amountView';
+const NUM_PAD_CONTAINER_VIEW_ID = 'numPadContainerView';
+const NUM_PAD_VIEW_ID = 'numPadView';
+
+function insertAtPosition(originalString, newSubstring, selectionPositionFrom, selectionPositionTo) {
+    // Check for invalid positions
+    if (selectionPositionFrom < 0 || selectionPositionTo < 0 || selectionPositionFrom > originalString.length || selectionPositionTo > originalString.length) {
+        return;
+    }
+
+    // If the positions are the same, it means we're inserting at a point
+    if (selectionPositionFrom === selectionPositionTo) {
+        if (selectionPositionFrom === originalString.length) {
+            return originalString; // If the insertion point is at the end, simply return the original string
+        }
+        return originalString.slice(0, selectionPositionFrom) + newSubstring + originalString.slice(selectionPositionFrom);
+    }
+
+    // Replace the selected range
+    return originalString.slice(0, selectionPositionFrom) + newSubstring + originalString.slice(selectionPositionTo);
+}
+
+// if we need manually to move selection to the left we need to decrease both selection start and end by one
+function decreaseBothSelectionByOne({start, end}) {
+    if (start === 0) {
+        return {start: 0, end: 0};
+    }
+    return {start: start - 1, end: end - 1};
+}
+
+function replaceWithZeroAtPosition(originalString, position) {
+    if (position === 0 || position > 2) {
+        return originalString;
+    }
+    return `${originalString.slice(0, position - 1)}0${originalString.slice(position)}`;
+}
+
+function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
+    const {numberFormat, translate} = useLocalize();
+    const {isExtraSmallScreenHeight} = useWindowDimensions();
+    const value = DateUtils.extractTime12Hour(defaultValue);
+    const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen();
+
+    const [isError, setError] = useState(false);
+    const [selectionHour, setSelectionHour] = useState({start: 0, end: 0});
+    const [selectionMinute, setSelectionMinute] = useState({start: 2, end: 2}); // we focus it by default so need  to have selection on the end
+    const [hours, setHours] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).hour);
+    const [minute, setMinute] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).minute);
+    const [amPmValue, setAmPmValue] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).period);
+
+    const hourInputRef = useRef(null);
+    const minuteInputRef = useRef(null);
+
+    const focusMinuteInputOnFirstCharacter = useCallback(() => {
+        const cleanupTimer = setSelection({start: 0, end: 0}, minuteInputRef, setSelectionMinute);
+        return cleanupTimer;
+    }, [selectionMinute]);
+    const focusHourInputOnLastCharacter = useCallback(() => {
+        setSelectionHour({start: 2, end: 2});
+        const timer = setTimeout(() => {
+            hourInputRef.current.focus();
+        }, 10);
+        return () => clearTimeout(timer);
+    }, []);
+
+    const validate = (time) => {
+        const isValid = ValidationUtils.isTimeAtLeastOneMinuteInFuture(time, defaultValue);
+        setError(isValid);
+        return isValid;
+    };
+
+    // This function receive value from hour input and validate it
+    // The valid format is HH(from 00 to 12). If the user input 9, it will be 09. If user try to change 09 to 19 it would skip the first character
+    const handleHourChange = (text) => {
+        const isOnlyNumericValue = /^\d+$/.test(text.trim());
+        // Skip if the user is pasting the text or use non numeric characters.
+        if (selectionHour.start !== selectionHour.end || !isOnlyNumericValue) {
+            return;
+        }
+        // Remove non-numeric characters.
+        const filteredText = text.replace(/[^0-9]/g, '');
+
+        let newHour = hours;
+        let newSelection = selectionHour.start;
+
+        // Case when the cursor is at the start.
+        if (selectionHour.start === 0) {
+            // Handle cases where the hour would be > 12.
+
+            // when you entering text the filteredText would consist of three numbers
+            const formattedText = `${filteredText[0]}${filteredText[2] || 0}`;
+            if (formattedText > 12 && formattedText <= 24) {
+                newHour = String(formattedText - 12).padStart(2, '0');
+                newSelection = 2;
+                setAmPmValue(CONST.TIME_PERIOD.PM);
+            } else if (formattedText > 24) {
+                newHour = `0${formattedText[1]}`;
+                newSelection = 2;
+            } else {
+                newHour = `${formattedText[0]}${formattedText[1]}`;
+                newSelection = 1;
+            }
+        } else if (selectionHour.start === 1) {
+            // Case when the cursor is at the second position.
+            const formattedText = `${filteredText[0]}${filteredText[1]}`;
+
+            if (filteredText.length < 2) {
+                // If we remove a value, prepend 0.
+                newHour = `0${text}`;
+                newSelection = 0;
+                // If the second digit is > 2, replace the hour with 0 and the second digit.
+            } else if (formattedText > 12 && formattedText <= 24) {
+                newHour = String(formattedText - 12).padStart(2, '0');
+                newSelection = 2;
+                setAmPmValue(CONST.TIME_PERIOD.PM);
+            } else if (formattedText > 24) {
+                newHour = `0${text[1]}`;
+                newSelection = 2;
+            } else {
+                newHour = `${text[0]}${text[1]}`;
+                setHours(newHour);
+                newSelection = 2;
+            }
+        } else if (selectionHour.start === 2 && selectionHour.end === 2) {
+            // Case when the cursor is at the end and no text is selected.
+            if (filteredText.length < 2) {
+                newHour = `${text}0`;
+                newSelection = 1;
+            } else {
+                newSelection = 2;
+            }
+        }
+
+        setHours(newHour);
+        if (newSelection === 2) {
+            focusMinuteInputOnFirstCharacter();
+        }
+        setSelectionHour({start: newSelection, end: newSelection});
+    };
+
+    // This function receive value from minute input and validate it
+    // The valid format is MM(from 00 to 59). If the user input 9, it will be 09. If user try to change 09 to 99 it would skip the character
+    const handleMinutesChange = (text) => {
+        const isOnlyNumericValue = /^\d+$/.test(text.trim());
+        // Skip if the user is pasting the text or use non numeric characters.
+        if (selectionMinute.start !== selectionMinute.end || !isOnlyNumericValue) {
+            return;
+        }
+
+        // Remove non-numeric characters.
+        const filteredText = text.replace(/[^0-9]/g, '');
+
+        let newMinute = minute;
+        let newSelection = selectionMinute.start;
+        // Case when user selects and replaces the text.
+        if (selectionMinute.start !== selectionMinute.end) {
+            // If the first digit is > 5, prepend 0.
+            if (filteredText.length === 1 && filteredText > 5) {
+                newMinute = `0${filteredText}`;
+                newSelection = 2;
+                // If the first digit is <= 5, append 0 at the end.
+            } else if (filteredText.length === 1 && filteredText <= 5) {
+                newMinute = `${filteredText}0`;
+                newSelection = 1;
+            } else {
+                newMinute = `${filteredText.slice(0, 2)}`;
+                newSelection = 2;
+            }
+        } else if (selectionMinute.start === 0) {
+            // Case when the cursor is at the start.
+            const formattedText = `${filteredText[0]}${filteredText[2] || 0}`;
+            if (text[0] >= 6) {
+                newMinute = `0${formattedText[1]}`;
+                newSelection = 2;
+            } else {
+                newMinute = `${formattedText[0]}${formattedText[1]}`;
+                newSelection = 1;
+            }
+        } else if (selectionMinute.start === 1) {
+            // Case when the cursor is at the second position.
+            // If we remove a value, prepend 0.
+            if (filteredText.length < 2) {
+                newMinute = `0${text}`;
+                newSelection = 0;
+                setSelectionHour({start: 2, end: 2});
+                hourInputRef.current.focus();
+            } else {
+                newMinute = `${text[0]}${text[1]}`;
+                newSelection = 2;
+            }
+        } else if (filteredText.length < 2) {
+            // Case when the cursor is at the end and no text is selected.
+            newMinute = `${text}0`;
+            newSelection = 1;
+        }
+
+        setMinute(newMinute);
+        setSelectionMinute({start: newSelection, end: newSelection});
+    };
+
+    /**
+     * Update amount with number or Backspace pressed for BigNumberPad.
+     * Validate new amount with decimal number regex up to 6 digits and 2 decimal digit to enable Next button
+     *
+     * @param {String} key
+     */
+    const updateAmountNumberPad = useCallback(
+        (key) => {
+            const isHourFocused = hourInputRef.current.isFocused();
+            const isMinuteFocused = minuteInputRef.current.isFocused();
+            if (!isHourFocused && !isMinuteFocused) {
+                minuteInputRef.current.focus();
+            }
+
+            if (key === '.') {
+                return;
+            }
+            if (key === '<' || key === 'Backspace') {
+                if (isHourFocused) {
+                    const newHour = replaceWithZeroAtPosition(hours, selectionHour.start);
+                    setHours(newHour);
+                    setSelectionHour(decreaseBothSelectionByOne(selectionHour));
+                } else if (isMinuteFocused) {
+                    if (selectionMinute.start === 0) {
+                        focusHourInputOnLastCharacter();
+                        return;
+                    }
+                    const newMinute = replaceWithZeroAtPosition(minute, selectionMinute.start);
+                    setMinute(newMinute);
+                    setSelectionMinute(decreaseBothSelectionByOne(selectionMinute));
+                }
+                return;
+            }
+            const trimmedKey = key.replace(/[^0-9]/g, '');
+
+            if (isHourFocused) {
+                handleHourChange(insertAtPosition(hours, trimmedKey, selectionHour.start, selectionHour.end));
+            } else if (isMinuteFocused) {
+                handleMinutesChange(insertAtPosition(minute, trimmedKey, selectionMinute.start, selectionMinute.end));
+            }
+        },
+        // eslint-disable-next-line react-hooks/exhaustive-deps
+        [minute, hours, selectionHour, selectionMinute],
+    );
+
+    useEffect(() => {
+        // The first focus event on the input defaults to the end of the text. Subsequent focuses can occur at any position within the text input. Therefore, we need to ensure the hour input is focused correctly.
+        hourInputRef.current.focus();
+
+        setSelectionMinute({start: 2, end: 2});
+        const timer = setTimeout(() => {
+            minuteInputRef.current.focus();
+        }, 10);
+        return () => clearTimeout(timer);
+    }, []);
+
+    const arrowConfig = useMemo(
+        () => ({
+            shouldPreventDefault: false,
+        }),
+        [],
+    );
+
+    const arrowLeftCallback = useCallback(() => {
+        const isMinuteFocused = minuteInputRef.current.isFocused();
+        if (isMinuteFocused && selectionMinute.start === 0) {
+            // hourInputRef.current.focus();
+            focusHourInputOnLastCharacter();
+        }
+        // eslint-disable-next-line react-hooks/exhaustive-deps
+    }, [selectionHour, selectionMinute]);
+    const arrowRightCallback = useCallback(() => {
+        const isHourFocused = hourInputRef.current.isFocused();
+
+        if (isHourFocused && selectionHour.start === 2) {
+            focusMinuteInputOnFirstCharacter();
+        }
+        // eslint-disable-next-line react-hooks/exhaustive-deps
+    }, [selectionHour, selectionMinute]);
+
+    useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_LEFT, arrowLeftCallback, arrowConfig);
+    useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_RIGHT, arrowRightCallback, arrowConfig);
+
+    const handleFocusOnBackspace = useCallback(
+        (e) => {
+            if (selectionMinute.start !== 0 || e.key !== 'Backspace') {
+                return;
+            }
+            hourInputRef.current.focus();
+        },
+        // eslint-disable-next-line react-hooks/exhaustive-deps
+        [selectionMinute.start],
+    );
+
+    const {styleForAM, styleForPM} = StyleUtils.getStatusAMandPMButtonStyle(amPmValue);
+
+    const numberPad = useCallback(() => {
+        if (!canUseTouchScreen) {
+            return null;
+        }
+        return (
+            <BigNumberPad
+                nativeID={NUM_PAD_VIEW_ID}
+                numberPressed={updateAmountNumberPad}
+                isDisabledLongPress
+            />
+        );
+    }, [canUseTouchScreen, updateAmountNumberPad]);
+
+    useEffect(() => {
+        onInputChange(`${hours}:${minute} ${amPmValue}`);
+        // eslint-disable-next-line react-hooks/exhaustive-deps
+    }, [hours, minute, amPmValue]);
+
+    const handleSubmit = () => {
+        const time = `${hours}:${minute} ${amPmValue}`;
+        const isValid = ValidationUtils.isTimeAtLeastOneMinuteInFuture(time, defaultValue);
+
+        setError(!isValid);
+        if (isValid) {
+            onSubmit(time);
+        }
+    };
+
+    return (
+        <View style={styles.flex1}>
+            <View style={[styles.flex1, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}>
+                <View
+                    nativeID={AMOUNT_VIEW_ID}
+                    style={[styles.flexRow, styles.w100, styles.justifyContentCenter, styles.timePickerInputsContainer, styles.mb8]}
+                >
+                    <AmountTextInput
+                        placeholder={numberFormat(0)}
+                        maxLength={2}
+                        formattedAmount={hours}
+                        onChangeAmount={handleHourChange}
+                        role={CONST.ACCESSIBILITY_ROLE.TEXT}
+                        ref={(ref) => {
+                            if (typeof forwardedRef === 'function') {
+                                forwardedRef({refHour: ref, minuteRef: minuteInputRef.current});
+                            } else if (forwardedRef && _.has(forwardedRef, 'current')) {
+                                // eslint-disable-next-line no-param-reassign
+                                forwardedRef.current = {hourRef: ref, minuteRef: minuteInputRef.current};
+                            }
+                            hourInputRef.current = ref;
+                        }}
+                        onSelectionChange={(e) => {
+                            setSelectionHour(e.nativeEvent.selection);
+                        }}
+                        style={styles.timePickerInput}
+                        containerStyles={[styles.timePickerHeight100]}
+                        selection={selectionHour}
+                        showSoftInputOnFocus={false}
+                    />
+                    <Text style={styles.timePickerSemiDot}>{CONST.COLON}</Text>
+                    <AmountTextInput
+                        placeholder={numberFormat(0)}
+                        maxLength={2}
+                        formattedAmount={minute}
+                        onKeyPress={handleFocusOnBackspace}
+                        onChangeAmount={handleMinutesChange}
+                        role={CONST.ACCESSIBILITY_ROLE.TEXT}
+                        ref={(ref) => {
+                            if (typeof forwardedRef === 'function') {
+                                forwardedRef({refHour: hourInputRef.current, minuteRef: ref});
+                            } else if (forwardedRef && _.has(forwardedRef, 'current')) {
+                                // eslint-disable-next-line no-param-reassign
+                                minuteInputRef.current = {hourRef: hourInputRef.current, minuteInputRef: ref};
+                            }
+                            minuteInputRef.current = ref;
+                        }}
+                        onSelectionChange={(e) => {
+                            setSelectionMinute(e.nativeEvent.selection);
+                        }}
+                        style={styles.timePickerInput}
+                        containerStyles={[styles.timePickerHeight100]}
+                        selection={selectionMinute}
+                        showSoftInputOnFocus={false}
+                    />
+                </View>
+                <View style={styles.timePickerSwitcherContainer}>
+                    <Button
+                        shouldEnableHapticFeedback
+                        innerStyles={styleForAM}
+                        medium={isExtraSmallScreenHeight}
+                        text={translate('common.am')}
+                        onLongPress={() => {}}
+                        onPress={() => {
+                            validate();
+                            setAmPmValue(CONST.TIME_PERIOD.AM);
+                        }}
+                        onPressOut={() => {}}
+                        onMouseDown={(e) => e.preventDefault()}
+                    />
+                    <Button
+                        shouldEnableHapticFeedback
+                        innerStyles={[...styleForPM, styles.ml1]}
+                        medium={isExtraSmallScreenHeight}
+                        text={translate('common.pm')}
+                        onLongPress={() => {}}
+                        onPress={() => {
+                            validate();
+                            setAmPmValue(CONST.TIME_PERIOD.PM);
+                        }}
+                        onPressOut={() => {}}
+                        onMouseDown={(e) => e.preventDefault()}
+                    />
+                </View>
+            </View>
+            {isError ? (
+                <FormHelpMessage
+                    isError={isError}
+                    message={translate('common.error.invalidTimeShouldBeFuture')}
+                    style={styles.pl5}
+                />
+            ) : (
+                <View style={styles.formHelperMessage} />
+            )}
+            <View
+                style={[styles.numberPadWrapper, styles.pb4]}
+                nativeID={NUM_PAD_CONTAINER_VIEW_ID}
+            >
+                {numberPad()}
+            </View>
+            <Button
+                success
+                medium={isExtraSmallScreenHeight}
+                style={[styles.mb5, styles.mh5]}
+                onPress={handleSubmit}
+                pressOnEnter
+                text={translate('common.save')}
+            />
+        </View>
+    );
+}
+
+TimePicker.propTypes = propTypes;
+TimePicker.defaultProps = defaultProps;
+TimePicker.displayName = 'TimePicker';
+
+const TimePickerWithRef = React.forwardRef((props, ref) => (
+    <TimePicker
+        // eslint-disable-next-line react/jsx-props-no-spreading
+        {...props}
+        forwardedRef={ref}
+    />
+));
+
+TimePickerWithRef.displayName = 'TimePickerWithRef';
+
+export default TimePickerWithRef;
diff --git a/src/components/TimePicker/setSelection.ios.ts b/src/components/TimePicker/setSelection.ios.ts
new file mode 100644
index 000000000000..6313588989dc
--- /dev/null
+++ b/src/components/TimePicker/setSelection.ios.ts
@@ -0,0 +1,11 @@
+import { RefObject } from 'react';
+import { TextInput } from 'react-native';
+
+export default function setSelection(
+  value: { start: number; end: number }, 
+  ref: RefObject<TextInput>
+) {
+  ref.current?.focus();
+  ref.current?.setNativeProps({ selection: value });
+  return () => {};
+}
diff --git a/src/components/TimePicker/setSelection.ts b/src/components/TimePicker/setSelection.ts
new file mode 100644
index 000000000000..06d93ef3937d
--- /dev/null
+++ b/src/components/TimePicker/setSelection.ts
@@ -0,0 +1,22 @@
+// setSelection.ts
+import { RefObject } from 'react';
+import { TextInput } from 'react-native';
+
+const setSelection = (
+  value: { start: number; end: number },
+  ref: RefObject<TextInput>,
+  setSelectionCallback: (value: { start: number; end: number }) => void
+): (() => void) => {
+  ref.current?.focus();
+
+  const timer = setTimeout(() => {
+    setSelectionCallback(value);
+  }, 10);
+
+  // Return the cleanup function
+  return () => {
+    clearTimeout(timer);
+  };
+};
+
+export default setSelection;
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 8c4007d39877..2b5c374a133d 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -5,7 +5,7 @@ import {withOnyx} from 'react-native-onyx';
 import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
 import HeaderWithBackButton from '@components/HeaderWithBackButton';
 import ScreenWrapper from '@components/ScreenWrapper';
-import TimePicker from '@components/TimePicker';
+import TimePicker from '@components/TimePicker/TimePicker';
 import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
 import usePrivatePersonalDetails from '@hooks/usePrivatePersonalDetails';
 import * as User from '@libs/actions/User';

From 6f821fca87025cab719d9f9801ced31692658d81 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 13 Nov 2023 16:12:08 +0100
Subject: [PATCH 095/118] update naming

---
 src/components/TimePicker.js                  | 482 ------------------
 src/components/TimePicker/TimePicker.js       |  11 +-
 src/components/TimePicker/setSelection.ios.ts |  15 +-
 src/components/TimePicker/setSelection.ts     |  26 +-
 src/libs/DateUtils.ts                         |  37 +-
 src/libs/ValidationUtils.ts                   |  27 +-
 .../CustomStatus/CustomClearAfterPage.js      |  12 +-
 .../Profile/CustomStatus/StatusPage.js        |   8 +-
 8 files changed, 60 insertions(+), 558 deletions(-)
 delete mode 100644 src/components/TimePicker.js

diff --git a/src/components/TimePicker.js b/src/components/TimePicker.js
deleted file mode 100644
index 2e8c1c90d93c..000000000000
--- a/src/components/TimePicker.js
+++ /dev/null
@@ -1,482 +0,0 @@
-import PropTypes from 'prop-types';
-import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
-import {View} from 'react-native';
-import _ from 'underscore';
-import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
-import useLocalize from '@hooks/useLocalize';
-import useWindowDimensions from '@hooks/useWindowDimensions';
-import DateUtils from '@libs/DateUtils';
-import * as DeviceCapabilities from '@libs/DeviceCapabilities';
-import * as ValidationUtils from '@libs/ValidationUtils';
-import styles from '@styles/styles';
-import * as StyleUtils from '@styles/StyleUtils';
-import CONST from '@src/CONST';
-import AmountTextInput from './AmountTextInput';
-import BigNumberPad from './BigNumberPad';
-import Button from './Button';
-import FormHelpMessage from './FormHelpMessage';
-import refPropTypes from './refPropTypes';
-import Text from './Text';
-
-const propTypes = {
-    /** Refs forwarded to the TextInputWithCurrencySymbol */
-    forwardedRef: refPropTypes,
-
-    /** Default value for the inputs */
-    defaultValue: PropTypes.string,
-
-    /** Callback to call when the Save button is pressed  */
-    onSubmit: PropTypes.func.isRequired,
-
-    /** Callback to call when the input changes */
-    onInputChange: PropTypes.func,
-};
-
-const defaultProps = {
-    forwardedRef: null,
-    onInputChange: () => {},
-    defaultValue: '',
-};
-
-const AMOUNT_VIEW_ID = 'amountView';
-const NUM_PAD_CONTAINER_VIEW_ID = 'numPadContainerView';
-const NUM_PAD_VIEW_ID = 'numPadView';
-
-function insertAtPosition(originalString, newSubstring, selectionPositionFrom, selectionPositionTo, fn) {
-    // Check for invalid positions
-    if (selectionPositionFrom < 0 || selectionPositionTo < 0 || selectionPositionFrom > originalString.length || selectionPositionTo > originalString.length) {
-        return;
-    }
-
-    // If the positions are the same, it means we're inserting at a point
-    if (selectionPositionFrom === selectionPositionTo) {
-        if (selectionPositionFrom === originalString.length) {
-            if (typeof fn === 'function') {
-                fn();
-            }
-            return originalString; // If the insertion point is at the end, simply return the original string
-        }
-        return originalString.slice(0, selectionPositionFrom) + newSubstring + originalString.slice(selectionPositionFrom);
-    }
-
-    // Replace the selected range
-    return originalString.slice(0, selectionPositionFrom) + newSubstring + originalString.slice(selectionPositionTo);
-}
-
-function decreaseBothSelectionByOne({start, end}) {
-    if (start === 0) {
-        return {start: 0, end: 0};
-    }
-    return {start: start - 1, end: end - 1};
-}
-
-function replaceWithZeroAtPosition(originalString, position) {
-    if (position === 0 || position > 2) {
-        return originalString;
-    }
-    return `${originalString.slice(0, position - 1)}0${originalString.slice(position)}`;
-}
-
-function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
-    const {numberFormat, translate} = useLocalize();
-    const {isExtraSmallScreenHeight} = useWindowDimensions();
-    const value = DateUtils.extractTime12Hour(defaultValue);
-    const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen();
-
-    const [isError, setError] = useState(false);
-    const [selectionHour, setSelectionHour] = useState({start: 0, end: 0});
-    const [selectionMinute, setSelectionMinute] = useState({start: 2, end: 2}); // we focus it by default so need  to have selection on the end
-    const [hours, setHours] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).hour);
-    const [minute, setMinute] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).minute);
-    const [amPmValue, setAmPmValue] = useState(() => DateUtils.get12HourTimeObjectFromDate(value).period);
-
-    const hourInputRef = useRef(null);
-    const minuteInputRef = useRef(null);
-
-    const focusMinuteInputOnFirstCharacter = useCallback(() => {
-        setSelectionMinute({start: 0, end: 0});
-        minuteInputRef.current.focus();
-    }, []);
-
-    const validate = (time) => {
-        const isValid = ValidationUtils.isTimeAtLeastOneMinuteInFuture(time, defaultValue);
-        setError(isValid);
-        return isValid;
-    };
-
-    // This function receive value from hour input and validate it
-    // The valid format is HH(from 00 to 12). If the user input 9, it will be 09. If user try to change 09 to 19 it would skip the first character
-    const handleHourChange = (text) => {
-        const isOnlyNumericValue = /^\d+$/.test(text.trim());
-        // Skip if the user is pasting the text or use non numeric characters.
-        if (selectionHour.start !== selectionHour.end || !isOnlyNumericValue) {
-            return;
-        }
-        // Remove non-numeric characters.
-        const filteredText = text.replace(/[^0-9]/g, '');
-
-        let newHour = hours;
-        let newSelection = selectionHour.start;
-
-        // Case when the cursor is at the start.
-        if (selectionHour.start === 0) {
-            // Handle cases where the hour would be > 12.
-
-            // when you entering text the filteredText would consist of three numbers
-            const formattedText = `${filteredText[0]}${filteredText[2] || 0}`;
-            if (formattedText > 12 && formattedText <= 24) {
-                newHour = String(formattedText - 12).padStart(2, '0');
-                newSelection = 2;
-                focusMinuteInputOnFirstCharacter();
-                setAmPmValue(CONST.TIME_PERIOD.PM);
-            } else if (formattedText > 24) {
-                newHour = `0${formattedText[1]}`;
-                newSelection = 2;
-                focusMinuteInputOnFirstCharacter();
-            } else {
-                newHour = `${formattedText[0]}${formattedText[1]}`;
-                newSelection = 1;
-            }
-        } else if (selectionHour.start === 1) {
-            // Case when the cursor is at the second position.
-            const formattedText = `${filteredText[0]}${filteredText[1]}`;
-
-            if (filteredText.length < 2) {
-                // If we remove a value, prepend 0.
-                newHour = `0${text}`;
-                newSelection = 0;
-                // If the second digit is > 2, replace the hour with 0 and the second digit.
-            } else if (formattedText > 12 && formattedText <= 24) {
-                newHour = String(formattedText - 12).padStart(2, '0');
-                newSelection = 2;
-                focusMinuteInputOnFirstCharacter();
-                setAmPmValue(CONST.TIME_PERIOD.PM);
-            } else if (formattedText > 24) {
-                newHour = `0${text[1]}`;
-                newSelection = 2;
-                focusMinuteInputOnFirstCharacter();
-            } else {
-                newHour = `${text[0]}${text[1]}`;
-                newSelection = 2;
-                focusMinuteInputOnFirstCharacter();
-            }
-        } else if (selectionHour.start === 2 && selectionHour.end === 2) {
-            // Case when the cursor is at the end and no text is selected.
-            if (filteredText.length < 2) {
-                newHour = `${text}0`;
-                newSelection = 1;
-            } else {
-                focusMinuteInputOnFirstCharacter();
-            }
-        }
-
-        setHours(newHour);
-        setSelectionHour({start: newSelection, end: newSelection});
-    };
-
-    // This function receive value from minute input and validate it
-    // The valid format is MM(from 00 to 59). If the user input 9, it will be 09. If user try to change 09 to 99 it would skip the character
-    const handleMinutesChange = (text) => {
-        const isOnlyNumericValue = /^\d+$/.test(text.trim());
-        // Skip if the user is pasting the text or use non numeric characters.
-        if (selectionMinute.start !== selectionMinute.end || !isOnlyNumericValue) {
-            return;
-        }
-
-        // Remove non-numeric characters.
-        const filteredText = text.replace(/[^0-9]/g, '');
-
-        let newMinute = minute;
-        let newSelection = selectionMinute.start;
-        // Case when user selects and replaces the text.
-        if (selectionMinute.start !== selectionMinute.end) {
-            // If the first digit is > 5, prepend 0.
-            if (filteredText.length === 1 && filteredText > 5) {
-                newMinute = `0${filteredText}`;
-                newSelection = 2;
-                // If the first digit is <= 5, append 0 at the end.
-            } else if (filteredText.length === 1 && filteredText <= 5) {
-                newMinute = `${filteredText}0`;
-                newSelection = 1;
-            } else {
-                newMinute = `${filteredText.slice(0, 2)}`;
-                newSelection = 2;
-            }
-        } else if (selectionMinute.start === 0) {
-            // Case when the cursor is at the start.
-            const formattedText = `${filteredText[0]}${filteredText[2] || 0}`;
-            if (text[0] >= 6) {
-                newMinute = `0${formattedText[1]}`;
-                newSelection = 2;
-            } else {
-                newMinute = `${formattedText[0]}${formattedText[1]}`;
-                newSelection = 1;
-            }
-        } else if (selectionMinute.start === 1) {
-            // Case when the cursor is at the second position.
-            // If we remove a value, prepend 0.
-            if (filteredText.length < 2) {
-                newMinute = `0${text}`;
-                newSelection = 0;
-                setSelectionHour({start: 2, end: 2});
-                hourInputRef.current.focus();
-            } else {
-                newMinute = `${text[0]}${text[1]}`;
-                newSelection = 2;
-            }
-        } else if (filteredText.length < 2) {
-            // Case when the cursor is at the end and no text is selected.
-            newMinute = `${text}0`;
-            newSelection = 1;
-        }
-
-        setMinute(newMinute);
-        setSelectionMinute({start: newSelection, end: newSelection});
-    };
-
-    /**
-     * Update amount with number or Backspace pressed for BigNumberPad.
-     * Validate new amount with decimal number regex up to 6 digits and 2 decimal digit to enable Next button
-     *
-     * @param {String} key
-     */
-    const updateAmountNumberPad = useCallback(
-        (key) => {
-            const isHourFocused = hourInputRef.current.isFocused();
-            const isMinuteFocused = minuteInputRef.current.isFocused();
-            if (!isHourFocused && !isMinuteFocused) {
-                hourInputRef.current.focus();
-                setTimeout(() => setSelectionHour({start: 0, end: 0}), 10);
-            }
-
-            if (key === '.') {
-                return;
-            }
-            if (key === '<' || key === 'Backspace') {
-                if (isHourFocused) {
-                    const newHour = replaceWithZeroAtPosition(hours, selectionHour.start);
-                    setHours(newHour);
-                    setSelectionHour(decreaseBothSelectionByOne(selectionHour));
-                } else if (isMinuteFocused) {
-                    if (selectionMinute.start === 0) {
-                        hourInputRef.current.focus();
-                    }
-                    const newMinute = replaceWithZeroAtPosition(minute, selectionMinute.start);
-                    setMinute(newMinute);
-                    setSelectionMinute(decreaseBothSelectionByOne(selectionMinute));
-                }
-                return;
-            }
-            const trimmedKey = key.replace(/[^0-9]/g, '');
-            if (isHourFocused) {
-                handleHourChange(insertAtPosition(hours, trimmedKey, selectionHour.start, selectionHour.end));
-            } else if (isMinuteFocused) {
-                handleMinutesChange(insertAtPosition(minute, trimmedKey, selectionMinute.start, selectionMinute.end));
-            }
-        },
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-        [minute, hours, selectionHour, selectionMinute],
-    );
-
-    useEffect(() => {
-        // The first focus event on the input defaults to the end of the text. Subsequent focuses can occur at any position within the text input. Therefore, we need to ensure the hour input is focused correctly.
-        hourInputRef.current.focus();
-        setTimeout(() => {
-            minuteInputRef.current.focus();
-        }, 10);
-    }, []);
-
-    const arrowConfig = useMemo(
-        () => ({
-            shouldPreventDefault: false,
-        }),
-        [],
-    );
-
-    const arrowLeftCallback = useCallback(() => {
-        const isMinuteFocused = minuteInputRef.current.isFocused();
-        if (isMinuteFocused && selectionMinute.start === 0) {
-            hourInputRef.current.focus();
-        }
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [selectionHour, selectionMinute]);
-    const arrowRightCallback = useCallback(() => {
-        const isHourFocused = hourInputRef.current.isFocused();
-
-        if (isHourFocused && selectionHour.start === 2) {
-            focusMinuteInputOnFirstCharacter();
-        }
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [selectionHour, selectionMinute]);
-
-    useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_LEFT, arrowLeftCallback, arrowConfig);
-    useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_RIGHT, arrowRightCallback, arrowConfig);
-
-    const handleFocusOnBackspace = useCallback(
-        (e) => {
-            if (selectionMinute.start !== 0 || e.key !== 'Backspace') {
-                return;
-            }
-            hourInputRef.current.focus();
-        },
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-        [selectionMinute.start],
-    );
-
-    const {styleForAM, styleForPM} = StyleUtils.getStatusAMandPMButtonStyle(amPmValue);
-
-    const numberPad = useCallback(() => {
-        if (!canUseTouchScreen) {
-            return null;
-        }
-        return (
-            <BigNumberPad
-                nativeID={NUM_PAD_VIEW_ID}
-                numberPressed={updateAmountNumberPad}
-                isDisabledLongPress
-            />
-        );
-    }, [canUseTouchScreen, updateAmountNumberPad]);
-
-    useEffect(() => {
-        onInputChange(`${hours}:${minute} ${amPmValue}`);
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [hours, minute, amPmValue]);
-
-    const handleSubmit = () => {
-        const time = `${hours}:${minute} ${amPmValue}`;
-        const isValid = ValidationUtils.isTimeAtLeastOneMinuteInFuture(time, defaultValue);
-
-        setError(!isValid);
-        if (isValid) {
-            onSubmit(time);
-        }
-    };
-
-    return (
-        <View style={styles.flex1}>
-            <View style={[styles.flex1, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}>
-                <View
-                    nativeID={AMOUNT_VIEW_ID}
-                    style={[styles.flexRow, styles.w100, styles.justifyContentCenter, styles.timePickerInputsContainer, styles.mb8]}
-                >
-                    <AmountTextInput
-                        placeholder={numberFormat(0)}
-                        maxLength={2}
-                        formattedAmount={hours}
-                        onChangeAmount={handleHourChange}
-                        role={CONST.ACCESSIBILITY_ROLE.TEXT}
-                        ref={(ref) => {
-                            if (typeof forwardedRef === 'function') {
-                                forwardedRef({refHour: ref, minuteRef: minuteInputRef.current});
-                            } else if (forwardedRef && _.has(forwardedRef, 'current')) {
-                                // eslint-disable-next-line no-param-reassign
-                                forwardedRef.current = {hourRef: ref, minuteRef: minuteInputRef.current};
-                            }
-                            hourInputRef.current = ref;
-                        }}
-                        onSelectionChange={(e) => {
-                            setSelectionHour(e.nativeEvent.selection);
-                        }}
-                        style={styles.timePickerInput}
-                        containerStyles={[styles.timePickerHeight100]}
-                        selection={selectionHour}
-                        showSoftInputOnFocus={false}
-                    />
-                    <Text style={styles.timePickerSemiDot}>{CONST.COLON}</Text>
-                    <AmountTextInput
-                        placeholder={numberFormat(0)}
-                        maxLength={2}
-                        formattedAmount={minute}
-                        onKeyPress={handleFocusOnBackspace}
-                        onChangeAmount={handleMinutesChange}
-                        role={CONST.ACCESSIBILITY_ROLE.TEXT}
-                        ref={(ref) => {
-                            if (typeof forwardedRef === 'function') {
-                                forwardedRef({refHour: hourInputRef.current, minuteRef: ref});
-                            } else if (forwardedRef && _.has(forwardedRef, 'current')) {
-                                // eslint-disable-next-line no-param-reassign
-                                minuteInputRef.current = {hourRef: hourInputRef.current, minuteInputRef: ref};
-                            }
-                            minuteInputRef.current = ref;
-                        }}
-                        onSelectionChange={(e) => {
-                            setSelectionMinute(e.nativeEvent.selection);
-                        }}
-                        style={styles.timePickerInput}
-                        containerStyles={[styles.timePickerHeight100]}
-                        selection={selectionMinute}
-                        showSoftInputOnFocus={false}
-                    />
-                </View>
-                <View style={styles.timePickerSwitcherContainer}>
-                    <Button
-                        shouldEnableHapticFeedback
-                        innerStyles={styleForAM}
-                        medium={isExtraSmallScreenHeight}
-                        text={translate('common.am')}
-                        onLongPress={() => {}}
-                        onPress={() => {
-                            validate();
-                            setAmPmValue(CONST.TIME_PERIOD.AM);
-                        }}
-                        onPressOut={() => {}}
-                        onMouseDown={(e) => e.preventDefault()}
-                    />
-                    <Button
-                        shouldEnableHapticFeedback
-                        innerStyles={[...styleForPM, styles.ml1]}
-                        medium={isExtraSmallScreenHeight}
-                        text={translate('common.pm')}
-                        onLongPress={() => {}}
-                        onPress={() => {
-                            validate();
-                            setAmPmValue(CONST.TIME_PERIOD.PM);
-                        }}
-                        onPressOut={() => {}}
-                        onMouseDown={(e) => e.preventDefault()}
-                    />
-                </View>
-            </View>
-            {isError ? (
-                <FormHelpMessage
-                    isError={isError}
-                    message={translate('common.error.invalidTimeShouldBeFuture')}
-                    style={styles.pl5}
-                />
-            ) : (
-                <View style={styles.formHelperMessage} />
-            )}
-            <View
-                style={[styles.numberPadWrapper, styles.pb4]}
-                nativeID={NUM_PAD_CONTAINER_VIEW_ID}
-            >
-                {numberPad()}
-            </View>
-            <Button
-                success
-                medium={isExtraSmallScreenHeight}
-                style={[styles.mb5, styles.mh5]}
-                onPress={handleSubmit}
-                pressOnEnter
-                text={translate('common.save')}
-            />
-        </View>
-    );
-}
-
-TimePicker.propTypes = propTypes;
-TimePicker.defaultProps = defaultProps;
-TimePicker.displayName = 'TimePicker';
-
-const TimePickerWithRef = React.forwardRef((props, ref) => (
-    <TimePicker
-        // eslint-disable-next-line react/jsx-props-no-spreading
-        {...props}
-        forwardedRef={ref}
-    />
-));
-
-TimePickerWithRef.displayName = 'TimePickerWithRef';
-
-export default TimePickerWithRef;
diff --git a/src/components/TimePicker/TimePicker.js b/src/components/TimePicker/TimePicker.js
index 3b9f70bbfb25..5379977411db 100644
--- a/src/components/TimePicker/TimePicker.js
+++ b/src/components/TimePicker/TimePicker.js
@@ -105,8 +105,8 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
     }, []);
 
     const validate = (time) => {
-        const isValid = ValidationUtils.isTimeAtLeastOneMinuteInFuture(time, defaultValue);
-        setError(isValid);
+        const isValid = DateUtils.isTimeAtLeastOneMinuteInFuture({timeString: time || `${hours}:${minute} ${amPmValue}`, dateTimeString: defaultValue});
+        setError(!isValid);
         return isValid;
     };
 
@@ -292,6 +292,8 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
         const timer = setTimeout(() => {
             minuteInputRef.current.focus();
         }, 10);
+
+        validate();
         return () => clearTimeout(timer);
     }, []);
 
@@ -355,9 +357,8 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
 
     const handleSubmit = () => {
         const time = `${hours}:${minute} ${amPmValue}`;
-        const isValid = ValidationUtils.isTimeAtLeastOneMinuteInFuture(time, defaultValue);
+        const isValid = validate(time);
 
-        setError(!isValid);
         if (isValid) {
             onSubmit(time);
         }
@@ -427,7 +428,6 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
                         text={translate('common.am')}
                         onLongPress={() => {}}
                         onPress={() => {
-                            validate();
                             setAmPmValue(CONST.TIME_PERIOD.AM);
                         }}
                         onPressOut={() => {}}
@@ -440,7 +440,6 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
                         text={translate('common.pm')}
                         onLongPress={() => {}}
                         onPress={() => {
-                            validate();
                             setAmPmValue(CONST.TIME_PERIOD.PM);
                         }}
                         onPressOut={() => {}}
diff --git a/src/components/TimePicker/setSelection.ios.ts b/src/components/TimePicker/setSelection.ios.ts
index 6313588989dc..0d1dfc004bc7 100644
--- a/src/components/TimePicker/setSelection.ios.ts
+++ b/src/components/TimePicker/setSelection.ios.ts
@@ -1,11 +1,8 @@
-import { RefObject } from 'react';
-import { TextInput } from 'react-native';
+import {RefObject} from 'react';
+import {TextInput} from 'react-native';
 
-export default function setSelection(
-  value: { start: number; end: number }, 
-  ref: RefObject<TextInput>
-) {
-  ref.current?.focus();
-  ref.current?.setNativeProps({ selection: value });
-  return () => {};
+export default function setSelection(value: {start: number; end: number}, ref: RefObject<TextInput>) {
+    ref.current?.focus();
+    ref.current?.setNativeProps({selection: value});
+    return () => {};
 }
diff --git a/src/components/TimePicker/setSelection.ts b/src/components/TimePicker/setSelection.ts
index 06d93ef3937d..36304b408f29 100644
--- a/src/components/TimePicker/setSelection.ts
+++ b/src/components/TimePicker/setSelection.ts
@@ -1,22 +1,18 @@
 // setSelection.ts
-import { RefObject } from 'react';
-import { TextInput } from 'react-native';
+import {RefObject} from 'react';
+import {TextInput} from 'react-native';
 
-const setSelection = (
-  value: { start: number; end: number },
-  ref: RefObject<TextInput>,
-  setSelectionCallback: (value: { start: number; end: number }) => void
-): (() => void) => {
-  ref.current?.focus();
+const setSelection = (value: {start: number; end: number}, ref: RefObject<TextInput>, setSelectionCallback: (value: {start: number; end: number}) => void): (() => void) => {
+    ref.current?.focus();
 
-  const timer = setTimeout(() => {
-    setSelectionCallback(value);
-  }, 10);
+    const timer = setTimeout(() => {
+        setSelectionCallback(value);
+    }, 10);
 
-  // Return the cleanup function
-  return () => {
-    clearTimeout(timer);
-  };
+    // Return the cleanup function
+    return () => {
+        clearTimeout(timer);
+    };
 };
 
 export default setSelection;
diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts
index 5dbdaf49fdff..905c1158d855 100644
--- a/src/libs/DateUtils.ts
+++ b/src/libs/DateUtils.ts
@@ -380,7 +380,7 @@ function getEndOfToday(): string {
 /**
  * returns {string} example: 2023-05-16 05:34:14
  */
-function getEndOfWeekFromNow(): string {
+function getOneWeekFromNow(): string {
     const date = addDays(new Date(), 7);
     return format(date, 'yyyy-MM-dd HH:mm:ss');
 }
@@ -437,7 +437,7 @@ function getDateFromStatusType(type: CustomStatusTypes): string {
         case CONST.CUSTOM_STATUS_TYPES.AFTER_TODAY:
             return getEndOfToday();
         case CONST.CUSTOM_STATUS_TYPES.AFTER_WEEK:
-            return getEndOfWeekFromNow();
+            return getOneWeekFromNow();
         case CONST.CUSTOM_STATUS_TYPES.NEVER:
             return CONST.CUSTOM_STATUS_TYPES.NEVER;
         default:
@@ -596,15 +596,32 @@ function areDatesIdentical(dateTimeStringFirst: string, dateTimeStringSecond: st
 }
 
 /**
- * param {String} dateTimeString
+ * Checks if the time input is at least one minute in the future.
+ * param {String} timeString: '04:24 AM'
+ * param {String} dateTimeString: '2023-11-14 14:24:00'
  * returns {Boolean}
  */
-function hasDateExpired(dateTimeString: string): boolean {
-    const validUntil = addMinutes(new Date(), 1);
-    const dateToCheck = parse(dateTimeString, 'yyyy-MM-dd HH:mm:ss', new Date());
+const isTimeAtLeastOneMinuteInFuture = ({timeString, dateTimeString}: {timeString?: string; dateTimeString: string}): boolean => {
+    let dateToCheck = dateTimeString;
+    if (timeString) {
+        //  return false;
+        // Parse the hour and minute from the time input
+        const [hourStr] = timeString.split(/[:\s]+/);
+        const hour = parseInt(hourStr, 10);
 
-    return isBefore(dateToCheck, validUntil);
-}
+        if (hour === 0) {
+            return false;
+        }
+
+        dateToCheck = combineDateAndTime(timeString, dateTimeString);
+    }
+
+    // Get current date and time
+    const now = new Date();
+
+    // Check if the combinedDate is at least one minute later than the current date and time
+    return isAfter(new Date(dateToCheck), addMinutes(now, 1));
+};
 
 /**
  * Checks if the input date is in the future compared to the reference date.
@@ -674,7 +691,7 @@ const DateUtils = {
     getDateStringFromISOTimestamp,
     getThirtyMinutesFromNow,
     getEndOfToday,
-    getEndOfWeekFromNow,
+    getOneWeekFromNow,
     getDateFromStatusType,
     getOneHourFromNow,
     extractDate,
@@ -685,7 +702,6 @@ const DateUtils = {
     areDatesIdentical,
     getTimePeriod,
     getLocalizedTimePeriodDescription,
-    hasDateExpired,
     combineDateAndTime,
     getDayValidationErrorKey,
     getTimeValidationErrorKey,
@@ -695,6 +711,7 @@ const DateUtils = {
     getMonthNames,
     getDaysOfWeek,
     formatWithUTCTimeZone,
+    isTimeAtLeastOneMinuteInFuture,
 };
 
 export default DateUtils;
diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts
index ef3ced771cca..87cffcc4a9d5 100644
--- a/src/libs/ValidationUtils.ts
+++ b/src/libs/ValidationUtils.ts
@@ -1,5 +1,5 @@
 import {parsePhoneNumber} from 'awesome-phonenumber';
-import {addMinutes, addYears, endOfMonth, format, isAfter, isBefore, isSameDay, isValid, isWithinInterval, parse, parseISO, startOfDay, subYears} from 'date-fns';
+import {addYears, endOfMonth, format, isAfter, isBefore, isSameDay, isValid, isWithinInterval, parse, parseISO, startOfDay, subYears} from 'date-fns';
 import {URL_REGEX_WITH_REQUIRED_PROTOCOL} from 'expensify-common/lib/Url';
 import isDate from 'lodash/isDate';
 import isEmpty from 'lodash/isEmpty';
@@ -375,30 +375,6 @@ function isValidAccountRoute(accountID: number): boolean {
     return CONST.REGEX.NUMBER.test(String(accountID)) && accountID > 0;
 }
 
-/**
- * Checks if the time input is at least one minute in the future. inputTime: '12:00 PM', inputDateTime: '2023-09-27'
- * */
-const isTimeAtLeastOneMinuteInFuture = (inputTime: string, inputDateTime: string): boolean => {
-    if (!inputTime) {
-        return false;
-    }
-    // Parse the hour and minute from the time input
-    const [hourStr] = inputTime.split(/[:\s]+/);
-    const hour = parseInt(hourStr, 10);
-
-    if (hour === 0) {
-        return false;
-    }
-
-    const combinedDate = DateUtils.combineDateAndTime(inputTime, inputDateTime);
-
-    // Get current date and time
-    const now = new Date();
-
-    // Check if the combinedDate is at least one minute later than the current date and time
-    return isAfter(new Date(combinedDate), addMinutes(now, 1));
-};
-
 /**
  * Validates that the date and time are at least one minute in the future.
  * data - A date and time string in 'YYYY-MM-DD HH:mm:ss.sssZ' format
@@ -454,7 +430,6 @@ export {
     isNumeric,
     isValidAccountRoute,
     getDatePassedError,
-    isTimeAtLeastOneMinuteInFuture,
     isValidRecoveryCode,
     validateDateTimeIsAtLeastOneMinuteInFuture,
 };
diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index 302a1f1fbbe1..d504b55fff33 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -24,17 +24,17 @@ function CustomClearAfterPage({translate, customStatus}) {
     const customClearAfter = lodashGet(customStatus, 'clearAfter', '');
 
     const onSubmit = (v) => {
-        User.updateDraftCustomStatus({clearAfter: DateUtils.combineDateAndTime(customClearAfter, v.dob)});
+        User.updateDraftCustomStatus({clearAfter: DateUtils.combineDateAndTime(customClearAfter, v.dataTime)});
         Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
     };
 
     const validate = useCallback((values) => {
-        const requiredFields = ['dob'];
+        const requiredFields = ['dataTime'];
         const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields);
-        const dateError = ValidationUtils.getDatePassedError(values.dob);
+        const dateError = ValidationUtils.getDatePassedError(values.dataTime);
 
-        if (values.dob && dateError) {
-            errors.dob = dateError;
+        if (values.dataTime && dateError) {
+            errors.dataTime = dateError;
         }
 
         return errors;
@@ -59,7 +59,7 @@ function CustomClearAfterPage({translate, customStatus}) {
                 shouldUseDefaultValue
             >
                 <NewDatePicker
-                    inputID="dob"
+                    inputID="dataTime"
                     label={translate('statusPage.date')}
                     defaultValue={DateUtils.extractDate(customClearAfter)}
                     minDate={moment().toDate()}
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index b540cdc29488..92660c21f16e 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -61,14 +61,14 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
             return true;
         }
 
-        return !DateUtils.hasDateExpired(clearAfterTime);
+        return DateUtils.isTimeAtLeastOneMinuteInFuture({dateTimeString: clearAfterTime});
     }, [draftClearAfter, currentUserClearAfter]);
 
     const navigateBackToPreviousScreen = useCallback(() => Navigation.goBack(ROUTES.SETTINGS_PROFILE, false, true), []);
     const updateStatus = useCallback(
         ({emojiCode, statusText}) => {
             const clearAfterTime = draftClearAfter || currentUserClearAfter;
-            if (DateUtils.hasDateExpired(clearAfterTime)) {
+            if (!DateUtils.isTimeAtLeastOneMinuteInFuture({dateTimeString: clearAfterTime})) {
                 setBrickRoadIndicator(isValidClearAfterDate() ? null : CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR);
                 return;
             }
@@ -126,7 +126,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
             }
             headerContainerStyles={[styles.staticHeaderImage]}
             backgroundColor={themeColors.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.STATUS]}
-            childrenContainerStyles={[styles.flex1]}
+            childrenContainerStyles={[styles.flex1, styles.pt0]}
             scrollViewContainerStyles={[styles.flex1]}
         >
             <FormProvider
@@ -139,7 +139,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                 validate={validateForm}
                 enabledWhenOffline
             >
-                <View style={[styles.mh5, styles.mb5]}>
+                <View style={[styles.mh5, styles.mv5]}>
                     <Text style={[styles.textHeadline]}>{translate('statusPage.setStatusTitle')}</Text>
                     <Text style={[styles.textNormal, styles.mt2]}>{translate('statusPage.statusExplanation')}</Text>
                 </View>

From 8ab585de148a858059b4c595c4c717f4f9482bf7 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 13 Nov 2023 16:33:49 +0100
Subject: [PATCH 096/118] prettier

---
 src/components/TimePicker/TimePicker.js | 29 ++++++++++++++-----------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/src/components/TimePicker/TimePicker.js b/src/components/TimePicker/TimePicker.js
index cf3a56f02252..5f89c1db7905 100644
--- a/src/components/TimePicker/TimePicker.js
+++ b/src/components/TimePicker/TimePicker.js
@@ -2,6 +2,12 @@ import PropTypes from 'prop-types';
 import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
 import {View} from 'react-native';
 import _ from 'underscore';
+import AmountTextInput from '@components/AmountTextInput';
+import BigNumberPad from '@components/BigNumberPad';
+import Button from '@components/Button';
+import FormHelpMessage from '@components/FormHelpMessage';
+import refPropTypes from '@components/refPropTypes';
+import Text from '@components/Text';
 import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
 import useLocalize from '@hooks/useLocalize';
 import useWindowDimensions from '@hooks/useWindowDimensions';
@@ -10,12 +16,6 @@ import * as DeviceCapabilities from '@libs/DeviceCapabilities';
 import styles from '@styles/styles';
 import * as StyleUtils from '@styles/StyleUtils';
 import CONST from '@src/CONST';
-import AmountTextInput from '../AmountTextInput';
-import BigNumberPad from '../BigNumberPad';
-import Button from '../Button';
-import FormHelpMessage from '../FormHelpMessage';
-import refPropTypes from '../refPropTypes';
-import Text from '../Text';
 import setSelection from './setSelection';
 
 const propTypes = {
@@ -94,7 +94,7 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
     const focusMinuteInputOnFirstCharacter = useCallback(() => {
         const cleanupTimer = setSelection({start: 0, end: 0}, minuteInputRef, setSelectionMinute);
         return cleanupTimer;
-    }, [selectionMinute]);
+    }, []);
     const focusHourInputOnLastCharacter = useCallback(() => {
         setSelectionHour({start: 2, end: 2});
         const timer = setTimeout(() => {
@@ -103,11 +103,14 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
         return () => clearTimeout(timer);
     }, []);
 
-    const validate = (time) => {
-        const isValid = DateUtils.isTimeAtLeastOneMinuteInFuture({timeString: time || `${hours}:${minute} ${amPmValue}`, dateTimeString: defaultValue});
-        setError(!isValid);
-        return isValid;
-    };
+    const validate = useCallback(
+        (time) => {
+            const isValid = DateUtils.isTimeAtLeastOneMinuteInFuture({timeString: time || `${hours}:${minute} ${amPmValue}`, dateTimeString: defaultValue});
+            setError(!isValid);
+            return isValid;
+        },
+        [hours, minute, amPmValue, defaultValue],
+    );
 
     // This function receive value from hour input and validate it
     // The valid format is HH(from 00 to 12). If the user input 9, it will be 09. If user try to change 09 to 19 it would skip the first character
@@ -294,7 +297,7 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
 
         validate();
         return () => clearTimeout(timer);
-    }, []);
+    }, [validate]);
 
     const arrowConfig = useMemo(
         () => ({

From 899005dc7afc124dd2f7ed2939d51582c2cf07b2 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 13 Nov 2023 18:29:41 +0100
Subject: [PATCH 097/118] clean ONYXKEYS after merge

---
 src/ONYXKEYS.ts                               |   7 +-
 .../Profile/CustomStatus/StatusSetPage.js     | 101 ------------------
 2 files changed, 1 insertion(+), 107 deletions(-)
 delete mode 100644 src/pages/settings/Profile/CustomStatus/StatusSetPage.js

diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index a4f1dec83369..357c4cacd471 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -320,11 +320,8 @@ const ONYXKEYS = {
         WAYPOINT_FORM_DRAFT: 'waypointFormDraft',
         SETTINGS_STATUS_SET_FORM: 'settingsStatusSetForm',
         SETTINGS_STATUS_SET_FORM_DRAFT: 'settingsStatusSetFormDraft',
-        SETTINGS_STATUS_CLEAR_AFTER_FORM: 'settingsStatusClearAfterForm',
-        SETTINGS_STATUS_CLEAR_AFTER_FORM_DRAFT: 'settingsStatusClearAfterFormDraft',
         SETTINGS_STATUS_SET_CLEAR_AFTER_FORM: 'settingsStatusSetClearAfterForm',
         SETTINGS_STATUS_CLEAR_DATE_FORM: 'settingsStatusClearDateForm',
-        SETTINGS_STATUS_SET_TIME_FORM: 'settingsStatusSetTIMEForm',
         SETTINGS_STATUS_SET_CLEAR_AFTER_FORM_DRAFT: 'settingsStatusSetClearAfterFormDraft',
         PRIVATE_NOTES_FORM: 'privateNotesForm',
         PRIVATE_NOTES_FORM_DRAFT: 'privateNotesFormDraft',
@@ -487,9 +484,7 @@ type OnyxValues = {
     [ONYXKEYS.FORMS.WAYPOINT_FORM]: OnyxTypes.Form;
     [ONYXKEYS.FORMS.WAYPOINT_FORM_DRAFT]: OnyxTypes.Form;
     [ONYXKEYS.FORMS.SETTINGS_STATUS_SET_FORM]: OnyxTypes.Form;
-    [ONYXKEYS.FORMS.SETTINGS_STATUS_SET_FORM_DRAFT]: OnyxTypes.Form;
-    [ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_AFTER_FORM]: OnyxTypes.Form;
-    [ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_AFTER_FORM_DRAFT]: OnyxTypes.Form;
+    [ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_DATE_FORM]: OnyxTypes.Form;
     [ONYXKEYS.FORMS.SETTINGS_STATUS_SET_CLEAR_AFTER_FORM]: OnyxTypes.Form;
     [ONYXKEYS.FORMS.SETTINGS_STATUS_SET_CLEAR_AFTER_FORM_DRAFT]: OnyxTypes.Form;
     [ONYXKEYS.FORMS.PRIVATE_NOTES_FORM]: OnyxTypes.Form;
diff --git a/src/pages/settings/Profile/CustomStatus/StatusSetPage.js b/src/pages/settings/Profile/CustomStatus/StatusSetPage.js
deleted file mode 100644
index ffe2d06b304a..000000000000
--- a/src/pages/settings/Profile/CustomStatus/StatusSetPage.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import lodashGet from 'lodash/get';
-import PropTypes from 'prop-types';
-import React from 'react';
-import {View} from 'react-native';
-import {withOnyx} from 'react-native-onyx';
-import EmojiPickerButtonDropdown from '@components/EmojiPicker/EmojiPickerButtonDropdown';
-import FormProvider from '@components/Form/FormProvider';
-import InputWrapper from '@components/Form/InputWrapper';
-import HeaderWithBackButton from '@components/HeaderWithBackButton';
-import ScreenWrapper from '@components/ScreenWrapper';
-import TextInput from '@components/TextInput';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
-import useLocalize from '@hooks/useLocalize';
-import compose from '@libs/compose';
-import Navigation from '@libs/Navigation/Navigation';
-import styles from '@styles/styles';
-import * as User from '@userActions/User';
-import CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
-import ROUTES from '@src/ROUTES';
-
-const propTypes = {
-    /** The draft status of the user */
-    // eslint-disable-next-line react/require-default-props
-    draftStatus: PropTypes.shape({
-        /** The emoji code of the draft status */
-        emojiCode: PropTypes.string,
-        /** The text of the draft status */
-        text: PropTypes.string,
-    }),
-
-    ...withCurrentUserPersonalDetailsPropTypes,
-};
-
-const INPUT_IDS = {
-    EMOJI_CODE: 'emojiCode',
-    STATUS_TEXT: 'statusText',
-};
-
-function StatusSetPage({draftStatus, currentUserPersonalDetails}) {
-    const {translate} = useLocalize();
-    const defaultEmoji = lodashGet(draftStatus, 'emojiCode') || lodashGet(currentUserPersonalDetails, 'status.emojiCode', '💬');
-    const defaultText = lodashGet(draftStatus, 'text') || lodashGet(currentUserPersonalDetails, 'status.text', '');
-
-    const onSubmit = (value) => {
-        User.updateDraftCustomStatus({text: value.statusText.trim(), emojiCode: value.emojiCode});
-        Navigation.goBack(ROUTES.SETTINGS_STATUS);
-    };
-
-    return (
-        <ScreenWrapper testID={StatusSetPage.displayName}>
-            <HeaderWithBackButton
-                title={translate('statusPage.status')}
-                onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS)}
-            />
-            <FormProvider
-                formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_FORM}
-                style={[styles.flexGrow1, styles.ph5]}
-                submitButtonText={translate('statusPage.save')}
-                onSubmit={onSubmit}
-                enabledWhenOffline
-            >
-                <View>
-                    <View style={[styles.mb4]}>
-                        <View style={[styles.mt1]}>
-                            <InputWrapper
-                                InputComponent={EmojiPickerButtonDropdown}
-                                inputID={INPUT_IDS.EMOJI_CODE}
-                                aria-label={INPUT_IDS.EMOJI_CODE}
-                                defaultValue={defaultEmoji}
-                            />
-                        </View>
-                        <InputWrapper
-                            InputComponent={TextInput}
-                            inputID={INPUT_IDS.STATUS_TEXT}
-                            label={translate('statusPage.message')}
-                            aria-label={INPUT_IDS.STATUS_TEXT}
-                            role={CONST.ACCESSIBILITY_ROLE.TEXT}
-                            defaultValue={defaultText}
-                            maxLength={CONST.STATUS_TEXT_MAX_LENGTH}
-                            autoFocus
-                            shouldDelayFocus
-                        />
-                    </View>
-                </View>
-            </FormProvider>
-        </ScreenWrapper>
-    );
-}
-
-StatusSetPage.displayName = 'StatusSetPage';
-StatusSetPage.propTypes = propTypes;
-
-export default compose(
-    withCurrentUserPersonalDetails,
-    withOnyx({
-        draftStatus: {
-            key: ONYXKEYS.CUSTOM_STATUS_DRAFT,
-        },
-    }),
-)(StatusSetPage);

From 0371e12b89ca31a549e195ac33da933260590ede Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 13 Nov 2023 18:50:00 +0100
Subject: [PATCH 098/118] fix types

---
 src/ONYXKEYS.ts | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index 357c4cacd471..c0f6d1baa682 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -321,8 +321,9 @@ const ONYXKEYS = {
         SETTINGS_STATUS_SET_FORM: 'settingsStatusSetForm',
         SETTINGS_STATUS_SET_FORM_DRAFT: 'settingsStatusSetFormDraft',
         SETTINGS_STATUS_SET_CLEAR_AFTER_FORM: 'settingsStatusSetClearAfterForm',
-        SETTINGS_STATUS_CLEAR_DATE_FORM: 'settingsStatusClearDateForm',
         SETTINGS_STATUS_SET_CLEAR_AFTER_FORM_DRAFT: 'settingsStatusSetClearAfterFormDraft',
+        SETTINGS_STATUS_CLEAR_DATE_FORM: 'settingsStatusClearDateForm',
+        SETTINGS_STATUS_CLEAR_DATE_FORM_DRAFT: 'settingsStatusClearDateFormDraft',
         PRIVATE_NOTES_FORM: 'privateNotesForm',
         PRIVATE_NOTES_FORM_DRAFT: 'privateNotesFormDraft',
         I_KNOW_A_TEACHER_FORM: 'iKnowTeacherForm',
@@ -484,7 +485,9 @@ type OnyxValues = {
     [ONYXKEYS.FORMS.WAYPOINT_FORM]: OnyxTypes.Form;
     [ONYXKEYS.FORMS.WAYPOINT_FORM_DRAFT]: OnyxTypes.Form;
     [ONYXKEYS.FORMS.SETTINGS_STATUS_SET_FORM]: OnyxTypes.Form;
+    [ONYXKEYS.FORMS.SETTINGS_STATUS_SET_FORM_DRAFT]: OnyxTypes.Form;
     [ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_DATE_FORM]: OnyxTypes.Form;
+    [ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_DATE_FORM_DRAFT]: OnyxTypes.Form;
     [ONYXKEYS.FORMS.SETTINGS_STATUS_SET_CLEAR_AFTER_FORM]: OnyxTypes.Form;
     [ONYXKEYS.FORMS.SETTINGS_STATUS_SET_CLEAR_AFTER_FORM_DRAFT]: OnyxTypes.Form;
     [ONYXKEYS.FORMS.PRIVATE_NOTES_FORM]: OnyxTypes.Form;

From b8131f6d2c4da53bbf3da3c23d2aed8da4af3df6 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 13 Nov 2023 19:20:38 +0100
Subject: [PATCH 099/118] rename field

---
 .../Profile/CustomStatus/CustomClearAfterPage.js     | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index d504b55fff33..4f31c277d6c0 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -24,17 +24,17 @@ function CustomClearAfterPage({translate, customStatus}) {
     const customClearAfter = lodashGet(customStatus, 'clearAfter', '');
 
     const onSubmit = (v) => {
-        User.updateDraftCustomStatus({clearAfter: DateUtils.combineDateAndTime(customClearAfter, v.dataTime)});
+        User.updateDraftCustomStatus({clearAfter: DateUtils.combineDateAndTime(customClearAfter, v.dateTime)});
         Navigation.goBack(ROUTES.SETTINGS_STATUS_CLEAR_AFTER);
     };
 
     const validate = useCallback((values) => {
-        const requiredFields = ['dataTime'];
+        const requiredFields = ['dateTime'];
         const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields);
-        const dateError = ValidationUtils.getDatePassedError(values.dataTime);
+        const dateError = ValidationUtils.getDatePassedError(values.dateTime);
 
-        if (values.dataTime && dateError) {
-            errors.dataTime = dateError;
+        if (values.dateTime && dateError) {
+            errors.dateTime = dateError;
         }
 
         return errors;
@@ -59,7 +59,7 @@ function CustomClearAfterPage({translate, customStatus}) {
                 shouldUseDefaultValue
             >
                 <NewDatePicker
-                    inputID="dataTime"
+                    inputID="dateTime"
                     label={translate('statusPage.date')}
                     defaultValue={DateUtils.extractDate(customClearAfter)}
                     minDate={moment().toDate()}

From de7ed58eed202ef6c18fa0dff79320852b0bd2cb Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 15 Nov 2023 15:34:30 +0100
Subject: [PATCH 100/118] update after merge

---
 src/pages/settings/Profile/CustomStatus/StatusPage.js | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 92660c21f16e..ef72a3deae07 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -57,7 +57,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
     const isValidClearAfterDate = useCallback(() => {
         const clearAfterTime = draftClearAfter || currentUserClearAfter;
-        if (clearAfterTime === CONST.CUSTOM_STATUS_TYPES.NEVER) {
+        if (clearAfterTime === CONST.CUSTOM_STATUS_TYPES.NEVER || clearAfterTime === '') {
             return true;
         }
 
@@ -68,7 +68,8 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
     const updateStatus = useCallback(
         ({emojiCode, statusText}) => {
             const clearAfterTime = draftClearAfter || currentUserClearAfter;
-            if (!DateUtils.isTimeAtLeastOneMinuteInFuture({dateTimeString: clearAfterTime})) {
+            const isValid = DateUtils.isTimeAtLeastOneMinuteInFuture({dateTimeString: clearAfterTime});
+            if (!isValid && clearAfterTime !== CONST.CUSTOM_STATUS_TYPES.NEVER) {
                 setBrickRoadIndicator(isValidClearAfterDate() ? null : CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR);
                 return;
             }

From 9b29c56bb2b61605520a389b8a0aedae8fbf08d3 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Fri, 17 Nov 2023 10:57:26 +0100
Subject: [PATCH 101/118] import styles from useThemeStyles after merge

---
 .../settings/Profile/CustomStatus/CustomClearAfterPage.js   | 6 +++---
 src/pages/settings/Profile/CustomStatus/SetTimePage.js      | 4 +++-
 .../settings/Profile/CustomStatus/StatusClearAfterPage.js   | 3 ++-
 src/pages/settings/Profile/CustomStatus/StatusPage.js       | 2 +-
 4 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
index 4f31c277d6c0..f2d156e343c9 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
@@ -1,5 +1,4 @@
 import lodashGet from 'lodash/get';
-import moment from 'moment';
 import React, {useCallback} from 'react';
 import {withOnyx} from 'react-native-onyx';
 import FormProvider from '@components/Form/FormProvider';
@@ -12,7 +11,7 @@ import compose from '@libs/compose';
 import DateUtils from '@libs/DateUtils';
 import Navigation from '@libs/Navigation/Navigation';
 import * as ValidationUtils from '@libs/ValidationUtils';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
 
@@ -21,6 +20,7 @@ const propTypes = {
 };
 
 function CustomClearAfterPage({translate, customStatus}) {
+    const styles = useThemeStyles();
     const customClearAfter = lodashGet(customStatus, 'clearAfter', '');
 
     const onSubmit = (v) => {
@@ -62,7 +62,7 @@ function CustomClearAfterPage({translate, customStatus}) {
                     inputID="dateTime"
                     label={translate('statusPage.date')}
                     defaultValue={DateUtils.extractDate(customClearAfter)}
-                    minDate={moment().toDate()}
+                    minDate={new Date()}
                 />
             </FormProvider>
         </ScreenWrapper>
diff --git a/src/pages/settings/Profile/CustomStatus/SetTimePage.js b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
index 2b5c374a133d..9e48b5826e7d 100644
--- a/src/pages/settings/Profile/CustomStatus/SetTimePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetTimePage.js
@@ -12,7 +12,7 @@ import * as User from '@libs/actions/User';
 import compose from '@libs/compose';
 import DateUtils from '@libs/DateUtils';
 import Navigation from '@libs/Navigation/Navigation';
-import styles from '@styles/styles';
+import useThemeStyles from '@styles/useThemeStyles';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
 
@@ -22,6 +22,8 @@ const propTypes = {
 
 function SetTimePage({translate, privatePersonalDetails, customStatus}) {
     usePrivatePersonalDetails();
+
+    const styles = useThemeStyles();
     const clearAfter = lodashGet(customStatus, 'clearAfter', '');
 
     const onSubmit = (time) => {
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 2bf6e588a5f4..dce128a8f550 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -19,10 +19,10 @@ import DateUtils from '@libs/DateUtils';
 import Navigation from '@libs/Navigation/Navigation';
 import * as ValidationUtils from '@libs/ValidationUtils';
 import personalDetailsPropType from '@pages/personalDetailsPropType';
+import useThemeStyles from '@styles/useThemeStyles';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
-import styles from '@src/styles/styles';
 
 const defaultProps = {
     ...withCurrentUserPersonalDetailsDefaultProps,
@@ -86,6 +86,7 @@ const useValidateCustomDate = (data) => {
 };
 
 function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
+    const styles = useThemeStyles();
     const localize = useLocalize();
     const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
     const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 0b3daa7c167d..5dce2df2a0ce 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -182,7 +182,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                             titleStyle={styles.ml0}
                             icon={Expensicons.Trashcan}
                             onPress={clearStatus}
-                    iconFill={theme.danger}
+                            iconFill={theme.danger}
                             wrapperStyle={[styles.pl2]}
                         />
                     )}

From 6bfa885605a268a5ab4d0f78a1feb06f116cedda Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 21 Nov 2023 10:00:51 +0100
Subject: [PATCH 102/118] update themes

---
 src/styles/themes/default.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/styles/themes/default.ts b/src/styles/themes/default.ts
index 8dd76a4776a4..0b56ba479713 100644
--- a/src/styles/themes/default.ts
+++ b/src/styles/themes/default.ts
@@ -96,7 +96,7 @@ const darkTheme = {
         [SCREENS.SETTINGS.WORKSPACES]: colors.pink800,
         [SCREENS.SETTINGS.WALLET]: colors.darkAppBackground,
         [SCREENS.SETTINGS.SECURITY]: colors.ice500,
-        [SCREENS.SETTINGS.STATUS]: colors.green700,
+        [SCREENS.SETTINGS.STATUS]: colors.darkAppBackground,
         [SCREENS.SETTINGS.ROOT]: colors.darkHighlightBackground,
     },
 } satisfies ThemeColors;

From a3bc42b6544601e85de3cac4adcb7e7513dca34f Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 21 Nov 2023 10:01:34 +0100
Subject: [PATCH 103/118] ditch the illustration

---
 .../CustomStatus/StatusClearAfterPage.js      | 22 ++++++-------
 .../Profile/CustomStatus/StatusPage.js        | 33 +++++++++----------
 2 files changed, 27 insertions(+), 28 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index dce128a8f550..3ed4405c7c89 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -54,16 +54,16 @@ function getSelectedStatusType(data) {
 }
 
 const useValidateCustomDate = (data) => {
-    const localize = useLocalize();
+    const {translate} = useLocalize();
     const [customDateError, setCustomDateError] = useState('');
     const [customTimeError, setCustomTimeError] = useState('');
     const validate = () => {
         const {dateValidationErrorKey, timeValidationErrorKey} = ValidationUtils.validateDateTimeIsAtLeastOneMinuteInFuture(data);
 
-        const dateError = dateValidationErrorKey ? localize.translate(dateValidationErrorKey) : '';
+        const dateError = dateValidationErrorKey ? translate(dateValidationErrorKey) : '';
         setCustomDateError(dateError);
 
-        const timeError = timeValidationErrorKey ? localize.translate(timeValidationErrorKey) : '';
+        const timeError = timeValidationErrorKey ? translate(timeValidationErrorKey) : '';
         setCustomTimeError(timeError);
 
         return {
@@ -87,7 +87,7 @@ const useValidateCustomDate = (data) => {
 
 function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
     const styles = useThemeStyles();
-    const localize = useLocalize();
+    const {translate} = useLocalize();
     const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', '');
     const draftClearAfter = lodashGet(customStatus, 'clearAfter', '');
     const [draftPeriod, setDraftPeriod] = useState(getSelectedStatusType(draftClearAfter || clearAfter));
@@ -95,11 +95,11 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
         () =>
             _.map(CONST.CUSTOM_STATUS_TYPES, (value, key) => ({
                 value,
-                text: localize.translate(`statusPage.timePeriods.${value}`),
+                text: translate(`statusPage.timePeriods.${value}`),
                 keyForList: key,
                 isSelected: draftPeriod === value,
             })),
-        [draftPeriod, localize],
+        [draftPeriod, translate],
     );
 
     const {customDateError, customTimeError, validateCustomDate} = useValidateCustomDate(draftClearAfter);
@@ -178,13 +178,13 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
             testID={StatusClearAfterPage.displayName}
         >
             <HeaderWithBackButton
-                title="Status"
+                title={translate('statusPage.clearAfter')}
                 onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS)}
             />
-            <Text style={[styles.textNormal, styles.mh5, styles.mv4]}>{localize.translate('statusPage.whenClearStatus')}</Text>
+            <Text style={[styles.textNormal, styles.mh5, styles.mv4]}>{translate('statusPage.whenClearStatus')}</Text>
             <FormProvider
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_CLEAR_AFTER_FORM}
-                submitButtonText="Save"
+                submitButtonText={translate('statusPage.save')}
                 onSubmit={onSubmit}
                 style={[styles.flexGrow1, styles.mb4]}
                 scrollContextEnabled={false}
@@ -197,7 +197,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                         <>
                             <MenuItemWithTopDescription
                                 title={customStatusDate}
-                                description={localize.translate('statusPage.date')}
+                                description={translate('statusPage.date')}
                                 shouldShowRightIcon
                                 containerStyle={styles.pr2}
                                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_CUSTOM)}
@@ -207,7 +207,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                             />
                             <MenuItemWithTopDescription
                                 title={customStatusTime}
-                                description={localize.translate('statusPage.time')}
+                                description={translate('statusPage.time')}
                                 shouldShowRightIcon
                                 containerStyle={styles.pr2}
                                 onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_TIME)}
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 5dce2df2a0ce..178c94dda2cf 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -2,14 +2,15 @@ import lodashGet from 'lodash/get';
 import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
 import {View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
-import MobileBackgroundImage from '@assets/images/money-stack.svg';
 import EmojiPickerButtonDropdown from '@components/EmojiPicker/EmojiPickerButtonDropdown';
 import FormProvider from '@components/Form/FormProvider';
 import InputWrapper from '@components/Form/InputWrapper';
 import HeaderPageLayout from '@components/HeaderPageLayout';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
 import * as Expensicons from '@components/Icon/Expensicons';
 import MenuItem from '@components/MenuItem';
 import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import ScreenWrapper from '@components/ScreenWrapper';
 import Text from '@components/Text';
 import TextInput from '@components/TextInput';
 import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
@@ -17,6 +18,7 @@ import useLocalize from '@hooks/useLocalize';
 import compose from '@libs/compose';
 import DateUtils from '@libs/DateUtils';
 import Navigation from '@libs/Navigation/Navigation';
+import * as StyleUtils from '@styles/StyleUtils';
 import useTheme from '@styles/themes/useTheme';
 import useThemeStyles from '@styles/useThemeStyles';
 import * as User from '@userActions/User';
@@ -117,21 +119,18 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
         }
         return {};
     }, [brickRoadIndicator]);
+
     return (
-        <HeaderPageLayout
-            title={translate('statusPage.status')}
-            onBackButtonPress={navigateBackToPreviousScreen}
-            headerContent={
-                <MobileBackgroundImage
-                    pointerEvents="none"
-                    style={styles.staticHeaderImage}
-                />
-            }
-            headerContainerStyles={[styles.staticHeaderImage]}
-            backgroundColor={theme.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.STATUS]}
-            childrenContainerStyles={[styles.flex1, styles.pt0]}
-            scrollViewContainerStyles={[styles.flex1]}
+        <ScreenWrapper
+            style={[StyleUtils.getBackgroundColorStyle(theme.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.STATUS])]}
+            shouldEnablePickerAvoiding={false}
+            includeSafeAreaPaddingBottom={false}
+            testID={HeaderPageLayout.displayName}
         >
+            <HeaderWithBackButton
+                title={translate('statusPage.status')}
+                onBackButtonPress={navigateBackToPreviousScreen}
+            />
             <FormProvider
                 formID={ONYXKEYS.FORMS.SETTINGS_STATUS_SET_FORM}
                 style={[styles.flexGrow1, styles.flex1]}
@@ -142,11 +141,11 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                 validate={validateForm}
                 enabledWhenOffline
             >
-                <View style={[styles.mh5, styles.mv5]}>
+                <View style={[styles.mh5, styles.mv4]}>
                     <Text style={[styles.textHeadline]}>{translate('statusPage.setStatusTitle')}</Text>
                     <Text style={[styles.textNormal, styles.mt2]}>{translate('statusPage.statusExplanation')}</Text>
                 </View>
-                <View style={[styles.mb2, styles.mt6]}>
+                <View style={[styles.mb2, styles.mt4]}>
                     <View style={[styles.mb4, styles.ph5]}>
                         <InputWrapper
                             InputComponent={EmojiPickerButtonDropdown}
@@ -188,7 +187,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                     )}
                 </View>
             </FormProvider>
-        </HeaderPageLayout>
+        </ScreenWrapper>
     );
 }
 

From 633af7aa43ef72803b915c739fe702986e1b10a0 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 29 Nov 2023 11:19:19 +0100
Subject: [PATCH 104/118] fix after merge

---
 src/ROUTES.ts                                          |  2 +-
 .../Navigation/AppNavigator/ModalStackNavigators.js    |  2 +-
 src/libs/Navigation/linkingConfig.ts                   | 10 ++--------
 .../{CustomClearAfterPage.js => SetDatePage.js}        | 10 +++++-----
 .../Profile/CustomStatus/StatusClearAfterPage.js       |  2 +-
 5 files changed, 10 insertions(+), 16 deletions(-)
 rename src/pages/settings/Profile/CustomStatus/{CustomClearAfterPage.js => SetDatePage.js} (92%)

diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 32986bab2627..0448ae4caccb 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -135,7 +135,7 @@ const ROUTES = {
     SETTINGS_STATUS: 'settings/profile/status',
     SETTINGS_STATUS_SET: 'settings/profile/status/set',
     SETTINGS_STATUS_CLEAR_AFTER: 'settings/profile/status/clear-after',
-    SETTINGS_STATUS_CLEAR_AFTER_CUSTOM: 'settings/profile/status/clear-after/custom',
+    SETTINGS_STATUS_CLEAR_AFTER_DATE: 'settings/profile/status/clear-after/date',
     SETTINGS_STATUS_CLEAR_AFTER_TIME: 'settings/profile/status/clear-after/time',
 
     KEYBOARD_SHORTCUTS: 'keyboard-shortcuts',
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
index 1020e38c6cea..9c1cb2ae5ceb 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
@@ -173,7 +173,7 @@ const SettingsModalStackNavigator = createModalStackNavigator({
     Settings_Add_Bank_Account: () => require('../../../pages/AddPersonalBankAccountPage').default,
     [SCREENS.SETTINGS.STATUS]: () => require('../../../pages/settings/Profile/CustomStatus/StatusPage').default,
     Settings_Status_Clear_After: () => require('../../../pages/settings/Profile/CustomStatus/StatusClearAfterPage').default,
-    Settings_Status_Clear_After_Custom: () => require('../../../pages/settings/Profile/CustomStatus/CustomClearAfterPage').default,
+    Settings_Status_Clear_After_Date: () => require('../../../pages/settings/Profile/CustomStatus/SetDatePage').default,
     Settings_Status_Clear_After_Time: () => require('../../../pages/settings/Profile/CustomStatus/SetTimePage').default,
     Workspace_Initial: () => require('../../../pages/workspace/WorkspaceInitialPage').default,
     Workspace_Settings: () => require('../../../pages/workspace/WorkspaceSettingsPage').default,
diff --git a/src/libs/Navigation/linkingConfig.ts b/src/libs/Navigation/linkingConfig.ts
index e5b5a48ba053..74599a312d99 100644
--- a/src/libs/Navigation/linkingConfig.ts
+++ b/src/libs/Navigation/linkingConfig.ts
@@ -213,18 +213,12 @@ const linkingConfig: LinkingOptions<RootStackParamList> = {
                             Settings_Status_Clear_After: {
                                 path: ROUTES.SETTINGS_STATUS_CLEAR_AFTER,
                             },
-                            Settings_Status_Clear_After_Custom: {
-                                path: ROUTES.SETTINGS_STATUS_CLEAR_AFTER_CUSTOM,
+                            Settings_Status_Clear_After_Date: {
+                                path: ROUTES.SETTINGS_STATUS_CLEAR_AFTER_DATE,
                             },
                             Settings_Status_Clear_After_Time: {
                                 path: ROUTES.SETTINGS_STATUS_CLEAR_AFTER_TIME,
                             },
-                            Settings_Status_SetTime: {
-                                path: ROUTES.SETTINGS_STATUS_SET_TIME,
-                            },
-                            Settings_Status_SetData: {
-                                path: ROUTES.SETTINGS_STATUS_SET_DATE,
-                            },
                             Workspace_Initial: {
                                 path: ROUTES.WORKSPACE_INITIAL.route,
                             },
diff --git a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/SetDatePage.js
similarity index 92%
rename from src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
rename to src/pages/settings/Profile/CustomStatus/SetDatePage.js
index f2d156e343c9..2574100f03fc 100644
--- a/src/pages/settings/Profile/CustomStatus/CustomClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetDatePage.js
@@ -19,7 +19,7 @@ const propTypes = {
     ...withLocalizePropTypes,
 };
 
-function CustomClearAfterPage({translate, customStatus}) {
+function SetDatePage({translate, customStatus}) {
     const styles = useThemeStyles();
     const customClearAfter = lodashGet(customStatus, 'clearAfter', '');
 
@@ -43,7 +43,7 @@ function CustomClearAfterPage({translate, customStatus}) {
     return (
         <ScreenWrapper
             includeSafeAreaPaddingBottom={false}
-            testID={CustomClearAfterPage.displayName}
+            testID={SetDatePage.displayName}
         >
             <HeaderWithBackButton
                 title={translate('statusPage.date')}
@@ -69,8 +69,8 @@ function CustomClearAfterPage({translate, customStatus}) {
     );
 }
 
-CustomClearAfterPage.propTypes = propTypes;
-CustomClearAfterPage.displayName = 'CustomClearAfterPage';
+SetDatePage.propTypes = propTypes;
+SetDatePage.displayName = 'SetDatePage';
 
 export default compose(
     withLocalize,
@@ -85,4 +85,4 @@ export default compose(
             key: `${ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_DATE_FORM}Draft`,
         },
     }),
-)(CustomClearAfterPage);
+)(SetDatePage);
diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
index 3ed4405c7c89..a4f9c1c3a4e5 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js
@@ -200,7 +200,7 @@ function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) {
                                 description={translate('statusPage.date')}
                                 shouldShowRightIcon
                                 containerStyle={styles.pr2}
-                                onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_CUSTOM)}
+                                onPress={() => Navigation.navigate(ROUTES.SETTINGS_STATUS_CLEAR_AFTER_DATE)}
                                 errorText={customDateError}
                                 titleTextStyle={styles.flex1}
                                 brickRoadIndicator={redBrickDateIndicator}

From 4068e30aaeba5295b60243f64745740178fd8c74 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 29 Nov 2023 15:30:48 +0100
Subject: [PATCH 105/118] fix after merge

---
 src/components/TextInput/BaseTextInput/index.js | 1 +
 src/styles/styles.ts                            | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/components/TextInput/BaseTextInput/index.js b/src/components/TextInput/BaseTextInput/index.js
index a28365480c7a..37458a600008 100644
--- a/src/components/TextInput/BaseTextInput/index.js
+++ b/src/components/TextInput/BaseTextInput/index.js
@@ -261,6 +261,7 @@ function BaseTextInput(props) {
                     style={[
                         props.autoGrowHeight && styles.autoGrowHeightInputContainer(textInputHeight, variables.componentSizeLarge, maxHeight),
                         !isMultiline && styles.componentHeightLarge,
+                        ...props.containerStyles,
                     ]}
                 >
                     <View
diff --git a/src/styles/styles.ts b/src/styles/styles.ts
index 8733d9819140..b45637d0f304 100644
--- a/src/styles/styles.ts
+++ b/src/styles/styles.ts
@@ -3897,7 +3897,7 @@ const styles = (theme: ThemeColors) =>
         timePickerSemiDot: {
             fontSize: 69,
             height: 84,
-            alignSelf: 'flex-end',
+            alignSelf: 'center',
         },
         timePickerSwitcherContainer: {
             flexDirection: 'row',
@@ -3930,7 +3930,7 @@ const styles = (theme: ThemeColors) =>
             minHeight: 54,
         },
         timePickerInputsContainer: {
-            maxHeight: 70,
+            maxHeight: 100,
         },
         timePickerButtonErrorText: {
             position: 'absolute',

From 12488b4e375037045b7540634295b96a28aa056f Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 29 Nov 2023 15:46:10 +0100
Subject: [PATCH 106/118] add Tooltip

---
 .../home/sidebar/AvatarWithOptionalStatus.js  | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/src/pages/home/sidebar/AvatarWithOptionalStatus.js b/src/pages/home/sidebar/AvatarWithOptionalStatus.js
index 4507b21a382c..a12289e56dd5 100644
--- a/src/pages/home/sidebar/AvatarWithOptionalStatus.js
+++ b/src/pages/home/sidebar/AvatarWithOptionalStatus.js
@@ -4,6 +4,7 @@ import React, {useCallback} from 'react';
 import {View} from 'react-native';
 import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
 import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
 import useLocalize from '@hooks/useLocalize';
 import Navigation from '@libs/Navigation/Navigation';
 import useThemeStyles from '@styles/useThemeStyles';
@@ -46,14 +47,16 @@ function AvatarWithOptionalStatus({emojiStatus, isCreateMenuOpen}) {
                 onPress={showStatusPage}
                 style={styles.flex1}
             >
-                <View style={styles.sidebarStatusAvatar}>
-                    <Text
-                        style={styles.emojiStatusLHN}
-                        numberOfLines={1}
-                    >
-                        {emojiStatus}
-                    </Text>
-                </View>
+                <Tooltip text={translate('statusPage.status')}>
+                    <View style={styles.sidebarStatusAvatar}>
+                        <Text
+                            style={styles.emojiStatusLHN}
+                            numberOfLines={1}
+                        >
+                            {emojiStatus}
+                        </Text>
+                    </View>
+                </Tooltip>
             </PressableWithoutFeedback>
             <PressableAvatarWithIndicator isCreateMenuOpen={isCreateMenuOpen} />
         </View>

From ab5a614413bd1ba3db6e8ec67001735c64d6e346 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 29 Nov 2023 16:00:54 +0100
Subject: [PATCH 107/118] clean translation

---
 src/languages/en.ts                                   | 1 -
 src/languages/es.ts                                   | 1 -
 src/pages/settings/Profile/CustomStatus/StatusPage.js | 3 +--
 3 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/languages/en.ts b/src/languages/en.ts
index b99917645a63..c36a9124a1b0 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -1153,7 +1153,6 @@ export default {
     },
     statusPage: {
         status: 'Status',
-        setStatusTitle: 'Set your status',
         statusExplanation: "Add an emoji to give your colleagues and friends an easy way to know what's going on. You can optionally add a message too!",
         today: 'Today',
         clearStatus: 'Clear status',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 7aac2d02f744..44dfb591997f 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1153,7 +1153,6 @@ export default {
     },
     statusPage: {
         status: 'Estado',
-        setStatusTitle: 'Establece tu estado',
         statusExplanation: 'Agrega un emoji para que tus colegas y amigos puedan saber fácilmente qué está pasando. ¡También puedes agregar un mensaje opcionalmente!',
         today: 'Hoy',
         clearStatus: 'Borrar estado',
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 178c94dda2cf..e72ab5ace1df 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -141,8 +141,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
                 validate={validateForm}
                 enabledWhenOffline
             >
-                <View style={[styles.mh5, styles.mv4]}>
-                    <Text style={[styles.textHeadline]}>{translate('statusPage.setStatusTitle')}</Text>
+                <View style={[styles.mh5, styles.mv1]}>
                     <Text style={[styles.textNormal, styles.mt2]}>{translate('statusPage.statusExplanation')}</Text>
                 </View>
                 <View style={[styles.mb2, styles.mt4]}>

From c0a4532033dd4c08ddcbcb3e20cb8ae060190a2b Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Fri, 1 Dec 2023 13:55:51 +0100
Subject: [PATCH 108/118] fix background after merge

---
 src/pages/settings/Profile/CustomStatus/StatusPage.js | 3 +++
 src/styles/themes/default.ts                          | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 62646f933de9..9b5675c4ec16 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -18,12 +18,14 @@ import useLocalize from '@hooks/useLocalize';
 import compose from '@libs/compose';
 import DateUtils from '@libs/DateUtils';
 import Navigation from '@libs/Navigation/Navigation';
+import * as StyleUtils from '@styles/StyleUtils';
 import useTheme from '@styles/themes/useTheme';
 import useThemeStyles from '@styles/useThemeStyles';
 import * as User from '@userActions/User';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
 
 const INPUT_IDS = {
     EMOJI_CODE: 'emojiCode',
@@ -120,6 +122,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
 
     return (
         <ScreenWrapper
+            style={[StyleUtils.getBackgroundColorStyle(theme.PAGE_THEMES[SCREENS.SETTINGS.STATUS].backgroundColor)]}
             shouldEnablePickerAvoiding={false}
             includeSafeAreaPaddingBottom={false}
             testID={HeaderPageLayout.displayName}
diff --git a/src/styles/themes/default.ts b/src/styles/themes/default.ts
index 519e818054e0..e11196952ecb 100644
--- a/src/styles/themes/default.ts
+++ b/src/styles/themes/default.ts
@@ -120,7 +120,7 @@ const darkTheme = {
             statusBarStyle: CONST.STATUS_BAR_STYLE.DARK_CONTENT,
         },
         [SCREENS.SETTINGS.STATUS]: {
-            backgroundColor: colors.green700,
+            backgroundColor: colors.darkAppBackground,
             statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
         },
         [SCREENS.SETTINGS.ROOT]: {

From a878f8e8d38e9a6d49a18825723f293f8c9d3e33 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Fri, 1 Dec 2023 13:56:19 +0100
Subject: [PATCH 109/118] fix theme style after merge

---
 src/components/TimePicker/TimePicker.js | 7 +++++--
 src/styles/StyleUtils.ts                | 6 +++---
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/components/TimePicker/TimePicker.js b/src/components/TimePicker/TimePicker.js
index 85263997be99..519c8bb3c8dd 100644
--- a/src/components/TimePicker/TimePicker.js
+++ b/src/components/TimePicker/TimePicker.js
@@ -13,8 +13,9 @@ import useLocalize from '@hooks/useLocalize';
 import useWindowDimensions from '@hooks/useWindowDimensions';
 import DateUtils from '@libs/DateUtils';
 import * as DeviceCapabilities from '@libs/DeviceCapabilities';
-import styles from '@styles/styles';
 import * as StyleUtils from '@styles/StyleUtils';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
 import CONST from '@src/CONST';
 import setSelection from './setSelection';
 
@@ -78,6 +79,8 @@ function replaceWithZeroAtPosition(originalString, position) {
 function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
     const {numberFormat, translate} = useLocalize();
     const {isExtraSmallScreenHeight} = useWindowDimensions();
+    const theme = useTheme();
+    const styles = useThemeStyles();
     const value = DateUtils.extractTime12Hour(defaultValue);
     const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen();
 
@@ -329,7 +332,7 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
         [selectionMinute.start],
     );
 
-    const {styleForAM, styleForPM} = StyleUtils.getStatusAMandPMButtonStyle(amPmValue);
+    const {styleForAM, styleForPM} = StyleUtils.getStatusAMandPMButtonStyle(theme, styles, amPmValue);
 
     const numberPad = useCallback(() => {
         if (!canUseTouchScreen) {
diff --git a/src/styles/StyleUtils.ts b/src/styles/StyleUtils.ts
index 6a8fb8593d0a..e13c01ab711e 100644
--- a/src/styles/StyleUtils.ts
+++ b/src/styles/StyleUtils.ts
@@ -1373,9 +1373,9 @@ function getTransparentColor(color: string) {
 /**
  * Get the style for the AM and PM buttons in the TimePicker
  */
-function getStatusAMandPMButtonStyle(amPmValue: string): {styleForAM: ViewStyle; styleForPM: ViewStyle} {
-    const computedStyleForAM: ViewStyle = amPmValue !== CONST.TIME_PERIOD.AM ? {backgroundColor: themeColors.componentBG} : {};
-    const computedStyleForPM: ViewStyle = amPmValue !== CONST.TIME_PERIOD.PM ? {backgroundColor: themeColors.componentBG} : {};
+function getStatusAMandPMButtonStyle(theme: ThemeColors, styles: ThemeStyles, amPmValue: string): {styleForAM: ViewStyle; styleForPM: ViewStyle} {
+    const computedStyleForAM: ViewStyle = amPmValue !== CONST.TIME_PERIOD.AM ? {backgroundColor: theme.componentBG} : {};
+    const computedStyleForPM: ViewStyle = amPmValue !== CONST.TIME_PERIOD.PM ? {backgroundColor: theme.componentBG} : {};
 
     return {
         styleForAM: [styles.timePickerWidth100, computedStyleForAM] as unknown as ViewStyle,

From 3a06323f2c77269f40f53b8afd051240aea7ae07 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 4 Dec 2023 17:38:52 +0100
Subject: [PATCH 110/118] fix import after merge

---
 src/pages/settings/Profile/CustomStatus/SetDatePage.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/pages/settings/Profile/CustomStatus/SetDatePage.js b/src/pages/settings/Profile/CustomStatus/SetDatePage.js
index 2574100f03fc..28f35c40e102 100644
--- a/src/pages/settings/Profile/CustomStatus/SetDatePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetDatePage.js
@@ -3,7 +3,7 @@ import React, {useCallback} from 'react';
 import {withOnyx} from 'react-native-onyx';
 import FormProvider from '@components/Form/FormProvider';
 import HeaderWithBackButton from '@components/HeaderWithBackButton';
-import NewDatePicker from '@components/NewDatePicker';
+import DatePicker from '@components/DatePicker';
 import ScreenWrapper from '@components/ScreenWrapper';
 import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
 import * as User from '@libs/actions/User';
@@ -58,7 +58,7 @@ function SetDatePage({translate, customStatus}) {
                 enabledWhenOffline
                 shouldUseDefaultValue
             >
-                <NewDatePicker
+                <DatePicker
                     inputID="dateTime"
                     label={translate('statusPage.date')}
                     defaultValue={DateUtils.extractDate(customClearAfter)}

From 8aae901495f32eb2f71c4b4a6b818988006c57e8 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Mon, 4 Dec 2023 17:43:56 +0100
Subject: [PATCH 111/118] lint

---
 src/pages/settings/Profile/CustomStatus/SetDatePage.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/settings/Profile/CustomStatus/SetDatePage.js b/src/pages/settings/Profile/CustomStatus/SetDatePage.js
index 28f35c40e102..30bd89b60177 100644
--- a/src/pages/settings/Profile/CustomStatus/SetDatePage.js
+++ b/src/pages/settings/Profile/CustomStatus/SetDatePage.js
@@ -1,9 +1,9 @@
 import lodashGet from 'lodash/get';
 import React, {useCallback} from 'react';
 import {withOnyx} from 'react-native-onyx';
+import DatePicker from '@components/DatePicker';
 import FormProvider from '@components/Form/FormProvider';
 import HeaderWithBackButton from '@components/HeaderWithBackButton';
-import DatePicker from '@components/DatePicker';
 import ScreenWrapper from '@components/ScreenWrapper';
 import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
 import * as User from '@libs/actions/User';

From caea704e3fe8a40af8895c4d41b58715515cf157 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Tue, 5 Dec 2023 12:06:50 +0100
Subject: [PATCH 112/118] fix tooltip hovering

---
 src/components/EmojiPicker/EmojiPickerButtonDropdown.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
index 72b3d0c66832..033d3475d485 100644
--- a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
+++ b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
@@ -5,7 +5,7 @@ import Icon from '@components/Icon';
 import * as Expensicons from '@components/Icon/Expensicons';
 import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
 import Text from '@components/Text';
-import Tooltip from '@components/Tooltip';
+import Tooltip from '@components/Tooltip/PopoverAnchorTooltip';
 import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
 import getButtonState from '@libs/getButtonState';
 import * as StyleUtils from '@styles/StyleUtils';

From 30b908d6d20192288cb93a827cadd1b7f526a907 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 6 Dec 2023 15:41:50 +0100
Subject: [PATCH 113/118] add screens after merge

---
 src/SCREENS.ts                                            | 4 +++-
 src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx | 4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index c0d3df82e228..920a2597ca4d 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -63,7 +63,9 @@ const SCREENS = {
         PREFERENCES_LANGUAGE: 'Settings_Preferences_Language',
         PREFERENCES_THEME: 'Settings_Preferences_Theme',
         CLOSE: 'Settings_Close',
-        STATUS_SET: 'Settings_Status_Set',
+        STATUS_CLEAR_AFTER: 'Settings_Status_Clear_After',
+        STATUS_CLEAR_AFTER_DATE: 'Settings_Status_Clear_After_Date',
+        STATUS_CLEAR_AFTER_TIME: 'Settings_Status_Clear_After_Time',
         TWO_FACTOR_AUTH: 'Settings_TwoFactorAuth',
         REPORT_CARD_LOST_OR_DAMAGED: 'Settings_ReportCardLostOrDamaged',
     },
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx
index 163423036362..d354df68a815 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx
@@ -206,7 +206,9 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
     [SCREENS.SETTINGS.ADD_DEBIT_CARD]: () => require('../../../pages/settings/Wallet/AddDebitCardPage').default as React.ComponentType,
     [SCREENS.SETTINGS.ADD_BANK_ACCOUNT]: () => require('../../../pages/AddPersonalBankAccountPage').default as React.ComponentType,
     [SCREENS.SETTINGS.STATUS]: () => require('../../../pages/settings/Profile/CustomStatus/StatusPage').default as React.ComponentType,
-    [SCREENS.SETTINGS.STATUS_SET]: () => require('../../../pages/settings/Profile/CustomStatus/StatusSetPage').default as React.ComponentType,
+    [SCREENS.SETTINGS.STATUS_CLEAR_AFTER]: () => require('../../../pages/settings/Profile/CustomStatus/StatusClearAfterPage').default as React.ComponentType,
+    [SCREENS.SETTINGS.STATUS_CLEAR_AFTER_DATE]: () => require('../../../pages/settings/Profile/CustomStatus/SetDatePage').default as React.ComponentType,
+    [SCREENS.SETTINGS.STATUS_CLEAR_AFTER_TIME]: () => require('../../../pages/settings/Profile/CustomStatus/SetTimePage').default as React.ComponentType,
     [SCREENS.WORKSPACE.INITIAL]: () => require('../../../pages/workspace/WorkspaceInitialPage').default as React.ComponentType,
     [SCREENS.WORKSPACE.SETTINGS]: () => require('../../../pages/workspace/WorkspaceSettingsPage').default as React.ComponentType,
     [SCREENS.WORKSPACE.CURRENCY]: () => require('../../../pages/workspace/WorkspaceSettingsCurrencyPage').default as React.ComponentType,

From 39dc1e0d7c8133f8ad3e676eed079665f6989a87 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 6 Dec 2023 16:01:50 +0100
Subject: [PATCH 114/118] fix typing

---
 src/libs/Navigation/types.ts | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index 7aa5bb32a4e4..db94fc8c0c0e 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -82,7 +82,9 @@ type SettingsNavigatorParamList = {
     [SCREENS.SETTINGS.ADD_DEBIT_CARD]: undefined;
     [SCREENS.SETTINGS.ADD_BANK_ACCOUNT]: undefined;
     [SCREENS.SETTINGS.STATUS]: undefined;
-    [SCREENS.SETTINGS.STATUS_SET]: undefined;
+    [SCREENS.SETTINGS.STATUS_CLEAR_AFTER]: undefined;
+    [SCREENS.SETTINGS.STATUS_CLEAR_AFTER_DATE]: undefined;
+    [SCREENS.SETTINGS.STATUS_CLEAR_AFTER_TIME]: undefined;
     [SCREENS.WORKSPACE.INITIAL]: undefined;
     [SCREENS.WORKSPACE.SETTINGS]: undefined;
     [SCREENS.WORKSPACE.CURRENCY]: undefined;

From cda11451292eed80ae8b2a420d5e2c69d91b6e1f Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 13 Dec 2023 10:11:31 +0100
Subject: [PATCH 115/118] migrate to useStyleUtils

---
 src/components/AmountTextInput.js | 3 ++-
 src/components/MenuItem.js        | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/components/AmountTextInput.js b/src/components/AmountTextInput.js
index b7491c974936..63e59d7eef4a 100644
--- a/src/components/AmountTextInput.js
+++ b/src/components/AmountTextInput.js
@@ -1,6 +1,6 @@
 import PropTypes from 'prop-types';
 import React from 'react';
-import * as StyleUtils from '@styles/StyleUtils';
+import useStyleUtils from '@styles/useStyleUtils';
 import useThemeStyles from '@styles/useThemeStyles';
 import CONST from '@src/CONST';
 import refPropTypes from './refPropTypes';
@@ -49,6 +49,7 @@ const defaultProps = {
 
 function AmountTextInput(props) {
     const styles = useThemeStyles();
+    const StyleUtils = useStyleUtils();
     return (
         <TextInput
             disableKeyboard
diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js
index e134d94cfa6a..679e8853742d 100644
--- a/src/components/MenuItem.js
+++ b/src/components/MenuItem.js
@@ -394,7 +394,7 @@ const MenuItem = React.forwardRef((props, ref) => {
                                     isError
                                     shouldShowRedDotIndicator={false}
                                     message={props.errorText}
-                                    style={[styles.menuItemError]}
+                                    style={styles.menuItemError}
                                 />
                             )}
                         </>

From b3f0937f95420cb05b4b3db385867d5ecd6f2c33 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 13 Dec 2023 10:12:29 +0100
Subject: [PATCH 116/118] fix getStatusAMandPMButtonStyle

---
 src/components/TimePicker/TimePicker.js | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/components/TimePicker/TimePicker.js b/src/components/TimePicker/TimePicker.js
index 519c8bb3c8dd..7da6084b5312 100644
--- a/src/components/TimePicker/TimePicker.js
+++ b/src/components/TimePicker/TimePicker.js
@@ -13,8 +13,7 @@ import useLocalize from '@hooks/useLocalize';
 import useWindowDimensions from '@hooks/useWindowDimensions';
 import DateUtils from '@libs/DateUtils';
 import * as DeviceCapabilities from '@libs/DeviceCapabilities';
-import * as StyleUtils from '@styles/StyleUtils';
-import useTheme from '@styles/themes/useTheme';
+import useStyleUtils from '@styles/useStyleUtils';
 import useThemeStyles from '@styles/useThemeStyles';
 import CONST from '@src/CONST';
 import setSelection from './setSelection';
@@ -79,8 +78,8 @@ function replaceWithZeroAtPosition(originalString, position) {
 function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
     const {numberFormat, translate} = useLocalize();
     const {isExtraSmallScreenHeight} = useWindowDimensions();
-    const theme = useTheme();
     const styles = useThemeStyles();
+    const StyleUtils = useStyleUtils();
     const value = DateUtils.extractTime12Hour(defaultValue);
     const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen();
 
@@ -332,7 +331,7 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
         [selectionMinute.start],
     );
 
-    const {styleForAM, styleForPM} = StyleUtils.getStatusAMandPMButtonStyle(theme, styles, amPmValue);
+    const {styleForAM, styleForPM} = StyleUtils.getStatusAMandPMButtonStyle(amPmValue);
 
     const numberPad = useCallback(() => {
         if (!canUseTouchScreen) {

From 2afce0a42f91653edda92bc98a3da47bab235f2c Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 13 Dec 2023 10:12:48 +0100
Subject: [PATCH 117/118] add shouldShowRedDotIndicator to FormHelpMessage

---
 src/components/FormHelpMessage.tsx | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/components/FormHelpMessage.tsx b/src/components/FormHelpMessage.tsx
index 27a1f5827d75..3d0b2df443f2 100644
--- a/src/components/FormHelpMessage.tsx
+++ b/src/components/FormHelpMessage.tsx
@@ -20,9 +20,12 @@ type FormHelpMessageProps = {
 
     /** Container style props */
     style?: StyleProp<ViewStyle>;
+
+    /** Whether to show dot indicator */
+    shouldShowRedDotIndicator?: boolean;
 };
 
-function FormHelpMessage({message = '', children, isError = true, style}: FormHelpMessageProps) {
+function FormHelpMessage({message = '', children, isError = true, style, shouldShowRedDotIndicator = true}: FormHelpMessageProps) {
     const theme = useTheme();
     const styles = useThemeStyles();
     if (isEmpty(message) && isEmpty(children)) {
@@ -33,13 +36,15 @@ function FormHelpMessage({message = '', children, isError = true, style}: FormHe
 
     return (
         <View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2, styles.mb1, style]}>
-            {isError && (
+            {isError && shouldShowRedDotIndicator && (
                 <Icon
                     src={Expensicons.DotIndicator}
                     fill={theme.danger}
                 />
             )}
-            <View style={[styles.flex1, isError && styles.ml2]}>{children ?? <Text style={[isError ? styles.formError : styles.formHelp, styles.mb0]}>{translatedMessage}</Text>}</View>
+            <View style={[styles.flex1, isError && shouldShowRedDotIndicator ? styles.ml2 : {}]}>
+                {children ?? <Text style={[isError ? styles.formError : styles.formHelp, styles.mb0]}>{translatedMessage}</Text>}
+            </View>
         </View>
     );
 }

From 47fa79c466b4e5e4548b0f703f54f9be6e9a3c57 Mon Sep 17 00:00:00 2001
From: Taras Perun <terry.perun@gmail.com>
Date: Wed, 13 Dec 2023 10:27:07 +0100
Subject: [PATCH 118/118] fix after merge

---
 src/ROUTES.ts                                         | 1 -
 src/SCREENS.ts                                        | 4 ----
 src/pages/settings/Profile/CustomStatus/StatusPage.js | 6 ++++--
 3 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index e0c7a16b4fd3..ca1fe9f0e81a 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -140,7 +140,6 @@ const ROUTES = {
         getRoute: (backTo?: string) => getUrlWithBackToParam('settings/security/two-factor-auth', backTo),
     },
     SETTINGS_STATUS: 'settings/profile/status',
-    SETTINGS_STATUS_SET: 'settings/profile/status/set',
     SETTINGS_STATUS_CLEAR_AFTER: 'settings/profile/status/clear-after',
     SETTINGS_STATUS_CLEAR_AFTER_DATE: 'settings/profile/status/clear-after/date',
     SETTINGS_STATUS_CLEAR_AFTER_TIME: 'settings/profile/status/clear-after/time',
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index d4aa75e97538..2cd263237866 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -37,14 +37,10 @@ const SCREENS = {
             CONTACT_METHODS: 'Settings_ContactMethods',
             CONTACT_METHOD_DETAILS: 'Settings_ContactMethodDetails',
             NEW_CONTACT_METHOD: 'Settings_NewContactMethod',
-
             STATUS_CLEAR_AFTER: 'Settings_Status_Clear_After',
             STATUS_CLEAR_AFTER_DATE: 'Settings_Status_Clear_After_Date',
             STATUS_CLEAR_AFTER_TIME: 'Settings_Status_Clear_After_Time',
-
             STATUS: 'Settings_Status',
-            STATUS_SET: 'Settings_Status_Set',
-
             PRONOUNS: 'Settings_Pronouns',
             TIMEZONE: 'Settings_Timezone',
             TIMEZONE_SELECT: 'Settings_Timezone_Select',
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index fce650ea23b2..1bf4165c15c5 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -1,6 +1,6 @@
 import lodashGet from 'lodash/get';
 import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
-import {View} from 'react-native';
+import {InteractionManager, View} from 'react-native';
 import {withOnyx} from 'react-native-onyx';
 import EmojiPickerButtonDropdown from '@components/EmojiPicker/EmojiPickerButtonDropdown';
 import FormProvider from '@components/Form/FormProvider';
@@ -86,7 +86,9 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
             });
 
             User.clearDraftCustomStatus();
-            navigateBackToPreviousScreen();
+            InteractionManager.runAfterInteractions(() => {
+                navigateBackToPreviousScreen();
+            });
         },
         [currentUserClearAfter, draftClearAfter, isValidClearAfterDate, navigateBackToPreviousScreen],
     );
