Compare commits
7 Commits
fdda679141
...
731e95a864
| Author | SHA1 | Date |
|---|---|---|
|
|
731e95a864 | |
|
|
f896e54d34 | |
|
|
b2dbb09951 | |
|
|
2e56c45db9 | |
|
|
1821b6f59e | |
|
|
b1f5b14287 | |
|
|
f18c470f14 |
|
|
@ -81,7 +81,7 @@ public function store(Request $request)
|
||||||
'no_telp' => $request->no_telp,
|
'no_telp' => $request->no_telp,
|
||||||
'tgl_booking' => $request->tgl_booking,
|
'tgl_booking' => $request->tgl_booking,
|
||||||
'deskripsi_tambahan' => $request->deskripsi_tambahan,
|
'deskripsi_tambahan' => $request->deskripsi_tambahan,
|
||||||
'kode_unik' => $kode_unik
|
'kode_unik' => $kode_unik,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,11 @@ public function show(string $id)
|
||||||
{
|
{
|
||||||
$data = BookingModel::where('kode_unik', $id)->first();
|
$data = BookingModel::where('kode_unik', $id)->first();
|
||||||
if($data != null) {
|
if($data != null) {
|
||||||
|
if($data->status_tes == '1' && $data->unix_expired_time < time()) {
|
||||||
|
$data->update([
|
||||||
|
'status_tes' => '0'
|
||||||
|
]);
|
||||||
|
}
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'status' => true,
|
'status' => true,
|
||||||
'msg' => 'Data ditemukan (' . $id . ')',
|
'msg' => 'Data ditemukan (' . $id . ')',
|
||||||
|
|
@ -46,6 +51,7 @@ public function show(string $id)
|
||||||
'nama_lengkap' => $data->nama_lengkap,
|
'nama_lengkap' => $data->nama_lengkap,
|
||||||
'kode_unik' => $data->kode_unik,
|
'kode_unik' => $data->kode_unik,
|
||||||
'tgl_booking' => $data->tgl_booking,
|
'tgl_booking' => $data->tgl_booking,
|
||||||
|
'jam_booking' => date('H:i:s', strtotime($data->created_at)),
|
||||||
'deskripsi_tambahan' => $data->deskripsi_tambahan,
|
'deskripsi_tambahan' => $data->deskripsi_tambahan,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\DataSoalModel;
|
||||||
|
use App\Models\DetailTestModel;
|
||||||
|
use App\Models\TestSessionsModel;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class FinishUjianController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getAllAnswer(Request $request) {
|
||||||
|
$data_session = TestSessionsModel::where('id_test_sessions', $request->id_test_sessions)->first();
|
||||||
|
if($data_session != null) {
|
||||||
|
if($data_session->status_session != '1') {
|
||||||
|
return response()->json([
|
||||||
|
'status' => false,
|
||||||
|
'message' => 'Data sesi tes belum dimulai atau telah usai. Silahkan cek status dengan kode untuk informasi lebih lanjut.'
|
||||||
|
]);
|
||||||
|
} else if($data_session->status_session == '1') {
|
||||||
|
$detail_test = DetailTestModel::where('id_test_sessions', $request->id_test_sessions)->get();
|
||||||
|
$data_ujian = [];
|
||||||
|
foreach($detail_test as $detail) {
|
||||||
|
$data_soal = DataSoalModel::where('id_soal', $detail->id_soal)->first();
|
||||||
|
$data_jawaban = $detail->jawaban;
|
||||||
|
if($data_jawaban == 'a') {
|
||||||
|
$data_jawaban = $data_soal->jawaban_a;
|
||||||
|
} else if($data_jawaban == 'b') {
|
||||||
|
$data_jawaban = $data_soal->jawaban_b;
|
||||||
|
} else if($data_jawaban == 'c') {
|
||||||
|
$data_jawaban = $data_soal->jawaban_c;
|
||||||
|
} else if($data_jawaban == 'd') {
|
||||||
|
$data_jawaban = $data_soal->jawaban_d;
|
||||||
|
} else if($data_jawaban == 'e') {
|
||||||
|
$data_jawaban = $data_soal->jawaban_e;
|
||||||
|
} else {
|
||||||
|
$data_jawaban = 'Tidak menjawab';
|
||||||
|
}
|
||||||
|
$data_ujian[] = [
|
||||||
|
'id_soal' => $detail->id_soal,
|
||||||
|
'jawaban' => $data_jawaban,
|
||||||
|
'jawaban_key' => $detail->jawaban,
|
||||||
|
'soal' => $data_soal->pertanyaan
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return response()->json([
|
||||||
|
'status' => true,
|
||||||
|
'data' => $data_ujian
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return response()->json([
|
||||||
|
'status' => false,
|
||||||
|
'message' => 'Data sesi tes tidak ditemukan.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$id_session = null;
|
||||||
|
if(session('id_test_sessions') != null) {
|
||||||
|
$id_session = session('id_test_sessions');
|
||||||
|
} else if($request->id_test_sessions != null) {
|
||||||
|
$id_session = $request->id_test_sessions;
|
||||||
|
} else {
|
||||||
|
return redirect()->route('cek-status.index')->with('error', 'Data sesi tes tidak ditemukan. Silakan mulai tes terlebih dahulu.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$data_session = TestSessionsModel::where('id_test_sessions', $id_session)->first();
|
||||||
|
if($data_session != null) {
|
||||||
|
if($data_session->status_session != '1') {
|
||||||
|
return redirect()->route('cek-status.index')->with('error', 'Data sesi tes belum dimulai atau telah usai. Silahkan cek status dengan kode untuk informasi lebih lanjut.');
|
||||||
|
} else if($data_session->status_session == '1') {
|
||||||
|
// $data_session->update([
|
||||||
|
// 'status_session' => '2',
|
||||||
|
// 'is_active' => '0'
|
||||||
|
// ]);
|
||||||
|
return view('user.pages.finish_ujian.index', compact('id_session'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return redirect()->route('cek-status.index')->with('error', 'Data sesi tes tidak ditemukan.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(Request $request, string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(string $id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,11 +3,72 @@
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\DataSoalModel;
|
use App\Models\DataSoalModel;
|
||||||
|
use App\Models\DetailTestModel;
|
||||||
use App\Models\TestSessionsModel;
|
use App\Models\TestSessionsModel;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class HalamanUjianController extends Controller
|
class HalamanUjianController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public function getCurrentAnswer(Request $request) {
|
||||||
|
$data_answer = DetailTestModel::where('id_soal', $request->id_question)
|
||||||
|
->where('id_test_sessions', $request->session_id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if($data_answer != null) {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'success',
|
||||||
|
'jawaban' => $data_answer->jawaban
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Data jawaban tidak ditemukan.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTimeLeft(Request $request) {
|
||||||
|
$data_session = TestSessionsModel::where('id_test_sessions', $request->session_id)->first();
|
||||||
|
if($data_session != null) {
|
||||||
|
if($data_session->status_session != '1') {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Data sesi tes belum dimulai atau telah usai. Silahkan cek status dengan kode untuk informasi lebih lanjut.'
|
||||||
|
]);
|
||||||
|
} else if($data_session->status_session == '1') {
|
||||||
|
if($data_session->is_active == '1') {
|
||||||
|
$time_left = $data_session->unix_end_time - time();
|
||||||
|
if($time_left <= 0) {
|
||||||
|
$data_session->update([
|
||||||
|
'status_session' => '2',
|
||||||
|
'is_active' => '0'
|
||||||
|
]);
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Waktu sesi tes telah habis. Silahkan cek status dengan kode untuk informasi lebih lanjut.'
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'success',
|
||||||
|
'time_left' => $data_session->unix_end_time
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Sesi tes belum aktif. Silahkan mulai tes terlebih dahulu.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Data sesi tes tidak ditemukan. Silakan mulai tes terlebih dahulu.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*/
|
*/
|
||||||
|
|
@ -27,6 +88,22 @@ public function index(Request $request)
|
||||||
if($data_session != null) {
|
if($data_session != null) {
|
||||||
if($data_session->status_session != '1') {
|
if($data_session->status_session != '1') {
|
||||||
return redirect()->route('cek-status.index')->with('error', 'Data sesi tes belum dimulai atau telah usai. Silahkan cek status dengan kode untuk informasi lebih lanjut.');
|
return redirect()->route('cek-status.index')->with('error', 'Data sesi tes belum dimulai atau telah usai. Silahkan cek status dengan kode untuk informasi lebih lanjut.');
|
||||||
|
} else if($data_session->status_session == '1') {
|
||||||
|
if($data_session->is_active == '0') {
|
||||||
|
$data_session->update([
|
||||||
|
'is_active' => '1',
|
||||||
|
'unix_start_time' => time(),
|
||||||
|
'unix_end_time' => time() + (20 * 60)
|
||||||
|
]);
|
||||||
|
} else if($data_session->is_active == '1') {
|
||||||
|
if(time() > $data_session->unix_end_time) {
|
||||||
|
$data_session->update([
|
||||||
|
'status_session' => '2',
|
||||||
|
'is_active' => '0'
|
||||||
|
]);
|
||||||
|
return redirect()->route('cek-status.index')->with('error', 'Waktu sesi tes telah habis. Silahkan cek status dengan kode untuk informasi lebih lanjut.');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return redirect()->route('cek-status.index')->with('error', 'Data sesi tes tidak ditemukan. Silakan mulai tes terlebih dahulu.');
|
return redirect()->route('cek-status.index')->with('error', 'Data sesi tes tidak ditemukan. Silakan mulai tes terlebih dahulu.');
|
||||||
|
|
@ -43,6 +120,30 @@ public function index(Request $request)
|
||||||
}
|
}
|
||||||
|
|
||||||
$data_question = DataSoalModel::all();
|
$data_question = DataSoalModel::all();
|
||||||
|
$answered_question = [];
|
||||||
|
$index_question = 1;
|
||||||
|
foreach($data_question as $detail) {
|
||||||
|
$detail_answer = DetailTestModel::where('id_soal', $detail->id_soal)
|
||||||
|
->where('id_test_sessions', $id_session)
|
||||||
|
->first();
|
||||||
|
if($detail_answer != null) {
|
||||||
|
$answered_question[] = [
|
||||||
|
'id_soal' => $detail->id_soal,
|
||||||
|
'nomor_soal' => $index_question,
|
||||||
|
'answered' => true,
|
||||||
|
'jawaban' => $detail_answer->jawaban
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$answered_question[] = [
|
||||||
|
'id_soal' => $detail->id_soal,
|
||||||
|
'nomor_soal' => $index_question,
|
||||||
|
'answered' => false,
|
||||||
|
'jawaban' => null
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$index_question++;
|
||||||
|
}
|
||||||
|
|
||||||
$total_question = null;
|
$total_question = null;
|
||||||
$is_last_question = false;
|
$is_last_question = false;
|
||||||
if($question_number <= 0 || $question_number > count($data_question)) {
|
if($question_number <= 0 || $question_number > count($data_question)) {
|
||||||
|
|
@ -54,7 +155,41 @@ public function index(Request $request)
|
||||||
$total_question = count($data_question);
|
$total_question = count($data_question);
|
||||||
$data_question = $data_question[$question_number - 1];
|
$data_question = $data_question[$question_number - 1];
|
||||||
|
|
||||||
return view("user.pages.ujian.index", compact('data_session', 'data_question', 'total_question', 'is_last_question', 'question_number'));
|
$answer = [];
|
||||||
|
if($data_question->jawaban_a != null) {
|
||||||
|
$answer[] = [
|
||||||
|
'key' => 'a',
|
||||||
|
'value' => $data_question->jawaban_a
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if($data_question->jawaban_b != null) {
|
||||||
|
$answer[] = [
|
||||||
|
'key' => 'b',
|
||||||
|
'value' => $data_question->jawaban_b
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if($data_question->jawaban_c != null) {
|
||||||
|
$answer[] = [
|
||||||
|
'key' => 'c',
|
||||||
|
'value' => $data_question->jawaban_c
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if($data_question->jawaban_d != null) {
|
||||||
|
$answer[] = [
|
||||||
|
'key' => 'd',
|
||||||
|
'value' => $data_question->jawaban_d
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if($data_question->jawaban_e != null) {
|
||||||
|
$answer[] = [
|
||||||
|
'key' => 'e',
|
||||||
|
'value' => $data_question->jawaban_e
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// dd($answer);
|
||||||
|
|
||||||
|
return view("user.pages.ujian.index", compact('data_session', 'data_question', 'total_question', 'is_last_question', 'question_number', 'answer', 'answered_question'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -70,7 +205,30 @@ public function create()
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
//
|
$data_session = TestSessionsModel::where('id_test_sessions', $request->session_id)->first();
|
||||||
|
if($data_session != null) {
|
||||||
|
if($data_session->status_session != '1') {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Data sesi tes belum dimulai atau telah usai. Silahkan cek status dengan kode untuk informasi lebih lanjut.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
DetailTestModel::updateOrCreate(
|
||||||
|
[
|
||||||
|
'id_soal' => $request->id_question,
|
||||||
|
'id_test_sessions' => $request->session_id
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'jawaban' => $request->jawaban_final
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Data sesi tes tidak ditemukan. Silakan mulai tes terlebih dahulu.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ class BookingModel extends Model
|
||||||
'kode_unik',
|
'kode_unik',
|
||||||
'tgl_booking',
|
'tgl_booking',
|
||||||
'deskripsi_tambahan',
|
'deskripsi_tambahan',
|
||||||
'status_tes'
|
'status_tes',
|
||||||
|
'unix_expired_time'
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
|
|
@ -38,7 +39,11 @@ protected static function boot()
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($model->status_tes)) {
|
if(empty($model->status_tes)) {
|
||||||
$model->status_tes = '0';
|
$model->status_tes = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(empty($model->unix_expired_time)) {
|
||||||
|
$model->unix_expired_time = (string) (time() + 86400); // Set expiration time to 24 hour from now
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class DetailTestModel extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'detail_test';
|
||||||
|
|
||||||
|
protected $primaryKey = 'id_detail_test';
|
||||||
|
|
||||||
|
protected $keyType = 'string';
|
||||||
|
|
||||||
|
public $incrementing = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'id_detail_test',
|
||||||
|
'id_soal',
|
||||||
|
'id_test_sessions',
|
||||||
|
'jawaban'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'id_detail_test' => 'string',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected static function boot()
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
static::creating(function ($model) {
|
||||||
|
if (empty($model->id_detail_test)) {
|
||||||
|
$model->id_detail_test = Str::uuid();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,7 +18,9 @@ class TestSessionsModel extends Model
|
||||||
'status_session',
|
'status_session',
|
||||||
'token_session',
|
'token_session',
|
||||||
'id_booking',
|
'id_booking',
|
||||||
|
'unix_start_time',
|
||||||
'is_active',
|
'is_active',
|
||||||
|
'unix_end_time',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('detail_test', function (Blueprint $table) {
|
||||||
|
$table->dropForeign(['id_test']);
|
||||||
|
$table->dropColumn('id_test');
|
||||||
|
$table->char('id_test_sessions', 36)->after('id_soal');
|
||||||
|
$table->foreign('id_test_sessions')->references('id_test_sessions')->on('test_sessions')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('detail_test', function (Blueprint $table) {
|
||||||
|
$table->dropForeign(['id_test_sessions']);
|
||||||
|
$table->dropColumn('id_test_sessions');
|
||||||
|
$table->unsignedBigInteger('id_test')->after('id_soal');
|
||||||
|
$table->foreign('id_test')->references('id_test')->on('test')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('detail_test', function (Blueprint $table) {
|
||||||
|
$table->foreign('id_soal')->references('id_soal')->on('soal')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('detail_test', function (Blueprint $table) {
|
||||||
|
$table->dropForeign(['id_soal']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('test_sessions', function (Blueprint $table) {
|
||||||
|
$table->char('unix_start_time', 20)->default(0)->after('token_session');
|
||||||
|
$table->char('unix_end_time', 20)->default(0)->after('is_active');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('test_sessions', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('unix_start_time');
|
||||||
|
$table->dropColumn('unix_end_time');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('soal', function (Blueprint $table) {
|
||||||
|
$table->string('jawaban_a')->nullable()->change();
|
||||||
|
$table->string('jawaban_b')->nullable()->change();
|
||||||
|
$table->string('jawaban_c')->nullable()->change();
|
||||||
|
$table->string('jawaban_d')->nullable()->change();
|
||||||
|
$table->string('jawaban_e')->nullable()->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('soal', function (Blueprint $table) {
|
||||||
|
$table->string('jawaban_a')->change();
|
||||||
|
$table->string('jawaban_b')->change();
|
||||||
|
$table->string('jawaban_c')->change();
|
||||||
|
$table->string('jawaban_d')->change();
|
||||||
|
$table->string('jawaban_e')->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('booking', function (Blueprint $table) {
|
||||||
|
$table->char('unix_expired_time', 20)->after('kode_unik');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('booking', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('unix_expired_time');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
|
|
@ -28,6 +28,8 @@
|
||||||
<link href="{{ asset('assets/users/assets/vendor/fontawesome-free/css/all.min.css') }}" rel="stylesheet">
|
<link href="{{ asset('assets/users/assets/vendor/fontawesome-free/css/all.min.css') }}" rel="stylesheet">
|
||||||
<link href="{{ asset('assets/users/assets/vendor/swiper/swiper-bundle.min.css') }}" rel="stylesheet">
|
<link href="{{ asset('assets/users/assets/vendor/swiper/swiper-bundle.min.css') }}" rel="stylesheet">
|
||||||
|
|
||||||
|
<link href="https://cdn.datatables.net/2.3.7/css/dataTables.dataTables.min.css" rel="stylesheet" />
|
||||||
|
|
||||||
<!-- Main CSS File -->
|
<!-- Main CSS File -->
|
||||||
<link href="{{ asset('assets/users/assets/css/main.css') }}" rel="stylesheet">
|
<link href="{{ asset('assets/users/assets/css/main.css') }}" rel="stylesheet">
|
||||||
|
|
||||||
|
|
@ -60,6 +62,7 @@ class="bi bi-arrow-up-short"></i></a>
|
||||||
<div id="preloader"></div>
|
<div id="preloader"></div>
|
||||||
|
|
||||||
<!-- Vendor JS Files -->
|
<!-- Vendor JS Files -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.5.1/dist/chart.umd.min.js"></script>
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
<script src="{{ asset('assets/users/assets/vendor/bootstrap/js/bootstrap.bundle.min.js') }}"></script>
|
<script src="{{ asset('assets/users/assets/vendor/bootstrap/js/bootstrap.bundle.min.js') }}"></script>
|
||||||
|
|
@ -69,6 +72,9 @@ class="bi bi-arrow-up-short"></i></a>
|
||||||
<script src="{{ asset('assets/users/assets/vendor/purecounter/purecounter_vanilla.js') }}"></script>
|
<script src="{{ asset('assets/users/assets/vendor/purecounter/purecounter_vanilla.js') }}"></script>
|
||||||
<script src="{{ asset('assets/users/assets/vendor/swiper/swiper-bundle.min.js') }}"></script>
|
<script src="{{ asset('assets/users/assets/vendor/swiper/swiper-bundle.min.js') }}"></script>
|
||||||
|
|
||||||
|
<script src="https://cdn.datatables.net/2.3.7/js/dataTables.min.js" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/heatmap.js/2.0.1/heatmap.min.js"></script>
|
||||||
|
|
||||||
<!-- Main JS File -->
|
<!-- Main JS File -->
|
||||||
<script src="{{ asset('assets/users/assets/js/main.js') }}"></script>
|
<script src="{{ asset('assets/users/assets/js/main.js') }}"></script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@
|
||||||
<ul class="list-group list-group-flush">
|
<ul class="list-group list-group-flush">
|
||||||
<li class="list-group-item">Nama Lengkap: <span id="nama_lengkap"></span></li>
|
<li class="list-group-item">Nama Lengkap: <span id="nama_lengkap"></span></li>
|
||||||
<li class="list-group-item">Kode Unik: <span id="kode_unik"></span></li>
|
<li class="list-group-item">Kode Unik: <span id="kode_unik"></span></li>
|
||||||
<li class="list-group-item">Tgl Booking: <span id="tgl_booking"></span></li>
|
<li class="list-group-item">Tgl dan Jam Booking: <span id="tgl_booking"></span> <span id="jam_booking"></span></li>
|
||||||
<li class="list-group-item">Deskripsi Tambahan: <span id="deskripsi"></span></li>
|
<li class="list-group-item">Deskripsi Tambahan: <span id="deskripsi"></span></li>
|
||||||
<li class="list-group-item">Status Tes: <span id="status"></span></li>
|
<li class="list-group-item">Status Tes: <span id="status"></span></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -137,28 +137,29 @@ function searchUserStatus() {
|
||||||
xhttp.onreadystatechange = function() {
|
xhttp.onreadystatechange = function() {
|
||||||
if(this.readyState == 4 && this.status == 200) {
|
if(this.readyState == 4 && this.status == 200) {
|
||||||
let response = JSON.parse(this.responseText);
|
let response = JSON.parse(this.responseText);
|
||||||
let status_dict = ['Belum dikonfirmasi (cek email anda)', 'Sudah dikonfirmasi, belum melakukan/menyelesaikan tes', 'Sudah melakukan tes'];
|
let status_dict = ['Sesi anda dinonaktifkan karena telah kedaluwarsa', 'Belum melakukan/menyelesaikan tes', 'Sudah melakukan tes'];
|
||||||
if(response.status) {
|
if(response.status) {
|
||||||
$('#result_data').show();
|
$('#result_data').show();
|
||||||
$('#nama_lengkap').html(response.nama_lengkap);
|
$('#nama_lengkap').html(response.nama_lengkap);
|
||||||
$('#kode_unik').html(response.kode_unik);
|
$('#kode_unik').html(response.kode_unik);
|
||||||
$('#tgl_booking').html(response.tgl_booking);
|
$('#tgl_booking').html(response.tgl_booking);
|
||||||
|
$('#jam_booking').html(response.jam_booking + " (waktu sistem)");
|
||||||
$('#deskripsi').html(response.deskripsi_tambahan);
|
$('#deskripsi').html(response.deskripsi_tambahan);
|
||||||
$('#status').html(status_dict[response.status_data]);
|
$('#status').html(status_dict[response.status_data]);
|
||||||
Swal.close();
|
Swal.close();
|
||||||
|
|
||||||
if(response.status_data == 0) {
|
if(response.status_data == 0) {
|
||||||
$('#alert_status').removeClass();
|
$('#alert_status').removeClass();
|
||||||
$('#alert_status').addClass('alert alert-primary');
|
$('#alert_status').addClass('alert alert-warning');
|
||||||
$('#alert_status').html('Kamu belum dikonfirmasi dengan psikolog, cek waktu konsultasi pada email anda untuk melakukan aktivasi!');
|
$('#alert_status').html('Session kamu dinonaktifkan!');
|
||||||
} else if(response.status_data == 1) {
|
} else if(response.status_data == 1) {
|
||||||
$('#alert_status').removeClass();
|
$('#alert_status').removeClass();
|
||||||
$('#alert_status').addClass('alert alert-info');
|
$('#alert_status').addClass('alert alert-info');
|
||||||
$('#alert_status').html('Kamu sudah dikonfirmasi oleh psikolog!');
|
$('#alert_status').html('Kamu bisa memulai tes sekarang!');
|
||||||
|
|
||||||
let test_session = getTestSession(response.id_booking);
|
let test_session = getTestSession(response.id_booking);
|
||||||
$('#result_test').show();
|
$('#result_test').show();
|
||||||
$('#result_test_title').html('Kamu sudah dikonfirmasi oleh psikolog! Kalau kamu sudah siap menjalankan tes, klik tombol di bawah untuk mulai tes kecemasan dari sistem kami!');
|
$('#result_test_title').html('Kalau kamu sudah siap menjalankan tes, klik tombol di bawah untuk mulai tes kecemasan dari sistem kami!');
|
||||||
if(test_session.status) {
|
if(test_session.status) {
|
||||||
if(test_session.status_session == 0) {
|
if(test_session.status_session == 0) {
|
||||||
$('#id_booking_input').val(response.id_booking);
|
$('#id_booking_input').val(response.id_booking);
|
||||||
|
|
@ -183,7 +184,7 @@ function searchUserStatus() {
|
||||||
} else if(!test_session.status) {
|
} else if(!test_session.status) {
|
||||||
$('#id_booking_input').val(response.id_booking);
|
$('#id_booking_input').val(response.id_booking);
|
||||||
$('#result_test').show();
|
$('#result_test').show();
|
||||||
$('#result_test_title').html('Kamu sudah dikonfirmasi oleh psikolog! Kalau kamu sudah siap menjalankan tes, klik tombol di bawah untuk mulai tes kecemasan dari sistem kami!');
|
$('#result_test_title').html('Kalau kamu sudah siap menjalankan tes, klik tombol di bawah untuk mulai tes kecemasan dari sistem kami!');
|
||||||
|
|
||||||
$('#result_test_status').html('Belum Dimulai');
|
$('#result_test_status').html('Belum Dimulai');
|
||||||
$('#result_test_status').removeClass();
|
$('#result_test_status').removeClass();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,231 @@
|
||||||
|
@section('title', 'Hasil Tes')
|
||||||
|
@extends('user.layouts.index')
|
||||||
|
@section('content')
|
||||||
|
<!-- Page Title -->
|
||||||
|
<div class="page-title">
|
||||||
|
<div class="heading">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row d-flex justify-content-center text-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<h1 class="heading-title">Hasil Tes Anda</h1>
|
||||||
|
<p class="mb-0">
|
||||||
|
Cek hasil tes kamu dari sini ya, jika kamu sudah mendapatkan kode dari email setelah melakukan booking, kamu bisa melihat hasil tes disini dengan kode tadi.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<nav class="breadcrumbs">
|
||||||
|
<div class="container">
|
||||||
|
<ol>
|
||||||
|
<li><a href="index.html">Home</a></li>
|
||||||
|
<li class="current">Hasil Tes</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div><!-- End Page Title -->
|
||||||
|
|
||||||
|
<!-- About Section -->
|
||||||
|
<section id="about" class="about section">
|
||||||
|
<div class="container" data-aos="fade-up" data-aos-delay="100">
|
||||||
|
<table class="table" id="table-data-hasil-ujian">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>No</th>
|
||||||
|
<th>Pertanyaan</th>
|
||||||
|
<th>Jawaban</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<h2 class="title">Grafik Kecepatan Mata</h2>
|
||||||
|
<canvas id="velocityChart"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-12 mt-5">
|
||||||
|
<h2 class="title">Heatmap Pergerakan Mata</h2>
|
||||||
|
<div style="position: relative; aspect-ratio: 16/9;">
|
||||||
|
<img src="{{ asset('assets/users/assets/img/overlay/overlay.png') }}" style="width:100%; height:100%; object-fit: cover;">
|
||||||
|
<div id="heatmapChart" style="aspect-ratio: 16/9;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section><!-- /About Section -->
|
||||||
|
|
||||||
|
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||||
|
<div id="liveToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||||
|
<div class="toast-header">
|
||||||
|
<strong class="me-auto"><i class="bi bi-exclamation-triangle"></i> Kesalahan</strong>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="toast-body">
|
||||||
|
{{ session('error') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('script')
|
||||||
|
<script>
|
||||||
|
const ws = new WebSocket('{{ env("WEBSOCKET_URL") }}');
|
||||||
|
let table = null;
|
||||||
|
let data_tobii = null;
|
||||||
|
let heatmapContainer = null;
|
||||||
|
let clientWidth = null;
|
||||||
|
let clientHeight = null;
|
||||||
|
let mappedHeatmapData = null;
|
||||||
|
let scaleX = null;
|
||||||
|
let scaleY = null;
|
||||||
|
let heatmapInstance = null;
|
||||||
|
|
||||||
|
function renderVelocityChart(timeseries) {
|
||||||
|
const base = timeseries.timestamp[0];
|
||||||
|
const labels = timeseries.timestamp.map(t => (t - base) / 1000);
|
||||||
|
const ctx = document.getElementById('velocityChart').getContext('2d');
|
||||||
|
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Velocity',
|
||||||
|
data: timeseries.velocity,
|
||||||
|
borderWidth: 2,
|
||||||
|
tension: 0.3
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
plugins: {
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: function(context) {
|
||||||
|
return "Velocity: " + context.raw.toFixed(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
display: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadData(data) {
|
||||||
|
const res = await fetch("{{ env('PYTHON_API_URL') }}/extract", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await res.json();
|
||||||
|
if(result != null) {
|
||||||
|
renderVelocityChart(result.timeseries);
|
||||||
|
mappedHeatmapData = result.heatmap.map(point => ({
|
||||||
|
x: point.x * scaleX,
|
||||||
|
y: point.y * scaleY,
|
||||||
|
value: point.value
|
||||||
|
}));
|
||||||
|
heatmapInstance.setData({
|
||||||
|
max: 10,
|
||||||
|
data: mappedHeatmapData
|
||||||
|
});
|
||||||
|
heatmapContainer.style.removeProperty('position');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
table = new DataTable("#table-data-hasil-ujian", {
|
||||||
|
searching: false,
|
||||||
|
paging: false,
|
||||||
|
ajax: {
|
||||||
|
url: '{{ route('hasil-tes.getAllAnswer', ['id_test_sessions' => $id_session]) }}',
|
||||||
|
dataSrc: 'data' // Specify the key containing the data array
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
data: null,
|
||||||
|
render: function(data, type, row, meta) {
|
||||||
|
return meta.row + 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'soal'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: null,
|
||||||
|
render: function(data, type, row) {
|
||||||
|
let renderedJawaban = null;
|
||||||
|
if(row.jawaban_key == 'a') {
|
||||||
|
renderedJawaban = `<span class="badge text-bg-primary">${row.jawaban}</span>`;
|
||||||
|
} else if(row.jawaban_key == 'b') {
|
||||||
|
renderedJawaban = `<span class="badge" style="background-color: #fc7938; color: white;">${row.jawaban}</span>`;
|
||||||
|
} else if(row.jawaban_key == 'c') {
|
||||||
|
renderedJawaban = `<span class="badge text-bg-danger">${row.jawaban}</span>`;
|
||||||
|
} else if(row.jawaban_key == 'd') {
|
||||||
|
renderedJawaban = `<span class="badge text-bg-warning">${row.jawaban}</span>`;
|
||||||
|
} else if(row.jawaban_key == 'e') {
|
||||||
|
renderedJawaban = `<span class="badge text-bg-success">${row.jawaban}</span>`;
|
||||||
|
} else {
|
||||||
|
renderedJawaban = `<span class="badge text-bg-secondary">${row.jawaban}</span>`;
|
||||||
|
}
|
||||||
|
return renderedJawaban;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.onopen = () => {
|
||||||
|
console.log("Connected to WebSocket");
|
||||||
|
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
type: 'get_json_file',
|
||||||
|
session_id: '{{ $id_session }}'
|
||||||
|
}));
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
if(data.type === 'json_file_data') {
|
||||||
|
if(data.data != null) {
|
||||||
|
data_tobii = data.data;
|
||||||
|
|
||||||
|
heatmapContainer = document.getElementById('heatmapChart');
|
||||||
|
clientWidth = heatmapContainer.clientWidth;
|
||||||
|
clientHeight = heatmapContainer.clientHeight;
|
||||||
|
scaleX = clientWidth / 1366;
|
||||||
|
scaleY = clientHeight / 768;
|
||||||
|
|
||||||
|
heatmapInstance = h337.create({
|
||||||
|
container: heatmapContainer,
|
||||||
|
radius: 40,
|
||||||
|
maxOpacity: 0.6,
|
||||||
|
blur: 0.85
|
||||||
|
});
|
||||||
|
loadData(data_tobii);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
@if (session('error'))
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
var toast = new bootstrap.Toast(document.getElementById('liveToast'));
|
||||||
|
toast.show();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endif
|
||||||
|
@endsection
|
||||||
|
|
@ -140,7 +140,7 @@
|
||||||
<script>
|
<script>
|
||||||
let getDataInterval = false;
|
let getDataInterval = false;
|
||||||
let checkTobiiInterval = null;
|
let checkTobiiInterval = null;
|
||||||
let tobiiConnectedStatus = true;
|
let tobiiConnectedStatus = false;
|
||||||
const ws = new WebSocket('{{ env("WEBSOCKET_URL") }}');
|
const ws = new WebSocket('{{ env("WEBSOCKET_URL") }}');
|
||||||
let SESSION_ID = '{{ $data_session->id_test_sessions }}';
|
let SESSION_ID = '{{ $data_session->id_test_sessions }}';
|
||||||
let TOKEN_SESSION = '{{ $data_session->token_session }}';
|
let TOKEN_SESSION = '{{ $data_session->token_session }}';
|
||||||
|
|
@ -151,9 +151,10 @@ function showTutorial(step, tutorialId) {
|
||||||
|
|
||||||
if(step === 2 || step === 3) {
|
if(step === 2 || step === 3) {
|
||||||
startTobii();
|
startTobii();
|
||||||
checkTobiiInterval = setInterval(() => {
|
|
||||||
checkTobiiConnection();
|
checkTobiiConnection();
|
||||||
}, 2000);
|
// checkTobiiInterval = setInterval(() => {
|
||||||
|
// checkTobiiConnection();
|
||||||
|
// }, 2000);
|
||||||
} else {
|
} else {
|
||||||
if(checkTobiiInterval) {
|
if(checkTobiiInterval) {
|
||||||
clearInterval(checkTobiiInterval);
|
clearInterval(checkTobiiInterval);
|
||||||
|
|
@ -282,10 +283,10 @@ function copyLinkTokenTobii() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkTobiiConnection() {
|
function checkTobiiConnection() {
|
||||||
ws.send(JSON.stringify({
|
// ws.send(JSON.stringify({
|
||||||
type: "check_tobii_connection",
|
// type: "check_tobii_connection",
|
||||||
session_id: SESSION_ID,
|
// session_id: SESSION_ID,
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
if(tobiiConnectedStatus) {
|
if(tobiiConnectedStatus) {
|
||||||
$('#status_tobii').text('Status Tobii: Terhubung').removeClass('text-danger').addClass('text-success');
|
$('#status_tobii').text('Status Tobii: Terhubung').removeClass('text-danger').addClass('text-success');
|
||||||
|
|
@ -353,15 +354,6 @@ function stopTobii() {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
console.log('Received data from WebSocket:', data);
|
console.log('Received data from WebSocket:', data);
|
||||||
|
|
||||||
// if(data.type === 'temp_data') {
|
|
||||||
// console.log('Received temp_data:', data);
|
|
||||||
// if((Date.now() - data.data[0].timestamp) < 5000) {
|
|
||||||
// tobiiConnectedStatus = true;
|
|
||||||
// } else {
|
|
||||||
// tobiiConnectedStatus = false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
if(data.type === 'tobii_data') {
|
if(data.type === 'tobii_data') {
|
||||||
try {
|
try {
|
||||||
moveTheEye(data.gaze_x, data.gaze_y);
|
moveTheEye(data.gaze_x, data.gaze_y);
|
||||||
|
|
@ -370,13 +362,16 @@ function stopTobii() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if(data.type === 'status_tobii') {
|
if(data.type === 'status_tobii_device') {
|
||||||
// if(data.status) {
|
if(data.status) {
|
||||||
// tobiiConnectedStatus = true;
|
console.log('Tobii device is connected');
|
||||||
// } else if(!data.status) {
|
tobiiConnectedStatus = true;
|
||||||
// tobiiConnectedStatus = false;
|
} else {
|
||||||
// }
|
console.log('Tobii device is not connected');
|
||||||
// }
|
tobiiConnectedStatus = false;
|
||||||
|
}
|
||||||
|
checkTobiiConnection();
|
||||||
|
}
|
||||||
|
|
||||||
if(data.type === 'reset_start_tobii') {
|
if(data.type === 'reset_start_tobii') {
|
||||||
startTobii();
|
startTobii();
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,19 @@
|
||||||
<nav class="navbar navbar-expand-lg bg-body-tertiary px-2">
|
<nav class="navbar navbar-expand-lg bg-body-tertiary px-2">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand" href="#">Smart Anxiety</a>
|
<a class="navbar-brand" href="#">Smart Anxiety</a>
|
||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
<div class="collapse navbar-collapse justify-content-between" id="navbarSupportedContent">
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0"></ul>
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0"></ul>
|
||||||
<div class="d-flex fw-bold">Time Left: <span id="time_left"></span></div>
|
<div class="d-flex col-md-4">
|
||||||
|
<div class="col-md-4 d-flex justify-content-center align-items-center">
|
||||||
|
Time Left: <span id="time_left"></span>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 d-flex justify-content-center align-items-center">
|
||||||
|
<span id="bg_status_tobii" class="rounded bg-warning d-block mx-2" style="width: 10px; aspect-ratio: 1/1;"></span>Status Tobii
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 d-flex justify-content-center align-items-center">
|
||||||
|
<button id="fullscreen_btn" data-status="fullscreen" class="btn btn-sm btn-outline-secondary" onclick="openFullscreen()">Fullscreen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
@ -19,38 +29,25 @@
|
||||||
<div class="col-md-9 border-end">
|
<div class="col-md-9 border-end">
|
||||||
<div class="row justify-content-center flex-column p-4">
|
<div class="row justify-content-center flex-column p-4">
|
||||||
<div class="col-md-12 border-bottom fs-4 fw-bold p-2">Soal</div>
|
<div class="col-md-12 border-bottom fs-4 fw-bold p-2">Soal</div>
|
||||||
|
<div class="col-md-12 d-none" id="id_question" value="{{ $data_question->id_soal }}"></div>
|
||||||
<div class="col-md-12 p-2" style="text-align: justify">{{ $data_question->pertanyaan }}</div>
|
<div class="col-md-12 p-2" style="text-align: justify">{{ $data_question->pertanyaan }}</div>
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="fs-4 fw-bold p-2">Jawaban:</div>
|
<div class="fs-4 fw-bold p-2">Jawaban:</div>
|
||||||
|
@foreach ($answer as $item)
|
||||||
<div class="form-check m-2">
|
<div class="form-check m-2">
|
||||||
<input class="form-check-input" type="radio" name="jawaban_final" id="jawaban_a">
|
<input class="form-check-input" type="radio" name="jawaban_final" id="jawaban_{{ $item['key'] }}">
|
||||||
<label class="form-check-label" for="jawaban_a">{{ $data_question->jawaban_a }}</label>
|
<label class="form-check-label" for="jawaban_{{ $item['key'] }}">{{ $item['value'] }}</label>
|
||||||
</div>
|
|
||||||
<div class="form-check m-2">
|
|
||||||
<input class="form-check-input" type="radio" name="jawaban_final" id="jawaban_b">
|
|
||||||
<label class="form-check-label" for="jawaban_b">{{ $data_question->jawaban_b }}</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check m-2">
|
|
||||||
<input class="form-check-input" type="radio" name="jawaban_final" id="jawaban_c">
|
|
||||||
<label class="form-check-label" for="jawaban_c">{{ $data_question->jawaban_c }}</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check m-2">
|
|
||||||
<input class="form-check-input" type="radio" name="jawaban_final" id="jawaban_d">
|
|
||||||
<label class="form-check-label" for="jawaban_d">{{ $data_question->jawaban_d }}</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check m-2">
|
|
||||||
<input class="form-check-input" type="radio" name="jawaban_final" id="jawaban_e">
|
|
||||||
<label class="form-check-label" for="jawaban_e">{{ $data_question->jawaban_e }}</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<div class="row p-3">
|
<div class="row p-3">
|
||||||
<div class="col-md-12 border-bottom fs-4 fw-bold p-2 mb-3">Navigasi Soal</div>
|
<div class="col-md-12 border-bottom fs-4 fw-bold p-2 mb-3">Navigasi Soal</div>
|
||||||
@for ($i = 0; $i < $total_question; $i++)
|
@foreach ($answered_question as $question)
|
||||||
<div onclick="changeQuestion({{ $i + 1 }})" class="col-md-1 btn d-flex justify-content-center align-items-center bg-light-subtle border rounded p-0 m-1" style="aspect-ratio: 1/1.5;">{{ $i + 1 }}</div>
|
<div onclick="changeQuestion({{ $question['nomor_soal'] }})" id="nomor_{{ $question['nomor_soal'] }}" class="col-md-1 btn d-flex justify-content-center align-items-center {{ $question['answered'] ? 'bg-secondary-subtle' : 'bg-light-subtle' }} border rounded p-0 m-1" style="aspect-ratio: 1/1.5;">{{ $question['nomor_soal'] }}</div>
|
||||||
@endfor
|
@endforeach
|
||||||
|
|
||||||
<div class="col-md-12 p-0 mt-3">
|
<div class="col-md-12 p-0 mt-3">
|
||||||
@if ($question_number > 1)
|
@if ($question_number > 1)
|
||||||
|
|
@ -64,6 +61,28 @@
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row p-3">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Instruksi</h5>
|
||||||
|
<p class="card-text">Silahkan baca soal dengan teliti dan pilih jawaban yang paling tepat.</p>
|
||||||
|
<div class="card-text d-flex align-items-center">
|
||||||
|
<span class="col-md-1 bg-light-subtle border rounded p-0 m-1" style="aspect-ratio: 1/1.5;"></span>
|
||||||
|
<span>adalah tanda bahwa jawaban BELUM diisi.</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-text d-flex align-items-center">
|
||||||
|
<span class="col-md-1 bg-secondary-subtle border rounded p-0 m-1" style="aspect-ratio: 1/1.5;"></span>
|
||||||
|
<span>adalah tanda bahwa jawaban SUDAH diisi.</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-text d-flex align-items-center">
|
||||||
|
<span class="col-md-1 bg-info border rounded p-0 m-1 text-white" style="aspect-ratio: 1/1.5;"></span>
|
||||||
|
<span>adalah tanda bahwa anda sedang membaca/menjawab soal ini.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -75,10 +94,41 @@
|
||||||
const ws = new WebSocket('{{ env("WEBSOCKET_URL") }}');
|
const ws = new WebSocket('{{ env("WEBSOCKET_URL") }}');
|
||||||
let SESSION_ID = '{{ $data_session->id_test_sessions }}';
|
let SESSION_ID = '{{ $data_session->id_test_sessions }}';
|
||||||
let TOKEN_SESSION = '{{ $data_session->token_session }}';
|
let TOKEN_SESSION = '{{ $data_session->token_session }}';
|
||||||
|
let UNIX_END_TIME = null;
|
||||||
|
|
||||||
function changeQuestion(num) {
|
function changeQuestion(num) {
|
||||||
let url_temp = window.location.href;
|
let url_temp = window.location.href;
|
||||||
let current_num = new URLSearchParams(window.location.search).get('question');
|
let current_num = new URLSearchParams(window.location.search).get('question');
|
||||||
|
let xhttp = new XMLHttpRequest();
|
||||||
|
let the_answer = null;
|
||||||
|
let token = document.getElementById('_token').getAttribute('value');
|
||||||
|
let formData = new FormData();
|
||||||
|
|
||||||
|
if(!current_num) {
|
||||||
|
current_num = '{{ $question_number }}';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(current_num == num) {
|
||||||
|
console.log('same question');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementsByName('jawaban_final').forEach(element => {
|
||||||
|
if (element.checked) {
|
||||||
|
the_answer = {
|
||||||
|
key: element.id.split('_')[1],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(the_answer) {
|
||||||
|
formData.append('jawaban_final', the_answer.key);
|
||||||
|
formData.append('_token', token);
|
||||||
|
formData.append('question', num);
|
||||||
|
formData.append('id_question', $('#id_question').attr('value'));
|
||||||
|
formData.append('session_id', SESSION_ID);
|
||||||
|
xhttp.open("POST", "{{ route('ujian.store') }}", false);
|
||||||
|
xhttp.send(formData);
|
||||||
|
}
|
||||||
stopTobii();
|
stopTobii();
|
||||||
if(!url_temp.includes('question')) {
|
if(!url_temp.includes('question')) {
|
||||||
window.location.href = url_temp + '&question=' + num;
|
window.location.href = url_temp + '&question=' + num;
|
||||||
|
|
@ -87,7 +137,96 @@ function changeQuestion(num) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCurrentAnswer() {
|
||||||
|
let id_question = $('#id_question').attr('value');
|
||||||
|
let xhttp = new XMLHttpRequest();
|
||||||
|
let current_num = new URLSearchParams(window.location.search).get('question');
|
||||||
|
|
||||||
|
if(!current_num) {
|
||||||
|
current_num = '{{ $question_number }}';
|
||||||
|
}
|
||||||
|
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
let response = JSON.parse(this.responseText);
|
||||||
|
document.getElementById('nomor_' + current_num).classList.remove('bg-light-subtle');
|
||||||
|
document.getElementById('nomor_' + current_num).classList.remove('bg-secondary-subtle');
|
||||||
|
document.getElementById('nomor_' + current_num).classList.add('bg-info');
|
||||||
|
document.getElementById('nomor_' + current_num).classList.add('text-white');
|
||||||
|
if(response.status == 'success') {
|
||||||
|
document.getElementsByName('jawaban_final').forEach(element => {
|
||||||
|
if (element.id.split('_')[1] == response.jawaban) {
|
||||||
|
element.checked = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhttp.open("GET", "{{ route('ujian.getCurrentAnswer') }}?id_question=" + id_question + "&session_id=" + SESSION_ID, false);
|
||||||
|
xhttp.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTimeLeft() {
|
||||||
|
let xhttp = new XMLHttpRequest();
|
||||||
|
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
let response = JSON.parse(this.responseText);
|
||||||
|
UNIX_END_TIME = response.time_left;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhttp.open("GET", "{{ route('ujian.getTimeLeft') }}?session_id=" + SESSION_ID, false);
|
||||||
|
xhttp.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTimeLeft() {
|
||||||
|
let time_left = UNIX_END_TIME - Math.floor(Date.now() / 1000);
|
||||||
|
if(time_left < 0) {
|
||||||
|
time_left = 0;
|
||||||
|
finishExam();
|
||||||
|
}
|
||||||
|
let minutes = Math.floor(time_left / 60);
|
||||||
|
let seconds = time_left % 60;
|
||||||
|
document.getElementById('time_left').innerText = ' ' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
|
||||||
|
}
|
||||||
|
|
||||||
function finishExam() {
|
function finishExam() {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Alert',
|
||||||
|
icon: 'question',
|
||||||
|
text: 'Apakah Anda yakin ingin mengakhiri ujian? (aksi tidak dapat dikembalikan)',
|
||||||
|
confirmButtonText: 'Ya',
|
||||||
|
cancelButtonText: 'Tidak',
|
||||||
|
showCancelButton: true,
|
||||||
|
showCloseButton: true,
|
||||||
|
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
event.preventDefault();
|
||||||
|
let current_num = new URLSearchParams(window.location.search).get('question');
|
||||||
|
let xhttp = new XMLHttpRequest();
|
||||||
|
let the_answer = null;
|
||||||
|
let token = document.getElementById('_token').getAttribute('value');
|
||||||
|
let formData = new FormData();
|
||||||
|
|
||||||
|
document.getElementsByName('jawaban_final').forEach(element => {
|
||||||
|
if (element.checked) {
|
||||||
|
the_answer = {
|
||||||
|
key: element.id.split('_')[1],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(the_answer) {
|
||||||
|
formData.append('jawaban_final', the_answer.key);
|
||||||
|
formData.append('_token', token);
|
||||||
|
formData.append('question', current_num);
|
||||||
|
formData.append('id_question', $('#id_question').attr('value'));
|
||||||
|
formData.append('session_id', SESSION_ID);
|
||||||
|
xhttp.open("POST", "{{ route('ujian.store') }}", false);
|
||||||
|
xhttp.send(formData);
|
||||||
|
console.log("sending answer (finish)");
|
||||||
|
}
|
||||||
|
|
||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
type: "command",
|
type: "command",
|
||||||
action: "stop",
|
action: "stop",
|
||||||
|
|
@ -105,6 +244,10 @@ function finishExam() {
|
||||||
status_sessions: false,
|
status_sessions: false,
|
||||||
session_id: SESSION_ID
|
session_id: SESSION_ID
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
window.location.href = "{{ route('hasil-tes.index') }}?id_test_sessions=" + SESSION_ID;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function startTobii() {
|
function startTobii() {
|
||||||
|
|
@ -123,6 +266,63 @@ function stopTobii() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openFullscreen() {
|
||||||
|
const status = $('#fullscreen_btn').attr('data-status');
|
||||||
|
const elem = document.documentElement;
|
||||||
|
if (status === 'fullscreen') {
|
||||||
|
if (elem.requestFullscreen) {
|
||||||
|
elem.requestFullscreen();
|
||||||
|
} else if (elem.webkitRequestFullscreen) {
|
||||||
|
elem.webkitRequestFullscreen(); // Safari
|
||||||
|
} else if (elem.msRequestFullscreen) {
|
||||||
|
elem.msRequestFullscreen(); // IE
|
||||||
|
}
|
||||||
|
$('#fullscreen_btn').attr('data-status', 'exit-fullscreen');
|
||||||
|
$('#fullscreen_btn').text('Exit Fullscreen');
|
||||||
|
s.send(JSON.stringify({
|
||||||
|
type: "command",
|
||||||
|
action: "start",
|
||||||
|
session_id: SESSION_ID
|
||||||
|
}));
|
||||||
|
} else if (status === 'exit-fullscreen') {
|
||||||
|
if (document.exitFullscreen) {
|
||||||
|
document.exitFullscreen();
|
||||||
|
} else if (document.webkitExitFullscreen) {
|
||||||
|
document.webkitExitFullscreen(); // Safari
|
||||||
|
} else if (document.msExitFullscreen) {
|
||||||
|
document.msExitFullscreen(); // IE
|
||||||
|
}
|
||||||
|
$('#fullscreen_btn').attr('data-status', 'fullscreen');
|
||||||
|
$('#fullscreen_btn').text('Enter Fullscreen');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkFullscreen() {
|
||||||
|
if (!document.fullscreenElement) {
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
type: "command",
|
||||||
|
action: "stop",
|
||||||
|
session_id: SESSION_ID
|
||||||
|
}));
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Alert',
|
||||||
|
icon: 'warning',
|
||||||
|
text: 'Anda keluar dari mode fullscreen, harap masuk ke mode fullscreen untuk melanjutkan ujian.',
|
||||||
|
confirmButtonText: 'Ya',
|
||||||
|
showCancelButton: false,
|
||||||
|
showCloseButton: false,
|
||||||
|
allowOutsideClick: false,
|
||||||
|
allowEscapeKey: false,
|
||||||
|
backdrop: `rgba(0, 0, 0, 0.4)`
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
openFullscreen();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
ws.onopen = () => {
|
ws.onopen = () => {
|
||||||
console.log("Connected to WebSocket");
|
console.log("Connected to WebSocket");
|
||||||
|
|
@ -133,13 +333,43 @@ function stopTobii() {
|
||||||
role: "web"
|
role: "web"
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
document.addEventListener('fullscreenchange', checkFullscreen);
|
||||||
|
checkFullscreen();
|
||||||
|
|
||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
type: "update_status",
|
type: "update_status",
|
||||||
status_sessions: true,
|
status_sessions: true,
|
||||||
session_id: SESSION_ID
|
session_id: SESSION_ID
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
|
||||||
|
if(data.type === 'reset_start_tobii') {
|
||||||
startTobii();
|
startTobii();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.type === 'status_tobii_device') {
|
||||||
|
if(data.status) {
|
||||||
|
console.log('Tobii device is connected');
|
||||||
|
// document.getElementById('status_tobii_device').innerText = 'Connected';
|
||||||
|
document.getElementById('bg_status_tobii').classList.remove('bg-warning');
|
||||||
|
document.getElementById('bg_status_tobii').classList.remove('bg-danger');
|
||||||
|
document.getElementById('bg_status_tobii').classList.add('bg-success');
|
||||||
|
} else {
|
||||||
|
console.log('Tobii device is not connected');
|
||||||
|
// document.getElementById('status_tobii_device').innerText = 'Not Connected';
|
||||||
|
document.getElementById('bg_status_tobii').classList.remove('bg-success');
|
||||||
|
document.getElementById('bg_status_tobii').classList.remove('bg-warning');
|
||||||
|
document.getElementById('bg_status_tobii').classList.add('bg-danger');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
startTobii();
|
||||||
|
getCurrentAnswer();
|
||||||
|
getTimeLeft();
|
||||||
|
setInterval(updateTimeLeft, 1000);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
use App\Http\Controllers\CekStatusController;
|
use App\Http\Controllers\CekStatusController;
|
||||||
use App\Http\Controllers\DashboardController;
|
use App\Http\Controllers\DashboardController;
|
||||||
use App\Http\Controllers\DataSoalController;
|
use App\Http\Controllers\DataSoalController;
|
||||||
|
use App\Http\Controllers\FinishUjianController;
|
||||||
use App\Http\Controllers\HalamanUjianController;
|
use App\Http\Controllers\HalamanUjianController;
|
||||||
use App\Http\Controllers\HasilTesController;
|
use App\Http\Controllers\HasilTesController;
|
||||||
use App\Http\Controllers\LandingController;
|
use App\Http\Controllers\LandingController;
|
||||||
|
|
@ -38,6 +39,10 @@
|
||||||
Route::resource('tobii-receiver', TobiiReceiverController::class)->only(['store', 'show']);
|
Route::resource('tobii-receiver', TobiiReceiverController::class)->only(['store', 'show']);
|
||||||
Route::get('tobii-receiver/fetch/data/{id_test_sessions}', [TobiiReceiverController::class, 'fetchDataTobii'])->name('tobii-receiver.fetchData');
|
Route::get('tobii-receiver/fetch/data/{id_test_sessions}', [TobiiReceiverController::class, 'fetchDataTobii'])->name('tobii-receiver.fetchData');
|
||||||
Route::resource('ujian', HalamanUjianController::class);
|
Route::resource('ujian', HalamanUjianController::class);
|
||||||
|
Route::get('ujian/get/current-answer', [HalamanUjianController::class, 'getCurrentAnswer'])->name('ujian.getCurrentAnswer');
|
||||||
|
Route::get('ujian/get/time-left', [HalamanUjianController::class, 'getTimeLeft'])->name('ujian.getTimeLeft');
|
||||||
|
Route::resource('hasil-tes', FinishUjianController::class)->only(['index', 'show']);
|
||||||
|
Route::get('hasil-tes/get/all-answer', [FinishUjianController::class, 'getAllAnswer'])->name('hasil-tes.getAllAnswer');
|
||||||
Route::middleware(['auth', 'role.auth'])->group(function() {
|
Route::middleware(['auth', 'role.auth'])->group(function() {
|
||||||
Route::resource('dashboard', DashboardController::class);
|
Route::resource('dashboard', DashboardController::class);
|
||||||
Route::resource('users', UsersController::class);
|
Route::resource('users', UsersController::class);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue