303 lines
12 KiB
PHP
303 lines
12 KiB
PHP
@section('title', 'Ujian Kecemasan')
|
|
{{-- @section('body_status_overflow', 'overflow: hidden;') --}}
|
|
@section('main_style', 'min-height: 100vh;')
|
|
@extends('user.layouts.test_layout.index')
|
|
@section('content')
|
|
<div class="container-fluid p-0 d-flex flex-column" style="min-height: 100vh">
|
|
<nav class="navbar navbar-expand-lg bg-body-tertiary px-2">
|
|
<div class="container-fluid">
|
|
<a class="navbar-brand" href="#">Smart Anxiety</a>
|
|
<div class="collapse navbar-collapse justify-content-between" id="navbarSupportedContent">
|
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0"></ul>
|
|
<div class="d-flex col-md-2">
|
|
<div class="col-md-6 d-flex justify-content-center align-items-center">
|
|
Time Left: <span id="time_left"></span>
|
|
</div>
|
|
<div class="col-md-6 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>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="d-flex flex-grow-1 container-fluid">
|
|
<div class="row flex-grow-1">
|
|
<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 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">
|
|
<div class="fs-4 fw-bold p-2">Jawaban:</div>
|
|
@foreach ($answer as $item)
|
|
<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>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="row p-3">
|
|
<div class="col-md-12 border-bottom fs-4 fw-bold p-2 mb-3">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">
|
|
<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>
|
|
@endsection
|
|
|
|
@section('script')
|
|
<script>
|
|
const ws = new WebSocket('{{ env("WEBSOCKET_URL") }}');
|
|
let SESSION_ID = '{{ $data_session->id_test_sessions }}';
|
|
let TOKEN_SESSION = '{{ $data_session->token_session }}';
|
|
let UNIX_END_TIME = null;
|
|
|
|
function changeQuestion(num) {
|
|
let url_temp = window.location.href;
|
|
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 == 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();
|
|
if(!url_temp.includes('question')) {
|
|
window.location.href = url_temp + '&question=' + num;
|
|
} else if(url_temp.includes('question')) {
|
|
window.location.href = window.location.href.replace('&question=' + current_num, '&question=' + num);
|
|
}
|
|
}
|
|
|
|
function getCurrentAnswer() {
|
|
let id_question = $('#id_question').attr('value');
|
|
let xhttp = new XMLHttpRequest();
|
|
let current_num = new URLSearchParams(window.location.search).get('question');
|
|
|
|
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() {
|
|
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({
|
|
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
|
|
}));
|
|
}
|
|
});
|
|
}
|
|
|
|
function startTobii() {
|
|
ws.send(JSON.stringify({
|
|
type: "command",
|
|
action: "start",
|
|
session_id: SESSION_ID
|
|
}));
|
|
}
|
|
|
|
function stopTobii() {
|
|
ws.send(JSON.stringify({
|
|
type: "command",
|
|
action: "stop",
|
|
session_id: SESSION_ID
|
|
}));
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
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: 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);
|
|
};
|
|
});
|
|
</script>
|
|
@endsection |