diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 4eb625affacd..f45e259b7b57 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -8454,6 +8454,12 @@ const CONST = { RESEND_CODE: 'ValidateCode-ResendCode', RECOVERY_CODE: 'ValidateCode-RecoveryCode', }, + INTERACTIVE_STEP_SUB_HEADER: { + STEP_BUTTON: 'InteractiveStepSubHeader-StepButton', + }, + SOCIALS: { + LINK: 'Socials', + }, }, DOMAIN: { diff --git a/src/components/InteractiveStepSubHeader.tsx b/src/components/InteractiveStepSubHeader.tsx index 387eb031a73f..de38723de3ba 100644 --- a/src/components/InteractiveStepSubHeader.tsx +++ b/src/components/InteractiveStepSubHeader.tsx @@ -2,6 +2,7 @@ import type {ForwardedRef} from 'react'; import React, {useImperativeHandle, useState} from 'react'; import type {ViewStyle} from 'react-native'; import {View} from 'react-native'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import colors from '@styles/theme/colors'; import variables from '@styles/variables'; @@ -41,6 +42,7 @@ const MIN_AMOUNT_OF_STEPS = 2; function InteractiveStepSubHeader({stepNames, startStepIndex = 0, onStepSelected, ref}: InteractiveStepSubHeaderProps) { const styles = useThemeStyles(); + const {translate} = useLocalize(); const containerWidthStyle: ViewStyle = stepNames.length < MIN_AMOUNT_FOR_EXPANDING ? styles.mnw60 : styles.mnw100; if (stepNames.length < MIN_AMOUNT_OF_STEPS) { @@ -67,7 +69,11 @@ function InteractiveStepSubHeader({stepNames, startStepIndex = 0, onStepSelected const amountOfUnions = stepNames.length - 1; return ( - + {stepNames.map((stepName, index) => { const isCompletedStep = currentStep > index; const isLockedStep = currentStep < index; @@ -99,10 +105,10 @@ function InteractiveStepSubHeader({stepNames, startStepIndex = 0, onStepSelected ]} disabled={isLockedStep || !onStepSelected} onPress={moveToStep} - accessible - accessibilityLabel={`${index + 1}`} - aria-current={currentStep === index ? 'step' : undefined} + accessible={false} + aria-hidden role={CONST.ROLE.BUTTON} + sentryLabel={CONST.SENTRY_LABEL.INTERACTIVE_STEP_SUB_HEADER.STEP_BUTTON} > {isCompletedStep ? ( = { nameEmailOrPhoneNumber: 'Name, E-Mail-Adresse oder Telefonnummer', findMember: 'Mitglied finden', searchForSomeone: 'Nach jemandem suchen', + userSelected: (username: string) => `${username} ausgewählt`, }, customApprovalWorkflow: { title: 'Benutzerdefinierter Genehmigungsworkflow', @@ -3081,10 +3082,7 @@ ${ detailsPage: { localTime: 'Ortszeit', }, - newChatPage: { - startGroup: 'Gruppe starten', - addToGroup: 'Zur Gruppe hinzufügen', - }, + newChatPage: {startGroup: 'Gruppe starten', addToGroup: 'Zur Gruppe hinzufügen', addUserToGroup: (username: string) => `${username} zur Gruppe hinzufügen`}, yearPickerPage: { year: 'Jahr', selectYear: 'Bitte ein Jahr auswählen', @@ -6531,6 +6529,7 @@ Fordern Sie Spesendetails wie Belege und Beschreibungen an, legen Sie Limits und symbols: 'Symbole', flags: 'Markierungen', }, + emojiNotSelected: 'Emoji nicht ausgewählt', }, newRoomPage: { newRoom: 'Neuer Raum', diff --git a/src/languages/en.ts b/src/languages/en.ts index 86de05f1f00a..605e3a8b1240 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -791,6 +791,7 @@ const translations = { nameEmailOrPhoneNumber: 'Name, email, or phone number', findMember: 'Find a member', searchForSomeone: 'Search for someone', + userSelected: (username: string) => `${username} selected`, }, customApprovalWorkflow: { title: 'Custom approval workflow', @@ -3105,6 +3106,7 @@ const translations = { newChatPage: { startGroup: 'Start group', addToGroup: 'Add to group', + addUserToGroup: (username: string) => `Add ${username} to group`, }, yearPickerPage: { year: 'Year', @@ -6453,6 +6455,7 @@ const translations = { onboardingHelp: 'Onboarding help', }, emojiPicker: { + emojiNotSelected: 'Emoji not selected', skinTonePickerLabel: 'Change default skin tone', headers: { frequentlyUsed: 'Frequently Used', diff --git a/src/languages/es.ts b/src/languages/es.ts index cfbd934aa1dd..c241176a54fa 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -562,6 +562,7 @@ const translations: TranslationDeepObject = { nameEmailOrPhoneNumber: 'Nombre, correo electrónico o número de teléfono', findMember: 'Encuentra un miembro', searchForSomeone: 'Busca a alguien', + userSelected: (username: string) => `${username} seleccionado`, }, customApprovalWorkflow: { title: 'Flujo de aprobación personalizado', @@ -2852,6 +2853,7 @@ ${amount} para ${merchant} - ${date}`, newChatPage: { startGroup: 'Crear grupo', addToGroup: 'Añadir al grupo', + addUserToGroup: (username: string) => `Añadir ${username} al grupo`, }, yearPickerPage: { year: 'Año', @@ -6242,6 +6244,7 @@ ${amount} para ${merchant} - ${date}`, onboardingHelp: 'Ayuda de incorporación', }, emojiPicker: { + emojiNotSelected: 'Emoji no seleccionado', skinTonePickerLabel: 'Elige el tono de piel por defecto', headers: { frequentlyUsed: 'Usado frecuentemente', diff --git a/src/languages/fr.ts b/src/languages/fr.ts index fa05ed6c5fb8..7d8a7ee4fd19 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -779,6 +779,7 @@ const translations: TranslationDeepObject = { nameEmailOrPhoneNumber: 'Nom, e-mail ou numéro de téléphone', findMember: 'Trouver un membre', searchForSomeone: 'Rechercher une personne', + userSelected: (username: string) => `${username} sélectionné`, }, customApprovalWorkflow: { title: 'Workflow d’approbation personnalisé', @@ -3090,6 +3091,7 @@ ${ newChatPage: { startGroup: 'Commencer le groupe', addToGroup: 'Ajouter au groupe', + addUserToGroup: (username: string) => `Ajouter ${username} au groupe`, }, yearPickerPage: { year: 'Année', @@ -6552,6 +6554,7 @@ Rendez obligatoires des informations de dépense comme les reçus et les descrip symbols: 'Symboles', flags: 'Drapeaux', }, + emojiNotSelected: 'Emoji non sélectionné', }, newRoomPage: { newRoom: 'Nouvelle salle', diff --git a/src/languages/it.ts b/src/languages/it.ts index 62414a798278..f0bfe272d8dd 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -776,6 +776,7 @@ const translations: TranslationDeepObject = { nameEmailOrPhoneNumber: 'Nome, email o numero di telefono', findMember: 'Trova un membro', searchForSomeone: 'Cerca qualcuno', + userSelected: (username: string) => `${username} selezionato`, }, customApprovalWorkflow: { title: 'Flusso di approvazione personalizzato', @@ -3071,10 +3072,7 @@ ${ detailsPage: { localTime: 'Ora locale', }, - newChatPage: { - startGroup: 'Avvia gruppo', - addToGroup: 'Aggiungi al gruppo', - }, + newChatPage: {startGroup: 'Avvia gruppo', addToGroup: 'Aggiungi al gruppo', addUserToGroup: (username: string) => `Aggiungi ${username} al gruppo`}, yearPickerPage: { year: 'Anno', selectYear: 'Seleziona un anno', @@ -6515,6 +6513,7 @@ Richiedi dettagli sulle spese come ricevute e descrizioni, imposta limiti e valo symbols: 'Simboli', flags: 'Segnalazioni', }, + emojiNotSelected: 'Emoji non selezionata', }, newRoomPage: { newRoom: 'Nuova stanza', diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 5b6847321fab..7248b5b5fbe2 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -772,6 +772,7 @@ const translations: TranslationDeepObject = { nameEmailOrPhoneNumber: '名前、メールアドレス、または電話番号', findMember: 'メンバーを検索', searchForSomeone: '誰かを検索', + userSelected: (username: string) => `${username} 選択された`, }, customApprovalWorkflow: { title: 'カスタム承認ワークフロー', @@ -3058,10 +3059,7 @@ ${ detailsPage: { localTime: '現地時間', }, - newChatPage: { - startGroup: 'グループを開始', - addToGroup: 'グループに追加', - }, + newChatPage: {startGroup: 'グループを開始', addToGroup: 'グループに追加', addUserToGroup: (username: string) => `${username} をグループに追加`}, yearPickerPage: { year: '年', selectYear: '年を選択してください', @@ -6461,6 +6459,7 @@ ${reportName} symbols: '記号', flags: 'フラグ', }, + emojiNotSelected: '絵文字が選択されていません', }, newRoomPage: { newRoom: '新しいルーム', diff --git a/src/languages/nl.ts b/src/languages/nl.ts index a6d424ad4d07..d3565b80bc36 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -775,6 +775,7 @@ const translations: TranslationDeepObject = { nameEmailOrPhoneNumber: 'Naam, e-mail of telefoonnummer', findMember: 'Lid zoeken', searchForSomeone: 'Iemand zoeken', + userSelected: (username: string) => `${username} geselecteerd`, }, customApprovalWorkflow: { title: 'Aangepaste goedkeuringsworkflow', @@ -3072,10 +3073,7 @@ ${ detailsPage: { localTime: 'Lokale tijd', }, - newChatPage: { - startGroup: 'Groep starten', - addToGroup: 'Aan groep toevoegen', - }, + newChatPage: {startGroup: 'Groep starten', addToGroup: 'Aan groep toevoegen', addUserToGroup: (username: string) => `${username} aan groep toevoegen`}, yearPickerPage: { year: 'Jaar', selectYear: 'Selecteer een jaar', @@ -6503,6 +6501,7 @@ Vereis onkostendetails zoals bonnen en beschrijvingen, stel limieten en standaar symbols: 'Symbolen', flags: 'Vlaggen', }, + emojiNotSelected: 'Emoji niet geselecteerd', }, newRoomPage: { newRoom: 'Nieuwe ruimte', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index c89befddfd28..cc7218d1f589 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -776,6 +776,7 @@ const translations: TranslationDeepObject = { nameEmailOrPhoneNumber: 'Imię i nazwisko, e-mail lub numer telefonu', findMember: 'Znajdź członka', searchForSomeone: 'Wyszukaj osobę', + userSelected: (username: string) => `Wybrano: ${username}`, }, customApprovalWorkflow: { title: 'Niestandardowy przepływ zatwierdzania', @@ -3064,10 +3065,7 @@ ${ detailsPage: { localTime: 'Czas lokalny', }, - newChatPage: { - startGroup: 'Rozpocznij grupę', - addToGroup: 'Dodaj do grupy', - }, + newChatPage: {startGroup: 'Rozpocznij grupę', addToGroup: 'Dodaj do grupy', addUserToGroup: (username: string) => `Dodaj ${username} do grupy`}, yearPickerPage: { year: 'Rok', selectYear: 'Wybierz rok', @@ -6493,6 +6491,7 @@ Wymagaj szczegółów wydatków, takich jak paragony i opisy, ustawiaj limity i symbols: 'Symbole', flags: 'Flagi', }, + emojiNotSelected: 'Nie wybrano emotikony', }, newRoomPage: { newRoom: 'Nowy pokój', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index bc9eb8065018..14b18c3e4444 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -775,6 +775,7 @@ const translations: TranslationDeepObject = { nameEmailOrPhoneNumber: 'Nome, e-mail ou número de telefone', findMember: 'Encontrar membro', searchForSomeone: 'Buscar alguém', + userSelected: (username: string) => `${username} selecionado`, }, customApprovalWorkflow: { title: 'Fluxo de aprovação personalizado', @@ -3064,10 +3065,7 @@ ${ detailsPage: { localTime: 'Hora local', }, - newChatPage: { - startGroup: 'Iniciar grupo', - addToGroup: 'Adicionar ao grupo', - }, + newChatPage: {startGroup: 'Iniciar grupo', addToGroup: 'Adicionar ao grupo', addUserToGroup: (username: string) => `Adicionar ${username} ao grupo`}, yearPickerPage: { year: 'Ano', selectYear: 'Selecione um ano', @@ -6497,6 +6495,7 @@ Exija dados de despesas como recibos e descrições, defina limites e padrões e symbols: 'Símbolos', flags: 'Bandeiras', }, + emojiNotSelected: 'Emoji não selecionado', }, newRoomPage: { newRoom: 'Nova sala', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 94d1d9cccc25..7e3ccb3340cf 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -767,6 +767,7 @@ const translations: TranslationDeepObject = { nameEmailOrPhoneNumber: '姓名、电子邮件或电话号码', findMember: '查找成员', searchForSomeone: '搜索联系人', + userSelected: (username: string) => `已选择 ${username}`, }, customApprovalWorkflow: { title: '自定义审批流程', @@ -3024,10 +3025,7 @@ ${ detailsPage: { localTime: '本地时间', }, - newChatPage: { - startGroup: '开始群组', - addToGroup: '添加到群组', - }, + newChatPage: {startGroup: '开始群组', addToGroup: '添加到群组', addUserToGroup: (username: string) => `将 ${username} 添加到群组`}, yearPickerPage: { year: '年份', selectYear: '请选择年份', @@ -6372,6 +6370,7 @@ ${reportName} symbols: '符号', flags: '标记', }, + emojiNotSelected: '未选择表情符号', }, newRoomPage: { newRoom: '新房间', diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index 65eab0f48eea..f517894144e4 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -414,8 +414,7 @@ function NewChatPage({ref}: NewChatPageProps) { onPress={() => toggleOption(item)} disabled={item.isDisabled} role={CONST.ROLE.CHECKBOX} - accessibilityLabel={item.text ?? ''} - accessibilityState={{checked: item.isSelected}} + accessibilityLabel={item.text ? translate('selectionList.userSelected', item.text) : ''} style={[styles.flexRow, styles.alignItemsCenter, styles.ml5, styles.optionSelectCircle]} > toggleOption(item)} style={[styles.pl2]} text={translate('newChatPage.addToGroup')} + accessibilityLabel={item.text ? translate('newChatPage.addUserToGroup', item.text) : ''} innerStyles={buttonInnerStyles} small /> diff --git a/src/pages/inbox/report/PureReportActionItem.tsx b/src/pages/inbox/report/PureReportActionItem.tsx index 1f4bd99431b4..920daa38d94c 100644 --- a/src/pages/inbox/report/PureReportActionItem.tsx +++ b/src/pages/inbox/report/PureReportActionItem.tsx @@ -546,7 +546,7 @@ function PureReportActionItem({ reportMetadata, }: PureReportActionItemProps) { const {transitionActionSheetState} = ActionSheetAwareScrollView.useActionSheetAwareScrollViewActions(); - const {translate, formatPhoneNumber, localeCompare, formatTravelDate, getLocalDateFromDatetime} = useLocalize(); + const {translate, formatPhoneNumber, localeCompare, formatTravelDate, getLocalDateFromDatetime, datetimeToCalendarTime} = useLocalize(); const {showConfirmModal} = useConfirmModal(); const personalDetail = useCurrentUserPersonalDetails(); const {shouldUseNarrowLayout} = useResponsiveLayout(); @@ -2047,6 +2047,12 @@ function PureReportActionItem({ ); }; + // Calculating accessibilityLabel for chat message with sender, date and time and the message content. + const displayName = getDisplayNameOrDefault(personalDetails?.[action.actorAccountID ?? CONST.DEFAULT_NUMBER_ID]); + const formattedTimestamp = datetimeToCalendarTime(action.created, false); + const plainMessage = getReportActionText(action); + const accessibilityLabel = `${displayName}, ${formattedTimestamp}, ${plainMessage}`; + return ( {shouldShowCreatedAction && createdActionContent} @@ -2067,7 +2073,8 @@ function PureReportActionItem({ onSecondaryInteraction={showPopover} preventDefaultContextMenu={draftMessage === undefined && !hasErrors} withoutFocusOnSecondaryInteraction - accessibilityLabel={translate('accessibilityHints.chatMessage')} + accessibilityLabel={accessibilityLabel} + accessibilityHint={translate('accessibilityHints.chatMessage')} accessibilityRole={CONST.ROLE.BUTTON} sentryLabel={CONST.SENTRY_LABEL.REPORT.PURE_REPORT_ACTION_ITEM} > diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index a6546e23e412..c3d257abcd25 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -462,7 +462,9 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr {({hovered, pressed}) => ( ( () => - Object.values(customUnitRates).map((value) => ({ - rate: value.rate, - value: value.customUnitRateID, - text: value.name, - alternateText: `${convertAmountToDisplayString(value.rate, value.currency ?? CONST.CURRENCY.USD)} / ${translate( - `common.${customUnit?.attributes?.unit ?? CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES}`, - )}`, - keyForList: value.customUnitRateID, - isDisabled: value.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, - pendingAction: - value.pendingAction ?? - value.pendingFields?.rate ?? - value.pendingFields?.enabled ?? - value.pendingFields?.currency ?? - value.pendingFields?.taxRateExternalID ?? - value.pendingFields?.taxClaimablePercentage ?? - value.pendingFields?.name ?? - customUnit?.pendingFields?.attributes ?? - (policy?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD ? policy?.pendingAction : undefined), - errors: value.errors ?? undefined, - rightElement: ( - updateDistanceRateEnabled(newValue, value.customUnitRateID)} - showLockIcon={!canDisableOrDeleteRate(value.customUnitRateID)} - disabled={value.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE} - /> - ), - })), - [canDisableOrDeleteRate, customUnitRates, translate, customUnit?.attributes?.unit, customUnit?.pendingFields?.attributes, policy?.pendingAction, updateDistanceRateEnabled], + Object.values(customUnitRates).map((value) => { + const alternateText = `${convertAmountToDisplayString(value.rate, value.currency ?? CONST.CURRENCY.USD)} / ${unitTranslation}`; + + return { + rate: value.rate, + value: value.customUnitRateID, + text: value.name, + alternateText, + keyForList: value.customUnitRateID, + isDisabled: value.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, + pendingAction: + value.pendingAction ?? + value.pendingFields?.rate ?? + value.pendingFields?.enabled ?? + value.pendingFields?.currency ?? + value.pendingFields?.taxRateExternalID ?? + value.pendingFields?.taxClaimablePercentage ?? + value.pendingFields?.name ?? + customUnit?.pendingFields?.attributes ?? + (policy?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD ? policy?.pendingAction : undefined), + errors: value.errors ?? undefined, + rightElement: ( + updateDistanceRateEnabled(newValue, value.customUnitRateID)} + showLockIcon={!canDisableOrDeleteRate(value.customUnitRateID)} + disabled={value.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE} + /> + ), + }; + }), + [canDisableOrDeleteRate, customUnitRates, unitTranslation, customUnit?.pendingFields?.attributes, policy?.pendingAction, updateDistanceRateEnabled], ); const filterRate = useCallback((rate: RateForList, searchInput: string) => { diff --git a/tests/ui/PaginationTest.tsx b/tests/ui/PaginationTest.tsx index 0af1f92ac56f..a3e4c7114fb3 100644 --- a/tests/ui/PaginationTest.tsx +++ b/tests/ui/PaginationTest.tsx @@ -88,7 +88,7 @@ function triggerListLayout(reportID?: string) { function getReportActions(reportID?: string) { const report = getReportScreen(reportID); return [ - ...within(report).queryAllByLabelText(TestHelper.translateLocal('accessibilityHints.chatMessage')), + ...within(report).queryAllByAccessibilityHint(TestHelper.translateLocal('accessibilityHints.chatMessage')), // Created action has a different accessibility label. ...within(report).queryAllByLabelText(TestHelper.translateLocal('accessibilityHints.chatWelcomeMessage')), ]; diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index 7bb228195876..aadc18d7a7ff 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -271,7 +271,7 @@ describe('Unread Indicators', () => { const createdAction = screen.queryByLabelText(welcomeMessageHintText); expect(createdAction).toBeTruthy(); const reportCommentsHintText = TestHelper.translateLocal('accessibilityHints.chatMessage'); - const reportComments = screen.queryAllByLabelText(reportCommentsHintText); + const reportComments = screen.queryAllByAccessibilityHint(reportCommentsHintText); expect(reportComments).toHaveLength(9); // Since the last read timestamp is the timestamp of action 3 we should have an unread indicator above the next "unread" action which will // have actionID of 4