Skip to content

Commit 72d8b77

Browse files
committed
Expand from one saved setting per profile to multiple saved settings per profile
1 parent 569d45a commit 72d8b77

33 files changed

Lines changed: 360 additions & 40 deletions

src/common/api/profiles.api.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
PROFILE_API_ENDPOINT,
33
PROFILE_METADATA_API_ENDPOINT,
44
PROFILE_PREFERRED_API_ENDPOINT,
5-
PROFILE_SETTINGS_API_ENDPOINT,
5+
PROFILE_SETTINGS_PATH,
66
} from '@/common/constants/api.constants';
77

88
import baseApi from './base.api';
@@ -52,13 +52,18 @@ export const deletePreferredProfile = (resourceType: ResourceTypeURL) => {
5252
});
5353
};
5454

55-
export const fetchProfileSettings = (profileId: string | number) =>
55+
export const fetchAllSettingsForProfile = (profileId: string | number) =>
5656
baseApi.getJson({
57-
url: `${PROFILE_SETTINGS_API_ENDPOINT}/${profileId}`,
57+
url: `${PROFILE_API_ENDPOINT}/${profileId}/${PROFILE_SETTINGS_PATH}`,
58+
}) as Promise<ProfileSettingsMetaList>;
59+
60+
export const fetchProfileSettings = (profileId: string | number, profileSettingsId: string | number) =>
61+
baseApi.getJson({
62+
url: `${PROFILE_API_ENDPOINT}/${profileId}/${PROFILE_SETTINGS_PATH}/${profileSettingsId}`,
5863
}) as Promise<ProfileSettings>;
5964

60-
export const saveProfileSettings = (profileId: string | number, settings: ProfileSettings) => {
61-
const url = `${PROFILE_SETTINGS_API_ENDPOINT}/${profileId}`;
65+
export const createProfileSettings = (profileId: string | number, settings: ProfileSettings) => {
66+
const url = `${PROFILE_API_ENDPOINT}/${profileId}/${PROFILE_SETTINGS_PATH}`;
6267
const body = JSON.stringify(settings);
6368

6469
return baseApi.request({
@@ -72,3 +77,23 @@ export const saveProfileSettings = (profileId: string | number, settings: Profil
7277
},
7378
});
7479
};
80+
81+
export const saveProfileSettings = (
82+
profileId: string | number,
83+
profileSettingsId: string | number,
84+
settings: ProfileSettings,
85+
) => {
86+
const url = `${PROFILE_API_ENDPOINT}/${profileId}/${PROFILE_SETTINGS_PATH}/${profileSettingsId}`;
87+
const body = JSON.stringify(settings);
88+
89+
return baseApi.request({
90+
url,
91+
requestParams: {
92+
method: 'PUT',
93+
body,
94+
headers: {
95+
'content-type': 'application/json',
96+
},
97+
},
98+
});
99+
};

src/common/constants/api.constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const INVENTORY_API_ENDPOINT = '/linked-data/inventory-instance';
99
export const PROFILE_API_ENDPOINT = '/linked-data/profile';
1010
export const PROFILE_METADATA_API_ENDPOINT = '/linked-data/profile/metadata';
1111
export const PROFILE_PREFERRED_API_ENDPOINT = '/linked-data/profile/preferred';
12-
export const PROFILE_SETTINGS_API_ENDPOINT = '/linked-data/profile/settings';
12+
export const PROFILE_SETTINGS_PATH = 'settings';
1313
export const AUTHORITY_ASSIGNMENT_CHECK_API_ENDPOINT = '/linked-data/authority-assignment-check';
1414
export const IMPORT_JSON_FILE_API_ENDPOINT = '/linked-data/import/file';
1515
export const IMPORT_JSON_URL_API_ENDPOINT = '/linked-data/import/url';

src/features/manageProfileSettings/components/ModalCloseProfileSettings/ModalCloseProfileSettings.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Modal } from '@/components/Modal';
77

88
import { useManageProfileSettingsState, useUIState } from '@/store';
99

10-
import { useSaveProfileSettings } from '../../hooks';
10+
import { useResetSettings, useSaveProfileSettings } from '../../hooks';
1111

1212
import './ModalCloseProfileSettings.scss';
1313

