#14: add timestamp for inserted & updated

This commit is contained in:
Your Name
2025-01-29 17:38:35 +01:00
parent 2f35648264
commit 9f25253ade
8 changed files with 311 additions and 25 deletions

View File

@@ -2,8 +2,10 @@ import { CommonModule } from '@angular/common';
import { Component, inject } from '@angular/core';
import { Auth } from '@angular/fire/auth';
import { GoogleAuthProvider, signInWithPopup } from 'firebase/auth';
import { PopoverComponent } from './components/popover.component';
import { DeckListComponent } from './deck-list.component';
import { ClickOutsideDirective } from './service/click-outside.directive';
import { PopoverService } from './services/popover.service';
@Component({
selector: 'app-root',
template: `
@@ -31,11 +33,10 @@ import { ClickOutsideDirective } from './service/click-outside.directive';
<h1 class="text-3xl font-bold mx-auto">Vocabulary Training</h1>
<div class="relative" appClickOutside (clickOutside)="showDropdown = false">
@if(photoURL){
<img [src]="photoURL" alt="User Photo" class="w-10 h-10 rounded-full cursor-pointer" (click)="toggleDropdown()" referrerpolicy="no-referrer" crossorigin="anonymous"/>
<img [src]="photoURL" alt="User Photo" class="w-10 h-10 rounded-full cursor-pointer" (click)="toggleDropdown()" referrerpolicy="no-referrer" crossorigin="anonymous" />
} @else {
<div class="image-placeholder w-10 h-10 rounded-full cursor-pointer">Image</div>
}
@if(showDropdown){
} @if(showDropdown){
<div class="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg">
<button (click)="logout()" class="block w-full text-left px-4 py-2 text-gray-700 hover:bg-gray-100">Abmelden</button>
</div>
@@ -44,6 +45,16 @@ import { ClickOutsideDirective } from './service/click-outside.directive';
</div>
<app-deck-list></app-deck-list>
</div>
<app-popover
[visible]="popoverVisible"
[title]="popoverTitle"
[message]="popoverMessage"
[showInput]="popoverShowInput"
[inputValue]="popoverInputValue"
[confirmText]="popoverConfirmText"
(confirmed)="handleConfirm($event)"
(canceled)="handleCancel()"
></app-popover>
`,
standalone: true,
styles: `
@@ -80,7 +91,7 @@ img:hover {
}
`,
imports: [CommonModule, DeckListComponent, ClickOutsideDirective],
imports: [CommonModule, DeckListComponent, ClickOutsideDirective, PopoverComponent],
})
export class AppComponent {
isLoggedIn = false;
@@ -88,14 +99,34 @@ export class AppComponent {
showDropdown = false;
photoURL: string = 'https://placehold.co/40';
// user: User | null = null;
popoverVisible = false;
popoverTitle = '';
popoverMessage = '';
popoverShowInput = false;
popoverInputValue = '';
popoverConfirmText = 'Confirm';
private confirmCallback?: (inputValue?: string) => void;
private cancelCallback?: () => void;
constructor(public popoverService: PopoverService) {
this.popoverService.popoverState$.subscribe(options => {
this.popoverVisible = true;
this.popoverTitle = options.title;
this.popoverMessage = options.message;
this.popoverShowInput = options.showInput;
this.popoverInputValue = options.inputValue;
this.popoverConfirmText = options.confirmText;
this.confirmCallback = options.onConfirm;
this.cancelCallback = options.onCancel;
});
}
ngOnInit() {
// Überprüfen des Login-Status beim Start der Anwendung
const isLoggedIn = localStorage.getItem('isLoggedIn') === 'true';
const accessToken = localStorage.getItem('accessToken');
const refreshToken = localStorage.getItem('refreshToken');
this.photoURL = localStorage.getItem('photoURL');
if (isLoggedIn && accessToken && refreshToken) {
this.isLoggedIn = true;
}
@@ -113,9 +144,9 @@ export class AppComponent {
localStorage.setItem('accessToken', await result.user.getIdToken());
localStorage.setItem('refreshToken', result.user.refreshToken);
localStorage.setItem('photoURL', result.user.photoURL);
this.showDropdown = false;
console.log('Logged in with Google', result.user);
} catch (error) {
console.error('Google Login failed', error);
@@ -133,4 +164,17 @@ export class AppComponent {
toggleDropdown() {
this.showDropdown = !this.showDropdown;
}
handleConfirm(inputValue?: string) {
this.popoverVisible = false;
if (this.confirmCallback) {
this.confirmCallback(inputValue);
}
}
handleCancel() {
this.popoverVisible = false;
if (this.cancelCallback) {
this.cancelCallback();
}
}
}

View File

@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map, Observable, switchMap } from 'rxjs';
import { Injectable } from '@angular/core';
import { map, Observable } from 'rxjs';
export interface Deck {
name: string;
@@ -10,6 +10,7 @@ export interface Deck {
export interface DeckImage {
boxes: Box[];
name: string;
//bildid: string;
id: string;
}
@@ -53,19 +54,21 @@ export interface OcrResult {
}
@Injectable({
providedIn: 'root'
providedIn: 'root',
})
export class DeckService {
private apiUrl = '/api/decks';
constructor(private http: HttpClient) { }
constructor(private http: HttpClient) {}
getDecks(): Observable<Deck[]> {
return this.http.get<any[]>(this.apiUrl).pipe(
map(decks => decks.map(deck => ({
name: deck.name,
images: this.groupImagesByName(deck.images)
})))
map(decks =>
decks.map(deck => ({
name: deck.name,
images: this.groupImagesByName(deck.images),
})),
),
);
}
@@ -77,7 +80,7 @@ export class DeckService {
imageMap[image.id] = {
name: image.name,
id: image.id,
boxes: []
boxes: [],
};
}
imageMap[image.id].boxes.push({
@@ -91,7 +94,7 @@ export class DeckService {
factor: image.factor,
reps: image.reps,
lapses: image.lapses,
isGraduated: image.isGraduated ? true : false
isGraduated: image.isGraduated ? true : false,
});
});
@@ -129,4 +132,4 @@ export class DeckService {
updateBox(box: Box): Observable<any> {
return this.http.put(`${this.apiUrl}/boxes/${box.id}`, box);
}
}
}