Changeset e48199a


Ignore:
Timestamp:
05/07/25 18:34:01 (10 days ago)
Author:
Aleksandar Panovski <apano77@…>
Branches:
main
Parents:
b67dfd3
Message:

Final version for DB

Files:
3 added
1 deleted
16 edited

Legend:

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

    rb67dfd3 re48199a  
    9696                const option = currentTime.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false });
    9797                slots.push(option);
    98                 currentTime.setMinutes(currentTime.getMinutes() + 15); // Increment by 15 minutes
     98                currentTime.setMinutes(currentTime.getMinutes() + 15);
    9999            }
    100100
     
    322322                            <div className="card-body">
    323323                                <div className="row">
    324                                     {/* Narrow left column: info and actions */}
     324
    325325                                    <div className="col-md-4">
    326326                                        <RestaurantInfo key={restaurant.id} restaurant={restaurant}/>
     
    340340                                    </div>
    341341
    342                                     {/* Wide right column: menu */}
     342
    343343                                    <div className="col-md-8">
    344344                                        <ReadOnlyMenuList restaurantId={restaurant.restaurantId}/>
  • my-react-app/src/components/ErrorPage.js

    rb67dfd3 re48199a  
    1 // ErrorPage.js
    21import React from 'react';
    32
     
    76            <h1>Oops! Something went wrong.</h1>
    87            <p>Please try again later or contact support.</p>
    9             {/* Add any additional content or error-specific messages */}
    108        </div>
    119    );
  • my-react-app/src/components/Layout.js

    rb67dfd3 re48199a  
    1 // Layout.js
    21import React from 'react';
    32import Header from './Header';
  • my-react-app/src/components/ReadOnlyMenuList.js

    rb67dfd3 re48199a  
    1414                const response = await axios.get(`http://localhost:8081/api/restaurant-menu/${restaurantId}`);
    1515                setMenuItems(response.data);
    16                 setCurrentPage(1); // Reset to first page on restaurant change
     16                setCurrentPage(1);
    1717            } catch (err) {
    1818                console.error('Failed to fetch menu:', err);
  • my-react-app/src/components/ReservationConfirmation.js

    rb67dfd3 re48199a  
    2727                const tableResponse = await axios.get(`http://localhost:8081/api/tables/${tableNumber}`);
    2828                setTable(tableResponse.data);
    29                 console.log(tableResponse.data)
    3029                const restaurantResponse = await axios.get(`http://localhost:8081/api/restaurants/${restaurantId}`);
    3130                setRestaurant(restaurantResponse.data);
     
    6564                preorderedItemName: item.itemName,
    6665                quantity: item.quantity,
    67                 price: item.price
     66                price: item.price,
     67                menuID: item.menuID
    6868            }))
    6969        };
     
    7676                }
    7777            });
    78             console.log('Reservation created successfully:', response.data);
    7978            navigate("/reservations")
    8079        } catch (error) {
     
    112111            localStorage.removeItem('remainingTime');
    113112            alert("Time has expired. Please try reserving again.");
    114             navigate('/restaurants'); // Redirect or take necessary action
     113            navigate('/restaurants');
    115114        }
    116115    }, [remainingTime, navigate]);
  • my-react-app/src/components/ReservationEdit.js

    rb67dfd3 re48199a  
    3030                setIsLoading(true);
    3131                const response = await axios.get(`http://localhost:8081/api/reservations/${reservationId}`);
    32                 console.log(response)
    3332                setCheckInTime(response.data.reservationDateTime);
    3433                setFormData(response.data);
    35                 setRestaurant(response.data.restaurantName);
     34
    3635                setRestaurantId(response.data.restaurantId);
     36                const restaurantResponse = await axios.get(`http://localhost:8081/api/restaurants/${response.data.restaurantId}`);
     37                setRestaurant(restaurantResponse.data);
    3738
    3839                setTableNumber(response.data.tableNumber);
     
    4546            }
    4647        };
    47 
    4848        fetchReservation();
    4949    }, [reservationId]);
     
    6464        }
    6565    }, [table]);
    66 
    67     const generateTimeOptions = (operatingHours) => {
    68         const now = new Date();
    69         const selectedDateObj = new Date(selectedDate);
    70 
    71         const { startTime, endTime } = parseOperatingHours(operatingHours, selectedDateObj);
    72 
    73         const isToday = selectedDateObj.toDateString() === now.toDateString();
    74 
    75         let currentTime;
    76 
    77         if (isToday) {
    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             }
    87         } else {
    88             currentTime = startTime;
    89         }
    90 
    91         const options = [];
    92         while (currentTime <= endTime) {
    93             options.push(currentTime.toTimeString().slice(0, 5));
    94             currentTime = new Date(currentTime.getTime() + 15 * 60 * 1000);
    95         }
    96 
    97         return options;
    98     };
    99 
    100     const roundToNext15Minutes = (date) => {
    101         const ms = 1000 * 60 * 15;
    102         return new Date(Math.ceil(date.getTime() / ms) * ms);
    103     };
    10466
    10567    useEffect(() => {
     
    178140    const formattedDate = `${year}-${month}-${day}`;
    179141
    180     const parseOperatingHours = (operatingHours, forDate) => {
    181         const [start, end] = operatingHours.split('-');
    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 };
    193     };
    194 
    195     useEffect(() => {
    196         if (formData?.restaurant?.operatingHours && selectedDate) {
    197             const options = generateTimeOptions(formData.restaurant.operatingHours);
     142    const generateTimeOptions = (operatingHours) => {
     143        const now = new Date();
     144        const selectedDateObj = new Date(selectedDate);
     145        const isToday = selectedDateObj.toDateString() === now.toDateString();
     146
     147        let options = [];
     148        for (const hours of operatingHours.split(',')) {
     149            const [start, end] = hours.trim().split('-');
     150            const startTime = new Date(selectedDateObj);
     151            const endTime = new Date(selectedDateObj);
     152            const [startHour, startMinute] = start.split(':').map(Number);
     153            const [endHour, endMinute] = end.split(':').map(Number);
     154            startTime.setHours(startHour, startMinute, 0);
     155            endTime.setHours(endHour, endMinute, 0);
     156
     157            if (isToday && startTime < now) {
     158                startTime.setTime(roundToNext15Minutes(now).getTime());
     159            }
     160
     161            if (endTime <= now) {
     162                setNoAvailableMessage('No available time due to closing.');
     163                continue;
     164            }
     165
     166            while (startTime <= endTime) {
     167                options.push(startTime.toTimeString().slice(0, 5));
     168                startTime.setMinutes(startTime.getMinutes() + 15);
     169            }
     170        }
     171
     172        return options.length ? options : ['No available time'];
     173    };
     174
     175    const roundToNext15Minutes = (date) => {
     176        const ms = 1000 * 60 * 15;
     177        const roundedTime = new Date(Math.ceil(date.getTime() / ms) * ms);
     178
     179        if (roundedTime.getTime() === date.getTime()) {
     180            roundedTime.setMinutes(roundedTime.getMinutes() + 15);
     181        }
     182
     183        return roundedTime;
     184    };
     185
     186    useEffect(() => {
     187        if (restaurant?.operatingHours && selectedDate) {
     188            const options = generateTimeOptions(restaurant.operatingHours);
    198189            setTimeOptions(options);
    199190        }
    200191    }, [restaurant, selectedDate]);
    201192
    202         // useEffect(() => {
    203         //     if (checkInTime) {
    204         //         const checkInDateObj = new Date(checkInTime);
    205         //         setSelectedDate(checkInDateObj.toISOString().split("T")[0]);
    206         //         setSelectedTime(checkInDateObj.toTimeString().slice(0, 5));
    207         //     }
    208         // }, [checkInTime]);
    209193
    210194    return (
     
    217201                    <div className="card-body">
    218202                        <h2 className="card-title">
    219                             {formData.restaurant.name} <StarRating key={formData.restaurant.id} rating={formData.restaurant.rating} />
     203                            {restaurant?.name}
     204                            <StarRating key={restaurant?.id} rating={restaurant?.rating || 0}/>
    220205                        </h2>
    221                         <p className="card-text">{formData.restaurant.name}</p>
    222                         <p className="card-text">{formData.restaurant.operatingHours}</p>
    223                         <p className="card-text">Ul. {formData.restaurant.address}</p>
    224                         <br />
     206                        <p className="card-text">Operating Hours: {restaurant?.operatingHours}</p>
     207                        <p className="card-text">Address: Ul. {restaurant?.address}</p>
     208                        <br/>
    225209                    </div>
    226210                    <form onSubmit={handleSubmit}>
  • my-react-app/src/components/RestaurantDetails.js

    rb67dfd3 re48199a  
    111111        });
    112112    };
    113 
    114     console.log(preOrderedItems)
    115113
    116114    const roundToNext15Minutes = (date) => {
  • my-react-app/src/components/StarRating.js

    rb67dfd3 re48199a  
    22
    33const StarRating = ({ rating }) => {
    4     // Convert the rating to a number between 0 and 5
    54    const normalizedRating = Math.min(Math.max(0, rating), 5);
    6     // Calculate the number of filled stars
    75    const filledStars = Math.floor(normalizedRating);
    8     // Calculate the number of half stars
    96    const hasHalfStar = normalizedRating - filledStars >= 0.5;
    107
     
    129        <div>
    1310            {[...Array(filledStars)].map((_, index) => (
    14                 <span key={index} className="star">&#9733;</span>
     11                <span key={`filled-${index}`} className="star">&#9733;</span>
    1512            ))}
    16             {hasHalfStar && <span className="star">&#9734;</span>}
     13
     14            {hasHalfStar && <span className="star half">&#9733;</span>}
     15
    1716            {[...Array(5 - filledStars - (hasHalfStar ? 1 : 0))].map((_, index) => (
    18                 <span key={filledStars + index + 1} className="star">&#9734;</span>
     17                <span key={`empty-${index}`} className="star">&#9734;</span>
    1918            ))}
    2019        </div>
     
    2322
    2423export default StarRating;
     24
  • src/main/java/com/example/rezevirajmasa/demo/dto/ReservationDTO.java

    rb67dfd3 re48199a  
    44import com.example.rezevirajmasa.demo.model.Reservation;
    55import com.example.rezevirajmasa.demo.model.Restaurant;
     6import lombok.Setter;
    67
    78import java.math.BigDecimal;
    89import java.time.LocalDateTime;
    910import java.util.List;
     11import java.util.stream.Collectors;
    1012
     13@Setter
    1114public class ReservationDTO {
    1215    private Long reservationID;
     
    2124    private String specialRequests;
    2225    private String paymentStatus;
    23     private List<PreorderedItem> preOrderedItems;
     26    private List<PreorderedItemDto> preOrderedItems;
    2427
    2528    public ReservationDTO() {
     
    2932                          LocalDateTime reservationDateTime, LocalDateTime checkInTime, Long restaurantId,
    3033                          int partySize, String reservationStatus, String specialRequests,
    31                           String paymentStatus, List<PreorderedItem> preOrderedItems) {
     34                          String paymentStatus, List<PreorderedItemDto> preOrderedItems) {
    3235        this.reservationID = reservationID;
    3336        this.userEmail = userEmail;
     
    5659        this.specialRequests = reservation.getSpecialRequests();
    5760        this.paymentStatus = reservation.getPaymentStatus();
    58         this.preOrderedItems = reservation.getPreOrderedItems();
     61
     62        this.preOrderedItems = reservation.getPreOrderedItems().stream()
     63                .map(preorderedItem -> new PreorderedItemDto(
     64                        preorderedItem.getPreorderedItemName(),
     65                        preorderedItem.getQuantity(),
     66                        preorderedItem.getPrice(),
     67                        preorderedItem.getMenu().getMenuID()))
     68                .collect(Collectors.toList());
    5969    }
    6070
     
    6373    }
    6474
    65     public void setReservationID(Long reservationID) {
    66         this.reservationID = reservationID;
    67     }
    68 
    6975    public String getUserEmail() {
    7076        return userEmail;
    71     }
    72 
    73     public void setUserEmail(String userEmail) {
    74         this.userEmail = userEmail;
    7577    }
    7678
     
    7981    }
    8082
    81     public void setRating(BigDecimal rating) {
    82         this.rating = rating;
    83     }
    84 
    8583    public Long getTableNumber() {
    8684        return tableNumber;
    87     }
    88 
    89     public void setTableNumber(Long tableNumber) {
    90         this.tableNumber = tableNumber;
    9185    }
    9286
     
    9589    }
    9690
    97     public void setReservationDateTime(LocalDateTime reservationDateTime) {
    98         this.reservationDateTime = reservationDateTime;
    99     }
    100 
    10191    public LocalDateTime getCheckInTime() {
    10292        return checkInTime;
    103     }
    104 
    105     public void setCheckInTime(LocalDateTime checkInTime) {
    106         this.checkInTime = checkInTime;
    10793    }
    10894
     
    11197    }
    11298
    113     public void setRestaurantId(Long restaurantId) {
    114         this.restaurantId = restaurantId;
    115     }
    116 
    11799    public int getPartySize() {
    118100        return partySize;
    119     }
    120 
    121     public void setPartySize(int partySize) {
    122         this.partySize = partySize;
    123101    }
    124102
     
    127105    }
    128106
    129     public void setReservationStatus(String reservationStatus) {
    130         this.reservationStatus = reservationStatus;
    131     }
    132 
    133107    public String getSpecialRequests() {
    134108        return specialRequests;
    135     }
    136 
    137     public void setSpecialRequests(String specialRequests) {
    138         this.specialRequests = specialRequests;
    139109    }
    140110
     
    143113    }
    144114
    145     public void setPaymentStatus(String paymentStatus) {
    146         this.paymentStatus = paymentStatus;
    147     }
    148 
    149     public List<PreorderedItem> getPreOrderedItems() {
     115    public List<PreorderedItemDto> getPreOrderedItems() {
    150116        return preOrderedItems;
    151117    }
    152118
    153     public void setPreOrderedItems(List<PreorderedItem> preOrderedItems) {
    154         this.preOrderedItems = preOrderedItems;
    155     }
    156119}
  • src/main/java/com/example/rezevirajmasa/demo/model/Menu.java

    rb67dfd3 re48199a  
    3838    private List<MenuTag> tags = new ArrayList<>();
    3939
     40    @OneToMany(mappedBy = "menu", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
     41    private List<PriceHistory> priceHistoryList = new ArrayList<>();
     42
    4043    public Menu() {
    4144    }
  • src/main/java/com/example/rezevirajmasa/demo/model/PreorderedItem.java

    rb67dfd3 re48199a  
    2626    private Integer quantity;
    2727
     28    @Column(name = "price_at_order", precision = 8, scale = 2, nullable = false)
    2829    private BigDecimal price;
    2930
     
    3233    @JoinColumn(name = "reservation_id", nullable = false)
    3334    private Reservation reservation;
     35
     36    @ManyToOne
     37    @JoinColumn(name = "menu_id", nullable = false)
     38    private Menu menu;
    3439}
  • src/main/java/com/example/rezevirajmasa/demo/model/Reservation.java

    rb67dfd3 re48199a  
    11package com.example.rezevirajmasa.demo.model;
    22
     3import com.example.rezevirajmasa.demo.dto.PreorderedItemDto;
    34import com.fasterxml.jackson.annotation.JsonBackReference;
    45import com.fasterxml.jackson.annotation.JsonManagedReference;
  • src/main/java/com/example/rezevirajmasa/demo/service/MenuService.java

    rb67dfd3 re48199a  
    33import com.example.rezevirajmasa.demo.model.Menu;
    44
     5import java.math.BigDecimal;
    56import java.util.List;
    67
    78public interface MenuService {
    89    public List<Menu> getMenuByRestaurantId(Long restaurantId);
     10    public void updateMenuPrice(Long menuId, BigDecimal newPrice);
     11    public Menu getMenuById(Long id);
    912}
  • src/main/java/com/example/rezevirajmasa/demo/service/impl/MenuServiceImpl.java

    rb67dfd3 re48199a  
    22
    33import com.example.rezevirajmasa.demo.model.Menu;
     4import com.example.rezevirajmasa.demo.model.PriceHistory;
    45import com.example.rezevirajmasa.demo.model.Restaurant;
    56import com.example.rezevirajmasa.demo.repository.MenuRepository;
     7import com.example.rezevirajmasa.demo.repository.PriceHistoryRepository;
    68import com.example.rezevirajmasa.demo.service.MenuService;
    79import com.example.rezevirajmasa.demo.service.RestaurantService;
     10import org.openqa.selenium.InvalidArgumentException;
    811import org.springframework.stereotype.Service;
    912
     13import java.math.BigDecimal;
     14import java.time.LocalDateTime;
    1015import java.util.List;
    1116
     
    1520    private final RestaurantService restaurantService;
    1621
    17     public MenuServiceImpl(MenuRepository menuRepository, RestaurantService restaurantService) {
     22    private final PriceHistoryRepository priceHistoryRepository;
     23
     24    public MenuServiceImpl(MenuRepository menuRepository, RestaurantService restaurantService, PriceHistoryRepository priceHistoryRepository) {
    1825        this.menuRepository = menuRepository;
    1926        this.restaurantService = restaurantService;
     27        this.priceHistoryRepository = priceHistoryRepository;
    2028    }
    2129
     
    2533        return menuRepository.findAllByRestaurant(restaurant);
    2634    }
     35
     36    @Override
     37    public void updateMenuPrice(Long menuId, BigDecimal newPrice) {
     38        Menu menu = menuRepository.findById(menuId)
     39                .orElseThrow(() -> new IllegalArgumentException("Menu not found"));
     40
     41        if (menu.getPrice() != null && !menu.getPrice().equals(newPrice)) {
     42            PriceHistory priceHistory = new PriceHistory(menu, menu.getPrice(), LocalDateTime.now());
     43            priceHistoryRepository.save(priceHistory);
     44        }
     45
     46        menu.setPrice(newPrice);
     47        menuRepository.save(menu);
     48    }
     49
     50    @Override
     51    public Menu getMenuById(Long id) {
     52        return menuRepository.findById(id)
     53                .orElseThrow(()->new InvalidArgumentException("Invalid id sent: " + id));
     54    }
    2755}
  • src/main/java/com/example/rezevirajmasa/demo/service/impl/ReservationImpl.java

    rb67dfd3 re48199a  
    11package com.example.rezevirajmasa.demo.service.impl;
    22
     3import com.example.rezevirajmasa.demo.dto.PreorderedItemDto;
    34import com.example.rezevirajmasa.demo.dto.ReservationDTO;
    45import com.example.rezevirajmasa.demo.mappers.UserMapper;
     
    89import com.example.rezevirajmasa.demo.repository.ReservationRepository;
    910import com.example.rezevirajmasa.demo.repository.TableRepository;
     11import com.example.rezevirajmasa.demo.service.MenuService;
    1012import com.example.rezevirajmasa.demo.service.ReservationHistoryService;
    1113import com.example.rezevirajmasa.demo.service.ReservationService;
    1214import com.example.rezevirajmasa.demo.service.UserService;
    1315import org.springframework.beans.factory.annotation.Autowired;
     16import org.springframework.context.annotation.Lazy;
    1417import org.springframework.stereotype.Service;
    1518
     
    3134    @Autowired
    3235    private ReservationRepository reservationRepository;
     36    @Autowired
     37    @Lazy
     38    private MenuService menuService;
    3339
    3440    public ReservationImpl(UserMapper userMapper) {
     
    8288            List<PreorderedItem> preOrderedItems = new ArrayList<>();
    8389
    84             for (PreorderedItem dtoItem : reservationDTO.getPreOrderedItems()) {
     90            for (PreorderedItemDto dtoItem : reservationDTO.getPreOrderedItems()) {
    8591                PreorderedItem item = new PreorderedItem();
    8692                item.setPreorderedItemName(dtoItem.getPreorderedItemName());
     
    8894                item.setPrice(dtoItem.getPrice());
    8995                item.setReservation(reservation);
     96
     97                Menu menu = menuService.getMenuById(dtoItem.getMenuID());
     98                item.setMenu(menu);
    9099
    91100                preOrderedItems.add(item);
  • src/main/java/com/example/rezevirajmasa/demo/web/rest/testController.java

    rb67dfd3 re48199a  
    6464    @GetMapping("/api/restaurants/{restaurantId}")
    6565    public ResponseEntity<RestaurantDTO> getRestaurantById(@PathVariable Long restaurantId) {
    66         return new ResponseEntity<RestaurantDTO>(restaurantService.findById(restaurantId), HttpStatus.OK);
     66        RestaurantDTO restaurantDTO = restaurantService.findById(restaurantId);
     67        return new ResponseEntity<>(restaurantDTO, HttpStatus.OK);
    6768    }
    6869
Note: See TracChangeset for help on using the changeset viewer.