professor and education updated
This commit is contained in:
@ -20,19 +20,14 @@ public class CourseDto {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private String duration;
|
private String duration;
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private Integer seats;
|
private Integer seats;
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private String category;
|
private String category;
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private String level;
|
private String level;
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private String instructor;
|
private String instructor;
|
||||||
|
|
||||||
private String price;
|
private String price;
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import net.shyshkin.study.fullstack.supportportal.backend.domain.ProfessorCatego
|
|||||||
import net.shyshkin.study.fullstack.supportportal.backend.domain.ProfessorSkill;
|
import net.shyshkin.study.fullstack.supportportal.backend.domain.ProfessorSkill;
|
||||||
import net.shyshkin.study.fullstack.supportportal.backend.domain.dto.ProfessorDto;
|
import net.shyshkin.study.fullstack.supportportal.backend.domain.dto.ProfessorDto;
|
||||||
import net.shyshkin.study.fullstack.supportportal.backend.domain.WorkingStatus;
|
import net.shyshkin.study.fullstack.supportportal.backend.domain.WorkingStatus;
|
||||||
import net.shyshkin.study.fullstack.supportportal.backend.exception.domain.EmailExistsException;
|
|
||||||
import net.shyshkin.study.fullstack.supportportal.backend.exception.domain.NotAnImageFileException;
|
import net.shyshkin.study.fullstack.supportportal.backend.exception.domain.NotAnImageFileException;
|
||||||
import net.shyshkin.study.fullstack.supportportal.backend.exception.domain.ProfessorNotFoundException;
|
import net.shyshkin.study.fullstack.supportportal.backend.exception.domain.ProfessorNotFoundException;
|
||||||
import net.shyshkin.study.fullstack.supportportal.backend.mapper.ProfessorMapper;
|
import net.shyshkin.study.fullstack.supportportal.backend.mapper.ProfessorMapper;
|
||||||
@ -18,12 +17,12 @@ import org.springframework.core.ParameterizedTypeReference;
|
|||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.http.RequestEntity;
|
import org.springframework.http.RequestEntity;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.transaction.Transactional;
|
import javax.transaction.Transactional;
|
||||||
@ -45,7 +44,6 @@ import static org.springframework.http.MediaType.*;
|
|||||||
public class ProfessorServiceImpl implements ProfessorService {
|
public class ProfessorServiceImpl implements ProfessorService {
|
||||||
|
|
||||||
public static final String EMAIL_NOT_FOUND_MSG = "Professor with email `%s` not found";
|
public static final String EMAIL_NOT_FOUND_MSG = "Professor with email `%s` not found";
|
||||||
public static final String EMAIL_EXISTS_MSG = "Professor with email `%s` is already registered";
|
|
||||||
public static final String PROFESSOR_NOT_FOUND_MSG = "Professor not found";
|
public static final String PROFESSOR_NOT_FOUND_MSG = "Professor not found";
|
||||||
|
|
||||||
private final ProfessorRepository professorRepository;
|
private final ProfessorRepository professorRepository;
|
||||||
@ -100,7 +98,7 @@ public class ProfessorServiceImpl implements ProfessorService {
|
|||||||
public Professor findByEmail(String email) {
|
public Professor findByEmail(String email) {
|
||||||
return professorRepository
|
return professorRepository
|
||||||
.findByEmail(email)
|
.findByEmail(email)
|
||||||
.orElseThrow(() -> new EmailExistsException(String.format(EMAIL_NOT_FOUND_MSG, email)));
|
.orElseThrow(() -> new ProfessorNotFoundException(String.format(EMAIL_NOT_FOUND_MSG, email)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -158,19 +156,21 @@ public class ProfessorServiceImpl implements ProfessorService {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Professor addNewProfessor(ProfessorDto professorDto) {
|
public Professor addNewProfessor(ProfessorDto professorDto) {
|
||||||
validateNewEmail(professorDto.getEmail());
|
// ✅ FIX: Removed validateNewEmail() - duplicate emails are now allowed
|
||||||
|
|
||||||
Professor professor = professorMapper.toEntity(professorDto);
|
Professor professor = professorMapper.toEntity(professorDto);
|
||||||
|
|
||||||
// Set a unique identifier for the professor
|
// Set a unique identifier for the professor
|
||||||
professor.setProfessorId(generateUuid());
|
professor.setProfessorId(generateUuid());
|
||||||
professor.setJoinDate(LocalDateTime.now());
|
professor.setJoinDate(
|
||||||
|
professorDto.getJoinDate() != null ? professorDto.getJoinDate() : LocalDateTime.now()
|
||||||
|
);
|
||||||
professor.setProfileImageUrl(generateDefaultProfileImageUrl(professor.getProfessorId()));
|
professor.setProfileImageUrl(generateDefaultProfileImageUrl(professor.getProfessorId()));
|
||||||
|
|
||||||
// Save the professor first to get the ID
|
// Save the professor first to get the ID
|
||||||
Professor savedProfessor = professorRepository.save(professor);
|
Professor savedProfessor = professorRepository.save(professor);
|
||||||
|
|
||||||
// Handle skills if provided
|
// ✅ Handle skills if provided
|
||||||
if (professorDto.getSkills() != null && !professorDto.getSkills().isEmpty()) {
|
if (professorDto.getSkills() != null && !professorDto.getSkills().isEmpty()) {
|
||||||
Set<ProfessorSkill> skills = professorDto.getSkills().stream()
|
Set<ProfessorSkill> skills = professorDto.getSkills().stream()
|
||||||
.filter(skillDto -> skillDto.getName() != null && !skillDto.getName().trim().isEmpty())
|
.filter(skillDto -> skillDto.getName() != null && !skillDto.getName().trim().isEmpty())
|
||||||
@ -183,7 +183,7 @@ public class ProfessorServiceImpl implements ProfessorService {
|
|||||||
savedProfessor.setSkills(skills);
|
savedProfessor.setSkills(skills);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle awards if provided
|
// ✅ Handle awards if provided
|
||||||
if (professorDto.getAwards() != null && !professorDto.getAwards().isEmpty()) {
|
if (professorDto.getAwards() != null && !professorDto.getAwards().isEmpty()) {
|
||||||
Set<ProfessorAward> awards = professorDto.getAwards().stream()
|
Set<ProfessorAward> awards = professorDto.getAwards().stream()
|
||||||
.filter(awardDto -> awardDto.getTitle() != null && !awardDto.getTitle().trim().isEmpty())
|
.filter(awardDto -> awardDto.getTitle() != null && !awardDto.getTitle().trim().isEmpty())
|
||||||
@ -213,9 +213,9 @@ public class ProfessorServiceImpl implements ProfessorService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public Professor updateProfessor(UUID professorId, ProfessorDto professorDto) {
|
public Professor updateProfessor(UUID professorId, ProfessorDto professorDto) {
|
||||||
Professor professor = professorRepository.findByProfessorId(professorId)
|
Professor professor = professorRepository.findByProfessorId(professorId)
|
||||||
.orElseThrow(() -> new RuntimeException("Professor not found with id: " + professorId));
|
.orElseThrow(() -> new ProfessorNotFoundException("Professor not found with id: " + professorId));
|
||||||
|
|
||||||
validateUpdateEmail(professorId, professorDto.getEmail());
|
// ✅ FIX: Removed validateUpdateEmail() - duplicate emails are now allowed
|
||||||
|
|
||||||
// Update basic fields
|
// Update basic fields
|
||||||
professor.setFirstName(professorDto.getFirstName());
|
professor.setFirstName(professorDto.getFirstName());
|
||||||
@ -226,7 +226,7 @@ public class ProfessorServiceImpl implements ProfessorService {
|
|||||||
professor.setOfficeLocation(professorDto.getOfficeLocation());
|
professor.setOfficeLocation(professorDto.getOfficeLocation());
|
||||||
professor.setStatus(professorDto.getStatus());
|
professor.setStatus(professorDto.getStatus());
|
||||||
professor.setCategory(professorDto.getCategory());
|
professor.setCategory(professorDto.getCategory());
|
||||||
|
|
||||||
// Update extended fields
|
// Update extended fields
|
||||||
professor.setPhone(professorDto.getPhone());
|
professor.setPhone(professorDto.getPhone());
|
||||||
professor.setSpecialty(professorDto.getSpecialty());
|
professor.setSpecialty(professorDto.getSpecialty());
|
||||||
@ -237,6 +237,7 @@ public class ProfessorServiceImpl implements ProfessorService {
|
|||||||
professor.setDesignation(professorDto.getDesignation());
|
professor.setDesignation(professorDto.getDesignation());
|
||||||
professor.setWorkDays(professorDto.getWorkDays());
|
professor.setWorkDays(professorDto.getWorkDays());
|
||||||
|
|
||||||
|
// ✅ Update joinDate if provided
|
||||||
if (professorDto.getJoinDate() != null) {
|
if (professorDto.getJoinDate() != null) {
|
||||||
professor.setJoinDate(professorDto.getJoinDate());
|
professor.setJoinDate(professorDto.getJoinDate());
|
||||||
}
|
}
|
||||||
@ -244,16 +245,12 @@ public class ProfessorServiceImpl implements ProfessorService {
|
|||||||
// Create a final reference for lambda expressions
|
// Create a final reference for lambda expressions
|
||||||
final Professor professorRef = professor;
|
final Professor professorRef = professor;
|
||||||
|
|
||||||
// ✅ CORRECT FIX: Update skills with orphanRemoval=true
|
// ✅ Update skills with orphanRemoval=true
|
||||||
// Initialize collection if null
|
|
||||||
if (professor.getSkills() == null) {
|
if (professor.getSkills() == null) {
|
||||||
professor.setSkills(new HashSet<>());
|
professor.setSkills(new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear existing skills (orphanRemoval will delete them from DB)
|
|
||||||
professor.getSkills().clear();
|
professor.getSkills().clear();
|
||||||
|
|
||||||
// Add new skills
|
|
||||||
if (professorDto.getSkills() != null && !professorDto.getSkills().isEmpty()) {
|
if (professorDto.getSkills() != null && !professorDto.getSkills().isEmpty()) {
|
||||||
Set<ProfessorSkill> newSkills = professorDto.getSkills().stream()
|
Set<ProfessorSkill> newSkills = professorDto.getSkills().stream()
|
||||||
.filter(skillDto -> skillDto.getName() != null && !skillDto.getName().trim().isEmpty())
|
.filter(skillDto -> skillDto.getName() != null && !skillDto.getName().trim().isEmpty())
|
||||||
@ -263,20 +260,15 @@ public class ProfessorServiceImpl implements ProfessorService {
|
|||||||
.professor(professorRef)
|
.professor(professorRef)
|
||||||
.build())
|
.build())
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
professor.getSkills().addAll(newSkills);
|
professor.getSkills().addAll(newSkills);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ CORRECT FIX: Update awards with orphanRemoval=true
|
// ✅ Update awards with orphanRemoval=true
|
||||||
// Initialize collection if null
|
|
||||||
if (professor.getAwards() == null) {
|
if (professor.getAwards() == null) {
|
||||||
professor.setAwards(new HashSet<>());
|
professor.setAwards(new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear existing awards (orphanRemoval will delete them from DB)
|
|
||||||
professor.getAwards().clear();
|
professor.getAwards().clear();
|
||||||
|
|
||||||
// Add new awards
|
|
||||||
if (professorDto.getAwards() != null && !professorDto.getAwards().isEmpty()) {
|
if (professorDto.getAwards() != null && !professorDto.getAwards().isEmpty()) {
|
||||||
Set<ProfessorAward> newAwards = professorDto.getAwards().stream()
|
Set<ProfessorAward> newAwards = professorDto.getAwards().stream()
|
||||||
.filter(awardDto -> awardDto.getTitle() != null && !awardDto.getTitle().trim().isEmpty())
|
.filter(awardDto -> awardDto.getTitle() != null && !awardDto.getTitle().trim().isEmpty())
|
||||||
@ -288,12 +280,11 @@ public class ProfessorServiceImpl implements ProfessorService {
|
|||||||
.professor(professorRef)
|
.professor(professorRef)
|
||||||
.build())
|
.build())
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
professor.getAwards().addAll(newAwards);
|
professor.getAwards().addAll(newAwards);
|
||||||
}
|
}
|
||||||
|
|
||||||
Professor savedProfessor = professorRepository.save(professor);
|
Professor savedProfessor = professorRepository.save(professor);
|
||||||
|
|
||||||
// Handle profile image if provided
|
// Handle profile image if provided
|
||||||
if (professorDto.getProfileImage() != null) {
|
if (professorDto.getProfileImage() != null) {
|
||||||
saveProfileImage(savedProfessor, professorDto.getProfileImage());
|
saveProfileImage(savedProfessor, professorDto.getProfileImage());
|
||||||
@ -340,22 +331,4 @@ public class ProfessorServiceImpl implements ProfessorService {
|
|||||||
var responseEntity = restTemplate.exchange(requestEntity, new ParameterizedTypeReference<byte[]>() {});
|
var responseEntity = restTemplate.exchange(requestEntity, new ParameterizedTypeReference<byte[]>() {});
|
||||||
return responseEntity.getBody();
|
return responseEntity.getBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateNewEmail(String email) {
|
|
||||||
if (professorRepository.existsByEmail(email)) {
|
|
||||||
throw new EmailExistsException(String.format(EMAIL_EXISTS_MSG, email));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Professor validateUpdateEmail(UUID professorId, String email) {
|
|
||||||
Objects.requireNonNull(professorId);
|
|
||||||
|
|
||||||
Professor currentProfessor = findByProfessorId(professorId);
|
|
||||||
|
|
||||||
if (!Objects.equals(currentProfessor.getEmail(), email) && professorRepository.existsByEmail(email)) {
|
|
||||||
throw new EmailExistsException(String.format(EMAIL_EXISTS_MSG, email));
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentProfessor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -120,10 +120,7 @@
|
|||||||
</label>
|
</label>
|
||||||
<input type="text" id="instructor" class="form-input" formControlName="instructor"
|
<input type="text" id="instructor" class="form-input" formControlName="instructor"
|
||||||
placeholder="e.g., Dr. John Smith">
|
placeholder="e.g., Dr. John Smith">
|
||||||
<div *ngIf="courseForm.get('instructor')?.invalid && courseForm.get('instructor')?.touched" class="error-message">
|
|
||||||
<i class="fa fa-exclamation-circle"></i>
|
|
||||||
Instructor is required.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -135,10 +132,7 @@
|
|||||||
</label>
|
</label>
|
||||||
<input type="text" id="duration" class="form-input" formControlName="duration"
|
<input type="text" id="duration" class="form-input" formControlName="duration"
|
||||||
placeholder="e.g., 3 Days, 2 Years">
|
placeholder="e.g., 3 Days, 2 Years">
|
||||||
<div *ngIf="courseForm.get('duration')?.invalid && courseForm.get('duration')?.touched" class="error-message">
|
|
||||||
<i class="fa fa-exclamation-circle"></i>
|
|
||||||
Duration is required.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -148,10 +142,7 @@
|
|||||||
</label>
|
</label>
|
||||||
<input type="number" id="seats" class="form-input" formControlName="seats"
|
<input type="number" id="seats" class="form-input" formControlName="seats"
|
||||||
placeholder="Enter available seats" min="1">
|
placeholder="Enter available seats" min="1">
|
||||||
<div *ngIf="courseForm.get('seats')?.invalid && courseForm.get('seats')?.touched" class="error-message">
|
|
||||||
<i class="fa fa-exclamation-circle"></i>
|
|
||||||
Number of seats is required.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -178,10 +169,7 @@
|
|||||||
<option value="Fellowship">Fellowship</option>
|
<option value="Fellowship">Fellowship</option>
|
||||||
<option value="Course">Course</option>
|
<option value="Course">Course</option>
|
||||||
</select>
|
</select>
|
||||||
<div *ngIf="courseForm.get('category')?.invalid && courseForm.get('category')?.touched" class="error-message">
|
|
||||||
<i class="fa fa-exclamation-circle"></i>
|
|
||||||
Category is required.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -197,10 +185,7 @@
|
|||||||
<option value="Professional">Professional</option>
|
<option value="Professional">Professional</option>
|
||||||
<option value="Post-Doctoral">Post-Doctoral</option>
|
<option value="Post-Doctoral">Post-Doctoral</option>
|
||||||
</select>
|
</select>
|
||||||
<div *ngIf="courseForm.get('level')?.invalid && courseForm.get('level')?.touched" class="error-message">
|
|
||||||
<i class="fa fa-exclamation-circle"></i>
|
|
||||||
Level is required.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -372,10 +357,7 @@
|
|||||||
</label>
|
</label>
|
||||||
<input type="text" id="eventSchedule" class="form-input" formControlName="schedule"
|
<input type="text" id="eventSchedule" class="form-input" formControlName="schedule"
|
||||||
placeholder="e.g., Q3 2025, Monthly Sessions, Ongoing">
|
placeholder="e.g., Q3 2025, Monthly Sessions, Ongoing">
|
||||||
<div *ngIf="upcomingEventForm.get('schedule')?.invalid && upcomingEventForm.get('schedule')?.touched" class="error-message">
|
|
||||||
<i class="fa fa-exclamation-circle"></i>
|
|
||||||
Schedule is required.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
@ -44,11 +44,11 @@ export class EducationComponent implements OnInit {
|
|||||||
this.courseForm = this.fb.group({
|
this.courseForm = this.fb.group({
|
||||||
title: ['', Validators.required],
|
title: ['', Validators.required],
|
||||||
description: ['', Validators.required],
|
description: ['', Validators.required],
|
||||||
duration: ['', Validators.required],
|
duration: [''],
|
||||||
seats: ['', [Validators.required, Validators.min(1)]],
|
seats: [''],
|
||||||
category: ['', Validators.required],
|
category: [''],
|
||||||
level: ['', Validators.required],
|
level: [''],
|
||||||
instructor: ['', Validators.required],
|
instructor: [''],
|
||||||
price: [''],
|
price: [''],
|
||||||
startDate: [''],
|
startDate: [''],
|
||||||
eligibility: [''],
|
eligibility: [''],
|
||||||
@ -59,7 +59,7 @@ export class EducationComponent implements OnInit {
|
|||||||
this.upcomingEventForm = this.fb.group({
|
this.upcomingEventForm = this.fb.group({
|
||||||
title: ['', Validators.required],
|
title: ['', Validators.required],
|
||||||
description: ['', Validators.required],
|
description: ['', Validators.required],
|
||||||
schedule: ['', Validators.required],
|
schedule: [''],
|
||||||
eventDate: [''],
|
eventDate: [''],
|
||||||
isActive: [true]
|
isActive: [true]
|
||||||
});
|
});
|
||||||
@ -381,5 +381,4 @@ export class EducationComponent implements OnInit {
|
|||||||
getApplicationCount(courseId?: number): number {
|
getApplicationCount(courseId?: number): number {
|
||||||
if (!courseId) return 0;
|
if (!courseId) return 0;
|
||||||
return this.applications.filter(app => app.course?.id === courseId).length;
|
return this.applications.filter(app => app.course?.id === courseId).length;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -25,6 +25,12 @@ interface Award {
|
|||||||
imageUrl?: string;
|
imageUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Skill {
|
||||||
|
id?: number;
|
||||||
|
name: string;
|
||||||
|
level: number;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-professor',
|
selector: 'app-professor',
|
||||||
templateUrl: './professor.component.html',
|
templateUrl: './professor.component.html',
|
||||||
@ -63,7 +69,8 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
description: '',
|
description: '',
|
||||||
designation: '',
|
designation: '',
|
||||||
workDays: [],
|
workDays: [],
|
||||||
awards: []
|
awards: [],
|
||||||
|
skills: []
|
||||||
};
|
};
|
||||||
|
|
||||||
public profileImageFileName: string | null;
|
public profileImageFileName: string | null;
|
||||||
@ -74,10 +81,14 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
public availableDays: string[] = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
public availableDays: string[] = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
||||||
public selectedWorkDays: { [key: string]: boolean } = {};
|
public selectedWorkDays: { [key: string]: boolean } = {};
|
||||||
|
|
||||||
// Awards management
|
// ✅ Awards management
|
||||||
public newProfessorAwards: Award[] = [];
|
public newProfessorAwards: Award[] = [];
|
||||||
public selectedProfessorAwards: Award[] = [];
|
public selectedProfessorAwards: Award[] = [];
|
||||||
|
|
||||||
|
// ✅ Skills management
|
||||||
|
public newProfessorSkills: Skill[] = [];
|
||||||
|
public selectedProfessorSkills: Skill[] = [];
|
||||||
|
|
||||||
private closeModal(modalId: string): void {
|
private closeModal(modalId: string): void {
|
||||||
const modalElement = document.getElementById(modalId);
|
const modalElement = document.getElementById(modalId);
|
||||||
if (!modalElement) return;
|
if (!modalElement) return;
|
||||||
@ -90,7 +101,6 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
document.querySelectorAll('.modal-backdrop').forEach(b => b.remove());
|
document.querySelectorAll('.modal-backdrop').forEach(b => b.remove());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private professorService: ProfessorService,
|
private professorService: ProfessorService,
|
||||||
private notificationService: NotificationService,
|
private notificationService: NotificationService,
|
||||||
@ -101,7 +111,7 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.getProfessors(true);
|
this.getProfessors(true);
|
||||||
this.loggedInUser = this.authenticationService.getUserFromLocalStorage();
|
this.loggedInUser = this.authenticationService.getUserFromLocalStorage();
|
||||||
this.initializeAwards();
|
this.initializeCollections();
|
||||||
this.setupModalEventListeners();
|
this.setupModalEventListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,16 +119,15 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
this.subs.unsubscribe();
|
this.subs.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeAwards(): void {
|
// ✅ FIX: Renamed and now initializes both awards and skills
|
||||||
|
private initializeCollections(): void {
|
||||||
this.newProfessorAwards = [];
|
this.newProfessorAwards = [];
|
||||||
this.selectedProfessorAwards = [];
|
this.selectedProfessorAwards = [];
|
||||||
|
this.newProfessorSkills = [];
|
||||||
|
this.selectedProfessorSkills = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup event listeners for Bootstrap modals to clear data when they close
|
|
||||||
*/
|
|
||||||
private setupModalEventListeners(): void {
|
private setupModalEventListeners(): void {
|
||||||
// Listen for edit modal close event
|
|
||||||
const editModal = document.getElementById('editProfessorModal');
|
const editModal = document.getElementById('editProfessorModal');
|
||||||
if (editModal) {
|
if (editModal) {
|
||||||
editModal.addEventListener('hidden.bs.modal', () => {
|
editModal.addEventListener('hidden.bs.modal', () => {
|
||||||
@ -126,7 +135,6 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for add modal close event
|
|
||||||
const addModal = document.getElementById('addProfessorModal');
|
const addModal = document.getElementById('addProfessorModal');
|
||||||
if (addModal) {
|
if (addModal) {
|
||||||
addModal.addEventListener('hidden.bs.modal', () => {
|
addModal.addEventListener('hidden.bs.modal', () => {
|
||||||
@ -135,42 +143,33 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear only profile image related data (used after successful operations)
|
|
||||||
*/
|
|
||||||
private invalidateVariables(): void {
|
private invalidateVariables(): void {
|
||||||
this.profileImage = null;
|
this.profileImage = null;
|
||||||
this.profileImageFileName = null;
|
this.profileImageFileName = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// ✅ FIX: Now clears skills too
|
||||||
* Clear all data related to adding a new professor
|
|
||||||
*/
|
|
||||||
private clearNewProfessorData(): void {
|
private clearNewProfessorData(): void {
|
||||||
this.profileImage = null;
|
this.profileImage = null;
|
||||||
this.profileImageFileName = null;
|
this.profileImageFileName = null;
|
||||||
this.selectedWorkDays = {};
|
this.selectedWorkDays = {};
|
||||||
this.newProfessorAwards = [];
|
this.newProfessorAwards = [];
|
||||||
|
this.newProfessorSkills = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// ✅ FIX: Now clears skills too
|
||||||
* Clear all data related to editing a professor
|
|
||||||
*/
|
|
||||||
private clearEditProfessorData(): void {
|
private clearEditProfessorData(): void {
|
||||||
this.profileImage = null;
|
this.profileImage = null;
|
||||||
this.profileImageFileName = null;
|
this.profileImageFileName = null;
|
||||||
this.selectedWorkDays = {};
|
this.selectedWorkDays = {};
|
||||||
this.selectedProfessorAwards = [];
|
this.selectedProfessorAwards = [];
|
||||||
|
this.selectedProfessorSkills = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Award management methods
|
// ─── Award management methods ────────────────────────────────────────────────
|
||||||
|
|
||||||
public addNewAward(): void {
|
public addNewAward(): void {
|
||||||
this.newProfessorAwards.push({
|
this.newProfessorAwards.push({ title: '', year: '', description: '', imageUrl: '' });
|
||||||
title: '',
|
|
||||||
year: '',
|
|
||||||
description: '',
|
|
||||||
imageUrl: ''
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeAward(index: number): void {
|
public removeAward(index: number): void {
|
||||||
@ -178,29 +177,43 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public addEditAward(): void {
|
public addEditAward(): void {
|
||||||
this.selectedProfessorAwards.push({
|
this.selectedProfessorAwards.push({ title: '', year: '', description: '', imageUrl: '' });
|
||||||
title: '',
|
|
||||||
year: '',
|
|
||||||
description: '',
|
|
||||||
imageUrl: ''
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeEditAward(index: number): void {
|
public removeEditAward(index: number): void {
|
||||||
this.selectedProfessorAwards.splice(index, 1);
|
this.selectedProfessorAwards.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Category display helper
|
// ─── Skill management methods ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
// ✅ NEW: Add skill for new professor form
|
||||||
|
public addNewSkill(): void {
|
||||||
|
this.newProfessorSkills.push({ name: '', level: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ NEW: Remove skill from new professor form
|
||||||
|
public removeSkill(index: number): void {
|
||||||
|
this.newProfessorSkills.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ NEW: Add skill for edit professor form
|
||||||
|
public addEditSkill(): void {
|
||||||
|
this.selectedProfessorSkills.push({ name: '', level: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ NEW: Remove skill from edit professor form
|
||||||
|
public removeEditSkill(index: number): void {
|
||||||
|
this.selectedProfessorSkills.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Category display helper ─────────────────────────────────────────────────
|
||||||
|
|
||||||
public getCategoryDisplayName(category: string): string {
|
public getCategoryDisplayName(category: string): string {
|
||||||
switch (category) {
|
switch (category) {
|
||||||
case 'FACULTY':
|
case 'FACULTY': return 'Faculty';
|
||||||
return 'Faculty';
|
case 'SUPPORT_TEAM': return 'Support Team';
|
||||||
case 'SUPPORT_TEAM':
|
case 'TRAINEE_FELLOW': return 'Trainee/Fellow';
|
||||||
return 'Support Team';
|
default: return 'Unknown';
|
||||||
case 'TRAINEE_FELLOW':
|
|
||||||
return 'Trainee/Fellow';
|
|
||||||
default:
|
|
||||||
return 'Unknown';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,14 +244,18 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onSelectProfessor(selectedProfessor: Professor): void {
|
public onSelectProfessor(selectedProfessor: Professor): void {
|
||||||
// Create a deep copy to avoid reference issues
|
|
||||||
this.selectedProfessor = JSON.parse(JSON.stringify(selectedProfessor));
|
this.selectedProfessor = JSON.parse(JSON.stringify(selectedProfessor));
|
||||||
|
|
||||||
// Create a separate copy for awards to display
|
// ✅ FIX: Load awards
|
||||||
this.selectedProfessorAwards = selectedProfessor.awards
|
this.selectedProfessorAwards = selectedProfessor.awards
|
||||||
? JSON.parse(JSON.stringify(selectedProfessor.awards))
|
? JSON.parse(JSON.stringify(selectedProfessor.awards))
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
// ✅ FIX: Load skills
|
||||||
|
this.selectedProfessorSkills = selectedProfessor.skills
|
||||||
|
? JSON.parse(JSON.stringify(selectedProfessor.skills))
|
||||||
|
: [];
|
||||||
|
|
||||||
// Set up work days for viewing
|
// Set up work days for viewing
|
||||||
this.selectedWorkDays = {};
|
this.selectedWorkDays = {};
|
||||||
if (selectedProfessor.workDays && Array.isArray(selectedProfessor.workDays)) {
|
if (selectedProfessor.workDays && Array.isArray(selectedProfessor.workDays)) {
|
||||||
@ -260,19 +277,13 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onCategoryChange(category: string): void {
|
public onCategoryChange(category: string): void {
|
||||||
// Clear profile image if Trainee/Fellow or Support Team is selected
|
|
||||||
if (category === 'TRAINEE_FELLOW' || category === 'SUPPORT_TEAM') {
|
if (category === 'TRAINEE_FELLOW' || category === 'SUPPORT_TEAM') {
|
||||||
this.profileImage = null;
|
this.profileImage = null;
|
||||||
this.profileImageFileName = null;
|
this.profileImageFileName = null;
|
||||||
// Reset file input
|
|
||||||
const fileInput = document.getElementById('newProfessorProfileImage') as HTMLInputElement;
|
const fileInput = document.getElementById('newProfessorProfileImage') as HTMLInputElement;
|
||||||
if (fileInput) {
|
if (fileInput) fileInput.value = '';
|
||||||
fileInput.value = '';
|
|
||||||
}
|
|
||||||
const editFileInput = document.getElementById('editProfessorProfileImage') as HTMLInputElement;
|
const editFileInput = document.getElementById('editProfessorProfileImage') as HTMLInputElement;
|
||||||
if (editFileInput) {
|
if (editFileInput) editFileInput.value = '';
|
||||||
editFileInput.value = '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +303,6 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
this.getProfessors(false);
|
this.getProfessors(false);
|
||||||
professorForm.reset();
|
professorForm.reset();
|
||||||
this.notificationService.notify(NotificationType.SUCCESS, `Professor ${professor.firstName} added successfully`);
|
this.notificationService.notify(NotificationType.SUCCESS, `Professor ${professor.firstName} added successfully`);
|
||||||
// Data will be cleared by modal close event listener
|
|
||||||
},
|
},
|
||||||
(errorResponse: HttpErrorResponse) => {
|
(errorResponse: HttpErrorResponse) => {
|
||||||
this.sendErrorNotification(errorResponse.error.message);
|
this.sendErrorNotification(errorResponse.error.message);
|
||||||
@ -333,10 +343,9 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onEditProfessor(professor: Professor): void {
|
public onEditProfessor(professor: Professor): void {
|
||||||
// Create a deep copy to avoid reference issues
|
|
||||||
this.selectedProfessor = JSON.parse(JSON.stringify(professor));
|
this.selectedProfessor = JSON.parse(JSON.stringify(professor));
|
||||||
|
|
||||||
// Set up work days for editing with validation
|
// Set up work days for editing
|
||||||
this.selectedWorkDays = {};
|
this.selectedWorkDays = {};
|
||||||
if (professor.workDays && Array.isArray(professor.workDays)) {
|
if (professor.workDays && Array.isArray(professor.workDays)) {
|
||||||
professor.workDays.forEach(day => {
|
professor.workDays.forEach(day => {
|
||||||
@ -346,11 +355,16 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up awards for editing - create a deep copy
|
// ✅ FIX: Load awards for editing
|
||||||
this.selectedProfessorAwards = professor.awards
|
this.selectedProfessorAwards = professor.awards
|
||||||
? JSON.parse(JSON.stringify(professor.awards))
|
? JSON.parse(JSON.stringify(professor.awards))
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
// ✅ FIX: Load skills for editing
|
||||||
|
this.selectedProfessorSkills = professor.skills
|
||||||
|
? JSON.parse(JSON.stringify(professor.skills))
|
||||||
|
: [];
|
||||||
|
|
||||||
this.clickButton('openProfessorEdit');
|
this.clickButton('openProfessorEdit');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,19 +374,14 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Updating professor:', this.selectedProfessor);
|
|
||||||
console.log('Selected work days:', this.selectedWorkDays);
|
|
||||||
console.log('Selected awards:', this.selectedProfessorAwards);
|
|
||||||
|
|
||||||
const formData = this.createExtendedProfessorFormData(this.selectedProfessor, this.profileImage);
|
const formData = this.createExtendedProfessorFormData(this.selectedProfessor, this.profileImage);
|
||||||
|
|
||||||
this.subs.add(this.professorService.updateProfessor(this.selectedProfessor.professorId, formData).subscribe(
|
this.subs.add(this.professorService.updateProfessor(this.selectedProfessor.professorId, formData).subscribe(
|
||||||
(professor: Professor) => {
|
(professor: Professor) => {
|
||||||
this.closeModal('editProfessorModal');
|
this.closeModal('editProfessorModal');
|
||||||
this.getProfessors(false);
|
this.getProfessors(false);
|
||||||
this.invalidateVariables(); // Only clear profile image related data
|
this.invalidateVariables();
|
||||||
this.notificationService.notify(NotificationType.SUCCESS, `Professor ${professor.firstName} updated successfully`);
|
this.notificationService.notify(NotificationType.SUCCESS, `Professor ${professor.firstName} updated successfully`);
|
||||||
// Other data will be cleared by modal close event listener
|
|
||||||
},
|
},
|
||||||
(errorResponse: HttpErrorResponse) => {
|
(errorResponse: HttpErrorResponse) => {
|
||||||
this.sendErrorNotification(errorResponse.error.message);
|
this.sendErrorNotification(errorResponse.error.message);
|
||||||
@ -383,65 +392,70 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
private createExtendedProfessorFormData(professor: any, profileImage: File | null): FormData {
|
private createExtendedProfessorFormData(professor: any, profileImage: File | null): FormData {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
||||||
// Basic fields
|
// ─── Basic fields ────────────────────────────────────────────────────────
|
||||||
formData.append('firstName', professor.firstName || '');
|
formData.append('firstName', professor.firstName || '');
|
||||||
formData.append('lastName', professor.lastName || '');
|
formData.append('lastName', professor.lastName || '');
|
||||||
formData.append('email', professor.email || '');
|
formData.append('email', professor.email || '');
|
||||||
formData.append('department', professor.department || '');
|
formData.append('department', professor.department || '');
|
||||||
formData.append('position', professor.position || '');
|
formData.append('position', professor.position || '');
|
||||||
formData.append('officeLocation', professor.officeLocation || '');
|
formData.append('officeLocation', professor.officeLocation || '');
|
||||||
formData.append('status', professor.status || 'ACTIVE');
|
formData.append('status', professor.status || 'ACTIVE');
|
||||||
formData.append('category', professor.category || 'FACULTY');
|
formData.append('category', professor.category || 'FACULTY');
|
||||||
|
|
||||||
// Extended fields
|
// ✅ FIX: Send joinDate
|
||||||
formData.append('phone', professor.phone || '');
|
if (professor.joinDate) {
|
||||||
formData.append('specialty', professor.specialty || '');
|
formData.append('joinDate', new Date(professor.joinDate).toISOString());
|
||||||
formData.append('experience', professor.experience || '');
|
}
|
||||||
formData.append('designation', professor.designation || professor.position || '');
|
|
||||||
formData.append('description', professor.description || '');
|
// ─── Extended fields ─────────────────────────────────────────────────────
|
||||||
formData.append('certification', professor.certification || '');
|
formData.append('phone', professor.phone || '');
|
||||||
|
formData.append('specialty', professor.specialty || '');
|
||||||
|
formData.append('experience', professor.experience || '');
|
||||||
|
formData.append('designation', professor.designation || professor.position || '');
|
||||||
|
formData.append('description', professor.description || '');
|
||||||
|
formData.append('certification', professor.certification || '');
|
||||||
|
|
||||||
// Only include training if NOT retired
|
// Only include training if NOT retired
|
||||||
if (professor.status !== WorkingStatus.RETIRED) {
|
formData.append('training',
|
||||||
formData.append('training', professor.training || '');
|
professor.status !== WorkingStatus.RETIRED ? (professor.training || '') : ''
|
||||||
} else {
|
);
|
||||||
formData.append('training', ''); // Clear training for retired faculty
|
|
||||||
}
|
|
||||||
|
|
||||||
// Work days - collect from selectedWorkDays object
|
// ─── Work days ───────────────────────────────────────────────────────────
|
||||||
const workDays = Object.keys(this.selectedWorkDays).filter(day => this.selectedWorkDays[day]);
|
const workDays = Object.keys(this.selectedWorkDays).filter(day => this.selectedWorkDays[day]);
|
||||||
if (workDays.length > 0) {
|
workDays.forEach(day => formData.append('workDays', day));
|
||||||
workDays.forEach(day => {
|
|
||||||
formData.append('workDays', day);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Awards - determine which awards array to use based on context
|
// ─── Awards ──────────────────────────────────────────────────────────────
|
||||||
const awardsToSubmit = professor.professorId ? this.selectedProfessorAwards : this.newProfessorAwards;
|
const awardsToSubmit = professor.professorId ? this.selectedProfessorAwards : this.newProfessorAwards;
|
||||||
if (awardsToSubmit && awardsToSubmit.length > 0) {
|
if (awardsToSubmit && awardsToSubmit.length > 0) {
|
||||||
// Filter out empty awards and only include those with at least title and year
|
|
||||||
const validAwards = awardsToSubmit.filter(award =>
|
const validAwards = awardsToSubmit.filter(award =>
|
||||||
award.title && award.title.trim() && award.year && award.year.trim()
|
award.title && award.title.trim() && award.year && award.year.trim()
|
||||||
);
|
);
|
||||||
|
|
||||||
validAwards.forEach((award, index) => {
|
validAwards.forEach((award, index) => {
|
||||||
formData.append(`awards[${index}].title`, award.title.trim());
|
formData.append(`awards[${index}].title`, award.title.trim());
|
||||||
formData.append(`awards[${index}].year`, award.year.trim());
|
formData.append(`awards[${index}].year`, award.year.trim());
|
||||||
formData.append(`awards[${index}].description`, award.description || '');
|
formData.append(`awards[${index}].description`, award.description || '');
|
||||||
formData.append(`awards[${index}].imageUrl`, award.imageUrl || '');
|
formData.append(`awards[${index}].imageUrl`, award.imageUrl || '');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Profile image - only add if not Trainee/Fellow or Support Team category
|
// ✅ FIX: Skills are now sent to backend
|
||||||
|
const skillsToSubmit = professor.professorId ? this.selectedProfessorSkills : this.newProfessorSkills;
|
||||||
|
if (skillsToSubmit && skillsToSubmit.length > 0) {
|
||||||
|
const validSkills = skillsToSubmit.filter(skill => skill.name && skill.name.trim());
|
||||||
|
validSkills.forEach((skill, index) => {
|
||||||
|
formData.append(`skills[${index}].name`, skill.name.trim());
|
||||||
|
formData.append(`skills[${index}].level`, String(skill.level ?? 0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Profile image ───────────────────────────────────────────────────────
|
||||||
if (profileImage && professor.category !== 'TRAINEE_FELLOW' && professor.category !== 'SUPPORT_TEAM') {
|
if (profileImage && professor.category !== 'TRAINEE_FELLOW' && professor.category !== 'SUPPORT_TEAM') {
|
||||||
formData.append('profileImage', profileImage);
|
formData.append('profileImage', profileImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log formData for debugging
|
// Debug log
|
||||||
console.log('FormData contents:');
|
console.log('FormData contents:');
|
||||||
formData.forEach((value, key) => {
|
formData.forEach((value, key) => console.log(`${key}:`, value));
|
||||||
console.log(`${key}:`, value);
|
|
||||||
});
|
|
||||||
|
|
||||||
return formData;
|
return formData;
|
||||||
}
|
}
|
||||||
@ -469,7 +483,7 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
if (!this.profileImage) return;
|
if (!this.profileImage) return;
|
||||||
this.refreshing = true;
|
this.refreshing = true;
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("profileImage", this.profileImage);
|
formData.append('profileImage', this.profileImage);
|
||||||
let professor = this.professorService.getSelectedProfessor();
|
let professor = this.professorService.getSelectedProfessor();
|
||||||
this.subs.sink = this.professorService.updateProfileImage(professor.professorId, formData).subscribe(
|
this.subs.sink = this.professorService.updateProfileImage(professor.professorId, formData).subscribe(
|
||||||
(event: HttpEvent<any>) => {
|
(event: HttpEvent<any>) => {
|
||||||
@ -538,9 +552,13 @@ export class ProfessorComponent implements OnInit, OnDestroy {
|
|||||||
description: '',
|
description: '',
|
||||||
designation: '',
|
designation: '',
|
||||||
workDays: [],
|
workDays: [],
|
||||||
awards: []
|
awards: [],
|
||||||
|
skills: []
|
||||||
};
|
};
|
||||||
this.clearNewProfessorData();
|
this.clearNewProfessorData();
|
||||||
this.clearEditProfessorData();
|
this.clearEditProfessorData();
|
||||||
|
// ✅ FIX: Also reset skill arrays explicitly
|
||||||
|
this.newProfessorSkills = [];
|
||||||
|
this.selectedProfessorSkills = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,6 +5,7 @@
|
|||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"outDir": "./dist/out-tsc",
|
"outDir": "./dist/out-tsc",
|
||||||
|
"rootDir": "./src",
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"strictPropertyInitialization": false,
|
"strictPropertyInitialization": false,
|
||||||
@ -33,4 +34,4 @@
|
|||||||
"strictInputAccessModifiers": true,
|
"strictInputAccessModifiers": true,
|
||||||
"strictTemplates": true
|
"strictTemplates": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user