Compare commits

..

9 Commits

30 changed files with 1501 additions and 1069 deletions

View File

@ -4,26 +4,84 @@ namespace App\Http\Controllers;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Response;
class AuthController extends Controller class AuthController extends Controller
{ {
private int $loginDecaySeconds = 60;
private int $maxLoginAttempts = 10;
public function index(){ public function index(){
$captcha = $this->generateCaptchaCode(6);
session(['login_captcha' => $captcha]);
$data = [ $data = [
'title' => 'Login Admin | Order Gizi' 'title' => 'Login Admin | Order Gizi',
]; ];
return view('auth.index', $data); return view('auth.index', $data);
} }
public function authanticate(){ public function authanticate(Request $request){
$credentials = request()->validate([ $validated = $request->validate([
'username' => 'required', 'username' => 'required',
'password' => 'required' 'password' => 'required',
'captcha' => 'required',
'website' => 'nullable',
]); ]);
if (trim((string) $request->input('website', '')) !== '') {
return back()->withInput($request->only('username'))
->with(['alertError' => 'Gagal Login!']);
}
$now = time();
$rateKey = 'login:' . $request->ip() . ':' . strtolower((string) $request->input('username'));
$windowSeconds = 60;
$maxAttempts = 10;
$attempts = (array) $request->session()->get($rateKey, []);
$attempts = array_values(array_filter($attempts, fn($ts) => is_int($ts) && $ts > ($now - $windowSeconds)));
if(count($attempts) >= $maxAttempts){
return back()->withInput($request->only('username'))
->with(['alertError' => 'rate']);
}
$backoffKey = $rateKey . ':backoff_until';
$until = (int) $request->session()->get($backoffKey, 0);
if($until > $now){
return back()->withInput($request->only('username'))
->with(['alertError' => 'backoff']);
}
$expectedCaptcha = (string) session('login_captcha', '');
$givenCaptcha = strtoupper(preg_replace('/\s+/', '', (string) $request->input('captcha', '')));
if($expectedCaptcha === '' || !hash_equals(strtoupper($expectedCaptcha), (string) $givenCaptcha)){
return back()->withInput($request->only('username'))
->with(['alertError' => 'captcha']);
}
$request->session()->forget('login_captcha');
// IMPORTANT: only pass auth credentials to Auth::attempt
// (do not include captcha / honeypot fields, otherwise Laravel will query non-existent columns)
$credentials = [
'username' => (string) ($validated['username'] ?? ''),
'password' => (string) ($validated['password'] ?? ''),
];
if(Auth::attempt($credentials)){ if(Auth::attempt($credentials)){
request()->session()->regenerate(); $request->session()->regenerate();
$request->session()->forget($rateKey);
$request->session()->forget($backoffKey);
return redirect()->intended('/dashboard'); return redirect()->intended('/dashboard');
} }
return back()->with(['alertError' => 'Terdapat kesalahan disini!']); // record failed attempt
$attempts[] = $now;
$request->session()->put($rateKey, $attempts);
// set exponential backoff (1,2,4,8,16,30 seconds max) based on failures in window
$failCount = count($attempts);
$delay = min(30, (int) pow(2, max(0, $failCount - 1)));
$request->session()->put($backoffKey, $now + $delay);
return back()->with(['alertError' => 'Gagal Login!']);
} }
public function logout() public function logout()
@ -33,4 +91,63 @@ class AuthController extends Controller
request()->session()->regenerateToken(); request()->session()->regenerateToken();
return redirect('/login'); return redirect('/login');
} }
public function captcha(){
$captcha = (string) session('login_captcha', '');
if($captcha === ''){
$captcha = $this->generateCaptchaCode(6);
session(['login_captcha' => $captcha]);
}
if(!function_exists('imagecreatetruecolor')){
return response('GD extension is not available', Response::HTTP_INTERNAL_SERVER_ERROR)->header('Content-Type', 'text/plain');
}
$width=140;
$height=44;
$img = imagecreatetruecolor($width, $height);
$bg = imagecolorallocate($img, 245, 247, 250);
$fg = imagecolorallocate($img, 35, 45, 70);
$noise = imagecolorallocate($img, 120, 130, 150);
imagefilledrectangle($img, 0, 0, $width, $height, $bg);
for($i = 0; $i < 6; $i++){
imageline(
$img,
random_int(0, $width),
random_int(0, $height),
random_int(0, $width),
random_int(0, $height),
$noise
);
}
for($i = 0; $i < 180; $i++){
imagesetpixel($img, random_int(0, $width - 1), random_int(0, $height - 1), $noise);
}
$font = 5;
$textWidth = imagefontwidth($font) * strlen($captcha);
$textHeight = imagefontwidth($font);
$x = (int) (($width - $textWidth) / 2);
$y = (int) (($height - $textHeight) / 2);
imagestring($img, $font, $x, $y, $captcha, $fg);
ob_start();
imagepng($img);
$png = ob_get_clean();
imagedestroy($img);
return response($png, 200)->header('Content-Type', 'image/png')->header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
}
public function generateCaptchaCode(int $length = 6): string
{
$chars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
$out = '';
$max = strlen($chars) - 1;
for ($i = 0; $i < $length; $i++){
$out .= $chars[random_int(0, $max)];
}
return $out;
}
} }

View File

@ -399,6 +399,7 @@ class CustomerController extends Controller
session()->flash('no_order', $noOrder); session()->flash('no_order', $noOrder);
return response([ return response([
'status' => true, 'status' => true,
'no_order' => $noOrder,
'message' => 'Terima kasih atas pesanan Anda. Mohon tunggu, kami sedang memprosesnya' 'message' => 'Terima kasih atas pesanan Anda. Mohon tunggu, kami sedang memprosesnya'
], 200); ], 200);
return back()->with('success', 'Bukti pembayaran berhasil diunggah.'); return back()->with('success', 'Bukti pembayaran berhasil diunggah.');

View File

