From 7b22699b13ac534bd586d249d6c82d99880e3e2f Mon Sep 17 00:00:00 2001 From: supalerk-ar66 Date: Thu, 22 Jan 2026 11:04:57 +0700 Subject: [PATCH] feat: Introduce `useCourse` and `useAuth` composables, and add new pages for user registration and dynamic course details. --- Frontend-Learner/composables/useAuth.ts | 16 +--------------- Frontend-Learner/composables/useCourse.ts | 11 ++++------- Frontend-Learner/pages/auth/register.vue | 13 ++----------- Frontend-Learner/pages/course/[id].vue | 13 ------------- 4 files changed, 7 insertions(+), 46 deletions(-) diff --git a/Frontend-Learner/composables/useAuth.ts b/Frontend-Learner/composables/useAuth.ts index c656b43d..de73dc2b 100644 --- a/Frontend-Learner/composables/useAuth.ts +++ b/Frontend-Learner/composables/useAuth.ts @@ -1,9 +1,4 @@ -// Shared global state for current user -import type { H3Event } from 'h3' - - -// Types based on API responses interface User { id: number username: string @@ -64,9 +59,8 @@ export const useAuth = () => { secure: false }) - // ... (previous code) - // Login + const login = async (credentials: { email: string; password: string }) => { try { const data = await $fetch(`${API_BASE_URL}/auth/login`, { @@ -98,7 +92,6 @@ export const useAuth = () => { } } - // Register const register = async (payload: RegisterPayload) => { try { const data = await $fetch(`${API_BASE_URL}/auth/register-learner`, { @@ -117,7 +110,6 @@ export const useAuth = () => { } } - // Fetch User Profile (/api/user/me) const fetchUserProfile = async () => { if (!token.value) return @@ -160,7 +152,6 @@ export const useAuth = () => { } } - // Update User Profile const updateUserProfile = async (payload: { first_name: string last_name: string @@ -188,7 +179,6 @@ export const useAuth = () => { } } - // Request Password Reset const requestPasswordReset = async (email: string) => { try { await $fetch(`${API_BASE_URL}/auth/reset-request`, { @@ -202,7 +192,6 @@ export const useAuth = () => { } } - // Confirm Reset Password const confirmResetPassword = async (payload: { token: string; password: string }) => { try { await $fetch(`${API_BASE_URL}/auth/reset-password`, { @@ -216,7 +205,6 @@ export const useAuth = () => { } } - // Change Password const changePassword = async (payload: { oldPassword: string, newPassword: string }) => { if (!token.value) return { success: false, error: 'ไม่พบ Token การใช้งาน' } @@ -235,7 +223,6 @@ export const useAuth = () => { } } - // Refresh Access Token const refreshAccessToken = async () => { if (!refreshToken.value) return false @@ -258,7 +245,6 @@ export const useAuth = () => { return false } - // Logout const logout = () => { token.value = null refreshToken.value = null // Clear refresh token diff --git a/Frontend-Learner/composables/useCourse.ts b/Frontend-Learner/composables/useCourse.ts index 3c2fb965..23d3d596 100644 --- a/Frontend-Learner/composables/useCourse.ts +++ b/Frontend-Learner/composables/useCourse.ts @@ -1,6 +1,3 @@ -import type { H3Event } from 'h3' - -// Types based on API responses export interface Course { id: number title: string | { th: string; en: string } @@ -10,7 +7,7 @@ export interface Course { price: string is_free: boolean have_certificate: boolean - status: string // 'DRAFT' | 'PUBLISHED' | ... + status: string category_id: number created_at?: string updated_at?: string @@ -20,10 +17,10 @@ export interface Course { approved_by?: number rejection_reason?: string - // Helper properties for UI (may be computed or mapped) + rating?: string lessons?: number | string - levelType?: 'neutral' | 'warning' | 'success' // For UI badging + levelType?: 'neutral' | 'warning' | 'success' chapters?: { id: number @@ -45,7 +42,7 @@ interface CourseResponse { } export interface EnrolledCourse { - id: number // enrollment_id + id: number course_id: number course: Course status: 'ENROLLED' | 'IN_PROGRESS' | 'COMPLETED' | 'DROPPED' diff --git a/Frontend-Learner/pages/auth/register.vue b/Frontend-Learner/pages/auth/register.vue index 7dcb7767..ca1d1fb4 100644 --- a/Frontend-Learner/pages/auth/register.vue +++ b/Frontend-Learner/pages/auth/register.vue @@ -20,7 +20,7 @@ const { errors, validate, clearFieldError } = useFormValidation(); const isLoading = ref(false); -// Reactive form state + const registerForm = reactive({ prefix: "นาย", username: "", @@ -32,7 +32,7 @@ const registerForm = reactive({ confirmPassword: "", }); -// Validation rules + const registerRules = { username: { rules: { @@ -197,11 +197,7 @@ const handleRegister = async () => {

- - -
- { class="dark-form-input" @update:model-value="onUsernameInput" /> - { @update:model-value="onEmailInput" /> - { @update:model-value="clearFieldError('confirmPassword')" /> -
@@ -294,7 +287,6 @@ const handleRegister = async () => { @update:model-value="onPhoneInput" /> - -
มีบัญชีอยู่แล้ว? เข้าสู่ระบบ diff --git a/Frontend-Learner/pages/course/[id].vue b/Frontend-Learner/pages/course/[id].vue index 2a81f20b..ddaae97f 100644 --- a/Frontend-Learner/pages/course/[id].vue +++ b/Frontend-Learner/pages/course/[id].vue @@ -14,14 +14,12 @@ const route = useRoute() const courseId = computed(() => parseInt(route.params.id as string)) const { fetchCourseById, enrollCourse } = useCourse() -// Fetch course data const { data: courseData, error, refresh } = await useAsyncData(`course-${courseId.value}`, () => fetchCourseById(courseId.value)) const course = computed(() => { return courseData.value?.success ? courseData.value.data : null }) -// Enroll State const isEnrolling = ref(false) const handleEnroll = async () => { @@ -43,7 +41,6 @@ const handleEnroll = async () => { } -// Helper for localization const getLocalizedText = (text: string | { th: string; en: string } | undefined | null) => { if (!text) return '' if (typeof text === 'string') return text @@ -60,7 +57,6 @@ useHead({