Skip to content

Commit

Permalink
chore: Merge 4.49.1 into master (#5731)
Browse files Browse the repository at this point in the history
  • Loading branch information
diegolmello authored Jun 6, 2024
2 parents 9191d47 + 4275a8d commit 1119492
Show file tree
Hide file tree
Showing 30 changed files with 365 additions and 87 deletions.
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode VERSIONCODE as Integer
versionName "4.49.0"
versionName "4.49.1"
vectorDrawables.useSupportLibrary = true
if (!isFoss) {
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useRef } from 'react';
import { StyleSheet, Text, View } from 'react-native';

import { CustomIcon, TIconsName } from '../../CustomIcon';
Expand Down Expand Up @@ -42,22 +42,28 @@ const FooterButtons = ({
confirmTitle = '',
disabled = false,
cancelBackgroundColor = '',
confirmBackgroundColor = ''
confirmBackgroundColor = '',
testID = ''
}): React.ReactElement => {
const { colors } = useTheme();
return (
<View style={styles.footerButtonsContainer}>
<Button
style={[styles.buttonSeparator, { flex: 1, backgroundColor: cancelBackgroundColor || colors.buttonBackgroundSecondaryDefault }]}
style={[
styles.buttonSeparator,
{ flex: 1, backgroundColor: cancelBackgroundColor || colors.buttonBackgroundSecondaryDefault }
]}
color={colors.backdropColor}
title={cancelTitle}
onPress={cancelAction}
testID={`${testID}-cancel`}
/>
<Button
style={{ flex: 1, backgroundColor: confirmBackgroundColor || colors.buttonBackgroundDangerDefault }}
title={confirmTitle}
onPress={confirmAction}
disabled={disabled}
testID={`${testID}-confirm`}
/>
</View>
);
Expand All @@ -76,62 +82,104 @@ const ActionSheetContentWithInputAndSubmit = ({
iconColor,
customText,
confirmBackgroundColor,
showInput = true
showInput = true,
inputs = [],
isDisabled
}: {
onSubmit: (inputValue: string) => void;
onSubmit: (inputValue: string | string[]) => void;
onCancel?: () => void;
title: string;
description: string;
description?: string;
testID: string;
secureTextEntry?: boolean;
placeholder: string;
placeholder?: string;
confirmTitle?: string;
iconName?: TIconsName;
iconColor?: string;
customText?: React.ReactElement;
confirmBackgroundColor?: string;
showInput?: boolean;
inputs?: { placeholder: string; secureTextEntry?: boolean; key: string }[];
isDisabled?: (inputValues: string[]) => boolean;
}): React.ReactElement => {
const { colors } = useTheme();
const [inputValue, setInputValue] = useState('');
const [inputValues, setInputValues] = useState(inputs.map(() => ''));
const inputRefs = useRef(inputs.map(() => React.createRef()));

const handleInputChange = (value: string, index: number) => {
const newInputValues = [...inputValues];
newInputValues[index] = value;
setInputValues(newInputValues);
};

const { hideActionSheet } = useActionSheet();

const renderInputs = () => {
if (inputs.length > 0) {
return inputs.map((inputConfig, index) => (
<FormTextInput
key={inputConfig.key}
value={inputValues[index]}
placeholder={inputConfig.placeholder}
onChangeText={value => handleInputChange(value, index)}
onSubmitEditing={() => {
if (index < inputs.length - 1) {
(inputRefs.current[index + 1] as any).current.focus();
} else {
setTimeout(() => {
hideActionSheet();
}, 100);
if (inputValues.every(value => value)) onSubmit(inputValues);
}
}}
inputRef={inputRefs.current[index] as any}
testID={`${testID}-input-${inputConfig.key}`}
secureTextEntry={inputConfig.secureTextEntry}
bottomSheet={isIOS}
/>
));
}

return (
<FormTextInput
value={inputValues[0]}
placeholder={placeholder}
onChangeText={value => handleInputChange(value, 0)}
onSubmitEditing={() => {
setTimeout(() => {
hideActionSheet();
}, 100);
if (inputValues[0]) onSubmit(inputValues[0]);
}}
testID={`${testID}-input`}
secureTextEntry={secureTextEntry}
bottomSheet={isIOS}
/>
);
};

const defaultDisabled = showInput && inputValues.some(value => !value);
const disabled = isDisabled ? isDisabled(inputValues) : defaultDisabled;

return (
<View style={sharedStyles.containerScrollView} testID='action-sheet-content-with-input-and-submit'>
<>
<View style={styles.titleContainer}>
{iconName ? <CustomIcon name={iconName} size={32} color={iconColor || colors.buttonBackgroundDangerDefault} /> : null}
<Text style={[styles.titleContainerText, { color: colors.fontDefault, paddingLeft: iconName ? 16 : 0 }]}>
{title}
</Text>
<Text style={[styles.titleContainerText, { color: colors.fontDefault, paddingLeft: iconName ? 16 : 0 }]}>{title}</Text>
</View>
<Text style={[styles.subtitleText, { color: colors.fontTitlesLabels }]}>{description}</Text>
{description ? <Text style={[styles.subtitleText, { color: colors.fontTitlesLabels }]}>{description}</Text> : null}
{customText}
</>
{showInput ? (
<FormTextInput
value={inputValue}
placeholder={placeholder}
onChangeText={value => setInputValue(value)}
onSubmitEditing={() => {
// fix android animation
setTimeout(() => {
hideActionSheet();
}, 100);
if (inputValue) onSubmit(inputValue);
}}
testID={testID}
secureTextEntry={secureTextEntry}
bottomSheet={isIOS}
/>
) : null}
{showInput ? renderInputs() : null}
<FooterButtons
confirmBackgroundColor={confirmBackgroundColor || colors.fontHint}
cancelAction={onCancel || hideActionSheet}
confirmAction={() => onSubmit(inputValue)}
confirmAction={() => onSubmit(inputs.length > 0 ? inputValues : inputValues[0])}
cancelTitle={i18n.t('Cancel')}
confirmTitle={confirmTitle || i18n.t('Save')}
disabled={!showInput ? false : !inputValue}
disabled={disabled}
testID={testID}
/>
</View>
);
Expand Down
107 changes: 107 additions & 0 deletions app/containers/ChangePasswordRequired.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React, { useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { useDispatch } from 'react-redux';

import { logout, setUser } from '../actions/login';
import I18n from '../i18n';
import { useSetting } from '../lib/hooks/useSetting';
import { showErrorAlert } from '../lib/methods/helpers';
import { Services } from '../lib/services';
import { useTheme } from '../theme';
import sharedStyles from '../views/Styles';
import { useActionSheet } from './ActionSheet';
import ActionSheetContentWithInputAndSubmit from './ActionSheet/ActionSheetContentWithInputAndSubmit';
import Button from './Button';
import { CustomIcon } from './CustomIcon';

export const ChangePasswordRequired = () => {
const [loading, setLoading] = useState(false);
const { colors } = useTheme();
const dispatch = useDispatch();
const { showActionSheet, hideActionSheet } = useActionSheet();

const requiresPasswordConfirmation = useSetting('Accounts_RequirePasswordConfirmation');
const passwordPlaceholder = useSetting('Accounts_PasswordPlaceholder') as string;
const passwordConfirmationPlaceholder = useSetting('Accounts_ConfirmPasswordPlaceholder') as string;

const changePassword = async (password: string) => {
setLoading(true);
try {
await Services.setUserPassword(password);
dispatch(setUser({ requirePasswordChange: false }));
hideActionSheet();
} catch (error: any) {
showErrorAlert(error?.reason || error?.message, I18n.t('Oops'));
}
setLoading(false);
};

const showActionSheetPassword = () => {
const inputs = [{ placeholder: passwordPlaceholder || I18n.t('Password'), secureTextEntry: true, key: 'password' }];
if (requiresPasswordConfirmation) {
inputs.push({
placeholder: passwordConfirmationPlaceholder || I18n.t('Confirm_your_password'),
secureTextEntry: true,
key: 'confirm-password'
});
}
showActionSheet({
children: (
<ActionSheetContentWithInputAndSubmit
title={I18n.t('Please_Enter_your_new_password')}
testID='change-password-required-sheet'
inputs={inputs}
onSubmit={input => changePassword(input[0])}
isDisabled={input => (loading || input[0] === '' || requiresPasswordConfirmation ? input[0] !== input[1] : false)}
/>
)
});
};

return (
<View style={[styles.container, { paddingTop: 120, backgroundColor: colors.surfaceLight }]}>
<View style={styles.iconContainer}>
<CustomIcon name='info' size={36} color={colors.statusFontWarning} />
</View>
<Text style={[styles.title, { color: colors.fontTitlesLabels }]}>{I18n.t('You_need_to_change_your_password')}</Text>
<Text style={[styles.description, { color: colors.fontDefault }]}>{I18n.t('To_continue_using_RocketChat')}</Text>
<Button
testID='change-password-required-button'
title={I18n.t('Change_password')}
type='primary'
onPress={showActionSheetPassword}
/>
<Button
testID='change-password-required-logout'
title={I18n.t('Logout')}
type='secondary'
backgroundColor={colors.surfaceTint}
onPress={() => dispatch(logout())}
/>
</View>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: '#fff'
},
iconContainer: {
alignItems: 'center',
padding: 24
},
title: {
fontSize: 20,
lineHeight: 30,
marginBottom: 24,
...sharedStyles.textBold
},
description: {
fontSize: 16,
lineHeight: 24,
marginBottom: 24,
...sharedStyles.textRegular
}
});
1 change: 1 addition & 0 deletions app/definitions/ILoggedUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface ILoggedUser {
alsoSendThreadToChannel: 'default' | 'always' | 'never';
bio?: string;
nickname?: string;
requirePasswordChange?: boolean;
}

export interface ILoggedUserResultFromServer
Expand Down
5 changes: 5 additions & 0 deletions app/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"Certificate_password": "Certificate password",
"Change_Language": "Change language",
"Change_language_loading": "Changing language.",
"Change_password": "Change password",
"changed_room_announcement": "changed room announcement to: {{announcement}}",
"changed_room_description": "changed room description to: {{description}}",
"changing_avatar": "changing avatar",
Expand Down Expand Up @@ -127,6 +128,7 @@
"Condensed": "Condensed",
"conference_call": "Conference call",
"Confirm": "Confirm",
"Confirm_your_password": "Confirm your password",
"Confirmation": "Confirmation",
"Connect": "Connect",
"Connecting": "Connecting...",
Expand Down Expand Up @@ -523,6 +525,7 @@
"Pinned_a_message": "Pinned a message:",
"Place_chat_on_hold": "Place chat on hold",
"Please_add_a_comment": "Please add a comment",
"Please_Enter_your_new_password": "Please enter your new password",
"Please_enter_your_password": "Please enter your password",
"Please_wait": "Please wait.",
"Preferences": "Preferences",
Expand Down Expand Up @@ -724,6 +727,7 @@
"Threads_displaying_following": "Displaying following",
"Threads_displaying_unread": "Displaying unread",
"Timezone": "Timezone",
"To_continue_using_RocketChat": "To continue using the mobile app, you need to change your password.",
"Token_expired": "Your session has expired. Please log in again.",
"Topic": "Topic",
"topic": "topic",
Expand Down Expand Up @@ -822,6 +826,7 @@
"You_colon": "You: ",
"You_dont_have_permission_to_perform_this_action": "You don’t have permission to perform this action. Check with a workspace administrator.",
"You_need_to_access_at_least_one_RocketChat_server_to_share_something": "You need to access at least one Rocket.Chat workspace to share something.",
"You_need_to_change_your_password": "You need to change your password",
"You_need_to_verifiy_your_email_address_to_get_notications": "You need to verify your email address to get notifications",
"you_were_mentioned": "you were mentioned",
"You_were_removed_from_channel": "You were removed from {{channel}}",
Expand Down
5 changes: 5 additions & 0 deletions app/i18n/locales/pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"Certificate_password": "Senha do certificado",
"Change_Language": "Alterar idioma",
"Change_language_loading": "Alterando idioma.",
"Change_password": "Alterar senha",
"changed_room_announcement": "alterou o anúncio da sala para: {{announcement}}",
"changed_room_description": "alterou a descrição da sala para: {{description}}",
"changing_avatar": "trocando avatar",
Expand Down Expand Up @@ -124,6 +125,7 @@
"Condensed": "Condensado",
"conference_call": "Video conferência",
"Confirm": "Confirmar",
"Confirm_your_password": "Confirme sua senha",
"Confirmation": "Confirmação",
"Connect": "Conectar",
"Connecting": "Conectando...",
Expand Down Expand Up @@ -515,6 +517,7 @@
"Pinned_a_message": "Fixou uma mensagem:",
"Place_chat_on_hold": "Colocar conversa em espera",
"Please_add_a_comment": "Por favor, adicione um comentário",
"Please_Enter_your_new_password": "Por favor, insira sua nova senha",
"Please_enter_your_password": "Por favor, digite sua senha",
"Please_wait": "Por favor, aguarde.",
"Preferences": "Preferências",
Expand Down Expand Up @@ -713,6 +716,7 @@
"Threads_displaying_following": "Mostrando seguindo",
"Threads_displaying_unread": "Mostrando não lidos",
"Timezone": "Fuso horário",
"To_continue_using_RocketChat": "Para continuar usando o aplicativo móvel, você precisa alterar sua senha.",
"Token_expired": "Sua sessão expirou. Por favor entre novamente.",
"Topic": "Tópico",
"topic": "tópico",
Expand Down Expand Up @@ -810,6 +814,7 @@
"You_colon": "Você: ",
"You_dont_have_permission_to_perform_this_action": "Você não tem permissão para realizar esta ação. Verifique com um administrador do espaço de trabalho.",
"You_need_to_access_at_least_one_RocketChat_server_to_share_something": "Você precisa acessar pelo menos uma workspace Rocket.Chat para compartilhar.",
"You_need_to_change_your_password": "Você precisa alterar sua senha",
"You_need_to_verifiy_your_email_address_to_get_notications": "Você precisa confirmar seu endereço de e-mail para obter notificações",
"you_were_mentioned": "você foi mencionado",
"You_were_removed_from_channel": "Você foi removido de {{channel}}",
Expand Down
12 changes: 6 additions & 6 deletions app/i18n/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -628,12 +628,12 @@
"Uploading": "Загрузка",
"Use": "Использовать",
"User": "Пользователь",
"User__username__is_now_a_leader_of__room_name_": "Пользователь {{username}} больше не лидер в чате {{room_name}}",
"User__username__is_now_a_moderator_of__room_name_": "Пользователь {{username}} больше не модератор в чате {{room_name}}",
"User__username__is_now_a_owner_of__room_name_": "Пользователь {{username}} больше не владелец в чате {{room_name}}",
"User__username__removed_from__room_name__leaders": "Пользователь {{username}} удален из {{room_name}} лидеров",
"User__username__removed_from__room_name__moderators": "Пользователь {{username}} удален из {{room_name}} модераторов",
"User__username__removed_from__room_name__owners": "Пользователь {{username}} удален из {{room_name}} владельцев",
"User__username__is_now_a_leader_of__room_name_": "Пользователь {{username}} теперь лидер в чате {{room_name}}",
"User__username__is_now_a_moderator_of__room_name_": "Пользователь {{username}} теперь модератор в чате {{room_name}}",
"User__username__is_now_a_owner_of__room_name_": "Пользователь {{username}} теперь владелец в чате {{room_name}}",
"User__username__removed_from__room_name__leaders": "Пользователь {{username}} удален из лидеров чата {{room_name}}",
"User__username__removed_from__room_name__moderators": "Пользователь {{username}} удален из модераторов чата {{room_name}}",
"User__username__removed_from__room_name__owners": "Пользователь {{username}} удален из владельцев чата {{room_name}}",
"User_has_been_ignored": "Пользователь теперь игнорируется",
"User_has_been_key": "Пользователь был {{key}}",
"User_has_been_removed_from_s": "Пользователь удален из {{s}}",
Expand Down
Loading

0 comments on commit 1119492

Please sign in to comment.