pl-fe: migrate about page to tanstack query

Signed-off-by: mkljczk <git@mkljczk.pl>
This commit is contained in:
mkljczk 2024-12-04 16:56:32 +01:00
parent 9fa4509870
commit 32fed66477
5 changed files with 27 additions and 117 deletions

View file

@ -1,44 +0,0 @@
// import MockAdapter from 'axios-mock-adapter';
import { Map as ImmutableMap } from 'immutable';
// import { staticClient } from 'pl-fe/api';
import { mockStore } from 'pl-fe/jest/test-helpers';
import {
FETCH_ABOUT_PAGE_REQUEST,
// FETCH_ABOUT_PAGE_SUCCESS,
FETCH_ABOUT_PAGE_FAIL,
fetchAboutPage,
} from './about';
describe('fetchAboutPage()', () => {
// it('creates the expected actions on success', () => {
// const mock = new MockAdapter(staticClient);
// mock.onGet('/instance/about/index.html')
// .reply(200, '<h1>Hello world</h1>');
// const expectedActions = [
// { type: FETCH_ABOUT_PAGE_REQUEST, slug: 'index' },
// { type: FETCH_ABOUT_PAGE_SUCCESS, slug: 'index', html: '<h1>Hello world</h1>' },
// ];
// const store = mockStore(ImmutableMap());
// return store.dispatch(fetchAboutPage()).then(() => {
// expect(store.getActions()).toEqual(expectedActions);
// });
// });
it('creates the expected actions on failure', () => {
const expectedActions = [
{ type: FETCH_ABOUT_PAGE_REQUEST, slug: 'asdf' },
{ type: FETCH_ABOUT_PAGE_FAIL, slug: 'asdf', error: new Error('Request failed with status code 404') },
];
const store = mockStore(ImmutableMap());
return store.dispatch(fetchAboutPage('asdf')).catch(() => {
expect(store.getActions()).toEqual(expectedActions);
});
});
});

View file

@ -1,55 +0,0 @@
import { staticFetch } from '../api';
import type { AppDispatch, RootState } from 'pl-fe/store';
const FETCH_ABOUT_PAGE_REQUEST = 'FETCH_ABOUT_PAGE_REQUEST' as const;
const FETCH_ABOUT_PAGE_SUCCESS = 'FETCH_ABOUT_PAGE_SUCCESS' as const;
const FETCH_ABOUT_PAGE_FAIL = 'FETCH_ABOUT_PAGE_FAIL' as const;
interface FetchAboutPageRequestAction {
type: typeof FETCH_ABOUT_PAGE_REQUEST;
slug: string;
locale?: string;
}
interface FetchAboutPageSuccessAction {
type: typeof FETCH_ABOUT_PAGE_SUCCESS;
slug: string;
locale?: string;
html: string;
}
interface FetchAboutPageFailAction {
type: typeof FETCH_ABOUT_PAGE_FAIL;
slug: string;
locale?: string;
error: unknown;
}
const fetchAboutPage = (slug = 'index', locale?: string) => (dispatch: AppDispatch, getState: () => RootState) => {
dispatch({ type: FETCH_ABOUT_PAGE_REQUEST, slug, locale });
const filename = `${slug}${locale ? `.${locale}` : ''}.html`;
return staticFetch(`/instance/about/${filename}`)
.then(({ data: html }) => {
dispatch({ type: FETCH_ABOUT_PAGE_SUCCESS, slug, locale, html });
return html;
})
.catch(error => {
dispatch({ type: FETCH_ABOUT_PAGE_FAIL, slug, locale, error });
throw error;
});
};
type AboutAction =
| FetchAboutPageRequestAction
| FetchAboutPageSuccessAction
| FetchAboutPageFailAction;
export {
fetchAboutPage,
FETCH_ABOUT_PAGE_REQUEST,
FETCH_ABOUT_PAGE_SUCCESS,
FETCH_ABOUT_PAGE_FAIL,
type AboutAction,
};

View file

@ -0,0 +1,19 @@
import { useQuery } from '@tanstack/react-query';
import { staticFetch } from 'pl-fe/api';
const fetchAboutPage = async (slug: string, locale?: string) => {
const filename = `${slug}${locale ? `.${locale}` : ''}.html`;
const { data } = await staticFetch(`/instance/about/${filename}`);
return data;
};
const useAboutPage = (slug = 'index', locale?: string) =>
useQuery({
queryKey: ['pl-fe', 'aboutPages', slug, locale],
queryFn: () => fetchAboutPage(slug, locale),
});
export { useAboutPage };

View file

@ -14,7 +14,7 @@ type PlfeResponse<T = any> = Response & { data: string; json: T };
* No authorization is needed.
*/
const staticFetch = (input: URL | RequestInfo, init?: RequestInit | undefined) => {
const fullPath = buildFullPath(input.toString(), BuildConfig.FE_SUBDIRECTORY);
const fullPath = buildFullPath(input.toString(), BuildConfig.BACKEND_URL);
return fetch(fullPath, init).then(async (response) => {
if (!response.ok) throw { response };

View file

@ -1,11 +1,10 @@
import React, { useEffect, useState } from 'react';
import React, { useState } from 'react';
import { FormattedMessage } from 'react-intl';
import { useParams } from 'react-router-dom';
import { fetchAboutPage } from 'pl-fe/actions/about';
import { useAboutPage } from 'pl-fe/api/hooks/pl-fe/use-about-page';
import { Navlinks } from 'pl-fe/components/navlinks';
import Card from 'pl-fe/components/ui/card';
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config';
import { useSettings } from 'pl-fe/hooks/use-settings';
@ -13,30 +12,21 @@ import { languages } from '../preferences';
/** Displays arbitrary user-uploaded HTML on a page at `/about/:slug` */
const AboutPage: React.FC = () => {
const dispatch = useAppDispatch();
const { slug } = useParams<{ slug?: string }>();
const { slug = 'index' } = useParams<{ slug?: string }>();
const settings = useSettings();
const plFeConfig = usePlFeConfig();
const [pageHtml, setPageHtml] = useState<string>('');
const [locale, setLocale] = useState<string>(settings.locale);
const { aboutPages } = plFeConfig;
const page = aboutPages[slug || 'about'];
const page = aboutPages[slug];
const defaultLocale = page?.defaultLocale;
const pageLocales = page?.locales || [];
const fetchLocale = Boolean(page && locale !== defaultLocale && pageLocales.includes(locale));
useEffect(() => {
const fetchLocale = Boolean(page && locale !== defaultLocale && pageLocales.includes(locale));
dispatch(fetchAboutPage(slug, fetchLocale ? locale : undefined)).then(html => {
setPageHtml(html);
}).catch(error => {
// TODO: Better error handling. 404 page?
setPageHtml('<h1>Page not found</h1>');
});
}, [locale, slug]);
const { data: pageHtml } = useAboutPage(slug, fetchLocale ? locale : undefined);
const alsoAvailable = (defaultLocale) && (
<div>
@ -67,7 +57,7 @@ const AboutPage: React.FC = () => {
<div>
<Card variant='rounded'>
<div className='prose mx-auto py-4 dark:prose-invert sm:p-6'>
<div dangerouslySetInnerHTML={{ __html: pageHtml }} />
{pageHtml && <div dangerouslySetInnerHTML={{ __html: pageHtml }} />}
{alsoAvailable}
</div>
</Card>