BugFix: IP Adresse & Subject instead of BehaviourSubject

This commit is contained in:
Andreas Knuth 2024-09-20 15:59:45 +02:00
parent 3e84b82c92
commit 16b880384b
16 changed files with 36 additions and 330 deletions

View File

@ -1,7 +1,7 @@
import { MiddlewareConsumer, Module } from '@nestjs/common'; import { createParamDecorator, ExecutionContext, MiddlewareConsumer, Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config'; import { ConfigModule } from '@nestjs/config';
import { PassportModule } from '@nestjs/passport'; import { PassportModule } from '@nestjs/passport';
import { WinstonModule, utilities as nestWinstonModuleUtilities } from 'nest-winston'; import { utilities as nestWinstonModuleUtilities, WinstonModule } from 'nest-winston';
import * as winston from 'winston'; import * as winston from 'winston';
import { AiModule } from './ai/ai.module'; import { AiModule } from './ai/ai.module';
import { AppController } from './app.controller'; import { AppController } from './app.controller';
@ -18,11 +18,17 @@ import dotenvFlow from 'dotenv-flow';
import { EventModule } from './event/event.module'; import { EventModule } from './event/event.module';
import { JwtStrategy } from './jwt.strategy'; import { JwtStrategy } from './jwt.strategy';
import { MailModule } from './mail/mail.module'; import { MailModule } from './mail/mail.module';
import { RealIpInfo } from './models/main.model';
import { PaymentModule } from './payment/payment.module'; import { PaymentModule } from './payment/payment.module';
import { RequestDurationMiddleware } from './request-duration/request-duration.middleware'; import { RequestDurationMiddleware } from './request-duration/request-duration.middleware';
import { SelectOptionsModule } from './select-options/select-options.module'; import { SelectOptionsModule } from './select-options/select-options.module';
import { UserModule } from './user/user.module'; import { UserModule } from './user/user.module';
export const RealIp = createParamDecorator((data: unknown, ctx: ExecutionContext): RealIpInfo => {
const request = ctx.switchToHttp().getRequest();
const ip = request.headers['cf-connecting-ip'] || request.headers['x-real-ip'] || request.headers['x-forwarded-for']?.split(',')[0] || request.connection.remoteAddress;
const countryCode = request.headers['cf-ipcountry'];
return { ip, countryCode };
});
// function loadEnvFiles() { // function loadEnvFiles() {
// // Determine which additional env file to load // // Determine which additional env file to load
// let envFilePath = ''; // let envFilePath = '';

View File

@ -1,5 +1,7 @@
import { Body, Controller, Headers, Ip, Post } from '@nestjs/common'; import { Body, Controller, Headers, Post } from '@nestjs/common';
import { RealIp } from 'src/app.module';
import { ListingEvent } from 'src/models/db.model'; import { ListingEvent } from 'src/models/db.model';
import { RealIpInfo } from 'src/models/main.model';
import { EventService } from './event.service'; import { EventService } from './event.service';
@Controller('event') @Controller('event')
@ -8,10 +10,10 @@ export class EventController {
@Post() @Post()
async createEvent( async createEvent(
@Body() event: ListingEvent, // Struktur des Body-Objekts entsprechend anpassen @Body() event: ListingEvent, // Struktur des Body-Objekts entsprechend anpassen
@Ip() userIp: string, // IP Adresse des Clients @RealIp() ipInfo: RealIpInfo, // IP Adresse des Clients
@Headers('user-agent') userAgent: string, // User-Agent des Clients @Headers('user-agent') userAgent: string, // User-Agent des Clients
) { ) {
event.userIp = userIp; event.userIp = ipInfo.ip;
event.userAgent = userAgent; event.userAgent = userAgent;
await this.eventService.createEvent(event); await this.eventService.createEvent(event);
return { message: 'Event gespeichert' }; return { message: 'Event gespeichert' };

View File

@ -1,17 +1,9 @@
import { Body, Controller, createParamDecorator, ExecutionContext, Get, Param, Post } from '@nestjs/common'; import { Body, Controller, Get, Param, Post } from '@nestjs/common';
import { RealIp } from 'src/app.module';
import { RealIpInfo } from 'src/models/main.model';
import { CountyRequest } from 'src/models/server.model'; import { CountyRequest } from 'src/models/server.model';
import { GeoService } from './geo.service'; import { GeoService } from './geo.service';
export interface RealIpInfo {
ip: string;
countryCode?: string;
}
export const RealIp = createParamDecorator((data: unknown, ctx: ExecutionContext): RealIpInfo => {
const request = ctx.switchToHttp().getRequest();
const ip = request.headers['cf-connecting-ip'] || request.headers['x-real-ip'] || request.headers['x-forwarded-for']?.split(',')[0] || request.connection.remoteAddress;
const countryCode = request.headers['cf-ipcountry'];
return { ip, countryCode };
});
@Controller('geo') @Controller('geo')
export class GeoController { export class GeoController {
constructor(private geoService: GeoService) {} constructor(private geoService: GeoService) {}

View File

@ -408,3 +408,7 @@ export interface CombinedUser {
stripeUser?: StripeUser; stripeUser?: StripeUser;
stripeSubscription?: StripeSubscription; stripeSubscription?: StripeSubscription;
} }
export interface RealIpInfo {
ip: string;
countryCode?: string;
}

View File

@ -2,7 +2,6 @@ import { Routes } from '@angular/router';
import { LogoutComponent } from './components/logout/logout.component'; import { LogoutComponent } from './components/logout/logout.component';
import { NotFoundComponent } from './components/not-found/not-found.component'; import { NotFoundComponent } from './components/not-found/not-found.component';
import { PaymentComponent } from './components/payment/payment.component';
import { AuthGuard } from './guards/auth.guard'; import { AuthGuard } from './guards/auth.guard';
import { ListingCategoryGuard } from './guards/listing-category.guard'; import { ListingCategoryGuard } from './guards/listing-category.guard';
import { UserListComponent } from './pages/admin/user-list/user-list.component'; import { UserListComponent } from './pages/admin/user-list/user-list.component';
@ -151,10 +150,6 @@ export const routes: Routes = [
path: 'pricing/:id', path: 'pricing/:id',
component: PricingComponent, component: PricingComponent,
}, },
{
path: 'payment',
component: PaymentComponent,
},
{ {
path: 'success', path: 'success',
component: SuccessComponent, component: SuccessComponent,

View File

@ -25,8 +25,8 @@ import { ConfirmationService } from './confirmation.service';
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 11V6m0 8h.01M19 10a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" /> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 11V6m0 8h.01M19 10a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
</svg> </svg>
@let confirmation = (confirmationService.confirmation$ | async); @let confirmation = (confirmationService.confirmation$ | async);
<h3 class="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">{{ confirmation.message }}</h3> <h3 class="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">{{ confirmation?.message }}</h3>
@if(confirmation.buttons==='both'){ @if(confirmation?.buttons==='both'){
<button <button
(click)="confirmationService.accept()" (click)="confirmationService.accept()"
type="button" type="button"

View File

@ -1,13 +1,13 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { ShareByEMail } from '../../../../../bizmatch-server/src/models/db.model'; import { ShareByEMail } from '../../../../../bizmatch-server/src/models/db.model';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
export class EMailService { export class EMailService {
private modalVisibleSubject = new BehaviorSubject<boolean>(false); private modalVisibleSubject = new Subject<boolean>();
private shareByEMailSubject = new BehaviorSubject<ShareByEMail>({}); private shareByEMailSubject = new Subject<ShareByEMail>();
private resolvePromise!: (value: boolean | ShareByEMail) => void; private resolvePromise!: (value: boolean | ShareByEMail) => void;
modalVisible$: Observable<boolean> = this.modalVisibleSubject.asObservable(); modalVisible$: Observable<boolean> = this.modalVisibleSubject.asObservable();

View File

@ -77,9 +77,7 @@ export class HeaderComponent {
}, 10); }, 10);
this.sharedService.currentProfilePhoto.subscribe(photoUrl => { this.sharedService.currentProfilePhoto.subscribe(photoUrl => {
if (photoUrl) { this.profileUrl = photoUrl;
this.profileUrl = photoUrl;
}
}); });
this.checkCurrentRoute(this.router.url); this.checkCurrentRoute(this.router.url);
@ -91,9 +89,7 @@ export class HeaderComponent {
}); });
this.userService.currentUser.pipe(untilDestroyed(this)).subscribe(u => { this.userService.currentUser.pipe(untilDestroyed(this)).subscribe(u => {
if (u !== undefined) { this.user = u;
this.user = u;
}
}); });
} }
private checkCurrentRoute(url: string): void { private checkCurrentRoute(url: string): void {

View File

@ -1,161 +0,0 @@
<section class="bg-white py-8 antialiased dark:bg-gray-900 md:py-16">
<div class="mx-auto max-w-screen-xl px-4 2xl:px-0">
<div class="mx-auto max-w-5xl">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl">Payment</h2>
<div class="mt-6 sm:mt-8 lg:flex lg:items-start lg:gap-12">
<form action="#" class="w-full rounded-lg border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-800 sm:p-6 lg:max-w-xl lg:p-8">
<div ngxStripeCardGroup class="mb-6 grid grid-cols-2 gap-4">
<div class="col-span-2 sm:col-span-1">
<label for="full_name" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white"> Full name (as displayed on card)* </label>
<input
type="text"
id="full_name"
class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500"
placeholder="Bonnie Green"
required
/>
</div>
<!-- <ngx-stripe-card-expiry [options]="cardOptions"></ngx-stripe-card-expiry>
<ngx-stripe-card-cvc [options]="cardOptions"></ngx-stripe-card-cvc> -->
<div class="col-span-2 sm:col-span-1">
<label for="card-number-input" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white"> Card number* </label>
<!-- <input
type="text"
id="card-number-input"
class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 pe-10 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500"
placeholder="xxxx-xxxx-xxxx-xxxx"
pattern="^4[0-9]{12}(?:[0-9]{3})?$"
required
/> -->
<div
class="ngx-input block w-full rounded-lg border border-gray-300 bg-gray-50 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500"
>
<ngx-stripe-card-number [options]="numberOptions"></ngx-stripe-card-number>
</div>
<!-- <ngx-stripe-card [options]="cardOptions" /> -->
</div>
<div>
<label for="card-expiration-input" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white">Card expiration* </label>
<!-- <div class="relative">
<div class="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3.5">
<svg class="h-4 w-4 text-gray-500 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
<path
fill-rule="evenodd"
d="M5 5a1 1 0 0 0 1-1 1 1 0 1 1 2 0 1 1 0 0 0 1 1h1a1 1 0 0 0 1-1 1 1 0 1 1 2 0 1 1 0 0 0 1 1h1a1 1 0 0 0 1-1 1 1 0 1 1 2 0 1 1 0 0 0 1 1 2 2 0 0 1 2 2v1a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V7a2 2 0 0 1 2-2ZM3 19v-7a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Zm6.01-6a1 1 0 1 0-2 0 1 1 0 0 0 2 0Zm2 0a1 1 0 1 1 2 0 1 1 0 0 1-2 0Zm6 0a1 1 0 1 0-2 0 1 1 0 0 0 2 0Zm-10 4a1 1 0 1 1 2 0 1 1 0 0 1-2 0Zm6 0a1 1 0 1 0-2 0 1 1 0 0 0 2 0Zm2 0a1 1 0 1 1 2 0 1 1 0 0 1-2 0Z"
clip-rule="evenodd"
/>
</svg>
</div>
<input
datepicker
datepicker-format="mm/yy"
id="card-expiration-input"
type="text"
class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 ps-9 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-blue-500 dark:focus:ring-blue-500"
placeholder="12/23"
required
/>
</div> -->
<div
class="ngx-input block w-full rounded-lg border border-gray-300 bg-gray-50 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500"
>
<ngx-stripe-card-expiry [options]="cvcOptions"></ngx-stripe-card-expiry>
</div>
</div>
<div>
<label for="cvv-input" class="mb-2 flex items-center gap-1 text-sm font-medium text-gray-900 dark:text-white">
CVV*
<button data-tooltip-target="cvv-desc" data-tooltip-trigger="hover" class="text-gray-400 hover:text-gray-900 dark:text-gray-500 dark:hover:text-white">
<svg class="h-4 w-4" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24">
<path
fill-rule="evenodd"
d="M2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10S2 17.523 2 12Zm9.408-5.5a1 1 0 1 0 0 2h.01a1 1 0 1 0 0-2h-.01ZM10 10a1 1 0 1 0 0 2h1v3h-1a1 1 0 1 0 0 2h4a1 1 0 1 0 0-2h-1v-4a1 1 0 0 0-1-1h-2Z"
clip-rule="evenodd"
/>
</svg>
</button>
<div
id="cvv-desc"
role="tooltip"
class="tooltip invisible absolute z-10 inline-block rounded-lg bg-gray-900 px-3 py-2 text-sm font-medium text-white opacity-0 shadow-sm transition-opacity duration-300 dark:bg-gray-700"
>
The last 3 or 4 digits on back of card
<div class="tooltip-arrow" data-popper-arrow></div>
</div>
</label>
<!-- <input
type="number"
id="cvv-input"
aria-describedby="helper-text-explanation"
class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500"
placeholder="•••"
required
/> -->
<div
class="ngx-input block w-full rounded-lg border border-gray-300 bg-gray-50 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500"
>
<ngx-stripe-card-cvc [options]="cvcOptions"></ngx-stripe-card-cvc>
</div>
</div>
</div>
<button
type="submit"
class="flex w-full items-center justify-center rounded-lg bg-primary-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-primary-800 focus:outline-none focus:ring-4 focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"
>
Pay now
</button>
</form>
<div class="mt-6 grow sm:mt-8 lg:mt-0">
<div class="space-y-4 rounded-lg border border-gray-100 bg-gray-50 p-6 dark:border-gray-700 dark:bg-gray-800">
<div class="space-y-2">
<dl class="flex items-center justify-between gap-4">
<dt class="text-base font-normal text-gray-500 dark:text-gray-400">Subscription Price</dt>
<dd class="text-base font-medium text-gray-900 dark:text-white">$49.00</dd>
</dl>
<!-- <dl class="flex items-center justify-between gap-4">
<dt class="text-base font-normal text-gray-500 dark:text-gray-400">Savings</dt>
<dd class="text-base font-medium text-green-500">-$299.00</dd>
</dl>
<dl class="flex items-center justify-between gap-4">
<dt class="text-base font-normal text-gray-500 dark:text-gray-400">Store Pickup</dt>
<dd class="text-base font-medium text-gray-900 dark:text-white">$99</dd>
</dl> -->
<dl class="flex items-center justify-between gap-4">
<dt class="text-base font-normal text-gray-500 dark:text-gray-400">Tax</dt>
<dd class="text-base font-medium text-gray-900 dark:text-white">$1.43</dd>
</dl>
</div>
<dl class="flex items-center justify-between gap-4 border-t border-gray-200 pt-2 dark:border-gray-700">
<dt class="text-base font-bold text-gray-900 dark:text-white">Total</dt>
<dd class="text-base font-bold text-gray-900 dark:text-white">$50.43</dd>
</dl>
</div>
<div class="mt-6 flex items-center justify-center gap-8">
<!-- <img class="h-8 w-auto dark:hidden" src="https://flowbite.s3.amazonaws.com/blocks/e-commerce/brand-logos/paypal.svg" alt="" />
<img class="hidden h-8 w-auto dark:flex" src="https://flowbite.s3.amazonaws.com/blocks/e-commerce/brand-logos/paypal-dark.svg" alt="" /> -->
<img class="h-8 w-auto dark:hidden" src="https://flowbite.s3.amazonaws.com/blocks/e-commerce/brand-logos/visa.svg" alt="" />
<img class="hidden h-8 w-auto dark:flex" src="https://flowbite.s3.amazonaws.com/blocks/e-commerce/brand-logos/visa-dark.svg" alt="" />
<img class="h-8 w-auto dark:hidden" src="https://flowbite.s3.amazonaws.com/blocks/e-commerce/brand-logos/mastercard.svg" alt="" />
<img class="hidden h-8 w-auto dark:flex" src="https://flowbite.s3.amazonaws.com/blocks/e-commerce/brand-logos/mastercard-dark.svg" alt="" />
</div>
</div>
</div>
<p class="mt-6 text-center text-gray-500 dark:text-gray-400 sm:mt-8 lg:text-left">
Payment processed by <a href="#" title="" class="font-medium text-primary-700 underline hover:no-underline dark:text-primary-500">Stripe</a> for
<a href="#" title="" class="font-medium text-primary-700 underline hover:no-underline dark:text-primary-500">Bizmatch Inc.</a>
- United States Of America
</p>
</div>
</div>
</section>

View File

@ -1,75 +0,0 @@
import { CommonModule } from '@angular/common';
import { Component, inject, ViewChild } from '@angular/core';
import { FormsModule, NgForm } from '@angular/forms';
import { StripeCardCvcElementOptions, StripeCardNumberElementOptions, StripeElementsOptions } from '@stripe/stripe-js';
import { injectStripe, StripeCardComponent, StripeCardCvcComponent, StripeCardExpiryComponent, StripeCardGroupDirective, StripeCardNumberComponent, StripeElementsDirective } from 'ngx-stripe';
import { PaymentService } from './payment.service';
@Component({
selector: 'app-payment-modal',
templateUrl: './payment.component.html',
standalone: true,
imports: [CommonModule, FormsModule, StripeCardNumberComponent, StripeCardExpiryComponent, StripeCardCvcComponent, StripeElementsDirective, StripeCardGroupDirective],
styles: `
.ngx-input{
padding:0.85rem
}
`,
})
export class PaymentComponent {
@ViewChild('cardElement') cardElement: StripeCardComponent;
stripe = injectStripe('your-stripe-publishable-key');
name: string;
constructor() {}
cvcOptions: StripeCardCvcElementOptions = {
style: {
base: {
iconColor: '#666EE8',
color: '#111827',
fontWeight: '300',
fontFamily: 'sans-serif',
fontSize: '14px',
'::placeholder': {
color: '#CFD7E0',
// color: '#6B7280',
},
},
},
};
numberOptions: StripeCardNumberElementOptions = {
showIcon: true,
style: {
base: {
iconColor: '#666EE8',
color: '#111827',
fontWeight: '300',
fontFamily: 'sans-serif',
fontSize: '14px',
'::placeholder': {
color: '#CFD7E0',
// color: '#6B7280',
},
},
},
};
elementsOptions: StripeElementsOptions = {
locale: 'en',
};
paymentService = inject(PaymentService);
onSubmit(form: NgForm) {
if (form.valid) {
this.stripe.createToken(this.cardElement.element, { name: this.name }).subscribe(result => {
if (result.token) {
this.paymentService.processPayment(result.token.id).subscribe(() => {
console.log('Payment successful');
});
} else if (result.error) {
console.error(result.error.message);
}
});
}
}
}

View File

@ -1,32 +0,0 @@
// 1. Shared Service (modal.service.ts)
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class PaymentService {
private modalVisibleSubject = new BehaviorSubject<boolean>(false);
modalVisible$: Observable<boolean> = this.modalVisibleSubject.asObservable();
private resolvePromise!: (value: boolean) => void;
constructor(private http: HttpClient) {}
openPaymentModal() {
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);
}
processPayment(token: string): Observable<any> {
return this.http.post('/api/subscription', { token });
}
}

View File

@ -234,6 +234,7 @@ export class AccountComponent {
this.profileUrl = `${this.env.imageBaseUrl}/pictures/profile/${emailToDirName(this.user.email)}.avif?_ts=${new Date().getTime()}`; this.profileUrl = `${this.env.imageBaseUrl}/pictures/profile/${emailToDirName(this.user.email)}.avif?_ts=${new Date().getTime()}`;
this.sharedService.changeProfilePhoto(this.profileUrl); this.sharedService.changeProfilePhoto(this.profileUrl);
} }
this.userService.changeUser(this.user);
await this.userService.saveGuaranteed(this.user); await this.userService.saveGuaranteed(this.user);
} }
} }

