From 543ba8fc45e75102161d182138c71f25d2c2b45e Mon Sep 17 00:00:00 2001
From: Mazarin <djaiss@users.noreply.github.com>
Date: Sat, 6 May 2023 08:29:02 -0400
Subject: [PATCH] feat: edit and delete a group (monicahq/chandler#484)

---
 .../Web/Controllers/GroupController.php       |  71 ++++++++-
 .../Web/ViewHelpers/GroupEditViewHelper.php   |  37 +++++
 .../Web/ViewHelpers/GroupShowViewHelper.php   |  13 +-
 lang/de.json                                  |   5 +
 lang/de/vault.php                             |   5 -
 lang/es.json                                  |   5 +
 lang/es/vault.php                             |   5 -
 lang/fr.json                                  |   5 +
 lang/fr/vault.php                             |   5 -
 lang/it.json                                  |   5 +
 lang/it/vault.php                             |   5 -
 lang/pt.json                                  |   5 +
 lang/pt/vault.php                             |   5 -
 lang/ru.json                                  |   7 +-
 lang/ru/vault.php                             |   5 -
 resources/js/Pages/Vault/Group/Edit.vue       | 149 ++++++++++++++++++
 resources/js/Pages/Vault/Group/Show.vue       |  71 ++++++++-
 routes/web.php                                |   3 +
 .../ViewHelpers/GroupEditViewHelperTest.php   |  67 ++++++++
 .../ViewHelpers/GroupShowViewHelperTest.php   |  12 +-
 20 files changed, 445 insertions(+), 40 deletions(-)
 create mode 100644 app/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupEditViewHelper.php
 delete mode 100644 lang/de/vault.php
 delete mode 100644 lang/es/vault.php
 delete mode 100644 lang/fr/vault.php
 delete mode 100644 lang/it/vault.php
 delete mode 100644 lang/pt/vault.php
 delete mode 100644 lang/ru/vault.php
 create mode 100644 resources/js/Pages/Vault/Group/Edit.vue
 create mode 100644 tests/Unit/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupEditViewHelperTest.php

diff --git a/app/Domains/Contact/ManageGroups/Web/Controllers/GroupController.php b/app/Domains/Contact/ManageGroups/Web/Controllers/GroupController.php
index 7a694260d4b..59acbf95e01 100644
--- a/app/Domains/Contact/ManageGroups/Web/Controllers/GroupController.php
+++ b/app/Domains/Contact/ManageGroups/Web/Controllers/GroupController.php
@@ -2,19 +2,25 @@
 
 namespace App\Domains\Contact\ManageGroups\Web\Controllers;
 
+use App\Domains\Contact\ManageGroups\Services\DestroyGroup;
+use App\Domains\Contact\ManageGroups\Services\UpdateGroup;
+use App\Domains\Contact\ManageGroups\Web\ViewHelpers\GroupEditViewHelper;
 use App\Domains\Contact\ManageGroups\Web\ViewHelpers\GroupIndexViewHelper;
 use App\Domains\Contact\ManageGroups\Web\ViewHelpers\GroupShowViewHelper;
 use App\Domains\Vault\ManageVault\Web\ViewHelpers\VaultIndexViewHelper;
 use App\Http\Controllers\Controller;
 use App\Models\Group;
 use App\Models\Vault;
+use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Gate;
 use Inertia\Inertia;
+use Inertia\Response;
 
 class GroupController extends Controller
 {
-    public function index(Request $request, string $vaultId)
+    public function index(Request $request, string $vaultId): Response
     {
         $vault = Vault::findOrFail($vaultId);
 
@@ -24,7 +30,7 @@ public function index(Request $request, string $vaultId)
         ]);
     }
 
