feat: add intro for new user

This commit is contained in:
BillieFaiqul 2025-05-18 16:26:53 +07:00
parent c7c2a6221d
commit 1093f01526
10 changed files with 330 additions and 163 deletions

View File

@ -1,28 +1,15 @@
<x-app-layout>
<x-slot name="header">
<div class="flex justify-between items-center">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
{{ __('Dashboard') }}
</h2>
<button id="resetIntroBtn" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
<i class="fas fa-question-circle mr-1"></i> Lihat Tutorial
</button>
</div>
</x-slot>
<div class="py-4">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<!-- Tips Alert for Dashboard -->
<x-alert.tips-alert pageId="dashboard" title="Tips untuk Anda">
<p>Selamat datang di dashboard! Berikut adalah beberapa tips untuk membantu Anda:</p>
<ul class="list-disc pl-5 mt-2">
<li>Gunakan panel Projects untuk melihat detail project</li>
<li>Untuk submissions bisa dilihat di panel Submissions</li>
<li>Pilih proyek dari dropdown sebelum mengunggah</li>
<li>Unggah file dengan cara drag & drop ZIP atau klik Browse Atau, masukkan link GitHub lengkap di kolom yang tersedia. Lalu klik tombol SUBMIT</li>
<li>Maka anda akan di arahkan ke proses pengujian</li>
<li>Anda bisa kemabali ke halaman dashboard untuk melihat status pengumpulan</li>
</ul>
</x-alert.tips-alert>
</div>
</div>
<div class="pb-5">
<div class="pt-5">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
@include('nodejs.dashboard.partials.projects.list')

View File

@ -1,16 +1,25 @@
<div class="flex flex-col max-w-sm rounded-lg overflow-hidden shadow-lg bg-white dark:bg-gray-900 h-full">
<!-- Contoh komponen project card dengan implementasi Intro.js yang lebih lengkap -->
<div class="flex flex-col max-w-sm rounded-lg overflow-hidden shadow-lg bg-white dark:bg-gray-900 h-full"
data-step="1"
data-intro="Klik Read More untuk melihat detail dari project ini."
data-title="Project Card"
data-position="right"
data-disable-interaction="false">
<img class="w-40 mx-auto my-4" src="{{$project->getImageAttribute()}}" alt="Project {{$project->title}}"
onerror="this.onerror=null;this.src='{{ asset('assets/nodejs/placeholder.png') }}';">
<div class="px-6 py-4">
<div class="font-bold text-xl mb-2 text-gray-800 dark:text-white">{{$project->title}}</div>
<p class="text-gray-700 text-base dark:text-gray-400 leading-tight line-clamp-3">
{{ $project->description }}
</p>
</div>
<div class="mt-auto px-6 pt-4 pb-2">
@forelse ($project->tech_stack as $key => $stack)
<span
class=" inline-block bg-gray-200 dark:bg-gray-700 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 dark:text-gray-200 mr-2 mb-2">
class="inline-block bg-gray-200 dark:bg-gray-700 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 dark:text-gray-200 mr-2 mb-2">
#{{$stack}}</span>
@empty
<span
@ -18,6 +27,7 @@ class="inline-block bg-gray-200 dark:bg-gray-700 rounded-full px-3 py-1 text-sm
tech stack</span>
@endforelse
</div>
<div class="px-6 py-2 bg-gray-100 dark:bg-secondary">
<a href="{{route('projects.show', $project->id)}}"
class="text-xs font-semibold text-secondary dark:text-white uppercase tracking-wide">
@ -26,3 +36,4 @@ class="text-xs font-semibold text-secondary dark:text-white uppercase tracking-w
</a>
</div>
</div>

View File

