Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display flatpage children #1075

Merged
merged 5 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 43 additions & 13 deletions frontend/src/components/pages/flatPage/FlatPage.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import Loader from 'components/Loader';
import Image from 'next/image';
import { colorPalette } from 'stylesheet';
import parse from 'html-react-parser';
import { Footer } from 'components/Footer';
import { Separator } from 'components/Separator';
import { PageHead } from 'components/PageHead';
import styled from 'styled-components';
import { useIntl } from 'react-intl';
import { FormattedMessage, useIntl } from 'react-intl';
import { generateFlatPageUrl } from 'modules/header/utills';
import { getGlobalConfig } from 'modules/utils/api.config';
import { useFlatPage } from './useFlatPage';
import { DetailsSection } from '../details/components/DetailsSection';
import { ErrorFallback } from '../search/components/ErrorFallback';
Expand All @@ -17,10 +20,6 @@ interface FlatPageUIProps {
flatPageUrl: string;
}

const BreadcrumbWrapper = styled.div`
margin-left: 2rem;
`;

export const FlatPageUI: React.FC<FlatPageUIProps> = ({ flatPageUrl }) => {
const { flatPage, isLoading, refetch } = useFlatPage(flatPageUrl);
const intl = useIntl();
Expand All @@ -44,10 +43,12 @@ export const FlatPageUI: React.FC<FlatPageUIProps> = ({ flatPageUrl }) => {
className="relative coverDetailsMobile desktop:h-coverDetailsDesktop text-center"
id="flatPage_cover"
>
<img
<Image
src={flatPage.attachment}
className="size-full object-top object-cover"
alt=""
width={1500}
height={550}
/>
<TextWithShadow
className="text-H3 desktop:text-H1
Expand All @@ -62,12 +63,12 @@ export const FlatPageUI: React.FC<FlatPageUIProps> = ({ flatPageUrl }) => {
<div className="px-4 desktop:px-10vw py-4 desktop:py-10" id="flatPage_content">
{(flatPage.attachment == null || flatPage.attachment.length === 0) && (
<div className="flex justify-center py-6 desktop:py-12">
<p className="text-H3 desktop:text-H1 font-bold text-primary1 text-center">
<h1 className="text-H3 desktop:text-H1 font-bold text-primary1 text-center">
{flatPage.title}
</p>
</h1>
</div>
)}
<BreadcrumbWrapper>
<div className="ml-5">
<Breadcrumb
breadcrumb={[
{
Expand All @@ -77,14 +78,14 @@ export const FlatPageUI: React.FC<FlatPageUIProps> = ({ flatPageUrl }) => {
{ label: flatPage?.title },
]}
/>
</BreadcrumbWrapper>
</div>
{flatPage.content !== null && flatPage.content.length > 0 && (
<HtmlText>{parse(flatPage.content)}</HtmlText>
<HtmlText className="mb-10">{parse(flatPage.content)}</HtmlText>
)}
{flatPage.sources.length > 0 && (
<>
<Separator />
<DetailsSection titleId="details.source">
<DetailsSection className="mb-10" titleId="details.source">
<div>
{flatPage.sources.map((source, i) => (
<DetailsSource
Expand All @@ -98,6 +99,35 @@ export const FlatPageUI: React.FC<FlatPageUIProps> = ({ flatPageUrl }) => {
</DetailsSection>
</>
)}
{flatPage.children && flatPage.children.length > 0 && (
<>
<Separator />
<h2 className="my-6 desktop:my-10 text-Mobile-H1 desktop:text-H2 font-bold">
<FormattedMessage id="page.children.title" />
</h2>
<ul className="mb-6 desktop:mb-18 flex flex-wrap gap-5 desktop:grid desktop:grid-cols-3 desktop:gap-6">
{flatPage.children.map(child => (
<li className="w-70 desktop:w-auto" key={child.id}>
<a
className="relative block rounded-xl overflow-hidden group after:absolute bg-gradient-to-t from-gradientOnImages after:inset-0 after:content-[''] after:bg-black/25"
href={generateFlatPageUrl(child.id, child.title)}
>
<Image
src={child.attachment ?? getGlobalConfig().fallbackImageUri}
className="size-full object-cover object-center transition-transform group-hover:scale-105"
width={400}
height={400}
alt=""
/>
<span className="font-bold items-center desktop:text-lg text-white absolute z-10 bottom-4 right-4 left-4">
{child.title}
</span>
</a>
</li>
))}
</ul>
</>
)}
</div>
<Footer />
</div>
Expand All @@ -106,6 +136,6 @@ export const FlatPageUI: React.FC<FlatPageUIProps> = ({ flatPageUrl }) => {
);
};

const TextWithShadow = styled.p`
const TextWithShadow = styled.h1`
text-shadow: 0 0 20px ${colorPalette.home.shadowOnImages};
`;
8 changes: 6 additions & 2 deletions frontend/src/components/pages/flatPage/useFlatPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@ import { isUrlString } from 'modules/utils/string';
import { useRouter } from 'next/router';
import { useQuery } from '@tanstack/react-query';
import { ONE_DAY } from 'services/constants/staleTime';
import { useQueryCommonDictionaries } from 'modules/dictionaries/api';

export const useFlatPage = (flatPageUrl: string | undefined) => {
const language = useRouter().locale ?? getDefaultLanguage();
const path = isUrlString(flatPageUrl) ? decodeURI(flatPageUrl) : '';
const id = isUrlString(flatPageUrl) ? flatPageUrl.split('-')[0] : '';

const commonDictionaries = useQueryCommonDictionaries(language);

const { data, refetch, isLoading, error } = useQuery<FlatPageDetails, Error>(
['flatPageDetails', id, language],
() => getFlatPageDetails(id, language),
() => getFlatPageDetails(id, language, commonDictionaries),
{
enabled: isUrlString(flatPageUrl),
enabled: isUrlString(flatPageUrl) && commonDictionaries !== undefined,
staleTime: ONE_DAY,
},
);
Expand Down
14 changes: 13 additions & 1 deletion frontend/src/modules/flatpage/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,28 @@ export const adaptFlatPages = (rawFlatPages: RawFlatPage[]): MenuItem[] => {
export const adaptFlatPageDetails = ({
rawFlatPageDetails,
sourceDictionnary,
rawFlatPageChildrenDetails,
}: {
rawFlatPageDetails: RawFlatPageDetails;
sourceDictionnary: SourceDictionnary;
rawFlatPageChildrenDetails: RawFlatPageDetails[];
}): FlatPageDetails => ({
id: rawFlatPageDetails.id,
title: rawFlatPageDetails.title,
content: rawFlatPageDetails.content,
sources: rawFlatPageDetails.source.map(sourceId => sourceDictionnary[sourceId]),
sources: rawFlatPageDetails.source.map(sourceId => sourceDictionnary[sourceId]).filter(Boolean),
attachment:
rawFlatPageDetails.attachments.length > 0 && rawFlatPageDetails.attachments[0].type === 'image'
? rawFlatPageDetails.attachments[0].url
: null,
children: rawFlatPageChildrenDetails.map(child => ({
id: child.id,
title: child.title,
content: child.content,
sources: child.source.map(sourceId => sourceDictionnary[sourceId]).filter(Boolean),
attachment:
child.attachments.length > 0 && child.attachments[0].type === 'image'
? child.attachments[0].thumbnail
: null,
})),
});
8 changes: 8 additions & 0 deletions frontend/src/modules/flatpage/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,11 @@ export const fetchFlatPageDetails = (query: APIQuery, id: string): Promise<RawFl
GeotrekAPI.get(`/flatpage/${encodeURIComponent(id)}/`, {
params: { ...query, ...fieldsParamFlatPageDetails },
}).then(r => r.data);

export const fetchChildrenFlatPageDetails = (
query: APIQuery,
id: string,
): Promise<APIResponseForList<RawFlatPageDetails>> =>
GeotrekAPI.get(`/flatpage/`, {
params: { ...query, ...fieldsParamFlatPageDetails, parent: id },
}).then(r => r.data);
30 changes: 19 additions & 11 deletions frontend/src/modules/flatpage/connector.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { MenuItem } from 'modules/menuItems/interface';
import { getSources } from 'modules/source/connector';
import { CommonDictionaries } from 'modules/dictionaries/interface';
import { adaptFlatPageDetails, adaptFlatPages } from './adapter';
import { fetchFlatPageDetails, fetchFlatPages } from './api';
import { FlatPageDetails } from './interface';
import { fetchChildrenFlatPageDetails, fetchFlatPageDetails, fetchFlatPages } from './api';
import { FlatPageDetails, RawFlatPageDetails } from './interface';

export const getFlatPages = async (language: string): Promise<MenuItem[]> => {
const rawFlatPages = await fetchFlatPages({ language });
Expand All @@ -12,18 +12,26 @@ export const getFlatPages = async (language: string): Promise<MenuItem[]> => {
export const getFlatPageDetails = async (
id: string,
language: string,
commonDictionaries?: CommonDictionaries,
): Promise<FlatPageDetails> => {
const { sources = {} } = commonDictionaries || {};
let rawFlatPageDetails;
let rawFlatPageChildrenDetails: RawFlatPageDetails[] = [];
try {
const [rawFlatPageDetails, sourceDictionnary] = await Promise.all([
fetchFlatPageDetails({ language }, id),
getSources(language),
]);
return adaptFlatPageDetails({
rawFlatPageDetails,
sourceDictionnary,
});
rawFlatPageDetails = await fetchFlatPageDetails({ language }, id);
} catch (e) {
console.error('Error in flatpage connector', e);
throw e;
}
try {
rawFlatPageChildrenDetails = (await fetchChildrenFlatPageDetails({ language }, id)).results;
// Old version of flatPage don't have `children` property
} catch (e) {
/* empty */
}
return adaptFlatPageDetails({
rawFlatPageDetails,
sourceDictionnary: sources,
rawFlatPageChildrenDetails,
});
};
1 change: 1 addition & 0 deletions frontend/src/modules/flatpage/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ export interface FlatPageDetails {
content: string;
sources: Source[];
attachment: string | null;
children?: FlatPageDetails[];
}
5 changes: 4 additions & 1 deletion frontend/src/pages/information/[flatPage].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useRouter } from 'next/router';
import { FlatPageUI } from 'components/pages/flatPage';
import { dehydrate, QueryClient } from '@tanstack/react-query';
import { routes } from 'services/routes';
import { getCommonDictionaries } from 'modules/dictionaries/connector';
import { getFlatPageDetails } from '../../modules/flatpage/connector';
import { isUrlString } from '../../modules/utils/string';
import { redirectIfWrongUrl } from '../../modules/utils/url';
Expand All @@ -15,8 +16,10 @@ export const getServerSideProps: GetServerSideProps = async context => {

const queryClient = new QueryClient();

const details = await getFlatPageDetails(id, locale);
const commonDictionaries = await getCommonDictionaries(locale);
await queryClient.prefetchQuery(['commonDictionaries', locale], () => commonDictionaries);

const details = await getFlatPageDetails(id, locale, commonDictionaries);
await queryClient.prefetchQuery(['flatPageDetails', id, locale], () => details);

const redirect = redirectIfWrongUrl(
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/translations/ca.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
"page": {
"back": "Tornada",
"not-found": "No s’ha trobat la pàgina",
"goToOffline": "Mostrar els continguts fora de línia"
"goToOffline": "Mostrar els continguts fora de línia",
"children": {
"title": "Per a més"
}
},
"search": {
"title": "Cerca",
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
"page": {
"back": "Zurück",
"not-found": "Diese Seite ist unauffindbar",
"goToOffline": "Inhalte offline anzeigen"
"goToOffline": "Inhalte offline anzeigen",
"children": {
"title": "Weiterführende Informationen"
}
},
"search": {
"title": "Suche",
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@
"page": {
"back": "Back",
"not-found": "This page was not found",
"goToOffline": "Display offline content"
"goToOffline": "Display offline content",
"children": {
"title": "Further information"
}
},
"search": {
"title": "Search",
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/translations/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
"page": {
"back": "Vuelta",
"not-found": "No hemos encontrado la página",
"goToOffline": "Mostrar los contenidos sin conexión"
"goToOffline": "Mostrar los contenidos sin conexión",
"children": {
"title": "Para más información"
}
},
"search": {
"title": "Busca",
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@
"page": {
"back": "Retour",
"not-found": "Cette page est introuvable",
"goToOffline": "Afficher les contenus hors ligne"
"goToOffline": "Afficher les contenus hors ligne",
"children": {
"title": "Pour aller plus loin"
}
},
"search": {
"title": "Recherche",
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/translations/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@
"page": {
"back": "Ritorno",
"not-found": "Questa pagina non è stata trovata",
"goToOffline": "Visualizzazione di contenuti offline"
"goToOffline": "Visualizzazione di contenuti offline",
"children": {
"title": "Per saperne di più"
}
},
"search": {
"title": "Ricerca",
Expand Down
Loading