-    public function show(Request $request, string $vaultId, int $groupId)
+    public function show(Request $request, string $vaultId, int $groupId): Response
     {
         $vault = Vault::findOrFail($vaultId);
         $group = Group::with([
@@ -34,7 +40,66 @@ public function show(Request $request, string $vaultId, int $groupId)
 
         return Inertia::render('Vault/Group/Show', [
             'layoutData' => VaultIndexViewHelper::layoutData($vault),
-            'data' => GroupShowViewHelper::data($group, Auth::user()),
+            'data' => GroupShowViewHelper::data($group),
         ]);
     }
+
+    public function edit(Request $request, string $vaultId, int $groupId): Response
+    {
+        Gate::authorize('vault-editor', $vaultId);
+
+        $vault = Vault::findOrFail($vaultId);
+        $group = Group::with([
+            'contacts',
+            'groupType',
+        ])->findOrFail($groupId);
+
+        return Inertia::render('Vault/Group/Edit', [
+            'layoutData' => VaultIndexViewHelper::layoutData($vault),
+            'data' => GroupEditViewHelper::data($group),
+        ]);
+    }
+
+    public function update(Request $request, string $vaultId, string $groupId)
+    {
+        Gate::authorize('vault-editor', $vaultId);
+
+        $data = [
+            'account_id' => Auth::user()->account_id,
+            'vault_id' => $vaultId,
+            'author_id' => Auth::id(),
+            'group_id' => $groupId,
+            'group_type_id' => $request->input('group_type_id'),
+            'name' => $request->input('name'),
+        ];
+
+        $group = (new UpdateGroup())->execute($data);
+
+        return response()->json([
+            'data' => route('group.show', [
+                'vault' => $vaultId,
+                'group' => $group,
+            ]),
+        ], 200);
+    }
+
+    public function destroy(Request $request, string $vaultId, string $groupId): JsonResponse
+    {
+        Gate::authorize('vault-editor', $vaultId);
+
+        $data = [
+            'account_id' => Auth::user()->account_id,
+            'vault_id' => $vaultId,
+            'author_id' => Auth::id(),
+            'group_id' => $groupId,
+        ];
+
+        (new DestroyGroup())->execute($data);
+
+        return response()->json([
+            'data' => route('group.index', [
+                'vault' => $vaultId,
+            ]),
+        ], 200);
+    }
 }
diff --git a/app/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupEditViewHelper.php b/app/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupEditViewHelper.php
new file mode 100644
index 00000000000..f5749c8417f
--- /dev/null
+++ b/app/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupEditViewHelper.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace App\Domains\Contact\ManageGroups\Web\ViewHelpers;
+
+use App\Models\Group;
+use App\Models\GroupType;
+
+class GroupEditViewHelper
+{
+    public static function data(Group $group): array
+    {
+        $groupTypes = $group->vault->account->groupTypes()
+            ->orderBy('position')
+            ->get()
+            ->map(fn (GroupType $groupType) => [
+                'id' => $groupType->id,
+                'name' => $groupType->label,
+            ]);
+
+        return [
+            'id' => $group->id,
+            'name' => $group->name,
+            'group_type_id' => $group->group_type_id,
+            'group_types' => $groupTypes,
+            'url' => [
+                'back' => route('group.show', [
+                    'vault' => $group->vault_id,
+                    'group' => $group->id,
+                ]),
+                'update' => route('group.update', [
+                    'vault' => $group->vault_id,
+                    'group' => $group->id,
+                ]),
+            ],
+        ];
+    }
+}
diff --git a/app/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupShowViewHelper.php b/app/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupShowViewHelper.php
index d379cf6b40c..251c3f9df64 100644
--- a/app/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupShowViewHelper.php
+++ b/app/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupShowViewHelper.php
@@ -5,7 +5,6 @@
 use App\Models\Contact;
 use App\Models\Group;
 use App\Models\GroupTypeRole;
-use App\Models\User;
 
 class GroupShowViewHelper
 {
@@ -16,7 +15,7 @@ class GroupShowViewHelper
      * So we need to group contacts by roles if they exist, or list them
      * alphabetically otherwise.
      */
-    public static function data(Group $group, User $user): array
+    public static function data(Group $group): array
     {
         $rolesCollection = $group->groupType->groupTypeRoles()
             ->orderBy('position')
@@ -75,6 +74,16 @@ public static function data(Group $group, User $user): array
                 'label' => $group->groupType->label,
             ],
             'roles' => $rolesCollection,
+            'url' => [
+                'edit' => route('group.edit', [
+                    'vault' => $group->vault_id,
+                    'group' => $group->id,
+                ]),
+                'destroy' => route('group.destroy', [
+                    'vault' => $group->vault_id,
+                    'group' => $group->id,
+                ]),
+            ],
         ];
     }
 }
diff --git a/lang/de.json b/lang/de.json
index 830ffc3a9b9..bfd4ff0a204 100644
--- a/lang/de.json
+++ b/lang/de.json
@@ -347,6 +347,7 @@
     "deleted a note": "hat eine Notiz gelöscht",
     "deleted a pet": "hat ein Haustier gelöscht",
     "Deleted author": "Autor gelöscht",
