Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/app/core/interceptors/handle/error.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export const errorInterceptor: HttpInterceptorFn = (req, next) => {
cancelText: 'Hủy',
onConfirm: () => {
router.navigate(['/auth/identity/login']);
localStorage.removeItem('token');
localStorage.removeItem('refreshToken');
},
},
})
Expand Down
3 changes: 3 additions & 0 deletions src/app/core/router-manager/horizontal-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function getNavHorizontalItems(roles: string[]): SidebarItem[] {
path: '/resource-learning/list-resource',
label: 'Kho tài liệu',
icon: 'fas fa-book',
isVisible: !(roles.length !== 0),
},
{
id: 'message',
Expand Down Expand Up @@ -50,6 +51,7 @@ export function getNavHorizontalItems(roles: string[]): SidebarItem[] {
path: '/service-and-payment/payment',
label: 'Thanh toán',
icon: 'fas fa-credit-card',
isVisible: !(roles.length !== 0),
},
{
id: 'organization ',
Expand All @@ -59,6 +61,7 @@ export function getNavHorizontalItems(roles: string[]): SidebarItem[] {
label: 'Tổ chức',
icon: 'fa-solid fa-building-user',
// isVisible: !roles.includes(auth_lv2[0]),
isVisible: !(roles.length !== 0),
},
];
}
3 changes: 2 additions & 1 deletion src/app/core/services/api-service/exercise.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ export class ExerciseService {
tags,
difficulty,
search
)
),
true
);
}

Expand Down
66 changes: 7 additions & 59 deletions src/app/core/services/api-service/post.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,71 +25,19 @@ export class PostService {
);
}

searchPosts(page: number, size: number, search?: string | null) {
return this.api.get<ApiResponse<IPaginationResponse<PostResponse[]>>>(
API_CONFIG.ENDPOINTS.GET.SEARCH_POST(page, size, search),
true
);
}

getPostDetails(id: string) {
return this.api.get<ApiResponse<PostResponse>>(
API_CONFIG.ENDPOINTS.GET.GET_POST_DETAILS(id)
);
}

//deprecated
// addPost(data: CreatePostRequest) {
// const formData = new FormData();

// // Helper append (chỉ thêm nếu có giá trị thật sự)
// const safeAppend = (key: string, value: any) => {
// if (
// value !== undefined &&
// value !== null &&
// !(typeof value === 'string' && value.trim() === '')
// ) {
// formData.append(key, value);
// }
// };

// // basic fields
// safeAppend('title', data.title);
// safeAppend('orgId', data.orgId);
// safeAppend('content', data.content);
// safeAppend('isPublic', String(data.isPublic));
// safeAppend('allowComment', String(data.allowComment));
// safeAppend('postType', data.postType);
// safeAppend('hashtag', data.hashtag);

// // array fields
// safeAppend(`oldImgesUrls`, data.oldImgesUrls);

// // optional status
// safeAppend('status', data.status);

// // fileDocument
// if (data.fileDocument) {
// const fd = data.fileDocument;
// safeAppend('fileDocument.file', fd.file);
// safeAppend('fileDocument.category', fd.category);
// safeAppend('fileDocument.description', fd.description);
// fd.tags?.forEach((tag, i) => safeAppend(`fileDocument.tags[${i}]`, tag));
// if (typeof fd.isLectureVideo === 'boolean') {
// safeAppend('fileDocument.isLectureVideo', String(fd.isLectureVideo));
// }
// if (typeof fd.isTextBook === 'boolean') {
// safeAppend('fileDocument.isTextBook', String(fd.isTextBook));
// }
// safeAppend('fileDocument.orgId', fd.orgId);
// }

// // Debug log
// for (const [key, val] of formData.entries()) {
// console.log(key, val);
// }

// // Gửi form-data (KHÔNG ép Content-Type)
// return this.api.post<NhatApiResponeNoData>(
// API_CONFIG.ENDPOINTS.POST.ADD_POST,
// formData,
// true
// );
// }

