Compare commits

..

31 Commits

Author SHA1 Message Date
Brayan Cerón
db7c7babd7 feat: add slot to extend the profile fields [Backport #1254] (#1375)
* feat: add ExtendedProfileFieldsSlot component

* feat: update ExtendedProfileFieldsSlot documentation and images

* fix: format code in ExtendedProfileFieldsSlot README for consistency

* feat: add error handling to ExtendedProfileFieldsSlot component

* feat: replace ExtendedProfileFieldsSlot with AdditionalProfileFieldsSlot and update documentation

* feat: add Example component for AdditionalProfileFieldsSlot and update README

* fix: update README to reflect correct slot name and widget ID for AdditionalProfileFieldsSlot

* chore: remove unused default_fields.png image
2025-12-04 15:51:47 -05:00
Awais Ansari
0e1574dba7 chore: updated NODE_ENV string in .env (#1238) 2025-04-25 15:21:20 +05:00
Brian Smith
0d45ae6599 feat: import FooterSlot from component package instead of slot package (#1230) 2025-04-24 12:18:00 -04:00
Brian Smith
78246cf26b feat: standardize slot ids (#1237) 2025-04-24 07:28:24 -04:00
renovate[bot]
ca193563ec fix(deps): update dependency @edx/frontend-component-header to v6.4.0 (#1236)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-23 16:13:09 -04:00
Awais Ansari
d0efd35e66 Revert "fix: removed extra api call and strict mode (#1234)" (#1235)
This reverts commit 375b704eef.
2025-04-23 15:42:58 -04:00
sundasnoreen12
375b704eef fix: removed extra api call and strict mode (#1234)
* fix: removed extra api call and strict mode

* fix: added default values
2025-04-23 22:13:06 +05:00
Hassan Raza
ae121358db fix: Update ORA notification display title (#1233) 2025-04-23 16:09:29 +05:00
renovate[bot]
92b7c58af7 fix(deps): update dependency long to v5.3.2 (#1232)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-21 05:46:58 +00:00
renovate[bot]
a4097fe6fc fix(deps): update dependency @openedx/frontend-slot-footer to v1.2.1 (#1231)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-21 05:46:49 +00:00
Awais Ansari
397f688300 fix: scrolling issue for active menu item 2025-04-16 15:29:09 +05:00
Awais Ansari
8bd4b1b9a8 chore: updated package-lock file 2025-04-16 15:29:09 +05:00
Awais Ansari
54d029c181 test: updated test case snapshots 2025-04-16 15:29:09 +05:00
Hassan Raza
e6a4636147 fix: Update course preference title for ora submission (#1222) 2025-04-16 15:29:09 +05:00
sundasnoreen12
efb4162926 test: added test cases 2025-04-16 15:29:09 +05:00
sundasnoreen12
6061232e10 refactor: refactor code 2025-04-16 15:29:09 +05:00
sundasnoreen12
ba6b8c8f9b refactor: refactor code 2025-04-16 15:29:09 +05:00
sundasnoreen12
9c16ba0075 fix: fixed course level preference issue 2025-04-16 15:29:09 +05:00
sundasnoreen12
02b987909b fix: fixed varaible name 2025-04-16 15:29:09 +05:00
sundasnoreen12
1bcc54bb05 fix: added changes for restricted country 2025-04-16 15:29:09 +05:00
sundasnoreen12
5a5b0b905b fix: removed unused selector 2025-04-16 15:29:09 +05:00
sundasnoreen12
44ed49c7d2 refactor: refactored code 2025-04-16 15:29:09 +05:00
sundasnoreen12
386baa3840 fix: changed frequency from never to daily on email preference change 2025-04-16 15:29:09 +05:00
Awais Ansari
f1a56ad6bc fix: updated notifications section url (#1185)
* fix: updated notifiations section url

* fix: updated test cases
2025-04-16 15:29:09 +05:00
Awais Ansari
465bb9f7a0 feat: added notification preferences settings at account level (#1159)
* feat: added notification preferences settings at account level

* fix: fixed test cases

* feat: added api for account notification type

* fix: fixed test cases and label

* test: added update account preference test case

* fix: fixed issue to update email cadence for account notification type

* refactor: updated time

* fix: fixed mixed cadence issue

* fix: fixed border issue when no preferences

* refactor: refactor code

---------

Co-authored-by: sundasnoreen12 <sundasnoreen12@gmail.com>
2025-04-16 15:29:09 +05:00
Muhammad Adeel Tajamul
f9b7525d44 refactor: moved unable to delete into component (#1177) 2025-04-16 15:29:09 +05:00
Muhammad Adeel Tajamul
c7e82295c2 feat: added feature to hide delete button for countries (#1176) 2025-04-16 15:29:09 +05:00
sundasnoreen12
e02cf28b54 fix: rebase with 2u 2025-04-16 15:29:09 +05:00
Awais Ansari
18c51e8e73 fix: translation and console errors (#1166) 2025-04-16 15:29:09 +05:00
ayesha waris
88b444e796 chore: rebase with master (#1158)
* fix: fixed support urls (#1155)

* fix(deps): update dependency @edx/frontend-component-header to v5.7.1 (#1156)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update dependency @openedx/frontend-slot-footer to v1.0.6 (#1157)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix: fixed certificates url

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-16 15:29:09 +05:00
Awais Ansari
71635b33b6 feat: added country disabling feature (#1116)
* feat: added country disabling feature

* refactor: removed isDisabledCountry additional call
2025-04-16 15:29:09 +05:00
20 changed files with 2398 additions and 508 deletions

8
.env
View File

@@ -15,7 +15,7 @@ LOGO_WHITE_URL=''
SHOW_EMAIL_CHANNEL=''
LOGOUT_URL=''
MARKETING_SITE_BASE_URL=''
NODE_ENV=''
NODE_ENV='production'
ORDER_HISTORY_URL=''
PUBLISHER_BASE_URL=''
REFRESH_ACCESS_TOKEN_ENDPOINT=''
@@ -31,10 +31,6 @@ MARKETING_EMAILS_OPT_IN=''
APP_ID=
MFE_CONFIG_API_URL=
PASSWORD_RESET_SUPPORT_LINK=''
SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT=''
ACCOUNT_BASICS_SUPPORT_URL=''
EMAIL_CONFIRMATION_SUPPORT_URL=''
CERTIFICATES_SUPPORT_URL=''
LEARNER_SUPPORT_URL=''
LEARNER_FEEDBACK_URL=''
SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT='https://help.edx.org/edxlearner/s/article/How-do-I-link-or-unlink-my-edX-account-to-a-social-media-account'
COUNTRIES_WITH_DELETE_ACCOUNT_DISABLED='[]'

View File

@@ -33,9 +33,5 @@ APP_ID=
MFE_CONFIG_API_URL=
PASSWORD_RESET_SUPPORT_LINK='mailto:support@example.com'
LEARNER_FEEDBACK_URL=''
SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT=''
ACCOUNT_BASICS_SUPPORT_URL=''
EMAIL_CONFIRMATION_SUPPORT_URL=''
CERTIFICATES_SUPPORT_URL=''
LEARNER_SUPPORT_URL=''
SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT='https://help.edx.org/edxlearner/s/article/How-do-I-link-or-unlink-my-edX-account-to-a-social-media-account'
COUNTRIES_WITH_DELETE_ACCOUNT_DISABLED='[]'

2583
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@
],
"dependencies": {
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
"@edx/frontend-component-footer": "^14.3.0",
"@edx/frontend-component-footer": "^14.6.0",
"@edx/frontend-component-header": "^6.2.0",
"@edx/frontend-platform": "^8.3.3",
"@edx/openedx-atlas": "^0.6.0",
@@ -38,8 +38,7 @@
"@fortawesome/free-regular-svg-icons": "^6.6.0",
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@fortawesome/react-fontawesome": "0.2.2",
"@openedx/frontend-plugin-framework": "^1.6.0",
"@openedx/frontend-slot-footer": "^1.1.0",
"@openedx/frontend-plugin-framework": "^1.7.0",
"@openedx/paragon": "^22.16.0",
"@tensorflow-models/blazeface": "0.1.0",
"@tensorflow/tfjs-converter": "4.22.0",
@@ -61,7 +60,7 @@
"lodash.pick": "4.4.0",
"lodash.pickby": "4.6.0",
"lodash.snakecase": "4.1.1",
"long": "5.3.1",
"long": "5.3.2",
"memoize-one": "^6.0.0",
"prop-types": "15.8.1",
"qs": "6.14.0",

View File

@@ -53,6 +53,7 @@ import { fetchSiteLanguages } from './site-language';
import { fetchCourseList } from '../notification-preferences/data/thunks';
import NotificationSettings from '../notification-preferences/NotificationSettings';
import { withLocation, withNavigate } from './hoc';
import AdditionalProfileFieldsSlot from '../plugin-slots/AdditionalProfileFieldsSlot';
class AccountSettingsPage extends React.Component {
constructor(props, context) {
@@ -732,6 +733,8 @@ class AccountSettingsPage extends React.Component {
emptyLabel={this.props.intl.formatMessage(messages['account.settings.field.language.proficiencies.empty'])}
{...editableFieldProps}
/>
<AdditionalProfileFieldsSlot />
</div>
<div className="account-section pt-3 mb-6" id="social-media">
<h2 className="section-heading h4 mb-3">

View File

@@ -59,7 +59,7 @@ export class DeleteAccount extends React.Component {
hasLinkedTPA, isVerifiedAccount, status, errorType, intl,
} = this.props;
const canDelete = isVerifiedAccount && !hasLinkedTPA;
const supportArticleUrl = getConfig().SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT;
const supportArticleUrl = process.env.SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT;
// TODO: We lack a good way of providing custom language for a particular site. This is a hack
// to allow edx.org to fulfill its business requirements.
@@ -102,7 +102,7 @@ export class DeleteAccount extends React.Component {
)}
</p>
<p>
<Hyperlink destination={getConfig().ACCOUNT_BASICS_SUPPORT_URL}>
<Hyperlink destination="https://help.edx.org/edxlearner/s/topic/0TOQq0000001UdZOAU/account-basics">
{intl.formatMessage(messages['account.settings.delete.account.text.change.instead'])}
</Hyperlink>
</p>
@@ -118,7 +118,7 @@ export class DeleteAccount extends React.Component {
{isVerifiedAccount ? null : (
<BeforeProceedingBanner
instructionMessageId={optInInstructionMessageId}
supportArticleUrl={getConfig().EMAIL_CONFIRMATION_SUPPORT_URL}
supportArticleUrl="https://support.edx.org/hc/en-us/articles/115000940568-How-do-I-confirm-my-email"
/>
)}
{hasLinkedTPA ? (

View File

@@ -11,7 +11,7 @@ const PrintingInstructions = (props) => {
// TODO: What would a generic version of this link look like? Should
// CERTIFICATE_SHARING_HELP_URL really be a configuration variable? In the meantime,
// We've removed the link from the default message.
destination={getConfig().CERTIFICATES_SUPPORT_URL}
destination="https://help.edx.org/edxlearner/s/topic/0TOQq0000001UVVOA2/certificates"
>
{props.intl.formatMessage(messages['account.settings.delete.account.text.3.link'])}
</Hyperlink>

View File

@@ -27,6 +27,7 @@ exports[`DeleteAccount should match default section snapshot 1`] = `
<p>
<a
className="pgn__hyperlink default-link standalone-link"
href="https://help.edx.org/edxlearner/s/topic/0TOQq0000001UdZOAU/account-basics"
target="_self"
>
Want to change your email, name, or password instead?
@@ -72,6 +73,7 @@ exports[`DeleteAccount should match unverified account section snapshot 1`] = `
<p>
<a
className="pgn__hyperlink default-link standalone-link"
href="https://help.edx.org/edxlearner/s/topic/0TOQq0000001UdZOAU/account-basics"
target="_self"
>
Want to change your email, name, or password instead?
@@ -110,7 +112,15 @@ exports[`DeleteAccount should match unverified account section snapshot 1`] = `
</svg>
</div>
<div>
Before proceeding, please activate your account.
Before proceeding, please
<a
className="pgn__hyperlink default-link standalone-link"
href="https://support.edx.org/hc/en-us/articles/115000940568-How-do-I-confirm-my-email"
target="_self"
>
activate your account
</a>
.
</div>
</div>
</div>
@@ -143,6 +153,7 @@ exports[`DeleteAccount should match unverified account section snapshot 2`] = `
<p>
<a
className="pgn__hyperlink default-link standalone-link"
href="https://help.edx.org/edxlearner/s/topic/0TOQq0000001UdZOAU/account-basics"
target="_self"
>
Want to change your email, name, or password instead?
@@ -181,7 +192,15 @@ exports[`DeleteAccount should match unverified account section snapshot 2`] = `
</svg>
</div>
<div>
Before proceeding, please unlink all social media accounts.
Before proceeding, please
<a
className="pgn__hyperlink default-link standalone-link"
href="https://help.edx.org/edxlearner/s/article/How-do-I-link-or-unlink-my-edX-account-to-a-social-media-account"
target="_self"
>
unlink all social media accounts
</a>
.
</div>
</div>
</div>

View File

@@ -130,7 +130,7 @@ const SummaryPanel = (props) => {
`}
values={{
support_link: (
<Alert.Link href={getConfig().LEARNER_SUPPORT_URL}>
<Alert.Link href="https://support.edx.org/hc/en-us">
{props.intl.formatMessage(
messages['id.verification.review.error'],
{ siteName: getConfig().SITE_NAME },

View File

@@ -7,7 +7,7 @@ import {
render, act, screen, fireEvent,
} from '@testing-library/react';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
import IdVerificationPage from '../IdVerificationPage';
import IdVerificationPageSlot from '../../plugin-slots/IdVerificationPageSlot';
import * as selectors from '../data/selectors';
jest.mock('../data/selectors', () => jest.fn().mockImplementation(() => ({ idVerificationSelector: () => ({}) })));
@@ -47,7 +47,7 @@ jest.mock('../panels/SubmittedPanel', () => function SubmittedPanelMock() {
return <></>;
});
const IntlIdVerificationPage = injectIntl(IdVerificationPage);
const IntlIdVerificationPage = injectIntl(IdVerificationPageSlot);
const mockStore = configureStore();
describe('IdVerificationPage', () => {

View File

@@ -12,7 +12,7 @@ import { createRoot } from 'react-dom/client';
import { Route, Routes, Outlet } from 'react-router-dom';
import Header from '@edx/frontend-component-header';
import FooterSlot from '@openedx/frontend-slot-footer';
import { FooterSlot } from '@edx/frontend-component-footer';
import configureStore from './data/configureStore';
import AccountSettingsPage, { NotFoundPage } from './account-settings';
@@ -72,11 +72,6 @@ initialize({
ENABLE_DOB_UPDATE: (process.env.ENABLE_DOB_UPDATE || false),
MARKETING_EMAILS_OPT_IN: (process.env.MARKETING_EMAILS_OPT_IN || false),
PASSWORD_RESET_SUPPORT_LINK: process.env.PASSWORD_RESET_SUPPORT_LINK,
SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT: process.env.SUPPORT_URL_TO_UNLINK_SOCIAL_MEDIA_ACCOUNT,
ACCOUNT_BASICS_SUPPORT_URL: process.env.ACCOUNT_BASICS_SUPPORT_URL,
EMAIL_CONFIRMATION_SUPPORT_URL: process.env.EMAIL_CONFIRMATION_SUPPORT_URL,
CERTIFICATES_SUPPORT_URL: process.env.CERTIFICATES_SUPPORT_URL,
LEARNER_SUPPORT_URL: process.env.LEARNER_SUPPORT_URL,
LEARNER_FEEDBACK_URL: process.env.LEARNER_FEEDBACK_URL,
}, 'App loadConfig override handler');
},

View File

@@ -27,7 +27,7 @@ const messages = defineMessages({
newQuestionPost {New question posts}
contentReported {Reported content}
courseUpdates {Course updates}
oraStaffNotifications {ORA new submissions}
oraStaffNotifications {New ORA submission for staff grading}
oraGradeAssigned {Essay assignment grade received}
other {{text}}
}`,

View File

@@ -0,0 +1,87 @@
# Additional Profile Fields
### Slot ID: `org.openedx.frontend.account.additional_profile_fields.v1`
## Description
This slot is used to replace/modify/hide the additional profile fields in the account page.
## Example
The following `env.config.jsx` will extend the default fields with a additional custom fields through a simple example component.
![Screenshot of Custom Fields](./images/custom_fields.png)
### Using the Example Component
Create a file named `env.config.jsx` at the MFE root with this:
```jsx
import { PLUGIN_OPERATIONS, DIRECT_PLUGIN } from '@openedx/frontend-plugin-framework';
import Example from './src/plugin-slots/AdditionalProfileFieldsSlot/example';
const config = {
pluginSlots: {
'org.openedx.frontend.account.additional_profile_fields.v1': {
plugins: [
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'additional_account_fields',
type: DIRECT_PLUGIN,
RenderWidget: Example,
},
},
],
},
},
};
export default config;
```
## Plugin Props
When implementing a plugin for this slot, the following props are available:
### `updateUserProfile`
- **Type**: Function
- **Description**: A function for updating the user's profile with new field values. This handles the API call to persist changes to the backend.
- **Usage**: Pass an object containing the field updates to be saved to the user's profile preserving the required structure. The function automatically handles the persistence and UI updates.
#### Example
``` javascript
updateUserProfile({ extendedProfile: [{ fieldName: 'favorite_color', fieldValue: value }] });
```
### `profileFieldValues`
- **Type**: Array of Objects
- **Description**: Contains the current values of all additional profile fields as an array of objects. Each object has a `fieldName` property (string) and a `fieldValue` property (which can be string, boolean, number, or other data types depending on the field type).
- **Usage**: Access specific field values by finding the object with the matching `fieldName` and reading its `fieldValue` property. Use array methods like `find()` to locate specific fields.
#### Example
```json
[
{
"fieldName": "favorite_color",
"fieldValue": "red"
},
{
"fieldName": "data_authorization",
"fieldValue": true
},
]
```
### `profileFieldErrors`
- **Type**: Object
- **Description**: Contains validation errors for profile fields. Each key corresponds to a field name, and the value is the error message.
- **Usage**: Check for field-specific errors to display validation feedback to users.
### `formComponents`
- **Type**: Object
- **Description**: Provides access to reusable form components that are consistent with the rest of the account page styling and behavior. These components follow the platform's design system and include proper validation and accessibility features.
- **Usage**: Use these components in your custom fields implementation to maintain UI consistency. Available components include `SwitchContent` for managing different UI states.
### `refreshUserProfile`
- **Type**: Function
- **Description**: A function that triggers a refresh of the user's profile data. This can be used after updating profile fields to ensure the UI reflects the latest data from the server.
- **Usage**: Call this function when you need to manually reload the user profile information. Note that `updateUserProfile` typically handles data refresh automatically.

View File

@@ -0,0 +1,104 @@
import { useState } from 'react';
import PropTypes from 'prop-types';
import { Form, Button } from '@openedx/paragon';
/**
* Straightforward example of how you could use the pluginProps provided by
* the AdditionalProfileFieldsSlot to create a custom profile field.
*
* Here you can set a 'favorite_color' field with radio buttons and
* save it to the user's profile, especifically to their `meta` in
* the user's model. For more information, see the documentation:
*
* https://github.com/openedx/edx-platform/blob/master/openedx/core/djangoapps/user_api/README.rst#persisting-optional-user-metadata
*/
const Example = ({
updateUserProfile, profileFieldValues, profileFieldErrors, formComponents: { SwitchContent } = {},
}) => {
const [formMode, setFormMode] = useState('default');
// Get current favorite color from profileFieldValues
const currentColorField = profileFieldValues?.find(field => field.fieldName === 'favorite_color');
const currentColor = currentColorField ? currentColorField.fieldValue : '';
const [value, setValue] = useState(currentColor);
const handleChange = e => setValue(e.target.value);
// Get any validation errors for the favorite_color field
const colorFieldError = profileFieldErrors?.favorite_color;
const handleSubmit = () => {
try {
updateUserProfile({ extendedProfile: [{ fieldName: 'favorite_color', fieldValue: value }] });
setFormMode('default');
} catch (error) {
setFormMode('edit');
}
};
return (
<div className="border .border-accent-500 p-3">
<h3 className="h3">Example Additional Profile Fields Slot</h3>
<SwitchContent
expression={formMode}
cases={{
default: (
<>
<h3 className="text-muted">
{value ? `Selected value: ${value}` : 'No color selected'}
</h3>
<Button onClick={() => setFormMode('edit')}>Edit</Button>
</>
),
edit: (
<>
<Form.Group>
<Form.Label>Which Color?</Form.Label>
<Form.RadioSet
name="colors"
onChange={handleChange}
value={value}
isInvalid={!!colorFieldError}
>
<Form.Radio value="red">Red</Form.Radio>
<Form.Radio value="green">Green</Form.Radio>
<Form.Radio value="blue">Blue</Form.Radio>
</Form.RadioSet>
{colorFieldError && (
<Form.Control.Feedback type="invalid">
{colorFieldError}
</Form.Control.Feedback>
)}
</Form.Group>
<Button onClick={handleSubmit} disabled={!value}>
Save
</Button>
</>
),
}}
/>
</div>
);
};
Example.propTypes = {
updateUserProfile: PropTypes.func.isRequired,
profileFieldValues: PropTypes.arrayOf(
PropTypes.shape({
fieldName: PropTypes.string.isRequired,
fieldValue: PropTypes.oneOfType([
PropTypes.string,
PropTypes.bool,
PropTypes.number,
]).isRequired,
}),
),
profileFieldErrors: PropTypes.objectOf(PropTypes.string),
formComponents: PropTypes.shape({
SwitchContent: PropTypes.elementType.isRequired,
}),
};
export default Example;

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@@ -0,0 +1,32 @@
import { PluginSlot } from '@openedx/frontend-plugin-framework';
import { useDispatch, useSelector } from 'react-redux';
import { camelCaseObject, snakeCaseObject } from '@edx/frontend-platform';
import { fetchSettings, saveSettings } from '../../account-settings/data/actions';
import SwitchContent from '../../account-settings/SwitchContent';
const AdditionalProfileFieldsSlot = () => {
const dispatch = useDispatch();
const extendedProfileValues = useSelector((state) => state.accountSettings.values.extended_profile);
const errors = useSelector((state) => state.accountSettings.errors);
const pluginProps = {
refreshUserProfile: (username) => dispatch(fetchSettings(username)),
updateUserProfile: (params) => dispatch(saveSettings(null, null, snakeCaseObject(params))),
profileFieldValues: camelCaseObject(extendedProfileValues),
profileFieldErrors: errors,
formComponents: {
SwitchContent,
},
};
return (
<PluginSlot
id="org.openedx.frontend.account.additional_profile_fields.v1"
pluginProps={pluginProps}
/>
);
};
export default AdditionalProfileFieldsSlot;

View File

@@ -1,12 +1,15 @@
# Footer Slot
### Slot ID: `footer_slot`
### Slot ID: `org.openedx.frontend.layout.footer.v1`
### Slot ID Aliases
* `footer_slot`
## Description
This slot is used to replace/modify/hide the footer.
The implementation of the `FooterSlot` component lives in [the `frontend-component-footer` repository](https://github.com/openedx/frontend-component-footer/tree/master/src/components/footer-slot).
The implementation of the `FooterSlot` component lives in [the `frontend-component-footer` repository](https://github.com/openedx/frontend-component-footer/).
## Example
@@ -23,7 +26,7 @@ import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-frame
const config = {
pluginSlots: {
footer_slot: {
'org.openedx.frontend.layout.footer.v1': {
plugins: [
{
// Hide the default footer

View File

@@ -1,6 +1,9 @@
# Footer Slot
# ID Verification Page Slot
### Slot ID: `id_verification_page_plugin`
### Slot ID: `org.openedx.frontend.account.id_verification_page.v1`
### Slot ID Aliases
* `id_verification_page_plugin`
## Description
@@ -19,13 +22,13 @@ import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-frame
const config = {
pluginSlots: {
id_verification_page_plugin: {
'org.openedx.frontend.account.id_verification_page.v1': {
plugins: [
{
// Insert a custom IDV Page
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'id_verification_page_plugin',
id: 'custom_id_verification_page',
type: DIRECT_PLUGIN,
RenderWidget: () => (
<div>

View File

@@ -2,7 +2,10 @@ import { PluginSlot } from '@openedx/frontend-plugin-framework';
import IdVerificationPage from '../../id-verification';
const IdVerificationPageSlot = () => (
<PluginSlot id="id_verification_page_plugin">
<PluginSlot
id="org.openedx.frontend.account.id_verification_page.v1"
idAliases={['id_verification_page_plugin']}
>
<IdVerificationPage />
</PluginSlot>
);

View File

@@ -1,4 +1,5 @@
# `frontend-app-account` Plugin Slots
* [`footer_slot`](./FooterSlot/)
* [`id_verification_page_plugin`](./IdVerificationPageSlot/)
* [`org.openedx.frontend.layout.footer.v1`](./FooterSlot/)
* [`org.openedx.frontend.account.id_verification_page.v1`](./IdVerificationPageSlot/)
* [`org.openedx.frontend.account.additional_profile_fields.v1`](./AdditionalProfileFieldsSlot/)