Skip to content

Commit

Permalink
feat: ability to archive contact (monicahq/chandler#140)
Browse files Browse the repository at this point in the history
  • Loading branch information
djaiss authored Jun 28, 2022
1 parent 8e68593 commit 3cee53a
Show file tree
Hide file tree
Showing 12 changed files with 284 additions and 5 deletions.
2 changes: 2 additions & 0 deletions app/Models/ContactFeedItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class ContactFeedItem extends Model
public const ACTION_LOAN_UPDATED = 'loan_updated';
public const ACTION_ADDED_TO_GROUP = 'added_to_group';
public const ACTION_REMOVED_FROM_GROUP = 'removed_from_group';
public const ACTION_ARCHIVED_CONTACT = 'archived';
public const ACTION_UNARCHIVED_CONTACT = 'unarchived';

/**
* The attributes that are mass assignable.
Expand Down
76 changes: 76 additions & 0 deletions domains/Contact/ManageContact/Services/ToggleArchiveContact.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace App\Contact\ManageContact\Services;

use App\Interfaces\ServiceInterface;
use App\Models\Contact;
use App\Models\ContactFeedItem;
use App\Services\BaseService;

class ToggleArchiveContact extends BaseService implements ServiceInterface
{
private array $data;

/**
* Get the validation rules that apply to the service.
*
* @return array
*/
public function rules(): array
{
return [
'account_id' => 'required|integer|exists:accounts,id',
'vault_id' => 'required|integer|exists:vaults,id',
'author_id' => 'required|integer|exists:users,id',
'contact_id' => 'required|integer|exists:contacts,id',
];
}

/**
* Get the permissions that apply to the user calling the service.
*
* @return array
*/
public function permissions(): array
{
return [
'author_must_belong_to_account',
'vault_must_belong_to_account',
'contact_must_belong_to_vault',
'author_must_be_vault_editor',
];
}

/**
* Toggle the archive state of a contact.
*
* @param array $data
* @return Contact
*/
public function execute(array $data): Contact
{
$this->data = $data;
$this->validate();

$this->contact->listed = ! $this->contact->listed;
$this->contact->save();

$this->createFeedItem();

return $this->contact;
}

private function validate(): void
{
$this->validateRules($this->data);
}

private function createFeedItem(): void
{
ContactFeedItem::create([
'author_id' => $this->author->id,
'contact_id' => $this->contact->id,
'action' => $this->contact->refresh()->listed ? ContactFeedItem::ACTION_UNARCHIVED_CONTACT : ContactFeedItem::ACTION_ARCHIVED_CONTACT,
]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace App\Contact\ManageContact\Web\Controllers;

use App\Contact\ManageContact\Services\ToggleArchiveContact;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class ContactArchiveController extends Controller
{
public function update(Request $request, int $vaultId, int $contactId)
{
$data = [
'account_id' => Auth::user()->account_id,
'author_id' => Auth::user()->id,
'vault_id' => $vaultId,
'contact_id' => $contactId,
];

(new ToggleArchiveContact())->execute($data);

return response()->json([
'data' => route('contact.show', [
'vault' => $vaultId,
'contact' => $contactId,
]),
], 200);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use App\Contact\ManageContact\Web\ViewHelpers\ContactEditViewHelper;
use App\Contact\ManageContact\Web\ViewHelpers\ContactIndexViewHelper;
use App\Contact\ManageContact\Web\ViewHelpers\ContactShowViewHelper;
use App\Helpers\PaginatorHelper;
use App\Http\Controllers\Controller;
use App\Models\Contact;
use App\Models\Vault;
Expand All @@ -27,11 +28,12 @@ public function index(Request $request, int $vaultId)
$contacts = Contact::where('vault_id', $request->route()->parameter('vault'))
->where('listed', true)
->orderBy('created_at', 'asc')
->paginate(10);
->paginate(25);

return Inertia::render('Vault/Contact/Index', [
'layoutData' => VaultIndexViewHelper::layoutData($vault),
'data' => ContactIndexViewHelper::data($contacts, $vault),
'paginator' => PaginatorHelper::getData($contacts),
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public static function data(Contact $contact, User $user): array

return [
'contact_name' => ModuleContactNameViewHelper::data($contact, $user),
'listed' => $contact->listed,
'template_pages' => $templatesPagesCollection,
'contact_information' => self::getContactInformation($templatePages, $contact, $user),
'group_summary_information' => GroupsViewHelper::summary($contact),
Expand All @@ -55,6 +56,10 @@ public static function data(Contact $contact, User $user): array
'can_be_deleted' => $user->getContactInVault($contact->vault)->id !== $contact->id,
],
'url' => [
'toggle_archive' => route('contact.archive.update', [
'vault' => $contact->vault_id,
'contact' => $contact->id,
]),
'update_template' => route('contact.blank', [
'vault' => $contact->vault_id,
'contact' => $contact->id,
Expand All @@ -73,6 +78,7 @@ public static function dataForTemplatePage(Contact $contact, User $user, Templat

return [
'contact_name' => ModuleContactNameViewHelper::data($contact, $user),
'listed' => $contact->listed,
'template_pages' => self::getTemplatePagesList($templatePages, $contact, $templatePage),
'contact_information' => self::getContactInformation($templatePages, $contact, $user),
'group_summary_information' => GroupsViewHelper::summary($contact),
Expand Down
18 changes: 18 additions & 0 deletions resources/js/Pages/Vault/Contact/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@
</inertia-link>
</li>
</ul>

<!-- pagination -->
<div v-if="!moduleMode" class="flex justify-between text-center">
<inertia-link
v-show="paginator.previousPageUrl"
class="fl dib"
:href="paginator.previousPageUrl"
title="Previous">
&larr; Previous
</inertia-link>
<inertia-link v-show="paginator.nextPageUrl" class="fr dib" :href="paginator.nextPageUrl" title="Next">
Next &rarr;
</inertia-link>
</div>
</div>
</div>
</div>
Expand All @@ -108,6 +122,10 @@ export default {
type: Object,
default: null,
},
paginator: {
type: Object,
default: null,
},
data: {
type: Object,
default: null,
Expand Down
31 changes: 30 additions & 1 deletion resources/js/Pages/Vault/Contact/Show.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@

<main class="sm:mt-18 relative">
<div class="mx-auto max-w-6xl px-2 py-2 sm:py-6 sm:px-6 lg:px-8">
<!-- banner if contact is archived -->
<!-- this is based on the `listed` boolean on the contact object -->
<div v-if="!data.listed" class="mb-8 rounded-lg border border-gray-300 px-3 py-2 text-center">
<span class="mr-4">🕸️</span> The contact is archived <span class="ml-4">🕷️</span>
</div>

<div class="special-grid grid grid-cols-1 gap-6 sm:grid-cols-3">
<!-- left -->
<div class="p-3 sm:p-3">
Expand All @@ -67,6 +73,16 @@
</div>

<ul class="text-xs">
<li v-if="data.listed" class="mb-2">
<inertia-link @click.prevent="toggleArchive()" class="cursor-pointer text-blue-500 hover:underline"
>Archive contact</inertia-link
>
</li>
<li v-if="!data.listed" class="mb-2">
<inertia-link @click.prevent="toggleArchive()" class="cursor-pointer text-blue-500 hover:underline"
>Unarchive contact</inertia-link
>
</li>
<li class="mb-2">
<inertia-link :href="data.url.update_template" class="cursor-pointer text-blue-500 hover:underline"
>Change template</inertia-link
Expand Down Expand Up @@ -323,7 +339,20 @@ export default {
this.$inertia.visit(response.data.data);
})
.catch((error) => {
this.loadingState = null;
this.form.errors = error.response.data;
});
}
},
toggleArchive() {
if (confirm('Are you sure?')) {
axios
.put(this.data.url.toggle_archive)
.then((response) => {
localStorage.success = 'Changes saved';
this.$inertia.visit(response.data.data);
})
.catch((error) => {
this.form.errors = error.response.data;
});
}
Expand Down
4 changes: 2 additions & 2 deletions resources/js/Pages/Vault/Search/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@
<div v-if="!processingSearch && Object.keys(results).length !== 0">
<contact :data="results.contacts" />

<note :data="results.notes" />

<group :data="results.groups" />

<note :data="results.notes" />
</div>

<!-- searching results -->
Expand Down
2 changes: 2 additions & 0 deletions resources/lang/en/contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
'feed_item_goal_created' => 'created a goal',
'feed_item_added_to_group' => 'added the contact to a group',
'feed_item_removed_from_group' => 'removed the contact from a group',
'feed_item_archived' => 'archived the contact',
'feed_item_unarchived' => 'unarchived the contact',

'group_create' => '+ Create a new group',
];
2 changes: 2 additions & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use App\Contact\ManageCalls\Web\Controllers\ContactModuleCallController;
use App\Contact\ManageContact\Web\Controllers\ContactArchiveController;
use App\Contact\ManageContact\Web\Controllers\ContactController;
use App\Contact\ManageContact\Web\Controllers\ContactLabelController;
use App\Contact\ManageContact\Web\Controllers\ContactNoTemplateController;
Expand Down Expand Up @@ -119,6 +120,7 @@
Route::get('/edit', [ContactController::class, 'edit'])->name('contact.edit');
Route::post('', [ContactController::class, 'update'])->name('contact.update');
Route::delete('', [ContactController::class, 'destroy'])->name('contact.destroy');
Route::put('/toggle', [ContactArchiveController::class, 'update'])->name('contact.archive.update');
Route::get('update-template', [ContactNoTemplateController::class, 'show'])->name('contact.blank');
Route::put('template', [ContactTemplateController::class, 'update'])->name('contact.template.update');

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

namespace Tests\Unit\Domains\Contact\ManageContact\Services;

use App\Contact\ManageContact\Services\ToggleArchiveContact;
use App\Exceptions\NotEnoughPermissionException;
use App\Models\Account;
use App\Models\Contact;
use App\Models\User;
use App\Models\Vault;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Validation\ValidationException;
use Tests\TestCase;

class ToggleArchiveContactTest extends TestCase
{
use DatabaseTransactions;

/** @test */
public function it_toggles_a_contact(): void
{
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$this->executeService($regis, $regis->account, $vault, $contact);
}

/** @test */
public function it_fails_if_wrong_parameters_are_given(): void
{
$request = [
'title' => 'Ross',
];

$this->expectException(ValidationException::class);
(new ToggleArchiveContact())->execute($request);
}

/** @test */
public function it_fails_if_user_doesnt_belong_to_account(): void
{
$this->expectException(ModelNotFoundException::class);

$regis = $this->createUser();
$account = $this->createAccount();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_MANAGE, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);

$this->executeService($regis, $account, $vault, $contact);
}

/** @test */
public function it_fails_if_contact_doesnt_belong_to_vault(): void
{
$this->expectException(ModelNotFoundException::class);

$regis = $this->createUser();
$vault = Vault::factory()->create();
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$otherVault = Vault::factory()->create();

$this->executeService($regis, $regis->account, $otherVault, $contact);
}

/** @test */
public function it_fails_if_user_doesnt_have_right_permission_in_vault(): void
{
$this->expectException(NotEnoughPermissionException::class);

$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_VIEW, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);

$this->executeService($regis, $regis->account, $vault, $contact);
}

private function executeService(User $author, Account $account, Vault $vault, Contact $contact): void
{
$request = [
'account_id' => $account->id,
'vault_id' => $vault->id,
'author_id' => $author->id,
'contact_id' => $contact->id,
];

$contact = (new ToggleArchiveContact())->execute($request);

$this->assertDatabaseHas('contacts', [
'id' => $contact->id,
'vault_id' => $vault->id,
'listed' => false,
]);

$contact = (new ToggleArchiveContact())->execute($request);

$this->assertDatabaseHas('contacts', [
'id' => $contact->id,
'vault_id' => $vault->id,
'listed' => true,
]);
}
}
Loading

0 comments on commit 3cee53a

Please sign in to comment.