Index: pom.xml
===================================================================
--- pom.xml	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ pom.xml	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -6,6 +6,6 @@
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>3.5.0</version>
-        <relativePath/> <!-- lookup parent from repository -->
+        <version>3.2.5</version>
+        <relativePath/>
     </parent>
     <groupId>com.zinemasterapp</groupId>
@@ -60,4 +60,13 @@
             <artifactId>spring-boot-starter-security</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+
     </dependencies>
 
Index: src/main/java/com/zinemasterapp/zinemasterapp/controller/AuthController.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/controller/AuthController.java	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ src/main/java/com/zinemasterapp/zinemasterapp/controller/AuthController.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -3,6 +3,9 @@
 
 import com.zinemasterapp.zinemasterapp.dto.LoginRequest;
+import com.zinemasterapp.zinemasterapp.model.PasswordResetToken;
 import com.zinemasterapp.zinemasterapp.model.User;
+import com.zinemasterapp.zinemasterapp.repository.TokenRepository;
 import com.zinemasterapp.zinemasterapp.repository.UserRepository;
+import com.zinemasterapp.zinemasterapp.service.EmailService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
@@ -13,4 +16,6 @@
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.core.token.TokenService;
+import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -19,4 +24,8 @@
 
 import javax.naming.AuthenticationException;
+import java.time.LocalDateTime;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
 
 @RestController//deka e REST API kontroler, vrakja JSON
@@ -24,25 +33,17 @@
 public class AuthController {
 
-//    @Autowired
-//    private AuthenticationManager authenticationManager;//avtomatski Springboot pravi AuthenticationManager
-//
-//    @PostMapping("/login")//na /api/auth/login primame POST metoda
-//    public ResponseEntity<?> login(@RequestBody LoginRequest request) {//ResponseEntity ni dozvoluva da kontrolirame HTTP status, response body
-//        try {
-//            Authentication authentication = authenticationManager.authenticate(
-//                    new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
-//            );
-//            return ResponseEntity.ok("Login successful!");
-//        }catch (BadCredentialsException e){
-//            return ResponseEntity.status(401).body("Invalid username or password");
-//        }catch (DisabledException e){
-//            return ResponseEntity.status(403).body("User is inactive");
-//        }
-//
-//    }
     private final UserRepository userRepository;//isto e kako @Autowired ama povekje imam so konstructor koristeno
+    private final TokenRepository tokenRepository;
 
-    public AuthController(UserRepository userRepository) {
+    @Autowired
+    private EmailService emailService;//service za isprakjanje emails
+    @Autowired
+    private PasswordEncoder passwordEncoder;//za enkodiranje na pass
+
+
+
+    public AuthController(UserRepository userRepository, TokenRepository tokenRepository) {
         this.userRepository = userRepository;
+        this.tokenRepository = tokenRepository;
     }
 
@@ -61,10 +62,55 @@
         }
 
-        // za demo
-        if ("test123".equals(request.getPassword())) {
-            return ResponseEntity.ok(user);//ova se stava vo localStorage, ova e JSON
+
+        if (passwordEncoder.matches(request.getPassword(), user.getPassword())) {//dali e ist so od baza pass
+            return ResponseEntity.ok(user);
         } else {
-            return ResponseEntity.status(401).body("Invalid password");//ova e String
+            return ResponseEntity.status(401).body("Invalid password");
         }
     }
+
+    @PostMapping("/request-password-reset")
+    public ResponseEntity<?> requestReset(@RequestBody Map<String, String> body) {
+        String username = body.get("username");
+        Optional<User> userOpt = userRepository.findByUsername(username);//dali postoi vo baza
+        if (userOpt.isPresent()) {
+            String token = UUID.randomUUID().toString();//namerno e bez seckanje na UUID za da e pobezbedno
+            PasswordResetToken prt = new PasswordResetToken();//kreirame token
+            prt.setToken(token);//tokenot
+            prt.setUser(userOpt.get());//korisnikot
+            prt.setExpiresAt(LocalDateTime.now().plusMinutes(15));
+            tokenRepository.save(prt);
+            String email = userOpt.get().getEmail();
+
+            String resetLink = "http://localhost:8082/reset-password?token=" + token;
+            emailService.sendResetLink(email, resetLink);//prakja email
+
+            return ResponseEntity.ok("Линкот е успешно пратен.");
+        }
+        return ResponseEntity.ok("That username is not found.");
+
+    }
+
+
+    @PostMapping("/reset-password")
+    public ResponseEntity<?> resetPassword(@RequestBody Map<String, String> body) {
+        String token = body.get("token");
+        String newPassword = body.get("newPassword");
+
+        PasswordResetToken prt = tokenRepository.findByToken(token)
+                .orElseThrow(() -> new RuntimeException("Invalid token"));//dali go imame vo baza tokenot -> linija 79/82
+        if (prt.getExpiresAt().isBefore(LocalDateTime.now())) {//dali pominalo 15min
+            return ResponseEntity.status(HttpStatus.GONE).body("Token expired");
+        }
+
+        User user = prt.getUser();
+        user.setPassword(passwordEncoder.encode(newPassword));
+        userRepository.save(user);
+        tokenRepository.delete(prt);//da ne se koristi pak tokenot
+
+        return ResponseEntity.ok("Password has been reset.");
+    }
+
+
+
 }
Index: src/main/java/com/zinemasterapp/zinemasterapp/controller/CategoryController.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/controller/CategoryController.java	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ src/main/java/com/zinemasterapp/zinemasterapp/controller/CategoryController.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -10,8 +10,5 @@
 import org.springframework.web.bind.annotation.*;
 
-import java.util.List;
-import java.util.Optional;
-import java.util.Random;
-import java.util.UUID;
+import java.util.*;
 
 @RestController
@@ -65,7 +62,13 @@
         for (Product p : products) {
             if (deleteProducts) {
-                p.setAccessable(false);
+                Set<Category> productCategories = p.getCategories();
+                if (productCategories.size() == 1 && productCategories.iterator().next().getId().equals(id)) {
+                    p.setAccessable(false);
+                }else {
+
+                    productCategories.removeIf(cat -> cat.getId().equals(id));
+                }
             } else {
-      //          p.setCategoryId(null);//dali ova ke pravi problem?
+                p.getCategories().removeIf(cat -> cat.getId().equals(id));
             }
         }
Index: src/main/java/com/zinemasterapp/zinemasterapp/controller/ProductController.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/controller/ProductController.java	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ src/main/java/com/zinemasterapp/zinemasterapp/controller/ProductController.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -5,6 +5,10 @@
 import com.zinemasterapp.zinemasterapp.model.Category;
 import com.zinemasterapp.zinemasterapp.model.Product;
+import com.zinemasterapp.zinemasterapp.model.ProductRequest;
+import com.zinemasterapp.zinemasterapp.model.ProductRequestItem;
 import com.zinemasterapp.zinemasterapp.repository.CategoryRepository;
 import com.zinemasterapp.zinemasterapp.repository.ProductRepository;
+import com.zinemasterapp.zinemasterapp.repository.ProductRequestItemRepository;
+import com.zinemasterapp.zinemasterapp.repository.ProductRequestRepository;
 import org.springframework.data.domain.Sort;
 import org.springframework.http.ResponseEntity;
@@ -15,5 +19,8 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.stream.Collectors;
 
 @RestController
@@ -24,8 +31,12 @@
     private final ProductRepository productRepository;
     private final CategoryRepository categoryRepository;
+    private final ProductRequestItemRepository productRequestItemRepository;
+    private final ProductRequestRepository productRequestRepository;
 
-    public ProductController(ProductRepository productRepository, CategoryRepository categoryRepository) {
+    public ProductController(ProductRepository productRepository, CategoryRepository categoryRepository, ProductRequestItemRepository productRequestItemRepository, ProductRequestRepository productRequestRepository) {
         this.productRepository = productRepository;
         this.categoryRepository = categoryRepository;
+        this.productRequestItemRepository = productRequestItemRepository;
+        this.productRequestRepository = productRequestRepository;
     }
 
@@ -113,4 +124,36 @@
     }
 
+    @GetMapping("/{id}/reservations-by-month")
+    public Map<String, Integer> getReservationsByMonth(@PathVariable String id) {
+        List<ProductRequestItem> items = productRequestItemRepository.findByProductId(id);//site naracki so toj proizvod
+
+        Map<String, Integer> reservationsPerMonth = new TreeMap<>();//prazna mapa
+
+        for (ProductRequestItem item : items) {//za baranje od baranjata
+            ProductRequest request = item.getRequest();
+            if (request != null && request.getRequestDate() != null) {//dali postoi narackata?
+                LocalDate date = request.getRequestDate();
+                String month = date.getMonth().toString() + " " + date.getYear();
+                reservationsPerMonth.put(month, reservationsPerMonth.getOrDefault(month, 0) + item.getQuantityRequested());
+            }
+        }
+
+        return reservationsPerMonth;//JULY 2025: 22
+        //AUGUST 2025: 23
+
+    }
+
+    @GetMapping("/{id}")
+    public ResponseEntity<Product> getProductById(@PathVariable String id) {
+        Optional<Product> product = productRepository.findById(id);
+        return product.map(ResponseEntity::ok)
+                .orElse(ResponseEntity.notFound().build());
+    }
+
+
+
+
+
+
 
 
Index: src/main/java/com/zinemasterapp/zinemasterapp/controller/UserController.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/controller/UserController.java	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ src/main/java/com/zinemasterapp/zinemasterapp/controller/UserController.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -103,4 +103,22 @@
     }
 
+    @PutMapping("/{id}")
+    public ResponseEntity<?> updateUser(@PathVariable String id, @RequestBody User updatedUser) {
+        Optional<User> optUser = userRepository.findById(id);
+        if (optUser.isEmpty()) return ResponseEntity.notFound().build();
+
+        User user = optUser.get();
+        user.setName(updatedUser.getName());
+        user.setSurname(updatedUser.getSurname());
+        user.setStartDate(updatedUser.getStartDate());
+        user.setUserType(updatedUser.getUserType());
+        user.setEmail(updatedUser.getEmail());
+        user.setAddress(updatedUser.getAddress());//sve setirame
+
+        userRepository.save(user);
+        return ResponseEntity.ok().build();
+    }
+
+
 
 
Index: src/main/java/com/zinemasterapp/zinemasterapp/model/PasswordResetToken.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/model/PasswordResetToken.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
+++ src/main/java/com/zinemasterapp/zinemasterapp/model/PasswordResetToken.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -0,0 +1,42 @@
+package com.zinemasterapp.zinemasterapp.model;
+
+import jakarta.persistence.*;
+
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "password_reset_token")
+public class PasswordResetToken {
+    @Id
+    private String token;
+
+    @OneToOne
+    @JoinColumn(name = "user_id")
+    private User user;
+
+    private LocalDateTime expiresAt;
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+    public LocalDateTime getExpiresAt() {
+        return expiresAt;
+    }
+
+    public void setExpiresAt(LocalDateTime expiresAt) {
+        this.expiresAt = expiresAt;
+    }
+}
Index: src/main/java/com/zinemasterapp/zinemasterapp/model/User.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/model/User.java	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ src/main/java/com/zinemasterapp/zinemasterapp/model/User.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -36,4 +36,15 @@
     @Column(name = "profile_pic")
     private String profilePic;
+
+    @Column(nullable = false, unique = true)
+    private String email;
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
 
     public String getProfilePic() {
Index: src/main/java/com/zinemasterapp/zinemasterapp/repository/ProductRequestItemRepository.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/repository/ProductRequestItemRepository.java	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ src/main/java/com/zinemasterapp/zinemasterapp/repository/ProductRequestItemRepository.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -9,3 +9,4 @@
 public interface ProductRequestItemRepository extends JpaRepository<ProductRequestItem, Long> {
     List<ProductRequestItem> findByRequestId(String requestId);
+    List<ProductRequestItem> findByProductId(String productId);
 }
Index: src/main/java/com/zinemasterapp/zinemasterapp/repository/TokenRepository.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/repository/TokenRepository.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
+++ src/main/java/com/zinemasterapp/zinemasterapp/repository/TokenRepository.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -0,0 +1,10 @@
+package com.zinemasterapp.zinemasterapp.repository;
+
+import com.zinemasterapp.zinemasterapp.model.PasswordResetToken;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface TokenRepository extends JpaRepository<PasswordResetToken, String> {
+    Optional<PasswordResetToken> findByToken(String token);
+}
Index: src/main/java/com/zinemasterapp/zinemasterapp/security/CustomUserAccess.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/security/CustomUserAccess.java	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ src/main/java/com/zinemasterapp/zinemasterapp/security/CustomUserAccess.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -35,3 +35,2 @@
     }
 }
-//moze i bez ova?
Index: src/main/java/com/zinemasterapp/zinemasterapp/security/SecurityConfig.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/security/SecurityConfig.java	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ src/main/java/com/zinemasterapp/zinemasterapp/security/SecurityConfig.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -39,6 +39,8 @@
                                 .requestMatchers(HttpMethod.POST, "/api/users").permitAll()
                         .requestMatchers(HttpMethod.PUT, "/api/users/**").permitAll()
+                                .requestMatchers(HttpMethod.POST, "/api/auth/").permitAll()
                         .requestMatchers(HttpMethod.GET, "/api/requests/**").permitAll()
                                 .requestMatchers(HttpMethod.GET, "/api/users/**").permitAll()
+                                .requestMatchers(HttpMethod.GET, "/api/products/*/reservations-by-month").permitAll()
                                 .requestMatchers(HttpMethod.POST, "/api/products").permitAll()
                                 .requestMatchers(HttpMethod.PUT, "/api/products/**").permitAll()
Index: src/main/java/com/zinemasterapp/zinemasterapp/service/EmailService.java
===================================================================
--- src/main/java/com/zinemasterapp/zinemasterapp/service/EmailService.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
+++ src/main/java/com/zinemasterapp/zinemasterapp/service/EmailService.java	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -0,0 +1,20 @@
+package com.zinemasterapp.zinemasterapp.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+
+@Service
+public class EmailService {
+    @Autowired
+    private JavaMailSender mailSender;
+
+    public void sendResetLink(String to, String link) {
+        SimpleMailMessage message = new SimpleMailMessage();
+        message.setTo(to);
+        message.setSubject("Промена на Лозинка");
+        message.setText("Кликнете тука за да ја промените лозинката: " + link);//body na mailot
+        mailSender.send(message);
+    }
+}
Index: src/main/resources/application.properties
===================================================================
--- src/main/resources/application.properties	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ src/main/resources/application.properties	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -16,4 +16,13 @@
 spring.web.resources.static-locations=classpath:/static/,file:src/main/resources/static/uploads/
 
+spring.mail.host=smtp.gmail.com
+spring.mail.port=587
+spring.mail.username=${MAIL_USERNAME}
+spring.mail.password=${MAIL_PASSWORD}
+spring.mail.properties.mail.smtp.auth=true
+spring.mail.properties.mail.smtp.starttls.enable=true
 
 
+
+
+
Index: zinemaster-frontend/src/components/AllRequests.vue
===================================================================
--- zinemaster-frontend/src/components/AllRequests.vue	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ zinemaster-frontend/src/components/AllRequests.vue	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -11,4 +11,7 @@
           <img :src="userProfileImage" alt="Profile" class="rounded-circle me-2 " style="width: 35px; height: 35px; object-fit: cover; border: 2px solid white; cursor: pointer;"/>
         </router-link>
+        <router-link v-if="user.userType === 'UserAdministrator'" to="/manage-users" class="btn btn-outline-warning btn-sm me-2">
+          Управувај со корисници
+        </router-link>
       </nav>
     </div>
@@ -65,5 +68,5 @@
         <div class="card shadow-sm text-dark h-100" :class="statusClass(req.status)">
           <div class="card-body d-flex align-items-start">
-            <div class="me-3 fs-2"><!--Moze da se trgne?-->
+            <div class="me-3 fs-2">
               <span v-if="req.status === 'approved'" class="text-success">✔️</span>
               <span v-else-if="req.status === 'pending'" class="text-warning">⏳</span>
@@ -74,5 +77,5 @@
               <p class="mb-1"><strong>Корисник:</strong> {{ req.username }}</p>
               <p class="mb-1"><strong>Датум:</strong> {{ req.requestDate }}</p>
-              <p class="mb-0"><strong>Статус:</strong> {{ req.status }}</p>
+              <p class="mb-0"><strong>Статус:</strong> {{ statusToMacedonian(req.status) }}</p>
               <p v-if="req.processedBy && req.status !== 'pending' " class="mt-2 text-muted small">
                 <span>{{req.status === 'approved' ? 'Одобрена од: ' : 'Одбиена од: ' }}</span> {{ req.processedBy }}
@@ -82,5 +85,5 @@
                   class="btn btn-sm mt-2 text-dark"
                   :class="buttonClass(req.status)"
-                  @click="toggleDetails(req.id)" v-if="req.status != 'unavailable'">
+                  @click="toggleDetails(req.id)" >
                 {{ expandedRequests.includes(req.id) ? 'Скриј производи' : 'Покажи производи' }}
               </button>
@@ -208,5 +211,5 @@
   const result = await Swal.fire({
     title: 'Потврда на статус',
-    text: `Дали сте сигурни дека сакате да ја означите нарачката како '${newStatus}'?`,
+    text: `Дали сте сигурни дека сакате да ја означите нарачката како '${statusToMacedonian(newStatus)}'?`,
     icon: 'question',
     showCancelButton: true,
@@ -231,5 +234,5 @@
       icon: 'success',
       title: 'Успешно',
-      text: `Нарачката е означена како '${newStatus}'`
+      text: `Нарачката е означена како '${statusToMacedonian(newStatus)}'`
     });
   } else {
@@ -265,4 +268,13 @@
 });
 
+const statusToMacedonian = (status) => {
+  switch (status) {
+    case 'approved': return 'Одобрено';
+    case 'pending': return 'Во тек';
+    case 'rejected': return 'Одбиено';
+    default: return status;
+  }
+};
+
 
 </script>
