Skip to content

Commit

Permalink
Merge pull request #35294 from fedirjh/ts-migration-signin
Browse files Browse the repository at this point in the history
[TS migration] Migrate Signin to TypeScript
  • Loading branch information
puneetlath authored Feb 14, 2024
2 parents 7787ed7 + f914990 commit 0b5446b
Show file tree
Hide file tree
Showing 51 changed files with 806 additions and 1,004 deletions.
2 changes: 2 additions & 0 deletions src/components/TextLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,6 @@ function TextLink({href, onPress, children, style, onMouseDown = (event) => even

TextLink.displayName = 'TextLink';

export type {LinkProps, PressProps};

export default forwardRef(TextLink);
8 changes: 5 additions & 3 deletions src/components/withToggleVisibilityView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import type {SetOptional} from 'type-fest';
import useThemeStyles from '@hooks/useThemeStyles';
import getComponentDisplayName from '@libs/getComponentDisplayName';

type ToggleVisibilityViewProps = {
type WithToggleVisibilityViewProps = {
/** Whether the content is visible. */
isVisible: boolean;
isVisible?: boolean;
};

export default function withToggleVisibilityView<TProps extends ToggleVisibilityViewProps, TRef>(
export default function withToggleVisibilityView<TProps extends WithToggleVisibilityViewProps, TRef>(
WrappedComponent: ComponentType<TProps & RefAttributes<TRef>>,
): (props: TProps & RefAttributes<TRef>) => ReactElement | null {
function WithToggleVisibilityView({isVisible = false, ...rest}: SetOptional<TProps, 'isVisible'>, ref: ForwardedRef<TRef>) {
Expand All @@ -30,3 +30,5 @@ export default function withToggleVisibilityView<TProps extends ToggleVisibility
WithToggleVisibilityView.displayName = `WithToggleVisibilityViewWithRef(${getComponentDisplayName(WrappedComponent)})`;
return React.forwardRef(WithToggleVisibilityView);
}

export type {WithToggleVisibilityViewProps};
3 changes: 2 additions & 1 deletion src/libs/Localize/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import CONST from '@src/CONST';
import translations from '@src/languages/translations';
import type {TranslationFlatObject, TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Locale} from '@src/types/onyx';
import type {ReceiptError} from '@src/types/onyx/Transaction';
import LocaleListener from './LocaleListener';
import BaseLocaleListener from './LocaleListener/BaseLocaleListener';
Expand Down Expand Up @@ -182,7 +183,7 @@ function formatMessageElementList<E extends MessageElementBase>(elements: readon
/**
* Returns the user device's preferred language.
*/
function getDevicePreferredLocale(): string {
function getDevicePreferredLocale(): Locale {
return RNLocalize.findBestAvailableLanguage([CONST.LOCALES.EN, CONST.LOCALES.ES])?.languageTag ?? CONST.LOCALES.DEFAULT;
}

Expand Down
4 changes: 2 additions & 2 deletions src/libs/Performance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type PrintPerformanceMetrics = () => void;
type MarkStart = (name: string, detail?: Record<string, unknown>) => PerformanceMark | void;
type MarkEnd = (name: string, detail?: Record<string, unknown>) => PerformanceMark | void;
type MeasureFailSafe = (measureName: string, startOrMeasureOptions: string, endMark?: string) => void;
type MeasureTTI = (endMark: string) => void;
type MeasureTTI = (endMark?: string) => void;
type TraceRender = (id: string, phase: Phase, actualDuration: number, baseDuration: number, startTime: number, commitTime: number, interactions: Set<unknown>) => PerformanceMeasure | void;
type WithRenderTrace = ({id}: WrappedComponentConfig) => WithRenderTraceHOC | BlankHOC;
type SubscribeToMeasurements = (callback: PerformanceEntriesCallback) => void;
Expand Down Expand Up @@ -104,7 +104,7 @@ if (Metrics.canCapturePerformanceMetrics()) {
/**
* Measures the TTI time. To be called when the app is considered to be interactive.
*/
Performance.measureTTI = (endMark: string) => {
Performance.measureTTI = (endMark?: string) => {
// Make sure TTI is captured when the app is really usable
InteractionManager.runAfterInteractions(() => {
requestAnimationFrame(() => {
Expand Down
7 changes: 1 addition & 6 deletions src/pages/signin/AppleSignInDesktopPage/index.website.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ import ThirdPartySignInPage from '@pages/signin/ThirdPartySignInPage';
import CONST from '@src/CONST';

function AppleSignInDesktopPage() {
return (
<ThirdPartySignInPage
// @ts-expect-error TODO: Remove this once SignIn (https://github.com/Expensify/App/issues/25224) is migrated to TypeScript.
signInProvider={CONST.SIGN_IN_METHOD.APPLE}
/>
);
return <ThirdPartySignInPage signInProvider={CONST.SIGN_IN_METHOD.APPLE} />;
}

export default AppleSignInDesktopPage;
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import PropTypes from 'prop-types';
import React, {useEffect} from 'react';
import {Keyboard, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import type {OnyxEntry} from 'react-native-onyx';
import Button from '@components/Button';
import FormHelpMessage from '@components/FormHelpMessage';
import Text from '@components/Text';
Expand All @@ -17,43 +16,25 @@ import * as Session from '@userActions/Session';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Account, Credentials} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import ChangeExpensifyLoginLink from './ChangeExpensifyLoginLink';
import Terms from './Terms';

const propTypes = {
/* Onyx Props */

type ChooseSSOOrMagicCodeOnyxProps = {
/** The credentials of the logged in person */
credentials: PropTypes.shape({
/** The email/phone the user logged in with */
login: PropTypes.string,
}),
credentials: OnyxEntry<Credentials>;

/** The details about the account that the user is signing in with */
account: PropTypes.shape({
/** Whether or not a sign on form is loading (being submitted) */
isLoading: PropTypes.bool,

/** Form that is being loaded */
loadingForm: PropTypes.oneOf(_.values(CONST.FORMS)),

/** Whether this account has 2FA enabled or not */
requiresTwoFactorAuth: PropTypes.bool,

/** Server-side errors in the submitted authentication code */
errors: PropTypes.objectOf(PropTypes.string),
}),

/** Function that returns whether the user is using SAML or magic codes to log in */
setIsUsingMagicCode: PropTypes.func.isRequired,
account: OnyxEntry<Account>;
};

const defaultProps = {
credentials: {},
account: {},
type ChooseSSOOrMagicCodeProps = ChooseSSOOrMagicCodeOnyxProps & {
/** Function that returns whether the user is using SAML or magic codes to log in */
setIsUsingMagicCode: (value: boolean) => void;
};

function ChooseSSOOrMagicCode({credentials, account, setIsUsingMagicCode}) {
function ChooseSSOOrMagicCode({credentials, account, setIsUsingMagicCode}: ChooseSSOOrMagicCodeProps) {
const styles = useThemeStyles();
const {isKeyboardShown} = useKeyboardState();
const {translate} = useLocalize();
Expand All @@ -77,7 +58,7 @@ function ChooseSSOOrMagicCode({credentials, account, setIsUsingMagicCode}) {
success
style={[styles.mv3]}
text={translate('samlSignIn.useSingleSignOn')}
isLoading={account.isLoading}
isLoading={account?.isLoading}
onPress={() => {
Navigation.navigate(ROUTES.SAML_SIGN_IN);
}}
Expand All @@ -93,14 +74,17 @@ function ChooseSSOOrMagicCode({credentials, account, setIsUsingMagicCode}) {
isDisabled={isOffline}
style={[styles.mv3]}
text={translate('samlSignIn.useMagicCode')}
isLoading={account.isLoading && account.loadingForm === (account.requiresTwoFactorAuth ? CONST.FORMS.VALIDATE_TFA_CODE_FORM : CONST.FORMS.VALIDATE_CODE_FORM)}
isLoading={account?.isLoading && account?.loadingForm === (account?.requiresTwoFactorAuth ? CONST.FORMS.VALIDATE_TFA_CODE_FORM : CONST.FORMS.VALIDATE_CODE_FORM)}
onPress={() => {
Session.resendValidateCode(credentials.login);
Session.resendValidateCode(credentials?.login);
setIsUsingMagicCode(true);
}}
/>
{Boolean(account) && !_.isEmpty(account.errors) && <FormHelpMessage message={ErrorUtils.getLatestErrorMessage(account)} />}
<ChangeExpensifyLoginLink onPress={() => Session.clearSignInData()} />
{!!account && !isEmptyObject(account.errors) && <FormHelpMessage message={ErrorUtils.getLatestErrorMessage(account)} />}
<ChangeExpensifyLoginLink
// @ts-expect-error TODO: Remove this once https://github.com/Expensify/App/pull/35404 is merged
onPress={() => Session.clearSignInData()}
/>
</View>
<View style={[styles.mt5, styles.signInPageWelcomeTextContainer]}>
<Terms />
Expand All @@ -109,11 +93,9 @@ function ChooseSSOOrMagicCode({credentials, account, setIsUsingMagicCode}) {
);
}

ChooseSSOOrMagicCode.propTypes = propTypes;
ChooseSSOOrMagicCode.defaultProps = defaultProps;
ChooseSSOOrMagicCode.displayName = 'ChooseSSOOrMagicCode';

export default withOnyx({
export default withOnyx<ChooseSSOOrMagicCodeProps, ChooseSSOOrMagicCodeOnyxProps>({
credentials: {key: ONYXKEYS.CREDENTIALS},
account: {key: ONYXKEYS.ACCOUNT},
})(ChooseSSOOrMagicCode);
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Str from 'expensify-common/lib/str';
import PropTypes from 'prop-types';
import React, {useEffect} from 'react';
import React, {useEffect, useMemo} from 'react';
import {Keyboard, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import Text from '@components/Text';
import TextLink from '@components/TextLink';
Expand All @@ -12,26 +12,25 @@ import useThemeStyles from '@hooks/useThemeStyles';
import redirectToSignIn from '@userActions/SignInRedirect';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Credentials} from '@src/types/onyx';

const propTypes = {
/* Onyx Props */

type EmailDeliveryFailurePageOnyxProps = {
/** The credentials of the logged in person */
credentials: PropTypes.shape({
/** The email/phone the user logged in with */
login: PropTypes.string,
}),
credentials: OnyxEntry<Credentials>;
};

const defaultProps = {
credentials: {},
};
type EmailDeliveryFailurePageProps = EmailDeliveryFailurePageOnyxProps;

function EmailDeliveryFailurePage(props) {
function EmailDeliveryFailurePage({credentials}: EmailDeliveryFailurePageProps) {
const styles = useThemeStyles();
const {isKeyboardShown} = useKeyboardState();
const {translate} = useLocalize();
const login = Str.isSMSLogin(props.credentials.login) ? Str.removeSMSDomain(props.credentials.login) : props.credentials.login;
const login = useMemo(() => {
if (!credentials?.login) {
return '';
}
return Str.isSMSLogin(credentials.login) ? Str.removeSMSDomain(credentials.login) : credentials.login;
}, [credentials?.login]);

// This view doesn't have a field for user input, so dismiss the device keyboard if shown
useEffect(() => {
Expand All @@ -43,7 +42,7 @@ function EmailDeliveryFailurePage(props) {

return (
<>
<View style={[styles.mv3, styles.flexRow, styles.justifyContentetween]}>
<View style={[styles.mv3, styles.flexRow]}>
<View style={[styles.flex1]}>
<Text>{translate('emailDeliveryFailurePage.ourEmailProvider', {login})}</Text>
<Text style={[styles.mt5]}>
Expand Down Expand Up @@ -89,10 +88,8 @@ function EmailDeliveryFailurePage(props) {
);
}

EmailDeliveryFailurePage.propTypes = propTypes;
EmailDeliveryFailurePage.defaultProps = defaultProps;
EmailDeliveryFailurePage.displayName = 'EmailDeliveryFailurePage';

export default withOnyx({
export default withOnyx<EmailDeliveryFailurePageProps, EmailDeliveryFailurePageOnyxProps>({
credentials: {key: ONYXKEYS.CREDENTIALS},
})(EmailDeliveryFailurePage);
7 changes: 1 addition & 6 deletions src/pages/signin/GoogleSignInDesktopPage/index.website.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ import ThirdPartySignInPage from '@pages/signin/ThirdPartySignInPage';
import CONST from '@src/CONST';

function GoogleSignInDesktopPage() {
return (
<ThirdPartySignInPage
// @ts-expect-error TODO: Remove this once SignIn (https://github.com/Expensify/App/issues/25224) is migrated to TypeScript.
signInProvider={CONST.SIGN_IN_METHOD.GOOGLE}
/>
);
return <ThirdPartySignInPage signInProvider={CONST.SIGN_IN_METHOD.GOOGLE} />;
}

export default GoogleSignInDesktopPage;
12 changes: 6 additions & 6 deletions src/pages/signin/Licenses.js → src/pages/signin/Licenses.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,26 @@ import {View} from 'react-native';
import LocalePicker from '@components/LocalePicker';
import Text from '@components/Text';
import TextLink from '@components/TextLink';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';

const currentYear = new Date().getFullYear();

function Licenses(props) {
function Licenses() {
const styles = useThemeStyles();
const {translate} = useLocalize();
return (
<>
<Text style={[styles.textExtraSmallSupporting, styles.mb4]}>{${currentYear} Expensify`}</Text>
<Text style={[styles.textExtraSmallSupporting]}>
{props.translate('termsOfUse.phrase5')}
{translate('termsOfUse.phrase5')}
<TextLink
style={[styles.textExtraSmallSupporting, styles.link]}
href={CONST.LICENSES_URL}
>
{' '}
{props.translate('termsOfUse.phrase6')}
{translate('termsOfUse.phrase6')}
</TextLink>
.
</Text>
Expand All @@ -32,7 +33,6 @@ function Licenses(props) {
);
}

Licenses.propTypes = {...withLocalizePropTypes};
Licenses.displayName = 'Licenses';

export default withLocalize(Licenses);
export default Licenses;
Loading

0 comments on commit 0b5446b

Please sign in to comment.