diff --git a/client/src/App.css b/client/src/App.css index 6ec89a0ffb80ce4a1ce554579bdf52cc29e2643a..ba8f4b27d339a1fcca665f1567e8af148fa54469 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -17,13 +17,30 @@ background-color: gray; min-height: 5vh; display: flex; - flex-direction: column; + flex-direction: row; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); color: white; + font-size: large; + margin: auto; } +#textfield1, #textfield2, #checkbox1 { + /* background-color: red; */ + margin: 1em; +} +/* +#textfield2 { + background-color: yellow; +} + +#checkbox1 { + background-color: green; +} */ + + + .App-link { color: #61dafb; } diff --git a/client/src/components/Header.tsx b/client/src/components/Header.tsx index 70a6a2f37cf400be4acfbf8bf9f3a12d23fe1fe5..319a057124d8ad36509850978a7c27617d9b648d 100644 --- a/client/src/components/Header.tsx +++ b/client/src/components/Header.tsx @@ -5,7 +5,9 @@ import { inject, observer } from 'mobx-react'; import * as services from './services'; type MyState = { - input: string + inputTitle: string, + inputGenre: string, + checkbox1_checked: boolean }; interface MoviesProps { @@ -17,7 +19,9 @@ class Header extends React.Component<MoviesProps, MyState> { super(props); this.state = { - input: '' + inputTitle: '', + inputGenre: '', + checkbox1_checked: false } } @@ -25,7 +29,12 @@ class Header extends React.Component<MoviesProps, MyState> { render() { return ( <div className="header"> - <input type="text" placeholder="Search for movies..." onChange={this.handleChange}></input> + Movie title: + <input type="text" placeholder="Search for movie titles..." onChange={this.handleChange} id="textfield1"></input> + Movie genre: + <input type="text" placeholder="Filter on genre..." onChange={this.handleChange} id="textfield2"></input> + Order by year: + <input type="checkbox" id="checkbox1" onChange={this.handleChange}></input> <button onClick={this.search}>Search</button> </div> @@ -33,21 +42,44 @@ class Header extends React.Component<MoviesProps, MyState> { } - handleChange = (e: any) => { - this.setState({ input: e.target.value }) - } + handleChange = (event: any) => { + let element = event.target.id + if (event.keyCode === 13) { // not working + console.log("enter") + this.search() + } + if (element == 'textfield1') { + this.setState({ inputTitle: event.target.value }) + } + if (element == 'textfield2') { + this.setState({ inputGenre: event.target.value }) + } + else if (element == 'checkbox1') { + this.setState({ checkbox1_checked: event.target.checked }) + } + // else if (element == 'checkbox12') { + // this.setState({ checkbox2_checked: event.target.checked }) + // } + } +// TODO mysql ordering not working because of graphql scrambling search = () => { - this.getMovieByColumnType(services.ColumnType.Title, this.state.input, 'id title genre description'); + this.getMoviesBySearch('id title genre description', this.state.inputTitle, this.state.inputGenre, this.state.checkbox1_checked); } getMovieByColumnType(columnType : services.ColumnType, value: string, neededData: string) { - services.queryFetch(services.generateQuery(columnType, value, neededData) , 'POST') + services.queryFetch(services.generateQuery(columnType, value, neededData)) .then(res => res.json()) .then(res => this.props.moviesStore.setMovies(res.data.getMovieByColumnType)) } + + getMoviesBySearch(neededData: string, title: string, genre: string, order: boolean) { + services.queryFetch(services.generateSearchQuery(neededData, title, genre, order)) + .then(res => res.json()) + .then(res => this.props.moviesStore.setMovies(res.data.getMoviesBySearch)) + } } diff --git a/client/src/components/Movies.tsx b/client/src/components/Movies.tsx index 1300856957c36c842aec250218b7e8825ea36fc2..6780abcea1658a590af2ed8069066715862dedd6 100644 --- a/client/src/components/Movies.tsx +++ b/client/src/components/Movies.tsx @@ -3,7 +3,7 @@ import { MoviesStore, MoviesStoreImplementation } from "./MoviesStore"; import { inject, observer } from 'mobx-react'; import * as services from './services'; -type MyProps = {}; +// type MyProps = {}; type MyState = { movies: any }; @@ -27,14 +27,14 @@ class Movies extends React.Component<MoviesProps, MyState> { getAllMovies() { - services.queryFetch(services.getAllMoviesQuery, 'POST') + services.queryFetch(services.getAllMoviesQuery) .then(res => res.json()) .then(res => this.props.moviesStore.setMovies(res.data.getAllMovies)) } getMovieByColumnType(columnType : services.ColumnType, value: string, neededData: string) { - services.queryFetch(services.generateQuery(columnType, value, neededData) , 'POST') + services.queryFetch(services.generateQuery(columnType, value, neededData)) .then(res => res.json()) .then(res => this.props.moviesStore.setMovies(res)) } diff --git a/client/src/components/services.ts b/client/src/components/services.ts index f88cff23bcff0bcbdd97f464e1cfe3e1c0149486..3519d71d7804d4f0eaf00e3033de5793dedcb731 100644 --- a/client/src/components/services.ts +++ b/client/src/components/services.ts @@ -1,6 +1,6 @@ -export function queryFetch(query: String, method: string) { +export function queryFetch(query: String) { return fetch('/graphql', { - method: method, + method: 'POST', headers: { "Content-Type": "application/json" }, body: JSON.stringify({ query: query, @@ -61,6 +61,17 @@ export function generateQuery(columnType: ColumnType, value: string, neededData: } +export function generateSearchQuery(neededData: string, title: string, genre: string, order: boolean){ + let query = ` + query { + getMoviesBySearch(title: "${title}", genre: "${genre}", order: ${order}) { + ${neededData} + } + }`; + console.log(query) + return query +} + export const getAllMoviesQuery = ` query { getAllMovies { diff --git a/server/package.json b/server/package.json index 36baeeffd0d058cab19d7c6ee1368a3ad15a3ef5..363c2dfb84c2745ffee9b4bd352f9e93bb38f18d 100644 --- a/server/package.json +++ b/server/package.json @@ -28,7 +28,7 @@ }, "scripts": { "start": "nodemon src/server.ts --exec ts-node", - "build": "react-scripts build", + "build": "tsc --build", "test": "react-scripts test", "eject": "react-scripts eject" }, diff --git a/server/src/server.ts b/server/src/server.ts index 9724f9b4bf3a8f7f532e23d005a26c8161b6d175..b1893ad90fa0718f7b93c08165dfe13338fd7c4d 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -1,9 +1,7 @@ declare var require: any -// id,title,genre,rating_dice_throw,year,director_first_name,director_last_name,description,cover_image -const movieData = require("../movies_with_image.json") var express = require('express'); var { graphqlHTTP } = require('express-graphql'); -var { GraphQLObjectType, GraphQLSchema, buildSchema, GraphQLInt, GraphQLString, GraphQLList } = require('graphql'); +var { GraphQLObjectType, GraphQLSchema, buildSchema, GraphQLInt, GraphQLString, GraphQLList, GraphQLBoolean } = require('graphql'); import {connect} from "./database" @@ -32,7 +30,6 @@ const RootQuery = new GraphQLObjectType({ const connection = await connect(); const response = await connection.query('SELECT * FROM movie'); return response[0]; - // return filmControllers.getFilms() } }, getMovieByColumnType: { @@ -59,6 +56,35 @@ const RootQuery = new GraphQLObjectType({ else if(typeof args.director_last_name!='undefined' && args.director_last_name){query = getQuery('director_last_name' , args.director_last_name)} else if(typeof args.description!='undefined' && args.description){query = getQuery('description' , args.description)} + const response = await connection.query(query); + return response[0]; + } + }, + getMoviesBySearch: { + type: new GraphQLList(MovieType), + args: { + id: {type: GraphQLInt}, + title: { type: GraphQLString }, + genre: { type: GraphQLString }, + rating_dice_throw: { type: GraphQLInt }, + year: { type: GraphQLInt }, + description: { type: GraphQLString }, + order: {type: GraphQLBoolean} + }, + async resolve(parent: any, args: any) { + const connection = await connect(); + let query = ''; + // if(typeof args.id!='undefined' && args.id){query = getQuery('id' , args.id)} + if(typeof args.title!='undefined' && typeof args.genre!='undefined'){ + console.log("resolve") + query = getSearchQuery(args.title, args.genre, args.order)} + // else if(typeof args.genre!='undefined' && args.genre){query = getQuery('genre' , args.genre)} + // else if(typeof args.rating_dice_throw!='undefined' && args.rating_dice_throw){query = getQuery('rating_dice_throw' , args.rating_dice_throw)} + // else if(typeof args.year!='undefined' && args.year){query = getQuery('year' , args.year)} + // else if(typeof args.director_first_name!='undefined' && args.director_first_name){query = getQuery('director_first_name' , args.director_first_name)} + // else if(typeof args.director_last_name!='undefined' && args.director_last_name){query = getQuery('director_last_name' , args.director_last_name)} + // else if(typeof args.description!='undefined' && args.description){query = getQuery('description' , args.description)} + const response = await connection.query(query); return response[0]; } @@ -66,10 +92,31 @@ const RootQuery = new GraphQLObjectType({ } }) -function getQuery(key: String, value: string){ +function getQuery(key: string, value: string){ return 'SELECT * FROM movie WHERE ' + key + ' = "' + value + '"' } +function getSearchQuery(title: string, genre: string, order: boolean): string { + let query = 'SELECT * FROM movie' + if (title != '') { + query = query + ' WHERE title LIKE "%' + title + '%"' + } + if (title != '' && genre != '') { + query = query + ' AND' + } + if (title == '' && genre != '') { + query = query + ' WHERE' + } + if (genre != '') { + query = query + ' genre LIKE "%' + genre + '%"' + } + if (order) { + query = query + ' ORDER BY "year"' + } + console.log(query) + return query +} + const Mutation = new GraphQLObjectType({ name: "Mutation", description: 'This is for creating a movie', @@ -122,15 +169,24 @@ const Mutation = new GraphQLObjectType({ const response = await connection.query('UPDATE movie SET title = ?, genre = ?, rating_dice_throw = ?, year = ?, director_first_name = ?, director_last_name = ? , description = ?, cover_image = ? WHERE id = ?', [args.title, args.genre, args.rating_dice_throw, args.year, args.director_first_name, args.director_last_name, args.description, args.cover_image, args.id]); return response[0]; } + }, + updateRating: { // TODO test this + type: MovieType, + args: { + id: {type: GraphQLInt}, + rating_dice_throw: { type: GraphQLInt } + }, + async resolve(parent: any, args: any) { + const connection = await connect(); + const response = await connection.query('UPDATE movie SET rating_dice_throw = ? WHERE id = ?', [args.genre, args.id]); + return response[0]; + } } } }) const schema = new GraphQLSchema({query: RootQuery, mutation: Mutation}) - -// var root = { hello: () => 'Hello world!' }; - var app = express(); app.use('/graphql', graphqlHTTP({ schema: schema,