Index: zinemaster-frontend/src/components/ForgotPassword.vue
===================================================================
--- zinemaster-frontend/src/components/ForgotPassword.vue	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
+++ zinemaster-frontend/src/components/ForgotPassword.vue	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -0,0 +1,46 @@
+<template>
+  <div class="d-flex align-items-center justify-content-center" style="height: 80vh;">
+    <div class="container p-4 shadow rounded" style="max-width: 500px; width: 100%;">
+      <h2 class="mb-3">Заборавена лозинка</h2>
+      <p>Внесете го вашето корисничко име и ќе ви испратиме линк за промена на лозинката.</p>
+
+      <div class="mb-3">
+        <label for="username" class="form-label">Корисничко име</label>
+        <input type="text" v-model="username" class="form-control" id="username" required />
+      </div>
+
+      <button class="btn btn-primary" @click="requestReset" :disabled="isSending">
+        {{ isSending ? 'Се испраќа...' : 'Испрати линк за промен' }}
+      </button>
+
+      <div class="mt-3 text-success" v-if="message">{{ message }}</div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+const username = ref('')
+const message = ref('')
+const isSending = ref(false)
+
+const requestReset = async () => {
+  isSending.value = true
+  try {
+    const res = await fetch('http://localhost:8081/api/auth/request-password-reset', {
+      method: 'POST',
+      headers: { 'Content-Type': 'application/json' },
+      body: JSON.stringify({ username: username.value })
+    })
+
+    const result = await res.text()
+    message.value = result
+  } catch (error) {
+    console.error(error)
+    message.value = 'Настана грешка при испраќањето на барањето.'
+  } finally {
+    isSending.value = false
+  }
+}
+</script>
Index: zinemaster-frontend/src/components/LoginPage.vue
===================================================================
--- zinemaster-frontend/src/components/LoginPage.vue	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ zinemaster-frontend/src/components/LoginPage.vue	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -6,33 +6,32 @@
       <form @submit.prevent="login" class="py-4">
         <div class="form-group mb-3">
-          <label for="username">Username</label>
+          <label for="username">Корисничко име</label>
           <div class="input-group">
             <span class="input-group-text"><i class="fas fa-user"></i></span>
             <input
-              type="text"
-              v-model="username"
-              class="form-control"
-              id="username"
-              placeholder="Type your username"
-              required
-            />
+                type="text"
+                v-model="username"
+                class="form-control"
+                id="username" placeholder="Type your username" required />
           </div>
         </div>
 
         <div class="form-group mb-3">
-          <label for="password">Password</label>
+          <label for="password">Лозинка</label>
           <div class="input-group">
             <span class="input-group-text"><i class="fas fa-lock"></i></span>
             <input
-              type="password"
-              v-model="password"
-              class="form-control"
-              id="password"
-              placeholder="Type your password"
-              required
-            />
+                :type="showPassword ? 'text' : 'password'"
+                v-model="password"
+                class="form-control"
+                id="password" placeholder="Type your password" required />
+            <span class="input-group-text" @click="showPassword = !showPassword" style="cursor: pointer;">
+  <i :class="showPassword ? 'fas fa-eye-slash' : 'fas fa-eye'"></i>
+</span>
+
           </div>
           <div class="text-end mt-1">
-            <a href="#" class="small text-decoration-none">Forgot password?</a>
+            <router-link to="/forgot-password" class="small text-decoration-none">Заборавена Лозинка?</router-link>
+
           </div>
         </div>
@@ -43,5 +42,5 @@
       </form>
 
-      
+
     </div>
   </div>
@@ -57,4 +56,6 @@
 const error = ref('');//reactive promenlivi - real time change
 const router = useRouter();
