pembenaran update projek
This commit is contained in:
parent
301fe0a3c4
commit
e0aefa4eb6
@ -108,41 +108,86 @@ class PlayerController extends Controller
|
|||||||
$data['student_id'] = auth()->user()->id;
|
$data['student_id'] = auth()->user()->id;
|
||||||
|
|
||||||
$total_lesson = Lesson::where('course_id', $request->course_id)->pluck('id')->toArray();
|
$total_lesson = Lesson::where('course_id', $request->course_id)->pluck('id')->toArray();
|
||||||
|
$watch_history = Watch_history::where('course_id', $request->course_id)->where('student_id', auth()->user()->id)->first();
|
||||||
$watch_history = Watch_history::where('course_id', $request->course_id)
|
$student_id = auth()->user()->id;
|
||||||
->where('student_id', auth()->user()->id)->first();
|
|
||||||
|
|
||||||
|
|
||||||
if (isset($watch_history) && $watch_history->id) {
|
if (isset($watch_history) && $watch_history->id) {
|
||||||
$lessons = (array) json_decode($watch_history->completed_lesson);
|
$completed_lessons = [];
|
||||||
if (! in_array($request->lesson_id, $lessons)) {
|
if (!empty($watch_history->completed_lesson)) {
|
||||||
array_push($lessons, $request->lesson_id);
|
$decoded = json_decode($watch_history->completed_lesson, true);
|
||||||
}
|
if (is_array($decoded)) {
|
||||||
|
$completed_lessons = array_map('intval', $decoded);
|
||||||
$data['completed_lesson'] = json_encode($lessons);
|
|
||||||
$data['watching_lesson_id'] = $request->lesson_id;
|
|
||||||
$data['completed_date'] = (count($total_lesson) == count($lessons)) ? time() : null;
|
|
||||||
Watch_history::where('course_id', $request->course_id)->where('student_id', auth()->user()->id)->update($data);
|
|
||||||
} else {
|
} else {
|
||||||
$lessons = [$request->lesson_id];
|
// Fallback jika format tidak valid
|
||||||
$data['completed_lesson'] = json_encode($lessons);
|
$completed_lesson_data = trim($watch_history->completed_lesson, '[]"\' ');
|
||||||
$data['watching_lesson_id'] = $request->lesson_id;
|
if (!empty($completed_lesson_data)) {
|
||||||
$data['completed_date'] = (count($total_lesson) == count($lessons)) ? time() : null;
|
$completed_lessons = array_map('intval', explode(',', $completed_lesson_data));
|
||||||
Watch_history::insert($data);
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progress_bar($request->course_id) >= 100) {
|
$completed_lessons = array_unique($completed_lessons);
|
||||||
$certificate = Certificate::where('user_id', auth()->user()->id)->where('course_id', $request->course_id);
|
sort($completed_lessons);
|
||||||
|
|
||||||
if ($certificate->count() == 0) {
|
$lesson_id_int = (int)$request->lesson_id;
|
||||||
$certificate_data['user_id'] = auth()->user()->id;
|
if (!in_array($lesson_id_int, $completed_lessons)) {
|
||||||
$certificate_data['course_id'] = $request->course_id;
|
$completed_lessons[] = $lesson_id_int;
|
||||||
$certificate_data['identifier'] = $this->generateIdentifier(12);
|
sort($completed_lessons);
|
||||||
$certificate_data['created_at'] = date('Y-m-d H:i:s');
|
}
|
||||||
Certificate::insert($certificate_data);
|
|
||||||
|
$data['completed_lesson'] = json_encode($completed_lessons);
|
||||||
|
$data['watching_lesson_id'] = $lesson_id_int;
|
||||||
|
|
||||||
|
Log::info('Updated lessons (integer array):', $completed_lessons);
|
||||||
|
|
||||||
|
Watch_history::where('course_id', $request->course_id)
|
||||||
|
->where('student_id', $student_id)
|
||||||
|
->update($data);
|
||||||
|
} else {
|
||||||
|
$lesson_id_int = (int)$request->lesson_id;
|
||||||
|
$completed_lessons = [$lesson_id_int];
|
||||||
|
|
||||||
|
$data['completed_lesson'] = json_encode($completed_lessons);
|
||||||
|
$data['watching_lesson_id'] = $lesson_id_int;
|
||||||
|
|
||||||
|
Log::info('New lessons (integer array):', $completed_lessons);
|
||||||
|
|
||||||
|
Watch_history::create($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// **LOGIKA SERTIFIKAT - dengan progress yang benar**
|
||||||
|
$completed_lessons = $completed_lessons ?? [];
|
||||||
|
$completed_in_course = array_intersect($completed_lessons, $total_lesson);
|
||||||
|
$completed_count = count($completed_in_course);
|
||||||
|
$total_count = count($total_lesson);
|
||||||
|
|
||||||
|
$progress_percentage = 0;
|
||||||
|
if ($total_count > 0) {
|
||||||
|
$progress_percentage = ($completed_count / $total_count) * 100;
|
||||||
|
}
|
||||||
|
Log::info('Progress percentage: ' . $progress_percentage);
|
||||||
|
// Jika progress 100% dan status project diterima, buat sertifikat
|
||||||
|
if ($progress_percentage >= 100) {
|
||||||
|
$certificateExists = Certificate::where('user_id', $student_id)
|
||||||
|
->where('course_id', $request->course_id)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if (!$certificateExists) {
|
||||||
|
if (method_exists($this, 'generateIdentifier')) {
|
||||||
|
$identifier = $this->generateIdentifier(12);
|
||||||
|
} else {
|
||||||
|
$identifier = \Illuminate\Support\Str::random(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
Certificate::create([
|
||||||
|
'user_id' => $student_id,
|
||||||
|
'course_id' => $request->course_id,
|
||||||
|
'identifier' => $identifier,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return redirect()->back();
|
return redirect()->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use App\Models\Builder_page;
|
|||||||
use App\Models\Category;
|
use App\Models\Category;
|
||||||
use App\Models\Certificate;
|
use App\Models\Certificate;
|
||||||
use App\Models\Course;
|
use App\Models\Course;
|
||||||
|
use App\Models\Lesson;
|
||||||
use App\Models\Message;
|
use App\Models\Message;
|
||||||
use App\Models\Message_code;
|
use App\Models\Message_code;
|
||||||
use App\Models\Review;
|
use App\Models\Review;
|
||||||
@ -15,6 +16,7 @@ use App\Models\User;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
use SimpleSoftwareIO\QrCode\Facades\QrCode;
|
use SimpleSoftwareIO\QrCode\Facades\QrCode;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use DB;
|
use DB;
|
||||||
|
|
||||||
use App\Http\Controllers\NewsletterController;
|
use App\Http\Controllers\NewsletterController;
|
||||||
@ -70,13 +72,13 @@ class HomeController extends Controller
|
|||||||
|
|
||||||
public function update_watch_history_with_duration(Request $request)
|
public function update_watch_history_with_duration(Request $request)
|
||||||
{
|
{
|
||||||
$userId = auth()->user()->id; // Get the logged-in user's ID
|
$userId = auth()->user()->id;
|
||||||
$courseProgress = 0;
|
$courseProgress = 0;
|
||||||
$isCompleted = 0;
|
$isCompleted = 0;
|
||||||
|
|
||||||
// Retrieve and sanitize input data
|
// Retrieve and sanitize input data
|
||||||
$courseId = htmlspecialchars($request->input('course_id'));
|
$courseId = (int) htmlspecialchars($request->input('course_id'));
|
||||||
$lessonId = htmlspecialchars($request->input('lesson_id'));
|
$lessonId = (int) htmlspecialchars($request->input('lesson_id'));
|
||||||
$currentDuration = htmlspecialchars($request->input('current_duration'));
|
$currentDuration = htmlspecialchars($request->input('current_duration'));
|
||||||
|
|
||||||
// Fetch current watch history record
|
// Fetch current watch history record
|
||||||
@ -90,17 +92,29 @@ class HomeController extends Controller
|
|||||||
|
|
||||||
// Fetch course details
|
// Fetch course details
|
||||||
$courseDetails = DB::table('courses')->where('id', $courseId)->first();
|
$courseDetails = DB::table('courses')->where('id', $courseId)->first();
|
||||||
$dripContentSettings = json_decode($courseDetails->drip_content_settings, true);
|
|
||||||
|
if (!$courseDetails) {
|
||||||
|
return response()->json([
|
||||||
|
'lesson_id' => $lessonId,
|
||||||
|
'course_progress' => 0,
|
||||||
|
'is_completed' => 0,
|
||||||
|
'error' => 'Course not found'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dripContentSettings = json_decode($courseDetails->drip_content_settings, true) ?? [];
|
||||||
|
|
||||||
if ($currentHistory) {
|
if ($currentHistory) {
|
||||||
$watchedDurationArr = json_decode($currentHistory->watched_counter, true);
|
$watchedDurationArr = json_decode($currentHistory->watched_counter, true);
|
||||||
if (!is_array($watchedDurationArr)) $watchedDurationArr = [];
|
if (!is_array($watchedDurationArr)) {
|
||||||
|
$watchedDurationArr = [];
|
||||||
if (!in_array($currentDuration, $watchedDurationArr)) {
|
|
||||||
array_push($watchedDurationArr, $currentDuration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$watchedDurationJson = json_encode($watchedDurationArr);
|
// Pastikan tidak ada duplikat
|
||||||
|
if (!in_array($currentDuration, $watchedDurationArr)) {
|
||||||
|
$watchedDurationArr[] = $currentDuration;
|
||||||
|
sort($watchedDurationArr);
|
||||||
|
}
|
||||||
|
|
||||||
DB::table('watch_durations')
|
DB::table('watch_durations')
|
||||||
->where([
|
->where([
|
||||||
@ -109,8 +123,9 @@ class HomeController extends Controller
|
|||||||
'watched_student_id' => $userId,
|
'watched_student_id' => $userId,
|
||||||
])
|
])
|
||||||
->update([
|
->update([
|
||||||
'watched_counter' => $watchedDurationJson,
|
'watched_counter' => json_encode($watchedDurationArr),
|
||||||
'current_duration' => $currentDuration,
|
'current_duration' => $currentDuration,
|
||||||
|
'updated_at' => now(),
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
$watchedDurationArr = [$currentDuration];
|
$watchedDurationArr = [$currentDuration];
|
||||||
@ -120,38 +135,65 @@ class HomeController extends Controller
|
|||||||
'watched_student_id' => $userId,
|
'watched_student_id' => $userId,
|
||||||
'current_duration' => $currentDuration,
|
'current_duration' => $currentDuration,
|
||||||
'watched_counter' => json_encode($watchedDurationArr),
|
'watched_counter' => json_encode($watchedDurationArr),
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Jika drip content tidak aktif, return early
|
||||||
if ($courseDetails->enable_drip_content != 1) {
|
if ($courseDetails->enable_drip_content != 1) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'lesson_id' => $lessonId,
|
'lesson_id' => $lessonId,
|
||||||
'course_progress' => null,
|
'course_progress' => 0,
|
||||||
'is_completed' => null
|
'is_completed' => 0
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch lesson details for duration calculations
|
// Fetch lesson details for duration calculations
|
||||||
$lessonTotalDuration = DB::table('lessons')->where('id', $lessonId)->value('duration');
|
$lessonTotalDuration = DB::table('lessons')->where('id', $lessonId)->value('duration');
|
||||||
|
if (!$lessonTotalDuration) {
|
||||||
|
return response()->json([
|
||||||
|
'lesson_id' => $lessonId,
|
||||||
|
'course_progress' => 0,
|
||||||
|
'is_completed' => 0,
|
||||||
|
'error' => 'Lesson duration not found'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
$lessonTotalDurationArr = explode(':', $lessonTotalDuration);
|
$lessonTotalDurationArr = explode(':', $lessonTotalDuration);
|
||||||
$lessonTotalSeconds = ($lessonTotalDurationArr[0] * 3600) + ($lessonTotalDurationArr[1] * 60) + $lessonTotalDurationArr[2];
|
if (count($lessonTotalDurationArr) < 3) {
|
||||||
$currentTotalSeconds = count($watchedDurationArr) * 5; // Assuming each increment represents 5 seconds
|
return response()->json([
|
||||||
|
'lesson_id' => $lessonId,
|
||||||
|
'course_progress' => 0,
|
||||||
|
'is_completed' => 0,
|
||||||
|
'error' => 'Invalid duration format'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$lessonTotalSeconds = ($lessonTotalDurationArr[0] * 3600) +
|
||||||
|
($lessonTotalDurationArr[1] * 60) +
|
||||||
|
$lessonTotalDurationArr[2];
|
||||||
|
$currentTotalSeconds = count($watchedDurationArr) * 5;
|
||||||
|
|
||||||
// Drip content completion logic
|
// Drip content completion logic
|
||||||
|
if (!empty($dripContentSettings) && isset($dripContentSettings['lesson_completion_role'])) {
|
||||||
if ($dripContentSettings['lesson_completion_role'] == 'duration') {
|
if ($dripContentSettings['lesson_completion_role'] == 'duration') {
|
||||||
if ($currentTotalSeconds >= $dripContentSettings['minimum_duration']) {
|
$minimumDuration = $dripContentSettings['minimum_duration'] ?? 0;
|
||||||
|
if ($currentTotalSeconds >= $minimumDuration) {
|
||||||
$isCompleted = 1;
|
$isCompleted = 1;
|
||||||
} elseif (($currentTotalSeconds + 4) >= $lessonTotalSeconds) {
|
} elseif (($currentTotalSeconds + 4) >= $lessonTotalSeconds) {
|
||||||
$isCompleted = 1;
|
$isCompleted = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$requiredDuration = ($lessonTotalSeconds / 100) * $dripContentSettings['minimum_percentage'];
|
$minimumPercentage = $dripContentSettings['minimum_percentage'] ?? 0;
|
||||||
|
$requiredDuration = ($lessonTotalSeconds / 100) * $minimumPercentage;
|
||||||
if ($currentTotalSeconds >= $requiredDuration) {
|
if ($currentTotalSeconds >= $requiredDuration) {
|
||||||
$isCompleted = 1;
|
$isCompleted = 1;
|
||||||
} elseif (($currentTotalSeconds + 4) >= $lessonTotalSeconds) {
|
} elseif (($currentTotalSeconds + 4) >= $lessonTotalSeconds) {
|
||||||
$isCompleted = 1;
|
$isCompleted = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update course progress if the lesson is completed
|
// Update course progress if the lesson is completed
|
||||||
if ($isCompleted == 1) {
|
if ($isCompleted == 1) {
|
||||||
@ -164,27 +206,92 @@ class HomeController extends Controller
|
|||||||
|
|
||||||
if ($watchHistory) {
|
if ($watchHistory) {
|
||||||
$lessonIds = json_decode($watchHistory->completed_lesson, true);
|
$lessonIds = json_decode($watchHistory->completed_lesson, true);
|
||||||
$courseProgress = $watchHistory->course_progress;
|
|
||||||
|
|
||||||
if (!is_array($lessonIds)) $lessonIds = [];
|
if (!is_array($lessonIds)) {
|
||||||
|
$lessonIds = [];
|
||||||
|
} else {
|
||||||
|
// Konversi semua nilai ke integer
|
||||||
|
$lessonIds = array_map('intval', $lessonIds);
|
||||||
|
$lessonIds = array_values(array_unique($lessonIds));
|
||||||
|
sort($lessonIds);
|
||||||
|
}
|
||||||
|
|
||||||
if (!in_array($lessonId, $lessonIds)) {
|
if (!in_array($lessonId, $lessonIds)) {
|
||||||
array_push($lessonIds, $lessonId);
|
// Tambahkan lesson baru
|
||||||
$totalLesson = DB::table('lessons')->where('course_id', $courseId)->count();
|
$lessonIds[] = $lessonId;
|
||||||
$courseProgress = (100 / $totalLesson) * count($lessonIds);
|
$lessonIds = array_unique($lessonIds);
|
||||||
|
sort($lessonIds);
|
||||||
|
|
||||||
$completedDate = ($courseProgress >= 100 && !$watchHistory->completed_date)
|
// Hitung total lesson yang valid di course
|
||||||
? time()
|
$totalLesson = DB::table('lessons')->where('course_id', $courseId)->count();
|
||||||
: $watchHistory->completed_date;
|
|
||||||
|
// Hitung progress yang akurat
|
||||||
|
if ($totalLesson > 0) {
|
||||||
|
// Ambil semua lesson ID yang valid di course ini
|
||||||
|
$validLessonIds = DB::table('lessons')
|
||||||
|
->where('course_id', $courseId)
|
||||||
|
->pluck('id')
|
||||||
|
->map(function($id) {
|
||||||
|
return (int)$id;
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// Hitung hanya lesson yang valid (ada di course ini)
|
||||||
|
$completedValidLessons = array_intersect($lessonIds, $validLessonIds);
|
||||||
|
$completedCount = count($completedValidLessons);
|
||||||
|
|
||||||
|
$courseProgress = ($completedCount / $totalLesson) * 100;
|
||||||
|
$courseProgress = round($courseProgress, 2);
|
||||||
|
$courseProgress = min(100, $courseProgress); // Pastikan tidak lebih dari 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tentukan completed_date
|
||||||
|
$updateData = [
|
||||||
|
'course_progress' => $courseProgress,
|
||||||
|
'completed_lesson' => json_encode($lessonIds, JSON_NUMERIC_CHECK), // Flag penting!
|
||||||
|
'watching_lesson_id' => $lessonId,
|
||||||
|
'updated_at' => now(),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Set completed_date hanya jika progress 100% dan belum ada
|
||||||
|
if ($courseProgress >= 100 && !$watchHistory->completed_date) {
|
||||||
|
$updateData['completed_date'] = now();
|
||||||
|
} elseif ($watchHistory->completed_date) {
|
||||||
|
$updateData['completed_date'] = $watchHistory->completed_date;
|
||||||
|
}
|
||||||
|
|
||||||
DB::table('watch_histories')
|
DB::table('watch_histories')
|
||||||
->where('id', $watchHistory->id)
|
->where('id', $watchHistory->id)
|
||||||
->update([
|
->update($updateData);
|
||||||
'course_progress' => $courseProgress,
|
|
||||||
'completed_lesson' => json_encode($lessonIds),
|
} else {
|
||||||
'completed_date' => $completedDate,
|
// Jika lesson sudah ada, ambil progress yang ada
|
||||||
]);
|
$courseProgress = $watchHistory->course_progress ?? 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Buat record baru di watch_histories
|
||||||
|
$lessonIds = [$lessonId];
|
||||||
|
$totalLesson = DB::table('lessons')->where('course_id', $courseId)->count();
|
||||||
|
|
||||||
|
if ($totalLesson > 0) {
|
||||||
|
$courseProgress = (1 / $totalLesson) * 100;
|
||||||
|
$courseProgress = round($courseProgress, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
$isCourseCompleted = $courseProgress >= 100;
|
||||||
|
|
||||||
|
dd(json_encode($lessonIds, JSON_NUMERIC_CHECK));
|
||||||
|
|
||||||
|
DB::table('watch_histories')->insert([
|
||||||
|
'course_id' => $courseId,
|
||||||
|
'student_id' => $userId,
|
||||||
|
'watching_lesson_id' => $lessonId,
|
||||||
|
'completed_lesson' => json_encode($lessonIds, JSON_NUMERIC_CHECK),
|
||||||
|
'course_progress' => $courseProgress,
|
||||||
|
'completed_date' => $isCourseCompleted ? now() : null,
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now(),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,6 +300,8 @@ class HomeController extends Controller
|
|||||||
'lesson_id' => $lessonId,
|
'lesson_id' => $lessonId,
|
||||||
'course_progress' => round($courseProgress),
|
'course_progress' => round($courseProgress),
|
||||||
'is_completed' => $isCompleted,
|
'is_completed' => $isCompleted,
|
||||||
|
'current_total_seconds' => $currentTotalSeconds,
|
||||||
|
'lesson_total_seconds' => $lessonTotalSeconds,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
309
app/Http/Controllers/instructor/ProjectController.php
Normal file
309
app/Http/Controllers/instructor/ProjectController.php
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\instructor;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Lesson;
|
||||||
|
use App\Models\ProjectSubmission;
|
||||||
|
use App\Models\Watch_history;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
class ProjectController extends Controller
|
||||||
|
{
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'status' => 'required|in:1,2',
|
||||||
|
'comment' => 'required_if:status,2',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$submission = ProjectSubmission::findOrFail($id);
|
||||||
|
|
||||||
|
$submission->status = $request->status;
|
||||||
|
$submission->reviewed_by = auth()->id();
|
||||||
|
$submission->reviewed_at = now();
|
||||||
|
|
||||||
|
if ($request->status == 1) {
|
||||||
|
$submission->comment = null;
|
||||||
|
} else {
|
||||||
|
$submission->comment = $request->comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
$submission->save();
|
||||||
|
|
||||||
|
return redirect()->back()->with('success', get_phrase('Project graded successfully'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$title = Lesson::join('sections', 'lessons.section_id', 'sections.id')
|
||||||
|
->join('courses', 'sections.course_id', 'courses.id')
|
||||||
|
->where('courses.user_id', auth()->user()->id)
|
||||||
|
->where('lessons.title', $request->title)
|
||||||
|
->first();
|
||||||
|
if ($title) {
|
||||||
|
Session::flash('error', get_phrase('Title has been taken.'));
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxSort = Lesson::where('section_id', $request->section)
|
||||||
|
->max('sort');
|
||||||
|
|
||||||
|
$data['user_id'] = auth()->user()->id;
|
||||||
|
$data['sort'] = $maxSort + 1;
|
||||||
|
$data['title'] = $request->title;
|
||||||
|
$data['course_id'] = $request->course_id;
|
||||||
|
$data['section_id'] = $request->section;
|
||||||
|
$data['description'] = $request->description;
|
||||||
|
$data['attachment'] = $request->attachment;
|
||||||
|
$data['summary'] = $request->summary;
|
||||||
|
$data['lesson_type'] = 'project';
|
||||||
|
$data['status'] = 1;
|
||||||
|
|
||||||
|
Lesson::insert($data);
|
||||||
|
|
||||||
|
Session::flash('success', get_phrase('Project has been created.'));
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIndex($id)
|
||||||
|
{
|
||||||
|
$participants = ProjectSubmission::join('users', 'project_submissions.user_id', '=', 'users.id')
|
||||||
|
->where('project_submissions.lesson_id', $id)
|
||||||
|
->select('users.name', 'users.id')
|
||||||
|
->distinct()
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view('instructor.project.grading.index', ['participants' => $participants, 'lesson_id' => $id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPreview(Request $request)
|
||||||
|
{
|
||||||
|
// Validasi input
|
||||||
|
$request->validate([
|
||||||
|
'lesson_id' => 'required|integer',
|
||||||
|
'user_id' => 'required|integer'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Cari submission terbaru
|
||||||
|
$submission = ProjectSubmission::where('lesson_id', $request->lesson_id)
|
||||||
|
->where('user_id', $request->user_id)
|
||||||
|
->latest()
|
||||||
|
->first();
|
||||||
|
// dd($submission); // <-- INI HARUS DIHAPUS ATAU DI-KOMEN
|
||||||
|
|
||||||
|
// Tentukan label komentar
|
||||||
|
$commentLabel = (!empty($submission) && !empty($submission->comment))
|
||||||
|
? "Revisi Sebelumnya"
|
||||||
|
: "Masukkan Revisi Anda";
|
||||||
|
|
||||||
|
// Return view preview
|
||||||
|
return view('instructor.project.grading.preview', compact('submission', 'commentLabel'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParticipantSubmission(Request $request)
|
||||||
|
{
|
||||||
|
$submissions = ProjectSubmission::where('lesson_id', $request->quizId)
|
||||||
|
->where('user_id', $request->participant)
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$html = '<option value="">' . get_phrase('Select a submission') . '</option>';
|
||||||
|
|
||||||
|
if($submissions->count() > 0){
|
||||||
|
foreach ($submissions as $submission) {
|
||||||
|
$date = date('d M Y, H:i', strtotime($submission->created_at));
|
||||||
|
|
||||||
|
$statusLabel = '';
|
||||||
|
if($submission->status == 1) $statusLabel = ' (Lulus)';
|
||||||
|
elseif($submission->status == 2) $statusLabel = ' (Revisi)';
|
||||||
|
else $statusLabel = ' (Pending)';
|
||||||
|
|
||||||
|
$html .= '<option value="' . $submission->id . '">' . $date . $statusLabel . '</option>';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$html .= '<option value="" disabled>' . get_phrase('No submission found') . '</option>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json($html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateSubmission(Request $request, $id)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'status' => 'required|in:1,2',
|
||||||
|
'comment' => 'required_if:status,2', // Wajib isi jika status 2 (Revisi)
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Menggunakan Model findOrFail
|
||||||
|
$submission = ProjectSubmission::findOrFail($id);
|
||||||
|
|
||||||
|
$submission->status = $request->status;
|
||||||
|
$submission->reviewed_by = auth()->id();
|
||||||
|
$submission->reviewed_at = now();
|
||||||
|
|
||||||
|
if ($request->status == 1) {
|
||||||
|
// Jika Diterima (1), Comment jadi NULL (sesuai request)
|
||||||
|
$submission->comment = null;
|
||||||
|
} else {
|
||||||
|
// Jika Perlu Perbaikan (2), Simpan Comment
|
||||||
|
$submission->comment = $request->comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
$submission->save();
|
||||||
|
|
||||||
|
// **LOGIKA WATCH HISTORY - DIPERBAIKI berdasarkan referensi**
|
||||||
|
|
||||||
|
$lesson = Lesson::findOrFail($submission->lesson_id);
|
||||||
|
|
||||||
|
$student_id = $submission->user_id;
|
||||||
|
$course_id = $lesson->course_id;
|
||||||
|
$lesson_id = $submission->lesson_id;
|
||||||
|
|
||||||
|
// Ambil semua lesson ID untuk course ini
|
||||||
|
$total_lesson = Lesson::where('course_id', $course_id)
|
||||||
|
->pluck('id')
|
||||||
|
->map(function($id) {
|
||||||
|
return (int)$id;
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// Cari watch_history untuk student ini
|
||||||
|
$watch_history = Watch_history::where('course_id', $course_id)
|
||||||
|
->where('student_id', $student_id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// **LOGIKA UTAMA berdasarkan referensi set_watch_history**
|
||||||
|
if ($watch_history) {
|
||||||
|
// Parse data lama dengan handling yang robust
|
||||||
|
$completed_lessons = [];
|
||||||
|
|
||||||
|
if (!empty($watch_history->completed_lesson)) {
|
||||||
|
$decoded = json_decode($watch_history->completed_lesson, true);
|
||||||
|
|
||||||
|
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
|
||||||
|
// Konversi semua nilai ke integer
|
||||||
|
$completed_lessons = array_map('intval', $decoded);
|
||||||
|
} else {
|
||||||
|
// Fallback jika format tidak valid
|
||||||
|
$completed_lesson_data = trim($watch_history->completed_lesson, '[]"\' ');
|
||||||
|
if (!empty($completed_lesson_data)) {
|
||||||
|
$completed_lessons = array_map('intval', explode(',', $completed_lesson_data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hapus duplikat dan sortir
|
||||||
|
$completed_lessons = array_unique($completed_lessons);
|
||||||
|
sort($completed_lessons);
|
||||||
|
|
||||||
|
// **HANYA tambahkan lesson jika project DITERIMA (status 1)**
|
||||||
|
if ($request->status == 1 && !in_array($lesson_id, $completed_lessons)) {
|
||||||
|
$completed_lessons[] = $lesson_id;
|
||||||
|
sort($completed_lessons);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hitung completion dengan benar (seperti referensi)
|
||||||
|
$completed_in_course = array_intersect($completed_lessons, $total_lesson);
|
||||||
|
$is_completed = count($total_lesson) > 0 &&
|
||||||
|
count($completed_in_course) >= count($total_lesson);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'course_id' => $course_id,
|
||||||
|
'student_id' => $student_id,
|
||||||
|
'watching_lesson_id' => $lesson_id,
|
||||||
|
'completed_lesson' => json_encode($completed_lessons, JSON_NUMERIC_CHECK), // Gunakan JSON_NUMERIC_CHECK
|
||||||
|
'completed_date' => $is_completed ? date('Y-m-d H:i:s') : null, // Format MySQL datetime
|
||||||
|
];
|
||||||
|
|
||||||
|
// **FIX: Update dengan student_id yang benar (bukan auth user)**
|
||||||
|
Watch_history::where('course_id', $course_id)
|
||||||
|
->where('student_id', $student_id)
|
||||||
|
->update($data);
|
||||||
|
|
||||||
|
// Log untuk debugging
|
||||||
|
\Log::info('Project submission watch history updated:', [
|
||||||
|
'project_submission_id' => $id,
|
||||||
|
'student_id' => $student_id,
|
||||||
|
'course_id' => $course_id,
|
||||||
|
'lesson_id' => $lesson_id,
|
||||||
|
'completed_lessons' => $completed_lessons,
|
||||||
|
'is_completed' => $is_completed,
|
||||||
|
'total_lessons_in_course' => count($total_lesson)
|
||||||
|
]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// **Jika tidak ada watch_history, buat baru**
|
||||||
|
// Hanya buat jika project DITERIMA (status 1)
|
||||||
|
if ($request->status == 1) {
|
||||||
|
$completed_lessons = [$lesson_id];
|
||||||
|
|
||||||
|
// Hitung completion untuk data baru
|
||||||
|
$is_completed = count($total_lesson) == 1 && in_array($lesson_id, $total_lesson);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'course_id' => $course_id,
|
||||||
|
'student_id' => $student_id,
|
||||||
|
'watching_lesson_id' => $lesson_id,
|
||||||
|
'completed_lesson' => json_encode($completed_lessons, JSON_NUMERIC_CHECK),
|
||||||
|
'completed_date' => $is_completed ? date('Y-m-d H:i:s') : null,
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now(),
|
||||||
|
];
|
||||||
|
|
||||||
|
Watch_history::create($data);
|
||||||
|
|
||||||
|
\Log::info('New watch history created from project submission:', [
|
||||||
|
'project_submission_id' => $id,
|
||||||
|
'student_id' => $student_id,
|
||||||
|
'course_id' => $course_id,
|
||||||
|
'lesson_id' => $lesson_id
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **LOGIKA SERTIFIKAT - dengan progress yang benar**
|
||||||
|
$completed_lessons = $completed_lessons ?? [];
|
||||||
|
$completed_in_course = array_intersect($completed_lessons, $total_lesson);
|
||||||
|
$completed_count = count($completed_in_course);
|
||||||
|
$total_count = count($total_lesson);
|
||||||
|
|
||||||
|
$progress_percentage = 0;
|
||||||
|
if ($total_count > 0) {
|
||||||
|
$progress_percentage = ($completed_count / $total_count) * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jika progress 100% dan status project diterima, buat sertifikat
|
||||||
|
if ($progress_percentage >= 100 && $request->status == 1) {
|
||||||
|
$certificateExists = Certificate::where('user_id', $student_id)
|
||||||
|
->where('course_id', $course_id)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if (!$certificateExists) {
|
||||||
|
// Cek jika method generateIdentifier ada
|
||||||
|
if (method_exists($this, 'generateIdentifier')) {
|
||||||
|
$identifier = $this->generateIdentifier(12);
|
||||||
|
} else {
|
||||||
|
// Fallback ke random string
|
||||||
|
$identifier = \Illuminate\Support\Str::random(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
Certificate::create([
|
||||||
|
'user_id' => $student_id,
|
||||||
|
'course_id' => $course_id,
|
||||||
|
'identifier' => $identifier,
|
||||||
|
]);
|
||||||
|
|
||||||
|
\Log::info('Certificate created after project submission:', [
|
||||||
|
'student_id' => $student_id,
|
||||||
|
'course_id' => $course_id,
|
||||||
|
'project_submission_id' => $id
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->back()->with('success', get_phrase('Project graded successfully'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -56,6 +56,11 @@ class QuizController extends Controller
|
|||||||
return redirect()->back();
|
return redirect()->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$maxSort = Lesson::where('section_id', $request->section)
|
||||||
|
->max('sort');
|
||||||
|
|
||||||
|
$data['user_id'] = auth()->user()->id;
|
||||||
|
$data['sort'] = $maxSort + 1;
|
||||||
$data['title'] = $request->title;
|
$data['title'] = $request->title;
|
||||||
$data['course_id'] = $request->course_id;
|
$data['course_id'] = $request->course_id;
|
||||||
$data['section_id'] = $request->section;
|
$data['section_id'] = $request->section;
|
||||||
|
|||||||
51
app/Http/Controllers/student/ProjectController.php
Normal file
51
app/Http/Controllers/student/ProjectController.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\student;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Lesson;
|
||||||
|
use App\Models\ProjectSubmission;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
|
class ProjectController extends Controller
|
||||||
|
{
|
||||||
|
public function submit(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'lesson_id' => 'required|exists:lessons,id',
|
||||||
|
'submission_link' => 'required|url',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$userId = auth()->user()->id;
|
||||||
|
$lessonId = $request->lesson_id;
|
||||||
|
|
||||||
|
$submission = ProjectSubmission::where('user_id', $userId)
|
||||||
|
->where('lesson_id', $lessonId)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($submission) {
|
||||||
|
$submission->drive_link = $request->submission_link;
|
||||||
|
$submission->status = 0;
|
||||||
|
$submission->submitted_at = Carbon::now();
|
||||||
|
$submission->save();
|
||||||
|
$message = get_phrase('Project successfully resubmitted.');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$submission = new ProjectSubmission();
|
||||||
|
$submission->user_id = $userId;
|
||||||
|
$submission->lesson_id = $lessonId;
|
||||||
|
$submission->submitted_at = Carbon::now();
|
||||||
|
$submission->drive_link = $request->submission_link;
|
||||||
|
$submission->status = 0;
|
||||||
|
$submission->save();
|
||||||
|
|
||||||
|
$message = get_phrase('Project successfully submitted.');
|
||||||
|
}
|
||||||
|
|
||||||
|
session()->flash('success', $message);
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -137,21 +137,24 @@ class QuizController extends Controller
|
|||||||
{
|
{
|
||||||
// Validasi Course
|
// Validasi Course
|
||||||
$course = Course::where('id', $course_id)->first();
|
$course = Course::where('id', $course_id)->first();
|
||||||
if (!$course) return;
|
if (!$course) return false;
|
||||||
|
|
||||||
// Validasi Enrollment
|
// Validasi Enrollment
|
||||||
$enrollment = Enrollment::where('course_id', $course->id)
|
$enrollment = Enrollment::where('course_id', $course->id)
|
||||||
->where('user_id', $student_id)
|
->where('user_id', $student_id)
|
||||||
->exists();
|
->exists();
|
||||||
|
|
||||||
// Cek Role (Jika admin/instruktur boleh bypass enrollment check)
|
// Cek Role
|
||||||
$currentUserRole = auth()->check() ? auth()->user()->role : 'student';
|
$currentUserRole = auth()->check() ? auth()->user()->role : 'student';
|
||||||
if (!$enrollment && ($currentUserRole != 'admin' && !is_course_instructor($course->id))) {
|
if (!$enrollment && ($currentUserRole != 'admin' && !is_course_instructor($course->id))) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ambil semua lesson ID untuk hitung progress manual
|
// Ambil semua lesson ID
|
||||||
$total_lesson_ids = Lesson::where('course_id', $course_id)->pluck('id')->toArray();
|
$total_lesson_ids = Lesson::where('course_id', $course_id)
|
||||||
|
->orderBy('id', 'asc')
|
||||||
|
->pluck('id')
|
||||||
|
->toArray();
|
||||||
|
|
||||||
// Ambil data history user
|
// Ambil data history user
|
||||||
$watch_history = Watch_history::where('course_id', $course_id)
|
$watch_history = Watch_history::where('course_id', $course_id)
|
||||||
@ -160,43 +163,72 @@ class QuizController extends Controller
|
|||||||
|
|
||||||
$completed_lessons = [];
|
$completed_lessons = [];
|
||||||
|
|
||||||
// Parse data lama
|
// Parse data lama dengan cara yang lebih aman
|
||||||
if ($watch_history && $watch_history->completed_lesson) {
|
if ($watch_history && !empty($watch_history->completed_lesson)) {
|
||||||
$decoded = json_decode($watch_history->completed_lesson, true);
|
$completed_lesson_data = $watch_history->completed_lesson;
|
||||||
if (is_array($decoded)) {
|
|
||||||
|
// Coba decode JSON
|
||||||
|
$decoded = json_decode($completed_lesson_data, true);
|
||||||
|
|
||||||
|
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
|
||||||
$completed_lessons = $decoded;
|
$completed_lessons = $decoded;
|
||||||
|
} else {
|
||||||
|
// Jika bukan JSON valid, coba parsing manual
|
||||||
|
$completed_lesson_data = trim($completed_lesson_data, '[]"\' ');
|
||||||
|
if (!empty($completed_lesson_data)) {
|
||||||
|
$completed_lessons = array_map('intval', explode(',', $completed_lesson_data));
|
||||||
|
$completed_lessons = array_unique($completed_lessons); // pastikan unik
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tambahkan lesson_id baru jika belum ada
|
// HANYA tambahkan lesson saat ini jika belum ada
|
||||||
if (!in_array($lesson_id, $completed_lessons)) {
|
$lesson_id_int = (int)$lesson_id;
|
||||||
$completed_lessons[] = $lesson_id;
|
if (!in_array($lesson_id_int, $completed_lessons)) {
|
||||||
|
$completed_lessons[] = $lesson_id_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tentukan apakah course selesai
|
// Sort dan pastikan unique
|
||||||
$is_completed = count($total_lesson_ids) <= count($completed_lessons);
|
sort($completed_lessons);
|
||||||
|
$completed_lessons = array_values(array_unique($completed_lessons));
|
||||||
|
|
||||||
|
// Course selesai jika semua lesson sudah completed
|
||||||
|
$all_lessons_completed = true;
|
||||||
|
foreach ($total_lesson_ids as $total_lesson_id) {
|
||||||
|
if (!in_array($total_lesson_id, $completed_lessons)) {
|
||||||
|
$all_lessons_completed = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$is_completed = $all_lessons_completed;
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'course_id' => $course_id,
|
'course_id' => $course_id,
|
||||||
'student_id' => $student_id,
|
'student_id' => $student_id,
|
||||||
'watching_lesson_id' => $lesson_id,
|
'watching_lesson_id' => $lesson_id,
|
||||||
'completed_lesson' => json_encode($completed_lessons),
|
'completed_lesson' => json_encode($completed_lessons),
|
||||||
'completed_date' => $is_completed ? time() : null,
|
'completed_date' => $is_completed ? now() : null,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Debug final data
|
||||||
|
// dd($data);
|
||||||
|
|
||||||
// Simpan ke DB
|
// Simpan ke DB
|
||||||
if ($watch_history) {
|
if ($watch_history) {
|
||||||
Watch_history::where('id', $watch_history->id)->update($data);
|
// Gunakan ini untuk memastikan hanya update yang diperlukan
|
||||||
|
$watch_history->update($data);
|
||||||
} else {
|
} else {
|
||||||
// Gunakan create agar timestamp created_at terisi otomatis
|
|
||||||
Watch_history::create($data);
|
Watch_history::create($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- LOGIKA SERTIFIKAT ---
|
// **LOGIKA SERTIFIKAT - dengan progress yang benar**
|
||||||
// Hitung progress secara manual agar lebih akurat
|
$completed_count = count(array_intersect($completed_lessons, $total_lesson_ids));
|
||||||
|
$total_count = count($total_lesson_ids);
|
||||||
|
|
||||||
$progress_percentage = 0;
|
$progress_percentage = 0;
|
||||||
if (count($total_lesson_ids) > 0) {
|
if ($total_count > 0) {
|
||||||
$progress_percentage = (count($completed_lessons) / count($total_lesson_ids)) * 100;
|
$progress_percentage = ($completed_count / $total_count) * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($progress_percentage >= 100) {
|
if ($progress_percentage >= 100) {
|
||||||
|
|||||||
24
app/Models/ProjectSubmission.php
Normal file
24
app/Models/ProjectSubmission.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class ProjectSubmission extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'lesson_id',
|
||||||
|
'user_id',
|
||||||
|
'drive_link',
|
||||||
|
'status',
|
||||||
|
'comment',
|
||||||
|
'reviewed_at',
|
||||||
|
'resubmitted_at',
|
||||||
|
'reviewed_by',
|
||||||
|
'created_at',
|
||||||
|
'updated_at'
|
||||||
|
];
|
||||||
|
}
|
||||||
@ -47,7 +47,7 @@
|
|||||||
<section class="video-playlist-section">
|
<section class="video-playlist-section">
|
||||||
<div class="my-container">
|
<div class="my-container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-8" id="player_content">
|
<div class="col-lg-8" id="player_content"> -->
|
||||||
@if(in_array($lesson_details->id, get_locked_lesson_ids($course_details->id, auth()->user()->id)) && $course_details->enable_drip_content)
|
@if(in_array($lesson_details->id, get_locked_lesson_ids($course_details->id, auth()->user()->id)) && $course_details->enable_drip_content)
|
||||||
@php
|
@php
|
||||||
$drip_content_settings = json_decode($course_details->drip_content_settings);
|
$drip_content_settings = json_decode($course_details->drip_content_settings);
|
||||||
|
|||||||
@ -40,8 +40,8 @@
|
|||||||
@include('course_player.player_config')
|
@include('course_player.player_config')
|
||||||
@else
|
@else
|
||||||
<div class="alert alert-danger text-center py-5">
|
<div class="alert alert-danger text-center py-5">
|
||||||
<h5>Invalid Google Drive Link</h5>
|
<h5>{{ get_phrase('Invalid Google Drive Link') }}</h5>
|
||||||
<p>Could not extract video ID from the provided URL.</p>
|
<p>{{ get_phrase('Could not extract video ID from the provided URL.') }}</p>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@elseif($lesson_details->lesson_type == 'image')
|
@elseif($lesson_details->lesson_type == 'image')
|
||||||
@ -62,7 +62,7 @@
|
|||||||
<div id="{{ $fullscreen_id }}" class="w-100 border rounded overflow-hidden bg-light">
|
<div id="{{ $fullscreen_id }}" class="w-100 border rounded overflow-hidden bg-light">
|
||||||
@if ($lesson_details->attachment_type == 'pdf')
|
@if ($lesson_details->attachment_type == 'pdf')
|
||||||
<a href="{{ $direct_pdf }}" target="_blank" class="btn btn-sm position-absolute top-0 end-0 mt-2 me-2 shadow" style="z-index: 1050; color: white; background: #001151;" title="Buka PDF di Tab Baru (tekan F11 untuk full screen)">
|
<a href="{{ $direct_pdf }}" target="_blank" class="btn btn-sm position-absolute top-0 end-0 mt-2 me-2 shadow" style="z-index: 1050; color: white; background: #001151;" title="Buka PDF di Tab Baru (tekan F11 untuk full screen)">
|
||||||
<i class="bi bi-box-arrow-up-right"></i> Buka Full PDF
|
<i class="bi bi-box-arrow-up-right"></i> {{ get_phrase('Open Full PDF') }}
|
||||||
</a>
|
</a>
|
||||||
<iframe src="{{ $pdf_src }}#toolbar=1&navpanes=0&scrollbar=1&view=FitH"
|
<iframe src="{{ $pdf_src }}#toolbar=1&navpanes=0&scrollbar=1&view=FitH"
|
||||||
class="w-100 border-0"
|
class="w-100 border-0"
|
||||||
@ -82,10 +82,10 @@
|
|||||||
|
|
||||||
<div class="text-center mb-3">
|
<div class="text-center mb-3">
|
||||||
<p class="mt-3 mb-1 fw-bold">
|
<p class="mt-3 mb-1 fw-bold">
|
||||||
Dokumen tidak dapat ditampilkan secara langsung
|
{{ get_phrase('The document cannot be displayed directly.') }}
|
||||||
</p>
|
</p>
|
||||||
<p class="text-muted small">
|
<p class="text-muted small">
|
||||||
Silakan unduh file untuk melihat isi dokumen
|
{{ get_phrase('Please download the file to view the contents of the document.') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -94,7 +94,7 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
download>
|
download>
|
||||||
<i class="fa fa-download me-1"></i>
|
<i class="fa fa-download me-1"></i>
|
||||||
Download Dokumen
|
{{ get_phrase('Download Document') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@ -104,6 +104,10 @@
|
|||||||
<div class="course-video-area border-primary pb-5">
|
<div class="course-video-area border-primary pb-5">
|
||||||
@include('course_player.quiz.index')
|
@include('course_player.quiz.index')
|
||||||
</div>
|
</div>
|
||||||
|
@elseif($lesson_details->lesson_type == 'project')
|
||||||
|
<div class="course-video-area border-primary pb-5">
|
||||||
|
@include('course_player.project.index')
|
||||||
|
</div>
|
||||||
@else
|
@else
|
||||||
<iframe class="embed-responsive-item" width="100%" src="{{ $lesson_details->lesson_src }}" allowfullscreen></iframe>
|
<iframe class="embed-responsive-item" width="100%" src="{{ $lesson_details->lesson_src }}" allowfullscreen></iframe>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
163
resources/views/course_player/project/index.blade.php
Normal file
163
resources/views/course_player/project/index.blade.php
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
@php
|
||||||
|
$project = App\Models\Lesson::where('id', request()->route()->parameter('id'))->firstOrFail();
|
||||||
|
|
||||||
|
$submission = DB::table('project_submissions')
|
||||||
|
->where('lesson_id', $project->id)
|
||||||
|
->where('user_id', auth()->id())
|
||||||
|
->first();
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* Mengatur agar list dan blockquote tidak memakan banyak ruang */
|
||||||
|
.description blockquote{
|
||||||
|
margin: 5px 0 !important;
|
||||||
|
padding: 0 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description ul, ul {
|
||||||
|
list-style-type: disc !important;
|
||||||
|
list-style-position: inside !important;
|
||||||
|
margin-left: 10px !important;
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description li {
|
||||||
|
display: list-item !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="row px-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<h4 class="quiz-title text-center mt-4 fw-bold">
|
||||||
|
<i class="fas fa-project-diagram me-2"></i> {{ $project->title }}
|
||||||
|
</h4>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="row mb-5">
|
||||||
|
<div class="col-12 mb-2">
|
||||||
|
<div class="card shadow-sm border-0">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title text-primary mb-3">
|
||||||
|
<i class="fas fa-file-alt me-2"></i>{{ get_phrase('Project Details') }}
|
||||||
|
</h5>
|
||||||
|
<div class="description text-secondary">
|
||||||
|
{!! $project->description !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="card shadow-sm border-0 bg-light">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title text-danger mb-3">
|
||||||
|
<i class="fas fa-clipboard-check me-2"></i>{{ get_phrase('Assessment criteria') }}
|
||||||
|
</h5>
|
||||||
|
<div class="description small text-muted">
|
||||||
|
{!! $project->attachment !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="submission-area p-4 border rounded mb-5">
|
||||||
|
<h5 class="mb-3">{{ get_phrase('Submit Assignment') }}</h5>
|
||||||
|
|
||||||
|
{{-- KONDISI 1: JIKA BELUM PERNAH SUBMIT --}}
|
||||||
|
@if(!$submission)
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<i class="fas fa-info-circle me-1"></i> {{ get_phrase('Please enter your project link below to be assessed.') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="{{ route('student.project.submit') }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<input type="hidden" name="lesson_id" value="{{ $project->id }}">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="project_link" class="form-label fw-bold">{{ get_phrase('Project Link (Google Drive/Github/Website)') }}</label>
|
||||||
|
<input type="url" class="form-control" id="project_link" name="submission_link" placeholder="https://..." required>
|
||||||
|
<div class="form-text">{{ get_phrase('Make sure the link is accessible to the instructor (Public/Anyone with link).') }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="eBtn gradient border-0">
|
||||||
|
<i class="fas fa-paper-plane me-1"></i> {{ get_phrase('Submit Project') }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{{-- KONDISI 2: JIKA SUDAH PERNAH SUBMIT --}}
|
||||||
|
@else
|
||||||
|
|
||||||
|
{{-- STATUS 0: MENUNGGU DIPERIKSA --}}
|
||||||
|
@if($submission->status == 0)
|
||||||
|
<div class="text-center p-5 border rounded bg-light">
|
||||||
|
<i class="fas fa-clock fa-3x text-warning mb-3"></i>
|
||||||
|
<h5 class="fw-bold">{{ get_phrase('Project is Being Reviewed') }}</h5>
|
||||||
|
<p class="text-muted">
|
||||||
|
{{ get_phrase('Thank you! We have received your project and it is currently in the instructor\'s review queue.') }}
|
||||||
|
</p>
|
||||||
|
<div class="mt-3">
|
||||||
|
<span class="text-secondary small">{{ get_phrase('Link that you submitted :') }} </span><br>
|
||||||
|
<a href="{{ $submission->drive_link }}" target="_blank" class="eBtn gradient border-0 btn-sm mt-1">
|
||||||
|
<i class="fas fa-external-link-alt me-1"></i> {{ get_phrase('View Your Project') }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- STATUS 2: PERLU REVISI --}}
|
||||||
|
@elseif($submission->status == 2)
|
||||||
|
<div class="alert alert-danger border-danger">
|
||||||
|
<h5 class="alert-heading fw-bold">
|
||||||
|
<i class="fas fa-exclamation-circle me-2"></i>{{ get_phrase('Project Needs Revision') }}
|
||||||
|
</h5>
|
||||||
|
<p>{{ get_phrase('The instructor has reviewed your project and provided feedback for improvement.') }}</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
{{-- Menampilkan Komentar Instruktur --}}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="fw-bold text-danger">{{ get_phrase('Instructor\'s Notes / Feedback:') }}</label>
|
||||||
|
<div class="bg-white p-3 rounded border border-danger text-dark mt-1">
|
||||||
|
{!! $submission->comment !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Form Resubmit --}}
|
||||||
|
<div class="mt-4">
|
||||||
|
<h6 class="fw-bold">{{ get_phrase('Submit Revision:') }}</h6>
|
||||||
|
<form action="{{ route('student.project.submit') }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<input type="hidden" name="lesson_id" value="{{ $project->id }}">
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
{{-- PERBAIKAN: name diubah jadi submission_link --}}
|
||||||
|
<input type="url" class="form-control" name="submission_link" placeholder="Masukkan link projek yang sudah diperbaiki..." required>
|
||||||
|
|
||||||
|
<button class="btn btn-danger" type="submit">
|
||||||
|
<i class="fas fa-redo me-1"></i> {{ get_phrase('Submit Revisions') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-text text-danger">{{ get_phrase('Make sure the new link includes the requested fix.') }} </div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- STATUS 1: DITERIMA / LULUS --}}
|
||||||
|
@elseif($submission->status == 1)
|
||||||
|
<div class="text-center p-5 border rounded bg-white border-success">
|
||||||
|
<i class="fas fa-check-circle fa-3x text-success mb-3"></i>
|
||||||
|
<h5 class="fw-bold text-success">{{ get_phrase('Congratulations! Project Accepted') }}</h5>
|
||||||
|
<p class="text-muted">
|
||||||
|
{{ get_phrase('Good work! Your project has met the assessment criteria.') }}
|
||||||
|
</p>
|
||||||
|
@if($submission->comment)
|
||||||
|
<div class="alert alert-success d-inline-block text-start mt-2">
|
||||||
|
<strong>{{ get_phrase('Instructor\'s Comment:') }}</strong> <br> {{ $submission->comment }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -9,7 +9,10 @@
|
|||||||
|
|
||||||
<a href="#" onclick="ajaxModal('{{ route('modal', ['instructor.quiz.create', 'id' => $course_details->id]) }}', '{{ get_phrase('Add new quiz') }}')" class="btn ol-btn-light ol-btn-sm">{{ get_phrase('Add quiz') }}</a>
|
<a href="#" onclick="ajaxModal('{{ route('modal', ['instructor.quiz.create', 'id' => $course_details->id]) }}', '{{ get_phrase('Add new quiz') }}')" class="btn ol-btn-light ol-btn-sm">{{ get_phrase('Add quiz') }}</a>
|
||||||
|
|
||||||
|
<a href="#" onclick="ajaxModal('{{ route('modal', ['instructor.project.create', 'id' => $course_details->id]) }}', '{{ get_phrase('Add new project') }}')" class="btn ol-btn-light ol-btn-sm">{{ get_phrase('Add project') }}</a>
|
||||||
|
|
||||||
<a href="#" onclick="ajaxModal('{{ route('modal', ['instructor.course.section_sort', 'id' => $course_details->id]) }}', '{{ get_phrase('Sort sections') }}')" class="btn ol-btn-light ol-btn-sm">{{ get_phrase('Sort Section') }}</a>
|
<a href="#" onclick="ajaxModal('{{ route('modal', ['instructor.course.section_sort', 'id' => $course_details->id]) }}', '{{ get_phrase('Sort sections') }}')" class="btn ol-btn-light ol-btn-sm">{{ get_phrase('Sort Section') }}</a>
|
||||||
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -58,7 +61,7 @@
|
|||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
@if ($lesson->lesson_type == 'quiz')
|
@if ($lesson->lesson_type == 'quiz')
|
||||||
<a href="#" data-bs-toggle="tooltip" title="{{ get_phrase('Result') }}" onclick="ajaxModal('{{ route('modal', ['instructor.quiz_result.index', 'id' => $lesson->id]) }}', '{{ get_phrase('Result') }}', 'modal-xl')" class="edit-delete">
|
<a href="#" data-bs-toggle="tooltip" title="{{ get_phrase('Result') }}" onclick="ajaxModal('{{ route('modal', ['instructor.quiz_result.index', 'id' => $lesson->id]) }}', '{{ get_phrase('Result') }}', 'modal-xl')" class="edit-delete">
|
||||||
<span class="fi fi-rr-clipboard-list-check"></span>
|
<span class="fi fi-rr-paperclip-vertical"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="#" data-bs-toggle="tooltip" title="{{ get_phrase('Questions') }}" onclick="ajaxModal('{{ route('modal', ['instructor.questions.index', 'id' => $lesson->id]) }}', '{{ get_phrase('Questions') }}', 'modal-lg')" class="edit-delete">
|
<a href="#" data-bs-toggle="tooltip" title="{{ get_phrase('Questions') }}" onclick="ajaxModal('{{ route('modal', ['instructor.questions.index', 'id' => $lesson->id]) }}', '{{ get_phrase('Questions') }}', 'modal-lg')" class="edit-delete">
|
||||||
@ -68,9 +71,20 @@
|
|||||||
<a href="#" data-bs-toggle="tooltip" title="{{ get_phrase('Edit quiz') }}" onclick="ajaxModal('{{ route('modal', ['instructor.quiz.edit', 'id' => $lesson->id]) }}', '{{ get_phrase('Edit quiz') }}')" class="edit-delete">
|
<a href="#" data-bs-toggle="tooltip" title="{{ get_phrase('Edit quiz') }}" onclick="ajaxModal('{{ route('modal', ['instructor.quiz.edit', 'id' => $lesson->id]) }}', '{{ get_phrase('Edit quiz') }}')" class="edit-delete">
|
||||||
<span class="fi-rr-pencil"></span>
|
<span class="fi-rr-pencil"></span>
|
||||||
</a>
|
</a>
|
||||||
|
@elseif ($lesson->lesson_type == 'project')
|
||||||
|
<a href="javascript:void(0);"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
title="{{ get_phrase('Submissions') }}"
|
||||||
|
onclick="ajaxModal('{{ route('instructor.project.grading.index', $lesson->id) }}', '{{ get_phrase('Submissions') }}', 'modal-xl')"
|
||||||
|
class="edit-delete">
|
||||||
|
<span class="fi fi-rr-clipboard-list"></span>
|
||||||
|
</a>
|
||||||
|
<a href="#" data-bs-toggle="tooltip" title="{{ get_phrase('Edit project') }}" onclick="ajaxModal('{{ route('modal', ['instructor.project.edit', 'id' => $lesson->id]) }}', '{{ get_phrase('Edit project') }}')" class="edit-delete">
|
||||||
|
<span class="fi-rr-pencil"></span>
|
||||||
|
</a>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if ($lesson->lesson_type != 'quiz')
|
@if ($lesson->lesson_type != 'quiz' && $lesson->lesson_type != 'project')
|
||||||
<a href="#" data-bs-toggle="tooltip" title="{{ get_phrase('Edit lesson') }}" onclick="ajaxModal('{{ route('modal', ['instructor.course.lesson_edit', 'id' => $lesson->id]) }}', '{{ get_phrase('Edit lesson') }}')" class="edit-delete">
|
<a href="#" data-bs-toggle="tooltip" title="{{ get_phrase('Edit lesson') }}" onclick="ajaxModal('{{ route('modal', ['instructor.course.lesson_edit', 'id' => $lesson->id]) }}', '{{ get_phrase('Edit lesson') }}')" class="edit-delete">
|
||||||
<span class="fi-rr-pencil"></span>
|
<span class="fi-rr-pencil"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@ -14,8 +14,6 @@
|
|||||||
{{ get_phrase('Google drive video') }}
|
{{ get_phrase('Google drive video') }}
|
||||||
@elseif($lesson_type == 'document')
|
@elseif($lesson_type == 'document')
|
||||||
{{ get_phrase('Document file') }}
|
{{ get_phrase('Document file') }}
|
||||||
@elseif ($lesson_type == 'scorm')
|
|
||||||
{{ get_phrase('Scorm content') }}
|
|
||||||
@else
|
@else
|
||||||
{{ ucfirst($lesson_type) }}
|
{{ ucfirst($lesson_type) }}
|
||||||
@endif
|
@endif
|
||||||
@ -47,14 +45,10 @@
|
|||||||
@include('instructor.course.youtube_type_lesson_add')
|
@include('instructor.course.youtube_type_lesson_add')
|
||||||
@elseif ($lesson_type == 'academy_cloud')
|
@elseif ($lesson_type == 'academy_cloud')
|
||||||
@include('instructor.course.academy_cloud_type_lesson_add')
|
@include('instructor.course.academy_cloud_type_lesson_add')
|
||||||
@elseif ($lesson_type == 'vimeo')
|
|
||||||
@include('instructor.course.vimeo_type_lesson_add')
|
|
||||||
@elseif ($lesson_type == 'html5')
|
@elseif ($lesson_type == 'html5')
|
||||||
@include('instructor.course.html5_type_lesson_add')
|
@include('instructor.course.html5_type_lesson_add')
|
||||||
@elseif ($lesson_type == 'video')
|
@elseif ($lesson_type == 'video')
|
||||||
@include('instructor.course.video_type_lesson_add')
|
@include('instructor.course.video_type_lesson_add')
|
||||||
@elseif ($lesson_type == 'amazon-s3')
|
|
||||||
@include('amazon_s3_type_lesson_add.php')
|
|
||||||
@elseif ($lesson_type == 'google_drive_video')
|
@elseif ($lesson_type == 'google_drive_video')
|
||||||
@include('instructor.course.google_drive_type_lesson_add')
|
@include('instructor.course.google_drive_type_lesson_add')
|
||||||
@elseif ($lesson_type == 'document')
|
@elseif ($lesson_type == 'document')
|
||||||
@ -65,8 +59,6 @@
|
|||||||
@include('instructor.course.image_file_type_lesson_add')
|
@include('instructor.course.image_file_type_lesson_add')
|
||||||
@elseif ($lesson_type == 'iframe')
|
@elseif ($lesson_type == 'iframe')
|
||||||
@include('instructor.course.iframe_type_lesson_add')
|
@include('instructor.course.iframe_type_lesson_add')
|
||||||
@elseif ($lesson_type == 'scorm')
|
|
||||||
@include('instructor.course.scorm_type_lesson_add')
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="form-group mb-3">
|
<div class="form-group mb-3">
|
||||||
|
|||||||
50
resources/views/instructor/project/create.blade.php
Normal file
50
resources/views/instructor/project/create.blade.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<form action="{{ route('instructor.course.project.store') }}" method="post">@csrf
|
||||||
|
|
||||||
|
<input type="hidden" name="course_id" value="{{ $id }}">
|
||||||
|
<div class="fpb7 mb-3">
|
||||||
|
<label class="form-label ol-form-label" for="title">
|
||||||
|
{{ get_phrase('Title') }}
|
||||||
|
<span class="text-danger ms-1">*</span>
|
||||||
|
</label>
|
||||||
|
<input class="form-control ol-form-control" type="text" id="title" name="title" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-12 fpb-7">
|
||||||
|
<label class="form-label ol-form-label">
|
||||||
|
{{ get_phrase('Section') }}
|
||||||
|
<span class="text-danger ms-1">*</span>
|
||||||
|
</label>
|
||||||
|
<select class="form-control ol-form-control ol-select2" data-toggle="select2" name="section">
|
||||||
|
<option value="">{{ get_phrase('Select an option') }}</option>
|
||||||
|
@foreach (App\Models\Section::where('course_id', $id)->get() as $section)
|
||||||
|
<option value="{{ $section->id }}">{{ $section->title }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fpb-7 mb-3">
|
||||||
|
<label for="description"
|
||||||
|
class="form-label ol-form-label col-form-label">{{ get_phrase('Project Assignment') }}</label>
|
||||||
|
<textarea name="description" rows="5" class="form-control ol-form-control text_editor"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fpb-7 mb-3">
|
||||||
|
<label for="attachment"
|
||||||
|
class="form-label ol-form-label col-form-label">{{ get_phrase('Assessment Criteria') }}</label>
|
||||||
|
<textarea name="attachment" rows="5" class="form-control ol-form-control text_editor"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fpb-7 mb-6">
|
||||||
|
<label for="attachment"
|
||||||
|
class="form-label ol-form-label col-form-label">{{ get_phrase('Summary') }}</label>
|
||||||
|
<textarea name="attachment" rows="5" class="form-control ol-form-control text_editor"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fpb7">
|
||||||
|
<button type="submit" class="btn ol-btn-primary">{{ get_phrase('Add Project') }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@include('instructor.init')
|
||||||
58
resources/views/instructor/project/edit.blade.php
Normal file
58
resources/views/instructor/project/edit.blade.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
@php
|
||||||
|
$project = App\Models\Lesson::join('sections', 'lessons.section_id', 'sections.id')
|
||||||
|
->join('courses', 'sections.course_id', 'courses.id')
|
||||||
|
->select('lessons.*', 'courses.id as course_id')
|
||||||
|
->where('lessons.id', $id)
|
||||||
|
->first();
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<form action="{{ route('instructor.course.project.update', $id) }}" method="post">@csrf
|
||||||
|
<div class="fpb7 mb-3">
|
||||||
|
<label class="form-label ol-form-label" for="title">
|
||||||
|
{{ get_phrase('Title') }}
|
||||||
|
<span class="text-danger ms-1">*</span>
|
||||||
|
</label>
|
||||||
|
<input class="form-control ol-form-control" type="text" id="title" name="title" value="{{ $project->title }}"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-12 fpb-7">
|
||||||
|
<label class="form-label ol-form-label">
|
||||||
|
{{ get_phrase('Section') }}
|
||||||
|
<span class="text-danger ms-1">*</span>
|
||||||
|
</label>
|
||||||
|
<select class="form-control ol-form-control ol-select2" data-toggle="select2" name="section">
|
||||||
|
<option value="">{{ get_phrase('Select an option') }}</option>
|
||||||
|
@foreach (App\Models\Section::where('course_id', $project->course_id)->get() as $section)
|
||||||
|
<option value="{{ $section->id }}" @if ($section->id == $project->section_id) selected @endif>
|
||||||
|
{{ $section->title }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fpb-7 mb-3">
|
||||||
|
<label for="description"
|
||||||
|
class="form-label ol-form-label col-form-label">{{ get_phrase('Project Assignment') }}</label>
|
||||||
|
<textarea name="description" rows="5" class="form-control ol-form-control text_editor">{!! $project->description !!}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fpb-7 mb-3">
|
||||||
|
<label for="attachment"
|
||||||
|
class="form-label ol-form-label col-form-label">{{ get_phrase('Assessment Criteria') }}</label>
|
||||||
|
<textarea name="attachment" rows="5" class="form-control ol-form-control text_editor">{!! $project->attachment !!}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fpb-7 mb-6">
|
||||||
|
<label for="summary"
|
||||||
|
class="form-label ol-form-label col-form-label">{{ get_phrase('Summary') }}</label>
|
||||||
|
<textarea name="summary" rows="5" class="form-control ol-form-control text_editor">{!! $project->summary !!}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="fpb7">
|
||||||
|
<button type="submit" class="btn ol-btn-primary">{{ get_phrase('Update Project') }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@include('instructor.init')
|
||||||
121
resources/views/instructor/project/grading/index.blade.php
Normal file
121
resources/views/instructor/project/grading/index.blade.php
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
{{-- Container Utama --}}
|
||||||
|
<div class="row g-0 h-100">
|
||||||
|
|
||||||
|
{{-- KOLOM KIRI: LIST SISWA --}}
|
||||||
|
<div class="col-md-4 border-end" style="min-height: 400px; max-height: 70vh; overflow-y: auto;">
|
||||||
|
<div class="p-3 border-bottom bg-light sticky-top">
|
||||||
|
<h6 class="mb-0 fw-bold"><i class="fas fa-users me-2"></i> {{ get_phrase('Student List') }}</h6>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="list-group list-group-flush" id="studentList">
|
||||||
|
@if($participants->isEmpty())
|
||||||
|
<div class="text-center p-5 text-muted small">
|
||||||
|
{{ get_phrase('No participants found.') }}
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
@foreach ($participants as $participant)
|
||||||
|
<a href="javascript:void(0);"
|
||||||
|
class="list-group-item list-group-item-action py-3 student-item"
|
||||||
|
{{-- PERBAIKAN DISINI: Tambahkan parameter ke-3 yaitu $lesson_id --}}
|
||||||
|
onclick="loadStudentSubmission(this, '{{ $participant->id }}', '{{ $lesson_id }}')">
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="me-3 d-flex align-items-center justify-content-center rounded-circle bg-primary text-white fw-bold"
|
||||||
|
style="width: 44px; height: 36px; font-size: 14px;">
|
||||||
|
{{ strtoupper(substr($participant->name, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-100">
|
||||||
|
<h6 class="mb-0 text-dark" style="font-size: 14px;">{{ $participant->name }}</h6>
|
||||||
|
<small class="text-muted" style="font-size: 12px;">{{ get_phrase('Click to grade') }}</small>
|
||||||
|
</div>
|
||||||
|
<i class="fas fa-chevron-right text-muted small"></i>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- KOLOM KANAN: AREA PREVIEW & GRADING --}}
|
||||||
|
<div class="col-md-8 bg-white">
|
||||||
|
{{-- ID ini penting: target AJAX --}}
|
||||||
|
<div id="grading-area" class="h-100 position-relative">
|
||||||
|
|
||||||
|
{{-- State Awal (Belum Klik) --}}
|
||||||
|
<div class="d-flex flex-column align-items-center justify-content-center h-100 text-center p-5">
|
||||||
|
<div class="mb-3 p-4 rounded-circle bg-light">
|
||||||
|
<i class="fi fi-rr-box-open fs-1 text-secondary opacity-50"></i>
|
||||||
|
</div>
|
||||||
|
<h6 class="text-muted">{{ get_phrase('Select a student to start grading') }}</h6>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function loadStudentSubmission(element, userId, lessonId) {
|
||||||
|
// Cegah event default
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// Validasi parameter
|
||||||
|
if (!userId || !lessonId) {
|
||||||
|
console.error("Missing parameters. User ID:", userId, "Lesson ID:", lessonId);
|
||||||
|
alert('Missing parameters');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Visual Active State
|
||||||
|
$('.student-item').removeClass('active bg-light');
|
||||||
|
$(element).addClass('active bg-light');
|
||||||
|
|
||||||
|
// 2. Loading State
|
||||||
|
$('#grading-area').html(`
|
||||||
|
<div class="d-flex flex-column align-items-center justify-content-center h-100">
|
||||||
|
<div class="spinner-border text-primary mb-2" role="status"></div>
|
||||||
|
<small class="text-muted">Loading data...</small>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Debugging
|
||||||
|
console.log("AJAX Call Parameters:");
|
||||||
|
console.log("- Lesson ID:", lessonId);
|
||||||
|
console.log("- User ID:", userId);
|
||||||
|
console.log("- URL:", "{{ route('instructor.project.grading.preview') }}");
|
||||||
|
console.log("- CSRF Token:", $('meta[name="csrf-token"]').attr('content'));
|
||||||
|
|
||||||
|
// 3. AJAX Call
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: "{{ route('instructor.project.grading.preview') }}",
|
||||||
|
data: {
|
||||||
|
lesson_id: lessonId,
|
||||||
|
user_id: userId
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
console.log("Success Response:", response.substring(0, 200)); // Log 200 karakter pertama
|
||||||
|
$('#grading-area').html(response);
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error("AJAX Error:", error);
|
||||||
|
console.error("Status:", status);
|
||||||
|
console.error("Response:", xhr.responseText);
|
||||||
|
|
||||||
|
$('#grading-area').html(`
|
||||||
|
<div class="alert alert-danger m-3">
|
||||||
|
<h6>Failed to load data</h6>
|
||||||
|
<small>Error: ${error}</small>
|
||||||
|
<br>
|
||||||
|
<small>Check console for details</small>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
182
resources/views/instructor/project/grading/preview.blade.php
Normal file
182
resources/views/instructor/project/grading/preview.blade.php
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
{{-- HAPUS <div class="row"> jika ada, gunakan div biasa --}}
|
||||||
|
<div class="h-100">
|
||||||
|
|
||||||
|
{{-- KONDISI 1: Belum Submit --}}
|
||||||
|
@if(!$submission)
|
||||||
|
<div class="d-flex flex-column align-items-center justify-content-center h-100 text-center p-5">
|
||||||
|
<div class="mb-3 p-3 bg-light rounded-circle">
|
||||||
|
<i class="fas fa-times text-danger fa-2x"></i>
|
||||||
|
</div>
|
||||||
|
<h5>{{ get_phrase('Not Submitted') }}</h5>
|
||||||
|
<p class="text-muted">{{ get_phrase('This student has not submitted the project yet.') }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- KONDISI 2: Sudah Submit --}}
|
||||||
|
@else
|
||||||
|
<div class="p-4">
|
||||||
|
{{-- Header Status --}}
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4 pb-3 border-bottom">
|
||||||
|
<div>
|
||||||
|
<h5 class="fw-bold mb-1">{{ get_phrase('Project Submission') }}</h5>
|
||||||
|
<small class="text-muted">
|
||||||
|
<i class="far fa-clock me-1"></i>
|
||||||
|
{{ date('d M Y, H:i', strtotime($submission->created_at)) }}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
@if($submission->status == 1)
|
||||||
|
<span class="badge bg-success px-3 py-2">{{ get_phrase('Accepted') }}</span>
|
||||||
|
@elseif($submission->status == 2)
|
||||||
|
<span class="badge bg-danger px-3 py-2">{{ get_phrase('Revision Needed') }}</span>
|
||||||
|
@else
|
||||||
|
<span class="badge bg-warning text-dark px-3 py-2">{{ get_phrase('Pending Review') }}</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Link Project --}}
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="fw-bold mb-2">{{ get_phrase('Student Project Link') }}</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control bg-light" value="{{ $submission->drive_link }}" readonly>
|
||||||
|
<a href="{{ $submission->drive_link }}" target="_blank" class="btn btn-primary">
|
||||||
|
<i class="fas fa-external-link-alt"></i> {{ get_phrase('Open') }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Form Grading --}}
|
||||||
|
<div class="card border bg-light shadow-none">
|
||||||
|
<div class="card-body">
|
||||||
|
<form action="{{ route('instructor.project.grading.update', $submission->id) }}" method="post" id="gradingForm">
|
||||||
|
@csrf
|
||||||
|
<h6 class="fw-bold mb-3"><i class="fas fa-check-double me-2"></i>{{ get_phrase('Grading') }}</h6>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="btn-group w-100" role="group">
|
||||||
|
<input type="radio" class="btn-check" name="status" id="accept_{{ $submission->id }}" value="1"
|
||||||
|
{{ $submission->status == 1 ? 'checked' : '' }} onchange="toggleComment(this)">
|
||||||
|
<label class="btn btn-outline-success" for="accept_{{ $submission->id }}">{{ get_phrase('Passed') }}</label>
|
||||||
|
|
||||||
|
<input type="radio" class="btn-check" name="status" id="revise_{{ $submission->id }}" value="2"
|
||||||
|
{{ $submission->status == 2 ? 'checked' : '' }} onchange="toggleComment(this)">
|
||||||
|
<label class="btn btn-outline-danger" for="revise_{{ $submission->id }}">{{ get_phrase('Revision Needed') }}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Area Komentar dengan WYSIWYG Editor --}}
|
||||||
|
<div id="comment_box_area" style="display: {{ $submission->status == 2 ? 'block' : 'none' }};">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="fw-bold text-danger mb-1">
|
||||||
|
{{ empty($submission->comment) ? get_phrase('Add Revision Notes') : get_phrase('Previous Revision Notes') }} *
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{{-- Textarea untuk Summernote --}}
|
||||||
|
<textarea name="comment" id="comment_editor" class="form-control">{{ $submission->comment }}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary w-100">{{ get_phrase('Save Grading') }}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Tambahkan CSS Summernote --}}
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
{{-- Tambahkan Script Summernote --}}
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let commentEditor = null;
|
||||||
|
|
||||||
|
function toggleComment(radio) {
|
||||||
|
let box = document.getElementById('comment_box_area');
|
||||||
|
|
||||||
|
if (radio.value == '2') {
|
||||||
|
$(box).slideDown();
|
||||||
|
// Inisialisasi editor jika belum diinisialisasi
|
||||||
|
initSummernote();
|
||||||
|
// Fokus ke editor
|
||||||
|
setTimeout(() => {
|
||||||
|
if (commentEditor && commentEditor.summernote) {
|
||||||
|
commentEditor.summernote('focus');
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
} else {
|
||||||
|
$(box).slideUp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi untuk menginisialisasi Summernote
|
||||||
|
function initSummernote() {
|
||||||
|
if (!commentEditor) {
|
||||||
|
$('#comment_editor').summernote({
|
||||||
|
height: 200,
|
||||||
|
toolbar: [
|
||||||
|
['style', ['style']],
|
||||||
|
['font', ['bold', 'italic', 'underline', 'clear']],
|
||||||
|
['fontname', ['fontname']],
|
||||||
|
['color', ['color']],
|
||||||
|
['para', ['ul', 'ol', 'paragraph']],
|
||||||
|
['table', ['table']],
|
||||||
|
['insert', ['link', 'picture']],
|
||||||
|
['view', ['fullscreen', 'codeview', 'help']]
|
||||||
|
],
|
||||||
|
placeholder: '{{ get_phrase("Explain what needs to be fixed...") }}'
|
||||||
|
});
|
||||||
|
commentEditor = $('#comment_editor');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi untuk validasi form sebelum submit
|
||||||
|
$('#gradingForm').on('submit', function(e) {
|
||||||
|
const status = $('input[name="status"]:checked').val();
|
||||||
|
|
||||||
|
if (status == '2') {
|
||||||
|
// Jika status "Revision Needed", pastikan ada konten di editor
|
||||||
|
let commentContent = '';
|
||||||
|
|
||||||
|
if (commentEditor && commentEditor.summernote) {
|
||||||
|
commentContent = commentEditor.summernote('code').trim();
|
||||||
|
} else {
|
||||||
|
commentContent = $('#comment_editor').val().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hapus tag HTML untuk cek konten sebenarnya
|
||||||
|
const plainText = commentContent.replace(/<[^>]*>/g, '').trim();
|
||||||
|
|
||||||
|
if (plainText === '') {
|
||||||
|
e.preventDefault();
|
||||||
|
alert('{{ get_phrase("Please add revision notes before submitting.") }}');
|
||||||
|
if (commentEditor && commentEditor.summernote) {
|
||||||
|
commentEditor.summernote('focus');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Inisialisasi editor otomatis jika sudah ada komentar sebelumnya dan status adalah "Revision Needed"
|
||||||
|
@if($submission && $submission->status == 2 && !empty($submission->comment))
|
||||||
|
$(document).ready(function() {
|
||||||
|
// Tunggu sebentar agar DOM siap
|
||||||
|
setTimeout(() => {
|
||||||
|
initSummernote();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
@endif
|
||||||
|
|
||||||
|
// Inisialisasi editor jika comment_box_area langsung terlihat
|
||||||
|
$(document).ready(function() {
|
||||||
|
@if($submission && $submission->status == 2)
|
||||||
|
// Tunggu sedikit agar DOM selesai render
|
||||||
|
setTimeout(() => {
|
||||||
|
initSummernote();
|
||||||
|
}, 200);
|
||||||
|
@endif
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@ -32,7 +32,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<input class="form-control ol-form-control" type="number" min="0" max="23" name="hour"
|
<input class="form-control ol-form-control" type="number" min="0" max="23" name="hour"
|
||||||
placeholder="00 hour">
|
placeholder="00 hour" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<input class="form-control ol-form-control" type="number" min="0" max="59" name="minute"
|
<input class="form-control ol-form-control" type="number" min="0" max="59" name="minute"
|
||||||
|
|||||||
@ -27,7 +27,7 @@ use App\Http\Controllers\NewsletterController;
|
|||||||
use App\Http\Controllers\ReportController;
|
use App\Http\Controllers\ReportController;
|
||||||
use App\Http\Controllers\SeoController;
|
use App\Http\Controllers\SeoController;
|
||||||
use App\Http\Controllers\SettingController;
|
use App\Http\Controllers\SettingController;
|
||||||
use App\Http\Controllers\Updater;
|
// use App\Http\Controllers\Updater;
|
||||||
use App\Http\Controllers\UsersController;
|
use App\Http\Controllers\UsersController;
|
||||||
use App\Http\Controllers\Admin\TutorBookingController;
|
use App\Http\Controllers\Admin\TutorBookingController;
|
||||||
use App\Http\Controllers\Admin\KnowledgeBaseController;
|
use App\Http\Controllers\Admin\KnowledgeBaseController;
|
||||||
@ -77,12 +77,12 @@ Route::name('admin.')->prefix('admin')->middleware('admin')->group(function () {
|
|||||||
//invoice
|
//invoice
|
||||||
Route::get('invoice/{id?}', [InvoiceController::class, 'invoice'])->name('admin.invoice');
|
Route::get('invoice/{id?}', [InvoiceController::class, 'invoice'])->name('admin.invoice');
|
||||||
|
|
||||||
Route::controller(Updater::class)->middleware('auth', 'verified')->group(function () {
|
// Route::controller(Updater::class)->middleware('auth', 'verified')->group(function () {
|
||||||
|
|
||||||
Route::post('admin/addon/create', 'update')->name('addon.create');
|
// Route::post('admin/addon/create', 'update')->name('addon.create');
|
||||||
Route::post('admin/addon/update', 'update')->name('addon.update');
|
// Route::post('admin/addon/update', 'update')->name('addon.update');
|
||||||
Route::post('admin/product/update', 'update')->name('product.update');
|
// Route::post('admin/product/update', 'update')->name('product.update');
|
||||||
});
|
// });
|
||||||
|
|
||||||
//curriculum
|
//curriculum
|
||||||
Route::controller(CurriculumController::class)->group(function () {
|
Route::controller(CurriculumController::class)->group(function () {
|
||||||
|
|||||||
@ -14,6 +14,7 @@ use App\Http\Controllers\instructor\PayoutController;
|
|||||||
use App\Http\Controllers\instructor\PayoutSettingsController;
|
use App\Http\Controllers\instructor\PayoutSettingsController;
|
||||||
use App\Http\Controllers\instructor\QuestionController;
|
use App\Http\Controllers\instructor\QuestionController;
|
||||||
use App\Http\Controllers\instructor\QuizController;
|
use App\Http\Controllers\instructor\QuizController;
|
||||||
|
use App\Http\Controllers\instructor\ProjectController;
|
||||||
use App\Http\Controllers\instructor\SalesReportController;
|
use App\Http\Controllers\instructor\SalesReportController;
|
||||||
use App\Http\Controllers\instructor\SectionController;
|
use App\Http\Controllers\instructor\SectionController;
|
||||||
use App\Http\Controllers\instructor\TeamTrainingController;
|
use App\Http\Controllers\instructor\TeamTrainingController;
|
||||||
@ -76,6 +77,16 @@ Route::name('instructor.')->prefix('instructor')->middleware(['instructor'])->gr
|
|||||||
Route::get('quiz/result/preview', 'result_preview')->name('quiz.result.preview');
|
Route::get('quiz/result/preview', 'result_preview')->name('quiz.result.preview');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// course project
|
||||||
|
Route::controller(ProjectController::class)->group(function () {
|
||||||
|
Route::post('course/project/store', 'store')->name('course.project.store');
|
||||||
|
Route::post('course/project/update/{id}', 'update')->name('course.project.update');
|
||||||
|
Route::get('/project/grading/preview', 'getPreview')->name('project.grading.preview');
|
||||||
|
Route::get('/project/grading/{id}', 'getIndex')->name('project.grading.index');
|
||||||
|
Route::get('/project/participant/submission', 'getParticipantSubmission')->name('project.participant.submission');
|
||||||
|
Route::post('/project/grading/update/{id}', 'updateSubmission')->name('project.grading.update');
|
||||||
|
});
|
||||||
|
|
||||||
// question route
|
// question route
|
||||||
Route::controller(QuestionController::class)->group(function () {
|
Route::controller(QuestionController::class)->group(function () {
|
||||||
Route::post('course/question/store', 'store')->name('course.question.store');
|
Route::post('course/question/store', 'store')->name('course.question.store');
|
||||||
|
|||||||
@ -14,6 +14,7 @@ use App\Http\Controllers\student\MyCoursesController;
|
|||||||
use App\Http\Controllers\student\MyProfileController;
|
use App\Http\Controllers\student\MyProfileController;
|
||||||
use App\Http\Controllers\student\MyTeamPackageController;
|
use App\Http\Controllers\student\MyTeamPackageController;
|
||||||
use App\Http\Controllers\student\OfflinePaymentController;
|
use App\Http\Controllers\student\OfflinePaymentController;
|
||||||
|
use App\Http\Controllers\student\ProjectController;
|
||||||
use App\Http\Controllers\student\VAPaymentController;
|
use App\Http\Controllers\student\VAPaymentController;
|
||||||
use App\Http\Controllers\student\PurchaseController;
|
use App\Http\Controllers\student\PurchaseController;
|
||||||
use App\Http\Controllers\student\QuizController;
|
use App\Http\Controllers\student\QuizController;
|
||||||
@ -49,6 +50,12 @@ Route::middleware(['auth'])->group(function () {
|
|||||||
Route::get('load/quiz/questions/', 'load_questions')->name('load.quiz.questions');
|
Route::get('load/quiz/questions/', 'load_questions')->name('load.quiz.questions');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// project routes
|
||||||
|
Route::controller(ProjectController::class)->group(function () {
|
||||||
|
Route::post('project/submit', 'submit')->name('student.project.submit');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// purchase routes
|
// purchase routes
|
||||||
Route::controller(PurchaseController::class)->group(function () {
|
Route::controller(PurchaseController::class)->group(function () {
|
||||||
Route::get('purchase/course/{course_id}', 'purchase_course')->name('purchase.course');
|
Route::get('purchase/course/{course_id}', 'purchase_course')->name('purchase.course');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user