Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,45 @@ def get_movies():


@app.post("/movies", response_model=schemas.Movie)
def add_movie(movie: schemas.MovieBase):
movie = models.Movie.create(**movie.dict())
def add_movie(movie: schemas.MovieCreate):
movie_instance = models.Movie.create(**movie.dict(exclude={"actors"}))
for actor in movie.actors:
if (actor.name is not None) or (actor.surname is not None):
actor_instance = models.Actor.create(**actor.dict())
models.ActorMovie.create(actor=(actor_instance), movie=(movie_instance))
return movie


@app.get("/movies/{movie_id}", response_model=schemas.Movie)
def get_movie(movie_id: int):
db_movie = models.Movie.filter(models.Movie.id == movie_id).first()
if db_movie is None:
raise HTTPException(status_code=404, detail="Movie not found")
return db_movie

@app.get("/actors", response_model=List[schemas.Actor])
def get_actors():
return list(models.Actor.select())

@app.post("/actors", response_model=schemas.Actor)
def add_actor(movie: schemas.ActorBase):
if (movie.name is None) or (movie.surname is None):
raise HTTPException(status_code=400, detail="Actor name and surname is required")
else:
movie = models.Actor.create(**movie.dict())
return movie

@app.delete("/movies/{movie_id}", response_model=schemas.Movie)
def get_movie(movie_id: int):
db_movie = models.Movie.filter(models.Movie.id == movie_id).first()
db_movie_actors = models.ActorMovie.filter(models.ActorMovie.movie_id == movie_id)

if db_movie is None:
raise HTTPException(status_code=404, detail="Movie not found")
db_movie.delete_instance()
else:
for actor in db_movie_actors:
db_actor = models.Actor.filter(models.Actor.id == actor.actor_id).first()
db_actor.delete_instance()
actor.delete_instance()
db_movie.delete_instance()

return db_movie
Binary file modified api/movies.db
Binary file not shown.
6 changes: 5 additions & 1 deletion api/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class MovieBase(BaseModel):


class MovieCreate(MovieBase):
pass
actors: List[ActorBase] = []


class Movie(MovieBase):
Expand All @@ -46,4 +46,8 @@ class Config:
orm_mode = True
getter_dict = PeeweeGetterDict

class ActorMovieBase(BaseModel):
actor_id: int
movie_id: int


40 changes: 40 additions & 0 deletions ui/src/ActorForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {useState} from "react";

// export default function ActorForm(props) {

// const [actorFields, setActorFields] = useState( { name: '', surname: '' })
// // const [actors, setActors] = useState([]);
// const handleAddActor = () => {
// const actor = { ...actorFields };
// console.log('actor', actor);
// setActors([...actors, actor]);
// setActorFields({ name: '', surname: '' });
// console.log('actorOut', actors);
// };

// const handleRemoveActor = (index) => {
// let actor = [...actors ];
// actor.splice(index, 1);
// setActors(actor);
// };


// return <div ><h3>Actors:</h3>
// <div >
// <ul>
// {actors.map((actor, index) => (
// <li key={index}>
// {actor.name} {actor.surname}
// <button type="button" onClick={() => handleRemoveActor(index)}>Remove</button>
// </li>
// ))}
// </ul>
// <label>
// Add Actor:
// <input type="text" placeholder="name" value={actorFields.name} onChange={(event) => setActorFields({ ...actorFields, name: event.target.value })} />
// <input type="text" placeholder="surname" value={actorFields.surname} onChange={(event) => setActorFields({ ...actorFields, surname: event.target.value })} />
// <button type="button" onClick={handleAddActor}> Add </button>
// </label>
// </div>
// </div>;
// }
84 changes: 76 additions & 8 deletions ui/src/App.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,99 @@
import './App.css';
import {useState} from "react";
import {useEffect, useState} from "react";
import "milligram";
import MovieForm from "./MovieForm";
import MoviesList from "./MoviesList";
// import ActorForm from "./ActorForm";