+const showPassword = ref(false);
+
 
 const login = async () => {//ova e demek pomoderno,ama i so method block da koristis isto ke e
Index: zinemaster-frontend/src/components/MainPage.vue
===================================================================
--- zinemaster-frontend/src/components/MainPage.vue	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ zinemaster-frontend/src/components/MainPage.vue	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -43,5 +43,5 @@
           <!-- izbor -->
           <div class="mb-3">
-            <label class="form-label">Избери акција:</label>
+            <label class="form-label">Избери акција:</label><!--mozda e poubavo da e vo edit del?-->
             <select class="form-select" v-model="categoryAction">
               <option  value="">-- Избери --</option>
@@ -165,4 +165,9 @@
                 </button>
                 <button v-if="user.userType === 'ProductAdministrator' && product.reserved == 0" class="btn btn-sm btn-danger ms-2" @click="deleteProduct(product.id)">Избриши</button>
+                <div class="mt-auto text-end pt-3">
+                  <router-link :to="`/products/${product.id}`" class="btn btn-outline-primary btn-sm" title="View Details">
+                    🔍
+                  </router-link>
+                </div>
               </div>
             </div>
@@ -263,5 +268,5 @@
 
 const submitRequest = async () => {
-  const payload = {
+  const payload = {//body
     userId: user.value.id,
     items: requestItems.value.map(item => ({
@@ -300,7 +305,7 @@
 
 
-const cancelRequest = () => {
+const cancelRequest = async () => {
   if (requestItems.value.length > 0) {
-    const result = Swal.fire({
+    const result = await Swal.fire({
       title: 'Потврда',
       text: 'Имате додадено производи. Дали сте сигурни дека сакате да ја откажете нарачката?',
@@ -310,5 +315,9 @@
       cancelButtonText: 'Не'
     });
-    if (!result.isConfirmed) return;
+
+
+    if (!result.isConfirmed) {
+      return;
+    }
   }
 
@@ -316,6 +325,9 @@
   for (const item of requestItems.value) {
     const product = products.value.find(p => p.id === item.id);
-    if (product) product.tempReserved -= item.quantity;
-  }
+    if (product) {
+      product.tempReserved -= item.quantity;
+    }
+  }
+
 
   requestItems.value = [];
@@ -323,5 +335,12 @@
   requestId.value = '';
   creatingRequest.value = false;
-};
+
+  await Swal.fire({
+    icon: 'success',
+    title: 'Откажано',
+    text: 'Нарачката е успешно откажана.'
+  });
+};
+
 
 const fetchProducts = async () => {
@@ -333,5 +352,5 @@
     accessible: p.accessible ?? true,
     tempReserved: 0 ,
-    categories: p.categories ?? []  ,
+    categories: p.categories ?? []  ,//sega moze od povekje kategorii da e eden proizvod
     addQuantity: 0
   }));
@@ -350,5 +369,5 @@
 
   const res = await fetch(`http://localhost:8081/api/products/${productId}`, {
-    method: 'DELETE'
+    method: 'DELETE'//logicko delete samo
   });
 
@@ -367,5 +386,5 @@
   quantity: 0,
   imageUrl: '',//da ne e so URL od google tuku kako so pfp da moze da se smeni
-  categoryIds:[],
+  categoryIds:[],//povekje categories
   reserved: 0,
   accessable: true
@@ -384,5 +403,5 @@
   }
 
-  const formData = new FormData();
+  const formData = new FormData();//payload
   formData.append("name", newProduct.value.name);
   formData.append("quantity", newProduct.value.quantity);
@@ -461,5 +480,5 @@
 const deleteCategoryWithProducts = async (categoryId) => {
   const confirmDelete = await Swal.fire({
-    title: 'Дали сакате да ја избришете оваа категорија ЗАЕДНО со сите производи во неа?',
+    title: 'Дали сакате да ја избришете оваа категорија ЗАЕДНО со сите производи во неа?',//samo tie sto imaat edna kategorija(a taa e ovaa sto se brishe)
     icon: 'warning',
     showCancelButton: true,
@@ -491,5 +510,5 @@
 const deleteCategoryOnly = async (categoryId) => {
   const confirmDelete = await Swal.fire({
-    title: 'Дали сакате да ја избришете оваа категорија, а производите да останат без категорија?',
+    title: 'Дали сакате да ја избришете оваа категорија, а производите да останат без категорија?',//ako ima povekje kategorii drugite ke ostanat
     icon: 'question',
     showCancelButton: true,
@@ -525,7 +544,7 @@
 };
 
-const deletableCategories = computed(() => {
+const deletableCategories = computed(() => {//nemozat site kategorii da se brishat(samo tie sto site proizvodi reserved=0)
   return categories.value.filter(cat => {
-    const relatedProducts = products.value.filter(p => p.categories && p.categories.some(c => c.id === cat.id) && p.accessable);
+    const relatedProducts = products.value.filter(p => p.categories && p.categories.some(c => c.id === cat.id) && p.accessable);//klucen zbore "some"
     return relatedProducts.length === 0 || relatedProducts.every(p => p.reserved === 0);
   });
@@ -533,5 +552,5 @@
 
 const toggleCategory = (catId) => {
-  const index = newProduct.value.categoryIds.indexOf(catId);
+  const index = newProduct.value.categoryIds.indexOf(catId);//ako postoi idex se trga od lista na kategorii,ako ne se dodava
   if (index === -1) {
     newProduct.value.categoryIds.push(catId);
@@ -560,5 +579,5 @@
 const getFullImageUrl = (relativePath) => {
   if(!relativePath)return "";
-  return "http://localhost:8081"+relativePath;
+  return "http://localhost:8081"+relativePath;//tuka mi e slikata
 }
 
@@ -594,6 +613,3 @@
   }
 };
-
-
-
 </script>
Index: zinemaster-frontend/src/components/ManageUsers.vue
===================================================================
--- zinemaster-frontend/src/components/ManageUsers.vue	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ zinemaster-frontend/src/components/ManageUsers.vue	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -4,4 +4,5 @@
       <h4 class="mb-0">ZineMaster</h4>
       <nav>
+        <router-link to="/main" class="btn btn-outline-light btn-sm me-2">Дома</router-link>
         <router-link to="/requests" class="btn btn-outline-light btn-sm me-2">Сите нарачки</router-link>
         <button class="btn btn-outline-light btn-sm me-2" @click="logout">Logout</button>
@@ -9,7 +10,5 @@
           <img :src="userProfileImage" alt="Profile" class="rounded-circle me-2 " style="width: 35px; height: 35px; object-fit: cover; border: 2px solid white; cursor: pointer;"/>
         </router-link>
-        <router-link v-if="currentUser.userType === 'UserAdministrator'" to="/manage-users" class="btn btn-outline-warning btn-sm me-2">
-          Управувај со корисници
-        </router-link>
+
 
       </nav>
@@ -24,39 +23,85 @@
     <div v-if="error" class="alert alert-danger">Грешка при вчитување на корисниците.</div>
 
-    <button class="btn btn-success mb-3" @click="showAddUserForm = !showAddUserForm">
+    <button class="btn btn-success mb-3" @click="toggleAddUserForm">
       {{ showAddUserForm ? 'Откажи' : 'Додади нов корисник' }}
     </button>
-
-    <div v-if="showAddUserForm" class="border rounded p-3 mb-4 bg-light">
+    <!--za dodadavnej-->
+    <form v-if="showAddUserForm" @submit.prevent="createUser" class="border rounded p-3 mb-4 bg-light">
       <h5>Нов корисник</h5>
-      <div class="mb-2">
-        <input v-model="newUser.name" type="text" class="form-control" placeholder="Име">
-      </div>
-      <div class="mb-2">
-        <input v-model="newUser.surname" type="text" class="form-control" placeholder="Презиме">
-      </div>
-      <div class="mb-2">
-        <input v-model="newUser.startDate" type="date" class="form-control">
-      </div>
-      <div class="mb-2">
-        <select v-model="newUser.userType" class="form-select">
-          <option value="Worker">Worker</option>
-          <option value="ProductAdministrator">ProductAdministrator</option>
-          <option value="UserAdministrator">UserAdministrator</option>
+
+      <div class="mb-2">
+        <input v-model="newUser.name" type="text" class="form-control" placeholder="Име" required>
+      </div>
+
+      <div class="mb-2">
+        <input v-model="newUser.surname" type="text" class="form-control" placeholder="Презиме" required>
+      </div>
+
+      <div class="mb-2">
+        <input v-model="newUser.startDate" type="date" class="form-control" required>
+      </div>
+
+      <div class="mb-2">
+        <input v-model="newUser.email" type="email" class="form-control" placeholder="Email адреса" required>
+      </div>
+
+      <div class="mb-2">
+        <select v-model="newUser.userType" class="form-select" required>
+          <option disabled value="">Избери тип</option>
+          <option value="Worker">Работник</option>
+          <option value="ProductAdministrator">Администратор на продукти</option>
+          <option value="UserAdministrator">Администратор на корисници</option>
         </select>
       </div>
+
       <div class="mb-3">
         <label for="address" class="form-label">Адреса</label>
         <select v-model="newUser.address" class="form-select" required>
           <option disabled value="">Избери адреса</option>
-          <option>Main Warehouse</option>
-          <option>Office A</option>
-          <option>Ohrids Warehouse B</option>
-          <option>Office C</option>
-
+          <option value="Main Warehouse">Главен Магацин</option>
+          <option value="Office A">Канцеларија А</option>
+          <option value="Ohrids Warehouse B">Магацин Б во Охрид</option>
+          <option value="Office C">Канцеларија Ц</option>
         </select>
       </div>
-      <button class="btn btn-primary" @click="createUser">Зачувај</button>
-    </div>
+
+      <button type="submit" class="btn btn-primary">Зачувај</button>
+    </form>
+
+    <!--za azuriranje-->
+    <form v-if="editUserForm" @submit.prevent="updateUser" class="border rounded p-3 mb-4 bg-light">
+      <h5>Уреди корисник</h5>
+
+      <div class="mb-2">
+        <input v-model="editUser.name" type="text" class="form-control" placeholder="Име" required>
+      </div>
+
+      <div class="mb-2">
+        <input v-model="editUser.surname" type="text" class="form-control" placeholder="Презиме" required>
+      </div>
+
+      <div class="mb-2">
+        <input v-model="editUser.startDate" type="date" class="form-control" required>
+      </div>
+
+      <div class="mb-2">
+        <input v-model="editUser.email" type="email" class="form-control" placeholder="Email" required>
+      </div>
+
+      <div class="mb-2">
+        <select v-model="editUser.address" class="form-select" required>
+          <option disabled value="">Избери адреса</option>
+          <option value="Main Warehouse">Главен Магацин</option>
+          <option value="Office A">Канцеларија А</option>
+          <option value="Ohrids Warehouse B">Магацин Б во Охрид</option>
+          <option value="Office C">Канцеларија Ц</option>
+        </select>
+      </div>
+
+      <button type="submit" class="btn btn-primary me-2">Зачувај</button>
+      <button type="button" class="btn btn-secondary" @click="cancelEdit">Откажи</button>
+    </form>
+
+
 
 
@@ -67,5 +112,4 @@
         <th style="cursor: pointer;" @click="sortByStartDate">
           Почетен датум
-
         </th>
         <th>Тип на корисник</th>
@@ -78,5 +122,5 @@
         <td>{{ u.name }} {{ u.surname }}</td>
         <td>{{ u.startDate }}</td>
-        <td>{{ u.userType }}</td>
+        <td>{{ typeWorkerToMacedonian(u.userType) }}</td>
         <td>
           <div v-if="u.access === 0">
@@ -85,7 +129,7 @@
           <div v-else>
             <select v-model="u.newRole" class="form-select form-select-sm w-auto d-inline-block me-2" :disabled="u.id === currentUser.id">
-              <option value="Worker">Worker</option>
-              <option value="ProductAdministrator">ProductAdministrator</option>
-              <option value="UserAdministrator">UserAdministrator</option>
+              <option value="Worker">Работник</option>
+              <option value="ProductAdministrator">Администратор на продукти</option>
+              <option value="UserAdministrator">Администратор на корисници</option>
             </select>
             <button class="btn btn-sm btn-primary" @click="updateRole(u)" :disabled="u.id === currentUser.id || u.userType === u.newRole">
@@ -100,4 +144,10 @@
           </label>
         </td>
+        <td>
+          <button class="btn btn-sm btn-outline-secondary me-2" @click="startEdit(u)" v-if="currentUser.userType === 'UserAdministrator'" :disabled="u.userType === 'UserAdministrator' || u.id === currentUser.id" >
+            🖉 Уреди
+          </button>
+        </td>
+
 
       </tr>
@@ -123,4 +173,13 @@
 const sortOrder = ref('asc');
 
+const typeWorkerToMacedonian = (type) =>{
+  switch (type) {
+    case 'Worker': return 'Работник';
+    case 'ProductAdministrator': return 'Администратор на продукти';
+    case 'UserAdministrator': return 'Администратор на корисници';
+    default: return type;
+  }
+}
+
 onMounted(async () => {
   const stored = localStorage.getItem('user');
@@ -139,5 +198,5 @@
     users.value = data.map(u => ({
       ...u,
-      newRole: u.userType
+      newRole: u.userType //na site properties plus dodavame nov propertie za newRole
     }));
     loading.value = false;
@@ -151,5 +210,5 @@
   const result = await Swal.fire({
     title: 'Промена на улога',
-    text: `Дали сте сигурни дека сакате да ја промените улогата на ${user.username} во ${user.newRole}?`,
+    text: `Дали сте сигурни дека сакате да ја промените улогата на ${user.username} во ${typeWorkerToMacedonian(user.newRole)}?`,
     icon: 'warning',
     showCancelButton: true,
@@ -191,5 +250,9 @@
 
   if (res.ok) {
-    alert(`Пристапот е ${newAccess === 1 ? 'одобрен' : 'одземен'}.`);
+    Swal.fire({
+      icon: 'success',
+      title: 'Успешна промена',
+      text: `Пристапот е ${newAccess === 1 ? 'одобрен' : 'одземен'}.`
+    });
     await fetchUsers();
   } else {
@@ -206,9 +269,13 @@
   try {
     const res = await fetch('http://localhost:8081/api/users');
-    if (!res.ok) throw new Error("Неуспешно превземање на корисници");
+    if (!res.ok)Swal.fire({
+      icon: 'error',
+      title: 'Грешка',
+      text: 'Грешка при вчитување на корисниците.'
+    });
 
     users.value = await res.json();
   } catch (err) {
-    console.error("Грешка при превземање на корисници:", err);
+    console.error(err);
   }
 };
@@ -228,7 +295,8 @@
   name: '',
   surname: '',
-  startDate: '',
+  startDate: new Date().toISOString().split('T')[0],//denesen datum e default
   userType: 'Worker',
-  address: ''
+  address: '',
+  email: ''
 });
 
@@ -243,5 +311,5 @@
   }
 
-  const password = 'test123';
+  const password = 'test123';//default
 
 
@@ -256,5 +324,6 @@
       password,
       access: 1,
-      address: newUser.value.address
+      address: newUser.value.address,
+      email: newUser.value.email
     })
   });
@@ -281,4 +350,59 @@
   router.push('/login');
 };
+const resetForm = () => {
+  newUser.value = {
+    name: '',
+    surname: '',
+    startDate: new Date().toISOString().split('T')[0],
+    userType: 'Worker',
+    address: '',
+    email: ''
+  };
+};
+
+const toggleAddUserForm = () => {
+  showAddUserForm.value = !showAddUserForm.value;
+  if (!showAddUserForm.value) {
+    resetForm();
+  }
+};
+
+const editUserForm = ref(false);
+const editUser = ref({});
+
+const startEdit = (user) => {
+  editUser.value = { ...user }; // copy od podatocite
+  editUserForm.value = true;
+};
+
+const cancelEdit = () => {
+  editUserForm.value = false;
+  editUser.value = {};
+};
+
+const updateUser = async () => {
+  const res = await fetch(`http://localhost:8081/api/users/${editUser.value.id}`, {
+    method: 'PUT',
+    headers: { 'Content-Type': 'application/json' },
+    body: JSON.stringify(editUser.value)
+  });
+
+  if (res.ok) {
+    await Swal.fire({
+      icon: 'success',
+      title: 'Успешно!',
+      text: 'Корисникот е ажуриран.'
+    });
+    editUserForm.value = false;
+    await fetchUsers();
+  } else {
+    Swal.fire({
+      icon: 'error',
+      title: 'Грешка!',
+      text: 'Не може да се ажурира корисникот.'
+    });
+  }
+};
+
 
 
@@ -331,3 +455,9 @@
 }
 
+input[type="checkbox"]:disabled + .slider {
+  background-color: #ccc;
+  cursor: not-allowed;
+  opacity: 0.6;
+}
+
 </style>
Index: zinemaster-frontend/src/components/ProductDetails.vue
===================================================================
--- zinemaster-frontend/src/components/ProductDetails.vue	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
+++ zinemaster-frontend/src/components/ProductDetails.vue	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -0,0 +1,76 @@
+<template>
+  <div class="mt-4">
+    <h3 class="text-center">{{ productName }}</h3>
+    <div class="row justify-content-center">
+      <div class="col-md-8 col-lg-6">
+        <canvas ref="chartCanvas" class="w-100"></canvas>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import Chart from 'chart.js/auto';
+import axios from 'axios';
+
+export default {//mora vaka ne dava da se raboti so props so script setup
+  props: ['id'],//go zemame od "parent page"
+  data() {
+    return {
+      chartInstance: null,
+      productName: ''
+    };
+  },
+  async mounted() {
+    try {
+      const productRes = await axios.get(`http://localhost:8081/api/products/${this.id}`);
+      this.productName = productRes.data.name;
+
+      const res = await axios.get(`http://localhost:8081/api/products/${this.id}/reservations-by-month`);//api/json
+      const data = res.data;
+
+      const labels = Object.keys(data);
+      const values = Object.values(data);
+
+      console.log(data);
+
+
+      if (this.chartInstance) {
+        this.chartInstance.destroy();//ako imalo go trgame
+      }
+
+      this.chartInstance = new Chart(this.$refs.chartCanvas, {
+        type: 'bar',
+        data: {
+          labels,
+          datasets: [{
+            label: 'Резервации по месеци',
+            data: values,
+            backgroundColor: '#f64a8a'
+          }]
+        },
+        options: {
+          responsive: true,
+          plugins: {
+            legend: { display: true },
+            title: {
+              display: true,
+              text: 'Месечни резервации'
+            }
+          },
+          scales: {
+            y: {
+              beginAtZero: true,
+              ticks: {
+                stepSize: 1
+              }
+            }
+          }
+        }
+      });
+    } catch (error) {
+      console.error(error);
+    }
+  }
+};
+</script>
Index: zinemaster-frontend/src/components/ProfilePage.vue
===================================================================
--- zinemaster-frontend/src/components/ProfilePage.vue	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ zinemaster-frontend/src/components/ProfilePage.vue	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -8,4 +8,7 @@
         <router-link to="/requests" class="btn btn-outline-light btn-sm me-2">Сите нарачки</router-link>
         <button class="btn btn-outline-light btn-sm me-2" @click="logout">Logout</button>
+        <router-link v-if="user.userType === 'UserAdministrator'" to="/manage-users" class="btn btn-outline-warning btn-sm me-2">
+          Управувај со корисници
+        </router-link>
 
       </nav>
@@ -26,9 +29,9 @@
             <input type="file" ref="fileInput" accept="image/*" @change="handleFileChange" style="display: none"/>
             <h4 class="card-title">{{ user.name }} {{ user.surname }}</h4>
-            <p class="text-muted">@{{ user.username }}</p>
+            <p class="text-muted">{{ user.username }}</p>
 
             <ul class="list-group text-start mt-3">
               <li class="list-group-item"><strong>Адреса:</strong> {{ user.address }}</li>
-              <li class="list-group-item"><strong>Тип:</strong> {{ user.userType }}</li>
+              <li class="list-group-item"><strong>Тип:</strong> {{ typeWorkerToMacedonian(user.userType) }}</li>
               <li class="list-group-item"><strong>Старт:</strong> {{ user.startDate }}</li>
               <li class="list-group-item"><strong>Статус: </strong>
@@ -96,5 +99,5 @@
                   <h5 class="card-title mb-1">Нарачка <strong>{{ req.id }}</strong></h5>
                   <p class="mb-1"><strong>Датум:</strong> {{ req.requestDate }}</p>
-                  <p class="mb-0"><strong>Статус:</strong> {{ req.status }}</p>
+                  <p class="mb-0"><strong>Статус:</strong> {{ statusToMacedonian(req.status) }}</p>
                   <p v-if="req.processedBy && req.status !== 'pending' " class="mt-2 text-muted small">
                     <span>{{req.status === 'approved' ? 'Одобрена од: ' : 'Одбиена од: ' }}</span> {{getUsernameById(req.processedBy)}}
@@ -148,4 +151,23 @@
 const allUsers = ref([]);
 
+
+const statusToMacedonian = (status) => {
+  switch (status) {
+    case 'approved': return 'Одобрено';
+    case 'pending': return 'Во тек';
+    case 'rejected': return 'Одбиено';
+    default: return status;
+  }
+};
+
+const typeWorkerToMacedonian = (type) =>{
+  switch (type) {
+    case 'Worker': return 'Работник';
+    case 'ProductAdministrator': return 'Администратор на продукти';
+    case 'UserAdministrator': return 'Администратор на корисници';
+    default: return type;
+  }
+}
+
 onMounted(async () => {
   const stored = localStorage.getItem('user');
@@ -232,9 +254,9 @@
 
 const handleFileChange = async (event) => {
-  const file = event.target.files[0];
+  const file = event.target.files[0];//od <input type="file">
   if (!file) return;
 
-  const reader = new FileReader();
-  reader.onload = async (e) => {
+  const reader = new FileReader();//sluzi za citanje na fileovi od klientot
+  reader.onload = async (e) => {//ova e 2
     const newUrl = e.target.result;
     userProfileImage.value = newUrl;
@@ -250,5 +272,5 @@
 
     if (res.ok) {
-      user.value.profilePic = newUrl;
+      user.value.profilePic = newUrl;//azurira
       localStorage.setItem("user", JSON.stringify(user.value));
       await Swal.fire({
@@ -266,5 +288,5 @@
   };
 
-  reader.readAsDataURL(file);
+  reader.readAsDataURL(file); //ova e 1
 };
 
Index: zinemaster-frontend/src/components/ResetPassword.vue
===================================================================
--- zinemaster-frontend/src/components/ResetPassword.vue	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
+++ zinemaster-frontend/src/components/ResetPassword.vue	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -0,0 +1,63 @@
+<template>
+  <div class="d-flex align-items-center justify-content-center" style="height: 80vh;">
+    <div class="container p-4 shadow rounded" style="max-width: 500px; width: 100%;">
+      <h2 class="text-center mb-4">Промени Лозинка</h2>
+
+      <div class="form-group mb-3">
+        <label for="password">Нова Лозинка</label>
+        <div class="input-group">
+          <input
+              :type="showPassword ? 'text' : 'password'"
+              class="form-control"
+              id="password" v-model="password" ref="passwordInput" />
+          <span class="input-group-text" @click="showPassword = !showPassword" style="cursor: pointer;">
+      <i :class="showPassword ? 'fas fa-eye-slash' : 'fas fa-eye'"></i>
+    </span>
+        </div>
+      </div>
+
+      <button @click="submitNewPassword" class="btn btn-primary w-100">
+        Промени Лозинка
+      </button>
+
+      <p v-if="message" class="mt-3 text-success text-center">{{ message }}</p>
+      <p v-if="error" class="mt-3 text-danger text-center">{{ error }}</p>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue';
+import { useRoute } from 'vue-router';
+import axios from 'axios';
+
+const password = ref('');
+const message = ref('');
+const error = ref('');
+const token = ref('');
+const showPassword = ref(false);
+
+
+const route = useRoute();
+
+onMounted(() => {
+  token.value = route.query.token;//од рутата го земаме токенот
+  if (!token.value) {
+    error.value = 'Невалиден токен.';
+  }
+});
+
+const submitNewPassword = async () => {
+  try {
+    const response = await axios.post('http://localhost:8081/api/auth/reset-password', {
+      token: token.value,//tokenot so go zemavme go prakjame
+      newPassword: password.value
+    });
+    message.value = response.data;
+    error.value = '';
+  } catch (err) {
+    error.value = err.response?.data || 'Има грешка.';
+    message.value = '';
+  }
+};
+</script>
Index: zinemaster-frontend/src/router/index.js
===================================================================
--- zinemaster-frontend/src/router/index.js	(revision 99adf50bc33c245de97c9ab3d513a66edfbbc65c)
+++ zinemaster-frontend/src/router/index.js	(revision 37cf0705121314723a82b25f95929c9e78ebd5f5)
@@ -1,9 +1,11 @@
 import { createRouter, createWebHistory } from 'vue-router';
-import Login from '../components/LoginPage.vue'; 
+import Login from '../components/LoginPage.vue';
 import Main from '../components/MainPage.vue';
-import Requests from '../components/AllRequests.vue'; 
+import Requests from '../components/AllRequests.vue';
 import Profile from '../components/ProfilePage.vue';
 import ManageUsers from '@/components/ManageUsers.vue';
-
+import ForgotPassword from '@/components/ForgotPassword.vue';
+import ResetPassword from '@/components/ResetPassword.vue';
+import ProductDetails from '@/components/ProductDetails.vue';
 
 const routes = [
@@ -13,5 +15,9 @@
   { path: '/requests', component: Requests },
   { path: '/profile', component: Profile },
-  { path: '/manage-users', component: ManageUsers}
+  { path: '/manage-users', component: ManageUsers},
+  { path: '/forgot-password', component: ForgotPassword},
+  { path: '/reset-password', component: ResetPassword},
+  { path: '/products/:id', component: ProductDetails, props: true }
+
 ];
 
@@ -23,3 +29,2 @@
 export default router;
 
-
