diff --git a/angular/.angular/cache/16.0.2/angular-webpack/dce62bf0d9033346257a7611f5885fbc901e18e6/0.pack b/angular/.angular/cache/16.0.2/angular-webpack/dce62bf0d9033346257a7611f5885fbc901e18e6/0.pack new file mode 100644 index 0000000..d1bc6a1 Binary files /dev/null and b/angular/.angular/cache/16.0.2/angular-webpack/dce62bf0d9033346257a7611f5885fbc901e18e6/0.pack differ diff --git a/angular/.angular/cache/16.0.2/angular-webpack/dce62bf0d9033346257a7611f5885fbc901e18e6/1.pack b/angular/.angular/cache/16.0.2/angular-webpack/dce62bf0d9033346257a7611f5885fbc901e18e6/1.pack new file mode 100644 index 0000000..5a23160 Binary files /dev/null and b/angular/.angular/cache/16.0.2/angular-webpack/dce62bf0d9033346257a7611f5885fbc901e18e6/1.pack differ diff --git a/angular/.angular/cache/16.0.2/angular-webpack/dce62bf0d9033346257a7611f5885fbc901e18e6/index.pack b/angular/.angular/cache/16.0.2/angular-webpack/dce62bf0d9033346257a7611f5885fbc901e18e6/index.pack new file mode 100644 index 0000000..eb9943a Binary files /dev/null and b/angular/.angular/cache/16.0.2/angular-webpack/dce62bf0d9033346257a7611f5885fbc901e18e6/index.pack differ diff --git a/angular/.angular/cache/16.0.2/angular-webpack/dce62bf0d9033346257a7611f5885fbc901e18e6/index.pack.old b/angular/.angular/cache/16.0.2/angular-webpack/dce62bf0d9033346257a7611f5885fbc901e18e6/index.pack.old new file mode 100644 index 0000000..2e28a26 Binary files /dev/null and b/angular/.angular/cache/16.0.2/angular-webpack/dce62bf0d9033346257a7611f5885fbc901e18e6/index.pack.old differ diff --git a/angular/src/app/contactform/contactform.component.ts b/angular/src/app/contactform/contactform.component.ts index 03faae9..cce0a8b 100644 --- a/angular/src/app/contactform/contactform.component.ts +++ b/angular/src/app/contactform/contactform.component.ts @@ -37,7 +37,7 @@ export class ContactformComponent { message: this.message }; - this.http.post('/api/contact', contactForm).subscribe( + this.http.post('/property/contact', contactForm).subscribe( () => { alert('Contact form submitted successfully!'); // Reset the form fields diff --git a/angular/src/app/models/property.ts b/angular/src/app/models/property.ts index 2342f9e..170b61f 100644 --- a/angular/src/app/models/property.ts +++ b/angular/src/app/models/property.ts @@ -1,4 +1,5 @@ export interface Property { + rentPerSqm: number; id: number; userId: number; externalId: string; diff --git a/angular/src/app/property-list/property-list.component.css b/angular/src/app/property-list/property-list.component.css index 4a29db4..f62c6ad 100644 --- a/angular/src/app/property-list/property-list.component.css +++ b/angular/src/app/property-list/property-list.component.css @@ -54,22 +54,29 @@ .contact-form.show { display: block; /* Show the contact form when the 'showContactForm' flag is set */ } - -.property-filter { - margin-bottom: 20px; +.property-filter select, +.property-filter input[type="number"], +.property-filter input[type="text"] { + margin-right: 10px; + height: 30px; /* Set a fixed height for all input fields */ } - -.property-filter label { +.property-filter button { margin-right: 10px; } -.property-filter select, .property-filter input[type="number"] { - margin-right: 10px; + max-width: 100px; /* Limit the width of the number field */ +} + +.property-filter input[type="number"]::-webkit-inner-spin-button, +.property-filter input[type="number"]::-webkit-outer-spin-button { + -webkit-appearance: none; /* Remove the spinner arrows on number input */ + margin: 0; /* Remove default margin */ } .property-filter .apply-button { margin-left: 10px; + height: 30px; /* Set a fixed height for the apply button */ } /* Adjust text size based on screen size */ @@ -84,3 +91,24 @@ width: 100%; /* Set the width to 100% for single item on a row */ } } +.property-filter select, +.property-filter input[type="number"], +.property-filter input[type="text"] { + margin-right: 10px; + height: 30px; /* Set a fixed height for all input fields */ +} + +.property-filter input[type="number"] { + max-width: 100px; /* Limit the width of the number field */ +} + +.property-filter input[type="number"]::-webkit-inner-spin-button, +.property-filter input[type="number"]::-webkit-outer-spin-button { + -webkit-appearance: none; /* Remove the spinner arrows on number input */ + margin: 0; /* Remove default margin */ +} + +.property-filter .apply-button { + margin-left: 10px; + height: 30px; /* Set a fixed height for the apply button */ +} diff --git a/angular/src/app/property-list/property-list.component.html b/angular/src/app/property-list/property-list.component.html index 644ed35..76f7e43 100644 --- a/angular/src/app/property-list/property-list.component.html +++ b/angular/src/app/property-list/property-list.component.html @@ -3,16 +3,16 @@

Properties

- + City: - + - + + - +

+
+ + + + + +
-
@@ -34,6 +41,7 @@

Properties

{{ property.city }} - {{ property.propertyType }}

{{ property.title }}, {{ property.postalCode }}

+

Area (sqm): {{ property.areaSqm }}

Rent: € {{ property.rent }}

Additional Costs: € {{ property.additionalCosts }}

Deposit: € {{ property.deposit }}

@@ -52,7 +60,7 @@

Properties

{{ property.descriptionTranslated }}

-

Area (sqm): {{ property.areaSqm }}

+

Furnish: {{ property.furnish }}

+

Is Room Active: {{ property.isRoomActive }}

Kitchen: {{ property.kitchen }}

Living: {{ property.living }}

Match Age: {{ property.matchAge }}

diff --git a/angular/src/app/property-list/property-list.component.ts b/angular/src/app/property-list/property-list.component.ts index 5f94bf4..cdc8e83 100644 --- a/angular/src/app/property-list/property-list.component.ts +++ b/angular/src/app/property-list/property-list.component.ts @@ -48,6 +48,8 @@ export class PropertyListComponent implements OnInit { selectedGender: string = ''; id: number = 2; distinctCities: string[] = []; + showFilterButtons: boolean = false; + currentPage = 1; constructor( private http: HttpClient, @@ -59,9 +61,11 @@ export class PropertyListComponent implements OnInit { } ngOnInit(): void { - this.applyFilters(); + this.applyInit(); this.getDistinctCities(); + this.selectedCity = this.distinctCities.length > 0 ? '' : 'All Cities'; } + onCitySelect(event: any) { this.selectedCity = event.target.value; } @@ -84,7 +88,7 @@ export class PropertyListComponent implements OnInit { (data: { cities: string[] }) => { this.distinctCities = data.toString().split(","); //data.split(","); if (this.distinctCities.length > 0) { - this.selectedCity = "all cities"; + this.selectedCity = "All Cities"; } }, error => { @@ -93,13 +97,33 @@ export class PropertyListComponent implements OnInit { ); } + applyInit(): void { + console.log('Apply Filters clicked'); + const apiUrl = 'http://localhost:8080/property'; + const params: any = {}; + + if (this.selectedCity && this.selectedCity !== 'All Cities') { + params.city = this.selectedCity; + } + // Make the API call with the updated URL and query parameters + this.http.get>(apiUrl, { params }).subscribe( + (data: Page) => { + console.log(data); // Log the API response + this.properties = data; + this.properties.content = this.properties.content.slice(0, 100); + }, + (error) => { + console.error('Error retrieving properties:', error); + } + ); + } applyFilters(): void { console.log('Apply Filters clicked'); const apiUrl = 'http://localhost:8080/property'; const params: any = {}; - if (this.selectedCity) { + if (this.selectedCity && this.selectedCity !== 'All Cities') { params.city = this.selectedCity; } @@ -121,7 +145,7 @@ export class PropertyListComponent implements OnInit { this.properties.content = this.properties.content.filter(property => { let meetsCriteria = true; - if (this.selectedCity && property.city !== this.selectedCity) { + if (this.selectedCity && this.selectedCity !== 'All Cities' && property.city !== this.selectedCity) { meetsCriteria = false; } @@ -137,6 +161,9 @@ export class PropertyListComponent implements OnInit { }); this.properties.content = this.properties.content.slice(0, 100); + + // Set the flag to show the filter buttons only after the "Apply Filters" button is clicked + this.showFilterButtons = true; }, (error) => { console.error('Error retrieving properties:', error); @@ -145,6 +172,119 @@ export class PropertyListComponent implements OnInit { } + filterRentDown(topN: number): void { + if (this.selectedCity && this.selectedCity !== 'All Cities') { + const apiUrl = 'http://localhost:8080/property'; + const params: any = { + city: this.selectedCity + }; + + // Make the API call with the updated URL and query parameters + this.http.get>(apiUrl, { params }).pipe( + map((data: Page) => { + // Sort the properties based on rent in descending order + data.content.sort((a, b) => b.rent - a.rent); + return data; + }), + tap((data: Page) => { + // Get the top N properties + this.properties.content = data.content.slice(0, topN); + }), + catchError((error) => { + console.error('Error retrieving properties:', error); + return of(null); + }) + ).subscribe(); + } + } + + filterRentUp(topN: number): void { + if (this.selectedCity && this.selectedCity !== 'All Cities') { + const apiUrl = 'http://localhost:8080/property'; + const params: any = { + city: this.selectedCity + }; + + // Make the API call with the updated URL and query parameters + this.http.get>(apiUrl, { params }).pipe( + map((data: Page) => { + // Sort the properties based on rent in ascending order + data.content.sort((a, b) => a.rent - b.rent); + return data; + }), + tap((data: Page) => { + // Get the top N properties + this.properties.content = data.content.slice(0, topN); + }), + catchError((error) => { + console.error('Error retrieving properties:', error); + return of(null); + }) + ).subscribe(); + } + } + filterSqmUp(topN: number): void { + if (this.selectedCity && this.selectedCity !== 'All Cities') { + const apiUrl = 'http://localhost:8080/property'; + const params: any = { + city: this.selectedCity + }; + + // Make the API call with the updated URL and query parameters + this.http.get>(apiUrl, { params }).pipe( + map((data: Page) => { + // Calculate rent per sqm for each property + data.content.forEach(property => { + property.rentPerSqm = property.rent / property.areaSqm; + }); + // Sort the properties based on rent per sqm in ascending order + data.content.sort((a, b) => a.rentPerSqm - b.rentPerSqm); + + return data; + }), + tap((data: Page) => { + // Get the top N properties + this.properties.content = data.content.slice(0, topN); + }), + catchError((error) => { + console.error('Error retrieving properties:', error); + return of(null); + }) + ).subscribe(); + } + } + + filterSqmDown(topN: number): void { + if (this.selectedCity && this.selectedCity !== 'All Cities') { + const apiUrl = 'http://localhost:8080/property'; + const params: any = { + city: this.selectedCity + }; + + // Make the API call with the updated URL and query parameters + this.http.get>(apiUrl, { params }).pipe( + map((data: Page) => { + // Calculate rent per sqm for each property + data.content.forEach(property => { + property.rentPerSqm = property.rent / property.areaSqm; + }); + + // Sort the properties based on rent per sqm in descending order + data.content.sort((a, b) => b.rentPerSqm - a.rentPerSqm); + + return data; + }), + tap((data: Page) => { + // Get the top N properties + this.properties.content = data.content.slice(0, topN); + }), + catchError((error) => { + console.error('Error retrieving properties:', error); + return of(null); + }) + ).subscribe(); + } + } } diff --git a/src/main/java/com/example/studenthousing/AppConfig.java b/src/main/java/com/example/studenthousing/AppConfig.java index a618c4d..254e037 100644 --- a/src/main/java/com/example/studenthousing/AppConfig.java +++ b/src/main/java/com/example/studenthousing/AppConfig.java @@ -1,6 +1,5 @@ package com.example.studenthousing; import javax.persistence.EntityManagerFactory; - import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @@ -8,11 +7,13 @@ import org.springframework.orm.jpa.LocalEntityManagerFactoryBean; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.beans.factory.annotation.Value; @Configuration @EnableJpaRepositories(basePackages = {"com.example.studenthousing"}) public class AppConfig { + @Bean public LocalEntityManagerFactoryBean entityManagerFactory() { LocalEntityManagerFactoryBean factoryBean = new LocalEntityManagerFactoryBean(); @@ -37,9 +38,9 @@ public PasswordEncoder encoder() { @Configuration public class EmailConfig { - private final String senderEmail = "your-sender-email@example.com"; // Replace with your sender email - private final String senderPassword = "your-sender-password"; // Replace with your sender email password - private final String smtpHost = "your-smtp-host"; // Replace with your SMTP host (e.g., "smtp.gmail.com") + private final String senderEmail = "codegorilla9@gmail.com"; // Replace with your sender email + private final String senderPassword = "CGA@2023"; // Replace with your sender email password + private final String smtpHost = "smtp.gmail.com"; // Replace with your SMTP host (e.g., "smtp.gmail.com") private final int smtpPort = 587; // Replace with your SMTP port (e.g., 587 for TLS) @Bean diff --git a/src/main/java/com/example/studenthousing/controller/ContactFormController.java b/src/main/java/com/example/studenthousing/controller/ContactFormController.java index 896ba58..7ea767a 100644 --- a/src/main/java/com/example/studenthousing/controller/ContactFormController.java +++ b/src/main/java/com/example/studenthousing/controller/ContactFormController.java @@ -23,7 +23,7 @@ public ContactFormController(EmailSender emailSender) { @PostMapping("/contact") public ResponseEntity submitContactForm(@RequestBody ContactForm contactForm) { try { - String recipientEmail = "your-email@example.com"; // Replace with your desired recipient email address + String recipientEmail = "codegorilla9@gmail.com"; // Replace with your desired recipient email address String subject = "New Contact Form Submission"; String body = "Name: " + contactForm.getName() + "\n" + "Email: " + contactForm.getEmail() + "\n" diff --git a/src/main/java/com/example/studenthousing/repository/PropertyRepository.java b/src/main/java/com/example/studenthousing/repository/PropertyRepository.java index ce98933..447fb07 100644 --- a/src/main/java/com/example/studenthousing/repository/PropertyRepository.java +++ b/src/main/java/com/example/studenthousing/repository/PropertyRepository.java @@ -12,12 +12,15 @@ public interface PropertyRepository extends JpaRepository { @Query("SELECT p FROM Property p ORDER BY p.id ASC") List findFirst10Properties(Pageable pageable); + Optional findPropertyById(int id); - @Query("SELECT DISTINCT p.city FROM Property p ORDER BY p.city asc") + + @Query("SELECT DISTINCT p.city FROM Property p ORDER BY p.city ASC ") List findAllDistinctCities(); - @Query("SELECT p FROM Property p WHERE p.city = :city") - Page findByCity(@Param("city") String city, Pageable pageable); - @Query("SELECT p FROM Property p ORDER BY p.id ASC") - Page findById(@Param("id") Integer id, Pageable pageable); -} \ No newline at end of file + @Query("SELECT p FROM Property p WHERE p.city = :city ORDER BY p.rent ASC ") + Page findByCity(@Param("city") String city, Pageable pageable); + + @Query("SELECT p FROM Property p WHERE p.id = :id") + Page findById(@Param("id") Integer id, Pageable pageable); +} diff --git a/src/main/java/com/example/studenthousing/services/EmailService.java b/src/main/java/com/example/studenthousing/services/EmailService.java new file mode 100644 index 0000000..78ed78e --- /dev/null +++ b/src/main/java/com/example/studenthousing/services/EmailService.java @@ -0,0 +1,31 @@ +package com.example.studenthousing.services; + +import com.example.studenthousing.EmailSender; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.mail.MessagingException; + +@Service +public class EmailService { + + private final EmailSender emailSender; + + @Autowired + public EmailService(EmailSender emailSender) { + this.emailSender = emailSender; + } + + public void sendMyEmail() { + String recipientEmail = "recipient@example.com"; + String subject = "Hello"; + String body = "This is the email body."; + + try { + emailSender.sendEmail(recipientEmail, subject, body); + System.out.println("Email sent successfully."); + } catch (MessagingException e) { + System.out.println("Failed to send email: " + e.getMessage()); + } + } +}