MIF_E31231392/resources/views/user/pages/tutorial_tes/index.blade.php

403 lines
15 KiB
PHP

@section('title', 'Tutorial Test Kecemasan')
@section('body_status_overflow', 'overflow: hidden;')
@section('main_style', 'width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center;')
@extends('user.layouts.test_layout.index')
@section('content')
<div class="container" id="tutorial_panel">
<div class="row justify-content-center">
<div class="col-md-8" id="tutorial_1">
<div class="card shadow-sm border-0">
<div class="card-body">
<h3 class="card-title fw-bold mb-4">Tutorial Tes Kecemasan</h3>
<p class="card-text mb-3">Berikut adalah tutorial untuk menjalankan tes kecemasan dari sistem kami. Pastikan kamu sudah membaca dan memahami setiap langkah yang ada di bawah ini sebelum memulai tes.</p>
<ol>
<li><strong>Persiapan:</strong> Pastikan kondisi kamu berada di tempat yang tenang dan nyaman.</li>
<li><strong>Durasi Tes:</strong> Tes ini akan memakan waktu sekitar 2-5 menit, tergantung pada kecepatanmu dalam menjawab pertanyaan.</li>
<li><strong>Jenis Pertanyaan:</strong> Tes ini terdiri dari beberapa pertanyaan yang dirancang untuk mengukur tingkat kecemasanmu. Jawablah setiap pertanyaan dengan jujur dan sesuai dengan perasaanmu saat ini.</li>
<li><strong>Hasil Tes:</strong> Setelah menyelesaikan tes, hasilnya akan dianalisis oleh sistem kami dan akan diberikan kepada psikolog yang menangani kasusmu. Psikolog akan memberikan feedback dan rekomendasi berdasarkan hasil tes tersebut. Kamu juga akan menerima laporan hasil tes secara detail dan juga bisa dilihat berdasarkan kode tes yang kamu dapatkan saat melakukan booking.</li>
<li><strong>Konsultasi Lanjutan:</strong> Jika hasil tes menunjukkan bahwa kamu mengalami tingkat kecemasan yang tinggi, psikolog mungkin akan menyarankan sesi konsultasi lanjutan untuk membahas hasil tes dan langkah selanjutnya yang bisa diambil.</li>
</ol>
<p class="card-text mt-3">Jika kamu sudah siap, silakan klik tombol "Next" di bawah ini untuk setup lingkungan terlebih dahulu.</p>
<button class="btn btn-primary" onclick="showTutorial(2, 'tutorial_1')">Next</button>
</div>
</div>
</div>
<div class="col-md-8" id="tutorial_2">
<div class="card shadow-sm border-0">
<div class="card-body">
<h3 class="card-title fw-bold mb-4">Setup Lingkungan</h3>
<p class="card-text mb-3">Sebelum tes dimulai, setup alat Tobii dibawah ini:</p>
<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>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>
<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>
</div>
</div>
</div>
<div class="col-md-8" id="tutorial_3">
<div class="card shadow-sm border-0">
<div class="card-body">
<h3 class="card-title fw-bold mb-4">Tes Keakuratan Mata</h3>
<p class="card-text mb-3">Sebelum tes dimulai, cek keakuratan device Tobii anda (disarankan full-screen), jika tidak akurat, lakukan kalibrasi kepada administrator.</p>
<button class="btn btn-primary" id="back_btn" onclick="showTutorial(2, 'tutorial_3')">Back</button>
<button class="btn btn-secondary" id="fullscreen_btn" onclick="openFullscreen(this)" data-status="fullscreen">Fullscreen</button>
<button class="btn btn-secondary" id="hide_btn" onclick="hidePanelTutorial(this)" data-status="hide">Hide</button>
<a class="btn btn-primary" id="start_ujian" href="#">Mulai Ujian</a>
</div>
</div>
</div>
</div>
</div>
<!-- btn show -->
<button type="button" class="btn btn-secondary position-absolute" onclick="showCalibrationPoints()" id="show_calibration" style="z-index: 999">Show</button>
<div class="position-absolute bg-white" style="width: 100vw; height: 100vh; z-index: -1;" id="calibration_point">
<table class="w-100 h-100">
<tr>
<td align="center">
<div class="rounded-circle bg-primary" style="width: 3%; aspect-ratio: 1/1;"></div>
</td>
<td align="center">
<div class="rounded-circle bg-primary" style="width: 3%; aspect-ratio: 1/1;"></div>
</td>
<td align="center">
<div class="rounded-circle bg-primary" style="width: 3%; aspect-ratio: 1/1;"></div>
</td>
</tr>
<tr>
<td align="center">
<div class="rounded-circle bg-primary" style="width: 3%; aspect-ratio: 1/1;"></div>
</td>
<td align="center">
<div class="rounded-circle bg-primary" style="width: 3%; aspect-ratio: 1/1;"></div>
</td>
<td align="center">
<div class="rounded-circle bg-primary" style="width: 3%; aspect-ratio: 1/1;"></div>
</td>
</tr>
<tr>
<td align="center">
<div class="rounded-circle bg-primary" style="width: 3%; aspect-ratio: 1/1;"></div>
</td>
<td align="center">
<div class="rounded-circle bg-primary" style="width: 3%; aspect-ratio: 1/1;"></div>
</td>
<td align="center">
<div class="rounded-circle bg-primary" style="width: 3%; aspect-ratio: 1/1;"></div>
</td>
</tr>
</table>
<div id="the_eye" class="rounded-circle bg-danger position-absolute" style="width: 1%; aspect-ratio: 1/1;"></div>
</div>
@endsection
@section('script')
<script>
let getDataInterval = false;
let checkTobiiInterval = null;
let tobiiConnectedStatus = false;
let ws = null;
let reconnectDelay = 1000;
let maxReconnectDelay = 10000;
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();
if(step === 2 || step === 3) {
startTobii();
checkTobiiConnection();
// checkTobiiInterval = setInterval(() => {
// checkTobiiConnection();
// }, 2000);
} else {
if(checkTobiiInterval) {
clearInterval(checkTobiiInterval);
}
stopTobii();
}
if(step === 3) {
$('#calibration_point').show();
let test_url = '{{ route('ujian.index', ['id_test_sessions' => '__ID_TEST_SESSIONS__']) }}';
$('#start_ujian').attr('href', test_url.replace('__ID_TEST_SESSIONS__', SESSION_ID));
} else {
$('#calibration_point').hide();
}
}
function hidePanelTutorial(btn) {
const status = $(btn).attr('data-status');
if (status === 'hide') {
$('#tutorial_panel').hide();
$('#show_calibration').show();
}
}
function showCalibrationPoints() {
$('#show_calibration').toggle();
$('#tutorial_panel').toggle();
}
function moveTheEye(x, y) {
const eye = $('#the_eye');
eye.css({ left: x + 'px', top: y + 'px' });
}
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');
} 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');
}
}
function generateLinkApiTobii() {
const linkApi = '{{ env("WEBSOCKET_URL") }}'.replace('ws://', '');
const linkId = SESSION_ID;
const linkToken = TOKEN_SESSION;
$('#link_api_tobii').val(linkApi);
$('#link_id_tobii').val(linkId);
$('#link_token_tobii').val(linkToken);
}
function copyLinkApiTobii() {
const linkApi = $('#link_api_tobii').val();
navigator.clipboard.writeText(linkApi)
.then(() => {
Swal.fire({
icon: 'success',
title: 'Link API berhasil disalin!',
showConfirmButton: true,
timer: 1500
});
})
.catch(err => {
Swal.fire({
icon: 'error',
title: 'Gagal menyalin Link API',
text: err,
});
});
}
function copyLinkIdTobii() {
const linkId = $('#link_id_tobii').val();
navigator.clipboard.writeText(linkId)
.then(() => {
Swal.fire({
icon: 'success',
title: 'Link ID berhasil disalin!',
showConfirmButton: true,
timer: 1500
});
})
.catch(err => {
Swal.fire({
icon: 'error',
title: 'Gagal menyalin Link ID',
text: err,
});
});
}
function copyLinkTokenTobii() {
const linkToken = $('#link_token_tobii').val();
navigator.clipboard.writeText(linkToken)
.then(() => {
Swal.fire({
icon: 'success',
title: 'Link Token berhasil disalin!',
showConfirmButton: true,
timer: 1500
});
})
.catch(err => {
Swal.fire({
icon: 'error',
title: 'Gagal menyalin Link Token',
text: err,
});
});
}
function checkTobiiConnection() {
// ws.send(JSON.stringify({
// type: "check_tobii_connection",
// session_id: SESSION_ID,
// }));
if(tobiiConnectedStatus) {
$('#status_tobii').text('Status Tobii: Terhubung').removeClass('text-danger').addClass('text-success');
$('#next_btn_connect_tobii').show();
} else {
$('#status_tobii').text('Status Tobii: Tidak Terhubung').removeClass('text-success').addClass('text-danger');
$('#next_btn_connect_tobii').hide();
}
}
async function fetchDataTobii() {
try {
const response = await fetch('{{ route("tobii-receiver.fetchData", ['id_test_sessions' => $data_session->id_test_sessions]) }}');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
moveTheEye(data.gaze_x, data.gaze_y);
} catch (error) {
console.error('Error fetching Tobii data:', error);
}
}
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",
action: "start",
session_id: SESSION_ID
}));
}
function stopTobii() {
ws.send(JSON.stringify({
type: "command",
action: "stop",
session_id: SESSION_ID
}));
}
$(document).ready(function() {
$('#tutorial_2').hide();
$('#tutorial_3').hide();
$('#next_btn_connect_tobii').hide();
$('#calibration_point').hide();
$('#show_calibration').hide();
generateLinkApiTobii();
startWebsocket();
console.log("hehehehehehehehehhehehe");
});
</script>
@endsection