Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ajustement manuel du score au niveau de la sous-action CAE #3016

Merged
merged 14 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {ActionDefinitionSummary} from 'core-logic/api/endpoints/ActionDefinitionSummaryReadEndpoint';
import {ActionCommentaireField} from 'ui/shared/actions/ActionCommentaire';
import {
useActionJustification,
useSaveActionJustification,
} from '../data/useActionJustification';

type ActionJustificationProps = {
action: ActionDefinitionSummary;
className?: string;
backgroundClassName?: string;
title?: string;
subtitle?: string;
autoFocus?: boolean;
onSave?: (payload: {
collectivite_id: number;
action_id: string;
texte: string;
modified_at: string;
}) => void;
};

const ActionJustification = ({
action,
className,
backgroundClassName,
title,
subtitle,
autoFocus,
onSave,
}: ActionJustificationProps) => {
const {actionJustification, isLoading} = useActionJustification(action.id);
const {saveActionJustification} = useSaveActionJustification();

return (
<div className={className}>
<ActionCommentaireField
dataTest={`just-${action.id}`}
backgroundClassName={backgroundClassName}
action={action}
initialValue={actionJustification?.texte ?? ''}
title={title}
subtitle={subtitle}
autoFocus={autoFocus}
disabled={isLoading}
onSave={payload => {
const savedData = {
collectivite_id: payload.collectivite_id,
action_id: payload.action_id,
texte: payload.commentaire,
modified_at: new Date().toDateString(),
};
onSave ? onSave(savedData) : saveActionJustification(savedData);
}}
/>
</div>
);
};