+    "Delete group": "Gruppe löschen",
     "Delete journal": "Tagebuch löschen",
     "Delete Team": "Team löschen",
     "Delete the address": "Adresse löschen",
@@ -379,6 +380,7 @@
     "Edit a journal": "Ein Journal bearbeiten",
     "Edit a post": "Beitrag bearbeiten",
     "edited a note": "hat eine Notiz bearbeitet",
+    "Edit group": "Gruppe bearbeiten",
     "Edit journal": "Tagebuch bearbeiten",
     "Edit journal information": "Tagebuchinformationen bearbeiten",
     "Edit journal metrics": "Tagebuch-Metriken bearbeiten",
@@ -388,6 +390,7 @@
     "Edit post": "Beitrag bearbeiten",
     "Edit Profile": "Profil bearbeiten",
     "Edit slice of life": "Schnitzel des Lebens bearbeiten",
+    "Edit the group": "Die Gruppe bearbeiten",
     "Edit the slice of life": "Das Schnitzel des Lebens bearbeiten",
     "Email": "E-Mail",
     "Email address": "E-Mail-Adresse",
@@ -921,6 +924,8 @@
     "The goal has been deleted": "Das Ziel wurde gelöscht",
     "The goal has been edited": "Das Ziel wurde bearbeitet",
     "The group has been added": "Die Gruppe wurde hinzugefügt",
+    "The group has been deleted": "Die Gruppe wurde gelöscht",
+    "The group has been updated": "Die Gruppe wurde aktualisiert",
     "The group type has been created": "Der Gruppentyp wurde erstellt",
     "The group type has been deleted": "Der Gruppentyp wurde gelöscht",
     "The group type has been updated": "Der Gruppentyp wurde aktualisiert",
diff --git a/lang/de/vault.php b/lang/de/vault.php
deleted file mode 100644
index 3a8fc529724..00000000000
--- a/lang/de/vault.php
+++ /dev/null
@@ -1,5 +0,0 @@
-<?php
-
-return [
-    'journal_number_posts' => '',
-];
diff --git a/lang/es.json b/lang/es.json
index 508ca1cad45..ca73de095dd 100644
--- a/lang/es.json
+++ b/lang/es.json
@@ -347,6 +347,7 @@
     "deleted a note": "eliminó una nota",
     "deleted a pet": "eliminó una mascota",
     "Deleted author": "Autor eliminado",
+    "Delete group": "Eliminar grupo",
     "Delete journal": "Eliminar diario",
     "Delete Team": "Borrar equipo",
     "Delete the address": "Eliminar la dirección",
@@ -379,6 +380,7 @@
     "Edit a journal": "Editar un diario",
     "Edit a post": "Editar una publicación.",
     "edited a note": "editó una nota",
+    "Edit group": "Editar grupo",
     "Edit journal": "Editar diario",
     "Edit journal information": "Editar información del diario",
     "Edit journal metrics": "Editar métricas del diario",
@@ -388,6 +390,7 @@
     "Edit post": "Editar publicación.",
     "Edit Profile": "Editar perfil",
     "Edit slice of life": "Editar fragmento de vida.",
+    "Edit the group": "Editar el grupo",
     "Edit the slice of life": "Editar el fragmento de vida.",
     "Email": "Correo electrónico",
     "Email address": "Dirección de correo electrónico",
@@ -921,6 +924,8 @@
     "The goal has been deleted": "La meta ha sido eliminada",
     "The goal has been edited": "La meta ha sido editada",
     "The group has been added": "El grupo ha sido añadido",
+    "The group has been deleted": "El grupo ha sido eliminado",
+    "The group has been updated": "El grupo ha sido actualizado",
     "The group type has been created": "El tipo de grupo ha sido creado",
     "The group type has been deleted": "El tipo de grupo ha sido eliminado",
     "The group type has been updated": "El tipo de grupo ha sido actualizado",
