diff --git a/app/Http/Controllers/API/ProgressController.php b/app/Http/Controllers/API/ProgressController.php
new file mode 100644
index 0000000..29563af
--- /dev/null
+++ b/app/Http/Controllers/API/ProgressController.php
@@ -0,0 +1,288 @@
+middleware('auth:sanctum');
+ }
+
+ // Method untuk mendapatkan progres materi
+ public function getMateriProgress($materiId)
+ {
+ // Ambil user yang terotentikasi
+ $user = Auth::user();
+
+ // Ambil materi berdasarkan ID
+ $materi = Materi::findOrFail($materiId);
+
+ // Menghitung total kategori dan submateri yang selesai
+ $totalSubmateri = 0;
+ $completedSubmateri = 0;
+
+ // Looping untuk setiap kategori dari materi
+ foreach ($materi->kategori as $kategori) {
+ $totalSubmateri += $kategori->subMateri()->count();
+
+ // Menghitung jumlah submateri yang selesai untuk kategori ini
+ $completedSubmateri += Progress::where('user_id', $user->id)
+ ->where('status', 'selesai')
+ ->whereIn('sub_materi_id', $kategori->subMateri->pluck('id'))
+ ->count();
+ }
+
+ // Menghitung persentase progres
+ $progressPercentage = ($totalSubmateri > 0) ? ($completedSubmateri / $totalSubmateri) * 100 : 0;
+
+ return response()->json([
+ 'materi' => $materi->title,
+ 'total_submateri' => $totalSubmateri,
+ 'completed_submateri' => $completedSubmateri,
+ 'progress_percentage' => $progressPercentage
+ ]);
+ }
+
+ // Method untuk update progress
+ public function updateProgress(Request $request, $subMateriId)
+ {
+ $user = Auth::user();
+
+ // Update atau buat data progres baru
+ $progress = Progress::updateOrCreate(
+ ['user_id' => $user->id, 'sub_materi_id' => $subMateriId],
+ ['status' => 'selesai']
+ );
+
+ return response()->json(['message' => 'Progress updated successfully']);
+ }
+
+ public function getProgressBySubMateri($subMateriId)
+{
+ // Ambil user yang terotentikasi
+ $user = Auth::user();
+
+ // Cek apakah ada progres untuk user ini pada submateri yang dimaksud, ambil yang terbaru
+ $progress = Progress::where('user_id', $user->id)
+ ->where('sub_materi_id', $subMateriId)
+ ->latest() // Mengambil data yang paling baru berdasarkan 'updated_at'
+ ->first();
+
+ // Jika progres ada, kembalikan statusnya
+ if ($progress) {
+ return response()->json([
+ 'sub_materi_id' => $subMateriId,
+ 'status' => $progress->status, // 'selesai', 'gagal', atau status lainnya
+ 'message' => 'Progress found',
+ ]);
+ }
+
+ // Jika tidak ada progres, kembalikan status belum selesai
+ return response()->json([
+ 'sub_materi_id' => $subMateriId,
+ 'status' => 'belum selesai', // Default status
+ 'message' => 'No progress found',
+ ]);
+}
+
+
+ public function getProgressPercentage(Request $request)
+ {
+ // Ambil user yang terotentikasi
+ $user = Auth::user();
+
+ // Ambil semua submateri yang ada di sistem
+ $totalSubmateri = SubMateri::count(); // Menghitung semua submateri yang ada
+ $completedSubmateri = Progress::where('user_id', $user->id)
+ ->where('status', 'selesai')
+ ->count(); // Menghitung submateri yang statusnya selesai
+
+ // Menghitung persentase progres
+ $progressPercentage = ($totalSubmateri > 0) ? ($completedSubmateri / $totalSubmateri) * 100 : 0;
+
+ // Return hasil persentase progres
+ return response()->json([
+ 'user_id' => $user->id,
+ 'nama_lengkap' => $user->nama_lengkap,
+ 'total_submateri' => $totalSubmateri,
+ 'completed_submateri' => $completedSubmateri,
+ 'progress_percentage' => $progressPercentage
+ ]);
+ }
+
+ public function getProgressPercentageById(Request $request, $user_id)
+{
+ // Validasi user_id jika diperlukan
+ if (!User::find($user_id)) {
+ return response()->json([
+ 'message' => 'User not found',
+ ], 404);
+ }
+
+ // Ambil user berdasarkan ID
+ $user = User::find($user_id);
+
+ // Ambil semua submateri yang ada di sistem
+ $totalSubmateri = SubMateri::count(); // Menghitung semua submateri yang ada
+ $completedSubmateri = Progress::where('user_id', $user->id)
+ ->where('status', 'selesai')
+ ->count(); // Menghitung submateri yang statusnya selesai
+
+ // Menghitung persentase progres
+ $progressPercentage = ($totalSubmateri > 0) ? ($completedSubmateri / $totalSubmateri) * 100 : 0;
+
+ // Return hasil persentase progres
+ return response()->json([
+ 'user_id' => $user->id,
+ 'nama_lengkap' => $user->nama_lengkap,
+ 'total_submateri' => $totalSubmateri,
+ 'completed_submateri' => $completedSubmateri,
+ 'progress_percentage' => $progressPercentage
+ ]);
+}
+
+
+public function saveRecordedAudioName(Request $request, $id_latihan)
+ {
+ // Validasi data yang masuk
+ $request->validate([
+ 'recorded_audio' => 'required|string', // Nama file audio yang disimpan
+ ]);
+
+ // Temukan latihan berdasarkan ID (tanpa memeriksa user_id)
+ $latihan = Latihan::find($id_latihan);
+
+ // Jika latihan ditemukan, simpan nama file rekaman ke kolom recorder_audio
+ if ($latihan) {
+ $latihan->recorder_audio = $request->recorded_audio;
+ $latihan->status = 'benar'; // Status latihan diubah menjadi selesai
+ $latihan->save();
+
+ return response()->json([
+ 'message' => 'Rekaman berhasil disimpan!',
+ 'latihan' => $latihan,
+ ], 200);
+ } else {
+ return response()->json([
+ 'message' => 'Latihan tidak ditemukan.',
+ ], 404);
+ }
+ }
+
+ // API untuk menyimpan data progres latihan yang telah diselesaikan
+ public function saveProgress(Request $request, $submateri_id)
+ {
+ // Validasi data yang masuk
+ $request->validate([
+ 'latihan_ids' => 'required|array', // Array dari ID latihan yang telah diselesaikan
+ 'latihan_ids.*' => 'exists:latihan,id', // Pastikan ID latihan ada di tabel latihan
+ ]);
+
+ // Ambil user_id dari token yang digunakan (auth)
+ $user_id = Auth::id(); // Mendapatkan ID pengguna yang terautentikasi
+
+ // Ambil data submateri untuk menampilkan title
+ $submateri = SubMateri::find($submateri_id);
+ if (!$submateri) {
+ return response()->json(['message' => 'SubMateri tidak ditemukan'], 404);
+ }
+
+ // Menyimpan progres untuk setiap latihan yang diselesaikan oleh pengguna
+ $savedProgress = [];
+ foreach ($request->latihan_ids as $latihanId) {
+ // Temukan latihan berdasarkan ID
+ $latihan = Latihan::find($latihanId);
+
+ // Jika latihan ditemukan, simpan ke tabel progres
+ if ($latihan) {
+ $progress = Progress::updateOrCreate(
+ [
+ 'user_id' => $user_id, // Gunakan user_id dari token
+ 'sub_materi_id' => $submateri_id,
+ 'id_latihan' => $latihan->id,
+ ],
+ [
+ 'status' => 'menunggu', // Status latihan diatur sebagai 'menunggu' setelah selesai
+ 'nilai' => $latihan->nilai, // Nilai latihan yang diberikan oleh pengajar
+ ]
+ );
+
+ // Menambahkan data progres yang baru disimpan untuk ditampilkan
+ $savedProgress[] = [
+ 'user_id' => $user_id,
+ 'sub_materi_id' => $submateri_id,
+ 'submateri_title' => $submateri->title, // Menambahkan title dari submateri
+ 'status' => 'menunggu',
+ 'id_latihan' => $latihan->id,
+ 'potongan_ayat' => $latihan->potongan_ayat,
+ 'latin_text' => $latihan->latin_text,
+ 'recorder_audio' => $latihan->recorder_audio,
+ ];
+ }
+ }
+
+ return response()->json([
+ 'message' => 'Progres latihan berhasil disimpan.',
+ 'progress' => $savedProgress,
+ ], 200);
+ }
+
+ public function getHasilPenilaianByUserAndSubMateri($submateri_id)
+{
+ // Ambil user_id dari token yang digunakan (auth)
+ $user_id = Auth::id(); // Mendapatkan ID pengguna yang terautentikasi
+
+ // Ambil data berdasarkan user_id dan submateri_id
+ $progressData = Progress::with([
+ 'latihan' => function ($query) {
+ $query->select('id', 'potongan_ayat', 'latin_text', 'recorder_audio', 'feedback_pengajar', 'status');
+ }
+ ])
+ ->where('user_id', $user_id) // Mengambil progress berdasarkan user_id yang terautentikasi
+ ->where('sub_materi_id', $submateri_id) // Mengambil progress berdasarkan submateri_id
+ ->get(['user_id', 'sub_materi_id', 'id_latihan', 'nilai']); // Pilih data yang diperlukan dari tabel progress
+
+ // Cek apakah ada data progress
+ if ($progressData->isEmpty()) {
+ return response()->json(['message' => 'Tidak ada data progres untuk pengguna ini pada submateri ini'], 404);
+ }
+
+ // Menyiapkan hasil yang akan dikembalikan
+ $results = $progressData->map(function ($progress) {
+ return [
+ 'user_id' => $progress->user_id,
+ 'sub_materi_id' => $progress->sub_materi_id,
+ 'id_latihan' => $progress->id_latihan,
+ 'nilai' => $progress->nilai,
+ 'potongan_ayat' => $progress->latihan->potongan_ayat,
+ 'latin_text' => $progress->latihan->latin_text,
+ 'recorder_audio' => $progress->latihan->recorder_audio,
+ 'feedback_pengajar' => $progress->latihan->feedback_pengajar,
+ 'status' => $progress->latihan->status,
+ ];
+ });
+
+ return response()->json([
+ 'message' => 'Data hasil penilaian berhasil diambil.',
+ 'data' => $results
+ ], 200);
+}
+
+
+}
+
diff --git a/app/Http/Controllers/API/UploadAudioController.php b/app/Http/Controllers/API/UploadAudioController.php
new file mode 100644
index 0000000..2b68c46
--- /dev/null
+++ b/app/Http/Controllers/API/UploadAudioController.php
@@ -0,0 +1,30 @@
+file('recorded_audio'));
+ // Validasi file
+ $request->validate([
+ // 'recorded_audio' => 'required|mimes:m4a,mp3,wav|max:10240', // Batasi ukuran file (misalnya 10MB)
+ 'recorded_audio' => 'required|mimes:m4a,mp3,wav', // Batasi ukuran file (misalnya 10MB)
+ ]);
+
+ // Mendapatkan file dari request
+ $file = $request->file('recorded_audio');
+
+ // Menyimpan file di disk public
+ $path = $file->store('audio_files', 'public'); // Menyimpan di folder `storage/app/public/audio_files`
+
+ return response()->json([
+ 'message' => 'File berhasil diupload!',
+ 'file_path' => $path
+ ], 200);
+ }
+}
diff --git a/app/Http/Controllers/API/UserControler.php b/app/Http/Controllers/API/UserControler.php
index c8ed669..33f0d38 100644
--- a/app/Http/Controllers/API/UserControler.php
+++ b/app/Http/Controllers/API/UserControler.php
@@ -5,11 +5,13 @@
use App\Helpers\ResponseFormatter;
use App\Http\Controllers\Controller;
use App\Models\User;
+use App\Models\Progress;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
+use Illuminate\Support\Facades\DB;
class UserControler extends Controller
{
@@ -87,6 +89,51 @@ public function login(Request $request)
}
}
+ public function loginWithTelp(Request $request)
+{
+ try {
+ $request->validate([
+ 'no_telp_wali' => 'required|string', // Validate 'no_telp_wali'
+ 'password' => 'required' // Validate password
+ ]);
+
+ // Find the user by 'no_telp_wali'
+ $user = User::where('no_telp_wali', $request->no_telp_wali)->first();
+
+ // Check if the user exists
+ if (!$user) {
+ return ResponseFormatter::error([
+ 'message' => 'No telepon salah'
+ ], 'Authentication Failed', 401);
+ }
+
+ // Check if the password is correct
+ if (!Hash::check($request->password, $user->password)) {
+ return ResponseFormatter::error([
+ 'message' => 'Password salah'
+ ], 'Authentication Failed', 401);
+ }
+
+ // Create token for the user
+ $tokenResult = $user->createToken('authToken')->plainTextToken;
+
+ return ResponseFormatter::success([
+ 'access_token' => $tokenResult,
+ 'token_type' => 'Bearer',
+ 'user' => [
+ 'peran' => $user->peran // Ensure 'peran' is included here
+ ]
+ ], 'Authenticated');
+ } catch (Exception $error) {
+ return ResponseFormatter::error([
+ 'message' => 'Something went wrong',
+ 'error' => $error->getMessage()
+ ], 'Authentication Failed', 500);
+ }
+}
+
+
+
public function fetch(Request $request)
{
return ResponseFormatter::success($request->user(), 'Data berhasil di ambil');
@@ -102,8 +149,10 @@ public function logout(Request $request)
public function getUsersByRole(Request $request)
{
try {
- // Ambil data user yang memiliki peran 'santri'
- $users = User::where('peran', 'santri')->get();
+ // Ambil data user yang memiliki peran 'santri' dan urutkan berdasarkan created_at secara descending
+ $users = User::where('peran', 'santri')
+ ->orderBy('created_at', 'desc')
+ ->get();
// Jika tidak ada user dengan peran 'santri'
if ($users->isEmpty()) {
@@ -128,6 +177,7 @@ public function getUsersByRole(Request $request)
}
}
+
public function getUserInfoById($id)
{
// Mencari user berdasarkan ID
@@ -259,55 +309,234 @@ public function tambahSantri(Request $request)
);
}
+ public function changePassword(Request $request)
+{
+ // Validasi inputan password baru
+ $validator = Validator::make($request->all(), [
+ 'new_password' => 'required|string|min:8|confirmed', // Pastikan password baru minimal 8 karakter dan dikonfirmasi
+ ]);
-// public function importSantri(Request $request)
-// {
-// // Validasi input
-// $validator = Validator::make($request->all(), [
-// 'santri' => 'required|array',
-// 'santri.*.nama_lengkap' => 'required|string|max:255',
-// 'santri.*.alamat' => 'required|string|max:255',
-// 'santri.*.usia' => 'required|string|max:255',
-// 'santri.*.no_telp_wali' => 'required|string|max:20',
-// 'santri.*.email' => 'required|email|max:255',
-// 'santri.*.jenis_kelamin' => 'required|string|in:Laki-laki,Perempuan',
-// 'santri.*.jenjang_pendidikan' => 'required|string|max:255',
-// ]);
+ // Jika validasi gagal
+ if ($validator->fails()) {
+ return response()->json([
+ 'status' => 'error',
+ 'message' => $validator->errors(),
+ ], 400);
+ }
-// // Jika validasi gagal
-// if ($validator->fails()) {
-// return ResponseFormatter::error(
-// null,
-// 'Validation Error',
-// 422
-// );
-// }
+ // Ambil user yang terautentikasi
+ $user = Auth::user();
-// // Ambil data santri dari request
-// $santriData = $request->input('santri');
-// $santriInserted = [];
+ // Update password pengguna secara manual
+ DB::table('users') // Gunakan query builder untuk update langsung
+ ->where('id', $user->id) // Menentukan user berdasarkan ID
+ ->update(['password' => Hash::make($request->new_password)]); // Enkripsi password baru dan simpan
+
+ return response()->json([
+ 'status' => 'success',
+ 'message' => 'Password berhasil diubah',
+ ], 200);
+}
+
+public function getUserInfoByToken(Request $request)
+{
+ // Mendapatkan pengguna yang terautentikasi
+ $user = Auth::user();
+
+ // Jika pengguna tidak ditemukan (misalnya, token tidak valid)
+ if (!$user) {
+ return ResponseFormatter::error(
+ null,
+ 'User not found',
+ 404
+ );
+ }
+
+ // Mengembalikan data pengguna dalam format JSON menggunakan ResponseFormatter
+ return ResponseFormatter::success(
+ [
+ 'id' => $user->id,
+ 'nama_lengkap' => $user->nama_lengkap,
+ 'alamat' => $user->alamat,
+ 'usia' => $user->usia,
+ 'no_telp_wali' => $user->no_telp_wali,
+ 'email' => $user->email,
+ 'jenis_kelamin' => $user->jenis_kelamin,
+ 'jenjang_pendidikan' => $user->jenjang_pendidikan,
+ ],
+ 'User data retrieved successfully'
+ );
+}
+
+public function updateUserByToken(Request $request)
+{
+ // Validasi data yang diterima
+ $validator = Validator::make($request->all(), [
+ 'nama_lengkap' => 'required|string|max:255',
+ 'alamat' => 'required|string|max:255',
+ 'usia' => 'required|string|max:255',
+ 'no_telp_wali' => 'required|string|max:20',
+ 'email' => 'required|email|max:255',
+ 'jenjang_pendidikan' => 'required|string|max:255',
+ 'jenis_kelamin' => 'required|string|in:Laki-laki,Perempuan',
+ ]);
+
+ // Jika validasi gagal, kembalikan respons error
+ if ($validator->fails()) {
+ return ResponseFormatter::error(
+ null,
+ 'Validation Error',
+ 422
+ );
+ }
+
+ // Mendapatkan pengguna yang terautentikasi
+ $user = Auth::user();
+
+ // Jika pengguna tidak ditemukan (misalnya, token tidak valid)
+ if (!$user) {
+ return ResponseFormatter::error(
+ null,
+ 'User not found',
+ 404
+ );
+ }
+
+ // Menggunakan DB::table untuk memperbarui data pengguna secara manual
+ DB::table('users')
+ ->where('id', $user->id)
+ ->update([
+ 'nama_lengkap' => $request->nama_lengkap,
+ 'alamat' => $request->alamat,
+ 'usia' => $request->usia,
+ 'no_telp_wali' => $request->no_telp_wali,
+ 'email' => $request->email,
+ 'jenjang_pendidikan' => $request->jenjang_pendidikan,
+ 'jenis_kelamin' => $request->jenis_kelamin,
+ ]);
+
+ // Mengembalikan respons sukses
+ return ResponseFormatter::success(
+ null,
+ 'User updated successfully'
+ );
+}
+
+
+
+
+
+
+ public function importSantri(Request $request)
+{
+ // Validasi input
+ $validator = Validator::make($request->all(), [
+ 'santri' => 'required|array',
+ 'santri.*.nama_lengkap' => 'required|string|max:255',
+ 'santri.*.alamat' => 'required|string|max:255',
+ 'santri.*.usia' => 'required|string|max:255',
+ 'santri.*.no_telp_wali' => 'required|string|max:20',
+ 'santri.*.email' => 'required|email|max:255',
+ 'santri.*.jenis_kelamin' => 'required|string|in:Laki-laki,Perempuan',
+ 'santri.*.jenjang_pendidikan' => 'required|string|max:255',
+ ]);
+
+ // Jika validasi gagal
+ if ($validator->fails()) {
+ return ResponseFormatter::error(
+ null,
+ 'Validation Error',
+ 422
+ );
+ }
+
+ // Ambil data santri dari request
+ $santriData = $request->input('santri');
+ $santriInserted = [];
+
+ // Simpan tiap santri ke database
+ foreach ($santriData as $santri) {
+ $santriInserted[] = User::create([
+ 'nama_lengkap' => $santri['nama_lengkap'],
+ 'alamat' => $santri['alamat'],
+ 'usia' => $santri['usia'],
+ 'no_telp_wali' => $santri['no_telp_wali'],
+ 'email' => $santri['email'],
+ 'jenis_kelamin' => $santri['jenis_kelamin'],
+ 'jenjang_pendidikan' => $santri['jenjang_pendidikan'],
+ 'peran' => 'santri',
+ 'password' => bcrypt('almuhajirin'), // password = email (dihash)
+ ]);
+ }
+
+ // Respon sukses
+ return ResponseFormatter::success(
+ $santriInserted,
+ 'Santri data imported successfully'
+ );
+}
+
+public function getUserProgres(Request $request)
+{
+ try {
+ // Ambil semua user dengan peran 'santri'
+ $santriUsers = User::where('peran', 'santri')->get(); // Ambil semua user dengan peran 'santri'
+
+ // Jika tidak ada santri
+ if ($santriUsers->isEmpty()) {
+ return response()->json([
+ 'status' => 'error',
+ 'message' => 'Tidak ada santri yang ditemukan.',
+ ], 404); // Status code 404 (Not Found)
+ }
+
+ // Ambil progres untuk setiap santri dan filter yang sudah menyelesaikan submateri
+ $santriProgressData = $santriUsers->map(function ($santri) {
+ // Ambil progres latihan yang telah diselesaikan oleh santri berdasarkan user ID
+ $progresData = Progress::where('user_id', $santri->id)
+ ->where('status', 'selesai') // Menghitung submateri yang sudah selesai
+ ->with('submateri') // Load data submateri yang terkait
+ ->get();
+
+ // Hitung jumlah submateri yang selesai
+ $completedSubmateriCount = $progresData->count(); // Menghitung jumlah data progres yang selesai
+
+ // Hanya tampilkan santri yang telah menyelesaikan submateri
+ if ($completedSubmateriCount > 0) {
+ return [
+ 'user_id' => $santri->id,
+ 'nama_lengkap' => $santri->nama_lengkap,
+ 'no_telp_wali' => $santri->no_telp_wali,
+ 'completed_submateri' => $completedSubmateriCount, // Jumlah submateri yang telah selesai
+ ];
+ }
+ })->filter(function ($santri) {
+ return $santri !== null; // Filter out santri that haven't completed any submateri
+ });
+
+ // Jika tidak ada santri yang menyelesaikan submateri
+ if ($santriProgressData->isEmpty()) {
+ return response()->json([
+ 'status' => 'error',
+ 'message' => 'Tidak ada santri yang telah menyelesaikan submateri.',
+ ], 404); // Status code 404 (Not Found)
+ }
+
+ // Kirim data progres untuk setiap santri yang sudah selesai latihan
+ return response()->json([
+ 'status' => 'success',
+ 'data' => $santriProgressData, // Mengembalikan data progres yang telah diselesaikan
+ ], 200);
+
+ } catch (\Exception $e) {
+ return response()->json([
+ 'status' => 'error',
+ 'message' => 'Something went wrong: ' . $e->getMessage(),
+ ], 500);
+ }
+}
-// // Simpan tiap santri ke database
-// foreach ($santriData as $santri) {
-// $santriInserted[] = User::create([
-// 'nama_lengkap' => $santri['nama_lengkap'],
-// 'alamat' => $santri['alamat'],
-// 'usia' => $santri['usia'],
-// 'no_telp_wali' => $santri['no_telp_wali'],
-// 'email' => $santri['email'],
-// 'jenis_kelamin' => $santri['jenis_kelamin'],
-// 'jenjang_pendidikan' => $santri['jenjang_pendidikan'],
-// 'peran' => 'santri',
-// 'password' => bcrypt($santri['email']), // password = email (dihash)
-// ]);
-// }
-// // Respon sukses
-// return ResponseFormatter::success(
-// $santriInserted,
-// 'Santri data imported successfully'
-// );
-// }
}
diff --git a/app/Http/Controllers/Auth/ConfirmPasswordController.php b/app/Http/Controllers/Auth/ConfirmPasswordController.php
new file mode 100644
index 0000000..3559954
--- /dev/null
+++ b/app/Http/Controllers/Auth/ConfirmPasswordController.php
@@ -0,0 +1,39 @@
+middleware('auth');
+ }
+}
diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php
new file mode 100644
index 0000000..465c39c
--- /dev/null
+++ b/app/Http/Controllers/Auth/ForgotPasswordController.php
@@ -0,0 +1,22 @@
+middleware('guest')->except('logout');
+ $this->middleware('auth')->only('logout');
+ }
+}
diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php
new file mode 100644
index 0000000..961ea36
--- /dev/null
+++ b/app/Http/Controllers/Auth/RegisterController.php
@@ -0,0 +1,72 @@
+middleware('guest');
+ }
+
+ /**
+ * Get a validator for an incoming registration request.
+ *
+ * @param array $data
+ * @return \Illuminate\Contracts\Validation\Validator
+ */
+ protected function validator(array $data)
+ {
+ return Validator::make($data, [
+ 'name' => ['required', 'string', 'max:255'],
+ 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
+ 'password' => ['required', 'string', 'min:8', 'confirmed'],
+ ]);
+ }
+
+ /**
+ * Create a new user instance after a valid registration.
+ *
+ * @param array $data
+ * @return \App\Models\User
+ */
+ protected function create(array $data)
+ {
+ return User::create([
+ 'name' => $data['name'],
+ 'email' => $data['email'],
+ 'password' => Hash::make($data['password']),
+ ]);
+ }
+}
diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php
new file mode 100644
index 0000000..fe965b2
--- /dev/null
+++ b/app/Http/Controllers/Auth/ResetPasswordController.php
@@ -0,0 +1,29 @@
+middleware('auth');
+ $this->middleware('signed')->only('verify');
+ $this->middleware('throttle:6,1')->only('verify', 'resend');
+ }
+}
diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php
new file mode 100644
index 0000000..7cbc2c3
--- /dev/null
+++ b/app/Http/Controllers/HomeController.php
@@ -0,0 +1,28 @@
+middleware('auth');
+ }
+
+ /**
+ * Show the application dashboard.
+ *
+ * @return \Illuminate\Contracts\Support\Renderable
+ */
+ public function index()
+ {
+ return view('home');
+ }
+}
diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php
index c34cdcf..b6ea116 100644
--- a/app/Http/Kernel.php
+++ b/app/Http/Kernel.php
@@ -39,7 +39,7 @@ class Kernel extends HttpKernel
],
'api' => [
- // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
+ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
diff --git a/app/Models/Latihan.php b/app/Models/Latihan.php
index 4382627..eedd6be 100644
--- a/app/Models/Latihan.php
+++ b/app/Models/Latihan.php
@@ -20,6 +20,14 @@ class Latihan extends Model
'materi_description',
'correct_audio',
'recorder_audio',
+ 'feedback_pengajar',
+ 'nilai',
+ 'status',
];
+ public function progress()
+ {
+ return $this->hasMany(Progress::class, 'id_latihan'); // Relasi balik ke Progress
+ }
+
}
diff --git a/app/Models/Progress.php b/app/Models/Progress.php
new file mode 100644
index 0000000..7ee396c
--- /dev/null
+++ b/app/Models/Progress.php
@@ -0,0 +1,31 @@
+belongsTo(User::class);
+ }
+
+ // Relasi ke SubMateri
+ public function subMateri()
+ {
+ return $this->belongsTo(SubMateri::class);
+ }
+
+ // Relasi ke Latihan
+ public function Latihan()
+ {
+ return $this->belongsTo(Latihan::class, 'id_latihan');
+ }
+}
diff --git a/composer.json b/composer.json
index 5b40f87..b111701 100644
--- a/composer.json
+++ b/composer.json
@@ -9,7 +9,9 @@
"guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^10.0",
"laravel/sanctum": "^3.2",
- "laravel/tinker": "^2.8"
+ "laravel/tinker": "^2.8",
+ "laravel/ui": "^4.6",
+ "phpmailer/phpmailer": "^6.10"
},
"require-dev": {
"fakerphp/faker": "^1.9.1",
diff --git a/composer.lock b/composer.lock
index cf350fa..37f4621 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "bfe12996eeecb6fdc8713a9fd9d431f8",
+ "content-hash": "1787b3b8dd905d7a2fb5758e07bf55a0",
"packages": [
{
"name": "brick/math",
@@ -1512,6 +1512,69 @@
},
"time": "2025-01-27T14:24:01+00:00"
},
+ {
+ "name": "laravel/ui",
+ "version": "v4.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laravel/ui.git",
+ "reference": "7d6ffa38d79f19c9b3e70a751a9af845e8f41d88"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laravel/ui/zipball/7d6ffa38d79f19c9b3e70a751a9af845e8f41d88",
+ "reference": "7d6ffa38d79f19c9b3e70a751a9af845e8f41d88",
+ "shasum": ""
+ },
+ "require": {
+ "illuminate/console": "^9.21|^10.0|^11.0|^12.0",
+ "illuminate/filesystem": "^9.21|^10.0|^11.0|^12.0",
+ "illuminate/support": "^9.21|^10.0|^11.0|^12.0",
+ "illuminate/validation": "^9.21|^10.0|^11.0|^12.0",
+ "php": "^8.0",
+ "symfony/console": "^6.0|^7.0"
+ },
+ "require-dev": {
+ "orchestra/testbench": "^7.35|^8.15|^9.0|^10.0",
+ "phpunit/phpunit": "^9.3|^10.4|^11.5"
+ },
+ "type": "library",
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Laravel\\Ui\\UiServiceProvider"
+ ]
+ },
+ "branch-alias": {
+ "dev-master": "4.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Laravel\\Ui\\": "src/",
+ "Illuminate\\Foundation\\Auth\\": "auth-backend/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "Laravel UI utilities and presets.",
+ "keywords": [
+ "laravel",
+ "ui"
+ ],
+ "support": {
+ "source": "https://github.com/laravel/ui/tree/v4.6.1"
+ },
+ "time": "2025-01-28T15:15:29+00:00"
+ },
{
"name": "league/commonmark",
"version": "2.6.1",
@@ -2390,6 +2453,87 @@
],
"time": "2024-11-21T10:36:35+00:00"
},
+ {
+ "name": "phpmailer/phpmailer",
+ "version": "v6.10.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHPMailer/PHPMailer.git",
+ "reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144",
+ "reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ctype": "*",
+ "ext-filter": "*",
+ "ext-hash": "*",
+ "php": ">=5.5.0"
+ },
+ "require-dev": {
+ "dealerdirect/phpcodesniffer-composer-installer": "^1.0",
+ "doctrine/annotations": "^1.2.6 || ^1.13.3",
+ "php-parallel-lint/php-console-highlighter": "^1.0.0",
+ "php-parallel-lint/php-parallel-lint": "^1.3.2",
+ "phpcompatibility/php-compatibility": "^9.3.5",
+ "roave/security-advisories": "dev-latest",
+ "squizlabs/php_codesniffer": "^3.7.2",
+ "yoast/phpunit-polyfills": "^1.0.4"
+ },
+ "suggest": {
+ "decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
+ "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
+ "ext-openssl": "Needed for secure SMTP sending and DKIM signing",
+ "greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
+ "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
+ "league/oauth2-google": "Needed for Google XOAUTH2 authentication",
+ "psr/log": "For optional PSR-3 debug logging",
+ "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
+ "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "PHPMailer\\PHPMailer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "LGPL-2.1-only"
+ ],
+ "authors": [
+ {
+ "name": "Marcus Bointon",
+ "email": "phpmailer@synchromedia.co.uk"
+ },
+ {
+ "name": "Jim Jagielski",
+ "email": "jimjag@gmail.com"
+ },
+ {
+ "name": "Andy Prevost",
+ "email": "codeworxtech@users.sourceforge.net"
+ },
+ {
+ "name": "Brent R. Matzelle"
+ }
+ ],
+ "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
+ "support": {
+ "issues": "https://github.com/PHPMailer/PHPMailer/issues",
+ "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.10.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/Synchro",
+ "type": "github"
+ }
+ ],
+ "time": "2025-04-24T15:19:31+00:00"
+ },
{
"name": "phpoption/phpoption",
"version": "1.9.3",
diff --git a/database/migrations/2014_10_12_100000_create_password_resets_table.php b/database/migrations/2014_10_12_100000_create_password_resets_table.php
new file mode 100644
index 0000000..fcacb80
--- /dev/null
+++ b/database/migrations/2014_10_12_100000_create_password_resets_table.php
@@ -0,0 +1,32 @@
+string('email')->index();
+ $table->string('token');
+ $table->timestamp('created_at')->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('password_resets');
+ }
+};
diff --git a/database/migrations/2025_06_02_184222_create_progress_table.php b/database/migrations/2025_06_02_184222_create_progress_table.php
new file mode 100644
index 0000000..0f9a1d6
--- /dev/null
+++ b/database/migrations/2025_06_02_184222_create_progress_table.php
@@ -0,0 +1,30 @@
+id();
+ $table->foreignId('user_id')->constrained('users')->onDelete('cascade');
+ $table->foreignId('sub_materi_id')->constrained('sub_materi')->onDelete('cascade');
+ $table->enum('status', ['selesai', 'belum selesai'])->default('belum selesai');
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('progress');
+ }
+};
diff --git a/database/migrations/2025_06_16_092657_add_fields_to_latihan_table.php b/database/migrations/2025_06_16_092657_add_fields_to_latihan_table.php
new file mode 100644
index 0000000..1ab01ee
--- /dev/null
+++ b/database/migrations/2025_06_16_092657_add_fields_to_latihan_table.php
@@ -0,0 +1,32 @@
+text('feedback_pengajar')->nullable()->after('recorder_audio');
+ $table->decimal('nilai', 5, 2)->nullable()->after('feedback_pengajar');
+ $table->enum('status', ['benar', 'salah'])->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('latihan', function (Blueprint $table) {
+ $table->dropColumn('feedback_pengajar');
+ $table->dropColumn('nilai');
+ $table->dropColumn('status');
+ });
+ }
+};
diff --git a/database/migrations/2025_06_16_093236_add_fields_to_progress_table.php b/database/migrations/2025_06_16_093236_add_fields_to_progress_table.php
new file mode 100644
index 0000000..d9595e4
--- /dev/null
+++ b/database/migrations/2025_06_16_093236_add_fields_to_progress_table.php
@@ -0,0 +1,28 @@
+decimal('nilai', 5, 2)->nullable()->after('status'); // Kolom nilai yang didapatkan oleh santri
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('progress', function (Blueprint $table) {
+ $table->dropColumn('nilai');
+ });
+ }
+};
diff --git a/database/migrations/2025_06_16_093929_update_status_field_in_progress_table.php b/database/migrations/2025_06_16_093929_update_status_field_in_progress_table.php
new file mode 100644
index 0000000..5622ded
--- /dev/null
+++ b/database/migrations/2025_06_16_093929_update_status_field_in_progress_table.php
@@ -0,0 +1,28 @@
+enum('status', ['selesai', 'menunggu', 'gagal', 'belum selesai'])->default('belum selesai')->change();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('progress', function (Blueprint $table) {
+ $table->enum('status', ['selesai', 'belum selesai'])->default('belum selesai')->change();
+ });
+ }
+};
diff --git a/database/migrations/2025_06_16_095119_add_id_latihan_to_progress_table.php b/database/migrations/2025_06_16_095119_add_id_latihan_to_progress_table.php
new file mode 100644
index 0000000..d5b81a9
--- /dev/null
+++ b/database/migrations/2025_06_16_095119_add_id_latihan_to_progress_table.php
@@ -0,0 +1,29 @@
+foreignId('id_latihan')->nullable()->constrained('latihan')->onDelete('cascade')->after('id_user');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('progress', function (Blueprint $table) {
+ $table->dropForeign(['id_latihan']); // Menghapus foreign key
+ $table->dropColumn('id_latihan'); // Menghapus kolom
+ });
+ }
+};
diff --git a/database/seeders/QuizTableSeeder.php b/database/seeders/QuizTableSeeder.php
index c76c827..0b57c2b 100644
--- a/database/seeders/QuizTableSeeder.php
+++ b/database/seeders/QuizTableSeeder.php
@@ -15,226 +15,257 @@ class QuizTableSeeder extends Seeder
public function run()
{
$questions = [
- // Soal 1
[
- 'id_materi' => 1,
- 'question' => 'Makharijul Huruf artinya .....',
- 'option_a' => 'Tempat-tempat keluarnya huruf hijaiah',
- 'option_b' => 'Tempat-tempat berubahnya huruf hijaiah',
- 'option_c' => 'Tempat-tempat hilangnya huruf hijaiah',
- 'option_d' => 'Tempat-tempat berkumpulnya huruf hijaiah',
- 'correct_option' => 'a',
- 'score' => 20,
- ],
- // Soal 2
- [
- 'id_materi' => 1,
- 'question' => 'Jumlah makhraj-makhraj huruf menurut Ibnu Jazari adalah .....',
- 'option_a' => '15 makhraj',
- 'option_b' => '16 makhraj',
- 'option_c' => '17 makhraj',
- 'option_d' => '18 makhraj',
- 'correct_option' => 'c',
- 'score' => 20,
- ],
- // Soal 3
- [
- 'id_materi' => 1,
- 'question' => 'Salah satu tempat keluarnya huruf adalah Al-Halqi. Halqi artinya .....',
- 'option_a' => 'Lidah',
- 'option_b' => 'Tenggorokan',
- 'option_c' => 'Rongga hidung',
- 'option_d' => 'Bibir',
- 'correct_option' => 'b',
- 'score' => 20,
- ],
- // Soal 4
- [
- 'id_materi' => 1,
- 'question' => 'Huruf ain (ع) merupakan huruf yang keluar dari .....',
- 'option_a' => 'Lidah bagian tengah',
- 'option_b' => 'Tenggorokan bagian tengah',
- 'option_c' => 'Lidah bagian ujung',
- 'option_d' => 'Tenggorokan bagian atas',
- 'correct_option' => 'b',
- 'score' => 20,
- ],
- // Soal 5
- [
- 'id_materi' => 1,
- 'question' => 'Jumlah huruf yang keluar lewat tenggorokan adalah .....',
- 'option_a' => '5 huruf',
- 'option_b' => '6 huruf',
- 'option_c' => '7 huruf',
- 'option_d' => '8 huruf',
- 'correct_option' => 'b',
- 'score' => 20,
- ],
- // Soal 6
- [
- 'id_materi' => 1,
- 'question' => 'Berikut ini merupakan huruf yang keluar lewat tenggorokan, kecuali .....',
- 'option_a' => 'Huruf ghain (غ)',
- 'option_b' => 'Huruf hamzah (ء)',
- 'option_c' => 'Huruf kha (خ)',
- 'option_d' => 'Huruf nun (ن)',
- 'correct_option' => 'd',
- 'score' => 20,
- ],
- // Soal 7
- [
- 'id_materi' => 1,
- 'question' => 'Berikut ini merupakan huruf yang memiliki makhraj sama dengan huruf jim (ج) adalah .....',
- 'option_a' => 'Huruf syin (ش)',
- 'option_b' => 'Huruf fa (ف)',
- 'option_c' => 'Huruf lam (ل)',
- 'option_d' => 'Huruf nun (ن)',
- 'correct_option' => 'a',
- 'score' => 20,
- ],
- // Soal 8
- [
- 'id_materi' => 1,
- 'question' => 'Huruf qaf (ق) merupakan huruf yang keluar dari lidah bagian ....',
- 'option_a' => 'Pangkal lidah',
- 'option_b' => 'Ujung lidah',
- 'option_c' => 'Tengah lidah',
- 'option_d' => 'Tepi lidah',
- 'correct_option' => 'a',
- 'score' => 20,
- ],
- // Soal 9
- [
- 'id_materi' => 1,
- 'question' => 'Jumlah huruf yang keluar lewat lidah adalah .....',
- 'option_a' => '15 huruf',
- 'option_b' => '16 huruf',
- 'option_c' => '17 huruf',
- 'option_d' => '18 huruf',
- 'correct_option' => 'd',
- 'score' => 20,
- ],
- // Soal 10
- [
- 'id_materi' => 1,
- 'question' => 'Jumlah huruf yang keluar lewat bibir adalah .....',
- 'option_a' => '2 huruf',
- 'option_b' => '3 huruf',
- 'option_c' => '4 huruf',
- 'option_d' => '5 huruf',
- 'correct_option' => 'c',
- 'score' => 20,
- ],
- // Soal 11
- [
- 'id_materi' => 1,
- 'question' => 'Berikut ini merupakan kelompok huruf yang keluar dari makhraj yang sama, kecuali .....',
- 'option_a' => 'Huruf ع dan ح',
- 'option_b' => 'Huruf غ dan خ',
- 'option_c' => 'Huruf ل dan ط',
- 'option_d' => 'Huruf ث, ذ, dan ظ',
- 'correct_option' => 'a',
- 'score' => 20,
- ],
- // Soal 12
- [
- 'id_materi' => 1,
- 'question' => 'Berikut ini merupakan huruf yang keluar dari pangkal lidah adalah .....',
- 'option_a' => 'Huruf kaf (ك)',
- 'option_b' => 'Huruf nun (ن)',
- 'option_c' => 'Huruf jim (ج)',
- 'option_d' => 'Huruf shad (ص)',
- 'correct_option' => 'a',
- 'score' => 20,
- ],
- // Soal 13
- [
- 'id_materi' => 1,
- 'question' => 'Berikut ini merupakan huruf yang keluar dari tengah lidah adalah .....',
- 'option_a' => 'Huruf kaf (ك)',
- 'option_b' => 'Huruf nun (ن)',
- 'option_c' => 'Huruf jim (ج)',
- 'option_d' => 'Huruf shad (ص)',
- 'correct_option' => 'c',
- 'score' => 20,
- ],
- // Soal 14
- [
- 'id_materi' => 1,
- 'question' => 'Huruf dhad (ض) merupakan huruf yang keluar dari .....',
- 'option_a' => 'Pangkal lidah',
- 'option_b' => 'Bibir dalam',
- 'option_c' => 'Tepi lidah',
- 'option_d' => 'Ujung lidah',
- 'correct_option' => 'c',
- 'score' => 20,
- ],
- // Soal 15
- [
- 'id_materi' => 1,
- 'question' => 'Dua huruf yang keluar dari makhraj yang sama disebut .....',
- 'option_a' => 'Mutamatsilain',
- 'option_b' => 'Mutajanisain',
- 'option_c' => 'Mutaqaribain',
- 'option_d' => 'Mutabaidain',
- 'correct_option' => 'c',
- 'score' => 20,
- ],
- // Soal 16
- [
- 'id_materi' => 1,
- 'question' => 'Berikut ini adalah huruf-huruf yang keluar dari ujung lidah, kecuali .....',
- 'option_a' => 'Huruf dal (د)',
- 'option_b' => 'Huruf tsa (ث)',
- 'option_c' => 'Huruf ya (ي)',
- 'option_d' => 'Huruf dha (ظ)',
- 'correct_option' => 'c',
- 'score' => 20,
- ],
- // Soal 17
- [
- 'id_materi' => 1,
- 'question' => 'Huruf yang keluar dari al-Jauf adalah .....',
- 'option_a' => 'Alif',
- 'option_b' => 'Ba',
- 'option_c' => 'Ta',
- 'option_d' => 'Tsa',
- 'correct_option' => 'a',
- 'score' => 20,
- ],
- // Soal 18
- [
- 'id_materi' => 1,
- 'question' => 'Berapa jumlah huruf yang keluar dari pangkal lidah? .....',
- 'option_a' => '1 huruf',
- 'option_b' => '2 huruf',
- 'option_c' => '3 huruf',
- 'option_d' => '4 huruf',
- 'correct_option' => 'b',
- 'score' => 20,
- ],
- // Soal 19
- [
- 'id_materi' => 1,
- 'question' => 'Berikut ini manakah pernyataan yang benar? .....',
- 'option_a' => 'Makhraj sin (س) adalah ujung lidah dengan rongga antara gigi atas dan gigi bawah yang lebih dekat dengan gigi bawah',
- 'option_b' => 'Makhraj ta (ت) adalah ujung lidah menempel dengan ujung gigi atas',
- 'option_c' => 'Makhraj tha (ط) adalah ujung lidah menempel dengan ujung gigi atas',
- 'option_d' => 'Makhraj tsa (ث) adalah ujung lidah dengan rongga antara gigi atas dan gigi bawah yang lebih dekat dengan gigi bawah',
- 'correct_option' => 'b',
- 'score' => 20,
- ],
- // Soal 20
- [
- 'id_materi' => 1,
- 'question' => 'Makhraj huruf zay (ز) adalah .....',
- 'option_a' => 'Ujung lidah dengan rongga antara gigi atas dan gigi bawah yang lebih dekat dengan gigi bawah',
- 'option_b' => 'Ujung lidah menempel dengan pangkal gigi atas',
- 'option_c' => 'Ujung lidah menempel dengan ujung gigi atas',
- 'option_d' => 'Tenggorakan bagian tengah',
- 'correct_option' => 'c',
- 'score' => 20,
- ],
+ 'id_materi' => 2,
+ 'question' => 'Ada berapa jumlah huruf yang memiliki sifat Jahr?',
+ 'option_a' => '19',
+ 'option_b' => '20',
+ 'option_c' => '21',
+ 'option_d' => '10',
+ 'correct_option' => 'b',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Ada berapa jumlah huruf yang memiliki sifat Tawassuth?',
+ 'option_a' => '4',
+ 'option_b' => '5',
+ 'option_c' => '10',
+ 'option_d' => '7',
+ 'correct_option' => 'b',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Ada berapa jumlah huruf yang memiliki sifat Tafasysyi?',
+ 'option_a' => '1',
+ 'option_b' => '4',
+ 'option_c' => '5',
+ 'option_d' => '7',
+ 'correct_option' => 'a',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Ada berapa jumlah huruf yang memiliki sifat Qalqalah?',
+ 'option_a' => '1',
+ 'option_b' => '4',
+ 'option_c' => '5',
+ 'option_d' => '7',
+ 'correct_option' => 'b',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Ada berapa jumlah huruf yang memiliki sifat Shafir?',
+ 'option_a' => '1',
+ 'option_b' => '4',
+ 'option_c' => '5',
+ 'option_d' => '3',
+ 'correct_option' => 'd',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Sifat apa yang berlawanan dari sifat Hams?',
+ 'option_a' => 'Syiddah',
+ 'option_b' => 'Tawassuth',
+ 'option_c' => 'Isti’la',
+ 'option_d' => 'Jahr',
+ 'correct_option' => 'd',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Sifat apa yang berlawanan dari sifat Ishmat?',
+ 'option_a' => 'Infitah',
+ 'option_b' => 'Idzlaq',
+ 'option_c' => 'Isti’la',
+ 'option_d' => 'Tawassuth',
+ 'correct_option' => 'b',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Sifat apa yang berlawanan dari sifat Isti’la?',
+ 'option_a' => 'Infitah',
+ 'option_b' => 'Istifal',
+ 'option_c' => 'Lin',
+ 'option_d' => 'Shafir',
+ 'correct_option' => 'b',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Sifat apa yang berlawanan dari sifat Shafir?',
+ 'option_a' => 'Lin',
+ 'option_b' => 'Qalqalah',
+ 'option_c' => 'Hams',
+ 'option_d' => 'Tidak ada',
+ 'correct_option' => 'd',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Sifat apa yang berlawanan dari sifat Infitah?',
+ 'option_a' => 'Ithbaq',
+ 'option_b' => 'Idzlaq',
+ 'option_c' => 'Jahr',
+ 'option_d' => 'Hams',
+ 'correct_option' => 'a',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Berikut ini adalah sifat-sifat yang dimiliki huruf ba (ب) kecuali...',
+ 'option_a' => 'Qalqalah',
+ 'option_b' => 'Jahr',
+ 'option_c' => 'Syiddah',
+ 'option_d' => 'Isti’la',
+ 'correct_option' => 'd',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Berikut ini adalah sifat-sifat yang dimiliki huruf ro (ر) kecuali...',
+ 'option_a' => 'Jahr',
+ 'option_b' => 'Syiddah',
+ 'option_c' => 'Takrir',
+ 'option_d' => 'Infitah',
+ 'correct_option' => 'd',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Berikut ini adalah sifat-sifat yang dimiliki huruf syin (ش) kecuali...',
+ 'option_a' => 'Hams',
+ 'option_b' => 'Rakhawah',
+ 'option_c' => 'Qalqalah',
+ 'option_d' => 'Tafasysyi',
+ 'correct_option' => 'c',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Berikut ini adalah sifat-sifat yang dimiliki huruf ta (ت) kecuali...',
+ 'option_a' => 'Hams',
+ 'option_b' => 'Syiddah',
+ 'option_c' => 'Istifal',
+ 'option_d' => 'Ithbaq',
+ 'correct_option' => 'd',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Berikut ini adalah sifat-sifat yang dimiliki huruf kho (خ) kecuali...',
+ 'option_a' => 'Hams',
+ 'option_b' => 'Rakhawah',
+ 'option_c' => 'Idzlaq',
+ 'option_d' => 'Isti’la',
+ 'correct_option' => 'b',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Manakah huruf berikut yang memiliki sifat Syiddah?',
+ 'option_a' => 'Syin',
+ 'option_b' => 'Qaf',
+ 'option_c' => 'Nun',
+ 'option_d' => 'Lam',
+ 'correct_option' => 'b',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Manakah huruf berikut yang memiliki sifat Inhiraf?',
+ 'option_a' => 'Syin',
+ 'option_b' => 'Qaf',
+ 'option_c' => 'Nun',
+ 'option_d' => 'Lam',
+ 'correct_option' => 'a',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Manakah huruf berikut yang memiliki sifat Istithalah?',
+ 'option_a' => 'Ro',
+ 'option_b' => 'Dhad',
+ 'option_c' => 'Mim',
+ 'option_d' => 'Ain',
+ 'correct_option' => 'b',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Manakah huruf berikut yang memiliki sifat Ghunnah?',
+ 'option_a' => 'Ro',
+ 'option_b' => 'Dhad',
+ 'option_c' => 'Mim',
+ 'option_d' => 'Ain',
+ 'correct_option' => 'c',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Manakah huruf berikut yang memiliki sifat Idzlaq?',
+ 'option_a' => 'Ro',
+ 'option_b' => 'Dhad',
+ 'option_c' => 'Syin',
+ 'option_d' => 'Ain',
+ 'correct_option' => 'c',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Pilih pernyataan benar berikut ini!',
+ 'option_a' => 'Jahr adalah tertahannya aliran nafas ketika mengucapkan huruf',
+ 'option_b' => 'Syiddah adalah mengalirnya suara ketika mengucapkan huruf',
+ 'option_c' => 'Isti’la adalah turunnya pangkal lidah ketika mengucapkan huruf',
+ 'option_d' => 'Tawassuth adalah tertahannya suara ketika mengucapkan huruf',
+ 'correct_option' => 'b',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Huruf ro dan lam memiliki sifat yang hampir sama, namun ada satu sifat yang membedakan keduanya. Sifat itu adalah sifat....',
+ 'option_a' => 'Istithalah',
+ 'option_b' => 'Tafasysyi',
+ 'option_c' => 'Takrir',
+ 'option_d' => 'Lin',
+ 'correct_option' => 'c',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Pilih pernyataan benar berikut ini!',
+ 'option_a' => 'Tawassuth merupakan sifat pertengahan antara Isti’la dan Istifal',
+ 'option_b' => 'Sifat Qalqalah merupakan sifat yang tidak memiliki lawan',
+ 'option_c' => 'Ada 10 huruf yang memiliki sifat Isti’la',
+ 'option_d' => 'Jumlah sifat yang dimiliki huruf hamzah adalah 9 sifat.',
+ 'correct_option' => 'a',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Sifat Inhiraf hanya dimiliki oleh dua huruf, yaitu',
+ 'option_a' => 'Lam dan Ro',
+ 'option_b' => 'Nun dan Mim',
+ 'option_c' => 'Hamzah dan Alif',
+ 'option_d' => 'Sin dan Shad',
+ 'correct_option' => 'a',
+ 'score' => 20,
+],
+[
+ 'id_materi' => 2,
+ 'question' => 'Pilih pernyataan benar berikut ini!',
+ 'option_a' => 'Sifat Takrir adalah bergetarnya bibir ketika mengucapkan huruf',
+ 'option_b' => 'Sifat Ishmat adalah cepatnya suara ketika mengucapkan huruf',
+ 'option_c' => 'Sifat Tafasysyi adalah lawan kata dari sifat Inhiraf',
+ 'option_d' => 'Sifat Lin adalah mengucapkan huruf dengan lentur',
+ 'correct_option' => 'd',
+ 'score' => 20,
+]
+
];
// Insert data soal ke dalam tabel quiz
diff --git a/package.json b/package.json
index 3a76ed0..2055b69 100644
--- a/package.json
+++ b/package.json
@@ -5,8 +5,13 @@
"build": "vite build"
},
"devDependencies": {
+ "@popperjs/core": "^2.11.6",
+ "@vitejs/plugin-vue": "^4.5.0",
"axios": "^1.1.2",
+ "bootstrap": "^5.2.3",
"laravel-vite-plugin": "^0.7.2",
- "vite": "^4.0.0"
+ "sass": "^1.56.1",
+ "vite": "^4.0.0",
+ "vue": "^3.2.37"
}
}
diff --git a/resources/js/app.js b/resources/js/app.js
index e59d6a0..4158f48 100644
--- a/resources/js/app.js
+++ b/resources/js/app.js
@@ -1 +1,39 @@
+/**
+ * First we will load all of this project's JavaScript dependencies which
+ * includes Vue and other libraries. It is a great starting point when
+ * building robust, powerful web applications using Vue and Laravel.
+ */
+
import './bootstrap';
+import { createApp } from 'vue';
+
+/**
+ * Next, we will create a fresh Vue application instance. You may then begin
+ * registering components with the application instance so they are ready
+ * to use in your application's views. An example is included for you.
+ */
+
+const app = createApp({});
+
+import ExampleComponent from './components/ExampleComponent.vue';
+app.component('example-component', ExampleComponent);
+
+/**
+ * The following block of code may be used to automatically register your
+ * Vue components. It will recursively scan this directory for the Vue
+ * components and automatically register them with their "basename".
+ *
+ * Eg. ./components/ExampleComponent.vue ->