function App() {
const [movies, setMovies] = useState([]);
const [addingMovie, setAddingMovie] = useState(false);
const [addActor, setAddActor] = useState([]);
// const [removeMovie, setRemoveMovie] = useState(false);

//current issue to fix read ID from backend that we can remove directly after adding
async function handleAddMovie(movie) {
const response = await fetch(`/movies`, {
method: 'POST',
body: JSON.stringify(movie),
headers: { 'Content-Type': 'application/json' }
});

if (response.ok) {
// fixed issue by adding reading (async) response deserialized from recived json
const movieFromServer = await response.json();
setMovies([...movies, movieFromServer]);
console.log(movies);
setAddingMovie(false);
}

}

async function handleRemoveMovie(movie) {
const response = await fetch(`/movies/${movie.id}`, {
method: 'DELETE'
});

if (response.ok) {
setMovies([...movies, movie]);
const removeMovie = movies.filter(m => m !== movie);

function handleAddMovie(movie) {
setMovies([...movies, movie]);
setAddingMovie(false);
setMovies(removeMovie);
}

}

async function handleAddActor(actor) {
const response = await fetch(`/actors`, {
method: 'POST',
body: JSON.stringify(actor),
headers: { 'Content-Type': 'application/json' }
});

if (response.ok) {
// fixed issue by adding reading (async) response deserialized from recived json
const actorFromServer = await response.json();
setAddActor([...addActor, actorFromServer]);;
}

}

//use effect = it will fetch data from backend only on start
//
useEffect(() => {
const fetchMovies = async () => {
const response = await fetch(`/movies`);

if (response.ok) {
const movies = await response.json();
setMovies(movies);
}
};

fetchMovies();
// empty array [] gives option that it is executed only onece because array is empty and it guarantte thei1 execution
// in other word effect worka on changes of array so if it is empty never change
}, []);

return (
<div className="container">
<h1>My favourite movies to watch</h1>
{movies.length === 0
? <p>No movies yet. Maybe add something?</p>
: <MoviesList movies={movies}
onDeleteMovie={(movie) => setMovies(movies.filter(m => m !== movie))}
onDeleteMovie={handleRemoveMovie}
/>}
{addingMovie
? <MovieForm onMovieSubmit={handleAddMovie}
buttonLabel="Add a movie"
/>
?<div>
<MovieForm onMovieSubmit={handleAddMovie}
onAddActor={handleAddActor}
buttonLabel="Add a movie"/>
{/* <ActorForm onAddActor={handleAddActor}
buttonLabel="Add an actor"/> */}
</div>
: <button onClick={() => setAddingMovie(true)}>Add a movie</button>}

</div>
);
}
Expand Down
63 changes: 55 additions & 8 deletions ui/src/MovieForm.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,87 @@
import {useState} from "react";
// import ActorForm from "./ActorForm";

export default function MovieForm(props) {
const [title, setTitle] = useState('');
const [year, setYear] = useState('');
const [director, setDirector] = useState('');
const [description, setDescription] = useState('');
const [name, setName] = useState('');
const [surname, setSurname] = useState('');
const [actors, setActors] = useState([]);
const [actorFields, setActorFields] = useState( { name: '', surname: '' })


function addMovie(event) {
event.preventDefault();
if (title.length < 5) {
return alert('Tytuł jest za krótki');
}
props.onMovieSubmit({title, year, director, description});
// if (title.length < 5) {
// return alert('Tytuł jest za krótki');
// }

props.onMovieSubmit({title, year, director, description, actors});

setTitle('');
setYear('');
setDirector('');
setDescription('');
setActors([]);
console.log('movieOut', {title, year, director, description});
}


const handleAddActor = () => {
const actor = { ...actorFields };
console.log('actor', actor);
setActors([...actors, actor]);
setActorFields({ name: '', surname: '' });
console.log('actorOut', actors);
};

const handleRemoveActor = (index) => {
let actor = [...actors ];
actor.splice(index, 1);
setActors(actor);
};



return <form onSubmit={addMovie}>
<h2>Add movie</h2>
<div>
<label>Tytuł</label>
<input type="text" value={title} onChange={(event) => setTitle(event.target.value)}/>
<input type="text" placeholder="title more than 5 characters" value={title} onChange={(event) => setTitle(event.target.value)}/>
</div>
<div>
<label>Year</label>
<input type="text" value={year} onChange={(event) => setYear(event.target.value)}/>
<input type="text" placeholder="year *" value={year} onChange={(event) => setYear(event.target.value)}/>
</div>
<div>
<label>Director</label>
<input type="text" value={director} onChange={(event) => setDirector(event.target.value)}/>
<input type="text" placeholder="director *" value={director} onChange={(event) => setDirector(event.target.value)}/>
</div>
<div>
<label>Description</label>
<textarea value={description} onChange={(event) => setDescription(event.target.value)}/>
<textarea value={description} placeholder="description (optional)" onChange={(event) => setDescription(event.target.value)}/>
</div>
{/* <ActorForm actors={actors} setActors={setActors}/> */}

<h3>Actors:</h3>

<div >
<ul>
{actors.map((actor, index) => (
<li key={index}>
{actor.name} {actor.surname}
<button type="button" onClick={() => handleRemoveActor(index)}>Remove</button>
</li>
))}
</ul>
<label>
Add Actor:
<input type="text" placeholder="name" value={actorFields.name} onChange={(event) => setActorFields({ ...actorFields, name: event.target.value })} />
<input type="text" placeholder="surname" value={actorFields.surname} onChange={(event) => setActorFields({ ...actorFields, surname: event.target.value })} />
<button type="button" onClick={handleAddActor}> Add </button>
</label>
</div>
<button>{props.buttonLabel || 'Submit'}</button>
</form>;
Expand Down
3 changes: 2 additions & 1 deletion ui/src/MoviesList.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ export default function MoviesList(props) {
return <div>
<h2>Movies</h2>
<ul className="movies-list">
{props.movies.map(movie => <li key={movie.title}>
{/* map by id it avoid issue when title is the same */}
{props.movies.map(movie => <li key={movie.id}>
<MovieListItem movie={movie} onDelete={() => props.onDeleteMovie(movie)}/>
</li>)}
</ul>
Expand Down