Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 32 additions & 12 deletions frontend/src/components/admin/UserModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,30 @@ const UserModal = ({ isOpen, onClose, onSave, initialData = null, clinics = [] }
useEffect(() => {
if (isOpen) {
if (initialData) {
// Om vi redigerar en veterinär, se till att fälten från vetRecord följer med in i formData
const role = (initialData.role || 'OWNER').replace('ROLE_', '');
setFormData({
...initialData,
role,
password: '',
licenseId: initialData.vetRecord?.licenseId || '',
specialization: initialData.vetRecord?.specialization || '',
bookingInfo: initialData.vetRecord?.bookingInfo || '',
clinicId: initialData.vetRecord?.clinicId || ''
clinicId: initialData.clinicId || '',
licenseId: '',
specialization: '',
bookingInfo: '',
});

if (role === 'VET') {
vetService.getAll().then(res => {
const vetRecord = res.data.find(v => v.userId === initialData.id);
if (vetRecord) {
setFormData(prev => ({
...prev,
licenseId: vetRecord.licenseId || '',
specialization: vetRecord.specialization || '',
bookingInfo: vetRecord.bookingInfo || '',
}));
}
}).catch(err => console.error('Kunde inte hämta veterinärdetaljer:', err));
Comment thread
TatjanaTrajkovic marked this conversation as resolved.
}
} else {
setFormData({
name: '', email: '', password: '',
Expand Down Expand Up @@ -70,12 +85,17 @@ const UserModal = ({ isOpen, onClose, onSave, initialData = null, clinics = [] }
bookingInfo: formData.bookingInfo
};

// CodeRabbit Fix: Kolla om det redan finns en veterinärpost (Edit vs Create)
const existingVetId = initialData?.vetRecord?.id;

if (existingVetId) {
await vetService.update(existingVetId, vetPayload);
} else if (userId) {
if (initialData) {
try {
await vetService.update(userId, vetPayload);
} catch (err) {
if (err.response?.status === 404) {
await vetService.create(vetPayload);
} else {
throw err;
}
}
} else {
await vetService.create(vetPayload);
}
}
Expand Down Expand Up @@ -211,7 +231,7 @@ const UserModal = ({ isOpen, onClose, onSave, initialData = null, clinics = [] }
{/* VETERINÄR-DETALJER */}
{isVet && (
<div className="pt-4 space-y-4 border-t border-slate-100">
<div className="space-y-1.5">
<div className="space-y-1.5">
<label htmlFor={licenseIdInput} className="text-[10px] font-black text-blue-500 uppercase tracking-widest ml-1 italic block text-left">Legitimations-ID</label>
<div className="relative">
<Award className="absolute left-4 top-3 text-blue-400" size={18} aria-hidden="true" />
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/AdminDashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const AdminDashboard = ({ userName, initialTab = 'USERS' }) => {
? await userService.update(selectedItem.id, userData)
: await userService.create(userData);

fetchData();
await fetchData();
return response;
};

Expand Down
1 change: 1 addition & 0 deletions frontend/src/services/api.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export const userService = {

export const vetService = {
create: (vetData) => api.post('/vets', vetData),
update: (userId, vetData) => api.put(`/vets/${userId}`, vetData),
getAll: () => api.get('/vets'),
getById: (id) => api.get(`/vets/${id}`),
};
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/org/example/vet1177/controller/VetController.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ public ResponseEntity<VetResponse> createVet(
return new ResponseEntity<>(response, HttpStatus.CREATED);
}

@PutMapping("/{userId}")
public ResponseEntity<VetResponse> updateVet(
@AuthenticationPrincipal User user,
@PathVariable UUID userId,
@Valid @RequestBody VetRequest request) {
log.info("PUT /api/vets/{}", userId);
adminPolicy.requireAdmin(user);
return ResponseEntity.ok(vetService.updateVet(userId, request));
}

@GetMapping
public ResponseEntity<List<VetResponse>> getAllVets() {
log.info("GET /api/vets");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Size;
import org.example.vet1177.entities.Role;

import java.util.UUID;

Expand All @@ -15,6 +16,8 @@ public class UserUpdateRequest {

private UUID clinicId;

private Role role;

public UUID getClinicId() {
return clinicId;
}
Expand All @@ -38,4 +41,12 @@ public String getName() {
public void setName(String name) {
this.name = name;
}

public Role getRole() {
return role;
}

public void setRole(Role role) {
this.role = role;
}
}
9 changes: 8 additions & 1 deletion src/main/java/org/example/vet1177/services/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,14 @@ public UserResponse updateUser(UUID id, UserUpdateRequest request) {
user.setName(request.getName());
}

if (request.getClinicId() != null) {
if (request.getRole() != null) {
user.setRole(request.getRole());
if (request.getRole() != Role.VET) {
user.setClinic(null);
}
}

if (request.getClinicId() != null && user.getRole() == Role.VET) {
applyClinicRulesForUpdate(user, request.getClinicId());
}
log.info("Updated user id={}", id);
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/org/example/vet1177/services/VetService.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,27 @@ public VetResponse createVet(VetRequest request) {
}
}

public VetResponse updateVet(UUID userId, VetRequest request) {
log.info("Updating vet userId={}", userId);
Vet vet = vetRepository.findById(userId)
.orElseThrow(() -> new ResourceNotFoundException("Vet", userId));

if (!vet.getLicenseId().equals(request.licenseId()) &&
vetRepository.existsByLicenseId(request.licenseId())) {
throw new BusinessRuleException("Licens-ID " + request.licenseId() + " används redan");
}

vet.setLicenseId(request.licenseId());
vet.setSpecialization(request.specialization());
vet.setBookingInfo(request.bookingInfo());

try {
return VetResponse.from(vetRepository.save(vet));
} catch (org.springframework.dao.DataIntegrityViolationException e) {
throw new BusinessRuleException("Licens-ID " + request.licenseId() + " används redan");
}
}

@Transactional(readOnly = true)
public List<VetResponse> getAllVets() {
log.debug("Fetching all vets");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,15 +316,16 @@ void updateUser_vet_changeClinic_updatesClinic() {
}

@Test
void updateUser_owner_setClinic_throwsBusinessRuleException() {
void updateUser_owner_setClinic_isIgnored() {
UserUpdateRequest request = new UserUpdateRequest();
request.setClinicId(clinicId);

when(userRepository.findById(userId)).thenReturn(Optional.of(ownerUser));
when(userRepository.save(ownerUser)).thenReturn(ownerUser);

assertThatThrownBy(() -> userService.updateUser(userId, request))
.isInstanceOf(BusinessRuleException.class)
.hasMessageContaining("Endast veterinärer kan kopplas till en klinik");
userService.updateUser(userId, request);

assertThat(ownerUser.getClinic()).isNull();
}

@Test
Expand Down