From b79a1f72209e9d65ba6f2559f5f4e97a7b2dc57b Mon Sep 17 00:00:00 2001 From: Hieu Nguyen Date: Mon, 8 Aug 2022 23:10:49 +0700 Subject: [PATCH] #5 - implemented when click article title redirect to article list page --- src/app/_api/apiURL.ts | 18 +++ src/app/_model/feed.model.ts | 5 + src/app/app.component.ts | 3 + src/app/pages/home/home.component.html | 4 +- src/app/pages/home/home.component.ts | 54 ++++++- .../post/post-list/post-list.component.html | 146 ++++++++++++++++++ .../post/post-list/post-list.component.scss | 71 +++++++++ .../post-list/post-list.component.spec.ts | 25 +++ src/app/post/post-list/post-list.component.ts | 116 ++++++++++++++ src/app/post/post-routing.module.ts | 2 + src/app/post/post.module.ts | 3 +- src/app/post/post.service.ts | 5 + src/app/shared/navbar/navbar.component.html | 27 +--- src/app/shared/navbar/navbar.component.ts | 13 +- src/index.html | 2 +- 15 files changed, 462 insertions(+), 32 deletions(-) create mode 100644 src/app/_api/apiURL.ts create mode 100644 src/app/post/post-list/post-list.component.html create mode 100644 src/app/post/post-list/post-list.component.scss create mode 100644 src/app/post/post-list/post-list.component.spec.ts create mode 100644 src/app/post/post-list/post-list.component.ts diff --git a/src/app/_api/apiURL.ts b/src/app/_api/apiURL.ts new file mode 100644 index 0000000..baea40d --- /dev/null +++ b/src/app/_api/apiURL.ts @@ -0,0 +1,18 @@ +export const API_SUB = [ + "Chính trị", + "Thời sự", + "Kinh doanh", + "Thế giới", + "Giải trí", + "Thể thao", + "Sức khỏe", + "Đời sống", + "Giáo dục", + "Pháp luật", + "Xe", + "Công nghệ", + "Bất động sản", + // "Tuần Việt Nam", + // "Du lịch", + // "Bạn đọc" +]; \ No newline at end of file diff --git a/src/app/_model/feed.model.ts b/src/app/_model/feed.model.ts index 8c520d8..6c1ec55 100644 --- a/src/app/_model/feed.model.ts +++ b/src/app/_model/feed.model.ts @@ -13,4 +13,9 @@ export interface FeedResponse { feed: Feed; items: Post[]; status: string; +} + +export interface FeedModel { + title: String, + slug:String } \ No newline at end of file diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7b239d7..3368214 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,4 +1,6 @@ import { Component } from '@angular/core'; +import slugify from 'slugify'; +import { API_SUB } from './_api/apiURL'; import { TokenStorageService } from "./_service/token-storage.service"; declare var $: any; @@ -41,4 +43,5 @@ export class AppComponent { routeChanged() { console.log("route changed"); } + } diff --git a/src/app/pages/home/home.component.html b/src/app/pages/home/home.component.html index 0d7d628..fd6dfc8 100644 --- a/src/app/pages/home/home.component.html +++ b/src/app/pages/home/home.component.html @@ -13,7 +13,9 @@
-

{{posts_list[0]?.categories}}

+ +

{{posts_list[0]?.categories}}

