diff --git a/changelogs/unreleased/86488_feat_ActionCard.json b/changelogs/unreleased/86488_feat_ActionCard.json
new file mode 100644
index 0000000000..5502c91b1b
--- /dev/null
+++ b/changelogs/unreleased/86488_feat_ActionCard.json
@@ -0,0 +1,5 @@
+{
+ "title": "ActionCard: add the possibility to define a quick action which is displayed above the button to see all the actions",
+ "type": "feat",
+ "packages": "ui"
+}
diff --git a/changelogs/unreleased/86488_feat_TreeView.json b/changelogs/unreleased/86488_feat_TreeView.json
new file mode 100644
index 0000000000..fa91ab2181
--- /dev/null
+++ b/changelogs/unreleased/86488_feat_TreeView.json
@@ -0,0 +1,5 @@
+{
+ "title": "TreeView: add the possibility to define additional actions on branch",
+ "type": "feat",
+ "packages": "ui"
+}
diff --git a/changelogs/unreleased/86488_refactor.json b/changelogs/unreleased/86488_refactor.json
new file mode 100644
index 0000000000..6b829b627d
--- /dev/null
+++ b/changelogs/unreleased/86488_refactor.json
@@ -0,0 +1,5 @@
+{
+ "title": "TreeView: use ActionCard for branch display",
+ "type": "refactor",
+ "packages": "ui"
+}
diff --git a/packages/core/src/components/templates/SearchTreeView/SearchTreeView.tsx b/packages/core/src/components/templates/SearchTreeView/SearchTreeView.tsx
index fbc2e25ad5..5b00261536 100644
--- a/packages/core/src/components/templates/SearchTreeView/SearchTreeView.tsx
+++ b/packages/core/src/components/templates/SearchTreeView/SearchTreeView.tsx
@@ -19,6 +19,7 @@
import React, {useCallback, useEffect, useState} from 'react';
import {StyleSheet, View} from 'react-native';
import {
+ ActionCardType,
ActionType,
AutoCompleteSearch,
HeaderContainer,
@@ -59,6 +60,7 @@ interface SearchTreeViewProps {
headerTopChildren?: any;
parentFieldName?: string;
renderBranch?: (item: any) => any;
+ getBranchActions?: (branch: any) => ActionCardType[];
renderLeaf: (item: any) => any;
actionList?: ActionType[];
verticalActions?: boolean;
@@ -94,6 +96,7 @@ const SearchTreeView = ({
headerTopChildren,
parentFieldName,
renderBranch,
+ getBranchActions,
renderLeaf,
actionList,
verticalActions,
@@ -236,6 +239,7 @@ const SearchTreeView = ({
parentFieldName={parentFieldName}
branchCardInfoButtonIndication={I18n.t('Base_Filter')}
renderBranch={renderBranch}
+ getBranchActions={getBranchActions}
renderLeaf={renderLeaf}
fetchData={fetchListAPI}
fetchBranchData={fetchBranchData}
diff --git a/packages/ui/__tests__/components/organisms/ActionCard.test.js b/packages/ui/__tests__/components/organisms/ActionCard.test.js
index c54184e0b7..f0fb9d0e5c 100644
--- a/packages/ui/__tests__/components/organisms/ActionCard.test.js
+++ b/packages/ui/__tests__/components/organisms/ActionCard.test.js
@@ -58,6 +58,18 @@ describe('ActionCard Component', () => {
expect(actionList[0].onPress).toHaveBeenCalled();
});
+ it('should render InfoButton components for quick action if present', () => {
+ const quickAction = {iconName: 'heart', onPress: jest.fn()};
+ const wrapper = shallow(
+ ,
+ );
+
+ expect(wrapper.find(InfoButton).length).toBe(actionList.length + 1);
+
+ const quickActionWrapper = wrapper.find(InfoButton).at(actionList.length);
+ expect(quickActionWrapper.props()).toMatchObject(quickAction);
+ });
+
it('should apply custom style to the container if provided', () => {
const customStyle = {width: 200};
const wrapper = shallow();
diff --git a/packages/ui/src/components/organisms/ActionCard/ActionCard.tsx b/packages/ui/src/components/organisms/ActionCard/ActionCard.tsx
index 25747e00bc..ea32bc3c0c 100644
--- a/packages/ui/src/components/organisms/ActionCard/ActionCard.tsx
+++ b/packages/ui/src/components/organisms/ActionCard/ActionCard.tsx
@@ -28,7 +28,7 @@ import {
const ACTION_WIDTH = 40;
const TWO_ACTIONS_HEIGHT = 84;
-interface Action {
+export interface Action {
iconName: string;
iconColor?: string;
helper?: string;
@@ -42,6 +42,7 @@ interface ActionCardProps {
style?: any;
children: any;
actionList: Action[];
+ quickAction?: Action;
horizontal?: boolean;
forceActionsDisplay?: boolean;
translator: (key: string) => string;
@@ -51,6 +52,7 @@ const ActionCard = ({
style,
children,
actionList,
+ quickAction,
horizontal = false,
forceActionsDisplay = false,
translator,
@@ -90,6 +92,12 @@ const ActionCard = ({
[actionList],
);
+ const _quickAction = useMemo(
+ () =>
+ quickAction != null && !quickAction.hidden ? quickAction : undefined,
+ [quickAction],
+ );
+
const isMoreThanOneAction = useMemo(
() => _actionList.length > 1,
[_actionList],
@@ -110,13 +118,14 @@ const ActionCard = ({
useEffect(() => {
const shouldDisplay =
- (_actionList.length > 2 ||
- (_actionList[0]?.large && horizontal) ||
- _actionList[1]?.large) &&
- !forceActionsDisplay;
+ (_quickAction != null && !_quickAction.large
+ ? _actionList.length > 1
+ : _actionList.length > 2 ||
+ (_actionList[0]?.large && horizontal) ||
+ _actionList[1]?.large) && !forceActionsDisplay;
setDisplaySeeActionsButton(shouldDisplay);
setIsActionsVisible(!shouldDisplay);
- }, [_actionList, forceActionsDisplay, horizontal]);
+ }, [_actionList, forceActionsDisplay, horizontal, _quickAction]);
const isCardMinHeight = useMemo(
() => _actionList.length > 1 || _actionList[0]?.large,
@@ -129,7 +138,7 @@ const ActionCard = ({
);
const getIconColor = (action: Action) => {
- return action.iconColor ?? Colors.secondaryColor_dark.background;
+ return action?.iconColor ?? Colors.secondaryColor_dark.background;
};
const renderHorizontalActions = (list, isLastList) => {
@@ -168,9 +177,7 @@ const ActionCard = ({
verticalActions.push(
{_actionList.length > 0 &&
- (displaySeeActionsButton && !isActionsVisible ? (
- setIsActionsVisible(true)}
- />
- ) : (
+ isActionsVisible &&
+ (!_quickAction || isMoreThanOneAction) && (
{horizontal ? (
<>
@@ -240,7 +240,42 @@ const ActionCard = ({
)}
- ))}
+ )}
+
+ {_quickAction != null && _actionList.length === 1 && (
+
+ )}
+ {displaySeeActionsButton && (
+ setIsActionsVisible(current => !current)}
+ />
+ )}
+ {_quickAction != null && (
+
+ )}
+
);
};
@@ -257,9 +292,6 @@ const getStyles = (isMoreThanOneAction: boolean) =>
cardContainer: {
flex: 1,
},
- seeActions: {
- width: 40,
- },
horizontalActionContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
@@ -269,13 +301,18 @@ const getStyles = (isMoreThanOneAction: boolean) =>
verticalActionContainer: {
flexDirection: 'row',
},
+ quickActionContainer: {
+ flexDirection: 'column-reverse',
+ flexWrap: 'wrap',
+ },
});
const getVerticalActionStyle = (isLargeAction: boolean) =>
StyleSheet.create({
action: {
+ width: ACTION_WIDTH,
height: isLargeAction ? '100%' : '50%',
},
- });
+ }).action;
export default ActionCard;
diff --git a/packages/ui/src/components/organisms/index.tsx b/packages/ui/src/components/organisms/index.tsx
index ab8fc63dcc..913b4316dd 100644
--- a/packages/ui/src/components/organisms/index.tsx
+++ b/packages/ui/src/components/organisms/index.tsx
@@ -16,7 +16,10 @@
* along with this program. If not, see .
*/
-export {default as ActionCard} from './ActionCard/ActionCard';
+export {
+ default as ActionCard,
+ Action as ActionCardType,
+} from './ActionCard/ActionCard';
export {default as AutoCompleteSearch} from './AutoCompleteSearch/AutoCompleteSearch';
export {default as CheckboxScrollList} from './CheckboxScrollList/CheckboxScrollList';
export {default as ChipSelect} from './ChipSelect/ChipSelect';
diff --git a/packages/ui/src/components/templates/TreeView/Branch.tsx b/packages/ui/src/components/templates/TreeView/Branch.tsx
index c507b7a995..d82c127cb5 100644
--- a/packages/ui/src/components/templates/TreeView/Branch.tsx
+++ b/packages/ui/src/components/templates/TreeView/Branch.tsx
@@ -20,6 +20,7 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {ActivityIndicator, StyleSheet, View} from 'react-native';
import {useThemeColor} from '../../../theme';
import {Label} from '../../molecules';
+import {ActionCardType} from '../../organisms';
import BranchCard from './BranchCard';
interface SubBranchViewProps {
@@ -30,11 +31,12 @@ interface SubBranchViewProps {
setOpenBranches: (current: any) => void;
branchCardInfoButtonIndication: string;
renderBranch: (renderParams: any) => any;
+ getBranchActions?: (renderParams: any) => ActionCardType[];
renderLeaf: (renderParams: any) => any;
fetchBranchData: (idParent: number) => Promise;
branchCondition: (item: any) => boolean;
onBranchFilterPress: (branch: any) => void;
- translator?: (translationKey: string) => string;
+ translator: (translationKey: string) => string;
}
const SubBranchView = ({
@@ -45,6 +47,7 @@ const SubBranchView = ({
setOpenBranches,
branchCardInfoButtonIndication,
renderBranch,
+ getBranchActions,
renderLeaf,
fetchBranchData,
branchCondition,
@@ -101,6 +104,7 @@ const SubBranchView = ({
setOpenBranches={setOpenBranches}
renderBranch={renderBranch}
branchCardInfoButtonIndication={branchCardInfoButtonIndication}
+ getBranchActions={getBranchActions}
renderLeaf={renderLeaf}
fetchBranchData={fetchBranchData}
branchCondition={branchCondition}
@@ -123,11 +127,12 @@ interface BranchProps {
setOpenBranches: (current: any) => void;
branchCardInfoButtonIndication: string;
renderBranch: (renderParams: any) => any;
+ getBranchActions?: (renderParams: any) => ActionCardType[];
renderLeaf: (renderParams: any) => any;
fetchBranchData: (idParent: number) => Promise;
branchCondition: (item: any) => boolean;
onBranchFilterPress: (branch: any) => void;
- translator?: (translationKey: string) => string;
+ translator: (translationKey: string) => string;
}
const Branch = ({
@@ -138,6 +143,7 @@ const Branch = ({
setOpenBranches,
branchCardInfoButtonIndication,
renderBranch,
+ getBranchActions,
renderLeaf,
fetchBranchData,
branchCondition,
@@ -189,6 +195,8 @@ const Branch = ({
parent={branch.item}
onFilterPress={onBranchFilterPress}
infoButtonIndication={branchCardInfoButtonIndication}
+ actionList={getBranchActions?.(branch)}
+ translator={translator}
/>
{isBranchOpen && (
void;
@@ -29,6 +28,8 @@ interface BranchCardProps {
parent: any;
onFilterPress: (branch: any) => void;
infoButtonIndication: string;
+ actionList?: ActionCardType[];
+ translator: (translationKey: string) => string;
}
const BranchCard = ({
@@ -38,42 +39,32 @@ const BranchCard = ({
parent,
onFilterPress,
infoButtonIndication,
+ actionList = [],
+ translator,
}: BranchCardProps) => {
- const Colors = useThemeColor();
-
return (
-
-
+ onFilterPress(parent),
+ }}
+ translator={translator}>
+
{children}
- onFilterPress(parent)}
- indication={infoButtonIndication}
- />
-
+
);
};
const styles = StyleSheet.create({
- container: {
- flex: 1,
- flexDirection: 'row',
- marginVertical: 2,
- marginHorizontal: 10,
- },
- cardContainer: {
- flex: 1,
- },
card: {
+ flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
@@ -81,9 +72,6 @@ const styles = StyleSheet.create({
paddingHorizontal: 15,
paddingRight: 15,
},
- infoButton: {
- width: 40,
- },
});
export default BranchCard;
diff --git a/packages/ui/src/components/templates/TreeView/TreeView.tsx b/packages/ui/src/components/templates/TreeView/TreeView.tsx
index fb5a2be920..94e881c309 100644
--- a/packages/ui/src/components/templates/TreeView/TreeView.tsx
+++ b/packages/ui/src/components/templates/TreeView/TreeView.tsx
@@ -17,7 +17,7 @@
*/
import React, {useEffect, useState} from 'react';
-import {ActionType, ScrollList} from '../../organisms';
+import {ActionCardType, ActionType, ScrollList} from '../../organisms';
import Branch from './Branch';
interface TreeViewProps {
@@ -31,6 +31,10 @@ interface TreeViewProps {
* Function used to display what is inside a branch card.
*/
renderBranch: (renderParams: any) => any;
+ /**
+ * Function used to get additional actions of a branch.
+ */
+ getBranchActions?: (renderParams: any) => ActionCardType[];
/**
* Function used to display a leaf card.
*/
@@ -51,7 +55,7 @@ interface TreeViewProps {
moreLoading: boolean;
isListEnd: boolean;
filter?: boolean;
- translator?: (translationKey: string) => string;
+ translator: (translationKey: string) => string;
disabledRefresh?: boolean;
actionList?: ActionType[];
verticalActions?: boolean;
@@ -65,6 +69,7 @@ const TreeView = ({
parentFieldName,
branchCardInfoButtonIndication,
renderBranch,
+ getBranchActions,
renderLeaf,
fetchData = () => [],
fetchBranchData,
@@ -94,6 +99,7 @@ const TreeView = ({
setOpenBranches={setOpenBranches}
renderBranch={renderBranch}
branchCardInfoButtonIndication={branchCardInfoButtonIndication}
+ getBranchActions={getBranchActions}
renderLeaf={renderLeaf}
fetchBranchData={fetchBranchData}
branchCondition={branchCondition}
diff --git a/packages/ui/stories/organisms/ActionCard.stories.tsx b/packages/ui/stories/organisms/ActionCard.stories.tsx
index 5b6c1918df..3047b700e0 100644
--- a/packages/ui/stories/organisms/ActionCard.stories.tsx
+++ b/packages/ui/stories/organisms/ActionCard.stories.tsx
@@ -17,6 +17,7 @@
*/
import React from 'react';
+import {View} from 'react-native';
import type {Meta} from '@storybook/react';
import {ActionCard as Component, Card, Text} from '../../src/components';
import {
@@ -35,47 +36,90 @@ export default meta;
export const ActionCard: Story = {
args: {
horizontal: false,
- carLarge: false,
- busColor: 'primaryColor',
- truckHidden: false,
- truckDisabled: false,
+ forceActionsDisplay: false,
+ quickAction_visible: true,
+ quickAction_iconName: 'airplane',
+ quickAction_iconColor: 'primaryColor',
+ quickAction_helper: 'Plane',
+ quickAction_isLarge: false,
+ quickAction_disabled: false,
+ action1_visible: true,
+ action1_iconName: 'car-front',
+ action1_iconColor: 'infoColor',
+ action1_helper: 'Car',
+ action1_isLarge: false,
+ action1_disabled: false,
+ action2_visible: true,
+ action2_iconName: 'bus-front',
+ action2_iconColor: 'secondaryColor_dark',
+ action2_helper: 'Bus',
+ action2_isLarge: false,
+ action2_disabled: false,
+ action3_visible: true,
+ action3_iconName: 'truck',
+ action3_iconColor: 'plannedColor',
+ action3_helper: 'Truck',
+ action3_isLarge: false,
+ action3_disabled: false,
},
argTypes: {
- busColor: colorPicker,
+ quickAction_iconColor: colorPicker,
+ action1_iconColor: colorPicker,
+ action2_iconColor: colorPicker,
+ action3_iconColor: colorPicker,
actionList: disabledControl,
- forceActionsDisplay: disabledControl,
+ quickAction: disabledControl,
translator: disabledControl,
},
render: args => (
-
- TEST
-
- }
- translator={key => key}
- {...args}
- actionList={[
- {
- iconName: 'car-front',
- helper: 'Car',
- large: args.carLarge,
+
+
+ TEST
+
+ }
+ translator={key => key}
+ {...args}
+ quickAction={{
+ iconName: args.quickAction_iconName,
+ iconColor: args.quickAction_iconColor.background,
+ helper: args.quickAction_helper,
+ large: args.quickAction_isLarge,
+ hidden: !args.quickAction_visible,
+ disabled: args.quickAction_disabled,
onPress: () => {},
- },
- {
- iconName: 'bus-front',
- iconColor: args.busColor?.background,
- helper: 'Bus',
- onPress: () => {},
- },
- {
- iconName: 'truck',
- helper: 'Truck',
- onPress: () => {},
- hidden: args.truckHidden,
- disabled: args.truckDisabled,
- },
- ]}
- />
+ }}
+ actionList={[
+ {
+ iconName: args.action1_iconName,
+ iconColor: args.action1_iconColor.background,
+ helper: args.action1_helper,
+ large: args.action1_isLarge,
+ hidden: !args.action1_visible,
+ disabled: args.action1_disabled,
+ onPress: () => {},
+ },
+ {
+ iconName: args.action2_iconName,
+ iconColor: args.action2_iconColor.background,
+ helper: args.action2_helper,
+ large: args.action2_isLarge,
+ hidden: !args.action2_visible,
+ disabled: args.action2_disabled,
+ onPress: () => {},
+ },
+ {
+ iconName: args.action3_iconName,
+ iconColor: args.action3_iconColor.background,
+ helper: args.action3_helper,
+ large: args.action3_isLarge,
+ hidden: !args.action3_visible,
+ disabled: args.action3_disabled,
+ onPress: () => {},
+ },
+ ]}
+ />
+
),
};