diff --git a/app/Livewire/Dashboard/DashboardConverter.php b/app/Livewire/Dashboard/DashboardConverter.php new file mode 100644 index 0000000..16782b3 --- /dev/null +++ b/app/Livewire/Dashboard/DashboardConverter.php @@ -0,0 +1,89 @@ +resetErrorBag(); + $this->uploadError = null; + + $this->validate([ + 'upload' => [ + 'required', + 'file', + 'max:'.UploadedFileRules::MAX_FILE_KILOBYTES, + ], + ], [ + 'upload.max' => 'This file is too large. Max upload size is '.(UploadedFileRules::MAX_FILE_KILOBYTES / 1024).' MB.', + ]); + + try { + $fileRecord = $storeUploadedFile->handle( + user: auth()->user(), + file: $this->upload, + ); + } catch (UnsupportedFileFormatException) { + $this->uploadError = 'This file type is not supported in beta. Upload PNG, JPG, WEBP or PDF.'; + $this->step = 'upload'; + + return; + } catch (FileStorageException) { + $this->uploadError = 'We could not store your file. Please try again.'; + $this->step = 'upload'; + + return; + } + + $this->currentFileId = $fileRecord->id; + $this->step = 'format'; + } + + public function replaceFile(): void + { + $this->resetCurrentUpload(); + } + + public function removeFile(): void + { + $this->resetCurrentUpload(); + } + + private function resetCurrentUpload(): void + { + $this->reset('upload', 'currentFileId', 'uploadError'); + $this->resetErrorBag(); + $this->step = 'upload'; + } + + public function getCurrentFileProperty(): ?FileRecord + { + return $this->currentFileId + ? FileRecord::query()->where('user_id', auth()->id())->find($this->currentFileId) + : null; + } + + public function render() + { + return view('livewire.dashboard.dashboard-converter'); + } +} diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php index 4b88af4..3cca978 100644 --- a/resources/views/dashboard.blade.php +++ b/resources/views/dashboard.blade.php @@ -6,21 +6,7 @@
- - - -
- -
- -
- Try: - - - - -
-
+
-
- -
-
diff --git a/resources/views/livewire/dashboard/dashboard-converter.blade.php b/resources/views/livewire/dashboard/dashboard-converter.blade.php new file mode 100644 index 0000000..666f652 --- /dev/null +++ b/resources/views/livewire/dashboard/dashboard-converter.blade.php @@ -0,0 +1,76 @@ +
+ + + @if ($step === 'upload') +
+
+ + + +
+ +
+

Drop your file here

+

PNG, JPG, WEBP and PDF supported in beta

+
+ + + +

Your files stay private. We delete them after conversion.

+ + @error('upload') +

{{ $message }}

+ @enderror + + @if ($uploadError) +

{{ $uploadError }}

+ @endif +
+ @endif + + @if ($step === 'format' && $this->currentFile) + @php($file = $this->currentFile) +
+
+
+ +
+

{{ $file->original_name }}

+

+ {{ strtoupper($file->extension) }} · + {{ number_format($file->size_bytes / 1024, 1) }} KB + @php($meta = $file->metadata_json ?? []) + @if (isset($meta['width'], $meta['height'])) + · {{ $meta['width'] }}×{{ $meta['height'] }} + @endif +

+
+
+ +
+ Replace + Remove +
+
+ +
+

Choose output format

+

Target format selection will be added in Phase 7.

