feat: patient view, media player, and rich editor enhancements
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class ExpandableText extends Component
|
||||
{
|
||||
public string $html = '';
|
||||
public int $limit = 200;
|
||||
public bool $expanded = false;
|
||||
|
||||
public function toggle(): void
|
||||
{
|
||||
$this->expanded = ! $this->expanded;
|
||||
}
|
||||
|
||||
public function render(): \Illuminate\View\View
|
||||
{
|
||||
return view('livewire.expandable-text');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Filament\Resources\PatientResource\Pages\EditPatient;
|
||||
use App\Models\Patient;
|
||||
use Filament\Forms\Components\FileUpload;
|
||||
use Filament\Forms\Concerns\InteractsWithForms;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Schemas\Schema;
|
||||
use Livewire\Component;
|
||||
|
||||
class PatientMediaPlayer extends Component implements HasForms
|
||||
{
|
||||
use InteractsWithForms;
|
||||
|
||||
public int $patientId;
|
||||
public string $field;
|
||||
public ?array $data = [];
|
||||
|
||||
public function mount(int $patientId, string $field): void
|
||||
{
|
||||
$this->patientId = $patientId;
|
||||
$this->field = $field;
|
||||
|
||||
$patient = Patient::find($patientId);
|
||||
|
||||
$this->form->fill([
|
||||
$field => EditPatient::normalizeFileList($patient?->{$field}),
|
||||
]);
|
||||
}
|
||||
|
||||
public function form(Schema $form): Schema
|
||||
{
|
||||
$component = match ($this->field) {
|
||||
'videos' => FileUpload::make('videos')
|
||||
->hiddenLabel()
|
||||
->multiple()
|
||||
->disk('public')
|
||||
->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()
|
||||
->openable()
|
||||
->panelLayout('grid')
|
||||
->extraAttributes(['class' => 'fi-video-gallery', 'data-hide-dropzone' => 'true'])
|
||||
->disabled()
|
||||
->deletable(false)
|
||||
->fetchFileInformation(false),
|
||||
|
||||
'audio_files' => FileUpload::make('audio_files')
|
||||
->hiddenLabel()
|
||||
->multiple()
|
||||
->disk('public')
|
||||
->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',
|
||||
])
|
||||
->downloadable()
|
||||
->openable()
|
||||
->extraAttributes(['data-hide-dropzone' => 'true'])
|
||||
->disabled()
|
||||
->deletable(false)
|
||||
->fetchFileInformation(false),
|
||||
|
||||
default => throw new \InvalidArgumentException("Unknown field: {$this->field}"),
|
||||
};
|
||||
|
||||
return $form
|
||||
->schema([$component])
|
||||
->statePath('data');
|
||||
}
|
||||
|
||||
public function render(): \Illuminate\View\View
|
||||
{
|
||||
return view('livewire.patient-media-player');
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,18 @@ class SettingsDropdown extends Component
|
||||
public bool $syncFailed = false;
|
||||
public array $reportLines = [];
|
||||
|
||||
public bool $peerConnected = false;
|
||||
public ?string $peerPath = null;
|
||||
public bool $peerChecked = false;
|
||||
|
||||
public function checkPeerStatus(): void
|
||||
{
|
||||
$result = SyncService::fromConfig()->ping();
|
||||
|
||||
$this->peerConnected = $result['connected'];
|
||||
$this->peerPath = $result['path'];
|
||||
$this->peerChecked = true;
|
||||
}
|
||||
public function runBackup(): void
|
||||
{
|
||||
$dbPath = database_path('database.sqlite');
|
||||
@@ -26,18 +38,62 @@ public function runBackup(): void
|
||||
return;
|
||||
}
|
||||
|
||||
$backupDir = storage_path('app/backups');
|
||||
$timestamp = now()->format('Y-m-d_H-i-s');
|
||||
$zipFilename = "matab-backup-{$timestamp}.zip";
|
||||
$zipPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $zipFilename;
|
||||
|
||||
if (! is_dir($backupDir)) {
|
||||
mkdir($backupDir, 0755, true);
|
||||
$zip = new \ZipArchive();
|
||||
if ($zip->open($zipPath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) {
|
||||
Notification::make()
|
||||
->title(__('navigation.backup.failed'))
|
||||
->danger()
|
||||
->send();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (glob($backupDir . '/matab-backup-*.sqlite') as $oldFile) {
|
||||
unlink($oldFile);
|
||||
$noCompressExts = [
|
||||
'jpg', 'jpeg', 'png', 'gif', 'webp',
|
||||
'mp4', 'mov', 'avi', 'mkv', 'webm',
|
||||
'mp3', 'wav', 'ogg', 'opus', 'm4a',
|
||||
'zip', 'gz', 'rar', '7z',
|
||||
];
|
||||
|
||||
$addFile = function (string $realPath, string $zipEntry) use ($zip, $noCompressExts): void {
|
||||
$zip->addFile($realPath, $zipEntry);
|
||||
$index = $zip->locateName($zipEntry);
|
||||
$ext = strtolower(pathinfo($realPath, PATHINFO_EXTENSION));
|
||||
if (in_array($ext, $noCompressExts, true)) {
|
||||
$zip->setCompressionIndex($index, \ZipArchive::CM_STORE);
|
||||
} else {
|
||||
$zip->setCompressionIndex($index, \ZipArchive::CM_DEFLATE, 9);
|
||||
}
|
||||
};
|
||||
|
||||
$addFile($dbPath, 'database/database.sqlite');
|
||||
|
||||
$publicPath = storage_path('app/public');
|
||||
foreach (['files', 'initials'] as $folder) {
|
||||
$folderPath = $publicPath . '/' . $folder;
|
||||
if (! is_dir($folderPath)) {
|
||||
continue;
|
||||
}
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($folderPath, \RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
\RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->isFile()) {
|
||||
$relativePath = str_replace('\\', '/', substr($file->getPathname(), strlen($folderPath) + 1));
|
||||
$addFile($file->getPathname(), $folder . '/' . $relativePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$filename = 'matab-backup-' . now()->format('Y-m-d_H-i-s') . '.sqlite';
|
||||
copy($dbPath, $backupDir . '/' . $filename);
|
||||
$zip->close();
|
||||
|
||||
session(['backup_tmp_path' => $zipPath, 'backup_tmp_name' => $zipFilename]);
|
||||
|
||||
$this->dispatch('backup-ready', url: route('backup.download'));
|
||||
|
||||
Notification::make()
|
||||
->title(__('navigation.backup.success'))
|
||||
|
||||
Reference in New Issue
Block a user