@@ -30,6 +30,8 @@ import {
3030 type MutationUpdateReservationUnitOptionArgs ,
3131 type ReservationUnitOptionNode ,
3232 type Maybe ,
33+ type MutationRejectAllSectionOptionsArgs ,
34+ type MutationRestoreAllSectionOptionsArgs ,
3335} from "common/types/gql-types" ;
3436import { formatDuration } from "common/src/common/util" ;
3537import { convertWeekday , type Day } from "common/src/conversion" ;
@@ -49,7 +51,11 @@ import { BirthDate } from "@/component/BirthDate";
4951import { Container } from "@/styles/layout" ;
5052import { ValueBox } from "../ValueBox" ;
5153import { TimeSelector } from "../TimeSelector" ;
52- import { APPLICATION_ADMIN_QUERY } from "../queries" ;
54+ import {
55+ APPLICATION_ADMIN_QUERY ,
56+ REJECT_ALL_SECTION_OPTIONS ,
57+ RESTORE_ALL_SECTION_OPTIONS ,
58+ } from "../queries" ;
5359import { getApplicantName , getApplicationStatusColor } from "@/helpers" ;
5460// TODO move
5561import { UPDATE_RESERVATION_UNIT_OPTION } from "@/spa/recurring-reservations/application-rounds/[id]/allocation/queries" ;
@@ -156,9 +162,6 @@ const StyledAccordion = styled(Accordion).attrs({
156162 } as React . CSSProperties ,
157163} ) `
158164 margin-top: 48px;
159- h4 {
160- margin-top: 4rem;
161- }
162165` ;
163166
164167const PreCard = styled . div `
@@ -211,6 +214,7 @@ const HeadingContainer = styled.div`
211214 display: flex;
212215 justify-content: space-between;
213216 margin-top: var(--spacing-s);
217+ align-items: start;
214218` ;
215219
216220const ApplicationSectionsContainer = styled . div `
@@ -429,6 +433,104 @@ function RejectOptionButton({
429433 ) ;
430434}
431435
436+ function RejectAllOptionsButton ( {
437+ section,
438+ applicationStatus,
439+ refetch,
440+ } : {
441+ section : ApplicationSectionNode ;
442+ applicationStatus : ApplicationStatusChoice ;
443+ refetch : ( ) => Promise < ApolloQueryResult < Query > > ;
444+ } ) {
445+ const { t } = useTranslation ( ) ;
446+
447+ const [ rejectMutation , { loading : rejectLoading } ] = useMutation <
448+ Query ,
449+ MutationRejectAllSectionOptionsArgs
450+ > ( REJECT_ALL_SECTION_OPTIONS ) ;
451+
452+ const [ restoreMutation , { loading : restoreLoading } ] = useMutation <
453+ Query ,
454+ MutationRestoreAllSectionOptionsArgs
455+ > ( RESTORE_ALL_SECTION_OPTIONS ) ;
456+
457+ const { notifyError } = useNotification ( ) ;
458+
459+ const isLoading = rejectLoading || restoreLoading ;
460+
461+ const mutate = async ( pk : Maybe < number > | undefined , restore : boolean ) => {
462+ if ( pk == null ) {
463+ // TODO this is an error
464+ return ;
465+ }
466+ if ( isLoading ) {
467+ return ;
468+ }
469+ try {
470+ const mutation = restore ? restoreMutation : rejectMutation ;
471+ await mutation ( {
472+ variables : {
473+ input : {
474+ pk,
475+ } ,
476+ } ,
477+ } ) ;
478+ refetch ( ) ;
479+ } catch ( err ) {
480+ const mutationErrors = getValidationErrors ( err ) ;
481+ if ( mutationErrors . length > 0 ) {
482+ // TODO handle other codes also
483+ const isInvalidState = mutationErrors . find (
484+ ( e ) => e . code === "CANNOT_REJECT_SECTION_OPTIONS"
485+ ) ;
486+ if ( isInvalidState ) {
487+ notifyError ( t ( "errors.cantRejectAlreadyAllocated" ) ) ;
488+ } else {
489+ // TODO this should show them with cleaner formatting (multiple errors)
490+ // TODO these should be translated
491+ const message = mutationErrors . map ( ( e ) => e . message ) . join ( ", " ) ;
492+ notifyError ( t ( "errors.formValidationError" , { message } ) ) ;
493+ }
494+ } else {
495+ notifyError ( t ( "errors.errorRejectingOption" ) ) ;
496+ }
497+ }
498+ } ;
499+
500+ const handleRejectAll = async ( ) => {
501+ mutate ( section . pk , false ) ;
502+ } ;
503+
504+ const handleRestoreAll = async ( ) => {
505+ mutate ( section . pk , true ) ;
506+ } ;
507+
508+ // codegen types allow undefined so have to do this for debugging
509+ if ( section . allocations == null ) {
510+ // eslint-disable-next-line no-console
511+ console . warn ( "section.allocations is null" , section ) ;
512+ }
513+
514+ const inAllocation =
515+ applicationStatus === ApplicationStatusChoice . InAllocation ;
516+ const isRejected = section . reservationUnitOptions . every ( ( x ) => x . rejected ) ;
517+ const hasAllocations = section . allocations != null && section . allocations > 0 ;
518+ const canReject = inAllocation && ! hasAllocations ;
519+ return (
520+ < Button
521+ disabled = { ! canReject }
522+ size = "small"
523+ variant = "secondary"
524+ onClick = { ( ) => ( isRejected ? handleRestoreAll ( ) : handleRejectAll ( ) ) }
525+ isLoading = { isLoading }
526+ >
527+ { isRejected
528+ ? t ( "Application.btnRestoreAll" )
529+ : t ( "Application.btnRejectAll" ) }
530+ </ Button >
531+ ) ;
532+ }
533+
432534interface DataType extends ReservationUnitOptionNode {
433535 index : number ;
434536}
@@ -551,7 +653,16 @@ function ApplicationSectionDetails({
551653 />
552654 < ValueBox label = { t ( "ApplicationEvent.dates" ) } value = { dates } />
553655 </ EventProps >
554- < H4 > { t ( "ApplicationEvent.requestedReservationUnits" ) } </ H4 >
656+ < HeadingContainer style = { { alignItems : "center" } } >
657+ < H4 as = "h3" > { t ( "ApplicationEvent.requestedReservationUnits" ) } </ H4 >
658+ < RejectAllOptionsButton
659+ section = { section }
660+ refetch = { refetch }
661+ applicationStatus = {
662+ application . status ?? ApplicationStatusChoice . Draft
663+ }
664+ />
665+ </ HeadingContainer >
555666 < ApplicationSectionsContainer >
556667 { rows . map ( ( row ) => (
557668 < div style = { { display : "contents" } } key = { row . pk } >
@@ -561,7 +672,7 @@ function ApplicationSectionDetails({
561672 </ div >
562673 ) ) }
563674 </ ApplicationSectionsContainer >
564- < H4 > { t ( "ApplicationEvent.requestedTimes" ) } </ H4 >
675+ < H4 as = "h3" > { t ( "ApplicationEvent.requestedTimes" ) } </ H4 >
565676 < EventSchedules >
566677 < TimeSelector applicationSection = { section } />
567678 < Card
@@ -667,7 +778,7 @@ function ApplicationDetails({
667778 </ ShowWhenTargetInvisible >
668779 < Container >
669780 < HeadingContainer >
670- < H2 ref = { ref } style = { { margin : "0" } } >
781+ < H2 as = "h1" ref = { ref } style = { { margin : "0" } } >
671782 { customerName }
672783 </ H2 >
673784 { application . status != null && (
0 commit comments