Skip to content

Commit 2071e02

Browse files
Merge pull request #275 from GovStackWorkingGroup/release-24.07.03
Release 24.07.03
2 parents 1800952 + 7795fb6 commit 2071e02

13 files changed

Lines changed: 325 additions & 69 deletions

frontend/LICENSE renamed to LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright [yyyy] [name of copyright owner]
189+
Copyright 2024 - Deutsche Gesellschaft für Internationale Zusammenarbeit (GIZ) GmbH
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ To configure and run the application, navigate to project directory - 'frontend'
1919
cd frontend
2020
```
2121

22+
#### Setup
23+
24+
Create an copy of example.env file.
25+
26+
```bash
27+
# Use default environmental variables, which can be adjusted if necessary
28+
mv .env.example .env
29+
```
30+
2231
and run the following commands:
2332

2433
```

frontend/components/shared/combined/RequirementSpecificationSelectBB.tsx

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { RefObject, useEffect, useImperativeHandle, useState } from 'react';
1+
import { RefObject, useEffect, useImperativeHandle, useRef, useState } from 'react';
22
import { useRouter } from 'next/router';
3+
import classNames from 'classnames';
34
import Pill from '../Pill';
45
import SelectInput from '../inputs/SelectInput';
56
import { ComplianceRequirementsType, SoftwareDetailsDataType, } from '../../../service/types';
@@ -9,6 +10,7 @@ import { REQUIREMENT_SPEC_STORAGE_NAME } from '../../../service/constants';
910
import IRSCFunctionalTable from '../../table/IRSC/IRSCFunctionalTable';
1011
import IRSCCrossCuttingTableType from '../../table/IRSC/IRSCCrossCuttingTable';
1112
import IRSCKeyDigitalFunctionalitiesTableType from '../../table/IRSC/IRSCKeyDigitalFunctionalitiesTable';
13+
import { handleSelectFocus } from '../../../hooks/utilities';
1214

1315
export type IRSCRequirementsFormRef = {
1416
validate: () => boolean;
@@ -63,6 +65,9 @@ const RequirementSpecificationSelectBBs = ({
6365
draftUUID: (draftUUID as string) || undefined,
6466
});
6567

68+
const selectRef = useRef<HTMLDivElement>(null);
69+
const [isSelectFocused, setIsSelectFocused] = useState(false);
70+
6671
useEffect(() => {
6772
handleAlreadySavedData();
6873
}, [draftData, savedInLocalStorage, interfaceRequirementsData]);
@@ -292,6 +297,7 @@ const RequirementSpecificationSelectBBs = ({
292297
}) => {
293298
setOptions([...options.filter(({ label }) => label !== value.label)]);
294299
setSelectedItems([...selectedItems, value.value]);
300+
setIsSelectFocused(false);
295301
};
296302

297303
const handleOnRemovePill = (item: {
@@ -468,14 +474,21 @@ const RequirementSpecificationSelectBBs = ({
468474
return (
469475
<div className="main-block">
470476
{!readOnlyView && (
471-
<SelectInput
472-
placeholder="Select Building Block(s)"
473-
className="input-select"
474-
onChange={handleOnSelect}
475-
// @ts-ignore
476-
options={options}
477-
handleSetOptions={handleSetOptions}
478-
/>
477+
<div ref={selectRef}>
478+
<SelectInput
479+
placeholder="Select Building Block(s)"
480+
className="input-select"
481+
onChange={handleOnSelect}
482+
options={options}
483+
handleSetOptions={handleSetOptions}
484+
onFocus={() => handleSelectFocus({
485+
items: selectedItems,
486+
ref: selectRef,
487+
setIsSelectFocused
488+
})}
489+
onBlur={() => setIsSelectFocused(false)}
490+
/>
491+
</div>
479492
)}
480493
{selectedItems.length > 0 ? (
481494
<div>
@@ -498,7 +511,7 @@ const RequirementSpecificationSelectBBs = ({
498511
{displayTable}
499512
</div>
500513
) : (
501-
<div>
514+
<div className={classNames({ 'height-150': (isSelectFocused && selectedItems.length === 0) })}>
502515
{format('app.view_report_details.noInformation',
503516
{ section: `${format('table.requirement_specification_compliance.label')}` })}
504517
</div>

frontend/components/shared/combined/SelectBBs.tsx

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { RefObject, useEffect, useImperativeHandle, useState } from 'react';
1+
import { RefObject, useEffect, useImperativeHandle, useRef, useState } from 'react';
22
import { useRouter } from 'next/router';
3+
import classNames from 'classnames';
34
import Pill from '../Pill';
45
import SelectInput from '../inputs/SelectInput';
56
import {
@@ -11,6 +12,7 @@ import IRSCInterfaceTable from '../../table/IRSC/IRSCInterfaceTable';
1112
import useTranslations from '../../../hooks/useTranslation';
1213
import useGetDraftData from '../../../hooks/useGetDraftDetail';
1314
import { INTERFACE_COMPLIANCE_STORAGE_NAME } from '../../../service/constants';
15+
import { handleSelectFocus } from '../../../hooks/utilities';
1416

1517
export type IRSCFormRef = {
1618
validate: () => boolean;
@@ -54,6 +56,9 @@ const SelectBBs = ({
5456
draftUUID: (draftUUID as string) || undefined,
5557
});
5658

59+
const selectRef = useRef<HTMLDivElement>(null);
60+
const [isSelectFocused, setIsSelectFocused] = useState(false);
61+
5762
useEffect(() => {
5863
handleAlreadySavedData();
5964
}, [draftData, interfaceRequirementsData, readOnlyData]);
@@ -401,14 +406,21 @@ const SelectBBs = ({
401406
return (
402407
<div className="main-block">
403408
{!readOnlyView && (
404-
<SelectInput
405-
placeholder="Select Building Block(s)"
406-
className="input-select"
407-
onChange={handleOnSelect}
408-
// @ts-ignore
409-
options={options}
410-
handleSetOptions={handleSetOptions}
411-
/>
409+
<div ref={selectRef}>
410+
<SelectInput
411+
placeholder="Select Building Block(s)"
412+
className="input-select"
413+
onChange={handleOnSelect}
414+
options={options}
415+
handleSetOptions={handleSetOptions}
416+
onFocus={() => handleSelectFocus({
417+
items: selectedItems,
418+
ref: selectRef,
419+
setIsSelectFocused
420+
})}
421+
onBlur={() => setIsSelectFocused(false)}
422+
/>
423+
</div>
412424
)}
413425
{selectedItems.length > 0 ? (
414426
<div>
@@ -430,7 +442,7 @@ const SelectBBs = ({
430442
{displayTable}
431443
</div>
432444
) : (
433-
<div>
445+
<div className={classNames({ 'height-150': (isSelectFocused && selectedItems.length === 0) })}>
434446
{format('app.view_report_details.noInformation',
435447
{ section: `${format('table.interface_compliance.label')}` })}
436448
</div>

frontend/components/shared/inputs/Inputs.less

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ margin-right: 20px;
249249
width: min-content;
250250
}
251251

252+
.height-150 {
253+
height: 150px;
254+
}
255+
252256
.dropdown-circle {
253257

254258
font-family: 'Arial';

frontend/components/shared/inputs/SelectInput.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ import { InputOptionsProps } from '../../../service/types';
77
type SelectProps = {
88
onChange: (args0: any) => void;
99
onBlur?: () => void;
10+
onFocus?: () => void;
1011
placeholder: string;
1112
className?: string;
12-
options:
13-
| OptionsOrGroups<InputOptionsProps[], GroupBase<InputOptionsProps[]>>
14-
| undefined;
13+
options: InputOptionsProps[];
1514
handleSetOptions: () => void;
1615
};
1716

1817
const SelectInput = ({
1918
onBlur,
19+
onFocus,
2020
placeholder,
2121
className,
2222
onChange,
@@ -34,6 +34,7 @@ const SelectInput = ({
3434
onBlur={onBlur}
3535
classNamePrefix="react-select"
3636
className={classNames(className)}
37+
onFocus={onFocus}
3738
/>
3839
);
3940
};

frontend/components/table/IRSC/IRSCCrossCuttingTable.tsx

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
FaCircleXmark,
88
FaRegCircleXmark,
99
} from 'react-icons/fa6';
10+
import { RiArrowDownSLine, RiArrowUpSLine } from 'react-icons/ri';
1011
import {
1112
ComplianceRequirementsType,
1213
IRSCTableType,
@@ -34,6 +35,9 @@ const IRSCCrossCuttingTableType = ({
3435
const [filledRequired, setFilledRequired] = useState<number>(0);
3536
const [filledRecommended, setFilledRecommended] = useState<number>(0);
3637
const [filledOptional, setFilledOptional] = useState<number>(0);
38+
const [isRequirementExpanded, setIsRequirementExpanded] = useState<boolean>(false);
39+
40+
const handleRequirementExpand = () => setIsRequirementExpanded(!isRequirementExpanded);
3741

3842
useEffect(() => {
3943
setUpdatedData(data);
@@ -257,13 +261,15 @@ const IRSCCrossCuttingTableType = ({
257261
{...row.getRowProps()}
258262
key={`row-${indexKey}`}
259263
className={`irsc-table-rows ${
260-
!isTableValid &&
261-
(row.values.fulfillment === undefined ||
262-
row.values.fulfillment === null ||
263-
row.values.fulfillment === -1)
264-
? 'irsc-invalid-row'
265-
: ''
266-
}`}
264+
!isTableValid &&
265+
(row.values.fulfillment === undefined ||
266+
row.values.fulfillment === null ||
267+
row.values.fulfillment === -1)
268+
? 'irsc-invalid-row'
269+
: ''
270+
}
271+
${(!isRequirementExpanded) ? 'irsc-table-row-collapse' : ''}
272+
`}
267273
>
268274
<TableCells row={row}/>
269275
</tr>
@@ -272,7 +278,12 @@ const IRSCCrossCuttingTableType = ({
272278
})}
273279
{rows.some((item) => item.original.status === 1) && (
274280
<tr>
275-
<td className="irsc-table-header-required" colSpan={3}>
281+
<td className={classNames(
282+
'irsc-table-header-required',
283+
{ 'irsc-table-row-collapse': !isRequirementExpanded }
284+
)}
285+
colSpan={3}
286+
>
276287
{`${format('table.recommended_not_required.label')} ${filledRecommended}/${recommendedNumber}`}
277288
</td>
278289
</tr>
@@ -284,7 +295,10 @@ const IRSCCrossCuttingTableType = ({
284295
<tr
285296
{...row.getRowProps()}
286297
key={`row-${indexKey}`}
287-
className="irsc-table-rows"
298+
className={classNames(
299+
'irsc-table-rows',
300+
{ 'irsc-table-row-collapse': !isRequirementExpanded }
301+
)}
288302
>
289303
<TableCells row={row}/>
290304
</tr>
@@ -293,7 +307,12 @@ const IRSCCrossCuttingTableType = ({
293307
})}
294308
{rows.some((item) => item.original.status === 2) && (
295309
<tr>
296-
<td className="irsc-table-header-required" colSpan={3}>
310+
<td className={classNames(
311+
'irsc-table-header-required',
312+
{ 'irsc-table-row-collapse': !isRequirementExpanded }
313+
)}
314+
colSpan={3}
315+
>
297316
{`${format('table.optional_not_required.label')} ${filledOptional}/${optionalNumber}`}
298317
</td>
299318
</tr>
@@ -305,13 +324,38 @@ const IRSCCrossCuttingTableType = ({
305324
<tr
306325
{...row.getRowProps()}
307326
key={`row-${indexKey}`}
308-
className="irsc-table-rows"
327+
className={classNames(
328+
'irsc-table-rows',
329+
{ 'irsc-table-row-collapse': !isRequirementExpanded }
330+
)}
309331
>
310332
<TableCells row={row}/>
311333
</tr>
312334
);
313335
}
314336
})}
337+
<tr>
338+
<td
339+
colSpan={3}
340+
className="irsc-table-header-required irsc-table-collapse-expand"
341+
onClick={handleRequirementExpand}
342+
>
343+
{isRequirementExpanded
344+
? <div className='irsc-table-collapse-expand-body'>
345+
<span className='irsc-table-arrow'>
346+
<RiArrowUpSLine/>
347+
</span>
348+
{format('table.collapse_requirements.label')}
349+
</div>
350+
: <div className='irsc-table-collapse-expand-body'>
351+
<span className='irsc-table-arrow'>
352+
<RiArrowDownSLine/>
353+
</span>
354+
{format('table.expand_requirements.label')}
355+
</div>
356+
}
357+
</td>
358+
</tr>
315359
</tbody>
316360
</table>
317361
</div>

0 commit comments

Comments
 (0)