Skip to content

Commit 8cc6abe

Browse files
authored
Merge pull request #144 from CapstoneProjectCMC/feature/sap-service-and-payment
fix AI layout
2 parents 5803753 + 4e02d31 commit 8cc6abe

File tree

22 files changed

+324
-82
lines changed

22 files changed

+324
-82
lines changed

src/app/core/interceptors/handle/error-handler.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export class ErrorHandlerService {
2626
cancelText: 'Hủy',
2727
onConfirm: () => {
2828
this.router.navigate(['/auth/identity/login']);
29+
localStorage.removeItem('token');
2930
},
3031
onCancel: () => {
3132
sendNotification(this.store, errorStatus, errorMessage, 'error');

src/app/core/models/api-response.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type loginResponse = {
2525
authenticated: boolean;
2626
enabled: boolean;
2727
active: boolean;
28+
needPasswordSetup: boolean;
2829
};
2930

3031
export interface IPaginationResponse<T> {

src/app/core/models/code.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export type ExerciseCodeResponse = {
3636
endTime: string; // ISO datetime
3737
duration: number; // minutes
3838
allowDiscussionId: string;
39+
purchased: boolean;
3940
resourceIds: string[];
4041
tags: string[];
4142
allowAiQuestion: boolean;

src/app/core/models/exercise.model.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export type ExerciseItem = {
2323
freeForOrg: boolean;
2424
tags: Set<string>;
2525
createdAt: string;
26+
purchased: boolean;
2627
};
2728

2829
export type UserBasicInfo = {
@@ -101,6 +102,7 @@ export interface ExerciseQuiz {
101102
endTime: string;
102103
duration: number;
103104
allowDiscussionId: string;
105+
purchased: boolean;
104106
resourceIds: string[];
105107
tags: string[];
106108
allowAiQuestion: boolean;

src/app/core/services/api-service/auth.service.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ export class AuthService {
3131
);
3232
}
3333

34+
createInitialPassword(password: string) {
35+
return this.api.post<ApiResponse<null>>(
36+
API_CONFIG.ENDPOINTS.POST.CREATE_FIRST_PASSWORD,
37+
{ password }
38+
);
39+
}
40+
3441
requestForgotPassword(email: string) {
3542
return this.api.post<ApiResponse<RequestForgotPasswordResponse>>(
3643
API_CONFIG.ENDPOINTS.POST.REQUEST_FORGOT_PASSWORD,

src/app/core/services/config-service/api.enpoints.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ export const API_CONFIG = {
148148
LOGIN: '/identity/auth/login',
149149
REGISTER: '/identity/auth/register',
150150
LOGOUT: '/identity/auth/logout',
151+
CREATE_FIRST_PASSWORD: '/identity/auth/user/create-password',
151152
REQUEST_FORGOT_PASSWORD: '/identity/auth/forgot-password/request',
152153
RESET_PASSWORD: `/identity/auth/forgot-password/reset`,
153154
REFRESH_TOKEN: '/identity/auth/refresh',
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!-- set-password-modal.component.html -->
2+
<div class="modal-backdrop" *ngIf="isOpen" (click)="close()"></div>
3+
4+
<div class="modal-wrapper" *ngIf="isOpen">
5+
<div class="modal-content">
6+
<h2>Đặt mật khẩu mới</h2>
7+
8+
<form (ngSubmit)="onSubmit()">
9+
<div class="form-group">
10+
<label for="password">Mật khẩu mới</label>
11+
<input
12+
id="password"
13+
type="password"
14+
[(ngModel)]="password"
15+
name="password"
16+
required
17+
/>
18+
</div>
19+
20+
<div class="form-group">
21+
<label for="confirmPassword">Nhập lại mật khẩu</label>
22+
<input
23+
id="confirmPassword"
24+
type="password"
25+
[(ngModel)]="confirmPassword"
26+
name="confirmPassword"
27+
required
28+
/>
29+
</div>
30+
31+
<p class="error-message" *ngIf="errorMessage">{{ errorMessage }}</p>
32+
33+
<div class="actions">
34+
<button type="button" class="btn cancel" (click)="close()">Hủy</button>
35+
<button type="submit" class="btn confirm" [disabled]="isLoading">
36+
{{ isLoading ? "Đang xử lý..." : "Xác nhận" }}
37+
</button>
38+
</div>
39+
</form>
40+
</div>
41+
</div>
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/* set-password-modal.component.scss */
2+
.modal-backdrop {
3+
position: fixed;
4+
inset: 0;
5+
background: rgba(0, 0, 0, 0.5);
6+
animation: fadeIn 0.3s ease forwards;
7+
z-index: 1000;
8+
}
9+
10+
.modal-wrapper {
11+
position: fixed;
12+
inset: 0;
13+
display: flex;
14+
justify-content: center;
15+
align-items: center;
16+
z-index: 1000;
17+
}
18+
19+
.modal-content {
20+
background: #fff;
21+
border-radius: 12px;
22+
padding: 24px;
23+
width: 400px;
24+
max-width: 90%;
25+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
26+
animation: slideIn 0.3s ease forwards;
27+
}
28+
29+
h2 {
30+
margin-bottom: 16px;
31+
font-size: 20px;
32+
text-align: center;
33+
}
34+
35+
.form-group {
36+
margin-bottom: 16px;
37+
display: flex;
38+
flex-direction: column;
39+
40+
label {
41+
font-size: 14px;
42+
margin-bottom: 6px;
43+
}
44+
45+
input {
46+
padding: 10px;
47+
border: 1px solid #ddd;
48+
border-radius: 6px;
49+
font-size: 14px;
50+
51+
&:focus {
52+
outline: none;
53+
border-color: #3f51b5;
54+
box-shadow: 0 0 0 2px rgba(63, 81, 181, 0.2);
55+
}
56+
}
57+
}
58+
59+
.error-message {
60+
color: #d32f2f;
61+
font-size: 13px;
62+
margin-bottom: 10px;
63+
}
64+
65+
.actions {
66+
display: flex;
67+
justify-content: flex-end;
68+
gap: 10px;
69+
70+
.btn {
71+
padding: 8px 16px;
72+
border-radius: 6px;
73+
cursor: pointer;
74+
border: none;
75+
font-size: 14px;
76+
transition: all 0.2s ease;
77+
78+
&.cancel {
79+
background: #e0e0e0;
80+
&:hover {
81+
background: #d5d5d5;
82+
}
83+
}
84+
85+
&.confirm {
86+
background: #3f51b5;
87+
color: white;
88+
&:hover {
89+
background: #303f9f;
90+
}
91+
&:disabled {
92+
background: #9fa8da;
93+
cursor: not-allowed;
94+
}
95+
}
96+
}
97+
}
98+
99+
/* Animations */
100+
@keyframes fadeIn {
101+
from {
102+
opacity: 0;
103+
}
104+
to {
105+
opacity: 1;
106+
}
107+
}
108+
109+
@keyframes slideIn {
110+
from {
111+
opacity: 0;
112+
transform: translateY(-20px);
113+
}
114+
to {
115+
opacity: 1;
116+
transform: translateY(0);
117+
}
118+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// set-password-modal.component.ts
2+
import { Component, EventEmitter, Input, Output } from '@angular/core';
3+
import { CommonModule } from '@angular/common';
4+
import { FormsModule } from '@angular/forms';
5+
import { AuthService } from '../../../../../core/services/api-service/auth.service';
6+
7+
@Component({
8+
selector: 'app-set-password-modal',
9+
standalone: true,
10+
imports: [CommonModule, FormsModule],
11+
templateUrl: './set-password-modal.component.html',
12+
styleUrls: ['./set-password-modal.component.scss'],
13+
})
14+
export class SetPasswordModalComponent {
15+
@Input() isOpen = false;
16+
@Output() closed = new EventEmitter<void>();
17+
18+
password = '';
19+
confirmPassword = '';
20+
isLoading = false;
21+
errorMessage = '';
22+
23+
constructor(private authService: AuthService) {}
24+
25+
close() {
26+
this.closed.emit();
27+
this.resetForm();
28+
this.isOpen = !this.isOpen;
29+
}
30+
31+
resetForm() {
32+
this.password = '';
33+
this.confirmPassword = '';
34+
this.errorMessage = '';
35+
this.isLoading = false;
36+
}
37+
38+
onSubmit() {
39+
if (!this.password || !this.confirmPassword) {
40+
this.errorMessage = 'Vui lòng nhập đầy đủ thông tin';
41+
return;
42+
}
43+
if (this.password.length < 6) {
44+
this.errorMessage = 'Mật khẩu phải có ít nhất 6 ký tự';
45+
return;
46+
}
47+
if (this.password !== this.confirmPassword) {
48+
this.errorMessage = 'Mật khẩu nhập lại không khớp';
49+
return;
50+
}
51+
52+
this.isLoading = true;
53+
this.authService.createInitialPassword(this.password).subscribe({
54+
next: () => {
55+
this.isLoading = false;
56+
this.close();
57+
// Có thể bắn event success hoặc toast ở đây
58+
},
59+
error: () => {
60+
this.isLoading = false;
61+
},
62+
});
63+
}
64+
}

src/app/features/auth/pages/login/login.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export class Login {
7070
authenticated: false,
7171
enabled: false,
7272
active: false,
73+
needPasswordSetup: false,
7374
};
7475

7576
constructor(

0 commit comments

Comments
 (0)