diff --git a/lang/es/vault.php b/lang/es/vault.php
deleted file mode 100644
index 3a8fc529724..00000000000
--- a/lang/es/vault.php
+++ /dev/null
@@ -1,5 +0,0 @@
-<?php
-
-return [
-    'journal_number_posts' => '',
-];
diff --git a/lang/fr.json b/lang/fr.json
index b38057c5b41..34170d6f7e7 100644
--- a/lang/fr.json
+++ b/lang/fr.json
@@ -347,6 +347,7 @@
     "deleted a note": "a supprimé une note",
     "deleted a pet": "a supprimé un animal de compagnie",
     "Deleted author": "Auteur supprimé",
+    "Delete group": "Supprimer le groupe",
     "Delete journal": "Supprimer le journal",
     "Delete Team": "Supprimer l’équipe",
     "Delete the address": "Supprimer l’adresse",
@@ -379,6 +380,7 @@
     "Edit a journal": "Modifier un journal",
     "Edit a post": "Modifier une publication",
     "edited a note": "a modifié une note",
+    "Edit group": "Modifier le groupe",
     "Edit journal": "Modifier le journal",
     "Edit journal information": "Modifier les informations du journal",
     "Edit journal metrics": "Modifier les métriques du journal",
@@ -388,6 +390,7 @@
     "Edit post": "Modifier la publication",
     "Edit Profile": "Éditer le profil",
     "Edit slice of life": "Modifier la tranche de vie",
+    "Edit the group": "Modifier le groupe",
     "Edit the slice of life": "Modifier la tranche de vie",
     "Email": "E-mail",
     "Email address": "Adresse email",
@@ -921,6 +924,8 @@
     "The goal has been deleted": "L’objectif a été supprimé",
     "The goal has been edited": "L’objectif a été modifié",
     "The group has been added": "Le groupe a été ajouté",
+    "The group has been deleted": "Le groupe a été supprimé",
+    "The group has been updated": "Le groupe a été mis à jour",
     "The group type has been created": "Le type de groupe a été créé",
     "The group type has been deleted": "Le type de groupe a été supprimé",
     "The group type has been updated": "Le type de groupe a été mis à jour",
diff --git a/lang/fr/vault.php b/lang/fr/vault.php
deleted file mode 100644
index 3a8fc529724..00000000000
--- a/lang/fr/vault.php
+++ /dev/null
@@ -1,5 +0,0 @@
-<?php
-
-return [
-    'journal_number_posts' => '',
-];
diff --git a/lang/it.json b/lang/it.json
index 69c7367da96..f6874565c3b 100644
--- a/lang/it.json
+++ b/lang/it.json
@@ -347,6 +347,7 @@
     "deleted a note": "ha eliminato una nota",
     "deleted a pet": "ha eliminato un animale domestico",
     "Deleted author": "Autore eliminato",
+    "Delete group": "Elimina gruppo",
     "Delete journal": "Elimina diario",
     "Delete Team": "Elimina Team",
     "Delete the address": "Elimina l'indirizzo",
@@ -379,6 +380,7 @@
     "Edit a journal": "Modifica un diario",
     "Edit a post": "Modifica un post",
     "edited a note": "ha modificato una nota",
+    "Edit group": "Modifica gruppo",
     "Edit journal": "Modifica diario",
     "Edit journal information": "Modifica informazioni diario",
     "Edit journal metrics": "Modifica metriche diario",
@@ -388,6 +390,7 @@
     "Edit post": "Modifica post",
     "Edit Profile": "Modifica Profilo",
     "Edit slice of life": "Modifica pezzo di vita",
+    "Edit the group": "Modifica il gruppo",
     "Edit the slice of life": "Modifica il pezzo di vita",
     "Email": "Email",
     "Email address": "Indirizzo email",
@@ -921,6 +924,8 @@
     "The goal has been deleted": "L'obiettivo è stato eliminato",
     "The goal has been edited": "L'obiettivo è stato modificato",
     "The group has been added": "Il gruppo è stato aggiunto",
+    "The group has been deleted": "Il gruppo è stato eliminato",
+    "The group has been updated": "Il gruppo è stato aggiornato",
     "The group type has been created": "Il tipo di gruppo è stato creato.",
     "The group type has been deleted": "Il tipo di gruppo è stato eliminato.",
     "The group type has been updated": "Il tipo di gruppo è stato aggiornato.",
