feat: Introduce core authentication service, several new admin management pages, and instructor feature tests.
All checks were successful
Build and Deploy Frontend Management to Dev Server / Build Frontend Management Docker Image (push) Successful in 52s
Build and Deploy Frontend Management to Dev Server / Deploy E-learning Frontend Management to Dev Server (push) Successful in 4s
Build and Deploy Frontend Management to Dev Server / Notify Deployment Status (push) Successful in 1s

This commit is contained in:
Missez 2026-03-06 11:24:10 +07:00
parent 000f9eea5c
commit 0205aab461
11 changed files with 818 additions and 121 deletions

View file

@ -3,35 +3,20 @@ export interface LoginRequest {
password: string;
}
// API Response structure (from backend)
// API Response structure (from backend) - new format: only token/refreshToken
export interface ApiLoginResponse {
token: string;
refreshToken: string;
user: {
id: number;
username: string;
email: string;
updated_at: string;
created_at: string;
role: {
code: string;
name: {
en: string;
th: string;
};
};
profile: {
prefix: {
en: string;
th: string;
};
first_name: string;
last_name: string;
phone: string | null;
avatar_url: string | null;
birth_date: string | null;
};
};
}
// JWT Payload structure (decoded from token)
export interface JwtPayload {
id: number;
username: string;
email: string;
roleCode: string;
iat: number;
exp: number;
}
// Frontend User structure
@ -55,6 +40,21 @@ export interface ApiResponse<T> {
data: T;
}
/**
* Decode JWT payload without verification (read-only)
* Verification is handled by the backend on each request
*/
function decodeJwtPayload(token: string): JwtPayload {
const base64Url = token.split('.')[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(
atob(base64).split('').map(c =>
'%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
).join('')
);
return JSON.parse(jsonPayload);
}
export const authService = {
async login(email: string, password: string): Promise<LoginResponse> {
const config = useRuntimeConfig();
@ -71,22 +71,26 @@ export const authService = {
const loginData = response.data;
// Decode JWT to get user info
const payload = decodeJwtPayload(loginData.token);
// Check if user role is STUDENT - block login
if (loginData.user.role.code === 'STUDENT') {
if (payload.roleCode === 'STUDENT') {
throw new Error('ไม่สามารถเข้าสู่ระบบได้ ระบบนี้สำหรับผู้สอนและผู้ดูแลระบบเท่านั้น');
}
// Transform API response to frontend format
// Return basic user info from JWT payload
// Full profile will be fetched via fetchUserProfile() in the auth store
return {
token: loginData.token,
refreshToken: loginData.refreshToken,
user: {
id: loginData.user.id.toString(),
email: loginData.user.email,
firstName: loginData.user.profile.first_name,
lastName: loginData.user.profile.last_name,
role: loginData.user.role.code,
avatarUrl: loginData.user.profile.avatar_url
id: payload.id.toString(),
email: payload.email,
firstName: '',
lastName: '',
role: payload.roleCode,
avatarUrl: null
},
message: response.message || 'เข้าสู่ระบบสำเร็จ'
};