@@ -26,8 +26,10 @@ export const ModalCloseProfileSettings: FC<ModalCloseProfileSettingsProps> = ({
2626
'setIsClosingNext',
2727
'nextSelectedProfile',
2828
'setSelectedProfile',
29+
'resetSelectedProfileSettingsMeta',
2930
'setIsModified',
3031
]);
32+
const { resetSettings } = useResetSettings();
3133
const { setIsManageProfileSettingsShowProfiles, setIsManageProfileSettingsShowEditor } = useUIState([
3234
'setIsManageProfileSettingsShowProfiles',
3335
'setIsManageProfileSettingsShowEditor',
@@ -41,6 +43,7 @@ export const ModalCloseProfileSettings: FC<ModalCloseProfileSettingsProps> = ({
4143
navigate(searchResultsUri);
4244
} else if (nextSelectedProfile) {
4345
setSelectedProfile(nextSelectedProfile);
46+
resetSettings();
4447
setIsManageProfileSettingsShowProfiles(false);
4548
setIsManageProfileSettingsShowEditor(true);
4649
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.modal-create-saved-setting {
2+
min-width: 475px;
3+
}

src/features/manageProfileSettings/components/ModalCreateSavedSetting/ModalCreateSavedSetting.test.tsx

Whitespace-only changes.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { ChangeEvent, FC, useEffect, useState } from 'react';
2+
import { FormattedMessage, useIntl } from 'react-intl';
3+
4+
import { Input } from '@/components/Input';
5+
import { Modal } from '@/components/Modal';
6+
7+
import { useSaveProfileSettings } from '../../hooks';
8+
9+
import './ModalCreateSavedSetting.scss';
10+
11+
type ModalCreateSavedSettingProps = {
12+
isOpen: boolean;
13+
setIsOpen: (isOpen: boolean) => void;
14+
};
15+
16+
export const ModalCreateSavedSetting: FC<ModalCreateSavedSettingProps> = ({ isOpen, setIsOpen }) => {
17+
const [isEmpty, setIsEmpty] = useState(false);
18+
const [name, setName] = useState('');
19+
const { formatMessage } = useIntl();
20+
const { saveSettings } = useSaveProfileSettings();
21+
22+
const handleNameChange = (evt: ChangeEvent<HTMLInputElement, Element>) => {
23+
setName(evt.target.value);
24+
};
25+
26+
const handleClose = () => {
27+
setName('');
28+
setIsOpen(false);
29+
};
30+
31+
const handleSubmit = async () => {
32+
await saveSettings(name);
33+
handleClose();
34+
};
35+
36+
useEffect(() => {
37+
setIsEmpty(name.length === 0);
38+
}, [name]);
39+
40+
return (
41+
<Modal
42+
data-testid="modal-create-saved-setting"
43+
className="modal-create-saved-setting"
44+
isOpen={isOpen}
45+
onClose={handleClose}
46+
onCancel={handleClose}
47+
onSubmit={handleSubmit}
48+
title={<FormattedMessage id="ld.profileSettings.createSavedSetting" />}
49+
cancelButtonLabel={formatMessage({ id: 'ld.cancel' })}
50+
submitButtonLabel={formatMessage({ id: 'ld.create.base' })}
51+
submitButtonDisabled={isEmpty}
52+
>
53+
<p>Provide a name for these saved profile settings.</p>
54+
<p>
55+
<label>
56+
Name
57+
<Input value={name} onChange={handleNameChange} />
58+
</label>
59+
</p>
60+
</Modal>
61+
);
62+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { ModalCreateSavedSetting } from './ModalCreateSavedSetting';

src/features/manageProfileSettings/components/ProfileSettings/ProfileSettings.tsx

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,22 @@ import ArrowLeftIcon from '@/assets/arrow-left-16.svg?react';
1717
import { CustomProfileToggle } from '../CustomProfileToggle';
1818
import { DefaultProfileOption } from '../DefaultProfileOption';
1919
import { ProfileSettingsEditor } from '../ProfileSettingsEditor';
20+
import { ProfileSettingsList } from '../ProfileSettingsList';
2021

2122
import './ProfileSettings.scss';
2223

2324
export const ProfileSettings = () => {
2425
const { setIsLoading } = useLoadingState();
2526
const { loadProfile } = useLoadProfile();
2627
const { loadProfileSettings } = useLoadProfileSettings();
27-
const { selectedProfile, setFullProfile, setProfileSettings } = useManageProfileSettingsState([
28-
'selectedProfile',
29-
'setFullProfile',
30-
'setProfileSettings',
31-
]);
28+
const { selectedProfile, selectedProfileSettingsMeta, setFullProfile, setProfileSettings, resetProfileSettings } =
29+
useManageProfileSettingsState([
30+
'selectedProfile',
31+
'selectedProfileSettingsMeta',
32+
'setFullProfile',
33+
'setProfileSettings',
34+
'resetProfileSettings',
35+
]);
3236
const {
3337
isManageProfileSettingsBelowBreakpoint,
3438
isManageProfileSettingsShowEditor,
@@ -54,9 +58,20 @@ export const ProfileSettings = () => {
5458
setIsLoading(true);
5559
const profile = await loadProfile(selectedProfile.id);
5660
setFullProfile(profile);
57-
setProfileSettings(
58-
await loadProfileSettings(String(selectedProfile.id), profile, selectedProfile.resourceType),
59-
);
61+
if (selectedProfileSettingsMeta) {
62+
if (selectedProfileSettingsMeta.id === 'default') {
63+
resetProfileSettings();
64+
} else {
65+
setProfileSettings(
66+
await loadProfileSettings(
67+
selectedProfileSettingsMeta.id,
68+
String(selectedProfile.id),
69+
profile,
70+
selectedProfile.resourceType,
71+
),
72+
);
73+
}
74+
}
6075
} catch {
6176
addStatusMessagesItem?.(
6277
UserNotificationFactory.createMessage(StatusType.error, 'ld.errorLoadingProfileSettings'),
@@ -68,7 +83,7 @@ export const ProfileSettings = () => {
6883

6984
initialize();
7085
}
71-
}, [selectedProfile]);
86+
}, [selectedProfile, selectedProfileSettingsMeta]);
7287

7388
const showView =
7489
!isManageProfileSettingsBelowBreakpoint ||
@@ -96,6 +111,8 @@ export const ProfileSettings = () => {
96111

97112
<hr />
98113

114+
<ProfileSettingsList />
115+
99116
<CustomProfileToggle />
100117

101118
<ProfileSettingsEditor />
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@use '@/common/styles/common.scss' as *;
2+
3+
.profile-settings-selector {
4+
padding: 8px 15px 25px;
5+
display: flex;
6+
flex-direction: row;
7+
align-items: center;
8+
gap: 1rem;
9+
max-width: 915px;
10+
11+
label {
12+
white-space: nowrap;
13+
}
14+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { useMemo } from 'react';
2+
import { FormattedMessage, useIntl } from 'react-intl';
3+
4+
import { Button, ButtonType } from '@/components/Button';
5+
import { Select, SelectValue } from '@/components/Select';
6+
7+
import { useLoadProfileSettingsMeta } from '@/features/profiles';
8+
9+
import { useManageProfileSettingsState, useUIState } from '@/store';
10+
11+
import { useResetSettings } from '../../hooks';
12+
13+
import './ProfileSettingsList.scss';
14+
15+
const metaToOption = (meta: ProfileSettingsMeta) => {
16+
return {
17+
label: meta.name,
18+
value: String(meta.id),
19+
};
20+
};
21+
22+
export const ProfileSettingsList = () => {
23+
const { formatMessage } = useIntl();
24+
const SETTINGS_OPTION_DEFAULT = [
25+
{
26+
label: formatMessage({ id: 'ld.profileSettings.defaultSettings' }),
27+
value: 'default',
28+
},
29+
];
30+
31+
const { selectedProfile, selectedProfileSettingsMeta, setSelectedProfileSettingsMeta, setSettingsName } =
32+
useManageProfileSettingsState([
33+
'selectedProfile',
34+
'selectedProfileSettingsMeta',
35+
'setSelectedProfileSettingsMeta',
36+
'setSettingsName',
37+
]);
38+
const { setIsManageProfileSettingsCreateSavedSettingModalOpen } = useUIState([
39+
'setIsManageProfileSettingsCreateSavedSettingModalOpen',
40+
]);
41+
const { resetSettings } = useResetSettings();
42+
const { data: settingsMeta } = useLoadProfileSettingsMeta(selectedProfile.id);
43+
44+
const settingsMetaOptions = useMemo(() => {
45+
return settingsMeta ? SETTINGS_OPTION_DEFAULT.concat(settingsMeta.map(metaToOption)) : SETTINGS_OPTION_DEFAULT;
46+
}, [SETTINGS_OPTION_DEFAULT, settingsMeta]);
47+
48+
const handleChange = (selected: SelectValue) => {
49+
resetSettings();
50+
const settingMeta = settingsMeta?.find(meta => String(meta.id) === selected.value);
51+
setSelectedProfileSettingsMeta(settingMeta || null);
52+
setSettingsName(settingMeta?.name || '');
53+
};
54+
55+
return (
56+
<div data-testid="profile-settings-selector-section" className="profile-settings-selector">
57+
<label id="profile-settings-selector-label" htmlFor="profile-settings-selector">
58+
<FormattedMessage id="ld.profileSettings.savedSettings" />
59+
</label>
60+
<Select
61+
ariaLabelledBy="profile-settings-selector-label"
62+
data-testid="profile-settings-selector"
63+
id="profile-settings-selector"
64+
value={String(selectedProfileSettingsMeta?.id || 'default')}
65+
options={settingsMetaOptions}
66+
onChange={handleChange}
67+
/>
68+
<Button
69+
type={ButtonType.Highlighted}
70+
label="New"
71+
onClick={() => setIsManageProfileSettingsCreateSavedSettingModalOpen(true)}
72+
/>
73+
</div>
74+
);
75+
};

0 commit comments

Comments
 (0)