Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [#173190756] Update profile on language selection #2184

Merged
merged 3 commits into from
Sep 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 58 additions & 11 deletions ts/screens/profile/LanguagesPreferencesScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { List } from "native-base";
import * as pot from "italia-ts-commons/lib/pot";
import * as React from "react";
import { Alert } from "react-native";
import { connect } from "react-redux";
import { fromNullable } from "fp-ts/lib/Option";
import { Locales, TranslationKeys } from "../../../locales/locales";
import { withLightModalContext } from "../../components/helpers/withLightModalContext";
import { ContextualHelpPropsMarkdown } from "../../components/screens/BaseScreenComponent";
Expand All @@ -15,12 +17,21 @@ import { preferredLanguageSaveSuccess } from "../../store/actions/persistedPrefe
import { Dispatch } from "../../store/actions/types";
import { preferredLanguageSelector } from "../../store/reducers/persistedPreferences";
import { GlobalState } from "../../store/reducers/types";
import { getLocalePrimaryWithFallback } from "../../utils/locale";
import {
fromLocaleToPreferredLanguage,
getLocalePrimaryWithFallback
} from "../../utils/locale";
import { profileUpsert } from "../../store/actions/profile";
import { withLoadingSpinner } from "../../components/helpers/withLoadingSpinner";
import { profileSelector } from "../../store/reducers/profile";
import { showToast } from "../../utils/showToast";

type Props = LightModalContextInterface &
ReturnType<typeof mapDispatchToProps> &
ReturnType<typeof mapStateToProps>;

type State = { isLoading: boolean; selectedLocale?: Locales };

const contextualHelpMarkdown: ContextualHelpPropsMarkdown = {
title: "profile.preferences.language.contextualHelpTitle",
body: "profile.preferences.language.contextualHelpContent"
Expand All @@ -31,13 +42,17 @@ const iconSize = 12;
/**
* Allows the user to select one of the available Languages as preferred
*/
class LanguagesPreferencesScreen extends React.PureComponent<Props> {
private isAlreadyPreferred = (language: Locales) =>
class LanguagesPreferencesScreen extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = { isLoading: false };
}

private isAlreadyPreferred = (language: Locales) =>
// if the preferred Lanuage is not set, we check if language is the same in use
this.props.preferredLanguage
this.props.preferredLanguage
.map(l => l === language)
.getOrElse(getLocalePrimaryWithFallback() === language)
;
.getOrElse(getLocalePrimaryWithFallback() === language);

private onLanguageSelected = (language: Locales) => {
if (!this.isAlreadyPreferred(language)) {
Expand All @@ -56,8 +71,9 @@ class LanguagesPreferencesScreen extends React.PureComponent<Props> {
text: I18n.t("global.buttons.confirm"),
style: "default",
onPress: () => {
this.props.preferredLanguageSaveSuccess(language);
this.showModal();
this.setState({ selectedLocale: language }, () => {
this.props.upsertProfile(language);
});
}
}
],
Expand All @@ -66,6 +82,29 @@ class LanguagesPreferencesScreen extends React.PureComponent<Props> {
}
};

public componentDidUpdate(prevProps: Readonly<Props>) {
// start updating
if (pot.isUpdating(this.props.profile)) {
this.setState({ isLoading: true });
return;
}

// update completed
if (pot.isUpdating(prevProps.profile) && pot.isSome(this.props.profile)) {
this.setState({ isLoading: false });
fromNullable(this.state.selectedLocale).map(
this.props.preferredLanguageSaveSuccess
);
this.showModal();
return;
}

// update error
if (pot.isUpdating(prevProps.profile) && pot.isError(this.props.profile)) {
showToast(I18n.t("errors.profileUpdateError"));
}
}

private showModal() {
this.props.showModal(
<AlertModal
Expand All @@ -75,7 +114,7 @@ class LanguagesPreferencesScreen extends React.PureComponent<Props> {
}

public render() {
return (
const ContainerComponent = withLoadingSpinner(() => (
<TopScreenComponent
contextualHelpMarkdown={contextualHelpMarkdown}
headerTitle={I18n.t("profile.preferences.title")}
Expand Down Expand Up @@ -114,12 +153,14 @@ class LanguagesPreferencesScreen extends React.PureComponent<Props> {
</List>
</ScreenContent>
</TopScreenComponent>
);
));
return <ContainerComponent isLoading={this.state.isLoading} />;
}
}

const mapStateToProps = (state: GlobalState) => ({
preferredLanguage: preferredLanguageSelector(state)
preferredLanguage: preferredLanguageSelector(state),
profile: profileSelector(state)
});

const mapDispatchToProps = (dispatch: Dispatch) => ({
Expand All @@ -128,6 +169,12 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
preferredLanguageSaveSuccess({
preferredLanguage: language
})
),
upsertProfile: (language: Locales) =>
dispatch(
profileUpsert.request({
preferred_languages: [fromLocaleToPreferredLanguage(language)]
})
)
});

Expand Down
3 changes: 1 addition & 2 deletions ts/store/actions/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
createAsyncAction,
createStandardAction
} from "typesafe-actions";
import { ExtendedProfile } from "../../../definitions/backend/ExtendedProfile";
import { InitializedProfile } from "../../../definitions/backend/InitializedProfile";

export const resetProfileState = createStandardAction("RESET_PROFILE_STATE")();
Expand All @@ -27,7 +26,7 @@ export const profileLoadFailure = createAction(
resolve => (error: Error) => resolve(error, { error: true })
);

type ProfileUpsertPayload = Partial<Omit<ExtendedProfile, "version">>;
type ProfileUpsertPayload = Partial<Omit<InitializedProfile, "version">>;

export const profileUpsert = createAsyncAction(
"PROFILE_UPSERT_REQUEST",
Expand Down
16 changes: 15 additions & 1 deletion ts/utils/locale.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Option, some } from "fp-ts/lib/Option";
import { fromNullable, Option, some } from "fp-ts/lib/Option";
import { Locales } from "../../locales/locales";
import I18n, { translations } from "../i18n";
import { PreferredLanguageEnum } from "../../definitions/backend/PreferredLanguage";
/**
* Helpers for handling locales
*/
Expand Down Expand Up @@ -33,3 +34,16 @@ export const getLocalePrimaryWithFallback = (fallback: Locales = "en") =>
.filter(l => translations.some(t => t.toLowerCase() === l.toLowerCase()))
.map(s => s as Locales)
.getOrElse(fallback);

const localePreferredLanguageMapping = new Map<Locales, PreferredLanguageEnum>([
["it", PreferredLanguageEnum.it_IT],
["en", PreferredLanguageEnum.en_GB]
]);

// from a given Locales return the relative PreferredLanguageEnum (fallback is en_GB)
export const fromLocaleToPreferredLanguage = (
locale: Locales
): PreferredLanguageEnum =>
fromNullable(localePreferredLanguageMapping.get(locale)).getOrElse(
PreferredLanguageEnum.en_GB
);