Add invitation frontend: invite modal, pending invitations, no-company view

Members Index:
- "Invite Member" button opens InviteMemberModal (email + role dropdown)
- Pending invitations section shows below members table with cancel buttons
- Members store gains inviteMember, fetchPendingInvitations, cancelInvitation

CompanySwitcher:
- Shows pending invitations greyed out below active companies
- Each with Accept/Decline mini-buttons
- Accepting refreshes bootstrap and switches to new company

NoCompanyView:
- Standalone page for users with zero accepted companies
- Shows pending invitations with Accept/Decline or "no companies" message
- Route: /admin/no-company

Invitation Pinia store:
- Manages user's own pending invitations (fetchPending, accept, decline)
- Bootstrap populates invitations from API response

Global store:
- Bootstrap action stores pending_invitations from response
This commit is contained in:
Darko Gjorgjijoski
2026-04-03 23:20:41 +02:00
parent 8a6c085288
commit 6343b4a17f
9 changed files with 491 additions and 2 deletions

View File

@@ -12,6 +12,7 @@ export const useMembersStore = (useWindow = false) => {
roles: [],
users: [],
totalUsers: 0,
pendingInvitations: [],
currentUser: null,
selectAllField: false,
selectedUsers: [],
@@ -226,6 +227,63 @@ export const useMembersStore = (useWindow = false) => {
this.selectAllField = true
}
},
fetchPendingInvitations() {
return new Promise((resolve, reject) => {
http
.get('/api/v1/company-invitations')
.then((response) => {
this.pendingInvitations = response.data.invitations
resolve(response)
})
.catch((err) => {
handleError(err)
reject(err)
})
})
},
inviteMember(data) {
return new Promise((resolve, reject) => {
http
.post('/api/v1/company-invitations', data)
.then((response) => {
const notificationStore = useNotificationStore()
notificationStore.showNotification({
type: 'success',
message: global.t('members.invited_message'),
})
this.fetchPendingInvitations()
resolve(response)
})
.catch((err) => {
handleError(err)
reject(err)
})
})
},
cancelInvitation(id) {
return new Promise((resolve, reject) => {
http
.delete(`/api/v1/company-invitations/${id}`)
.then((response) => {
const notificationStore = useNotificationStore()
notificationStore.showNotification({
type: 'success',
message: global.t('members.invitation_cancelled'),
})
this.pendingInvitations = this.pendingInvitations.filter(
(inv) => inv.id !== id
)
resolve(response)
})
.catch((err) => {
handleError(err)
reject(err)
})
})
},
},
})()
}