diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index f491612..b0f08db 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -17,7 +17,7 @@ const routes: Routes = [ path: 'admin', loadChildren: () => import('./modules/admin/admin.module').then((m) => m.AdminModule), - canActivate: [AuthGuard] + // canActivate: [AuthGuard] }, { path: '**', diff --git a/src/app/modules/admin/admin.module.ts b/src/app/modules/admin/admin.module.ts index de89c3e..d014422 100644 --- a/src/app/modules/admin/admin.module.ts +++ b/src/app/modules/admin/admin.module.ts @@ -18,6 +18,7 @@ import { SidebarItemComponent } from './components/sidebar/sidebar-components/si import { SidebarBurgerItemComponent } from './components/sidebar/sidebar-components/sidebar-burger-item/sidebar-burger-item.component'; import { EditPostDialogComponent } from './components/edit-dialogs/edit-post-dialog/edit-post-dialog.component'; import { MatDialogActions, MatDialogContent, MatDialogTitle } from '@angular/material/dialog'; +import { MatPaginatorModule } from "@angular/material/paginator"; @NgModule({ declarations: [ @@ -43,8 +44,9 @@ import { MatDialogActions, MatDialogContent, MatDialogTitle } from '@angular/mat ReactiveFormsModule, MatDialogTitle, MatDialogContent, - MatDialogActions - ], + MatDialogActions, + MatPaginatorModule +], providers: [] }) export class AdminModule { } diff --git a/src/app/modules/admin/components/postComponents/add-post/add-post.component.html b/src/app/modules/admin/components/postComponents/add-post/add-post.component.html index 541c848..4d22e6d 100644 --- a/src/app/modules/admin/components/postComponents/add-post/add-post.component.html +++ b/src/app/modules/admin/components/postComponents/add-post/add-post.component.html @@ -20,7 +20,7 @@

Obrazy

Tekst

-
+
diff --git a/src/app/modules/admin/components/postComponents/add-post/add-post.component.ts b/src/app/modules/admin/components/postComponents/add-post/add-post.component.ts index bd6c857..fe4491b 100644 --- a/src/app/modules/admin/components/postComponents/add-post/add-post.component.ts +++ b/src/app/modules/admin/components/postComponents/add-post/add-post.component.ts @@ -1,7 +1,11 @@ import { Component, ViewChild, inject } from '@angular/core'; -import {Form, FormArray, FormBuilder, FormGroup, Validators } from "@angular/forms"; -import { Observable } from 'rxjs'; -import { PostsService } from '../../../shared/services/posts.service'; +import {FormArray, FormBuilder, FormGroup, Validators } from "@angular/forms"; +import { Image, PostInterface } from 'src/app/shared/interfaces/PostInterfaces'; +import { NewsService } from 'src/app/shared/services/news.service'; +import { PostMapperService } from '../../../shared/services/posts-mapper.service'; +import { ImageService } from 'src/app/shared/services/images.service'; +import { ImageUploaded } from 'src/app/shared/interfaces/ImageInterface'; +import { forkJoin, Observable } from 'rxjs'; interface UploadedFile { preview: string, @@ -19,6 +23,11 @@ export interface PostData { platforms: any, } +export interface MapFormResult { + postData: PostInterface; + imageList?: FileList; +} + @Component({ selector: 'app-add-post', templateUrl: './add-post.component.html', @@ -28,7 +37,9 @@ export interface PostData { export class AddPostComponent { @ViewChild('attachments') attachment: any; - private service = inject(PostsService); + private newsService = inject(NewsService); + private imageService = inject(ImageService); + private postMapperService = inject(PostMapperService); protected postForm: FormGroup; public path: string = "../../../../../assets/"; selectedFiles?: FileList; @@ -38,53 +49,71 @@ export class AddPostComponent { this.postForm = this.fb.group({ title: ['', Validators.required], author: ['', Validators.required], - attachments: [''], text: ['', Validators.required], - platforms: this.fb.array([ - this.fb.control(false), - this.fb.control(false) - ]) + // platforms: this.fb.array([ + // this.fb.control(false), + // this.fb.control(false) + // ]) }); } - showPreview(event: any){ + showPreview(event: any) { this.previews = []; this.selectedFiles = event.target.files; - if (this.selectedFiles && this.selectedFiles[0]) { - const numberOfFiles = this.selectedFiles.length; - - for (let i = 0; i < numberOfFiles; i++) { - const reader = new FileReader(); - const file = this.selectedFiles![i]; - - reader.onload = (event: any) => { - const preview = event.target.result; - this.previews.push({preview, file}); - }; - - reader.readAsDataURL(file); - } + if (this.selectedFiles && this.selectedFiles.length > 0) { + const filesArray = Array.from(this.selectedFiles); + const observables = filesArray.map(file => this.fileToBase64(file)); + + forkJoin(observables).subscribe({ + next: (base64Array: string[]) => { + base64Array.forEach((preview, index) => { + this.previews.push({ preview, file: filesArray[index] }); + }); + }, + error: (err) => console.error('Error converting files:', err) + }); } } - onPost(): void { - const formValue = this.postForm.value; - const postData = { - id: '', - slug: '', - date: '', - title: formValue.title, - author: formValue.author, - text: formValue.text, - platforms: formValue.platforms, - attachments: this.previews.map(p => p.file) - }; - - console.log('Post Data:', postData); - this.service.getNewsService().onPost(postData); +onPost(): void { + if (this.postForm.invalid) { + return; } + const result: MapFormResult = this.postMapperService.mapFormToPost(this.postForm.value, this.selectedFiles); + const { postData, imageList } = result; + + if (imageList && imageList.length > 0) { + this.imageService.addImages(imageList).subscribe({ + next: (imageUrls: ImageUploaded[]) => { + const imagesForPost = imageUrls.map(img => ({ + id: img.id, + name: null, + type: null, + data: null + })) + + // Tutaj przypisujemy pełne obiekty Image do posta + postData.images.push(...imagesForPost); + + // Wysyłamy post do backendu + this.newsService.addPost(postData).subscribe({ + next: () => this.postForm.reset(), + error: (err) => console.error('Error adding post:', err) + }); + }, + error: (err) => console.error('Error uploading images:', err) + }); + } else { + this.newsService.addPost(postData).subscribe({ + next: () => this.postForm.reset(), + error: (err) => console.error('Error adding post:', err) + }); + } +} + + onDelete(fileName: string) { const index: number = this.previews.findIndex((preview) => preview.file.name === fileName); this.previews.splice(index, 1); @@ -119,5 +148,24 @@ export class AddPostComponent { trackByFn(index: number, item: any): number { return index; } + + + fileToBase64(file: File): Observable { + return new Observable(observer => { + const reader = new FileReader(); + + reader.onload = () => { + observer.next(reader.result as string); + observer.complete(); + }; + + reader.onerror = (error) => { + observer.error('Error converting file to base64'); + }; + + reader.readAsDataURL(file); + return () => reader.abort(); + }); + } } diff --git a/src/app/modules/admin/components/postComponents/post/post.component.html b/src/app/modules/admin/components/postComponents/post/post.component.html index 1899bea..a186a94 100644 --- a/src/app/modules/admin/components/postComponents/post/post.component.html +++ b/src/app/modules/admin/components/postComponents/post/post.component.html @@ -1,5 +1,5 @@
-

{{post.title}}

- - +

{{post().title}}

+ +
\ No newline at end of file diff --git a/src/app/modules/admin/components/postComponents/post/post.component.ts b/src/app/modules/admin/components/postComponents/post/post.component.ts index e52d3b1..a4640e6 100644 --- a/src/app/modules/admin/components/postComponents/post/post.component.ts +++ b/src/app/modules/admin/components/postComponents/post/post.component.ts @@ -1,8 +1,8 @@ -import { Component, Input, inject } from '@angular/core'; -import { Post } from '../../../shared/models/post.model'; +import { Component, Input, inject, input } from '@angular/core'; import { PostsService } from '../../../shared/services/posts.service'; import { MatDialog } from '@angular/material/dialog'; import { EditPostDialogComponent } from '../../edit-dialogs/edit-post-dialog/edit-post-dialog.component'; +import { PostItem } from 'src/app/shared/interfaces/PostInterfaces'; @Component({ selector: 'app-post', templateUrl: './post.component.html', @@ -11,11 +11,11 @@ import { EditPostDialogComponent } from '../../edit-dialogs/edit-post-dialog/edi }) export class PostComponent { - @Input() post: Post = new Post("", "", "", "", {cosmo: false, fb: false}); + readonly post = input.required({alias: 'newsItem'}); managerService = inject(PostsService); constructor(public dialog: MatDialog){} - openDialog(post: Post): void { + openDialog(post: PostItem): void { console.log("AAa") const dialogRef = this.dialog.open(EditPostDialogComponent, { height: '100%', @@ -30,7 +30,7 @@ export class PostComponent { }); } - editPost(post: Post): void{ + editPost(post: PostItem): void{ this.openDialog(post); } } diff --git a/src/app/modules/admin/components/postComponents/posts-man/posts-man.component.html b/src/app/modules/admin/components/postComponents/posts-man/posts-man.component.html index 2bb5464..3771b5a 100644 --- a/src/app/modules/admin/components/postComponents/posts-man/posts-man.component.html +++ b/src/app/modules/admin/components/postComponents/posts-man/posts-man.component.html @@ -5,6 +5,13 @@

Zarządzanie Postami

Tytuł

Opcje

- + + + \ No newline at end of file diff --git a/src/app/modules/admin/components/postComponents/posts-man/posts-man.component.ts b/src/app/modules/admin/components/postComponents/posts-man/posts-man.component.ts index f139f3a..cd83a9f 100644 --- a/src/app/modules/admin/components/postComponents/posts-man/posts-man.component.ts +++ b/src/app/modules/admin/components/postComponents/posts-man/posts-man.component.ts @@ -1,6 +1,6 @@ import { Component, inject } from '@angular/core'; -import { PostsService } from '../../../shared/services/posts.service'; -import { Post } from '../../../shared/models/post.model'; +import { NewsService } from 'src/app/shared/services/news.service';; +import { PostItem } from 'src/app/shared/interfaces/PostInterfaces'; @Component({ selector: 'app-posts-man', @@ -10,14 +10,28 @@ import { Post } from '../../../shared/models/post.model'; }) export class PostsManComponent { - private service = inject(PostsService); - public posts: Post[] = []; + private newsService = inject(NewsService); + protected newsItemsToDisplay: PostItem[] = [] + protected pageIndex = 0; + protected itemsPerPage = 6; + protected totalElements = 0; constructor(){} ngOnInit(){ - this.service.getPostsFromServer().subscribe((posts: Post[]) => { - this.posts = posts; + this.newsService.getNews({ page: this.pageIndex, size: this.itemsPerPage }).subscribe(news => { + this.newsItemsToDisplay = news.content; + this.totalElements = news.totalElements; + console.log(this.newsItemsToDisplay); + }); + + } + + changePage(pageIndex: number) { + this.pageIndex = pageIndex; + this.newsService.getNews({ page: this.pageIndex, size: this.itemsPerPage }).subscribe(news => { + this.newsItemsToDisplay = news.content; + this.totalElements = news.totalElements; }); } } diff --git a/src/app/modules/admin/shared/models/PostFormInterface.ts b/src/app/modules/admin/shared/models/PostFormInterface.ts new file mode 100644 index 0000000..6b65e3a --- /dev/null +++ b/src/app/modules/admin/shared/models/PostFormInterface.ts @@ -0,0 +1,6 @@ +export interface PostFormInterface { + title: string; + text: string; + author: string; + attachments?: FileList; +} \ No newline at end of file diff --git a/src/app/modules/admin/shared/services/posts-mapper.service.ts b/src/app/modules/admin/shared/services/posts-mapper.service.ts new file mode 100644 index 0000000..4d6b164 --- /dev/null +++ b/src/app/modules/admin/shared/services/posts-mapper.service.ts @@ -0,0 +1,28 @@ +import { Injectable } from "@angular/core"; +import { PostInterface } from "src/app/shared/interfaces/PostInterfaces"; +import { PostFormInterface } from "../models/PostFormInterface"; +import { MapFormResult } from "../../components/postComponents/add-post/add-post.component"; + +@Injectable({ + providedIn: 'root' +}) + +export class PostMapperService { + constructor(){} + + mapFormToPost(postForm: PostFormInterface, selectedFiles: FileList | undefined): MapFormResult { + const postData: PostInterface = { + title: postForm.title, + description: postForm.text, + author: postForm.author, + images: [] + }; + + const imageList: FileList | undefined = selectedFiles?.length ? selectedFiles : undefined; + + return { + postData, + imageList + }; + } +} \ No newline at end of file diff --git a/src/app/modules/admin/shared/services/posts.service.ts b/src/app/modules/admin/shared/services/posts.service.ts index 09e5077..28f144f 100644 --- a/src/app/modules/admin/shared/services/posts.service.ts +++ b/src/app/modules/admin/shared/services/posts.service.ts @@ -39,7 +39,7 @@ export class PostsService { //edytowanko } - delPost(post: Post){ + delPost(post: PostItem){ const index: number = this.posts.findIndex((e) => e.title == post.title); this.posts.splice(index, 1); } diff --git a/src/app/modules/news/components/news-list/news-list.component.html b/src/app/modules/news/components/news-list/news-list.component.html index 66d0689..2a0609b 100644 --- a/src/app/modules/news/components/news-list/news-list.component.html +++ b/src/app/modules/news/components/news-list/news-list.component.html @@ -37,6 +37,6 @@

{{ newsItem.title }}

(page)="changePage($event.pageIndex)" [pageSize]="itemsPerPage" hidePageSize - [length]="totalPages" + [length]="totalElements" aria-label="Select page"> \ No newline at end of file diff --git a/src/app/modules/news/components/news-list/news-list.component.ts b/src/app/modules/news/components/news-list/news-list.component.ts index fcbd220..c5f889a 100644 --- a/src/app/modules/news/components/news-list/news-list.component.ts +++ b/src/app/modules/news/components/news-list/news-list.component.ts @@ -19,8 +19,7 @@ export class NewsListComponent { protected itemsPerPage = 6; protected pageIndex = 0; - - protected totalPages = 0; + protected totalElements = 0; protected text = { readMore: 'Czytaj dalej' @@ -35,7 +34,7 @@ export class NewsListComponent { ngOnInit() { this.subscription = this.newsService.getNews({ page: this.pageIndex, size: this.itemsPerPage }).subscribe(news => { this.newsItems = news.content - this.totalPages = news.totalPages + this.totalElements = news.totalElements this.changePage(0); }); } @@ -49,6 +48,11 @@ export class NewsListComponent { const displayIndexStart = pageIndex * this.itemsPerPage; const displayIndexEnd = displayIndexStart + this.itemsPerPage; + this.newsService.getNews({ page: this.pageIndex, size: this.itemsPerPage }).subscribe(news => { + this.newsItemsToDisplay = news.content; + this.totalElements = news.totalElements; + }); + this.newsItemsToDisplay = this.newsItems.slice(displayIndexStart, displayIndexEnd); scrollTop('smooth'); } diff --git a/src/app/modules/news/news.module.ts b/src/app/modules/news/news.module.ts index 2dcb4e0..aea9180 100644 --- a/src/app/modules/news/news.module.ts +++ b/src/app/modules/news/news.module.ts @@ -11,7 +11,6 @@ import { NewsArticleComponent } from './components/news-article/news-article.com import { MatIconModule } from '@angular/material/icon'; import { MatPaginatorModule } from '@angular/material/paginator'; - @NgModule({ declarations: [ NewsComponent, diff --git a/src/app/shared/consts.ts b/src/app/shared/consts.ts index e3b8b03..6e62717 100644 --- a/src/app/shared/consts.ts +++ b/src/app/shared/consts.ts @@ -1,3 +1,3 @@ export const API_KEY = process.env['API_KEY'] ?? "INVALID_API_KEY"; -export const API_URL = 'http://localhost:8080' \ No newline at end of file +export const API_URL = 'http://localhost:8080' diff --git a/src/app/shared/interfaces/ImageInterface.ts b/src/app/shared/interfaces/ImageInterface.ts new file mode 100644 index 0000000..358328d --- /dev/null +++ b/src/app/shared/interfaces/ImageInterface.ts @@ -0,0 +1,22 @@ +export interface Image { + size: any; + name: string; + type: string; + data: string; +} + +export interface ImageUploaded { + id: string; + url: string; +} + +export interface ImageEntity { + id: string; + name: string | null; + type: string | null; + data: string | null; +} + +export interface ImageList { + images: ImageEntity[]; +} \ No newline at end of file diff --git a/src/app/shared/interfaces/PostInterfaces.ts b/src/app/shared/interfaces/PostInterfaces.ts index ed861bb..993a078 100644 --- a/src/app/shared/interfaces/PostInterfaces.ts +++ b/src/app/shared/interfaces/PostInterfaces.ts @@ -1,3 +1,5 @@ +import { ImageEntity } from "./ImageInterface"; + export interface PostDetails { title?:string; id: string; @@ -8,6 +10,13 @@ export interface PostDetails { date?: string; } +export interface PostInterface { + title: string; + description: string; + author: string; + images: ImageEntity[]; +} + export interface IPostsResponse { content: PostItem[]; pageable: Pageable; diff --git a/src/app/shared/models/images.ts b/src/app/shared/models/images.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/models/news.ts b/src/app/shared/models/news.ts new file mode 100644 index 0000000..b77bd88 --- /dev/null +++ b/src/app/shared/models/news.ts @@ -0,0 +1,8 @@ +export interface NewsItem { + id: string; + slug: string; + title: string, + content: string; + date: string; + imageUrl: string; +} \ No newline at end of file diff --git a/src/app/shared/services/http.service.ts b/src/app/shared/services/http.service.ts index 8a850b8..5146413 100644 --- a/src/app/shared/services/http.service.ts +++ b/src/app/shared/services/http.service.ts @@ -1,7 +1,6 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { inject, Injectable } from '@angular/core'; -import { Observable, of } from 'rxjs'; -import { AuthResult } from '../interfaces/AuthInterfaces'; +import { catchError, Observable, throwError } from 'rxjs'; import { API_KEY, API_URL } from '../consts'; @Injectable({ @@ -22,15 +21,11 @@ export class HttpService { } post(endpoint: string, data: any, options?: any): Observable{ - // return this.http.post(`${this.apiUrl}/${endpoint}`, data, options).pipe( - // catchError(error => { - // console.error('Error occurred:', error); - // return throwError('Something went wrong!'); - // }) - // ); - return of({ - message: 'Login successful', - isAuthenticated: true - }); + return this.http.post(`${API_URL}/${endpoint}`, data, { ...this.httpOptions }).pipe( + catchError(error => { + console.error('Error occurred:', error); + return throwError('Something went wrong!'); + }) + ); } } diff --git a/src/app/shared/services/images.service.ts b/src/app/shared/services/images.service.ts new file mode 100644 index 0000000..d4b337c --- /dev/null +++ b/src/app/shared/services/images.service.ts @@ -0,0 +1,22 @@ +import { inject, Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { HttpService } from './http.service'; + +@Injectable({ + providedIn: 'root' +}) +export class ImageService { + private http: HttpService = inject(HttpService); + private readonly apiController: string = 'api/images'; + + constructor() {} + + addImages(images: FileList): Observable { + const formData = new FormData(); + for(let i = 0; i < images.length; i++) { + formData.append('images', images[i], images[i].name); + } + + return this.http.post(`${this.apiController}`, formData); + } +} \ No newline at end of file diff --git a/src/app/shared/services/news.service.ts b/src/app/shared/services/news.service.ts index 0fb2312..56783ff 100644 --- a/src/app/shared/services/news.service.ts +++ b/src/app/shared/services/news.service.ts @@ -2,7 +2,7 @@ import { inject, Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { PostData } from 'src/app/modules/admin/components/postComponents/add-post/add-post.component'; import { HttpService } from './http.service'; -import { IPostsResponse, PostDetails } from '../interfaces/PostInterfaces'; +import { IPostsResponse, PostDetails, PostInterface } from '../interfaces/PostInterfaces'; interface PagingParams { page?: number, @@ -40,43 +40,12 @@ export class NewsService { return this.http.get(url) } - onPost(news: PostData){ - let id = String(parseInt(fakeNews[fakeNews.length - 1].id) - 1); - - const date = new Date(); - let day = date.getDate(); - let month = date.getMonth() + 1; - let year = date.getFullYear(); - let currentDate = `${day}-${month}-${year}`; - - console.log({ - id: id, - slug: id, - title: news.title, - content: news.text, - date: currentDate, - imageUrl: news.attachments[0].file, - }) - - fakeNews.push({ - id: id, - slug: id, - title: news.title, - content: news.text, - date: currentDate, - imageUrl: news.attachments[0].file, - }); - - console.log(fakeNews); + handlePost(){ - // let updatedNews: NewsItem = { - // ...news, - // title: news.title, - // content: news.text, - // imageUrl: news.attachments[0].file, - // }; + } - // this.http.post(`${this.apiController}/post`, news); + addPost(news: PostInterface): Observable { + return this.http.post(`${this.apiController}`, news); } onEdit(news: PostData){