diff --git a/frontend_management/.env.example b/frontend_management/.env.example index d5e0ccc9..dbb3e3f7 100644 --- a/frontend_management/.env.example +++ b/frontend_management/.env.example @@ -1,5 +1,3 @@ # API Configuration -API_BASE_URL=http://localhost:3001/api +NUXT_PUBLIC_API_BASE_URL=http://localhost:3001/api -# Application -NODE_ENV=development diff --git a/frontend_management/.gitignore b/frontend_management/.gitignore index c05a50a2..df2ba243 100644 --- a/frontend_management/.gitignore +++ b/frontend_management/.gitignore @@ -23,4 +23,13 @@ logs .env.* !.env.example deploy.ps1 -*.tar \ No newline at end of file +*.tar + +# Playwright +tests +tests/.auth/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +playwright.config.ts \ No newline at end of file diff --git a/frontend_management/components/course/AnnouncementsTab.vue b/frontend_management/components/course/AnnouncementsTab.vue index 84b49a14..1efe7f2b 100644 --- a/frontend_management/components/course/AnnouncementsTab.vue +++ b/frontend_management/components/course/AnnouncementsTab.vue @@ -342,11 +342,18 @@ const save = async () => { saving.value = true; try { + // Convert local datetime to ISO string to preserve timezone + const payload = { ...form.value }; + if (payload.published_at) { + const localDate = new Date(payload.published_at.replace(' ', 'T')); + payload.published_at = localDate.toISOString(); + } + if (editing.value) { - await instructorService.updateAnnouncement(props.courseId, editing.value.id, form.value); + await instructorService.updateAnnouncement(props.courseId, editing.value.id, payload); $q.notify({ type: 'positive', message: 'บันทึกประกาศสำเร็จ', position: 'top' }); } else { - const created = await instructorService.createAnnouncement(props.courseId, form.value); + const created = await instructorService.createAnnouncement(props.courseId, payload); // Upload pending files for (const file of pendingFiles.value) { diff --git a/frontend_management/components/course/InstructorsTab.vue b/frontend_management/components/course/InstructorsTab.vue index 323a5a72..4f47af73 100644 --- a/frontend_management/components/course/InstructorsTab.vue +++ b/frontend_management/components/course/InstructorsTab.vue @@ -32,7 +32,7 @@ {{ instructor.user.email }} - + @@ -139,6 +139,10 @@ const isPrimaryInstructor = computed(() => { return myRecord?.is_primary === true; }); +const currentUserId = computed(() => { + return authStore.user?.id ? parseInt(authStore.user.id) : null; +}); + // Methods const fetchInstructors = async () => { loading.value = true; diff --git a/frontend_management/package-lock.json b/frontend_management/package-lock.json index 665d28ad..e113ea0c 100644 --- a/frontend_management/package-lock.json +++ b/frontend_management/package-lock.json @@ -18,6 +18,7 @@ }, "devDependencies": { "@nuxtjs/tailwindcss": "^6.14.0", + "@playwright/test": "^1.58.2", "@types/node": "^25.0.3", "nuxt-quasar-ui": "^3.0.0" } @@ -2773,6 +2774,22 @@ "node": ">=14" } }, + "node_modules/@playwright/test": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz", + "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@polka/url": { "version": "1.0.0-next.29", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", @@ -8783,6 +8800,53 @@ "pathe": "^2.0.3" } }, + "node_modules/playwright": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", + "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", + "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/portfinder": { "version": "1.0.38", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz", diff --git a/frontend_management/package.json b/frontend_management/package.json index 0cd042dd..9ca64017 100644 --- a/frontend_management/package.json +++ b/frontend_management/package.json @@ -7,7 +7,11 @@ "dev": "nuxt dev", "generate": "nuxt generate", "preview": "nuxt preview", - "postinstall": "nuxt prepare" + "postinstall": "nuxt prepare", + "test": "playwright test", + "test:ui": "playwright test --ui", + "test:headed": "playwright test --headed", + "test:report": "playwright show-report" }, "dependencies": { "@pinia/nuxt": "^0.11.3", @@ -21,7 +25,8 @@ }, "devDependencies": { "@nuxtjs/tailwindcss": "^6.14.0", + "@playwright/test": "^1.58.2", "@types/node": "^25.0.3", "nuxt-quasar-ui": "^3.0.0" } -} +} \ No newline at end of file diff --git a/frontend_management/pages/admin/index.vue b/frontend_management/pages/admin/index.vue index cf1121ed..e4e6b968 100644 --- a/frontend_management/pages/admin/index.vue +++ b/frontend_management/pages/admin/index.vue @@ -182,6 +182,7 @@