@infosoftas/s4-orders-js-sdk 0.0.1-alpha1
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/.prettierignore +1 -0
- package/.prettierrc.json +7 -0
- package/package.json +41 -0
- package/src/App.scss +24 -0
- package/src/App.tsx +184 -0
- package/src/ErrorBoundary.tsx +41 -0
- package/src/api/OrdersApi.ts +44 -0
- package/src/api/SubscribeApi.ts +51 -0
- package/src/assets/styles/forms.scss +105 -0
- package/src/assets/styles/general.scss +38 -0
- package/src/assets/styles/variables.scss +29 -0
- package/src/components/Alert/Alert.tsx +22 -0
- package/src/components/Alert/alert.scss +21 -0
- package/src/components/Button/Button.tsx +43 -0
- package/src/components/Button/button.scss +48 -0
- package/src/components/FormFields/EmailField.tsx +53 -0
- package/src/components/FormFields/FormFields.helper.ts +16 -0
- package/src/components/FormFields/FormFieldsMapper.ts +13 -0
- package/src/components/FormFields/NameField.tsx +46 -0
- package/src/components/FormFields/PhoneField.tsx +55 -0
- package/src/components/Loader/Loader.tsx +22 -0
- package/src/components/Loader/loader.scss +37 -0
- package/src/components/MainIframe/MainIframe.tsx +42 -0
- package/src/components/OrderForm/OrderForm.tsx +235 -0
- package/src/components/OrderForm/orderForm.scss +10 -0
- package/src/constants/index.ts +8 -0
- package/src/enums/api.ts +4 -0
- package/src/enums/general.ts +12 -0
- package/src/hooks/useIframe.tsx +59 -0
- package/src/hooks/useMessageEvent.tsx +142 -0
- package/src/hooks/useQueryParams.ts +5 -0
- package/src/index.tsx +22 -0
- package/src/types/api.ts +12 -0
- package/src/types/general.ts +50 -0
- package/src/types/order.ts +41 -0
- package/src/utils/fetcher.ts +89 -0
- package/src/utils/helper.ts +18 -0
- package/src/utils/order.helper.ts +48 -0
- package/tsconfig.json +41 -0
- package/webpack.config.js +103 -0
package/.prettierignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
node_modules
|
package/.prettierrc.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@infosoftas/s4-orders-js-sdk",
|
|
3
|
+
"version" : "0.0.1-alpha1",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"build": "rimraf dist && webpack --env mode=production"
|
|
6
|
+
},
|
|
7
|
+
"eslintConfig": {
|
|
8
|
+
"extends": [
|
|
9
|
+
"react-app"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"prop-types": "^15.8.1",
|
|
14
|
+
"react": "^18.3.1",
|
|
15
|
+
"react-dom": "^18.3.1",
|
|
16
|
+
"react-hook-form": "^7.53.0",
|
|
17
|
+
"rimraf": "^6.0.1"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@babel/core": "^7.24.3",
|
|
21
|
+
"@babel/preset-env": "^7.18.10",
|
|
22
|
+
"@babel/preset-react": "^7.18.6",
|
|
23
|
+
"@babel/preset-typescript": "^7.24.7",
|
|
24
|
+
"@types/react": "^18.0.17",
|
|
25
|
+
"@types/react-dom": "^18.0.6",
|
|
26
|
+
"babel-loader": "^8.3.0",
|
|
27
|
+
"css-loader": "^7.1.2",
|
|
28
|
+
"dotenv-webpack": "^8.1.0",
|
|
29
|
+
"mini-css-extract-plugin": "^2.9.1",
|
|
30
|
+
"sass": "^1.79.2",
|
|
31
|
+
"sass-loader": "^16.0.1",
|
|
32
|
+
"style-loader": "^4.0.0",
|
|
33
|
+
"ts-loader": "^9.5.1",
|
|
34
|
+
"typescript": "^5.6.2",
|
|
35
|
+
"webpack": "^5.95.0",
|
|
36
|
+
"webpack-cli": "^5.1.4"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "restricted"
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/App.scss
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
@import 'Assets/styles/variables.scss';
|
|
2
|
+
@import 'Assets/styles/general.scss';
|
|
3
|
+
|
|
4
|
+
.sdk-order-container {
|
|
5
|
+
|
|
6
|
+
*,
|
|
7
|
+
*::before,
|
|
8
|
+
*::after {
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.sdk-iframe-wrapper {
|
|
13
|
+
display : flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
align-items : center;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
iframe {
|
|
19
|
+
max-width : 640px;
|
|
20
|
+
border : none;
|
|
21
|
+
background : transparent;
|
|
22
|
+
border-radius: $border-radius * 2;
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/App.tsx
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { FC, useEffect, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { MessageEventTypeEnum, PaymentMethodEnum } from 'Enums/general';
|
|
4
|
+
import useMessageEvent from 'Hooks/useMessageEvent';
|
|
5
|
+
import OrderForm from 'Component/OrderForm/OrderForm';
|
|
6
|
+
import Loader from 'Component/Loader/Loader';
|
|
7
|
+
import MainIframe from 'Component/MainIframe/MainIframe';
|
|
8
|
+
import Alert from 'Component/Alert/Alert';
|
|
9
|
+
import { ConfigType } from 'Types/general';
|
|
10
|
+
import { CompleteOrderParamsType, OrderInfoType } from 'Types/order';
|
|
11
|
+
import { orderComplete } from 'API/OrdersApi';
|
|
12
|
+
import { prepareErrorMessage } from 'Utils/helper';
|
|
13
|
+
|
|
14
|
+
import ErrorBoundary from './ErrorBoundary';
|
|
15
|
+
|
|
16
|
+
import './App.scss';
|
|
17
|
+
|
|
18
|
+
const App: FC<ConfigType> = ({
|
|
19
|
+
moduleTitle,
|
|
20
|
+
apiKey,
|
|
21
|
+
templatePackageId,
|
|
22
|
+
subscriberId,
|
|
23
|
+
userId,
|
|
24
|
+
identityProviderId,
|
|
25
|
+
organizationId,
|
|
26
|
+
redirectUrl,
|
|
27
|
+
showIframe,
|
|
28
|
+
paymentMethodsOptions,
|
|
29
|
+
availablePaymentMethods = [],
|
|
30
|
+
language = 'en-US',
|
|
31
|
+
merchantAgreementUrl = '',
|
|
32
|
+
settings = {
|
|
33
|
+
successText: 'Order successful completed!',
|
|
34
|
+
failureText: 'Something went wrong!',
|
|
35
|
+
buttonText: 'Start',
|
|
36
|
+
},
|
|
37
|
+
}) => {
|
|
38
|
+
const [loading, setLoading] = useState<boolean>(false);
|
|
39
|
+
const [showOrderForm, setShowOrderForm] = useState<boolean>(true);
|
|
40
|
+
const [iframeSrc, setIframeSrc] = useState<string | null>(null);
|
|
41
|
+
const [orderId, setOrderId] = useState<string | null>(null);
|
|
42
|
+
const [isConfirmed, setIsConfirmed] = useState<boolean>(false);
|
|
43
|
+
const [isFailed, setIsFailed] = useState<boolean>(false);
|
|
44
|
+
const [failedMsg, setFailedMsg] = useState<string>('');
|
|
45
|
+
const [orderInfo, setOrderInfo] = useState<OrderInfoType | null>(null);
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (apiKey) {
|
|
49
|
+
sessionStorage.setItem('sdk_api_key', apiKey);
|
|
50
|
+
}
|
|
51
|
+
}, [apiKey]);
|
|
52
|
+
|
|
53
|
+
const messageCallback = async (
|
|
54
|
+
data: CompleteOrderParamsType
|
|
55
|
+
): Promise<void> => {
|
|
56
|
+
setLoading(true);
|
|
57
|
+
setIframeSrc(null);
|
|
58
|
+
setShowOrderForm(false);
|
|
59
|
+
setIsFailed(false);
|
|
60
|
+
try {
|
|
61
|
+
await orderComplete(orderId || data.orderId || '');
|
|
62
|
+
setIsConfirmed(true);
|
|
63
|
+
setLoading(false);
|
|
64
|
+
if (window === top) {
|
|
65
|
+
top.postMessage(
|
|
66
|
+
{
|
|
67
|
+
type: MessageEventTypeEnum.ORDER_FLOW_COMPLETE,
|
|
68
|
+
isCompleted: true,
|
|
69
|
+
orderInfo: orderInfo,
|
|
70
|
+
},
|
|
71
|
+
top?.location?.origin || '*'
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.log(error);
|
|
76
|
+
setFailedMsg(
|
|
77
|
+
prepareErrorMessage(error as Error, settings?.failureText)
|
|
78
|
+
);
|
|
79
|
+
setIsFailed(true);
|
|
80
|
+
setLoading(false);
|
|
81
|
+
setShowOrderForm(true);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const handleMessageEvent = (type: MessageEventTypeEnum) => {
|
|
86
|
+
if (type === MessageEventTypeEnum.CANCEL) {
|
|
87
|
+
setLoading(false);
|
|
88
|
+
setOrderId(null);
|
|
89
|
+
setOrderInfo(null);
|
|
90
|
+
setIframeSrc(null);
|
|
91
|
+
setIsConfirmed(false);
|
|
92
|
+
setIsFailed(false);
|
|
93
|
+
setShowOrderForm(true);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
useMessageEvent(
|
|
98
|
+
messageCallback,
|
|
99
|
+
handleMessageEvent,
|
|
100
|
+
!!showIframe,
|
|
101
|
+
orderInfo
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const handleForm = (url: string | null, data?: OrderInfoType | null) => {
|
|
105
|
+
setIsConfirmed(false);
|
|
106
|
+
setIsFailed(false);
|
|
107
|
+
setOrderId(data?.orderId || null);
|
|
108
|
+
setOrderInfo(data || null);
|
|
109
|
+
if (url) {
|
|
110
|
+
if (
|
|
111
|
+
showIframe &&
|
|
112
|
+
data?.paymentMethod === PaymentMethodEnum.SwedbankPay
|
|
113
|
+
) {
|
|
114
|
+
setIframeSrc(url);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
window.location.href = url;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
setIframeSrc(null);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
if (window !== top) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<ErrorBoundary>
|
|
131
|
+
<div
|
|
132
|
+
className={`sdk-order-container ${
|
|
133
|
+
iframeSrc ? 'show-iframe' : ''
|
|
134
|
+
}`}
|
|
135
|
+
data-testid="sdk-order-module-id"
|
|
136
|
+
>
|
|
137
|
+
{moduleTitle && <h1 className="text-center">{moduleTitle}</h1>}
|
|
138
|
+
{loading && (
|
|
139
|
+
<div className="d-flex justify-center">
|
|
140
|
+
<Loader size="lg" dark={true} />
|
|
141
|
+
</div>
|
|
142
|
+
)}
|
|
143
|
+
{!iframeSrc && showOrderForm && (
|
|
144
|
+
<OrderForm
|
|
145
|
+
callback={handleForm}
|
|
146
|
+
templatePackageId={templatePackageId}
|
|
147
|
+
subscriberId={subscriberId}
|
|
148
|
+
userId={userId}
|
|
149
|
+
identityProviderId={identityProviderId}
|
|
150
|
+
organizationId={organizationId}
|
|
151
|
+
paymentMethods={availablePaymentMethods}
|
|
152
|
+
buttonText={settings?.buttonText}
|
|
153
|
+
paymentMethodLabel={settings?.paymentMethodLabel}
|
|
154
|
+
errorReqMsg={settings?.errorReqMsg}
|
|
155
|
+
errorInvalidEmailMsg={settings?.errorInvalidEmailMsg}
|
|
156
|
+
errorInvalidPhoneMsg={settings?.errorInvalidPhoneMsg}
|
|
157
|
+
defaultValues={settings?.orderDefaultValues}
|
|
158
|
+
redirectUrl={
|
|
159
|
+
showIframe
|
|
160
|
+
? window.location.href.split('?')[0]
|
|
161
|
+
: redirectUrl ||
|
|
162
|
+
window.location.href.split('?')[0]
|
|
163
|
+
}
|
|
164
|
+
paymentMethodsOptions={paymentMethodsOptions}
|
|
165
|
+
language={language}
|
|
166
|
+
merchantAgreementUrl={merchantAgreementUrl}
|
|
167
|
+
/>
|
|
168
|
+
)}
|
|
169
|
+
{showIframe && <MainIframe iframeSrc={iframeSrc} />}
|
|
170
|
+
{isConfirmed && (
|
|
171
|
+
<Alert
|
|
172
|
+
className="mt-2"
|
|
173
|
+
type="success"
|
|
174
|
+
msg={settings?.successText}
|
|
175
|
+
/>
|
|
176
|
+
)}
|
|
177
|
+
|
|
178
|
+
{isFailed && <Alert className="mt-2" msg={failedMsg} />}
|
|
179
|
+
</div>
|
|
180
|
+
</ErrorBoundary>
|
|
181
|
+
);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export default App;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { Component, ErrorInfo, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
interface State {
|
|
8
|
+
hasError: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class ErrorBoundary extends Component<Props, State> {
|
|
12
|
+
public state: State = {
|
|
13
|
+
hasError: false,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
public static getDerivedStateFromError(): State {
|
|
17
|
+
// Update state so the next render will show the fallback UI.
|
|
18
|
+
return { hasError: true };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
|
22
|
+
console.error('Uncaught error:', error, errorInfo);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public render() {
|
|
26
|
+
if (this.state.hasError) {
|
|
27
|
+
return (
|
|
28
|
+
<div className="layout-wrapper">
|
|
29
|
+
<h1>
|
|
30
|
+
Something went wrong. Please reload the page and try
|
|
31
|
+
again.
|
|
32
|
+
</h1>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return this.props.children;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default ErrorBoundary;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { AgreementsType } from 'Types/order';
|
|
2
|
+
import fetcher from 'Utils/fetcher';
|
|
3
|
+
|
|
4
|
+
type RequestOrderStartType = {
|
|
5
|
+
subscriberId?: string;
|
|
6
|
+
subscriptionPlan?: {
|
|
7
|
+
organizationId?: string;
|
|
8
|
+
templateSubscriptionPlanId?: string;
|
|
9
|
+
};
|
|
10
|
+
paymentAgreement: AgreementsType;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type OrderResponseType = {
|
|
14
|
+
terminalRedirectUrl: string;
|
|
15
|
+
id: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const orderStart = (
|
|
19
|
+
body: RequestOrderStartType
|
|
20
|
+
): Promise<OrderResponseType> =>
|
|
21
|
+
fetcher<OrderResponseType, RequestOrderStartType>({
|
|
22
|
+
method: 'POST',
|
|
23
|
+
url: '/order',
|
|
24
|
+
headers: {
|
|
25
|
+
'S4-ORDERS-API-KEY':
|
|
26
|
+
sessionStorage.getItem('sdk_api_key') ||
|
|
27
|
+
process.env.API_KEY ||
|
|
28
|
+
'',
|
|
29
|
+
},
|
|
30
|
+
body,
|
|
31
|
+
}) as Promise<OrderResponseType>;
|
|
32
|
+
|
|
33
|
+
export const orderComplete = (id: string): Promise<OrderResponseType> =>
|
|
34
|
+
fetcher<OrderResponseType, null>({
|
|
35
|
+
method: 'POST',
|
|
36
|
+
url: `/order/${id}/complete`,
|
|
37
|
+
headers: {
|
|
38
|
+
'S4-ORDERS-API-KEY':
|
|
39
|
+
sessionStorage.getItem('sdk_api_key') ||
|
|
40
|
+
process.env.API_KEY ||
|
|
41
|
+
'',
|
|
42
|
+
},
|
|
43
|
+
body: null,
|
|
44
|
+
}) as Promise<OrderResponseType>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fetcher from 'Utils/fetcher';
|
|
2
|
+
|
|
3
|
+
type CreateSubscriberRequestType = {
|
|
4
|
+
name?: string;
|
|
5
|
+
email?: string;
|
|
6
|
+
phone?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type CreateSubscriberResponseType = {
|
|
10
|
+
id: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type MapSubscriberToUserRequestType = {
|
|
14
|
+
identityProviderId: string;
|
|
15
|
+
userId: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type MapSubscriberToUserResponseType = {
|
|
19
|
+
id: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const createSubscriber = (
|
|
23
|
+
body: CreateSubscriberRequestType
|
|
24
|
+
): Promise<CreateSubscriberResponseType> =>
|
|
25
|
+
fetcher<CreateSubscriberResponseType, CreateSubscriberRequestType>({
|
|
26
|
+
method: 'POST',
|
|
27
|
+
url: '/subscriber',
|
|
28
|
+
headers: {
|
|
29
|
+
'S4-ORDERS-API-KEY':
|
|
30
|
+
sessionStorage.getItem('sdk_api_key') ||
|
|
31
|
+
process.env.API_KEY ||
|
|
32
|
+
'',
|
|
33
|
+
},
|
|
34
|
+
body,
|
|
35
|
+
}) as Promise<CreateSubscriberResponseType>;
|
|
36
|
+
|
|
37
|
+
export const mapSubscriberToUser = (
|
|
38
|
+
id: string,
|
|
39
|
+
body: MapSubscriberToUserRequestType
|
|
40
|
+
): Promise<MapSubscriberToUserResponseType> =>
|
|
41
|
+
fetcher<MapSubscriberToUserResponseType, MapSubscriberToUserRequestType>({
|
|
42
|
+
method: 'POST',
|
|
43
|
+
url: `/subscriber/${id}/user`,
|
|
44
|
+
headers: {
|
|
45
|
+
'S4-ORDERS-API-KEY':
|
|
46
|
+
sessionStorage.getItem('sdk_api_key') ||
|
|
47
|
+
process.env.API_KEY ||
|
|
48
|
+
'',
|
|
49
|
+
},
|
|
50
|
+
body,
|
|
51
|
+
}) as Promise<MapSubscriberToUserResponseType>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
@import 'Assets/styles/variables.scss';
|
|
2
|
+
|
|
3
|
+
.field-label {
|
|
4
|
+
display : block;
|
|
5
|
+
margin-bottom: 0.375em;
|
|
6
|
+
font-weight : 500;
|
|
7
|
+
text-align : left;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.field-wrapper {
|
|
11
|
+
display : flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
width : 100%;
|
|
14
|
+
margin-bottom : 20px;
|
|
15
|
+
|
|
16
|
+
label {
|
|
17
|
+
display : block;
|
|
18
|
+
order : 1;
|
|
19
|
+
margin-bottom: 0.375em;
|
|
20
|
+
font-weight : 500;
|
|
21
|
+
text-align : left;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.caption {
|
|
25
|
+
order: 3;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.input-control {
|
|
29
|
+
order: 2;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.input-control {
|
|
34
|
+
width : 100%;
|
|
35
|
+
padding : 0.25em 0.5em;
|
|
36
|
+
border : 2px solid $input-border-color;
|
|
37
|
+
border-radius : 4px;
|
|
38
|
+
font-size : 16px;
|
|
39
|
+
font-size : max(16px, 1em);
|
|
40
|
+
font-family : inherit;
|
|
41
|
+
background-color: $white;
|
|
42
|
+
|
|
43
|
+
&[disabled],
|
|
44
|
+
&[readonly],
|
|
45
|
+
&:read-only,
|
|
46
|
+
.disabled,
|
|
47
|
+
.red-only {
|
|
48
|
+
border-color : $input-border-disabled-color;
|
|
49
|
+
background-color: $input-border-disabled-bg-color;
|
|
50
|
+
cursor : not-allowed;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
&:focus {
|
|
54
|
+
border-color: hsl($input-focus-h, $input-focus-s, $input-focus-l);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.radio-button-control {
|
|
59
|
+
label {
|
|
60
|
+
display : flex;
|
|
61
|
+
margin-bottom: 0.375em;
|
|
62
|
+
font-weight : 500;
|
|
63
|
+
position : relative;
|
|
64
|
+
overflow : hidden;
|
|
65
|
+
cursor : pointer;
|
|
66
|
+
|
|
67
|
+
input {
|
|
68
|
+
position: absolute;
|
|
69
|
+
left : -9999px;
|
|
70
|
+
|
|
71
|
+
&:checked+span.value-block {
|
|
72
|
+
background-color: mix($white, $primary-color, 84%);
|
|
73
|
+
|
|
74
|
+
&:before {
|
|
75
|
+
box-shadow: inset 0 0 0 0.4375em $primary-color;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
span.value-block {
|
|
81
|
+
display : flex;
|
|
82
|
+
align-items : center;
|
|
83
|
+
padding : 0.375em 0.75em 0.375em 0.375em;
|
|
84
|
+
border-radius: 20px;
|
|
85
|
+
transition : 0.25s ease;
|
|
86
|
+
|
|
87
|
+
&:hover {
|
|
88
|
+
background-color: mix($white, $primary-color, 84%);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&:before {
|
|
92
|
+
content : "";
|
|
93
|
+
display : flex;
|
|
94
|
+
flex-shrink : 0;
|
|
95
|
+
width : 1.5em;
|
|
96
|
+
height : 1.5em;
|
|
97
|
+
margin-right : 0.375em;
|
|
98
|
+
border-radius : 50%;
|
|
99
|
+
background-color: $white;
|
|
100
|
+
box-shadow : inset 0 0 0 0.125em $primary-color;
|
|
101
|
+
transition : 0.25s ease;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
@import 'Assets/styles/variables.scss';
|
|
2
|
+
@import 'Assets/styles/forms.scss';
|
|
3
|
+
|
|
4
|
+
.d-flex {
|
|
5
|
+
display: flex;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.justify-center {
|
|
9
|
+
justify-content: center;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.align-center {
|
|
13
|
+
align-items: center;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.mt-2 {
|
|
17
|
+
margin-top: 0.5rem;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.mb-2 {
|
|
21
|
+
margin-bottom: 0.5rem;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.text-error {
|
|
25
|
+
color: $error-color !important;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.text-success {
|
|
29
|
+
color: $success-color !important
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.text-center {
|
|
33
|
+
text-align: center;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.caption {
|
|
37
|
+
font-size: $xs-font-size;
|
|
38
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
$white : #fff;
|
|
2
|
+
$black : #000;
|
|
3
|
+
$blue : #007bff;
|
|
4
|
+
$green : #5fa757;
|
|
5
|
+
$red : #c9252d;
|
|
6
|
+
$grey : #6c757d;
|
|
7
|
+
$light-gray : #f8f9fa;
|
|
8
|
+
$dark-gray : #343a40;
|
|
9
|
+
$error-color : $red;
|
|
10
|
+
$success-test-color : $green;
|
|
11
|
+
$text-color : $dark-gray;
|
|
12
|
+
$primary-color : $blue;
|
|
13
|
+
$input-border-color : $grey;
|
|
14
|
+
$input-border-disabled-color : #ccc;
|
|
15
|
+
$input-border-disabled-bg-color: #eee;
|
|
16
|
+
$success-color : #155724;
|
|
17
|
+
$success-bg-color : #d4edda;
|
|
18
|
+
$success-border-color : #c3e6cb;
|
|
19
|
+
$danger-color : #721c24;
|
|
20
|
+
$danger-bg-color : #f8d7da;
|
|
21
|
+
$danger-border-color : #f5c6cb;
|
|
22
|
+
$input-focus-h : 245;
|
|
23
|
+
$input-focus-s : 100%;
|
|
24
|
+
$input-focus-l : 42%;
|
|
25
|
+
$font-size : 1rem;
|
|
26
|
+
$sm-font-size : 0.875rem;
|
|
27
|
+
$xs-font-size : 0.75rem;
|
|
28
|
+
$border-radius : 4px;
|
|
29
|
+
$size-bezel : 0.5rem;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
|
|
3
|
+
import './alert.scss';
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
msg?: string;
|
|
7
|
+
type?: 'danger' | 'success';
|
|
8
|
+
className?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const Alert: FC<Props> = ({ msg, type = 'danger', className = '' }) => {
|
|
12
|
+
return msg ? (
|
|
13
|
+
<div
|
|
14
|
+
className={`sdk-alert ${type} ${className}`}
|
|
15
|
+
data-testid="sdk-alert-id"
|
|
16
|
+
>
|
|
17
|
+
{msg}
|
|
18
|
+
</div>
|
|
19
|
+
) : null;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default Alert;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
@import 'Assets/styles/variables.scss';
|
|
2
|
+
|
|
3
|
+
.sdk-alert {
|
|
4
|
+
position : relative;
|
|
5
|
+
padding : .75rem 1.25rem;
|
|
6
|
+
margin-bottom: 1rem;
|
|
7
|
+
border : 1px solid transparent;
|
|
8
|
+
border-radius: .25rem;
|
|
9
|
+
|
|
10
|
+
&.danger {
|
|
11
|
+
color : $danger-color;
|
|
12
|
+
background-color: $danger-bg-color;
|
|
13
|
+
border-color : $danger-border-color;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&.success {
|
|
17
|
+
color : $success-color;
|
|
18
|
+
background-color: $success-bg-color;
|
|
19
|
+
border-color : $success-border-color;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { FC, MouseEvent } from 'react';
|
|
2
|
+
|
|
3
|
+
import Loader from 'Component/Loader/Loader';
|
|
4
|
+
|
|
5
|
+
import './button.scss';
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
|
|
9
|
+
type?: 'button' | 'submit' | 'reset';
|
|
10
|
+
btnType?: 'primary';
|
|
11
|
+
buttonText?: string;
|
|
12
|
+
loading?: boolean;
|
|
13
|
+
disable?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const Button: FC<Props> = ({
|
|
17
|
+
onClick,
|
|
18
|
+
type = 'button',
|
|
19
|
+
btnType = 'primary',
|
|
20
|
+
buttonText = 'Start',
|
|
21
|
+
loading = false,
|
|
22
|
+
disable = false,
|
|
23
|
+
}) => {
|
|
24
|
+
const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
|
|
25
|
+
onClick?.(e);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<button
|
|
30
|
+
data-testid="sdk-button-id"
|
|
31
|
+
type={type}
|
|
32
|
+
disabled={loading || disable}
|
|
33
|
+
className={`sdk-btn ${btnType ? `${btnType}-btn` : ''} ${
|
|
34
|
+
loading ? 'loading' : ''
|
|
35
|
+
} ${disable ? 'disabled' : ''}`}
|
|
36
|
+
onClick={handleClick}
|
|
37
|
+
>
|
|
38
|
+
{loading ? <Loader className="btn-loader" /> : buttonText}
|
|
39
|
+
</button>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default Button;
|