410 lines
24 KiB
PHP
410 lines
24 KiB
PHP
<x-app-layout>
|
|
@section('title', 'Tambah Obat Keluar')
|
|
|
|
<div class="space-y-6" x-data="{
|
|
step: 1,
|
|
step1Valid: false,
|
|
errors: {},
|
|
validateStep1() {
|
|
this.errors = {};
|
|
let valid = true;
|
|
|
|
const obatId = document.getElementById('obat_masuk_id').value;
|
|
const kodeBatch = document.getElementById('kode_batch').value;
|
|
const tujuanPemakaian = document.getElementById('tujuan_pemakaian').value;
|
|
const jumlah = document.getElementById('jumlah').value;
|
|
const tanggalPengeluaran = document.getElementById('tanggal_pengeluaran').value;
|
|
const tanggalKadaluarsa = document.getElementById('tanggal_kadaluarsa').value;
|
|
|
|
if (!obatId) {
|
|
this.errors.obat_id = 'Obat harus dipilih';
|
|
valid = false;
|
|
}
|
|
if (!kodeBatch) {
|
|
this.errors.kode_batch = 'Kode batch harus diisi';
|
|
valid = false;
|
|
}
|
|
if (!tujuanPemakaian) {
|
|
this.errors.tujuan_pemakaian = 'Tujuan pemakaian harus diisi';
|
|
valid = false;
|
|
}
|
|
if (!jumlah || jumlah < 1) {
|
|
this.errors.jumlah = 'Jumlah harus diisi dengan angka minimal 1';
|
|
valid = false;
|
|
}
|
|
if (!tanggalPengeluaran) {
|
|
this.errors.tanggal_pengeluaran = 'Tanggal pengeluaran harus diisi';
|
|
valid = false;
|
|
}
|
|
if (!tanggalKadaluarsa) {
|
|
this.errors.tanggal_kadaluarsa = 'Tanggal kadaluarsa harus diisi';
|
|
valid = false;
|
|
}
|
|
|
|
this.step1Valid = valid;
|
|
return valid;
|
|
},
|
|
goToStep2() {
|
|
if (this.validateStep1()) {
|
|
this.step = 2;
|
|
}
|
|
},
|
|
tryGoToStep2() {
|
|
if (!this.step1Valid && this.step === 1) {
|
|
this.validateStep1();
|
|
if (!this.step1Valid) {
|
|
return;
|
|
}
|
|
}
|
|
if (this.step1Valid) {
|
|
this.step = 2;
|
|
}
|
|
},
|
|
updateKadaluarsa(e) {
|
|
const selectedOption = e.target.options[e.target.selectedIndex];
|
|
if (selectedOption) {
|
|
document.getElementById('kode_batch').value = selectedOption.dataset.kodeBatch || '';
|
|
|
|
if (selectedOption.dataset.kadaluarsa) {
|
|
document.getElementById('tanggal_kadaluarsa').value = selectedOption.dataset.kadaluarsa;
|
|
}
|
|
}
|
|
}
|
|
}">
|
|
<!-- Breadcrumb -->
|
|
<nav class="flex" aria-label="Breadcrumb">
|
|
<ol class="inline-flex items-center space-x-1">
|
|
<li>
|
|
<a href="{{ route('obat-keluar.index') }}" class="text-[#7A7FAE] hover:text-[#4A538F]">Obat Keluar</a>
|
|
</li>
|
|
<li>
|
|
<div class="flex items-center">
|
|
<svg class="w-4 h-4 text-[#7A7FAE]" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
|
|
</svg>
|
|
<span class="ml-1 text-[#2F347A] font-medium">Tambah Obat</span>
|
|
</div>
|
|
</li>
|
|
</ol>
|
|
</nav>
|
|
|
|
<div class="flex items-center justify-between">
|
|
<h1 class="text-2xl font-bold text-[#2F347A]">Tambah Obat Keluar</h1>
|
|
</div>
|
|
|
|
<!-- Step Indicator - Arrow Style -->
|
|
<div class="flex items-center justify-center">
|
|
<!-- Step 1 -->
|
|
<div class="flex items-center cursor-pointer" @click="step = 1">
|
|
<div :class="step === 1 ? 'bg-[#4A538F]' : (step1Valid ? 'bg-[#1F9254]' : 'bg-[#E5E7F2]')"
|
|
class="relative flex items-center px-6 py-3 transition-colors"
|
|
style="clip-path: polygon(0 0, calc(100% - 15px) 0, 100% 50%, calc(100% - 15px) 100%, 0 100%);">
|
|
<span :class="step === 1 || step1Valid ? 'text-white' : 'text-[#7A7FAE]'" class="font-bold mr-2">1</span>
|
|
<span :class="step === 1 || step1Valid ? 'text-white font-semibold' : 'text-[#7A7FAE]'" class="transition-colors">
|
|
Informasi Obat
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 2 -->
|
|
<div class="flex items-center -ml-3" :class="step1Valid ? 'cursor-pointer' : 'cursor-not-allowed'" @click="tryGoToStep2()">
|
|
<div :class="step === 2 ? 'bg-[#4A538F]' : 'bg-[#E5E7F2]'"
|
|
class="relative flex items-center px-6 py-3 pl-8 transition-colors"
|
|
style="clip-path: polygon(15px 0, calc(100% - 15px) 0, 100% 50%, calc(100% - 15px) 100%, 15px 100%, 0 50%);">
|
|
<span :class="step === 2 ? 'text-white' : 'text-[#7A7FAE]'" class="font-bold mr-2">2</span>
|
|
<span :class="step === 2 ? 'text-white font-semibold' : 'text-[#7A7FAE]'" class="transition-colors">
|
|
Data Administratif
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<form method="POST" action="{{ route('obat-keluar.store') }}">
|
|
@csrf
|
|
|
|
<!-- Step 1: Informasi Obat -->
|
|
<div x-show="step === 1" x-transition>
|
|
<!-- Info Alert -->
|
|
<div x-data="{ showAlert: true }" x-show="showAlert"
|
|
class="mb-4 p-4 bg-[#E9EBF5] border border-[#4A538F] rounded-lg flex items-start justify-between">
|
|
<div class="flex items-start gap-3">
|
|
<svg class="w-5 h-5 text-[#4A538F] mt-0.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
</svg>
|
|
<p class="text-sm text-[#4A538F]">
|
|
<strong>Info:</strong> Kategori dan satuan obat akan otomatis terisi berdasarkan data obat yang dipilih. Stok akan otomatis berkurang sesuai jumlah yang dikeluarkan.
|
|
</p>
|
|
</div>
|
|
<button type="button" @click="showAlert = false" class="text-[#4A538F] hover:text-[#2F347A] flex-shrink-0">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Card 1: Informasi Obat -->
|
|
<x-card class="p-6 mb-6">
|
|
<h3 class="text-lg font-semibold text-[#2F347A] mb-4 pb-2 border-b border-[#E5E7F2]">Informasi Obat</h3>
|
|
|
|
<!-- Obat Selection (Full Width) -->
|
|
<div class="mb-4">
|
|
<label for="obat_masuk_id" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Obat <span class="text-red-500">*</span>
|
|
</label>
|
|
<select name="obat_masuk_id" id="obat_masuk_id" required @change="updateKadaluarsa($event); validateStep1()"
|
|
:class="errors.obat_id ? 'border-red-500' : 'border-[#E5E7F2]'"
|
|
class="w-full px-4 py-2.5 border rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] bg-white text-[#2F347A]">
|
|
<option value="">Pilih Obat</option>
|
|
@foreach($obats as $obat)
|
|
<option value="{{ $obat->id }}"
|
|
data-kadaluarsa="{{ $obat->tanggal_kadaluarsa ? $obat->tanggal_kadaluarsa->format('Y-m-d') : '' }}"
|
|
data-kode-batch="{{ $obat->kode_batch }}"
|
|
{{ old('obat_masuk_id') == $obat->id ? 'selected' : '' }}>
|
|
{{ $obat->nama_obat }} (Stok: {{ $obat->stok }}) - Batch: {{ $obat->kode_batch }}
|
|
</option>
|
|
@endforeach
|
|
</select>
|
|
<p x-show="errors.obat_id" x-text="errors.obat_id" class="mt-1 text-sm text-red-600"></p>
|
|
@error('obat_masuk_id')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- 2-Column Grid for Other Fields -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<!-- Kode Batch -->
|
|
<div>
|
|
<label for="kode_batch" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Kode Batch <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="text" name="kode_batch" id="kode_batch" value="{{ old('kode_batch') }}"
|
|
placeholder="Terisi otomatis dari pilihan obat" required @input="validateStep1()"
|
|
:class="errors.kode_batch ? 'border-red-500' : 'border-[#E5E7F2]'"
|
|
class="w-full px-4 py-2.5 border rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A] bg-gray-100 cursor-not-allowed" readonly>
|
|
<p x-show="errors.kode_batch" x-text="errors.kode_batch" class="mt-1 text-sm text-red-600"></p>
|
|
@error('kode_batch')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Barcode Obat -->
|
|
<div>
|
|
<label for="barcode" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Barcode Obat
|
|
</label>
|
|
<input type="text" name="barcode" id="barcode" value="{{ old('barcode') }}"
|
|
placeholder="Masukkan barcode (opsional)"
|
|
class="w-full px-4 py-2.5 border border-[#E5E7F2] rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A]">
|
|
@error('barcode')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Tujuan Pemakaian -->
|
|
<div>
|
|
<label for="tujuan_pemakaian" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Tujuan Pemakaian <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="text" name="tujuan_pemakaian" id="tujuan_pemakaian"
|
|
value="{{ old('tujuan_pemakaian') }}"
|
|
placeholder="Contoh: Untuk pasien rawat inap" required @input="validateStep1()"
|
|
:class="errors.tujuan_pemakaian ? 'border-red-500' : 'border-[#E5E7F2]'"
|
|
class="w-full px-4 py-2.5 border rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A]">
|
|
<p x-show="errors.tujuan_pemakaian" x-text="errors.tujuan_pemakaian" class="mt-1 text-sm text-red-600"></p>
|
|
@error('tujuan_pemakaian')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Sumber Dana -->
|
|
<div>
|
|
<label for="sumber_dana" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Sumber Dana
|
|
</label>
|
|
<input type="text" name="sumber_dana" id="sumber_dana" value="{{ old('sumber_dana') }}"
|
|
placeholder="Masukkan sumber dana (opsional)"
|
|
class="w-full px-4 py-2.5 border border-[#E5E7F2] rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A]">
|
|
@error('sumber_dana')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
</div>
|
|
</x-card>
|
|
|
|
<!-- Card 2: Jumlah dan Tanggal -->
|
|
<x-card class="p-6 mb-6">
|
|
<h3 class="text-lg font-semibold text-[#2F347A] mb-4 pb-2 border-b border-[#E5E7F2]">Jumlah, Harga, dan Tanggal</h3>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
<!-- Jumlah -->
|
|
<div>
|
|
<label for="jumlah" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Jumlah <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="number" name="jumlah" id="jumlah" value="{{ old('jumlah') }}"
|
|
min="1" placeholder="Jumlah obat keluar" required @input="validateStep1()"
|
|
:class="errors.jumlah ? 'border-red-500' : 'border-[#E5E7F2]'"
|
|
class="w-full px-4 py-2.5 border rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A]">
|
|
<p x-show="errors.jumlah" x-text="errors.jumlah" class="mt-1 text-sm text-red-600"></p>
|
|
@error('jumlah')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Harga -->
|
|
<div>
|
|
<label for="harga" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Harga (Rp)
|
|
</label>
|
|
<input type="number" name="harga" id="harga" value="{{ old('harga') }}"
|
|
min="0" step="100" placeholder="Harga satuan (opsional)"
|
|
class="w-full px-4 py-2.5 border border-[#E5E7F2] rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A]">
|
|
@error('harga')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Harga Total -->
|
|
<div>
|
|
<label for="harga_total" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Harga Total (Rp)
|
|
</label>
|
|
<input type="number" name="harga_total" id="harga_total" value="{{ old('harga_total') }}"
|
|
min="0" step="100" placeholder="Harga total (opsional)"
|
|
class="w-full px-4 py-2.5 border border-[#E5E7F2] rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A]">
|
|
@error('harga_total')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Tanggal Pengeluaran -->
|
|
<div>
|
|
<label for="tanggal_pengeluaran" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Tanggal Pengeluaran <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="date" name="tanggal_pengeluaran" id="tanggal_pengeluaran"
|
|
value="{{ old('tanggal_pengeluaran', date('Y-m-d')) }}" required @change="validateStep1()"
|
|
:class="errors.tanggal_pengeluaran ? 'border-red-500' : 'border-[#E5E7F2]'"
|
|
class="w-full px-4 py-2.5 border rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A]">
|
|
<p x-show="errors.tanggal_pengeluaran" x-text="errors.tanggal_pengeluaran" class="mt-1 text-sm text-red-600"></p>
|
|
@error('tanggal_pengeluaran')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Tanggal Kadaluarsa -->
|
|
<div>
|
|
<label for="tanggal_kadaluarsa" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Tanggal Kadaluarsa <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="date" name="tanggal_kadaluarsa" id="tanggal_kadaluarsa"
|
|
value="{{ old('tanggal_kadaluarsa') }}" required @change="validateStep1()"
|
|
:class="errors.tanggal_kadaluarsa ? 'border-red-500' : 'border-[#E5E7F2]'"
|
|
class="w-full px-4 py-2.5 border rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A] bg-gray-100 cursor-not-allowed" readonly>
|
|
<p x-show="errors.tanggal_kadaluarsa" x-text="errors.tanggal_kadaluarsa" class="mt-1 text-sm text-red-600"></p>
|
|
@error('tanggal_kadaluarsa')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
</div>
|
|
</x-card>
|
|
|
|
<!-- Step 1 Actions -->
|
|
<div class="flex justify-end gap-4">
|
|
<x-btn type="secondary" href="{{ route('obat-keluar.index') }}">Batal</x-btn>
|
|
<button type="button" @click="goToStep2()"
|
|
class="inline-flex items-center gap-2 px-5 py-2.5 rounded-lg font-medium bg-[#4A538F] text-white hover:bg-[#424B84] transition-colors">
|
|
Selanjutnya
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 2: Data Administratif -->
|
|
<div x-show="step === 2" x-transition>
|
|
<x-card class="p-6 mb-6">
|
|
<h3 class="text-lg font-semibold text-[#2F347A] mb-4 pb-2 border-b border-[#E5E7F2]">Data Administratif</h3>
|
|
|
|
<div class="grid grid-cols-2 gap-6">
|
|
<!-- No. Pengeluaran -->
|
|
<div>
|
|
<label for="no_pengeluaran" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
No. Pengeluaran
|
|
</label>
|
|
<input type="text" name="no_pengeluaran" id="no_pengeluaran" value="{{ old('no_pengeluaran') }}"
|
|
placeholder="Nomor pengeluaran (opsional)"
|
|
class="w-full px-4 py-2.5 border border-[#E5E7F2] rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A]">
|
|
@error('no_pengeluaran')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Nama Penerima -->
|
|
<div>
|
|
<label for="nama_penerima" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Nama Penerima <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="text" name="nama_penerima" id="nama_penerima" value="{{ old('nama_penerima') }}"
|
|
placeholder="Nama penerima obat" required
|
|
class="w-full px-4 py-2.5 border border-[#E5E7F2] rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A]">
|
|
@error('nama_penerima')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Nama Petugas -->
|
|
<div>
|
|
<label for="nama_petugas" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Nama Petugas <span class="text-red-500">*</span>
|
|
</label>
|
|
<input type="text" name="nama_petugas" id="nama_petugas"
|
|
value="{{ old('nama_petugas', auth()->user()->name) }}"
|
|
placeholder="Nama petugas" required
|
|
class="w-full px-4 py-2.5 border border-[#E5E7F2] rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A]">
|
|
@error('nama_petugas')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Status (hidden, default proses) -->
|
|
<input type="hidden" name="status" value="proses">
|
|
</div>
|
|
|
|
<!-- Keterangan -->
|
|
<div class="mt-6">
|
|
<label for="catatan" class="block text-sm font-medium text-[#2F347A] mb-1">
|
|
Keterangan
|
|
</label>
|
|
<textarea name="catatan" id="catatan" rows="3"
|
|
placeholder="Keterangan tambahan (opsional)"
|
|
class="w-full px-4 py-2.5 border border-[#E5E7F2] rounded-lg focus:ring-2 focus:ring-[#4A538F] focus:border-[#4A538F] text-[#2F347A] resize-none">{{ old('catatan') }}</textarea>
|
|
@error('catatan')
|
|
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
</x-card>
|
|
|
|
<!-- Step 2 Actions -->
|
|
<div class="flex justify-between">
|
|
<button type="button" @click="step = 1"
|
|
class="inline-flex items-center gap-2 px-5 py-2.5 rounded-lg font-medium bg-[#E9EBF5] text-[#4A538F] hover:bg-[#d8dce8] transition-colors">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
|
</svg>
|
|
Kembali
|
|
</button>
|
|
<button type="submit"
|
|
class="inline-flex items-center gap-2 px-5 py-2.5 rounded-lg font-medium bg-[#4A538F] text-white hover:bg-[#424B84] transition-colors">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
|
</svg>
|
|
Simpan
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</x-app-layout>
|