feat: add lab tests, patient file management, and prescription improvements
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
namespace App\Filament\Resources;
|
||||
use App\Filament\Resources\PatientResource\Pages;
|
||||
use App\Filament\Resources\PatientResource\RelationManagers\VisitsRelationManager;
|
||||
use App\Models\LabTest;
|
||||
use App\Models\Medication;
|
||||
use App\Models\Patient;
|
||||
use App\Models\PatientIllness;
|
||||
@@ -34,6 +35,8 @@
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Components\Grid;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\Tabs;
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Enums\FontWeight;
|
||||
use Filament\Support\Enums\Width;
|
||||
@@ -125,10 +128,6 @@ public static function form(Schema $schema): Schema
|
||||
|
||||
TextInput::make('father_name')
|
||||
->label(__('patients.fields.father_name'))
|
||||
->required()
|
||||
->validationMessages([
|
||||
'required' => __('patients.validation.father_name_required'),
|
||||
])
|
||||
->maxLength(50),
|
||||
|
||||
TextInput::make('icno')
|
||||
@@ -203,6 +202,7 @@ public static function form(Schema $schema): Schema
|
||||
|
||||
TextInput::make('refered_by')
|
||||
->label(__('patients.fields.refered_by'))
|
||||
->required()
|
||||
->maxLength(50),
|
||||
|
||||
TextInput::make('doc_id')
|
||||
@@ -286,11 +286,25 @@ public static function form(Schema $schema): Schema
|
||||
->schema([
|
||||
RichEditor::make('surgery_before')
|
||||
->label(__('patients.fields.surgery_before'))
|
||||
->extraInputAttributes(['style' => 'min-height: 150px']),
|
||||
->extraInputAttributes(['style' => 'min-height: 150px'])
|
||||
->toolbarButtons([
|
||||
['bold', 'italic', 'underline', 'strike', 'link'],
|
||||
['highlight'],
|
||||
['h2', 'h3', 'alignStart', 'alignCenter', 'alignEnd'],
|
||||
['blockquote', 'bulletList', 'orderedList'],
|
||||
['undo', 'redo'],
|
||||
]),
|
||||
|
||||
RichEditor::make('sergery_after')
|
||||
->label(__('patients.fields.sergery_after'))
|
||||
->extraInputAttributes(['style' => 'min-height: 150px']),
|
||||
->extraInputAttributes(['style' => 'min-height: 150px'])
|
||||
->toolbarButtons([
|
||||
['bold', 'italic', 'underline', 'strike', 'link'],
|
||||
['highlight'],
|
||||
['h2', 'h3', 'alignStart', 'alignCenter', 'alignEnd'],
|
||||
['blockquote', 'bulletList', 'orderedList'],
|
||||
['undo', 'redo'],
|
||||
]),
|
||||
])
|
||||
->columns(2)
|
||||
->columnSpanFull(),
|
||||
@@ -301,8 +315,14 @@ public static function form(Schema $schema): Schema
|
||||
->label(__('patients.fields.photos_before'))
|
||||
->multiple()
|
||||
->image()
|
||||
->panelLayout('grid')
|
||||
->extraAttributes(['class' => 'fi-photo-gallery'])
|
||||
->disk('public')
|
||||
->directory('surgery_photos/before')
|
||||
->directory(function ($record) {
|
||||
$year = \Morilog\Jalali\Jalalian::now()->getYear();
|
||||
$icno = $record?->icno ?? '';
|
||||
return "files/surgery_photos/{$year}/{$icno}/before";
|
||||
})
|
||||
->downloadable()
|
||||
->openable()
|
||||
->fetchFileInformation(false),
|
||||
@@ -311,8 +331,14 @@ public static function form(Schema $schema): Schema
|
||||
->label(__('patients.fields.photos_after'))
|
||||
->multiple()
|
||||
->image()
|
||||
->panelLayout('grid')
|
||||
->extraAttributes(['class' => 'fi-photo-gallery'])
|
||||
->disk('public')
|
||||
->directory('surgery_photos/after')
|
||||
->directory(function ($record) {
|
||||
$year = \Morilog\Jalali\Jalalian::now()->getYear();
|
||||
$icno = $record?->icno ?? '';
|
||||
return "files/surgery_photos/{$year}/{$icno}/after";
|
||||
})
|
||||
->downloadable()
|
||||
->openable()
|
||||
->fetchFileInformation(false),
|
||||
@@ -321,35 +347,41 @@ public static function form(Schema $schema): Schema
|
||||
->label(__('patients.fields.videos'))
|
||||
->multiple()
|
||||
->disk('public')
|
||||
->directory('surgery_photos/videos')
|
||||
->acceptedFileTypes(['video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/x-matroska', 'video/webm', 'audio/mpeg', 'audio/mp3', 'audio/wav', 'audio/ogg', 'audio/aac'])
|
||||
->directory(function ($record) {
|
||||
$year = \Morilog\Jalali\Jalalian::now()->getYear();
|
||||
$icno = $record?->icno ?? '';
|
||||
return "files/surgery_photos/{$year}/{$icno}/videos";
|
||||
})
|
||||
->acceptedFileTypes([
|
||||
'video/mp4', 'video/quicktime', 'video/x-msvideo',
|
||||
'video/x-matroska', 'video/webm',
|
||||
'audio/mpeg', 'audio/mp3', 'audio/wav', 'audio/x-wav',
|
||||
'audio/ogg', 'audio/opus', 'audio/mp4', 'audio/x-m4a',
|
||||
'audio/aac', 'audio/x-aac', 'audio/flac', 'audio/x-flac',
|
||||
'audio/webm', 'audio/amr', 'audio/3gpp', 'audio/3gpp2',
|
||||
'audio/aiff', 'audio/x-aiff',
|
||||
])
|
||||
->maxSize(102400)
|
||||
->downloadable()
|
||||
->panelLayout('grid')
|
||||
->extraAttributes(['class' => 'fi-video-gallery'])
|
||||
->fetchFileInformation(false),
|
||||
|
||||
FileUpload::make('audio_files')
|
||||
->label(__('patients.fields.audio_files'))
|
||||
->multiple()
|
||||
->disk('public')
|
||||
->directory('audio_files')
|
||||
->directory(function ($record) {
|
||||
$year = \Morilog\Jalali\Jalalian::now()->getYear();
|
||||
$icno = $record?->icno ?? '';
|
||||
return "files/surgery_photos/{$year}/{$icno}/audio";
|
||||
})
|
||||
->acceptedFileTypes([
|
||||
'audio/mpeg',
|
||||
'audio/mp3',
|
||||
'audio/wav',
|
||||
'audio/x-wav',
|
||||
'audio/ogg',
|
||||
'audio/opus',
|
||||
'audio/mp4',
|
||||
'audio/x-m4a',
|
||||
'audio/aac',
|
||||
'audio/x-aac',
|
||||
'audio/flac',
|
||||
'audio/x-flac',
|
||||
'audio/webm',
|
||||
'audio/amr',
|
||||
'audio/3gpp',
|
||||
'audio/3gpp2',
|
||||
'audio/aiff',
|
||||
'audio/x-aiff',
|
||||
'audio/mpeg', 'audio/mp3', 'audio/wav', 'audio/x-wav',
|
||||
'audio/ogg', 'audio/opus', 'audio/mp4', 'audio/x-m4a',
|
||||
'audio/aac', 'audio/x-aac', 'audio/flac', 'audio/x-flac',
|
||||
'audio/webm', 'audio/amr', 'audio/3gpp', 'audio/3gpp2',
|
||||
'audio/aiff', 'audio/x-aiff',
|
||||
])
|
||||
->downloadable()
|
||||
->fetchFileInformation(false),
|
||||
@@ -444,15 +476,15 @@ public static function table(Table $table): Table
|
||||
: []
|
||||
)
|
||||
->formatStateUsing(function ($state) {
|
||||
$text = strip_tags($state ?? '');
|
||||
if (! $text) {
|
||||
$plain = strip_tags($state ?? '');
|
||||
if (! $plain) {
|
||||
return '-';
|
||||
}
|
||||
if (mb_strlen($text) > 30) {
|
||||
return mb_substr($text, 0, 30)
|
||||
if (mb_strlen($plain) > 30) {
|
||||
return $state
|
||||
. ' <span class="text-primary-600 text-xs font-semibold cursor-pointer">... بیشتر</span>';
|
||||
}
|
||||
return $text;
|
||||
return $state;
|
||||
})
|
||||
->html()
|
||||
->action(
|
||||
@@ -479,15 +511,15 @@ public static function table(Table $table): Table
|
||||
: []
|
||||
)
|
||||
->formatStateUsing(function ($state) {
|
||||
$text = strip_tags($state ?? '');
|
||||
if (! $text) {
|
||||
$plain = strip_tags($state ?? '');
|
||||
if (! $plain) {
|
||||
return '-';
|
||||
}
|
||||
if (mb_strlen($text) > 30) {
|
||||
return mb_substr($text, 0, 30)
|
||||
if (mb_strlen($plain) > 30) {
|
||||
return $state
|
||||
. ' <span class="text-primary-600 text-xs font-semibold cursor-pointer">... بیشتر</span>';
|
||||
}
|
||||
return $text;
|
||||
return $state;
|
||||
})
|
||||
->html()
|
||||
->action(
|
||||
@@ -522,7 +554,7 @@ public static function table(Table $table): Table
|
||||
->iconColor(fn ($state) => $state ? 'success' : 'gray')
|
||||
->placeholder('-'),
|
||||
])
|
||||
->defaultSort('created_at', 'desc')
|
||||
->defaultSort('updated_at', 'desc')
|
||||
->recordActions([
|
||||
Action::make('surgeryAppointment')
|
||||
->label(__('patients.actions.surgery_appointment'))
|
||||
@@ -597,18 +629,65 @@ public static function table(Table $table): Table
|
||||
])
|
||||
->action(function (Patient $record, array $data, array $arguments, Action $action): void {
|
||||
if (! empty($arguments['delete'])) {
|
||||
$existingAppointment = $record->surgeryAppointment;
|
||||
|
||||
SurgeryAppointment::where('patient_id', $record->id)->delete();
|
||||
|
||||
if ($existingAppointment) {
|
||||
\App\Filament\Pages\SmsLogsPage::cancelAppointmentMessages(
|
||||
$record->hand_phone ?? '',
|
||||
$existingAppointment->surgery_date->toDateTimeString(),
|
||||
);
|
||||
}
|
||||
|
||||
\Filament\Notifications\Notification::make()
|
||||
->title(__('patients.actions.appointment_deleted'))
|
||||
->success()
|
||||
->send();
|
||||
return;
|
||||
}
|
||||
$dateStr = $data['surgery_date'];
|
||||
$timeStr = $data['surgery_time'] ?? '00:00';
|
||||
|
||||
$dateStr = $data['surgery_date'];
|
||||
$timeStr = $data['surgery_time'] ?? '00:00';
|
||||
$surgeryDateTime = \Carbon\Carbon::parse($dateStr . ' ' . $timeStr);
|
||||
$jalaliDate = Jalalian::fromCarbon($surgeryDateTime)->format('Y/m/d');
|
||||
$jalaliDate = Jalalian::fromCarbon($surgeryDateTime)->format('Y/m/d');
|
||||
|
||||
$apiKey = \App\Models\OsurgInitial::val('sms_api_key', config('sms.api_key'));
|
||||
$apiUrl = \App\Models\OsurgInitial::val('sms_api_url', config('sms.api_url'));
|
||||
$smsPayload = [
|
||||
'phoneNumber' => $record->hand_phone ?? '',
|
||||
'patientName' => $record->full_name,
|
||||
'surgeryDate' => $jalaliDate,
|
||||
'patientId' => $record->id,
|
||||
'surgeryDateFull' => $surgeryDateTime->toDateTimeString(),
|
||||
];
|
||||
|
||||
try {
|
||||
$response = \Illuminate\Support\Facades\Http::timeout(30)
|
||||
->withHeader('X-API-Key', $apiKey)
|
||||
->asJson()
|
||||
->post($apiUrl . '/surgery-reminder', $smsPayload);
|
||||
|
||||
if (! ($response->json('success') ?? false)) {
|
||||
\Filament\Notifications\Notification::make()
|
||||
->title(__('patients.actions.api_failed'))
|
||||
->body($response->json('message') ?? '')
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
$action->halt();
|
||||
return;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
\Filament\Notifications\Notification::make()
|
||||
->title(__('patients.actions.api_failed'))
|
||||
->body($e->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
$action->halt();
|
||||
return;
|
||||
}
|
||||
|
||||
$appointment = SurgeryAppointment::updateOrCreate(
|
||||
['patient_id' => $record->id],
|
||||
@@ -619,44 +698,21 @@ public static function table(Table $table): Table
|
||||
);
|
||||
|
||||
try {
|
||||
$response = \Illuminate\Support\Facades\Http::timeout(30)
|
||||
->withHeader('X-API-Key', \App\Models\OsurgInitial::val('sms_api_key', config('sms.api_key')))
|
||||
->post(\App\Models\OsurgInitial::val('sms_api_url', config('sms.api_url')) . '/surgery-reminder', [
|
||||
'phoneNumber' => $record->hand_phone ?? '',
|
||||
'patientName' => $record->full_name,
|
||||
'surgeryDate' => $jalaliDate,
|
||||
'appointmentId' => $appointment->id,
|
||||
'patientId' => $record->id,
|
||||
'surgeryDateFull' => $surgeryDateTime->toDateTimeString(),
|
||||
]);
|
||||
|
||||
if (! ($response->json('success') ?? false)) {
|
||||
\Filament\Notifications\Notification::make()
|
||||
->title(__('patients.actions.appointment_saved'))
|
||||
->body(__('patients.actions.api_failed') . ': ' . ($response->json('message') ?? ''))
|
||||
->warning()
|
||||
->send();
|
||||
} else {
|
||||
\Filament\Notifications\Notification::make()
|
||||
->title(__('patients.actions.appointment_saved'))
|
||||
->body(__('patients.actions.sms_sent'))
|
||||
->success()
|
||||
->send();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
\Illuminate\Support\Facades\Log::warning('Surgery appointment API failed', [
|
||||
'patient_id' => $record->id,
|
||||
'appointment_id' => $appointment->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
\Filament\Notifications\Notification::make()
|
||||
->title(__('patients.actions.appointment_saved'))
|
||||
->body(__('patients.actions.api_failed') . ': ' . $e->getMessage())
|
||||
->warning()
|
||||
->send();
|
||||
\Illuminate\Support\Facades\Http::timeout(30)
|
||||
->withHeader('X-API-Key', $apiKey)
|
||||
->asJson()
|
||||
->post($apiUrl . '/surgery-reminder', array_merge($smsPayload, [
|
||||
'appointmentId' => $appointment->id,
|
||||
]));
|
||||
} catch (\Throwable) {
|
||||
}
|
||||
|
||||
\Filament\Notifications\Notification::make()
|
||||
->title(__('patients.actions.appointment_saved'))
|
||||
->body(__('patients.actions.sms_sent'))
|
||||
->success()
|
||||
->send();
|
||||
|
||||
$record->refresh();
|
||||
$action->halt();
|
||||
}),
|
||||
@@ -674,6 +730,7 @@ public static function table(Table $table): Table
|
||||
|
||||
if ($prescription) {
|
||||
$medicationIds = $prescription->medication_ids ?? [];
|
||||
$labTestIds = $prescription->lab_test_ids ?? [];
|
||||
$content = $prescription->content ?? '';
|
||||
} else {
|
||||
$defaultMeds = Medication::where('is_active', true)
|
||||
@@ -681,6 +738,11 @@ public static function table(Table $table): Table
|
||||
->orderBy('name')
|
||||
->get();
|
||||
$medicationIds = $defaultMeds->pluck('id')->toArray();
|
||||
$labTestIds = LabTest::where('is_active', true)
|
||||
->where('is_default', true)
|
||||
->orderBy('name')
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
$content = $defaultMeds->isNotEmpty()
|
||||
? '<ul>' . $defaultMeds->map(fn ($m) =>
|
||||
'<li>' . implode(' ', array_filter([
|
||||
@@ -694,10 +756,16 @@ public static function table(Table $table): Table
|
||||
: '';
|
||||
}
|
||||
|
||||
$labContent = isset($prescription)
|
||||
? ($prescription->lab_content ?? '')
|
||||
: '';
|
||||
|
||||
return [
|
||||
'medication_ids' => $medicationIds,
|
||||
'medication_order' => $medicationIds,
|
||||
'lab_test_ids' => $labTestIds,
|
||||
'content' => $content,
|
||||
'lab_content' => $labContent,
|
||||
'issue_date' => now()->toDateString(),
|
||||
];
|
||||
})
|
||||
@@ -716,66 +784,107 @@ public static function table(Table $table): Table
|
||||
|
||||
\Filament\Forms\Components\Hidden::make('medication_order'),
|
||||
|
||||
\Filament\Forms\Components\CheckboxList::make('medication_ids')
|
||||
->label(__('prescriptions.fields.medication_ids'))
|
||||
->options(fn () => Medication::where('is_active', true)
|
||||
->orderBy('name')
|
||||
->get()
|
||||
->mapWithKeys(fn ($m) => [
|
||||
$m->id => implode(' ', array_filter([
|
||||
$m->dosage_form,
|
||||
$m->name,
|
||||
$m->strength,
|
||||
$m->quantity ? '#' . $m->quantity : null,
|
||||
$m->timing,
|
||||
])),
|
||||
])
|
||||
->toArray()
|
||||
)
|
||||
->columns(2)
|
||||
->live()
|
||||
->afterStateUpdated(function (array $state, callable $set, callable $get) {
|
||||
$currentOrder = array_map('intval', (array) ($get('medication_order') ?: []));
|
||||
$state = array_map('intval', $state);
|
||||
Tabs::make()
|
||||
->tabs([
|
||||
Tab::make(__('prescriptions.sections.medications'))
|
||||
->icon('heroicon-o-clipboard-document-list')
|
||||
->schema([
|
||||
\Filament\Forms\Components\CheckboxList::make('medication_ids')
|
||||
->label(__('prescriptions.fields.medication_ids'))
|
||||
->options(fn () => Medication::where('is_active', true)
|
||||
->orderBy('name')
|
||||
->get()
|
||||
->mapWithKeys(fn ($m) => [
|
||||
$m->id => implode(' ', array_filter([
|
||||
$m->dosage_form,
|
||||
$m->name,
|
||||
$m->strength,
|
||||
$m->quantity ? '#' . $m->quantity : null,
|
||||
$m->timing,
|
||||
])),
|
||||
])
|
||||
->toArray()
|
||||
)
|
||||
->columns(2)
|
||||
->live()
|
||||
->afterStateUpdated(function (array $state, callable $set, callable $get) {
|
||||
$currentOrder = array_map('intval', (array) ($get('medication_order') ?: []));
|
||||
$state = array_map('intval', $state);
|
||||
|
||||
$newOrder = array_values(
|
||||
array_filter($currentOrder, fn ($id) => in_array($id, $state))
|
||||
);
|
||||
$newOrder = array_values(
|
||||
array_filter($currentOrder, fn ($id) => in_array($id, $state))
|
||||
);
|
||||
|
||||
foreach ($state as $id) {
|
||||
if (! in_array($id, $newOrder)) {
|
||||
$newOrder[] = $id;
|
||||
}
|
||||
}
|
||||
foreach ($state as $id) {
|
||||
if (! in_array($id, $newOrder)) {
|
||||
$newOrder[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
$set('medication_order', $newOrder);
|
||||
$set('medication_order', $newOrder);
|
||||
|
||||
if (empty($newOrder)) {
|
||||
$set('content', null);
|
||||
return;
|
||||
}
|
||||
if (empty($newOrder)) {
|
||||
$set('content', null);
|
||||
return;
|
||||
}
|
||||
|
||||
$medications = Medication::whereIn('id', $newOrder)->get()->keyBy('id');
|
||||
$html = '<ul>' . collect($newOrder)
|
||||
->map(fn ($id) => isset($medications[$id])
|
||||
? '<li>' . implode(' ', array_filter([
|
||||
$medications[$id]->dosage_form,
|
||||
$medications[$id]->name,
|
||||
$medications[$id]->strength,
|
||||
$medications[$id]->quantity ? '#' . $medications[$id]->quantity : null,
|
||||
$medications[$id]->timing,
|
||||
])) . '</li>'
|
||||
: ''
|
||||
)
|
||||
->filter()
|
||||
->implode('') . '</ul>';
|
||||
$medications = Medication::whereIn('id', $newOrder)->get()->keyBy('id');
|
||||
$html = '<ul>' . collect($newOrder)
|
||||
->map(fn ($id) => isset($medications[$id])
|
||||
? '<li>' . implode(' ', array_filter([
|
||||
$medications[$id]->dosage_form,
|
||||
$medications[$id]->name,
|
||||
$medications[$id]->strength,
|
||||
$medications[$id]->quantity ? '#' . $medications[$id]->quantity : null,
|
||||
$medications[$id]->timing,
|
||||
])) . '</li>'
|
||||
: ''
|
||||
)
|
||||
->filter()
|
||||
->implode('') . '</ul>';
|
||||
|
||||
$set('content', $html);
|
||||
})
|
||||
->columnSpanFull(),
|
||||
$set('content', $html);
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
\Filament\Forms\Components\RichEditor::make('content')
|
||||
->label(__('prescriptions.fields.content'))
|
||||
\Filament\Forms\Components\RichEditor::make('content')
|
||||
->label(__('prescriptions.fields.content'))
|
||||
->columnSpanFull(),
|
||||
]),
|
||||
|
||||
Tab::make(__('prescriptions.sections.lab_tests'))
|
||||
->icon('heroicon-o-beaker')
|
||||
->schema([
|
||||
\Filament\Forms\Components\CheckboxList::make('lab_test_ids')
|
||||
->label(__('prescriptions.fields.lab_test_ids'))
|
||||
->options(fn () => LabTest::where('is_active', true)
|
||||
->orderBy('name')
|
||||
->get()
|
||||
->mapWithKeys(fn ($t) => [$t->id => $t->name])
|
||||
->toArray()
|
||||
)
|
||||
->columns(2)
|
||||
->live()
|
||||
->afterStateUpdated(function (array $state, callable $set) {
|
||||
if (empty($state)) {
|
||||
$set('lab_content', null);
|
||||
return;
|
||||
}
|
||||
$tests = LabTest::whereIn('id', $state)
|
||||
->orderBy('name')
|
||||
->get();
|
||||
$html = '<ul>' . $tests->map(fn ($t) =>
|
||||
'<li>' . $t->name . '</li>'
|
||||
)->implode('') . '</ul>';
|
||||
$set('lab_content', $html);
|
||||
})
|
||||
->columnSpanFull(),
|
||||
|
||||
\Filament\Forms\Components\RichEditor::make('lab_content')
|
||||
->label(__('prescriptions.fields.lab_content'))
|
||||
->columnSpanFull(),
|
||||
]),
|
||||
])
|
||||
->columnSpanFull(),
|
||||
])
|
||||
->modalSubmitAction(false)
|
||||
@@ -804,7 +913,9 @@ public static function table(Table $table): Table
|
||||
'issue_date' => $data['issue_date'] ?? '',
|
||||
'issue_datetime' => now(),
|
||||
'medication_ids' => $data['medication_order'] ?? $data['medication_ids'] ?? [],
|
||||
'lab_test_ids' => $data['lab_test_ids'] ?? [],
|
||||
'content' => $data['content'] ?? '',
|
||||
'lab_content' => $data['lab_content'] ?? '',
|
||||
]
|
||||
);
|
||||
|
||||
@@ -833,12 +944,12 @@ public static function table(Table $table): Table
|
||||
$record->audio_files,
|
||||
]))
|
||||
)
|
||||
->modalWidth(Width::Large)
|
||||
->modalWidth(Width::ExtraLarge)
|
||||
->fillForm(fn (Patient $record): array => [
|
||||
'photos_before' => $record->photos_before ?? [],
|
||||
'photos_after' => $record->photos_after ?? [],
|
||||
'videos' => $record->videos ?? [],
|
||||
'audio_files' => $record->audio_files ?? [],
|
||||
'photos_before' => \App\Filament\Resources\PatientResource\Pages\EditPatient::normalizeFileList($record->photos_before),
|
||||
'photos_after' => \App\Filament\Resources\PatientResource\Pages\EditPatient::normalizeFileList($record->photos_after),
|
||||
'videos' => \App\Filament\Resources\PatientResource\Pages\EditPatient::normalizeFileList($record->videos),
|
||||
'audio_files' => \App\Filament\Resources\PatientResource\Pages\EditPatient::normalizeFileList($record->audio_files),
|
||||
])
|
||||
->schema([
|
||||
Grid::make(2)
|
||||
@@ -847,34 +958,52 @@ public static function table(Table $table): Table
|
||||
->label(__('patients.fields.photos_before'))
|
||||
->multiple()
|
||||
->image()
|
||||
->imagePreviewHeight('150')
|
||||
->panelLayout('grid')
|
||||
->disk('public')
|
||||
->directory('surgery_photos/before')
|
||||
->directory(function (Patient $record) {
|
||||
$year = \Morilog\Jalali\Jalalian::now()->getYear();
|
||||
return "files/surgery_photos/{$year}/{$record->icno}/before";
|
||||
})
|
||||
->downloadable()
|
||||
->openable()
|
||||
->disabled()
|
||||
->fetchFileInformation(false)
|
||||
->extraAttributes(['data-hide-dropzone' => 'true']),
|
||||
->extraAttributes(['class' => 'fi-photo-gallery fi-photo-gallery-view', 'data-hide-dropzone' => 'true']),
|
||||
|
||||
FileUpload::make('photos_after')
|
||||
->label(__('patients.fields.photos_after'))
|
||||
->multiple()
|
||||
->image()
|
||||
->imagePreviewHeight('150')
|
||||
->panelLayout('grid')
|
||||
->disk('public')
|
||||
->directory('surgery_photos/after')
|
||||
->directory(function (Patient $record) {
|
||||
$year = \Morilog\Jalali\Jalalian::now()->getYear();
|
||||
return "files/surgery_photos/{$year}/{$record->icno}/after";
|
||||
})
|
||||
->downloadable()
|
||||
->openable()
|
||||
->disabled()
|
||||
->fetchFileInformation(false)
|
||||
->extraAttributes(['data-hide-dropzone' => 'true']),
|
||||
->extraAttributes(['class' => 'fi-photo-gallery fi-photo-gallery-view', 'data-hide-dropzone' => 'true']),
|
||||
|
||||
FileUpload::make('videos')
|
||||
->label(__('patients.fields.videos'))
|
||||
->multiple()
|
||||
->disk('public')
|
||||
->directory('surgery_photos/videos')
|
||||
->acceptedFileTypes(['video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/x-matroska', 'video/webm', 'audio/mpeg', 'audio/mp3', 'audio/wav', 'audio/ogg', 'audio/aac'])
|
||||
->directory(function (Patient $record) {
|
||||
$year = \Morilog\Jalali\Jalalian::now()->getYear();
|
||||
return "files/surgery_photos/{$year}/{$record->icno}/videos";
|
||||
})
|
||||
->acceptedFileTypes([
|
||||
'video/mp4', 'video/quicktime', 'video/x-msvideo',
|
||||
'video/x-matroska', 'video/webm',
|
||||
'audio/mpeg', 'audio/mp3', 'audio/wav', 'audio/x-wav',
|
||||
'audio/ogg', 'audio/opus', 'audio/mp4', 'audio/x-m4a',
|
||||
'audio/aac', 'audio/x-aac', 'audio/flac', 'audio/x-flac',
|
||||
'audio/webm', 'audio/amr', 'audio/3gpp', 'audio/3gpp2',
|
||||
'audio/aiff', 'audio/x-aiff',
|
||||
])
|
||||
->maxSize(102400)
|
||||
->downloadable()
|
||||
->disabled()
|
||||
->fetchFileInformation(false)
|
||||
@@ -884,26 +1013,29 @@ public static function table(Table $table): Table
|
||||
->label(__('patients.fields.audio_files'))
|
||||
->multiple()
|
||||
->disk('public')
|
||||
->directory('audio_files')
|
||||
->directory(function (Patient $record) {
|
||||
$year = \Morilog\Jalali\Jalalian::now()->getYear();
|
||||
return "files/surgery_photos/{$year}/{$record->icno}/audio";
|
||||
})
|
||||
->acceptedFileTypes([
|
||||
'audio/mpeg',
|
||||
'audio/mp3',
|
||||
'audio/wav',
|
||||
'audio/x-wav',
|
||||
'audio/ogg',
|
||||
'audio/opus',
|
||||
'audio/mp4',
|
||||
'audio/x-m4a',
|
||||
'audio/aac',
|
||||
'audio/x-aac',
|
||||
'audio/flac',
|
||||
'audio/x-flac',
|
||||
'audio/webm',
|
||||
'audio/amr',
|
||||
'audio/3gpp',
|
||||
'audio/3gpp2',
|
||||
'audio/aiff',
|
||||
'audio/x-aiff',
|
||||
'audio/mpeg',
|
||||
'audio/mp3',
|
||||
'audio/wav',
|
||||
'audio/x-wav',
|
||||
'audio/ogg',
|
||||
'audio/opus',
|
||||
'audio/mp4',
|
||||
'audio/x-m4a',
|
||||
'audio/aac',
|
||||
'audio/x-aac',
|
||||
'audio/flac',
|
||||
'audio/x-flac',
|
||||
'audio/webm',
|
||||
'audio/amr',
|
||||
'audio/3gpp',
|
||||
'audio/3gpp2',
|
||||
'audio/aiff',
|
||||
'audio/x-aiff',
|
||||
])
|
||||
->downloadable()
|
||||
->disabled()
|
||||
|
||||
Reference in New Issue
Block a user