@pagamio/frontend-commons-lib 0.8.340 → 0.8.342
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.
|
@@ -66,9 +66,10 @@ export interface PhonePinLoginConfig {
|
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
68
68
|
* Configuration for the username + PIN login tab.
|
|
69
|
-
* When provided,
|
|
70
|
-
* tabs.
|
|
71
|
-
*
|
|
69
|
+
* When provided, an "Operator ID + PIN" tab is displayed alongside the other
|
|
70
|
+
* tabs. Operator IDs are admin-assigned 10-digit numeric identifiers (the
|
|
71
|
+
* underlying API field stays `loginNumber`; only the user-facing copy has
|
|
72
|
+
* been renamed to align with the mobile Welcome Back screen).
|
|
72
73
|
*/
|
|
73
74
|
export interface UsernamePinLoginConfig {
|
|
74
75
|
/** Login with login number and PIN. Should throw on error. */
|
|
@@ -77,7 +78,7 @@ export interface UsernamePinLoginConfig {
|
|
|
77
78
|
* Optional callback called instead of onLoginSuccess when mustChangePIN is true.
|
|
78
79
|
*/
|
|
79
80
|
onMustChangePIN?: (loginNumber: string, response: any) => void;
|
|
80
|
-
/** Optional label for the username-PIN tab (default: '
|
|
81
|
+
/** Optional label for the username-PIN tab (default: 'Operator ID') */
|
|
81
82
|
tabLabel?: string;
|
|
82
83
|
/** Optional label for the password tab (default: 'Email & Password') */
|
|
83
84
|
passwordTabLabel?: string;
|
|
@@ -164,8 +165,9 @@ interface PagamioLoginPageProps<T extends CustomAuthConfig> extends BaseAuthPage
|
|
|
164
165
|
*/
|
|
165
166
|
phonePinConfig?: PhonePinLoginConfig;
|
|
166
167
|
/**
|
|
167
|
-
* When provided, adds
|
|
168
|
-
* form. The tab handles the 2-step
|
|
168
|
+
* When provided, adds an "Operator ID" tab alongside the standard login
|
|
169
|
+
* form. The tab handles the 2-step Operator ID + PIN flow internally.
|
|
170
|
+
* (Underlying API field name stays `loginNumber`.)
|
|
169
171
|
*/
|
|
170
172
|
usernamePinConfig?: UsernamePinLoginConfig;
|
|
171
173
|
}
|
|
@@ -53,7 +53,18 @@ export function PagamioLoginPage({ logo, text = loginPageDefaultText, appLabel,
|
|
|
53
53
|
const [isLoading, setIsLoading] = useState(false);
|
|
54
54
|
const [error, setError] = useState(null);
|
|
55
55
|
const formRef = useRef(null);
|
|
56
|
-
|
|
56
|
+
// Default-active tab follows the "phone-first" hierarchy from the
|
|
57
|
+
// commerce-os mobile Welcome Back screen: Phone → Operator ID → Email.
|
|
58
|
+
// Falls back to whichever tab is actually configured when the others
|
|
59
|
+
// aren't enabled, so single-tab consumers keep working unchanged.
|
|
60
|
+
const showPhoneTabInitial = Boolean(phoneOtpConfig || phonePinConfig);
|
|
61
|
+
const showUsernameTabInitial = Boolean(usernamePinConfig);
|
|
62
|
+
const defaultActiveTab = showPhoneTabInitial
|
|
63
|
+
? 'phone'
|
|
64
|
+
: showUsernameTabInitial
|
|
65
|
+
? 'username'
|
|
66
|
+
: 'password';
|
|
67
|
+
const [activeTab, setActiveTab] = useState(defaultActiveTab);
|
|
57
68
|
const [phoneStep, setPhoneStep] = useState('enterPhone');
|
|
58
69
|
const [phoneNumber, setPhoneNumber] = useState('');
|
|
59
70
|
const [phoneOtpValue, setPhoneOtpValue] = useState('');
|
|
@@ -98,16 +109,19 @@ export function PagamioLoginPage({ logo, text = loginPageDefaultText, appLabel,
|
|
|
98
109
|
];
|
|
99
110
|
const loginNumberField = [
|
|
100
111
|
{
|
|
112
|
+
// Internal field name stays `loginNumber` to match the auth API
|
|
113
|
+
// payload; only the user-facing strings change to "Operator ID" to
|
|
114
|
+
// align with the mobile Welcome Back screen.
|
|
101
115
|
name: 'loginNumber',
|
|
102
|
-
label: '
|
|
116
|
+
label: 'Operator ID',
|
|
103
117
|
type: 'text',
|
|
104
|
-
placeholder: '
|
|
118
|
+
placeholder: 'Enter Operator ID',
|
|
105
119
|
gridSpan: 12,
|
|
106
120
|
validation: {
|
|
107
|
-
required: '
|
|
121
|
+
required: 'Operator ID is required',
|
|
108
122
|
pattern: {
|
|
109
123
|
value: /^\d{10}$/,
|
|
110
|
-
message: '
|
|
124
|
+
message: 'Operator ID must be exactly 10 digits',
|
|
111
125
|
},
|
|
112
126
|
},
|
|
113
127
|
},
|
|
@@ -308,10 +322,10 @@ export function PagamioLoginPage({ logo, text = loginPageDefaultText, appLabel,
|
|
|
308
322
|
usernamePinConfig?.passwordTabLabel ??
|
|
309
323
|
'Email';
|
|
310
324
|
const phoneTabLabel = phoneOtpConfig?.tabLabel ?? phonePinConfig?.tabLabel ?? 'Phone';
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
325
|
+
// "Operator ID" aligns the web tab label with the mobile Welcome Back
|
|
326
|
+
// screen. Consumers can still override via usernamePinConfig.tabLabel.
|
|
327
|
+
const usernameTabLabel = usernamePinConfig?.tabLabel ?? 'Operator ID';
|
|
328
|
+
return (_jsx(AuthPageLayout, { appLabel: appLabel, title: text.welcomeTitle, subtitle: text.welcomeSubtitle, errorMessage: activeTab === 'password' ? (error ?? authError?.message) : undefined, logo: logo, className: className, horizontal: false, sideContent: features && features.length > 0 ? _jsx(FeatureCarousel, { features: features }) : undefined, sideContentClass: sideContentClass, footer: footer, children: _jsxs("div", { className: "mt-8", children: [showTabs && (_jsxs("div", { className: "mb-6 flex divide-x divide-border overflow-hidden rounded-lg border border-border", role: "tablist", "aria-label": "Login method", children: [showPhoneTab && (_jsx("button", { type: "button", role: "tab", "aria-selected": activeTab === 'phone', onClick: () => {
|
|
315
329
|
setActiveTab('phone');
|
|
316
330
|
setPhoneStep('enterPhone');
|
|
317
331
|
setPhoneOtpValue('');
|
|
@@ -326,7 +340,9 @@ export function PagamioLoginPage({ logo, text = loginPageDefaultText, appLabel,
|
|
|
326
340
|
setUsernameError(null);
|
|
327
341
|
}, className: `flex-1 whitespace-nowrap px-3 py-2.5 text-center text-sm font-medium transition-colors ${activeTab === 'username'
|
|
328
342
|
? 'bg-primary text-primary-foreground'
|
|
329
|
-
: 'bg-background text-foreground/70 hover:bg-muted'}`, children: usernameTabLabel }))
|
|
343
|
+
: 'bg-background text-foreground/70 hover:bg-muted'}`, children: usernameTabLabel })), _jsx("button", { type: "button", role: "tab", "aria-selected": activeTab === 'password', onClick: () => setActiveTab('password'), className: `flex-1 whitespace-nowrap px-3 py-2.5 text-center text-sm font-medium transition-colors ${activeTab === 'password'
|
|
344
|
+
? 'bg-primary text-primary-foreground'
|
|
345
|
+
: 'bg-background text-foreground/70 hover:bg-muted'}`, children: passwordTabLabel })] })), activeTab === 'password' && (_jsxs(_Fragment, { children: [_jsx(FormEngine, { fields: loginFields, onSubmit: handleSubmit, layout: "vertical", className: "mb-0 px-0", submitButtonClass: "w-full", submitButtonText: isLoading ? text.loadingButtonLabel : text.loginButtonLabel, onCancel: () => { }, showCancelButton: false, showSubmittingText: false, formRef: formRef, initialValues: {
|
|
330
346
|
...(loginFieldType === 'email' ? { email: '' } : { username: '' }),
|
|
331
347
|
password: '',
|
|
332
348
|
rememberMe: false,
|
|
@@ -351,6 +367,6 @@ export function PagamioLoginPage({ logo, text = loginPageDefaultText, appLabel,
|
|
|
351
367
|
setUsernameStep('enterLoginNumber');
|
|
352
368
|
setLoginNumberPinValue('');
|
|
353
369
|
setUsernameError(null);
|
|
354
|
-
}, className: "w-full text-sm text-foreground/70", children: "\u2190 Change
|
|
370
|
+
}, className: "w-full text-sm text-foreground/70", children: "\u2190 Change Operator ID" })] }))] }))] }) }));
|
|
355
371
|
}
|
|
356
372
|
export default PagamioLoginPage;
|
|
@@ -177,6 +177,15 @@ export interface UsePagamioTableConfig<T extends BaseEntity> {
|
|
|
177
177
|
enabled?: boolean;
|
|
178
178
|
staleTime?: number;
|
|
179
179
|
gcTime?: number;
|
|
180
|
+
/**
|
|
181
|
+
* Auto-refetch interval (ms) for tables backed by long-running jobs
|
|
182
|
+
* (exports, imports, async report generation). Pass a fixed number to
|
|
183
|
+
* always poll, `false` to disable, or a predicate `(rows) => number | false`
|
|
184
|
+
* that returns the interval only while any row is still in flight — the
|
|
185
|
+
* predicate runs on every fetch settle so polling stops automatically
|
|
186
|
+
* once everything is terminal.
|
|
187
|
+
*/
|
|
188
|
+
refetchInterval?: number | false | ((rows: T[]) => number | false);
|
|
180
189
|
/**
|
|
181
190
|
* Keep the previous page's rows visible while the next page fetches
|
|
182
191
|
* (TanStack `placeholderData: keepPreviousData`). Defaults to true so
|
|
@@ -17,4 +17,4 @@ export declare const pagamioMapping: ResponseMapping;
|
|
|
17
17
|
* The hook tracks `page` zero-indexed internally; we bump on the way out.
|
|
18
18
|
*/
|
|
19
19
|
export declare const pagamioQueryConfig: QueryParamConfig;
|
|
20
|
-
export declare const usePagamioTable: <T extends BaseEntity>({ queryKey, queryFn, enabled: queryEnabled, staleTime, gcTime, keepPreviousData: keepPrev, data: clientData, columns, defaultFilters, responseMapping, queryParamConfig, pagination: paginationConfig, filtering: filteringConfig, sorting: sortingConfig, toolbar, searchPlaceholder, onRowClick, rowClassName, expandable, renderDetailPanel, }: UsePagamioTableConfig<T>) => UsePagamioTableReturn<T>;
|
|
20
|
+
export declare const usePagamioTable: <T extends BaseEntity>({ queryKey, queryFn, enabled: queryEnabled, staleTime, gcTime, refetchInterval, keepPreviousData: keepPrev, data: clientData, columns, defaultFilters, responseMapping, queryParamConfig, pagination: paginationConfig, filtering: filteringConfig, sorting: sortingConfig, toolbar, searchPlaceholder, onRowClick, rowClassName, expandable, renderDetailPanel, }: UsePagamioTableConfig<T>) => UsePagamioTableReturn<T>;
|
|
@@ -158,7 +158,7 @@ function clientSort(items, sortConfig) {
|
|
|
158
158
|
return sorted;
|
|
159
159
|
}
|
|
160
160
|
// ─── Hook ────────────────────────────────────────────────────────────
|
|
161
|
-
export const usePagamioTable = ({ queryKey, queryFn, enabled: queryEnabled = true, staleTime, gcTime, keepPreviousData: keepPrev = true, data: clientData, columns, defaultFilters = {}, responseMapping = springBootMapping, queryParamConfig = defaultQueryConfig, pagination: paginationConfig = { enabled: true, mode: 'client' }, filtering: filteringConfig = { enabled: true, mode: 'client', searchMode: 'server' }, sorting: sortingConfig = { enabled: true, mode: 'client' }, toolbar, searchPlaceholder, onRowClick, rowClassName, expandable, renderDetailPanel, }) => {
|
|
161
|
+
export const usePagamioTable = ({ queryKey, queryFn, enabled: queryEnabled = true, staleTime, gcTime, refetchInterval, keepPreviousData: keepPrev = true, data: clientData, columns, defaultFilters = {}, responseMapping = springBootMapping, queryParamConfig = defaultQueryConfig, pagination: paginationConfig = { enabled: true, mode: 'client' }, filtering: filteringConfig = { enabled: true, mode: 'client', searchMode: 'server' }, sorting: sortingConfig = { enabled: true, mode: 'client' }, toolbar, searchPlaceholder, onRowClick, rowClassName, expandable, renderDetailPanel, }) => {
|
|
162
162
|
// ── Local state ──────────────────────────────────────────────────
|
|
163
163
|
const [currentPage, setCurrentPage] = useState(paginationConfig.pageIndex ?? 0);
|
|
164
164
|
const [pageSize, setPageSize] = useState(paginationConfig.pageSize ?? 10);
|
|
@@ -190,6 +190,18 @@ export const usePagamioTable = ({ queryKey, queryFn, enabled: queryEnabled = tru
|
|
|
190
190
|
staleTime,
|
|
191
191
|
gcTime,
|
|
192
192
|
placeholderData: keepPrev ? keepPreviousData : undefined,
|
|
193
|
+
// Predicate form re-extracts rows from the raw response so callers can
|
|
194
|
+
// gate polling on row state (e.g. "any pending export") without needing
|
|
195
|
+
// to know the responseMapping shape.
|
|
196
|
+
refetchInterval: typeof refetchInterval === 'function'
|
|
197
|
+
? (query) => {
|
|
198
|
+
const raw = query.state.data;
|
|
199
|
+
if (!raw)
|
|
200
|
+
return false;
|
|
201
|
+
const { data: rows } = processResponse(raw, responseMapping);
|
|
202
|
+
return refetchInterval(rows);
|
|
203
|
+
}
|
|
204
|
+
: refetchInterval,
|
|
193
205
|
});
|
|
194
206
|
// ── Process server response ──────────────────────────────────────
|
|
195
207
|
const { serverData, serverTotal } = useMemo(() => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pagamio/frontend-commons-lib",
|
|
3
3
|
"description": "Pagamio library for Frontend reusable components like the form engine and table container",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.342",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"provenance": false
|