361 lines
17 KiB
PHP
361 lines
17 KiB
PHP
@section('title', 'Tutorial Test Kecemasan')
|
|
@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 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>
|
|
</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">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">
|
|
<!-- row 1 -->
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 2%; left: 2%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 2%; left: 19.2%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 2%; left: 38.4%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 2%; left: 57.6%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 2%; left: 76.8%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 2%; left: 96%"></div>
|
|
|
|
<!-- row 2 -->
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 19.2%; left: 2%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 19.2%; left: 19.2%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 19.2%; left: 38.4%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 19.2%; left: 57.6%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 19.2%; left: 76.8%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 19.2%; left: 96%"></div>
|
|
|
|
<!-- row 3 -->
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 38.4%; left: 2%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 38.4%; left: 19.2%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 38.4%; left: 38.4%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 38.4%; left: 57.6%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 38.4%; left: 76.8%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 38.4%; left: 96%"></div>
|
|
|
|
<!-- row 4 -->
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 57.6%; left: 2%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 57.6%; left: 19.2%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 57.6%; left: 38.4%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 57.6%; left: 57.6%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 57.6%; left: 76.8%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 57.6%; left: 96%"></div>
|
|
|
|
<!-- row 5 -->
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 76.8%; left: 2%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 76.8%; left: 19.2%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 76.8%; left: 38.4%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 76.8%; left: 57.6%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 76.8%; left: 76.8%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 76.8%; left: 96%"></div>
|
|
|
|
<!-- row 6 -->
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 96%; left: 2%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 96%; left: 19.2%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 96%; left: 38.4%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 96%; left: 57.6%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 96%; left: 76.8%"></div>
|
|
<div class="rounded-circle bg-primary position-absolute" style="width: 0.5%; aspect-ratio: 1/1; top: 96%; left: 96%"></div>
|
|
|
|
<div id="the_eye" class="rounded-circle bg-danger position-absolute" style="width: 0.5%; aspect-ratio: 1/1;"></div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('script')
|
|
<script>
|
|
let getDataInterval = false;
|
|
let checkTobiiInterval = null;
|
|
let tobiiConnectedStatus = false;
|
|
const ws = new WebSocket('{{ env("WEBSOCKET_URL") }}');
|
|
let SESSION_ID = '{{ $data_session->id_test_sessions }}';
|
|
let TOKEN_SESSION = '{{ $data_session->token_session }}';
|
|
|
|
function showTutorial(step, tutorialId) {
|
|
$(`#${tutorialId}`).hide();
|
|
$(`#tutorial_${step}`).show();
|
|
|
|
if(step === 2) {
|
|
checkTobiiInterval = setInterval(() => {
|
|
checkTobiiConnection();
|
|
}, 2000);
|
|
} else {
|
|
if(checkTobiiInterval) {
|
|
clearInterval(checkTobiiInterval);
|
|
}
|
|
}
|
|
|
|
if(step === 3) {
|
|
$('#calibration_point').show();
|
|
} else {
|
|
$('#calibration_point').hide();
|
|
}
|
|
}
|
|
|
|
async function startPolling() {
|
|
while(getDataInterval) {
|
|
await fetchDataTobii();
|
|
await delay(300);
|
|
}
|
|
}
|
|
|
|
function delay(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
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_temp_data",
|
|
id_session: 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);
|
|
}
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
$('#tutorial_2').hide();
|
|
$('#tutorial_3').hide();
|
|
$('#next_btn_connect_tobii').hide();
|
|
$('#calibration_point').hide();
|
|
$('#show_calibration').hide();
|
|
generateLinkApiTobii();
|
|
|
|
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);
|
|
|
|
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_not_active') {
|
|
console.log('Tobii data not active:', data);
|
|
moveTheEye(data.data[0].gaze_x, data.data[0].gaze_y);
|
|
}
|
|
};
|
|
});
|
|
|
|
</script>
|
|
@endsection |