From cdde31f7a3e8120f54398eed8f6d6f3343bc2808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B4=20Quang=20=C4=90=E1=BB=A9c?= Date: Wed, 3 Sep 2025 02:19:54 +0700 Subject: [PATCH] add user to block --- .../handle/error-handler.service.ts | 7 + src/app/core/models/organization.model.ts | 13 ++ .../api-service/organization.service.ts | 8 + .../services/config-service/api.enpoints.ts | 3 + .../exercise-code-details.component.html | 4 +- .../exercise-code-details.component.ts | 3 + .../exercise-details.component.ts | 1 + .../list-exercise/list-exercise.component.ts | 1 - .../details-organization.component.scss | 2 +- .../details-organization.component.ts | 8 +- .../modal-add-user-to-block.component.html | 58 ++++++ .../modal-add-user-to-block.component.scss | 150 ++++++++++++++ .../modal-add-user-to-block.component.ts | 95 +++++++++ .../organization-routing.module.ts | 11 +- .../block-details.component.html | 61 ++++++ .../block-details.component.scss | 194 ++++++++++++++++++ .../block-details/block-details.component.ts | 90 ++++++++ .../in-a-organization.component.html | 6 - .../in-a-organization.component.scss | 11 - .../in-a-organization.component.ts | 11 - .../pages/org-blocks/org-blocks.component.ts | 5 +- .../org-details/org-details.component.html | 7 +- .../org-details/org-details.component.scss | 28 +++ .../org-details/org-details.component.ts | 12 +- 24 files changed, 742 insertions(+), 47 deletions(-) create mode 100644 src/app/features/organization/organization-component/modal-add-user-to-block/modal-add-user-to-block.component.html create mode 100644 src/app/features/organization/organization-component/modal-add-user-to-block/modal-add-user-to-block.component.scss create mode 100644 src/app/features/organization/organization-component/modal-add-user-to-block/modal-add-user-to-block.component.ts create mode 100644 src/app/features/organization/pages/block-details/block-details.component.html create mode 100644 src/app/features/organization/pages/block-details/block-details.component.scss create mode 100644 src/app/features/organization/pages/block-details/block-details.component.ts delete mode 100644 src/app/features/organization/pages/in-a-organization/in-a-organization.component.html delete mode 100644 src/app/features/organization/pages/in-a-organization/in-a-organization.component.scss delete mode 100644 src/app/features/organization/pages/in-a-organization/in-a-organization.component.ts diff --git a/src/app/core/interceptors/handle/error-handler.service.ts b/src/app/core/interceptors/handle/error-handler.service.ts index 6b4f0607..bdf80487 100644 --- a/src/app/core/interceptors/handle/error-handler.service.ts +++ b/src/app/core/interceptors/handle/error-handler.service.ts @@ -41,6 +41,13 @@ export class ErrorHandlerService { 'Bạn đã mua sản phẩm này rồi!', 'warning' ); + } else if (errorCode === 4059101) { + sendNotification( + this.store, + 'Hết tiền!', + 'Bạn cần nạp tiền vào tài khoản của mình trước nhé!', + 'error' + ); } else { sendNotification( this.store, diff --git a/src/app/core/models/organization.model.ts b/src/app/core/models/organization.model.ts index 9684cadb..d1090366 100644 --- a/src/app/core/models/organization.model.ts +++ b/src/app/core/models/organization.model.ts @@ -86,3 +86,16 @@ export type ParamGetAllBlockOfOrg = { activeOnlyMembers?: boolean; includeUnassigned?: boolean; }; + +//add user +export type InfoUserNeedToAdd = { + userId: string; + role: string; + active: string; +}; + +export type AddUsersOrgRequest = { + members: InfoUserNeedToAdd[]; + defaultRole: string; + active: boolean; +}; diff --git a/src/app/core/services/api-service/organization.service.ts b/src/app/core/services/api-service/organization.service.ts index 13df2e73..a9b79ae8 100644 --- a/src/app/core/services/api-service/organization.service.ts +++ b/src/app/core/services/api-service/organization.service.ts @@ -3,6 +3,7 @@ import { ApiMethod } from '../config-service/api.methods'; import { ApiResponse, IPaginationResponse } from '../../models/api-response'; import { API_CONFIG } from '../config-service/api.enpoints'; import { + AddUsersOrgRequest, BlockResponse, CreateOrgRequest, EditOrgRequest, @@ -102,4 +103,11 @@ export class OrganizationService { API_CONFIG.ENDPOINTS.GET.GET_BLOCK_DETAILS(blockId, data) ); } + + bulkAddToBlock(blockId: string, data: AddUsersOrgRequest) { + return this.api.post>( + API_CONFIG.ENDPOINTS.POST.BULK_ADD_TO_BLOCK(blockId), + data + ); + } } diff --git a/src/app/core/services/config-service/api.enpoints.ts b/src/app/core/services/config-service/api.enpoints.ts index 8a5073f7..6f58d634 100644 --- a/src/app/core/services/config-service/api.enpoints.ts +++ b/src/app/core/services/config-service/api.enpoints.ts @@ -267,6 +267,9 @@ export const API_CONFIG = { PURCHASE: '/payment/purchase', CREATE_ORGANIZATION: '/org/organization', CREATE_BLOCK_IN_ORG: (orgId: string) => `/org/${orgId}/block`, + BULK_ADD_TO_ORG: (orgId: string) => `/org/${orgId}/members:bulk`, + BULK_ADD_TO_BLOCK: (blockId: string) => + `/org/block/${blockId}/members:bulk`, }, PUT: { EDIT_FILE: (id: string) => `/file/api/FileDocument/edit/${id}`, diff --git a/src/app/features/excercise/exercise-pages/exercise-code-details/exercise-code-details.component.html b/src/app/features/excercise/exercise-pages/exercise-code-details/exercise-code-details.component.html index f1398eb5..84c6a2fe 100644 --- a/src/app/features/excercise/exercise-pages/exercise-code-details/exercise-code-details.component.html +++ b/src/app/features/excercise/exercise-pages/exercise-code-details/exercise-code-details.component.html @@ -81,9 +81,7 @@

{{ exercise.title }}

- - {{ exercise.cost }} - + {{ exercise.cost | formatView }} VNĐ
diff --git a/src/app/features/excercise/exercise-pages/exercise-code-details/exercise-code-details.component.ts b/src/app/features/excercise/exercise-pages/exercise-code-details/exercise-code-details.component.ts index 52cb1944..cc63a0bb 100644 --- a/src/app/features/excercise/exercise-pages/exercise-code-details/exercise-code-details.component.ts +++ b/src/app/features/excercise/exercise-pages/exercise-code-details/exercise-code-details.component.ts @@ -31,6 +31,7 @@ import { isAvailabelTime } from '../../../../shared/utils/availableTime'; import { PaymentService } from '../../../../core/services/api-service/payment.service'; import { v4 as uuidv4 } from 'uuid'; import { IPurChaseTransactionRequest } from '../../../../core/models/service-and-payment'; +import { FormatViewPipe } from '../../../../shared/pipes/format-view.pipe'; @Component({ selector: 'app-exercise-code-details', @@ -39,6 +40,7 @@ import { IPurChaseTransactionRequest } from '../../../../core/models/service-and FormsModule, UpdateCodeDetailsComponent, UpdateExerciseComponent, + FormatViewPipe, ], templateUrl: './exercise-code-details.component.html', styleUrls: ['./exercise-code-details.component.scss'], @@ -230,6 +232,7 @@ export class ExerciseCodeDetailsComponent { this.authorName = res.result.user.displayName; this.authorRoles = Array.from(res.result.user.roles).join(', '); this.avatarUrl = res.result.user.avatarUrl ?? avatarUrlDefault; + this.isBought = res.result.purchased; } this.isActionActive = activeForMyContent( res.result.user?.username ?? '', diff --git a/src/app/features/excercise/exercise-pages/exercise-details/exercise-details.component.ts b/src/app/features/excercise/exercise-pages/exercise-details/exercise-details.component.ts index 7da48952..f8a85aa6 100644 --- a/src/app/features/excercise/exercise-pages/exercise-details/exercise-details.component.ts +++ b/src/app/features/excercise/exercise-pages/exercise-details/exercise-details.component.ts @@ -224,6 +224,7 @@ export class ExerciseDetailsComponent implements OnInit { if (res.result.user) { this.authorName = res.result.user.displayName; this.avatarUrl = res.result.user.avatarUrl; + this.isBought = res.result.purchased; this.availabelDate = res.result.startTime ? new Date(res.result.startTime) : null; diff --git a/src/app/features/excercise/exercise-pages/list-exercise/list-exercise.component.ts b/src/app/features/excercise/exercise-pages/list-exercise/list-exercise.component.ts index fae0a9a1..3d36f9b1 100644 --- a/src/app/features/excercise/exercise-pages/list-exercise/list-exercise.component.ts +++ b/src/app/features/excercise/exercise-pages/list-exercise/list-exercise.component.ts @@ -89,7 +89,6 @@ export class ListExerciseComponent implements OnInit { { value: '1', label: 'Trung bình' }, { value: '2', label: 'Khó' }, ]; - const role = decodeJWT(localStorage.getItem('token') ?? '')?.payload.scope; } private mapExerciseResToCardDataUI(data: ExerciseItem[]): CardExcercise[] { diff --git a/src/app/features/organization/organization-component/details-organization/details-organization.component.scss b/src/app/features/organization/organization-component/details-organization/details-organization.component.scss index 61975904..007fff2f 100644 --- a/src/app/features/organization/organization-component/details-organization/details-organization.component.scss +++ b/src/app/features/organization/organization-component/details-organization/details-organization.component.scss @@ -108,7 +108,7 @@ .org-name { margin: 0; - font-size: 28px; + font-size: 24px; font-weight: 700; color: var(--title-text); line-height: 1.2; diff --git a/src/app/features/organization/organization-component/details-organization/details-organization.component.ts b/src/app/features/organization/organization-component/details-organization/details-organization.component.ts index 098c41cc..80427330 100644 --- a/src/app/features/organization/organization-component/details-organization/details-organization.component.ts +++ b/src/app/features/organization/organization-component/details-organization/details-organization.component.ts @@ -53,9 +53,9 @@ export class DetailsOrganizationComponent implements OnInit { }); } - getStatusLabel(status: number): string { + getStatusLabel(status: number | string): string { switch (status) { - case 0: + case 'Active': return 'Hoạt động'; case 1: return 'Tạm ngưng'; @@ -66,9 +66,9 @@ export class DetailsOrganizationComponent implements OnInit { } } - getStatusClass(status: number): string { + getStatusClass(status: number | string): string { switch (status) { - case 0: + case 'Active': return 'status-active'; case 1: return 'status-inactive'; diff --git a/src/app/features/organization/organization-component/modal-add-user-to-block/modal-add-user-to-block.component.html b/src/app/features/organization/organization-component/modal-add-user-to-block/modal-add-user-to-block.component.html new file mode 100644 index 00000000..1ceb3d10 --- /dev/null +++ b/src/app/features/organization/organization-component/modal-add-user-to-block/modal-add-user-to-block.component.html @@ -0,0 +1,58 @@ + + + diff --git a/src/app/features/organization/organization-component/modal-add-user-to-block/modal-add-user-to-block.component.scss b/src/app/features/organization/organization-component/modal-add-user-to-block/modal-add-user-to-block.component.scss new file mode 100644 index 00000000..fbe7cddd --- /dev/null +++ b/src/app/features/organization/organization-component/modal-add-user-to-block/modal-add-user-to-block.component.scss @@ -0,0 +1,150 @@ +.modal-backdrop { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.4); + opacity: 0; + transition: opacity 0.3s ease; + pointer-events: none; + visibility: hidden; + + &.show { + opacity: 1; + pointer-events: auto; + visibility: visible; + z-index: 10000; + } +} + +.modal-wrapper { + position: fixed; + inset: 0; + display: flex; + justify-content: center; + align-items: center; + transform: translateY(-30px); + opacity: 0; + transition: all 0.3s ease; + visibility: hidden; + + &.show { + transform: translateY(0); + opacity: 1; + visibility: visible; + z-index: 10000; + } +} + +.modal-content { + background: #fff; + border-radius: 12px; + width: 600px; + max-width: 90%; + max-height: 80%; + overflow-y: auto; + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2); + animation: fadeIn 0.3s ease; + display: flex; + flex-direction: column; +} + +.modal-header, +.modal-footer { + padding: 12px 16px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.search-box { + padding: 8px 16px; + + input { + width: 100%; + padding: 8px 12px; + border-radius: 8px; + border: 1px solid #ccc; + } +} + +.results { + padding: 8px 16px; + .user-item { + display: flex; + align-items: center; + gap: 12px; + padding: 8px; + cursor: pointer; + border-radius: 8px; + transition: background 0.2s; + + &:hover { + background: #f5f5f5; + } + + img { + width: 36px; + height: 36px; + border-radius: 50%; + } + + strong { + display: block; + font-size: 14px; + } + span { + font-size: 12px; + color: #666; + } + } +} + +.selected { + padding: 8px 16px; + h3 { + margin: 8px 0; + } + .chip { + display: inline-flex; + align-items: center; + padding: 4px 8px; + background: #e5f0ff; + border-radius: 16px; + margin: 4px; + font-size: 13px; + + button { + background: none; + border: none; + margin-left: 6px; + cursor: pointer; + font-weight: bold; + } + } +} + +.btn-cancel { + padding: 8px 16px; + border: none; + background: #f1f1f1; + border-radius: 8px; + cursor: pointer; +} +.btn-save { + padding: 8px 16px; + border: none; + background: #2563eb; + color: white; + border-radius: 8px; + cursor: pointer; + + &:disabled { + background: #93c5fd; + } +} + +.close-btn { + font-size: 20px; + background: none; + border: none; + cursor: pointer; +} diff --git a/src/app/features/organization/organization-component/modal-add-user-to-block/modal-add-user-to-block.component.ts b/src/app/features/organization/organization-component/modal-add-user-to-block/modal-add-user-to-block.component.ts new file mode 100644 index 00000000..9c6ae530 --- /dev/null +++ b/src/app/features/organization/organization-component/modal-add-user-to-block/modal-add-user-to-block.component.ts @@ -0,0 +1,95 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { debounceTime, Subject, switchMap } from 'rxjs'; +import { SearchUserProfileResponse } from '../../../../core/models/user.models'; +import { InfoUserNeedToAdd } from '../../../../core/models/organization.model'; +import { UserService } from '../../../../core/services/api-service/user.service'; +import { OrganizationService } from '../../../../core/services/api-service/organization.service'; + +@Component({ + selector: 'app-modal-add-user-to-block', + standalone: true, + imports: [CommonModule, FormsModule], + templateUrl: './modal-add-user-to-block.component.html', + styleUrls: ['./modal-add-user-to-block.component.scss'], +}) +export class ModalAddUserToBlockComponent { + @Input() isOpen = false; + @Input() blockId!: string; + @Output() closed = new EventEmitter(); + @Output() saved = new EventEmitter(); + + searchQuery = ''; + searchChanged = new Subject(); + + searchResults: SearchUserProfileResponse[] = []; + selectedUsers: InfoUserNeedToAdd[] = []; + + loading = false; + submitting = false; + + constructor( + private userService: UserService, + private orgService: OrganizationService + ) { + this.searchChanged + .pipe( + debounceTime(400), + switchMap((query) => + this.userService.searchUserProfile(1, 10, { q: query }) + ) + ) + .subscribe({ + next: (res) => { + this.searchResults = res.result.data; + }, + error: () => { + this.searchResults = []; + }, + }); + } + + onSearchChange(query: string) { + this.searchChanged.next(query); + } + + addUser(user: SearchUserProfileResponse) { + if (this.selectedUsers.find((u) => u.userId === user.userId)) return; + this.selectedUsers.push({ + userId: user.userId, + role: user.roles[0], + active: user.active.toString(), + }); + } + + removeUser(userId: string) { + this.selectedUsers = this.selectedUsers.filter((u) => u.userId !== userId); + } + + submit() { + if (!this.blockId || this.selectedUsers.length === 0) return; + this.submitting = true; + this.orgService + .bulkAddToBlock(this.blockId, { + members: this.selectedUsers, + defaultRole: 'STUDENT', + active: true, + }) + .subscribe({ + next: () => { + this.saved.emit(); + this.close(); + this.submitting = false; + }, + error: (err) => { + this.submitting = false; + }, + }); + } + + close() { + this.isOpen = false; + setTimeout(() => this.closed.emit(), 300); // delay cho transition + } +} diff --git a/src/app/features/organization/organization-routing.module.ts b/src/app/features/organization/organization-routing.module.ts index 2ad86dc5..71336213 100644 --- a/src/app/features/organization/organization-routing.module.ts +++ b/src/app/features/organization/organization-routing.module.ts @@ -3,9 +3,10 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { LayoutOrganizationComponent } from './layout-organization/layout-organization.component'; import { OrganizationManagementComponent } from './pages/organization-management/organization-management.component'; -import { InAOrganizationComponent } from './pages/in-a-organization/in-a-organization.component'; import { RoleGuard } from '../../core/guards/router-protected/role.guard'; import { OrgBlocksComponent } from './pages/org-blocks/org-blocks.component'; +import { BlockDetailsComponent } from './pages/block-details/block-details.component'; +import { OrgDetailsComponent } from './pages/org-details/org-details.component'; const routes: Routes = [ { @@ -21,7 +22,7 @@ const routes: Routes = [ }, { path: 'in-org/:orgId', - component: InAOrganizationComponent, + component: OrgDetailsComponent, children: [ { path: 'org-details', @@ -29,6 +30,12 @@ const routes: Routes = [ title: 'Chi tiết tổ chức', data: { breadcrumb: 'Chi tiết tổ chức' }, }, + { + path: 'block-details/:blockId', + component: BlockDetailsComponent, + title: 'Chi tiết khối', + data: { breadcrumb: 'Chi tiết khối' }, + }, ], title: 'Tổ chức', data: { breadcrumb: 'Tổ chức' }, diff --git a/src/app/features/organization/pages/block-details/block-details.component.html b/src/app/features/organization/pages/block-details/block-details.component.html new file mode 100644 index 00000000..cd78d3ce --- /dev/null +++ b/src/app/features/organization/pages/block-details/block-details.component.html @@ -0,0 +1,61 @@ +
+
+
+

{{ block.name }}

+
+ Mã: {{ block.code }} +
+

{{ block.description }}

+
+
+ +
+
+ +
+ +
+
+

Thành viên ({{ members.length }})

+ +
+ +
+
+ avatar +
+
+ {{ m.user.displayName }} + +
+ +
+
+ + {{ m.role }} +
+
+
Đang tải...
+
+
+ + +
diff --git a/src/app/features/organization/pages/block-details/block-details.component.scss b/src/app/features/organization/pages/block-details/block-details.component.scss new file mode 100644 index 00000000..252be4d8 --- /dev/null +++ b/src/app/features/organization/pages/block-details/block-details.component.scss @@ -0,0 +1,194 @@ +.block-details-page { + padding: 20px; + max-width: 1200px; + margin: 0 auto; +} + +.block-header-section { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + padding-bottom: 20px; +} + +.info-block h1 { + font-size: 2.5rem; + font-weight: 700; + margin: 0; +} + +.info-block .meta-info .code { + font-size: 0.9rem; + color: #777; + display: block; + margin-top: 5px; +} + +.info-block .description { + margin-top: 10px; + color: #555; + line-height: 1.5; +} + +.actions .btn-primary { + background-color: #007bff; /* Ví dụ màu xanh dương */ + color: white; + border: none; + padding: 12px 24px; + border-radius: 8px; + font-size: 1rem; + cursor: pointer; + transition: background-color 0.3s ease; + display: flex; + align-items: center; + gap: 8px; +} + +.divider { + border: 0; + height: 1px; + background-color: #ddd; + margin: 20px 0; +} + +.members-section { + background-color: #f9f9f9; + border-radius: 12px; + padding: 20px; +} + +.members-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; +} + +.members-header h2 { + font-size: 1.5rem; + font-weight: 600; + margin: 0; +} + +.search-box { + position: relative; + width: 250px; +} + +.search-box input { + width: 100%; + padding: 8px 12px; + padding-right: 40px; + border-radius: 8px; + border: 1px solid #ccc; + box-sizing: border-box; +} + +.search-box .fa-search { + position: absolute; + right: 15px; + top: 50%; + transform: translateY(-50%); + color: #999; +} + +.members-list { + max-height: 500px; /* Chiều cao cố định cho phép cuộn */ + overflow-y: auto; + padding-right: 5px; /* Để tránh thanh cuộn che mất nội dung */ +} + +.member-card { + display: flex; + align-items: center; + gap: 15px; + padding: 15px; + background: white; + border-radius: 12px; + margin-bottom: 10px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05); + transition: transform 0.2s ease; +} + +.member-card:hover { + transform: translateY(-3px); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1); +} + +.member-card.inactive { + opacity: 0.6; +} + +.avatar { + width: 50px; + height: 50px; + border-radius: 50%; + object-fit: cover; +} + +.member-info { + flex-grow: 1; +} + +.member-info .name-status { + display: flex; + align-items: center; + gap: 8px; +} + +.member-info .name { + font-weight: 600; + font-size: 1rem; +} + +.member-info .email { + font-size: 0.8rem; + color: #777; +} + +.role-badge { + font-size: 0.9rem; + font-weight: 600; + color: #007bff; + display: flex; + align-items: center; + gap: 5px; +} + +.role-badge .fa-crown { + color: gold; +} + +.status-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background-color: #ccc; +} + +.status-dot.active { + background-color: #28a745; +} + +.loading { + text-align: center; + padding: 12px; + font-size: 0.9rem; + color: #777; +} + +@media (max-width: 768px) { + .block-header-section { + flex-direction: column; + align-items: flex-start; + } + .actions { + width: 100%; + margin-top: 15px; + } + .search-box { + width: 100%; + margin-top: 10px; + } +} diff --git a/src/app/features/organization/pages/block-details/block-details.component.ts b/src/app/features/organization/pages/block-details/block-details.component.ts new file mode 100644 index 00000000..6ada6cdf --- /dev/null +++ b/src/app/features/organization/pages/block-details/block-details.component.ts @@ -0,0 +1,90 @@ +import { Component, OnInit } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ActivatedRoute } from '@angular/router'; +import { ScrollEndDirective } from '../../../../shared/directives/scroll-end.directive'; +import { OrganizationService } from '../../../../core/services/api-service/organization.service'; +import { + BlockResponse, + MemberResponse, +} from '../../../../core/models/organization.model'; +import { ModalAddUserToBlockComponent } from '../../organization-component/modal-add-user-to-block/modal-add-user-to-block.component'; +import { avatarUrlDefault } from '../../../../core/constants/value.constant'; + +@Component({ + selector: 'app-block-details', + standalone: true, + imports: [CommonModule, ScrollEndDirective, ModalAddUserToBlockComponent], + templateUrl: './block-details.component.html', + styleUrls: ['./block-details.component.scss'], +}) +export class BlockDetailsComponent implements OnInit { + blockId!: string; + block!: BlockResponse; + avatarDefault = avatarUrlDefault; + + members: MemberResponse[] = []; + page = 1; + size = 15; + totalPages = 1; + isLoading = false; + isAddUserOpen = false; + + constructor( + private route: ActivatedRoute, + private orgService: OrganizationService + ) { + this.route.paramMap.subscribe((params) => { + this.blockId = params.get('blockId') || ''; + }); + } + + ngOnInit(): void { + if (this.blockId) { + this.loadBlockDetails(); + } + } + + loadBlockDetails(loadMore = false) { + if (this.isLoading || (loadMore && this.page > this.totalPages)) return; + + this.isLoading = true; + this.orgService + .getBlockDetails(this.blockId, { + membersPage: this.page, + membersSize: this.size, + activeOnly: true, + }) + .subscribe({ + next: (res) => { + this.block = res.result; + this.totalPages = this.block.members.totalPages; + + if (loadMore) { + this.members = [...this.members, ...this.block.members.data]; + } else { + this.members = this.block.members.data; + } + + this.isLoading = false; + }, + error: () => { + this.isLoading = false; + }, + }); + } + + reloadMembers() { + this.loadBlockDetails(); + } + + onScrollEnd() { + if (this.page < this.totalPages) { + this.page++; + this.loadBlockDetails(true); + } + } + + openModalAdd() { + this.isAddUserOpen = !this.isAddUserOpen; + } +} diff --git a/src/app/features/organization/pages/in-a-organization/in-a-organization.component.html b/src/app/features/organization/pages/in-a-organization/in-a-organization.component.html deleted file mode 100644 index 59916d08..00000000 --- a/src/app/features/organization/pages/in-a-organization/in-a-organization.component.html +++ /dev/null @@ -1,6 +0,0 @@ -
- -
- -
-
diff --git a/src/app/features/organization/pages/in-a-organization/in-a-organization.component.scss b/src/app/features/organization/pages/in-a-organization/in-a-organization.component.scss deleted file mode 100644 index fbf6f872..00000000 --- a/src/app/features/organization/pages/in-a-organization/in-a-organization.component.scss +++ /dev/null @@ -1,11 +0,0 @@ -.organization-page-container { - display: flex; - flex-direction: column; - height: calc(100vh - 150px); - overflow: auto; - .content-router-org { - display: flex; - flex-direction: column; - padding: 12px; - } -} diff --git a/src/app/features/organization/pages/in-a-organization/in-a-organization.component.ts b/src/app/features/organization/pages/in-a-organization/in-a-organization.component.ts deleted file mode 100644 index 94761894..00000000 --- a/src/app/features/organization/pages/in-a-organization/in-a-organization.component.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Component } from '@angular/core'; -import { DetailsOrganizationComponent } from '../../organization-component/details-organization/details-organization.component'; -import { AdminRoutingModule } from '../../../dashboard/dashboard-routing.module'; - -@Component({ - selector: 'app-in-a-organization', - imports: [DetailsOrganizationComponent, AdminRoutingModule], - templateUrl: './in-a-organization.component.html', - styleUrl: './in-a-organization.component.scss', -}) -export class InAOrganizationComponent {} diff --git a/src/app/features/organization/pages/org-blocks/org-blocks.component.ts b/src/app/features/organization/pages/org-blocks/org-blocks.component.ts index 0f3226ff..210720a5 100644 --- a/src/app/features/organization/pages/org-blocks/org-blocks.component.ts +++ b/src/app/features/organization/pages/org-blocks/org-blocks.component.ts @@ -170,6 +170,9 @@ export class OrgBlocksComponent implements OnInit { } goToBlock(id: string) { - this.router.navigate(['']); + this.router.navigate([ + `/organization/in-org/${this.orgId}/block-details/`, + id, + ]); } } diff --git a/src/app/features/organization/pages/org-details/org-details.component.html b/src/app/features/organization/pages/org-details/org-details.component.html index c9c5ae2e..59916d08 100644 --- a/src/app/features/organization/pages/org-details/org-details.component.html +++ b/src/app/features/organization/pages/org-details/org-details.component.html @@ -1 +1,6 @@ -

org-details works!

+
+ +
+ +
+
diff --git a/src/app/features/organization/pages/org-details/org-details.component.scss b/src/app/features/organization/pages/org-details/org-details.component.scss index e69de29b..50166006 100644 --- a/src/app/features/organization/pages/org-details/org-details.component.scss +++ b/src/app/features/organization/pages/org-details/org-details.component.scss @@ -0,0 +1,28 @@ +.organization-page-container { + display: flex; + flex-direction: column; + height: calc(100vh - 150px); + overflow: auto; + &::-webkit-scrollbar { + width: 8px; // chiều rộng thanh cuộn + } + + &::-webkit-scrollbar-track { + background: transparent; // nền phía sau thanh cuộn + } + &::-webkit-scrollbar-button { + display: none; // ẩn mũi tên hai đầu + height: 0; + width: 0; + } + &::-webkit-scrollbar-button:single-button { + display: none; // ẩn mũi tên ↑ và ↓ + height: 0; + width: 0; + } + .content-router-org { + display: flex; + flex-direction: column; + padding: 12px; + } +} diff --git a/src/app/features/organization/pages/org-details/org-details.component.ts b/src/app/features/organization/pages/org-details/org-details.component.ts index 0f7d3b40..9ffcc1a9 100644 --- a/src/app/features/organization/pages/org-details/org-details.component.ts +++ b/src/app/features/organization/pages/org-details/org-details.component.ts @@ -1,11 +1,11 @@ import { Component } from '@angular/core'; +import { DetailsOrganizationComponent } from '../../organization-component/details-organization/details-organization.component'; +import { AdminRoutingModule } from '../../../dashboard/dashboard-routing.module'; @Component({ - selector: 'app-org-details', - imports: [], + selector: 'app-in-a-organization', + imports: [DetailsOrganizationComponent, AdminRoutingModule], templateUrl: './org-details.component.html', - styleUrl: './org-details.component.scss' + styleUrl: './org-details.component.scss', }) -export class OrgDetailsComponent { - -} +export class OrgDetailsComponent {}