Feture #52: Social Media Integration, BugFix: #89 Sates as ng-select, send Listing as EMail to friend
This commit is contained in:
parent
630c31cfc9
commit
f4f576d4a9
|
|
@ -1,5 +1,5 @@
|
||||||
import { Body, Controller, Post } from '@nestjs/common';
|
import { Body, Controller, Post } from '@nestjs/common';
|
||||||
import { User } from 'src/models/db.model';
|
import { ShareByEMail, User } from 'src/models/db.model';
|
||||||
import { ErrorResponse, MailInfo } from '../models/main.model';
|
import { ErrorResponse, MailInfo } from '../models/main.model';
|
||||||
import { MailService } from './mail.service.js';
|
import { MailService } from './mail.service.js';
|
||||||
|
|
||||||
|
|
@ -18,4 +18,8 @@ export class MailController {
|
||||||
sendSubscriptionConfirmation(@Body() user: User): Promise<void | ErrorResponse> {
|
sendSubscriptionConfirmation(@Body() user: User): Promise<void | ErrorResponse> {
|
||||||
return this.mailService.sendSubscriptionConfirmation(user);
|
return this.mailService.sendSubscriptionConfirmation(user);
|
||||||
}
|
}
|
||||||
|
@Post('send2Friend')
|
||||||
|
send2Friend(@Body() shareByEMail: ShareByEMail): Promise<void | ErrorResponse> {
|
||||||
|
return this.mailService.send2Friend(shareByEMail);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
import path, { join } from 'path';
|
import path, { join } from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { ZodError } from 'zod';
|
import { ZodError } from 'zod';
|
||||||
import { SenderSchema, User } from '../models/db.model.js';
|
import { SenderSchema, ShareByEMail, ShareByEMailSchema, User } from '../models/db.model.js';
|
||||||
import { ErrorResponse, MailInfo, isEmpty } from '../models/main.model.js';
|
import { ErrorResponse, MailInfo, isEmpty } from '../models/main.model.js';
|
||||||
import { UserService } from '../user/user.service.js';
|
import { UserService } from '../user/user.service.js';
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
|
@ -96,4 +96,33 @@ export class MailService {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
async send2Friend(shareByEMail: ShareByEMail): Promise<void | ErrorResponse> {
|
||||||
|
try {
|
||||||
|
const validatedSender = ShareByEMailSchema.parse(shareByEMail);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof ZodError) {
|
||||||
|
const formattedErrors = error.errors.map(err => ({
|
||||||
|
field: err.path.join('.'),
|
||||||
|
message: err.message,
|
||||||
|
}));
|
||||||
|
throw new BadRequestException(formattedErrors);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
await this.mailerService.sendMail({
|
||||||
|
to: shareByEMail.recipientEmail,
|
||||||
|
from: `"Bizmatch.net" <info@bizmatch.net>`,
|
||||||
|
subject: `${shareByEMail.type === 'business' ? 'Business' : 'Commercial Property'} For Sale: ${shareByEMail.listingTitle}`,
|
||||||
|
//template: './inquiry', // `.hbs` extension is appended automatically
|
||||||
|
template: join(__dirname, '../..', 'mail/templates/send2Friend.hbs'),
|
||||||
|
context: {
|
||||||
|
name: shareByEMail.name,
|
||||||
|
email: shareByEMail.email,
|
||||||
|
listingTitle: shareByEMail.listingTitle,
|
||||||
|
url: shareByEMail.url,
|
||||||
|
id: shareByEMail.id,
|
||||||
|
type: shareByEMail.type,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Notification</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
color: #333333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.email-container {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 20px auto;
|
||||||
|
background-color: #ffffff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid #dddddd;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.content p {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.content .plan-info {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #0056b3;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
margin-top: 30px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #888888;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="email-container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>Notification</h1>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<p>Hello,</p>
|
||||||
|
|
||||||
|
<p>Your friend {{name}} ({{email}}) believed you might find this <b>{{#if (eq type "commercialProperty")}}Commercial Property{{else if (eq type "business")}}Business{{/if}} for sale listing </b> on <a href="{{url}}">bizmatch.net</a> interesting.</p>
|
||||||
|
|
||||||
|
<span class="info-value"><a href="{{url}}/listing/{{id}}">{{listingTitle}}</a></span>
|
||||||
|
|
||||||
|
<p>Bizmatch is one of the most reliable platforms for buying and selling businesses.</p>
|
||||||
|
|
||||||
|
<p>Best regards,</p>
|
||||||
|
<p>The Bizmatch Support Team</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p>© 2024 Bizmatch. All rights reserved.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -301,3 +301,13 @@ export const SenderSchema = z.object({
|
||||||
comments: z.string().min(10, { message: 'Comments must be at least 10 characters long' }),
|
comments: z.string().min(10, { message: 'Comments must be at least 10 characters long' }),
|
||||||
});
|
});
|
||||||
export type Sender = z.infer<typeof SenderSchema>;
|
export type Sender = z.infer<typeof SenderSchema>;
|
||||||
|
export const ShareByEMailSchema = z.object({
|
||||||
|
name: z.string().min(6, { message: 'Name must be at least 6 characters long' }),
|
||||||
|
recipientEmail: z.string().email({ message: 'Invalid email address' }),
|
||||||
|
email: z.string().email({ message: 'Invalid email address' }),
|
||||||
|
listingTitle: z.string().optional().nullable(),
|
||||||
|
url: z.string().url({ message: 'Invalid URL format' }).optional().nullable(),
|
||||||
|
id: z.string().optional().nullable(),
|
||||||
|
type: ListingsCategoryEnum,
|
||||||
|
});
|
||||||
|
export type ShareByEMail = z.infer<typeof ShareByEMailSchema>;
|
||||||
|
|
|
||||||
|
|
@ -36,3 +36,4 @@
|
||||||
<app-message-container></app-message-container>
|
<app-message-container></app-message-container>
|
||||||
<app-search-modal></app-search-modal>
|
<app-search-modal></app-search-modal>
|
||||||
<app-confirmation></app-confirmation>
|
<app-confirmation></app-confirmation>
|
||||||
|
<app-email></app-email>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { filter } from 'rxjs/operators';
|
||||||
import build from '../build';
|
import build from '../build';
|
||||||
import { ConfirmationComponent } from './components/confirmation/confirmation.component';
|
import { ConfirmationComponent } from './components/confirmation/confirmation.component';
|
||||||
import { ConfirmationService } from './components/confirmation/confirmation.service';
|
import { ConfirmationService } from './components/confirmation/confirmation.service';
|
||||||
|
import { EMailComponent } from './components/email/email.component';
|
||||||
import { FooterComponent } from './components/footer/footer.component';
|
import { FooterComponent } from './components/footer/footer.component';
|
||||||
import { HeaderComponent } from './components/header/header.component';
|
import { HeaderComponent } from './components/header/header.component';
|
||||||
import { MessageContainerComponent } from './components/message/message-container.component';
|
import { MessageContainerComponent } from './components/message/message-container.component';
|
||||||
|
|
@ -17,7 +18,7 @@ import { UserService } from './services/user.service';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, RouterOutlet, HeaderComponent, FooterComponent, MessageContainerComponent, SearchModalComponent, ConfirmationComponent],
|
imports: [CommonModule, RouterOutlet, HeaderComponent, FooterComponent, MessageContainerComponent, SearchModalComponent, ConfirmationComponent, EMailComponent],
|
||||||
providers: [],
|
providers: [],
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrl: './app.component.scss',
|
styleUrl: './app.component.scss',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<!-- Main modal -->
|
||||||
|
<div *ngIf="eMailService.modalVisible$ | async" id="authentication-modal" tabindex="-1" class="z-40 fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full flex items-center justify-center">
|
||||||
|
<div class="relative p-4 w-full max-w-md max-h-full">
|
||||||
|
<!-- Modal content -->
|
||||||
|
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
|
||||||
|
<!-- Modal header -->
|
||||||
|
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
|
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-white">Email listing to a friend</h3>
|
||||||
|
<button
|
||||||
|
(click)="eMailService.reject()"
|
||||||
|
type="button"
|
||||||
|
class="end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white"
|
||||||
|
>
|
||||||
|
<svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
|
||||||
|
</svg>
|
||||||
|
<span class="sr-only">Close modal</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Modal body -->
|
||||||
|
<div class="p-4 md:p-5">
|
||||||
|
<form class="space-y-4" action="#">
|
||||||
|
<div>
|
||||||
|
<app-validated-input label="Your Email" name="email" [(ngModel)]="shareByEMail.email"></app-validated-input>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<app-validated-input label="Your Name" name="name" [(ngModel)]="shareByEMail.name"></app-validated-input>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<app-validated-input label="Your Friend's EMail" name="recipientEmail" [(ngModel)]="shareByEMail.recipientEmail"></app-validated-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
(click)="sendMail()"
|
||||||
|
class="w-full text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
|
||||||
|
>
|
||||||
|
Send EMail
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
|
import { ShareByEMail } from '../../../../../bizmatch-server/src/models/db.model';
|
||||||
|
import { MailService } from '../../services/mail.service';
|
||||||
|
import { ValidatedInputComponent } from '../validated-input/validated-input.component';
|
||||||
|
import { ValidationMessagesService } from '../validation-messages.service';
|
||||||
|
import { EMailService } from './email.service';
|
||||||
|
|
||||||
|
@UntilDestroy()
|
||||||
|
@Component({
|
||||||
|
selector: 'app-email',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, FormsModule, ValidatedInputComponent],
|
||||||
|
templateUrl: './email.component.html',
|
||||||
|
template: ``,
|
||||||
|
})
|
||||||
|
export class EMailComponent {
|
||||||
|
shareByEMail: ShareByEMail = {};
|
||||||
|
constructor(public eMailService: EMailService, private mailService: MailService, private validationMessagesService: ValidationMessagesService) {}
|
||||||
|
ngOnInit() {
|
||||||
|
this.eMailService.shareByEMail$.pipe(untilDestroyed(this)).subscribe(val => {
|
||||||
|
this.shareByEMail = val;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async sendMail() {
|
||||||
|
try {
|
||||||
|
const result = await this.mailService.mailToFriend(this.shareByEMail);
|
||||||
|
this.eMailService.accept();
|
||||||
|
} catch (error) {
|
||||||
|
if (error.error && Array.isArray(error.error?.message)) {
|
||||||
|
this.validationMessagesService.updateMessages(error.error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.validationMessagesService.clearMessages(); // Löschen Sie alle bestehenden Validierungsnachrichten
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
|
import { ShareByEMail } from '../../../../../bizmatch-server/src/models/db.model';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class EMailService {
|
||||||
|
private modalVisibleSubject = new BehaviorSubject<boolean>(false);
|
||||||
|
private shareByEMailSubject = new BehaviorSubject<ShareByEMail>({});
|
||||||
|
private resolvePromise!: (value: boolean) => void;
|
||||||
|
|
||||||
|
modalVisible$: Observable<boolean> = this.modalVisibleSubject.asObservable();
|
||||||
|
shareByEMail$: Observable<ShareByEMail> = this.shareByEMailSubject.asObservable();
|
||||||
|
|
||||||
|
showShareByEMail(shareByEMail: ShareByEMail): Promise<boolean> {
|
||||||
|
this.shareByEMailSubject.next(shareByEMail);
|
||||||
|
this.modalVisibleSubject.next(true);
|
||||||
|
return new Promise<boolean>(resolve => {
|
||||||
|
this.resolvePromise = resolve;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
accept(): void {
|
||||||
|
this.modalVisibleSubject.next(false);
|
||||||
|
this.resolvePromise(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
reject(): void {
|
||||||
|
this.modalVisibleSubject.next(false);
|
||||||
|
this.resolvePromise(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
<share-button button="print" showText="true"></share-button>
|
<share-button button="print" showText="true"></share-button>
|
||||||
<!-- <share-button button="email" showText="true"></share-button> -->
|
<!-- <share-button button="email" showText="true"></share-button> -->
|
||||||
<div class="inline">
|
<div class="inline">
|
||||||
<button class="share share-email text-white font-bold text-xs py-1.5 px-2 inline-flex items-center">
|
<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>
|
<i class="fa-solid fa-envelope"></i>
|
||||||
<span class="ml-2">Email</span>
|
<span class="ml-2">Email</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -56,14 +56,6 @@
|
||||||
<share-button button="x" showText="true"></share-button>
|
<share-button button="x" showText="true"></share-button>
|
||||||
<share-button button="linkedin" showText="true"></share-button>
|
<share-button button="linkedin" showText="true"></share-button>
|
||||||
</div>
|
</div>
|
||||||
<!-- @if(listing && listingUser && (listingUser?.email===user?.email || isAdmin())){
|
|
||||||
<button
|
|
||||||
[routerLink]="['/editBusinessListing', listing.id]"
|
|
||||||
class="w-full sm:w-auto px-4 py-2 mt-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"
|
|
||||||
>
|
|
||||||
Edit
|
|
||||||
</button>
|
|
||||||
} -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right column -->
|
<!-- Right column -->
|
||||||
|
|
@ -77,8 +69,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<app-validated-input label="Phone Number" name="phoneNumber" [(ngModel)]="mailinfo.sender.phoneNumber" kind="tel"></app-validated-input>
|
<app-validated-input label="Phone Number" name="phoneNumber" [(ngModel)]="mailinfo.sender.phoneNumber" kind="tel" mask="(000) 000-0000"></app-validated-input>
|
||||||
<app-validated-input label="Country/State" name="state" [(ngModel)]="mailinfo.sender.state"></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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,10 @@ import { lastValueFrom } from 'rxjs';
|
||||||
import { BusinessListing, User } from '../../../../../../bizmatch-server/src/models/db.model';
|
import { BusinessListing, User } from '../../../../../../bizmatch-server/src/models/db.model';
|
||||||
import { KeycloakUser, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model';
|
import { KeycloakUser, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||||
import { environment } from '../../../../environments/environment';
|
import { environment } from '../../../../environments/environment';
|
||||||
|
import { EMailService } from '../../../components/email/email.service';
|
||||||
import { MessageService } from '../../../components/message/message.service';
|
import { MessageService } from '../../../components/message/message.service';
|
||||||
import { ValidatedInputComponent } from '../../../components/validated-input/validated-input.component';
|
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 { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component';
|
||||||
import { ValidationMessagesService } from '../../../components/validation-messages.service';
|
import { ValidationMessagesService } from '../../../components/validation-messages.service';
|
||||||
import { HistoryService } from '../../../services/history.service';
|
import { HistoryService } from '../../../services/history.service';
|
||||||
|
|
@ -22,7 +24,7 @@ import { createMailInfo, map2User } from '../../../utils/utils';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-details-business-listing',
|
selector: 'app-details-business-listing',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [SharedModule, ValidatedInputComponent, ValidatedTextareaComponent, ShareButton],
|
imports: [SharedModule, ValidatedInputComponent, ValidatedTextareaComponent, ShareButton, ValidatedNgSelectComponent],
|
||||||
providers: [],
|
providers: [],
|
||||||
templateUrl: './details-business-listing.component.html',
|
templateUrl: './details-business-listing.component.html',
|
||||||
styleUrl: '../details.scss',
|
styleUrl: '../details.scss',
|
||||||
|
|
@ -70,6 +72,7 @@ export class DetailsBusinessListingComponent {
|
||||||
private validationMessagesService: ValidationMessagesService,
|
private validationMessagesService: ValidationMessagesService,
|
||||||
private messageService: MessageService,
|
private messageService: MessageService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
|
public emailService: EMailService,
|
||||||
) {
|
) {
|
||||||
this.router.events.subscribe(event => {
|
this.router.events.subscribe(event => {
|
||||||
if (event instanceof NavigationEnd) {
|
if (event instanceof NavigationEnd) {
|
||||||
|
|
@ -153,4 +156,21 @@ export class DetailsBusinessListingComponent {
|
||||||
isAlreadyFavorite() {
|
isAlreadyFavorite() {
|
||||||
return this.listing.favoritesForUser.includes(this.user.email);
|
return this.listing.favoritesForUser.includes(this.user.email);
|
||||||
}
|
}
|
||||||
|
async showShareByEMail() {
|
||||||
|
const result = await this.emailService.showShareByEMail({
|
||||||
|
email: this.user.email,
|
||||||
|
name: `${this.user.firstname} ${this.user.lastname}`,
|
||||||
|
url: environment.mailinfoUrl,
|
||||||
|
listingTitle: this.listing.title,
|
||||||
|
id: this.listing.id,
|
||||||
|
type: 'business',
|
||||||
|
});
|
||||||
|
if (result) {
|
||||||
|
this.messageService.addMessage({
|
||||||
|
severity: 'success',
|
||||||
|
text: 'Your Email has beend sent',
|
||||||
|
duration: 5000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,102 +1,3 @@
|
||||||
<!-- <div class="surface-ground h-full">
|
|
||||||
<div class="px-6 py-5">
|
|
||||||
<div class="surface-card p-4 shadow-2 border-round">
|
|
||||||
<div class="flex justify-content-between align-items-center align-content-center mb-2">
|
|
||||||
<div class="font-medium text-3xl text-900 mb-3">{{ listing?.title }}</div>
|
|
||||||
@if(historyService.canGoBack){
|
|
||||||
<p-button icon="pi pi-times" [rounded]="true" severity="danger" (click)="historyService.goBack()"></p-button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
@if(listing){
|
|
||||||
<div class="grid">
|
|
||||||
<div class="col-12 md:col-6">
|
|
||||||
<ul class="list-none p-0 m-0 border-top-1 border-300">
|
|
||||||
<li class="flex align-items-center py-3 px-2 flex-wrap">
|
|
||||||
<div class="text-500 w-full md:w-3 font-medium flex">Description</div>
|
|
||||||
<div class="text-900 w-full md:w-9 line-height-3" [innerHTML]="description"></div>
|
|
||||||
</li>
|
|
||||||
<li class="flex align-items-center py-3 px-2 flex-wrap surface-ground">
|
|
||||||
<div class="text-500 w-full md:w-3 font-medium">Property Category</div>
|
|
||||||
<div class="text-900 w-full md:w-9">{{ selectOptions.getCommercialProperty(listing.type) }}</div>
|
|
||||||
</li>
|
|
||||||
<li class="flex align-items-center py-3 px-2 flex-wrap">
|
|
||||||
<div class="text-500 w-full md:w-3 font-medium">Located in</div>
|
|
||||||
<div class="text-900 w-full md:w-9">{{ selectOptions.getState(listing.state) }}</div>
|
|
||||||
</li>
|
|
||||||
<li class="flex align-items-center py-3 px-2 flex-wrap surface-ground">
|
|
||||||
<div class="text-500 w-full md:w-3 font-medium">City</div>
|
|
||||||
<div class="text-900 w-full md:w-9">{{ listing.city }}</div>
|
|
||||||
</li>
|
|
||||||
<li class="flex align-items-center py-3 px-2 flex-wrap">
|
|
||||||
<div class="text-500 w-full md:w-3 font-medium">Zip Code</div>
|
|
||||||
<div class="text-900 w-full md:w-9">{{ listing.zipCode }}</div>
|
|
||||||
</li>
|
|
||||||
<li class="flex align-items-center py-3 px-2 flex-wrap surface-ground">
|
|
||||||
<div class="text-500 w-full md:w-3 font-medium">County</div>
|
|
||||||
<div class="text-900 w-full md:w-9">{{ listing.county }}</div>
|
|
||||||
</li>
|
|
||||||
<li class="flex align-items-center py-3 px-2 flex-wrap">
|
|
||||||
<div class="text-500 w-full md:w-3 font-medium">Asking Price:</div>
|
|
||||||
<div class="text-900 w-full md:w-9">{{ listing.price | currency }}</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
@if(listing && listingUser && (listingUser?.email===user?.email || isAdmin())){
|
|
||||||
<button pButton pRipple label="Edit" icon="pi pi-file-edit" class="w-auto" [routerLink]="['/editCommercialPropertyListing', listing.id]"></button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-12 md:col-6">
|
|
||||||
<p-galleria [value]="listing.imageOrder" [showIndicators]="true" [showThumbnails]="false" [responsiveOptions]="responsiveOptions" [containerStyle]="{ 'max-width': '640px' }" [numVisible]="5">
|
|
||||||
<ng-template pTemplate="item" let-item>
|
|
||||||
<img src="{{ env.imageBaseUrl }}/pictures/property/{{ listing.imagePath }}/{{ listing.serialId }}/{{ item }}" style="width: 100%" />
|
|
||||||
</ng-template>
|
|
||||||
</p-galleria>
|
|
||||||
@if (mailinfo){
|
|
||||||
<div class="surface-card p-4 border-round p-fluid">
|
|
||||||
<div class="font-medium text-xl text-primary text-900 mb-3">Contact the Author of this Listing</div>
|
|
||||||
<div class="font-italic text-sm text-900 mb-5">Please include your contact info below</div>
|
|
||||||
<div class="grid formgrid p-fluid">
|
|
||||||
<div class="field mb-4 col-12 md:col-6">
|
|
||||||
<label for="name" class="font-medium text-900">Your Name</label>
|
|
||||||
<input [ngClass]="{ 'ng-invalid': containsError('name'), 'ng-dirty': containsError('name') }" id="name" type="text" pInputText [(ngModel)]="mailinfo.sender.name" />
|
|
||||||
</div>
|
|
||||||
<div class="field mb-4 col-12 md:col-6">
|
|
||||||
<label for="email" class="font-medium text-900">Your Email</label>
|
|
||||||
<input id="email" type="text" pInputText [(ngModel)]="mailinfo.sender.email" />
|
|
||||||
</div>
|
|
||||||
<div class="field mb-4 col-12 md:col-6">
|
|
||||||
<label for="phoneNumber" class="font-medium text-900">Phone Number</label>
|
|
||||||
<p-inputMask mask="(999) 999-9999" placeholder="(123) 456-7890" [(ngModel)]="mailinfo.sender.phoneNumber"></p-inputMask>
|
|
||||||
</div>
|
|
||||||
<div class="field mb-4 col-12 md:col-6">
|
|
||||||
<label for="state" class="font-medium text-900">Country/State</label>
|
|
||||||
<input id="state" type="text" pInputText [(ngModel)]="mailinfo.sender.state" />
|
|
||||||
</div>
|
|
||||||
<div class="surface-border border-top-1 opacity-50 mb-4 col-12"></div>
|
|
||||||
<div class="field mb-4 col-12">
|
|
||||||
<label for="notes" class="font-medium text-900">Questions/Comments</label>
|
|
||||||
<textarea id="notes" pInputTextarea [autoResize]="true" [rows]="5" [(ngModel)]="mailinfo.sender.comments"></textarea>
|
|
||||||
</div>
|
|
||||||
@if(listingUser){
|
|
||||||
<div class="surface-border mb-4 col-12 flex align-items-center">
|
|
||||||
Listing by <a routerLink="/details-user/{{ listingUser.id }}" class="mr-2 font-semibold">{{ listingUser.firstname }} {{ listingUser.lastname }}</a>
|
|
||||||
@if(listingUser.hasCompanyLogo){
|
|
||||||
<img src="{{ env.imageBaseUrl }}/pictures/logo/{{ listing.imagePath }}.avif?_ts={{ ts }}" class="mr-5 lg:mb-0" style="max-height: 30px; max-width: 100px" />
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<button pButton pRipple label="Submit" icon="pi pi-file" class="w-auto" (click)="mail()"></button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<div class="container mx-auto p-4">
|
<div class="container mx-auto p-4">
|
||||||
<div class="bg-white shadow-md rounded-lg overflow-hidden">
|
<div class="bg-white shadow-md rounded-lg overflow-hidden">
|
||||||
@if(listing){
|
@if(listing){
|
||||||
|
|
@ -104,7 +5,7 @@
|
||||||
<h1 class="text-3xl font-bold mb-4">{{ listing?.title }}</h1>
|
<h1 class="text-3xl font-bold mb-4">{{ listing?.title }}</h1>
|
||||||
<button
|
<button
|
||||||
(click)="historyService.goBack()"
|
(click)="historyService.goBack()"
|
||||||
class="absolute top-4 right-4 bg-red-500 text-white rounded-full w-8 h-8 flex items-center justify-center hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-opacity-50"
|
class="print:hidden absolute top-4 right-4 bg-red-500 text-white rounded-full w-8 h-8 flex items-center justify-center hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-opacity-50"
|
||||||
>
|
>
|
||||||
<i class="fas fa-times"></i>
|
<i class="fas fa-times"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -143,9 +44,42 @@
|
||||||
<div class="w-full sm:w-2/3 p-2">{{ detail.value }}</div>
|
<div class="w-full sm:w-2/3 p-2">{{ detail.value }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if(listing && listingUser && (listingUser?.email===user?.email || isAdmin())){
|
<div class="py-4 print:hidden">
|
||||||
|
@if(listing && listingUser && (listingUser?.email===user?.email || isAdmin())){
|
||||||
|
<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-solid fa-floppy-disk"></i>
|
||||||
|
<span class="ml-2">Edit</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
} @if(user){
|
||||||
|
<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-solid fa-floppy-disk"></i>
|
||||||
|
@if(listing.favoritesForUser.includes(user.email)){
|
||||||
|
<span class="ml-2">Saved ...</span>
|
||||||
|
}@else {
|
||||||
|
<span class="ml-2">Save</span>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<share-button button="print" showText="true"></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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<share-button button="facebook" showText="true"></share-button>
|
||||||
|
<share-button button="x" showText="true"></share-button>
|
||||||
|
<share-button button="linkedin" showText="true"></share-button>
|
||||||
|
</div>
|
||||||
|
<!-- @if(listing && listingUser && (listingUser?.email===user?.email || isAdmin())){
|
||||||
<button class="mt-4 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600" [routerLink]="['/editCommercialPropertyListing', listing.id]">Edit</button>
|
<button class="mt-4 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600" [routerLink]="['/editCommercialPropertyListing', listing.id]">Edit</button>
|
||||||
}
|
} -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full lg:w-1/2 mt-6 lg:mt-0">
|
<div class="w-full lg:w-1/2 mt-6 lg:mt-0">
|
||||||
|
|
@ -177,39 +111,18 @@
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6">
|
<div class="mt-6 print:hidden">
|
||||||
<h2 class="text-xl font-semibold mb-4">Contact the Author of this Listing</h2>
|
<h2 class="text-xl font-semibold mb-4">Contact the Author of this Listing</h2>
|
||||||
<p class="text-sm text-gray-600 mb-4">Please include your contact info below</p>
|
<p class="text-sm text-gray-600 mb-4">Please include your contact info below</p>
|
||||||
<form class="space-y-4">
|
<form class="space-y-4">
|
||||||
<!-- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
|
||||||
<div>
|
|
||||||
<label for="name" class="block text-sm font-medium text-gray-700 mb-1">Your Name</label>
|
|
||||||
<input type="text" id="name" name="name" [(ngModel)]="mailinfo.sender.name" class="w-full px-3 py-2 border border-gray-300 rounded-md" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-1">Your Email</label>
|
|
||||||
<input type="email" id="email" name="email" [(ngModel)]="mailinfo.sender.email" class="w-full px-3 py-2 border border-gray-300 rounded-md" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="phone" class="block text-sm font-medium text-gray-700 mb-1">Phone Number</label>
|
|
||||||
<input type="tel" id="phone" name="phone" [(ngModel)]="mailinfo.sender.phoneNumber" class="w-full px-3 py-2 border border-gray-300 rounded-md" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="location" class="block text-sm font-medium text-gray-700 mb-1">Country/State</label>
|
|
||||||
<input type="text" id="location" name="location" [(ngModel)]="mailinfo.sender.state" class="w-full px-3 py-2 border border-gray-300 rounded-md" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mb-4">
|
|
||||||
<label for="message" class="block text-sm font-medium text-gray-700 mb-1">Questions/Comments</label>
|
|
||||||
<textarea id="message" name="message" [(ngModel)]="mailinfo.sender.comments" rows="4" class="w-full px-3 py-2 border border-gray-300 rounded-md"></textarea>
|
|
||||||
</div> -->
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-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 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>
|
<app-validated-input label="Your Email" name="email" [(ngModel)]="mailinfo.sender.email" kind="email"></app-validated-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<app-validated-input label="Phone Number" name="phoneNumber" [(ngModel)]="mailinfo.sender.phoneNumber" kind="tel"></app-validated-input>
|
<app-validated-input label="Phone Number" name="phoneNumber" [(ngModel)]="mailinfo.sender.phoneNumber" kind="tel" mask="(000) 000-0000"></app-validated-input>
|
||||||
<app-validated-input label="Country/State" name="state" [(ngModel)]="mailinfo.sender.state"></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>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<app-validated-textarea label="Questions/Comments" name="comments" [(ngModel)]="mailinfo.sender.comments"></app-validated-textarea>
|
<app-validated-textarea label="Questions/Comments" name="comments" [(ngModel)]="mailinfo.sender.comments"></app-validated-textarea>
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,15 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { faTimes } from '@fortawesome/free-solid-svg-icons';
|
import { faTimes } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { KeycloakService } from 'keycloak-angular';
|
import { KeycloakService } from 'keycloak-angular';
|
||||||
|
import { ShareButton } from 'ngx-sharebuttons/button';
|
||||||
import { lastValueFrom } from 'rxjs';
|
import { lastValueFrom } from 'rxjs';
|
||||||
import { CommercialPropertyListing, User } from '../../../../../../bizmatch-server/src/models/db.model';
|
import { CommercialPropertyListing, User } from '../../../../../../bizmatch-server/src/models/db.model';
|
||||||
import { CommercialPropertyListingCriteria, ErrorResponse, KeycloakUser, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model';
|
import { CommercialPropertyListingCriteria, ErrorResponse, KeycloakUser, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||||
import { environment } from '../../../../environments/environment';
|
import { environment } from '../../../../environments/environment';
|
||||||
|
import { EMailService } from '../../../components/email/email.service';
|
||||||
import { MessageService } from '../../../components/message/message.service';
|
import { MessageService } from '../../../components/message/message.service';
|
||||||
import { ValidatedInputComponent } from '../../../components/validated-input/validated-input.component';
|
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 { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component';
|
||||||
import { ValidationMessagesService } from '../../../components/validation-messages.service';
|
import { ValidationMessagesService } from '../../../components/validation-messages.service';
|
||||||
import { HistoryService } from '../../../services/history.service';
|
import { HistoryService } from '../../../services/history.service';
|
||||||
|
|
@ -24,7 +27,7 @@ import { createMailInfo, map2User } from '../../../utils/utils';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-details-commercial-property-listing',
|
selector: 'app-details-commercial-property-listing',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [SharedModule, ValidatedInputComponent, ValidatedTextareaComponent],
|
imports: [SharedModule, ValidatedInputComponent, ValidatedTextareaComponent, ShareButton, ValidatedNgSelectComponent],
|
||||||
providers: [],
|
providers: [],
|
||||||
templateUrl: './details-commercial-property-listing.component.html',
|
templateUrl: './details-commercial-property-listing.component.html',
|
||||||
styleUrl: '../details.scss',
|
styleUrl: '../details.scss',
|
||||||
|
|
@ -77,6 +80,7 @@ export class DetailsCommercialPropertyListingComponent {
|
||||||
private validationMessagesService: ValidationMessagesService,
|
private validationMessagesService: ValidationMessagesService,
|
||||||
private messageService: MessageService,
|
private messageService: MessageService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
|
private emailService: EMailService,
|
||||||
) {
|
) {
|
||||||
this.mailinfo = { sender: {}, email: '', url: environment.mailinfoUrl };
|
this.mailinfo = { sender: {}, email: '', url: environment.mailinfoUrl };
|
||||||
|
|
||||||
|
|
@ -152,4 +156,28 @@ export class DetailsCommercialPropertyListingComponent {
|
||||||
getImageIndices(): number[] {
|
getImageIndices(): number[] {
|
||||||
return this.listing && this.listing.imageOrder ? this.listing.imageOrder.slice(1).map((e, i) => i + 1) : [];
|
return this.listing && this.listing.imageOrder ? this.listing.imageOrder.slice(1).map((e, i) => i + 1) : [];
|
||||||
}
|
}
|
||||||
|
save() {
|
||||||
|
this.listing.favoritesForUser.push(this.user.email);
|
||||||
|
this.listingsService.save(this.listing, 'commercialProperty');
|
||||||
|
}
|
||||||
|
isAlreadyFavorite() {
|
||||||
|
return this.listing.favoritesForUser.includes(this.user.email);
|
||||||
|
}
|
||||||
|
async showShareByEMail() {
|
||||||
|
const result = await this.emailService.showShareByEMail({
|
||||||
|
email: this.user.email,
|
||||||
|
name: `${this.user.firstname} ${this.user.lastname}`,
|
||||||
|
url: environment.mailinfoUrl,
|
||||||
|
listingTitle: this.listing.title,
|
||||||
|
id: this.listing.id,
|
||||||
|
type: 'commercialProperty',
|
||||||
|
});
|
||||||
|
if (result) {
|
||||||
|
this.messageService.addMessage({
|
||||||
|
severity: 'success',
|
||||||
|
text: 'Your Email has beend sent',
|
||||||
|
duration: 5000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,3 +70,10 @@ button.share {
|
||||||
.share-email {
|
.share-email {
|
||||||
background-color: #ff961c;
|
background-color: #ff961c;
|
||||||
}
|
}
|
||||||
|
:host ::ng-deep .ng-select-container {
|
||||||
|
height: 42px !important;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
.ng-value-container .ng-input {
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,25 +43,4 @@ export class FavoritesComponent {
|
||||||
const result = await Promise.all([await this.listingsService.getFavoriteListings('business'), await this.listingsService.getFavoriteListings('commercialProperty')]);
|
const result = await Promise.all([await this.listingsService.getFavoriteListings('business'), await this.listingsService.getFavoriteListings('commercialProperty')]);
|
||||||
this.favorites = [...result[0], ...result[1]];
|
this.favorites = [...result[0], ...result[1]];
|
||||||
}
|
}
|
||||||
// listings: Array<ListingType> = []; //dataListings as unknown as Array<BusinessListing>;
|
|
||||||
// myListings: Array<ListingType>;
|
|
||||||
// user: User;
|
|
||||||
// constructor(
|
|
||||||
// public userService: UserService,
|
|
||||||
// public keycloakService: KeycloakService,
|
|
||||||
// private listingsService: ListingsService,
|
|
||||||
// private cdRef: ChangeDetectorRef,
|
|
||||||
// public selectOptions: SelectOptionsService,
|
|
||||||
// private messageService: MessageService,
|
|
||||||
// private confirmationService: ConfirmationService,
|
|
||||||
// ) {}
|
|
||||||
// async ngOnInit() {
|
|
||||||
// // const keycloakUser = this.userService.getKeycloakUser();
|
|
||||||
// const token = await this.keycloakService.getToken();
|
|
||||||
// const keycloakUser = map2User(token);
|
|
||||||
// const email = keycloakUser.email;
|
|
||||||
// this.user = await this.userService.getByMail(email);
|
|
||||||
// const result = await Promise.all([await this.listingsService.getListingsByEmail(this.user.email, 'business'), await this.listingsService.getListingsByEmail(this.user.email, 'commercialProperty')]);
|
|
||||||
// this.myListings = [...result[0], ...result[1]];
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { lastValueFrom } from 'rxjs';
|
import { lastValueFrom } from 'rxjs';
|
||||||
|
import { ShareByEMail } from '../../../../bizmatch-server/src/models/db.model';
|
||||||
import { ErrorResponse, MailInfo } from '../../../../bizmatch-server/src/models/main.model';
|
import { ErrorResponse, MailInfo } from '../../../../bizmatch-server/src/models/main.model';
|
||||||
import { environment } from '../../environments/environment';
|
import { environment } from '../../environments/environment';
|
||||||
|
|
||||||
|
|
@ -14,4 +15,7 @@ export class MailService {
|
||||||
async mail(mailinfo: MailInfo): Promise<void | ErrorResponse> {
|
async mail(mailinfo: MailInfo): Promise<void | ErrorResponse> {
|
||||||
return await lastValueFrom(this.http.post(`${this.apiBaseUrl}/bizmatch/mail`, mailinfo));
|
return await lastValueFrom(this.http.post(`${this.apiBaseUrl}/bizmatch/mail`, mailinfo));
|
||||||
}
|
}
|
||||||
|
async mailToFriend(shareByEMail: ShareByEMail): Promise<void | ErrorResponse> {
|
||||||
|
return await lastValueFrom(this.http.post(`${this.apiBaseUrl}/bizmatch/mail/send2Friend`, shareByEMail));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue