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

[TC-910] Separate unable to join #458

Merged
merged 3 commits into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 26 additions & 22 deletions frontend/src/components/recommitment/RecommitmentFormBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,8 @@
const [parQDownloaded, setParQDownloaded] = useState(false);

const [unableToJoinReasons, setUnableToJoinReasons] = useState<{
selectedReasons: string[];
otherReason: string;
}>({
selectedReasons: [],
otherReason: '',
});
[key in Program]?: { selectedReasons: string[]; otherReason: string };
}>({});
const [assertionsChecked, setAssertionsChecked] = useState<boolean>(false);

const isDeclarationComplete = (): boolean => {
Expand Down Expand Up @@ -269,12 +265,18 @@
}, [recommitmentAnswer]);

const handleSubmitRecommitment = async () => {
const selectedReasons = unableToJoinReasons.selectedReasons.map(
(r) => reasonDefinitions[r as keyof typeof reasonDefinitions],
);
const reasons = [...selectedReasons, unableToJoinReasons.otherReason].join(', ');
const currentYear = new Date().getFullYear();

Check warning on line 268 in frontend/src/components/recommitment/RecommitmentFormBase.tsx

View workflow job for this annotation

GitHub Actions / lint

React Hook useEffect has a missing dependency: 'getSteps'. Either include it or remove the dependency array

const getReasons = (program: Program) => {
const selectedReasons = (unableToJoinReasons[program]?.selectedReasons || []).map(
(r) => reasonDefinitions[r as keyof typeof reasonDefinitions],
).filter(r => !!r);
if (unableToJoinReasons[program]?.otherReason) {
return [...selectedReasons, unableToJoinReasons[program]?.otherReason].join('; ');
}
return selectedReasons.join('; ');
}

const createDecision = (
status: RecommitmentStatus,
programType: Program,
Expand All @@ -283,8 +285,7 @@
status,
year: currentYear,
program: programType,

...(includeReason && { memberReason: reasons }),
...(includeReason && { memberReason: getReasons(programType) }),
});