export default ActionJustification;
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {useActionStatut} from 'core-logic/hooks/useActionStatut';
import {useEffect, useRef, useState} from 'react';
import {useLocation} from 'react-router-dom';
import {Accordion} from 'ui/Accordion';
import ActionJustification from 'app/pages/collectivite/EtatDesLieux/Referentiel/SuiviAction/ActionJustification';
import {ActionCommentaire} from 'ui/shared/actions/ActionCommentaire';
import {SuiviScoreRow} from '../data/useScoreRealise';
import SubActionDescription from './SubActionDescription';
Expand Down Expand Up @@ -47,7 +48,9 @@ const SubActionCard = ({
(statut === null && filled === true));

const shouldHideTasksStatus =
(statut !== null && statut?.avancement !== 'non_renseigne') ||
(statut !== null &&
statut?.avancement !== 'non_renseigne' &&
statut?.avancement !== 'detaille') ||
statut?.concerne === false;

// Déplie les tâches si
Expand Down Expand Up @@ -109,6 +112,7 @@ const SubActionCard = ({
<SubActionHeader
action={subAction}
actionScores={actionScores}
actionAvancement={avancement}
displayProgressBar={shouldDisplayProgressBar}
displayActionCommentaire={
auditStatus === 'audit_en_cours' && !openSubAction
Expand All @@ -122,7 +126,16 @@ const SubActionCard = ({
<div className="p-6">
{/* Commentaire associé à la sous-action */}
{(auditStatus !== 'audit_en_cours' || openSubAction) && (
<ActionCommentaire action={subAction} className="mb-10" />
<>
<ActionCommentaire action={subAction} className="mb-10" />
{subAction.referentiel === 'cae' && avancement === 'detaille' && (
<ActionJustification
action={subAction}
className="mb-10"
title="Justification de l’ajustement manuel du score"
/>
)}
</>
)}

{/* Section Description et Exemples */}
Expand All @@ -148,6 +161,9 @@ const SubActionCard = ({
tasks={tasks}
actionScores={actionScores}
hideStatus={shouldHideTasksStatus}
statusWarningMessage={
statut !== null && statut?.avancement === 'detaille'
}
/>
}
initialState={openTasks}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ import ActionProgressBar from 'ui/referentiels/ActionProgressBar';
import {SuiviScoreRow} from '../data/useScoreRealise';
import {ActionCommentaire} from 'ui/shared/actions/ActionCommentaire';
import {ExpandToggle} from 'ui/icons/ExpandToggle';
import ActionJustification from 'app/pages/collectivite/EtatDesLieux/Referentiel/SuiviAction/ActionJustification';
import {TActionAvancement} from 'types/alias';

type SubActionHeaderProps = {
action: ActionDefinitionSummary;
actionScores: {[actionId: string]: SuiviScoreRow};
actionAvancement?: TActionAvancement;
hideStatus?: boolean;
statusWarningMessage?: boolean;
displayProgressBar?: boolean;
displayActionCommentaire?: boolean;
openSubAction?: boolean;
Expand All @@ -30,7 +34,9 @@ type SubActionHeaderProps = {
const SubActionHeader = ({
action,
actionScores,
actionAvancement,
hideStatus = false,
statusWarningMessage = false,
displayProgressBar = false,
displayActionCommentaire = false,
openSubAction = false,
Expand Down Expand Up @@ -105,6 +111,7 @@ const SubActionHeader = ({
<ActionStatusDropdown
action={action}
actionScores={actionScores}
statusWarningMessage={statusWarningMessage}
onSaveStatus={onSaveStatus}
/>
)}
Expand All @@ -114,6 +121,13 @@ const SubActionHeader = ({
action={action}
backgroundClassName="!bg-[#f6f6f6] group-hover:!bg-[#eee]"
/>
{action.referentiel === 'cae' && actionAvancement === 'detaille' && (
<ActionJustification
action={action}
className="mt-10"
title="Justification de l’ajustement manuel du score"
/>
)}
</div>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type SubActionTaskProps = {
task: ActionDefinitionSummary;
actionScores: {[actionId: string]: SuiviScoreRow};
hideStatus?: boolean;
statusWarningMessage?: boolean;
onSaveStatus?: (payload: StatusToSavePayload) => void;
};

Expand All @@ -22,6 +23,7 @@ const SubActionTask = ({
task,
actionScores,
hideStatus = false,
statusWarningMessage = false,
onSaveStatus,
}: SubActionTaskProps): JSX.Element => {
const [openCommentaire, setOpenCommentaire] = useState(false);
Expand Down Expand Up @@ -51,6 +53,7 @@ const SubActionTask = ({
action={task}
actionScores={actionScores}
hideStatus={hideStatus}
statusWarningMessage={statusWarningMessage}
onSaveStatus={onSaveStatus}
/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type SubActionTasksListProps = {
tasks: ActionDefinitionSummary[];
actionScores: {[actionId: string]: SuiviScoreRow};
hideStatus?: boolean;
statusWarningMessage?: boolean;
onSaveStatus?: (payload: StatusToSavePayload) => void;
};

Expand All @@ -18,6 +19,7 @@ const SubActionTasksList = ({
tasks,
actionScores,
hideStatus = false,
statusWarningMessage = false,
onSaveStatus,
}: SubActionTasksListProps): JSX.Element => {
return (
Expand All @@ -28,6 +30,7 @@ const SubActionTasksList = ({
task={task}
actionScores={actionScores}
hideStatus={hideStatus}
statusWarningMessage={statusWarningMessage}
onSaveStatus={onSaveStatus}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {supabaseClient} from 'core-logic/api/supabase';
import {useCollectiviteId} from 'core-logic/hooks/params';
import {useMutation, useQuery, useQueryClient} from 'react-query';
import {Database} from 'types/database.types';

const fetchJustification = async (
collectivite_id: number | null,
action_id: string | null
) => {
const {error, data} = await supabaseClient
.from('justification_ajustement')
.select()
.match({collectivite_id, action_id});

if (error) throw new Error(error.message);

return data;
};

export const useActionJustification = (action_id: string) => {
const collectivite_id = useCollectiviteId();

const {data, isLoading} = useQuery(
['action_justification', collectivite_id, action_id],
() => fetchJustification(collectivite_id, action_id)
);

return {
actionJustification: data ? data[0] : null,
isLoading,
};
};

export const useSaveActionJustification = () => {
const queryClient = useQueryClient();
const {
isLoading,
mutate: saveActionJustification,
data: lastReply,
} = useMutation(write, {
mutationKey: 'action_justification',
onSuccess: (data, variables) => {
queryClient.refetchQueries([
'action_justification',
variables.collectivite_id,
variables.action_id,
]);
},
});

return {
isLoading,
saveActionJustification,
lastReply,
};
};

type ActionJustificationWrite =
Database['public']['Tables']['justification_ajustement']['Insert'];
const write = async (justification: ActionJustificationWrite) =>
supabaseClient.from('justification_ajustement').upsert([justification], {
onConflict: 'collectivite_id,action_id',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {useScores} from 'core-logic/hooks/scoreHooks';
import {referentielId} from 'utils/actions';

export const useTasksScoreRepartition = (actionId: string) => {
const scores = useScores();
// Modification nécessaire côté back sur "action_statuts" pour éviter l'appel de useScores
const tasksScores = scores[referentielId(actionId)].filter(
act => act.action_id.includes(actionId) && act.action_id !== actionId
);
const subActionScore = scores[referentielId(actionId)].filter(
act => act.action_id === actionId
);

let scoreFait = 0;
let scoreProgramme = 0;
let scorePasFait = 0;

tasksScores.forEach(task => {
scoreFait += task.point_fait;
scoreProgramme += task.point_programme;
scorePasFait += task.point_pas_fait;
});

return {
tasksScores,
avancementDetaille: [scoreFait, scoreProgramme, scorePasFait],
scoreMax: subActionScore[0].point_potentiel,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import {useAudit, useIsAuditeur} from 'app/pages/collectivite/Audit/useAudit';
import {useActionScore} from './scoreHooks';
import {Database} from 'types/database.types';
import {useCollectiviteId} from './params';
import {TActionAvancement} from 'types/alias';

/**
* Charge le statut d'une action
*/
export const useActionStatut = (actionId: string) => {
const collectivite_id = useCollectiviteId();
const {data, isLoading} = useQuery(['action_statut', collectivite_id], () =>
fetchCollectiviteActionStatuts(collectivite_id ?? undefined),
fetchCollectiviteActionStatuts(collectivite_id ?? undefined)
);

const statut = data?.find(action => action.action_id === actionId) || null;
Expand All @@ -22,7 +23,7 @@ export const useActionStatut = (actionId: string) => {
action =>
action.action_id.includes(actionId) &&
action.action_id.split(actionId)[1] !== '' &&
action.avancement !== 'non_renseigne',
action.avancement !== 'non_renseigne'
) !== undefined || null;

return {
Expand All @@ -32,6 +33,28 @@ export const useActionStatut = (actionId: string) => {
};
};

export const useTasksStatus = (tasksIds: string[]) => {
const collectivite_id = useCollectiviteId();
const {data, isLoading} = useQuery(['action_statut', collectivite_id], () =>
fetchCollectiviteActionStatuts(collectivite_id ?? undefined)
);

let tasksStatus: {
[key: string]: {avancement: TActionAvancement; concerne: boolean};
} = {};

tasksIds.forEach(taskId => {
const task = data?.find(action => action.action_id === taskId);
if (task !== undefined)
tasksStatus = {
...tasksStatus,
[taskId]: {avancement: task.avancement, concerne: task.concerne},
};
});

return {tasksStatus, isLoading};
};

const fetchCollectiviteActionStatuts = async (collectivite_id?: number) => {
if (!collectivite_id) {
return null;
Expand Down Expand Up @@ -91,6 +114,6 @@ export const useEditActionStatutIsDisabled = (actionId: string) => {
collectivite.readonly ||
!score ||
score.desactive ||
(audit && (!isAuditeur || audit.valide)),
(audit && (!isAuditeur || audit.valide))
);
};
Loading