libremdb/src/pages/find/index.tsx
2023-05-21 18:15:03 +05:30

77 lines
2.7 KiB
TypeScript

import { GetServerSideProps, InferGetServerSidePropsType } from 'next';
import Layout from 'src/layouts/Layout';
import ErrorInfo from 'src/components/error/ErrorInfo';
import Meta from 'src/components/meta/Meta';
import Results from 'src/components/find';
import Form from 'src/components/forms/find';
import Find, { FindQueryParams } from 'src/interfaces/shared/search';
import { AppError } from 'src/interfaces/shared/error';
import basicSearch from 'src/utils/fetchers/basicSearch';
import getOrSetApiCache from 'src/utils/getOrSetApiCache';
import { cleanQueryStr } from 'src/utils/helpers';
import { findKey } from 'src/utils/constants/keys';
import styles from 'src/styles/modules/pages/find/find.module.scss';
type Props = InferGetServerSidePropsType<typeof getServerSideProps>;
const getMetadata = (title: string | null) => ({
title: title || 'Search',
description: title
? `results for '${title}'`
: 'Search for anything on libremdb, a free & open source IMDb front-end',
});
const BasicSearch = ({ data: { title, results }, error }: Props) => {
if (error) return <ErrorInfo message={error.message} statusCode={error.statusCode} />;
return (
<>
<Meta {...getMetadata(title)} />
<Layout className={`${styles.find} ${!title && styles.find__home}`}>
{title && ( // only showing when user has searched for something
<Results results={results} title={title} className={styles.results} />
)}
<Form className={styles.form} />
</Layout>
</>
);
};
// TODO: use generics for passing in queryParams(to components) for better type-checking.
type Data =
| { data: { title: string; results: Find }; error: null }
| { data: { title: null; results: null }; error: null }
| { data: { title: string; results: null }; error: AppError };
export const getServerSideProps: GetServerSideProps<Data, FindQueryParams> = async ctx => {
// sample query str: find/?q=babylon&s=tt&ttype=ft&exact=true
const queryObj = ctx.query as FindQueryParams;
const query = queryObj.q?.trim();
if (!query) return { props: { data: { title: null, results: null }, error: null } };
try {
const entries = Object.entries(queryObj);
const queryStr = cleanQueryStr(entries);
const res = await getOrSetApiCache(findKey(queryStr), basicSearch, queryStr);
return {
props: { data: { title: query, results: res }, error: null },
};
} catch (error: any) {
const { message, statusCode } = error;
ctx.res.statusCode = statusCode;
ctx.res.statusMessage = message;
return {
props: {
error: { message, statusCode },
data: { title: query, results: null },
},
};
}
};
export default BasicSearch;