UI enhancements for file request

This commit is contained in:
Čarodej
2022-02-25 09:42:55 +01:00
parent 293eb679fa
commit c3a6f5d703
13 changed files with 152 additions and 19 deletions

View File

@@ -24,10 +24,11 @@ class UploadRequestFactory extends Factory
return [ return [
'id' => $this->faker->uuid, 'id' => $this->faker->uuid,
'user_id' => $this->faker->uuid, 'user_id' => $this->faker->uuid,
'folder_id' => $this->faker->uuid, 'folder_id' => $this->faker->uuid,
'email' => $this->faker->email, 'email' => $this->faker->email,
'notes' => $this->faker->realText(80), 'name' => $this->faker->name,
'status' => $this->faker->randomElement( 'notes' => $this->faker->realText(80),
'status' => $this->faker->randomElement(
['active', 'filled', 'expired'] ['active', 'filled', 'expired']
), ),
'created_at' => $this->faker->dateTimeBetween('-1 months'), 'created_at' => $this->faker->dateTimeBetween('-1 months'),

View File

@@ -16,9 +16,10 @@ class CreateUploadRequestsTable extends Migration
Schema::create('upload_requests', function (Blueprint $table) { Schema::create('upload_requests', function (Blueprint $table) {
$table->uuid('id'); $table->uuid('id');
$table->uuid('user_id'); $table->uuid('user_id');
$table->uuid('folder_id'); $table->uuid('folder_id')->nullable();
$table->enum('status', ['active', 'filling', 'filled', 'expired'])->default('active'); $table->enum('status', ['active', 'filling', 'filled', 'expired'])->default('active');
$table->string('email')->nullable(); $table->string('email')->nullable();
$table->text('name')->nullable();
$table->longText('notes')->nullable(); $table->longText('notes')->nullable();
$table->timestamps(); $table->timestamps();
$table->charset = 'utf8mb4'; $table->charset = 'utf8mb4';

View File

@@ -16,11 +16,12 @@
v-slot="{ invalid }" v-slot="{ invalid }"
tag="form" tag="form"
> >
<!--Send Request by Email-->
<AppInputSwitch <AppInputSwitch
:title="$t('Send Request by Email')" :title="$t('Send Request by Email')"
:description="$t('Send your file request on recipients email')" :description="$t('Send your file request on recipients email')"
> >
<SwitchInput v-model="shareViaEmail" :state="shareViaEmail" class="switch" /> <SwitchInput v-model="shareViaEmail" :state="shareViaEmail" />
</AppInputSwitch> </AppInputSwitch>
<!--Set email--> <!--Set email-->
@@ -44,6 +45,35 @@
</AppInputText> </AppInputText>
</ValidationProvider> </ValidationProvider>
<!--Custom Folder Name-->
<AppInputSwitch
:title="$t('Custom Folder Name')"
:description="$t('Created folder with files will be named with your own name.')"
>
<SwitchInput v-model="customFolderName" :state="customFolderName" />
</AppInputSwitch>
<!--Set email-->
<ValidationProvider
v-if="customFolderName"
tag="div"
mode="passive"
name="Name"
rules="required"
v-slot="{ errors }"
>
<AppInputText :error="errors[0]" class="-mt-2">
<input
v-model="form.name"
:class="{ 'border-red': errors[0] }"
type="text"
ref="input"
class="focus-border-theme input-dark"
:placeholder="$t('Type name...')"
/>
</AppInputText>
</ValidationProvider>
<!--Set note--> <!--Set note-->
<ValidationProvider tag="div" mode="passive" name="Note" v-slot="{ errors }"> <ValidationProvider tag="div" mode="passive" name="Note" v-slot="{ errors }">
<AppInputText :title="$t('Message (optional)')" :description="$t('This message will be showed for your email recipient or in the upload page.')" :error="errors[0]" :is-last="true"> <AppInputText :title="$t('Message (optional)')" :description="$t('This message will be showed for your email recipient or in the upload page.')" :error="errors[0]" :is-last="true">
@@ -124,9 +154,11 @@ export default {
email: undefined, email: undefined,
notes: undefined, notes: undefined,
folder_id: undefined, folder_id: undefined,
name: undefined,
}, },
generatedUploadRequest: undefined, generatedUploadRequest: undefined,
shareViaEmail: false, shareViaEmail: false,
customFolderName: false,
pickedItem: undefined, pickedItem: undefined,
isLoading: false, isLoading: false,
} }
@@ -159,8 +191,10 @@ export default {
}, },
created() { created() {
events.$on('popup:open', (args) => { events.$on('popup:open', (args) => {
if (args.name === 'create-file-request') this.pickedItem = args.item if (args.name === 'create-file-request')
this.form.folder_id = args.item.data.id this.pickedItem = args.item
this.form.folder_id = args.item?.data.id
}) })
// Close popup // Close popup
@@ -172,8 +206,10 @@ export default {
this.pickedItem = undefined this.pickedItem = undefined
this.shareViaEmail = false this.shareViaEmail = false
this.customFolderName = false
this.form = { this.form = {
name: undefined,
email: undefined, email: undefined,
notes: undefined, notes: undefined,
folder_id: undefined, folder_id: undefined,

View File

@@ -53,7 +53,7 @@ import ThumbnailItem from './ThumbnailItem'
import ButtonBase from '../FilesView/ButtonBase' import ButtonBase from '../FilesView/ButtonBase'
import Spinner from '../FilesView/Spinner' import Spinner from '../FilesView/Spinner'
import TreeMenu from './TreeMenu' import TreeMenu from './TreeMenu'
import { isArray, isNull } from 'lodash' import { isArray } from 'lodash'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { events } from '../../bus' import { events } from '../../bus'

View File

@@ -2,7 +2,7 @@
<PopupWrapper> <PopupWrapper>
<div class="flex h-full -translate-y-7 transform items-center justify-center px-8 text-center md:translate-y-0"> <div class="flex h-full -translate-y-7 transform items-center justify-center px-8 text-center md:translate-y-0">
<div> <div>
<img src="https://twemoji.maxcdn.com/v/13.1.0/svg/1f914.svg" alt="" class="mx-auto mb-4 w-20 md:mt-6" /> <img src="https://twemoji.maxcdn.com/v/13.1.0/svg/1f914.svg" alt="" class="mx-auto mb-4 w-20 md:mt-6 min-h-[80px]" />
<h1 v-if="title" class="mb-2 text-2xl font-bold"> <h1 v-if="title" class="mb-2 text-2xl font-bold">
{{ title }} {{ title }}

View File

@@ -25,7 +25,7 @@
<!--Item icon--> <!--Item icon-->
<hard-drive-icon <hard-drive-icon
v-if="['public', 'files'].includes(nodes.location)" v-if="['public', 'files', 'upload-request'].includes(nodes.location)"
size="17" size="17"
class="icon vue-feather shrink-0" class="icon vue-feather shrink-0"
:class="{ 'text-theme dark-text-theme': isSelectedItem }" :class="{ 'text-theme dark-text-theme': isSelectedItem }"

View File

@@ -4,7 +4,11 @@
<FilePreview /> <FilePreview />
<Spotlight /> <Spotlight />
<!--Mobile Navigation--> <!--Spotlight Addons-->
<CreateUploadRequestPopup />
<CreateTeamFolderPopup />
<!--Mobile Navigation-->
<MobileNavigation /> <MobileNavigation />
<!--ConfirmPopup Popup--> <!--ConfirmPopup Popup-->
@@ -82,6 +86,8 @@ import {
UsersIcon, UsersIcon,
} from 'vue-feather-icons' } from 'vue-feather-icons'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import CreateUploadRequestPopup from "../components/Others/CreateUploadRequestPopup";
import CreateTeamFolderPopup from "../components/Teams/CreateTeamFolderPopup";
export default { export default {
name: 'Admin', name: 'Admin',
@@ -186,6 +192,8 @@ export default {
}, },
}, },
components: { components: {
CreateTeamFolderPopup,
CreateUploadRequestPopup,
MobileNavigationToolbar, MobileNavigationToolbar,
FilePreview, FilePreview,
Spotlight, Spotlight,

View File

@@ -142,7 +142,7 @@
{{ emptyPageDescription }} {{ emptyPageDescription }}
</p> </p>
<InfoBox class="max-w-[420px] mx-auto"> <InfoBox v-if="uploadRequest.data.attributes.notes && uploadRequest.data.attributes.status === 'active'" class="max-w-[420px] mx-auto">
<b>{{ $t('{name} leave you a message', {name: userName}) }}: </b> <b>{{ $t('{name} leave you a message', {name: userName}) }}: </b>
<p>{{ uploadRequest.data.attributes.notes }}</p> <p>{{ uploadRequest.data.attributes.notes }}</p>
</InfoBox> </InfoBox>

View File

@@ -4,6 +4,10 @@
<FilePreview /> <FilePreview />
<Spotlight /> <Spotlight />
<!--Spotlight Addons-->
<CreateUploadRequestPopup />
<CreateTeamFolderPopup />
<ConfirmPopup /> <ConfirmPopup />
<ConfirmPassword /> <ConfirmPassword />
@@ -87,10 +91,14 @@ import { mapGetters } from 'vuex'
import CardNavigation from '../components/Admin/CardNavigation' import CardNavigation from '../components/Admin/CardNavigation'
import ConfirmPassword from '../components/Others/ConfirmPassword' import ConfirmPassword from '../components/Others/ConfirmPassword'
import MobileNavigationToolbar from '../components/Mobile/MobileNavigationToolbar' import MobileNavigationToolbar from '../components/Mobile/MobileNavigationToolbar'
import CreateUploadRequestPopup from "../components/Others/CreateUploadRequestPopup";
import CreateTeamFolderPopup from "../components/Teams/CreateTeamFolderPopup";
export default { export default {
name: 'Settings', name: 'Settings',
components: { components: {
CreateTeamFolderPopup,
CreateUploadRequestPopup,
MobileNavigationToolbar, MobileNavigationToolbar,
MobileNavigation, MobileNavigation,
ConfirmPassword, ConfirmPassword,

View File

@@ -1,4 +1,5 @@
<?php <?php
namespace Domain\UploadRequest\Controllers; namespace Domain\UploadRequest\Controllers;
use Auth; use Auth;
@@ -16,6 +17,7 @@ class CreateUploadRequestController extends Controller
'folder_id' => $request->input('folder_id'), 'folder_id' => $request->input('folder_id'),
'email' => $request->input('email'), 'email' => $request->input('email'),
'notes' => $request->input('notes'), 'notes' => $request->input('notes'),
'name' => $request->input('name'),
]); ]);
// If user type email, notify by email // If user type email, notify by email

View File

@@ -65,9 +65,9 @@ class UploadFilesForUploadRequestController
// Create folder // Create folder
DB::table('folders')->insert([ DB::table('folders')->insert([
'id' => $uploadRequest->id, 'id' => $uploadRequest->id,
'parent_id' => $uploadRequest->folder_id, 'parent_id' => $uploadRequest->folder_id ?? null,
'user_id' => $uploadRequest->user_id, 'user_id' => $uploadRequest->user_id,
'name' => "Upload Request from $timestampName", 'name' => $uploadRequest->name ?? "Upload Request from $timestampName",
]); ]);
// Update upload request status // Update upload request status

View File

@@ -1,4 +1,5 @@
<?php <?php
namespace Domain\UploadRequest\Requests; namespace Domain\UploadRequest\Requests;
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Foundation\Http\FormRequest;
@@ -23,9 +24,10 @@ class StoreUploadRequest extends FormRequest
public function rules() public function rules()
{ {
return [ return [
'email' => 'sometimes|string', 'email' => 'sometimes|string|nullable',
'notes' => 'sometimes|string', 'notes' => 'sometimes|string|nullable',
'folder_id' => 'required|string', 'folder_id' => 'sometimes|string',
'name' => 'sometimes|string|nullable',
]; ];
} }
} }

View File

@@ -1,4 +1,5 @@
<?php <?php
namespace Tests\Domain\UploadRequest; namespace Tests\Domain\UploadRequest;
use Domain\UploadRequest\Notifications\UploadRequestFulfilledNotification; use Domain\UploadRequest\Notifications\UploadRequestFulfilledNotification;
@@ -78,6 +79,34 @@ class UploadRequestTest extends TestCase
Notification::assertNothingSent(); Notification::assertNothingSent();
} }
/**
* @test
*/
public function user_create_upload_request_with_name()
{
$user = User::factory()
->hasSettings()
->create();
$this
->actingAs($user)
->postJson('/api/upload-request', [
'folder_id' => '00cacdb9-1d09-4a32-8ad7-c0d45d66b758',
'notes' => 'Please send me your files...',
'name' => 'My name',
])
->assertCreated();
$this->assertDatabasehas('upload_requests', [
'folder_id' => '00cacdb9-1d09-4a32-8ad7-c0d45d66b758',
'notes' => 'Please send me your files...',
'email' => null,
'name' => 'My name',
]);
Notification::assertNothingSent();
}
/** /**
* @test * @test
*/ */
@@ -103,7 +132,7 @@ class UploadRequestTest extends TestCase
/** /**
* @test * @test
*/ */
public function it_upload_file_and_create_upload_request_folder() public function it_upload_file_and_create_upload_request_folder_without_custom_folder_name()
{ {
$user = User::factory() $user = User::factory()
->hasSettings() ->hasSettings()
@@ -114,6 +143,7 @@ class UploadRequestTest extends TestCase
'status' => 'active', 'status' => 'active',
'user_id' => $user->id, 'user_id' => $user->id,
'created_at' => now(), 'created_at' => now(),
'name' => null,
]); ]);
$file = UploadedFile::fake() $file = UploadedFile::fake()
@@ -144,6 +174,51 @@ class UploadRequestTest extends TestCase
Storage::assertExists("files/$user->id/$file->basename"); Storage::assertExists("files/$user->id/$file->basename");
} }
/**
* @test
*/
public function it_upload_file_and_create_upload_request_folder_with_custom_folder_name()
{
$user = User::factory()
->hasSettings()
->create();
$uploadRequest = UploadRequest::factory()
->create([
'status' => 'active',
'user_id' => $user->id,
'created_at' => now(),
'name' => 'My Documents',
]);
$file = UploadedFile::fake()
->create('fake-file.pdf', 12000000, 'application/pdf');
$this
->postJson("/api/upload-request/$uploadRequest->id/upload", [
'filename' => $file->name,
'file' => $file,
'parent_id' => null,
'path' => "/$file->name",
'is_last' => 'true',
])->assertStatus(201);
$this
->assertDatabaseHas('upload_requests', [
'status' => 'filling',
])
->assertDatabaseHas('folders', [
'id' => $uploadRequest->id,
'name' => 'My Documents',
])->assertDatabaseHas('files', [
'parent_id' => $uploadRequest->id,
]);
$file = File::first();
Storage::assertExists("files/$user->id/$file->basename");
}
/** /**
* @test * @test
*/ */