@ -4,7 +4,11 @@
<div>
<x-input-label for="project_id" :value="__('Select Project Before Uploading')" class="mb-2" />
<select name="project_id" id="project_id"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-secondary-500 focus:border-secondary-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-secondary-500 dark:focus:border-secondary-500">
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-secondary-500 focus:border-secondary-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-secondary-500 dark:focus:border-secondary-500"
data-step="2"
data-intro="Pilih project yang ingin Anda kirimkan. Jika Anda sudah mengirimkan project ini sebelumnya, Anda tidak dapat mengirimkannya lagi."
data-title="Select Project"
data-disable-interaction="false">
<option value="">Select Project</option>
@foreach ($projects as $project)
@php
@ -28,18 +32,30 @@ class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:
</select>
<x-input-error :messages="$errors->get('project_id')" class="mt-2" />
</div>
<div class="mt-4">
<div class="mt-4"
data-step="3"
data-intro="Upload file ZIP project Anda di sini. Pastikan file yang diunggah adalah file ZIP."
data-title="Upload ZIP File"
data-disable-interaction="false">
<x-input-label for="folder" :value="__('Submit The Source Code')" class="mb-2" />
<input type="file" name="folder_path" id="folder" data-allow-reorder="true" data-max-file-size="3MB" />
<x-input-error :messages="$errors->get('folder')" class="mt-2" />
</div>
<div class="mt-4">
<div class="mt-4"
data-step="4"
data-intro="Jika Anda tidak ingin mengunggah file ZIP, Anda dapat memasukkan tautan ke repositori GitHub Anda di sini."
data-title="Or Github Link"
data-disable-interaction="false">
<x-input-label for="github_url" :value="__('Or Github Link')" />
<x-text-input id="github_url" class="block mt-1 w-full" type="text" name="github_url"
:value="old('github_url')" placeholder="E.g. https://github.com/username/repository.git" />
<x-input-error :messages="$errors->get('github_url')" class="mt-2" />
</div>
<div class="flex items-center justify-end mt-12">
<div class="flex items-center justify-end mt-12"
data-step="5"
data-intro="Klik tombol 'Submit' untuk mengirimkan project Anda."
data-title="Submit Project"
data-disable-interaction="false">
<x-primary-button class="ml-4">
{{ __('Submit') }}
</x-primary-button>

View File

@ -1,4 +1,8 @@
<table class="table" id="submissions_table">
<table class="table" id="submissions_table"
data-step="6"
data-intro="Tekan title dari project untuk melihat detail dari submission anda."
data-title="Submission Table"
data-disable-interaction="false">
<thead>
<tr>
<th>Title</th>

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
@ -13,28 +13,73 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
<!-- Scripts -->
<!-- Styles -->
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" />
<link href="https://unpkg.com/filepond@^4/dist/filepond.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://unpkg.com/intro.js/minified/introjs.min.css" />
<!-- Tambahan: tema Intro.js untuk tampilan yang lebih baik -->
<link rel="stylesheet" href="https://unpkg.com/intro.js/themes/introjs-modern.css" />
<link href="{{asset('css/nodejs_style.css')}}" rel="stylesheet">
<!-- Custom CSS for IntroJS modification -->
<style>
/* Hide the default skip button */
.introjs-skipbutton {
display: none !important;
}
/* Custom navigation container at bottom */
.introjs-tooltipbuttons {
display: flex;
justify-content: space-between;
align-items: center;
}
/* Custom skip button at bottom */
.custom-skip-button {
display: inline-block;
text-decoration: none;
padding: 6px 16px;
font-size: 14px;
font-weight: bold;
line-height: 1.5;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
color: white;
background-color: transparent;
border: 1px solid transparent; /* awalnya tidak terlihat */
border-radius: 999px;
transition: all 0.2s ease;
}
.custom-skip-button:hover {
border-color: white;
background-color: transparent;
}
</style>
<!-- Scripts -->
<script src="https://code.jquery.com/jquery-3.6.4.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<script src="https://unpkg.com/filepond-plugin-file-validate-type/dist/filepond-plugin-file-validate-type.js">
</script>
<script src="https://unpkg.com/filepond-plugin-file-validate-type/dist/filepond-plugin-file-validate-type.js"></script>
<script src="https://unpkg.com/filepond@^4/dist/filepond.js"></script>
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
<script src="https://unpkg.com/pdfobject@2.2.10/pdfobject.min.js"></script>
<link href="{{asset('css/nodejs_style.css')}}" rel="stylesheet">
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
</head>
<script src="https://unpkg.com/intro.js/minified/intro.min.js"></script>
</head>
<body class="font-sans antialiased">
<body class="font-sans antialiased">
<div class="min-h-screen bg-gray-100 dark:bg-gray-900">
@include('nodejs.layouts.navigation')
@ -52,7 +97,100 @@
{{ $slot }}
</main>
</div>
<!-- Konfigurasi Intro.js yang dimodifikasi -->
<script>
document.addEventListener("DOMContentLoaded", function () {
// Cek apakah pengguna sudah pernah melihat intro (menggunakan localStorage)
const hasSeenIntro = localStorage.getItem('hasSeenNodeJSIntro');
// Cek apakah ada elemen dengan data-step di halaman
const hasIntroElements = document.querySelectorAll('[data-step]').length > 0;
if (hasIntroElements && !hasSeenIntro) {
startTutorial();
}
// Tambahkan event listener untuk tombol reset tutorial
const resetIntroBtn = document.getElementById('resetIntroBtn');
if (resetIntroBtn) {
resetIntroBtn.addEventListener('click', function() {
localStorage.removeItem('hasSeenNodeJSIntro');
startTutorial();
});
}
// Fungsi untuk memulai tutorial
function startTutorial() {
if (document.querySelectorAll('[data-step]').length === 0) return;
// Konfigurasi yang lebih lengkap untuk intro.js
const intro = introJs();
// Konfigurasi umum
intro.setOptions({
nextLabel: 'Lanjut',
prevLabel: 'Kembali',
skipLabel: 'Lewati', // Ini tidak akan terlihat karena kita sembunyikan button aslinya
doneLabel: 'Selesai',
hidePrev: false,
hideNext: false,
showStepNumbers: true,
showBullets: true,
showProgress: true,
scrollToElement: true,
scrollTo: 'element',
disableInteraction: false,
tooltipPosition: 'auto',
highlightClass: 'intro-highlight',
tooltipClass: 'customTooltip',
exitOnOverlayClick: false,
exitOnEsc: true,
overlayOpacity: 0.8
});
// Event untuk memodifikasi tooltips setelah mereka dibuat
intro.onafterchange(function(targetElement) {
// Sembunyikan tombol skip default dan buat tombol skip kustom
setTimeout(function() {
const tooltipButtons = document.querySelector('.introjs-tooltipbuttons');
const skipExists = tooltipButtons.querySelector('.custom-skip-button');
// Hanya tambahkan tombol jika belum ada
if (!skipExists) {
const skipButton = document.createElement('button');
skipButton.className = 'custom-skip-button';
skipButton.innerHTML = 'Lewati';
// Tambahkan event untuk skip
skipButton.addEventListener('click', function() {
intro.exit();
localStorage.setItem('hasSeenNodeJSIntro', 'true');
});
// Tempatkan tombol Lewati di sebelah paling kanan
const nextButtons = tooltipButtons.querySelector('.introjs-nextbutton');
tooltipButtons.appendChild(skipButton);
}
}, 10);
});
// Jalankan tutorial
intro.start();
// Simpan bahwa pengguna sudah melihat intro
intro.oncomplete(function() {
localStorage.setItem('hasSeenNodeJSIntro', 'true');
});
intro.onexit(function() {
localStorage.setItem('hasSeenNodeJSIntro', 'true');
});
}
});
</script>
@yield('scripts')
</body>
</body>
</html>

View File

@ -1,42 +1,31 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
<div class="flex justify-between items-center">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight" data-step="1" data-intro="Ini adalah judul dari project yang sedang Anda lihat saat ini" data-title="Project Name" data-position="top" data-disable-interaction="false">
{{ __('Project:') . ' ' . $project->title }}
</h2>
<button id="resetIntroBtn" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
<i class="fas fa-question-circle mr-1"></i> Lihat Tutorial
</button>
</div>
</x-slot>
<div class="py-4">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<!-- Tips Alert for Dashboard -->
<x-alert.tips-alert pageId="project" title="Tips untuk Anda">
<p>Selamat datang di project! Berikut adalah beberapa tips untuk membantu Anda:</p>
<ul class="list-disc pl-5 mt-2">
<li>Klik ikon garis 3 di sebelah nama guide untuk membuka opsi</li>
<li>Pilih "View" untuk melihat PDF di halaman yang sama</li>
<li>Pilih "Open in a new tab" untuk membuka di tab baru</li>
<li>Pilih "Download" untuk menyimpan PDF ke perangkat Anda</li>
<li>Klik "All Guides" di panel Download untuk mengunduh semua panduan sekaligus</li>
<li>Klik "All Supplements" di panel Download untuk mengunduh file tambahan/pendukung</li>
</ul>
</x-alert.tips-alert>
</div>
</div>
<div class="pt-5">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg" data-step="2" data-intro="Bagian ini berisi detail project termasuk judul, deskripsi dan teknologi yang digunakan dalam project ini" data-title="Project Detail" data-position="top" data-disable-interaction="false">
@include('nodejs.projects.partials.details')
</div>
</div>
</div>
<div class="py-5">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg pb-18">
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg pb-18" data-step="3" data-intro="Di bagian ini, Anda dapat melihat semua panduan PDF terkait project ini. Klik 'View' untuk membuka panduan PDF langsung di halaman ini" data-title="Project Guide" data-position="top" data-disable-interaction="false">
@include('nodejs.projects.partials.guides')
</div>
</div>
</div>
<div class="py-5">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg" data-step="4" data-intro="Di sini Anda dapat mengunduh semua materi project sekaligus berdasarkan kategori - panduan, materi tambahan, dan tes" data-title="Project Download" data-position="top" data-disable-interaction="false">
@include('nodejs.projects.partials.downloads')
</div>
</div>