const decisionMap = {
Expand Down Expand Up @@ -318,6 +319,7 @@

const decision =
decisionMap[recommitmentAnswer as keyof typeof decisionMap] || {};
console.log(decision);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

console.log

await updateRecommitment(personnel.id, { ...decision, supervisorInformation });
onClose();
};
Expand Down Expand Up @@ -385,24 +387,26 @@
const nextClickable = (): boolean => {
const currentComponentType = currentComponent.type;

// For InitialRecommitmentDropdown, require a selection
if (currentComponentType === InitialRecommitmentDropdown) {
return recommitmentAnswer !== undefined;
}

// For UnableToJoin, require at least one reason selected and other reason text if 'other' is selected
if (currentComponentType === UnableToJoin) {
const hasSelectedReasons = unableToJoinReasons.selectedReasons.length > 0;
const needsOtherReason = unableToJoinReasons.selectedReasons.includes('other');

if (!hasSelectedReasons) {
const programs = Object.keys(unableToJoinReasons);
if (programs.length === 0) {
return false;
}

if (needsOtherReason && !unableToJoinReasons.otherReason.trim()) {
return false;
for (const program of programs) {
if ((unableToJoinReasons[program as Program]?.selectedReasons || []).length === 0) {
return false;
}
if (
(unableToJoinReasons[program as Program]?.selectedReasons || []).includes('other') &&
!unableToJoinReasons[program as Program]?.otherReason?.trim()
) {
return false;
}
}

return true;
}

Expand Down
151 changes: 88 additions & 63 deletions frontend/src/components/recommitment/UnableToJoin.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import { Program } from '@/common';
import { useState } from 'react';
import { useEffect, useState } from 'react';

interface Reason {
id: string;
text: string;
}
export interface SupervisorInformation {
email: string;

firstName: string;

lastName: string;

phone?: string;
}

Expand All @@ -25,83 +22,111 @@
{ id: 'leave', text: 'Extended leave (e.g. Annual, Sickness, Maternity, etc.)' },
{ id: 'other', text: 'Other reasons' },
];

interface UnableToJoinProps {
program: string;
onUpdate: (data: { selectedReasons: string[]; otherReason: string }) => void;
program: Program;
onUpdate: (data: {
[key in Program]?: { selectedReasons: string[]; otherReason: string };
}) => void;
}

export const UnableToJoin = ({ program, onUpdate }: UnableToJoinProps) => {
const [selectedReasons, setSelectedReasons] = useState<string[]>([]);
const [otherReason, setOtherReason] = useState('');
const programs = program === Program.ALL ? [Program.BCWS, Program.EMCR] : [program];
const [reasons, setReasons] = useState<{
[key in Program]?: {
selectedReasons: string[];
otherReason: string;
}
}>(() => {
const initialReasons: { [key in Program]?: { selectedReasons: string[]; otherReason: string } } = {};
programs.forEach((prog) => {
initialReasons[prog] = { selectedReasons: [], otherReason: '' };
});
return initialReasons;
});

const handleCheckboxChange = (reasonId: string) => {
setSelectedReasons((prev) => {
const newReasons = prev.includes(reasonId)
? prev.filter((id) => id !== reasonId)
: [...prev, reasonId];
useEffect(() => {
onUpdate(reasons);
}, [reasons]);

// If unchecking 'other', clear the textarea
if (reasonId === 'other' && prev.includes(reasonId)) {
setOtherReason('');
onUpdate({ selectedReasons: newReasons, otherReason: '' });
} else {
onUpdate({ selectedReasons: newReasons, otherReason });
}
const handleCheckboxChange = (program: Program, reasonId: string) => {
setReasons((prev) => {

Check warning on line 52 in frontend/src/components/recommitment/UnableToJoin.tsx

View workflow job for this annotation

GitHub Actions / lint

React Hook useEffect has a missing dependency: 'onUpdate'. Either include it or remove the dependency array. If 'onUpdate' changes too often, find the parent component that defines it and wrap that definition in useCallback
const programPreviousReasons = prev[program]?.selectedReasons || [];
const newReasons = programPreviousReasons.includes(reasonId)
? programPreviousReasons.filter((id) => id !== reasonId)
: [...programPreviousReasons, reasonId];

const otherReason = reasonId === 'other' && programPreviousReasons.includes(reasonId) ?
'' :
prev[program]?.otherReason || '';

return newReasons;
return {
...prev,
[program]: {
selectedReasons: newReasons,
otherReason,
},
};
});
};

const handleOtherReasonChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
const newOtherReason = e.target.value;
setOtherReason(newOtherReason);
onUpdate({ selectedReasons, otherReason: newOtherReason });
const handleOtherReasonChange = (program: Program, newOtherReason: string) => {
setReasons((prev) => {
const programPreviousReasons = prev[program]?.selectedReasons || [];
return {
...prev,
[program]: {
...prev[program],

Check failure on line 78 in frontend/src/components/recommitment/UnableToJoin.tsx

View workflow job for this annotation

GitHub Actions / lint

'programPreviousReasons' is assigned a value but never used
otherReason: newOtherReason,
},
}
});
};

return (
<div className="px-8 min-h-[500px]">
<h6 className="text-sm font-semibold mb-4">
I am unable to join
{program !== Program.ALL ? ` ${program.toUpperCase()} ` : ' '}this year
because:
</h6>
{programs.map(program => (
<div className="py-2">
<h6 className="text-sm font-semibold mb-4">
I am unable to join {program.toUpperCase()} because:
</h6>

Check failure on line 92 in frontend/src/components/recommitment/UnableToJoin.tsx

View workflow job for this annotation

GitHub Actions / lint

Missing "key" prop for element in iterator
<div className="space-y-4">
{REASONS.map((reason) => (
<div key={reason.id}>
<div className="flex items-center">
<input
type="checkbox"
id={reason.id}
checked={selectedReasons.includes(reason.id)}
onChange={() => handleCheckboxChange(reason.id)}
className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<label
htmlFor={reason.id}
className="ml-3 text-sm font-medium text-gray-700"
>
{reason.text}
</label>
</div>
<div className="space-y-4">
{REASONS.map((reason) => (
<div key={`${program}-${reason.id}`}>
<div className="flex items-center">
<input
type="checkbox"
id={`${program}-${reason.id}`}
checked={(reasons[program as Program]?.selectedReasons || []).includes(reason.id)}
onChange={() => handleCheckboxChange(program as Program, reason.id)}
className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<label
htmlFor={`${program}-${reason.id}`}
className="ml-3 text-sm font-medium text-gray-700"
>
{reason.text}
</label>
</div>

{reason.id === 'other' && selectedReasons.includes('other') && (
<div className="mt-6 ml-7">
<p className="text-sm font-semibold pb-2">Please provide details for &quot;Other reasons&quot;.<span className="text-red-900">*</span></p>
<textarea
id="otherReason"
value={otherReason}
onChange={handleOtherReasonChange}
placeholder="Add a comment"
rows={3}
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 text-sm"
/>
{reason.id === 'other' && (reasons[program as Program]?.selectedReasons || []).includes('other') && (
<div className="mt-6 ml-7">
<p className="text-sm font-semibold pb-2">Please provide details for &quot;Other reasons&quot;.<span className="text-red-900">*</span></p>
<textarea
id={`${program}-otherReason`}
value={reasons[program as Program]?.otherReason || ''}
onChange={(e) => handleOtherReasonChange(program as Program, e.target.value)}
placeholder="Add a comment"
rows={3}
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 text-sm"
/>
</div>
)}
</div>
)}
))}
</div>
))}
</div>
</div>
))}
</div>
);
};
1 change: 1 addition & 0 deletions frontend/src/hooks/profileData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,7 @@ export const memberData = (personnel?: Personnel) => {
href="https://intranet.gov.bc.ca/assets/intranet/bcws-intranet/wildfire-teams/documents/core_team_guidelines.pdf"
target="_blank"
rel="noreferrer"
className="text-blue-700 underline"
>
CORE Team Guidelines
</a>
Expand Down
Loading