@transferwise/components 0.0.0-experimental-37390a6 → 0.0.0-experimental-833aa39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/card/Card.js +13 -20
- package/build/card/Card.js.map +1 -1
- package/build/card/Card.mjs +14 -21
- package/build/card/Card.mjs.map +1 -1
- package/build/common/Option/Option.js.map +1 -1
- package/build/common/Option/Option.mjs.map +1 -1
- package/build/i18n/en.json +1 -0
- package/build/i18n/en.json.js +1 -0
- package/build/i18n/en.json.js.map +1 -1
- package/build/i18n/en.json.mjs +1 -0
- package/build/i18n/en.json.mjs.map +1 -1
- package/build/main.css +6 -0
- package/build/styles/main.css +6 -0
- package/build/styles/upload/Upload.css +6 -0
- package/build/types/card/Card.d.ts.map +1 -1
- package/build/types/common/Option/Option.d.ts +0 -2
- package/build/types/common/Option/Option.d.ts.map +1 -1
- package/build/types/upload/Upload.d.ts +1 -0
- package/build/types/upload/Upload.d.ts.map +1 -1
- package/build/types/upload/Upload.messages.d.ts +4 -0
- package/build/types/upload/Upload.messages.d.ts.map +1 -1
- package/build/types/upload/steps/completeStep/completeStep.d.ts +1 -3
- package/build/types/upload/steps/completeStep/completeStep.d.ts.map +1 -1
- package/build/types/upload/steps/uploadImageStep/uploadImageStep.d.ts +1 -0
- package/build/types/upload/steps/uploadImageStep/uploadImageStep.d.ts.map +1 -1
- package/build/upload/Upload.js +18 -4
- package/build/upload/Upload.js.map +1 -1
- package/build/upload/Upload.messages.js +3 -0
- package/build/upload/Upload.messages.js.map +1 -1
- package/build/upload/Upload.messages.mjs +3 -0
- package/build/upload/Upload.messages.mjs.map +1 -1
- package/build/upload/Upload.mjs +18 -4
- package/build/upload/Upload.mjs.map +1 -1
- package/build/upload/steps/completeStep/completeStep.js +15 -30
- package/build/upload/steps/completeStep/completeStep.js.map +1 -1
- package/build/upload/steps/completeStep/completeStep.mjs +16 -31
- package/build/upload/steps/completeStep/completeStep.mjs.map +1 -1
- package/build/upload/steps/uploadImageStep/uploadImageStep.js +27 -1
- package/build/upload/steps/uploadImageStep/uploadImageStep.js.map +1 -1
- package/build/upload/steps/uploadImageStep/uploadImageStep.mjs +27 -1
- package/build/upload/steps/uploadImageStep/uploadImageStep.mjs.map +1 -1
- package/package.json +4 -4
- package/src/card/Card.spec.tsx +3 -35
- package/src/card/Card.story.tsx +40 -56
- package/src/card/Card.tsx +14 -32
- package/src/common/Option/Option.tsx +0 -2
- package/src/i18n/en.json +1 -0
- package/src/main.css +6 -0
- package/src/upload/Upload.css +6 -0
- package/src/upload/Upload.less +5 -0
- package/src/upload/Upload.messages.ts +4 -0
- package/src/upload/Upload.spec.js +8 -7
- package/src/upload/Upload.story.tsx +1 -0
- package/src/upload/Upload.tsx +27 -8
- package/src/upload/steps/completeStep/completeStep.spec.js +0 -8
- package/src/upload/steps/completeStep/completeStep.tsx +14 -29
- package/src/upload/steps/uploadImageStep/uploadImageStep.spec.js +12 -0
- package/src/upload/steps/uploadImageStep/uploadImageStep.tsx +22 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transferwise/components",
|
|
3
|
-
"version": "0.0.0-experimental-
|
|
3
|
+
"version": "0.0.0-experimental-833aa39",
|
|
4
4
|
"description": "Neptune React components",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -93,12 +93,12 @@
|
|
|
93
93
|
"rollup-preserve-directives": "^1.1.1",
|
|
94
94
|
"storybook": "^8.2.2",
|
|
95
95
|
"@transferwise/less-config": "3.1.0",
|
|
96
|
-
"@
|
|
97
|
-
"@
|
|
96
|
+
"@transferwise/neptune-css": "0.0.0-experimental-833aa39",
|
|
97
|
+
"@wise/components-theming": "1.5.0"
|
|
98
98
|
},
|
|
99
99
|
"peerDependencies": {
|
|
100
100
|
"@transferwise/icons": "^3.7.0",
|
|
101
|
-
"@transferwise/neptune-css": "
|
|
101
|
+
"@transferwise/neptune-css": "0.0.0-experimental-833aa39",
|
|
102
102
|
"@wise/art": "^2.7.0",
|
|
103
103
|
"@wise/components-theming": "^1.0.0",
|
|
104
104
|
"react": ">=18",
|
package/src/card/Card.spec.tsx
CHANGED
|
@@ -104,49 +104,17 @@ describe('Card', () => {
|
|
|
104
104
|
expect(screen.getByTestId('chevron-up-icon')).toHaveClass(Position.BOTTOM);
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
describe('when collapsed', () => {
|
|
109
|
-
const CONTENT = 'mock children';
|
|
110
|
-
|
|
111
|
-
it('should not render children', async () => {
|
|
112
|
-
renderCard({ children: CONTENT });
|
|
113
|
-
expect(screen.queryByText(CONTENT)).not.toBeInTheDocument();
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should render appropriate aria attributes', async () => {
|
|
117
|
-
renderCard({ children: CONTENT });
|
|
118
|
-
const button = screen.getByRole('button');
|
|
119
|
-
expect(button).toHaveAttribute('aria-expanded', 'false')
|
|
120
|
-
expect(button).not.toHaveAttribute('aria-controls')
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
107
|
describe('when expanded', () => {
|
|
125
|
-
const defaultProps = {
|
|
126
|
-
children: 'mock children',
|
|
127
|
-
isExpanded: true,
|
|
128
|
-
};
|
|
129
|
-
|
|
130
108
|
it('flips chevron', () => {
|
|
131
|
-
renderCard(
|
|
109
|
+
renderCard({ children: 'mock children', isExpanded: true });
|
|
132
110
|
|
|
133
111
|
expect(screen.getByTestId('chevron-up-icon')).toHaveClass(Position.TOP);
|
|
134
112
|
});
|
|
135
113
|
|
|
136
114
|
it('renders children', () => {
|
|
137
|
-
renderCard(
|
|
138
|
-
|
|
139
|
-
expect(screen.getByText(defaultProps.children)).toBeInTheDocument();
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('should render appropriate aria attributes', async () => {
|
|
143
|
-
const {container} = renderCard(defaultProps);
|
|
144
|
-
const button = screen.getByRole('button');
|
|
145
|
-
const controlledId = button.getAttribute('aria-controls');
|
|
146
|
-
expect(button).toHaveAttribute('aria-expanded', 'true')
|
|
115
|
+
renderCard({ children: 'mock children', isExpanded: true });
|
|
147
116
|
|
|
148
|
-
|
|
149
|
-
expect(contentId).toBe(controlledId);
|
|
117
|
+
expect(screen.getByText('mock children')).toBeInTheDocument();
|
|
150
118
|
});
|
|
151
119
|
});
|
|
152
120
|
});
|
package/src/card/Card.story.tsx
CHANGED
|
@@ -1,70 +1,54 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { select, text } from '@storybook/addon-knobs';
|
|
2
2
|
import { FastFlag as FastFlagIcon } from '@transferwise/icons';
|
|
3
3
|
import { useState } from 'react';
|
|
4
|
-
import { fn } from '@storybook/test';
|
|
5
4
|
|
|
6
5
|
import Card from '.';
|
|
7
|
-
|
|
8
|
-
type Story = StoryObj<typeof Card>;
|
|
6
|
+
import { CardProps } from './Card';
|
|
9
7
|
|
|
10
8
|
export default {
|
|
11
9
|
component: Card,
|
|
12
10
|
title: 'Layouts/Card',
|
|
13
|
-
args: {
|
|
14
|
-
title: 'A card',
|
|
15
|
-
details: 'Some details about this card',
|
|
16
|
-
children: 'Lorem ipsum dolor sit amet.',
|
|
17
|
-
onClick: fn(),
|
|
18
|
-
as: 'div',
|
|
19
|
-
},
|
|
20
|
-
tags: ['autodocs'],
|
|
21
|
-
} satisfies Meta<typeof Card>;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export const Basic: Story = {
|
|
25
|
-
render: function Render(args) {
|
|
26
|
-
const [isExpanded, setIsExpanded] = useState(false);
|
|
27
|
-
|
|
28
|
-
const handleClick = (isCurrentExpanded: boolean) => {
|
|
29
|
-
setIsExpanded(isCurrentExpanded)
|
|
30
|
-
args?.onClick?.(!isExpanded);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return <Card {...args} isExpanded={isExpanded} onClick={handleClick} />;
|
|
34
|
-
}
|
|
35
11
|
};
|
|
36
12
|
|
|
13
|
+
const Template = (props: Pick<CardProps, 'isExpanded' | 'icon' | 'onClick'>) => {
|
|
14
|
+
const elementType = select('elementType', ['div', 'li'], 'div');
|
|
15
|
+
const title = text('title', 'A card');
|
|
16
|
+
const details = text('details', 'Some details about this card');
|
|
17
|
+
const content = text('content', 'Lorem ipsum dolor sit amet.');
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Card as={elementType} title={title} details={details} {...props}>
|
|
21
|
+
{content}
|
|
22
|
+
</Card>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
37
25
|
|
|
38
|
-
export const
|
|
39
|
-
|
|
40
|
-
const [expandedCardIndex, setExpandedCardIndex] = useState<number | null>(0);
|
|
26
|
+
export const Basic = () => {
|
|
27
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
41
28
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
setExpandedCardIndex(index !== expandedCardIndex ? index : null);
|
|
45
|
-
};
|
|
29
|
+
return <Template isExpanded={isExpanded} onClick={setIsExpanded} />;
|
|
30
|
+
};
|
|
46
31
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
32
|
+
export const Multiple = () => {
|
|
33
|
+
const [expandedCardIndex, setExpandedCardIndex] = useState<number | null>(0);
|
|
34
|
+
|
|
35
|
+
const handleOnCardClick = (index: number) => {
|
|
36
|
+
setExpandedCardIndex(index !== expandedCardIndex ? index : null);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<>
|
|
41
|
+
<Template
|
|
42
|
+
icon={<FastFlagIcon />}
|
|
43
|
+
isExpanded={expandedCardIndex === 0}
|
|
44
|
+
onClick={() => handleOnCardClick(0)}
|
|
45
|
+
/>
|
|
46
|
+
<Template
|
|
47
|
+
icon={<FastFlagIcon />}
|
|
48
|
+
isExpanded={expandedCardIndex === 1}
|
|
49
|
+
onClick={() => handleOnCardClick(1)}
|
|
50
|
+
/>
|
|
51
|
+
<Template isExpanded={expandedCardIndex === 2} onClick={() => handleOnCardClick(2)} />
|
|
52
|
+
</>
|
|
53
|
+
);
|
|
70
54
|
};
|
package/src/card/Card.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { clsx } from 'clsx';
|
|
2
|
-
import { forwardRef
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
3
|
|
|
4
4
|
import Body from '../body';
|
|
5
5
|
import Chevron from '../chevron';
|
|
@@ -40,16 +40,13 @@ const Card = forwardRef(function Card(
|
|
|
40
40
|
}: CardProps,
|
|
41
41
|
reference,
|
|
42
42
|
) {
|
|
43
|
-
const
|
|
44
|
-
const contentId = useId();
|
|
45
|
-
const isExpandable = Boolean(children);
|
|
46
|
-
|
|
43
|
+
const isOpen = !!(isExpanded && children);
|
|
47
44
|
|
|
48
45
|
return (
|
|
49
46
|
<Element
|
|
50
47
|
ref={reference}
|
|
51
48
|
className={clsx('np-card', className, {
|
|
52
|
-
'np-card--expanded':
|
|
49
|
+
'np-card--expanded': isOpen,
|
|
53
50
|
'np-card--inactive': !children,
|
|
54
51
|
'np-card--has-icon': !!icon,
|
|
55
52
|
})}
|
|
@@ -57,38 +54,23 @@ const Card = forwardRef(function Card(
|
|
|
57
54
|
data-testid={dataTestId}
|
|
58
55
|
>
|
|
59
56
|
<Option
|
|
60
|
-
aria-expanded={isExpandable ? isExpanded : undefined}
|
|
61
|
-
aria-controls={isExpanded ? contentId : undefined}
|
|
62
|
-
id={labelId}
|
|
63
57
|
aria-label={ariaLabel}
|
|
64
|
-
as={
|
|
65
|
-
className=
|
|
58
|
+
as={children ? 'button' : 'div'}
|
|
59
|
+
className={clsx('np-card__button')}
|
|
66
60
|
media={icon}
|
|
67
61
|
title={title}
|
|
68
62
|
content={details}
|
|
69
63
|
showMediaAtAllSizes
|
|
70
|
-
button={
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
onClick={isExpandable ? () => onClick?.(!isExpanded) : undefined}
|
|
64
|
+
button={children && <Chevron orientation={isOpen ? Position.TOP : Position.BOTTOM} />}
|
|
65
|
+
onClick={children ? () => onClick?.(!isExpanded) : undefined}
|
|
74
66
|
/>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
)}
|
|
83
|
-
|
|
84
|
-
{isExpandable && isExpanded && (
|
|
85
|
-
<Body
|
|
86
|
-
as="div"
|
|
87
|
-
type={Typography.BODY_LARGE}
|
|
88
|
-
className={clsx('np-card__content', isExpanded ? 'd-block' : 'hide')}
|
|
89
|
-
id={contentId}
|
|
90
|
-
aria-labelledby={labelId}
|
|
91
|
-
>
|
|
67
|
+
<div
|
|
68
|
+
className={clsx('np-card__divider', {
|
|
69
|
+
'np-card__divider--expanded': isOpen,
|
|
70
|
+
})}
|
|
71
|
+
/>
|
|
72
|
+
{isOpen && (
|
|
73
|
+
<Body as="span" type={Typography.BODY_LARGE} className="np-card__content d-block">
|
|
92
74
|
{children}
|
|
93
75
|
</Body>
|
|
94
76
|
)}
|
|
@@ -6,8 +6,6 @@ import { LinkProps } from '../commonProps';
|
|
|
6
6
|
|
|
7
7
|
export interface BaseOptionProps extends Omit<HTMLAttributes<HTMLElement>, 'title' | 'content'> {
|
|
8
8
|
'aria-label'?: string;
|
|
9
|
-
'aria-expanded'?: boolean;
|
|
10
|
-
'aria-controls'?: string;
|
|
11
9
|
media?: ReactNode;
|
|
12
10
|
name?: string;
|
|
13
11
|
htmlFor?: string;
|
package/src/i18n/en.json
CHANGED
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"neptune.Upload.csWrongTypeMessage": "File type not supported. Please try again with a different file",
|
|
36
36
|
"neptune.Upload.psButtonText": "Cancel",
|
|
37
37
|
"neptune.Upload.psProcessingText": "Uploading...",
|
|
38
|
+
"neptune.Upload.retry": "Retry",
|
|
38
39
|
"neptune.Upload.usButtonText": "Or select a file",
|
|
39
40
|
"neptune.Upload.usDropMessage": "Drop file to start upload",
|
|
40
41
|
"neptune.Upload.usPlaceholder": "Drag and drop a file less than {maxSize}MB",
|
package/src/main.css
CHANGED
|
@@ -5444,6 +5444,12 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
5444
5444
|
.tw-droppable-sm {
|
|
5445
5445
|
min-height: 245px;
|
|
5446
5446
|
}
|
|
5447
|
+
.upload-error-message {
|
|
5448
|
+
margin-top: 24px;
|
|
5449
|
+
margin-top: var(--padding-medium);
|
|
5450
|
+
border-top: 1px solid rgba(0,0,0,0.10196);
|
|
5451
|
+
border-top: 1px solid var(--color-border-neutral);
|
|
5452
|
+
}
|
|
5447
5453
|
.np-upload-button-container {
|
|
5448
5454
|
border-style: solid;
|
|
5449
5455
|
}
|
package/src/upload/Upload.css
CHANGED
package/src/upload/Upload.less
CHANGED
|
@@ -46,6 +46,7 @@ const props = {
|
|
|
46
46
|
psProcessingText: 'psProcessingText',
|
|
47
47
|
usAccept: 'image/*',
|
|
48
48
|
usButtonText: 'Or Select File',
|
|
49
|
+
usButtonRetryText: 'Try again',
|
|
49
50
|
usDropMessage: 'Drop file to start upload',
|
|
50
51
|
usPlaceholder: 'Drag and drop a file less than 5MB',
|
|
51
52
|
};
|
|
@@ -231,7 +232,7 @@ describe('Upload', () => {
|
|
|
231
232
|
expect(component.find(CompleteStep)).toHaveLength(1);
|
|
232
233
|
});
|
|
233
234
|
|
|
234
|
-
it('step
|
|
235
|
+
it('step UploadImageStep is called with error props', async () => {
|
|
235
236
|
component = mount(<Upload {...props} />);
|
|
236
237
|
const upload = component.children();
|
|
237
238
|
asyncFileRead.mockImplementation(async () => {
|
|
@@ -244,12 +245,12 @@ describe('Upload', () => {
|
|
|
244
245
|
await waitForUpload();
|
|
245
246
|
component.update();
|
|
246
247
|
|
|
247
|
-
expect(component.find(
|
|
248
|
-
...
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
248
|
+
expect(component.find(UploadImageStep).props()).toStrictEqual({
|
|
249
|
+
...UPLOADIMAGE_STEP_PROPS,
|
|
250
|
+
isComplete: false,
|
|
251
|
+
errorMessage: 'csFailureText',
|
|
252
|
+
usButtonText: 'Try again',
|
|
253
|
+
usHelpImage: null,
|
|
253
254
|
});
|
|
254
255
|
});
|
|
255
256
|
|
package/src/upload/Upload.tsx
CHANGED
|
@@ -50,6 +50,7 @@ export interface UploadProps extends WrappedComponentProps {
|
|
|
50
50
|
*/
|
|
51
51
|
usAccept?: string;
|
|
52
52
|
usButtonText?: string;
|
|
53
|
+
usButtonRetryText?: string;
|
|
53
54
|
usDisabled?: boolean;
|
|
54
55
|
usDropMessage?: string;
|
|
55
56
|
usHelpImage?: React.ReactNode;
|
|
@@ -325,6 +326,7 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
325
326
|
usDropMessage,
|
|
326
327
|
usAccept,
|
|
327
328
|
usButtonText,
|
|
329
|
+
usButtonRetryText,
|
|
328
330
|
usDisabled,
|
|
329
331
|
usHelpImage,
|
|
330
332
|
usLabel,
|
|
@@ -359,7 +361,7 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
359
361
|
'tw-droppable-lg droppable-lg': size === 'lg',
|
|
360
362
|
'droppable-dropping': isDroppable,
|
|
361
363
|
'droppable-processing': isProcessing,
|
|
362
|
-
'droppable-complete': isComplete,
|
|
364
|
+
'droppable-complete': isComplete && !isError,
|
|
363
365
|
'droppable-negative': isError,
|
|
364
366
|
})}
|
|
365
367
|
onDragEnter={(event) => this.onDragEnter(event)}
|
|
@@ -395,16 +397,36 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
395
397
|
onClear={(event) => this.handleOnClear(event)}
|
|
396
398
|
/>
|
|
397
399
|
)}
|
|
398
|
-
{/* Starts render the step when isSuccess
|
|
400
|
+
{/* Starts render the step when isSuccess is true so markup is there when css transition kicks in
|
|
399
401
|
css transition to work properly */}
|
|
400
|
-
{(isSuccess ||
|
|
402
|
+
{(isSuccess || isComplete) && !isError && (
|
|
401
403
|
<CompleteStep
|
|
402
404
|
fileName={fileName}
|
|
403
405
|
isComplete={isComplete}
|
|
404
|
-
isError={isError}
|
|
405
406
|
isImage={isImage}
|
|
406
407
|
csButtonText={csButtonText || intl.formatMessage(messages.csButtonText)}
|
|
407
|
-
|
|
408
|
+
csSuccessText={csSuccessText || intl.formatMessage(messages.csSuccessText)}
|
|
409
|
+
uploadedImage={uploadedImage}
|
|
410
|
+
onClear={(event) => this.handleOnClear(event)}
|
|
411
|
+
/>
|
|
412
|
+
)}
|
|
413
|
+
{isError && (
|
|
414
|
+
<UploadImageStep
|
|
415
|
+
fileDropped={async (file) => {
|
|
416
|
+
this.reset();
|
|
417
|
+
await this.fileDropped(file);
|
|
418
|
+
}}
|
|
419
|
+
isComplete={!isError}
|
|
420
|
+
usAccept={usAccept}
|
|
421
|
+
usButtonText={usButtonRetryText || intl.formatMessage(messages.retry)}
|
|
422
|
+
usDisabled={usDisabled}
|
|
423
|
+
usHelpImage={null}
|
|
424
|
+
usLabel={usLabel}
|
|
425
|
+
usPlaceholder={
|
|
426
|
+
usPlaceholder ||
|
|
427
|
+
intl.formatMessage(messages.usPlaceholder, { maxSize: maxSize / 1000000 })
|
|
428
|
+
}
|
|
429
|
+
errorMessage={this.getErrorMessage(
|
|
408
430
|
response != null &&
|
|
409
431
|
typeof response === 'object' &&
|
|
410
432
|
'status' in response &&
|
|
@@ -412,9 +434,6 @@ export class Upload extends Component<UploadProps, UploadState> {
|
|
|
412
434
|
? response.status
|
|
413
435
|
: undefined,
|
|
414
436
|
)}
|
|
415
|
-
csSuccessText={csSuccessText || intl.formatMessage(messages.csSuccessText)}
|
|
416
|
-
uploadedImage={uploadedImage}
|
|
417
|
-
onClear={(event) => this.handleOnClear(event)}
|
|
418
437
|
/>
|
|
419
438
|
)}
|
|
420
439
|
{!isProcessing && (
|
|
@@ -41,14 +41,6 @@ describe('CompleteStep', () => {
|
|
|
41
41
|
});
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
describe('when error is true', () => {
|
|
45
|
-
it('renders errorMessage and icon when error is true', () => {
|
|
46
|
-
component = shallow(<CompleteStep {...COMPLETED_STEP_PROPS} isError />);
|
|
47
|
-
expect(component.find('p').text()).toBe(COMPLETED_STEP_PROPS.csFailureText);
|
|
48
|
-
expect(component.find(StatusIcon)).toHaveLength(1);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
44
|
it('renders button when csButtonText is set up', () => {
|
|
53
45
|
expect(component.find(Button)).toHaveLength(1);
|
|
54
46
|
});
|
|
@@ -3,17 +3,13 @@ import { Document as DocumentIcon } from '@transferwise/icons';
|
|
|
3
3
|
import { Typography } from '../../..';
|
|
4
4
|
import Body from '../../../body';
|
|
5
5
|
import Button from '../../../button';
|
|
6
|
-
import { Sentiment, Size } from '../../../common';
|
|
7
|
-
import StatusIcon from '../../../statusIcon';
|
|
8
6
|
import Title from '../../../title';
|
|
9
7
|
|
|
10
8
|
export interface CompleteStepProps {
|
|
11
9
|
csButtonText: string;
|
|
12
10
|
csSuccessText: string;
|
|
13
|
-
csFailureText: string;
|
|
14
11
|
fileName: string;
|
|
15
12
|
isComplete: boolean;
|
|
16
|
-
isError: boolean;
|
|
17
13
|
isImage: boolean;
|
|
18
14
|
uploadedImage?: string;
|
|
19
15
|
onClear: React.MouseEventHandler<HTMLButtonElement>;
|
|
@@ -21,11 +17,9 @@ export interface CompleteStepProps {
|
|
|
21
17
|
|
|
22
18
|
export default function CompleteStep({
|
|
23
19
|
csButtonText,
|
|
24
|
-
csFailureText,
|
|
25
20
|
csSuccessText,
|
|
26
21
|
fileName,
|
|
27
22
|
isComplete,
|
|
28
|
-
isError,
|
|
29
23
|
isImage,
|
|
30
24
|
onClear,
|
|
31
25
|
uploadedImage,
|
|
@@ -37,34 +31,25 @@ export default function CompleteStep({
|
|
|
37
31
|
className="droppable-card-content d-flex flex-column align-items-center"
|
|
38
32
|
aria-live="polite"
|
|
39
33
|
>
|
|
40
|
-
{
|
|
41
|
-
|
|
42
|
-
<StatusIcon size={Size.LARGE} sentiment={Sentiment.NEGATIVE} />
|
|
43
|
-
{csFailureText && <p className="m-t-2 m-b-0">{csFailureText}</p>}
|
|
44
|
-
</>
|
|
34
|
+
{isImage && uploadedImage ? (
|
|
35
|
+
<img src={uploadedImage} alt="OK" className="thumbnail " />
|
|
45
36
|
) : (
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
<img src={uploadedImage} alt="OK" className="thumbnail " />
|
|
49
|
-
) : (
|
|
50
|
-
<DocumentIcon />
|
|
51
|
-
)}
|
|
37
|
+
<DocumentIcon />
|
|
38
|
+
)}
|
|
52
39
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
)}
|
|
63
|
-
</>
|
|
40
|
+
{fileName && (
|
|
41
|
+
<Body as="p" className="m-b-0">
|
|
42
|
+
{fileName}
|
|
43
|
+
</Body>
|
|
44
|
+
)}
|
|
45
|
+
{csSuccessText && (
|
|
46
|
+
<Title className="caption m-t-1" type={Typography.TITLE_BODY}>
|
|
47
|
+
{csSuccessText}
|
|
48
|
+
</Title>
|
|
64
49
|
)}
|
|
65
50
|
</div>
|
|
66
51
|
{csButtonText && (
|
|
67
|
-
<Button className=
|
|
52
|
+
<Button className="m-t-1" onClick={onClear}>
|
|
68
53
|
{csButtonText}
|
|
69
54
|
</Button>
|
|
70
55
|
)}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Upload as UploadIcon } from '@transferwise/icons';
|
|
2
2
|
import { shallow } from 'enzyme';
|
|
3
|
+
import StatusIcon from '../../../statusIcon/StatusIcon';
|
|
3
4
|
|
|
4
5
|
import UploadImageStep from '.';
|
|
5
6
|
|
|
@@ -13,6 +14,7 @@ describe('uploadImageStep', () => {
|
|
|
13
14
|
usLabel: '',
|
|
14
15
|
usHelpImage: '',
|
|
15
16
|
usPlaceholder: '',
|
|
17
|
+
errorMessage: '',
|
|
16
18
|
};
|
|
17
19
|
let component;
|
|
18
20
|
beforeEach(() => {
|
|
@@ -63,4 +65,14 @@ describe('uploadImageStep', () => {
|
|
|
63
65
|
|
|
64
66
|
expect(component.find('.test-image')).toHaveLength(1);
|
|
65
67
|
});
|
|
68
|
+
|
|
69
|
+
describe('when errorMessage is not empty', () => {
|
|
70
|
+
it('renders errorMessage and icon when error is true', () => {
|
|
71
|
+
component = shallow(
|
|
72
|
+
<UploadImageStep {...UPLOADIMAGE_STEP_PROPS} errorMessage="error message" />,
|
|
73
|
+
);
|
|
74
|
+
expect(component.find('.upload-error-message').text()).toBe('<InlineAlert />');
|
|
75
|
+
expect(component.find(StatusIcon)).toHaveLength(1);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
66
78
|
});
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Upload as UploadIcon } from '@transferwise/icons';
|
|
2
2
|
import { createRef, PureComponent } from 'react';
|
|
3
|
+
import StatusIcon from '../../../statusIcon';
|
|
4
|
+
import { Sentiment, Size } from '../../../common';
|
|
5
|
+
import InlineAlert from '../../../inlineAlert';
|
|
3
6
|
|
|
4
7
|
export interface UploadImageStepProps {
|
|
5
8
|
fileDropped: (file: File) => void;
|
|
@@ -10,6 +13,7 @@ export interface UploadImageStepProps {
|
|
|
10
13
|
usHelpImage: React.ReactNode;
|
|
11
14
|
usLabel: string;
|
|
12
15
|
usPlaceholder: string;
|
|
16
|
+
errorMessage?: string | string[];
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
export default class UploadImageStep extends PureComponent<UploadImageStepProps> {
|
|
@@ -25,6 +29,15 @@ export default class UploadImageStep extends PureComponent<UploadImageStepProps>
|
|
|
25
29
|
|
|
26
30
|
getImage = () => {
|
|
27
31
|
const { usHelpImage, usLabel } = this.props;
|
|
32
|
+
const { errorMessage } = this.props;
|
|
33
|
+
|
|
34
|
+
if (errorMessage) {
|
|
35
|
+
return (
|
|
36
|
+
<div className="d-flex flex-column align-items-center">
|
|
37
|
+
<StatusIcon size={Size.LARGE} sentiment={Sentiment.NEGATIVE} />
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
28
41
|
|
|
29
42
|
if (!usHelpImage) {
|
|
30
43
|
return (
|
|
@@ -42,7 +55,8 @@ export default class UploadImageStep extends PureComponent<UploadImageStepProps>
|
|
|
42
55
|
};
|
|
43
56
|
|
|
44
57
|
render() {
|
|
45
|
-
const { isComplete, usAccept, usButtonText, usDisabled, usLabel, usPlaceholder } =
|
|
58
|
+
const { isComplete, usAccept, usButtonText, usDisabled, usLabel, usPlaceholder, errorMessage } =
|
|
59
|
+
this.props;
|
|
46
60
|
|
|
47
61
|
return (
|
|
48
62
|
<div>
|
|
@@ -67,6 +81,13 @@ export default class UploadImageStep extends PureComponent<UploadImageStepProps>
|
|
|
67
81
|
onChange={() => this.onManualUpload()}
|
|
68
82
|
/>
|
|
69
83
|
</label>
|
|
84
|
+
{errorMessage && (
|
|
85
|
+
<div className="upload-error-message">
|
|
86
|
+
<div className="m-t-3 has-error">
|
|
87
|
+
<InlineAlert type={Sentiment.NEGATIVE}>{errorMessage}</InlineAlert>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
)}
|
|
70
91
|
</div>
|
|
71
92
|
</div>
|
|
72
93
|
</div>
|