Skip to content

Commit d9a581e

Browse files
committed
Add functionality to edit book
1 parent d4495b7 commit d9a581e

File tree

3 files changed

+126
-6
lines changed

3 files changed

+126
-6
lines changed

app/controllers/api/v1/books_controller.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ def create
2222
end
2323

2424
def update
25-
if book.update(book_params)
25+
if current_user != @book.recommender
26+
render json: { error: "You are not authorized to delete this book." }, status: :unauthorized
27+
elsif @book.update(book_params)
2628
render json: BookSerializer.new(@book).serializable_hash
2729
else
28-
render json: book.errors, status: :unprocessable_entity
30+
render json: @book.errors, status: :unprocessable_entity
2931
end
3032
end
3133

app/javascript/components/pages/BookDetail.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ const BookDetail = () => {
7474
)}
7575
</div>
7676
<div className="card-footer bg-secondary text-center">
77-
<button type="submit" className="btn btn-warning mx-2">
77+
<Link to={`/books/${id}/edit`} className="btn btn-warning mx-2">
7878
Edit Book
79-
</button>
79+
</Link>
8080
<button
8181
type="submit"
8282
className="btn btn-danger mx-2"
Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,125 @@
1-
import React from 'react';
1+
import React, { useState, useEffect } from 'react';
2+
import { useNavigate, useParams } from 'react-router-dom';
3+
import Button from 'react-bootstrap/Button';
4+
import Form from 'react-bootstrap/Form';
5+
import Card from 'react-bootstrap/Card';
6+
import Container from 'react-bootstrap/Container';
27

38
const EditBook = () => {
4-
return <h2>Here you can edit recommended book</h2>;
9+
const { id } = useParams();
10+
const [bookData, setBookData] = useState({
11+
title: '',
12+
author: '',
13+
description: '',
14+
});
15+
const navigate = useNavigate();
16+
17+
useEffect(() => {
18+
const fetchBook = async () => {
19+
const response = await fetch(`http://localhost:3000/api/v1/books/${id}`);
20+
const bookData = await response.json();
21+
setBookData({
22+
title: bookData.data.attributes.title,
23+
author: bookData.data.attributes.author,
24+
description: bookData.data.attributes.description,
25+
});
26+
};
27+
28+
fetchBook();
29+
}, [id]);
30+
31+
const handleInputChange = (event) => {
32+
const { name, value } = event.target;
33+
setBookData({ ...bookData, [name]: value });
34+
};
35+
36+
const handleSubmit = async (event) => {
37+
event.preventDefault();
38+
const csrfToken = document
39+
.querySelector('meta[name="csrf-token"]')
40+
.getAttribute('content');
41+
const response = await fetch(`http://localhost:3000/api/v1/books/${id}`, {
42+
method: 'PATCH',
43+
headers: {
44+
'Content-Type': 'application/json',
45+
'X-CSRF-Token': csrfToken,
46+
},
47+
body: JSON.stringify({ book: bookData }),
48+
});
49+
50+
if (response.ok) {
51+
const updatedBook = await response.json();
52+
navigate(`/books/${updatedBook.data.id}`);
53+
} else if (response.status === 401) {
54+
alert('You are not authorized to delete this book.');
55+
} else {
56+
alert('Failed to delete the book. Please try again.');
57+
}
58+
};
59+
60+
return (
61+
<Container className="d-flex justify-content-center my-5">
62+
<Card className="shadow-lg" style={{ maxWidth: '500px', width: '100%' }}>
63+
<Card.Body>
64+
<Card.Title className="text-center mb-4">Edit Book</Card.Title>
65+
<Form onSubmit={handleSubmit}>
66+
<Form.Group className="mb-3">
67+
<Form.Label>Book Title</Form.Label>
68+
<Form.Control
69+
type="text"
70+
placeholder="Enter book title"
71+
className="shadow-sm"
72+
name="title"
73+
value={bookData.title}
74+
onChange={handleInputChange}
75+
required
76+
/>
77+
</Form.Group>
78+
79+
<Form.Group className="mb-3">
80+
<Form.Label>Book Author</Form.Label>
81+
<Form.Control
82+
type="text"
83+
placeholder="Enter book author"
84+
className="shadow-sm"
85+
name="author"
86+
value={bookData.author}
87+
onChange={handleInputChange}
88+
required
89+
/>
90+
</Form.Group>
91+
92+
<Form.Group className="mb-4">
93+
<Form.Label>Book Description</Form.Label>
94+
<Form.Control
95+
as="textarea"
96+
rows={4}
97+
placeholder="Enter book description"
98+
className="shadow-sm"
99+
name="description"
100+
value={bookData.description}
101+
onChange={handleInputChange}
102+
required
103+
/>
104+
</Form.Group>
105+
106+
<div className="text-center">
107+
<Button variant="info" type="submit" className="w-100 mb-3">
108+
Update
109+
</Button>
110+
<Button
111+
variant="secondary"
112+
onClick={() => navigate(`/books/${id}`)}
113+
className="w-100"
114+
>
115+
Cancel
116+
</Button>
117+
</div>
118+
</Form>
119+
</Card.Body>
120+
</Card>
121+
</Container>
122+
);
5123
};
6124

7125
export default EditBook;

0 commit comments

Comments
 (0)