Changeset e15e8d9


Ignore:
Timestamp:
04/30/25 18:24:41 (2 weeks ago)
Author:
Aleksandar Panovski <apano77@…>
Branches:
main
Children:
2518b3a
Parents:
deea3c4
Message:

menu feature done

Files:
4 added
10 edited

Legend:

Unmodified
Added
Removed
  • my-react-app/src/components/ReservationConfirmation.js

    rdeea3c4 re15e8d9  
    33import axios from 'axios';
    44import { useNavigate } from 'react-router-dom';
    5 import {jwtDecode} from "jwt-decode";
     5import { useLocation } from 'react-router-dom';
     6import { jwtDecode } from "jwt-decode";
    67import {request} from "../axios_helper";
    78import restaurants from "./Restaurants";
     
    1011    const navigate = useNavigate();
    1112
     13    const location = useLocation();
     14    const preOrderedItems = location.state?.preOrderedItems || [];
    1215    const [restaurant, setRestaurant] = useState({});
    1316    const [user, setUser] = useState({});
     
    5962            specialRequests: specialRequests.trim(),
    6063            paymentStatus: 'Pending',
     64            preOrderedItems: preOrderedItems.map(item => `${item.itemName}:${item.quantity}:${item.price}`)
    6165        };
    6266
     
    117121        return `${formattedDate} - ${formattedTime}`;
    118122    };
     123
     124    const grandTotal = preOrderedItems.reduce((acc, item) => acc + item.price * item.quantity, 0).toFixed(2);
     125    const itemQuantityString = preOrderedItems
     126        .map(item => `${item.itemName}:${item.quantity}`)
     127        .join(',');
    119128
    120129    return (
     
    156165                                    <br />
    157166                                </p>
     167                                {preOrderedItems.length > 0 ? (
     168                                    <div className="row">
     169                                        {preOrderedItems.map((item) => (
     170                                            <div key={item.menuID} className="col-md-4 mb-4">
     171                                                <div className="list-group shadow-sm p-3">
     172                                                    <p className="item"><strong>Item:</strong> {item.itemName}</p>
     173                                                    <p className="item"><strong>Price:</strong> ${item.price.toFixed(2)}</p>
     174                                                    <p className="item"><strong>Quantity:</strong> {item.quantity}</p>
     175                                                    <p className="item"><strong>Total:</strong> ${(item.price * item.quantity).toFixed(2)}</p>
     176                                                </div>
     177                                            </div>
     178                                        ))}
     179
     180                                        <div className="col-12 mt-4">
     181                                            <div className="list-group shadow-sm p-4 text-center">
     182                                                <h4>Grand Total: ${grandTotal}</h4>
     183                                            </div>
     184                                        </div>
     185                                    </div>
     186                                ) : (
     187                                    <p>No pre-ordered items.</p>
     188                                )}
    158189                            </div>
    159190                            <div className="card-footer">
  • my-react-app/src/components/ReservationEdit.js

    rdeea3c4 re15e8d9  
    6565    }, [table]);
    6666
    67     const generateTimeSlots = (operatingHours, interval) => {
    68         const slots = [];
    69         const [startTimeStr, endTimeStr] = operatingHours.split('-');
    70         const [startHours, startMinutes] = startTimeStr.split(':').map(Number);
    71         const [endHours, endMinutes] = endTimeStr.split(':').map(Number);
    72 
    73         const startTime = new Date();
    74         startTime.setHours(startHours, startMinutes, 0, 0);
    75 
    76         const endTime = new Date();
    77         endTime.setHours(endHours, endMinutes, 0, 0);
    78 
    79         let currentTime = startTime;
    80         while (currentTime <= endTime) {
    81             slots.push(new Date(currentTime).toISOString());
    82             currentTime = new Date(currentTime.getTime() + interval * 60000);
    83         }
    84 
    85         return slots;
    86     };
    87 
    8867    const generateTimeOptions = (operatingHours) => {
    89         const { startTime, endTime } = parseOperatingHours(operatingHours);
    9068        const now = new Date();
    91 
    9269        const selectedDateObj = new Date(selectedDate);
     70
     71        const { startTime, endTime } = parseOperatingHours(operatingHours, selectedDateObj);
     72
    9373        const isToday = selectedDateObj.toDateString() === now.toDateString();
    94         const isTomorrow = selectedDateObj > now && selectedDateObj.getDate() === now.getDate() + 1;
    9574
    9675        let currentTime;
    9776
    9877        if (isToday) {
    99             currentTime = roundToNext15Minutes(new Date());
     78            const roundedNow = roundToNext15Minutes(now);
     79
     80            if (roundedNow < startTime) {
     81                currentTime = startTime;
     82            } else if (roundedNow > endTime) {
     83                return [];
     84            } else {
     85                currentTime = roundedNow;
     86            }
    10087        } else {
    101             currentTime = new Date(startTime);
     88            currentTime = startTime;
    10289        }
    10390
     
    11198    };
    11299
    113     useEffect(() => {
    114         const operatingHours = table?.restaurant?.operatingHours || "09:00-00:00";
    115         const allTimeSlots = generateTimeSlots(operatingHours, timeSlotInterval);
    116 
    117         const availableSlots = allTimeSlots.filter((slot) =>
    118             !tableReservations.includes(slot)
    119         );
    120 
    121         setFilteredTimeSlots(availableSlots);
    122     }, [tableReservations, table]);
     100    const roundToNext15Minutes = (date) => {
     101        const ms = 1000 * 60 * 15;
     102        return new Date(Math.ceil(date.getTime() / ms) * ms);
     103    };
     104
     105    useEffect(() => {
     106        if (table?.restaurant?.operatingHours && selectedDate) {
     107            const options = generateTimeOptions(table.restaurant.operatingHours);
     108            setTimeOptions(options);
     109        }
     110    }, [table, selectedDate]);
     111
    123112
    124113    const handleInputChange = (e) => {
     
    189178    const formattedDate = `${year}-${month}-${day}`;
    190179
    191     const parseOperatingHours = (operatingHours) => {
     180    const parseOperatingHours = (operatingHours, forDate) => {
    192181        const [start, end] = operatingHours.split('-');
    193         return {
    194             startTime: new Date(`1970-01-01T${start}:00`),
    195             endTime: new Date(`1970-01-01T${end}:00`)
    196         };
     182
     183        const [startHour, startMinute] = start.split(':').map(Number);
     184        const [endHour, endMinute] = end.split(':').map(Number);
     185
     186        const startTime = new Date(forDate);
     187        startTime.setHours(startHour, startMinute, 0, 0);
     188
     189        const endTime = new Date(forDate);
     190        endTime.setHours(endHour, endMinute, 0, 0);
     191
     192        return { startTime, endTime };
    197193    };
    198194
  • my-react-app/src/components/Reservations.js

    rdeea3c4 re15e8d9  
    2424                const response = await axios.get(`http://localhost:8081/api/reservations/by/${userId}`);
    2525                setReservations(response.data);
     26                console.log(response.data)
    2627            } catch (error) {
    2728                console.error('Error fetching reservations:', error);
     
    8889                                        "Not specified"} </p>
    8990                                    <p className="card-text">Party Size: {reservation.partySize || "Not specified"}</p>
     91                                    {reservation.preOrderedItems && reservation.preOrderedItems.length > 0 ? (
     92                                        <div className="mt-3">
     93                                            <h5 className="text-primary">Pre-Ordered Items:</h5>
     94                                            <ul className="list-group mb-3">
     95                                                {reservation.preOrderedItems.map((itemStr, index) => {
     96                                                    const parts = itemStr.split(':');
     97                                                    const name = parts[0];
     98                                                    const quantity = parseInt(parts[1], 10) || 0;
     99                                                    const price = parseFloat(parts[2]) || 0;
     100
     101                                                    return (
     102                                                        <li key={index} className="list-group-item d-flex justify-content-between align-items-center">
     103                                                            <span><strong>{name}</strong> × {quantity}</span>
     104                                                            <span className="badge bg-success rounded-pill">${(price * quantity).toFixed(2)}</span>
     105                                                        </li>
     106                                                    );
     107                                                })}
     108                                            </ul>
     109
     110                                            <div className="alert alert-info text-center" role="alert">
     111                                                <h5>Grand Total: ${reservation.preOrderedItems.reduce((acc, itemStr) => {
     112                                                    const parts = itemStr.split(':');
     113                                                    const quantity = parseInt(parts[1], 10) || 0;
     114                                                    const price = parseFloat(parts[2]) || 0;
     115                                                    return acc + (quantity * price);
     116                                                }, 0).toFixed(2)}</h5>
     117                                            </div>
     118                                        </div>
     119                                    ) : (
     120                                        <p>No pre-ordered items.</p>
     121                                    )}
    90122                                    <p className="card-text text-danger">Special Requests: {reservation.specialRequests || "None"}</p>
    91123                                    <p className="card-text">Status: {reservation.status || "Pending"}</p>
  • my-react-app/src/components/RestaurantDetails.js

    rdeea3c4 re15e8d9  
    55import { useParams } from 'react-router-dom';
    66import StarRating from "./StarRating";
     7import MenuList from "./MenuList";
    78
    89
     
    1011    const navigate = useNavigate();
    1112    const { id } = useParams();
     13    const [preOrderedItems, setPreOrderedItems] = useState([]);
    1214
    1315    const [restaurant, setRestaurant] = useState(null);
     
    100102        const encodedRestaurantId = encodeURIComponent(restaurant.restaurantId);
    101103
    102         navigate(`/reservationConfirmation/${encodedTableId}/${encodedDateTime}/${encodedRestaurantId}`);
    103     };
     104        const totalPrice = preOrderedItems.reduce((acc, item) => acc + item.price * item.quantity, 0).toFixed(2);
     105
     106        navigate(`/reservationConfirmation/${encodedTableId}/${encodedDateTime}/${encodedRestaurantId}`, {
     107            state: {
     108                preOrderedItems: preOrderedItems,
     109                totalPrice: totalPrice,
     110            }
     111        });
     112    };
     113
    104114
    105115    const roundToNext15Minutes = (date) => {
     
    174184                            </>
    175185                        )}
    176 
     186                        <MenuList
     187                            restaurantId={restaurant.restaurantId}
     188                            setPreOrderedItems={setPreOrderedItems}
     189                            preOrderedItems={preOrderedItems}
     190                        />
    177191                        <br />
    178192                        <button
    179193                            className="btn btn-primary"
    180194                            onClick={handleReservationConfirmation}
    181                             disabled={!selectedTableId || !selectedDate || !selectedTime}
    182                         >
     195                            disabled={!selectedTableId || !selectedDate || !selectedTime}>
    183196                            Confirm Reservation
    184197                        </button>
  • my-react-app/src/components/RestaurantInfo.js

    rdeea3c4 re15e8d9  
    11import React from 'react';
    22import StarRating from "./StarRating";
     3import MenuList from "./MenuList";
    34
    45const RestaurantInfo = ({ restaurant }) => {
     
    89                {restaurant.name} <StarRating key={restaurant.id} rating={restaurant.rating}/>
    910            </h2>
    10             <p className="card-text">{restaurant.cuisineType}</p> {/* Assuming cuisineType is provided */}
    11             <p className="card-text">{restaurant.operatingHours}</p> {/* Assuming operatingHours is provided */}
    12             <p className="card-text">Ul. {restaurant.address}</p> {/* Assuming address is provided */}
     11            <p className="card-text">{restaurant.cuisineType}</p>
     12            <p className="card-text">{restaurant.operatingHours}</p>
     13            <p className="card-text">Ul. {restaurant.address}</p>
     14            <MenuList restaurantId={restaurant.id} />
    1315        </div>
    1416    );
  • src/main/java/com/example/rezevirajmasa/demo/dto/ReservationDTO.java

    rdeea3c4 re15e8d9  
    66import java.math.BigDecimal;
    77import java.time.LocalDateTime;
     8import java.util.List;
    89
    910public class ReservationDTO {
     
    1920    private String specialRequests;
    2021    private String paymentStatus;
     22    private List<String> preOrderedItems;
     23
    2124
    2225    public ReservationDTO() {
    2326    }
    2427
    25     public ReservationDTO(Long reservationID, String userEmail, BigDecimal rating, Long tableNumber, LocalDateTime reservationDateTime, LocalDateTime checkInTime, Restaurant restaurant, int partySize, String status, String specialRequests, String paymentStatus) {
     28    public ReservationDTO(Long reservationID, String userEmail, BigDecimal rating, Long tableNumber, LocalDateTime reservationDateTime, LocalDateTime checkInTime, Restaurant restaurant, int partySize, String status, String specialRequests, String paymentStatus, List<String> preOrderedItems) {
    2629        this.reservationID = reservationID;
    2730        this.userEmail = userEmail;
     
    3538        this.specialRequests = specialRequests;
    3639        this.paymentStatus = paymentStatus;
     40        this.preOrderedItems = preOrderedItems;
    3741    }
    3842
     
    4953        this.specialRequests = reservation.getSpecialRequests();
    5054        this.paymentStatus = reservation.getPaymentStatus();
     55        this.preOrderedItems = reservation.getPreOrderedItems();
     56    }
     57
     58    public List<String> getPreOrderedItems() {
     59        return preOrderedItems;
     60    }
     61
     62    public void setPreOrderedItems(List<String> preOrderedItems) {
     63        this.preOrderedItems = preOrderedItems;
    5164    }
    5265
  • src/main/java/com/example/rezevirajmasa/demo/model/Menu.java

    rdeea3c4 re15e8d9  
    11package com.example.rezevirajmasa.demo.model;
    22
     3import com.fasterxml.jackson.annotation.JsonIgnore;
    34import jakarta.persistence.*;
     5import lombok.Data;
    46
    57import java.math.BigDecimal;
     
    79@Entity
    810@Table(name = "menus")
     11@Data
    912public class Menu {
    1013    @Id
     
    1518    @ManyToOne
    1619    @JoinColumn(name = "RestaurantID", nullable = false)
     20    @JsonIgnore
    1721    private Restaurant restaurant;
    1822
  • src/main/java/com/example/rezevirajmasa/demo/model/Reservation.java

    rdeea3c4 re15e8d9  
    44import com.fasterxml.jackson.annotation.JsonManagedReference;
    55import jakarta.persistence.*;
     6import lombok.Data;
     7import lombok.Getter;
     8import lombok.Setter;
    69
    710import java.math.BigDecimal;
    811import java.time.LocalDateTime;
    912import java.time.LocalTime;
     13import java.util.ArrayList;
     14import java.util.List;
    1015
    1116@Entity
    1217@Table(name = "reservations")
     18@Data
    1319public class Reservation {
    1420
     
    4753    private LocalDateTime checkInTime;
    4854
     55    @Getter
    4956    @Column(name = "CheckOutTime")
    5057    private LocalDateTime checkOutTime;
    5158
    52 //    @Column(name = "TotalAmount", precision = 8, scale = 2)
    53 //    private BigDecimal totalAmount;
     59    @ElementCollection
     60    @CollectionTable(name = "reservation_preordered_items", joinColumns = @JoinColumn(name = "reservation_id"))
     61    @Column(name = "item")
     62    private List<String> preOrderedItems = new ArrayList<>();
    5463
    5564    @Column(name = "PaymentStatus", length = 20, nullable = false, columnDefinition = "VARCHAR default 'Unpaid'")
     
    7180
    7281    public Reservation(User user, TableEntity table, Restaurant restaurant, LocalDateTime reservationDateTime, int partySize, String specialRequests, String status, LocalDateTime checkInTime, LocalDateTime checkOutTime, String paymentStatus) {
    73 //        this.customer = customer;
    7482        this.table = table;
    7583        this.user = user;
     
    8492    }
    8593
    86     public User getUser() {
    87         return user;
    88     }
    89 
    90     public void setUser(User user) {
    91         this.user = user;
    92     }
    93 
    94     public Long getReservationID() {
    95         return reservationID;
    96     }
    97 
    98     public void setReservationID(Long reservationID) {
    99         this.reservationID = reservationID;
    100     }
    101 
    102 
    103     public TableEntity getTable() {
    104         return table;
    105     }
    106 
    107     public void setTable(TableEntity table) {
    108         this.table = table;
    109     }
    110 
    111     public Restaurant getRestaurant() {
    112         return restaurant;
    113     }
    114 
    115     public void setRestaurant(Restaurant restaurant) {
    116         this.restaurant = restaurant;
    117     }
    118 
    119     public LocalDateTime getReservationDateTime() {
    120         return reservationDateTime;
    121     }
    122 
    123     public void setReservationDateTime(LocalDateTime reservationDateTime) {
    124         this.reservationDateTime = reservationDateTime;
    125     }
    126 
    127     public int getPartySize() {
    128         return partySize;
    129     }
    130 
    131     public void setPartySize(int partySize) {
    132         this.partySize = partySize;
    133     }
    134 
    135     public String getSpecialRequests() {
    136         return specialRequests;
    137     }
    138 
    139     public void setSpecialRequests(String specialRequests) {
    140         this.specialRequests = specialRequests;
    141     }
    142 
    143     public String getStatus() {
    144         return status;
    145     }
    146 
    147     public void setStatus(String status) {
    148         this.status = status;
    149     }
    150 
    151     public LocalDateTime getCheckInTime() {
    152         return checkInTime;
    153     }
    154 
    155     public void setCheckInTime(LocalDateTime checkInTime) {
    156         this.checkInTime = checkInTime;
    157     }
    158 
    159     public LocalDateTime getCheckOutTime() {
    160         return checkOutTime;
    161     }
    162 
    163     public void setCheckOutTime(LocalDateTime checkOutTime) {
    164         this.checkOutTime = checkOutTime;
    165     }
    166 
    167     public String getPaymentStatus() {
    168         return paymentStatus;
    169     }
    170 
    171     public void setPaymentStatus(String paymentStatus) {
    172         this.paymentStatus = paymentStatus;
    173     }
    17494
    17595    @Override
  • src/main/java/com/example/rezevirajmasa/demo/service/impl/ReservationImpl.java

    rdeea3c4 re15e8d9  
    6363            TableEntity table = optionalTable.get();
    6464
    65             LocalDateTime reservationTime = reservationDTO.getReservationDateTime();
    66             LocalDateTime startTime = reservationTime.minusHours(2);
    67             LocalDateTime endTime = reservationTime.plusHours(2);
     65            LocalDateTime startTime = reservationDTO.getReservationDateTime().plusHours(1);
     66            LocalDateTime endTime = reservationDTO.getReservationDateTime().plusHours(3);
    6867
    6968            boolean hasConflict = table.getReservations().stream()
     
    9392            reservation.setPaymentStatus(reservationDTO.getPaymentStatus() != null ? reservationDTO.getPaymentStatus() : "Unpaid");
    9493            reservation.setUser(user);
     94            reservation.setPreOrderedItems(reservationDTO.getPreOrderedItems());
    9595            reservation.setRestaurant(reservationDTO.getRestaurant());
    96             reservation.setCheckInTime(reservationTime);
     96            reservation.setCheckInTime(reservationDTO.getReservationDateTime().plusHours(1));
    9797            reservation.setReservationDateTime(LocalDateTime.now());
    98             reservation.setCheckOutTime(reservationTime.plusHours(2));
     98            reservation.setCheckOutTime(reservationDTO.getReservationDateTime().plusHours(3));
    9999            reservation.setRestaurant(reservationDTO.getRestaurant());
    100100
  • src/main/java/com/example/rezevirajmasa/demo/web/rest/testController.java

    rdeea3c4 re15e8d9  
    3737    private final ReservationHistoryService reservationHistoryService;
    3838    private final TableService tableService;
     39    private final MenuService menuService;
    3940    private final UserMapper userMapper;
    4041    private final TokenService tokenService;
    41     public testController(RestaurantService restaurantService, CustomerService customerService, UserService userService, ReservationService reservationService, ReservationHistoryService reservationHistoryService, TableService tableService, UserMapper userMapper, TokenService tokenService) {
     42    public testController(RestaurantService restaurantService, CustomerService customerService, UserService userService, ReservationService reservationService, ReservationHistoryService reservationHistoryService, TableService tableService, MenuService menuService, UserMapper userMapper, TokenService tokenService) {
    4243        this.restaurantService = restaurantService;
    4344        this.customerService = customerService;
     
    4647        this.reservationHistoryService = reservationHistoryService;
    4748        this.tableService = tableService;
     49        this.menuService = menuService;
    4850        this.userMapper = userMapper;
    4951        this.tokenService = tokenService;
     
    272274        return new ResponseEntity<>(reservations, HttpStatus.OK);
    273275    }
     276
     277    // menu calls
     278    @GetMapping("/api/restaurant-menu/{restaurantId}")
     279    public List<Menu> getMenuByRestaurantId(@PathVariable Long restaurantId) {
     280        return menuService.getMenuByRestaurantId(restaurantId);
     281    }
    274282}
Note: See TracChangeset for help on using the changeset viewer.