Compare commits
31 Commits
2u-main
...
release/te
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db7c7babd7 | ||
|
|
0e1574dba7 | ||
|
|
0d45ae6599 | ||
|
|
78246cf26b | ||
|
|
ca193563ec | ||
|
|
d0efd35e66 | ||
|
|
375b704eef | ||
|
|
ae121358db | ||
|
|
92b7c58af7 | ||
|
|
a4097fe6fc | ||
|
|
397f688300 | ||
|
|
8bd4b1b9a8 | ||
|
|
54d029c181 | ||
|
|
e6a4636147 | ||
|
|
efb4162926 | ||
|
|
6061232e10 | ||
|
|
ba6b8c8f9b | ||
|
|
9c16ba0075 | ||
|
|
02b987909b | ||
|
|
1bcc54bb05 | ||
|
|
5a5b0b905b | ||
|
|
44ed49c7d2 | ||
|
|
386baa3840 | ||
|
|
f1a56ad6bc | ||
|
|
465bb9f7a0 | ||
|
|
f9b7525d44 | ||
|
|
c7e82295c2 | ||
|
|
e02cf28b54 | ||
|
|
18c51e8e73 | ||
|
|
88b444e796 | ||
|
|
71635b33b6 |
8
.env
8
.env
@@ -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='[]'
|
||||
|
||||
@@ -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
2583
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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 ? (
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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');
|
||||
},
|
||||
|
||||
@@ -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}}
|
||||
}`,
|
||||
|
||||
87
src/plugin-slots/AdditionalProfileFieldsSlot/README.md
Normal file
87
src/plugin-slots/AdditionalProfileFieldsSlot/README.md
Normal 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.
|
||||
|
||||

|
||||
|
||||
### 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.
|
||||
104
src/plugin-slots/AdditionalProfileFieldsSlot/example/index.jsx
Normal file
104
src/plugin-slots/AdditionalProfileFieldsSlot/example/index.jsx
Normal 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 |
32
src/plugin-slots/AdditionalProfileFieldsSlot/index.jsx
Normal file
32
src/plugin-slots/AdditionalProfileFieldsSlot/index.jsx
Normal 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;
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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/)
|
||||
|
||||
Reference in New Issue
Block a user