Skip to content

Commit dddfd90

Browse files
committed
feat: add visibility settings for extended profile fields in profile management
1 parent 300a52e commit dddfd90

File tree

6 files changed

+77
-30
lines changed

6 files changed

+77
-30
lines changed

src/profile/data/sagas.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ export function* handleSaveProfile(action) {
129129
'visibilityLanguageProficiencies',
130130
'visibilityName',
131131
'visibilitySocialLinks',
132+
'visibilityExtendedProfile',
132133
]);
133134

134135
if (Object.keys(preferencesDrafts).length > 0) {

src/profile/data/selectors.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ export const visibilitiesSelector = createSelector(
239239
visibilityLanguageProficiencies: preferences.visibilityLanguageProficiencies || 'all_users',
240240
visibilityName: preferences.visibilityName || 'all_users',
241241
visibilitySocialLinks: preferences.visibilitySocialLinks || 'all_users',
242+
visibilityExtendedProfile: preferences.visibilityExtendedProfile || 'all_users',
242243
};
243244
case 'private':
244245
return {
@@ -249,6 +250,7 @@ export const visibilitiesSelector = createSelector(
249250
visibilityLanguageProficiencies: 'private',
250251
visibilityName: 'private',
251252
visibilitySocialLinks: 'private',
253+
visibilityExtendedProfile: 'private',
252254
};
253255
case 'all_users':
254256
default:
@@ -264,6 +266,7 @@ export const visibilitiesSelector = createSelector(
264266
visibilityLanguageProficiencies: 'all_users',
265267
visibilityName: 'all_users',
266268
visibilitySocialLinks: 'all_users',
269+
visibilityExtendedProfile: 'all_users',
267270
};
268271
}
269272
},
@@ -312,6 +315,10 @@ export const formValuesSelector = createSelector(
312315
drafts.visibilitySocialLinks,
313316
visibilities.visibilitySocialLinks,
314317
),
318+
visibilityExtendedProfile: chooseFormValue(
319+
drafts.visibilityExtendedProfile,
320+
visibilities.visibilityExtendedProfile,
321+
),
315322
}),
316323
);
317324

src/profile/data/services.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,12 @@ export async function deleteProfilePhoto(username) {
8989
export async function getPreferences(username) {
9090
const { data } = await getHttpClient().get(`${getConfig().LMS_BASE_URL}/api/user/v1/preferences/${username}`);
9191

92-
return camelCaseObject(data);
92+
const processedData = camelCaseObject(data);
93+
94+
return {
95+
...processedData,
96+
visibilityExtendedProfile: JSON.parse(data['visibility.extended_profile']),
97+
};
9398
}
9499

95100
// PATCH PREFERENCES
@@ -105,8 +110,11 @@ export async function patchPreferences(username, params) {
105110
visibility_name: 'visibility.name',
106111
visibility_social_links: 'visibility.social_links',
107112
visibility_time_zone: 'visibility.time_zone',
113+
visibility_extended_profile: 'visibility.extended_profile',
108114
});
109115

116+
processedParams['visibility.extended_profile'] = JSON.stringify(processedParams['visibility.extended_profile']);
117+
110118
await getHttpClient().patch(`${getConfig().LMS_BASE_URL}/api/user/v1/preferences/${username}`, processedParams, {
111119
headers: { 'Content-Type': 'application/merge-patch+json' },
112120
});

src/profile/forms/ExtendedProfileFields.jsx

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import PropTypes from 'prop-types';
3-
import { connect } from 'react-redux';
3+
import { connect, useSelector } from 'react-redux';
44
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
5-
import get from 'lodash.get';
6-
7-
// Mock Data
8-
import mockData from '../data/mock_data';
95

106
// Components
117
import EditableItemHeader from './elements/EditableItemHeader';
@@ -19,17 +15,41 @@ const ExtendedProfileFields = (props) => {
1915
extendedProfileFields, formId, changeHandler, submitHandler, closeHandler, openHandler, editMode,
2016
} = props;
2117

22-
// if (!learningGoal) {
23-
// learningGoal = mockData.learningGoal;
24-
// }
18+
const draftProfile = useSelector((state) => state.profilePage.drafts);
19+
const extendedProfile = useSelector((state) => state.profilePage.account.extendedProfile);
20+
const visibilityExtendedProfile = useSelector((state) => state.profilePage.preferences.visibilityExtendedProfile);
21+
const [currentEditingField, setCurrentEditingField] = useState(null);
22+
23+
const handleOpenEdit = (form) => {
24+
const [parentFormId, fieldId] = form.split('/');
25+
26+
openHandler(parentFormId);
27+
setCurrentEditingField(fieldId);
28+
};
29+
30+
const handleCloseEdit = () => {
31+
closeHandler(null);
32+
setCurrentEditingField(null);
33+
};
2534

