feat: manage labels (monicahq/chandler#9)
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Settings\Personalize\Labels;
|
||||
|
||||
use Inertia\Inertia;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Services\Account\ManageLabels\CreateLabel;
|
||||
use App\Services\Account\ManageLabels\UpdateLabel;
|
||||
use App\Services\Account\ManageLabels\DestroyLabel;
|
||||
use App\Http\Controllers\Vault\ViewHelpers\VaultIndexViewHelper;
|
||||
use App\Http\Controllers\Settings\Personalize\Labels\ViewHelpers\PersonalizeLabelIndexViewHelper;
|
||||
|
||||
class PersonalizeLabelController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return Inertia::render('Settings/Personalize/Labels/Index', [
|
||||
'layoutData' => VaultIndexViewHelper::layoutData(),
|
||||
'data' => PersonalizeLabelIndexViewHelper::data(Auth::user()->account),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => Auth::user()->account_id,
|
||||
'author_id' => Auth::user()->id,
|
||||
'name' => $request->input('name'),
|
||||
'description' => $request->input('description'),
|
||||
];
|
||||
|
||||
$label = (new CreateLabel)->execute($data);
|
||||
|
||||
return response()->json([
|
||||
'data' => PersonalizeLabelIndexViewHelper::dtoLabel($label),
|
||||
], 201);
|
||||
}
|
||||
|
||||
public function update(Request $request, int $labelId)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => Auth::user()->account_id,
|
||||
'author_id' => Auth::user()->id,
|
||||
'label_id' => $labelId,
|
||||
'name' => $request->input('name'),
|
||||
'description' => $request->input('description'),
|
||||
];
|
||||
|
||||
$label = (new UpdateLabel)->execute($data);
|
||||
|
||||
return response()->json([
|
||||
'data' => PersonalizeLabelIndexViewHelper::dtoLabel($label),
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function destroy(Request $request, int $labelId)
|
||||
{
|
||||
$data = [
|
||||
'account_id' => Auth::user()->account_id,
|
||||
'author_id' => Auth::user()->id,
|
||||
'label_id' => $labelId,
|
||||
];
|
||||
|
||||
(new DestroyLabel)->execute($data);
|
||||
|
||||
return response()->json([
|
||||
'data' => true,
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Settings\Personalize\Labels\ViewHelpers;
|
||||
|
||||
use App\Models\Label;
|
||||
use App\Models\Account;
|
||||
|
||||
class PersonalizeLabelIndexViewHelper
|
||||
{
|
||||
public static function data(Account $account): array
|
||||
{
|
||||
$labels = $account->labels()
|
||||
->withCount('contacts')
|
||||
->orderBy('name', 'asc')
|
||||
->get();
|
||||
|
||||
$collection = collect();
|
||||
foreach ($labels as $label) {
|
||||
$collection->push(self::dtoLabel($label));
|
||||
}
|
||||
|
||||
return [
|
||||
'labels' => $collection,
|
||||
'url' => [
|
||||
'settings' => route('settings.index'),
|
||||
'personalize' => route('settings.personalize.index'),
|
||||
'label_store' => route('settings.personalize.label.store'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public static function dtoLabel(Label $label): array
|
||||
{
|
||||
return [
|
||||
'id' => $label->id,
|
||||
'name' => $label->name,
|
||||
'count' => $label->contacts_count,
|
||||
'url' => [
|
||||
'update' => route('settings.personalize.label.update', [
|
||||
'label' => $label->id,
|
||||
]),
|
||||
'destroy' => route('settings.personalize.label.destroy', [
|
||||
'label' => $label->id,
|
||||
]),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ class PersonalizeIndexViewHelper
|
||||
'settings' => route('settings.index'),
|
||||
'back' => route('settings.index'),
|
||||
'manage_relationships' => route('settings.personalize.relationship.index'),
|
||||
'manage_labels' => route('settings.personalize.label.index'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Services\Account\ManageLabels;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Label;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Jobs\CreateAuditLog;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Services\Account\ManageLabels;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Label;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Jobs\CreateAuditLog;
|
||||
use App\Services\BaseService;
|
||||
use App\Interfaces\ServiceInterface;
|
||||
@@ -22,6 +22,7 @@ class UpdateLabel extends BaseService implements ServiceInterface
|
||||
'author_id' => 'required|integer|exists:users,id',
|
||||
'label_id' => 'required|integer|exists:labels,id',
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'nullable|string|max:65535',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -52,6 +53,8 @@ class UpdateLabel extends BaseService implements ServiceInterface
|
||||
->findOrFail($data['label_id']);
|
||||
|
||||
$label->name = $data['name'];
|
||||
$label->description = $this->valueOrNull($data, 'description');
|
||||
$label->slug = Str::slug($data['name'], '-');
|
||||
$label->save();
|
||||
|
||||
CreateAuditLog::dispatch([
|
||||
|
||||
@@ -8,7 +8,6 @@ use App\Interfaces\ServiceInterface;
|
||||
|
||||
class StoreNameOrderPreference extends BaseService implements ServiceInterface
|
||||
{
|
||||
private User $user;
|
||||
private array $data;
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
"eslint-plugin-promise": ">=4.2.1",
|
||||
"eslint-plugin-standard": ">=4.0.0",
|
||||
"eslint-plugin-vue": "^7.0.1",
|
||||
"husky": "^4.3.0",
|
||||
"laravel-mix": "^6.0.6",
|
||||
"lint-staged": "^8.2.1",
|
||||
"lodash": "^4.17.19",
|
||||
"postcss": "^8.4.4",
|
||||
"postcss-import": "^14.0.1",
|
||||
|
||||
@@ -30,9 +30,10 @@
|
||||
<main class="sm:mt-20 relative">
|
||||
<div class="max-w-md mx-auto px-2 py-2 sm:py-6 sm:px-6 lg:px-8">
|
||||
<h2 class="text-lg text-center mb-6">Personalize the account</h2>
|
||||
<div class="bg-white border border-gray-200 rounded-lg mb-6 p-5">
|
||||
<div class="bg-white border border-gray-200 rounded-lg p-5">
|
||||
<ul>
|
||||
<li class="mb-2"><span class="mr-1">🥸</span> <Link :href="data.url.manage_relationships" class="text-sky-500 hover:text-blue-900">Manage relationship types</Link></li>
|
||||
<li class=""><span class="mr-1">🏷</span> <Link :href="data.url.manage_labels" class="text-sky-500 hover:text-blue-900">Manage labels</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
<style lang="scss" scoped>
|
||||
.item-list {
|
||||
&:hover:first-child {
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
&:hover:last-child {
|
||||
border-bottom-left-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<Layout :layoutData="layoutData">
|
||||
<!-- breadcrumb -->
|
||||
<nav class="sm:border-b bg-white">
|
||||
<div class="max-w-8xl mx-auto px-4 sm:px-6 py-2 hidden md:block">
|
||||
<div class="flex items-baseline justify-between space-x-6">
|
||||
<ul class="text-sm">
|
||||
<li class="inline mr-2 text-gray-600">You are here:</li>
|
||||
<li class="inline mr-2">
|
||||
<Link :href="data.url.settings" class="text-sky-500 hover:text-blue-900">Settings</Link>
|
||||
</li>
|
||||
<li class="inline mr-2 relative">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3 inline relative icon-breadcrumb" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</li>
|
||||
<li class="inline mr-2"><Link :href="data.url.personalize" class="text-sky-500 hover:text-blue-900">Personalize your account</Link></li>
|
||||
<li class="inline mr-2 relative">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3 inline relative icon-breadcrumb" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</li>
|
||||
<li class="inline">Labels</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="sm:mt-20 relative">
|
||||
<div class="max-w-3xl mx-auto px-2 py-2 sm:py-6 sm:px-6 lg:px-8">
|
||||
<!-- title + cta -->
|
||||
<div class="sm:flex items-center justify-between mb-6 sm:mt-0 mt-8">
|
||||
<h3 class="mb-4 sm:mb-0"><span class="mr-1">🏷</span> All the labels used in the account</h3>
|
||||
<pretty-button @click="showLabelModal" v-if="!createlabelModalShown" :text="'Add a label'" :icon="'plus'" />
|
||||
</div>
|
||||
|
||||
<!-- modal to create a new group type -->
|
||||
<form v-if="createlabelModalShown" @submit.prevent="submit()" class="bg-white border border-gray-200 rounded-lg mb-6">
|
||||
<div class="p-5 border-b border-gray-200">
|
||||
<errors :errors="form.errors" />
|
||||
|
||||
<text-input v-model="form.name"
|
||||
:label="'Name'"
|
||||
:type="'text'" :autofocus="true"
|
||||
:input-class="'block w-full'"
|
||||
:required="true"
|
||||
:ref="'newLabel'"
|
||||
:autocomplete="false"
|
||||
:maxlength="255"
|
||||
@esc-key-pressed="createlabelModalShown = false" />
|
||||
</div>
|
||||
|
||||
<div class="p-5 flex justify-between">
|
||||
<pretty-span @click="createlabelModalShown = false" :text="'Cancel'" :classes="'mr-3'" />
|
||||
<pretty-button :text="'Create label'" :state="loadingState" :icon="'plus'" :classes="'save'" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- list of groups types -->
|
||||
<ul v-if="localLabels.length > 0" class="bg-white border border-gray-200 rounded-lg mb-6">
|
||||
<li v-for="label in localLabels" :key="label.id" class="border-b border-gray-200 hover:bg-slate-50 item-list">
|
||||
<!-- detail of the group type -->
|
||||
<div v-if="renamelabelModalShownId != label.id" class="flex justify-between items-center px-5 py-2">
|
||||
<span class="text-base">{{ label.name }} <span class="text-xs text-gray-500">({{ label.count }} contacts)</span></span>
|
||||
|
||||
<!-- actions -->
|
||||
<ul class="text-sm">
|
||||
<li @click="updateLabelModal(label)" class="cursor-pointer inline mr-4 text-sky-500 hover:text-blue-900">Rename</li>
|
||||
<li @click="destroy(label)" class="cursor-pointer inline text-red-500 hover:text-red-900">Delete</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- rename a label modal -->
|
||||
<form v-if="renamelabelModalShownId == label.id" @submit.prevent="update(label)" class="border-b border-gray-200 hover:bg-slate-50 item-list">
|
||||
<div class="p-5 border-b border-gray-200">
|
||||
<errors :errors="form.errors" />
|
||||
|
||||
<text-input v-model="form.name"
|
||||
:label="'Name'"
|
||||
:type="'text'" :autofocus="true"
|
||||
:input-class="'block w-full'"
|
||||
:required="true"
|
||||
:ref="'rename' + label.id"
|
||||
:autocomplete="false"
|
||||
:maxlength="255"
|
||||
@esc-key-pressed="renamelabelModalShownId = 0" />
|
||||
</div>
|
||||
|
||||
<div class="p-5 flex justify-between">
|
||||
<pretty-span @click.prevent="renamelabelModalShownId = 0" :text="'Cancel'" :classes="'mr-3'" />
|
||||
<pretty-button :text="'Rename'" :state="loadingState" :icon="'check'" :classes="'save'" />
|
||||
</div>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- blank state -->
|
||||
<div v-if="localLabels.length == 0" class="bg-white border border-gray-200 rounded-lg mb-6">
|
||||
<p class="p-5 text-center">Labels let you classify contacts using a system that matters to you.</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Layout from '@/Shared/Layout';
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
import PrettyButton from '@/Shared/PrettyButton';
|
||||
import PrettyLink from '@/Shared/PrettyLink';
|
||||
import PrettySpan from '@/Shared/PrettySpan';
|
||||
import TextInput from '@/Shared/TextInput';
|
||||
import Errors from '@/Shared/Errors';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Layout,
|
||||
Link,
|
||||
PrettyButton,
|
||||
PrettyLink,
|
||||
PrettySpan,
|
||||
TextInput,
|
||||
Errors,
|
||||
},
|
||||
|
||||
props: {
|
||||
layoutData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loadingState: '',
|
||||
createlabelModalShown: false,
|
||||
renamelabelModalShownId: 0,
|
||||
localLabels: [],
|
||||
form: {
|
||||
name: '',
|
||||
description: '',
|
||||
errors: [],
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.localLabels = this.data.labels;
|
||||
},
|
||||
|
||||
methods: {
|
||||
showLabelModal() {
|
||||
this.form.name = '';
|
||||
this.createlabelModalShown = true;
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.newLabel.focus();
|
||||
});
|
||||
},
|
||||
|
||||
updateLabelModal(label) {
|
||||
this.form.name = label.name;
|
||||
this.renamelabelModalShownId = label.id;
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs[`rename${label.id}`].focus();
|
||||
});
|
||||
},
|
||||
|
||||
submit() {
|
||||
this.loadingState = 'loading';
|
||||
|
||||
axios.post(this.data.url.label_store, this.form)
|
||||
.then(response => {
|
||||
this.flash('The label has been created', 'success');
|
||||
this.localLabels.unshift(response.data.data);
|
||||
this.loadingState = null;
|
||||
this.createlabelModalShown = false;
|
||||
})
|
||||
.catch(error => {
|
||||
this.loadingState = null;
|
||||
this.form.errors = error.response.data;
|
||||
});
|
||||
},
|
||||
|
||||
update(label) {
|
||||
this.loadingState = 'loading';
|
||||
|
||||
axios.put(label.url.update, this.form)
|
||||
.then(response => {
|
||||
this.flash('The label has been updated', 'success');
|
||||
this.localLabels[this.localLabels.findIndex(x => x.id === label.id)] = response.data.data;
|
||||
this.loadingState = null;
|
||||
this.renamelabelModalShownId = 0;
|
||||
})
|
||||
.catch(error => {
|
||||
this.loadingState = null;
|
||||
this.form.errors = error.response.data;
|
||||
});
|
||||
},
|
||||
|
||||
destroy(label) {
|
||||
if(confirm("Are you sure? This will remove the labels from all contacts, but won't delete the contacts themselves.")) {
|
||||
|
||||
axios.delete(label.url.destroy)
|
||||
.then(response => {
|
||||
this.flash('The label has been deleted', 'success');
|
||||
var id = this.localLabels.findIndex(x => x.id === label.id);
|
||||
this.localLabels.splice(id, 1);
|
||||
})
|
||||
.catch(error => {
|
||||
this.loadingState = null;
|
||||
this.form.errors = error.response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -90,7 +90,7 @@
|
||||
</div>
|
||||
|
||||
<div class="p-5 flex justify-between">
|
||||
<pretty-link @click="createGroupTypeModalShown = false" :text="'Cancel'" :classes="'mr-3'" />
|
||||
<pretty-span @click="createGroupTypeModalShown = false" :text="'Cancel'" :classes="'mr-3'" />
|
||||
<pretty-button :text="'Create group type'" :state="loadingState" :icon="'plus'" :classes="'save'" />
|
||||
</div>
|
||||
</form>
|
||||
@@ -245,7 +245,6 @@
|
||||
import Layout from '@/Shared/Layout';
|
||||
import { Link } from '@inertiajs/inertia-vue3';
|
||||
import PrettyButton from '@/Shared/PrettyButton';
|
||||
import PrettyLink from '@/Shared/PrettyLink';
|
||||
import PrettySpan from '@/Shared/PrettySpan';
|
||||
import TextInput from '@/Shared/TextInput';
|
||||
import Errors from '@/Shared/Errors';
|
||||
@@ -255,7 +254,6 @@ export default {
|
||||
Layout,
|
||||
Link,
|
||||
PrettyButton,
|
||||
PrettyLink,
|
||||
PrettySpan,
|
||||
TextInput,
|
||||
Errors,
|
||||
|
||||
@@ -41,6 +41,9 @@ pre {
|
||||
<!-- edit mode -->
|
||||
<form v-if="editMode" @submit.prevent="submit()" class="bg-white border border-gray-200 rounded-lg mb-6">
|
||||
<div class="px-5 py-2 border-b border-gray-200">
|
||||
|
||||
<Errors :errors="form.errors" />
|
||||
|
||||
<div class="flex items-center mb-2">
|
||||
<input v-model="form.nameOrder" id="first_name_last_name" value="%first_name% %last_name%" name="name-order" type="radio" class="h-4 w-4 text-sky-500 border-gray-300">
|
||||
<label for="first_name_last_name" class="ml-3 block text-sm font-medium text-gray-700 cursor-pointer">
|
||||
|
||||
@@ -10,6 +10,7 @@ use App\Http\Controllers\Auth\AcceptInvitationController;
|
||||
use App\Http\Controllers\Settings\Personalize\PersonalizeController;
|
||||
use App\Http\Controllers\Settings\Preferences\PreferencesController;
|
||||
use App\Http\Controllers\Settings\CancelAccount\CancelAccountController;
|
||||
use App\Http\Controllers\Settings\Personalize\Labels\PersonalizeLabelController;
|
||||
use App\Http\Controllers\Settings\Personalize\Relationships\PersonalizeRelationshipController;
|
||||
use App\Http\Controllers\Settings\Personalize\Relationships\PersonalizeRelationshipTypeController;
|
||||
|
||||
@@ -73,6 +74,12 @@ Route::middleware(['auth', 'verified'])->group(function () {
|
||||
Route::post('relationships/{groupType}/types', [PersonalizeRelationshipTypeController::class, 'store'])->name('settings.personalize.relationship.type.store');
|
||||
Route::put('relationships/{groupType}/types/{type}', [PersonalizeRelationshipTypeController::class, 'update'])->name('settings.personalize.relationship.type.update');
|
||||
Route::delete('relationships/{groupType}/types/{type}', [PersonalizeRelationshipTypeController::class, 'destroy'])->name('settings.personalize.relationship.type.destroy');
|
||||
|
||||
// labels
|
||||
Route::get('labels', [PersonalizeLabelController::class, 'index'])->name('settings.personalize.label.index');
|
||||
Route::post('labels', [PersonalizeLabelController::class, 'store'])->name('settings.personalize.label.store');
|
||||
Route::put('labels/{label}', [PersonalizeLabelController::class, 'update'])->name('settings.personalize.label.update');
|
||||
Route::delete('labels/{label}', [PersonalizeLabelController::class, 'destroy'])->name('settings.personalize.label.destroy');
|
||||
});
|
||||
|
||||
// cancel
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Controllers\Settings\Personalize\Labels\ViewHelpers;
|
||||
|
||||
use function env;
|
||||
use Tests\TestCase;
|
||||
use App\Models\Label;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use App\Http\Controllers\Settings\Personalize\Labels\ViewHelpers\PersonalizeLabelIndexViewHelper;
|
||||
|
||||
class PersonalizeLabelIndexViewHelperTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
/** @test */
|
||||
public function it_gets_the_data_needed_for_the_view(): void
|
||||
{
|
||||
$label = Label::factory()->create();
|
||||
$array = PersonalizeLabelIndexViewHelper::data($label->account);
|
||||
$this->assertEquals(
|
||||
2,
|
||||
count($array)
|
||||
);
|
||||
$this->assertArrayHasKey('labels', $array);
|
||||
$this->assertEquals(
|
||||
[
|
||||
'settings' => env('APP_URL').'/settings',
|
||||
'personalize' => env('APP_URL').'/settings/personalize',
|
||||
'label_store' => env('APP_URL').'/settings/personalize/labels',
|
||||
],
|
||||
$array['url']
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_gets_the_data_needed_for_the_data_transfer_object(): void
|
||||
{
|
||||
$label = Label::factory()->create();
|
||||
$array = PersonalizeLabelIndexViewHelper::dtoLabel($label);
|
||||
$this->assertEquals(
|
||||
[
|
||||
'id' => $label->id,
|
||||
'name' => $label->name,
|
||||
'count' => 0,
|
||||
'url' => [
|
||||
'update' => route('settings.personalize.label.update', [
|
||||
'label' => $label->id,
|
||||
]),
|
||||
'destroy' => route('settings.personalize.label.destroy', [
|
||||
'label' => $label->id,
|
||||
]),
|
||||
],
|
||||
],
|
||||
$array
|
||||
);
|
||||
}
|
||||
}
|
||||
+1
@@ -21,6 +21,7 @@ class PersonalizeIndexViewHelperTest extends TestCase
|
||||
'settings' => env('APP_URL').'/settings',
|
||||
'back' => env('APP_URL').'/settings',
|
||||
'manage_relationships' => env('APP_URL').'/settings/personalize/relationships',
|
||||
'manage_labels' => env('APP_URL').'/settings/personalize/labels',
|
||||
],
|
||||
],
|
||||
$array
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\User;
|
||||
|
||||
use Tests\TestCase;
|
||||
use App\Models\User;
|
||||
use App\Models\Account;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Services\User\StoreNameOrderPreference;
|
||||
use App\Services\Account\ManageLabels\CreateLabel;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
class StoreNameOrderPreferenceTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
/** @test */
|
||||
public function it_stores_the_name_order_preference(): void
|
||||
{
|
||||
$ross = $this->createUser();
|
||||
$this->executeService($ross, '%name%', $ross->account);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_fails_if_wrong_parameters_are_given(): void
|
||||
{
|
||||
$request = [
|
||||
'title' => 'Ross',
|
||||
];
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
(new CreateLabel)->execute($request);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_fails_if_user_doesnt_belong_to_account(): void
|
||||
{
|
||||
$this->expectException(ModelNotFoundException::class);
|
||||
|
||||
$ross = $this->createAdministrator();
|
||||
$account = $this->createAccount();
|
||||
$this->executeService($ross, '%user%', $account);
|
||||
}
|
||||
|
||||
public function it_fails_if_name_order_has_no_variable(): void
|
||||
{
|
||||
$this->expectException(ModelNotFoundException::class);
|
||||
|
||||
$ross = $this->createAdministrator();
|
||||
$this->executeService($ross, '', $ross->account);
|
||||
}
|
||||
|
||||
public function it_fails_if_name_order_has_no_closing_percent_symbol(): void
|
||||
{
|
||||
$this->expectException(ModelNotFoundException::class);
|
||||
|
||||
$ross = $this->createAdministrator();
|
||||
$this->executeService($ross, '%', $ross->account);
|
||||
}
|
||||
|
||||
private function executeService(User $author, string $nameOrder, Account $account): void
|
||||
{
|
||||
Queue::fake();
|
||||
|
||||
$request = [
|
||||
'account_id' => $account->id,
|
||||
'author_id' => $author->id,
|
||||
'name_order' => $nameOrder,
|
||||
];
|
||||
|
||||
$user = (new StoreNameOrderPreference)->execute($request);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'account_id' => $account->id,
|
||||
'name_order' => $nameOrder,
|
||||
]);
|
||||
|
||||
$this->assertInstanceOf(
|
||||
User::class,
|
||||
$user
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user