diff --git a/Modules/Internal/Http/Controllers/Api/RequestLogController.php b/Modules/Internal/Http/Controllers/Api/RequestLogController.php
index ba9ab91f..4058a280 100755
--- a/Modules/Internal/Http/Controllers/Api/RequestLogController.php
+++ b/Modules/Internal/Http/Controllers/Api/RequestLogController.php
@@ -1224,6 +1224,34 @@ class RequestLogController extends Controller
]);
}
}
+ return Helper::responseJson(data: $request->toArray(), message: 'File Success Uploaded');
+ }
+
+ public function approvalFiles(Request $request, $id)
+ {
+ Helper::setCustomPHPIniSettings();
+ $requestLog = RequestLog::findOrFail($id);
+ $nominal = $request->nominal;
+ if($nominal){
+ $requestLog->nominal = $nominal;
+ $requestLog->save();
+ }
+ if ($request->hasFile('approval_files')) {
+ foreach ($request->approval_files as $file) {
+ $fileData = File::storeFile('approval', $id, $file);
+ $requestLog->files()->updateOrCreate([
+ 'type' => 'approval',
+ 'name' => $fileData['name'],
+ 'original_name' => $file->getClientOriginalName(),
+ 'extension' => $file->getClientOriginalExtension(),
+ 'source' => env('FILESYSTEM_DISK'),
+ 'path' => $fileData['path'],
+ 'created_by' => auth()->user()->id,
+ 'updated_by' => auth()->user()->id,
+ 'reason' => $request->reason,
+ ]);
+ }
+ }
return Helper::responseJson(data: $request->toArray(), message: 'File Success Uploaded');
}
diff --git a/Modules/Internal/Routes/api.php b/Modules/Internal/Routes/api.php
index 0445b0d2..6709a385 100755
--- a/Modules/Internal/Routes/api.php
+++ b/Modules/Internal/Routes/api.php
@@ -323,6 +323,7 @@ Route::prefix('internal')->group(function () {
Route::post('customer-service/request/exportFiledInvoice', [RequestLogController::class, 'exportFiledInvoice']);
Route::get('customer-service/request/data', [RequestLogController::class, 'generateDataRequestLogExcel']);
Route::post('customer-service/request/{id}/add_file', [RequestLogController::class, 'requestFiles']);
+ Route::post('customer-service/request/{id}/approval_files', [RequestLogController::class, 'approvalFiles']);
Route::post('customer-service/request/{id}/delete_file', [RequestLogController::class, 'deleteFiles']);
Route::post('customer-service/request/final-log', [RequestLogController::class, 'updateFinalLog']);
diff --git a/Modules/Internal/Transformers/RequestLogShowResource.php b/Modules/Internal/Transformers/RequestLogShowResource.php
index 647de78d..9349c037 100755
--- a/Modules/Internal/Transformers/RequestLogShowResource.php
+++ b/Modules/Internal/Transformers/RequestLogShowResource.php
@@ -174,6 +174,7 @@ class RequestLogShowResource extends JsonResource
'keterangan' => $requestLog['keterangan'],
'hak_kamar_pasien' => $requestLog['hak_kamar_pasien'],
'penempatan_kamar' => $requestLog['penempatan_kamar'],
+ 'nominal' => $requestLog['nominal'],
'catatan' => $requestLog['catatan'],
'reason' => $requestLog['reason'],
'diagnosis' => $icd,
diff --git a/app/Models/File.php b/app/Models/File.php
index a6adacf9..793dd4d3 100755
--- a/app/Models/File.php
+++ b/app/Models/File.php
@@ -111,28 +111,62 @@ class File extends Model
// return $path;
// }
+ // public static function storeFile($type, $id, $file)
+ // {
+ // // Pastikan directory tidak punya trailing slash
+ // $directory = rtrim(self::getDirectory($type), '/');
+
+ // // Buat nama file yang unik dan aman
+ // $originalName = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
+ // $extension = $file->getClientOriginalExtension();
+ // $safeName = Str::slug($originalName);
+ // $uniqueName = $safeName . '-' . uniqid() . '.' . $extension;
+
+ // // Upload file ke disk 's3' dengan visibility 'public'
+ // $path = Storage::disk('s3')->putFileAs(
+ // $directory,
+ // $file,
+ // $uniqueName,
+ // 'public'
+ // );
+
+ // // Kembalikan path dan nama unik agar bisa digunakan di controller
+ // return [
+ // 'path' => $directory . '/' . $uniqueName, // hasil konsisten
+ // 'name' => $uniqueName,
+ // ];
+ // }
+
public static function storeFile($type, $id, $file)
{
- // Pastikan directory tidak punya trailing slash
+ // 1. Ambil nama disk dari konfigurasi default
+ // Nilainya akan 'public', 'local', atau 's3' tergantung .env Anda
+ $disk = config('filesystems.default');
+
$directory = rtrim(self::getDirectory($type), '/');
- // Buat nama file yang unik dan aman
+ // Buat nama file yang unik dan aman (kode Anda sudah bagus)
$originalName = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
$extension = $file->getClientOriginalExtension();
$safeName = Str::slug($originalName);
$uniqueName = $safeName . '-' . uniqid() . '.' . $extension;
- // Upload file ke disk 's3' dengan visibility 'public'
- $path = Storage::disk('s3')->putFileAs(
- $directory,
- $file,
- $uniqueName,
- 'public'
+ // 2. Gunakan disk yang sudah dinamis
+ $path = Storage::disk($disk)->putFileAs(
+ $directory,
+ $file,
+ $uniqueName
);
- // Kembalikan path dan nama unik agar bisa digunakan di controller
+ // 3. (Sangat Direkomendasikan) Tambahkan penanganan error
+ if ($path === false) {
+ Log::error("Gagal menyimpan file ke disk '{$disk}' pada path: {$directory}/{$uniqueName}");
+ return false; // Kembalikan false jika upload gagal
+ }
+
+ // 4. Kembalikan path asli dari hasil upload untuk konsistensi
return [
- 'path' => $directory . '/' . $uniqueName, // hasil konsisten
+ 'path' => $path, // Gunakan $path yang dikembalikan oleh Storage
'name' => $uniqueName,
];
}
diff --git a/app/Models/RequestLog.php b/app/Models/RequestLog.php
index bd180522..0ae461e9 100755
--- a/app/Models/RequestLog.php
+++ b/app/Models/RequestLog.php
@@ -53,7 +53,8 @@ class RequestLog extends Model
'created_final_by',
'specialities_id',
'dppj',
- 'type_of_member'
+ 'type_of_member',
+ 'nominal',
];
protected $hidden = [
diff --git a/database/migrations/2025_09_10_103219_add_columns_nominal_to_table_request_log.php b/database/migrations/2025_09_10_103219_add_columns_nominal_to_table_request_log.php
new file mode 100644
index 00000000..f2294eab
--- /dev/null
+++ b/database/migrations/2025_09_10_103219_add_columns_nominal_to_table_request_log.php
@@ -0,0 +1,32 @@
+integer('nominal')->default(0)->after('total_cob');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('table_request_log', function (Blueprint $table) {
+ $table->dropColumn('nominal');
+ });
+ }
+};
diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogSendWa.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogSendWa.tsx
new file mode 100755
index 00000000..ddd123ab
--- /dev/null
+++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogSendWa.tsx
@@ -0,0 +1,185 @@
+import { Stack, Typography, Button, Paper, Grid, IconButton, TextField } from "@mui/material";
+import MuiDialog from "@/components/MuiDialog";
+import { fDate, fDateTimesecond } from '@/utils/formatTime';
+import { ContentCopy, WhatsApp, Instagram, Facebook, Telegram } from "@mui/icons-material";
+
+type DialogConfirmationType = {
+ openDialog: boolean;
+ setOpenDialog: any;
+ onSubmit?: void;
+ requestLog: any;
+ shareLink: boolean;
+};
+
+export default function DialogSendWa({
+ requestLog,
+ setOpenDialog,
+ openDialog,
+ shareLink = false,
+}: DialogConfirmationType) {
+ const data = {
+ provider: requestLog?.provider || "LOG",
+ memberId: requestLog?.member_id || "-",
+ policyNumber: requestLog?.policy_number || "-",
+ name: requestLog?.name || "-",
+ submissionDate: requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : "-",
+ claimMethod: requestLog?.claim_method || "-",
+ serviceType: requestLog?.service_type || "-",
+ linkApproval: requestLog?.url_approval || "https://example.com/approval-link",
+ };
+
+ const getContent = () => (
+
+ Are you sure want to send this request ?
+
+
+
+
+ Member ID
+
+
+
+ {data.memberId}
+
+
+
+
+ Policy Number
+
+
+
+ {data.policyNumber}
+
+
+
+
+ Name
+
+
+
+ {data.name}
+
+
+
+
+ Submission Date
+
+
+
+ {data.submissionDate}
+
+
+
+
+ Claim Method
+
+
+
+ {data.claimMethod}
+
+
+
+
+ Service Type
+
+
+
+ {data.serviceType}
+
+
+
+ {shareLink ? (
+ <>
+ Share this link only with authorized parties!
+ {/*
+
+
+
+
+
+
+
+
+
+
+
+
+ */}
+
+ or copy link
+
+
+
+
+ >
+ ): null }
+
+ );
+
+ const getAction = () => {
+ if (shareLink) {
+ return (
+
+
+
+ );
+ }
+
+ const handleSend = () => {
+ const message = `*Request Approval*
+ Yth. Bapak/Ibu, Nama Penerima
+ Mohon persetujuan atas data berikut:
+
+ Provider: *${data.provider}*
+ Member ID: ${data.memberId}
+ Nama: ${data.name}
+ Policy Number: ${data.policyNumber}
+ Submission Date: ${data.submissionDate}
+ Claim Method: ${data.claimMethod}
+ Service Type: ${data.serviceType}
+
+ Silakan klik link berikut untuk approval:
+ ${data.linkApproval}`;
+
+ const encodedMessage = encodeURIComponent(message);
+ const waUrl = `https://wa.me/6283807417196?text=${encodedMessage}`;
+ window.open(waUrl, "_blank");
+ };
+
+ return (
+
+
+
+
+ );
+ };
+
+ return (
+
+ );
+}
diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx
index 6c5eeb16..fb45bb08 100755
--- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx
+++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx
@@ -30,6 +30,7 @@ import { useFieldArray, useForm } from 'react-hook-form';
import { useNavigate, useParams, useLocation } from 'react-router-dom';
import { useEffect, useState, useRef, useMemo } from 'react';
import axios from '../../../utils/axios';
+import { enqueueSnackbar } from 'notistack';
// pages
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
import { DetailFinalLogType } from './Model/Types';
@@ -43,6 +44,7 @@ import { Delete, EditOutlined, ExpandMore } from '@mui/icons-material';
import {BenefitData } from '../FinalLog/Model/Types'
import AddIcon from '@mui/icons-material/Add';
import { LoadingButton } from '@mui/lab';
+import { makeFormData } from '@/utils/jsonToFormData';
// Import Card Detail Final LOG
import CardDetail from '../Components/CardDetail';
@@ -67,6 +69,8 @@ import CardFile from '../Components/CardFile';
import DialogEditFinalLOG from './Components/DialogEditFinalLOG';
import DialogDeleteFileLog from './Components/DialogDeleteFileLog';
import DialogUploadFileFinalLog from './Components/DialogUploadFileFinalLog';
+import DialogSendWa from './Components/DialogSendWa';
+import { set } from 'nprogress';
// ----------------------------------------------------------------------
@@ -79,6 +83,7 @@ export default function Detail() {
const { themeStretch } = useSettings();
const [requestLog, setRequestLog] = useState();
const [isReversal, setIsReversal] = useState(false);
+ const [submitLoading, setSubmitLoading] = useState(false);
const defaultValues: any = {nominal : 0};
const validationSchema = Yup.object().shape({nominal: Yup.number().typeError('Nominal harus berupa angka').required('Nominal harus diisi')})
@@ -91,7 +96,25 @@ export default function Detail() {
const { handleSubmit, reset, watch, setValue, formState: { isDirty, isSubmitting, errors } } = methods;
const onSubmit = async (data: any) => {
- alert('Nominal: ' + data.nominal);
+ setSubmitLoading(true);
+ const formData = makeFormData({
+ request_logs_id: id,
+ approval_files: fileApprovals,
+ nominal: data.nominal,
+ });
+ axios
+ .post(`/customer-service/request/${id}/approval_files`, formData)
+ .then((response) => {
+ enqueueSnackbar('Berhasil membuat data', { variant: 'success' });
+
+ window.location.reload()
+ })
+ .catch(({ response }) => {
+ enqueueSnackbar('Something Went Wrong', { variant: 'error' });
+ })
+ .then(() => {
+ setSubmitLoading(false);
+ });
}
const { id } = useParams();
@@ -130,6 +153,8 @@ export default function Detail() {
const [openDialogEditDetail, setDialogDEditDetail] = useState(false);
const [openDialogBenefit, setDialogBenefit] = useState(false);
const [openDialogMedicine, setDialogMedicine] = useState(false);
+ const [openDialogSendWa, setDialogSendWa] = useState(false);
+ const [shareLink, setShareLink] = useState(false);
// Handel Delete Detail Benefit
const [idBenefitData, setIdBenefitData] = useState();
@@ -175,16 +200,16 @@ export default function Detail() {
const fileDiagnosaInput = useRef(null);
- const [fileDiagnosas, setFileDiagnosas] = useState([]);
+ const [fileApprovals, setFileApproval] = useState([]);
const handleDiagnosaInputChange = (event:any) => {
if (event.target.files[0]) {
- setFileDiagnosas([...fileDiagnosas, ...event.target.files]);
+ setFileApproval([...fileApprovals, ...event.target.files]);
} else {
console.log('NO FILE');
}
};
- const removeDiagnosaFiles = (filesState:any, index:any) => {
- setFileDiagnosas(
+ const removeApprovalFiles = (filesState:any, index:any) => {
+ setFileApproval(
filesState.filter((file:any, fileIndex:any) => {
return fileIndex != index;
})
@@ -381,7 +406,7 @@ export default function Detail() {
Upload Tindakan Persetujuan
- {fileDiagnosas?.map((file: any, index: number) => (
+ {fileApprovals?.map((file: any, index: number) => (
removeDiagnosaFiles(fileDiagnosas, index)}
+ onClick={() => removeApprovalFiles(fileApprovals, index)}
/>
))}
@@ -438,29 +463,60 @@ export default function Detail() {
label="Nominal"
required
placeholder="Nominal"
+ value={requestLog?.nominal || 0}
/>
-
Simpan
-
+ */}
+
+ {/* TOMBOL SIMPAN DI KIRI */}
+
+ Simpan
+
+
+ {/* Ini adalah spacer untuk mendorong tombol berikutnya ke kanan */}
+
+
+ {/* GRUP TOMBOL DI KANAN */}
+
+
+
+
+
-
+
+
)}
{/* FILE YANG SUDAH TERUPLOAD */}
- {requestLog?.files?.map((documentType, index) => (
+ {requestLog?.files
+ ?.filter((document) => document.type === 'approval')
+ ?.map((documentType, index) => (
+
+
+
+
{/* Medicine */}
@@ -843,7 +909,9 @@ export default function Detail() {
) : null }
- {requestLog?.files?.map((documentType, index) => (
+ {requestLog?.files
+ ?.filter((document) => document.type !== 'approval')
+ ?.map((documentType, index) => (