Compare commits
No commits in common. "feb7916fff2fb5ef646a187ae19ba77c04ef3e73" and "fbb03ba9fe92ac327f95f778da9274d09fa1dc58" have entirely different histories.
feb7916fff
...
fbb03ba9fe
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\BookingModel;
|
||||
use Carbon\Carbon;
|
||||
use Generator;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
|
|
@ -75,7 +74,6 @@ public function store(Request $request)
|
|||
]);
|
||||
|
||||
$kode_unik = $this->generateCode();
|
||||
$tgl_request = Carbon::parse($request->tgl_booking)->timestamp + 86399;
|
||||
|
||||
BookingModel::create([
|
||||
'nama_lengkap' => $request->nama_lengkap,
|
||||
|
|
@ -84,7 +82,6 @@ public function store(Request $request)
|
|||
'tgl_booking' => $request->tgl_booking,
|
||||
'deskripsi_tambahan' => $request->deskripsi_tambahan,
|
||||
'kode_unik' => $kode_unik,
|
||||
'unix_expired_time' => $tgl_request
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
|
|
|
|||
|
|
@ -38,18 +38,10 @@ public function show(string $id)
|
|||
{
|
||||
$data = BookingModel::where('kode_unik', $id)->first();
|
||||
if($data != null) {
|
||||
if($data->status_tes == '1' && $data->unix_expired_time < time()) { // Lebih dari exp
|
||||
if($data->status_tes == '1' && $data->unix_expired_time < time()) {
|
||||
$data->update([
|
||||
'status_tes' => '0'
|
||||
]);
|
||||
} else if($data->status_tes == '1' && time() < ($data->unix_expired_time - 86399)) { // Kurang dari exp 00.00
|
||||
$data->update([
|
||||
'status_tes' => '0'
|
||||
]);
|
||||
} else if($data->status_tes == '0' && time() > ($data->unix_expired_time - 86399) && time() < ($data->unix_expired_time)) {
|
||||
$data->update([
|
||||
'status_tes' => '1'
|
||||
]);
|
||||
}
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
|
|
@ -59,8 +51,7 @@ public function show(string $id)
|
|||
'nama_lengkap' => $data->nama_lengkap,
|
||||
'kode_unik' => $data->kode_unik,
|
||||
'tgl_booking' => $data->tgl_booking,
|
||||
'start_test' => date('H:i:s', $data->unix_expired_time - 86399),
|
||||
'end_test' => date('H:i:s', $data->unix_expired_time),
|
||||
'jam_booking' => date('H:i:s', strtotime($data->created_at)),
|
||||
'deskripsi_tambahan' => $data->deskripsi_tambahan,
|
||||
]);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ 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 == '0') {
|
||||
if($data_session->status_session != '1') {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Data sesi tes dinonaktifkan. Silahkan cek status dengan kode untuk informasi lebih lanjut.'
|
||||
'message' => 'Data sesi tes belum dimulai atau telah usai. Silahkan cek status dengan kode untuk informasi lebih lanjut.'
|
||||
]);
|
||||
} else if($data_session->status_session == '2') {
|
||||
} 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) {
|
||||
|
|
@ -73,15 +73,13 @@ public function index(Request $request)
|
|||
|
||||
$data_session = TestSessionsModel::where('id_test_sessions', $id_session)->first();
|
||||
if($data_session != null) {
|
||||
if($data_session->status_session == '0') {
|
||||
return redirect()->route('cek-status.index')->with('error', 'Data sesi tes dinonaktifkan. Silahkan cek status dengan kode untuk informasi lebih lanjut.');
|
||||
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 if($data_session->status_session == '2') {
|
||||
// $data_session->update([
|
||||
// 'status_session' => '2',
|
||||
// 'is_active' => '0'
|
||||
// ]);
|
||||
return view('user.pages.finish_ujian.index', compact('id_session'));
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class HalamanUjianController extends Controller
|
|||
function fetchQuestion(Request $request) {
|
||||
$data_question = DataSoalModel::all();
|
||||
if($data_question != null) {
|
||||
$number_question = $request->question_index;
|
||||
$number_question = $request->question_number;
|
||||
if($number_question <= 0 || $number_question > count($data_question)) {
|
||||
$number_question = 1;
|
||||
}
|
||||
|
|
@ -66,12 +66,6 @@ public function getCurrentAnswer(Request $request) {
|
|||
];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'jawaban' => null,
|
||||
'choices' => null
|
||||
]);
|
||||
}
|
||||
$data_answer = DetailTestModel::where('id_soal', $request->id_question)
|
||||
->where('id_test_sessions', $request->session_id)
|
||||
|
|
@ -92,45 +86,6 @@ public function getCurrentAnswer(Request $request) {
|
|||
}
|
||||
}
|
||||
|
||||
public function getNavigationField(Request $request) {
|
||||
$id_session = null;
|
||||
if(session('session_id') != null) {
|
||||
$id_session = session('session_id');
|
||||
} else if($request->session_id != null) {
|
||||
$id_session = $request->session_id;
|
||||
} else {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'msg' => 'Test session id tidak ditemukan'
|
||||
]);
|
||||
}
|
||||
|
||||
$data_soal = DataSoalModel::all();
|
||||
$result = [];
|
||||
$index = 1;
|
||||
foreach($data_soal as $soal) {
|
||||
$data_jawaban = DetailTestModel::where(['id_soal' => $soal->id_soal, 'id_test_sessions' => $id_session])->first();
|
||||
if($data_jawaban != null) {
|
||||
$result[] = [
|
||||
'index' => $index,
|
||||
'answered' => true,
|
||||
'data' => $data_jawaban
|
||||
];
|
||||
} else {
|
||||
$result[] = [
|
||||
'index' => $index,
|
||||
'answered' => false
|
||||
];
|
||||
}
|
||||
$index += 1;
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'data' => $result
|
||||
]);
|
||||
}
|
||||
|
||||
public function getTimeLeft(Request $request) {
|
||||
$data_session = TestSessionsModel::where('id_test_sessions', $request->session_id)->first();
|
||||
if($data_session != null) {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ protected static function boot()
|
|||
}
|
||||
|
||||
if(empty($model->unix_expired_time)) {
|
||||
$model->unix_expired_time = (string) (time() + 86399); // Set expiration time to 24 hour from now
|
||||
$model->unix_expired_time = (string) (time() + 86400); // Set expiration time to 24 hour from now
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@
|
|||
|
|
||||
*/
|
||||
|
||||
'timezone' => 'Asia/Jakarta',
|
||||
'timezone' => 'UTC',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
<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" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
|
||||
|
||||
<!-- Main CSS File -->
|
||||
<link href="{{ asset('assets/users/assets/css/main.css') }}" rel="stylesheet">
|
||||
|
|
@ -75,7 +74,6 @@ class="bi bi-arrow-up-short"></i></a>
|
|||
|
||||
<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>
|
||||
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
|
||||
|
||||
<!-- Main JS File -->
|
||||
<script src="{{ asset('assets/users/assets/js/main.js') }}"></script>
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
<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">Kode Unik: <span id="kode_unik"></span></li>
|
||||
<li class="list-group-item">Tgl dan Jam Ujian (sesuai booking): <span id="tgl_booking"></span><span id="jam_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">Status Tes: <span id="status"></span></li>
|
||||
</ul>
|
||||
|
|
@ -137,13 +137,13 @@ function searchUserStatus() {
|
|||
xhttp.onreadystatechange = function() {
|
||||
if(this.readyState == 4 && this.status == 200) {
|
||||
let response = JSON.parse(this.responseText);
|
||||
let status_dict = ['Sesi anda dinonaktifkan karena telah kedaluwarsa atau belum sesuai jadwal yang telah di booking', '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) {
|
||||
$('#result_data').show();
|
||||
$('#nama_lengkap').html(response.nama_lengkap);
|
||||
$('#kode_unik').html(response.kode_unik);
|
||||
$('#tgl_booking').html(`<b>${response.tgl_booking}</b>`);
|
||||
$('#jam_booking').html(", Valid dari jam <b>" + response.start_test + "</b>, sampai dengan jam <b>" + response.end_test + "</b>");
|
||||
$('#tgl_booking').html(response.tgl_booking);
|
||||
$('#jam_booking').html(response.jam_booking + " (waktu sistem)");
|
||||
$('#deskripsi').html(response.deskripsi_tambahan);
|
||||
$('#status').html(status_dict[response.status_data]);
|
||||
Swal.close();
|
||||
|
|
@ -151,7 +151,7 @@ function searchUserStatus() {
|
|||
if(response.status_data == 0) {
|
||||
$('#alert_status').removeClass();
|
||||
$('#alert_status').addClass('alert alert-warning');
|
||||
$('#alert_status').html('Session kamu dinonaktifkan atau belum sesuai jam yang telah di booking!');
|
||||
$('#alert_status').html('Session kamu dinonaktifkan!');
|
||||
} else if(response.status_data == 1) {
|
||||
$('#alert_status').removeClass();
|
||||
$('#alert_status').addClass('alert alert-info');
|
||||
|
|
@ -180,10 +180,6 @@ function searchUserStatus() {
|
|||
$('#result_test_status').html('Selesai');
|
||||
$('#result_test_status').removeClass();
|
||||
$('#result_test_status').addClass('fw-bold text-white bg-success p-2 rounded-pill');
|
||||
let test_url = '{{ route('hasil-tes.index', ['id_test_sessions' => '__ID_TEST_SESSIONS__']) }}';
|
||||
$('#result_test_link').show();
|
||||
$('#result_test_link').html('Tes Sudah Selesai, Klik untuk melihat hasil');
|
||||
$('#result_test_link').attr('href', test_url.replace('__ID_TEST_SESSIONS__', test_session.id_test_sessions));
|
||||
}
|
||||
} else if(!test_session.status) {
|
||||
$('#id_booking_input').val(response.id_booking);
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@
|
|||
<input type="tel" name="phone" id="no_telp" class="form-control" placeholder="Nomor Telepon" required="">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<input type="text" name="date" id="tgl_book" class="form-control" required="" aria-describedby="dateHelp" placeholder="Pilih tanggal...">
|
||||
<input type="date" name="date" id="tgl_book" class="form-control" required="" aria-describedby="dateHelp">
|
||||
<div id="dateHelp" class="form-text">Untuk detail jam, akan dikirim melalui email mu yaa.</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
|
|
@ -484,14 +484,5 @@ function sendAppointment() {
|
|||
xhttp.send(formData);
|
||||
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
flatpickr("#tgl_book", {
|
||||
enableTime: false,
|
||||
dateFormat: "Y-m-d",
|
||||
minDate: 'today',
|
||||
maxDate: new Date().fp_incr(7)
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -30,10 +30,37 @@
|
|||
<ol>
|
||||
<li><strong>Persiapan:</strong> Pastikan Tobii sudah terhubung dan berfungsi dengan baik.</li>
|
||||
<li><strong>Penempatan:</strong> Tempatkan Tobii di posisi yang sesuai untuk mendeteksi gerakan mata dengan akurat.</li>
|
||||
<li><strong>Hubungkan Tobii:</strong> Hubungkan Tobii ke dalam web dengan menggunakan aplikasi API, jika tidak terhubung, hubungi administrator.</li>
|
||||
<li><strong>Hubungkan Tobii:</strong> Hubungkan Tobii ke dalam web dengan menggunakan link API dibawah ini.</li>
|
||||
<li><strong>Hasil:</strong> Setelah menghubungkan ke web berhasil, akan muncul notifikasi bahwa Tobii telah terhubung.</li>
|
||||
<li><strong>Selanjutnya:</strong> Melakukan kalibrasi mata dengan Tobii.</li>
|
||||
</ol>
|
||||
<h5 class="">Link API Tobii:</h5>
|
||||
<div class="row px-3">
|
||||
<div class="col-md-11">
|
||||
<input type="text" disabled id="link_api_tobii" class="input form-control mb-3" value="">
|
||||
</div>
|
||||
<div class="col-md-1 p-0">
|
||||
<button class="btn btn-secondary" onclick="copyLinkApiTobii()">Copy</button>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="">Link ID Tobii:</h5>
|
||||
<div class="row px-3">
|
||||
<div class="col-md-11">
|
||||
<input type="text" disabled id="link_id_tobii" class="input form-control mb-3" value="">
|
||||
</div>
|
||||
<div class="col-md-1 p-0">
|
||||
<button class="btn btn-secondary" onclick="copyLinkIdTobii()">Copy</button>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="">Link Token Tobii:</h5>
|
||||
<div class="row px-3">
|
||||
<div class="col-md-11">
|
||||
<input type="text" disabled id="link_token_tobii" class="input form-control mb-3" value="">
|
||||
</div>
|
||||
<div class="col-md-1 p-0">
|
||||
<button class="btn btn-secondary" onclick="copyLinkTokenTobii()">Copy</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="card-text mt-3" id="status_tobii">Memuat...</p>
|
||||
<button class="btn btn-primary" id="back_btn" onclick="showTutorial(1, 'tutorial_2')">Back</button>
|
||||
<button class="btn btn-primary" id="next_btn_connect_tobii" onclick="showTutorial(3, 'tutorial_2')">Next</button>
|
||||
|
|
@ -101,79 +128,10 @@
|
|||
let getDataInterval = false;
|
||||
let checkTobiiInterval = null;
|
||||
let tobiiConnectedStatus = false;
|
||||
let ws = null;
|
||||
let reconnectDelay = 1000;
|
||||
let maxReconnectDelay = 10000;
|
||||
const ws = new WebSocket('{{ env("WEBSOCKET_URL") }}');
|
||||
let SESSION_ID = '{{ $data_session->id_test_sessions }}';
|
||||
let TOKEN_SESSION = '{{ $data_session->token_session }}';
|
||||
|
||||
function startWebsocket() {
|
||||
console.log("Connecting to WebSocket...");
|
||||
ws = new WebSocket('{{ env("WEBSOCKET_URL") }}');
|
||||
ws.onopen = () => {
|
||||
console.log("Connected to WebSocket");
|
||||
reconnectDelay = 1000;
|
||||
ws.send(JSON.stringify({
|
||||
type: "register",
|
||||
session_id: SESSION_ID,
|
||||
token_session: TOKEN_SESSION,
|
||||
role: "web"
|
||||
}));
|
||||
|
||||
searchingTobiiDevice();
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
type: "update_status",
|
||||
status_sessions: false,
|
||||
id_session: SESSION_ID
|
||||
}));
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log('Received data from WebSocket:', data);
|
||||
|
||||
if(data.type === 'tobii_data') {
|
||||
try {
|
||||
moveTheEye(data.gaze_x, data.gaze_y);
|
||||
} catch(error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
if(data.type === 'status_tobii_device') {
|
||||
if(data.status) {
|
||||
console.log('Tobii device is connected');
|
||||
tobiiConnectedStatus = true;
|
||||
} else {
|
||||
console.log('Tobii device is not connected');
|
||||
tobiiConnectedStatus = false;
|
||||
searchingTobiiDevice();
|
||||
}
|
||||
checkTobiiConnection();
|
||||
}
|
||||
|
||||
if(data.type === 'reset_start_tobii') {
|
||||
startTobii();
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = function (error) {
|
||||
console.log("WebSocket error");
|
||||
};
|
||||
|
||||
ws.onclose = function () {
|
||||
setTimeout(() => {
|
||||
reconnectDelay = Math.min(
|
||||
reconnectDelay * 2,
|
||||
maxReconnectDelay
|
||||
);
|
||||
console.log("Disconnected from WebSocket. Retrying in " + reconnectDelay + " ms...");
|
||||
startWebsocket();
|
||||
}, reconnectDelay);
|
||||
};
|
||||
}
|
||||
|
||||
function showTutorial(step, tutorialId) {
|
||||
$(`#${tutorialId}`).hide();
|
||||
$(`#tutorial_${step}`).show();
|
||||
|
|
@ -339,39 +297,6 @@ function checkTobiiConnection() {
|
|||
}
|
||||
}
|
||||
|
||||
async function searchingTobiiDevice() {
|
||||
try {
|
||||
console.log('Searching for tobii...');
|
||||
const response = await fetch('{{ env('TOBII_API_URL') }}', {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
session_id: SESSION_ID,
|
||||
token: TOKEN_SESSION,
|
||||
url: "{{ env('WEBSOCKET_URL') }}"
|
||||
})
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
console.error('Failed to get tobii device, retrying...');
|
||||
setTimeout(5000);
|
||||
searchingTobiiDevice();
|
||||
return;
|
||||
}
|
||||
const data = await response.json();
|
||||
if(data.session_id == SESSION_ID && data.token == TOKEN_SESSION) {
|
||||
tobiiConnectedStatus = true;
|
||||
console.log('Done searching...');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error getting Tobii device:', error);
|
||||
setTimeout(5000);
|
||||
searchingTobiiDevice();
|
||||
}
|
||||
}
|
||||
|
||||
function startTobii() {
|
||||
ws.send(JSON.stringify({
|
||||
type: "command",
|
||||
|
|
@ -395,8 +320,50 @@ function stopTobii() {
|
|||
$('#calibration_point').hide();
|
||||
$('#show_calibration').hide();
|
||||
generateLinkApiTobii();
|
||||
startWebsocket();
|
||||
console.log("hehehehehehehehehhehehe");
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log("Connected to WebSocket");
|
||||
ws.send(JSON.stringify({
|
||||
type: "register",
|
||||
session_id: SESSION_ID,
|
||||
token_session: TOKEN_SESSION,
|
||||
role: "web"
|
||||
}));
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
type: "update_status",
|
||||
status_sessions: false,
|
||||
id_session: SESSION_ID
|
||||
}));
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log('Received data from WebSocket:', data);
|
||||
|
||||
if(data.type === 'tobii_data') {
|
||||
try {
|
||||
moveTheEye(data.gaze_x, data.gaze_y);
|
||||
} catch(error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
if(data.type === 'status_tobii_device') {
|
||||
if(data.status) {
|
||||
console.log('Tobii device is connected');
|
||||
tobiiConnectedStatus = true;
|
||||
} else {
|
||||
console.log('Tobii device is not connected');
|
||||
tobiiConnectedStatus = false;
|
||||
}
|
||||
checkTobiiConnection();
|
||||
}
|
||||
|
||||
if(data.type === 'reset_start_tobii') {
|
||||
startTobii();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -29,16 +29,34 @@
|
|||
<div class="col-md-9 border-end">
|
||||
<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 p-2 d-none" id="id_question" style="text-align: justify"></div>
|
||||
<div class="col-md-12 p-2" id="text_question" style="text-align: justify"></div>
|
||||
<div class="col-md-12" id="answer_field">
|
||||
<div class="fs-4 fw-bold p-2">Jawaban:</div>
|
||||
{{-- <div class="form-check m-2">
|
||||
<input class="form-check-input" type="radio" name="jawaban_final" id="jawaban_{{ $item['key'] }}">
|
||||
<label class="form-check-label" for="jawaban_{{ $item['key'] }}">{{ $item['value'] }}</label>
|
||||
</div> --}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="row p-3" id="navigation_field">
|
||||
<div class="col-md-12 border-bottom fs-4 fw-bold p-2 mb-3">Navigasi Soal</div>
|
||||
<div class="row p-3">
|
||||
<div class="col-md-12 border-bottom fs-4 fw-bold p-2 mb-3" id="navigation_field">Navigasi Soal</div>
|
||||
{{-- @foreach ($answered_question as $question)
|
||||
<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>
|
||||
@endforeach
|
||||
|
||||
<div class="col-md-12 p-0 mt-3">
|
||||
@if ($question_number > 1)
|
||||
<div class="btn btn-secondary" onclick="changeQuestion({{ $question_number - 1 }})">Previous</div>
|
||||
@endif
|
||||
|
||||
@if ($is_last_question)
|
||||
<div class="btn btn-success" onclick="finishExam()">Finish</div>
|
||||
@else
|
||||
<div class="btn btn-primary" onclick="changeQuestion({{ $question_number + 1 }})">Next</div>
|
||||
@endif
|
||||
</div> --}}
|
||||
</div>
|
||||
<div class="row p-3">
|
||||
<div class="col-md-12">
|
||||
|
|
@ -70,171 +88,11 @@
|
|||
|
||||
@section('script')
|
||||
<script>
|
||||
let ws = null;
|
||||
let reconnectDelay = 1000;
|
||||
let maxReconnectDelay = 10000;
|
||||
const ws = new WebSocket('{{ env("WEBSOCKET_URL") }}');
|
||||
const SESSION_ID = '{{ $data_session->id_test_sessions }}';
|
||||
const TOKEN_SESSION = '{{ $data_session->token_session }}';
|
||||
let UNIX_END_TIME = null;
|
||||
let QUESTION_INDEX = 1;
|
||||
let QUESTION_ID = null;
|
||||
let CURRENT_BTN = null;
|
||||
let CAPTION_BTN = null;
|
||||
|
||||
function startWebsocket() {
|
||||
console.log("Connecting to WebSocket...");
|
||||
ws = new WebSocket('{{ env("WEBSOCKET_URL") }}');
|
||||
ws.onopen = () => {
|
||||
console.log("Connected to WebSocket");
|
||||
ws.send(JSON.stringify({
|
||||
type: "register",
|
||||
session_id: SESSION_ID,
|
||||
token_session: TOKEN_SESSION,
|
||||
role: "web"
|
||||
}));
|
||||
|
||||
document.addEventListener('fullscreenchange', checkFullscreen);
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
type: "update_status",
|
||||
status_sessions: true,
|
||||
session_id: SESSION_ID
|
||||
}));
|
||||
|
||||
searchingTobiiDevice()
|
||||
checkFullscreen();
|
||||
getTimeLeft();
|
||||
setInterval(updateTimeLeft, 1000);
|
||||
getNavigationField();
|
||||
setCurrentNavigation();
|
||||
fetchQuestion(QUESTION_INDEX);
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
if(data.type === 'reset_start_tobii') {
|
||||
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');
|
||||
searchingTobiiDevice();
|
||||
// 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');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = function (error) {
|
||||
console.log("WebSocket error");
|
||||
};
|
||||
|
||||
ws.onclose = function () {
|
||||
setTimeout(() => {
|
||||
reconnectDelay = Math.min(
|
||||
reconnectDelay * 2,
|
||||
maxReconnectDelay
|
||||
);
|
||||
console.log("Disconnected from WebSocket. Retrying in " + reconnectDelay + " ms...");
|
||||
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');
|
||||
startWebsocket();
|
||||
}, reconnectDelay);
|
||||
};
|
||||
}
|
||||
|
||||
async function searchingTobiiDevice() {
|
||||
try {
|
||||
console.log('Searching for tobii...');
|
||||
const response = await fetch('{{ env('TOBII_API_URL') }}', {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
session_id: SESSION_ID,
|
||||
token: TOKEN_SESSION,
|
||||
url: "{{ env('WEBSOCKET_URL') }}"
|
||||
})
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
console.error('Failed to get tobii device, retrying...');
|
||||
setTimeout(5000);
|
||||
searchingTobiiDevice();
|
||||
return;
|
||||
}
|
||||
const data = await response.json();
|
||||
if(data.session_id == SESSION_ID && data.token == TOKEN_SESSION) {
|
||||
// tobiiConnectedStatus = true;
|
||||
startTobii();
|
||||
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');
|
||||
console.log('Done searching...');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error getting Tobii device:', error);
|
||||
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');
|
||||
setTimeout(5000);
|
||||
searchingTobiiDevice();
|
||||
}
|
||||
}
|
||||
|
||||
function changeQuestion(num) {
|
||||
Swal.showLoading();
|
||||
|
||||
let xhttp = new XMLHttpRequest();
|
||||
let the_answer = null;
|
||||
let token = document.getElementById('_token').getAttribute('value');
|
||||
let formData = new FormData();
|
||||
|
||||
if(QUESTION_INDEX == num) {
|
||||
console.log('same question');
|
||||
Swal.close();
|
||||
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', QUESTION_ID);
|
||||
formData.append('session_id', SESSION_ID);
|
||||
xhttp.open("POST", "{{ route('ujian.store') }}", true);
|
||||
xhttp.send(formData);
|
||||
}
|
||||
// stopTobii();
|
||||
QUESTION_INDEX = num;
|
||||
getNavigationField();
|
||||
fetchQuestion(QUESTION_INDEX);
|
||||
}
|
||||
|
||||
function setCurrentNavigation() {
|
||||
$('#nomor_' + QUESTION_INDEX).removeClass('bg-light-subtle');
|
||||
$('#nomor_' + QUESTION_INDEX).removeClass('bg-secondary-subtle');
|
||||
$('#nomor_' + QUESTION_INDEX).addClass('bg-info');
|
||||
}
|
||||
|
||||
function fetchQuestion(question_index) {
|
||||
let xhttp = new XMLHttpRequest();
|
||||
|
|
@ -244,7 +102,6 @@ function fetchQuestion(question_index) {
|
|||
let response = JSON.parse(this.responseText);
|
||||
if(response.status) {
|
||||
$('#text_question').html(response.data.pertanyaan);
|
||||
QUESTION_ID = response.data.id_soal;
|
||||
getCurrentAnswer(response.data.id_soal);
|
||||
} else {
|
||||
Swal.fire({
|
||||
|
|
@ -257,69 +114,10 @@ function fetchQuestion(question_index) {
|
|||
}
|
||||
}
|
||||
|
||||
xhttp.open("GET", "{{ route('ujian.fetchQuestion') }}?session_id=" + SESSION_ID + "&question_index=" + question_index, true);
|
||||
xhttp.open("GET", "{{ route('ujian.fetchQuestion') }}?session_id=" + SESSION_ID + "&question_index=" + question_index, false);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
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 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', QUESTION_INDEX);
|
||||
formData.append('id_question', QUESTION_ID);
|
||||
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({
|
||||
type: "command",
|
||||
action: "stop",
|
||||
session_id: SESSION_ID
|
||||
}));
|
||||
|
||||
//send_data_to_db
|
||||
ws.send(JSON.stringify({
|
||||
type: "send_data_to_db",
|
||||
session_id: SESSION_ID
|
||||
}));
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
type: "update_status",
|
||||
status_sessions: false,
|
||||
session_id: SESSION_ID
|
||||
}));
|
||||
|
||||
window.location.href = "{{ route('hasil-tes.index') }}?id_test_sessions=" + SESSION_ID;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getCurrentAnswer(id_question) {
|
||||
let xhttp = new XMLHttpRequest();
|
||||
|
||||
|
|
@ -338,15 +136,6 @@ function getCurrentAnswer(id_question) {
|
|||
`;
|
||||
});
|
||||
$('#answer_field').append(choices_html);
|
||||
if(response.jawaban != null) {
|
||||
document.getElementsByName('jawaban_final').forEach(element => {
|
||||
if (element.id.split('_')[1] == response.jawaban) {
|
||||
element.checked = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
Swal.close();
|
||||
checkFullscreen();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -354,58 +143,6 @@ function getCurrentAnswer(id_question) {
|
|||
xhttp.send();
|
||||
}
|
||||
|
||||
function getNavigationField() {
|
||||
let xhttp = new XMLHttpRequest();
|
||||
let total_question = 0;
|
||||
|
||||
xhttp.onreadystatechange = function() {
|
||||
if(this.readyState == 4 && this.status == 200) {
|
||||
let response = JSON.parse(this.responseText);
|
||||
if(response.status) {
|
||||
let navigation_field = '<div class="col-md-12 border-bottom fs-4 fw-bold p-2 mb-3">Navigasi Soal</div>';
|
||||
$('#navigation_field').html(navigation_field);
|
||||
response.data.forEach((q) => {
|
||||
let answered = 'bg-light-subtle';
|
||||
if(q.answered) {
|
||||
answered = 'bg-secondary-subtle'
|
||||
}
|
||||
navigation_field += `
|
||||
<div onclick="changeQuestion(${q.index})" id="nomor_${q.index}" class="col-md-1 btn d-flex justify-content-center align-items-center ${answered} border rounded p-0 m-1" style="aspect-ratio: 1/1.5;">${q.index}</div>
|
||||
`;
|
||||
total_question += 1;
|
||||
});
|
||||
if(QUESTION_INDEX <= total_question) {
|
||||
let next_num = 0;
|
||||
next_num = QUESTION_INDEX + 1;
|
||||
if(next_num > total_question) {
|
||||
// tombol finish dan back
|
||||
navigation_field += `
|
||||
<div class="btn btn-secondary mb-2" onclick="changeQuestion(${QUESTION_INDEX - 1})">Back</div>
|
||||
`;
|
||||
navigation_field += `
|
||||
<div class="btn btn-success" onclick="finishExam()">Finish</div>
|
||||
`;
|
||||
} else {
|
||||
if((QUESTION_INDEX - 1) != 0) {
|
||||
navigation_field += `
|
||||
<div class="btn btn-secondary mb-2" onclick="changeQuestion(${QUESTION_INDEX - 1})">Back</div>
|
||||
`;
|
||||
}
|
||||
navigation_field += `
|
||||
<div class="btn btn-primary" status="false" onclick="changeQuestion(${QUESTION_INDEX + 1})">Next</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
$('#navigation_field').html(navigation_field);
|
||||
setCurrentNavigation();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhttp.open('GET', '{{ route('ujian.navigationField') }}?session_id=' + SESSION_ID, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function getTimeLeft() {
|
||||
let xhttp = new XMLHttpRequest();
|
||||
|
||||
|
|
@ -501,7 +238,54 @@ function checkFullscreen() {
|
|||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
startWebsocket();
|
||||
ws.onopen = () => {
|
||||
console.log("Connected to WebSocket");
|
||||
ws.send(JSON.stringify({
|
||||
type: "register",
|
||||
session_id: SESSION_ID,
|
||||
token_session: TOKEN_SESSION,
|
||||
role: "web"
|
||||
}));
|
||||
|
||||
document.addEventListener('fullscreenchange', checkFullscreen);
|
||||
// checkFullscreen();
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
type: "update_status",
|
||||
status_sessions: true,
|
||||
session_id: SESSION_ID
|
||||
}));
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
if(data.type === 'reset_start_tobii') {
|
||||
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);
|
||||
fetchQuestion(QUESTION_INDEX);
|
||||
};
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -42,7 +42,6 @@
|
|||
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::get('ujian/fetch/question', [HalamanUjianController::class, 'fetchQuestion'])->name('ujian.fetchQuestion');
|
||||
Route::get('ujian/fetch/navigation-field', [HalamanUjianController::class, 'getNavigationField'])->name('ujian.navigationField');
|
||||
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() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue