23/06/25 update api
This commit is contained in:
parent
08de48498d
commit
d592d6ea43
|
@ -0,0 +1,288 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// app/Http/Controllers/Api/ProgressController.php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Progress;
|
||||||
|
use App\Models\Materi;
|
||||||
|
use App\Models\user;
|
||||||
|
use App\Models\Latihan;
|
||||||
|
use App\Models\SubMateri;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use App\Helpers\ResponseFormatter;
|
||||||
|
|
||||||
|
class ProgressController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// Menambahkan middleware untuk otentikasi dengan token
|
||||||
|
$this->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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\API;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class UploadAudioController extends Controller
|
||||||
|
{
|
||||||
|
public function uploadAudio(Request $request)
|
||||||
|
{
|
||||||
|
print($request->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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,11 +5,13 @@
|
||||||
use App\Helpers\ResponseFormatter;
|
use App\Helpers\ResponseFormatter;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Models\Progress;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class UserControler extends Controller
|
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)
|
public function fetch(Request $request)
|
||||||
{
|
{
|
||||||
return ResponseFormatter::success($request->user(), 'Data berhasil di ambil');
|
return ResponseFormatter::success($request->user(), 'Data berhasil di ambil');
|
||||||
|
@ -102,8 +149,10 @@ public function logout(Request $request)
|
||||||
public function getUsersByRole(Request $request)
|
public function getUsersByRole(Request $request)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// Ambil data user yang memiliki peran 'santri'
|
// Ambil data user yang memiliki peran 'santri' dan urutkan berdasarkan created_at secara descending
|
||||||
$users = User::where('peran', 'santri')->get();
|
$users = User::where('peran', 'santri')
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
|
||||||
// Jika tidak ada user dengan peran 'santri'
|
// Jika tidak ada user dengan peran 'santri'
|
||||||
if ($users->isEmpty()) {
|
if ($users->isEmpty()) {
|
||||||
|
@ -128,6 +177,7 @@ public function getUsersByRole(Request $request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getUserInfoById($id)
|
public function getUserInfoById($id)
|
||||||
{
|
{
|
||||||
// Mencari user berdasarkan 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)
|
// Jika validasi gagal
|
||||||
// {
|
if ($validator->fails()) {
|
||||||
// // Validasi input
|
return response()->json([
|
||||||
// $validator = Validator::make($request->all(), [
|
'status' => 'error',
|
||||||
// 'santri' => 'required|array',
|
'message' => $validator->errors(),
|
||||||
// 'santri.*.nama_lengkap' => 'required|string|max:255',
|
], 400);
|
||||||
// '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
|
// Ambil user yang terautentikasi
|
||||||
// if ($validator->fails()) {
|
$user = Auth::user();
|
||||||
// return ResponseFormatter::error(
|
|
||||||
// null,
|
|
||||||
// 'Validation Error',
|
|
||||||
// 422
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Ambil data santri dari request
|
// Update password pengguna secara manual
|
||||||
// $santriData = $request->input('santri');
|
DB::table('users') // Gunakan query builder untuk update langsung
|
||||||
// $santriInserted = [];
|
->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'
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Foundation\Auth\ConfirmsPasswords;
|
||||||
|
|
||||||
|
class ConfirmPasswordController extends Controller
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Confirm Password Controller
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This controller is responsible for handling password confirmations and
|
||||||
|
| uses a simple trait to include the behavior. You're free to explore
|
||||||
|
| this trait and override any functions that require customization.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
use ConfirmsPasswords;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where to redirect users when the intended url fails.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $redirectTo = '/home';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new controller instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('auth');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
|
|
||||||
|
class ForgotPasswordController extends Controller
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Password Reset Controller
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This controller is responsible for handling password reset emails and
|
||||||
|
| includes a trait which assists in sending these notifications from
|
||||||
|
| your application to your users. Feel free to explore this trait.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
use SendsPasswordResetEmails;
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||||
|
|
||||||
|
class LoginController extends Controller
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Login Controller
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This controller handles authenticating users for the application and
|
||||||
|
| redirecting them to your home screen. The controller uses a trait
|
||||||
|
| to conveniently provide its functionality to your applications.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
use AuthenticatesUsers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where to redirect users after login.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $redirectTo = '/home';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new controller instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('guest')->except('logout');
|
||||||
|
$this->middleware('auth')->only('logout');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Foundation\Auth\RegistersUsers;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
class RegisterController extends Controller
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Register Controller
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This controller handles the registration of new users as well as their
|
||||||
|
| validation and creation. By default this controller uses a trait to
|
||||||
|
| provide this functionality without requiring any additional code.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
use RegistersUsers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where to redirect users after registration.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $redirectTo = '/home';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new controller instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->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']),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||||
|
|
||||||
|
class ResetPasswordController extends Controller
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Password Reset Controller
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This controller is responsible for handling password reset requests
|
||||||
|
| and uses a simple trait to include this behavior. You're free to
|
||||||
|
| explore this trait and override any methods you wish to tweak.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
use ResetsPasswords;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where to redirect users after resetting their password.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $redirectTo = '/home';
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Foundation\Auth\VerifiesEmails;
|
||||||
|
|
||||||
|
class VerificationController extends Controller
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Email Verification Controller
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This controller is responsible for handling email verification for any
|
||||||
|
| user that recently registered with the application. Emails may also
|
||||||
|
| be re-sent if the user didn't receive the original email message.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
use VerifiesEmails;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where to redirect users after verification.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $redirectTo = '/home';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new controller instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('auth');
|
||||||
|
$this->middleware('signed')->only('verify');
|
||||||
|
$this->middleware('throttle:6,1')->only('verify', 'resend');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class HomeController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new controller instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('auth');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the application dashboard.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Contracts\Support\Renderable
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view('home');
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,7 +39,7 @@ class Kernel extends HttpKernel
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||||
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
|
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
],
|
],
|
||||||
|
|
|
@ -20,6 +20,14 @@ class Latihan extends Model
|
||||||
'materi_description',
|
'materi_description',
|
||||||
'correct_audio',
|
'correct_audio',
|
||||||
'recorder_audio',
|
'recorder_audio',
|
||||||
|
'feedback_pengajar',
|
||||||
|
'nilai',
|
||||||
|
'status',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function progress()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Progress::class, 'id_latihan'); // Relasi balik ke Progress
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Progress extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = ['user_id', 'sub_materi_id', 'status', 'nilai','id_latihan',];
|
||||||
|
|
||||||
|
// Relasi ke User
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,9 @@
|
||||||
"guzzlehttp/guzzle": "^7.2",
|
"guzzlehttp/guzzle": "^7.2",
|
||||||
"laravel/framework": "^10.0",
|
"laravel/framework": "^10.0",
|
||||||
"laravel/sanctum": "^3.2",
|
"laravel/sanctum": "^3.2",
|
||||||
"laravel/tinker": "^2.8"
|
"laravel/tinker": "^2.8",
|
||||||
|
"laravel/ui": "^4.6",
|
||||||
|
"phpmailer/phpmailer": "^6.10"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"fakerphp/faker": "^1.9.1",
|
"fakerphp/faker": "^1.9.1",
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "bfe12996eeecb6fdc8713a9fd9d431f8",
|
"content-hash": "1787b3b8dd905d7a2fb5758e07bf55a0",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
|
@ -1512,6 +1512,69 @@
|
||||||
},
|
},
|
||||||
"time": "2025-01-27T14:24:01+00:00"
|
"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",
|
"name": "league/commonmark",
|
||||||
"version": "2.6.1",
|
"version": "2.6.1",
|
||||||
|
@ -2390,6 +2453,87 @@
|
||||||
],
|
],
|
||||||
"time": "2024-11-21T10:36:35+00:00"
|
"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",
|
"name": "phpoption/phpoption",
|
||||||
"version": "1.9.3",
|
"version": "1.9.3",
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('password_resets', function (Blueprint $table) {
|
||||||
|
$table->string('email')->index();
|
||||||
|
$table->string('token');
|
||||||
|
$table->timestamp('created_at')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('password_resets');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('progress', function (Blueprint $table) {
|
||||||
|
$table->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');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('latihan', function (Blueprint $table) {
|
||||||
|
$table->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');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('progress', function (Blueprint $table) {
|
||||||
|
$table->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');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('progress', function (Blueprint $table) {
|
||||||
|
$table->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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('progress', function (Blueprint $table) {
|
||||||
|
$table->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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -15,226 +15,257 @@ class QuizTableSeeder extends Seeder
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
$questions = [
|
$questions = [
|
||||||
// Soal 1
|
|
||||||
[
|
[
|
||||||
'id_materi' => 1,
|
'id_materi' => 2,
|
||||||
'question' => 'Makharijul Huruf artinya .....',
|
'question' => 'Ada berapa jumlah huruf yang memiliki sifat Jahr?',
|
||||||
'option_a' => 'Tempat-tempat keluarnya huruf hijaiah',
|
'option_a' => '19',
|
||||||
'option_b' => 'Tempat-tempat berubahnya huruf hijaiah',
|
'option_b' => '20',
|
||||||
'option_c' => 'Tempat-tempat hilangnya huruf hijaiah',
|
'option_c' => '21',
|
||||||
'option_d' => 'Tempat-tempat berkumpulnya huruf hijaiah',
|
'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',
|
'correct_option' => 'a',
|
||||||
'score' => 20,
|
'score' => 20,
|
||||||
],
|
],
|
||||||
// Soal 2
|
[
|
||||||
[
|
'id_materi' => 2,
|
||||||
'id_materi' => 1,
|
'question' => 'Ada berapa jumlah huruf yang memiliki sifat Qalqalah?',
|
||||||
'question' => 'Jumlah makhraj-makhraj huruf menurut Ibnu Jazari adalah .....',
|
'option_a' => '1',
|
||||||
'option_a' => '15 makhraj',
|
'option_b' => '4',
|
||||||
'option_b' => '16 makhraj',
|
'option_c' => '5',
|
||||||
'option_c' => '17 makhraj',
|
'option_d' => '7',
|
||||||
'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',
|
'correct_option' => 'b',
|
||||||
'score' => 20,
|
'score' => 20,
|
||||||
],
|
],
|
||||||
// Soal 4
|
[
|
||||||
[
|
'id_materi' => 2,
|
||||||
'id_materi' => 1,
|
'question' => 'Ada berapa jumlah huruf yang memiliki sifat Shafir?',
|
||||||
'question' => 'Huruf ain (ع) merupakan huruf yang keluar dari .....',
|
'option_a' => '1',
|
||||||
'option_a' => 'Lidah bagian tengah',
|
'option_b' => '4',
|
||||||
'option_b' => 'Tenggorokan bagian tengah',
|
'option_c' => '5',
|
||||||
'option_c' => 'Lidah bagian ujung',
|
'option_d' => '3',
|
||||||
'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',
|
'correct_option' => 'd',
|
||||||
'score' => 20,
|
'score' => 20,
|
||||||
],
|
],
|
||||||
// Soal 7
|
[
|
||||||
[
|
'id_materi' => 2,
|
||||||
'id_materi' => 1,
|
'question' => 'Sifat apa yang berlawanan dari sifat Hams?',
|
||||||
'question' => 'Berikut ini merupakan huruf yang memiliki makhraj sama dengan huruf jim (ج) adalah .....',
|
'option_a' => 'Syiddah',
|
||||||
'option_a' => 'Huruf syin (ش)',
|
'option_b' => 'Tawassuth',
|
||||||
'option_b' => 'Huruf fa (ف)',
|
'option_c' => 'Isti’la',
|
||||||
'option_c' => 'Huruf lam (ل)',
|
'option_d' => 'Jahr',
|
||||||
'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',
|
'correct_option' => 'd',
|
||||||
'score' => 20,
|
'score' => 20,
|
||||||
],
|
],
|
||||||
// Soal 10
|
[
|
||||||
[
|
'id_materi' => 2,
|
||||||
'id_materi' => 1,
|
'question' => 'Sifat apa yang berlawanan dari sifat Ishmat?',
|
||||||
'question' => 'Jumlah huruf yang keluar lewat bibir adalah .....',
|
'option_a' => 'Infitah',
|
||||||
'option_a' => '2 huruf',
|
'option_b' => 'Idzlaq',
|
||||||
'option_b' => '3 huruf',
|
'option_c' => 'Isti’la',
|
||||||
'option_c' => '4 huruf',
|
'option_d' => 'Tawassuth',
|
||||||
'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',
|
'correct_option' => 'b',
|
||||||
'score' => 20,
|
'score' => 20,
|
||||||
],
|
],
|
||||||
// Soal 19
|
[
|
||||||
[
|
'id_materi' => 2,
|
||||||
'id_materi' => 1,
|
'question' => 'Sifat apa yang berlawanan dari sifat Isti’la?',
|
||||||
'question' => 'Berikut ini manakah pernyataan yang benar? .....',
|
'option_a' => 'Infitah',
|
||||||
'option_a' => 'Makhraj sin (س) adalah ujung lidah dengan rongga antara gigi atas dan gigi bawah yang lebih dekat dengan gigi bawah',
|
'option_b' => 'Istifal',
|
||||||
'option_b' => 'Makhraj ta (ت) adalah ujung lidah menempel dengan ujung gigi atas',
|
'option_c' => 'Lin',
|
||||||
'option_c' => 'Makhraj tha (ط) adalah ujung lidah menempel dengan ujung gigi atas',
|
'option_d' => 'Shafir',
|
||||||
'option_d' => 'Makhraj tsa (ث) adalah ujung lidah dengan rongga antara gigi atas dan gigi bawah yang lebih dekat dengan gigi bawah',
|
|
||||||
'correct_option' => 'b',
|
'correct_option' => 'b',
|
||||||
'score' => 20,
|
'score' => 20,
|
||||||
],
|
],
|
||||||
// Soal 20
|
[
|
||||||
[
|
'id_materi' => 2,
|
||||||
'id_materi' => 1,
|
'question' => 'Sifat apa yang berlawanan dari sifat Shafir?',
|
||||||
'question' => 'Makhraj huruf zay (ز) adalah .....',
|
'option_a' => 'Lin',
|
||||||
'option_a' => 'Ujung lidah dengan rongga antara gigi atas dan gigi bawah yang lebih dekat dengan gigi bawah',
|
'option_b' => 'Qalqalah',
|
||||||
'option_b' => 'Ujung lidah menempel dengan pangkal gigi atas',
|
'option_c' => 'Hams',
|
||||||
'option_c' => 'Ujung lidah menempel dengan ujung gigi atas',
|
'option_d' => 'Tidak ada',
|
||||||
'option_d' => 'Tenggorakan bagian tengah',
|
'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',
|
'correct_option' => 'c',
|
||||||
'score' => 20,
|
'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
|
// Insert data soal ke dalam tabel quiz
|
||||||
|
|
|
@ -5,8 +5,13 @@
|
||||||
"build": "vite build"
|
"build": "vite build"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@popperjs/core": "^2.11.6",
|
||||||
|
"@vitejs/plugin-vue": "^4.5.0",
|
||||||
"axios": "^1.1.2",
|
"axios": "^1.1.2",
|
||||||
|
"bootstrap": "^5.2.3",
|
||||||
"laravel-vite-plugin": "^0.7.2",
|
"laravel-vite-plugin": "^0.7.2",
|
||||||
"vite": "^4.0.0"
|
"sass": "^1.56.1",
|
||||||
|
"vite": "^4.0.0",
|
||||||
|
"vue": "^3.2.37"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 './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 -> <example-component></example-component>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Object.entries(import.meta.glob('./**/*.vue', { eager: true })).forEach(([path, definition]) => {
|
||||||
|
// app.component(path.split('/').pop().replace(/\.\w+$/, ''), definition.default);
|
||||||
|
// });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finally, we will attach the application instance to a HTML element with
|
||||||
|
* an "id" attribute of "app". This element is included with the "auth"
|
||||||
|
* scaffolding. Otherwise, you will need to add an element yourself.
|
||||||
|
*/
|
||||||
|
|
||||||
|
app.mount('#app');
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'bootstrap';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We'll load the axios HTTP library which allows us to easily issue requests
|
* We'll load the axios HTTP library which allows us to easily issue requests
|
||||||
* to our Laravel back-end. This library automatically handles sending the
|
* to our Laravel back-end. This library automatically handles sending the
|
||||||
|
@ -24,7 +26,7 @@ window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||||
// broadcaster: 'pusher',
|
// broadcaster: 'pusher',
|
||||||
// key: import.meta.env.VITE_PUSHER_APP_KEY,
|
// key: import.meta.env.VITE_PUSHER_APP_KEY,
|
||||||
// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
|
// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
|
||||||
// wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
|
// wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
|
||||||
// wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
|
// wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
|
||||||
// wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
|
// wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
|
||||||
// forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
|
// forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Example Component</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
I'm an example component.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
mounted() {
|
||||||
|
console.log('Component mounted.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Body
|
||||||
|
$body-bg: #f8fafc;
|
||||||
|
|
||||||
|
// Typography
|
||||||
|
$font-family-sans-serif: 'Nunito', sans-serif;
|
||||||
|
$font-size-base: 0.9rem;
|
||||||
|
$line-height-base: 1.6;
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Fonts
|
||||||
|
@import url('https://fonts.bunny.net/css?family=Nunito');
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
@import 'variables';
|
||||||
|
|
||||||
|
// Bootstrap
|
||||||
|
@import 'bootstrap/scss/bootstrap';
|
|
@ -0,0 +1,73 @@
|
||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">{{ __('Login') }}</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="POST" action="{{ route('login') }}">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
|
||||||
|
|
||||||
|
@error('email')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="password" class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
|
||||||
|
|
||||||
|
@error('password')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-6 offset-md-4">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
|
||||||
|
|
||||||
|
<label class="form-check-label" for="remember">
|
||||||
|
{{ __('Remember Me') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-0">
|
||||||
|
<div class="col-md-8 offset-md-4">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
{{ __('Login') }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
@if (Route::has('password.request'))
|
||||||
|
<a class="btn btn-link" href="{{ route('password.request') }}">
|
||||||
|
{{ __('Forgot Your Password?') }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -0,0 +1,49 @@
|
||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">{{ __('Confirm Password') }}</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
{{ __('Please confirm your password before continuing.') }}
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('password.confirm') }}">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="password" class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
|
||||||
|
|
||||||
|
@error('password')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-0">
|
||||||
|
<div class="col-md-8 offset-md-4">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
{{ __('Confirm Password') }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
@if (Route::has('password.request'))
|
||||||
|
<a class="btn btn-link" href="{{ route('password.request') }}">
|
||||||
|
{{ __('Forgot Your Password?') }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -0,0 +1,47 @@
|
||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">{{ __('Reset Password') }}</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
@if (session('status'))
|
||||||
|
<div class="alert alert-success" role="alert">
|
||||||
|
{{ session('status') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('password.email') }}">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
|
||||||
|
|
||||||
|
@error('email')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-0">
|
||||||
|
<div class="col-md-6 offset-md-4">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
{{ __('Send Password Reset Link') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -0,0 +1,65 @@
|
||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">{{ __('Reset Password') }}</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="POST" action="{{ route('password.update') }}">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<input type="hidden" name="token" value="{{ $token }}">
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ $email ?? old('email') }}" required autocomplete="email" autofocus>
|
||||||
|
|
||||||
|
@error('email')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="password" class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
|
||||||
|
|
||||||
|
@error('password')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="password-confirm" class="col-md-4 col-form-label text-md-end">{{ __('Confirm Password') }}</label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-0">
|
||||||
|
<div class="col-md-6 offset-md-4">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
{{ __('Reset Password') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -0,0 +1,77 @@
|
||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">{{ __('Register') }}</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="POST" action="{{ route('register') }}">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="name" class="col-md-4 col-form-label text-md-end">{{ __('Name') }}</label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>
|
||||||
|
|
||||||
|
@error('name')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">
|
||||||
|
|
||||||
|
@error('email')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="password" class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
|
||||||
|
|
||||||
|
@error('password')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="password-confirm" class="col-md-4 col-form-label text-md-end">{{ __('Confirm Password') }}</label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-0">
|
||||||
|
<div class="col-md-6 offset-md-4">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
{{ __('Register') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -0,0 +1,28 @@
|
||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">{{ __('Verify Your Email Address') }}</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
@if (session('resent'))
|
||||||
|
<div class="alert alert-success" role="alert">
|
||||||
|
{{ __('A fresh verification link has been sent to your email address.') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
{{ __('Before proceeding, please check your email for a verification link.') }}
|
||||||
|
{{ __('If you did not receive the email') }},
|
||||||
|
<form class="d-inline" method="POST" action="{{ route('verification.resend') }}">
|
||||||
|
@csrf
|
||||||
|
<button type="submit" class="btn btn-link p-0 m-0 align-baseline">{{ __('click here to request another') }}</button>.
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -0,0 +1,23 @@
|
||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">{{ __('Dashboard') }}</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
@if (session('status'))
|
||||||
|
<div class="alert alert-success" role="alert">
|
||||||
|
{{ session('status') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
{{ __('You are logged in!') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -0,0 +1,80 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<!-- CSRF Token -->
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
|
||||||
|
<title>{{ config('app.name', 'Laravel') }}</title>
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="dns-prefetch" href="//fonts.bunny.net">
|
||||||
|
<link href="https://fonts.bunny.net/css?family=Nunito" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Scripts -->
|
||||||
|
@vite(['resources/sass/app.scss', 'resources/js/app.js'])
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" href="{{ url('/') }}">
|
||||||
|
{{ config('app.name', 'Laravel') }}
|
||||||
|
</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
|
<!-- Left Side Of Navbar -->
|
||||||
|
<ul class="navbar-nav me-auto">
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Right Side Of Navbar -->
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<!-- Authentication Links -->
|
||||||
|
@guest
|
||||||
|
@if (Route::has('login'))
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
|
||||||
|
</li>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if (Route::has('register'))
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
|
||||||
|
</li>
|
||||||
|
@endif
|
||||||
|
@else
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
|
||||||
|
{{ Auth::user()->name }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
|
||||||
|
<a class="dropdown-item" href="{{ route('logout') }}"
|
||||||
|
onclick="event.preventDefault();
|
||||||
|
document.getElementById('logout-form').submit();">
|
||||||
|
{{ __('Logout') }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
|
||||||
|
@csrf
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
@endguest
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main class="py-4">
|
||||||
|
@yield('content')
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,13 +1,16 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Http\Controllers\API\UserControler;
|
use App\Http\Controllers\API\UserControler;
|
||||||
|
use App\Http\Controllers\API\ChangePassController;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use App\Http\Controllers\API\MateriControler;
|
use App\Http\Controllers\API\MateriControler;
|
||||||
|
use App\Http\Controllers\API\UploadAudioController;
|
||||||
use App\Http\Controllers\API\KategoryController;
|
use App\Http\Controllers\API\KategoryController;
|
||||||
use App\Http\Controllers\API\SubMateriControler;
|
use App\Http\Controllers\API\SubMateriControler;
|
||||||
use App\Http\Controllers\API\LatihanControler;
|
use App\Http\Controllers\API\LatihanControler;
|
||||||
use App\Http\Controllers\QuizController;
|
use App\Http\Controllers\QuizController;
|
||||||
|
use App\Http\Controllers\API\ProgressController;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
@ -23,10 +26,12 @@
|
||||||
|
|
||||||
Route::post('register', [UserControler::class, 'register']);
|
Route::post('register', [UserControler::class, 'register']);
|
||||||
Route::post('login', [UserControler::class, 'login']);
|
Route::post('login', [UserControler::class, 'login']);
|
||||||
|
Route::post('loginWithTelp', [UserControler::class, 'loginWithTelp']);
|
||||||
|
|
||||||
Route::middleware('auth:sanctum')->group(function () {
|
Route::middleware('auth:sanctum')->group(function () {
|
||||||
Route::get('user', [UserControler::class, 'fetch']);
|
Route::get('user', [UserControler::class, 'fetch']);
|
||||||
Route::post('logout', [UserControler::class, 'logout']);
|
Route::post('logout', [UserControler::class, 'logout']);
|
||||||
|
Route::post('/change_password', [UserControler::class, 'changePassword']);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('/materi', [MateriControler::class, 'getMateri']);
|
Route::get('/materi', [MateriControler::class, 'getMateri']);
|
||||||
|
@ -53,5 +58,27 @@
|
||||||
Route::put('/updateUser/{id}', [UserControler::class, 'updateUserById']);
|
Route::put('/updateUser/{id}', [UserControler::class, 'updateUserById']);
|
||||||
|
|
||||||
Route::post('/tambahSantri', [UserControler::class, 'tambahSantri']);
|
Route::post('/tambahSantri', [UserControler::class, 'tambahSantri']);
|
||||||
|
|
||||||
|
Route::get('/userByToken', [UserControler::class, 'getUserInfoByToken']);
|
||||||
|
|
||||||
|
// Memperbarui data pengguna berdasarkan token
|
||||||
|
Route::post('/user/updateBytoken', [UserControler::class, 'updateUserByToken']);
|
||||||
|
Route::post('/importSantri', [UserControler::class, 'importSantri']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::middleware('auth:sanctum')->group(function () {
|
||||||
|
Route::get('/materi/{materiId}/progress', [ProgressController::class, 'getMateriProgress']);
|
||||||
|
Route::post('/progress/{subMateriId}/update', [ProgressController::class, 'updateProgress']);
|
||||||
|
Route::get('/progress/{subMateriId}/status', [ProgressController::class, 'getProgressBySubMateri']);
|
||||||
|
Route::get('/progres/presentase', [ProgressController::class, 'getProgressPercentage']);
|
||||||
|
Route::get('/progres/{user_id}', [ProgressController::class, 'getProgressPercentageById']);
|
||||||
|
Route::put('latihan/{id_latihan}/saverecord', [ProgressController::class, 'saveRecordedAudioName']);
|
||||||
|
Route::post('progress/{submateri_id}/save', [ProgressController::class, 'saveProgress']);
|
||||||
|
Route::get('/hasil-penilaian/{submateri_id}', [ProgressController::class, 'getHasilPenilaianByUserAndSubMateri']);
|
||||||
|
Route::post('/upload_audio', [UploadAudioController::class, 'uploadAudio']);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Route::get('/users/progres', [UserControler::class, 'getUserProgres']);
|
||||||
|
|
||||||
|
|
|
@ -16,3 +16,7 @@
|
||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
return view('welcome');
|
return view('welcome');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Auth::routes();
|
||||||
|
|
||||||
|
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
|
||||||
|
|
|
@ -1,11 +1,28 @@
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import laravel from 'laravel-vite-plugin';
|
import laravel from 'laravel-vite-plugin';
|
||||||
|
import vue from '@vitejs/plugin-vue';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
laravel({
|
laravel({
|
||||||
input: ['resources/css/app.css', 'resources/js/app.js'],
|
input: [
|
||||||
|
'resources/sass/app.scss',
|
||||||
|
'resources/js/app.js',
|
||||||
|
],
|
||||||
refresh: true,
|
refresh: true,
|
||||||
}),
|
}),
|
||||||
|
vue({
|
||||||
|
template: {
|
||||||
|
transformAssetUrls: {
|
||||||
|
base: null,
|
||||||
|
includeAbsolute: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
vue: 'vue/dist/vue.esm-bundler.js',
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue