Skip to content

Commit

Permalink
feat: added locale
Browse files Browse the repository at this point in the history
  • Loading branch information
Martijn-Schoenmaker-Webbio committed Jan 29, 2024
1 parent bc86b80 commit 091f7cd
Show file tree
Hide file tree
Showing 13 changed files with 222 additions and 82 deletions.
36 changes: 36 additions & 0 deletions src/plugins/strapi-plugin-internal-links/admin/src/api/locales.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useQuery } from 'react-query';

import { useFetchClient } from '@strapi/helper-plugin';

const QUERY_KEY = 'locales';

export type Locale = {
id: number;
code: string;
name?: string;
isDefault?: boolean;
createdAt?: string;
updatedAt?: string;
};

export const fetchLocales = async ({ fetchClient }: Record<string, any>): Promise<Locale[] | undefined> => {
try {
const { get } = fetchClient;
const { data } = await get('i18n/locales');

return data;
} catch {
return undefined;
}
};

export const useGetLocales = (params: Record<string, any>) => {
const fetchClient = useFetchClient();

return useQuery<Locale[] | undefined, Error>([QUERY_KEY], () =>
fetchLocales({
...params,
fetchClient
})
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { FieldLabel } from '@strapi/design-system';

import S from './styles';
import { useReactSelectCustomStyles } from './react-select-custom-styles';
import { Label } from '../label';

export interface IComboboxProps extends AsyncProps<IReactSelectValue, false, GroupBase<IReactSelectValue>> {
customOption?: typeof components.Option<IReactSelectValue, false, GroupBase<IReactSelectValue>>;
Expand Down Expand Up @@ -35,12 +36,12 @@ const Combobox = (props: IComboboxProps) => {
return (
<S.Wrapper>
{props.label && (
<S.LabelWrapper>
<Label>
<FieldLabel action={labelAction} required={required}>
{props.label}
</FieldLabel>
{extraLabelElement}
</S.LabelWrapper>
</Label>
)}
<AsyncSelect
{...selectProps}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,9 @@ const Option = styled.span`
flex-direction: column;
`;

const LabelWrapper = styled.div`
${({ theme }) => css`
width: 100%;
display: flex;
gap: 4px;
justify-content: space-between;
color: ${theme.colors.neutral800};
font-size: ${theme.fontSizes[1]};
`}
`;

const ComboboxStyles = {
Wrapper,
Option,
LabelWrapper
Option
};

export default ComboboxStyles;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useFetchClient } from '@strapi/helper-plugin';

import { IContentTypeOption } from './use-content-type-options';
import pluginId from '../../../plugin-id';
import { useGetDefaultStrapiLocale } from '../../../utils/use-get-default-locale';
import { useGetStrapiLocales } from '../../../utils/use-get-strapi-locales';

export interface IPageOption {
id: number;
Expand Down Expand Up @@ -60,7 +60,7 @@ const fetchPageOptions = async (
};

export const usePageOptions = (contentType?: IContentTypeOption, initialId?: string | number | null) => {
const { defaultLocale } = useGetDefaultStrapiLocale();
const { defaultLocale } = useGetStrapiLocales();
const fetchClient = useFetchClient();

const { data, status, isLoading, isFetching, isError } = useQuery(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState, useLayoutEffect, useEffect, ChangeEvent } from 'react'
import * as yup from 'yup';
import { useIntl } from 'react-intl';
import { ReactSelect } from '@strapi/helper-plugin';
import { Alert, ToggleCheckbox, Stack, Button, FieldLabel, Field, FieldError, FieldInput } from '@strapi/design-system';
import { Alert, ToggleCheckbox, Stack, Button, Field, FieldError, FieldInput } from '@strapi/design-system';

import Option from './option';
import useContentTypeOptions, { IContentTypeOption } from './hooks/use-content-type-options';
Expand All @@ -15,6 +15,7 @@ import { PageSearch } from './page-select';
import { Platform } from '../../api/platform';
import { IInternalLinkAttribute } from '..';
import { useGetConfig } from '../../api/config';
import { Label } from '../label';

interface IProps extends Omit<IUseInternalLinkInputReturn, 'initialLink' | 'isInitialData' | 'resetInternalLink'> {
attributeOptions?: IInternalLinkAttribute['options'];
Expand Down Expand Up @@ -247,11 +248,11 @@ const InternalLinkForm = ({ link, setLink, errors, setErrors, attributeOptions }

{shouldShowTitle && (
<Field name="text" id="text" error={errors.text} required>
<FieldLabel>
<Label>
{formatMessage({
id: getTrad('internal-link.form.text')
})}
</FieldLabel>
</Label>

<FieldInput type="text" value={link.text} onChange={onTextChange} onBlur={onTextBlur} required />

Expand All @@ -261,11 +262,11 @@ const InternalLinkForm = ({ link, setLink, errors, setErrors, attributeOptions }

{!isExternalTab && !isLoadingConfig && !useSinglePageType && (
<Field required>
<FieldLabel>
<Label>
{formatMessage({
id: getTrad('internal-link.form.collection')
})}
</FieldLabel>
</Label>

<ReactSelect
inputId="collection"
Expand Down Expand Up @@ -300,11 +301,11 @@ const InternalLinkForm = ({ link, setLink, errors, setErrors, attributeOptions }

{!isExternalTab && pageBuilderEnabled && platformOptions.length > 1 && (
<Field required>
<FieldLabel>
<Label>
{formatMessage({
id: getTrad('internal-link.form.platform')
})}
</FieldLabel>
</Label>

<ReactSelect
inputId="platform"
Expand Down Expand Up @@ -349,11 +350,11 @@ const InternalLinkForm = ({ link, setLink, errors, setErrors, attributeOptions }

{pluginConfig?.enableUrlAddition && !isExternalTab && (
<Field name="urlAddition" id="urlAddition">
<FieldLabel>
<Label>
{formatMessage({
id: getTrad('internal-link.form.urlAddition')
})}
</FieldLabel>
</Label>

<FieldInput
type="text"
Expand All @@ -368,11 +369,11 @@ const InternalLinkForm = ({ link, setLink, errors, setErrors, attributeOptions }

<div style={!isExternalTab ? { display: 'none' } : undefined}>
<Field name="link" id="link" error={errors.url} required>
<FieldLabel>
<Label>
{formatMessage({
id: getTrad(`internal-link.form.${translationLinkKey}`)
})}
</FieldLabel>
</Label>

<FieldInput
type="text"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import React from 'react';
import React, { useEffect } from 'react';
import { useIntl } from 'react-intl';
import debounce from 'lodash/debounce';
import { OptionProps, SingleValue, components } from 'react-select';
import { useCMEditViewDataManager, useFetchClient } from '@strapi/helper-plugin';
import { Flex, FieldLabel } from '@strapi/design-system';

import { Combobox, IReactSelectValue } from '../../Combobox';
import { getSearchFilteredEntities } from '../../../api/search-filtered-entity';
import { useGetLocaleFromUrl } from '../../../utils/use-get-locale-from-url';

import S from './styles';
import getTrad from '../../../utils/get-trad';
import { GlobalPluginConfig } from '../../../../../utils/config.types';
import { useGetEntity } from '../../../api/entity';
import { LocaleSelect } from './locale-select';

import S from './styles';
import { Label } from '../../label';

const SEARCH_DEBOUNCE_MS = 150;
const PAGE = 1;
Expand Down Expand Up @@ -39,21 +42,34 @@ export const PageSearch = ({ uid, selectedId, platformTitle, pageBuilderConfig,
const fetchClient = useFetchClient();
const form = useCMEditViewDataManager() as any;

const urlLocale = useGetLocaleFromUrl();
const selectedLocale = form.initialData?.locale || urlLocale;

const { data: entityFromId } = useGetEntity({
const {
data: entityFromId,
isLoading: isLoadingEntity,
dataUpdatedAt
} = useGetEntity({
uid,
id: selectedId,
pageBuilderConfig
});

const urlLocale = useGetLocaleFromUrl();
const [selectedLocale, setSelectedLocale] = React.useState<string | undefined>();

useEffect(() => {
if (!selectedLocale && !isLoadingEntity && dataUpdatedAt) {
setSelectedLocale(entityFromId?.locale || form.initialData?.locale || urlLocale);
}
}, [entityFromId]);

const selectedPageFromId = mapSelectItem(entityFromId);

const isPagePageType = !uid;
const searchEntitiesIsEnabled = !isPagePageType;

const getItems = async (inputValue?: string, platformTitle?: string): Promise<PageReactSelectValue[]> => {
if (!selectedLocale) {
return [];
}

const searchEntities = await getSearchFilteredEntities({
fetchClient,
page: PAGE,
Expand All @@ -78,6 +94,10 @@ export const PageSearch = ({ uid, selectedId, platformTitle, pageBuilderConfig,
};

const handleChange = (item?: SingleValue<PageReactSelectValue>) => onChange(item);
const handleLocaleChange = (locale?: string) => {
onChange();
setSelectedLocale(locale);
};

const debouncedFetch = debounce((searchTerm, callback, selectedPlatformTitle?: string) => {
promiseOptions(searchTerm, selectedPlatformTitle).then((result) => {
Expand All @@ -91,27 +111,42 @@ export const PageSearch = ({ uid, selectedId, platformTitle, pageBuilderConfig,
});

return (
<Combobox
key={`rerenderOnUidOrPlatformChange-${uid}-${platformTitle}`}
id="collectionTypeSearch"
label={formatMessage({
id: getTrad('internal-link.form.page')
})}
loadOptions={(i, c) => debouncedFetch(i, c, platformTitle)}
cacheOptions
// @ts-ignore onChange is correct
onChange={handleChange}
// @ts-ignore customOption is correct
customOption={CustomOption}
// @ts-ignore customOption is correct
value={selectedPageFromId}
defaultOptions={searchEntitiesIsEnabled}
placeholder={formatMessage({
id: getTrad('internal-link.form.page.placeholder')
})}
required
isDisabled={!uid}
/>
<Flex direction="column" width="100%">
<Label>
<FieldLabel required>
{formatMessage({
id: getTrad('internal-link.form.page')
})}
</FieldLabel>
</Label>
<Flex width="100%" gap={2}>
<LocaleSelect
onChange={handleLocaleChange}
isDisabled={isPagePageType}
value={selectedLocale}
isLoadingValue={isLoadingEntity || !dataUpdatedAt}
/>

<Combobox
key={`rerenderOnUidOrPlatformChange-${uid}-${platformTitle}-${selectedLocale}`}
id="collectionTypeSearch"
loadOptions={(i, c) => debouncedFetch(i, c, platformTitle)}
cacheOptions
// @ts-ignore onChange is correct
onChange={handleChange}
// @ts-ignore customOption is correct
customOption={CustomOption}
// @ts-ignore customOption is correct
value={selectedPageFromId}
defaultOptions={!isPagePageType}
placeholder={formatMessage({
id: getTrad('internal-link.form.page.placeholder')
})}
required
isDisabled={isPagePageType}
/>
</Flex>
</Flex>
);
};

Expand All @@ -126,8 +161,8 @@ const CustomOption = (props: OptionProps<PageReactSelectValue, false>) => {
);
};

const mapSelectItem = (initialValue?: Record<string, any>): SingleValue<PageReactSelectValue | null> =>
initialValue?.id
function mapSelectItem(initialValue?: Record<string, any>): SingleValue<PageReactSelectValue | null> {
return initialValue?.id
? {
id: initialValue.id,
value: String(initialValue?.id),
Expand All @@ -140,3 +175,4 @@ const mapSelectItem = (initialValue?: Record<string, any>): SingleValue<PageReac
locale: initialValue.locale || ''
}
: null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';
import { SingleSelect, SingleSelectOption } from '@strapi/design-system';

import { IReactSelectValue } from '../../Combobox';
import { useGetLocales } from '../../../api/locales';
import S from './styles';

export interface LocaleReactSelectValue extends Omit<IReactSelectValue, 'initialSelected'> {
id: number;
name?: string;
isDefault?: boolean;
}

interface Props {
isDisabled?: boolean;
onChange: (newValue?: string) => void;
value?: string;
isLoadingValue?: boolean;
}

export const LocaleSelect = ({ onChange, isDisabled, value, isLoadingValue }: Props) => {
const { data: allLocales } = useGetLocales({});

const handleChange = (item?: string) => {
onChange(item);
};

return (
<S.LocaleSelectWrapper>
<SingleSelect
required
disabled={isLoadingValue || isDisabled || (allLocales || [])?.length < 2}
value={value}
onChange={handleChange}
>
{(allLocales || []).map((l) => (
<SingleSelectOption value={l.code}>{l.code.toLocaleUpperCase()}</SingleSelectOption>
))}
</SingleSelect>
</S.LocaleSelectWrapper>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ const CustomOptionStatus = styled(Box)`
border-radius: 100px;
`;

const LocaleSelectWrapper = styled.div`
max-width: 64px;
`;

export default {
CustomOptionStatus,
CustomOption
CustomOption,
LocaleSelectWrapper
};
Loading

0 comments on commit 091f7cd

Please sign in to comment.