From 0ed804f7ef87f75cf8bc0fafa68383859ae76828 Mon Sep 17 00:00:00 2001
From: miki549 <szucs549@gmail.com>
Date: Fri, 2 May 2025 17:21:45 +0200
Subject: [PATCH] =?UTF-8?q?m=C5=B1k=C3=B6dik:=20login=20register=20randel?=
 =?UTF-8?q?=C3=A9seim=20men=C3=BCpontban=20megjelennek=20a=20leadottak=20m?=
 =?UTF-8?q?egjelennek=20a=20term=C3=A9kek=20k=C3=A9pei?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 backend/build.gradle                          |  2 +
 .../java/kisbe32/backend/AuthController.java  | 30 ++++++-
 .../java/kisbe32/backend/LoginRequest.java    | 33 ++++++++
 .../src/main/java/kisbe32/backend/Order.java  | 12 ++-
 .../main/java/kisbe32/backend/OrderItem.java  | 18 +++++
 .../kisbe32/backend/OrderItemRepository.java  |  2 +-
 .../java/kisbe32/backend/OrderRepository.java |  2 +-
 .../src/main/java/kisbe32/backend/User.java   |  5 ++
 .../main/java/kisbe32/backend/WebConfig.java  |  6 +-
 frontend/Dockerfile                           |  2 +
 frontend/src/App.vue                          | 18 ++++-
 frontend/src/components/Cart.vue              | 56 +++++++------
 frontend/src/components/Login.vue             | 32 ++++----
 frontend/src/components/MainContent.vue       | 46 ++++++++---
 frontend/src/components/Orders.vue            | 78 +++++++++++++++----
 frontend/src/components/Register.vue          | 51 ++++++++----
 frontend/src/config/api.js                    |  2 +-
 frontend/src/stores/cartStore.js              | 33 +++++++-
 frontend/vite.config.js                       |  2 +-
 19 files changed, 340 insertions(+), 90 deletions(-)

diff --git a/backend/build.gradle b/backend/build.gradle
index deebb25..d2f1cc4 100644
--- a/backend/build.gradle
+++ b/backend/build.gradle
@@ -22,6 +22,8 @@ dependencies {
 	implementation 'org.springframework.boot:spring-boot-starter-web'
 	implementation 'org.springframework.boot:spring-boot-starter-data-rest'
 	implementation 'org.springframework.boot:spring-boot-starter-actuator'
+	implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
+	implementation 'com.fasterxml.jackson.core:jackson-databind'
 	runtimeOnly 'org.postgresql:postgresql'
 	testImplementation 'org.springframework.boot:spring-boot-starter-test'
 	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
diff --git a/backend/src/main/java/kisbe32/backend/AuthController.java b/backend/src/main/java/kisbe32/backend/AuthController.java
index e396a83..54bc076 100644
--- a/backend/src/main/java/kisbe32/backend/AuthController.java
+++ b/backend/src/main/java/kisbe32/backend/AuthController.java
@@ -15,16 +15,40 @@ public class AuthController {
     @Autowired
     private UserRepository userRepository;
 
-    @PostMapping("/login")
+    @PostMapping("/api/login")
     public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
         User user = userRepository.findByUsername(request.getUsername());
 
         // Simple string comparison for password
         if (user != null && user.getPassword().equals(request.getPassword())) {
-            return ResponseEntity.ok(new LoginResponse(true, user.getId(), user.getUsername()));
+            return ResponseEntity.ok(new LoginResponse(true, user.getId(), user.getUsername(), user.getEmail(), user.getRole()));
         } else {
             return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
-                    .body(new LoginResponse(false, null, null));
+                    .body(new LoginResponse(false, null, null, null, null));
         }
     }
+    
+    @PostMapping("/api/register")
+    public ResponseEntity<LoginResponse> register(@RequestBody LoginRequest request) {
+        // Check if username already exists
+        User existingUser = userRepository.findByUsername(request.getUsername());
+        if (existingUser != null) {
+            return ResponseEntity.status(HttpStatus.CONFLICT)
+                    .body(new LoginResponse(false, null, null, null, null));
+        }
+        
+        // Create new user
+        User newUser = new User();
+        newUser.setUsername(request.getUsername());
+        newUser.setPassword(request.getPassword());
+        newUser.setEmail(request.getEmail());
+        newUser.setRole("USER");
+        
+        // Save user to database
+        User savedUser = userRepository.save(newUser);
+        
+        // Return success response with user details
+        return ResponseEntity.status(HttpStatus.CREATED)
+                .body(new LoginResponse(true, savedUser.getId(), savedUser.getUsername(), savedUser.getEmail(), savedUser.getRole()));
+    }
 }