diff --git a/lang/it/vault.php b/lang/it/vault.php
deleted file mode 100644
index 3a8fc529724..00000000000
--- a/lang/it/vault.php
+++ /dev/null
@@ -1,5 +0,0 @@
-<?php
-
-return [
-    'journal_number_posts' => '',
-];
diff --git a/lang/pt.json b/lang/pt.json
index ca1f455afaa..d43188ab776 100644
--- a/lang/pt.json
+++ b/lang/pt.json
@@ -347,6 +347,7 @@
     "deleted a note": "excluiu uma nota",
     "deleted a pet": "excluiu um animal de estimação",
     "Deleted author": "Autor excluído",
+    "Delete group": "Excluir grupo",
     "Delete journal": "Excluir diário",
     "Delete Team": "Eliminar Equipa",
     "Delete the address": "Excluir o endereço",
@@ -379,6 +380,7 @@
     "Edit a journal": "Editar um diário",
     "Edit a post": "Editar um post",
     "edited a note": "editou uma nota",
+    "Edit group": "Editar grupo",
     "Edit journal": "Editar diário",
     "Edit journal information": "Editar informações do diário",
     "Edit journal metrics": "Editar métricas do diário",
@@ -388,6 +390,7 @@
     "Edit post": "Editar post",
     "Edit Profile": "Editar Perfil",
     "Edit slice of life": "Editar pedacinho da vida",
+    "Edit the group": "Editar o grupo",
     "Edit the slice of life": "Editar o pedacinho da vida",
     "Email": "E-mail",
     "Email address": "Endereço de email",
@@ -921,6 +924,8 @@
     "The goal has been deleted": "A meta foi excluída",
     "The goal has been edited": "A meta foi editada",
     "The group has been added": "O grupo foi adicionado",
+    "The group has been deleted": "O grupo foi excluído",
+    "The group has been updated": "O grupo foi atualizado",
     "The group type has been created": "O tipo de grupo foi criado",
     "The group type has been deleted": "O tipo de grupo foi excluído",
     "The group type has been updated": "O tipo de grupo foi atualizado",
diff --git a/lang/pt/vault.php b/lang/pt/vault.php
deleted file mode 100644
index 3a8fc529724..00000000000
--- a/lang/pt/vault.php
+++ /dev/null
@@ -1,5 +0,0 @@
-<?php
-
-return [
-    'journal_number_posts' => '',
-];
diff --git a/lang/ru.json b/lang/ru.json
index c8e66462d82..2b2b89e370e 100644
--- a/lang/ru.json
+++ b/lang/ru.json
@@ -24,7 +24,7 @@
     "+ pronoun": "+ местоимение",
     "+ suffix": "+ суффикс",
     ":count contact|:count contacts": ":count контакт|:count контакта|:count контактов",
-    ":count hours slept": "",
+    ":count hours slept": ":count часов сна",
     ":count min read": ":count мин чтения|:count мин чтения|:count мин чтения",
     ":count post|:count posts": ":count пост|:count поста|:count постов",
     ":count template section|:count template sections": ":count раздел шаблона|:count раздела шаблона|:count разделов шаблона",
@@ -347,6 +347,7 @@
     "deleted a note": "Удалена заметка",
     "deleted a pet": "Удален питомец",
     "Deleted author": "Удален автор",
+    "Delete group": "Удалить группу",
     "Delete journal": "Удалить журнал",
     "Delete Team": "Удалить команду",
     "Delete the address": "Удалить адрес",
@@ -379,6 +380,7 @@
     "Edit a journal": "Редактировать журнал",
     "Edit a post": "Редактировать пост",
     "edited a note": "отредактирована заметка",
+    "Edit group": "Редактировать группу",
     "Edit journal": "Редактировать журнал",
     "Edit journal information": "Редактировать информацию журнала",
     "Edit journal metrics": "Редактировать метрики журнала",
@@ -388,6 +390,7 @@
     "Edit post": "Редактировать пост",
     "Edit Profile": "Редактировать профиль",
     "Edit slice of life": "Редактировать ломтик жизни",
+    "Edit the group": "Редактировать группу",
     "Edit the slice of life": "Редактировать ломтик жизни",
     "Email": "E-Mail адрес",
     "Email address": "Адрес электронной почты",
@@ -921,6 +924,8 @@
     "The goal has been deleted": "Цель была удалена",
     "The goal has been edited": "Цель была изменена",
     "The group has been added": "Группа была добавлена",
+    "The group has been deleted": "Группа была удалена",
+    "The group has been updated": "Группа была обновлена",
     "The group type has been created": "Тип группы был создан",
     "The group type has been deleted": "Тип группы был удален",
     "The group type has been updated": "Тип группы был обновлен",
