1- import React from "react" ;
2- import { Grid } from "@mui/material" ;
1+ import React , { useMemo } from "react" ;
2+ import { Box } from "@mui/material" ;
33import { useTranslation } from "next-i18next" ;
4+ import ArrowBackIcon from "@mui/icons-material/ArrowBack" ;
5+ import SaveOutlinedIcon from "@mui/icons-material/SaveOutlined" ;
46import AletheiaButton , { ButtonType } from "../../Button" ;
57import {
68 ReviewTaskEvents ,
@@ -26,16 +28,6 @@ const PRIMARY_ACTIONS: Partial<Record<ReviewTaskStates, ReviewTaskEvents>> = {
2628 [ ReviewTaskStates . rejected ] : ReviewTaskEvents . addRejectionComment ,
2729} ;
2830
29- function getButtonType (
30- event : ReviewTaskEvents ,
31- currentState : string
32- ) : ButtonType {
33- if ( event === ReviewTaskEvents . goback ) return ButtonType . gray ;
34- const primaryEvent = PRIMARY_ACTIONS [ currentState as ReviewTaskStates ] ;
35- if ( primaryEvent && event === primaryEvent ) return ButtonType . blue ;
36- return ButtonType . whiteBlue ;
37- }
38-
3931interface ActionToolbarProps {
4032 events : ReviewTaskEvents [ ] ;
4133 permissions : PermissionContext ;
@@ -55,51 +47,127 @@ const ActionToolbar = ({
5547} : ActionToolbarProps ) => {
5648 const { t } = useTranslation ( ) ;
5749
58- const filteredEvents = events . filter (
59- ( event ) =>
60- event !== ReviewTaskEvents . draft &&
61- permissions . canSubmitActions . includes ( event )
62- ) ;
50+ const primaryEvent = PRIMARY_ACTIONS [ currentState as ReviewTaskStates ] ;
51+
52+ // Separate events into groups for proper layout
53+ const { goBackEvent, secondaryEvents, primaryActionEvent } = useMemo ( ( ) => {
54+ const allowed = events . filter (
55+ ( event ) =>
56+ event !== ReviewTaskEvents . draft &&
57+ permissions . canSubmitActions . includes ( event )
58+ ) ;
59+
60+ const goBack = allowed . find ( ( e ) => e === ReviewTaskEvents . goback ) ;
61+ const primary = allowed . find ( ( e ) => e === primaryEvent ) ;
62+ const secondary = allowed . filter (
63+ ( e ) => e !== ReviewTaskEvents . goback && e !== primary
64+ ) ;
65+
66+ return {
67+ goBackEvent : goBack ,
68+ secondaryEvents : secondary ,
69+ primaryActionEvent : primary ,
70+ } ;
71+ } , [ events , permissions . canSubmitActions , primaryEvent ] ) ;
72+
73+ const showSaveDraft =
74+ permissions . showSaveDraftButton &&
75+ permissions . canSubmitActions . includes ( ReviewTaskEvents . draft ) ;
6376
6477 return (
65- < Grid
66- container
67- style = { {
68- padding : "32px 0 0" ,
69- justifyContent : "space-evenly" ,
70- gap : "10px" ,
78+ < Box
79+ sx = { {
80+ display : "flex" ,
81+ alignItems : "center" ,
82+ justifyContent : "space-between" ,
83+ padding : "12px 20px" ,
84+ position : "sticky" ,
85+ bottom : 0 ,
86+ backgroundColor : "inherit" ,
87+ borderTop : "1px solid rgba(0, 0, 0, 0.12)" ,
88+ zIndex : 10 ,
89+ gap : "12px" ,
7190 } }
7291 >
73- { permissions . showSaveDraftButton &&
74- permissions . canSubmitActions . includes (
75- ReviewTaskEvents . draft
76- ) && (
92+ { /* Left group: navigation actions */ }
93+ < Box sx = { { display : "flex" , alignItems : "center" , gap : "8px" } } >
94+ { goBackEvent && (
95+ < AletheiaButton
96+ loading = { isLoading [ goBackEvent ] }
97+ type = { ButtonType . gray }
98+ htmlType = "button"
99+ onClick = { ( ) => onButtonClick ( goBackEvent ) }
100+ event = { goBackEvent }
101+ data-cy = { `testClaimReview${ goBackEvent } ` }
102+ icon = { < ArrowBackIcon style = { { fontSize : 16 } } /> }
103+ style = { { textTransform : "none" , fontWeight : 500 } }
104+ >
105+ { t ( `reviewTask:${ goBackEvent } ` ) }
106+ </ AletheiaButton >
107+ ) }
108+ </ Box >
109+
110+ { /* Right group: save + secondary + primary action */ }
111+ < Box
112+ sx = { {
113+ display : "flex" ,
114+ alignItems : "center" ,
115+ gap : "10px" ,
116+ flexWrap : "wrap" ,
117+ justifyContent : "flex-end" ,
118+ } }
119+ >
120+ { showSaveDraft && (
77121 < AletheiaButton
78122 loading = { isLoading [ ReviewTaskEvents . draft ] }
79- type = { ButtonType . whiteBlue }
123+ type = { ButtonType . whiteBlack }
80124 htmlType = "button"
81125 onClick = { ( ) => onButtonClick ( ReviewTaskEvents . draft ) }
82126 event = { ReviewTaskEvents . draft }
83127 data-cy = { `testClaimReview${ ReviewTaskEvents . draft } ` }
128+ icon = { < SaveOutlinedIcon style = { { fontSize : 16 } } /> }
129+ style = { { textTransform : "none" , fontWeight : 500 } }
84130 >
85131 { t ( `reviewTask:${ ReviewTaskEvents . draft } ` ) }
86132 </ AletheiaButton >
87133 ) }
88134
89- { filteredEvents . map ( ( event ) => (
90- < AletheiaButton
91- loading = { isLoading [ event ] }
92- key = { event }
93- type = { getButtonType ( event , currentState ) }
94- htmlType = { defineButtonHtmlType ( event ) }
95- onClick = { ( ) => onButtonClick ( event ) }
96- event = { event }
97- data-cy = { `testClaimReview${ event } ` }
98- >
99- { t ( `reviewTask:${ event } ` ) }
100- </ AletheiaButton >
101- ) ) }
102- </ Grid >
135+ { secondaryEvents . map ( ( event ) => (
136+ < AletheiaButton
137+ loading = { isLoading [ event ] }
138+ key = { event }
139+ type = { ButtonType . whiteBlack }
140+ htmlType = { defineButtonHtmlType ( event ) }
141+ onClick = { ( ) => onButtonClick ( event ) }
142+ event = { event }
143+ data-cy = { `testClaimReview${ event } ` }
144+ style = { { textTransform : "none" , fontWeight : 500 } }
145+ >
146+ { t ( `reviewTask:${ event } ` ) }
147+ </ AletheiaButton >
148+ ) ) }
149+
150+ { primaryActionEvent && (
151+ < AletheiaButton
152+ loading = { isLoading [ primaryActionEvent ] }
153+ type = { ButtonType . blue }
154+ htmlType = { defineButtonHtmlType ( primaryActionEvent ) }
155+ onClick = { ( ) => onButtonClick ( primaryActionEvent ) }
156+ event = { primaryActionEvent }
157+ data-cy = { `testClaimReview${ primaryActionEvent } ` }
158+ style = { {
159+ textTransform : "none" ,
160+ fontWeight : 600 ,
161+ minWidth : 140 ,
162+ height : 44 ,
163+ fontSize : "13px" ,
164+ } }
165+ >
166+ { t ( `reviewTask:${ primaryActionEvent } ` ) }
167+ </ AletheiaButton >
168+ ) }
169+ </ Box >
170+ </ Box >
103171 ) ;
104172} ;
105173
0 commit comments