\ No newline at end of file
diff --git a/backend/src/main/java/kisbe32/backend/LoginRequest.java b/backend/src/main/java/kisbe32/backend/LoginRequest.java
index 26aa511..dc236b4 100644
--- a/backend/src/main/java/kisbe32/backend/LoginRequest.java
+++ b/backend/src/main/java/kisbe32/backend/LoginRequest.java
@@ -3,6 +3,7 @@ package kisbe32.backend;
 class LoginRequest {
     private String username;
     private String password;
+    private String email;
 
     // Default constructor needed for JSON deserialization
     public LoginRequest() {}
@@ -11,24 +12,50 @@ class LoginRequest {
         this.username = username;
         this.password = password;
     }
+    
+    public LoginRequest(String username, String email, String password) {
+        this.username = username;
+        this.email = email;
+        this.password = password;
+    }
 
     public String getUsername() { return username; }
     public void setUsername(String username) { this.username = username; }
 
     public String getPassword() { return password; }
     public void setPassword(String password) { this.password = password; }
+    
+    public String getEmail() { return email; }
+    public void setEmail(String email) { this.email = email; }
 }
 
 class LoginResponse {
     private boolean success;
     private Integer userId;
     private String username;
+    private String email;
+    private String role;
 
     public LoginResponse(boolean success, Integer userId, String username) {
         this.success = success;
         this.userId = userId;
         this.username = username;
     }
+    
+    public LoginResponse(boolean success, Integer userId, String username, String role) {
+        this.success = success;
+        this.userId = userId;
+        this.username = username;
+        this.role = role;
+    }
+    
+    public LoginResponse(boolean success, Integer userId, String username, String email, String role) {
+        this.success = success;
+        this.userId = userId;
+        this.username = username;
+        this.email = email;
+        this.role = role;
+    }
 
     public boolean isSuccess() { return success; }
     public void setSuccess(boolean success) { this.success = success; }
@@ -38,4 +65,10 @@ class LoginResponse {
 
     public String getUsername() { return username; }
     public void setUsername(String username) { this.username = username; }
+    
+    public String getEmail() { return email; }
+    public void setEmail(String email) { this.email = email; }
+    
+    public String getRole() { return role; }
+    public void setRole(String role) { this.role = role; }
 }
\ No newline at end of file
diff --git a/backend/src/main/java/kisbe32/backend/Order.java b/backend/src/main/java/kisbe32/backend/Order.java
index f3ca63a..1e5b2f6 100644
--- a/backend/src/main/java/kisbe32/backend/Order.java
+++ b/backend/src/main/java/kisbe32/backend/Order.java
@@ -4,6 +4,7 @@ import jakarta.persistence.*;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.List;
+import com.fasterxml.jackson.annotation.*;
 
 @Entity
 @Table(name = "orders")
@@ -15,6 +16,8 @@ public class Order {
 
     @ManyToOne
     @JoinColumn(name = "user_id", nullable = false)
+    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
+    @JsonIdentityReference(alwaysAsId = true)
     private User user;
 
     @Column(name = "order_date", nullable = false)
@@ -26,7 +29,7 @@ public class Order {
     @Column(name = "total_price", nullable = false)
     private BigDecimal totalPrice;
 
-    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
+    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
     private List<OrderItem> items;
 
     protected Order() {}
@@ -43,6 +46,13 @@ public class Order {
     public User getUser() { return user; }
     public LocalDateTime getOrderDate() { return orderDate; }
     public String getStatus() { return status; }
+    
+    @JsonProperty("totalAmount")
     public BigDecimal getTotalPrice() { return totalPrice; }
+    
     public List<OrderItem> getItems() { return items; }
+    
+    // Setters
+    public void setOrderDate(LocalDateTime orderDate) { this.orderDate = orderDate; }
+    public void setItems(List<OrderItem> items) { this.items = items; }
 }
\ No newline at end of file
diff --git a/backend/src/main/java/kisbe32/backend/OrderItem.java b/backend/src/main/java/kisbe32/backend/OrderItem.java
index bf6260a..a84b82d 100644
--- a/backend/src/main/java/kisbe32/backend/OrderItem.java
+++ b/backend/src/main/java/kisbe32/backend/OrderItem.java
@@ -3,6 +3,7 @@ package kisbe32.backend;
 import jakarta.persistence.*;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import com.fasterxml.jackson.annotation.*;
 
 @Entity
 @Table(name = "orderitems")
@@ -14,10 +15,13 @@ public class OrderItem {
 
     @ManyToOne
     @JoinColumn(name = "order_id", nullable = false)
+    @JsonBackReference
     private Order order;
 
     @ManyToOne
     @JoinColumn(name = "product_id", nullable = false)
+    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
+    @JsonIdentityReference(alwaysAsId = true)
     private Product product;
 
     @Column(name = "quantity", nullable = false)
@@ -39,12 +43,26 @@ public class OrderItem {
         this.product = product;
         this.quantity = quantity;
         this.price = price;
+        this.createdAt = LocalDateTime.now();
+        this.updatedAt = LocalDateTime.now();
     }
 
     // Getters
     public Integer getId() { return id; }
     public Order getOrder() { return order; }
+    
     public Product getProduct() { return product; }
+    
+    @JsonProperty("productId")
+    public Integer getProductId() { 
+        return product != null ? product.getId() : null; 
+    }
+    
     public Integer getQuantity() { return quantity; }
     public BigDecimal getPrice() { return price; }
+    public LocalDateTime getCreatedAt() { return createdAt; }
+    public LocalDateTime getUpdatedAt() { return updatedAt; }
+    
+    // Setters
+    public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
 }
\ No newline at end of file
diff --git a/backend/src/main/java/kisbe32/backend/OrderItemRepository.java b/backend/src/main/java/kisbe32/backend/OrderItemRepository.java
index 1447349..087a503 100644
--- a/backend/src/main/java/kisbe32/backend/OrderItemRepository.java
+++ b/backend/src/main/java/kisbe32/backend/OrderItemRepository.java
@@ -12,5 +12,5 @@ interface OrderItemRepository extends JpaRepository<OrderItem, Integer> {
     List<OrderItem> findByOrderId(@Param("orderId") Integer orderId);
 
     // Find order items by product ID
-    List<OrderItem> findByProductId(@Param("productId") Integer productId);
+    List<OrderItem> findByProduct_Id(@Param("productId") Integer productId);
 }
diff --git a/backend/src/main/java/kisbe32/backend/OrderRepository.java b/backend/src/main/java/kisbe32/backend/OrderRepository.java
index 3ed2633..2420475 100644
--- a/backend/src/main/java/kisbe32/backend/OrderRepository.java
+++ b/backend/src/main/java/kisbe32/backend/OrderRepository.java
@@ -9,7 +9,7 @@ import java.util.List;
 @RepositoryRestResource(collectionResourceRel = "orders", path = "orders")
 interface OrderRepository extends JpaRepository<Order, Integer> {
     // Find orders by user ID
-    List<Order> findByUserId(@Param("userId") Integer userId);
+    List<Order> findByUser_Id(@Param("userId") Integer userId);
 
     // Find orders by status
     List<Order> findByStatus(@Param("status") String status);
diff --git a/backend/src/main/java/kisbe32/backend/User.java b/backend/src/main/java/kisbe32/backend/User.java
index 5d0139f..e4f6ffe 100644
--- a/backend/src/main/java/kisbe32/backend/User.java
+++ b/backend/src/main/java/kisbe32/backend/User.java
@@ -15,6 +15,7 @@ public class User {
     private String username;
     private String email;
     private String password;
+    private String role;
 
     // Default constructor required by JPA
     public User() {}
@@ -23,6 +24,7 @@ public class User {
         this.username = username;
         this.email = email;
         this.password = password;
+        this.role = "USER"; // Default role
     }
 
     // Getters and setters
@@ -37,4 +39,7 @@ public class User {
 
     public String getPassword() { return password; }
     public void setPassword(String password) { this.password = password; }
+    
+    public String getRole() { return role; }
+    public void setRole(String role) { this.role = role; }
 }
\ No newline at end of file
diff --git a/backend/src/main/java/kisbe32/backend/WebConfig.java b/backend/src/main/java/kisbe32/backend/WebConfig.java
index 826898c..77d5b97 100644
--- a/backend/src/main/java/kisbe32/backend/WebConfig.java
+++ b/backend/src/main/java/kisbe32/backend/WebConfig.java
@@ -9,7 +9,9 @@ public class WebConfig implements WebMvcConfigurer {
 	@Override
 	public void addCorsMappings(CorsRegistry registry) {
 		registry.addMapping("/**") // Allow all endpoints
-				.allowedOrigins("*")
-				.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS");
+				.allowedOrigins("http://localhost", "http://localhost:80")
+				.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
+				.allowedHeaders("*")
+				.allowCredentials(true);
 	}
 }
\ No newline at end of file
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
index c448e2f..19ae6e9 100644
--- a/frontend/Dockerfile
+++ b/frontend/Dockerfile
@@ -21,6 +21,8 @@ RUN echo 'server { \
         proxy_pass http://backend:8080/api/; \
         proxy_set_header Host $host; \
         proxy_set_header X-Real-IP $remote_addr; \
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; \
+        proxy_set_header X-Forwarded-Proto $scheme; \
     } \
 }' > /etc/nginx/conf.d/default.conf
 EXPOSE 80
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index acbf44c..5f41346 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -4,17 +4,31 @@
   import Register from './components/Register.vue'
   import Cart from './components/Cart.vue'
   import Orders from './components/Orders.vue'
-  import { ref } from 'vue'
+  import { ref, onMounted } from 'vue'
 
   const currentPage = ref('main')
+  // Frissítés trigger
+  const authStateUpdate = ref(0)
+  
   function navigate(view){
     currentPage.value = view
+    // Frissítjük az auth állapotot navigáció után
+    authStateUpdate.value++
   }
+  
+  // Figyeljük a localStorage változásait
+  function handleStorageChange() {
+    authStateUpdate.value++
+  }
+  
+  onMounted(() => {
+    window.addEventListener('storage', handleStorageChange)
+  })
 </script>
 
 <template>
     <main>
-      <MainContent v-if="currentPage === 'main'" @navigate="navigate" />
+      <MainContent v-if="currentPage === 'main'" @navigate="navigate" :key="authStateUpdate" />
       <Login v-else-if="currentPage === 'login'" @navigate="navigate" />
       <Register v-else-if="currentPage === 'register'" @navigate="navigate" />
       <Cart v-else-if="currentPage === 'cart'" @navigate="navigate" />
diff --git a/frontend/src/components/Cart.vue b/frontend/src/components/Cart.vue
index 27b4443..25885af 100644
--- a/frontend/src/components/Cart.vue
+++ b/frontend/src/components/Cart.vue
@@ -45,39 +45,51 @@ async function checkout() {
     error.value = null;
     successMessage.value = null;
 
-    const token = localStorage.getItem('authToken');
+    // Felhasználó ellenőrzése localStorage-ból
+    const userStr = localStorage.getItem('user');
 
-    if (!token) {
+    if (!userStr) {
       error.value = "Bejelentkezés szükséges a vásárláshoz!";
       emit('navigate', 'login');
       return;
     }
 
+    // Felhasználó adatok kinyerése
+    const user = JSON.parse(userStr);
+
+    // Adatok előkészítése - csak primitív értékek használata, nem reaktív objektumok
+    const simpleItems = cartItems.value.map(item => ({
+      productId: item.id,
+      quantity: item.quantity,
+      price: Number(item.price)
+    }));
+
+    // Összérték számítása
+    const totalAmountValue = simpleItems.reduce((sum, item) => sum + (item.price * item.quantity), 0);
+
+    // Rendelés adatok előkészítése
     const orderData = {
-      items: cartItems.value.map(item => ({
-        productId: item.id,
-        quantity: item.quantity
-      }))
+      userId: Number(user.id),
+      status: "confirmed",
+      orderDate: new Date().toISOString(),
+      totalAmount: totalAmountValue,
+      items: simpleItems
     };
 
-    const response = await axios.post(`${API_BASE_URL}/orders`, orderData, {
-      headers: {
-        Authorization: `Bearer ${token}`
-      }
-    });
-
-    if (response.data.success) {
-      successMessage.value = "Sikeres vásárlás! Köszönjük rendelését.";
-      // Clear the cart after successful purchase
-      cartItems.value.forEach(item => {
-        cartStore.removeFromCart(item.id);
-      });
-    } else {
-      error.value = response.data.message || "Hiba történt a vásárlás során!";
-    }
+    console.log("Rendelési adatok:", JSON.stringify(orderData));
+
+    // Rendelés küldése a backend API-nak
+    const response = await axios.post(`${API_BASE_URL}/orders`, orderData);
+
+    // Sikeres rendelés
+    successMessage.value = "Sikeres vásárlás! Köszönjük rendelését.";
+    
+    // Kosár ürítése sikeres rendelés után
+    cartStore.clearCart();
+    
   } catch (err) {
     console.error('Checkout error:', err);
-    error.value = err.response?.data?.message || "Hiba történt a vásárlás során! Kérjük próbálja újra később.";
+    error.value = "Hiba történt a vásárlás során! Kérjük próbálja újra később.";
   } finally {
     isLoading.value = false;
   }
diff --git a/frontend/src/components/Login.vue b/frontend/src/components/Login.vue
index b99afe7..2895050 100644
--- a/frontend/src/components/Login.vue
+++ b/frontend/src/components/Login.vue
@@ -20,26 +20,28 @@ async function onLogin() {
       password: password.value
     });
 
-    // Handle successful login
-    if (response.data.success) {
-      // Store the token if your API returns one
-      if (response.data.token) {
-        localStorage.setItem('authToken', response.data.token);
-      }
-
-      // Store user info if needed
-      if (response.data.user) {
-        localStorage.setItem('user', JSON.stringify(response.data.user));
-      }
-
+    // Store user info in local storage
+    if (response.data) {
+      // Create user object from response
+      const user = {
+        id: response.data.userId,
+        username: response.data.username,
+        role: response.data.role || 'USER'
+      };
+      
+      // Store in localStorage
+      localStorage.setItem('user', JSON.stringify(user));
+      
+      // Triggereljük a localStorage változás eseményt, 
+      // hogy más komponensek is értesüljenek róla
+      window.dispatchEvent(new Event('storage'));
+      
       // Navigate back to main page
       emit('navigate', 'main');
-    } else {
-      error.value = response.data.message || 'Hibás felhasználónév vagy jelszó';
     }
   } catch (err) {
     console.error('Login error:', err);
-    error.value = err.response?.data?.message || 'Hiba történt a bejelentkezés során';
+    error.value = 'Hibás felhasználónév vagy jelszó';
   } finally {
     isLoading.value = false;
   }
diff --git a/frontend/src/components/MainContent.vue b/frontend/src/components/MainContent.vue
index ac91181..860f287 100644
--- a/frontend/src/components/MainContent.vue
+++ b/frontend/src/components/MainContent.vue
@@ -35,13 +35,14 @@ const checkAuthStatus = () => {
   const token = localStorage.getItem('authToken');
   const userStr = localStorage.getItem('user');
 
-  if (token && userStr) {
+  if (userStr) {
     isLoggedIn.value = true;
     try {
       currentUser.value = JSON.parse(userStr);
     } catch (e) {
       console.error('User data parsing error:', e);
       currentUser.value = null;
+      isLoggedIn.value = false;
     }
   } else {
     isLoggedIn.value = false;
@@ -54,6 +55,9 @@ const logout = () => {
   localStorage.removeItem('authToken');
   localStorage.removeItem('user');
   checkAuthStatus();
+  
+  // Triggereljük a localStorage változás eseményt is
+  window.dispatchEvent(new Event('storage'));
 };
 
 onMounted(() => {
@@ -99,14 +103,38 @@ const fetchProducts = async () => {
     const response = await axios.get(`${API_BASE_URL}/products`);
     
     // Az adatbázisból érkező adatok formázása
-    products.value = response.data.map(product => ({
-      id: product.id,
-      name: product.name,
-      category: (product.category || '').toLowerCase(),
-      price: product.price,
-      stock: product.stock,
-      image: product.image_url || 'https://via.placeholder.com/600x600'
-    }));
+    // Check if the data has _embedded.products structure (HAL format)
+    const productsData = response.data._embedded?.products || [];
+    
+    // Egyszerű placeholder kép data URL formátumban
+    const placeholderImage = 'data:image/png;base64,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';
+    
+    products.value = productsData.map(product => {
+      let imageUrl = product.imageUrl || product.image_url;
+      
+      // Ellenőrizzük, hogy létezik-e a kép URL
+      if (!imageUrl) {
+        imageUrl = placeholderImage;
+      } 
+      // Ellenőrizzük, hogy a kép URL tartalmaz-e http vagy https protokollt
+      else if (!imageUrl.startsWith('http://') && !imageUrl.startsWith('https://') && !imageUrl.startsWith('data:')) {
+        // Relatív URL esetén egészítsük ki
+        if (imageUrl.startsWith('/')) {
+          imageUrl = `${API_BASE_URL}${imageUrl}`;
+        } else {
+          imageUrl = `${API_BASE_URL}/${imageUrl}`;
+        }
+      }
+      
+      return {
+        id: product.id,
+        name: product.name,
+        category: (product.category || '').toLowerCase(),
+        price: product.price,
+        stock: product.stock,
+        image: imageUrl
+      };
+    });
     
   } catch (err) {
     console.error('Hiba a termékek betöltése során:', err);
diff --git a/frontend/src/components/Orders.vue b/frontend/src/components/Orders.vue
index 8413367..b73ff6f 100644
--- a/frontend/src/components/Orders.vue
+++ b/frontend/src/components/Orders.vue
@@ -17,24 +17,72 @@ async function fetchOrders() {
     isLoading.value = true
     error.value = null
 
-    const token = localStorage.getItem('authToken')
-
-    if (!token) {
+    // Felhasználó adatok ellenőrzése localStorage-ban
+    const userStr = localStorage.getItem('user')
+    
+    if (!userStr) {
       error.value = 'Bejelentkezés szükséges a rendelések megtekintéséhez'
       return
     }
 
-    const response = await axios.get(`${API_BASE_URL}/orders`, {
-      headers: {
-        Authorization: `Bearer ${token}`
+    // Felhasználó adatok JSON-ból
+    const user = JSON.parse(userStr)
+    console.log("Felhasználói adatok:", user)
+    
+    // Az adott felhasználó rendeléseinek lekérdezése a megfelelő végpontról
+    const apiUrl = `${API_BASE_URL}/orders/user/${user.id}`
+    console.log("API kérés URL:", apiUrl)
+    
+    try {
+      const response = await axios.get(apiUrl)
+      console.log('Rendelés válasz:', response.data)
+      
+      // Ha üres a válasz, üres tömböt állítunk be
+      if (!response.data || response.data.length === 0) {
+        console.log("Nincsenek rendelések")
+        orders.value = []
+        return
       }
-    })
-
-    if (response.data.success) {
-      orders.value = response.data.orders
-    } else {
-      error.value = 'Nem sikerült betölteni a rendeléseket'
+      
+      if (Array.isArray(response.data)) {
+        console.log("Tömb válasz feldolgozása")
+        orders.value = response.data.map(order => ({
+          id: order.id,
+          order_date: order.orderDate,
+          status: order.status || 'confirmed',
+          total_amount: order.totalAmount || order.totalPrice || 0,
+          OrderItems: Array.isArray(order.items) ? order.items : []
+        }))
+      } else if (response.data._embedded && response.data._embedded.orders) {
+        console.log("Spring Data REST válasz feldolgozása")
+        orders.value = response.data._embedded.orders.map(order => ({
+          id: order.id,
+          order_date: order.orderDate,
+          status: order.status || 'confirmed',
+          total_amount: order.totalAmount || order.totalPrice || 0,
+          OrderItems: Array.isArray(order.items) ? order.items : []
+        }))
+      } else {
+        // Próbáljuk egyetlen objektumként kezelni
+        console.log("Egyedi objektum válasz feldolgozása")
+        if (response.data.id) {
+          orders.value = [{
+            id: response.data.id,
+            order_date: response.data.orderDate,
+            status: response.data.status || 'confirmed',
+            total_amount: response.data.totalAmount || response.data.totalPrice || 0,
+            OrderItems: Array.isArray(response.data.items) ? response.data.items : []
+          }]
+        } else {
+          orders.value = []
+        }
+      }
+    } catch (error) {
+      console.error("API hívási hiba:", error)
+      throw error
     }
+    
+    console.log('Feldolgozott rendelések:', orders.value)
   } catch (err) {
     console.error('Rendelések betöltési hiba:', err)
     error.value = 'Hiba történt a rendelések betöltése során'
@@ -131,12 +179,12 @@ onMounted(fetchOrders)
             </div>
 
             <div class="order-items" v-if="order.OrderItems && order.OrderItems.length">
-              <div v-for="item in order.OrderItems" :key="item.id" class="order-item">
+              <div v-for="(item, index) in order.OrderItems" :key="index" class="order-item">
                 <div class="item-quantity">{{ item.quantity }}×</div>
                 <div class="item-name">
-                  {{ item.product ? item.product.name : `Termék #${item.productId}` }}
+                  {{ item.product && item.product.name ? item.product.name : `Termék #${item.productId || (item.product ? item.product.id : 'ismeretlen')}` }}
                 </div>
-                <div class="item-price">{{ item.price * item.quantity }} Ft</div>
+                <div class="item-price">{{ (item.price || 0) * (item.quantity || 1) }} Ft</div>
               </div>
             </div>
 
diff --git a/frontend/src/components/Register.vue b/frontend/src/components/Register.vue
index 76f08d8..9032d15 100644
--- a/frontend/src/components/Register.vue
+++ b/frontend/src/components/Register.vue
@@ -6,6 +6,7 @@ import {API_BASE_URL} from "@/config/api.js";
 const emit = defineEmits(['navigate'])
 
 const username = ref('')
+const email = ref('')
 const password = ref('')
 const confirmPassword = ref('')
 const error = ref('')
@@ -19,34 +20,49 @@ async function onRegister() {
       return
     }
 
+    // Email validáció
+    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+    if (!emailRegex.test(email.value)) {
+      error.value = 'Kérjük, adjon meg egy érvényes email címet!'
+      return
+    }
+
     error.value = ''
     isLoading.value = true
 
     const response = await axios.post(`${API_BASE_URL}/register`, {
       username: username.value,
+      email: email.value,
       password: password.value
     });
 
-    // Handle successful registration
-    if (response.data.success) {
-      // Store the token if your API returns one
-      if (response.data.token) {
-        localStorage.setItem('authToken', response.data.token);
-      }
-
-      // Store user info if needed
-      if (response.data.user) {
-        localStorage.setItem('user', JSON.stringify(response.data.user));
-      }
-
+    // Store user info in local storage
+    if (response.data) {
+      // Create user object from response
+      const user = {
+        id: response.data.userId,
+        username: response.data.username,
+        email: response.data.email,
+        role: response.data.role || 'USER'
+      };
+      
+      // Store in localStorage
+      localStorage.setItem('user', JSON.stringify(user));
+      
+      // Triggereljük a localStorage változás eseményt, 
+      // hogy más komponensek is értesüljenek róla
+      window.dispatchEvent(new Event('storage'));
+      
       // Navigate back to main page
       emit('navigate', 'main');
-    } else {
-      error.value = response.data.message || 'Hiba történt a regisztráció során';
     }
   } catch (err) {
     console.error('Registration error:', err);
-    error.value = err.response?.data?.message || 'Hiba történt a regisztráció során';
+    if (err.response && err.response.status === 409) {
+      error.value = 'Ez a felhasználónév vagy email cím már foglalt!';
+    } else {
+      error.value = 'Hiba történt a regisztráció során. Kérjük, próbálja újra!';
+    }
   } finally {
     isLoading.value = false;
   }
@@ -81,6 +97,11 @@ function onBack() {
             <input type="text" id="username" v-model="username" required />
           </div>
 
+          <div class="form-group">
+            <label for="email">Email cím</label>
+            <input type="email" id="email" v-model="email" required />
+          </div>
+
           <div class="form-group">
             <label for="password">Jelszó</label>
             <input type="password" id="password" v-model="password" required />
diff --git a/frontend/src/config/api.js b/frontend/src/config/api.js
index b7e6565..969c830 100644
--- a/frontend/src/config/api.js
+++ b/frontend/src/config/api.js
@@ -1 +1 @@
-export const API_BASE_URL = 'http://localhost:8080/api';
\ No newline at end of file
+export const API_BASE_URL = '/api';
\ No newline at end of file
diff --git a/frontend/src/stores/cartStore.js b/frontend/src/stores/cartStore.js
index 3d5d339..38ce0e5 100644
--- a/frontend/src/stores/cartStore.js
+++ b/frontend/src/stores/cartStore.js
@@ -1,10 +1,31 @@
 // src/stores/cartStore.js
 import { ref, computed, watch } from 'vue'
+import { API_BASE_URL } from '@/config/api.js'
 
 // Create a reactive cart
 const cartItems = ref([])
 const isCartLoaded = ref(false)
 
+// Helper function to format image URL
+function formatImageUrl(imageUrl) {
+  if (!imageUrl) {
+    return null;
+  }
+  
+  // Ha már tartalmaz protokollt (http, https, data), akkor nem változtatunk rajta
+  if (imageUrl.startsWith('http://') || imageUrl.startsWith('https://') || imageUrl.startsWith('data:')) {
+    return imageUrl;
+  }
+  
+  // Relatív URL esetén kiegészítjük
+  if (imageUrl.startsWith('/')) {
+    return `${API_BASE_URL}${imageUrl}`;
+  }
+  
+  // Egyéb esetben
+  return `${API_BASE_URL}/${imageUrl}`;
+}
+
 // Load cart from localStorage
 function loadCart() {
     if (isCartLoaded.value) return
@@ -60,7 +81,7 @@ function addToCart(product, quantity = 1) {
                     id: product.id,
                     name: product.name,
                     price: product.price,
-                    image: product.image,
+                    image: formatImageUrl(product.image),
                     quantity: availableStock,
                     stock: product.stock // Store stock info for later checks
                 });
@@ -81,7 +102,7 @@ function addToCart(product, quantity = 1) {
             id: product.id,
             name: product.name,
             price: product.price,
-            image: product.image,
+            image: formatImageUrl(product.image),
             quantity: quantity,
             stock: product.stock // Store stock info for later checks
         });
@@ -103,6 +124,13 @@ function updateQuantity(productId, quantity) {
     }
 }
 
+// Kosár teljes törlése
+function clearCart() {
+    loadCart()
+    cartItems.value = []
+    localStorage.removeItem('cart')
+}
+
 // Computed properties
 const totalItems = computed(() => {
     loadCart()
@@ -119,6 +147,7 @@ export default {
     addToCart,
     removeFromCart,
     updateQuantity,
+    clearCart,
     totalItems,
     totalPrice,
     loadCart
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
index 4eafdca..118ab15 100644
--- a/frontend/vite.config.js
+++ b/frontend/vite.config.js
@@ -18,7 +18,7 @@ export default defineConfig({
   server: {
     proxy: {
       '/api': {
-        target: 'http://localhost:8080',
+        target: 'http://backend:8080',
         changeOrigin: true
       }
     }
-- 
GitLab