Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Myreservations #15

Merged
merged 4 commits into from
Mar 4, 2024
Merged
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
72 changes: 67 additions & 5 deletions src/Components/MyReservations.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,73 @@
import React from 'react';
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchReservations, removeReservation } from '../Redux/reservations/myReservationsSlice';
import '../MyReservations.css';

function MyReservations() {
const dispatch = useDispatch();
const reservations = useSelector((state) => state.myReservations.reservations);
const status = useSelector((state) => state.myReservations.status);
const error = useSelector((state) => state.myReservations.error);

useEffect(() => {
if (status === 'idle') {
dispatch(fetchReservations());
}
}, [status, dispatch]);

const handleDelete = (reservationId) => {
dispatch(removeReservation(reservationId));
};

if (status === 'loading') {
return <div>Loading...</div>;
}

if (status === 'failed') {
return (
<div>
Error:
{error}
</div>
);
}

return (
<div>
{/* <h1>StaySpare</h1>
<p>This is the main Content of the Hotel application</p> */}
This is my reservations page
<div className="myreservationspage">
<h1>My Reservations</h1>
{reservations.map((reservation) => (
<ul key={reservation.id} className="reservation-card-container">
<div className="reservation-card-detail">
<img className="place-img" src={reservation.place.photo} alt={reservation.place.description} />
<li>
<h2>{reservation.place.description}</h2>
<p>
<strong>Check-in:</strong>
{' '}
{reservation.start_date}
</p>
<p>
<strong>Check-out:</strong>
{' '}
{reservation.end_date}
</p>
<p>
<strong>Price:</strong>
{' '}
{reservation.price}
</p>
<button
type="button"
id="delete-button"
onClick={() => handleDelete(reservation.id)}
>
Delete
</button>
</li>
</div>
</ul>

))}
</div>
);
}
Expand Down
69 changes: 69 additions & 0 deletions src/MyReservations.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
p {
color: black;
}

.myreservationspage {
margin-top: auto;
padding: 0;
font-family: Arial, sans-serif;
}

.reservation-card-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin: 0 auto;
padding: 0;
}

.reservation-details {
display: flex;
flex-direction: column;
align-items: center;
}

#delete-button {
background-color: #f44336;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
cursor: pointer;
width: 100%;
}

.reservation-card-detail {
transition: transform 2.5s ease;
padding: 1rem;
}

.reservation-card-detail:hover {
border: solid 2px #e2dddd;
border-radius: 2rem;
transform: scale(1.04);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
cursor: pointer;
}

table {
border-collapse: collapse;
width: 100%;
border-radius: 2rem;
}

th {
border: solid 1px black;
padding: 8px;
text-align: left;
background-color: #f2f2f2;
}

td {
border: solid 1px black;
padding: 8px;
text-align: left;
}

tr:nth-child(even) {
background-color: #d6d4d4;
}
65 changes: 65 additions & 0 deletions src/Redux/reservations/myReservationsSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// reservationsSlice.js

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import axios from 'axios';

export const fetchReservations = createAsyncThunk(
'myReservations/fetchReservations',
async () => {
const userId = localStorage.getItem('userId');
const response = await axios.get(`http://localhost:3000/api/v1/users/${userId}/reservations`);
return response.data;
},
);

export const removeReservation = createAsyncThunk(
'myReservations/removeReservation',
async (reservationId) => {
const userId = localStorage.getItem('userId');
try {
await axios.delete(`http://localhost:3000/api/v1/users/${userId}/reservations/${reservationId}`);
return reservationId;
} catch (error) {
throw Error('Failed to delete reservation');
}
},
);

const myReservationsSlice = createSlice({
name: 'myReservations',
initialState: {
reservations: [],
status: 'idle',
error: null,
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchReservations.pending, (state) => {
state.status = 'loading';
})
.addCase(fetchReservations.fulfilled, (state, action) => {
state.status = 'succeeded';
state.reservations = action.payload;
})
.addCase(fetchReservations.rejected, (state, action) => {
state.status = 'failed';
state.error = action.error.message;
})
.addCase(removeReservation.pending, (state) => {
state.status = 'loading';
})
.addCase(removeReservation.fulfilled, (state, action) => {
state.status = 'succeeded';
state.reservations = state.reservations.filter(
(reservation) => reservation.id !== action.payload,
);
})
.addCase(removeReservation.rejected, (state, action) => {
state.status = 'failed';
state.error = action.error.message;
});
},
});

export default myReservationsSlice.reducer;
2 changes: 2 additions & 0 deletions src/Redux/store.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { configureStore } from '@reduxjs/toolkit';
import placesReducer from './places/placesSlice';
import addPlaceReducer from './places/addPlaceSlice';
import reservationsReducer from './reservations/myReservationsSlice';

export default configureStore({
reducer: {
places: placesReducer,
addPlace: addPlaceReducer,
myReservations: reservationsReducer,
},
});
Loading