diff --git a/resources/js/Components/Common/Invitation/InvitationMoreOptionsDropdown.vue b/resources/js/Components/Common/Invitation/InvitationMoreOptionsDropdown.vue new file mode 100644 index 00000000..46343e3c --- /dev/null +++ b/resources/js/Components/Common/Invitation/InvitationMoreOptionsDropdown.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/resources/js/Components/Common/Invitation/InvitationTable.vue b/resources/js/Components/Common/Invitation/InvitationTable.vue index fe4c66b7..582f69a5 100644 --- a/resources/js/Components/Common/Invitation/InvitationTable.vue +++ b/resources/js/Components/Common/Invitation/InvitationTable.vue @@ -18,7 +18,7 @@ onMounted(async () => {
+ style="grid-template-columns: 1fr 1fr 80px"> diff --git a/resources/js/Components/Common/Invitation/InvitationTableRow.vue b/resources/js/Components/Common/Invitation/InvitationTableRow.vue index f30df0d3..1824f223 100644 --- a/resources/js/Components/Common/Invitation/InvitationTableRow.vue +++ b/resources/js/Components/Common/Invitation/InvitationTableRow.vue @@ -2,20 +2,76 @@ import type { Invitation } from '@/utils/api'; import TableRow from '@/Components/TableRow.vue'; import { capitalizeFirstLetter } from '../../../utils/format'; +import InvitationMoreOptionsDropdown from '@/Components/Common/Invitation/InvitationMoreOptionsDropdown.vue'; +import { api } from '../../../../../openapi.json.client'; +import { getCurrentOrganizationId } from '@/utils/useUser'; +import { useNotificationsStore } from '@/utils/notification'; +import { useInvitationsStore } from '@/utils/useInvitations'; +const { handleApiRequestNotifications } = useNotificationsStore(); -defineProps<{ +const props = defineProps<{ invitation: Invitation; }>(); + +async function deleteInvitation() { + const organizationId = getCurrentOrganizationId(); + if (organizationId) { + await handleApiRequestNotifications( + () => + api.removeInvitation( + {}, + { + params: { + invitation: props.invitation.id, + organization: organizationId, + }, + } + ), + 'Invitation removed successfully', + 'Error removing invitation', + () => { + useInvitationsStore().fetchInvitations(); + } + ); + } +} + +async function resendInvitation() { + const organizationId = getCurrentOrganizationId(); + if (organizationId) { + await handleApiRequestNotifications( + () => + api.resendInvitationEmail( + {}, + { + params: { + invitation: props.invitation.id, + organization: organizationId, + }, + } + ), + 'Invitation mail sent successfully', + 'Error sending invitation mail' + ); + } +} diff --git a/resources/js/Components/Common/Member/MemberInviteModal.vue b/resources/js/Components/Common/Member/MemberInviteModal.vue index 431f6ae9..01c43c2e 100644 --- a/resources/js/Components/Common/Member/MemberInviteModal.vue +++ b/resources/js/Components/Common/Member/MemberInviteModal.vue @@ -8,9 +8,16 @@ import { useFocus } from '@vueuse/core'; import InputLabel from '@/Components/InputLabel.vue'; import InputError from '@/Components/InputError.vue'; import type { Role } from '@/types/jetstream'; -import { useForm } from '@inertiajs/vue3'; +import { Link, useForm } from '@inertiajs/vue3'; import { getCurrentOrganizationId } from '@/utils/useUser'; import { filterRoles } from '@/utils/roles'; +import { hasActiveSubscription, isBillingActivated } from '@/utils/billing'; +import { CreditCardIcon, UserGroupIcon } from '@heroicons/vue/20/solid'; +import { canUpdateOrganization } from '@/utils/permissions'; +import { api } from '../../../../../openapi.json.client'; +import type { MemberRole } from '@/utils/api'; +import { z } from 'zod'; +import { useNotificationsStore } from '@/utils/notification'; const show = defineModel('show', { default: false }); const saving = ref(false); @@ -19,25 +26,55 @@ defineProps<{ availableRoles: Role[]; }>(); +const errors = ref({ + email: '', + role: '', +}); + const addTeamMemberForm = useForm({ email: '', role: null as string | null, }); const emit = defineEmits(['close']); +const { handleApiRequestNotifications } = useNotificationsStore(); async function submit() { + if (addTeamMemberForm.role === null || addTeamMemberForm.email === '') { + errors.value.email = z + .string() + .email() + .safeParse(addTeamMemberForm.email).success + ? '' + : 'Please enter a valid email address'; + errors.value.role = + addTeamMemberForm.role === null ? 'Please select a role' : ''; + return; + } + const organizationId = getCurrentOrganizationId(); if (organizationId) { - addTeamMemberForm.post(route('team-members.store', organizationId), { - errorBag: 'addTeamMember', - preserveScroll: true, - onSuccess: () => { + await handleApiRequestNotifications( + () => + api.invite( + { + email: addTeamMemberForm.email, + role: addTeamMemberForm.role as MemberRole, + }, + { + params: { + organization: organizationId, + }, + } + ), + 'Member invited', + 'Failed to invite member', + () => { addTeamMemberForm.reset(); emit('close'); show.value = false; - }, - }); + } + ); } } @@ -54,7 +91,34 @@ useFocus(clientNameInput, { initialValue: true });