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
1 change: 1 addition & 0 deletions src/app/core/interceptors/handle/error-handler.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class ErrorHandlerService {
cancelText: 'Hủy',
onConfirm: () => {
this.router.navigate(['/auth/identity/login']);
localStorage.removeItem('token');
},
onCancel: () => {
sendNotification(this.store, errorStatus, errorMessage, 'error');
Expand Down
1 change: 1 addition & 0 deletions src/app/core/models/api-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type loginResponse = {
authenticated: boolean;
enabled: boolean;
active: boolean;
needPasswordSetup: boolean;
};

export interface IPaginationResponse<T> {
Expand Down
1 change: 1 addition & 0 deletions src/app/core/models/code.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export type ExerciseCodeResponse = {
endTime: string; // ISO datetime
duration: number; // minutes
allowDiscussionId: string;
purchased: boolean;
resourceIds: string[];
tags: string[];
allowAiQuestion: boolean;
Expand Down
2 changes: 2 additions & 0 deletions src/app/core/models/exercise.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type ExerciseItem = {
freeForOrg: boolean;
tags: Set<string>;
createdAt: string;
purchased: boolean;
};

export type UserBasicInfo = {
Expand Down Expand Up @@ -101,6 +102,7 @@ export interface ExerciseQuiz {
endTime: string;
duration: number;
allowDiscussionId: string;
purchased: boolean;
resourceIds: string[];
tags: string[];
allowAiQuestion: boolean;
Expand Down
7 changes: 7 additions & 0 deletions src/app/core/services/api-service/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ export class AuthService {
);
}

createInitialPassword(password: string) {
return this.api.post<ApiResponse<null>>(
API_CONFIG.ENDPOINTS.POST.CREATE_FIRST_PASSWORD,
{ password }
);
}

requestForgotPassword(email: string) {
return this.api.post<ApiResponse<RequestForgotPasswordResponse>>(
API_CONFIG.ENDPOINTS.POST.REQUEST_FORGOT_PASSWORD,
Expand Down
1 change: 1 addition & 0 deletions src/app/core/services/config-service/api.enpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export const API_CONFIG = {
LOGIN: '/identity/auth/login',
REGISTER: '/identity/auth/register',
LOGOUT: '/identity/auth/logout',
CREATE_FIRST_PASSWORD: '/identity/auth/user/create-password',
REQUEST_FORGOT_PASSWORD: '/identity/auth/forgot-password/request',
RESET_PASSWORD: `/identity/auth/forgot-password/reset`,
REFRESH_TOKEN: '/identity/auth/refresh',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!-- set-password-modal.component.html -->
<div class="modal-backdrop" *ngIf="isOpen" (click)="close()"></div>

<div class="modal-wrapper" *ngIf="isOpen">
<div class="modal-content">
<h2>Đặt mật khẩu mới</h2>

<form (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="password">Mật khẩu mới</label>
<input
id="password"
type="password"
[(ngModel)]="password"
name="password"
required
/>
</div>

<div class="form-group">
<label for="confirmPassword">Nhập lại mật khẩu</label>
<input
id="confirmPassword"
type="password"
[(ngModel)]="confirmPassword"
name="confirmPassword"
required
/>
</div>

<p class="error-message" *ngIf="errorMessage">{{ errorMessage }}</p>

<div class="actions">
<button type="button" class="btn cancel" (click)="close()">Hủy</button>
<button type="submit" class="btn confirm" [disabled]="isLoading">
{{ isLoading ? "Đang xử lý..." : "Xác nhận" }}
</button>
</div>
</form>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/* set-password-modal.component.scss */
.modal-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
animation: fadeIn 0.3s ease forwards;
z-index: 1000;
}

.modal-wrapper {
position: fixed;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}

.modal-content {
background: #fff;
border-radius: 12px;
padding: 24px;
width: 400px;
max-width: 90%;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
animation: slideIn 0.3s ease forwards;
}

h2 {
margin-bottom: 16px;
font-size: 20px;
text-align: center;
}

.form-group {
margin-bottom: 16px;
display: flex;
flex-direction: column;

label {
font-size: 14px;
margin-bottom: 6px;
}

input {
padding: 10px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 14px;

&:focus {
outline: none;
border-color: #3f51b5;
box-shadow: 0 0 0 2px rgba(63, 81, 181, 0.2);
}
}
}

.error-message {
color: #d32f2f;
font-size: 13px;
margin-bottom: 10px;
}

.actions {
display: flex;
justify-content: flex-end;
gap: 10px;

.btn {
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
border: none;
font-size: 14px;
transition: all 0.2s ease;

&.cancel {
background: #e0e0e0;
&:hover {
background: #d5d5d5;
}
}

&.confirm {
background: #3f51b5;
color: white;
&:hover {
background: #303f9f;
}
&:disabled {
background: #9fa8da;
cursor: not-allowed;
}
}
}
}

/* Animations */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// set-password-modal.component.ts
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { AuthService } from '../../../../../core/services/api-service/auth.service';

@Component({
selector: 'app-set-password-modal',
standalone: true,
imports: [CommonModule, FormsModule],
templateUrl: './set-password-modal.component.html',
styleUrls: ['./set-password-modal.component.scss'],
})
export class SetPasswordModalComponent {
@Input() isOpen = false;
@Output() closed = new EventEmitter<void>();

password = '';
confirmPassword = '';
isLoading = false;
errorMessage = '';

constructor(private authService: AuthService) {}

close() {
this.closed.emit();
this.resetForm();
this.isOpen = !this.isOpen;
}

resetForm() {
this.password = '';
this.confirmPassword = '';
this.errorMessage = '';
this.isLoading = false;
}

onSubmit() {
if (!this.password || !this.confirmPassword) {
this.errorMessage = 'Vui lòng nhập đầy đủ thông tin';
return;
}
if (this.password.length < 6) {
this.errorMessage = 'Mật khẩu phải có ít nhất 6 ký tự';
return;
}
if (this.password !== this.confirmPassword) {
this.errorMessage = 'Mật khẩu nhập lại không khớp';
return;
}

this.isLoading = true;
this.authService.createInitialPassword(this.password).subscribe({
next: () => {
this.isLoading = false;
this.close();
// Có thể bắn event success hoặc toast ở đây
},
error: () => {
this.isLoading = false;
},
});
}
}
1 change: 1 addition & 0 deletions src/app/features/auth/pages/login/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export class Login {
authenticated: false,
enabled: false,
active: false,
needPasswordSetup: false,
};

constructor(
Expand Down
20 changes: 19 additions & 1 deletion src/app/features/auth/pages/oauth-callback/oauth-callback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { Router, ActivatedRoute } from '@angular/router';
import { AuthService } from '../../../../core/services/api-service/auth.service';
import { LoadingOverlayComponent } from '../../../../shared/components/fxdonad-shared/loading-overlay/loading-overlay.component';
import { Store } from '@ngrx/store';
import { sendNotification } from '../../../../shared/utils/notification';
import {
openModalNotification,
sendNotification,
} from '../../../../shared/utils/notification';
import { setVariable } from '../../../../shared/store/variable-state/variable.actions';

@Component({
selector: 'app-oauth-callback',
Expand Down Expand Up @@ -38,6 +42,20 @@ export class OauthCallbackComponent {
if (res.code === 20000) {
this.router.navigate(['/exercise/exercise-layout/list']);
localStorage.setItem('token', res.result.accessToken);
localStorage.setItem('refreshToken', res.result.refreshToken);

if (!res.result.needPasswordSetup) {
openModalNotification(
this.store,
'Cảnh báo',
'Tài khoản của bạn chưa có mật khẩu, hãy cài đặt nó sớm nhất có thể để tránh rủi ro.',
'Đồng ý',
'hủy'
);
this.store.dispatch(
setVariable({ key: 'needPasswordSetup', value: true })
);
}
} else {
this.router.navigate(['/auth/identity/login']);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export class ExerciseCodeDetailsComponent {
active: false,
cost: 0,
freeForOrg: false,
purchased: false,
visibility: false,
startTime: '',
endTime: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export class ExerciseDetailsComponent implements OnInit {
freeForOrg: false,
visibility: false,
startTime: '',
purchased: false,
endTime: '',
duration: 0,
allowDiscussionId: 'chưa có',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,9 @@ export class ListExerciseComponent implements OnInit {
next: (res) => {
this.pageIndex = 1;
this.searchData = '';
this.fetchData();
setTimeout(() => {
this.fetchData();
}, 2000);
this.showModalCreate = false;
sendNotification(this.store, 'Thành công', res.message, 'success');
this.store.dispatch(clearLoading());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';
import { BehaviorSubject, Observable, combineLatest, of } from 'rxjs';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { switchMap, map, startWith, catchError } from 'rxjs/operators';
import {
ApiResponse,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
display: flex;
justify-content: end;
z-index: 3;
// Bỏ sự kiện cho toàn container
pointer-events: none;

.chat-box {
pointer-events: auto; // Chỉ phần này thao tác được
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/app/shared/components/my-shared/header/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,12 @@
<app-profile-menu
*ngIf="showProfileMenu"
[isVisible]="isMenuVisible"
[needSetNewPass]="needCreateNewPass"
(closeMenu)="onCloseMenu()"
(openSetPassword)="openSetPassword($event)"
></app-profile-menu>

<app-set-password-modal
[isOpen]="setPassword"
(closed)="setPassword = false"
></app-set-password-modal>
Loading