26-
// if (!editMode || editMode === 'empty') { // editMode defaults to 'empty', not sure why yet
27-
// editMode = mockData.editMode;
28-
// }
35+
const handleChangeExtendedField = (name, value) => {
36+
const [parentFormId, fieldName] = name.split('/');
37+
if (name.includes('visibility')) {
38+
changeHandler(parentFormId, { [fieldName]: value });
39+
} else {
40+
const fieldIndex = extendedProfile.findIndex((field) => field.fieldName === fieldName);
41+
const newFields = extendedProfile.map(
42+
(extendedField, index) => (index === fieldIndex ? { ...extendedField, fieldValue: value } : extendedField),
43+
);
44+
changeHandler(parentFormId, newFields);
45+
}
46+
};
2947

30-
// if (!visibilityLearningGoal) {
31-
// visibilityLearningGoal = mockData.visibilityLearningGoal;
32-
// }
48+
const handleSubmitExtendedField = (form) => {
49+
const [parentFormId] = form.split('/');
50+
submitHandler(parentFormId);
51+
setCurrentEditingField(null);
52+
};
3353

3454
return extendedProfileFields?.map((field) => (
3555
<SwitchContent
@@ -46,24 +66,30 @@ const ExtendedProfileFields = (props) => {
4666
),
4767
text: (
4868
<TextField
49-
formId={formId}
50-
changeHandler={changeHandler}
51-
submitHandler={submitHandler}
52-
closeHandler={closeHandler}
53-
openHandler={openHandler}
54-
editMode={editMode}
69+
formId={`${formId}/${field.name}`}
70+
editMode={currentEditingField === field.name ? editMode : 'editable'}
71+
changeHandler={handleChangeExtendedField}
72+
submitHandler={handleSubmitExtendedField}
73+
closeHandler={handleCloseEdit}
74+
openHandler={handleOpenEdit}
5575
{...field}
5676
/>
5777
),
5878
select: (
5979
<SelectField
60-
formId={formId}
61-
changeHandler={changeHandler}
62-
submitHandler={submitHandler}
63-
closeHandler={closeHandler}
64-
openHandler={openHandler}
65-
editMode={editMode}
80+
formId={`${formId}/${field.name}`}
81+
editMode={currentEditingField === field.name ? editMode : 'editable'}
82+
changeHandler={handleChangeExtendedField}
83+
submitHandler={handleSubmitExtendedField}
84+
closeHandler={handleCloseEdit}
85+
openHandler={handleOpenEdit}
6686
{...field}
87+
value={draftProfile?.extendedProfile?.find(
88+
(extendedField) => extendedField.fieldName === field.name,
89+
)?.fieldValue ?? field.value}
90+
visibility={
91+
draftProfile?.visibilityExtendedProfile?.[field.name] ?? visibilityExtendedProfile?.[field.name]
92+
}
6793
/>
6894
),
6995
}}

src/profile/forms/elements/SelectField.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import FormControls from './FormControls';
66
import EditableItemHeader from './EditableItemHeader';
77
import EmptyContent from './EmptyContent';
88
import SwitchContent from './SwitchContent';
9+
import { capitalizeFirstLetter } from '../../utils';
910

1011
const SelectField = ({
1112
formId,
@@ -76,7 +77,7 @@ const SelectField = ({
7677
)}
7778
</Form.Group>
7879
<FormControls
79-
visibilityId={`visibility${formId}`}
80+
visibilityId={`visibility${capitalizeFirstLetter(formId)}`}
8081
saveState={saveState}
8182
visibility={visibility}
8283
cancelHandler={handleClose}
@@ -131,7 +132,7 @@ SelectField.propTypes = {
131132
code: PropTypes.string.isRequired,
132133
name: PropTypes.string.isRequired,
133134
})).isRequired,
134-
fieldMessages: PropTypes.objectOf(PropTypes.string).isRequired,
135+
// fieldMessages: PropTypes.objectOf(PropTypes.string).isRequired,
135136
label: PropTypes.string.isRequired,
136137
emptyMessage: PropTypes.string.isRequired,
137138
changeHandler: PropTypes.func.isRequired,

src/profile/utils.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ export function modifyObjectKeys(object, modify) {
2323
return result;
2424
}
2525

26+
export function capitalizeFirstLetter(val) {
27+
return String(val).charAt(0).toUpperCase() + String(val).slice(1);
28+
}
29+
2630
export function camelCaseObject(object) {
2731
return modifyObjectKeys(object, camelCase);
2832
}

0 commit comments

Comments
 (0)