Skip to content
This repository has been archived by the owner on May 8, 2024. It is now read-only.

Commit

Permalink
feat: homepage
Browse files Browse the repository at this point in the history
  • Loading branch information
BoYanZh committed Feb 17, 2024
1 parent a969a3a commit e2e88cc
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 81 deletions.
80 changes: 49 additions & 31 deletions src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,6 @@ export interface SchemaAuth {
username?: string
}

export interface SchemaCreateMovie {
/** @maxLength 255 */
author: string
meta: SchemaMeta
status: number
/** @maxLength 255 */
title: string
user_id: string
}

export interface SchemaCreateUser {
/** @maxLength 150 */
email: string
Expand Down Expand Up @@ -57,27 +47,30 @@ export interface SchemaJWT {
user_id?: string
}

export interface SchemaMeta {
description?: string
picture?: string
/**
* @min 1
* @max 10
*/
rating?: number
}

export interface SchemaMovie {
/** @maxLength 255 */
author: string
created_at?: string
cast: string
/** @maxLength 255 */
category: string
/** @maxLength 255 */
director: string
id?: string
meta: SchemaMeta
status: number
/** @maxLength 255 */
producer: string
/** @maxLength 255 */
rating_code: string
/** @maxLength 255 */
reviews: string
/** @maxLength 255 */
show_time: string
/** @maxLength 255 */
synopsis: string
/** @maxLength 255 */
title: string
updated_at?: string
user_id: string
/** @maxLength 1023 */
trailer_picture: string
/** @maxLength 1023 */
trailer_video: string
}

export interface SchemaMovieListResponse {
Expand All @@ -102,6 +95,30 @@ export interface SchemaUpdateUser {
last_name: string
}

export interface SchemaUpsertMovie {
/** @maxLength 255 */
cast: string
/** @maxLength 255 */
category: string
/** @maxLength 255 */
director: string
/** @maxLength 255 */
producer: string
/** @maxLength 255 */
rating_code: string
/** @maxLength 255 */
reviews: string
show_time: string
/** @maxLength 255 */
synopsis: string
/** @maxLength 255 */
title: string
/** @maxLength 1023 */
trailer_picture: string
/** @maxLength 1023 */
trailer_video: string
}

export interface SchemaUser {
created_at?: string
email?: string
Expand Down Expand Up @@ -574,6 +591,10 @@ export class Api<
offset?: number
/** limit */
limit?: number
/** search by title */
search?: string
/** the moive is running or not */
running?: boolean
},
params: RequestParams = {}
) =>
Expand All @@ -595,14 +616,11 @@ export class Api<
* @request POST:/api/v1/movies
* @secure
*/
v1MoviesCreate: (
createmovie: SchemaCreateMovie,
params: RequestParams = {}
) =>
v1MoviesCreate: (movie: SchemaUpsertMovie, params: RequestParams = {}) =>
this.request<SchemaMovie, SchemaErrorResponse>({
path: `/api/v1/movies`,
method: 'POST',
body: createmovie,
body: movie,
secure: true,
type: ContentType.Json,
format: 'json',
Expand Down
28 changes: 15 additions & 13 deletions src/components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,22 @@ const Index: React.FC = () => {
</Button>
</Link>
) : (
<Link to={`/login?from=${location.pathname}`}>
<Button type='button' className='btn my-1 mx-0 mx-lg-1'>
Login
</Button>
</Link>
<>
<Link to={`/login?from=${location.pathname}`}>
<Button type='button' className='btn my-1 mx-0 mx-lg-1'>
Login
</Button>
</Link>
<Link to='/register'>
<Button
type='button'
className='btn btn-warning my-1 mx-0 mx-lg-1'
>
Register
</Button>
</Link>
</>
)}
<Link to='/register'>
<Button
type='button'
className='btn btn-warning my-1 mx-0 mx-lg-1'
>
Register
</Button>
</Link>
</Nav>
</Navbar.Collapse>
</Container>
Expand Down
136 changes: 109 additions & 27 deletions src/pages/Main/index.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,125 @@
import './style.module.css'
import { useRequest } from 'ahooks'
import type { SchemaMovie } from 'client'
import PageContainer from 'components/PageContainer'
import type React from 'react'
import { useState } from 'react'
import { Button, Col, Form, Modal, Row } from 'react-bootstrap'
import Card from 'react-bootstrap/Card'
import ListGroup from 'react-bootstrap/ListGroup'
import { Link } from 'react-router-dom'
import Backend from 'utils/service'

const Movie: React.FC<{ movie: SchemaMovie }> = ({ movie }) => {
const [show, setShow] = useState(false)

const handleClose = () => setShow(false)
const handleShow = () => setShow(true)
return (
<Card style={{ width: '18rem' }} className='mb-3'>
<Card.Img variant='top' src={movie.trailer_picture} />
<Card.Body>
<Card.Title>{movie.title}</Card.Title>
<Card.Text>
<div>Director: {movie.director}</div>
<div>Cast: {movie.cast}</div>
<div>Category: {movie.category}</div>
</Card.Text>
<Button variant='secondary' onClick={handleShow}>
Watch Trailer
</Button>{' '}
<Link to={`/moive/${movie.id}/book`}>
<Button variant='primary'>Book Movie</Button>
</Link>
</Card.Body>
<Modal
size='lg'
aria-labelledby='contained-modal-title-vcenter'
centered
show={show}
onHide={handleClose}
>
<Modal.Header closeButton>
<Modal.Title>Trailer of {movie.title}</Modal.Title>
</Modal.Header>
<Modal.Body>
{/* eslint-disable-next-line react/iframe-missing-sandbox */}
<iframe
width='100%'
height='400px'
src={movie.trailer_video}
title='Trailer'
allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'
allowFullScreen
sandbox='allow-scripts allow-popups allow-same-origin'
/>
</Modal.Body>
</Modal>
</Card>
)
}
const MovieList: React.FC<{ movies: SchemaMovie[] }> = ({ movies }) => (
<Row>
{movies.map(movie => (
<Col key={movie.id}>
<Movie movie={movie} />
</Col>
))}
</Row>
)

const RunningMovieList: React.FC<{ search: string }> = ({ search }) => {
const { data, loading } = useRequest(
async () => Backend.movie.v1MoviesList({ running: true, search }),
{ refreshDeps: [search], debounceWait: 200 }
)
return (
!loading && (data?.data.data ? <MovieList movies={data.data.data} /> : null)
)
}

const ComingMovieList: React.FC<{ search: string }> = ({ search }) => {
const { data, loading } = useRequest(
async () => Backend.movie.v1MoviesList({ running: false, search }),
{ refreshDeps: [search], debounceWait: 200 }
)
return (
!loading && (data?.data.data ? <MovieList movies={data.data.data} /> : null)
)
}

const Index: React.FC = () => {
const { data, loading } = useRequest(async () => Backend.movie.v1MoviesList())
const [search, setSearch] = useState('')
return (
<PageContainer>
<div className='text-center'>
<h1>Vite + React + React-Bootstrap Boilerplate</h1>
<div className='text-center mb-3'>
<h1>All Moives</h1>
<p>
Visit backend swagger: <a href='/swagger'>here</a>
</p>
<Form.Control
type='text'
placeholder='Search'
onChange={e => setSearch(e.target.value)}
/>
</div>
<div
style={{
width: '100%',
display: 'flex',
justifyContent: 'center',
alignContent: 'center'
}}
>
<Card style={{ width: '18rem' }}>
<Card.Body>
<Card.Title>
<b>{loading ? 'loading...' : 'Movies'}</b>
</Card.Title>
</Card.Body>
{!loading && (
<ListGroup variant='flush'>
{data?.data.data?.map(movie => (
<ListGroup.Item key={movie.id}>{movie.title}</ListGroup.Item>
))}
</ListGroup>
)}
</Card>
</div>
<Row>
<Col lg={6}>
<div className='text-center mb-3'>
<h1>Currently Running</h1>
</div>
<div className='movie-list-container'>
<RunningMovieList search={search} />
</div>
</Col>
<Col lg={6}>
<div className='text-center mb-3'>
<h1>Coming Soon</h1>
</div>
<div className='movie-list-container'>
<ComingMovieList search={search} />
</div>
</Col>
</Row>
</PageContainer>
)
}
Expand Down
6 changes: 6 additions & 0 deletions src/pages/Main/style.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.movie-list-container {
width: '100%';
display: 'flex';
justify-content: 'center';
align-content: 'center';
}
22 changes: 12 additions & 10 deletions src/pages/MovieCreate/index.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
import { useRequest } from 'ahooks'
import PageContainer from 'components/PageContainer'
import { useAuth } from 'hooks/useAuth'
import { useState } from 'react'
import Button from 'react-bootstrap/Button'
import Form from 'react-bootstrap/Form'
import { useNavigate } from 'react-router-dom'
import Backend from 'utils/service'

const Index: React.FC = () => {
const { user } = useAuth()
const navigate = useNavigate()
const [movieTitle, setMovieTitle] = useState('my movie')
const { run: create } = useRequest(
async () =>
// TODO: replace the movie with user input
Backend.movie.v1MoviesCreate({
author: 'string',
meta: {
description: 'string',
picture: 'string',
rating: 10
},
status: 0,
title: movieTitle,
user_id: user?.id ?? ''
cast: 'cast',
category: 'category',
director: 'director',
producer: 'producer',
rating_code: 'rating_code',
reviews: 'reviews',
show_time: '2016-01-02T15:04:05Z',
synopsis: 'synopsis',
trailer_picture: 'https://placehold.co/600x400',
trailer_video:
'https://www.youtube.com/embed/NpEaa2P7qZI?si=Ev2ybUCHzVxQPIO1&amp;controls=0'
}),
{
manual: true,
Expand Down

0 comments on commit e2e88cc

Please sign in to comment.