Skip to content

Commit 7209093

Browse files
fix: same title entities (#584)
* fix: same title entities * fix: run lint * fix: improve navigation empty state * fix: fix undefined path
1 parent f6a909d commit 7209093

35 files changed

Lines changed: 2468 additions & 1864 deletions

File tree

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { useCallback } from 'react';
2+
import { useIntl } from 'react-intl';
3+
4+
import { Plus } from '@strapi/icons';
5+
import { Box, Button } from '@strapi/design-system';
6+
7+
import { ToBeFixed } from '../../../../../types';
8+
import { changeCollapseItemDeep } from '../../../utils';
9+
import { NavigationSchema } from '../../../../../api/validators';
10+
import { getTrad } from '../../../../../translations';
11+
12+
type ManageNavigationItemsProps = {
13+
currentNavigation: NavigationSchema | undefined;
14+
setCurrentNavigation: (navigation: NavigationSchema) => void;
15+
canUpdate: boolean;
16+
addNewNavigationItem: (
17+
event: MouseEvent,
18+
viewParentId?: number,
19+
isMenuAllowedLevel?: boolean,
20+
levelPath?: string,
21+
parentAttachedToMenu?: boolean,
22+
structureId?: string,
23+
maxOrder?: number
24+
) => void;
25+
};
26+
27+
export const ManageNavigationItems: React.FC<ManageNavigationItemsProps> = ({
28+
currentNavigation,
29+
setCurrentNavigation,
30+
canUpdate,
31+
addNewNavigationItem,
32+
}) => {
33+
const { formatMessage } = useIntl();
34+
35+
const handleExpandAll = useCallback(() => {
36+
if (currentNavigation) {
37+
setCurrentNavigation({
38+
...currentNavigation,
39+
items: currentNavigation.items.map((item) => changeCollapseItemDeep(item, false)),
40+
});
41+
}
42+
}, [setCurrentNavigation, currentNavigation, changeCollapseItemDeep]);
43+
44+
const handleCollapseAll = useCallback(() => {
45+
if (currentNavigation) {
46+
setCurrentNavigation({
47+
...currentNavigation,
48+
items: currentNavigation.items.map((item) => changeCollapseItemDeep(item, true)),
49+
});
50+
}
51+
}, [setCurrentNavigation, currentNavigation, changeCollapseItemDeep]);
52+
53+
const handleNewNavigationItem = useCallback(
54+
(event: MouseEvent) => {
55+
const maxOrder = (currentNavigation?.items ?? []).reduce(
56+
(acc, { order }) => Math.max(acc, order),
57+
0
58+
);
59+
addNewNavigationItem(
60+
event,
61+
undefined,
62+
true,
63+
'',
64+
true,
65+
currentNavigation?.items.length.toString(),
66+
maxOrder + 1
67+
);
68+
},
69+
[addNewNavigationItem, currentNavigation?.items]
70+
);
71+
72+
const actions = [
73+
{
74+
onClick: handleExpandAll,
75+
type: 'submit',
76+
variant: 'tertiary',
77+
tradId: 'header.action.expandAll',
78+
margin: '8px',
79+
},
80+
{
81+
onClick: handleCollapseAll,
82+
type: 'submit',
83+
variant: 'tertiary',
84+
tradId: 'header.action.collapseAll',
85+
margin: '8px',
86+
},
87+
] as Array<ToBeFixed>;
88+
89+
if (canUpdate) {
90+
actions.push({
91+
onClick: handleNewNavigationItem as ToBeFixed,
92+
type: 'submit',
93+
variant: 'primary',
94+
tradId: 'header.action.newItem',
95+
startIcon: <Plus />,
96+
margin: '8px',
97+
});
98+
}
99+
100+
return actions.map(({ tradId, margin, ...item }, i) => (
101+
<Box marginLeft={margin} key={i}>
102+
<Button {...item}> {formatMessage(getTrad(tradId))} </Button>
103+
</Box>
104+
));
105+
};

admin/src/pages/HomePage/components/Search/index.tsx renamed to admin/src/pages/HomePage/components/NavigationContentHeader/Search/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { Search as SearchIcon } from '@strapi/icons';
33
import { ChangeEvent, useCallback, useEffect, useRef, useState } from 'react';
44
import { useIntl } from 'react-intl';
55

6-
import { getTrad } from '../../../../translations';
7-
import { Effect } from '../../../../types';
6+
import { getTrad } from '../../../../../translations';
7+
import { Effect } from '../../../../../types';
88

99
interface Props {
1010
value: string;
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import { useCallback } from 'react';
2+
import { useIntl } from 'react-intl';
3+
4+
import {
5+
Box,
6+
Button,
7+
Flex,
8+
SingleSelect,
9+
SingleSelectOption,
10+
Typography,
11+
} from '@strapi/design-system';
12+
import { ListPlus } from '@strapi/icons';
13+
14+
import { getTrad } from '../../../../translations';
15+
import {
16+
useCopyNavigationI18n,
17+
useI18nCopyNavigationItemsModal,
18+
useResetContentTypes,
19+
useResetNavigations,
20+
} from '../../hooks';
21+
import { NavigationSchema } from '../../../../api/validators';
22+
import { appendViewId } from '../../utils/appendViewId';
23+
24+
type NavigationEmptyStateProps = {
25+
canUpdate: boolean;
26+
addNewNavigationItem: any;
27+
availableLocale: string[];
28+
availableNavigations: NavigationSchema[];
29+
currentNavigation: NavigationSchema | undefined;
30+
setCurrentNavigation: (navigation: NavigationSchema) => void;
31+
};
32+
33+
export const NavigationEmptyState: React.FC<NavigationEmptyStateProps> = ({
34+
canUpdate,
35+
addNewNavigationItem,
36+
availableLocale,
37+
availableNavigations,
38+
currentNavigation,
39+
setCurrentNavigation,
40+
}) => {
41+
const copyNavigationI18nMutation = useCopyNavigationI18n();
42+
43+
const { formatMessage } = useIntl();
44+
45+
const resetContentTypes = useResetContentTypes();
46+
const resetNavigations = useResetNavigations();
47+
48+
const {
49+
i18nCopyItemsModal,
50+
i18nCopySourceLocale,
51+
setI18nCopyModalOpened,
52+
setI18nCopySourceLocale,
53+
} = useI18nCopyNavigationItemsModal(
54+
useCallback(
55+
(sourceLocale) => {
56+
const source = availableNavigations.find(
57+
({ locale, documentId }) =>
58+
locale === sourceLocale && documentId === currentNavigation?.documentId
59+
);
60+
61+
if (source) {
62+
if (source.documentId && currentNavigation?.documentId) {
63+
copyNavigationI18nMutation.mutate(
64+
{
65+
source: source.locale,
66+
target: currentNavigation.locale,
67+
documentId: source.documentId,
68+
},
69+
{
70+
onSuccess(res) {
71+
copyNavigationI18nMutation.reset();
72+
setCurrentNavigation({
73+
...res.data,
74+
items: res.data.items.map(appendViewId),
75+
});
76+
resetContentTypes();
77+
resetNavigations();
78+
},
79+
}
80+
);
81+
}
82+
}
83+
},
84+
[currentNavigation]
85+
)
86+
);
87+
88+
const openI18nCopyModalOpened = useCallback(() => {
89+
i18nCopySourceLocale && setI18nCopyModalOpened(true);
90+
}, [setI18nCopyModalOpened, i18nCopySourceLocale]);
91+
92+
return (
93+
<Flex direction="column" minHeight="400px" justifyContent="center">
94+
<Box padding={4}>
95+
<Typography variant="beta" textColor="neutral600">
96+
{formatMessage(getTrad('empty.description'))}
97+
</Typography>
98+
</Box>
99+
{canUpdate && (
100+
<Button
101+
variant="secondary"
102+
startIcon={<ListPlus />}
103+
label={formatMessage(getTrad('empty.cta'))}
104+
onClick={addNewNavigationItem}
105+
>
106+
{formatMessage(getTrad('empty.cta'))}
107+
</Button>
108+
)}
109+
{canUpdate && !!availableLocale.length && (
110+
<Flex direction="column" justifyContent="center">
111+
<Box paddingTop={3} paddingBottom={3}>
112+
<Typography variant="beta" textColor="neutral600">
113+
{formatMessage(getTrad('view.i18n.fill.cta.header'))}
114+
</Typography>
115+
</Box>
116+
<Flex direction="row" justifyContent="center" alignItems="center">
117+
<Box paddingLeft={1} paddingRight={1}>
118+
<SingleSelect
119+
onChange={setI18nCopySourceLocale}
120+
value={i18nCopySourceLocale}
121+
size="S"
122+
>
123+
{availableLocale.map((locale) => (
124+
<SingleSelectOption key={locale} value={locale}>
125+
{formatMessage(getTrad('view.i18n.fill.option'), { locale })}
126+
</SingleSelectOption>
127+
))}
128+
</SingleSelect>
129+
</Box>
130+
<Box paddingLeft={1} paddingRight={1}>
131+
<Button
132+
variant="tertiary"
133+
onClick={openI18nCopyModalOpened}
134+
disabled={!i18nCopySourceLocale}
135+
size="S"
136+
>
137+
{formatMessage(getTrad('view.i18n.fill.cta.button'))}
138+
</Button>
139+
</Box>
140+
</Flex>
141+
</Flex>
142+
)}
143+
{canUpdate && i18nCopyItemsModal}
144+
</Flex>
145+
);
146+
};

admin/src/pages/HomePage/components/AdditionalFieldInput/index.tsx renamed to admin/src/pages/HomePage/components/NavigationItemForm/components/AdditionalFields/AdditionalFieldInput/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import { useEffect, useMemo } from 'react';
1111
import { useIntl } from 'react-intl';
1212

1313
import { Toggle } from '@strapi/design-system';
14-
import { NavigationItemCustomField } from '../../../../schemas';
15-
import { getTrad } from '../../../../translations';
14+
import { NavigationItemCustomField } from '../../../../../../../schemas';
15+
import { getTrad } from '../../../../../../../translations';
1616

1717
export type AdditionalFieldInputProps = {
1818
name?: string;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { useMemo } from 'react';
2+
import { useIntl } from 'react-intl';
3+
import { isEmpty } from 'lodash';
4+
5+
import { Grid, MultiSelect, MultiSelectOption } from '@strapi/design-system';
6+
import { Field } from '@sensinum/strapi-utils';
7+
8+
import { getTrad } from '../../../../../../../translations';
9+
import { FormChangeEvent } from '../../../../../../../types';
10+
import { useNavigationItemFormContext } from '../../../context/NavigationItemFormContext';
11+
import { useConfig } from '../../../../../hooks';
12+
13+
export const AudienceField = () => {
14+
const { formatMessage } = useIntl();
15+
16+
const configQuery = useConfig();
17+
18+
const availableAudiences = configQuery.data?.availableAudience ?? [];
19+
20+
const audienceOptions = useMemo(
21+
() =>
22+
availableAudiences.map((item) => ({
23+
value: item.documentId ?? 0,
24+
label: item.name ?? ' ',
25+
})),
26+
[availableAudiences]
27+
);
28+
29+
const { isLoading, renderError, onChange, handleChange, values } = useNavigationItemFormContext();
30+
31+
return (
32+
<Grid.Item alignItems="flex-start" key="audience" col={12}>
33+
<Field
34+
name="audience"
35+
label={formatMessage(getTrad('popup.item.form.audience.label'))}
36+
error={renderError('audience')}
37+
hint={
38+
!isLoading && isEmpty(audienceOptions)
39+
? formatMessage(getTrad('popup.item.form.title.placeholder', 'e.g. Blog'))
40+
: undefined
41+
}
42+
>
43+
<MultiSelect
44+
name="audience"
45+
value={values.audience}
46+
onChange={(eventOrPath: FormChangeEvent) =>
47+
handleChange('audience', eventOrPath, onChange)
48+
}
49+
width="100%"
50+
>
51+
{audienceOptions.map(({ value, label }) => (
52+
<MultiSelectOption key={value} value={value}>
53+
{label}
54+
</MultiSelectOption>
55+
))}
56+
</MultiSelect>
57+
</Field>
58+
</Grid.Item>
59+
);
60+
};
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Grid } from '@strapi/design-system';
2+
import { Field } from '@sensinum/strapi-utils';
3+
import { useNavigationItemFormContext } from '../../../context/NavigationItemFormContext';
4+
import { get } from 'lodash';
5+
import { AdditionalFieldInput } from '../AdditionalFieldInput';
6+
import { NavigationItemCustomField } from '../../../../../../../schemas';
7+
8+
type CustomFieldsFieldProps = {
9+
additionalField: NavigationItemCustomField;
10+
};
11+
12+
export const CustomFieldsField: React.FC<CustomFieldsFieldProps> = ({ additionalField }) => {
13+
const { canUpdate, isLoading, onChange, handleChange, renderError, values } =
14+
useNavigationItemFormContext();
15+
16+
return (
17+
<Grid.Item alignItems="flex-start" key={additionalField.name} col={6}>
18+
<Field
19+
name={`additionalFields.${additionalField.name}`}
20+
label={additionalField.label}
21+
hint={additionalField.description}
22+
required={additionalField.required}
23+
error={renderError(`additionalFields.${additionalField.name}`)}
24+
>
25+
<AdditionalFieldInput
26+
name={`additionalFields.${additionalField.name}`}
27+
field={additionalField}
28+
isLoading={isLoading}
29+
onChange={onChange}
30+
onChangeEnhancer={handleChange}
31+
value={get(values?.additionalFields, additionalField.name)}
32+
disabled={!canUpdate}
33+
/>
34+
</Field>
35+
</Grid.Item>
36+
);
37+
};

0 commit comments

Comments
 (0)