+
diff --git a/src/app/pages/home/home.component.ts b/src/app/pages/home/home.component.ts index aa4bbe7..7b90caa 100644 --- a/src/app/pages/home/home.component.ts +++ b/src/app/pages/home/home.component.ts @@ -1,22 +1,23 @@ import { Component, OnInit } from '@angular/core'; -import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; +import slugify from 'slugify'; import { PostService } from 'src/app/post/post.service'; +import { API_SUB } from 'src/app/_api/apiURL'; import { Feed, FeedResponse } from 'src/app/_model/feed.model'; import { Post } from 'src/app/_model/post.model'; - @Component({ selector: 'app-home', templateUrl: './home.component.html', styleUrls: ['./home.component.scss'] }) export class HomeComponent implements OnInit { - title = 'Home'; + title = 'Trang chủ'; posts_list!: Post[]; feed!: Feed; sports_news_list!: Post[]; tech_list!: Post[]; + first_post_slug!: string; constructor(private postService: PostService) { this.posts_list = []; @@ -29,14 +30,43 @@ export class HomeComponent implements OnInit { } load_data() { - this.load_politics_news(); + // this.load_politics_news(); + this.load_hot_news(); this.load_sports_news(); this.load_tech_news(); } + load_hot_news() { + this.postService.get_news_list_by_slug('vietnamnet').subscribe((res: FeedResponse) => { + this.posts_list = res.items; + this.posts_list.forEach(elm => { + var title = elm['title']; + var first = title.replace("'", "'"); + var second = first.replace("'", "'"); + elm['title'] = second; + }); + console.log("politics", res); + + Object.entries(res).map(([key, value]) => { + if (key === 'items') { + this.posts_list = value; + } + if (key === 'feed') { + this.feed = value; + } + }); + }); + } + load_politics_news() { this.postService.get_politics_news().subscribe((res: FeedResponse) => { this.posts_list = res.items; + this.posts_list.forEach(elm => { + var title = elm['title']; + var first = title.replace("'", "'"); + var second = first.replace("'", "'"); + elm['title'] = second; + }); console.log("politics", res); Object.entries(res).map(([key, value]) => { @@ -53,6 +83,12 @@ export class HomeComponent implements OnInit { load_sports_news() { this.postService.get_sports_news().subscribe((res: FeedResponse) => { this.sports_news_list = res.items; + this.sports_news_list.forEach(elm => { + var title = elm['title']; + var first = title.replace("'", "'"); + var second = first.replace("'", "'"); + elm['title'] = second; + }); console.log("sport", res); }); } @@ -60,6 +96,12 @@ export class HomeComponent implements OnInit { load_tech_news() { this.postService.get_technology_news().subscribe((res: FeedResponse) => { this.tech_list = res.items; + this.tech_list.forEach(elm => { + var title = elm['title']; + var first = title.replace("'", "'"); + var second = first.replace("'", "'"); + elm['title'] = second; + }); console.log("tech", res); }); } @@ -91,4 +133,8 @@ export class HomeComponent implements OnInit { return this.tech_list.slice(startIndex, amount); } + get_slug(titleName: string) { + var slug = slugify(titleName.toLowerCase()).replace("dj", "d") + return slug; + } } diff --git a/src/app/post/post-list/post-list.component.html b/src/app/post/post-list/post-list.component.html new file mode 100644 index 0000000..f607923 --- /dev/null +++ b/src/app/post/post-list/post-list.component.html @@ -0,0 +1,146 @@ + +
+

{{title}}

+
+
+
+
+ '../../../assets/images/skeleton-loading.gif' +
+
+
Theo Vietnamnet +
+
+ +
+
+

{{posts_list?.[0]?.description}}

+
+
+
+
+

{{get_duration(posts_list?.[0]?.pubDate||"")}} + + Nguồn : Vietnamnet +

+
+
+
+
+
+ '../../../assets/images/skeleton-loading.gif' +
+
+
Theo Vietnamnet +
+
+ +
+
+

{{posts_list?.[1]?.description}}

+
+
+
+
+

{{get_duration(posts_list?.[1]?.pubDate||"")}} + + Nguồn : Vietnamnet +

+
+
+
+
+
+ +
+
+
+

{{item?.description}}

+
+
+
+ '../../../assets/images/skeleton-loading.gif' +
+
+
+
+

{{get_duration(item?.pubDate||"")}} + + Nguồn : Vietnamnet +

+
+
+
+
+
+
+
+
+ '../../../assets/images/skeleton-loading.gif' +
+ +
+
+
+
+

Mới nhất

+
+
+
+
+
+

{{get_time_in_words(item?.pubDate||"")}} +

+
+
+
+ +
+
+

{{item?.description}}

+
+
+
+
+
+ '../../../assets/images/skeleton-loading.gif' +
+
+
+
+ \ No newline at end of file diff --git a/src/app/post/post-list/post-list.component.scss b/src/app/post/post-list/post-list.component.scss new file mode 100644 index 0000000..570cfb0 --- /dev/null +++ b/src/app/post/post-list/post-list.component.scss @@ -0,0 +1,71 @@ +.hr__line { + border-top: 1px solid black; +} + +.w-90 { + width: 90% !important; +} + +.fs-20 { + font-size: 20px !important; +} +.fs-11 { + font-size: 11px !important; +} + +.hot-post { + font-size: 23px; + font-weight: bold; +} + +.new__post { + font-size: 18px; + font-weight: bold; +} + +.hot-title { + color: black; + text-decoration: none; + font-size: 23px; +} +.hot-title:hover { + color: black; + text-decoration: underline; +} +.line-part { + border-left: 1px solid #e0e3e6; +} +.news-title { + color: black; + text-decoration: none; + font-weight: bold; +} +.news-title:hover { + text-decoration: underline; + color: black; +} +.news-topic { + color: black !important; +} +.credit { + border-bottom: 1px solid #e0e3e6; + padding-bottom: 20px; +} + +.img__sub { + width: 230px; + height: 136px; + object-fit: cover; +} + +@media only screen and (max-width: 768px) { + .img__sub { + width: 100%; + height: 100%; + } +} + +.vl { + border-left: 6px solid green; + height: 100px; +} diff --git a/src/app/post/post-list/post-list.component.spec.ts b/src/app/post/post-list/post-list.component.spec.ts new file mode 100644 index 0000000..2d39c24 --- /dev/null +++ b/src/app/post/post-list/post-list.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PostListComponent } from './post-list.component'; + +describe('PostListComponent', () => { + let component: PostListComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ PostListComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PostListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/post/post-list/post-list.component.ts b/src/app/post/post-list/post-list.component.ts new file mode 100644 index 0000000..275def0 --- /dev/null +++ b/src/app/post/post-list/post-list.component.ts @@ -0,0 +1,116 @@ +import { Component, OnInit } from '@angular/core'; +import { Title } from '@angular/platform-browser'; +import { ActivatedRoute } from '@angular/router'; +import slugify from 'slugify'; +import { API_SUB } from 'src/app/_api/apiURL'; +import { Feed, FeedResponse } from 'src/app/_model/feed.model'; +import { Post } from 'src/app/_model/post.model'; +import { PostService } from '../post.service'; + +@Component({ + selector: 'app-post-list', + templateUrl: './post-list.component.html', + styleUrls: ['./post-list.component.scss'] +}) + +export class PostListComponent implements OnInit { + title!: string; + slug!: string; + posts_list!: Post[]; + feed!: Feed; + + constructor(private activatedRoute: ActivatedRoute, private titleService: Title, private postService: PostService) { + this.posts_list = []; + } + + ngOnInit(): void { + this.load_data(); + } + + load_data() { + this.get_title(); + this.get_post_list(); + this.set_title(); + } + + set_title() { + var final = this.title.substring(0, 1).toUpperCase() + this.title.substring(1, this.title.length); + if (final === "Vietnamnet") { + final = "Tin nóng"; + this.title = "Tin nóng"; + } + this.titleService.setTitle(final + " | News"); + } + + get_post_list() { + this.postService.get_news_list_by_slug(this.slug).subscribe((res: FeedResponse) => { + this.posts_list = res.items; + this.posts_list.forEach(elm => { + var title = elm['title']; + var first = title.replace("&amp;apos;", "'"); + var second = first.replace("&amp;apos;", "'"); + elm['title'] = second; + }); + + console.log(this.slug, res); + + Object.entries(res).map(([key, value]) => { + if (key === 'items') { + this.posts_list = value; + } + if (key === 'feed') { + this.feed = value; + } + }); + }); + } + + get_title() { + this.activatedRoute.params.subscribe((params) => { + this.title = params['title']; + this.slug = params['title']; + }); + + Object.entries(API_SUB).map(([key, value]) => { + var item = { + title: value, + slug: slugify(value.toLowerCase()).replace("dj", "d") + }; + if (item.slug === this.title) { + this.title = item.title; + } + }); + } + + get_duration(date: string) { + var date2: any = new Date(); + var date1: any = new Date(date); + var differenceHour = Math.floor(Math.abs(date2 - date1) / 36e5); + if (differenceHour < 1) { + var differenceMinute = (date2.getTime() - date1.getTime()) / 1000; + differenceMinute /= 60; + return Math.abs(Math.round(differenceMinute)) + " phút trước"; + } + if (differenceHour > 24) { + return Math.floor((date2 - date1) / (1000 * 60 * 60 * 24)) + " ngày trước"; + } + return differenceHour + ' giờ trước'; + } + + get_posts_with_amount(startIndex: number, endIndex: number) { + return this.posts_list.slice(startIndex, endIndex); + } + + get_time_in_words(date: string) { + var monthNames = ["Tháng Một", "Tháng Hai", "Tháng Ba", "Tháng Bốn", "Tháng Năm", "Tháng Sáu", + "Tháng Bảy", "Tháng Tám", "Tháng Chín", "Tháng Mười", "Tháng Mười", "Tháng Mười Hai" + ]; + var d = new Date(date); + var day = d.getDay(); + var month = monthNames[d.getMonth()]; + var year = d.getFullYear(); + + var fullDatetime = 'Ngày '+day+', '+month+' , '+year; + return fullDatetime; + } +} diff --git a/src/app/post/post-routing.module.ts b/src/app/post/post-routing.module.ts index 124e82b..44cdd74 100644 --- a/src/app/post/post-routing.module.ts +++ b/src/app/post/post-routing.module.ts @@ -1,10 +1,12 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { MdbLazyLoadingModule } from 'mdb-angular-ui-kit/lazy-loading'; +import { PostListComponent } from './post-list/post-list.component'; import { SearchResultComponent } from './search-result/search-result.component'; const routes: Routes = [ { path: 'search/:keyword/:tag', component: SearchResultComponent }, + { path: ':title', component: PostListComponent } ]; @NgModule({ diff --git a/src/app/post/post.module.ts b/src/app/post/post.module.ts index a0b94ce..1b2a474 100644 --- a/src/app/post/post.module.ts +++ b/src/app/post/post.module.ts @@ -5,9 +5,10 @@ import { SharedModule } from '../shared/shared.module'; import { SearchResultComponent } from './search-result/search-result.component'; import { MdbLazyLoadingModule } from 'code/mdb-angular-ui-kit/lazy-loading'; import { PostService } from './post.service'; +import { PostListComponent } from './post-list/post-list.component'; @NgModule({ - declarations: [SearchResultComponent], + declarations: [SearchResultComponent, PostListComponent], imports: [ CommonModule, PostRoutingModule, diff --git a/src/app/post/post.service.ts b/src/app/post/post.service.ts index 5546038..9771afd 100644 --- a/src/app/post/post.service.ts +++ b/src/app/post/post.service.ts @@ -25,4 +25,9 @@ export class PostService { return this.http.get("https://api.rss2json.com/v1/api.json?rss_url=https%3A%2F%2Fvietnamnet.vn%2Fcong-nghe.rss") .pipe(catchError(err => this.commonService.handleError(err, "Lỗi khi lấy bài viết công nghệ"))); } + + get_news_list_by_slug(slug: string) { + return this.http.get("https://api.rss2json.com/v1/api.json?rss_url=https%3A%2F%2Fvietnamnet.vn%2F" + slug + ".rss") + .pipe(catchError(err => this.commonService.handleError(err, "Lỗi khi lấy bài viết " + slug))); + } } diff --git a/src/app/shared/navbar/navbar.component.html b/src/app/shared/navbar/navbar.component.html index 09b2d98..fdd426d 100644 --- a/src/app/shared/navbar/navbar.component.html +++ b/src/app/shared/navbar/navbar.component.html @@ -53,31 +53,10 @@ class="fas fa-home fs-4"> - - - - - - - -
diff --git a/src/app/shared/navbar/navbar.component.ts b/src/app/shared/navbar/navbar.component.ts index 981f532..0f88a54 100644 --- a/src/app/shared/navbar/navbar.component.ts +++ b/src/app/shared/navbar/navbar.component.ts @@ -1,5 +1,8 @@ import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; +import slugify from 'slugify'; +import { API_SUB } from 'src/app/_api/apiURL'; +import { FeedModel } from 'src/app/_model/feed.model'; import { TokenStorageService } from "../../_service/token-storage.service"; declare var $: any; @@ -12,12 +15,20 @@ declare var $: any; export class NavbarComponent implements OnInit { currentUser: any; keyword!: string; - + feeds_list!: FeedModel[]; constructor(private tokenStorage: TokenStorageService) { } ngOnInit(): void { this.currentUser = this.tokenStorage.getUser(); + this.feeds_list = []; + Object.entries(API_SUB).map(([key,value]) => { + var item = { + title: value, + slug: slugify(value.toLowerCase()).replace("dj", "d") + }; + this.feeds_list.push(item); + }); } openSearchBox() { diff --git a/src/index.html b/src/index.html index 5aacf08..9745eae 100644 --- a/src/index.html +++ b/src/index.html @@ -3,7 +3,7 @@ - Home | News + Trang chủ | News