diff --git a/app/Http/Middleware/ShareInertiaData.php b/app/Http/Middleware/ShareInertiaData.php
index 92a1dcca..cbe154f3 100644
--- a/app/Http/Middleware/ShareInertiaData.php
+++ b/app/Http/Middleware/ShareInertiaData.php
@@ -27,7 +27,6 @@ class ShareInertiaData
/** @var PermissionStore $permissions */
$permissions = app(PermissionStore::class);
Inertia::share(array_filter([
- 'permissions' => $request->user() !== null && $request->user()->currentTeam !== null ? $permissions->getPermissions($request->user()->currentTeam) : [],
'jetstream' => function () use ($request) {
/** @var User|null $user */
$user = $request->user();
@@ -49,6 +48,7 @@ class ShareInertiaData
];
},
'auth' => [
+ 'permissions' => $request->user() !== null && $request->user()->currentTeam !== null ? $permissions->getPermissions($request->user()->currentTeam) : [],
'user' => function () use ($request): array {
/** @var User|null $user */
$user = $request->user();
diff --git a/resources/js/Components/Common/Client/ClientMoreOptionsDropdown.vue b/resources/js/Components/Common/Client/ClientMoreOptionsDropdown.vue
index 2ab8e438..a57b9f9b 100644
--- a/resources/js/Components/Common/Client/ClientMoreOptionsDropdown.vue
+++ b/resources/js/Components/Common/Client/ClientMoreOptionsDropdown.vue
@@ -2,6 +2,7 @@
import Dropdown from '@/Components/Dropdown.vue';
import { TrashIcon } from '@heroicons/vue/20/solid';
import type { Client } from '@/utils/api';
+import { canDeleteClients } from '@/utils/permissions';
const emit = defineEmits<{
delete: [];
@@ -31,6 +32,7 @@ const props = defineProps<{
No clients found
- Create your first client now!
+
+ Create your first client now!
+
Create your First Client
diff --git a/resources/js/Components/Common/Member/MemberMoreOptionsDropdown.vue b/resources/js/Components/Common/Member/MemberMoreOptionsDropdown.vue
index 8e3d091b..e86a15a4 100644
--- a/resources/js/Components/Common/Member/MemberMoreOptionsDropdown.vue
+++ b/resources/js/Components/Common/Member/MemberMoreOptionsDropdown.vue
@@ -2,6 +2,7 @@
import Dropdown from '@/Components/Dropdown.vue';
import { TrashIcon } from '@heroicons/vue/20/solid';
import type { Member } from '@/utils/api';
+import { canDeleteMembers } from '@/utils/permissions';
const emit = defineEmits<{
delete: [];
@@ -31,6 +32,7 @@ const props = defineProps<{
Invite
Delete
diff --git a/resources/js/Components/Common/Project/ProjectTable.vue b/resources/js/Components/Common/Project/ProjectTable.vue
index 7222e9a4..0c4445aa 100644
--- a/resources/js/Components/Common/Project/ProjectTable.vue
+++ b/resources/js/Components/Common/Project/ProjectTable.vue
@@ -8,6 +8,7 @@ import ProjectCreateModal from '@/Components/Common/Project/ProjectCreateModal.v
import { storeToRefs } from 'pinia';
import ProjectTableHeading from '@/Components/Common/Project/ProjectTableHeading.vue';
import ProjectTableRow from '@/Components/Common/Project/ProjectTableRow.vue';
+import { canCreateProjects } from '@/utils/permissions';
const { projects } = storeToRefs(useProjectsStore());
@@ -29,8 +30,11 @@ const createProject = ref(false);
No projects found
- Create your first project now!
+
+ Create your first project now!
+
Create your First Project
diff --git a/resources/js/Components/Common/Tag/TagTable.vue b/resources/js/Components/Common/Tag/TagTable.vue
index b32177ac..e8e12c5b 100644
--- a/resources/js/Components/Common/Tag/TagTable.vue
+++ b/resources/js/Components/Common/Tag/TagTable.vue
@@ -8,6 +8,7 @@ import { useTagsStore } from '@/utils/useTags';
import TagTableRow from '@/Components/Common/Tag/TagTableRow.vue';
import TagCreateModal from '@/Components/Common/Tag/TagCreateModal.vue';
import TagTableHeading from '@/Components/Common/Tag/TagTableHeading.vue';
+import { canCreateTags } from '@/utils/permissions';
const { tags } = storeToRefs(useTagsStore());
const createTag = ref(false);
@@ -28,8 +29,13 @@ const createTag = ref(false);
No tags found
- Create your first tag now!
-
+ Create your first tag now!
+
+ Create your First Tag
diff --git a/resources/js/Components/Common/Tag/TagTableRow.vue b/resources/js/Components/Common/Tag/TagTableRow.vue
index 5c22f46e..e1f067f2 100644
--- a/resources/js/Components/Common/Tag/TagTableRow.vue
+++ b/resources/js/Components/Common/Tag/TagTableRow.vue
@@ -3,6 +3,7 @@ import type { Tag } from '@/utils/api';
import { useTagsStore } from '@/utils/useTags';
import TagMoreOptionsDropdown from '@/Components/Common/Tag/TagMoreOptionsDropdown.vue';
import TableRow from '@/Components/TableRow.vue';
+import { canDeleteTags } from '@/utils/permissions';
const props = defineProps<{
tag: Tag;
@@ -24,6 +25,7 @@ function deleteTag() {
diff --git a/resources/js/Components/Common/Task/TaskTable.vue b/resources/js/Components/Common/Task/TaskTable.vue
index 384e6a52..f1364c72 100644
--- a/resources/js/Components/Common/Task/TaskTable.vue
+++ b/resources/js/Components/Common/Task/TaskTable.vue
@@ -8,6 +8,7 @@ import { useTasksStore } from '@/utils/useTasks';
import TaskTableRow from '@/Components/Common/Task/TaskTableRow.vue';
import TaskTableHeading from '@/Components/Common/Task/TaskTableHeading.vue';
import TaskCreateModal from '@/Components/Common/Task/TaskCreateModal.vue';
+import { canCreateTasks } from '@/utils/permissions';
const { tasks } = storeToRefs(useTasksStore());
@@ -39,8 +40,13 @@ const createTask = ref(false);
No tasks found
- Create your first task now!
-
+ Create your first task now!
+
+ Create your First Task
diff --git a/resources/js/Components/OrganizationSwitcher.vue b/resources/js/Components/OrganizationSwitcher.vue
index dc1630cd..6f23e88a 100644
--- a/resources/js/Components/OrganizationSwitcher.vue
+++ b/resources/js/Components/OrganizationSwitcher.vue
@@ -6,6 +6,7 @@ import { router, usePage } from '@inertiajs/vue3';
import type { Organization, User } from '@/types/models';
import { isBillingActivated } from '@/utils/billing';
import { initializeStores } from '@/utils/init';
+import { canUpdateOrganization } from '@/utils/permissions';
const page = usePage<{
jetstream: {
@@ -88,7 +89,9 @@ const switchToTeam = (team: Organization) => {
Organization Settings
-
+
Billing
diff --git a/resources/js/Layouts/AppLayout.vue b/resources/js/Layouts/AppLayout.vue
index 039ad327..5afee363 100644
--- a/resources/js/Layouts/AppLayout.vue
+++ b/resources/js/Layouts/AppLayout.vue
@@ -21,6 +21,12 @@ import MainContainer from '@/Pages/MainContainer.vue';
import { onMounted, ref } from 'vue';
import NotificationContainer from '@/Components/NotificationContainer.vue';
import { initializeStores } from '@/utils/init';
+import {
+ canViewClients,
+ canViewMembers,
+ canViewProjects,
+ canViewTags,
+} from '@/utils/permissions';
defineProps({
title: String,
@@ -84,6 +90,7 @@ onMounted(async () => {
{
route().current('projects')
">
{
useClientsStore().fetchClients();
@@ -31,7 +32,10 @@ const createClient = ref(false);
Archived
- Create Client
diff --git a/resources/js/Pages/Members.vue b/resources/js/Pages/Members.vue
index 1e513d07..9898de80 100644
--- a/resources/js/Pages/Members.vue
+++ b/resources/js/Pages/Members.vue
@@ -12,6 +12,7 @@ import MemberInviteModal from '@/Components/Common/Member/MemberInviteModal.vue'
import type { Role } from '@/types/jetstream';
import PageTitle from '@/Components/Common/PageTitle.vue';
import InvitationTable from '@/Components/Common/Invitation/InvitationTable.vue';
+import { canCreateInvitations } from '@/utils/permissions';
const inviteMember = ref(false);
@@ -44,7 +45,10 @@ function isActiveTab(tab: string) {
>
- Invite member
{
Create Task
@@ -96,7 +98,7 @@ onMounted(() => {
-
+
{
useProjectsStore().fetchProjects();
@@ -30,7 +31,10 @@ const createProject = ref(false);
Archived
-
Create Project
@@ -18,7 +19,10 @@ const createTag = ref(false);
- Create Tag
diff --git a/resources/js/Pages/Teams/Partials/UpdateTeamNameForm.vue b/resources/js/Pages/Teams/Partials/UpdateTeamNameForm.vue
index c286e341..08ff878c 100644
--- a/resources/js/Pages/Teams/Partials/UpdateTeamNameForm.vue
+++ b/resources/js/Pages/Teams/Partials/UpdateTeamNameForm.vue
@@ -10,6 +10,7 @@ import type { Organization } from '@/types/models';
import type { Permissions } from '@/types/jetstream';
import { CreditCardIcon } from '@heroicons/vue/20/solid';
import { isBillingActivated } from '@/utils/billing';
+import { canUpdateOrganization } from '@/utils/permissions';
const props = defineProps<{
team: Organization;
@@ -63,7 +64,9 @@ const updateTeamName = () => {
+ v-if="
+ isBillingActivated() && canUpdateOrganization()
+ ">
Go to Billing
diff --git a/resources/js/Pages/Teams/Show.vue b/resources/js/Pages/Teams/Show.vue
index e6acbe37..b4e16a94 100644
--- a/resources/js/Pages/Teams/Show.vue
+++ b/resources/js/Pages/Teams/Show.vue
@@ -7,6 +7,7 @@ import UpdateTeamNameForm from '@/Pages/Teams/Partials/UpdateTeamNameForm.vue';
import type { Organization } from '@/types/models';
import type { Permissions, Role } from '@/types/jetstream';
import ImportData from '@/Pages/Teams/Partials/ImportData.vue';
+import { canUpdateOrganization } from '@/utils/permissions';
defineProps<{
team: Organization;
@@ -42,7 +43,9 @@ defineProps<{
-
+
diff --git a/resources/js/utils/init.ts b/resources/js/utils/init.ts
index d97838e1..212e0c4e 100644
--- a/resources/js/utils/init.ts
+++ b/resources/js/utils/init.ts
@@ -5,13 +5,18 @@ import { useCurrentTimeEntryStore } from '@/utils/useCurrentTimeEntry';
import { useClientsStore } from '@/utils/useClients';
import { useMembersStore } from '@/utils/useMembers';
import { useTimeEntriesStore } from '@/utils/useTimeEntries';
+import { canViewClients, canViewMembers } from '@/utils/permissions';
export function initializeStores() {
useProjectsStore().fetchProjects();
useTasksStore().fetchTasks();
useTagsStore().fetchTags();
useCurrentTimeEntryStore().fetchCurrentTimeEntry();
- useClientsStore().fetchClients();
- useMembersStore().fetchMembers();
+ if (canViewMembers()) {
+ useMembersStore().fetchMembers();
+ }
+ if (canViewClients()) {
+ useClientsStore().fetchClients();
+ }
useTimeEntriesStore().fetchTimeEntries();
}
diff --git a/resources/js/utils/permissions.ts b/resources/js/utils/permissions.ts
new file mode 100644
index 00000000..7f05f86e
--- /dev/null
+++ b/resources/js/utils/permissions.ts
@@ -0,0 +1,83 @@
+import { usePage } from '@inertiajs/vue3';
+
+const page = usePage<{
+ auth: {
+ permissions: string[];
+ };
+}>();
+
+function currentUserHasPermission(permission: string) {
+ console.log(page.props.auth.permissions);
+ if (Array.isArray(page.props.auth.permissions)) {
+ return page.props.auth.permissions.includes(permission);
+ }
+ return false;
+}
+
+export function canUpdateOrganization() {
+ return currentUserHasPermission('organizations:update');
+}
+
+export function canViewProjects() {
+ return currentUserHasPermission('projects:view');
+}
+
+export function canCreateProjects() {
+ return currentUserHasPermission('projects:create');
+}
+
+export function canUpdateProjects() {
+ return currentUserHasPermission('projects:update');
+}
+
+export function canDeleteProjects() {
+ return currentUserHasPermission('projects:delete');
+}
+
+export function canViewProjectMembers() {
+ return currentUserHasPermission('project-members:view');
+}
+
+export function canCreateTasks() {
+ return currentUserHasPermission('tasks:create');
+}
+
+export function canCreateClients() {
+ return currentUserHasPermission('clients:create');
+}
+
+export function canDeleteClients() {
+ return currentUserHasPermission('clients:delete');
+}
+
+export function canViewClients() {
+ return currentUserHasPermission('clients:view');
+}
+
+export function canViewMembers() {
+ return currentUserHasPermission('members:view');
+}
+
+export function canDeleteMembers() {
+ return currentUserHasPermission('members:delete');
+}
+
+export function canInvitePlaceholderMembers() {
+ return currentUserHasPermission('members:invite-placeholder');
+}
+
+export function canCreateInvitations() {
+ return currentUserHasPermission('invitations:create');
+}
+
+export function canViewTags() {
+ return currentUserHasPermission('tags:view');
+}
+
+export function canCreateTags() {
+ return currentUserHasPermission('tags:create');
+}
+
+export function canDeleteTags() {
+ return currentUserHasPermission('tags:delete');
+}