diff --git a/lang/ru/vault.php b/lang/ru/vault.php
deleted file mode 100644
index 3a8fc529724..00000000000
--- a/lang/ru/vault.php
+++ /dev/null
@@ -1,5 +0,0 @@
-<?php
-
-return [
-    'journal_number_posts' => '',
-];
diff --git a/resources/js/Pages/Vault/Group/Edit.vue b/resources/js/Pages/Vault/Group/Edit.vue
new file mode 100644
index 00000000000..a5ebbb9bd83
--- /dev/null
+++ b/resources/js/Pages/Vault/Group/Edit.vue
@@ -0,0 +1,149 @@
+<script setup>
+import Layout from '@/Shared/Layout.vue';
+import { Inertia } from '@inertiajs/inertia';
+import { useForm } from '@inertiajs/inertia-vue3';
+import PrettyLink from '@/Shared/Form/PrettyLink.vue';
+import PrettyButton from '@/Shared/Form/PrettyButton.vue';
+import TextInput from '@/Shared/Form/TextInput.vue';
+import Dropdown from '@/Shared/Form/Dropdown.vue';
+import Errors from '@/Shared/Form/Errors.vue';
+import { onMounted, nextTick, ref } from 'vue';
+import { trans } from 'laravel-vue-i18n';
+
+const props = defineProps({
+  layoutData: Object,
+  data: Object,
+});
+
+const form = useForm({
+  name: '',
+  group_type_id: 0,
+  errors: [],
+});
+
+const loadingState = ref(null);
+const nameField = ref(null);
+
+onMounted(() => {
+  form.name = props.data.name;
+  form.group_type_id = props.data.group_type_id;
+
+  nextTick(() => {
+    nameField.value.focus();
+  });
+});
+
+const update = () => {
+  loadingState.value = 'loading';
+
+  axios
+    .put(props.data.url.update, form)
+    .then((response) => {
+      loadingState.value = null;
+      localStorage.success = trans('The group has been updated');
+      Inertia.visit(response.data.data);
+    })
+    .catch((error) => {
+      form.errors = error.response.data;
+      loadingState.value = null;
+    });
+};
+</script>
+
+<template>
+  <layout :layout-data="layoutData" :inside-vault="true">
+    <!-- breadcrumb -->
+    <nav class="bg-white dark:bg-gray-900 sm:mt-20 sm:border-b">
+      <div class="max-w-8xl mx-auto hidden px-4 py-2 sm:px-6 md:block">
+        <div class="flex items-baseline justify-between space-x-6">
+          <ul class="text-sm">
+            <li class="mr-2 inline text-gray-600 dark:text-gray-400">
+              {{ $t('You are here:') }}
+            </li>
+            <li class="mr-2 inline">
+              <inertia-link :href="data.url.back" class="text-blue-500 hover:underline">
+                {{ $t('Groups') }}
+              </inertia-link>
+            </li>
+            <li class="relative mr-2 inline">
+              <svg
+                xmlns="http://www.w3.org/2000/svg"
+                class="icon-breadcrumb relative inline h-3 w-3"
+                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="mr-2 inline">
+              <inertia-link :href="data.url.back" class="text-blue-500 hover:underline">{{ data.name }}</inertia-link>
+            </li>
+            <li class="relative mr-2 inline">
+              <svg
+                xmlns="http://www.w3.org/2000/svg"
+                class="icon-breadcrumb relative inline h-3 w-3"
+                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">{{ $t('Edit group') }}</li>
+          </ul>
+        </div>
+      </div>
+    </nav>
+
+    <main class="relative sm:mt-16">
+      <div class="mx-auto max-w-lg px-2 py-2 sm:px-6 sm:py-6 lg:px-8">
+        <form
+          class="mb-6 rounded-lg border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900"
+          @submit.prevent="update()">
+          <div class="section-head border-b border-gray-200 bg-blue-50 p-5 dark:border-gray-700 dark:bg-blue-900">
+            <h1 class="text-center text-2xl font-medium">
+              {{ $t('Edit the group') }}
+            </h1>
+          </div>
+          <errors :errors="form.errors" />
+
+          <!-- name -->
+          <div class="border-b border-gray-200 p-5 dark:border-gray-700">
+            <text-input
+              v-model="form.name"
+              :ref="'nameField'"
+              :autofocus="true"
+              :div-outer-class="'mb-5'"
+              :input-class="'block w-full'"
+              :required="true"
+              :maxlength="255"
+              :label="$t('Name')" />
+          </div>
+
+          <!-- group type -->
+          <div class="border-b border-gray-200 p-5 dark:border-gray-700">
+            <dropdown
+              v-model="form.group_type_id"
+              :data="props.data.group_types"
+              :required="true"
+              :placeholder="$t('Choose a value')"
+              :dropdown-class="'block w-full'"
+              :label="$t('Group type')" />
+          </div>
+
+          <!-- actions -->
+          <div class="flex justify-between p-5">
+            <pretty-link :href="props.data.url.back" :text="$t('Cancel')" :classes="'mr-3'" />
+            <pretty-button :text="$t('Save')" :state="loadingState" :icon="'check'" :classes="'save'" />
+          </div>
+        </form>
+      </div>
+    </main>
+  </layout>
+</template>
+
+<style lang="scss" scoped>
+.section-head {
+  border-top-left-radius: 7px;
+  border-top-right-radius: 7px;
+}
+</style>
diff --git a/resources/js/Pages/Vault/Group/Show.vue b/resources/js/Pages/Vault/Group/Show.vue
index 1e2a802ba59..f2a6bff3e75 100644
--- a/resources/js/Pages/Vault/Group/Show.vue
+++ b/resources/js/Pages/Vault/Group/Show.vue
@@ -1,11 +1,39 @@
 <script setup>
