From 29be40363b140f433482e7828751d059879e6bc0 Mon Sep 17 00:00:00 2001 From: jajjibhai008 Date: Fri, 28 Jun 2024 19:24:10 +0500 Subject: [PATCH] feat: mark static strings for i18n in members tab on budget detail page --- .../BudgetDetailMembersTabContents.jsx | 15 +- .../GroupMembersCsvDownloadTableAction.jsx | 34 +++- .../LearnerCreditGroupMembersTable.jsx | 181 ++++++++++-------- .../members-tab/MemberDetailsTableCell.jsx | 7 +- .../MemberEnrollmentsTableColumnHeader.jsx | 15 +- .../members-tab/MemberStatusTableCell.jsx | 99 ++++++++-- .../MemberStatusTableColumnHeader.jsx | 15 +- .../members-tab/MembersTableSwitchFilter.jsx | 8 +- .../bulk-actions/MemberRemoveAction.jsx | 8 +- .../bulk-actions/MemberRemoveModal.jsx | 107 ++++++++--- 10 files changed, 350 insertions(+), 139 deletions(-) diff --git a/src/components/learner-credit-management/members-tab/BudgetDetailMembersTabContents.jsx b/src/components/learner-credit-management/members-tab/BudgetDetailMembersTabContents.jsx index 6e6489154d..e92f31df35 100644 --- a/src/components/learner-credit-management/members-tab/BudgetDetailMembersTabContents.jsx +++ b/src/components/learner-credit-management/members-tab/BudgetDetailMembersTabContents.jsx @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { Skeleton } from '@openedx/paragon'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; import LearnerCreditGroupMembersTable from './LearnerCreditGroupMembersTable'; import { @@ -39,9 +40,19 @@ const BudgetDetailMembersTabContents = ({ enterpriseUUID, refresh, setRefresh }) {!isRemovedMembersLoading ? ( <>
-

Budget Members

+

+ +

- Members choose what to learn from the catalog and spend from the budget to enroll. +

{ + const intl = useIntl(); const selectedEmails = Object.keys(tableInstance.state.selectedRowIds); const selectedEmailCount = selectedEmails.length; const [alertModalOpen, setAlertModalOpen] = useState(false); @@ -74,13 +76,21 @@ const GroupMembersCsvDownloadTableAction = ({ if (selectedEmailCount > 0) { buttonSelectedNumber = isEntireTableSelected ? `(${tableInstance.itemCount})` : `(${selectedEmailCount})`; } else { - buttonSelectedNumber = `all (${tableInstance.itemCount})`; + buttonSelectedNumber = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.all', + defaultMessage: 'all ({itemCounts})', + description: 'All members selected in the Members table', + }, { itemCounts: tableInstance.itemCount }); } return ( <> setAlertModalOpen(false)} footerNode={( @@ -89,14 +99,21 @@ const GroupMembersCsvDownloadTableAction = ({ variant="tertiary" onClick={() => setAlertModalOpen(false)} > - Close + )} >

- We're sorry but something went wrong while downloading your CSV. - Please refer to the error below and try again later. +

{alertModalExc}

@@ -107,7 +124,12 @@ const GroupMembersCsvDownloadTableAction = ({ className="border rounded-0 border-dark-500" disabled={tableInstance.itemCount === 0} > - Download {buttonSelectedNumber} + ); diff --git a/src/components/learner-credit-management/members-tab/LearnerCreditGroupMembersTable.jsx b/src/components/learner-credit-management/members-tab/LearnerCreditGroupMembersTable.jsx index 9b4c6cc15f..551a6f171b 100644 --- a/src/components/learner-credit-management/members-tab/LearnerCreditGroupMembersTable.jsx +++ b/src/components/learner-credit-management/members-tab/LearnerCreditGroupMembersTable.jsx @@ -4,6 +4,7 @@ import { DataTable, Dropdown, Icon, IconButton, } from '@openedx/paragon'; import { MoreVert, RemoveCircle } from '@openedx/paragon/icons'; +import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; import TableTextFilter from '../TableTextFilter'; import CustomDataTableEmptyState from '../CustomDataTableEmptyState'; import MemberDetailsTableCell from './MemberDetailsTableCell'; @@ -41,7 +42,12 @@ const KabobMenu = ({ /> - Remove member + + @@ -74,87 +80,98 @@ const LearnerCreditGroupMembersTable = ({ setRefresh, groupUuid, removedGroupMembersCount, -}) => ( - ]} - columns={[ - { - Header: 'Member Details', - accessor: 'memberDetails', - Cell: MemberDetailsTableCell, - }, - { - Header: MemberStatusTableColumnHeader, - accessor: 'status', - Cell: MemberStatusTableCell, - Filter: removedGroupMembersCount > 0 ? ( - - ) :
, - filter: 'status', - }, - { - Header: 'Recent action', - accessor: 'recentAction', - Cell: ({ row }) => row.original.recentAction, - disableFilters: true, - }, - { - Header: MemberEnrollmentsTableColumnHeader, - accessor: 'enrollmentCount', - Cell: ({ row }) => row.original.enrollmentCount, - disableFilters: true, - }, - ]} - initialTableOptions={{ - getRowId: row => row?.memberDetails.userEmail, - autoResetPage: true, - }} - initialState={{ - pageSize: MEMBERS_TABLE_PAGE_SIZE, - pageIndex: DEFAULT_PAGE, - sortBy: [ - { id: 'memberDetails', desc: true }, - ], - filters: [], - }} - bulkActions={[ - , - , - ]} - additionalColumns={[ - { - id: 'action', - Header: '', - // eslint-disable-next-line react/no-unstable-nested-components - Cell: (props) => ( - - ), - }, - ]} - fetchData={fetchTableData} - data={tableData.results} - itemCount={tableData.itemCount} - pageCount={tableData.pageCount} - EmptyTableComponent={CustomDataTableEmptyState} - /> -); +}) => { + const intl = useIntl(); + return ( + ]} + columns={[ + { + Header: intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.columns.memberDetails', + defaultMessage: 'Member Details', + description: 'Column header for the Member Details column in the Members tab of the Budget Detail page', + }), + accessor: 'memberDetails', + Cell: MemberDetailsTableCell, + }, + { + Header: MemberStatusTableColumnHeader, + accessor: 'status', + Cell: MemberStatusTableCell, + Filter: removedGroupMembersCount > 0 ? ( + + ) :
, + filter: 'status', + }, + { + Header: intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.columns.recentAction', + defaultMessage: 'Recent action', + description: 'Column header for the Recent action column in the Members tab of the Budget Detail page', + }), + accessor: 'recentAction', + Cell: ({ row }) => row.original.recentAction, + disableFilters: true, + }, + { + Header: MemberEnrollmentsTableColumnHeader, + accessor: 'enrollmentCount', + Cell: ({ row }) => row.original.enrollmentCount, + disableFilters: true, + }, + ]} + initialTableOptions={{ + getRowId: row => row?.memberDetails.userEmail, + autoResetPage: true, + }} + initialState={{ + pageSize: MEMBERS_TABLE_PAGE_SIZE, + pageIndex: DEFAULT_PAGE, + sortBy: [ + { id: 'memberDetails', desc: true }, + ], + filters: [], + }} + bulkActions={[ + , + , + ]} + additionalColumns={[ + { + id: 'action', + Header: '', + // eslint-disable-next-line react/no-unstable-nested-components + Cell: (props) => ( + + ), + }, + ]} + fetchData={fetchTableData} + data={tableData.results} + itemCount={tableData.itemCount} + pageCount={tableData.pageCount} + EmptyTableComponent={CustomDataTableEmptyState} + /> + ); +}; KabobMenu.propTypes = { row: PropTypes.shape({ diff --git a/src/components/learner-credit-management/members-tab/MemberDetailsTableCell.jsx b/src/components/learner-credit-management/members-tab/MemberDetailsTableCell.jsx index 5c65f8a2d6..86915c2c79 100644 --- a/src/components/learner-credit-management/members-tab/MemberDetailsTableCell.jsx +++ b/src/components/learner-credit-management/members-tab/MemberDetailsTableCell.jsx @@ -6,6 +6,7 @@ import { import { Person, } from '@openedx/paragon/icons'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; const MemberDetailsTableCell = ({ row, @@ -26,7 +27,11 @@ const MemberDetailsTableCell = ({ memberDetails = (

- Former member +

{row.original.memberDetails.userEmail}

diff --git a/src/components/learner-credit-management/members-tab/MemberEnrollmentsTableColumnHeader.jsx b/src/components/learner-credit-management/members-tab/MemberEnrollmentsTableColumnHeader.jsx index fd39695adb..c7d01e64b2 100644 --- a/src/components/learner-credit-management/members-tab/MemberEnrollmentsTableColumnHeader.jsx +++ b/src/components/learner-credit-management/members-tab/MemberEnrollmentsTableColumnHeader.jsx @@ -6,18 +6,29 @@ import { Icon, } from '@openedx/paragon'; import { InfoOutline } from '@openedx/paragon/icons'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; const MemberEnrollmentsTableColumnHeader = () => ( - Enrollments + -
Total number of enrollment originated from the budget
+
+ +
)} > diff --git a/src/components/learner-credit-management/members-tab/MemberStatusTableCell.jsx b/src/components/learner-credit-management/members-tab/MemberStatusTableCell.jsx index bd177479a7..654a96ab0f 100644 --- a/src/components/learner-credit-management/members-tab/MemberStatusTableCell.jsx +++ b/src/components/learner-credit-management/members-tab/MemberStatusTableCell.jsx @@ -6,11 +6,13 @@ import { import { CheckCircle, RemoveCircle, Timelapse, } from '@openedx/paragon/icons'; +import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; import { HELP_CENTER_GROUPS_INVITE_LINK } from '../../settings/data/constants'; const MemberStatusTableCell = ({ row, }) => { + const intl = useIntl(); let icon; let text; let popoverHeader; @@ -19,26 +21,75 @@ const MemberStatusTableCell = ({ let popoverExtra2; if (row.original.status === 'pending') { icon = Timelapse; - text = 'Waiting for member'; - popoverHeader = `Waiting for ${row.original.memberDetails.userEmail}`; - popoverBody = 'This member must accept their invitation to browse this budget\'s catalog ' - + 'and enroll using their member permissions by logging in or creating an account within 90 days.'; - popoverExtra1 = 'Need help?'; - popoverExtra2 = 'Learn more about adding budget members in Learner Credit at '; + text = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.pending', + defaultMessage: 'Waiting for member', + description: 'Status of the member invitation', + }); + popoverHeader = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.pendingPopoverHeader', + defaultMessage: 'Waiting for {userEmail}', + description: 'Popover header for the pending status', + }, { userEmail: row.original.memberDetails.userEmail }); + popoverBody = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.pendingPopoverBody', + defaultMessage: "This member must accept their invitation to browse this budget's catalog and enroll using their member permissions by logging in or creating an account within 90 days.", + description: 'Popover body for the pending status', + }); + popoverExtra1 = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.pendingPopoverExtra1', + defaultMessage: 'Need help?', + description: 'Extra text for the pending status', + }); + popoverExtra2 = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.pendingPopoverExtra2', + defaultMessage: 'Learn more about adding budget members in Learner Credit at ', + description: 'Extra text for the pending status', + }); } else if (row.original.status === 'accepted') { icon = CheckCircle; - text = 'Accepted'; - popoverHeader = 'Invitation accepted'; - popoverBody = 'This member has successfully accepted the member invitation and can ' - + 'now browse this budget\'s catalog and enroll using their member permissions.'; + text = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.accepted', + defaultMessage: 'Accepted', + description: 'Status of the member invitation', + }); + popoverHeader = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.acceptedPopoverHeader', + defaultMessage: 'Invitation accepted', + description: 'Popover header for the accepted status', + }); + popoverBody = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.acceptedPopoverBody', + defaultMessage: "This member has successfully accepted the member invitation and can now browse this budget's catalog and enroll using their member permissions.", + description: 'Popover body for the accepted status', + }); } else { icon = RemoveCircle; - text = 'Removed'; - popoverHeader = 'Member removed'; - popoverBody = 'This member has been successfully removed and can not browse this budget\'s ' - + 'catalog and enroll using their member permissions.'; - popoverExtra1 = 'Want to add them back?'; - popoverExtra2 = 'Follow the steps provided at '; + text = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removed', + defaultMessage: 'Removed', + description: 'Status of the member invitation', + }); + popoverHeader = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removedPopoverHeader', + defaultMessage: 'Member removed', + description: 'Popover header for the removed status', + }); + popoverBody = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removedPopoverBody', + defaultMessage: "This member has been successfully removed and can not browse this budget's catalog and enroll using their member permissions.", + description: 'Popover body for the removed status', + }); + popoverExtra1 = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removedPopoverExtra1', + defaultMessage: 'Want to add them back?', + description: 'Extra text for the removed status', + }); + popoverExtra2 = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removedPopoverExtra2', + defaultMessage: 'Follow the steps provided at ', + description: 'Extra text for the removed status', + }); } return (

{popoverExtra1}

{popoverExtra2} - - Help Center: Inviting Budget Members - + ( + + {chunks} + + ), + }} + />

)} diff --git a/src/components/learner-credit-management/members-tab/MemberStatusTableColumnHeader.jsx b/src/components/learner-credit-management/members-tab/MemberStatusTableColumnHeader.jsx index 8440d5cc3a..bc1e6c1563 100644 --- a/src/components/learner-credit-management/members-tab/MemberStatusTableColumnHeader.jsx +++ b/src/components/learner-credit-management/members-tab/MemberStatusTableColumnHeader.jsx @@ -6,18 +6,29 @@ import { Icon, } from '@openedx/paragon'; import { InfoOutline } from '@openedx/paragon/icons'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; const MemberStatusTableColumnHeader = () => ( - Status + -
Status of the member invitation.
+
+ +
)} > diff --git a/src/components/learner-credit-management/members-tab/MembersTableSwitchFilter.jsx b/src/components/learner-credit-management/members-tab/MembersTableSwitchFilter.jsx index f0fd650228..884e4d03f3 100644 --- a/src/components/learner-credit-management/members-tab/MembersTableSwitchFilter.jsx +++ b/src/components/learner-credit-management/members-tab/MembersTableSwitchFilter.jsx @@ -1,6 +1,7 @@ import { Form, DataTableContext } from '@openedx/paragon'; import PropTypes from 'prop-types'; import React, { useContext } from 'react'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; const MembersTableSwitchFilter = ({ removedGroupMembersCount }) => { const { columns } = useContext(DataTableContext); @@ -16,7 +17,12 @@ const MembersTableSwitchFilter = ({ removedGroupMembersCount }) => { }} data-testid="show-removed-toggle" > - Show removed ({removedGroupMembersCount}) + ); }; diff --git a/src/components/learner-credit-management/members-tab/bulk-actions/MemberRemoveAction.jsx b/src/components/learner-credit-management/members-tab/bulk-actions/MemberRemoveAction.jsx index 3ff9619e2a..fcaa45274f 100644 --- a/src/components/learner-credit-management/members-tab/bulk-actions/MemberRemoveAction.jsx +++ b/src/components/learner-credit-management/members-tab/bulk-actions/MemberRemoveAction.jsx @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Button } from '@openedx/paragon'; import { RemoveCircle } from '@openedx/paragon/icons'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; import MemberRemoveModal from './MemberRemoveModal'; import useRemoveMember from '../../data/hooks/useRemoveMember'; @@ -25,7 +26,12 @@ const MemberRemoveAction = ({ onClick={handleRemoveClick} disabled={!totalToRemove} > - Remove ({totalToRemove}) + { - let buttonNumberLabel = 'all'; +const generateRemoveModalSubmitLabel = (intl, totalToRemove, isRemoveIndividualUser) => { + let buttonNumberLabel = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removeModal.remove.all', + defaultMessage: 'all', + description: 'Button state when user click on remove button for all users', + }); if (isRemoveIndividualUser) { - buttonNumberLabel = 'member'; + buttonNumberLabel = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removeModal.remove.individual', + defaultMessage: 'member', + description: 'Button state when user click on remove button for individual user', + }); } else if (Number.isFinite(totalToRemove)) { - buttonNumberLabel = `(${totalToRemove})`; + buttonNumberLabel = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removeModal.remove.number', + defaultMessage: '({totalToRemove})', + description: 'Button state when user click on remove button', + }, { totalToRemove }); } return { - default: `Remove ${buttonNumberLabel}`, - pending: `Removing ${buttonNumberLabel}`, - complete: 'Done', - error: `Retry remove ${buttonNumberLabel}`, + default: intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removeModal.remove', + defaultMessage: 'Remove {buttonNumberLabel}', + description: 'Button state when user click on remove button', + }, { buttonNumberLabel }), + pending: intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removeModal.removing', + defaultMessage: 'Removing {buttonNumberLabel}', + description: 'Button state when removing action is in pending state', + }, { buttonNumberLabel }), + complete: intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removeModal.done', + defaultMessage: 'Done', + description: 'Button state when removing action is completed', + }), + error: intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removeModal.retry', + defaultMessage: 'Retry remove {buttonNumberLabel}', + description: 'Button state when removing action is failed', + }, { buttonNumberLabel }), }; }; @@ -45,10 +74,14 @@ const MemberRemoveModal = ({ groupUuid, isRemoveIndividualUser, }) => { + const intl = useIntl(); const [requestState, setRequestState, initialRequestState] = useRequestState(isOpen); - const buttonLabels = generateRemoveModalSubmitLabel(totalToRemove, isRemoveIndividualUser); + const buttonLabels = generateRemoveModalSubmitLabel(intl, totalToRemove, isRemoveIndividualUser); + const title = intl.formatMessage({ + id: 'learnerCreditManagement.budgetDetail.membersTab.membersTable.removeModal.title', + defaultMessage: 'Remove member{memberCount, plural, one {} other {s}}?', + }, { memberCount: removeAllUsers || totalToRemove > 1 ? 2 : 1 }); - const title = `Remove member${removeAllUsers || totalToRemove > 1 ? 's' : ''}?`; const { subsidyAccessPolicyId } = useBudgetId(); const { data: subsidyAccessPolicy } = useSubsidyAccessPolicy(subsidyAccessPolicyId); const handleSubmit = useCallback(async () => { @@ -115,29 +148,57 @@ const MemberRemoveModal = ({ {requestState.error - && ( + && ( -

There was an error with your request. Please try again.

- If the error persists,{' '} - - contact customer support. - + +

+

+ ( + + {chunks} + + ), + }} + />

- )} -

This action cannot be undone.

+ )}

- The members will be notified and immediately lose access to browse the catalog - and enroll using this budget’s available Learner Credit balance. Removal will - not impact any current or past enrollments the members may have originated - through this budget. + +

+

+

- Go back +