@ -38,7 +38,7 @@ class PesananController extends Controller
$tanggalFormatted = [Carbon::now()->toDateString()]; $tanggalFormatted = [Carbon::now()->toDateString()];
} }
$dataPending = Order::whereIn('status_order', [ $dataPending = Order::where('statusenabled', true)->whereIn('status_order', [
'Menunggu Konfirmasi Pembayaran', 'Menunggu Konfirmasi Pembayaran',
'Menunggu Konfirmasi Pembayaran Via Billing', 'Menunggu Konfirmasi Pembayaran Via Billing',
'Menunggu Konfirmasi Pesanan MCU' 'Menunggu Konfirmasi Pesanan MCU'
@ -200,6 +200,7 @@ class PesananController extends Controller
public function dataPending(){ public function dataPending(){
$data = Order::selectRaw('DATE(entry_at) as tgl, COUNT(*) as total') $data = Order::selectRaw('DATE(entry_at) as tgl, COUNT(*) as total')
->where('statusenabled', true)
->whereIn('status_order', [ ->whereIn('status_order', [
'Menunggu Konfirmasi Pembayaran', 'Menunggu Konfirmasi Pembayaran',
'Menunggu Konfirmasi Pembayaran Via Billing', 'Menunggu Konfirmasi Pembayaran Via Billing',

View File

@ -0,0 +1,178 @@
<?php
namespace App\Http\Controllers;
use App\Models\Survey;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Arr;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
class SurveyController extends Controller
{
public function index(Request $request){
if(!session()->has('payment_success')){
return redirect('/');
}
$no_order = $request->query('no_order');
$type = $request->query('type');
$data = [
'title' => 'Survey Gizi',
'mcu' => false,
'no_order' => $no_order,
'type' => $type
];
return view('guest.survey.index', $data);
}
public function store(){
DB::connection('dbOrderGizi')->beginTransaction();
try {
$payload =[
'no_order' => request('no_order'),
'type' => request('type'),
'keterangan' => request('kritik_saran'),
'kepuasan' => request('kepuasan'),
'created_at' => now()
];
Survey::create($payload);
DB::connection('dbOrderGizi')->commit();
session()->flash('payment_success', true);
session()->flash('no_order', $payload['no_order']);
return response()->json([
'status' => true,
'message' => 'Survei berhasil disimpan'
]);
} catch (\Throwable $th) {
DB::connection('dbOrderGizi')->rollBack();
return response()->json([
'status' => false,
'message' => 'Data gagal disimpan ' . $th->getMessage()
]);
}
}
public function datatable(){
$data = Survey::query();
$tanggal = request('tanggal');
if(!empty($tanggal)){
$flattened = is_array($tanggal[0]) ? Arr::flatten($tanggal) : $tanggal;
$data->whereIn(DB::raw('DATE(created_at)'), $flattened);
}else{
$now = Carbon::now()->format('Y-m-d');
$data->whereDate('created_at', $now);
}
$data = $data->get();
return response()->json([
'rows' => $data->values(),
'total' => $data->count(),
]);
}
public function chartDataSurvey(Request $request)
{
$tanggal = $request->query('tanggal');
if(is_string($tanggal)) $tanggal = json_decode($tanggal, true);
$query = Survey::query();
if (!empty($tanggal) && is_array($tanggal)) {
$query->whereIn(DB::raw('DATE(created_at)'), $tanggal);
} else {
$query->whereDate('created_at', Carbon::today());
}
$allData = $query->get();
// Pisahkan data untuk perhitungan Card
$dataBaru = $allData->where('type', 'pengguna_baru');
$dataLama = $allData->where('type', 'pelanggan_setia');
return response()->json([
'responden' => [
'baru' => $dataBaru->count(),
'lama' => $dataLama->count(),
],
'kepuasan_baru' => [
'total' => $dataBaru->count(),
'puas' => $dataBaru->where('kepuasan', 'Puas')->count(),
'tidak_puas' => $dataBaru->where('kepuasan', 'Tidak Puas')->count(),
],
'kepuasan_lama' => [
'total' => $dataLama->count(),
'puas' => $dataLama->where('kepuasan', 'Puas')->count(),
'tidak_puas' => $dataLama->where('kepuasan', 'Tidak Puas')->count(),
]
]);
}
public function dashboardSurvey(){
$data = [
'title' => 'List Survey Order Gizi'
];
return view('dashboard.survey.index', $data);
}
public function exportSurveyExcel(){
$startDate = Carbon::parse(request('start_date'))->startOfDay();
$endDate = Carbon::parse(request('end_date'))->endOfDay();
$data = Survey::whereBetween('created_at', [$startDate, $endDate])->get();
$waktu_cetak = Carbon::now()->locale('id')->translatedFormat('d F Y');
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', "Laporan Survei dari {$startDate->format('Y-m-d')} sampai {$endDate->format('Y-m-d')}");
$sheet->mergeCells('A1:E1');
$sheet->getStyle('A1')->getFont()->setBold(true)->setSize(14);
$sheet->getStyle('A1')->getAlignment()->setHorizontal('center');
$sheet->setCellValue('A2', "Waktu Cetak: {$waktu_cetak}");
$sheet->mergeCells('A2:E2');
$sheet->getStyle('A2')->getAlignment()->setHorizontal('center');
// Header tabel
$headers = ["No", "Nama", "Tipe Survei", "Kepuasan", "Kritik dan Saran"];
$sheet->fromArray($headers, null, 'A4');
$sheet->getStyle('A4:E4')->applyFromArray([
'font' => ['bold' => true],
'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER],
'borders' => [
'allBorders' => [
'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN
]
]
]);
$sheet->getStyle('A4:E4')->getFont()->setBold(true);
$sheet->getStyle('A4:E4')->getAlignment()->setHorizontal('center');
$sheet->getStyle('A4:E4')->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
// Isi data
$row = 5;
foreach ($data as $index => $item) {
$sheet->setCellValue("A{$row}", $index + 1);
$sheet->setCellValue("B{$row}", $item->order->nama_pemesan);
$sheet->setCellValue("C{$row}", $item->type === "pelanggan_setia" ? "Pelanggan Setia" : "Pengguna Baru");
$sheet->setCellValue("D{$row}", $item->kepuasan);
$sheet->setCellValue("E{$row}", $item->keterangan);
$row++;
}
// Auto size kolom
foreach(range('A', 'E') as $col){
$sheet->getColumnDimension($col)->setAutoSize(true);
}
$lastRow = $row - 1;
$sheet->setAutoFilter("A4:E{$lastRow}");
// Download file
$fileName = "Laporan Survei {$startDate->format('Y-m-d')} sampai {$endDate->format('Y-m-d')} ". '.xlsx';
$writer = new Xlsx($spreadsheet);
// Output ke browser
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header("Content-Disposition: attachment; filename=\"{$fileName}\"");
header('Cache-Control: max-age=0');
$writer->save('php://output');
exit;
}
}

25
app/Models/Survey.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Survey extends Model
{
protected $connection = 'dbOrderGizi';
protected $table = 'public.survey';
public $timestamps = false;
protected $primaryKey = "id";
protected $with = ['order'];
protected $fillable =[
'no_order',
'type',
'keterangan',
'kepuasan',
'created_at'
];
public function order(){
return $this->belongsTo(Order::class, 'no_order', 'no_order')->select('no_order', 'nama_pemesan');
}
}

View File

@ -2,7 +2,10 @@
namespace App\Providers; namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\URL; use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
@ -21,6 +24,11 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function boot(): void public function boot(): void
{ {
RateLimiter::for('login', function (Request $request) {
// Coarse protection against floods; detailed failure-based limiting stays in AuthController.
return Limit::perMinute(60)->by($request->ip());
});
Blade::component('dashboard.pesanan.components.modalExport', 'modalExport'); Blade::component('dashboard.pesanan.components.modalExport', 'modalExport');
Blade::component('dashboard.pesanan.components.infoPesanan', 'infoPesanan'); Blade::component('dashboard.pesanan.components.infoPesanan', 'infoPesanan');
if ($this->app->environment('production')) { if ($this->app->environment('production')) {

View File

@ -3,7 +3,7 @@ APP_ENV=production
APP_KEY=base64:R54Pgs6qwWsP6eKZGCcHNd7rrsSSU0DsWSbFHwaT4Bc= APP_KEY=base64:R54Pgs6qwWsP6eKZGCcHNd7rrsSSU0DsWSbFHwaT4Bc=
APP_DEBUG=true APP_DEBUG=true
APP_URL=http://127.0.0.1:8000/ APP_URL=http://127.0.0.1:8000/
APP_TIMEZONE =Asia/Jakarta APP_TIMEZONE=Asia/Jakarta
APP_LOCALE=en APP_LOCALE=en
APP_FALLBACK_LOCALE=en APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US APP_FAKER_LOCALE=en_US
@ -23,7 +23,7 @@ LOG_LEVEL=debug
DB_CONNECTION_ORDER_GIZI= pgsql DB_CONNECTION_ORDER_GIZI= pgsql
DB_HOST_ORDER_GIZI = 172.16.88.22 DB_HOST_ORDER_GIZI = 172.16.88.22
DB_PORT_ORDER_GIZI = 5432 DB_PORT_ORDER_GIZI = 5432
DB_DATABASE_ORDER_GIZI = order_gizi DB_DATABASE_ORDER_GIZI = lms_mutu
DB_USERNAME_ORDER_GIZI = simrs DB_USERNAME_ORDER_GIZI = simrs
DB_PASSWORD_ORDER_GIZI = @S1mrs.3205@ DB_PASSWORD_ORDER_GIZI = @S1mrs.3205@

View File

@ -305,7 +305,7 @@ h6 {
} }
.header .logo img { .header .logo img {
max-height: 36px; max-height: 60px;
margin-right: 8px; margin-right: 8px;
} }
@ -347,6 +347,10 @@ h6 {
.header .navmenu { .header .navmenu {
order: 3; order: 3;
} }
.header .logo img {
max-height: 35px;
margin-right: 8px;
}
} }
.scrolled .header { .scrolled .header {

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

View File

@ -1,4 +1,3 @@
async function submitOrderToServer(){ async function submitOrderToServer(){
const totalHarga = hitungTotalHarga(); const totalHarga = hitungTotalHarga();
@ -109,19 +108,38 @@ async function submitOrderToServer(){
}); });
const result = await response.json(); const result = await response.json();
if (result.status) { if (result.status) {
// ✅ Hapus sessionStorage di client // ✅ Hapus sessionStorage di client
clearSession() clearSession()
Swal.fire({ Swal.fire({
title: 'Pesanan Berhasil!', title: '<span style="color: #00796b;">Pesanan Berhasil!</span>',
text: 'Terima kasih, pesanan Anda sedang kami siapkan.',
icon: 'success', icon: 'success',
confirmButtonText: 'Berhasil!', iconColor: '#2e7d32', // Warna hijau Kemenkes
confirmButtonColor: '#28a745' html: `
}).then(() => { <p class="text-muted mb-4">Terima kasih, pesanan Anda sedang kami siapkan.</p>
window.location.href = "/success-page"; // kehalaman success <div class="p-3 border-0 rounded-4 shadow-sm mb-3" style="background-color: #f1f8f7;">
}); <p class="small fw-bold mb-3 text-uppercase" style="color: #004d40; letter-spacing: 1px;">Bantu Kami Meningkatkan Layanan:</p>
<button type="button" onclick="location.href='/survey?no_order=${result.no_order}&type=pengguna_baru'"
class="btn w-100 mb-3 py-3 border-0 shadow-sm transition-hover"
style="background-color: #00a99d; color: white; border-radius: 12px;">
<div class="fw-bold px-2">Saya Pengguna Baru</div>
<div style="font-size: 0.75rem; opacity: 0.9;">Survei kemudahan aplikasi pemesanan</div>
</button>
<button type="button" onclick="location.href='/survey?no_order=${result.no_order}&type=pelanggan_setia'"
class="btn w-100 py-3 border-0 shadow-sm transition-hover"
style="background-color: #005eb8; color: white; border-radius: 12px;">
<div class="fw-bold px-2">Saya Pelanggan Setia</div>
<div style="font-size: 0.75rem; opacity: 0.9;">Survei rasa, variasi, dan penampilan menu</div>
</button>
</div>
`,
showConfirmButton: false,
showCancelButton: false,
allowOutsideClick: false,
allowEscapeKey: false
})
} else { } else {
clearSession() clearSession()
Swal.fire({ Swal.fire({

View File

@ -32,7 +32,6 @@ document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.next-step').forEach(btn => { document.querySelectorAll('.next-step').forEach(btn => {
btn.addEventListener('click', async () => { btn.addEventListener('click', async () => {
const btnLoad = btn; const btnLoad = btn;
const originalHTML = btnLoad.innerHTML;
btnLoad.disabled = true; btnLoad.disabled = true;
btnLoad.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Memproses...'; btnLoad.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Memproses...';
let cart = JSON.parse(sessionStorage.getItem('cart') || '[]'); let cart = JSON.parse(sessionStorage.getItem('cart') || '[]');
@ -105,7 +104,7 @@ document.addEventListener('DOMContentLoaded', () => {
Swal.fire('Error', 'Terjadi kesalahan, silakan coba lagi.', 'error'); Swal.fire('Error', 'Terjadi kesalahan, silakan coba lagi.', 'error');
}finally{ }finally{
btnLoad.disabled = false; btnLoad.disabled = false;
btnLoad.innerHTML = originalHTML; btnLoad.innerHTML = 'Selanjutnya';
} }
}); });
@ -219,13 +218,7 @@ function showStep(index) {
for(let i = 1; i <= total; i++){ for(let i = 1; i <= total; i++){
const circle = document.getElementById(`step-circle-${i}`) const circle = document.getElementById(`step-circle-${i}`)
if(circle){ if(circle){
circle.classList.toggle('active', i === index + 1); circle.classList.toggle('active', i === index + 1)
circle.classList.toggle('completed', i < index + 1);
}
const indicator = document.getElementById(`indicator-step-${i}`);
if (indicator) {
indicator.classList.toggle('active', i === index + 1);
indicator.classList.toggle('completed', i < index + 1);
} }
} }
} }
@ -244,8 +237,6 @@ function toggleCustomerFields() {
if ($nama[0] && $nama[0].selectize) { if ($nama[0] && $nama[0].selectize) {
$nama[0].selectize.destroy(); $nama[0].selectize.destroy();
} }
switch (selected) { switch (selected) {
case 'Karyawan RSAB Harapan Kita': case 'Karyawan RSAB Harapan Kita':
$('.karyawan').show(); $('.karyawan').show();
@ -255,19 +246,35 @@ function toggleCustomerFields() {
$("#help_email_karyawan").removeClass('d-none') $("#help_email_karyawan").removeClass('d-none')
selectKaryawan(); // inisialisasi ulang selectize selectKaryawan(); // inisialisasi ulang selectize
break; break;
case 'Karyawan RSAB Harapan Kita (Rapat Internal, Seminar /Pelatihan)':
$('.karyawan').show();
$nama.val('')
$nama.removeClass('form-control')
$("#help_nama_pemesan").removeClass('d-none')
$("#help_email_karyawan").removeClass('d-none')
selectKaryawan(); // inisialisasi ulang selectize
break;
case 'Keluarga Pasien / Penunggu Pasien': case 'Keluarga Pasien / Penunggu Pasien':
$('.pasien').show(); $('.pasien').show();
$nama.addClass('form-control') $nama.addClass('form-control')
$("#help_nama_pemesan").addClass('d-none') $("#help_nama_pemesan").addClass('d-none')
$("#help_email_karyawan").addClass('d-none') $("#help_email_karyawan").addClass('d-none')
break; break;
case 'Masyarakat Umum (Corporate)' :
default: // Masyarakat Umum
$('.umum').show(); $('.umum').show();
$nama.addClass('form-control') $nama.addClass('form-control')
$("#help_nama_pemesan").addClass('d-none') $("#help_nama_pemesan").addClass('d-none')
$("#help_email_karyawan").addClass('d-none') $("#help_email_karyawan").addClass('d-none')
$("#modalAttentionModeUmum").modal('show');
break; break;
case 'Masyarakat Umum (Personal)' :
$('.umum').show();
$nama.addClass('form-control')
$("#help_nama_pemesan").addClass('d-none')
$("#help_email_karyawan").addClass('d-none')
$("#modalAttentionModeUmum").modal('show');
break;
default:
} }
} }
$('input[name="jenis_customer"]').on('change', toggleCustomerFields); $('input[name="jenis_customer"]').on('change', toggleCustomerFields);
@ -350,12 +357,15 @@ toggleCustomerFields();
if (checkout_biodata.jenis_customer === "Karyawan RSAB Harapan Kita") { if (checkout_biodata.jenis_customer === "Karyawan RSAB Harapan Kita") {
$('#karyawan').removeClass('d-none'); $('#karyawan').removeClass('d-none');
$('#pasien').addClass('d-none'); $('#pasien').addClass('d-none');
$('#umum').addClass('d-none');
} else if (checkout_biodata.jenis_customer === "Keluarga Pasien / Penunggu Pasien") { } else if (checkout_biodata.jenis_customer === "Keluarga Pasien / Penunggu Pasien") {
$('#karyawan').addClass('d-none'); $('#karyawan').addClass('d-none');
$('#pasien').removeClass('d-none'); $('#pasien').removeClass('d-none');
$('#umum').addClass('d-none');
} else { } else {
$('#karyawan').addClass('d-none'); $('#karyawan').addClass('d-none');
$('#pasien').addClass('d-none'); $('#pasien').addClass('d-none');
$('#umum').removeClass('d-none');
} }

View File

@ -1,67 +1,73 @@
let filterState = {}; let filterState = {};
$(document).ready(function () { $(document).ready(function(){
const jenisMenuAwal = $("#tabJenisMenu .btn.active").data("filter") || 'makanan'; const jenisMenuAwal = $("#tabJenisMenu .nav-link.active").data("filter")
filterState = { filterState ={
jenis_menu: jenisMenuAwal, jenis_menu: jenisMenuAwal,
search: '', search:'',
per_page: 50, per_page: 50,
}; }
fetchMenu(filterState); fetchMenu(filterState)
$('#tabJenisMenu .btn').on('click', function (e) { $('#tabJenisMenu .btn').on('click', function(e) {
e.preventDefault(); e.preventDefault();
const jenis = $(this).data('filter'); const jenis = $(this).data('filter');
$('#tabJenisMenu .btn').removeClass('active'); // reset semua button jadi outline-success
$(this).addClass('active'); $('#tabJenisMenu .btn')
.removeClass('btn-success active')
.addClass('btn-outline-success');
if (typeof datePicker !== 'undefined') { // set button yang dipilih jadi active
datePicker.clear(); $(this)
} .removeClass('btn-outline-success')
$('#tanggalTerpilihLabel').addClass('d-none'); .addClass('btn-success active');
$('#labelTanggalText').text('Menampilkan menu...');
// reset datepicker & label
datePicker.clear();
$('#tanggalTerpilihLabel').addClass('d-none').text('');
$('#resetTanggal').addClass('d-none'); $('#resetTanggal').addClass('d-none');
// set filter state
filterState.jenis_menu = jenis; filterState.jenis_menu = jenis;
fetchMenu(filterState); fetchMenu(filterState);
}); });
$(".alert-link").on('click', function (e) { $(".alert-link").on('click', function(e){
e.preventDefault(); e.preventDefault();
const konsultasiBtn = $('#tabJenisMenu .btn[data-filter="konsultasi"]'); $('#tabJenisMenu .btn').removeClass('btn-success active').addClass('btn-outline-success');
if (konsultasiBtn.length) { $('#tabJenisMenu .btn[data-filter="konsultasi" ]').removeClass('btn-outline-success').addClass('btn-success active');
$('#tabJenisMenu .btn').removeClass('active');
konsultasiBtn.addClass('active');
}
if (typeof datePicker !== 'undefined') { if (typeof datePicker !== 'undefined') {
datePicker.clear(); datePicker.clear();
} }
filterState.jenis_menu = 'konsultasi'; filterState.jenis_menu = 'konsultasi';
$('#tanggalTerpilihLabel').addClass('d-none'); document.getElementById('tanggalTerpilihLabel').classList.add('d-none'); // Sembunyikan label
$('#labelTanggalText').text('Menampilkan menu...'); document.getElementById('tanggalTerpilihLabel').textContent = '';
$('#resetTanggal').addClass('d-none'); document.getElementById('resetTanggal').classList.add('d-none');
fetchMenu(filterState); fetchMenu(filterState);
}); })
let searchTimout; let searchTimout;
$('#searchMenu').on('input', function () { $('#searchMenu').on('input', function(){
clearTimeout(searchTimout); clearTimeout(searchTimout);
const keyword = $(this).val(); const keyword = $(this).val();
searchTimout = setTimeout(() => { searchTimout = setTimeout(() => {
filterState.search = keyword; filterState.search = keyword;
fetchMenu(filterState); fetchMenu(filterState)
}, 300); }, 300)
}); })
});
})
function changePerPage(select) { function changePerPage(select) {
const newPerPage = parseInt(select.value); const newPerPage = parseInt(select.value);
filterState.per_page = newPerPage; filterState.per_page = newPerPage
fetchMenu(filterState); fetchMenu(filterState)
} }

BIN
public/logo/gizi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

BIN
public/logo/nice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
public/logo/no_nice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -58,11 +58,19 @@
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<p class="mb-4">Please sign-in to your account</p> <p class="mb-4">Please sign-in to your account</p>
@if (session()->has('alertError')) @if (session()->has('alertError'))
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger fw-bold" role="alert">
Username atau password salah! @if(session('alertError') === 'rate')
</div> Terlalu banyak percobaan login. Coba lagi dalam 1 menit.
@endif @elseif(session('alertError') === 'backoff')
Mohon tunggu beberapa detik sebelum mencoba lagi.
@elseif(session('alertError') === 'captcha')
Captcha tidak sesuai
@else
Username atau password salah!
@endif
</div>
@endif
<form action="/login" class="mb-3" method="POST"> <form action="/login" class="mb-3" method="POST">
@csrf @csrf
<div class="mb-3"> <div class="mb-3">
@ -92,6 +100,20 @@
<span class="input-group-text cursor-pointer"><i class="bx bx-hide"></i></span> <span class="input-group-text cursor-pointer"><i class="bx bx-hide"></i></span>
</div> </div>
</div> </div>
<div class="mb-4">
<label class="form-label">Captcha</label>
<div class="d-flex align-items-center gap-2">
<img
src="{{ route('captcha.login') }}?t={{ time() }}"
alt="captcha"
class="border rounded"
style="height: 44px; width: 140px; object-fit: cover;"
>
<input type="text" name="captcha" class="form-control text-uppercase" placeholder="Masukkan kode di gambar" autocomplete="off" required>
<a href="/login" class="btn btn-outline-secondary" title="Refresh captcha">Refresh</a>
</div>
<div class="form-text text-muted">Masukkan kode sesuai yang ditampilkan (huruf tidak membedakan kapital/kecil).</div>
</div>
<div class="mb-3"> <div class="mb-3">
<button class="btn btn-primary d-grid w-100" type="submit">Login</button> <button class="btn btn-primary d-grid w-100" type="submit">Login</button>
</div> </div>

View File

@ -109,6 +109,14 @@
<div data-i18n="User interface">Laporan Pesanan </div> <div data-i18n="User interface">Laporan Pesanan </div>
</a> </a>
</li> </li>
<li class="menu-item {{ Request::is('dashboard/survey') ? 'active' : '' }}">
<a href="/dashboard/survey" class="menu-link">
<i class="menu-icon tf-icons bx bx-box"></i>
<div data-i18n="User interface">Survei </div>
</a>
</li>
{{-- <li class="menu-item {{ Request::is('dashboard/laporan-pesanan') ? 'active' : '' }}"> {{-- <li class="menu-item {{ Request::is('dashboard/laporan-pesanan') ? 'active' : '' }}">

View File

@ -30,7 +30,7 @@
<li class="nav-item navbar-dropdown dropdown-user dropdown"> <li class="nav-item navbar-dropdown dropdown-user dropdown">
<a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);" data-bs-toggle="dropdown"> <a class="nav-link dropdown-toggle hide-arrow" href="javascript:void(0);" data-bs-toggle="dropdown">
<div class="avatar avatar-online"> <div class="avatar avatar-online">
<img src="/assets/img/avatars/1.png" alt class="w-px-40 h-auto rounded-circle" /> <img src="/assets/img/avatars/8.jpg" alt class="w-px-40 h-auto rounded-circle" />
</div> </div>
</a> </a>
<ul class="dropdown-menu dropdown-menu-end"> <ul class="dropdown-menu dropdown-menu-end">
@ -39,12 +39,11 @@
<div class="d-flex"> <div class="d-flex">
<div class="flex-shrink-0 me-3"> <div class="flex-shrink-0 me-3">
<div class="avatar avatar-online"> <div class="avatar avatar-online">
<img src="/assets/img/avatars/1.png" alt class="w-px-40 h-auto rounded-circle" /> <img src="/assets/img/avatars/8.jpg" alt class="w-px-40 h-auto rounded-circle" />
</div> </div>
</div> </div>
<div class="flex-grow-1"> <div class="flex-grow-1">
<span class="fw-semibold d-block">John Doe</span> <span class="fw-semibold d-block">Admin</span>
<small class="text-muted">Admin</small>
</div> </div>
</div> </div>
</a> </a>

View File

@ -0,0 +1,183 @@
@extends('dashboard.layouts.main')
@section('body_main')
<div class="container-xxl flex-grow-1 container-p-y">
<h4 class="fw-bold py-3 mb-4">
<span class="text-muted fw-light">Dashboard /</span> Survei
</h4>
<div class="row mb-4">
<div class="col-md-6 mb-3">
<div class="card border-0 shadow-sm h-100" style="border-left: 5px solid #00a99d !important;">
<div class="card-header pb-0">
<h6 class=" fw-normal mb-0">Statistik Pengguna Baru Total <b id="confirm_pb_total"></b></h6>
</div>
<div class="card-body">
<canvas id="barChartBaru" style="max-height: 150px;"></canvas>
</div>
</div>
</div>
<div class="col-md-6 mb-3">
<div class="card border-0 shadow-sm h-100" style="border-left: 5px solid #005eb8 !important;">
<div class="card-header pb-0">
<h6 class=" fw-normal mb-0">Statistik Pelanggan Setia Total <b id="confirm_ps_total"></b></h6>
</div>
<div class="card-body">
<canvas id="barChartLama" style="max-height: 150px;"></canvas>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Data Detail Survei <strong id="confirm_date_survey"></strong></h5>
<div class="d-flex align-items-center gap-2">
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="exportSurvei()">
<i class="fa fa-download me-1"></i> Export
</button>
<div class="input-group input-group-sm" style="width: 240px;">
<span class="input-group-text bg-white"><i class="fa fa-calendar-alt"></i></span>
<input type="text" class="form-control tanggal-input" id="tanggal" placeholder="Pilih tanggal" readonly>
</div>
</div>
</div>
<div class="card-body">
<table class="table" id="datatableSurvey"></table>
</div>
</div>
</div>
@include('dashboard.survey.modal.export')
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
const datatable = $("#datatableSurvey");
const modalExport = document.getElementById('modalExportSurvei');
// Inisialisasi variabel Chart agar bisa di-destroy saat update
let chartBaruObj, chartLamaObj;
function initDt(selectDate = []) {
datatable.bootstrapTable('destroy');
datatable.bootstrapTable({
url: "/dashboard/datatable/survey",
method: 'get',
queryParams: function(params) {
params.tanggal = selectDate;
return params;
},
showColumns: true,
pagination: true,
serverSide: true,
pageSize: 10,
columns: [
{ title: "Nama Pelanggan", field: 'order.nama_pemesan' },
{
title: "Type Survei",
field: 'type',
formatter: (v, row) => row?.type === "pengguna_baru" ? "Pengguna Baru" : "Pelanggan Setia"
},
{ title: "Kepuasan", field: 'kepuasan' },
{ title: "Kritik dan Saran", field: 'keterangan' },
],
});
}
// Fungsi perbaikan untuk Bar Chart Horizontal
function updateBarChart(chartId, puas, tidakPuas) {
const ctx = document.getElementById(chartId).getContext('2d');
// Hancurkan instance lama agar tidak tumpang tindih saat hover
if (chartId === 'barChartBaru' && chartBaruObj) chartBaruObj.destroy();
if (chartId === 'barChartLama' && chartLamaObj) chartLamaObj.destroy();
const config = {
type: 'bar',
data: {
labels: ['Puas', 'Tidak Puas'],
datasets: [{
data: [puas, tidakPuas],
backgroundColor: [
chartId === 'barChartBaru' ? '#00a99d' : '#005eb8',
'#dc3545'
],
borderRadius: 5,
barThickness: 20
}]
},
options: {
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false },
tooltip: { enabled: true }
},
scales: {
x: {
beginAtZero: true,
grid: { display: false },
ticks: { stepSize: 1, precision: 0 }
},
y: { grid: { display: false } }
}
}
};
if (chartId === 'barChartBaru') chartBaruObj = new Chart(ctx, config);
else chartLamaObj = new Chart(ctx, config);
}
async function loadCharts(selectDate = []) {
try {
const dateParam = encodeURIComponent(JSON.stringify(selectDate));
const response = await fetch(`/dashboard/chart/survey?tanggal=${dateParam}`);
const data = await response.json();
console.log(data);
// 1. Update Statistik Bar Chart Pengguna Baru
if(data.kepuasan_baru) {
updateBarChart('barChartBaru', data.kepuasan_baru.puas, data.kepuasan_baru.tidak_puas);
$("#confirm_pb_total").text(data.kepuasan_baru.total);
}
// 2. Update Statistik Bar Chart Pelanggan Setia
if(data.kepuasan_lama) {
updateBarChart('barChartLama', data.kepuasan_lama.puas, data.kepuasan_lama.tidak_puas);
$("#confirm_ps_total").text(data.kepuasan_lama.total);
}
} catch (error) {
console.error("Error load chart:", error);
}
}
document.addEventListener('DOMContentLoaded', function() {
flatpickr('#tanggal', {
dateFormat: "Y-m-d",
mode: "multiple",
locale: "id",
onValueUpdate: function(selectedDates) {
const formatted = selectedDates.map(d => {
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
});
initDt(formatted);
loadCharts(formatted);
let text = formatted.length > 0 ? ': ' + formatted.join(', ') : 'Hari Ini';
$("#confirm_date_survey").text(text);
}
});
$("#confirm_date_survey").text('Hari Ini');
initDt();
loadCharts();
});
function exportSurvei(){
new bootstrap.Modal(modalExport).show()
}
</script>
@endsection

View File

@ -0,0 +1,50 @@
<!-- Modal -->
<div class="modal fade" id="modalExportSurvei" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h5 class="modal-title fs-5">Export Data</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- Modal Form -->
<form action="/dashboard/survey/export" method="POST">
@csrf
<div class="modal-body">
<div class="container">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="exampleFormControlInput1">Start Date</label>
<input type="date" class="form-control" name="start_date" id="start_date" required>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="exampleFormControlInput1">End Date</label>
<input type="date" class="form-control" name="end_date" id="end_date" required>
</div>
</div>
</div>
</div>
</div>
<!-- Modal Footer -->
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
<button type="submit" class="btn btn-primary">Export</button>
</div>
</form>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const today = new Date().toISOString().split('T')[0]; // Mendapatkan tanggal hari ini dalam format YYYY-MM-DD
$('#start_date').val(today);
$('#end_date').val(today);
});
</script>

View File

@ -2,197 +2,57 @@
@section('body_main_guests') @section('body_main_guests')
<section class="section py-5 bg-light"> <section class="section py-5 bg-light">
<style>
.checkout-wrapper {
background: #ffffff;
border-radius: 28px;
}
.checkout-header {
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
#stepIndicators {
gap: 0.75rem;
}
#stepIndicators .step-indicator {
position: relative;
}
#stepIndicators .step-circle {
width: 44px;
height: 44px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
background: #e9f5ef;
color: #2c9e7b;
margin: 0 auto;
transition: all 0.2s ease;
}
#stepIndicators .step-indicator.active .step-circle,
#stepIndicators .step-indicator.completed .step-circle,
#stepIndicators .step-circle.completed {
background: linear-gradient(135deg, #2c9e7b, #22a3a3);
color: #fff;
box-shadow: 0 0.85rem 1.6rem rgba(34, 163, 163, 0.25);
}
#stepIndicators .step-indicator small {
font-weight: 600;
letter-spacing: 0.02em;
color: #6c7d7b;
}
#stepIndicators .step-indicator.active small,
#stepIndicators .step-indicator.completed small {
color: #2c7d66;
}
.progress {
height: 8px;
background-color: #eef2f1;
border-radius: 999px;
}
.progress-bar {
border-radius: 999px;
transition: width 0.25s ease;
}
.form-step {
border-radius: 18px;
border: 1px solid rgba(0, 0, 0, 0.04);
background: #ffffff;
}
.form-step .section-title {
font-size: 1.05rem;
font-weight: 700;
color: #2b6351;
}
.info-alert {
border-radius: 16px;
border-left: 4px solid #2c9e7b;
background: #f2fbf7;
}
.summary-card {
border-radius: 18px;
border: 1px solid rgba(0, 0, 0, 0.05);
}
.drop-zone {
border: 2px dashed rgba(44, 158, 123, 0.35);
border-radius: 16px;
transition: all 0.3s ease;
background: rgba(44, 158, 123, 0.05);
}
.drop-zone:hover {
border-color: rgba(44, 158, 123, 0.6);
background: rgba(44, 158, 123, 0.08);
}
@media (max-width: 991.98px) {
.checkout-wrapper {
border-radius: 22px;
padding: 2rem;
}
}
@media (max-width: 767.98px) {
.checkout-wrapper {
padding: 1.75rem;
}
#stepIndicators {
flex-direction: column;
align-items: stretch;
text-align: left;
}
#stepIndicators .step-indicator {
display: flex;
align-items: center;
gap: 0.85rem;
padding: 0.6rem 0.85rem;
border-radius: 999px;
background: #f8fbfa;
}
#stepIndicators .step-circle {
margin: 0;
}
#stepIndicators .step-indicator small {
margin-top: 0.25rem;
}
}
@media (max-width: 575.98px) {
.checkout-wrapper {
padding: 1.4rem;
}
}
</style>
<div class="container"> <div class="container">
<div class="checkout-wrapper shadow-sm p-4 p-xl-5 mx-auto"> <div class="d-flex justify-content-between align-items-center mb-4">
<div class="checkout-header mb-4 pb-3 d-flex flex-column flex-lg-row align-items-lg-center gap-3"> <h4 class="mb-0">Checkout Order</h4>
<div> <a href="/" class="btn btn-outline-success">
<h3 class="fw-bold mb-1">Checkout Pesanan</h3> <i class="fa fa-arrow-left me-1"></i> Kembali ke Menu
<p class="text-muted mb-0 small">Lengkapi data, konfirmasi pesanan, lalu selesaikan pembayaran.</p> </a>
</div>
<div class="ms-lg-auto">
<a href="/" class="btn btn-outline-success rounded-pill px-3">
<i class="fa fa-arrow-left me-2"></i>Kembali ke Menu
</a>
</div>
</div> </div>
<form id="checkoutFormFinal" method="POST" enctype="multipart/form-data" class="mt-3"> {{-- Form Identitas --}}
@csrf <form id="checkoutFormFinal" method="POST" enctype="multipart/form-data">
<div class="d-flex justify-content-between flex-column flex-lg-row align-items-stretch mb-4 px-lg-2" id="stepIndicators"> @csrf
<div class="step-indicator text-center flex-fill active" id="indicator-step-1"> <!-- Step Indicators -->
<div class="step-circle active" id="step-circle-1">1</div> <div class="d-flex justify-content-between align-items-center mb-3 px-2" id="stepIndicators">
<small class="d-block mt-2 text-uppercase">Data Pemesan</small> <div class="step-indicator text-center flex-fill">
</div> <div class="step-circle" id="step-circle-1">1</div>
<div class="step-indicator text-center flex-fill" id="indicator-step-2"> <small class="d-block mt-1">Data</small>
<div class="step-circle" id="step-circle-2">2</div> </div>
<small class="d-block mt-2 text-uppercase">Konfirmasi</small> <div class="step-indicator text-center flex-fill">
</div> <div class="step-circle" id="step-circle-2">2</div>
<div class="step-indicator text-center flex-fill" id="indicator-step-3"> <small class="d-block mt-1">Konfirmasi</small>
<div class="step-circle" id="step-circle-3">3</div> </div>
<small class="d-block mt-2 text-uppercase">Pembayaran</small> <div class="step-indicator text-center flex-fill">
</div> <div class="step-circle" id="step-circle-3">3</div>
</div> <small class="d-block mt-1">Pembayaran</small>
</div>
<div class="progress mb-4">
<div class="progress-bar bg-success" role="progressbar" id="stepProgressBar" style="width: 33%;">
Langkah 1 dari 3
</div>
</div>
@include('guest.checkout.step.step1')
@include('guest.checkout.step.step2')
@include('guest.checkout.step.step3')
</form>
</div> </div>
<div class="progress mb-4">
<div class="progress-bar bg-success" role="progressbar" id="stepProgressBar" style="width: 50%;">
Langkah 1 dari 2
</div>
</div>
{{-- STEP ONE --}}
@include('guest.checkout.step.step1')
{{-- STEP TWO --}}
@include('guest.checkout.step.step2')
{{-- STEP THREE --}}
@include('guest.checkout.step.step3')
</form>
</div>
</div> </div>
</section> </section>
@include('guest.checkout.modal.noteOrder') @include('guest.checkout.modal.noteOrder')
@include('guest.checkout.modal.confirmPaymentBilling') @include('guest.checkout.modal.confirmPaymentBilling')
<script> @include('guest.checkout.modal.attentionModeUmum')
const karhohidrats = {!! json_encode($karbohidrat) !!}; <script>
</script> const karhohidrats = {!! json_encode($karbohidrat) !!}
<script src="{{ ver('/js/checkout/index.js') }}"></script> </script>
<script src="{{ ver('/js/checkout/action.js') }}"></script> <script src="{{ ver('/js/checkout/index.js') }}"></script>
<script src="{{ ver('/js/checkout/action.js') }}"></script>
@endsection @endsection

View File

@ -0,0 +1,46 @@
<div class="modal fade" id="modalAttentionModeUmum" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-md">
<div class="modal-content shadow rounded-4">
<!-- Modal Header -->
<div class="modal-header bg-warning bg-opacity-10 border-bottom-0">
<h5 class="modal-title fw-bold text-warning">
<i class="fa-solid fa-circle-info me-2"></i> Informasi Pemesanan Masyarakat Umum
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Tutup"></button>
</div>
<!-- Modal Body -->
<div class="modal-body">
<p class="mb-2">
<strong>Perhatian:</strong> Pemesanan untuk <strong>Masyarakat Umum</strong>:
</p>
<ul class="mb-3 ps-3">
<li>
Bagi masyarakat umum ,<strong>makanan yang dipesan harus diambil sendiri / tidak diantar/ dapat menggunakan jasa antar online yang dipesan oleh konsumen sendiri</strong>, diambil di Instalsi Gizi RSAB Harapan Kita
</li>
<li>
Waktu pengambilan makanan:
<ul class="ps-3 mt-1">
<li>Siang: <strong>12.00 - 13.00 WIB</strong></li>
<li>Sore: <strong>16.00 - 17.00 WIB</strong></li>
</ul>
</li>
<li>Pemesanan tidak dapat dibatalkan dan tidak ada pengembalian uang.</li>
<li>
Butuh bantuan? Hubungi WhatsApp <strong>Instalasi Gizi</strong>:
<a href="https://wa.me/08815611382" target="_blank">08815611382</a><br>
<small class="text-muted">Jam kerja: 08.00 - 15.00 WIB</small>
</li>
</ul>
</div>
<!-- Modal Footer -->
<div class="modal-footer">
<button type="button" class="btn btn-secondary rounded-pill" data-bs-dismiss="modal">
Saya Mengerti
</button>
</div>
</div>
</div>
</div>

View File

@ -1,133 +1,155 @@
<div class="form-step card shadow-sm border-0 p-4 active"> <div class="form-step active">
<h5 class="section-title mb-4">Langkah 1: Informasi Pemesan</h5> <div class="row g-3 mb-4">
<input type="hidden" name="cart_data" id="cart_data"> <input type="hidden" name="cart_data" id="cart_data">
<div class="col-md-6">
<label for="exampleInputEmail1" class="form-label">Apakah Anda Seorang ? <span class="text-danger">*</span></label>
<div class="form-check">
<input class="form-check-input" type="radio" name="jenis_customer" id="radio_kp" value="Keluarga Pasien / Penunggu Pasien" required>
<label class="form-check-label" for="radio_kp">
Keluarga Pasien / Penunggu Pasien
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="jenis_customer" id="radio_karyawan" value="Karyawan RSAB Harapan Kita" required>
<label class="form-check-label" for="radio_karyawan" >
Karyawan RSAB Harapan Kita
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="jenis_customer" id="radio_karyawan" value="Karyawan RSAB Harapan Kita (Rapat Internal, Seminar /Pelatihan)" required>
<label class="form-check-label" for="radio_karyawan" >
Karyawan RSAB Harapan Kita (Rapat Internal, Seminar /Pelatihan)
</label>
</div>
{{-- <div class="form-check">
<input class="form-check-input" type="radio" name="jenis_customer" id="radio_public" value="Masyarakat Umum" required>
<label class="form-check-label" for="radio_public">
Masyarakat Umum
</label>
</div> --}}
<div class="form-check">
<input class="form-check-input" type="radio" name="jenis_customer" id="radio_public" value="Masyarakat Umum (Personal)" required>
<label class="form-check-label" for="radio_public">
Masyarakat Umum (Personal)
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="jenis_customer" id="radio_public" value="Masyarakat Umum (Corporate)" required>
<label class="form-check-label" for="radio_public">
Masyarakat Umum (Corporate)
</label>
</div>
</div>
<div class="col-md-6">
<label for="exampleInputEmail1" class="form-label">Jenis Kelamin <span class="text-danger">*</span></label>
<div class="form-check">
<input class="form-check-input" type="radio" name="jenis_kelamin" value="Laki-laki" required>
<label class="form-check-label">
Laki-laki
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="jenis_kelamin" id="radio_kp" value="Perempuan" required>
<label class="form-check-label">
Perempuan
</label>
</div>
</div>
<div class="col-md-6">
<label class="form-label">Nama Pemesan <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="nama_pemesan" id="nama_pemesan" required>
<input type="hidden" class="form-control" name="id_karyawan" id="id_karyawan">
<div id="help_nama_pemesan" class="form-text d-none">Silakan cari dan pilih nama karyawan.</div>
</div>
<div class="col-md-6">
<label class="form-label">No. Whatsapp <span class="text-danger">*</span></label>
<input type="number" class="form-control" name="no_whatsapp" id="no_whatsapp" required>
</div>
<div class="col-md-12">
<label class="form-label">Email <span class="text-danger">*</span></label>
<input type="email" class="form-control" name="email" id="email" required>
<div id="help_email_karyawan" class="form-text d-none">Notifikasi dari sistem belum dapat dikirim ke email dengan domain @rsabhk.co.id, oleh karena itu karyawan disarankan memakai alamat email lain</div>
</div>
{{-- <div class="col-md-6">
<label class="form-label">Tanggal Lahir</label>
<input type="date" class="form-control" name="tanggal_lahir" id="tanggal_lahir">
</div> --}}
<div class="col-md-6">
<label class="form-label">Tinggi Badan</label>
<input type="number" class="form-control" name="tinggi_badan" id="tinggi_badan">
</div>
<div class="col-md-6">
<label class="form-label">Berat Badan</label>
<input type="number" class="form-control" name="berat_badan" id="berat_badan">
</div>
<div class="row g-4 mb-4">
<div class="col-md-6"> {{-- Pasien --}}
<label class="form-label fw-semibold">Anda sebagai <span class="text-danger">*</span></label> <div class="col-md-6 pasien">
<div class="card border-0 shadow-sm p-3 h-100"> <label class="form-label">Nama Pasien <span class="text-danger">*</span></label>
<div class="form-check mb-2"> <input type="text" class="form-control pasien-field" name="nama_pasien" id="nama_pasien">
<input class="form-check-input" type="radio" name="jenis_customer" id="radio_karyawan" value="Karyawan RSAB Harapan Kita" required> </div>
<label class="form-check-label" for="radio_karyawan"> <div class="col-md-6 pasien">
Karyawan RSAB Harapan Kita <label class="form-label">Ruang Perawatan <span class="text-danger">*</span></label>
</label> <select class="form-select pasien-field" name="ruang_perawatan" id="ruang_perawatan">
</div> <option value="">Pilih...</option>
<div class="form-check mb-2"> <option value="Ruang Kenanga">Ruang Kenanga</option>
<input class="form-check-input" type="radio" name="jenis_customer" id="radio_kp" value="Keluarga Pasien / Penunggu Pasien" required> <option value="Ruang Menur">Ruang Menur</option>
<label class="form-check-label" for="radio_kp"> <option value="Ruang Melati">Ruang Melati</option>
Keluarga Pasien / Penunggu Pasien <option value="Ruang Mawar">Ruang Mawar</option>
</label> <option value="Ruang Cempaka">Ruang Cempaka</option>
</div> <option value="Ruang Widuri">Ruang Widuri</option>
<div class="form-check"> <option value="Ruang Teratai">Ruang Teratai</option>
<input class="form-check-input" type="radio" name="jenis_customer" id="radio_public" value="Masyarakat Umum" required> <option value="Ruang Anggrek">Ruang Anggrek</option>
<label class="form-check-label" for="radio_public"> <option value="Ruang VK">Ruang VK</option>
Masyarakat Umum <option value="Klinik Melati">Klinik Melati</option>
</label> <option value="Ruang Tanjung">Ruang Tanjung</option>
</div> <option value="Ruang Gambir">Ruang Gambir</option>
</select>
</div>
<div class="col-md-6 pasien">
<label class="form-label">Nomor Kamar Perawatan <span class="text-danger">*</span></label>
<input type="text" class="form-control pasien-field" name="no_kamar" id="no_kamar">
</div>
<div class="col-md-6 pasien">
<label class="form-label">Kelas Perawatan <span class="text-danger">*</span></label>
<select class="form-select pasien-field" name="kelas_perawatan" id="kelas_perawatan">
<option value="">Pilih...</option>
<option value="VIP A">VIP A</option>
<option value="VIP B">VIP B</option>
<option value="Kelas I">Kelas I</option>
<option value="Klinik Melati">Klinik Melati</option>
</select>
</div>
{{-- End Pasien --}}
{{-- Karyawan --}}
<div class="col-md-6 karyawan">
<label class="form-label">Bagian /Instalasi <span class="text-danger">*</span></label>
<input type="text" class="karyawan-field" name="bagian_instalasi" id="bagian_instalasi">
</div>
<div class="col-md-6 karyawan">
<label class="form-label">Ekstensien yang bisa di Hubungi</label>
<input type="text" class="form-control karyawan-field" name="no_ekstensien" id="no_ekstensien">
</div>
{{-- End Karyawan --}}
{{-- Umum --}}
<div class="col-md-12 umum">
<label class="form-label">Alamat <span class="text-danger">*</span></label>
<textarea class="form-control umum-field" name="alamat" id="alamat"></textarea>
</div>
{{-- End Umum --}}
</div>
<button type="button" class="btn btn-success w-100 next-step">Lanjutkan</button>
</div> </div>
</div> {{-- <script>
new TomSelect("#ruang_perawatan",{
<div class="col-md-6"> sortField: {field: "text"}
<label class="form-label fw-semibold">Jenis Kelamin <span class="text-danger">*</span></label> })
<div class="card border-0 shadow-sm p-3 h-100"> </script> --}}
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="jenis_kelamin" value="Laki-laki" required>
<label class="form-check-label">
Laki-laki
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="jenis_kelamin" value="Perempuan" required>
<label class="form-check-label">
Perempuan
</label>
</div>
</div>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Nama Pemesan <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="nama_pemesan" id="nama_pemesan" required>
<input type="hidden" class="form-control" name="id_karyawan" id="id_karyawan">
<div id="help_nama_pemesan" class="form-text d-none">Silakan cari dan pilih nama karyawan.</div>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">No. Whatsapp <span class="text-danger">*</span></label>
<input type="number" class="form-control" name="no_whatsapp" id="no_whatsapp" required>
</div>
<div class="col-md-12">
<label class="form-label fw-semibold">Email <span class="text-danger">*</span></label>
<input type="email" class="form-control" name="email" id="email" required>
<div id="help_email_karyawan" class="form-text d-none">Notifikasi dari sistem belum dapat dikirim ke email dengan domain @rsabhk.co.id, oleh karena itu karyawan disarankan memakai alamat email lain.</div>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Tinggi Badan (cm)</label>
<input type="number" class="form-control" name="tinggi_badan" id="tinggi_badan">
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Berat Badan (kg)</label>
<input type="number" class="form-control" name="berat_badan" id="berat_badan">
</div>
{{-- Pasien --}}
<div class="col-md-6 pasien">
<label class="form-label fw-semibold">Nama Pasien <span class="text-danger">*</span></label>
<input type="text" class="form-control pasien-field" name="nama_pasien" id="nama_pasien">
</div>
<div class="col-md-6 pasien">
<label class="form-label fw-semibold">Ruang Perawatan <span class="text-danger">*</span></label>
<select class="form-select pasien-field" name="ruang_perawatan" id="ruang_perawatan">
<option value="">Pilih...</option>
<option value="Ruang Kenanga">Ruang Kenanga</option>
<option value="Ruang Menur">Ruang Menur</option>
<option value="Ruang Melati">Ruang Melati</option>
<option value="Ruang Mawar">Ruang Mawar</option>
<option value="Ruang Cempaka">Ruang Cempaka</option>
<option value="Ruang Widuri">Ruang Widuri</option>
<option value="Ruang Teratai">Ruang Teratai</option>
<option value="Ruang Anggrek">Ruang Anggrek</option>
<option value="Ruang VK">Ruang VK</option>
<option value="Klinik Melati">Klinik Melati</option>
<option value="Ruang Tanjung">Ruang Tanjung</option>
<option value="Ruang Gambir">Ruang Gambir</option>
</select>
</div>
<div class="col-md-6 pasien">
<label class="form-label fw-semibold">Nomor Kamar Perawatan <span class="text-danger">*</span></label>
<input type="text" class="form-control pasien-field" name="no_kamar" id="no_kamar">
</div>
<div class="col-md-6 pasien">
<label class="form-label fw-semibold">Kelas Perawatan <span class="text-danger">*</span></label>
<select class="form-select pasien-field" name="kelas_perawatan" id="kelas_perawatan">
<option value="">Pilih...</option>
<option value="VIP A">VIP A</option>
<option value="VIP B">VIP B</option>
<option value="Kelas I">Kelas I</option>
<option value="Klinik Melati">Klinik Melati</option>
</select>
</div>
{{-- End Pasien --}}
{{-- Karyawan --}}
<div class="col-md-6 karyawan">
<label class="form-label fw-semibold">Bagian / Instalasi <span class="text-danger">*</span></label>
<input type="text" class="form-control karyawan-field" name="bagian_instalasi" id="bagian_instalasi">
</div>
<div class="col-md-6 karyawan">
<label class="form-label fw-semibold">Ekstensi yang dapat dihubungi</label>
<input type="text" class="form-control karyawan-field" name="no_ekstensien" id="no_ekstensien">
</div>
{{-- End Karyawan --}}
{{-- Umum --}}
<div class="col-md-12 umum">
<label class="form-label fw-semibold">Alamat <span class="text-danger">*</span></label>
<textarea class="form-control umum-field" name="alamat" id="alamat" rows="3"></textarea>
</div>
{{-- End Umum --}}
</div>
<div class="d-grid d-md-flex justify-content-md-end">
<button type="button" class="btn btn-success btn-lg px-4 next-step">Selanjutnya</button>
</div>
</div>

View File

@ -1,61 +1,83 @@
<div class="form-step card shadow-sm border-0 p-4 d-none"> <div class="form-step d-none">
<h5 class="section-title mb-4">Langkah 2: Konfirmasi Pesanan</h5> <h5 class="mb-4">Langkah 2: Konfirmasi Pemesanan</h5>
<div class="summary-card bg-light p-3 rounded mb-3"> {{-- Ringkasan Pesanan --}}
<h6 class="fw-semibold mb-3 text-success">Ringkasan Pesanan</h6> <h6 class="fw-bold mb-3">Pesanan Gizi</h6>
<div id="checkout_cart_summary">
{{-- Render melalui JavaScript --}}
</div>
</div>
<div class="d-flex flex-column flex-md-row justify-content-between gap-2 mt-4">
<button type="button" class="btn btn-outline-secondary px-4 prev-step">
<i class="fa fa-arrow-left me-2"></i>Sebelumnya
</button>
<button type="button" class="btn btn-success px-4 next-step" id="btnSimpanPemesanan">
Lanjut Pembayaran
</button>
</div>
<div class="info-alert alert alert-info py-3 px-4 small mt-4 d-none" id="karyawan" role="alert"> <div id="checkout_cart_summary">
<div class="fw-bold mb-2 text-success"> {{-- Akan diisi oleh JavaScript --}}
<i class="fa fa-info-circle me-1"></i>Informasi Penting untuk Karyawan </div>
</div>
<p class="mb-2">
Makanan yang dipesan <strong>harus diambil sendiri</strong> (tidak diantar).
Pengambilan dilakukan di <strong>Instalasi Gizi (Ruang Distribusi Makan)</strong> dengan jadwal berikut:
</p>
<ul class="mb-0 ps-3">
<li>Pemesanan tidak dapat dibatalkan dan tidak ada pengembalian uang.</li>
<li>
Waktu pengambilan makanan:
<ul class="ps-3 mt-1">
<li>Siang: <strong>12.00 - 13.00 WIB</strong></li>
<li>Sore: <strong>16.00 - 17.00 WIB</strong></li>
</ul>
</li>
<li>
Butuh bantuan? Hubungi WhatsApp <strong>Instalasi Gizi</strong>:
<a href="https://wa.me/08815611382" target="_blank">08815611382</a><br>
<small class="text-muted">Jam kerja: 08.00 - 15.00 WIB</small>
</li>
</ul>
</div>
<div class="info-alert alert alert-info py-3 px-4 small mt-3 d-none" id="pasien" role="alert"> <div class="d-flex justify-content-between mt-4">
<div class="fw-bold mb-2 text-success"> <button type="button" class="btn btn-secondary prev-step">Sebelumnya</button>
<i class="fa fa-info-circle me-1"></i>Informasi Penting untuk Keluarga Pasien <button type="button" class="btn btn-success next-step" id="btnSimpanPemesanan">Lanjutkan</button>
</div> </div>
<p class="mb-2">
Makanan yang dipesan <strong>akan diantarkan</strong> langsung ke ruang perawatan. <div class="alert alert-info py-3 px-4 border-4 mt-3 d-none" id="karyawan" role="alert">
</p> <div class="fw-bold mb-2">
<ul class="mb-0 ps-3"> <i class="fa fa-info-circle me-1"></i>Informasi Penting
<li>Pemesanan tidak dapat dibatalkan dan tidak ada pengembalian uang.</li> </div>
<li> <p class="mb-2">
Butuh bantuan? Hubungi WhatsApp <strong>Instalasi Gizi</strong>: Bagi Karyawan, makanan yang dipesan <strong>harus diambil sendiri</strong> (tidak diantar).
<a href="https://wa.me/08815611382" target="_blank">08815611382</a><br> Pengambilan dilakukan di <strong>Instalasi Gizi (Ruang Distribusi Makan)</strong> dengan jadwal berikut:
<small class="text-muted">Jam kerja: 08.00 - 15.00 WIB</small> </p>
</li> <ul class="mb-0 ps-3">
</ul> <li>Pemesanan tidak dapat dibatalkan dan tidak ada pengembalian uang.</li>
</div> <li>
</div> Waktu pengambilan makanan:
<ul class="ps-3 mt-1">
<li>Siang: <strong>12.00 - 13.00 WIB</strong></li>
<li>Sore: <strong>16.00 - 17.00 WIB</strong></li>
</ul>
</li>
<li>
Butuh bantuan? Hubungi WhatsApp <strong>Instalasi Gizi</strong>:
<a href="https://wa.me/08815611382" target="_blank">08815611382</a><br>
<small class="text-muted">Jam kerja: 08.00 - 15.00 WIB</small>
</li>
</ul>
</div>
<div class="alert alert-info py-3 px-4 border-4 mt-3 d-none" id="pasien" role="alert">
<div class="fw-bold mb-2">
<i class="fa fa-info-circle me-1"></i>Informasi Penting
</div>
<p class="mb-2">
Bagi Keluarga atau Penunggu Pasien, makanan yang dipesan <strong>akan diantarkan</strong> ke ruang perawatan.
</p>
<ul class="mb-0 ps-3">
<li>
Pemesanan tidak dapat dibatalkan dan tidak ada pengembalian uang.
</li>
<li>
Butuh bantuan? Hubungi WhatsApp <strong>Instalasi Gizi</strong>:
<a href="https://wa.me/08815611382 " target="_blank">08815611382 </a> <br>
<small class="text-muted">Jam kerja: 08.00 - 15.00 WIB</small>
</li>
</ul>
</div>
<div class="alert alert-info py-3 px-4 border-4 mt-3 d-none" id="umum" role="alert">
<div class="fw-bold mb-2">
<i class="fa fa-info-circle me-1"></i>Informasi Penting
</div>
<p class="mb-2">
Bagi masyarakat umum ,<strong>makanan yang dipesan harus diambil sendiri / tidak diantar/ dapat menggunakan jasa antar online yang dipesan oleh konsumen sendiri</strong>, diambil di Instalasi Gizi RSAB Harapan Kita.
</p>
<ul class="mb-0 ps-3">
<li>
Waktu pengambilan makanan:
<ul class="ps-3 mt-1">
<li>Siang: <strong>12.00 - 13.00 WIB</strong></li>
<li>Sore: <strong>16.00 - 17.00 WIB</strong></li>
</ul>
</li>
<li>Pemesanan tidak dapat dibatalkan dan tidak ada pengembalian uang.</li>
<li>
Butuh bantuan? Hubungi WhatsApp <strong>Instalasi Gizi</strong>:
<a href="https://wa.me/08815611382" target="_blank">08815611382</a><br>
<small class="text-muted">Jam kerja: 08.00 - 15.00 WIB</small>
</li>
</ul>
</div>
</div>

View File

@ -1,110 +1,117 @@
<div class="form-step card shadow-sm border-0 p-4 d-none"> <div class="form-step">
<h5 class="section-title mb-4 text-center">Langkah 3: Selesaikan Pembayaran</h5> <h5 class="mb-4 text-center fw-bold">Langkah 3: Lakukan Pembayaran</h5>
<div class="card shadow-sm border-0 p-4 mb-4"> <div class="card shadow-sm p-4">
<div class="row justify-content-center text-center mb-3"> <div class="row justify-content-center text-center">
<div class="col-12 col-sm-10 col-md-8 col-lg-6"> <div class="col-12 col-sm-10 col-md-8 col-lg-6 mb-3">
<img src="/logo/qris.jpg" alt="Pembayaran" class="img-fluid rounded shadow" style="max-width: 360px;"> <img src="/logo/qris.jpg" alt="Pembayaran"
</div> class="img-fluid rounded shadow w-100"
</div> style="max-width: 500px; height: auto;">
</div>
</div>
<div class="row justify-content-center px-2">
<div class="col-12 col-md-8">
<div class="text-center mb-3">
<h6 class="fw-bold">Detail Pembayaran</h6>
</div>
<div class="card shadow-sm mb-3 rounded">
<div class="card-body">
<!-- No Order -->
<div class="row mb-3 align-items-center">
<div class="col-md-6 col-sm-12 fw-semibold">No Order</div>
<div class="col-md-6 col-sm-12 text-sm-end">
<div class="d-flex justify-content-between justify-content-sm-end align-items-center gap-2">
</div>
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="copyNoOrder()">
<i class="fa fa-copy me-1"></i> Salin
</button><strong id="no_order_display" class="d-block small text-break text-wrap text-sm-end"></strong>
</div>
</div>
<!-- Bank -->
<div class="row mb-3">
<div class="col-md-6 col-sm-12 fw-semibold">Bank</div>
<div class="col-md-6 col-sm-12 text-sm-end">Bank BRI</div>
</div>
<!-- Nama Rekening -->
<div class="row mb-3">
<div class="col-md-6 col-sm-12 fw-semibold">Nama Rek.</div>
<div class="col-md-6 col-sm-12 text-sm-end">RPL 182 RSAB HARKIT OPR BLU PENERIMAAN</div>
</div>
<!-- No Rek -->
<div class="row mb-3 align-items-center">
<div class="col-md-6 col-sm-12 fw-semibold">No.Rek</div>
<div class="col-md-6 col-sm-12 text-sm-end">
<div class="d-flex justify-content-between justify-content-sm-end align-items-center gap-2">
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="copyNoRek()">
<i class="fa fa-copy me-1"></i> Salin
</button>
</div>
<strong id="noRekText" class="d-block text-sm-end">096201000073308</strong>
</div>
</div>
<!-- Nominal -->
<div class="row mb-3">
<div class="col-md-6 col-sm-12 fw-semibold">Nominal</div>
<div class="col-md-6 col-sm-12 text-sm-end" id="no_order_price">Rp 0</div>
</div>
<!-- Waktu Pembayaran -->
<div class="row mb-2">
<div class="col-md-6 col-sm-12 fw-semibold">Waktu Pembayaran</div>
<div class="col-md-6 col-sm-12 text-sm-end" id="countdownPayment"></div>
</div>
<div class="row justify-content-center px-md-3">
<div class="col-12 col-lg-10">
<div class="summary-card card shadow-sm border-0 mb-4">
<div class="card-body">
<h6 class="fw-semibold text-success mb-3 text-center text-md-start">Detail Pembayaran</h6>
<div class="row g-3 align-items-center mb-3">
<div class="col-md-5 col-sm-12 text-muted fw-semibold">No. Order</div>
<div class="col-md-7 col-sm-12 text-md-end">
<div class="d-flex flex-wrap justify-content-between justify-content-md-end align-items-center gap-2">
<strong id="no_order_display" class="small text-break"></strong>
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="copyNoOrder()">
<i class="fa fa-copy me-1"></i> Salin
</button>
</div> </div>
</div> </div>
<p class="text-muted small text-center px-2">
Mohon untuk melakukan pembayaran sebelum batas waktu yang tertera, lalu unggah bukti pembayaran sebagai konfirmasi.
</p>
</div>
</div>
<div class="row justify-content-center mt-4">
<div class="mb-3">
<label for="cara_pembayaran" class="form-label fw-semibold">Metode Pembayaran</label>
<select class="form-select" id="cara_pembayaran" name="cara_pembayaran" onchange="toggleBuktiPembayaran()">
<option value="transfer">Transfer Bank</option>
<option value="billing">Billing RS</option>
</select>
<input type="hidden" id="no_order_result" name="no_order_result">
</div> </div>
<div class="row g-3 mb-3"> <div id="bukti_section">
<div class="col-md-5 col-sm-12 text-muted fw-semibold">Bank</div> <label for="bukti_pembayaran" class="form-label fw-semibold">Upload Bukti Pembayaran</label>
<div class="col-md-7 col-sm-12 text-md-end">Bank BRI</div> <div class="card p-3 border-dashed position-relative text-center shadow-sm">
</div> <input type="file" class="form-control position-absolute top-0 start-0 opacity-0 w-100 h-100"
id="bukti_pembayaran" name="bukti_pembayaran" accept="image/*" onchange="previewBuktiPembayaran()">
<div class="row g-3 mb-3"> <div id="preview_text" class="text-muted">
<div class="col-md-5 col-sm-12 text-muted fw-semibold">Nama Rekening</div> Klik atau drag file ke sini untuk upload<br>
<div class="col-md-7 col-sm-12 text-md-end">RPL 182 RSAB HARKIT OPR BLU PENERIMAAN</div> <small>Format: JPG, PNG | Max: 2MB</small>
</div>
<div class="row g-3 align-items-center mb-3">
<div class="col-md-5 col-sm-12 text-muted fw-semibold">No. Rekening</div>
<div class="col-md-7 col-sm-12 text-md-end">
<div class="d-flex flex-wrap justify-content-between justify-content-md-end align-items-center gap-2">
<strong id="noRekText" class="text-break">096201000073308</strong>
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="copyNoRek()">
<i class="fa fa-copy me-1"></i> Salin
</button>
</div> </div>
<img id="bukti_preview" class="img-fluid rounded mt-3 d-none" style="max-height: 300px; object-fit: contain;" />
</div> </div>
</div> </div>
<div class="mb-3" id="billing_section" style="display:none;">
<div class="row g-3 mb-3"> <label for="exampleInputEmail1" class="form-label">No. Medical Record</label>
<div class="col-md-5 col-sm-12 text-muted fw-semibold">Nominal</div> <input type="text" class="form-control" name="medical_record" id="medical_record" placeholder="Masukkan No. Medical Record">
<div class="col-md-7 col-sm-12 text-md-end fw-semibold text-success" id="no_order_price">Rp 0</div>
</div>
<div class="row g-3">
<div class="col-md-5 col-sm-12 text-muted fw-semibold">Batas Waktu Pembayaran</div>
<div class="col-md-7 col-sm-12 text-md-end text-danger fw-semibold" id="countdownPayment"></div>
</div> </div>
<p class="text-muted small text-center px-2 py-2">
<strong>Makanan yg sudah dipesan tidak dapat dibatalkan, dan tidak ada pengembalian uang</strong>
</p>
</div> </div>
</div> </div>
<p class="text-muted small text-center px-2"> <div class="d-flex justify-content-center mt-4">
Lakukan pembayaran sebelum batas waktu berakhir, kemudian unggah bukti transfer untuk mempercepat verifikasi. <button type="submit" class="btn btn-success w-100">Selesaikan Pesanan</button>
</p>
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-lg-10">
<div class="mb-3">
<label for="cara_pembayaran" class="form-label fw-semibold">Metode Pembayaran</label>
<select class="form-select" id="cara_pembayaran" name="cara_pembayaran" onchange="toggleBuktiPembayaran()">
<option value="transfer">Transfer Bank</option>
<option value="billing">Billing RS</option>
</select>
<input type="hidden" id="no_order_result" name="no_order_result">
</div>
<div id="bukti_section" class="mb-3">
<label for="bukti_pembayaran" class="form-label fw-semibold">Upload Bukti Pembayaran</label>
<div class="drop-zone position-relative text-center p-4">
<input type="file" class="form-control position-absolute top-0 start-0 opacity-0 w-100 h-100"
id="bukti_pembayaran" name="bukti_pembayaran" accept="image/*" onchange="previewBuktiPembayaran()">
<div id="preview_text" class="text-muted">
Klik atau tarik file ke area ini untuk mengunggah<br>
<small>Format: JPG, PNG | Maksimal: 2MB</small>
</div>
<img id="bukti_preview" class="img-fluid rounded mt-3 d-none" style="max-height: 280px; object-fit: contain;" />
</div> </div>
</div> </div>
<div class="mb-3" id="billing_section" style="display:none;">
<label class="form-label fw-semibold">No. Medical Record</label>
<input type="text" class="form-control" name="medical_record" id="medical_record" placeholder="Masukkan No. Medical Record">
</div>
<div class="alert alert-warning text-muted small text-center mt-3 mb-4" role="alert">
<strong>Perhatian:</strong> Makanan yang sudah dipesan tidak dapat dibatalkan dan tidak ada pengembalian dana.
</div>
</div>
</div>
<div class="d-flex flex-column flex-md-row justify-content-between gap-2 mt-2">
<button type="button" class="btn btn-outline-secondary px-4 prev-step">
<i class="fa fa-arrow-left me-2"></i>Kembali
</button>
<button type="submit" class="btn btn-success px-4">Selesaikan Pesanan</button>
</div>
</div>

View File

@ -1,71 +1,71 @@
<div class="modal fade" id="checkoutModal" tabindex="-1" aria-labelledby="checkoutModalLabel" aria-hidden="true"> <div class="modal fade" id="checkoutModal" tabindex="-1" aria-labelledby="checkoutModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable"> <div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content border-0 shadow-lg"> <div class="modal-content">
<div class="modal-header bg-success text-white border-0"> <div class="modal-header">
<h5 class="modal-title fw-semibold" id="checkoutModalLabel"> <h5 class="modal-title fw-bold" id="checkoutModalLabel">Pesanan Catering RSAB Harapan Kita</h5>
<i class="fa fa-utensils me-2"></i>Detail Menu Pilihan
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<form id="checkoutForm"> <form id="checkoutForm">
<div class="modal-body bg-light"> <div class="modal-body">
<div class="row g-3 align-items-start"> <div class="row g-3">
<div class="col-md-5 text-center"> <div class="col-md-4 text-center">
<input type="hidden" id="apakah_someday"> <input type="hidden" id="apakah_someday">
<input type="hidden" id="apakah_menu_siang"> <input type="hidden" id="apakah_menu_siang">
<input type="hidden" id="apakah_menu_sore"> <input type="hidden" id="apakah_menu_sore">
<input type="hidden" id="tgl_tersedia"> <input type="hidden" id="tgl_tersedia">
<div class="bg-white rounded-4 shadow-sm p-2 h-100 d-flex align-items-center justify-content-center"> <img id="cathering_order_photo" class="img-fluid rounded shadow" style="max-height: 370px; width:270px;" alt="Foto Menu">
<img id="cathering_order_photo" class="img-fluid rounded-4" style="max-height: 320px; object-fit: cover;" alt="Foto Menu">
</div>
</div> </div>
<div class="col-md-7"> <div class="col-md-8">
<div class="bg-white rounded-4 shadow-sm p-4 h-100"> <h5 id="cathering_order_name" class="mb-2 fw-bold"></h5>
<h4 id="cathering_order_name" class="fw-bold text-success mb-2"></h4> <div id="kalori_detail" class="mb-2"></div>
<div class="d-flex flex-wrap gap-2 align-items-center text-muted small mb-3"> <div id="tgl_menu_tersedia" class="mb-2"></div>
<span id="kalori_detail"></span>
<span id="tgl_menu_tersedia" class="badge bg-light text-success border border-success-subtle"></span> <div class="card shadow-sm border-0 rounded-3 p-3 bg-light">
<div class="d-flex justify-content-between align-items-center small mb-2 d-none">
<span class="text-muted">
<i class="bi bi-person-badge"></i> Harga Karyawan:
</span>
<span class="fw-bold text-success" id="cathering_order_price_karyawan"></span>
</div> </div>
<div class="card border-0 bg-light rounded-4 mb-3"> <div class="d-flex justify-content-between align-items-center">
<div class="card-body py-3 px-4"> <span class="">
<div class="d-flex justify-content-between align-items-center small mb-2 d-none"> <i class="bi bi-cash-coin"></i> Harga:
<span class="text-muted"> </span>
<i class="bi bi-person-badge me-1"></i>Harga Karyawan <span class="fw-bold fs-5 text-primary" id="cathering_order_price_public"></span>
</span>
<span class="fw-bold text-success" id="cathering_order_price_karyawan"></span>
</div>
<div class="d-flex justify-content-between align-items-center">
<span class="fw-semibold text-secondary">
<i class="bi bi-cash-coin me-1"></i>Harga
</span>
<span class="fw-bold fs-5 text-primary" id="cathering_order_price_public"></span>
</div>
</div>
</div> </div>
</div>
<p id="cathering_order_deskripsi" class="text-muted small mb-3"></p>
<div id="tag_klasifikasi_menu" class="mb-2"></div>
<div id="kalori_menu" class="mb-2"></div>
<input type="hidden" id="cathering_order_menu_id">
<input type="hidden" id="cathering_order_jenis_menu">
</div> <p id="cathering_order_deskripsi"
class="text-muted small mb-2 mt-2"
style="
max-width: 100%;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
">
</p>
<div id="tag_klasifikasi_menu" class="mb-2"></div>
<div id="kalori_menu" class="mb-2"></div>
<input type="hidden" id="cathering_order_menu_id">
<input type="hidden" id="cathering_order_jenis_menu">
</div> </div>
</div> </div>
</div> </div>
<div class="modal-footer bg-white border-0 justify-content-between"> <div class="modal-footer">
<div class="text-muted small"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
Pastikan detail menu sudah sesuai sebelum melanjutkan pemesanan. <button type="submit" class="btn btn-success">
</div> <i class="fas fa-shopping-cart me-1"></i> Pesan Sekarang
<div class="d-flex gap-2"> </button>
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Batal</button>
<button type="submit" class="btn btn-success">
<i class="fas fa-cart-plus me-2"></i>Tambah ke Keranjang
</button>
</div>
</div> </div>
</form> </form>
</div> </div>

View File

@ -1,454 +1,144 @@
@extends('guest.layout.main') @extends('guest.layout.main')
@section('body_main_guests') @section('body_main_guests')
<section class="section pb-0 bg-light"> <section class="section py-3 bg-light">
<style> <div class="container">
.guest-hero { <div class="row">
background: linear-gradient(140deg, #3fb072 0%, #268a76 60%, #166d62 100%); <div class="col-12 mb-2 text-center">
border-radius: 26px; <div class="btn-group flex-wrap nav-tabs" role="group" id="tabJenisMenu">
color: #fff; <button type="button" class="btn btn-success active" data-filter="makanan">
overflow: hidden; <i class="bi bi-egg-fried me-1"></i> Makanan
position: relative; </button>
} <button type="button" class="btn btn-outline-success" data-filter="minuman">
<i class="bi bi-cup-straw me-1"></i> Minuman
.guest-hero::before, </button>
.guest-hero::after { <button type="button" class="btn btn-outline-success" data-filter="snack">
content: ""; <i class="bi bi-cookie me-1"></i> Snack
position: absolute; </button>
border-radius: 50%; <button type="button" class="btn btn-outline-success" data-filter="paket">
background: rgba(255, 255, 255, 0.15); <i class="bi bi-gift me-1"></i> Paket
filter: blur(0); </button>
} <button type="button" class="btn btn-outline-success" data-filter="konsultasi">
<i class="bi bi-person-heart me-1"></i> Konsultasi Gizi
.guest-hero::before { </button>
width: 240px; <button type="button" class="btn btn-outline-success" data-filter="cara_pesan">
height: 240px; <i class="bi bi-journal-text me-1"></i> Cara Pesan
top: -90px;
right: -70px;
}
.guest-hero::after {
width: 160px;
height: 160px;
bottom: -70px;
left: -60px;
}
.guest-hero__badge {
background: rgba(255, 255, 255, 0.15);
border-radius: 999px;
font-size: 0.78rem;
letter-spacing: 0.08em;
padding: 0.45rem 1.1rem;
text-transform: uppercase;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.guest-hero__title {
font-size: 2.5rem;
}
.guest-hero__lead {
color: rgba(255, 255, 255, 0.82);
max-width: 520px;
}
.guest-hero__card {
background: rgba(255, 255, 255, 0.96);
border-radius: 20px;
}
.filter-toolbar {
margin-top: -2.75rem;
position: relative;
z-index: 2;
}
.filter-toolbar .card {
border-radius: 22px;
}
.btn-filter {
background: #ffffff;
border: 1px solid rgba(40, 123, 98, 0.18);
border-radius: 999px;
color: #1f6f56;
font-weight: 600;
padding: 0.55rem 1.15rem;
transition: all 0.2s ease;
}
.btn-filter i {
color: #2c9e7b;
font-size: 1rem;
}
.btn-filter:hover {
box-shadow: 0 0.75rem 1.65rem rgba(32, 122, 96, 0.14);
transform: translateY(-2px);
}
.btn-filter.active {
background: linear-gradient(135deg, #2c9e7b, #22a3a3);
border-color: transparent;
color: #fff;
box-shadow: 0 0.9rem 1.8rem rgba(34, 163, 163, 0.2);
}
.btn-filter.active i {
color: #fff;
}
.input-icon {
position: relative;
}
.input-icon .icon {
position: absolute;
top: 50%;
left: 1.15rem;
transform: translateY(-50%);
color: #7a8a8d;
}
.input-icon .form-control {
background: #f5f9f6;
border-radius: 16px;
border: 1px solid transparent;
padding-left: 3rem;
transition: all 0.25s ease;
}
.input-icon .form-control:focus {
background: #fff;
border-color: rgba(40, 123, 98, 0.35);
box-shadow: 0 1rem 2rem rgba(32, 122, 96, 0.18);
}
.selected-range {
background: #eef9f2;
border: 1px solid rgba(40, 123, 98, 0.15);
border-radius: 12px;
color: #1a5a46;
padding: 0.5rem 0.85rem;
}
.info-banner {
border-radius: 18px;
}
.info-banner .soft-badge {
background: rgba(44, 158, 123, 0.14);
border-radius: 999px;
color: #1e6d52;
font-weight: 600;
padding: 0.45rem 1.1rem;
}
.info-callout {
border-radius: 20px;
}
.info-callout .icon-wrapper {
width: 48px;
height: 48px;
border-radius: 16px;
background: rgba(44, 158, 123, 0.14);
display: flex;
align-items: center;
justify-content: center;
color: #2c9e7b;
font-size: 1.1rem;
}
#menuBtn {
background: linear-gradient(135deg, #ff8662, #ff5d56);
border: none;
}
#floatingCartButton {
background: linear-gradient(135deg, #248c73, #1c6a5c);
border: none;
}
#floatingCartButton .btn {
background: rgba(255, 255, 255, 0.2);
border: none;
}
@media (max-width: 1199.98px) {
.guest-hero__title {
font-size: 2.2rem;
}
.guest-hero__lead {
font-size: 1.05rem;
}
}
@media (max-width: 991.98px) {
.guest-hero {
border-radius: 22px;
text-align: center;
}
.guest-hero__title {
font-size: 2rem;
}
.guest-hero__lead {
margin-inline: auto;
}
.guest-hero__card {
margin-top: 2rem;
text-align: left;
}
.filter-toolbar {
margin-top: -2.25rem;
}
}
@media (max-width: 767.98px) {
.guest-hero {
padding: 2.4rem 1.6rem;
}
.guest-hero__title {
font-size: 1.75rem;
}
.guest-hero__lead {
font-size: 0.95rem;
}
.guest-hero__badge {
font-size: 0.68rem;
}
.btn-filter {
width: 100%;
justify-content: center;
font-size: 0.85rem;
padding: 0.5rem 0.9rem;
}
.filter-toolbar .card-body {
padding: 1.25rem;
}
#tanggal-filter .form-control {
font-size: 0.9rem;
padding-right: 1rem;
}
#menuBtn,
#floatingCartButton,
#cartList {
width: 90%;
}
.info-banner .card-body,
.info-callout .card-body {
text-align: center;
gap: 1rem;
}
}
@media (max-width: 575.98px) {
.guest-hero {
padding: 2.2rem 1.35rem;
}
.guest-hero__title {
font-size: 1.65rem;
}
.btn-filter {
font-size: 0.8rem;
}
.input-icon .icon {
left: 1rem;
}
}
</style>
<div class="container position-relative">
<div class="guest-hero px-4 px-lg-5 py-5 mb-5 shadow-sm" data-aos="fade-up">
<div class="row align-items-center g-4">
<div class="col-lg-7">
<span class="guest-hero__badge mb-3">
<i class="fa fa-seedling"></i>
Instalasi Gizi RSAB Harapan Kita
</span>
<h1 class="guest-hero__title fw-bold mb-3 text-white">Menu Sehat Siap Antar ke Ruang Perawatan</h1>
<p class="guest-hero__lead mb-4">
Pilih hidangan bernutrisi tinggi untuk karyawan, keluarga pasien, ataupun masyarakat umum.
Pesanan dimonitor ahli gizi dan dapat dilacak secara daring.
</p>
<div class="d-flex flex-wrap gap-2 justify-content-lg-start justify-content-center">
<a href="#order_guest_id" class="btn btn-light text-success fw-semibold shadow-sm px-4">
<i class="fa fa-utensils me-2"></i>Lihat Menu
</a>
<a href="#" class="btn btn-outline-light text-white fw-semibold px-4 js-open-guide">
<i class="fa fa-book-open me-2"></i>Panduan Pemesanan
</a>
</div>
</div>
<div class="col-lg-5">
<div class="guest-hero__card card border-0 shadow-lg h-100">
<div class="card-body p-4">
<h5 class="fw-semibold text-primary mb-3">Kenapa Order Gizi?</h5>
<ul class="list-unstyled small text-muted mb-0">
<li class="d-flex gap-2 mb-2">
<i class="fa fa-check-circle text-success mt-1"></i>
<span>Resep dibuat dan diawasi ahli gizi sesuai kebutuhan nutrisi pasien dan keluarga.</span>
</li>
<li class="d-flex gap-2 mb-2">
<i class="fa fa-check-circle text-success mt-1"></i>
<span>Pilihan lengkap mulai dari makanan utama, snack, paket hemat, hingga jadwal konsultasi.</span>
</li>
<li class="d-flex gap-2">
<i class="fa fa-check-circle text-success mt-1"></i>
<span>Pemesanan daring cepat, pembayaran fleksibel, dan status pesanan bisa dipantau.</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="filter-toolbar" data-aos="fade-up" data-aos-delay="100">
<div class="card border-0 shadow-sm">
<div class="card-body p-3 p-lg-4">
<div class="d-flex flex-wrap gap-2 justify-content-center" id="tabJenisMenu">
<button type="button" class="btn btn-filter active" data-filter="makanan">
<i class="bi bi-egg-fried me-2"></i>Makanan
</button>
<button type="button" class="btn btn-filter" data-filter="minuman">
<i class="bi bi-cup-straw me-2"></i>Minuman
</button>
<button type="button" class="btn btn-filter" data-filter="snack">
<i class="bi bi-cookie me-2"></i>Snack
</button>
<button type="button" class="btn btn-filter" data-filter="paket">
<i class="bi bi-gift me-2"></i>Paket
</button>
<button type="button" class="btn btn-filter" data-filter="konsultasi">
<i class="bi bi-person-heart me-2"></i>Konsultasi Gizi
</button>
<button type="button" class="btn btn-filter" data-filter="cara_pesan">
<i class="bi bi-journal-text me-2"></i>Cara Pesan
</button>
</div>
<div class="row g-3 align-items-end mt-2" id="tanggal-filter">
<div class="col-lg-6">
<label class="form-label text-muted fw-semibold small text-uppercase mb-2">Cari Menu</label>
<div class="input-icon">
<i class="fa fa-search icon"></i>
<input type="text" class="form-control form-control-lg" id="searchMenu" placeholder="Cari menu favorit..." />
</div>
</div>
<div class="col-lg-6">
<div class="d-flex justify-content-between align-items-center mb-2">
<label class="form-label text-muted fw-semibold small text-uppercase mb-0">
Rentang Tanggal
<a tabindex="0" role="button" class="text-muted ms-1" data-bs-toggle="popover" data-bs-trigger="focus" title="Panduan" data-bs-content="Pilih rentang tanggal untuk melihat menu tersedia.">
<i class="fa fa-info-circle"></i>
</a>
</label>
<button type="button" id="resetTanggal" class="btn btn-link btn-sm text-decoration-none text-muted d-none">Reset</button>
</div>
<div class="input-icon">
<i class="fa fa-calendar-alt icon"></i>
<input type="text" id="tanggal" class="form-control form-control-lg tanggal-input" readonly placeholder="Pilih rentang tanggal" />
</div>
<div id="tanggalTerpilihLabel" class="selected-range small mt-2 d-none">
<i class="fa fa-calendar-check text-success me-2"></i>
<span id="labelTanggalText">Menampilkan menu...</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="info-banner card border-0 shadow-sm mt-4" data-aos="fade-up" data-aos-delay="150">
<div class="card-body d-flex flex-column flex-lg-row align-items-lg-center gap-3">
<div class="soft-badge d-inline-flex align-items-center gap-2">
<i class="fa fa-user-md"></i>
Konsultasi Gizi
</div>
<div class="flex-grow-1 text-muted">
Butuh rekomendasi menu? <a href="#" class="alert-link fw-semibold">Daftar konsultasi</a> atau hubungi
<a href="https://wa.me/08815611382" target="_blank" class="fw-semibold text-decoration-none text-success">08815611382</a>
<span class="d-block small mt-1 text-secondary">Jam layanan: 08.00 - 15.00 WIB</span>
</div>
<div class="d-flex flex-wrap gap-2 justify-content-lg-end">
<a href="https://wa.me/08815611382" target="_blank" class="btn btn-success btn-sm px-3">
<i class="fa-brands fa-whatsapp me-2"></i>Hubungi Kami
</a>
<button type="button" class="btn btn-outline-success btn-sm px-3 js-open-guide d-none d-lg-inline-flex">
<i class="fa fa-journal-text me-2"></i>Cara Pesan
</button> </button>
</div> </div>
</div> </div>
{{-- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 mb-2 ">
<ul class="nav nav-tabs" id="tabJenisMenu">
<li class="nav-item"><a class="nav-link active text-success" href="#" data-filter="makanan">Makanan</a></li>
<li class="nav-item "><a class="nav-link text-black" href="#" data-filter="minuman">Minuman</a></li>
<li class="nav-item"><a class="nav-link text-black" href="#" data-filter="snack">Snack</a></li>
<li class="nav-item"><a class="nav-link text-black" href="#" data-filter="paket">Paket</a></li>
<li class="nav-item"><a class="nav-link text-black" href="#" data-filter="konsultasi">Jadwal Konsultasi Gizi</a></li>
<li class="nav-item"><a class="nav-link text-black" href="#" data-filter="cara_pesan">Cara Pesan</a></li>
</ul>
</div> --}}
</div>
<!-- Filter Pencarian + Tanggal -->
<div class="row gx-2 gy-1 mb-2" id="tanggal-filter">
<!-- Kolom Cari -->
<div class="col-6">
<label class="fw-bold small text-muted mb-1">Cari Makanan</label>
<input type="text" class="form-control form-control-sm"
id="searchMenu" placeholder="Pencarian...">
</div>
<!-- Kolom Tanggal -->
<div class="col-6">
<label class="fw-bold small text-muted mb-1">
Tanggal
<a tabindex="0" role="button" data-bs-toggle="popover"
data-bs-trigger="focus" title="Panduan"
data-bs-content="Pilih rentang tanggal untuk melihat menu tersedia.">
<i class="fa fa-info-circle text-secondary ms-1"></i>
</a>
</label>
<div class="input-group input-group-sm">
<span class="input-group-text bg-white px-2">
<i class="fa fa-calendar-alt text-primary"></i>
</span>
<input type="text" id="tanggal" class="form-control form-control-sm tanggal-input"
readonly placeholder="Pilih rentang tanggal">
<button type="button" id="resetTanggal"
class="btn btn-sm btn-light border d-none" title="Reset">
<i class="fa fa-times text-muted"></i>
</button>
</div>
<div id="tanggalTerpilihLabel"
class="bg-light border text-dark small mt-1 d-none rounded px-2 py-1">
<i class="fa fa-calendar-check text-success me-1"></i>
<span id="labelTanggalText">Menampilkan menu...</span>
</div>
</div>
</div> </div>
<div class="mt-4" id="order_guest_id"></div> <!-- Marquee Info -->
<div class="alert alert-info mb-3 shadow-sm rounded-3 small p-2" role="alert">
<marquee behavior="scroll" direction="left" scrollamount="3"
onmouseover="this.stop()" onmouseout="this.start()">
<i class="fa fa-user-md text-primary me-1"></i>
<strong>Konsultasi Gizi!</strong>
Butuh rekomendasi menu? <a href="#" class="alert-link">Daftar sekarang</a>.
Hubungi <a href="https://wa.me/08815611382" target="_blank">08815611382</a>
<span class="text-muted">(08:00-15:00 WIB)</span>
</marquee>
</div>
<div id="order_guest_id"></div>
<!-- Tombol Menu -->
<button type="button" id="menuBtn" <button type="button" id="menuBtn"
class="btn position-fixed start-50 translate-middle-x rounded-pill shadow-lg d-flex align-items-center gap-2 px-3 py-2 d-none text-white" class="btn btn-danger position-fixed start-50 translate-middle-x
style="bottom: 75px; z-index: 1051; font-size: .85rem;" onclick="toggleCartList()"> rounded-pill shadow-lg d-flex align-items-center gap-2
<i class="fa-solid fa-bell-concierge"></i> px-2 py-1 d-none"
<span>Menu Dipilih</span> style="bottom: 75px; z-index: 1051; font-size: .8rem;" onclick="toggleCartList()">
<i class="fa-solid fa-bell-concierge"></i>
<span>Menu Dipilih</span>
</button> </button>
<div id="cartList" <div id="cartList"
class="position-fixed start-50 translate-middle-x bg-white rounded shadow-lg d-none" class="position-fixed start-50 translate-middle-x bg-white rounded shadow-lg d-none"
style="bottom: 125px; z-index: 1050; width: 90%; max-width: 420px; max-height: 45vh; overflow-y: auto;"> style="bottom: 125px; z-index: 1050; width: 90%; max-width: 420px; max-height: 45vh; overflow-y: auto;">
<div class="p-2" id="cartListBody"> <div class="p-2" id="cartListBody">
<!-- diisi JS --> <!-- diisi JS -->
</div> </div>
<div class="d-flex gap-1 p-2 border-top"> <div class="d-flex gap-1 p-2 border-top">
<a class="btn btn-sm btn-success flex-fill" href="/checkout">Pesan Sekarang</a> <a class="btn btn-sm btn-success flex-fill" href="/checkout">Pesan Sekarang</a>
</div> </div>
</div> </div>
<!-- Floating Cart -->
<div id="floatingCartButton" <div id="floatingCartButton"
class="position-fixed start-50 translate-middle-x text-white rounded-pill shadow-lg d-none d-flex align-items-center justify-content-between px-3 py-2" class="position-fixed start-50 translate-middle-x bg-success text-white
rounded-pill shadow-lg d-none d-flex align-items-center
justify-content-between px-3 py-2"
onclick="checkout()" onclick="checkout()"
style="bottom: 15px; z-index: 1050; width: 90%; max-width: 420px; font-size: .8rem;"> style="bottom: 15px; z-index: 1050; width: 90%; max-width: 420px; font-size: .8rem;">
<div> <div>
<strong><span id="floatingCartCount">0</span> item</strong><br> <strong><span id="floatingCartCount">0</span> item</strong><br>
<small id="floatingCartDesc" class="text-white-50">Lihat keranjang</small> <small id="floatingCartDesc">Lihat keranjang</small>
</div> </div>
<div class="btn btn-sm rounded-circle"> <div class="btn btn-light btn-sm rounded-circle">
<i class="fa-solid fa-cart-shopping text-white"></i> <i class="fa-solid fa-cart-shopping text-success"></i>
</div> </div>
</div> </div>
<div class="info-callout card border-0 shadow-sm mt-5" data-aos="fade-up" data-aos-delay="200">
<div class="card-body d-flex flex-column flex-md-row align-items-start gap-3"> <div class="alert alert-info py-3 px-4 small border-start border-4 border-primary mt-3" role="alert">
<div class="icon-wrapper"> <div class="fw-bold mb-2">
<i class="fa fa-info-circle"></i> <i class="fa fa-info-circle me-1"></i>Informasi
</div>
<div>
<h6 class="fw-semibold text-primary mb-2">Butuh Bantuan?</h6>
<p class="mb-2 text-muted small">
Hubungi WhatsApp <strong>Instalasi Gizi</strong> di
<a href="https://wa.me/08815611382" target="_blank" class="fw-semibold text-decoration-none text-success">08815611382</a>
untuk pertanyaan seputar pemesanan.
</p>
<span class="badge bg-light text-muted fw-normal">Jam kerja: 08.00 - 15.00 WIB</span>
</div>
</div> </div>
<ul class="mb-0 ps-3 pe-3">
<li>
Butuh bantuan? Hubungi WhatsApp <strong>Instalasi Gizi</strong>:
<a href="https://wa.me/08815611382 " target="_blank">08815611382 </a> <br>
<span class="text-muted">Jam kerja: 08.00 - 15.00 WIB</small>
</li>
</ul>
</div> </div>
</div> </div>
</section> </section>
@ -460,68 +150,58 @@
<script src="{{ ver('/js/order_guest/functions.js') }}"></script> <script src="{{ ver('/js/order_guest/functions.js') }}"></script>
<script src="{{ ver('/js/order_guest/index.js') }}"></script> <script src="{{ ver('/js/order_guest/index.js') }}"></script>
<script> <script>
const labelElement = document.getElementById('tanggalTerpilihLabel'); const datePicker = flatpickr("#tanggal", {
const labelText = document.getElementById('labelTanggalText');
const resetTanggalButton = document.getElementById('resetTanggal');
const datePicker = flatpickr("#tanggal", {
dateFormat: "Y-m-d", dateFormat: "Y-m-d",
mode: "range", mode: "range",
onChange: function (selectedDates) { onChange: function (selectedDates, dateStr) {
const label = document.getElementById('tanggalTerpilihLabel');
const resetBtn = document.getElementById('resetTanggal');
if (selectedDates.length === 2) { if (selectedDates.length === 2) {
const [start, end] = selectedDates; const [start, end] = selectedDates;
const startDay = start.getDate(); const startDay = start.getDate();
const endDay = end.getDate(); const endDay = end.getDate();
if (start.getTime() === end.getTime()) { if (start.getTime() === end.getTime()) {
labelText.textContent = `Menampilkan menu tersedia untuk tanggal: ${formatTanggal(start)}`; label.textContent = `Menampilkan menu tersedia untuk tanggal: ${formatTanggal(start)}`;
} else { } else {
labelText.textContent = `Menampilkan menu tersedia dari ${formatTanggal(start)} hingga ${formatTanggal(end)}`; label.textContent = `Menampilkan menu tersedia dari ${formatTanggal(start)} hingga ${formatTanggal(end)}`;
} }
const activeFilter = document.querySelector('#tabJenisMenu .btn.btn-success.active')?.dataset?.filter || null;
const activeFilter = document.querySelector('#tabJenisMenu .btn.active')?.dataset?.filter || null; // Baru kirim ke fetchMenu jika dua tanggal sudah dipilih
fetchMenu({ jenis_menu: activeFilter, tanggal_awal: startDay, tanggal_akhir: endDay }); fetchMenu({ jenis_menu: activeFilter, tanggal_awal: startDay, tanggal_akhir: endDay });
labelElement.classList.remove('d-none'); label.classList.remove('d-none');
resetTanggalButton.classList.remove('d-none'); resetBtn.classList.remove('d-none');
} }
} }
});
function formatTanggal(dateObj) {
const bulan = [
"Januari", "Februari", "Maret", "April", "Mei", "Juni",
"Juli", "Agustus", "September", "Oktober", "November", "Desember"
];
const d = dateObj.getDate();
const m = bulan[dateObj.getMonth()];
const y = dateObj.getFullYear();
return `${d} ${m} ${y}`;
}
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('[data-bs-toggle="popover"]').forEach(el => new bootstrap.Popover(el));
});
resetTanggalButton.addEventListener('click', function () {
const activeFilter = document.querySelector('#tabJenisMenu .btn.active')?.dataset?.filter || null;
datePicker.clear();
labelElement.classList.add('d-none');
labelText.textContent = 'Menampilkan menu...';
resetTanggalButton.classList.add('d-none');
fetchMenu({ jenis_menu: activeFilter, tanggal_awal: null, tanggal_akhir: null });
});
document.querySelectorAll('.js-open-guide').forEach(btn => {
btn.addEventListener('click', function (e) {
e.preventDefault();
const guideBtn = document.querySelector('#tabJenisMenu .btn[data-filter="cara_pesan"]');
if (guideBtn) {
guideBtn.click();
guideBtn.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}); });
});
function formatTanggal(dateObj) {
const bulan = [
"Januari", "Februari", "Maret", "April", "Mei", "Juni",
"Juli", "Agustus", "September", "Oktober", "November", "Desember"
];
const d = dateObj.getDate();
const m = bulan[dateObj.getMonth()];
const y = dateObj.getFullYear();
return `${d} ${m} ${y}`;
}
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('[data-bs-toggle="popover"]').forEach(el => new bootstrap.Popover(el));
});
document.getElementById('resetTanggal').addEventListener('click', function() {
const activeFilter = document.querySelector('#tabJenisMenu .nav-link.active')?.dataset?.filter || null;
datePicker.clear(); // Reset tanggal
document.getElementById('tanggalTerpilihLabel').classList.add('d-none'); // Sembunyikan label
document.getElementById('tanggalTerpilihLabel').textContent = '';
document.getElementById('resetTanggal').classList.add('d-none');
fetchMenu({ jenis_menu: activeFilter, tanggal_awal: null, tanggal_akhir: null, });
});
</script> </script>
@endsection @endsection

View File

@ -5,6 +5,7 @@
<div class="container position-relative d-flex align-items-center justify-content-between"> <div class="container position-relative d-flex align-items-center justify-content-between">
<a href="/" class="logo d-flex align-items-center me-auto"> <a href="/" class="logo d-flex align-items-center me-auto">
<!-- Uncomment the line below if you also wish to use an image logo --> <!-- Uncomment the line below if you also wish to use an image logo -->
<img src="/logo/gizi.png" alt="Logo RSAB HARAPAN KITA" class="" style="height:125px;">
<img src="/logo/logo_rsabhk.png" alt="Logo RSAB HARAPAN KITA" class="logo-img"> <img src="/logo/logo_rsabhk.png" alt="Logo RSAB HARAPAN KITA" class="logo-img">
<h1 class="sitename"></h1> <h1 class="sitename"></h1>
</a> </a>
@ -16,7 +17,7 @@
MCU MCU
</button> </button>
@endif @endif
<button type="button" class="btn btn-outline-success position-relative me-1 d-flex" style="font-size:14px;" onclick="checkOrderHref()"> <button type="button" class="btn btn-outline-success position-relative d-flex lh-sm" style="font-size:14px;" onclick="checkOrderHref()">
Check Order Check Order
</button> </button>

View File

@ -0,0 +1,155 @@
@extends('guest.layout.main')
@section('body_main_guests')
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8 col-lg-7">
<div class="text-center mb-5">
@if($type === "pengguna_baru")
<h2 class="fw-bold text-dark mb-3">Form Kepuasan Pelanggan Terkait Penggunaan Aplikasi Catering Gizi RSABHK</h2>
@else
<h2 class="fw-bold text-dark mb-3">Form Kepuasan Pelanggan Catering Instalasi Gizi RSAB HK </h2>
@endif
<p class="text-secondary mx-auto" style="max-width: 500px;">
Terima kasih telah memesan di <strong>Catering Instalasi Gizi RSAB HK</strong>. Masukan Anda sangat berarti bagi peningkatan kualitas layanan kami.
</p>
<div class="mx-auto mt-3"></div>
</div>
<form action="" method="POST" id="surveyForm">
@csrf
<div class="card border-0 shadow-sm mb-4 overflow-hidden" style="border-radius: 15px;">
{{-- <div class="card-body p-4">
<div class="d-flex align-items-center mb-3">
<div class="bg-light rounded-circle p-2 me-3">
<i class="fas fa-user text-primary"></i>
</div>
<label class="form-label fw-semibold mb-0">Nama Pelanggan <span class="text-danger">*</span></label>
</div>
<input type="text" name="nama_pelanggan" class="form-control custom-input" placeholder="Masukkan nama lengkap Anda..." required>
</div> --}}
</div>
<div class="card border-0 shadow-sm mb-4" style="border-radius: 15px;">
<div class="card-body p-4 text-center">
@if($type === "pengguna_baru")
<label class="form-label fw-semibold d-block mb-4">Menurut Anda apakah aplikasi pemesanan catering gizi saat ini mudah untuk digunakan? <span class="text-danger">*</span></label>
@else
<label class="form-label fw-semibold d-block mb-4">Bagaimana pelayanan catering gizi yang anda dapatkan ? <span class="text-danger">*</span></label>
@endif
<p class="text-muted small mb-4"><i class="fas fa-info-circle me-1"></i> Silakan pilih salah satu ikon di bawah ini</p>
<input type="hidden" name="type" value={{ $type }} />
<input type="hidden" name="no_order" value={{ $no_order }} />
<div class="row g-3">
<div class="col-6">
<input type="radio" class="btn-check" name="kepuasan" id="puas" value="Puas" required>
<label class="btn btn-outline-light w-100 p-4 emoji-card" for="puas">
<div class="emoji-icon mb-2"><img src="/logo/nice.png" style="height:120px;"/> </div>
<div class="fw-bold text-dark">Puas</div>
</label>
</div>
<div class="col-6">
<input type="radio" class="btn-check" name="kepuasan" id="tidak_puas" value="Tidak Puas">
<label class="btn btn-outline-light w-100 p-4 emoji-card" for="tidak_puas">
<div class="emoji-icon mb-2"><img src="/logo/no_nice.png" style="height:120px;"/></div>
<div class="fw-bold text-dark">Tidak Puas</div>
</label>
</div>
</div>
</div>
</div>
<div class="card border-0 shadow-sm mb-4" style="border-radius: 15px;">
<div class="card-body p-4">
<div class="d-flex align-items-center mb-3">
<div class="bg-light rounded-circle p-2 me-3">
<i class="fas fa-comment-dots text-primary"></i>
</div>
<label class="form-label fw-semibold mb-0">Kritik dan Saran <span class="text-danger">*</span></label>
</div>
<textarea name="kritik_saran" class="form-control custom-input" rows="3" placeholder="Tuliskan masukan atau saran Anda di sini..." required></textarea>
</div>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end mb-5">
{{-- <button type="reset" class="btn btn-light px-4 fw-medium text-muted">Tutup</button> --}}
<button type="submit" class="btn btn-primary px-5 fw-bold shadow-sm">Kirim Masukan</button>
</div>
</form>
</div>
</div>
</div>
<style>
/* Emoji Card Selector */
.emoji-card {
border: 2px solid #9b9c9e !important;
border-radius: 15px !important;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
background: #fff;
}
.emoji-icon {
font-size: 2.5rem;
transition: transform 0.3s ease;
}
.btn-check:checked + .emoji-card {
background-color: #b8ddff !important;
transform: translateY(-5px);
}
.btn-check:checked + .emoji-card .emoji-icon {
transform: scale(1.2);
}
.emoji-card:hover {
border-color: #0c0c0c !important;
background: #0f0f0f;
}
/* Requirement text */
.text-danger {
font-size: 0.8rem;
}
</style>
<script>
$("#surveyForm").on('submit', async function(e){
e.preventDefault()
const buttonSubmit = $(this).find('button[type="submit"]')
if(buttonSubmit.prop('disabled')) return;
buttonSubmit.prop('disabled', true).html('<i class="fas fa-spinner fa-spin me-2"></i>Memperoses')
const formData = new FormData(this);
try {
const response = await fetch('/survey', {
method: 'POST',
body: formData,
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
}
});
const result = await response.json()
if(result.status){
Swal.fire({
title: 'Survei Berhasil!',
text: 'Terima kasih, Masukan anda sangat berarti bagi kami.',
icon: 'success',
confirmButtonText: 'Berhasil!',
confirmButtonColor: '#28a745'
}).then(() => {
window.location.href = "/success-page"; // kehalaman success
});
}
} catch (error) {
Swal.fire({
title: 'Gagal!',
text: "Terjadi kesalahan saat mengirim melakukan survei.",
icon: 'error',
confirmButtonText: 'Tutup!'
})
}finally{
buttonSubmit.prop('disabled', false).html('Selesaikan Survei')
}
})
</script>
@endsection

View File

@ -10,6 +10,7 @@ use App\Http\Controllers\KlasifikasiMenuController;
use App\Http\Controllers\MasterMcuController; use App\Http\Controllers\MasterMcuController;
use App\Http\Controllers\MenuController; use App\Http\Controllers\MenuController;
use App\Http\Controllers\PesananController; use App\Http\Controllers\PesananController;
use App\Http\Controllers\SurveyController;
use App\Mail\NotifikasiCustomer; use App\Mail\NotifikasiCustomer;
use Barryvdh\DomPDF\Facade\Pdf; use Barryvdh\DomPDF\Facade\Pdf;
use Barryvdh\Snappy\Facades\SnappyPdf; use Barryvdh\Snappy\Facades\SnappyPdf;
@ -20,8 +21,8 @@ use Illuminate\Support\Facades\Route;
// return view('layouts.blank'); // return view('layouts.blank');
// }); // });
Route::get('/login', [AuthController::class, 'index'])->name('login')->middleware('guest'); Route::get('/login', [AuthController::class, 'index'])->name('login')->middleware('guest');
Route::post('/login', [AuthController::class, 'authanticate']); Route::post('/login', [AuthController::class, 'authanticate'])->middleware('throttle:login');
Route::get('/captcha/login', [AuthController::class, 'captcha'])->name('captcha.login');
Route::group(['middleware' => ['auth']], function(){ Route::group(['middleware' => ['auth']], function(){
Route::group(['prefix' => 'dashboard'], function(){ Route::group(['prefix' => 'dashboard'], function(){
@ -83,6 +84,11 @@ Route::group(['middleware' => ['auth']], function(){
Route::get('/pekerjaan/detail/{id}', [PesananController::class, 'getPekerjaanDetail']); Route::get('/pekerjaan/detail/{id}', [PesananController::class, 'getPekerjaanDetail']);
Route::get('/pekerjaan/label', [PesananController::class, 'downloadLabel']); Route::get('/pekerjaan/label', [PesananController::class, 'downloadLabel']);
Route::get('/data/pending-pekerjaan', [PesananController::class, 'dataPekerjaanPending']); Route::get('/data/pending-pekerjaan', [PesananController::class, 'dataPekerjaanPending']);
Route::get('/survey', [SurveyController::class, 'dashboardSurvey']);
Route::get('/datatable/survey', [SurveyController::class, 'datatable']);
Route::get('/chart/survey', [SurveyController::class, 'chartDataSurvey']);
Route::post('/survey/export', [SurveyController::class, 'exportSurveyExcel']);
}); });
Route::post('/logout', [AuthController::class, 'logout']); Route::post('/logout', [AuthController::class, 'logout']);
@ -103,6 +109,9 @@ Route::get('/success-mcu', [CustomerController::class, 'successMcu']);
Route::get('/karyawan', [CustomerController::class, 'karyawan']); Route::get('/karyawan', [CustomerController::class, 'karyawan']);
Route::get('/unit-instalasi', [CustomerController::class, 'unitInstalasi']); Route::get('/unit-instalasi', [CustomerController::class, 'unitInstalasi']);
Route::get('/server-time', fn()=> response()->json(['now' => now()])); Route::get('/server-time', fn()=> response()->json(['now' => now()]));
Route::get('/survey', [SurveyController::class, 'index']);
Route::post('/survey', [SurveyController::class, 'store']);
// Route::get('/send-mail', function(){ // Route::get('/send-mail', function(){
// Mail::to('skyjok14@gmail.com')->queue(new NotifikasiCustomer('Test')); // Mail::to('skyjok14@gmail.com')->queue(new NotifikasiCustomer('Test'));