update daftar pengguna
This commit is contained in:
@@ -1,56 +1,286 @@
|
||||
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasAddUser" aria-labelledby="offcanvasAddUserLabel">
|
||||
<div class="offcanvas-header border-bottom">
|
||||
<h5 id="offcanvasAddUserLabel" class="offcanvas-title">Tambah User Baru</h5>
|
||||
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body mx-0 flex-grow-0 p-6 h-100">
|
||||
<form class="add-new-user pt-0" id="formAddUser" action="{{ route('users.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="mb-4">
|
||||
<label class="form-label" for="add-user-fullname">Nama Lengkap</label>
|
||||
<input type="text" class="form-control" id="add-user-fullname" placeholder="John Doe" name="name" required />
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label" for="add-user-username">Nama akun</label>
|
||||
<input type="text" class="form-control" id="add-user-username" placeholder="john" name="username" required />
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label" for="add-user-email">Email</label>
|
||||
<input type="email" id="add-user-email" class="form-control" placeholder="john.doe@example.com" name="email" required />
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label" for="add-user-role">User Role</label>
|
||||
<select id="add-user-role" class="form-select" name="role" required>
|
||||
<option value="">Pilih Role</option>
|
||||
@foreach($roles as $roleEnum)
|
||||
<option value="{{ $roleEnum->value }}">{{ ucfirst(str_replace('_', ' ', $roleEnum->value)) }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-4 form-password-toggle">
|
||||
<label class="form-label" for="add-user-password">Password</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<input type="password" id="add-user-password" name="password" class="form-control" placeholder="············" required />
|
||||
<span class="input-group-text cursor-pointer" onclick="togglePassword(this)">
|
||||
<i class="ti tabler-eye-off"></i>
|
||||
</span>
|
||||
@extends('layout.main')
|
||||
|
||||
@section('content')
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
<div class="card">
|
||||
<div class="card-header border-bottom mb-4 d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0">Tambah User Baru</h5>
|
||||
<a href="{{ route('users.index') }}" class="btn btn-sm btn-label-secondary">
|
||||
<i class="ti tabler-arrow-left me-1"></i> Kembali
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
@if(session('error'))
|
||||
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||
{{ session('error') }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4 form-password-toggle">
|
||||
<label class="form-label" for="add-user-password-confirm">Konfirmasi Password</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<input type="password" id="add-user-password-confirm" name="password_confirmation" class="form-control" placeholder="············" required />
|
||||
<span class="input-group-text cursor-pointer" onclick="togglePassword(this)">
|
||||
<i class="ti tabler-eye-off"></i>
|
||||
</span>
|
||||
@endif
|
||||
|
||||
<form id="formAddUser" action="{{ route('users.store') }}" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
|
||||
<h6 class="mb-3">Informasi Akun</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4 form-control-validation">
|
||||
<label class="form-label" for="add-profile-nama">Nama Lengkap<span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control @error('nama') is-invalid @enderror" id="add-profile-nama" name="nama" value="{{ old('nama') }}" />
|
||||
@error('nama')<div class="invalid-feedback">{{ $message }}</div>@enderror
|
||||
</div>
|
||||
<div class="col-md-6 mb-4 form-control-validation">
|
||||
<label class="form-label" for="add-profile-email">Email<span class="text-danger">*</span></label>
|
||||
<input type="email" class="form-control @error('email') is-invalid @enderror" id="add-profile-email" name="email" value="{{ old('email') }}" />
|
||||
@error('email')<div class="invalid-feedback">{{ $message }}</div>@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 d-flex gap-3">
|
||||
<button type="submit" class="btn btn-primary flex-grow-1 data-submit">Simpan</button>
|
||||
<button type="reset" class="btn btn-label-secondary flex-grow-1" data-bs-dismiss="offcanvas">Batal</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4 form-control-validation">
|
||||
<label class="form-label" for="add-profile-username">Nama Akun<span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control @error('username') is-invalid @enderror" id="add-profile-username" name="username" value="{{ old('username') }}" />
|
||||
@error('username')<div class="invalid-feedback">{{ $message }}</div>@enderror
|
||||
</div>
|
||||
<div class="col-md-6 mb-4 form-control-validation">
|
||||
<label class="form-label" for="add-profile-role">Role<span class="text-danger">*</span></label>
|
||||
<select id="add-profile-role" name="role" class="select2 form-select @error('role') is-invalid @enderror" data-placeholder="Pilih Role">
|
||||
<option value="">Pilih Role</option>
|
||||
@foreach($roles as $roleEnum)
|
||||
<option value="{{ $roleEnum->value }}" {{ old('role', \App\Enums\Role::PETANI->value) === $roleEnum->value ? 'selected' : '' }}>
|
||||
{{ ucfirst(str_replace('_', ' ', $roleEnum->value)) }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('role')<div class="invalid-feedback d-block">{{ $message }}</div>@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4 form-control-validation">
|
||||
<label class="form-label" for="add-profile-telepon">No. Telepon<span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control @error('telepon') is-invalid @enderror" id="add-profile-telepon" name="telepon" value="{{ old('telepon') }}" />
|
||||
@error('telepon')<div class="invalid-feedback">{{ $message }}</div>@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4 form-control-validation form-password-toggle">
|
||||
<label class="form-label" for="add-profile-password">Password<span class="text-danger">*</span></label>
|
||||
<div class="input-group input-group-merge">
|
||||
<input type="password" id="add-profile-password" name="password" class="form-control @error('password') is-invalid @enderror" />
|
||||
<button type="button" class="input-group-text cursor-pointer password-toggle" aria-label="Lihat password">
|
||||
<i class="ti tabler-eye-off"></i>
|
||||
</button>
|
||||
</div>
|
||||
@error('password')<div class="invalid-feedback d-block">{{ $message }}</div>@enderror
|
||||
</div>
|
||||
<div class="col-md-6 mb-4 form-control-validation form-password-toggle">
|
||||
<label class="form-label" for="add-profile-password-confirm">Konfirmasi Password<span class="text-danger">*</span></label>
|
||||
<div class="input-group input-group-merge">
|
||||
<input type="password" id="add-profile-password-confirm" name="password_confirmation" class="form-control" />
|
||||
<button type="button" class="input-group-text cursor-pointer password-toggle" aria-label="Lihat konfirmasi password">
|
||||
<i class="ti tabler-eye-off"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
<h6 class="mb-3">Lokasi & Alamat</h6>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<label class="form-label" for="add-profile-provinsi">Provinsi</label>
|
||||
<select id="add-profile-provinsi" class="select2 form-select" data-placeholder="Pilih Provinsi">
|
||||
<option value="">Pilih Provinsi</option>
|
||||
@foreach($provinsi as $prov)
|
||||
<option value="{{ $prov->id }}">{{ $prov->nama }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-4">
|
||||
<label class="form-label" for="add-profile-kabupaten">Kabupaten/Kota</label>
|
||||
<select id="add-profile-kabupaten" class="select2 form-select" data-placeholder="Pilih Kabupaten/Kota">
|
||||
<option value="">Pilih Kabupaten/Kota</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<label class="form-label" for="add-profile-kecamatan">Kecamatan</label>
|
||||
<select id="add-profile-kecamatan" class="select2 form-select" data-placeholder="Pilih Kecamatan">
|
||||
<option value="">Pilih Kecamatan</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-4 form-control-validation">
|
||||
<label class="form-label" for="add-profile-desa">Desa/Kelurahan<span class="text-danger">*</span></label>
|
||||
<select id="add-profile-desa" name="desa_kelurahan_id" class="select2 form-select @error('desa_kelurahan_id') is-invalid @enderror" data-placeholder="Pilih Desa/Kelurahan">
|
||||
<option value="">Pilih Desa/Kelurahan</option>
|
||||
</select>
|
||||
@error('desa_kelurahan_id')<div class="invalid-feedback d-block">{{ $message }}</div>@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label" for="add-profile-alamat">Alamat Lengkap</label>
|
||||
<textarea class="form-control" id="add-profile-alamat" name="alamat" rows="2">{{ old('alamat') }}</textarea>
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
<h6 class="mb-3">Dokumen Pribadi</h6>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4 form-control-validation">
|
||||
<label class="form-label" for="add-profile-no-ktp">NIK (KTP)</label>
|
||||
<input type="text" class="form-control @error('ktp') is-invalid @enderror" id="add-profile-no-ktp" name="ktp" value="{{ old('ktp') }}" />
|
||||
@error('ktp')<div class="invalid-feedback">{{ $message }}</div>@enderror
|
||||
</div>
|
||||
<div class="col-md-6 mb-4 form-control-validation">
|
||||
<label class="form-label" for="add-profile-no-kk">No. KK</label>
|
||||
<input type="text" class="form-control @error('kk') is-invalid @enderror" id="add-profile-no-kk" name="kk" value="{{ old('kk') }}" />
|
||||
@error('kk')<div class="invalid-feedback">{{ $message }}</div>@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4 form-control-validation">
|
||||
<label class="form-label" for="add-profile-file-ktp">File KTP</label>
|
||||
<input type="file" class="form-control @error('file_ktp') is-invalid @enderror" id="add-profile-file-ktp" name="file_ktp" accept="image/*,.pdf" />
|
||||
@error('file_ktp')<div class="invalid-feedback">{{ $message }}</div>@enderror
|
||||
<div id="add-preview-container-ktp" class="mt-3 d-none">
|
||||
<img id="add-preview-image-ktp" src="" alt="Preview KTP" class="img-thumbnail d-none" style="width: 100%; max-height: 250px; object-fit: contain; background-color: #f8f9fa;">
|
||||
<div id="add-preview-pdf-ktp" class="badge bg-label-danger p-2 w-100 d-none"><i class="ti tabler-file-type-pdf ti-sm me-1"></i> Dokumen PDF (Baru Terpilih)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-4 form-control-validation">
|
||||
<label class="form-label" for="add-profile-file-kk">File KK</label>
|
||||
<input type="file" class="form-control @error('file_kk') is-invalid @enderror" id="add-profile-file-kk" name="file_kk" accept="image/*,.pdf" />
|
||||
@error('file_kk')<div class="invalid-feedback">{{ $message }}</div>@enderror
|
||||
<div id="add-preview-container-kk" class="mt-3 d-none">
|
||||
<img id="add-preview-image-kk" src="" alt="Preview KK" class="img-thumbnail d-none" style="width: 100%; max-height: 250px; object-fit: contain; background-color: #f8f9fa;">
|
||||
<div id="add-preview-pdf-kk" class="badge bg-label-danger p-2 w-100 d-none"><i class="ti tabler-file-type-pdf ti-sm me-1"></i> Dokumen PDF (Baru Terpilih)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-end">
|
||||
<a href="{{ route('users.index') }}" class="btn btn-label-secondary me-2">Batal</a>
|
||||
<button type="submit" class="btn btn-primary">Simpan Perubahan</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
'use strict';
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
|
||||
$(document).on('click', '.password-toggle', function () {
|
||||
const input = this.closest('.input-group').querySelector('input');
|
||||
const icon = this.querySelector('i');
|
||||
const isHidden = input.type === 'password';
|
||||
|
||||
input.type = isHidden ? 'text' : 'password';
|
||||
icon.className = isHidden ? 'ti tabler-eye' : 'ti tabler-eye-off';
|
||||
this.setAttribute('aria-label', isHidden ? 'Sembunyikan password' : 'Lihat password');
|
||||
});
|
||||
|
||||
function handleFilePreview(inputId, containerId, imageId, pdfId) {
|
||||
$(`#${inputId}`).on('change', function(event) {
|
||||
const file = event.target.files[0];
|
||||
const $container = $(`#${containerId}`);
|
||||
const $image = $(`#${imageId}`);
|
||||
const $pdf = $(`#${pdfId}`);
|
||||
|
||||
if (!file) {
|
||||
$container.addClass('d-none');
|
||||
return;
|
||||
}
|
||||
|
||||
$container.removeClass('d-none');
|
||||
if (file.type.match('image.*')) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
$image.attr('src', e.target.result).removeClass('d-none');
|
||||
$pdf.addClass('d-none');
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else if (file.type === 'application/pdf') {
|
||||
$image.addClass('d-none').attr('src', '');
|
||||
$pdf.removeClass('d-none');
|
||||
} else {
|
||||
$container.addClass('d-none');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setupCascadingDropdown() {
|
||||
$('#add-profile-provinsi').on('change', function () {
|
||||
const provinsiId = $(this).val();
|
||||
const $kabupaten = $('#add-profile-kabupaten');
|
||||
const $kecamatan = $('#add-profile-kecamatan');
|
||||
const $desa = $('#add-profile-desa');
|
||||
|
||||
$kabupaten.empty().append('<option value="">Pilih Kabupaten/Kota</option>').trigger('change');
|
||||
$kecamatan.empty().append('<option value="">Pilih Kecamatan</option>').trigger('change');
|
||||
$desa.empty().append('<option value="">Pilih Desa/Kelurahan</option>').trigger('change');
|
||||
|
||||
if (provinsiId) {
|
||||
$.get(`/kabupatenkotabyprovinsi/${provinsiId}`, function (res) {
|
||||
const dataList = Array.isArray(res) ? res : (res.data || []);
|
||||
$.each(dataList, function (key, val) {
|
||||
$kabupaten.append(`<option value="${val.id}">${val.nama}</option>`);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#add-profile-kabupaten').on('change', function () {
|
||||
const kabupatenId = $(this).val();
|
||||
const $kecamatan = $('#add-profile-kecamatan');
|
||||
const $desa = $('#add-profile-desa');
|
||||
|
||||
$kecamatan.empty().append('<option value="">Pilih Kecamatan</option>').trigger('change');
|
||||
$desa.empty().append('<option value="">Pilih Desa/Kelurahan</option>').trigger('change');
|
||||
|
||||
if (kabupatenId) {
|
||||
$.get(`/kecamatanbykabupatenkota/${kabupatenId}`, function (res) {
|
||||
const dataList = Array.isArray(res) ? res : (res.data || []);
|
||||
$.each(dataList, function (key, val) {
|
||||
$kecamatan.append(`<option value="${val.id}">${val.nama}</option>`);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#add-profile-kecamatan').on('change', function () {
|
||||
const kecamatanId = $(this).val();
|
||||
const $desa = $('#add-profile-desa');
|
||||
|
||||
$desa.empty().append('<option value="">Pilih Desa/Kelurahan</option>').trigger('change');
|
||||
|
||||
if (kecamatanId) {
|
||||
$.get(`/desakelurahanbykecamatan/${kecamatanId}`, function (res) {
|
||||
const dataList = Array.isArray(res) ? res : (res.data || []);
|
||||
$.each(dataList, function (key, val) {
|
||||
$desa.append(`<option value="${val.id}">${val.nama}</option>`);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleFilePreview('add-profile-file-ktp', 'add-preview-container-ktp', 'add-preview-image-ktp', 'add-preview-pdf-ktp');
|
||||
handleFilePreview('add-profile-file-kk', 'add-preview-container-kk', 'add-preview-image-kk', 'add-preview-pdf-kk');
|
||||
setupCascadingDropdown();
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@@ -85,9 +85,9 @@
|
||||
<div class="card">
|
||||
<div class="card-header border-bottom d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0">Daftar Pengguna</h5>
|
||||
<button class="btn btn-sm btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasAddUser">
|
||||
<i class="ti tabler-plus me-1"></i> Add New User
|
||||
</button>
|
||||
<a class="btn btn-sm btn-primary" href="{{ route('users.create') }}">
|
||||
<i class="ti tabler-plus me-1"></i> Tambah User Baru
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<form method="GET" action="{{ route('users.index') }}" id="filterForm">
|
||||
@@ -204,7 +204,6 @@
|
||||
{{ $users->appends(request()->query())->links('pagination::bootstrap-5') }}
|
||||
</div>
|
||||
</div>
|
||||
@include('konfigurasi.user.add')
|
||||
@include('konfigurasi.user.edit')
|
||||
</div>
|
||||
@endsection
|
||||
@@ -369,77 +368,5 @@
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
|
||||
function togglePassword(element) {
|
||||
const input = element.parentElement.querySelector('input');
|
||||
const icon = element.querySelector('i');
|
||||
if (input.type === 'password') {
|
||||
input.type = 'text';
|
||||
icon.className = 'ti ti-eye tabler-eye';
|
||||
} else {
|
||||
input.type = 'password';
|
||||
icon.className = 'ti ti-eye-off tabler-eye-off';
|
||||
}
|
||||
}
|
||||
|
||||
const formAddUser = document.getElementById('formAddUser');
|
||||
const offcanvasElement = document.getElementById('offcanvasAddUser');
|
||||
|
||||
if (formAddUser && offcanvasElement) {
|
||||
|
||||
formAddUser.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
let formData = new FormData(this);
|
||||
let submitBtn = this.querySelector('button[type="submit"]');
|
||||
|
||||
submitBtn.disabled = true;
|
||||
let originalText = submitBtn.innerHTML;
|
||||
submitBtn.innerHTML = 'Menyimpan...';
|
||||
|
||||
fetch(this.action, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.innerHTML = originalText;
|
||||
|
||||
if (data.status === 'success') {
|
||||
let bsOffcanvas = bootstrap.Offcanvas.getInstance(offcanvasElement) || new bootstrap.Offcanvas(offcanvasElement);
|
||||
bsOffcanvas.hide();
|
||||
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil!',
|
||||
text: data.message,
|
||||
showConfirmButton: false,
|
||||
timer: 1500
|
||||
}).then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
} else {
|
||||
let errorMsg = data.message || 'Terjadi kesalahan.';
|
||||
if (data.errors) {
|
||||
errorMsg = Object.values(data.errors).map(err => err.join(', ')).join('<br>');
|
||||
}
|
||||
Swal.fire({ icon: 'error', title: 'Gagal!', html: errorMsg });
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.innerHTML = originalText;
|
||||
Swal.fire({ icon: 'error', title: 'Error', text: 'Koneksi bermasalah atau terjadi kesalahan server.' });
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@endpush
|
||||
|
||||
Reference in New Issue
Block a user