Skip to content

Commit

Permalink
feat(frontend): modal component and basic request hookup (#91)
Browse files Browse the repository at this point in the history
  • Loading branch information
sct committed Sep 15, 2020
1 parent 42cf45f commit 626099a
Show file tree
Hide file tree
Showing 9 changed files with 298 additions and 29 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"next": "9.5.3",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-spring": "^8.0.27",
"react-transition-group": "^4.4.1",
"reflect-metadata": "^0.1.13",
"sqlite3": "^5.0.0",
Expand All @@ -43,6 +44,7 @@
"@types/lodash": "^4.14.161",
"@types/node": "^14.10.0",
"@types/react": "^16.9.49",
"@types/react-dom": "^16.9.8",
"@types/react-transition-group": "^4.4.0",
"@types/swagger-ui-express": "^4.1.2",
"@types/yamljs": "^0.2.31",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import React, { ButtonHTMLAttributes } from 'react';

export type ButtonType =
| 'default'
| 'primary'
| 'danger'
| 'warning'
| 'success';

interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
buttonType?: 'default' | 'primary' | 'danger' | 'warning' | 'success';
buttonType?: ButtonType;
buttonSize?: 'default' | 'lg' | 'md' | 'sm';
}

Expand Down Expand Up @@ -38,7 +45,7 @@ const Button: React.FC<ButtonProps> = ({
break;
default:
buttonStyle.push(
'border-gray-300 leading-5 font-medium rounded-md text-gray-700 bg-white hover:text-gray-500 focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50'
'leading-5 font-medium rounded-md text-gray-200 bg-cool-gray-500 hover:bg-cool-gray-400 hover:text-white focus:border-blue-300 focus:shadow-outline-blue active:text-gray-200 active:bg-cool-gray-400'
);
}

Expand Down
143 changes: 143 additions & 0 deletions src/components/Common/Modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import React, { MouseEvent, ReactNode } from 'react';
import ReactDOM from 'react-dom';
import Button, { ButtonType } from '../Button';
import { useTransition, animated } from 'react-spring';
import { useLockBodyScroll } from '../../../hooks/useLockBodyScroll';

interface ModalProps {
title?: string;
onCancel?: (e: MouseEvent<HTMLElement>) => void;
onOk?: (e: MouseEvent<HTMLButtonElement>) => void;
cancelText?: string;
okText?: string;
cancelButtonType?: ButtonType;
okButtonType?: ButtonType;
visible?: boolean;
disableScrollLock?: boolean;
backgroundClickable?: boolean;
iconSvg?: ReactNode;
}

const Modal: React.FC<ModalProps> = ({
title,
onCancel,
onOk,
cancelText,
okText,
cancelButtonType,
okButtonType,
children,
visible,
disableScrollLock,
backgroundClickable = true,
iconSvg,
}) => {
useLockBodyScroll(!!visible, disableScrollLock);
const transitions = useTransition(visible, null, {
from: { opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 },
config: { tension: 500, velocity: 40, friction: 60 },
});
const containerTransitions = useTransition(visible, null, {
from: { opacity: 0, transform: 'scale(0.5)' },
enter: { opacity: 1, transform: 'scale(1)' },
leave: { opacity: 0, transform: 'scale(0.5)' },
config: { tension: 500, velocity: 40, friction: 60 },
});

const cancelType = cancelButtonType ?? 'default';
const okType = okButtonType ?? 'primary';

return (
<>
{transitions.map(
({ props, item, key }) =>
item &&
ReactDOM.createPortal(
<animated.div
className="fixed top-0 left-0 right-0 bottom-0 bg-cool-gray-800 bg-opacity-50 w-full h-full z-50 flex justify-center items-center"
style={props}
key={key}
onClick={
typeof onCancel === 'function' && backgroundClickable
? onCancel
: undefined
}
onKeyDown={(e) => {
if (e.key === 'Escape') {
typeof onCancel === 'function' && backgroundClickable
? onCancel
: undefined;
}
}}
>
{containerTransitions.map(
({ props, item, key }) =>
item && (
<animated.div
style={props}
className="inline-block align-bottom bg-cool-gray-700 rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
key={key}
>
<div className="sm:flex sm:items-start">
{iconSvg && (
<div className="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-cool-gray-600 text-white sm:mx-0 sm:h-10 sm:w-10">
{iconSvg}
</div>
)}
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
{title && (
<h3
className="text-lg leading-6 font-medium text-white"
id="modal-headline"
>
{title}
</h3>
)}
{children && (
<div className="mt-2">
<p className="text-sm leading-5 text-cool-gray-300">
{children}
</p>
</div>
)}
</div>
</div>
{(onCancel || onOk) && (
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
{typeof onOk === 'function' && (
<Button
buttonType={okType}
onClick={onOk}
className="ml-3"
>
{okText ? okText : 'Ok'}
</Button>
)}
{typeof onCancel === 'function' && (
<Button
buttonType={cancelType}
onClick={onCancel}
className="px-4"
>
{cancelText ? cancelText : 'Cancel'}
</Button>
)}
</div>
)}
</animated.div>
)
)}
</animated.div>,
document.body
)
)}
</>
);
};

export default Modal;
42 changes: 22 additions & 20 deletions src/components/Discover/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { useRef } from 'react';
import useSWR, { useSWRInfinite } from 'swr';
import React from 'react';
import useSWR from 'swr';
import type { MovieResult, TvResult } from '../../../server/models/Search';
import TitleCard from '../TitleCard';
import useVerticalScroll from '../../hooks/useVerticalScroll';

interface MovieDiscoverResult {
page: number;
Expand All @@ -18,17 +17,6 @@ interface TvDiscoverResult {
results: TvResult[];
}

const getKey = (
pageIndex: number,
previousPageData: MovieDiscoverResult | null
) => {
if (previousPageData && pageIndex + 1 > previousPageData.totalPages) {
return null;
}

return `/api/v1/discover/movies?page=${pageIndex + 1}`;
};

const Discover: React.FC = () => {
const { data: movieData, error: movieError } = useSWR<MovieDiscoverResult>(
'/api/v1/discover/movies'
Expand All @@ -47,12 +35,16 @@ const Discover: React.FC = () => {
</div>
</div>
<div
className="overflow-x-scroll whitespace-no-wrap hide-scrollbar scrolling-touch overscroll-x-contain -ml-2 -mr-4"
className="overflow-x-scroll whitespace-no-wrap hide-scrollbar scrolling-touch overscroll-x-contain -ml-4 -mr-4"
style={{ height: 295 }}
>
{movieData?.results.map((title) => (
<div key={title.id} className="px-2 inline-block">
<div
key={title.id}
className="first:px-4 last:px-4 px-2 inline-block"
>
<TitleCard
id={title.id}
image={title.posterPath}
status={title.request?.status}
summary={title.overview}
Expand All @@ -66,7 +58,10 @@ const Discover: React.FC = () => {
{!movieData &&
!movieError &&
[...Array(10)].map((_item, i) => (
<div key={`placeholder-${i}`} className="px-2 inline-block">
<div
key={`placeholder-${i}`}
className="first:px-4 last:px-4 px-2 inline-block"
>
<TitleCard.Placeholder />
</div>
))}
Expand All @@ -79,12 +74,16 @@ const Discover: React.FC = () => {
</div>
</div>
<div
className="overflow-x-scroll whitespace-no-wrap hide-scrollbar scrolling-touch overscroll-x-contain -ml-2 -mr-4"
className="overflow-x-scroll whitespace-no-wrap hide-scrollbar scrolling-touch overscroll-x-contain -ml-4 -mr-4"
style={{ height: 295 }}
>
{tvData?.results.map((title) => (
<div key={title.id} className="px-2 inline-block">
<div
key={title.id}
className="first:px-4 last:px-4 px-2 inline-block"
>
<TitleCard
id={title.id}
image={title.posterPath}
status={title.request?.status}
summary={title.overview}
Expand All @@ -98,7 +97,10 @@ const Discover: React.FC = () => {
{!tvData &&
!tvError &&
[...Array(10)].map((_item, i) => (
<div key={`placeholder-${i}`} className="px-2 inline-block">
<div
key={`placeholder-${i}`}
className="first:px-4 last:px-4 px-2 inline-block"
>
<TitleCard.Placeholder />
</div>
))}
Expand Down
2 changes: 2 additions & 0 deletions src/components/Search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const Search: React.FC = () => {
case 'movie':
titleCard = (
<TitleCard
id={title.id}
image={title.posterPath}
status={title.request?.status}
summary={title.overview}
Expand All @@ -102,6 +103,7 @@ const Search: React.FC = () => {
case 'tv':
titleCard = (
<TitleCard
id={title.id}
image={title.posterPath}
status={title.request?.status}
summary={title.overview}
Expand Down

0 comments on commit 626099a

Please sign in to comment.