+
+
+ @endif +
+
diff --git a/tests/Feature/DashboardRouteTest.php b/tests/Feature/DashboardRouteTest.php index 7701272..4311b2d 100644 --- a/tests/Feature/DashboardRouteTest.php +++ b/tests/Feature/DashboardRouteTest.php @@ -16,6 +16,15 @@ ->assertSee('Convert any file'); }); +it('renders dashboard converter on dashboard page', function () { + $user = User::factory()->create(); + + $this->actingAs($user) + ->get(route('dashboard')) + ->assertOk() + ->assertSee('Drop your file here'); +}); + it('renders dashboard inside the app layout', function () { $this->actingAs(User::factory()->create()) ->get('/dashboard') @@ -41,16 +50,3 @@ ->assertSee('Contact Support') ->assertSee('Refer a Friend'); }); - -it('renders dashboard UI skeleton', function () { - $this->actingAs(User::factory()->create()) - ->get('/dashboard') - ->assertOk() - ->assertSee('Convert any file') - ->assertSee('File') - ->assertSee('Format') - ->assertSee('Settings') - ->assertSee('Convert') - ->assertSee('Recent Conversions') - ->assertSee('Marketing Report.pdf'); -}); diff --git a/tests/Feature/Livewire/DashboardConverterTest.php b/tests/Feature/Livewire/DashboardConverterTest.php new file mode 100644 index 0000000..6f8aad8 --- /dev/null +++ b/tests/Feature/Livewire/DashboardConverterTest.php @@ -0,0 +1,11 @@ +assertSee('Drop your file here') + ->assertSee('PNG, JPG, WEBP and PDF supported in beta') + ->assertSee('Choose file'); +}); diff --git a/tests/Feature/Livewire/DashboardConverterUploadTest.php b/tests/Feature/Livewire/DashboardConverterUploadTest.php new file mode 100644 index 0000000..108dfb8 --- /dev/null +++ b/tests/Feature/Livewire/DashboardConverterUploadTest.php @@ -0,0 +1,113 @@ +create(); + + Livewire::actingAs($user) + ->test(DashboardConverter::class) + ->set('upload', UploadedFile::fake()->image('sample.png', 600, 400)) + ->call('storeUpload') + ->assertSet('step', 'format') + ->assertSee('sample.png') + ->assertSee('Choose output format'); + + expect(FileRecord::query()->where('original_name', 'sample.png')->exists())->toBeTrue(); +}); + +it('resets current file when replacing uploaded file', function () { + Storage::fake('local'); + + $user = User::factory()->create(); + + Livewire::actingAs($user) + ->test(DashboardConverter::class) + ->set('upload', UploadedFile::fake()->image('first.png')) + ->call('storeUpload') + ->assertSet('step', 'format') + ->call('replaceFile') + ->assertSet('step', 'upload') + ->assertSet('currentFileId', null) + ->assertSee('Drop your file here'); +}); + +it('removes uploaded file from current flow', function () { + Storage::fake('local'); + + $user = User::factory()->create(); + + Livewire::actingAs($user) + ->test(DashboardConverter::class) + ->set('upload', UploadedFile::fake()->image('remove-me.png')) + ->call('storeUpload') + ->assertSet('step', 'format') + ->call('removeFile') + ->assertSet('step', 'upload') + ->assertSet('currentFileId', null) + ->assertDontSee('remove-me.png'); +}); + +it('shows an error for unsupported upload format', function () { + Storage::fake('local'); + + $user = User::factory()->create(); + + Livewire::actingAs($user) + ->test(DashboardConverter::class) + ->set('upload', UploadedFile::fake()->create('notes.txt', 10, 'text/plain')) + ->call('storeUpload') + ->assertSet('step', 'upload') + ->assertSee('not supported'); +}); + +it('shows format step placeholder after successful upload', function () { + Storage::fake('local'); + + $user = User::factory()->create(); + + Livewire::actingAs($user) + ->test(DashboardConverter::class) + ->set('upload', UploadedFile::fake()->image('photo.png')) + ->call('storeUpload') + ->assertSet('step', 'format') + ->assertSee('Choose output format') + ->assertSee('Target format selection will be added in Phase 7'); +}); + +it('shows uploaded file summary after upload', function () { + Storage::fake('local'); + + $user = User::factory()->create(); + + Livewire::actingAs($user) + ->test(DashboardConverter::class) + ->set('upload', UploadedFile::fake()->image('avatar.jpg', 800, 600)) + ->call('storeUpload') + ->assertSee('avatar.jpg') + ->assertSee('JPG') + ->assertSee('KB') + ->assertSee('Replace') + ->assertSee('Remove'); +}); + +it('does not create a file record when no file is provided', function () { + Storage::fake('local'); + + $user = User::factory()->create(); + + Livewire::actingAs($user) + ->test(DashboardConverter::class) + ->call('storeUpload') + ->assertSet('step', 'upload') + ->assertHasErrors(['upload' => 'required']); + + expect(FileRecord::query()->count())->toBe(0); +});