+import { ref, reactive } from 'vue';
 import Layout from '@/Shared/Layout.vue';
 import Avatar from '@/Shared/Avatar.vue';
+import { Inertia } from '@inertiajs/inertia';
+import { trans } from 'laravel-vue-i18n';
+import JetConfirmationModal from '@/Components/Jetstream/ConfirmationModal.vue';
+import JetDangerButton from '@/Components/Jetstream/DangerButton.vue';
+import JetSecondaryButton from '@/Components/Jetstream/SecondaryButton.vue';
 
-defineProps({
+const props = defineProps({
   layoutData: Object,
   data: Object,
 });
+
+const deletingGroup = ref(false);
+const deleteGroupForm = reactive({
+  processing: false,
+});
+
+const destroy = () => {
+  deleteGroupForm.processing = true;
+
+  axios
+    .delete(props.data.url.destroy)
+    .then((response) => {
+      deleteGroupForm.processing = false;
+
+      localStorage.success = trans('The group has been deleted');
+      Inertia.visit(response.data.data);
+    })
+    .catch((error) => {
+      deleteGroupForm.processing = false;
+      form.errors = error.response.data;
+    });
+};
 </script>
 
 <template>
@@ -69,7 +97,7 @@ defineProps({
           </div>
 
           <!-- type -->
-          <div class="flex items-center">
+          <div class="mr-8 flex items-center">
             <svg
               xmlns="http://www.w3.org/2000/svg"
               fill="none"
@@ -85,6 +113,20 @@ defineProps({
 
             <p class="text-center text-gray-600">{{ $t('Group type: :name', { name: data.type.label }) }}</p>
           </div>
+
+          <!-- actions -->
+          <div class="flex items-center">
+            <ul class="list">
+              <li class="mr-4 inline">
+                <inertia-link :href="props.data.url.edit" class="text-blue-500 hover:underline">{{
+                  $t('Edit')
+                }}</inertia-link>
+              </li>
+              <li class="inline" @click="deletingGroup = true">
+                <span class="inline cursor-pointer text-red-500 hover:text-red-900">{{ $t('Delete') }}</span>
+              </li>
+            </ul>
+          </div>
         </div>
 
         <!-- contacts by roles -->
@@ -108,6 +150,31 @@ defineProps({
             </div>
           </div>
         </div>
+
+        <!-- Delete Contact Confirmation Modal -->
+        <JetConfirmationModal :show="deletingGroup" @close="deletingGroup = false">
+          <template #title>
+            {{ $t('Delete group') }}
+          </template>
+
+          <template #content>
+            {{ $t('Are you sure? This action cannot be undone.') }}
+          </template>
+
+          <template #footer>
+            <JetSecondaryButton @click="deletingGroup = false">
+              {{ $t('Cancel') }}
+            </JetSecondaryButton>
+
+            <JetDangerButton
+              class="ml-3"
+              :class="{ 'opacity-25': deleteGroupForm.processing }"
+              :disabled="deleteGroupForm.processing"
+              @click="destroy">
+              {{ $t('Delete') }}
+            </JetDangerButton>
+          </template>
+        </JetConfirmationModal>
       </div>
     </main>
   </layout>
diff --git a/routes/web.php b/routes/web.php
index 5ea072ef082..664f75cbbbc 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -385,6 +385,9 @@
             Route::get('groups', [GroupController::class, 'index'])->name('group.index');
             Route::middleware('can:group-owner,vault,group')->prefix('groups')->group(function () {
                 Route::get('{group}', [GroupController::class, 'show'])->name('group.show');
+                Route::get('{group}/edit', [GroupController::class, 'edit'])->name('group.edit');
+                Route::put('{group}', [GroupController::class, 'update'])->name('group.update');
+                Route::delete('{group}', [GroupController::class, 'destroy'])->name('group.destroy');
             });
 
             // journal page
diff --git a/tests/Unit/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupEditViewHelperTest.php b/tests/Unit/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupEditViewHelperTest.php
new file mode 100644
index 00000000000..86c38986894
--- /dev/null
+++ b/tests/Unit/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupEditViewHelperTest.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Tests\Unit\Domains\Contact\ManageGroups\Web\ViewHelpers;
+
+use App\Domains\Contact\ManageGroups\Web\ViewHelpers\GroupEditViewHelper;
+use App\Models\Contact;
+use App\Models\Group;
+use App\Models\GroupType;
+use Illuminate\Foundation\Testing\DatabaseTransactions;
+use Tests\TestCase;
+
+class GroupEditViewHelperTest extends TestCase
+{
+    use DatabaseTransactions;
+
+    /** @test */
+    public function it_gets_the_data_needed_for_the_view(): void
+    {
+        $contact = Contact::factory()->create();
+        $groupType = GroupType::factory()->create([
+            'account_id' => $contact->vault->account_id,
+        ]);
+        $group = Group::factory()->create([
+            'vault_id' => $contact->vault_id,
+            'group_type_id' => $groupType->id,
+        ]);
+        $array = GroupEditViewHelper::data($group);
+
+        $this->assertCount(
+            5,
+            $array
+        );
+
+        $this->assertEquals(
+            $group->id,
+            $array['id']
+        );
+
+        $this->assertEquals(
+            $group->name,
+            $array['name']
+        );
+
+        $this->assertEquals(
+            $groupType->id,
+            $array['group_type_id']
+        );
+
+        $this->assertEquals(
+            [
+                0 => [
+                    'id' => $groupType->id,
+                    'name' => $groupType->label,
+                ],
+            ],
+            $array['group_types']->toArray()
+        );
+
+        $this->assertEquals(
+            [
+                'back' => env('APP_URL').'/vaults/'.$contact->vault->id.'/groups/'.$group->id,
+                'update' => env('APP_URL').'/vaults/'.$contact->vault->id.'/groups/'.$group->id,
+            ],
+            $array['url']
+        );
+    }
+}
diff --git a/tests/Unit/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupShowViewHelperTest.php b/tests/Unit/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupShowViewHelperTest.php
index 835fad910a0..2ffd0815494 100644
--- a/tests/Unit/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupShowViewHelperTest.php
+++ b/tests/Unit/Domains/Contact/ManageGroups/Web/ViewHelpers/GroupShowViewHelperTest.php
@@ -39,10 +39,10 @@ public function it_gets_all_the_groups_associated_with_the_contact(): void
             $otherContact->id => ['group_type_role_id' => $sisterRole->id],
         ]);
 
-        $array = GroupShowViewHelper::data($group, $user);
+        $array = GroupShowViewHelper::data($group);
 
         $this->assertCount(
-            5,
+            6,
             $array
         );
 
@@ -60,5 +60,13 @@ public function it_gets_all_the_groups_associated_with_the_contact(): void
             2,
             $array['contact_count']
         );
+
+        $this->assertEquals(
+            [
+                'edit' => env('APP_URL').'/vaults/'.$contact->vault->id.'/groups/'.$group->id.'/edit',
+                'destroy' => env('APP_URL').'/vaults/'.$contact->vault->id.'/groups/'.$group->id,
+            ],
+            $array['url']
+        );
     }
 }