View File

@ -1,6 +1,6 @@
import { HttpClient, HttpHeaders } from '@angular/common/http'; import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject, lastValueFrom, Observable } from 'rxjs'; import { lastValueFrom, Observable } from 'rxjs';
import { CityAndStateResult, CountyResult, GeoResult, IpInfo } from '../../../../bizmatch-server/src/models/main.model'; import { CityAndStateResult, CountyResult, GeoResult, IpInfo } from '../../../../bizmatch-server/src/models/main.model';
import { Place } from '../../../../bizmatch-server/src/models/server.model'; import { Place } from '../../../../bizmatch-server/src/models/server.model';
import { environment } from '../../environments/environment'; import { environment } from '../../environments/environment';
@ -11,7 +11,6 @@ import { environment } from '../../environments/environment';
export class GeoService { export class GeoService {
private apiBaseUrl = environment.apiBaseUrl; private apiBaseUrl = environment.apiBaseUrl;
private baseUrl: string = 'https://nominatim.openstreetmap.org/search'; private baseUrl: string = 'https://nominatim.openstreetmap.org/search';
private ipInfo$ = new BehaviorSubject<IpInfo | null>(null);
private fetchingData: Observable<IpInfo> | null = null; private fetchingData: Observable<IpInfo> | null = null;
private readonly storageKey = 'ipInfo'; private readonly storageKey = 'ipInfo';
constructor(private http: HttpClient) {} constructor(private http: HttpClient) {}
@ -34,27 +33,6 @@ export class GeoService {
return this.http.get<IpInfo>(`${this.apiBaseUrl}/bizmatch/geo/ipinfo/georesult/wysiwyg`); return this.http.get<IpInfo>(`${this.apiBaseUrl}/bizmatch/geo/ipinfo/georesult/wysiwyg`);
} }
// getIpInfo(): Observable<IpInfo | null> {
// if (this.ipInfo$.getValue() !== null) {
// // Wenn wir bereits Daten haben, geben wir sie sofort zurück
// return this.ipInfo$.asObservable();
// } else if (this.fetchingData) {
// // Wenn wir gerade Daten abrufen, geben wir diesen Observable zurück
// return this.fetchingData;
// } else {
// // Ansonsten initiieren wir den Abruf
// this.fetchingData = this.fetchIpAndGeoLocation().pipe(
// tap(data => this.ipInfo$.next(data)),
// catchError(error => {
// console.error('Error fetching IP info:', error);
// this.ipInfo$.next(null);
// return of(null);
// }),
// shareReplay(1),
// );
// return this.fetchingData;
// }
// }
async getIpInfo(): Promise<IpInfo | null> { async getIpInfo(): Promise<IpInfo | null> {
// Versuche zuerst, die Daten aus dem sessionStorage zu holen // Versuche zuerst, die Daten aus dem sessionStorage zu holen
const storedData = sessionStorage.getItem(this.storageKey); const storedData = sessionStorage.getItem(this.storageKey);

View File

@ -1,12 +1,12 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs'; import { Subject } from 'rxjs';
import { BusinessListingCriteria, CommercialPropertyListingCriteria, UserListingCriteria } from '../../../../bizmatch-server/src/models/main.model'; import { BusinessListingCriteria, CommercialPropertyListingCriteria, UserListingCriteria } from '../../../../bizmatch-server/src/models/main.model';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
export class SearchService { export class SearchService {
private criteriaSource = new BehaviorSubject<BusinessListingCriteria | CommercialPropertyListingCriteria | UserListingCriteria>(null); private criteriaSource = new Subject<BusinessListingCriteria | CommercialPropertyListingCriteria | UserListingCriteria>();
currentCriteria = this.criteriaSource.asObservable(); currentCriteria = this.criteriaSource.asObservable();
constructor() {} constructor() {}

View File

@ -1,11 +1,11 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs'; import { Subject } from 'rxjs';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
export class SharedService { export class SharedService {
private profilePhotoSource = new BehaviorSubject<string>(null); private profilePhotoSource = new Subject<string>();
currentProfilePhoto = this.profilePhotoSource.asObservable(); currentProfilePhoto = this.profilePhotoSource.asObservable();
constructor() {} constructor() {}

View File

@ -1,7 +1,7 @@
import { HttpClient, HttpHeaders } from '@angular/common/http'; import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { PaymentMethod } from '@stripe/stripe-js'; import { PaymentMethod } from '@stripe/stripe-js';
import { BehaviorSubject, catchError, forkJoin, lastValueFrom, map, Observable, of } from 'rxjs'; import { catchError, forkJoin, lastValueFrom, map, Observable, of, Subject } from 'rxjs';
import urlcat from 'urlcat'; import urlcat from 'urlcat';
import { User } from '../../../../bizmatch-server/src/models/db.model'; import { User } from '../../../../bizmatch-server/src/models/db.model';
import { CombinedUser, KeycloakUser, ResponseUsersArray, StripeSubscription, StripeUser, UserListingCriteria } from '../../../../bizmatch-server/src/models/main.model'; import { CombinedUser, KeycloakUser, ResponseUsersArray, StripeSubscription, StripeUser, UserListingCriteria } from '../../../../bizmatch-server/src/models/main.model';
@ -13,7 +13,7 @@ import { environment } from '../../environments/environment';
export class UserService { export class UserService {
private apiBaseUrl = environment.apiBaseUrl; private apiBaseUrl = environment.apiBaseUrl;
private userSource = new BehaviorSubject<User>(undefined); private userSource = new Subject<User>();
currentUser = this.userSource.asObservable(); currentUser = this.userSource.asObservable();
constructor(private http: HttpClient) {} constructor(private http: HttpClient) {}