This commit is contained in:
2025-04-06 21:49:44 +02:00
parent 7d64ee11bf
commit 466e1dcdce
44 changed files with 1780 additions and 1520 deletions

View File

@@ -29,14 +29,24 @@
</div>
<div class="py-4 print:hidden">
@if(listing && listingUser && (listingUser?.email===user?.email || (authService.isAdmin() | async))){
<div class="inline">
<!-- <div class="inline">
<button class="share share-edit text-white font-bold text-xs py-1.5 px-2 inline-flex items-center" [routerLink]="['/editBusinessListing', listing.id]">
<i class="fa-regular fa-pen-to-square"></i>
<span class="ml-2">Edit</span>
</button>
</div> -->
<div class="inline">
<button [routerLink]="['/editBusinessListing', listing.id]" class="sb-wrapper sb-show-icon sb-show-text" style="--button-color: #0088cc" aria-label="Share by email">
<div class="sb-content">
<div class="sb-icon">
<i class="fa-solid fa-envelope fa-fw"></i>
</div>
<div class="sb-text">Edit</div>
</div>
</button>
</div>
} @if(user){
<div class="inline">
<!-- <div class="inline">
<button class="share share-save text-white font-bold text-xs py-1.5 px-2 inline-flex items-center" (click)="save()" [disabled]="listing.favoritesForUser.includes(user.email)">
<i class="fa-regular fa-heart"></i>
@if(listing.favoritesForUser.includes(user.email)){
@@ -45,14 +55,31 @@
<span class="ml-2">Save</span>
}
</button>
</div> -->
<div class="inline">
<button class="sb-wrapper sb-show-icon sb-show-text" style="--button-color: #e60023" (click)="save()" aria-label="Share by email">
<div class="sb-content">
<div class="sb-icon">
<i class="fa-solid fa-envelope fa-fw"></i>
</div>
@if(listing.favoritesForUser.includes(user.email)){
<div class="sb-text">Saved ...</div>
}@else {
<div class="sb-text">Save</div>
}
</div>
</button>
</div>
}
<share-button button="print" showText="true" (click)="createEvent('print')"></share-button>
<!-- <share-button button="email" showText="true"></share-button> -->
<div class="inline">
<button class="share share-email text-white font-bold text-xs py-1.5 px-2 inline-flex items-center" (click)="showShareByEMail()">
<i class="fa-solid fa-envelope"></i>
<span class="ml-2">Email</span>
<button class="sb-wrapper sb-show-icon sb-show-text" style="--button-color: #ff961c" (click)="showShareByEMail()" aria-label="Share by email">
<div class="sb-content">
<div class="sb-icon">
<i class="fa-solid fa-envelope fa-fw"></i>
</div>
<div class="sb-text">Email</div>
</div>
</button>
</div>
@@ -68,26 +95,180 @@
</div>
<!-- Right column -->
<!-- Kontaktformular mit konsistenten Höhen und Breiten -->
<!-- Kontaktformular mit konsistenten Höhen und Breiten -->
<div class="w-full lg:w-1/2 mt-6 lg:mt-0 print:hidden">
<!-- <h2 class="text-lg font-semibold my-4">Contact the Author of this Listing</h2> -->
<div class="md:mt-8 mb-4 text-2xl font-bold mb-4">Contact the Author of this Listing</div>
<p class="text-sm mb-4">Please include your contact info below</p>
<form class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<app-validated-input label="Your Name" name="name" [(ngModel)]="mailinfo.sender.name"></app-validated-input>
<app-validated-input label="Your Email" name="email" [(ngModel)]="mailinfo.sender.email" kind="email"></app-validated-input>
<div class="md:mt-8 mb-4 text-2xl font-bold">Contact the Author of this Listing</div>
<p class="text-sm mb-6">Please include your contact info below</p>
<form class="space-y-6">
<!-- Erste Zeile: Name und E-Mail -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Name Eingabe -->
<div>
<label for="name" class="block text-gray-700 mb-2 font-medium flex items-center">
Your Name
<div *ngIf="validationService.hasMessage('name')" class="ml-2 relative group">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
<div class="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 hidden group-hover:block bg-gray-800 text-white text-xs px-2 py-1 rounded whitespace-nowrap">
{{ validationService.getMessage('name')?.message }}
</div>
</div>
</label>
<div class="relative">
<input
id="name"
name="name"
type="text"
[(ngModel)]="mailinfo.sender.name"
placeholder="Enter your name"
class="w-full px-3 py-3 pl-10 border border-gray-300 rounded-lg focus:outline-none focus:border-black focus:ring-0"
[class.border-red-500]="validationService.hasMessage('name')"
/>
<svg xmlns="http://www.w3.org/2000/svg" class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
</div>
</div>
<!-- E-Mail Eingabe -->
<div>
<label for="email" class="block text-gray-700 mb-2 font-medium flex items-center">
Your Email
<div *ngIf="validationService.hasMessage('email')" class="ml-2 relative group">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
<div class="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 hidden group-hover:block bg-gray-800 text-white text-xs px-2 py-1 rounded whitespace-nowrap">
{{ validationService.getMessage('email')?.message }}
</div>
</div>
</label>
<div class="relative">
<input
id="email"
name="email"
type="email"
[(ngModel)]="mailinfo.sender.email"
placeholder="Enter your email"
class="w-full px-3 py-3 pl-10 border border-gray-300 rounded-lg focus:outline-none focus:border-black focus:ring-0"
[class.border-red-500]="validationService.hasMessage('email')"
/>
<svg xmlns="http://www.w3.org/2000/svg" class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
</div>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<app-validated-input label="Phone Number" name="phoneNumber" [(ngModel)]="mailinfo.sender.phoneNumber" mask="(000) 000-0000"></app-validated-input>
<!-- <app-validated-input label="Country/State" name="state" [(ngModel)]="mailinfo.sender.state"></app-validated-input> -->
<app-validated-ng-select label="State" name="state" [(ngModel)]="mailinfo.sender.state" [items]="selectOptions?.states"></app-validated-ng-select>
<!-- Zweite Zeile: Telefon und Bundesland -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Telefon Eingabe -->
<div>
<label for="phone" class="block text-gray-700 mb-2 font-medium flex items-center">
Phone Number
<div *ngIf="validationService.hasMessage('phoneNumber')" class="ml-2 relative group">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
<div class="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 hidden group-hover:block bg-gray-800 text-white text-xs px-2 py-1 rounded whitespace-nowrap">
{{ validationService.getMessage('phoneNumber')?.message }}
</div>
</div>
</label>
<div class="relative">
<input
id="phone"
name="phoneNumber"
type="tel"
[(ngModel)]="mailinfo.sender.phoneNumber"
mask="(000) 000-0000"
placeholder="(123) 456-7890"
class="w-full px-3 py-3 pl-10 border border-gray-300 rounded-lg focus:outline-none focus:border-black focus:ring-0"
[class.border-red-500]="validationService.hasMessage('phoneNumber')"
/>
<svg xmlns="http://www.w3.org/2000/svg" class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"
/>
</svg>
</div>
</div>
<!-- Bundesland Select -->
<div>
<label for="state" class="block text-gray-700 mb-2 font-medium flex items-center">
State
<div *ngIf="validationService.hasMessage('state')" class="ml-2 relative group">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
<div class="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 hidden group-hover:block bg-gray-800 text-white text-xs px-2 py-1 rounded whitespace-nowrap">
{{ validationService.getMessage('state')?.message }}
</div>
</div>
</label>
<div class="relative">
<select
id="state"
name="state"
[(ngModel)]="mailinfo.sender.state"
class="w-full px-3 py-3 pl-10 border border-gray-300 rounded-lg bg-white focus:outline-none focus:border-black focus:ring-0 appearance-none"
[class.border-red-500]="validationService.hasMessage('state')"
>
<option value="" disabled selected>Select your state</option>
<option *ngFor="let state of selectOptions?.states" [value]="state.value">{{ state.name }}</option>
</select>
<svg xmlns="http://www.w3.org/2000/svg" class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 21v-4m0 0V5a2 2 0 012-2h6.5l1 1H21l-3 6 3 6h-8.5l-1-1H5a2 2 0 00-2 2zm9-13.5V9" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" class="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5 pointer-events-none" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</div>
</div>
</div>
<!-- Kommentarfeld -->
<div>
<app-validated-textarea label="Questions/Comments" name="comments" [(ngModel)]="mailinfo.sender.comments"></app-validated-textarea>
<label for="comments" class="block text-gray-700 mb-2 font-medium flex items-center">
Questions/Comments
<div *ngIf="validationService.hasMessage('comments')" class="ml-2 relative group">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
<div class="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 hidden group-hover:block bg-gray-800 text-white text-xs px-2 py-1 rounded whitespace-nowrap">
{{ validationService.getMessage('comments')?.message }}
</div>
</div>
</label>
<textarea
id="comments"
name="comments"
[(ngModel)]="mailinfo.sender.comments"
placeholder="Type your questions or comments here..."
rows="4"
class="w-full px-3 py-3 border border-gray-300 rounded-lg focus:outline-none focus:border-black focus:ring-0"
[class.border-red-500]="validationService.hasMessage('comments')"
></textarea>
</div>
<!-- Submit Button -->
<div>
<button (click)="mail()" class="w-full sm:w-auto px-6 py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 transition-colors duration-200">
<span class="flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
</svg>
Submit
</span>
</button>
</div>
<button (click)="mail()" class="w-full sm:w-auto px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50">Submit</button>
</form>
</div>
</div>

View File

@@ -14,10 +14,6 @@ import { BusinessListing, EventTypeEnum, ShareByEMail, User } from '../../../../
import { KeycloakUser, MailInfo } from '../../../../../bizmatch-server/src/models/main.model';
import { environment } from '../../../environments/environment';
import { EMailService } from '../../components/email/email.service';
import { ValidatedInputComponent } from '../../components/validated-input/validated-input.component';
import { ValidatedNgSelectComponent } from '../../components/validated-ng-select/validated-ng-select.component';
import { ValidatedTextareaComponent } from '../../components/validated-textarea/validated-textarea.component';
import { ValidationMessagesService } from '../../components/validation-messages.service';
import { AuditService } from '../../services/audit.service';
import { AuthService } from '../../services/auth.service';
import { GeoService } from '../../services/geo.service';
@@ -27,14 +23,56 @@ import { MailService } from '../../services/mail.service';
import { MessageService } from '../../services/message.service';
import { SelectOptionsService } from '../../services/select-options.service';
import { UserService } from '../../services/user.service';
import { ValidationService } from '../../services/validation.service';
import { createMailInfo, map2User } from '../../utils/utils';
@Component({
selector: 'app-details-business-listing',
standalone: true,
imports: [CommonModule, FormsModule, RouterModule, FontAwesomeModule, ValidatedInputComponent, ValidatedTextareaComponent, ShareButton, ValidatedNgSelectComponent],
imports: [CommonModule, FormsModule, RouterModule, FontAwesomeModule, ShareButton],
providers: [],
templateUrl: './details-business-listing.component.html',
styles: `
.inline .sb-wrapper {
margin: var(--sb-margin, .3125em);
padding: var(--sb-padding, 0);
min-width: var(--sb-min-width, 4.125em);
height: var(--sb-height, 2.5em);
color: var(--sb-color, #fff);
background: var(--sb-background);
font-size: var(--sb-font-size, 13px);
line-height: var(--sb-line-height, 2.571em);
border: var(--sb-border);
border-radius: var(--sb-border-radius, 4px);
transition: var(--sb-transition);
box-shadow: var(--sb-box-shadow);
text-shadow: var(--sb-text-shadow);
overflow: var(--sb-overflow, hidden);
--sb-color: #fff;
--sb-background: var(--button-color);
cursor: pointer;
position: relative;
outline: 0;
}
.inline .sb-content {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: 0 1em;
}
.inline .sb-icon {
display: flex;
align-items: center;
}
.inline .sb-text {
margin-left: 0.5em;
font-weight: bold;
}
`,
})
export class DetailsBusinessListingComponent {
// listings: Array<BusinessListing>;
@@ -76,13 +114,13 @@ export class DetailsBusinessListingComponent {
private mailService: MailService,
private sanitizer: DomSanitizer,
public historyService: HistoryService,
private validationMessagesService: ValidationMessagesService,
private messageService: MessageService,
private auditService: AuditService,
public emailService: EMailService,
private geoService: GeoService,
public authService: AuthService,
private cdref: ChangeDetectorRef,
public validationService: ValidationService,
) {
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
@@ -112,7 +150,7 @@ export class DetailsBusinessListingComponent {
}
ngOnDestroy() {
this.validationMessagesService.clearMessages(); // Löschen Sie alle bestehenden Validierungsnachrichten
this.validationService.clearMessages(); // Löschen Sie alle bestehenden Validierungsnachrichten
}
async mail() {
@@ -120,7 +158,7 @@ export class DetailsBusinessListingComponent {
this.mailinfo.email = this.listingUser.email;
this.mailinfo.listing = this.listing;
await this.mailService.mail(this.mailinfo);
this.validationMessagesService.clearMessages();
this.validationService.clearMessages();
this.auditService.createEvent(this.listing.id, 'contact', this.user?.email, this.mailinfo.sender);
this.messageService.addMessage({ severity: 'success', text: 'Your message has been sent to the creator of the listing', duration: 3000 });
this.mailinfo = createMailInfo(this.user);
@@ -130,9 +168,7 @@ export class DetailsBusinessListingComponent {
text: 'An error occurred while sending the request - Please check your inputs',
duration: 5000,
});
if (error.error && Array.isArray(error.error?.message)) {
this.validationMessagesService.updateMessages(error.error.message);
}
this.validationService.handleApiError(error.error);
}
}
get listingDetails() {