//sử dụng postWithFormData
createPost(data: CreatePostRequest) {
const { fileDocument, ...otherData } = data;
Expand Down
6 changes: 6 additions & 0 deletions src/app/core/services/config-service/api.enpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ export const API_CONFIG = {
GET_CHAT_MESSAGES: (page: number, size: number, conversationId: string) =>
`/chat/messages?page=${page}&size=${size}&conversationId=${conversationId}`,
GET_POST_DETAILS: (postId: string) => `/post/${postId}`,
SEARCH_POST: (page: number, size: number, search?: string | null) => {
let query = `/search/posts/filter?page=${page}&size=${size}`;
if (search) query += `&q=${encodeURIComponent(search)}`;

return query;
},
GET_SAVED_POSTS: (page: number, size: number) =>
`/profile/posts/saved?page=${page}&size=${size}`,
GET_COMMENT_BY_POST_ID: (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<div class="main-exercise-container-layout">
@if (showSidebar) {
<app-main-sidebar
[sidebarItems]="sidebarData"
[isCollapsed]="isSidebarCollapsed"
>
</app-main-sidebar>
@if (showSidebar && isAuthenticated) {
<app-main-sidebar
[sidebarItems]="sidebarData"
[isCollapsed]="isSidebarCollapsed"
>
</app-main-sidebar>
}

<div class="content-exercise-container">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { filter } from 'rxjs/internal/operators/filter';
import { sidebarExercises } from '../../../core/router-manager/vetical-menu-dynamic/exercise-vetical-menu';
import { decodeJWT } from '../../../shared/utils/stringProcess';
import { SidebarItem } from '../../../core/models/data-handle';
import { checkAuthenticated } from '../../../shared/utils/authenRoleActions';

@Component({
selector: 'app-exercise-layout',
Expand All @@ -20,6 +21,7 @@ export class ExerciseLayoutComponent implements OnInit, OnDestroy {
sidebarData: SidebarItem[] = [];

showSidebar = true;
isAuthenticated = false;

// Danh sách các route cần ẩn sidebar
private routesToHideSidebar: string[] = [
Expand All @@ -32,6 +34,7 @@ export class ExerciseLayoutComponent implements OnInit, OnDestroy {
constructor(private router: Router) {
const roles = decodeJWT(localStorage.getItem('token') ?? '')?.payload.roles;
this.sidebarData = sidebarExercises(roles);
this.isAuthenticated = checkAuthenticated();
}

ngOnInit() {
Expand Down
67 changes: 32 additions & 35 deletions src/app/features/post/pages/post-list/post-list.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
[isSvg]="false"
[icon]="'fa fa-search'"
></app-input>
<app-dropdown-button
<!-- <app-dropdown-button
[label]="'Vai trò'"
[options]="tag"
[variant]="'secondary'"
Expand Down Expand Up @@ -47,7 +47,8 @@
[isSearchable]="true"
[minHeight]="true"
[needIndexColor]="true"
></app-dropdown-button>
></app-dropdown-button> -->
@if (authenticated) {
<div class="post-list-button">
<app-btn-type1
thumb="+"
Expand All @@ -56,52 +57,48 @@
(click)="handleAdd()"
></app-btn-type1>
</div>
}
</div>
</div>

<div class="list-post-card-container">
<!-- Hiển thị bài viết khi có dữ liệu và không đang tải -->
<!-- Đang để tạm hàm fetchPostList(), khi nào có loadnextpage sẽ thay thế -->
@if (posts && posts.length > 0) {
<div
class="list-post-card"
appScrollEnd
(appScrollEnd)="loadNextPage()"
>
@for (post of posts; track trackByPostId($index, post)) {
<div>
<app-post-card
[post]="post"
(delete)="openModalDelete(post.id)"
(upvote)="handleUpVote(post.id)"
(downvote)="handleDownVote(post.id)"
(mainClick)="goToDetail($event)"
(save)="handleToggleSave(post.id)"
></app-post-card>
</div>
}
@if (posts && posts.length > 0 && !(isLoadingInitial || isLoadingMore ||
isLoading)) {
<div class="list-post-card" appScrollEnd (appScrollEnd)="loadNextPage()">
@for (post of posts; track trackByPostId($index, post)) {
<div>
<app-post-card
[post]="post"
(delete)="openModalDelete(post.id)"
(upvote)="handleUpVote(post.id)"
(downvote)="handleDownVote(post.id)"
(mainClick)="goToDetail($event)"
(save)="handleToggleSave(post.id)"
></app-post-card>
</div>
}
</div>
}

<!-- Hiển thị skeleton loading khi đang tải -->
@if (isLoadingInitial || isLoadingMore) {
<div class="list-post-card">
<app-skeleton-loading type="card" [count]="8"></app-skeleton-loading>
</div>
@if (isLoadingInitial || isLoadingMore || isLoading) {
<div class="list-post-card">
<app-skeleton-loading type="card" [count]="8"></app-skeleton-loading>
</div>
}

<!-- Hiển thị thông báo "Không có dữ liệu" với hình ảnh động khi không có bài viết -->
@if (!isLoading && (!posts || posts.length === 0)) {
<div
class="no-data-container"
>
<ng-lottie
[options]="lottieOptions"
style="width: 200px; height: 200px"
>
</ng-lottie>
<p>Không có dữ liệu</p>
</div>
<div class="no-data-container">
<ng-lottie
[options]="lottieOptions"
style="width: 200px; height: 200px"
>
</ng-lottie>
<p>Không có dữ liệu</p>
</div>
}
</div>
</div>
Expand All @@ -112,7 +109,7 @@
[items]="trendingData"
title="Popular Technologies"
[maxItems]="15"
>
>
</app-trending>
</div>
<div class="popular-post">
Expand Down
Loading
Loading