@temboplus/frontend-react-core 0.1.3-beta.9 → 0.1.4
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/LICENSE +15 -0
- package/README.md +80 -334
- package/dist/index.cjs.js +15 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +4 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/timezone/index.cjs.js +16 -0
- package/dist/{notifications → timezone}/index.cjs.js.map +1 -1
- package/dist/timezone/index.d.ts +4 -0
- package/dist/timezone/index.d.ts.map +1 -0
- package/dist/timezone/index.js +5 -0
- package/dist/{notifications → timezone}/index.js.map +1 -1
- package/dist/timezone/use-format-date.d.ts +23 -0
- package/dist/timezone/use-format-date.d.ts.map +1 -0
- package/dist/timezone/use-timezone-date.d.ts +18 -0
- package/dist/timezone/use-timezone-date.d.ts.map +1 -0
- package/dist/timezone/use-timezone.d.ts +20 -0
- package/dist/timezone/use-timezone.d.ts.map +1 -0
- package/dist/use-timezone-date-B-P03WD_.js +81 -0
- package/dist/use-timezone-date-B-P03WD_.js.map +1 -0
- package/dist/use-timezone-date-s1Ru9Fw6.js +88 -0
- package/dist/use-timezone-date-s1Ru9Fw6.js.map +1 -0
- package/package.json +58 -63
- package/dist/InfoCircleOutlined-B7d2aRfV.js +0 -7
- package/dist/InfoCircleOutlined-B7d2aRfV.js.map +0 -1
- package/dist/InfoCircleOutlined-DYs90hdV.js +0 -7
- package/dist/InfoCircleOutlined-DYs90hdV.js.map +0 -1
- package/dist/ZoomOutOutlined-CW-jqBMI.js +0 -2
- package/dist/ZoomOutOutlined-CW-jqBMI.js.map +0 -1
- package/dist/ZoomOutOutlined-Pw8hpWWK.js +0 -2
- package/dist/ZoomOutOutlined-Pw8hpWWK.js.map +0 -1
- package/dist/alerts/index.cjs.js +0 -2
- package/dist/alerts/index.cjs.js.map +0 -1
- package/dist/alerts/index.d.ts +0 -1
- package/dist/alerts/index.js +0 -2
- package/dist/alerts/index.js.map +0 -1
- package/dist/dialogs/index.cjs.js +0 -2
- package/dist/dialogs/index.cjs.js.map +0 -1
- package/dist/dialogs/index.d.ts +0 -1
- package/dist/dialogs/index.js +0 -2
- package/dist/dialogs/index.js.map +0 -1
- package/dist/features/alerts/alert.d.ts +0 -12
- package/dist/features/alerts/alert.js +0 -95
- package/dist/features/alerts/index.d.ts +0 -1
- package/dist/features/alerts/index.js +0 -1
- package/dist/features/dialogs/index.d.ts +0 -1
- package/dist/features/dialogs/index.js +0 -1
- package/dist/features/dialogs/modal-provider.d.ts +0 -3
- package/dist/features/dialogs/modal-provider.js +0 -6
- package/dist/features/dialogs/tembo-confirm.d.ts +0 -63
- package/dist/features/dialogs/tembo-confirm.js +0 -111
- package/dist/features/input-validation/account-name-validator.d.ts +0 -13
- package/dist/features/input-validation/account-name-validator.js +0 -28
- package/dist/features/input-validation/account-number-validator.d.ts +0 -13
- package/dist/features/input-validation/account-number-validator.js +0 -65
- package/dist/features/input-validation/amount-validator.d.ts +0 -78
- package/dist/features/input-validation/amount-validator.js +0 -100
- package/dist/features/input-validation/index.d.ts +0 -5
- package/dist/features/input-validation/index.js +0 -5
- package/dist/features/input-validation/phone-number-validator.d.ts +0 -25
- package/dist/features/input-validation/phone-number-validator.js +0 -79
- package/dist/features/input-validation/swift-code-validator.d.ts +0 -13
- package/dist/features/input-validation/swift-code-validator.js +0 -38
- package/dist/features/notifications/index.d.ts +0 -3
- package/dist/features/notifications/index.js +0 -3
- package/dist/features/notifications/tembo-notify.d.ts +0 -50
- package/dist/features/notifications/tembo-notify.js +0 -140
- package/dist/features/notifications/toast-config.d.ts +0 -12
- package/dist/features/notifications/toast-config.js +0 -60
- package/dist/features/notifications/toast-container.d.ts +0 -19
- package/dist/features/notifications/toast-container.js +0 -89
- package/dist/index.js +0 -1
- package/dist/notifications/index.cjs.js +0 -2
- package/dist/notifications/index.d.ts +0 -1
- package/dist/notifications/index.js +0 -2
- package/dist/providers.d.ts +0 -37
- package/dist/providers.js +0 -32
- package/dist/tembo-notify-Bp14qngd.js +0 -2
- package/dist/tembo-notify-Bp14qngd.js.map +0 -1
- package/dist/tembo-notify-h5Xn66oA.js +0 -2
- package/dist/tembo-notify-h5Xn66oA.js.map +0 -1
- package/dist/theme/colors.d.ts +0 -278
- package/dist/theme/colors.js +0 -212
- package/dist/theme/constants.d.ts +0 -143
- package/dist/theme/constants.js +0 -82
- package/dist/theme/index.cjs.js +0 -2
- package/dist/theme/index.cjs.js.map +0 -1
- package/dist/theme/index.d.ts +0 -3
- package/dist/theme/index.js +0 -2
- package/dist/theme/index.js.map +0 -1
- package/dist/theme/theme-provider.d.ts +0 -99
- package/dist/theme/theme-provider.js +0 -404
- package/dist/theme-provider-Ca4P0Hcp.js +0 -11
- package/dist/theme-provider-Ca4P0Hcp.js.map +0 -1
- package/dist/theme-provider-RhAw3jw_.js +0 -11
- package/dist/theme-provider-RhAw3jw_.js.map +0 -1
- package/dist/validation/index.cjs.js +0 -2
- package/dist/validation/index.cjs.js.map +0 -1
- package/dist/validation/index.d.ts +0 -1
- package/dist/validation/index.js +0 -2
- package/dist/validation/index.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 TemboPlus
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,385 +1,131 @@
|
|
|
1
1
|
# @temboplus/frontend-react-core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React hooks that wrap pure helpers from [`@temboplus/frontend-core`](https://github.com/TemboPlus-Frontend/frontend-core-js) for use in React applications across the TemboPlus platform.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Today the package ships one feature area — timezone — with more to be added as React-flavored counterparts to frontend-core utilities are needed.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
|
-
|
|
9
|
-
# or
|
|
10
|
-
yarn add @temboplus/frontend-react-core
|
|
10
|
+
bun add @temboplus/frontend-react-core
|
|
11
11
|
# or
|
|
12
|
-
|
|
12
|
+
npm install @temboplus/frontend-react-core
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
This package requires the following peer dependencies:
|
|
15
|
+
Peer dependency:
|
|
18
16
|
|
|
19
17
|
```bash
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## 🚀 Quick Start
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
import { PHONE_NUMBER_VALIDATOR, AMOUNT_VALIDATOR } from '@temboplus/frontend-react-core';
|
|
27
|
-
|
|
28
|
-
// Use in your Ant Design form
|
|
29
|
-
const formRules = {
|
|
30
|
-
phoneNumber: [{ required: true, validator: PHONE_NUMBER_VALIDATOR('TZ') }],
|
|
31
|
-
amount: [{ required: true, validator: AMOUNT_VALIDATOR({ currencyCode: 'TZS' }) }]
|
|
32
|
-
};
|
|
18
|
+
bun add react
|
|
33
19
|
```
|
|
34
20
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
### ✅ Form Validators (Available Now)
|
|
38
|
-
|
|
39
|
-
Type-safe, country-aware form validators for Ant Design forms with built-in internationalization and error messaging.
|
|
40
|
-
|
|
41
|
-
### 🔄 Coming Soon
|
|
21
|
+
Runtime dependency (auto-installed):
|
|
42
22
|
|
|
43
|
-
-
|
|
44
|
-
- **Hooks Library** - Custom React hooks for common patterns
|
|
45
|
-
- **Context Providers** - Application-wide state management
|
|
46
|
-
- **Theme System** - Consistent design tokens and styling
|
|
47
|
-
- **Utility Functions** - Helper functions for React applications
|
|
23
|
+
- `@temboplus/frontend-core` — the pure utilities and domain entities the hooks wrap.
|
|
48
24
|
|
|
49
|
-
##
|
|
25
|
+
## Subpath imports
|
|
50
26
|
|
|
51
|
-
|
|
27
|
+
Import the focused surface or the root entry; both work:
|
|
52
28
|
|
|
53
|
-
|
|
29
|
+
```ts
|
|
30
|
+
// Focused (recommended — keeps your bundles honest):
|
|
31
|
+
import { useTimezone } from "@temboplus/frontend-react-core/timezone";
|
|
54
32
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
Validates general phone number format using libphonenumber-js.
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
import { PHONE_NUMBER_VALIDATOR } from '@temboplus/frontend-react-core';
|
|
61
|
-
|
|
62
|
-
// Basic usage
|
|
63
|
-
const rules = [{ required: true, validator: PHONE_NUMBER_VALIDATOR('TZ') }];
|
|
64
|
-
|
|
65
|
-
// Supported countries: TZ, KE, and all libphonenumber-js supported countries
|
|
33
|
+
// Or the root:
|
|
34
|
+
import { useTimezone } from "@temboplus/frontend-react-core";
|
|
66
35
|
```
|
|
67
36
|
|
|
68
|
-
|
|
69
|
-
- Validates phone number format for any country
|
|
70
|
-
- Returns normalized E.164 format on success
|
|
71
|
-
- Country-specific error messages
|
|
72
|
-
- Supports international and local number formats
|
|
73
|
-
|
|
74
|
-
#### `MOBILE_PHONE_VALIDATOR(countryCode?: ISO2CountryCode)`
|
|
75
|
-
|
|
76
|
-
Validates mobile phone numbers eligible for payout operations (stricter validation).
|
|
37
|
+
## Timezone hooks
|
|
77
38
|
|
|
78
|
-
|
|
79
|
-
import { MOBILE_PHONE_VALIDATOR } from '@temboplus/frontend-react-core';
|
|
39
|
+
Each app passes its own `storageKey` so timezone preferences don't collide across products sharing a browser origin. Wrap once in your app and use the bare hook everywhere:
|
|
80
40
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
#### `ACCOUNT_NAME_VALIDATOR`
|
|
91
|
-
|
|
92
|
-
Validates bank account holder names.
|
|
41
|
+
```ts
|
|
42
|
+
// src/shared/lib/timezone.ts (or similar)
|
|
43
|
+
import {
|
|
44
|
+
useTimezone as useTimezoneBase,
|
|
45
|
+
useTimezoneDate as useTimezoneDateBase,
|
|
46
|
+
useFormatDate as useFormatDateBase,
|
|
47
|
+
useFormatDateTime as useFormatDateTimeBase,
|
|
48
|
+
useFormatTime as useFormatTimeBase,
|
|
49
|
+
} from "@temboplus/frontend-react-core/timezone";
|
|
93
50
|
|
|
94
|
-
|
|
95
|
-
import { ACCOUNT_NAME_VALIDATOR } from '@temboplus/frontend-react-core';
|
|
51
|
+
const STORAGE_KEY = "myapp.timezone";
|
|
96
52
|
|
|
97
|
-
const
|
|
53
|
+
export const useTimezone = () => useTimezoneBase({ storageKey: STORAGE_KEY });
|
|
54
|
+
export const useTimezoneDate = () => useTimezoneDateBase({ storageKey: STORAGE_KEY });
|
|
55
|
+
export const useFormatDate = () => useFormatDateBase({ storageKey: STORAGE_KEY });
|
|
56
|
+
export const useFormatDateTime = () => useFormatDateTimeBase({ storageKey: STORAGE_KEY });
|
|
57
|
+
export const useFormatTime = () => useFormatTimeBase({ storageKey: STORAGE_KEY });
|
|
98
58
|
```
|
|
99
59
|
|
|
100
|
-
|
|
101
|
-
- 3-50 characters length
|
|
102
|
-
- Only letters, spaces, hyphens, apostrophes, commas
|
|
103
|
-
- At least two words (first name + last name)
|
|
104
|
-
- Not all uppercase
|
|
105
|
-
- No numbers or special characters
|
|
60
|
+
### `useTimezone()`
|
|
106
61
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
Validates SWIFT/BIC codes for banks.
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
import { SWIFT_CODE_VALIDATOR } from '@temboplus/frontend-react-core';
|
|
113
|
-
|
|
114
|
-
// Country-specific validation
|
|
115
|
-
const rules = [{ required: true, validator: SWIFT_CODE_VALIDATOR('TZ') }];
|
|
116
|
-
|
|
117
|
-
// Multi-country validation
|
|
118
|
-
const rules = [{ required: true, validator: SWIFT_CODE_VALIDATOR() }];
|
|
62
|
+
```ts
|
|
63
|
+
const [timezone, setTimezone] = useTimezone();
|
|
119
64
|
```
|
|
120
65
|
|
|
121
|
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
- Automatic uppercase conversion
|
|
125
|
-
- Real bank verification
|
|
126
|
-
|
|
127
|
-
#### `ACCOUNT_NUMBER_VALIDATOR(countryCode?: ISO2CountryCode)`
|
|
128
|
-
|
|
129
|
-
Validates bank account numbers with country-specific formats.
|
|
66
|
+
- Reads from `localStorage[storageKey]` on mount (after first paint, to avoid SSR mismatch).
|
|
67
|
+
- Falls back to `DEFAULT_TIMEZONE` (`"Africa/Nairobi"`) when nothing's stored.
|
|
68
|
+
- `setTimezone(next)` validates against `Intl.supportedValuesOf("timeZone")` plus TemboPlus operating/anchor zones, then persists.
|
|
130
69
|
|
|
131
|
-
|
|
132
|
-
import { ACCOUNT_NUMBER_VALIDATOR } from '@temboplus/frontend-react-core';
|
|
70
|
+
### `useTimezoneDate()`
|
|
133
71
|
|
|
134
|
-
|
|
135
|
-
```
|
|
72
|
+
Boundary helpers bound to the current timezone preference. Re-memoises when the preference changes.
|
|
136
73
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
- **Tanzania (TZ)**: 9-19 characters
|
|
140
|
-
- Automatic space removal and normalization
|
|
141
|
-
|
|
142
|
-
#### `AMOUNT_VALIDATOR(options?: AmountValidatorOptions)`
|
|
143
|
-
|
|
144
|
-
Validates monetary amounts with currency-specific constraints.
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
import { AMOUNT_VALIDATOR } from '@temboplus/frontend-react-core';
|
|
148
|
-
|
|
149
|
-
// Basic usage with defaults
|
|
150
|
-
const rules = [{ required: true, validator: AMOUNT_VALIDATOR() }];
|
|
151
|
-
|
|
152
|
-
// Custom configuration
|
|
153
|
-
const rules = [{
|
|
154
|
-
required: true,
|
|
155
|
-
validator: AMOUNT_VALIDATOR({
|
|
156
|
-
currencyCode: 'KES',
|
|
157
|
-
min: 100,
|
|
158
|
-
max: 50000,
|
|
159
|
-
invalidFormatMessage: 'Please enter a valid amount',
|
|
160
|
-
minMessage: 'Minimum amount is 100 KES',
|
|
161
|
-
maxMessage: 'Maximum amount is 50,000 KES'
|
|
162
|
-
})
|
|
163
|
-
}];
|
|
164
|
-
|
|
165
|
-
// Disable constraints
|
|
166
|
-
const rules = [{
|
|
167
|
-
required: true,
|
|
168
|
-
validator: AMOUNT_VALIDATOR({
|
|
169
|
-
currencyCode: 'USD',
|
|
170
|
-
min: null, // No minimum
|
|
171
|
-
max: null, // No maximum
|
|
172
|
-
})
|
|
173
|
-
}];
|
|
174
|
-
```
|
|
74
|
+
```ts
|
|
75
|
+
const { tz, startOfDay, endOfDay, parse, sameDay, toUtc } = useTimezoneDate();
|
|
175
76
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
- **Other**: Min: 1, Max: 1,000,000
|
|
180
|
-
|
|
181
|
-
**Options:**
|
|
182
|
-
```typescript
|
|
183
|
-
interface AmountValidatorOptions {
|
|
184
|
-
currencyCode?: CurrencyCode; // Default: 'TZS'
|
|
185
|
-
min?: number | null; // Default: currency-specific
|
|
186
|
-
max?: number | null; // Default: currency-specific
|
|
187
|
-
invalidFormatMessage?: string; // Custom error message
|
|
188
|
-
minMessage?: string; // Custom minimum error
|
|
189
|
-
maxMessage?: string; // Custom maximum error
|
|
190
|
-
}
|
|
77
|
+
const utcStart = startOfDay(pickerDate); // UTC instant of midnight in `tz`
|
|
78
|
+
const utcEnd = endOfDay(pickerDate);
|
|
79
|
+
const zoned = parse("2026-05-15T00:00:00Z"); // TZDate; getDate() reports `tz` wall clock
|
|
191
80
|
```
|
|
192
81
|
|
|
193
|
-
|
|
194
|
-
- Supports all currencies from @temboplus/frontend-core
|
|
195
|
-
- Handles comma-separated numbers (1,000.50)
|
|
196
|
-
- Rejects negative amounts
|
|
197
|
-
- Currency-specific formatting
|
|
198
|
-
- Returns normalized numeric format
|
|
199
|
-
|
|
200
|
-
## 🎯 Usage Examples
|
|
82
|
+
### `useFormatDate*()`
|
|
201
83
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
import React from 'react';
|
|
206
|
-
import { Form, Input, Button } from 'antd';
|
|
207
|
-
import {
|
|
208
|
-
PHONE_NUMBER_VALIDATOR,
|
|
209
|
-
AMOUNT_VALIDATOR,
|
|
210
|
-
ACCOUNT_NAME_VALIDATOR,
|
|
211
|
-
SWIFT_CODE_VALIDATOR,
|
|
212
|
-
ACCOUNT_NUMBER_VALIDATOR,
|
|
213
|
-
} from '@temboplus/frontend-react-core';
|
|
214
|
-
|
|
215
|
-
const PayoutForm: React.FC = () => {
|
|
216
|
-
const [form] = Form.useForm();
|
|
217
|
-
|
|
218
|
-
const onFinish = (values: any) => {
|
|
219
|
-
console.log('Validated values:', values);
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
return (
|
|
223
|
-
<Form form={form} onFinish={onFinish} layout="vertical">
|
|
224
|
-
<Form.Item
|
|
225
|
-
label="Phone Number"
|
|
226
|
-
name="phoneNumber"
|
|
227
|
-
rules={[{ required: true, validator: PHONE_NUMBER_VALIDATOR('TZ') }]}
|
|
228
|
-
>
|
|
229
|
-
<Input placeholder="+255 712 345 678" />
|
|
230
|
-
</Form.Item>
|
|
231
|
-
|
|
232
|
-
<Form.Item
|
|
233
|
-
label="Amount"
|
|
234
|
-
name="amount"
|
|
235
|
-
rules={[{
|
|
236
|
-
required: true,
|
|
237
|
-
validator: AMOUNT_VALIDATOR({
|
|
238
|
-
currencyCode: 'TZS',
|
|
239
|
-
min: 1000,
|
|
240
|
-
max: 100000
|
|
241
|
-
})
|
|
242
|
-
}]}
|
|
243
|
-
>
|
|
244
|
-
<Input placeholder="10,000" />
|
|
245
|
-
</Form.Item>
|
|
246
|
-
|
|
247
|
-
<Form.Item
|
|
248
|
-
label="Account Name"
|
|
249
|
-
name="accountName"
|
|
250
|
-
rules={[{ required: true, validator: ACCOUNT_NAME_VALIDATOR }]}
|
|
251
|
-
>
|
|
252
|
-
<Input placeholder="John Smith" />
|
|
253
|
-
</Form.Item>
|
|
254
|
-
|
|
255
|
-
<Form.Item
|
|
256
|
-
label="Bank SWIFT Code"
|
|
257
|
-
name="swiftCode"
|
|
258
|
-
rules={[{ required: true, validator: SWIFT_CODE_VALIDATOR('TZ') }]}
|
|
259
|
-
>
|
|
260
|
-
<Input placeholder="CORUTZTZ" />
|
|
261
|
-
</Form.Item>
|
|
262
|
-
|
|
263
|
-
<Form.Item
|
|
264
|
-
label="Account Number"
|
|
265
|
-
name="accountNumber"
|
|
266
|
-
rules={[{ required: true, validator: ACCOUNT_NUMBER_VALIDATOR('TZ') }]}
|
|
267
|
-
>
|
|
268
|
-
<Input placeholder="123456789" />
|
|
269
|
-
</Form.Item>
|
|
270
|
-
|
|
271
|
-
<Form.Item>
|
|
272
|
-
<Button type="primary" htmlType="submit">
|
|
273
|
-
Submit
|
|
274
|
-
</Button>
|
|
275
|
-
</Form.Item>
|
|
276
|
-
</Form>
|
|
277
|
-
);
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
export default PayoutForm;
|
|
281
|
-
```
|
|
84
|
+
Reactive formatters. Re-render automatically when the user changes their timezone preference.
|
|
282
85
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
import { useState } from 'react';
|
|
287
|
-
import { PHONE_NUMBER_VALIDATOR, AMOUNT_VALIDATOR } from '@temboplus/frontend-react-core';
|
|
288
|
-
|
|
289
|
-
const MultiCountryForm: React.FC = () => {
|
|
290
|
-
const [selectedCountry, setSelectedCountry] = useState<'TZ' | 'KE'>('TZ');
|
|
291
|
-
|
|
292
|
-
const getValidationRules = () => ({
|
|
293
|
-
phoneNumber: [{
|
|
294
|
-
required: true,
|
|
295
|
-
validator: PHONE_NUMBER_VALIDATOR(selectedCountry)
|
|
296
|
-
}],
|
|
297
|
-
amount: [{
|
|
298
|
-
required: true,
|
|
299
|
-
validator: AMOUNT_VALIDATOR({
|
|
300
|
-
currencyCode: selectedCountry === 'TZ' ? 'TZS' : 'KES'
|
|
301
|
-
})
|
|
302
|
-
}]
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
// Rest of component...
|
|
306
|
-
};
|
|
86
|
+
```ts
|
|
87
|
+
const fmtDateTime = useFormatDateTime();
|
|
88
|
+
return <span>{fmtDateTime(row.createdAt)}</span>; // "25 MAY 2026, 02:30 PM"
|
|
307
89
|
```
|
|
308
90
|
|
|
309
|
-
|
|
91
|
+
Available variants:
|
|
310
92
|
|
|
311
|
-
|
|
|
312
|
-
|
|
313
|
-
|
|
|
314
|
-
|
|
|
315
|
-
|
|
|
93
|
+
| Hook | Output |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `useFormatDate` | `25 MAY 2026` |
|
|
96
|
+
| `useFormatDateTime` | `25 MAY 2026, 02:30 PM` |
|
|
97
|
+
| `useFormatDateTimeWithSeconds` | `25 MAY 2026, 02:30:45 PM` |
|
|
98
|
+
| `useFormatTime` | `02:30 PM` |
|
|
316
99
|
|
|
317
|
-
|
|
100
|
+
For non-React call sites, the imperative siblings live in [`@temboplus/frontend-core`](https://github.com/TemboPlus-Frontend/frontend-core-js):
|
|
318
101
|
|
|
319
|
-
|
|
102
|
+
```ts
|
|
103
|
+
import { formatDateTime } from "@temboplus/frontend-core";
|
|
320
104
|
|
|
321
|
-
|
|
322
|
-
// Phone validation errors
|
|
323
|
-
"Invalid Tanzania phone number format. Please enter a valid Tanzania phone number."
|
|
324
|
-
|
|
325
|
-
// Amount validation errors
|
|
326
|
-
"Amount must be at least TSh 1,000. Please enter a higher amount."
|
|
327
|
-
"Negative amounts are not allowed. Please enter a positive amount."
|
|
328
|
-
|
|
329
|
-
// Account name errors
|
|
330
|
-
"Invalid account name. Please enter a valid full name with at least two words."
|
|
331
|
-
|
|
332
|
-
// SWIFT code errors
|
|
333
|
-
"Invalid Tanzania SWIFT code. Please enter a valid Tanzania bank SWIFT/BIC code."
|
|
105
|
+
formatDateTime(date, "Africa/Nairobi"); // "25 MAY 2026, 02:30 PM"
|
|
334
106
|
```
|
|
335
107
|
|
|
336
|
-
##
|
|
337
|
-
|
|
338
|
-
### 1. Always Specify Country Context
|
|
339
|
-
```typescript
|
|
340
|
-
// ✅ Good - specific country validation
|
|
341
|
-
validator: PHONE_NUMBER_VALIDATOR('TZ')
|
|
342
|
-
|
|
343
|
-
// ❌ Less ideal - generic validation
|
|
344
|
-
validator: PHONE_NUMBER_VALIDATOR()
|
|
345
|
-
```
|
|
108
|
+
## Development
|
|
346
109
|
|
|
347
|
-
|
|
348
|
-
```typescript
|
|
349
|
-
// ✅ Good - explicit required validation
|
|
350
|
-
rules: [
|
|
351
|
-
{ required: true, message: 'Phone number is required' },
|
|
352
|
-
{ validator: PHONE_NUMBER_VALIDATOR('TZ') }
|
|
353
|
-
]
|
|
110
|
+
Bun for everything, Biome for lint+format, mise for the toolchain pin.
|
|
354
111
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
### 3. Custom Error Messages
|
|
360
|
-
```typescript
|
|
361
|
-
// ✅ Good - custom business-specific messages
|
|
362
|
-
validator: AMOUNT_VALIDATOR({
|
|
363
|
-
currencyCode: 'TZS',
|
|
364
|
-
min: 5000,
|
|
365
|
-
minMessage: 'Minimum transfer amount is TSh 5,000 for international transfers'
|
|
366
|
-
})
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
### 4. Normalize Return Values
|
|
370
|
-
```typescript
|
|
371
|
-
const onFinish = (values: any) => {
|
|
372
|
-
// Validators return normalized values
|
|
373
|
-
console.log(values.phoneNumber); // "+255712345678" (E.164 format)
|
|
374
|
-
console.log(values.amount); // "10000.00" (normalized number)
|
|
375
|
-
console.log(values.swiftCode); // "CORUTZTZ" (uppercase)
|
|
376
|
-
};
|
|
112
|
+
```bash
|
|
113
|
+
mise install # one-time: installs pinned Bun
|
|
114
|
+
bun install
|
|
115
|
+
bun run dev # rollup build in watch mode
|
|
377
116
|
```
|
|
378
117
|
|
|
379
|
-
|
|
118
|
+
| Script | Does |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| `bun run dev` | Rollup build in watch mode |
|
|
121
|
+
| `bun run build` | `tsc` declarations + Rollup bundles to `dist/` (CJS + ESM, each with a `"use client"` banner) |
|
|
122
|
+
| `bun run test` | `bun:test` (passes with zero tests; smoke test only — bun:test has no DOM, so real hook tests live in consumer apps) |
|
|
123
|
+
| `bun run lint` | Biome check |
|
|
124
|
+
| `bun run format` | Biome auto-fix |
|
|
125
|
+
| `bun run typecheck` | `tsc --noEmit` |
|
|
380
126
|
|
|
381
|
-
|
|
127
|
+
Tag-driven releases via `.github/workflows/release.yml` — update `CHANGELOG.md`, bump `package.json`, push a `vX.Y.Z` tag.
|
|
382
128
|
|
|
383
|
-
##
|
|
129
|
+
## License
|
|
384
130
|
|
|
385
|
-
|
|
131
|
+
[ISC](./LICENSE) © TemboPlus
|
package/dist/index.cjs.js
CHANGED
|
@@ -1,2 +1,16 @@
|
|
|
1
|
-
"use
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var useTimezoneDate = require('./use-timezone-date-s1Ru9Fw6.js');
|
|
5
|
+
require('@temboplus/frontend-core');
|
|
6
|
+
require('react');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
exports.useFormatDate = useTimezoneDate.useFormatDate;
|
|
11
|
+
exports.useFormatDateTime = useTimezoneDate.useFormatDateTime;
|
|
12
|
+
exports.useFormatDateTimeWithSeconds = useTimezoneDate.useFormatDateTimeWithSeconds;
|
|
13
|
+
exports.useFormatTime = useTimezoneDate.useFormatTime;
|
|
14
|
+
exports.useTimezone = useTimezoneDate.useTimezone;
|
|
15
|
+
exports.useTimezoneDate = useTimezoneDate.useTimezoneDate;
|
|
2
16
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":[
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from "./
|
|
1
|
+
export * from "./timezone/index.js";
|
|
2
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC"}
|
package/dist/index.esm.js
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
export { u as useFormatDate, a as useFormatDateTime, b as useFormatDateTimeWithSeconds, c as useFormatTime, d as useTimezone, e as useTimezoneDate } from './use-timezone-date-B-P03WD_.js';
|
|
3
|
+
import '@temboplus/frontend-core';
|
|
4
|
+
import 'react';
|
|
2
5
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":[
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var useTimezoneDate = require('../use-timezone-date-s1Ru9Fw6.js');
|
|
5
|
+
require('@temboplus/frontend-core');
|
|
6
|
+
require('react');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
exports.useFormatDate = useTimezoneDate.useFormatDate;
|
|
11
|
+
exports.useFormatDateTime = useTimezoneDate.useFormatDateTime;
|
|
12
|
+
exports.useFormatDateTimeWithSeconds = useTimezoneDate.useFormatDateTimeWithSeconds;
|
|
13
|
+
exports.useFormatTime = useTimezoneDate.useFormatTime;
|
|
14
|
+
exports.useTimezone = useTimezoneDate.useTimezone;
|
|
15
|
+
exports.useTimezoneDate = useTimezoneDate.useTimezoneDate;
|
|
16
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/timezone/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
export { u as useFormatDate, a as useFormatDateTime, b as useFormatDateTimeWithSeconds, c as useFormatTime, d as useTimezone, e as useTimezoneDate } from '../use-timezone-date-B-P03WD_.js';
|
|
3
|
+
import '@temboplus/frontend-core';
|
|
4
|
+
import 'react';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralised, reactive date-formatter hooks. Each returns a function
|
|
3
|
+
* `(date: Date) => string` bound to the user's current timezone
|
|
4
|
+
* preference. Consumers re-render automatically when the preference
|
|
5
|
+
* changes in Settings.
|
|
6
|
+
*
|
|
7
|
+
* For non-React call sites, import the imperative siblings directly
|
|
8
|
+
* from `@temboplus/frontend-core`.
|
|
9
|
+
*/
|
|
10
|
+
type Options = {
|
|
11
|
+
storageKey: string;
|
|
12
|
+
defaultTimezone?: string;
|
|
13
|
+
};
|
|
14
|
+
/** `25 MAY 2026` */
|
|
15
|
+
export declare function useFormatDate(options: Options): (date: Date) => string;
|
|
16
|
+
/** `25 MAY 2026, 02:30 PM` */
|
|
17
|
+
export declare function useFormatDateTime(options: Options): (date: Date) => string;
|
|
18
|
+
/** `25 MAY 2026, 02:30:45 PM` — audit rows where seconds matter. */
|
|
19
|
+
export declare function useFormatDateTimeWithSeconds(options: Options): (date: Date) => string;
|
|
20
|
+
/** `02:30 PM` */
|
|
21
|
+
export declare function useFormatTime(options: Options): (date: Date) => string;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=use-format-date.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-format-date.d.ts","sourceRoot":"","sources":["../../src/timezone/use-format-date.ts"],"names":[],"mappings":"AAYA;;;;;;;;GAQG;AAEH,KAAK,OAAO,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhE,oBAAoB;AACpB,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAGtE;AAED,8BAA8B;AAC9B,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAG1E;AAED,oEAAoE;AACpE,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,OAAO,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAGrF;AAED,iBAAiB;AACjB,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAGtE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { toUtcInstant } from "@temboplus/frontend-core";
|
|
2
|
+
/**
|
|
3
|
+
* Boundary helpers bound to the user's current timezone preference.
|
|
4
|
+
* Re-memoises when the preference changes so date pickers / range
|
|
5
|
+
* builders pick up the new offset automatically.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useTimezoneDate(options: {
|
|
8
|
+
storageKey: string;
|
|
9
|
+
defaultTimezone?: string;
|
|
10
|
+
}): {
|
|
11
|
+
tz: string;
|
|
12
|
+
startOfDay: (date: Date) => Date;
|
|
13
|
+
endOfDay: (date: Date) => Date;
|
|
14
|
+
parse: (iso: string) => import("@date-fns/tz").TZDate;
|
|
15
|
+
sameDay: (a: Date, b: Date) => boolean;
|
|
16
|
+
toUtc: typeof toUtcInstant;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=use-timezone-date.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-timezone-date.d.ts","sourceRoot":"","sources":["../../src/timezone/use-timezone-date.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,YAAY,EACb,MAAM,0BAA0B,CAAC;AAKlC;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE;;uBAKhE,IAAI;qBACN,IAAI;iBACR,MAAM;iBACN,IAAI,KAAK,IAAI;;EAK/B"}
|