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

ENT-8762: Marked strings for the i18n of the first 2 tabs of admin portal settings page. #1244

Merged
merged 3 commits into from
Jun 3, 2024
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ intl_imports = ./node_modules/.bin/intl-imports.js
i18n = ./src/i18n
transifex_input = $(i18n)/transifex_input.json
# This directory must match .babelrc .
transifex_temp = ./temp/babel-plugin-react-intl
transifex_temp = ./temp/babel-plugin-formatjs

shell: ## run a shell on the cookie-cutter container
docker exec -it /bin/bash
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
],
"scripts": {
"build": "fedx-scripts webpack",
"i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null",
"i18n_extract": "fedx-scripts formatjs extract",
"build:with-theme": "THEME=npm:@edx/brand-edx.org@latest npm run install-theme && fedx-scripts webpack",
"check-types": "tsc --noemit",
"lint": "fedx-scripts eslint --ext .js --ext .jsx .; npm run check-types",
Expand Down
11 changes: 5 additions & 6 deletions src/components/ConfirmationModal/ConfirmationModal.test.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import {
render, screen,
} from '@testing-library/react';
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom/extend-expect';

import ConfirmationModal from './index';
import { renderWithI18nProvider } from '../test/testUtils';

describe('<ConfirmationModal />', () => {
const basicProps = {
Expand All @@ -16,20 +15,20 @@ describe('<ConfirmationModal />', () => {

it('should call onConfirm when confirm button is clicked', () => {
const mockHandleConfirm = jest.fn();
render(<ConfirmationModal {...basicProps} onConfirm={mockHandleConfirm} />);
renderWithI18nProvider(<ConfirmationModal {...basicProps} onConfirm={mockHandleConfirm} />);
userEvent.click(screen.getByText('Confirm'));
expect(mockHandleConfirm).toHaveBeenCalledTimes(1);
});

it('should call onClose when modal is closed', () => {
const mockHandleClose = jest.fn();
render(<ConfirmationModal {...basicProps} onClose={mockHandleClose} />);
renderWithI18nProvider(<ConfirmationModal {...basicProps} onClose={mockHandleClose} />);
userEvent.click(screen.getByText('Cancel'));
expect(mockHandleClose).toHaveBeenCalledTimes(1);
});

it('should show error alert if confirmButtonState = error', () => {
render(<ConfirmationModal {...basicProps} confirmButtonState="errored" />);
renderWithI18nProvider(<ConfirmationModal {...basicProps} confirmButtonState="errored" />);
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
});
});
158 changes: 110 additions & 48 deletions src/components/ConfirmationModal/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,49 @@ import {
ModalDialog, ActionRow, Button, StatefulButton, Alert,
} from '@openedx/paragon';
import { Info } from '@openedx/paragon/icons';
import { defineMessages, FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';

export const DEFAULT_TITLE = 'Are you sure?';

const CONFIRM_TEXT = 'Confirm';
const CANCEL_TEXT = 'Cancel';
const LOADING_TEXT = 'Loading...';
const TRY_AGAIN_TEXT = 'Try again';

export const CONFIRM_BUTTON_STATES = {
default: 'default',
pending: 'pending',
errored: 'errored',
};

const messages = defineMessages({
[DEFAULT_TITLE]: {
id: 'adminPortal.confirmationModal.defaultTitle',
defaultMessage: 'Are you sure?',
description: 'Default title for the confirmation modal',
},
[CONFIRM_TEXT]: {
id: 'adminPortal.confirmationModal.confirm',
defaultMessage: 'Confirm',
description: 'Confirm button text for the confirmation modal',
},
[CANCEL_TEXT]: {
id: 'adminPortal.confirmationModal.cancel',
defaultMessage: 'Cancel',
description: 'Cancel button text for the confirmation modal',
},
[LOADING_TEXT]: {
id: 'adminPortal.confirmationModal.loading',
defaultMessage: 'Loading...',
description: 'Loading state text for the confirmation modal',
},
[TRY_AGAIN_TEXT]: {
id: 'adminPortal.confirmationModal.tryAgain',
defaultMessage: 'Try again',
description: 'Try again button text for the confirmation modal',
},
});

const ConfirmationModal = ({
isOpen,
disabled,
Expand All @@ -24,49 +59,76 @@ const ConfirmationModal = ({
confirmText,
cancelText,
...rest
}) => (
<ModalDialog
title="Confirmation Modal"
variant="default"
isOpen={isOpen}
onClose={onClose}
{...rest}
>
<ModalDialog.Header>
<ModalDialog.Title>
{title}
</ModalDialog.Title>
{confirmButtonState === CONFIRM_BUTTON_STATES.errored && (
<Alert
icon={Info}
variant="danger"
>
<Alert.Heading>
Something went wrong
</Alert.Heading>
Please try again.
</Alert>
)}
</ModalDialog.Header>
<ModalDialog.Body>
{body}
</ModalDialog.Body>
<ModalDialog.Footer>
<ActionRow>
<Button onClick={onClose} variant="outline-primary">
{cancelText}
</Button>
<StatefulButton
labels={confirmButtonLabels}
state={confirmButtonState}
variant="primary"
disabled={disabled}
onClick={onConfirm}
/>
</ActionRow>
</ModalDialog.Footer>
</ModalDialog>
);
}) => {
const intl = useIntl();
const defaultMessage = confirmButtonLabels[CONFIRM_BUTTON_STATES.default];
const pendingMessage = confirmButtonLabels[CONFIRM_BUTTON_STATES.pending];
const erroredMessage = confirmButtonLabels[CONFIRM_BUTTON_STATES.errored];

// This code snippet first checks if the message exists in the messages object, and if it does,
// it formats the message using the intl.formatMessage function. If the message does not exist,
// it uses the defaultMessage value.
const translatedConfirmButtonLabels = {
[CONFIRM_BUTTON_STATES.default]:
messages[defaultMessage] ? intl.formatMessage(messages[defaultMessage]) : defaultMessage,
[CONFIRM_BUTTON_STATES.pending]:
messages[pendingMessage] ? intl.formatMessage(messages[pendingMessage]) : pendingMessage,
[CONFIRM_BUTTON_STATES.errored]:
messages[erroredMessage] ? intl.formatMessage(messages[erroredMessage]) : erroredMessage,
};

return (
<ModalDialog
title="Confirmation Modal"
variant="default"
isOpen={isOpen}
onClose={onClose}
{...rest}
>
<ModalDialog.Header>
<ModalDialog.Title>
{messages[title] ? intl.formatMessage(messages[title]) : title}
</ModalDialog.Title>
{confirmButtonState === CONFIRM_BUTTON_STATES.errored && (
<Alert
icon={Info}
variant="danger"
>
<Alert.Heading>
<FormattedMessage
id="confirmationModal.error"
defaultMessage="Something went wrong"
description="Error message for the confirmation modal"
/>
</Alert.Heading>
<FormattedMessage
id="confirmationModal.errorDescription"
defaultMessage="Please try again."
description="Error description for the confirmation modal"
/>
</Alert>
)}
</ModalDialog.Header>
<ModalDialog.Body>
{body}
</ModalDialog.Body>
<ModalDialog.Footer>
<ActionRow>
<Button onClick={onClose} variant="outline-primary">
{messages[cancelText] ? intl.formatMessage(messages[cancelText]) : cancelText}
</Button>
<StatefulButton
labels={translatedConfirmButtonLabels}
state={confirmButtonState}
variant="primary"
disabled={disabled}
onClick={onConfirm}
/>
</ActionRow>
</ModalDialog.Footer>
</ModalDialog>
);
};

ConfirmationModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
Expand All @@ -88,14 +150,14 @@ ConfirmationModal.propTypes = {
ConfirmationModal.defaultProps = {
disabled: false,
confirmButtonLabels: {
[CONFIRM_BUTTON_STATES.default]: 'Confirm',
[CONFIRM_BUTTON_STATES.pending]: 'Loading...',
[CONFIRM_BUTTON_STATES.errored]: 'Try again',
[CONFIRM_BUTTON_STATES.default]: CONFIRM_TEXT,
[CONFIRM_BUTTON_STATES.pending]: LOADING_TEXT,
[CONFIRM_BUTTON_STATES.errored]: TRY_AGAIN_TEXT,
},
confirmButtonState: CONFIRM_BUTTON_STATES.default,
title: DEFAULT_TITLE,
confirmText: 'Confirm',
cancelText: 'Cancel',
confirmText: CONFIRM_TEXT,
cancelText: CANCEL_TEXT,
};

export default ConfirmationModal;
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const CurrentContentHighlightHeader = ({ enterpriseId }) => {
</ActionRow>
<p>
<FormattedMessage
id="highlights.catalog.visibility.tab.catalog.visibility.not.updated.alert.error.header.title.message"
id="highlights.catalogVisibility.tab.catalog.error.title"
defaultMessage="Create up to {maxHighlights} highlights for your learners."
description="Header title for error alert shown to admin when catalog visibility failed to update."
values={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
BROWSE_AND_REQUEST_ALERT_TEXT,
} from './data/constants';
import { ROUTE_NAMES } from '../EnterpriseApp/data/constants';
import { SETTINGS_TABS_VALUES } from '../settings/data/constants';
import { ACCESS_TAB } from '../settings/data/constants';

const mockStore = configureMockStore([thunk]);

Expand All @@ -36,7 +36,7 @@ jest.mock('react-router-dom', () => ({
useNavigate: () => mockNavigate,
}));

const SETTINGS_PAGE_LOCATION = `/${ENTERPRISE_SLUG}/admin/${ROUTE_NAMES.settings}/${SETTINGS_TABS_VALUES.access}`;
const SETTINGS_PAGE_LOCATION = `/${ENTERPRISE_SLUG}/admin/${ROUTE_NAMES.settings}/${ACCESS_TAB}`;

const NewFeatureAlertBrowseAndRequestWrapper = () => (
<Router>
Expand Down
4 changes: 2 additions & 2 deletions src/components/NewFeatureAlertBrowseAndRequest/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
BROWSE_AND_REQUEST_ALERT_COOKIE_PREFIX,
} from '../subscriptions/data/constants';
import { ROUTE_NAMES } from '../EnterpriseApp/data/constants';
import { SETTINGS_TABS_VALUES } from '../settings/data/constants';
import { ACCESS_TAB } from '../settings/data/constants';

/**
* Generates string use to identify cookie
Expand Down Expand Up @@ -37,7 +37,7 @@ const NewFeatureAlertBrowseAndRequest = ({ enterpriseId, enterpriseSlug, intl })
* Redirects user to settings page, access tab
*/
const handleGoToSettings = () => {
navigate(`/${enterpriseSlug}/admin/${ROUTE_NAMES.settings}/${SETTINGS_TABS_VALUES.access}`);
navigate(`/${enterpriseSlug}/admin/${ROUTE_NAMES.settings}/${ACCESS_TAB}`);
};

return (
Expand Down
4 changes: 2 additions & 2 deletions src/components/ProductTours/tests/ProductTours.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
TOUR_TARGETS,
} from '../constants';
import { ROUTE_NAMES } from '../../EnterpriseApp/data/constants';
import { SETTINGS_TABS_VALUES } from '../../settings/data/constants';
import { ACCESS_TAB } from '../../settings/data/constants';
import { SubsidyRequestsContext } from '../../subsidy-requests';
import { EnterpriseSubsidiesContext } from '../../EnterpriseSubsidiesContext';
import { SUPPORTED_SUBSIDY_TYPES } from '../../../data/constants/subsidyRequests';
Expand All @@ -31,7 +31,7 @@ const mockStore = configureMockStore([thunk]);
const ENTERPRISE_SLUG = 'sluggy';

const SUBSCRIPTION_PAGE_LOCATION = `/${ENTERPRISE_SLUG}/admin/${ROUTE_NAMES.subscriptionManagement}`;
const SETTINGS_PAGE_LOCATION = `/${ENTERPRISE_SLUG}/admin/${ROUTE_NAMES.settings}/${SETTINGS_TABS_VALUES.access}`;
const SETTINGS_PAGE_LOCATION = `/${ENTERPRISE_SLUG}/admin/${ROUTE_NAMES.settings}/${ACCESS_TAB}`;
const LEARNER_CREDIT_PAGE_LOCATION = `/${ENTERPRISE_SLUG}/admin/${ROUTE_NAMES.learnerCredit}`;

const ToursWithContext = ({
Expand Down
4 changes: 2 additions & 2 deletions src/components/forms/ValidatedFormCheckbox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { ReactNode } from 'react';
import omit from 'lodash/omit';
import isString from 'lodash/isString';

Expand All @@ -9,7 +9,7 @@ import { useFormContext } from './FormContext';

type InheritedParagonCheckboxProps = {
className?: string;
children: string;
children: ReactNode;
};

export type ValidatedFormCheckboxProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ const BudgetActions = ({
</h3>
<p>
<FormattedMessage
id="lcm.budget.detail.page.overview.budget.actions.all.people.choose.learn"
id="lcm.budget.detail.page.overview.budget.actions.all.people.choose.learn.description"
defaultMessage="All people in your organization can choose what to learn
from the catalog and spend from the available balance to enroll."
description="Decription which tells that user can choose from the catalog and spend from the available balance to enroll"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const AssignmentAllocationHelpCollapsibles = ({ enterpriseId, course }) => (
<ul className="x-small pl-4 py-2">
<li>
<FormattedMessage
id="lcm.budget.detail.page.catalog.tab.course.card.total.assignment.cost.will.be.earmarked"
id="lcm.budget.detailsPage.catalog.tab.course.card.total.assignment.cost"
defaultMessage="The total assignment cost will be earmarked as {doubleQoute}assigned{doubleQoute} funds in your
Learner Credit budget so you can{apostrophe}t overspend."
description="A step which explains that the total assignment cost will be earmarked as 'assigned' funds in your Learner Credit budget"
Expand Down
17 changes: 15 additions & 2 deletions src/components/settings/SettingsAccessTab/ActionsTableCell.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getConfig } from '@edx/frontend-platform/config';
import { logError } from '@edx/frontend-platform/logging';
import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils';

import { FormattedMessage } from '@edx/frontend-platform/i18n';
import LinkDeactivationAlertModal from './LinkDeactivationAlertModal';
import LinkCopiedToast from './LinkCopiedToast';
import { SETTINGS_ACCESS_EVENTS } from '../../../eventTracking';
Expand Down Expand Up @@ -69,9 +70,21 @@ const ActionsTableCell = ({ row, onDeactivateLink, enterpriseUUID }) => {
<div className="d-flex justify-content-end">
<ActionRow>
{hasClipboard && (
<Button onClick={handleCopyLink} variant="link" size="inline">Copy</Button>
<Button onClick={handleCopyLink} variant="link" size="inline">
<FormattedMessage
id="adminPortal.settings.access.copyLink"
defaultMessage="Copy"
description="Label for the copy link button."
/>
</Button>
)}
<Button onClick={handleDeactivateClick} variant="link" size="inline">Deactivate</Button>
<Button onClick={handleDeactivateClick} variant="link" size="inline">
<FormattedMessage
id="adminPortal.settings.access.deactivateLink"
defaultMessage="Deactivate"
description="Label for the deactivate link button."
/>
</Button>
</ActionRow>
</div>
<LinkDeactivationAlertModal
Expand Down
Loading
Loading