@@ -32,6 +32,8 @@ import {
3232 type Maybe ,
3333 type MutationRejectAllSectionOptionsArgs ,
3434 type MutationRestoreAllSectionOptionsArgs ,
35+ type MutationRejectAllApplicationOptionsArgs ,
36+ type MutationRestoreAllApplicationOptionsArgs ,
3537} from "common/types/gql-types" ;
3638import { formatDuration } from "common/src/common/util" ;
3739import { convertWeekday , type Day } from "common/src/conversion" ;
@@ -54,7 +56,9 @@ import { TimeSelector } from "../TimeSelector";
5456import {
5557 APPLICATION_ADMIN_QUERY ,
5658 REJECT_ALL_SECTION_OPTIONS ,
59+ REJECT_APPLICATION ,
5760 RESTORE_ALL_SECTION_OPTIONS ,
61+ RESTORE_APPLICATION ,
5862} from "../queries" ;
5963import { getApplicantName , getApplicationStatusColor } from "@/helpers" ;
6064// TODO move
@@ -166,7 +170,7 @@ const StyledAccordion = styled(Accordion).attrs({
166170
167171const PreCard = styled . div `
168172 font-size: var(--fontsize-body-s);
169- margin-bottom: var(--spacing-m );
173+ margin-bottom: var(--spacing-2-xs );
170174` ;
171175
172176const EventSchedules = styled . div `
@@ -428,7 +432,9 @@ function RejectOptionButton({
428432 disabled = { isDisabled }
429433 data-testid = { `reject-btn-${ option . pk } ` }
430434 >
431- { isRejected ? t ( "Application.btnRevert" ) : t ( "Application.btnReject" ) }
435+ { isRejected
436+ ? t ( "Application.section.btnRestore" )
437+ : t ( "Application.section.btnReject" ) }
432438 </ Button >
433439 ) ;
434440}
@@ -525,8 +531,8 @@ function RejectAllOptionsButton({
525531 isLoading = { isLoading }
526532 >
527533 { isRejected
528- ? t ( "Application.btnRestoreAll" )
529- : t ( "Application.btnRejectAll" ) }
534+ ? t ( "Application.section. btnRestoreAll" )
535+ : t ( "Application.section. btnRejectAll" ) }
530536 </ Button >
531537 ) ;
532538}
@@ -694,6 +700,115 @@ function ApplicationSectionDetails({
694700 ) ;
695701}
696702
703+ function RejectApplicationButton ( {
704+ application,
705+ refetch,
706+ } : {
707+ application : ApplicationNode ;
708+ refetch : ( ) => Promise < ApolloQueryResult < Query > > ;
709+ } ) : JSX . Element {
710+ const { t } = useTranslation ( ) ;
711+ const { notifyError } = useNotification ( ) ;
712+
713+ const [ rejectionMutation , { loading : isRejectionLoading } ] = useMutation <
714+ Query ,
715+ MutationRejectAllApplicationOptionsArgs
716+ > ( REJECT_APPLICATION ) ;
717+
718+ const [ restoreMutation , { loading : isRestoreLoading } ] = useMutation <
719+ Query ,
720+ MutationRestoreAllApplicationOptionsArgs
721+ > ( RESTORE_APPLICATION ) ;
722+
723+ const isLoading = isRejectionLoading || isRestoreLoading ;
724+
725+ const updateApplication = async (
726+ pk : Maybe < number > | undefined ,
727+ shouldReject : boolean
728+ ) => {
729+ if ( pk == null ) {
730+ return ;
731+ }
732+ if ( isLoading ) {
733+ return ;
734+ }
735+
736+ const mutation = shouldReject ? rejectionMutation : restoreMutation ;
737+ try {
738+ await mutation ( {
739+ variables : {
740+ input : {
741+ pk,
742+ } ,
743+ } ,
744+ } ) ;
745+ refetch ( ) ;
746+ } catch ( err ) {
747+ const mutationErrors = getValidationErrors ( err ) ;
748+ if ( mutationErrors . length > 0 ) {
749+ // TODO handle other codes also
750+ const isInvalidState = mutationErrors . find (
751+ ( e ) => e . code === "CANNOT_REJECT_APPLICATION_OPTIONS"
752+ ) ;
753+ if ( isInvalidState ) {
754+ notifyError ( t ( "errors.cantRejectAlreadyAllocated" ) ) ;
755+ } else {
756+ // TODO this should show them with cleaner formatting (multiple errors)
757+ // TODO these should be translated
758+ const message = mutationErrors . map ( ( e ) => e . message ) . join ( ", " ) ;
759+ notifyError ( t ( "errors.formValidationError" , { message } ) ) ;
760+ }
761+ } else {
762+ notifyError ( t ( "errors.errorRejectingApplication" ) ) ;
763+ }
764+ }
765+ } ;
766+
767+ const handleRejectAll = async ( ) => {
768+ updateApplication ( application . pk , true ) ;
769+ } ;
770+
771+ const handleRestoreAll = async ( ) => {
772+ updateApplication ( application . pk , false ) ;
773+ } ;
774+
775+ // codegen types allow undefined so have to do this for debugging
776+ if ( application . applicationSections == null ) {
777+ // eslint-disable-next-line no-console
778+ console . warn ( "application.applicationSections is null" , application ) ;
779+ }
780+ if ( application . status == null ) {
781+ // eslint-disable-next-line no-console
782+ console . warn ( "application.status is null" , application ) ;
783+ }
784+
785+ const isInAllocation =
786+ application . status === ApplicationStatusChoice . InAllocation ;
787+ const hasBeenAllocated =
788+ application . applicationSections ?. some ( ( section ) =>
789+ section . reservationUnitOptions . some (
790+ ( option ) => option . allocatedTimeSlots ?. length > 0
791+ )
792+ ) ?? false ;
793+ const canReject = isInAllocation && ! hasBeenAllocated ;
794+ const isRejected =
795+ application . applicationSections ?. every ( ( section ) =>
796+ section . reservationUnitOptions . every ( ( option ) => option . rejected )
797+ ) ?? false ;
798+
799+ return (
800+ < Button
801+ size = "small"
802+ variant = "secondary"
803+ theme = "black"
804+ onClick = { ( ) => ( isRejected ? handleRestoreAll ( ) : handleRejectAll ( ) ) }
805+ disabled = { ! canReject }
806+ >
807+ { isRejected ? t ( "Application.btnRestore" ) : t ( "Application.btnReject" ) }
808+ </ Button >
809+ ) ;
810+ }
811+
697812function ApplicationDetails ( {
698813 applicationPk,
699814} : {
@@ -789,12 +904,19 @@ function ApplicationDetails({
789904 { t ( "Application.applicationReceivedTime" ) } { " " }
790905 { formatDate ( application . lastModifiedDate , "d.M.yyyy HH:mm" ) }
791906 </ PreCard >
907+ < div style = { { marginBottom : "var(--spacing-s)" } } >
908+ < RejectApplicationButton
909+ application = { application }
910+ refetch = { refetch }
911+ />
912+ </ div >
792913 < Card
793914 theme = { {
794915 "--background-color" : "var(--color-black-5)" ,
795916 "--padding-horizontal" : "var(--spacing-m)" ,
796917 "--padding-vertical" : "var(--spacing-m)" ,
797918 } }
919+ style = { { marginBottom : "var(--spacing-m)" } }
798920 >
799921 < CardContentContainer >
800922 < DefinitionList >
0 commit comments