From 31581f9c234322f98b4274de43f15a85c924f260 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Thu, 18 Jan 2024 16:24:22 +0000 Subject: [PATCH 1/5] refactor(typescript): migrate workspacenewroompage --- src/components/ScreenWrapper.tsx | 14 +- src/libs/ErrorUtils.ts | 5 +- src/libs/ValidationUtils.ts | 8 +- ...ewRoomPage.js => WorkspaceNewRoomPage.tsx} | 194 +++++++----------- 4 files changed, 96 insertions(+), 125 deletions(-) rename src/pages/workspace/{WorkspaceNewRoomPage.js => WorkspaceNewRoomPage.tsx} (73%) diff --git a/src/components/ScreenWrapper.tsx b/src/components/ScreenWrapper.tsx index 0653e2ff8577..b2815d02dcd6 100644 --- a/src/components/ScreenWrapper.tsx +++ b/src/components/ScreenWrapper.tsx @@ -24,7 +24,7 @@ import SafeAreaConsumer from './SafeAreaConsumer'; import TestToolsModal from './TestToolsModal'; type ChildrenProps = { - insets?: EdgeInsets; + insets: EdgeInsets; safeAreaPaddingBottomStyle?: { paddingBottom?: DimensionValue; }; @@ -190,7 +190,17 @@ function ScreenWrapper( return ( - {({insets, paddingTop, paddingBottom, safeAreaPaddingBottomStyle}) => { + {({ + insets = { + top: 0, + bottom: 0, + left: 0, + right: 0, + }, + paddingTop, + paddingBottom, + safeAreaPaddingBottomStyle, + }) => { const paddingStyle: StyleProp = {}; if (includePaddingTop) { diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 159a5817189b..68bfbe706ac6 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -1,9 +1,10 @@ import CONST from '@src/CONST'; -import type {TranslationFlatObject, TranslationPaths} from '@src/languages/types'; +import type {TranslationFlatObject} from '@src/languages/types'; import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon'; import type Response from '@src/types/onyx/Response'; import DateUtils from './DateUtils'; import * as Localize from './Localize'; +import type {MaybePhraseKey} from './Localize'; function getAuthenticateErrorMessage(response: Response): keyof TranslationFlatObject { switch (response.jsonCode) { @@ -101,7 +102,7 @@ type ErrorsList = Record; * @param errorList - An object containing current errors in the form * @param message - Message to assign to the inputID errors */ -function addErrorMessage(errors: ErrorsList, inputID?: string, message?: TKey) { +function addErrorMessage(errors: ErrorsList, inputID?: string, message?: MaybePhraseKey) { if (!message || !inputID) { return; } diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index 9ba11fb16d6a..4a98a2e99f06 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -3,6 +3,7 @@ import {URL_REGEX_WITH_REQUIRED_PROTOCOL} from 'expensify-common/lib/Url'; import isDate from 'lodash/isDate'; import isEmpty from 'lodash/isEmpty'; import isObject from 'lodash/isObject'; +import type {OnyxCollection} from 'react-native-onyx'; import CONST from '@src/CONST'; import type {Report} from '@src/types/onyx'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; @@ -354,8 +355,11 @@ function isReservedRoomName(roomName: string): boolean { /** * Checks if the room name already exists. */ -function isExistingRoomName(roomName: string, reports: Record, policyID: string): boolean { - return Object.values(reports).some((report) => report && report.policyID === policyID && report.reportName === roomName); +function isExistingRoomName(roomName: string, reports: OnyxCollection, policyID: string): boolean { + if (!reports) { + return false; + } + return Object.values(reports).some((report) => report?.policyID === policyID && report?.reportName === roomName); } /** diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.tsx similarity index 73% rename from src/pages/workspace/WorkspaceNewRoomPage.js rename to src/pages/workspace/WorkspaceNewRoomPage.tsx index 35fab36e5d41..318c3a4d744b 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -1,8 +1,9 @@ -import PropTypes from 'prop-types'; +import {useIsFocused} from '@react-navigation/core'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {ValueOf} from 'type-fest'; import BlockingView from '@components/BlockingViews/BlockingView'; import Button from '@components/Button'; import FormProvider from '@components/Form/FormProvider'; @@ -14,14 +15,12 @@ import RoomNameInput from '@components/RoomNameInput'; import ScreenWrapper from '@components/ScreenWrapper'; import TextInput from '@components/TextInput'; import ValuePicker from '@components/ValuePicker'; -import withNavigationFocus from '@components/withNavigationFocus'; import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import compose from '@libs/compose'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; @@ -32,98 +31,58 @@ import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {Account, Form, Policy, Report as ReportType, Session} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; -const propTypes = { - /** All reports shared with the user */ - reports: PropTypes.shape({ - /** The report name */ - reportName: PropTypes.string, - - /** The report type */ - type: PropTypes.string, - - /** ID of the policy */ - policyID: PropTypes.string, - }), - - /** The list of policies the user has access to. */ - policies: PropTypes.objectOf( - PropTypes.shape({ - /** The policy type */ - type: PropTypes.oneOf(_.values(CONST.POLICY.TYPE)), - - /** The name of the policy */ - name: PropTypes.string, - - /** The ID of the policy */ - id: PropTypes.string, - }), - ), - - /** Whether navigation is focused */ - isFocused: PropTypes.bool.isRequired, - - /** Form state for NEW_ROOM_FORM */ - formState: PropTypes.shape({ - /** Loading state for the form */ - isLoading: PropTypes.bool, - - /** Field errors in the form */ - errorFields: PropTypes.objectOf(PropTypes.objectOf(PropTypes.string)), - }), - - /** Session details for the user */ - session: PropTypes.shape({ - /** accountID of current user */ - accountID: PropTypes.number, - }), - - /** policyID for main workspace */ - activePolicyID: PropTypes.string, +type FormValues = { + welcomeMessage: string; + roomName: string; + policyID: string | null; + writeCapability: ValueOf; + visibility: ValueOf; }; -const defaultProps = { - reports: {}, - policies: {}, - formState: { - isLoading: false, - errorFields: {}, - }, - session: { - accountID: 0, - }, - activePolicyID: null, + +type WorkspaceNewRoomPageOnyxProps = { + policies: OnyxCollection; + reports: OnyxCollection; + formState: OnyxEntry
; + session: OnyxEntry; + activePolicyID: OnyxEntry['activePolicyID']>; }; -function WorkspaceNewRoomPage(props) { +type WorkspaceNewRoomPageProps = WorkspaceNewRoomPageOnyxProps; + +function WorkspaceNewRoomPage({policies, reports, formState, session, activePolicyID}: WorkspaceNewRoomPageProps) { const styles = useThemeStyles(); + const isFocused = useIsFocused(); const {translate} = useLocalize(); const {isOffline} = useNetwork(); const {isSmallScreenWidth} = useWindowDimensions(); - const [visibility, setVisibility] = useState(CONST.REPORT.VISIBILITY.RESTRICTED); - const [policyID, setPolicyID] = useState(props.activePolicyID); - const [writeCapability, setWriteCapability] = useState(CONST.REPORT.WRITE_CAPABILITIES.ALL); - const wasLoading = usePrevious(props.formState.isLoading); + const [visibility, setVisibility] = useState(CONST.REPORT.VISIBILITY.RESTRICTED); + const [policyID, setPolicyID] = useState(activePolicyID); + const [writeCapability, setWriteCapability] = useState(CONST.REPORT.WRITE_CAPABILITIES.ALL); + const wasLoading = usePrevious(!!formState?.isLoading); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); const isPolicyAdmin = useMemo(() => { if (!policyID) { return false; } - return ReportUtils.isPolicyAdmin(policyID, props.policies); - }, [policyID, props.policies]); - const [newRoomReportID, setNewRoomReportID] = useState(undefined); + return ReportUtils.isPolicyAdmin(policyID, policies); + }, [policyID, policies]); + const [newRoomReportID, setNewRoomReportID] = useState(); /** - * @param {Object} values - form input values passed by the Form component + * @param values - form input values passed by the Form component */ - const submit = (values) => { - const participants = [props.session.accountID]; + const submit = (values: FormValues) => { + const participants = session ? [session.accountID ?? -1] : []; const parsedWelcomeMessage = ReportUtils.getParsedComment(values.welcomeMessage); const policyReport = ReportUtils.buildOptimisticChatReport( participants, values.roomName, CONST.REPORT.CHAT_TYPE.POLICY_ROOM, - policyID, + policyID ?? undefined, CONST.REPORT.OWNER_ACCOUNT_ID_FAKE, false, '', @@ -146,16 +105,16 @@ function WorkspaceNewRoomPage(props) { if (policyID) { return; } - setPolicyID(props.activePolicyID); - }, [props.activePolicyID, policyID]); + setPolicyID(activePolicyID); + }, [activePolicyID, policyID]); useEffect(() => { - if (!(((wasLoading && !props.formState.isLoading) || (isOffline && props.formState.isLoading)) && _.isEmpty(props.formState.errorFields))) { + if (!(((wasLoading && !formState?.isLoading) || (isOffline && formState?.isLoading)) && isEmptyObject(formState?.errorFields))) { return; } Navigation.dismissModal(newRoomReportID); // eslint-disable-next-line react-hooks/exhaustive-deps -- we just want this to update on changing the form State - }, [props.formState]); + }, [formState]); useEffect(() => { if (isPolicyAdmin) { @@ -170,8 +129,8 @@ function WorkspaceNewRoomPage(props) { * @returns {Boolean} */ const validate = useCallback( - (values) => { - const errors = {}; + (values: FormValues) => { + const errors: Record = {}; if (!values.roomName || values.roomName === CONST.POLICY.ROOM_PREFIX) { // We error if the user doesn't enter a room name or left blank @@ -182,7 +141,7 @@ function WorkspaceNewRoomPage(props) { } else if (ValidationUtils.isReservedRoomName(values.roomName)) { // Certain names are reserved for default rooms and should not be used for policy rooms. ErrorUtils.addErrorMessage(errors, 'roomName', ['newRoomPage.roomNameReservedError', {reservedName: values.roomName}]); - } else if (ValidationUtils.isExistingRoomName(values.roomName, props.reports, values.policyID)) { + } else if (ValidationUtils.isExistingRoomName(values.roomName, reports, values.policyID ?? '')) { // Certain names are reserved for default rooms and should not be used for policy rooms. ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomAlreadyExistsError'); } @@ -193,22 +152,22 @@ function WorkspaceNewRoomPage(props) { return errors; }, - [props.reports], + [reports], ); const workspaceOptions = useMemo( () => - _.map(PolicyUtils.getActivePolicies(props.policies), (policy) => ({ + PolicyUtils.getActivePolicies(policies)?.map((policy) => ({ label: policy.name, key: policy.id, value: policy.id, - })), - [props.policies], + })) ?? [], + [policies], ); const writeCapabilityOptions = useMemo( () => - _.map(CONST.REPORT.WRITE_CAPABILITIES, (value) => ({ + Object.values(CONST.REPORT.WRITE_CAPABILITIES).map((value) => ({ value, label: translate(`writeCapabilityPage.writeCapability.${value}`), })), @@ -217,14 +176,13 @@ function WorkspaceNewRoomPage(props) { const visibilityOptions = useMemo( () => - _.map( - _.filter(_.values(CONST.REPORT.VISIBILITY), (visibilityOption) => visibilityOption !== CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE), - (visibilityOption) => ({ + Object.values(CONST.REPORT.VISIBILITY) + .filter((visibilityOption) => visibilityOption !== CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE) + .map((visibilityOption) => ({ label: translate(`newRoomPage.visibilityOptions.${visibilityOption}`), value: visibilityOption, description: translate(`newRoomPage.${visibilityOption}Description`), - }), - ), + })), [translate], ); @@ -270,6 +228,7 @@ function WorkspaceNewRoomPage(props) { // This is because when wrapping whole screen the screen was freezing when changing Tabs. keyboardVerticalOffset={variables.contentHeaderHeight + variables.tabSelectorButtonHeight + variables.tabSelectorButtonPadding + insets.top} > + {/** @ts-expect-error TODO: Remove this once FormProvider (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript. */} (account && account.activePolicyID) || null, - initialValue: null, - }, - }), -)(WorkspaceNewRoomPage); +export default withOnyx({ + policies: { + key: ONYXKEYS.COLLECTION.POLICY, + }, + reports: { + key: ONYXKEYS.COLLECTION.REPORT, + }, + formState: { + key: ONYXKEYS.FORMS.NEW_ROOM_FORM, + }, + session: { + key: ONYXKEYS.SESSION, + }, + activePolicyID: { + key: ONYXKEYS.ACCOUNT, + selector: (account) => account?.activePolicyID ?? null, + initialValue: null, + }, +})(WorkspaceNewRoomPage); From d9fb612f3a622ce1e205c915e05fec790ec62d17 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Fri, 19 Jan 2024 17:17:18 +0000 Subject: [PATCH 2/5] refactor(typescript): apply pull request feedback --- src/pages/workspace/WorkspaceNewRoomPage.tsx | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 318c3a4d744b..27063d01fe33 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -32,6 +32,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Account, Form, Policy, Report as ReportType, Session} from '@src/types/onyx'; +import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; type FormValues = { @@ -43,10 +44,19 @@ type FormValues = { }; type WorkspaceNewRoomPageOnyxProps = { + /** The list of policies the user has access to. */ policies: OnyxCollection; + + /** All reports shared with the user */ reports: OnyxCollection; + + /** Form state for NEW_ROOM_FORM */ formState: OnyxEntry; + + /** Session details for the user */ session: OnyxEntry; + + /** policyID for main workspace */ activePolicyID: OnyxEntry['activePolicyID']>; }; @@ -76,7 +86,7 @@ function WorkspaceNewRoomPage({policies, reports, formState, session, activePoli * @param values - form input values passed by the Form component */ const submit = (values: FormValues) => { - const participants = session ? [session.accountID ?? -1] : []; + const participants = session?.accountID ? [session.accountID] : []; const parsedWelcomeMessage = ReportUtils.getParsedComment(values.welcomeMessage); const policyReport = ReportUtils.buildOptimisticChatReport( participants, @@ -125,12 +135,12 @@ function WorkspaceNewRoomPage({policies, reports, formState, session, activePoli }, [isPolicyAdmin]); /** - * @param {Object} values - form input values passed by the Form component - * @returns {Boolean} + * @param values - form input values passed by the Form component + * @returns an object containing validation errors, if any were found during validation */ const validate = useCallback( - (values: FormValues) => { - const errors: Record = {}; + (values: FormValues): OnyxCommon.Errors => { + const errors: OnyxCommon.Errors = {}; if (!values.roomName || values.roomName === CONST.POLICY.ROOM_PREFIX) { // We error if the user doesn't enter a room name or left blank From 4542a8f47e37ef419e94ba7fe33c8b04f960dda6 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Fri, 26 Jan 2024 18:07:56 +0000 Subject: [PATCH 3/5] refactor: apply pull request feedback --- src/pages/workspace/WorkspaceNewRoomPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 27063d01fe33..323594b1703a 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -86,7 +86,7 @@ function WorkspaceNewRoomPage({policies, reports, formState, session, activePoli * @param values - form input values passed by the Form component */ const submit = (values: FormValues) => { - const participants = session?.accountID ? [session.accountID] : []; + const participants = [session?.accountID ?? 0]; const parsedWelcomeMessage = ReportUtils.getParsedComment(values.welcomeMessage); const policyReport = ReportUtils.buildOptimisticChatReport( participants, From da4ffd7d3bec3c3f67c1738ac1e47f3b3ba083e0 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Mon, 29 Jan 2024 22:15:07 +0000 Subject: [PATCH 4/5] refactor(typescript): fix types --- src/pages/workspace/WorkspaceNewRoomPage.tsx | 63 +++++++++----------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 59606d9bbcfd..b156261c7e77 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -8,6 +8,7 @@ import BlockingView from '@components/BlockingViews/BlockingView'; import Button from '@components/Button'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; +import type {OnyxFormValuesFields} from '@components/Form/types'; import * as Illustrations from '@components/Icon/Illustrations'; import KeyboardAvoidingView from '@components/KeyboardAvoidingView'; import OfflineIndicator from '@components/OfflineIndicator'; @@ -31,18 +32,10 @@ import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {Account, Form, Policy, Report as ReportType, Session} from '@src/types/onyx'; +import type {Account, NewRoomForm, Policy, Report as ReportType, Session} from '@src/types/onyx'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -type FormValues = { - welcomeMessage: string; - roomName: string; - policyID: string | null; - writeCapability: ValueOf; - visibility: ValueOf; -}; - type WorkspaceNewRoomPageOnyxProps = { /** The list of policies the user has access to. */ policies: OnyxCollection; @@ -51,7 +44,7 @@ type WorkspaceNewRoomPageOnyxProps = { reports: OnyxCollection; /** Form state for NEW_ROOM_FORM */ - formState: OnyxEntry; + formState: OnyxEntry; /** Session details for the user */ session: OnyxEntry; @@ -68,23 +61,23 @@ function WorkspaceNewRoomPage({policies, reports, formState, session, activePoli const {translate} = useLocalize(); const {isOffline} = useNetwork(); const {isSmallScreenWidth} = useWindowDimensions(); - const [visibility, setVisibility] = useState(CONST.REPORT.VISIBILITY.RESTRICTED); - const [writeCapability, setWriteCapability] = useState(CONST.REPORT.WRITE_CAPABILITIES.ALL); - const wasLoading = usePrevious(props.formState.isLoading); + const [visibility, setVisibility] = useState>(CONST.REPORT.VISIBILITY.RESTRICTED); + const [writeCapability, setWriteCapability] = useState>(CONST.REPORT.WRITE_CAPABILITIES.ALL); + const wasLoading = usePrevious(formState?.isLoading); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); const workspaceOptions = useMemo( () => - _.map(PolicyUtils.getActivePolicies(props.policies), (policy) => ({ + PolicyUtils.getActivePolicies(policies)?.map((policy) => ({ label: policy.name, key: policy.id, value: policy.id, - })), - [props.policies], + })) ?? [], + [policies], ); - const [policyID, setPolicyID] = useState(() => { - if (_.some(workspaceOptions, (option) => option.value === props.activePolicyID)) { - return props.activePolicyID; + const [policyID, setPolicyID] = useState(() => { + if (!!activePolicyID && workspaceOptions.some((option) => option.value === activePolicyID)) { + return activePolicyID; } return ''; }); @@ -100,9 +93,9 @@ function WorkspaceNewRoomPage({policies, reports, formState, session, activePoli /** * @param values - form input values passed by the Form component */ - const submit = (values: FormValues) => { + const submit = (values: OnyxFormValuesFields<'newRoomForm'>) => { const participants = [session?.accountID ?? 0]; - const parsedWelcomeMessage = ReportUtils.getParsedComment(values.welcomeMessage); + const parsedWelcomeMessage = ReportUtils.getParsedComment(values.welcomeMessage ?? ''); const policyReport = ReportUtils.buildOptimisticChatReport( participants, values.roomName, @@ -128,17 +121,17 @@ function WorkspaceNewRoomPage({policies, reports, formState, session, activePoli useEffect(() => { if (policyID) { - if (!_.some(workspaceOptions, (opt) => opt.value === policyID)) { + if (!workspaceOptions.some((opt) => opt.value === policyID)) { setPolicyID(''); } return; } - if (_.some(workspaceOptions, (opt) => opt.value === props.activePolicyID)) { - setPolicyID(props.activePolicyID); + if (!!activePolicyID && workspaceOptions.some((opt) => opt.value === activePolicyID)) { + setPolicyID(activePolicyID); } else { setPolicyID(''); } - }, [props.activePolicyID, policyID, workspaceOptions]); + }, [activePolicyID, policyID, workspaceOptions]); useEffect(() => { if (!(((wasLoading && !formState?.isLoading) || (isOffline && formState?.isLoading)) && isEmptyObject(formState?.errorFields))) { @@ -161,7 +154,7 @@ function WorkspaceNewRoomPage({policies, reports, formState, session, activePoli * @returns an object containing validation errors, if any were found during validation */ const validate = useCallback( - (values: FormValues): OnyxCommon.Errors => { + (values: OnyxFormValuesFields<'newRoomForm'>): OnyxCommon.Errors => { const errors: OnyxCommon.Errors = {}; if (!values.roomName || values.roomName === CONST.POLICY.ROOM_PREFIX) { @@ -250,7 +243,6 @@ function WorkspaceNewRoomPage({policies, reports, formState, session, activePoli // This is because when wrapping whole screen the screen was freezing when changing Tabs. keyboardVerticalOffset={variables.contentHeaderHeight + variables.tabSelectorButtonHeight + variables.tabSelectorButtonPadding + insets.top} > - {/** @ts-expect-error TODO: Remove this once FormProvider (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript. */} setPolicyID(value as typeof policyID)} /> {isPolicyAdmin && ( setWriteCapability(value as typeof writeCapability)} /> )} setVisibility(value as typeof visibility)} value={visibility} furtherDetails={visibilityDescription} shouldShowTooltips={false} From c8fa7935a786b13d30899458e3028412c3db3ccc Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Mon, 29 Jan 2024 22:57:50 +0000 Subject: [PATCH 5/5] chore: resolve linter issues --- src/CONST.ts | 1 + src/hooks/useNetwork.ts | 5 +++-- src/pages/workspace/WorkspaceNewRoomPage.tsx | 9 +++++---- src/setup/index.js | 2 +- src/types/onyx/Network.ts | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index b1a84aef3ca0..19f1642f0533 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -848,6 +848,7 @@ const CONST = { DEFAULT_TIME_ZONE: {automatic: true, selected: 'America/Los_Angeles'}, DEFAULT_ACCOUNT_DATA: {errors: null, success: '', isLoading: false}, DEFAULT_CLOSE_ACCOUNT_DATA: {errors: null, success: '', isLoading: false}, + DEFAULT_NETWORK_DATA: {isOffline: false}, FORMS: { LOGIN_FORM: 'LoginForm', VALIDATE_CODE_FORM: 'ValidateCodeForm', diff --git a/src/hooks/useNetwork.ts b/src/hooks/useNetwork.ts index f9e1a627c5f5..1e4a6d4cf2ca 100644 --- a/src/hooks/useNetwork.ts +++ b/src/hooks/useNetwork.ts @@ -1,17 +1,18 @@ import {useContext, useEffect, useRef} from 'react'; import {NetworkContext} from '@components/OnyxProvider'; +import CONST from '@src/CONST'; type UseNetworkProps = { onReconnect?: () => void; }; -type UseNetwork = {isOffline?: boolean}; +type UseNetwork = {isOffline: boolean}; export default function useNetwork({onReconnect = () => {}}: UseNetworkProps = {}): UseNetwork { const callback = useRef(onReconnect); callback.current = onReconnect; - const {isOffline} = useContext(NetworkContext) ?? {}; + const {isOffline} = useContext(NetworkContext) ?? CONST.DEFAULT_NETWORK_DATA; const prevOfflineStatusRef = useRef(isOffline); useEffect(() => { // If we were offline before and now we are not offline then we just reconnected diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index b156261c7e77..092d4bd2c4b6 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -63,8 +63,9 @@ function WorkspaceNewRoomPage({policies, reports, formState, session, activePoli const {isSmallScreenWidth} = useWindowDimensions(); const [visibility, setVisibility] = useState>(CONST.REPORT.VISIBILITY.RESTRICTED); const [writeCapability, setWriteCapability] = useState>(CONST.REPORT.WRITE_CAPABILITIES.ALL); - const wasLoading = usePrevious(formState?.isLoading); + const wasLoading = usePrevious(!!formState?.isLoading); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); + const {isLoading = false, errorFields = {}} = formState ?? {}; const workspaceOptions = useMemo( () => @@ -100,7 +101,7 @@ function WorkspaceNewRoomPage({policies, reports, formState, session, activePoli participants, values.roomName, CONST.REPORT.CHAT_TYPE.POLICY_ROOM, - policyID ?? undefined, + policyID, CONST.REPORT.OWNER_ACCOUNT_ID_FAKE, false, '', @@ -134,12 +135,12 @@ function WorkspaceNewRoomPage({policies, reports, formState, session, activePoli }, [activePolicyID, policyID, workspaceOptions]); useEffect(() => { - if (!(((wasLoading && !formState?.isLoading) || (isOffline && formState?.isLoading)) && isEmptyObject(formState?.errorFields))) { + if (!(((wasLoading && !isLoading) || (isOffline && isLoading)) && isEmptyObject(errorFields))) { return; } Navigation.dismissModal(newRoomReportID); // eslint-disable-next-line react-hooks/exhaustive-deps -- we just want this to update on changing the form State - }, [formState]); + }, [isLoading, errorFields]); useEffect(() => { if (isPolicyAdmin) { diff --git a/src/setup/index.js b/src/setup/index.js index aac6f1e4e732..5955c6c218f2 100644 --- a/src/setup/index.js +++ b/src/setup/index.js @@ -33,7 +33,7 @@ export default function () { // Clear any loading and error messages so they do not appear on app startup [ONYXKEYS.SESSION]: {loading: false}, [ONYXKEYS.ACCOUNT]: CONST.DEFAULT_ACCOUNT_DATA, - [ONYXKEYS.NETWORK]: {isOffline: false}, + [ONYXKEYS.NETWORK]: CONST.DEFAULT_NETWORK_DATA, [ONYXKEYS.IS_SIDEBAR_LOADED]: false, [ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT]: true, [ONYXKEYS.MODAL]: { diff --git a/src/types/onyx/Network.ts b/src/types/onyx/Network.ts index 32b084bbf2f7..173ca486b53c 100644 --- a/src/types/onyx/Network.ts +++ b/src/types/onyx/Network.ts @@ -1,6 +1,6 @@ type Network = { /** Is the network currently offline or not */ - isOffline?: boolean; + isOffline: boolean; /** Should the network be forced offline */ shouldForceOffline?: boolean;