Skip to content

Commit

Permalink
feat: list of groups in the vault (monicahq/chandler#228)
Browse files Browse the repository at this point in the history
  • Loading branch information
djaiss authored Sep 21, 2022
1 parent 3d9cc3b commit b8e5847
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Contact\ManageGroups\Web\Controllers;

use App\Contact\ManageGroups\Web\ViewHelpers\GroupIndexViewHelper;
use App\Contact\ManageGroups\Web\ViewHelpers\GroupShowViewHelper;
use App\Http\Controllers\Controller;
use App\Models\Group;
Expand All @@ -15,6 +16,12 @@ class GroupController extends Controller
{
public function index(Request $request, int $vaultId)
{
$vault = Vault::findOrFail($vaultId);

return Inertia::render('Vault/Group/Index', [
'layoutData' => VaultIndexViewHelper::layoutData($vault),
'data' => GroupIndexViewHelper::data($vault),
]);
}

public function show(Request $request, int $vaultId, int $groupId)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace App\Contact\ManageGroups\Web\ViewHelpers;

use App\Models\Contact;
use App\Models\Group;
use App\Models\Vault;
use Illuminate\Support\Collection;

class GroupIndexViewHelper
{
/**
* Gets the list of groups in the vault.
*
* @param Vault $vault
* @return Collection
*/
public static function data(Vault $vault): Collection
{
return $vault->groups()->with('contacts')
->orderBy('name')
->get()
->map(function (Group $group) {
$contactsCollection = $group->contacts()
->get()
->map(fn (Contact $contact) => [
'id' => $contact->id,
'name' => $contact->name,
'age' => $contact->age,
'avatar' => $contact->avatar,
'url' => route('contact.show', [
'vault' => $contact->vault_id,
'contact' => $contact->id,
]),
]);

return [
'id' => $group->id,
'name' => $group->name,
'url' => [
'show' => route('group.show', [
'vault' => $group->vault_id,
'group' => $group->id,
]),
],
'contacts' => $contactsCollection,
];
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ public static function upcomingReminders(Vault $vault, User $user): array
$currentDate = Carbon::now()->copy();
$currentDate->second = 0;

// this query is a bit long and tough to do, and it could surely
// be optimized if I knew how to properly join queries

// first we get all the user notification channels for the users in the vault
$userNotificationChannels = $vault->users->flatMap(fn ($u) => $u->notificationChannels);

Expand Down Expand Up @@ -79,6 +76,10 @@ public static function upcomingReminders(Vault $vault, User $user): array
];
});

// this line removes the null values that are added when the contact
// is not in the vault (in the method above)
$remindersCollection = $remindersCollection->filter(fn ($value) => $value != null);

return [
'reminders' => $remindersCollection,
'url' => [
Expand Down
1 change: 1 addition & 0 deletions lang/en/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
'layout_menu_dashboard' => 'Dashboard',
'layout_menu_reports' => 'Reports',
'layout_menu_contacts' => 'Contacts',
'layout_menu_groups' => 'Groups',
'layout_menu_tasks' => 'Tasks',
'layout_menu_gift_center' => 'Gifts',
'layout_menu_loans' => 'Loans & debts',
Expand Down
7 changes: 7 additions & 0 deletions lang/en/vault.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
'show_contacts_labels_blank' => 'No labels yet.',
'show_contacts_cta' => 'Add a contact',

/***************************************************************
* VAULT - GROUP LIST
**************************************************************/

'show_groups_index' => 'All groups in the vault',
'show_groups_blank' => 'Groups let you put your contacts together in a single place.',

/***************************************************************
* VAULT - ADD A CONTACT
**************************************************************/
Expand Down
69 changes: 69 additions & 0 deletions resources/js/Pages/Vault/Group/Index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<script setup>
import Layout from '@/Shared/Layout.vue';
import Avatar from '@/Shared/Avatar.vue';
defineProps({
layoutData: Object,
data: Object,
});
</script>

<template>
<layout :layout-data="layoutData" :inside-vault="true">
<main class="relative sm:mt-24">
<div class="mx-auto max-w-4xl px-2 py-2 sm:py-6 sm:px-6 lg:px-8">
<!-- group title -->
<h3 class="mb-6 font-semibold">
<span class="mr-1"> 👥 </span>
{{ $t('vault.show_groups_index') }}
</h3>

<div v-if="data.length != 0">
<ul class="group-list mb-6 rounded-lg border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900">
<li
v-for="group in data"
:key="group.id"
class="flex items-center justify-between border-b border-gray-200 px-5 py-2 hover:bg-slate-50 dark:border-gray-700 dark:bg-slate-900 hover:dark:bg-slate-800">
<inertia-link :href="group.url.show" class="text-blue-500 hover:underline">{{ group.name }}</inertia-link>

<div v-if="group.contacts" class="relative flex -space-x-2 overflow-hidden py-1">
<div v-for="contact in group.contacts" :key="contact.id" class="inline-block">
<inertia-link :href="contact.url.show">
<avatar :data="contact.avatar" :classes="'h-8 w-8 rounded-full ring-2 ring-white'" />
</inertia-link>
</div>
</div>
</li>
</ul>
</div>

<!-- blank state -->
<div
v-if="data.length == 0"
class="mb-6 rounded-lg border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900">
<p class="p-5 text-center">
{{ $t('vault.show_groups_blank') }}
</p>
</div>
</div>
</main>
</layout>
</template>

<style lang="scss" scoped>
.group-list {
li:hover:first-child {
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
li:last-child {
border-bottom: 0;
}
li:hover:last-child {
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
}
</style>
3 changes: 2 additions & 1 deletion resources/js/Pages/Vault/Group/Show.vue
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,12 @@ defineProps({
<!-- contacts by roles -->
<div v-for="role in data.roles" :key="role.id" class="mb-8">
<p
v-if="role.contacts.length > 0"
class="mr-2 mb-2 inline-block rounded bg-neutral-200 py-1 px-2 text-xs font-semibold text-neutral-800 last:mr-0">
{{ role.label }}
</p>

<div class="grid grid-cols-3 gap-x-12 gap-y-6 sm:grid-cols-4">
<div v-if="role.contacts.length > 0" class="grid grid-cols-3 gap-x-12 gap-y-6 sm:grid-cols-4">
<div
v-for="contact in role.contacts"
:key="contact.id"
Expand Down
7 changes: 7 additions & 0 deletions resources/js/Shared/Layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,13 @@
{{ $t('app.layout_menu_contacts') }}
</inertia-link>

<inertia-link
:href="layoutData.vault.url.groups"
:class="{ 'bg-blue-700 text-white': $page.component.startsWith('Vault/Group') }"
class="mr-2 rounded-md px-2 py-1 text-sm font-medium hover:bg-gray-700 hover:text-white dark:bg-sky-400/20 dark:text-slate-400 hover:dark:text-slate-300">
{{ $t('app.layout_menu_groups') }}
</inertia-link>

<inertia-link
:href="layoutData.vault.url.tasks"
:class="{
Expand Down
2 changes: 1 addition & 1 deletion routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,8 @@
});

// group page
Route::get('groups', [GroupController::class, 'index'])->name('group.index');
Route::prefix('groups')->middleware(['group'])->group(function () {
Route::get('', [GroupController::class, 'index'])->name('group.index');
Route::get('{group}', [GroupController::class, 'show'])->name('group.show');
});

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

namespace Tests\Unit\Domains\Contact\ManageGroups\Web\ViewHelpers;

use App\Contact\ManageGroups\Web\ViewHelpers\GroupIndexViewHelper;
use App\Models\Contact;
use App\Models\Group;
use App\Models\GroupType;
use App\Models\GroupTypeRole;
use App\Models\User;
use App\Models\Vault;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;

class GroupIndexViewHelperTest extends TestCase
{
use DatabaseTransactions;

/** @test */
public function it_gets_all_the_groups_associated_with_the_vault(): void
{
$user = User::factory()->create();
$vault = Vault::factory()->create([]);
$contact = Contact::factory()->create([
'vault_id' => $vault->id,
]);
$groupType = GroupType::factory()->create();
$parentRole = GroupTypeRole::factory()->create([
'group_type_id' => $groupType->id,
]);
$group = Group::factory()->create([
'vault_id' => $contact->vault_id,
'group_type_id' => $groupType->id,
]);
$group->contacts()->syncWithoutDetaching([
$contact->id => ['group_type_role_id' => $parentRole->id],
]);

$collection = GroupIndexViewHelper::data($vault, $user);

$this->assertCount(
1,
$collection
);

$this->assertEquals(
$group->id,
$collection->toArray()[0]['id']
);

$this->assertEquals(
$group->name,
$collection->toArray()[0]['name']
);

$this->assertEquals(
env('APP_URL').'/vaults/'.$vault->id.'/groups/'.$group->id,
$collection->toArray()[0]['url']['show']
);
}
}

0 comments on commit b8e5847

Please sign in to comment.