-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
adds ability to see titles, names, and images lists closes #6
- Loading branch information
Showing
20 changed files
with
818 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import type { DataKind, Data as TData } from 'src/interfaces/shared/list'; | ||
import type { ToArray } from 'src/interfaces/shared'; | ||
import Images from './Images'; | ||
import Names from './Names'; | ||
import Titles from './Titles'; | ||
|
||
type Props = { | ||
data: ToArray<TData<DataKind>>; | ||
}; | ||
|
||
const Data = ({ data }: Props) => { | ||
if (isDataImages(data)) return <Images images={data} />; | ||
if (isDataNames(data)) return <Names names={data} />; | ||
|
||
return <Titles titles={data} />; | ||
}; | ||
export default Data; | ||
|
||
const isDataImages = (data: unknown): data is TData<'images'>[] => | ||
Array.isArray(data) && typeof data[0] === 'string'; | ||
|
||
const isDataNames = (data: unknown): data is TData<'names'>[] => | ||
Array.isArray(data) && data[0] && typeof data[0] === 'object' && 'about' in data[0]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import Image from 'next/future/image'; | ||
import { modifyIMDbImg } from 'src/utils/helpers'; | ||
import type { Data } from 'src/interfaces/shared/list'; | ||
import styles from 'src/styles/modules/components/list/images.module.scss'; | ||
|
||
type Props = { | ||
images: Data<'images'>[]; | ||
}; | ||
|
||
const Images = ({ images }: Props) => { | ||
return ( | ||
<section className={styles.container}> | ||
{images.map(image => ( | ||
<figure className={styles.imgContainer} key={image}> | ||
<Image src={modifyIMDbImg(image, 400)} alt='' fill className={styles.img} sizes='200px'/> | ||
</figure> | ||
))} | ||
</section> | ||
); | ||
}; | ||
|
||
export default Images; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import Link from 'next/link'; | ||
import { formatDate } from 'src/utils/helpers'; | ||
import List from 'src/interfaces/shared/list'; | ||
import styles from 'src/styles/modules/components/list/meta.module.scss'; | ||
|
||
type Props = { | ||
title: string; | ||
meta: List['meta']; | ||
description: List['description']; | ||
}; | ||
const Meta = ({ title, meta, description }: Props) => { | ||
const by = meta.by.link ? ( | ||
<Link href={meta.by.link}> | ||
<a className='link'>{meta.by.name}</a> | ||
</Link> | ||
) : ( | ||
meta.by.name | ||
); | ||
|
||
return ( | ||
<header className={styles.container}> | ||
<h1 className='heading heading__secondary'>{title}</h1> | ||
<ul className={styles.list}> | ||
<li>by {by}</li> | ||
<li>{meta.created}</li> | ||
{meta.updated && <li>{meta.updated}</li>} | ||
<li> | ||
{meta.num} {meta.type} | ||
</li> | ||
</ul> | ||
{description && <p>{description}</p>} | ||
</header> | ||
); | ||
}; | ||
export default Meta; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import Image from 'next/future/image'; | ||
import { getProxiedIMDbImgUrl, modifyIMDbImg } from 'src/utils/helpers'; | ||
import { Card } from 'src/components/card'; | ||
import type { Data } from 'src/interfaces/shared/list'; | ||
import styles from 'src/styles/modules/components/list/names.module.scss'; | ||
import OptionalLink from './OptionalLink'; | ||
|
||
type Props = { | ||
names: Data<'names'>[]; | ||
}; | ||
|
||
const Names = ({ names }: Props) => { | ||
return ( | ||
<ul className={styles.names}> | ||
{names.map(name => ( | ||
<Name {...name} key={name.name} /> | ||
))} | ||
</ul> | ||
); | ||
}; | ||
export default Names; | ||
|
||
const Name = ({ about, image, job, knownFor, knownForLink, name, url }: Props['names'][number]) => { | ||
// const style: CSSProperties = { | ||
// backgroundImage: image ? `url(${getProxiedIMDbImgUrl(modifyIMDbImg(image, 300))})` : undefined, | ||
// }; | ||
|
||
return ( | ||
<Card hoverable className={styles.name}> | ||
<div className={styles.imgContainer}> | ||
{image ? ( | ||
<Image src={modifyIMDbImg(image, 400)} alt='' fill className={styles.img} sizes='200px' /> | ||
) : ( | ||
<svg className={styles.imgNA}> | ||
<use href='/svg/sprite.svg#icon-image-slash' /> | ||
</svg> | ||
)} | ||
</div> | ||
<div className={styles.info}> | ||
<h2 className={`heading ${styles.heading}`}> | ||
<OptionalLink href={url} className={`heading ${styles.heading}`}> | ||
{name} | ||
</OptionalLink> | ||
</h2> | ||
<ul className={styles.basicInfo} aria-label='quick facts'> | ||
{job && <li>{job}</li>} | ||
{knownFor && ( | ||
<li> | ||
<OptionalLink href={knownForLink}>{knownFor}</OptionalLink> | ||
</li> | ||
)} | ||
</ul> | ||
<p>{about}</p> | ||
</div> | ||
</Card> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import type { ReactNode, ComponentPropsWithoutRef } from 'react'; | ||
import Link from 'next/link'; | ||
|
||
const OptionalLink = ({ | ||
href, | ||
children, | ||
...rest | ||
}: { href?: string | null; children: ReactNode } & Omit<ComponentPropsWithoutRef<'a'>, 'href'>) => ( | ||
<> | ||
{href ? ( | ||
<Link href={href}> | ||
<a {...rest}>{children}</a> | ||
</Link> | ||
) : ( | ||
children | ||
)} | ||
</> | ||
); | ||
|
||
export default OptionalLink; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import OptionalLink from './OptionalLink'; | ||
import type List from 'src/interfaces/shared/list'; | ||
import styles from 'src/styles/modules/components/list/pagination.module.scss'; | ||
|
||
type Props = { | ||
pagination: List['pagination']; | ||
}; | ||
const Pagination = ({ pagination }: Props) => { | ||
const prevLink = pagination.prev && pagination.prev !== '#' ? pagination.prev : null; | ||
const nextLink = pagination.next && pagination.next !== '#' ? pagination.next : null; | ||
|
||
if (!prevLink && !nextLink) return null; | ||
|
||
return ( | ||
<nav aria-label='pagination'> | ||
<ul className={styles.nav}> | ||
<li aria-hidden={!prevLink}> | ||
<OptionalLink href={prevLink} className='link'> | ||
Prev | ||
</OptionalLink> | ||
</li> | ||
<li>{pagination.range} shown</li> | ||
<li aria-hidden={!nextLink}> | ||
<OptionalLink href={nextLink} className='link'> | ||
Next | ||
</OptionalLink> | ||
</li> | ||
</ul> | ||
</nav> | ||
); | ||
}; | ||
|
||
export default Pagination; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import Image from 'next/future/image'; | ||
import { getProxiedIMDbImgUrl, modifyIMDbImg } from 'src/utils/helpers'; | ||
import { Card } from 'src/components/card'; | ||
import type { Data } from 'src/interfaces/shared/list'; | ||
import styles from 'src/styles/modules/components/list/titles.module.scss'; | ||
import { CSSProperties } from 'react'; | ||
import OptionalLink from './OptionalLink'; | ||
|
||
type Props = { | ||
titles: Data<'titles'>[]; | ||
}; | ||
|
||
const Titles = ({ titles }: Props) => { | ||
return ( | ||
<ul className={styles.titles}> | ||
{titles.map(title => ( | ||
<Title {...title} key={title.name} /> | ||
))} | ||
</ul> | ||
); | ||
}; | ||
export default Titles; | ||
|
||
const Title = (props: Props['titles'][number]) => { | ||
const style: CSSProperties = { | ||
backgroundImage: props.image | ||
? `url(${getProxiedIMDbImgUrl(modifyIMDbImg(props.image, 300))})` | ||
: undefined, | ||
}; | ||
|
||
return ( | ||
<Card hoverable className={styles.title}> | ||
<div className={styles.imgContainer}> | ||
{props.image ? ( | ||
<Image src={modifyIMDbImg(props.image, 400)} alt='' fill className={styles.img} /> | ||
) : ( | ||
<svg className={styles.imgNA}> | ||
<use href='/svg/sprite.svg#icon-image-slash' /> | ||
</svg> | ||
)} | ||
</div> | ||
<div className={styles.info}> | ||
<h2 className={`heading heading__tertiary ${styles.heading}`}> | ||
<OptionalLink href={props.url} className={`heading ${styles.heading}`}> | ||
{props.name} {props.year} | ||
</OptionalLink> | ||
</h2> | ||
<ul className={styles.basicInfo} aria-label='quick facts'> | ||
{props.certificate && <li>{props.certificate}</li>} | ||
{props.runtime && <li>{props.runtime}</li>} | ||
{props.genre && <li>{props.genre}</li>} | ||
</ul> | ||
<ul className={styles.ratings}> | ||
{Boolean(props.rating) && <li className={styles.rating}> | ||
<span className={styles.rating__num}>{props.rating}</span> | ||
<svg className={styles.rating__icon}> | ||
<use href='/svg/sprite.svg#icon-rating'></use> | ||
</svg> | ||
<span className={styles.rating__text}> Avg. rating</span> | ||
</li>} | ||
{Boolean(props.metascore) && <li className={styles.rating}> | ||
<span className={styles.rating__num}>{props.metascore}</span> | ||
<span className={styles.rating__text}>Metascore</span> | ||
</li>} | ||
</ul> | ||
<p className={styles.plot}> | ||
<span>Plot:</span> {props.plot} | ||
</p> | ||
<ul className={styles.otherInfo}> | ||
{props.otherInfo.map(([infoHeading, info]) => ( | ||
<li key={infoHeading}> | ||
<span>{infoHeading}:</span> {info} | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
</Card> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export { default as Data } from './Data'; | ||
export { default as Meta } from './Meta'; | ||
export { default as Pagination } from './Pagination'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
import type Name from './name'; | ||
|
||
export type Media = Name['media']; // exactly the same in title and name | ||
|
||
// forcefully makes array of individual elements of T, where t is any conditional type. | ||
export type ToArray<T> = T extends any ? T[] : never; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import list from 'src/utils/fetchers/list'; | ||
|
||
// for full title | ||
type List = Awaited<ReturnType<typeof list>>; | ||
export type { List as default }; | ||
|
||
type DataTitle = { | ||
image: string | null; | ||
name: string; | ||
url: string | null; | ||
year: string; | ||
certificate: string; | ||
runtime: string; | ||
genre: string; | ||
plot: string; | ||
rating: string; | ||
metascore: string; | ||
otherInfo: string[][]; | ||
}; | ||
|
||
type DataName = { | ||
image: string | null; | ||
name: string; | ||
url: string | null; | ||
job: string | null; | ||
knownFor: string | null; | ||
knownForLink: string | null; | ||
about: string; | ||
}; | ||
|
||
type DataImage = string; | ||
|
||
export type DataKind = 'images' | 'titles' | 'names'; | ||
|
||
export type Data<T extends DataKind> = T extends 'images' | ||
? DataImage | ||
: T extends 'names' | ||
? DataName | ||
: DataTitle; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { GetServerSideProps, InferGetServerSidePropsType } from 'next'; | ||
import Meta from 'src/components/meta/Meta'; | ||
import Layout from 'src/components/layout'; | ||
import ErrorInfo from 'src/components/error/ErrorInfo'; | ||
import { Data, Meta as ListMeta, Pagination } from 'src/components/list'; | ||
import { AppError } from 'src/interfaces/shared/error'; | ||
import TList from 'src/interfaces/shared/list'; | ||
import getOrSetApiCache from 'src/utils/getOrSetApiCache'; | ||
import list from 'src/utils/fetchers/list'; | ||
import { listKey } from 'src/utils/constants/keys'; | ||
import styles from 'src/styles/modules/pages/list/list.module.scss'; | ||
|
||
type Props = InferGetServerSidePropsType<typeof getServerSideProps>; | ||
|
||
const List = ({ data, error, originalPath }: Props) => { | ||
if (error) return <ErrorInfo {...error} originalPath={originalPath} />; | ||
|
||
const description = data.description || `List created by ${data.meta.by.name} (${data.meta.num} ${data.meta.type}).` | ||
|
||
return ( | ||
<> | ||
<Meta title={data.title} description={description} /> | ||
<Layout className={styles.list} originalPath={originalPath}> | ||
<ListMeta title={data.title} description={data.description} meta={data.meta} /> | ||
{/* @ts-expect-error don't have time to fix it. just a type fluff. */} | ||
<Data data={data.data} /> | ||
<Pagination pagination={data.pagination} /> | ||
</Layout> | ||
</> | ||
); | ||
}; | ||
|
||
type TData = ({ data: TList; error: null } | { error: AppError; data: null }) & { | ||
originalPath: string; | ||
}; | ||
type Params = { listId: string }; | ||
|
||
export const getServerSideProps: GetServerSideProps<TData, Params> = async ctx => { | ||
const listId = ctx.params!.listId; | ||
const pageNum = (ctx.query.page as string | undefined) ?? '1'; | ||
const originalPath = ctx.resolvedUrl; | ||
try { | ||
const data = await getOrSetApiCache(listKey(listId, pageNum), list, listId, pageNum); | ||
|
||
return { props: { data, error: null, originalPath } }; | ||
} catch (error: any) { | ||
const { message = 'Internal server error', statusCode = 500 } = error; | ||
ctx.res.statusCode = statusCode; | ||
ctx.res.statusMessage = message; | ||
return { props: { error: { message, statusCode }, data: null, originalPath } }; | ||
} | ||
}; | ||
|
||
export default List; |
Oops, something went wrong.