Skip to content

Commit

Permalink
Merge pull request #34502 from s-alves10/refactor/issue-31999
Browse files Browse the repository at this point in the history
[TS migration] Migrate 'TeachersUnite' page to TypeScript
  • Loading branch information
puneetlath committed Jan 22, 2024
2 parents b1c49db + 3e0c5ec commit f3111a4
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 98 deletions.
Original file line number Diff line number Diff line change
@@ -1,35 +1,26 @@
import PropTypes from 'prop-types';
import React from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import * as LoginUtils from '@libs/LoginUtils';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Session} from '@src/types/onyx';
import ImTeacherUpdateEmailPage from './ImTeacherUpdateEmailPage';
import IntroSchoolPrincipalPage from './IntroSchoolPrincipalPage';

const propTypes = {
/** Current user session */
session: PropTypes.shape({
/** Current user primary login */
email: PropTypes.string.isRequired,
}),
type ImTeacherPageOnyxProps = {
session: OnyxEntry<Session>;
};

const defaultProps = {
session: {
email: null,
},
};
type ImTeacherPageProps = ImTeacherPageOnyxProps;

function ImTeacherPage(props) {
const isLoggedInEmailPublicDomain = LoginUtils.isEmailPublicDomain(props.session.email);
function ImTeacherPage(props: ImTeacherPageProps) {
const isLoggedInEmailPublicDomain = LoginUtils.isEmailPublicDomain(props.session?.email ?? '');
return isLoggedInEmailPublicDomain ? <ImTeacherUpdateEmailPage /> : <IntroSchoolPrincipalPage />;
}

ImTeacherPage.propTypes = propTypes;
ImTeacherPage.defaultProps = defaultProps;
ImTeacherPage.displayName = 'ImTeacherPage';

export default withOnyx({
export default withOnyx<ImTeacherPageProps, ImTeacherPageOnyxProps>({
session: {
key: ONYXKEYS.SESSION,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ import Navigation from '@libs/Navigation/Navigation';
import variables from '@styles/variables';
import ROUTES from '@src/ROUTES';

const propTypes = {};

const defaultProps = {};

function ImTeacherUpdateEmailPage() {
const styles = useThemeStyles();
const {translate} = useLocalize();
Expand Down Expand Up @@ -49,8 +45,6 @@ function ImTeacherUpdateEmailPage() {
);
}

ImTeacherUpdateEmailPage.propTypes = propTypes;
ImTeacherUpdateEmailPage.defaultProps = defaultProps;
ImTeacherUpdateEmailPage.displayName = 'ImTeacherUpdateEmailPage';

export default ImTeacherUpdateEmailPage;
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import type {OnyxEntry} from 'react-native-onyx/lib/types';
import FormProvider from '@components/Form/FormProvider';
import InputWrapper from '@components/Form/InputWrapper';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
Expand All @@ -22,71 +20,66 @@ import TeachersUnite from '@userActions/TeachersUnite';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {LoginList} from '@src/types/onyx';

const propTypes = {
/** Login list for the user that is signed in */
loginList: PropTypes.shape({
/** Phone/Email associated with user */
partnerUserID: PropTypes.string,
}),
type IntroSchoolPrincipalFormData = {
firstName: string;
lastName: string;
partnerUserID: string;
};

const defaultProps = {
loginList: {},
type IntroSchoolPrincipalPageOnyxProps = {
loginList: OnyxEntry<LoginList>;
};

function IntroSchoolPrincipalPage(props) {
type IntroSchoolPrincipalPageProps = IntroSchoolPrincipalPageOnyxProps;

function IntroSchoolPrincipalPage(props: IntroSchoolPrincipalPageProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const {isProduction} = useEnvironment();

/**
* @param {Object} values
* @param {String} values.firstName
* @param {String} values.partnerUserID
* @param {String} values.lastName
* Submit form to pass firstName, partnerUserID and lastName
*/
const onSubmit = (values) => {
const onSubmit = (values: IntroSchoolPrincipalFormData) => {
const policyID = isProduction ? CONST.TEACHERS_UNITE.PROD_POLICY_ID : CONST.TEACHERS_UNITE.TEST_POLICY_ID;
TeachersUnite.addSchoolPrincipal(values.firstName.trim(), values.partnerUserID.trim(), values.lastName.trim(), policyID);
};

/**
* @param {Object} values
* @param {String} values.firstName
* @param {String} values.partnerUserID
* @returns {Object} - An object containing the errors for each inputID
* @returns - An object containing the errors for each inputID
*/
const validate = useCallback(
(values) => {
(values: IntroSchoolPrincipalFormData) => {
const errors = {};

if (!ValidationUtils.isValidLegalName(values.firstName)) {
ErrorUtils.addErrorMessage(errors, 'firstName', translate('privatePersonalDetails.error.hasInvalidCharacter'));
} else if (_.isEmpty(values.firstName)) {
ErrorUtils.addErrorMessage(errors, 'firstName', translate('bankAccount.error.firstName'));
ErrorUtils.addErrorMessage(errors, 'firstName', 'privatePersonalDetails.error.hasInvalidCharacter');
} else if (!values.firstName) {
ErrorUtils.addErrorMessage(errors, 'firstName', 'bankAccount.error.firstName');
}
if (!ValidationUtils.isValidLegalName(values.lastName)) {
ErrorUtils.addErrorMessage(errors, 'lastName', translate('privatePersonalDetails.error.hasInvalidCharacter'));
} else if (_.isEmpty(values.lastName)) {
ErrorUtils.addErrorMessage(errors, 'lastName', translate('bankAccount.error.lastName'));
ErrorUtils.addErrorMessage(errors, 'lastName', 'privatePersonalDetails.error.hasInvalidCharacter');
} else if (!values.lastName) {
ErrorUtils.addErrorMessage(errors, 'lastName', 'bankAccount.error.lastName');
}
if (_.isEmpty(values.partnerUserID)) {
ErrorUtils.addErrorMessage(errors, 'partnerUserID', translate('teachersUnitePage.error.enterEmail'));
if (!values.partnerUserID) {
ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'teachersUnitePage.error.enterEmail');
}
if (!_.isEmpty(values.partnerUserID) && lodashGet(props.loginList, values.partnerUserID.toLowerCase())) {
if (values.partnerUserID && props.loginList?.[values.partnerUserID.toLowerCase()]) {
ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'teachersUnitePage.error.tryDifferentEmail');
}
if (!_.isEmpty(values.partnerUserID) && !Str.isValidEmail(values.partnerUserID)) {
ErrorUtils.addErrorMessage(errors, 'partnerUserID', translate('teachersUnitePage.error.enterValidEmail'));
if (values.partnerUserID && !Str.isValidEmail(values.partnerUserID)) {
ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'teachersUnitePage.error.enterValidEmail');
}
if (!_.isEmpty(values.partnerUserID) && LoginUtils.isEmailPublicDomain(values.partnerUserID)) {
ErrorUtils.addErrorMessage(errors, 'partnerUserID', translate('teachersUnitePage.error.tryDifferentEmail'));
if (values.partnerUserID && LoginUtils.isEmailPublicDomain(values.partnerUserID)) {
ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'teachersUnitePage.error.tryDifferentEmail');
}

return errors;
},
[props.loginList, translate],
[props.loginList],
);

return (
Expand All @@ -98,6 +91,7 @@ function IntroSchoolPrincipalPage(props) {
title={translate('teachersUnitePage.introSchoolPrincipal')}
onBackButtonPress={() => Navigation.goBack(ROUTES.TEACHERS_UNITE)}
/>
{/* @ts-expect-error TODO: Remove this once FormProvider (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript. */}
<FormProvider
enabledWhenOffline
style={[styles.flexGrow1, styles.ph5]}
Expand All @@ -109,6 +103,7 @@ function IntroSchoolPrincipalPage(props) {
<Text style={[styles.mb6]}>{translate('teachersUnitePage.schoolPrincipalVerfiyExpense')}</Text>
<View>
<InputWrapper
// @ts-expect-error TODO: Remove this once InputWrapper (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript.
InputComponent={TextInput}
inputID="firstName"
name="firstName"
Expand All @@ -121,6 +116,7 @@ function IntroSchoolPrincipalPage(props) {
</View>
<View style={styles.mv4}>
<InputWrapper
// @ts-expect-error TODO: Remove this once InputWrapper (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript.
InputComponent={TextInput}
inputID="lastName"
name="lastName"
Expand All @@ -133,6 +129,7 @@ function IntroSchoolPrincipalPage(props) {
</View>
<View>
<InputWrapper
// @ts-expect-error TODO: Remove this once InputWrapper (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript.
InputComponent={TextInput}
inputID="partnerUserID"
name="partnerUserID"
Expand All @@ -148,10 +145,8 @@ function IntroSchoolPrincipalPage(props) {
);
}

IntroSchoolPrincipalPage.propTypes = propTypes;
IntroSchoolPrincipalPage.defaultProps = defaultProps;
IntroSchoolPrincipalPage.displayName = 'IntroSchoolPrincipalPage';

export default withOnyx({
export default withOnyx<IntroSchoolPrincipalPageProps, IntroSchoolPrincipalPageOnyxProps>({
loginList: {key: ONYXKEYS.LOGIN_LIST},
})(IntroSchoolPrincipalPage);
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import type {OnyxEntry} from 'react-native-onyx/lib/types';
import FormProvider from '@components/Form/FormProvider';
import InputWrapper from '@components/Form/InputWrapper';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
Expand All @@ -22,32 +20,29 @@ import TeachersUnite from '@userActions/TeachersUnite';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {LoginList} from '@src/types/onyx';

const propTypes = {
/** Login list for the user that is signed in */
loginList: PropTypes.shape({
/** Phone/Email associated with user */
partnerUserID: PropTypes.string,
}),
type KnowATeacherFormData = {
firstName: string;
lastName: string;
partnerUserID: string;
};

const defaultProps = {
loginList: {},
type KnowATeacherPageOnyxProps = {
loginList: OnyxEntry<LoginList>;
};

function KnowATeacherPage(props) {
type KnowATeacherPageProps = KnowATeacherPageOnyxProps;

function KnowATeacherPage(props: KnowATeacherPageProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const {isProduction} = useEnvironment();

/**
* Submit form to pass firstName, partnerUserID and lastName
* @param {Object} values
* @param {String} values.partnerUserID
* @param {String} values.firstName
* @param {String} values.lastName
*/
const onSubmit = (values) => {
const onSubmit = (values: KnowATeacherFormData) => {
const phoneLogin = LoginUtils.getPhoneLogin(values.partnerUserID);
const validateIfnumber = LoginUtils.validateNumber(phoneLogin);
const contactMethod = (validateIfnumber || values.partnerUserID).trim().toLowerCase();
Expand All @@ -60,40 +55,37 @@ function KnowATeacherPage(props) {
};

/**
* @param {Object} values
* @param {String} values.firstName
* @param {String} values.partnerUserID
* @returns {Object} - An object containing the errors for each inputID
* @returns - An object containing the errors for each inputID
*/
const validate = useCallback(
(values) => {
(values: KnowATeacherFormData) => {
const errors = {};
const phoneLogin = LoginUtils.getPhoneLogin(values.partnerUserID);
const validateIfnumber = LoginUtils.validateNumber(phoneLogin);

if (!ValidationUtils.isValidLegalName(values.firstName)) {
ErrorUtils.addErrorMessage(errors, 'firstName', translate('privatePersonalDetails.error.hasInvalidCharacter'));
} else if (_.isEmpty(values.firstName)) {
ErrorUtils.addErrorMessage(errors, 'firstName', translate('bankAccount.error.firstName'));
ErrorUtils.addErrorMessage(errors, 'firstName', 'privatePersonalDetails.error.hasInvalidCharacter');
} else if (!values.firstName) {
ErrorUtils.addErrorMessage(errors, 'firstName', 'bankAccount.error.firstName');
}
if (!ValidationUtils.isValidLegalName(values.lastName)) {
ErrorUtils.addErrorMessage(errors, 'lastName', translate('privatePersonalDetails.error.hasInvalidCharacter'));
} else if (_.isEmpty(values.lastName)) {
ErrorUtils.addErrorMessage(errors, 'lastName', translate('bankAccount.error.lastName'));
ErrorUtils.addErrorMessage(errors, 'lastName', 'privatePersonalDetails.error.hasInvalidCharacter');
} else if (!values.lastName) {
ErrorUtils.addErrorMessage(errors, 'lastName', 'bankAccount.error.lastName');
}
if (_.isEmpty(values.partnerUserID)) {
ErrorUtils.addErrorMessage(errors, 'partnerUserID', translate('teachersUnitePage.error.enterPhoneEmail'));
if (!values.partnerUserID) {
ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'teachersUnitePage.error.enterPhoneEmail');
}
if (!_.isEmpty(values.partnerUserID) && lodashGet(props.loginList, validateIfnumber || values.partnerUserID.toLowerCase())) {
if (values.partnerUserID && props.loginList?.[validateIfnumber || values.partnerUserID.toLowerCase()]) {
ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'teachersUnitePage.error.tryDifferentEmail');
}
if (!_.isEmpty(values.partnerUserID) && !(validateIfnumber || Str.isValidEmail(values.partnerUserID))) {
if (values.partnerUserID && !(validateIfnumber || Str.isValidEmail(values.partnerUserID))) {
ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'contacts.genericFailureMessages.invalidContactMethod');
}

return errors;
},
[props.loginList, translate],
[props.loginList],
);

return (
Expand All @@ -105,6 +97,7 @@ function KnowATeacherPage(props) {
title={translate('teachersUnitePage.iKnowATeacher')}
onBackButtonPress={() => Navigation.goBack(ROUTES.TEACHERS_UNITE)}
/>
{/* @ts-expect-error TODO: Remove this once FormProvider (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript. */}
<FormProvider
enabledWhenOffline
style={[styles.flexGrow1, styles.ph5]}
Expand All @@ -116,6 +109,7 @@ function KnowATeacherPage(props) {
<Text style={[styles.mb6]}>{translate('teachersUnitePage.getInTouch')}</Text>
<View>
<InputWrapper
// @ts-expect-error TODO: Remove this once InputWrapper (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript.
InputComponent={TextInput}
inputID="firstName"
name="fname"
Expand All @@ -128,6 +122,7 @@ function KnowATeacherPage(props) {
</View>
<View style={styles.mv4}>
<InputWrapper
// @ts-expect-error TODO: Remove this once InputWrapper (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript.
InputComponent={TextInput}
inputID="lastName"
name="lname"
Expand All @@ -140,6 +135,7 @@ function KnowATeacherPage(props) {
</View>
<View>
<InputWrapper
// @ts-expect-error TODO: Remove this once InputWrapper (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript.
InputComponent={TextInput}
inputID="partnerUserID"
name="partnerUserID"
Expand All @@ -155,10 +151,8 @@ function KnowATeacherPage(props) {
);
}

KnowATeacherPage.propTypes = propTypes;
KnowATeacherPage.defaultProps = defaultProps;
KnowATeacherPage.displayName = 'KnowATeacherPage';

export default withOnyx({
export default withOnyx<KnowATeacherPageProps, KnowATeacherPageOnyxProps>({
loginList: {key: ONYXKEYS.LOGIN_LIST},
})(KnowATeacherPage);
File renamed without changes.

0 comments on commit f3111a4

Please sign in to comment.