@temboplus/frontend-react-core 0.1.3-beta.1 → 0.1.3-beta.3
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/dist/alerts/index.cjs.js +1 -1
- package/dist/alerts/index.d.ts +1 -0
- package/dist/alerts/index.js +1 -1
- package/dist/dialogs/index.cjs.js +1 -1
- package/dist/dialogs/index.d.ts +1 -0
- package/dist/dialogs/index.js +1 -1
- package/dist/features/alerts/alert.js +95 -0
- package/dist/features/alerts/index.js +1 -0
- package/dist/features/dialogs/index.js +1 -0
- package/dist/features/dialogs/modal-provider.js +6 -0
- package/dist/features/dialogs/tembo-confirm.js +111 -0
- package/dist/features/input-validation/account-name-validator.js +28 -0
- package/dist/features/input-validation/account-number-validator.js +65 -0
- package/dist/features/input-validation/amount-validator.js +100 -0
- package/dist/features/input-validation/index.js +5 -0
- package/dist/features/input-validation/phone-number-validator.js +79 -0
- package/dist/features/input-validation/swift-code-validator.js +38 -0
- package/dist/features/notifications/index.js +3 -0
- package/dist/features/notifications/tembo-notify.js +149 -0
- package/dist/features/notifications/toast-config.js +53 -0
- package/dist/features/notifications/toast-container.js +18 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1 -0
- package/dist/notifications/index.cjs.js +1 -1
- package/dist/notifications/index.d.ts +1 -0
- package/dist/notifications/index.js +1 -1
- package/dist/providers.js +32 -0
- package/dist/{tembo-notify-C-QGduBt.js → tembo-notify-B-mUpU8q.js} +2 -2
- package/dist/{tembo-notify-C-QGduBt.js.map → tembo-notify-B-mUpU8q.js.map} +1 -1
- package/dist/{tembo-notify-D-uOV3t0.js → tembo-notify-C4_8DSSc.js} +2 -2
- package/dist/{tembo-notify-D-uOV3t0.js.map → tembo-notify-C4_8DSSc.js.map} +1 -1
- package/dist/theme/colors.d.ts +55 -23
- package/dist/theme/colors.js +212 -0
- package/dist/theme/constants.js +82 -0
- package/dist/theme/index.cjs.js +1 -1
- package/dist/theme/index.js +1 -1
- package/dist/theme/theme-provider.d.ts +18 -6
- package/dist/theme/theme-provider.js +404 -0
- package/dist/theme-provider-Ca4P0Hcp.js +11 -0
- package/dist/theme-provider-Ca4P0Hcp.js.map +1 -0
- package/dist/theme-provider-RhAw3jw_.js +11 -0
- package/dist/theme-provider-RhAw3jw_.js.map +1 -0
- package/dist/validation/index.d.ts +1 -0
- package/package.json +5 -2
- package/dist/theme-provider-D_oV1J_K.js +0 -11
- package/dist/theme-provider-D_oV1J_K.js.map +0 -1
- package/dist/theme-provider-Dqvy24OD.js +0 -11
- package/dist/theme-provider-Dqvy24OD.js.map +0 -1
package/dist/alerts/index.cjs.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("../theme-provider-
|
|
1
|
+
"use strict";var e=require("../theme-provider-RhAw3jw_.js"),r=require("antd");require("lodash");var o=require("../InfoCircleOutlined-B7d2aRfV.js");require("react");const{Text:t}=r.Typography;exports.TemboAlert=({type:n="info",message:s,description:i,icon:c,showIcon:x=!0,style:l})=>{const{colors:a,constants:d}=e.useTemboTheme(),u=(e=>{switch(e){case"success":return{background:a.success.bg,border:a.success.main,iconColor:a.success.main,textColor:a.success.text};case"warning":return{background:a.warning.bg,border:a.warning.main,iconColor:a.warning.main,textColor:a.warning.text};case"error":return{background:a.error.bg,border:a.error.main,iconColor:a.error.main,textColor:a.error.text};default:return{background:a.info.bg,border:a.info.main,iconColor:a.info.main,textColor:a.info.text}}})(n),g=c||(r=>{switch(r){case"success":return e.jsxRuntimeExports.jsx(o.RefIcon$2,{});case"warning":return e.jsxRuntimeExports.jsx(o.RefIcon,{});case"error":return e.jsxRuntimeExports.jsx(o.RefIcon$3,{});default:return e.jsxRuntimeExports.jsx(o.RefIcon$1,{})}})(n),p=x?22:0;return e.jsxRuntimeExports.jsx("div",{style:Object.assign({width:"100%",padding:"12px 16px",backgroundColor:u.background,borderRadius:d.radius.sm,borderLeft:`3px solid ${u.border}`},l),children:e.jsxRuntimeExports.jsxs(r.Space,{direction:"vertical",size:s?6:0,style:{width:"100%"},children:[s&&e.jsxRuntimeExports.jsxs(r.Flex,{gap:8,align:"center",children:[x&&e.jsxRuntimeExports.jsx("div",{style:{color:u.iconColor,fontSize:14,lineHeight:1},children:g}),"string"==typeof s?e.jsxRuntimeExports.jsx(t,{strong:!0,style:{fontSize:13,color:u.textColor,lineHeight:1.4},children:s}):s]}),i&&e.jsxRuntimeExports.jsxs(r.Flex,{gap:8,align:"flex-start",children:[!s&&x&&e.jsxRuntimeExports.jsx("div",{style:{color:u.iconColor,fontSize:14,lineHeight:1,marginTop:1},children:g}),"string"==typeof i?e.jsxRuntimeExports.jsx(t,{style:{fontSize:12,color:a.text.secondary,lineHeight:1.5,paddingLeft:s&&x?p:0},children:i}):e.jsxRuntimeExports.jsx("div",{style:{fontSize:12,color:a.text.secondary,lineHeight:1.5,paddingLeft:s&&x?p:0},children:i})]})]})})};
|
|
2
2
|
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../features/alerts";
|
package/dist/alerts/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as r,j as e}from"../theme-provider-
|
|
1
|
+
import{u as r,j as e}from"../theme-provider-Ca4P0Hcp.js";import{Typography as o,Space as n,Flex as t}from"antd";import"lodash";import{a as i,c as s,R as c,b as a}from"../InfoCircleOutlined-DYs90hdV.js";import"react";const{Text:l}=o,d=({type:o="info",message:d,description:g,icon:x,showIcon:u=!0,style:f})=>{const{colors:h,constants:m}=r(),p=(r=>{switch(r){case"success":return{background:h.success.bg,border:h.success.main,iconColor:h.success.main,textColor:h.success.text};case"warning":return{background:h.warning.bg,border:h.warning.main,iconColor:h.warning.main,textColor:h.warning.text};case"error":return{background:h.error.bg,border:h.error.main,iconColor:h.error.main,textColor:h.error.text};default:return{background:h.info.bg,border:h.info.main,iconColor:h.info.main,textColor:h.info.text}}})(o),b=x||(r=>{switch(r){case"success":return e.jsx(a,{});case"warning":return e.jsx(c,{});case"error":return e.jsx(s,{});default:return e.jsx(i,{})}})(o),j=u?22:0;return e.jsx("div",{style:Object.assign({width:"100%",padding:"12px 16px",backgroundColor:p.background,borderRadius:m.radius.sm,borderLeft:`3px solid ${p.border}`},f),children:e.jsxs(n,{direction:"vertical",size:d?6:0,style:{width:"100%"},children:[d&&e.jsxs(t,{gap:8,align:"center",children:[u&&e.jsx("div",{style:{color:p.iconColor,fontSize:14,lineHeight:1},children:b}),"string"==typeof d?e.jsx(l,{strong:!0,style:{fontSize:13,color:p.textColor,lineHeight:1.4},children:d}):d]}),g&&e.jsxs(t,{gap:8,align:"flex-start",children:[!d&&u&&e.jsx("div",{style:{color:p.iconColor,fontSize:14,lineHeight:1,marginTop:1},children:b}),"string"==typeof g?e.jsx(l,{style:{fontSize:12,color:h.text.secondary,lineHeight:1.5,paddingLeft:d&&u?j:0},children:g}):e.jsx("div",{style:{fontSize:12,color:h.text.secondary,lineHeight:1.5,paddingLeft:d&&u?j:0},children:g})]})]})})};export{d as TemboAlert};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("../theme-provider-
|
|
1
|
+
"use strict";var e=require("../theme-provider-RhAw3jw_.js"),s=require("antd"),t=require("@ebay/nice-modal-react");require("lodash");var n=require("../InfoCircleOutlined-B7d2aRfV.js"),o=require("../ZoomOutOutlined-BY_CCwq7.js");function r(e){return e&&e.__esModule?e:{default:e}}require("react");var i=r(t);const c=i.default.create(n=>{var o,r,i;const c=t.useModal();return e.jsxRuntimeExports.jsx(s.Modal,{open:c.visible,title:n.title,onOk:async()=>{n.onOk&&await n.onOk(),c.resolve(!0),c.remove()},onCancel:()=>{n.onCancel&&n.onCancel(),c.resolve(!1),c.remove()},okText:null!==(o=n.okText)&&void 0!==o?o:"OK",cancelText:null!==(r=n.cancelText)&&void 0!==r?r:"Cancel",okButtonProps:{danger:n.okDanger,type:null!==(i=n.okType)&&void 0!==i?i:"primary"},centered:!0,destroyOnClose:!0,children:e.jsxRuntimeExports.jsxs("div",{style:{display:"flex",gap:12,alignItems:"flex-start"},children:[n.icon&&e.jsxRuntimeExports.jsx("div",{style:{fontSize:22,marginTop:2},children:n.icon}),e.jsxRuntimeExports.jsx("div",{style:{flex:1},children:n.content})]})})});const a=()=>{const{colors:s}=e.useTemboTheme();return e.jsxRuntimeExports.jsx(n.RefIcon,{style:{color:s.error.main}})},l=()=>{const{colors:s}=e.useTemboTheme();return e.jsxRuntimeExports.jsx(o.RefIcon,{style:{color:s.warning.main}})},u=()=>{const{colors:s}=e.useTemboTheme();return e.jsxRuntimeExports.jsx(n.RefIcon$1,{style:{color:s.info.main}})},x=()=>{const{colors:s}=e.useTemboTheme();return e.jsxRuntimeExports.jsx(n.RefIcon$2,{style:{color:s.success.main}})},m=()=>{const{colors:s}=e.useTemboTheme();return e.jsxRuntimeExports.jsx(o.RefIcon$1,{style:{color:s.primary.main}})};exports.ConfirmDialog=c,exports.TemboConfirm=class{static async danger(s){return i.default.show(c,Object.assign(Object.assign({},s),{icon:e.jsxRuntimeExports.jsx(a,{}),okDanger:!0,okType:"primary"}))}static async warning(s){return i.default.show(c,Object.assign(Object.assign({},s),{icon:e.jsxRuntimeExports.jsx(l,{})}))}static async info(s){return i.default.show(c,Object.assign(Object.assign({},s),{icon:e.jsxRuntimeExports.jsx(u,{})}))}static async success(s){return i.default.show(c,Object.assign(Object.assign({},s),{icon:e.jsxRuntimeExports.jsx(x,{})}))}static async confirm(s){return i.default.show(c,Object.assign(Object.assign({},s),{icon:e.jsxRuntimeExports.jsx(m,{})}))}};
|
|
2
2
|
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../features/dialogs";
|
package/dist/dialogs/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as s,u as n}from"../theme-provider-
|
|
1
|
+
import{j as s,u as n}from"../theme-provider-Ca4P0Hcp.js";import{Modal as o}from"antd";import e,{useModal as t}from"@ebay/nice-modal-react";import"lodash";import{R as r,a as c,b as a}from"../InfoCircleOutlined-DYs90hdV.js";import{R as i,a as l}from"../ZoomOutOutlined-BL6A5RSq.js";import"react";const j=e.create(n=>{var e,r,c;const a=t();return s.jsx(o,{open:a.visible,title:n.title,onOk:async()=>{n.onOk&&await n.onOk(),a.resolve(!0),a.remove()},onCancel:()=>{n.onCancel&&n.onCancel(),a.resolve(!1),a.remove()},okText:null!==(e=n.okText)&&void 0!==e?e:"OK",cancelText:null!==(r=n.cancelText)&&void 0!==r?r:"Cancel",okButtonProps:{danger:n.okDanger,type:null!==(c=n.okType)&&void 0!==c?c:"primary"},centered:!0,destroyOnClose:!0,children:s.jsxs("div",{style:{display:"flex",gap:12,alignItems:"flex-start"},children:[n.icon&&s.jsx("div",{style:{fontSize:22,marginTop:2},children:n.icon}),s.jsx("div",{style:{flex:1},children:n.content})]})})});class m{static async danger(n){return e.show(j,Object.assign(Object.assign({},n),{icon:s.jsx(y,{}),okDanger:!0,okType:"primary"}))}static async warning(n){return e.show(j,Object.assign(Object.assign({},n),{icon:s.jsx(x,{})}))}static async info(n){return e.show(j,Object.assign(Object.assign({},n),{icon:s.jsx(d,{})}))}static async success(n){return e.show(j,Object.assign(Object.assign({},n),{icon:s.jsx(u,{})}))}static async confirm(n){return e.show(j,Object.assign(Object.assign({},n),{icon:s.jsx(p,{})}))}}const y=()=>{const{colors:o}=n();return s.jsx(r,{style:{color:o.error.main}})},x=()=>{const{colors:o}=n();return s.jsx(i,{style:{color:o.warning.main}})},d=()=>{const{colors:o}=n();return s.jsx(c,{style:{color:o.info.main}})},u=()=>{const{colors:o}=n();return s.jsx(a,{style:{color:o.success.main}})},p=()=>{const{colors:o}=n();return s.jsx(l,{style:{color:o.primary.main}})};export{j as ConfirmDialog,m as TemboConfirm};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Space, Flex, Typography } from 'antd';
|
|
3
|
+
import { InfoCircleOutlined, CheckCircleOutlined, ExclamationCircleOutlined, CloseCircleOutlined } from '@ant-design/icons';
|
|
4
|
+
import { useTemboTheme } from '../../theme/index.js';
|
|
5
|
+
const { Text } = Typography;
|
|
6
|
+
export const TemboAlert = ({ type = 'info', message: title, description, icon, showIcon = true, style, }) => {
|
|
7
|
+
const { colors, constants } = useTemboTheme();
|
|
8
|
+
const getAlertColors = (alertType) => {
|
|
9
|
+
switch (alertType) {
|
|
10
|
+
case 'success':
|
|
11
|
+
return {
|
|
12
|
+
background: colors.success.bg,
|
|
13
|
+
border: colors.success.main,
|
|
14
|
+
iconColor: colors.success.main,
|
|
15
|
+
textColor: colors.success.text,
|
|
16
|
+
};
|
|
17
|
+
case 'warning':
|
|
18
|
+
return {
|
|
19
|
+
background: colors.warning.bg,
|
|
20
|
+
border: colors.warning.main,
|
|
21
|
+
iconColor: colors.warning.main,
|
|
22
|
+
textColor: colors.warning.text,
|
|
23
|
+
};
|
|
24
|
+
case 'error':
|
|
25
|
+
return {
|
|
26
|
+
background: colors.error.bg,
|
|
27
|
+
border: colors.error.main,
|
|
28
|
+
iconColor: colors.error.main,
|
|
29
|
+
textColor: colors.error.text,
|
|
30
|
+
};
|
|
31
|
+
case 'info':
|
|
32
|
+
default:
|
|
33
|
+
return {
|
|
34
|
+
background: colors.info.bg,
|
|
35
|
+
border: colors.info.main,
|
|
36
|
+
iconColor: colors.info.main,
|
|
37
|
+
textColor: colors.info.text,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const getDefaultIcon = (alertType) => {
|
|
42
|
+
switch (alertType) {
|
|
43
|
+
case 'success':
|
|
44
|
+
return _jsx(CheckCircleOutlined, {});
|
|
45
|
+
case 'warning':
|
|
46
|
+
return _jsx(ExclamationCircleOutlined, {});
|
|
47
|
+
case 'error':
|
|
48
|
+
return _jsx(CloseCircleOutlined, {});
|
|
49
|
+
case 'info':
|
|
50
|
+
default:
|
|
51
|
+
return _jsx(InfoCircleOutlined, {});
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const alertColors = getAlertColors(type);
|
|
55
|
+
const alertIcon = icon || getDefaultIcon(type);
|
|
56
|
+
// Calculate icon width for alignment (icon + gap)
|
|
57
|
+
const iconWidth = showIcon ? 14 + 8 : 0; // icon size + gap
|
|
58
|
+
const renderTitle = () => {
|
|
59
|
+
if (typeof title === 'string') {
|
|
60
|
+
return (_jsx(Text, { strong: true, style: {
|
|
61
|
+
fontSize: 13,
|
|
62
|
+
color: alertColors.textColor,
|
|
63
|
+
lineHeight: 1.4,
|
|
64
|
+
}, children: title }));
|
|
65
|
+
}
|
|
66
|
+
return title;
|
|
67
|
+
};
|
|
68
|
+
const renderDescription = () => {
|
|
69
|
+
if (typeof description === 'string') {
|
|
70
|
+
return (_jsx(Text, { style: {
|
|
71
|
+
fontSize: 12,
|
|
72
|
+
color: colors.text.secondary,
|
|
73
|
+
lineHeight: 1.5,
|
|
74
|
+
paddingLeft: title && showIcon ? iconWidth : 0,
|
|
75
|
+
}, children: description }));
|
|
76
|
+
}
|
|
77
|
+
// For React nodes, wrap in a div with appropriate styling
|
|
78
|
+
return (_jsx("div", { style: {
|
|
79
|
+
fontSize: 12,
|
|
80
|
+
color: colors.text.secondary,
|
|
81
|
+
lineHeight: 1.5,
|
|
82
|
+
paddingLeft: title && showIcon ? iconWidth : 0,
|
|
83
|
+
}, children: description }));
|
|
84
|
+
};
|
|
85
|
+
return (_jsx("div", { style: Object.assign({ width: '100%', padding: '12px 16px', backgroundColor: alertColors.background, borderRadius: constants.radius.sm, borderLeft: `3px solid ${alertColors.border}` }, style), children: _jsxs(Space, { direction: "vertical", size: title ? 6 : 0, style: { width: '100%' }, children: [title && (_jsxs(Flex, { gap: 8, align: "center", children: [showIcon && (_jsx("div", { style: {
|
|
86
|
+
color: alertColors.iconColor,
|
|
87
|
+
fontSize: 14,
|
|
88
|
+
lineHeight: 1,
|
|
89
|
+
}, children: alertIcon })), renderTitle()] })), description && (_jsxs(Flex, { gap: 8, align: "flex-start", children: [!title && showIcon && (_jsx("div", { style: {
|
|
90
|
+
color: alertColors.iconColor,
|
|
91
|
+
fontSize: 14,
|
|
92
|
+
lineHeight: 1,
|
|
93
|
+
marginTop: 1,
|
|
94
|
+
}, children: alertIcon })), renderDescription()] }))] }) }));
|
|
95
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./alert.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./tembo-confirm.js";
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Modal } from 'antd';
|
|
3
|
+
import NiceModal, { useModal } from '@ebay/nice-modal-react';
|
|
4
|
+
import { ExclamationCircleOutlined, QuestionCircleOutlined, InfoCircleOutlined, WarningOutlined, CheckCircleOutlined, } from '@ant-design/icons';
|
|
5
|
+
import { useTemboTheme } from '../../theme/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Base confirmation dialog using NiceModal
|
|
8
|
+
*/
|
|
9
|
+
export const ConfirmDialog = NiceModal.create((props) => {
|
|
10
|
+
var _a, _b, _c;
|
|
11
|
+
const modal = useModal();
|
|
12
|
+
const handleOk = async () => {
|
|
13
|
+
if (props.onOk) {
|
|
14
|
+
await props.onOk();
|
|
15
|
+
}
|
|
16
|
+
modal.resolve(true);
|
|
17
|
+
modal.remove();
|
|
18
|
+
};
|
|
19
|
+
const handleCancel = () => {
|
|
20
|
+
if (props.onCancel) {
|
|
21
|
+
props.onCancel();
|
|
22
|
+
}
|
|
23
|
+
modal.resolve(false);
|
|
24
|
+
modal.remove();
|
|
25
|
+
};
|
|
26
|
+
return (_jsx(Modal, { open: modal.visible, title: props.title, onOk: handleOk, onCancel: handleCancel, okText: (_a = props.okText) !== null && _a !== void 0 ? _a : 'OK', cancelText: (_b = props.cancelText) !== null && _b !== void 0 ? _b : 'Cancel', okButtonProps: {
|
|
27
|
+
danger: props.okDanger,
|
|
28
|
+
type: (_c = props.okType) !== null && _c !== void 0 ? _c : 'primary',
|
|
29
|
+
}, centered: true, destroyOnClose: true, children: _jsxs("div", { style: { display: 'flex', gap: 12, alignItems: 'flex-start' }, children: [props.icon && (_jsx("div", { style: { fontSize: 22, marginTop: 2 }, children: props.icon })), _jsx("div", { style: { flex: 1 }, children: props.content })] }) }));
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* TemboConfirm - Unified confirmation dialog system
|
|
33
|
+
*
|
|
34
|
+
* Provides consistent, theme-aligned confirmation dialogs using NiceModal.
|
|
35
|
+
* Uses theme colors at invocation time to ensure proper theming.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* // Danger confirmation
|
|
40
|
+
* const confirmed = await TemboConfirm.danger({
|
|
41
|
+
* title: 'Delete Payment',
|
|
42
|
+
* content: 'This action cannot be undone.',
|
|
43
|
+
* okText: 'Yes, Delete',
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* if (confirmed) {
|
|
47
|
+
* // proceed with deletion
|
|
48
|
+
* }
|
|
49
|
+
*
|
|
50
|
+
* // Warning confirmation
|
|
51
|
+
* await TemboConfirm.warning({
|
|
52
|
+
* title: 'Unsaved Changes',
|
|
53
|
+
* content: 'You have unsaved changes. Continue?',
|
|
54
|
+
* });
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export class TemboConfirm {
|
|
58
|
+
/**
|
|
59
|
+
* Show a danger/destructive confirmation dialog (red OK button)
|
|
60
|
+
*/
|
|
61
|
+
static async danger(props) {
|
|
62
|
+
// We need to get colors from context, but static methods can't use hooks
|
|
63
|
+
// Solution: Accept colors as optional param or use a wrapper component
|
|
64
|
+
return NiceModal.show(ConfirmDialog, Object.assign(Object.assign({}, props), { icon: _jsx(DangerIcon, {}), okDanger: true, okType: 'primary' }));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Show a warning confirmation dialog (orange icon)
|
|
68
|
+
*/
|
|
69
|
+
static async warning(props) {
|
|
70
|
+
return NiceModal.show(ConfirmDialog, Object.assign(Object.assign({}, props), { icon: _jsx(WarningIcon, {}) }));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Show an info confirmation dialog (blue icon)
|
|
74
|
+
*/
|
|
75
|
+
static async info(props) {
|
|
76
|
+
return NiceModal.show(ConfirmDialog, Object.assign(Object.assign({}, props), { icon: _jsx(InfoIcon, {}) }));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Show a success confirmation dialog (green icon)
|
|
80
|
+
*/
|
|
81
|
+
static async success(props) {
|
|
82
|
+
return NiceModal.show(ConfirmDialog, Object.assign(Object.assign({}, props), { icon: _jsx(SuccessIcon, {}) }));
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Show a generic question dialog
|
|
86
|
+
*/
|
|
87
|
+
static async confirm(props) {
|
|
88
|
+
return NiceModal.show(ConfirmDialog, Object.assign(Object.assign({}, props), { icon: _jsx(QuestionIcon, {}) }));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Icon wrapper components that use the theme hook
|
|
92
|
+
const DangerIcon = () => {
|
|
93
|
+
const { colors } = useTemboTheme();
|
|
94
|
+
return _jsx(ExclamationCircleOutlined, { style: { color: colors.error.main } });
|
|
95
|
+
};
|
|
96
|
+
const WarningIcon = () => {
|
|
97
|
+
const { colors } = useTemboTheme();
|
|
98
|
+
return _jsx(WarningOutlined, { style: { color: colors.warning.main } });
|
|
99
|
+
};
|
|
100
|
+
const InfoIcon = () => {
|
|
101
|
+
const { colors } = useTemboTheme();
|
|
102
|
+
return _jsx(InfoCircleOutlined, { style: { color: colors.info.main } });
|
|
103
|
+
};
|
|
104
|
+
const SuccessIcon = () => {
|
|
105
|
+
const { colors } = useTemboTheme();
|
|
106
|
+
return _jsx(CheckCircleOutlined, { style: { color: colors.success.main } });
|
|
107
|
+
};
|
|
108
|
+
const QuestionIcon = () => {
|
|
109
|
+
const { colors } = useTemboTheme();
|
|
110
|
+
return _jsx(QuestionCircleOutlined, { style: { color: colors.primary.main } });
|
|
111
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { BankValidation } from "@temboplus/frontend-core";
|
|
2
|
+
/**
|
|
3
|
+
* Validator for account name field using existing BankValidation.
|
|
4
|
+
* Ensures the account name meets the criteria defined in your validation utils.
|
|
5
|
+
*
|
|
6
|
+
* @param rule - The rule object for validation
|
|
7
|
+
* @param value - The value to validate
|
|
8
|
+
* @returns Promise resolving to trimmed account name or rejecting with error
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // In form rules
|
|
12
|
+
* rules: [{ required: true, validator: ACCOUNT_NAME_VALIDATOR }]
|
|
13
|
+
*/
|
|
14
|
+
export const ACCOUNT_NAME_VALIDATOR = (rule, value) => {
|
|
15
|
+
const accountNameString = value === null || value === void 0 ? void 0 : value.toString().trim();
|
|
16
|
+
// If field is empty/undefined/null
|
|
17
|
+
if (!accountNameString) {
|
|
18
|
+
if (rule.required) {
|
|
19
|
+
return Promise.reject(new Error("Account name is required."));
|
|
20
|
+
}
|
|
21
|
+
return Promise.resolve(undefined);
|
|
22
|
+
}
|
|
23
|
+
const isValid = BankValidation.validateAccountName(accountNameString);
|
|
24
|
+
if (isValid) {
|
|
25
|
+
return Promise.resolve(accountNameString);
|
|
26
|
+
}
|
|
27
|
+
return Promise.reject(new Error("Invalid account name. Please enter a valid full name with at least two words (e.g., 'John Smith', 'Anna-Marie Johnson')."));
|
|
28
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { BankValidation, Country } from "@temboplus/frontend-core";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a validator for bank account numbers specific to a country.
|
|
4
|
+
* Uses BankValidation.validateAccountNumber() for validation.
|
|
5
|
+
*
|
|
6
|
+
* @param countryCode - The ISO2 country code for validation context
|
|
7
|
+
* @returns Validator function for AntD form rules
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // In form rules
|
|
11
|
+
* rules: [{ required: true, validator: ACCOUNT_NUMBER_VALIDATOR('KE') }]
|
|
12
|
+
*/
|
|
13
|
+
export const ACCOUNT_NUMBER_VALIDATOR = (countryCode) => {
|
|
14
|
+
return (rule, value) => {
|
|
15
|
+
var _a;
|
|
16
|
+
const accountNumberString = value === null || value === void 0 ? void 0 : value.toString().trim();
|
|
17
|
+
// If field is empty/undefined/null
|
|
18
|
+
if (!accountNumberString) {
|
|
19
|
+
if (rule.required) {
|
|
20
|
+
return Promise.reject(new Error("Account number is required."));
|
|
21
|
+
}
|
|
22
|
+
return Promise.resolve(undefined);
|
|
23
|
+
}
|
|
24
|
+
// Remove spaces for validation but keep original format for display
|
|
25
|
+
const normalizedAccountNumber = removeSpaces(accountNumberString);
|
|
26
|
+
if (countryCode) {
|
|
27
|
+
const isValid = BankValidation.validateAccountNumber(normalizedAccountNumber, countryCode);
|
|
28
|
+
if (isValid) {
|
|
29
|
+
return Promise.resolve(normalizedAccountNumber);
|
|
30
|
+
}
|
|
31
|
+
const countryName = (_a = Country.from(countryCode)) === null || _a === void 0 ? void 0 : _a.name;
|
|
32
|
+
const formatHint = getAccountNumberFormatHint(countryCode);
|
|
33
|
+
return Promise.reject(new Error(`Invalid ${countryName} account number format. ${formatHint}`));
|
|
34
|
+
}
|
|
35
|
+
const isValid = BankValidation.validateAccountNumberForAnyCountry(normalizedAccountNumber);
|
|
36
|
+
if (isValid) {
|
|
37
|
+
return Promise.resolve(normalizedAccountNumber);
|
|
38
|
+
}
|
|
39
|
+
return Promise.reject(new Error(`Invalid account number format`));
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
// ==================== UTILITY FUNCTIONS ====================
|
|
43
|
+
/**
|
|
44
|
+
* Removes all whitespace characters from the given string.
|
|
45
|
+
*
|
|
46
|
+
* @param input - The input string from which spaces should be removed
|
|
47
|
+
* @returns A new string with all whitespace characters removed
|
|
48
|
+
*/
|
|
49
|
+
function removeSpaces(input) {
|
|
50
|
+
return input.replace(/\s+/g, "");
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Gets account number format hint based on country.
|
|
54
|
+
*
|
|
55
|
+
* @param countryCode - The ISO2 country code
|
|
56
|
+
* @returns Format hint string for the specific country
|
|
57
|
+
*/
|
|
58
|
+
function getAccountNumberFormatHint(countryCode) {
|
|
59
|
+
const formatHints = {
|
|
60
|
+
TZ: "Account number should be 9-19 characters long.",
|
|
61
|
+
KE: "Account number should be 10, 12, or 15 alphanumeric characters.",
|
|
62
|
+
// Add more country-specific hints as needed
|
|
63
|
+
};
|
|
64
|
+
return formatHints[countryCode] || "Please enter a valid account number.";
|
|
65
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Amount } from "@temboplus/frontend-core";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a validator for monetary amounts using the Amount class.
|
|
4
|
+
* Validates format, currency, and range constraints with currency-specific defaults.
|
|
5
|
+
* Only allows positive amounts (including zero).
|
|
6
|
+
*
|
|
7
|
+
* **Default Range Constraints by Currency:**
|
|
8
|
+
* - **TZS (Tanzanian Shilling)**: Min: 1,000 TZS, Max: 1,000,000 TZS
|
|
9
|
+
* - **KES (Kenyan Shilling)**: Min: 40 KES, Max: 40,000,000 KES
|
|
10
|
+
* - **Other Currencies**: Min: 1, Max: 1,000,000 (in respective currency units)
|
|
11
|
+
*
|
|
12
|
+
* These defaults are applied only when `min` and/or `max` options are not explicitly provided.
|
|
13
|
+
* You can override these defaults by providing explicit `min` and `max` values in the options.
|
|
14
|
+
* Set `min` or `max` to `null` to completely disable that constraint.
|
|
15
|
+
*
|
|
16
|
+
* @param options - Configuration options for amount validation
|
|
17
|
+
* @returns Validator function for AntD form rules
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Basic validation with TZS currency (uses default min: 1,000 TZS, max: 1,000,000 TZS)
|
|
21
|
+
* rules: [{ required: true, validator: AMOUNT_VALIDATOR() }]
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // Basic validation with KES currency (uses default min: 40 KES, max: 40,000,000 KES)
|
|
25
|
+
* rules: [{ required: true, validator: AMOUNT_VALIDATOR({ currencyCode: 'KES' }) }]
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // Override default ranges with custom min/max values
|
|
29
|
+
* rules: [{
|
|
30
|
+
* required: true,
|
|
31
|
+
* validator: AMOUNT_VALIDATOR({
|
|
32
|
+
* currencyCode: 'USD',
|
|
33
|
+
* min: 1, // Custom minimum (overrides default)
|
|
34
|
+
* max: 10000, // Custom maximum (overrides default)
|
|
35
|
+
* })
|
|
36
|
+
* }]
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* // Disable range validation by setting min and max to null
|
|
40
|
+
* rules: [{
|
|
41
|
+
* required: true,
|
|
42
|
+
* validator: AMOUNT_VALIDATOR({
|
|
43
|
+
* currencyCode: 'USD',
|
|
44
|
+
* min: null, // No minimum constraint
|
|
45
|
+
* max: null, // No maximum constraint
|
|
46
|
+
* })
|
|
47
|
+
* }]
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* // Disable only minimum constraint, keep maximum
|
|
51
|
+
* rules: [{
|
|
52
|
+
* required: true,
|
|
53
|
+
* validator: AMOUNT_VALIDATOR({
|
|
54
|
+
* currencyCode: 'TZS',
|
|
55
|
+
* min: null, // No minimum constraint
|
|
56
|
+
* // max uses default (1,000,000 TZS)
|
|
57
|
+
* })
|
|
58
|
+
* }]
|
|
59
|
+
*/
|
|
60
|
+
export const AMOUNT_VALIDATOR = (options = {}) => {
|
|
61
|
+
const { currencyCode = "TZS", invalidFormatMessage, minMessage, maxMessage, } = options;
|
|
62
|
+
const { min: defaultMin, max: defaultMax } = Amount.getTransactionLimits(currencyCode);
|
|
63
|
+
// Use provided values, or fall back to currency-specific defaults
|
|
64
|
+
// If explicitly set to null, no constraint will be applied
|
|
65
|
+
const min = options.min !== undefined ? options.min : defaultMin;
|
|
66
|
+
const max = options.max !== undefined ? options.max : defaultMax;
|
|
67
|
+
return (rule, value) => {
|
|
68
|
+
// Convert value to string for processing
|
|
69
|
+
const amountString = value === null || value === void 0 ? void 0 : value.toString().trim();
|
|
70
|
+
// If field is empty/undefined/null
|
|
71
|
+
if (!amountString) {
|
|
72
|
+
if (rule.required) {
|
|
73
|
+
return Promise.reject(new Error("Amount is required."));
|
|
74
|
+
}
|
|
75
|
+
return Promise.resolve(undefined);
|
|
76
|
+
}
|
|
77
|
+
// Try to create Amount instance
|
|
78
|
+
const amountInstance = Amount.from(amountString, currencyCode);
|
|
79
|
+
if (!amountInstance) {
|
|
80
|
+
return Promise.reject(new Error(invalidFormatMessage ||
|
|
81
|
+
`Invalid amount format. Please enter a valid monetary amount (e.g., "1000", "1,234.56").`));
|
|
82
|
+
}
|
|
83
|
+
// Reject negative amounts (always not allowed)
|
|
84
|
+
if (amountInstance.isNegative()) {
|
|
85
|
+
return Promise.reject(new Error("Negative amounts are not allowed. Please enter a positive amount."));
|
|
86
|
+
}
|
|
87
|
+
// Check minimum constraint (only if min is not null)
|
|
88
|
+
if (min !== null && amountInstance.lessThan(min)) {
|
|
89
|
+
return Promise.reject(new Error(minMessage ||
|
|
90
|
+
`Amount must be at least ${(defaultMin === null || defaultMin === void 0 ? void 0 : defaultMin.label) || min}. Please enter a higher amount.`));
|
|
91
|
+
}
|
|
92
|
+
// Check maximum constraint (only if max is not null)
|
|
93
|
+
if (max !== null && amountInstance.greaterThan(max)) {
|
|
94
|
+
return Promise.reject(new Error(maxMessage ||
|
|
95
|
+
`Amount must not exceed ${(defaultMax === null || defaultMax === void 0 ? void 0 : defaultMax.label) || max}. Please enter a lower amount.`));
|
|
96
|
+
}
|
|
97
|
+
// Return the formatted numeric value (normalized)
|
|
98
|
+
return Promise.resolve(amountInstance.formattedNumericValue);
|
|
99
|
+
};
|
|
100
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Country, PhoneNumberFactory } from "@temboplus/frontend-core";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a validator for general phone numbers that validates format and country.
|
|
4
|
+
* Uses PhoneNumberFactory.canCreate() for validation.
|
|
5
|
+
*
|
|
6
|
+
* @param countryCode - The ISO2 country code for validation context
|
|
7
|
+
* @returns Validator function for AntD form rules
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // In form rules
|
|
11
|
+
* rules: [{ required: true, validator: PHONE_NUMBER_VALIDATOR('TZ') }]
|
|
12
|
+
*/
|
|
13
|
+
export const PHONE_NUMBER_VALIDATOR = (countryCode) => {
|
|
14
|
+
return (rule, value) => {
|
|
15
|
+
var _a;
|
|
16
|
+
const phoneString = value === null || value === void 0 ? void 0 : value.toString().trim();
|
|
17
|
+
// If field is empty/undefined/null
|
|
18
|
+
if (!phoneString) {
|
|
19
|
+
if (rule.required) {
|
|
20
|
+
return Promise.reject(new Error("Phone number is required."));
|
|
21
|
+
}
|
|
22
|
+
return Promise.resolve(undefined);
|
|
23
|
+
}
|
|
24
|
+
const isValid = PhoneNumberFactory.canCreate(phoneString, {
|
|
25
|
+
defaultCountry: countryCode,
|
|
26
|
+
});
|
|
27
|
+
if (isValid) {
|
|
28
|
+
// Return normalized phone number
|
|
29
|
+
const phoneInstance = PhoneNumberFactory.create(phoneString, {
|
|
30
|
+
defaultCountry: countryCode,
|
|
31
|
+
});
|
|
32
|
+
return Promise.resolve((phoneInstance === null || phoneInstance === void 0 ? void 0 : phoneInstance.e164Format) || phoneString);
|
|
33
|
+
}
|
|
34
|
+
if (countryCode) {
|
|
35
|
+
const countryName = (_a = Country.from(countryCode)) === null || _a === void 0 ? void 0 : _a.name;
|
|
36
|
+
return Promise.reject(new Error(`Invalid ${countryName} phone number format. Please enter a valid ${countryName} phone number.`));
|
|
37
|
+
}
|
|
38
|
+
return Promise.reject(new Error("This phone number is invalid."));
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Creates a validator for mobile phone numbers eligible for payout operations.
|
|
43
|
+
* Uses PhoneNumberFactory.checkPayoutEligibility() for validation.
|
|
44
|
+
*
|
|
45
|
+
* @param countryCode - The ISO2 country code for validation context
|
|
46
|
+
* @returns Validator function for AntD form rules
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // In form rules
|
|
50
|
+
* rules: [{ required: true, validator: MOBILE_PHONE_VALIDATOR('TZ') }]
|
|
51
|
+
*/
|
|
52
|
+
export const MOBILE_PHONE_VALIDATOR = (countryCode) => {
|
|
53
|
+
return (rule, value) => {
|
|
54
|
+
var _a;
|
|
55
|
+
const phoneString = value === null || value === void 0 ? void 0 : value.toString().trim();
|
|
56
|
+
// If field is empty/undefined/null
|
|
57
|
+
if (!phoneString) {
|
|
58
|
+
if (rule.required) {
|
|
59
|
+
return Promise.reject(new Error("Mobile phone number is required."));
|
|
60
|
+
}
|
|
61
|
+
return Promise.resolve(undefined);
|
|
62
|
+
}
|
|
63
|
+
const phoneInstance = PhoneNumberFactory.create(phoneString, {
|
|
64
|
+
defaultCountry: countryCode,
|
|
65
|
+
});
|
|
66
|
+
if (!phoneInstance) {
|
|
67
|
+
return Promise.reject(new Error("This phone number is invalid."));
|
|
68
|
+
}
|
|
69
|
+
const isEligibleForPayout = PhoneNumberFactory.checkPayoutEligibility(phoneInstance);
|
|
70
|
+
if (isEligibleForPayout) {
|
|
71
|
+
return Promise.resolve((phoneInstance === null || phoneInstance === void 0 ? void 0 : phoneInstance.e164Format) || phoneString);
|
|
72
|
+
}
|
|
73
|
+
if (countryCode) {
|
|
74
|
+
const countryName = (_a = Country.from(countryCode)) === null || _a === void 0 ? void 0 : _a.name;
|
|
75
|
+
return Promise.reject(new Error(`Invalid ${countryName} phone number format. Please enter a valid ${countryName} phone number.`));
|
|
76
|
+
}
|
|
77
|
+
return Promise.reject(new Error("This phone number is invalid."));
|
|
78
|
+
};
|
|
79
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { BankValidation, Country } from "@temboplus/frontend-core";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a validator for SWIFT/BIC codes specific to a country.
|
|
4
|
+
* Uses BankValidation.validateSwiftCode() for validation.
|
|
5
|
+
*
|
|
6
|
+
* @param countryCode - The ISO2 country code for validation context
|
|
7
|
+
* @returns Validator function for AntD form rules
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // In form rules
|
|
11
|
+
* rules: [{ required: true, validator: SWIFT_CODE_VALIDATOR('TZ') }]
|
|
12
|
+
*/
|
|
13
|
+
export const SWIFT_CODE_VALIDATOR = (countryCode) => {
|
|
14
|
+
return (rule, value) => {
|
|
15
|
+
var _a;
|
|
16
|
+
const swiftCodeString = value === null || value === void 0 ? void 0 : value.toString().trim().toUpperCase();
|
|
17
|
+
// If field is empty/undefined/null
|
|
18
|
+
if (!swiftCodeString) {
|
|
19
|
+
if (rule.required) {
|
|
20
|
+
return Promise.reject(new Error("SWIFT code is required."));
|
|
21
|
+
}
|
|
22
|
+
return Promise.resolve(undefined);
|
|
23
|
+
}
|
|
24
|
+
if (countryCode) {
|
|
25
|
+
const isValid = BankValidation.validateSwiftCode(swiftCodeString, countryCode);
|
|
26
|
+
if (isValid) {
|
|
27
|
+
return Promise.resolve(swiftCodeString);
|
|
28
|
+
}
|
|
29
|
+
const countryName = (_a = Country.from(countryCode)) === null || _a === void 0 ? void 0 : _a.name;
|
|
30
|
+
return Promise.reject(new Error(`Invalid ${countryName} SWIFT code. Please enter a valid ${countryName} bank SWIFT/BIC code.`));
|
|
31
|
+
}
|
|
32
|
+
const isValid = BankValidation.validateSwiftCodeForAnyCountry(swiftCodeString);
|
|
33
|
+
if (isValid) {
|
|
34
|
+
return Promise.resolve(swiftCodeString);
|
|
35
|
+
}
|
|
36
|
+
return Promise.reject(new Error(`Invalid SWIFT code. Please enter a valid supported bank SWIFT/BIC code.`));
|
|
37
|
+
};
|
|
38
|
+
};
|