Skip to content
Snippets Groups Projects
Commit c62421c6 authored by Tore.Brede's avatar Tore.Brede
Browse files

GREG-100: Adding functinality for cancelling invitation

parent cdb2a423
No related branches found
No related tags found
1 merge request!129GREG-100: Cancel invitation
import { useState } from 'react'
import React, { useState } from 'react'
import {
Table,
TableBody,
......@@ -23,15 +23,24 @@ import SponsorGuestButtons from '../../components/sponsorGuestButtons'
interface GuestProps {
persons: Guest[]
cancelCallback?: (roleId: string) => void
}
interface PersonLineProps {
person: Guest
role: Role
showStatusColumn?: boolean
displayCancel?: boolean
cancelCallback?: (roleId: string) => void
}
const PersonLine = ({ person, role, showStatusColumn }: PersonLineProps) => {
const PersonLine = ({
person,
role,
showStatusColumn,
displayCancel,
cancelCallback,
}: PersonLineProps) => {
const [t, i18n] = useTranslation(['common'])
return (
......@@ -65,13 +74,27 @@ const PersonLine = ({ person, role, showStatusColumn }: PersonLineProps) => {
{i18n.language === 'en' ? role.ou_en : role.ou_nb}
</TableCell>
<TableCell align="left">
<Button
variant="contained"
component={Link}
to={`/sponsor/guest/${person.pid}`}
>
{t('common:details')}
</Button>
{displayCancel ? (
<Button
data-testid="button-invite-cancel"
sx={{ color: 'theme.palette.secondary', mr: 1 }}
onClick={() => {
if (cancelCallback) {
cancelCallback(role.id)
}
}}
>
{t('common:button.cancel')}
</Button>
) : (
<Button
variant="contained"
component={Link}
to={`/sponsor/guest/${person.pid}`}
>
{t('common:details')}
</Button>
)}
</TableCell>
</TableRow>
)
......@@ -79,9 +102,15 @@ const PersonLine = ({ person, role, showStatusColumn }: PersonLineProps) => {
PersonLine.defaultProps = {
showStatusColumn: false,
displayCancel: false,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
cancelCallback: (roleId: number) => {},
}
const WaitingForGuestRegistration = ({ persons }: GuestProps) => {
const WaitingForGuestRegistration = ({
persons,
cancelCallback,
}: GuestProps) => {
const [activeExpanded, setActiveExpanded] = useState(false)
// Show guests that have not responded to the invite yet
......@@ -119,7 +148,12 @@ const WaitingForGuestRegistration = ({ persons }: GuestProps) => {
guests.map((person) =>
person.roles ? (
person.roles.map((role) => (
<PersonLine role={role} person={person} />
<PersonLine
role={role}
person={person}
displayCancel
cancelCallback={cancelCallback}
/>
))
) : (
<></>
......@@ -273,13 +307,17 @@ const WaitingGuests = ({ persons }: GuestProps) => {
interface FrontPageProps {
guests: Guest[]
cancelRole: (roleId: string) => void
}
function FrontPage({ guests }: FrontPageProps) {
function FrontPage({ guests, cancelRole }: FrontPageProps) {
return (
<Page>
<SponsorGuestButtons yourGuestsActive />
<WaitingForGuestRegistration persons={guests} />
<WaitingForGuestRegistration
persons={guests}
cancelCallback={cancelRole}
/>
<WaitingGuests persons={guests} />
<ActiveGuests persons={guests} />
</Page>
......
......@@ -3,7 +3,7 @@ import { Route } from 'react-router-dom'
import FrontPage from 'routes/sponsor/frontpage'
import { FetchedGuest, Guest } from 'interfaces'
import { parseRole } from 'utils'
import { parseRole, submitJsonOpts } from 'utils'
import GuestRoutes from './guest'
function Sponsor() {
......@@ -37,6 +37,29 @@ function Sponsor() {
}
}
const cancelRole = (roleId: string) => {
// There is no body for this request, but using submitJsonOpts still to
// set the CSRF-token
fetch(`/api/ui/v1/invite/?role_id=${roleId}`, submitJsonOpts('DELETE', {}))
.then((res) => {
if (!res.ok) {
return null
}
return res.text()
})
.then((result) => {
if (result !== null) {
// The invitation has been removed. Just reload all the data form the server to get updated data.
// The guests state will be updated by getGuestsInfo and this will trigger a rerender
getGuestsInfo()
}
})
.catch((error) => {
// TODO User should get some feedback telling him something failed
console.log('error', error)
})
}
useEffect(() => {
getGuestsInfo()
}, [])
......@@ -47,7 +70,7 @@ function Sponsor() {
<GuestRoutes />
</Route>
<Route exact path="/sponsor">
<FrontPage guests={guests} />
<FrontPage guests={guests} cancelRole={cancelRole} />
</Route>
</>
)
......
......@@ -7,7 +7,7 @@ from django.http.response import JsonResponse
from django.utils import timezone
from rest_framework import status
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.generics import CreateAPIView, GenericAPIView
from rest_framework.generics import CreateAPIView, GenericAPIView, DestroyAPIView
from rest_framework.parsers import JSONParser
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
......@@ -20,7 +20,7 @@ from gregui.api.serializers.invitation import InviteGuestSerializer
from gregui.models import GregUserProfile
class CreateInvitationView(CreateAPIView):
class CreateInvitationView(CreateAPIView, DestroyAPIView):
"""
Invitation creation endpoint
......@@ -72,6 +72,23 @@ class CreateInvitationView(CreateAPIView):
print(invitationlink)
return Response(status=status.HTTP_201_CREATED)
def delete(self, request, *args, **kwargs) -> Response:
role_id = request.query_params["role_id"]
invitationlink = InvitationLink.objects.get(invitation__role_id=int(role_id))
# TODO Determine if person should be deleted as well
if invitationlink:
if invitationlink.invitation.role.person.is_registered or invitationlink.invitation.role.person.is_verified:
# The guest has already gone through the registration step. The guest should
# not be verified, but including that check just in case here
return Response(status.HTTP_400_BAD_REQUEST)
# Delete the role, the cascading will cause all the invitation links connected
# to it to be removed as well
invitationlink.invitation.role.delete()
return Response(status=status.HTTP_200_OK)
class CheckInvitationView(APIView):
authentication_classes = []
......@@ -245,7 +262,7 @@ class InvitedGuestView(GenericAPIView):
@staticmethod
def _get_identity_or_none(
person: Person, identity_type: Identity.IdentityType
person: Person, identity_type: Identity.IdentityType
) -> Optional[str]:
try:
return person.identities.get(type=identity_type).value
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment