Skip to content

Commit bf4e61b

Browse files
committed
front: create power restriction grid modal
1 parent 8a557c5 commit bf4e61b

File tree

17 files changed

+428
-103
lines changed

17 files changed

+428
-103
lines changed

front/public/locales/en/rollingstock.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"add": "Add",
23
"addNewRollingStock": "New rolling stock",
34
"addNewTractionMode": "Add a new traction mode",
45
"basePowerClass": "Power class",

front/public/locales/en/translation.json

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"reset-north": "Reset camera",
2727
"save": "Save",
2828
"search": "Search",
29+
"selected": "already selected",
2930
"settings": "Settings",
3031
"sort": "Sort",
3132
"train(s)": "train(s)",

front/public/locales/fr/rollingstock.json

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"add": "Ajouter",
23
"addNewRollingStock": "Nouveau matériel roulant",
34
"addNewTractionMode": "Ajouter un nouveau mode de traction",
45
"basePowerClass": "Classe de puissance",

front/public/locales/fr/translation.json

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"reset-north": "Réinitialiser la caméra",
2727
"save": "Sauvegarder",
2828
"search": "Rechercher",
29+
"selected": "déjà sélectionné",
2930
"settings": "Paramètres",
3031
"sort": "Tri",
3132
"train(s)": "train(s)",
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
.d-flex .select-improved {
2-
flex-grow:4
2+
flex-grow: 4;
3+
}
4+
5+
.add-border-top {
6+
border-top: var(--coolgray3) solid 1px;
7+
border-top-right-radius: 0.4375rem;
8+
border-top-left-radius: 0.4375rem;
39
}

front/src/common/BootstrapSNCF/SelectImprovedSNCF.tsx

+36-26
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ interface SelectProps<T> {
2020
dataTestId?: string;
2121
isOpened?: boolean;
2222
setSelectVisibility?: (arg: boolean) => void;
23+
noTogglingHeader?: boolean;
2324
}
2425

2526
function SelectImproved<T extends string | SelectOptionObject>({
@@ -37,6 +38,7 @@ function SelectImproved<T extends string | SelectOptionObject>({
3738
blockMenu = false,
3839
isOpened = false,
3940
setSelectVisibility,
41+
noTogglingHeader = false,
4042
}: SelectProps<T>) {
4143
const [isOpen, setIsOpen] = useState(isOpened);
4244
const [selectedItem, setSelectedItem] = useState<T | undefined>(value);
@@ -127,36 +129,44 @@ function SelectImproved<T extends string | SelectOptionObject>({
127129
)}
128130
<div className={`select-improved ${isOpen ? 'active' : ''}`}>
129131
<div className="select-control">
130-
<div
131-
className={`input-group ${sm ? 'input-group-sm' : ''}`}
132-
tabIndex={0}
133-
role="button"
134-
onClick={() => setIsOpen(!isOpen)}
135-
>
136-
<p
137-
className={`form-control is-placeholder d-flex align-items-center ${
138-
bgWhite ? 'bg-white' : ''
139-
}`}
140-
style={sm ? { minHeight: '1.813rem' } : undefined}
132+
{!noTogglingHeader && (
133+
<div
134+
className={`input-group ${sm ? 'input-group-sm' : ''}`}
135+
tabIndex={0}
136+
role="button"
137+
onClick={() => setIsOpen(!isOpen)}
141138
>
142-
{renderSelectedItem()}
143-
</p>
144-
<div className="input-group-append input-group-last">
145-
<button
146-
className="btn btn-primary btn-only-icon"
139+
<p
140+
className={`form-control is-placeholder d-flex align-items-center ${
141+
bgWhite ? 'bg-white' : ''
142+
}`}
147143
style={sm ? { minHeight: '1.813rem' } : undefined}
148-
type="button"
149-
aria-expanded="false"
150-
aria-controls="selecttoggle"
151144
>
152-
<i
153-
className={`${isOpen ? 'icons-arrow-up' : 'icons-arrow-down'} icons-size-x75`}
154-
aria-hidden="true"
155-
/>
156-
</button>
145+
{renderSelectedItem()}
146+
</p>
147+
<div className="input-group-append input-group-last">
148+
<button
149+
className="btn btn-primary btn-only-icon"
150+
style={sm ? { minHeight: '1.813rem' } : undefined}
151+
type="button"
152+
aria-expanded="false"
153+
aria-controls="selecttoggle"
154+
>
155+
<i
156+
className={`${isOpen ? 'icons-arrow-up' : 'icons-arrow-down'} icons-size-x75`}
157+
aria-hidden="true"
158+
/>
159+
</button>
160+
</div>
157161
</div>
158-
</div>
159-
<div className={cx('select-menu', { 'position-relative': blockMenu })} id="-selecttoggle">
162+
)}
163+
<div
164+
id="-selecttoggle"
165+
className={cx('select-menu', {
166+
'add-border-top': noTogglingHeader,
167+
'position-relative': blockMenu,
168+
})}
169+
>
160170
<div className="d-flex flex-column">
161171
{withSearch && (
162172
<div className="form-control-container w-100 has-left-icon mb-3">

front/src/common/Grid.scss

+26-14
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,39 @@
55

66
.grid-item {
77
width: 77px;
8-
max-width: 77px;
9-
padding: 10px 7px;
10-
border-bottom: solid 1px gray;
11-
list-style-type: none;
12-
cursor: pointer;
8+
padding-inline: 11px 7px;
9+
padding-block: 10px;
10+
border: none;
11+
border-bottom: solid 1px var(--coolgray11);
12+
// This font allows items to be perfectly aligned as each letters have the same width
13+
font-family: monospace;
14+
color: var(--coolgray11);
15+
background-color: transparent;
16+
overflow: hidden;
17+
text-overflow: ellipsis;
18+
text-align: left;
19+
white-space: nowrap;
1320

14-
&:hover {
21+
&.filtered {
22+
opacity: 0.2;
23+
}
24+
25+
&:hover,
26+
&:focus {
1527
background-color: var(--primary);
1628
color: var(--white);
29+
// to remove browser style on focus
30+
outline: none;
1731
}
1832

19-
.grid-name {
20-
// This font allows items to be perfectly aligned as each letters have the same width
21-
font-family: monospace;
22-
overflow: hidden;
23-
text-overflow: ellipsis;
24-
white-space: nowrap;
33+
&.present:focus,
34+
&.present:hover {
35+
background-color: transparent;
2536
}
2637

27-
.filtered {
28-
opacity: 0.2;
38+
span.present {
39+
opacity: 0.7;
40+
color: var(--green);
2941
}
3042
}
3143
}

front/src/common/Grid.tsx

+37-18
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,53 @@
11
import React from 'react';
22
import cx from 'classnames';
33
import './Grid.scss';
4+
import { useTranslation } from 'react-i18next';
45

56
type GridProps = {
6-
data: string[];
7+
gridData: string[];
78
filter?: string;
89
extraClass?: string;
910
updateData: (data: string) => void;
11+
selectorData?: (string | null)[];
1012
};
1113

1214
function isFiltered(item: string, filter: string): boolean {
1315
return filter !== '' && !item.toLocaleLowerCase().includes(filter.toLocaleLowerCase());
1416
}
1517

16-
const Grid = ({ data, filter, extraClass, updateData }: GridProps) => (
17-
<div className={`grid-list ${extraClass}`}>
18-
{data.map((item, i) => (
19-
<button
20-
key={i}
21-
type="button"
22-
title={item}
23-
className={cx('grid-item', {
24-
filtered: filter && isFiltered(item, filter),
25-
})}
26-
onClick={() => updateData(item)}
27-
>
28-
{item}
29-
</button>
30-
))}
31-
</div>
32-
);
18+
function isInSelector(data: (string | null)[], item: string) {
19+
return data.includes(item);
20+
}
21+
22+
const Grid = ({ gridData, filter, extraClass, updateData, selectorData }: GridProps) => {
23+
const { t } = useTranslation('translation');
24+
return (
25+
<div className={`grid-list ${extraClass}`}>
26+
{gridData.map((item, i) => (
27+
<button
28+
key={i}
29+
type="button"
30+
disabled={selectorData && isInSelector(selectorData, item)}
31+
title={`${item} ${
32+
selectorData && isInSelector(selectorData, item) ? t('common.selected') : ''
33+
}`}
34+
className={cx('grid-item', {
35+
filtered: filter && isFiltered(item, filter),
36+
present: selectorData && isInSelector(selectorData, item),
37+
})}
38+
onClick={() => updateData(item)}
39+
>
40+
<span
41+
className={cx({
42+
present: selectorData && isInSelector(selectorData, item),
43+
})}
44+
>
45+
{item}
46+
</span>
47+
</button>
48+
))}
49+
</div>
50+
);
51+
};
3352

3453
export default Grid;

front/src/common/SelectorSNCF.tsx

+8-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,14 @@ export default function SelectorSNCF<
9191
}}
9292
key={`selector-${title}-${index}`}
9393
>
94-
<div className={`${mainClass}-item-name pt-1 pl-3`}>
94+
<div
95+
className={`${mainClass}-item-name pt-1 pl-3`}
96+
title={
97+
!isNull(item)
98+
? t(getTranslationKey(translationList, String(item)))
99+
: t('unspecified')
100+
}
101+
>
95102
{!isNull(item)
96103
? t(getTranslationKey(translationList, String(item)))
97104
: t('unspecified')}

front/src/modules/rollingStock/components/RollingStockEditor/AddRollingstockParam.tsx

+24-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import cx from 'classnames';
66
import { useTranslation } from 'react-i18next';
77
import { RiAddFill } from 'react-icons/ri';
88
import { compact } from 'lodash';
9+
import { useModal } from 'common/BootstrapSNCF/ModalSNCF';
10+
import PowerRestrictionGridModal from './PowerRestrictionGridModal';
911

1012
export default function AddRollingstockParam({
1113
listName,
@@ -22,8 +24,11 @@ export default function AddRollingstockParam({
2224
}) {
2325
const COMFORT_LEVELS_KEY: keyof RollingStockSelectorParams = 'comfortLevels';
2426
const TRACTION_MODES_KEY: keyof RollingStockSelectorParams = 'tractionModes';
27+
const POWER_RESTRICTIONS_KEY: keyof RollingStockSelectorParams = 'powerRestrictions';
2528

2629
const { t } = useTranslation('rollingstock');
30+
const { openModal } = useModal();
31+
2732
const [isSelectVisible, setIsSelectVisible] = useState(false);
2833
const isTractionModes = listName === TRACTION_MODES_KEY;
2934

@@ -45,7 +50,7 @@ export default function AddRollingstockParam({
4550
};
4651
});
4752

48-
return (
53+
return listName !== POWER_RESTRICTIONS_KEY ? (
4954
<div>
5055
<button
5156
type="button"
@@ -72,9 +77,27 @@ export default function AddRollingstockParam({
7277
bgWhite
7378
isOpened
7479
setSelectVisibility={setIsSelectVisible}
80+
noTogglingHeader
7581
/>
7682
</div>
7783
)}
7884
</div>
85+
) : (
86+
<button
87+
type="button"
88+
className="rollingstock-selector-buttons mb-2"
89+
onClick={() =>
90+
openModal(
91+
<PowerRestrictionGridModal
92+
powerRestrictionsList={allOptionsList as string[]}
93+
updatePowerRestrictions={updateDisplayedLists}
94+
currentPowerRestrictions={displayedLists.powerRestrictions}
95+
/>,
96+
'lg'
97+
)
98+
}
99+
>
100+
<RiAddFill />
101+
</button>
79102
);
80103
}

0 commit comments

Comments
 (0)