View File

@ -116,7 +116,7 @@ function loadProjects() {
success: function(response) {
if (response.status === 'success') {
const projects = response.data.projects;
let options = '<option value="">Pilih Proyek</option>';
let options = '<option value="">Select Project</option>';
projects.forEach(project => {
options += `<option value="${project.id}">${project.title}</option>`;

View File

@ -1,24 +1,17 @@
<x-app-layout>
<x-slot name="header">
<div class="flex items-center justify-between">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
{{ __('Submissions') }}
</h2>
<button id="resetIntroBtn" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
<i class="fas fa-question-circle mr-1"></i> Lihat Tutorial
</button>
</div>
</x-slot>
<div class="py-4">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<!-- Tips Alert for Dashboard -->
<x-alert.tips-alert pageId="submission-index" title="Tips untuk Anda">
<p>Selamat datang di Submission! Berikut adalah beberapa tips untuk membantu Anda:</p>
<ul class="list-disc pl-5 mt-2">
<li>Perhatikan kolom "Status" untuk melihat hasil pengajuan Anda</li>
<li>Klik ikon menu garis 3 untuk melihat opsi tindakan</li>
<li>Pilih "Restart submission" untuk mencoba ulang pengajuan yang gagal</li>
<li>Pilih "Delete submission" untuk menghapus pengajuan dari daftar</li>
<li>Klik judul project untuk melihat history dan lebih detail mengenai submission</li>
</ul>
</x-alert.tips-alert>
</div>
</div>
<div class="py-4"></div>
<div class="py-2">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg pb-12">

View File

@ -11,6 +11,7 @@
<tbody>
</tbody>
</table>
@section('scripts')
<script type="text/javascript">
function requestServer(element){
@ -102,7 +103,6 @@ function requestServer(element){
});
break;
case "change-source-code":
// redirect to change source code page
window.location = '/nodejs/submissions/change/' + submission_id;
break;
default:
@ -110,7 +110,6 @@ function requestServer(element){
}
}
$(function () {
var table = $('#submissions_table').DataTable({
"processing": true,
@ -135,11 +134,51 @@ function requestServer(element){
},
ajax: "{{ route('submissions') }}",
columns: [
{data: 'title', name: 'title', orderable: true, searchable: true},
// {data: 'submission_count', name: 'submission_count', orderable: true, searchable: false, className: "text-center"},
{data: 'attempts_count', name: 'attempts_count', orderable: true, searchable: false, className: "text-center"},
{data: 'submission_status', name: 'submission_status', orderable: true, searchable: true, className: "text-center"},
{data: 'action', name: 'action', orderable: false, searchable: false, className: "text-center"},
{
data: 'title',
name: 'title',
orderable: true,
searchable: true,
createdCell: function (td) {
$(td).attr({
'data-step': '1',
'data-intro': 'Klik Tittle Project untuk melihat lebih detail submission, anda dapat dapat melihat detail pengujian dan mendownload hasil pengujiannya.',
'data-title': 'Submission Detail',
'data-position': 'right',
'data-disable-interaction': 'false'
});
}
},
{
data: 'attempts_count',
name: 'attempts_count',
orderable: true,
searchable: false,
className: "text-center"
},
{
data: 'submission_status',
name: 'submission_status',
orderable: true,
searchable: true,
className: "text-center"
},
{
data: 'action',
name: 'action',
orderable: false,
searchable: false,
className: "text-center",
createdCell: function (td) {
$(td).attr({
'data-step': '2',
'data-intro': 'Jika anda sudah mensubmit sebuah project, anda dapat mengulang dan menghapus submission project tersebut dengan mengklik tombol yang muncul disini.',
'data-title': 'Submission Action',
'data-position': 'right',
'data-disable-interaction': 'false'
});
}
},
]
});
});

View File

@ -6,16 +6,6 @@
</h2>
</x-slot>
<div class="py-4">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<!-- Tips Alert for Dashboard -->
<x-alert.tips-alert pageId="submission-show" title="Tips untuk Anda">
<p>Selamat datang di Submission! Berikut adalah beberapa tips untuk membantu Anda:</p>
<ul class="list-disc pl-5 mt-2">
<li>Klik "View" untuk melihat feedback atau error log dari sistem</li>
<li>Klik "Download Results" untuk mengunduh laporan berupa json</li>
</ul>
</x-alert.tips-alert>
</div>
</div>
<div class="py-5">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">