diff --git a/frontend/src/hooks/useInvitations.ts b/frontend/src/hooks/useInvitations.ts index 5868666..c607d90 100644 --- a/frontend/src/hooks/useInvitations.ts +++ b/frontend/src/hooks/useInvitations.ts @@ -28,8 +28,9 @@ export interface InvitationDetails { business_name: string; invited_by: string | null; expires_at: string; - create_bookable_resource: boolean; - resource_name: string; + create_bookable_resource?: boolean; + resource_name?: string; + invitation_type?: 'tenant' | 'staff'; } export interface StaffPermissions { @@ -113,13 +114,21 @@ export const useResendInvitation = () => { /** * Hook to get invitation details by token (for acceptance page) + * Tries platform tenant invitations first, then falls back to staff invitations */ export const useInvitationDetails = (token: string | null) => { return useQuery({ queryKey: ['invitation', token], queryFn: async () => { - const { data } = await apiClient.get(`/staff/invitations/token/${token}/`); - return data; + // Try platform tenant invitation first + try { + const { data } = await apiClient.get(`/platform/tenant-invitations/token/${token}/`); + return { ...data, invitation_type: 'tenant' }; + } catch { + // Fall back to staff invitation + const { data } = await apiClient.get(`/staff/invitations/token/${token}/`); + return { ...data, invitation_type: 'staff' }; + } }, enabled: !!token, retry: false, @@ -128,6 +137,7 @@ export const useInvitationDetails = (token: string | null) => { /** * Hook to accept an invitation + * Tries platform tenant invitation first, then falls back to staff invitation */ export const useAcceptInvitation = () => { return useMutation({ @@ -136,28 +146,54 @@ export const useAcceptInvitation = () => { firstName, lastName, password, + invitationType, }: { token: string; firstName: string; lastName: string; password: string; + invitationType?: 'tenant' | 'staff'; }) => { - const { data } = await apiClient.post(`/staff/invitations/token/${token}/accept/`, { + const payload = { first_name: firstName, last_name: lastName, password, - }); - return data; + }; + + // Use known invitation type if provided, otherwise try tenant first + if (invitationType === 'staff') { + const { data } = await apiClient.post(`/staff/invitations/token/${token}/accept/`, payload); + return data; + } + + try { + const { data } = await apiClient.post(`/platform/tenant-invitations/token/${token}/accept/`, payload); + return data; + } catch { + const { data } = await apiClient.post(`/staff/invitations/token/${token}/accept/`, payload); + return data; + } }, }); }; /** * Hook to decline an invitation + * Note: Platform tenant invitations may not have a decline endpoint */ export const useDeclineInvitation = () => { return useMutation({ - mutationFn: async (token: string) => { + mutationFn: async ({ token, invitationType }: { token: string; invitationType?: 'tenant' | 'staff' }) => { + if (invitationType === 'tenant') { + // Platform tenant invitations - check if decline endpoint exists + try { + const { data } = await apiClient.post(`/platform/tenant-invitations/token/${token}/decline/`); + return data; + } catch { + // May not have decline endpoint, just return success + return { status: 'declined' }; + } + } const { data } = await apiClient.post(`/staff/invitations/token/${token}/decline/`); return data; }, diff --git a/frontend/src/pages/AcceptInvitePage.tsx b/frontend/src/pages/AcceptInvitePage.tsx index 88bb907..7e6830d 100644 --- a/frontend/src/pages/AcceptInvitePage.tsx +++ b/frontend/src/pages/AcceptInvitePage.tsx @@ -68,6 +68,7 @@ const AcceptInvitePage: React.FC = () => { firstName: firstName.trim(), lastName: lastName.trim(), password, + invitationType: invitation?.invitation_type, }); // Set auth tokens and redirect to dashboard @@ -89,7 +90,7 @@ const AcceptInvitePage: React.FC = () => { } try { - await declineInvitationMutation.mutateAsync(token!); + await declineInvitationMutation.mutateAsync({ token: token!, invitationType: invitation?.invitation_type }); setDeclined(true); } catch (err: any) { setFormError(err.response?.data?.error || t('acceptInvite.declineFailed', 'Failed to decline invitation'));