@qumra/jisr 1.0.0 → 1.0.1
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/README.md +205 -271
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
# @qumra/jisr
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@qumra/jisr)
|
|
4
|
+
[](https://opensource.org/licenses/ISC)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
> App Bridge for Qumra embedded apps — React hooks for communicating with the Qumra Admin.
|
|
7
|
+
>
|
|
8
|
+
> **جسر** (Jisr) = Bridge in Arabic
|
|
9
|
+
|
|
10
|
+
`@qumra/jisr` provides a set of React hooks and utilities for seamless communication between embedded applications (running in iframes) and the Qumra Admin interface via `postMessage`. Perfect for building extensible admin apps that need to interact with the parent Qumra environment.
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- 🌉 **iframe ↔ Admin Communication** — Transparent two-way messaging
|
|
15
|
+
- 🎣 **Custom React Hooks** — `useNavigate`, `useToast`, `useModal`, `useSaveBar`, and more
|
|
16
|
+
- 📘 **TypeScript Support** — Fully typed exports for better DX
|
|
17
|
+
- 🔐 **Authenticated Requests** — Built-in hook for fetch with auth headers
|
|
18
|
+
- ⚡ **Simple Setup** — Wrap your app with `QumraAppBridgeProvider`
|
|
6
19
|
|
|
7
20
|
## Installation
|
|
8
21
|
|
|
@@ -10,359 +23,249 @@ This package mirrors the functionality of Shopify's `@shopify/app-bridge-react`
|
|
|
10
23
|
npm install @qumra/jisr react react-dom
|
|
11
24
|
```
|
|
12
25
|
|
|
13
|
-
|
|
26
|
+
### Peer Dependencies
|
|
14
27
|
|
|
15
|
-
|
|
28
|
+
- `react` >= 18
|
|
29
|
+
- `react-dom` >= 18
|
|
16
30
|
|
|
17
|
-
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
### 1. Wrap Your App with the Provider
|
|
18
34
|
|
|
19
|
-
```
|
|
20
|
-
import React from 'react';
|
|
35
|
+
```jsx
|
|
21
36
|
import { QumraAppBridgeProvider } from '@qumra/jisr';
|
|
22
|
-
import { App } from './App';
|
|
23
37
|
|
|
24
|
-
|
|
38
|
+
function App() {
|
|
25
39
|
return (
|
|
26
|
-
<QumraAppBridgeProvider
|
|
27
|
-
<
|
|
40
|
+
<QumraAppBridgeProvider>
|
|
41
|
+
<YourAppComponent />
|
|
28
42
|
</QumraAppBridgeProvider>
|
|
29
43
|
);
|
|
30
44
|
}
|
|
31
|
-
```
|
|
32
45
|
|
|
33
|
-
|
|
46
|
+
export default App;
|
|
47
|
+
```
|
|
34
48
|
|
|
35
|
-
|
|
49
|
+
### 2. Use Hooks in Your Components
|
|
36
50
|
|
|
37
|
-
```
|
|
38
|
-
import
|
|
39
|
-
import {
|
|
40
|
-
useNavigate,
|
|
41
|
-
useToast,
|
|
42
|
-
useSaveBar,
|
|
43
|
-
} from '@qumra/jisr';
|
|
51
|
+
```jsx
|
|
52
|
+
import { useNavigate, useToast } from '@qumra/jisr';
|
|
44
53
|
|
|
45
|
-
|
|
46
|
-
const navigate = useNavigate();
|
|
47
|
-
const
|
|
48
|
-
const saveBar = useSaveBar();
|
|
49
|
-
const [hasChanges, setHasChanges] = React.useState(false);
|
|
50
|
-
|
|
51
|
-
const handleChange = () => {
|
|
52
|
-
setHasChanges(true);
|
|
53
|
-
saveBar.show({
|
|
54
|
-
saveLabel: 'Save Changes',
|
|
55
|
-
discardLabel: 'Discard',
|
|
56
|
-
});
|
|
57
|
-
};
|
|
54
|
+
function MyComponent() {
|
|
55
|
+
const { navigate } = useNavigate();
|
|
56
|
+
const { showToast } = useToast();
|
|
58
57
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// Save your data here
|
|
63
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
64
|
-
toast.show({ message: 'Saved successfully!' });
|
|
65
|
-
saveBar.hide();
|
|
66
|
-
setHasChanges(false);
|
|
67
|
-
} catch (error) {
|
|
68
|
-
toast.show({
|
|
69
|
-
message: 'Error saving changes',
|
|
70
|
-
isError: true,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
58
|
+
const handleClick = () => {
|
|
59
|
+
showToast('Hello from embedded app!', 'success');
|
|
60
|
+
navigate('/dashboard');
|
|
73
61
|
};
|
|
74
62
|
|
|
75
|
-
return
|
|
76
|
-
<div>
|
|
77
|
-
<input
|
|
78
|
-
type="text"
|
|
79
|
-
placeholder="Product name"
|
|
80
|
-
onChange={handleChange}
|
|
81
|
-
/>
|
|
82
|
-
<button onClick={handleSave}>Save</button>
|
|
83
|
-
<button onClick={() => navigate('/products')}>
|
|
84
|
-
Back to Products
|
|
85
|
-
</button>
|
|
86
|
-
</div>
|
|
87
|
-
);
|
|
63
|
+
return <button onClick={handleClick}>Navigate & Toast</button>;
|
|
88
64
|
}
|
|
89
65
|
```
|
|
90
66
|
|
|
91
|
-
##
|
|
67
|
+
## Hooks Reference
|
|
92
68
|
|
|
93
|
-
### useAppBridge
|
|
69
|
+
### `useAppBridge`
|
|
94
70
|
|
|
95
|
-
|
|
71
|
+
Access the core `AppBridge` instance directly for advanced use cases.
|
|
96
72
|
|
|
97
|
-
```
|
|
73
|
+
```jsx
|
|
98
74
|
import { useAppBridge } from '@qumra/jisr';
|
|
99
75
|
|
|
100
|
-
|
|
76
|
+
function AdvancedComponent() {
|
|
101
77
|
const bridge = useAppBridge();
|
|
102
78
|
|
|
103
79
|
const handleCustomAction = () => {
|
|
104
|
-
bridge.dispatch({
|
|
105
|
-
type: 'APP::CUSTOM_ACTION',
|
|
106
|
-
payload: { /* your data */ },
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// Subscribe to events
|
|
110
|
-
const unsubscribe = bridge.subscribe('HOST::RESPONSE', (data) => {
|
|
111
|
-
console.log('Received:', data);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
return () => unsubscribe();
|
|
80
|
+
bridge.dispatch({ type: 'CUSTOM_ACTION', payload: { /* ... */ } });
|
|
115
81
|
};
|
|
116
82
|
|
|
117
|
-
return <button onClick={handleCustomAction}>Custom Action</button>;
|
|
83
|
+
return <button onClick={handleCustomAction}>Send Custom Action</button>;
|
|
118
84
|
}
|
|
119
85
|
```
|
|
120
86
|
|
|
121
|
-
### useNavigate
|
|
87
|
+
### `useNavigate`
|
|
122
88
|
|
|
123
|
-
Navigate within the Qumra Admin
|
|
89
|
+
Navigate within the Qumra Admin interface.
|
|
124
90
|
|
|
125
|
-
```
|
|
91
|
+
```jsx
|
|
126
92
|
import { useNavigate } from '@qumra/jisr';
|
|
127
93
|
|
|
128
|
-
|
|
129
|
-
const navigate = useNavigate();
|
|
94
|
+
function NavigationComponent() {
|
|
95
|
+
const { navigate } = useNavigate();
|
|
130
96
|
|
|
131
97
|
return (
|
|
132
|
-
|
|
133
|
-
<button onClick={() => navigate('/
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
<button
|
|
137
|
-
onClick={() => navigate('https://example.com', {
|
|
138
|
-
external: true,
|
|
139
|
-
})}
|
|
140
|
-
>
|
|
141
|
-
Open External Site
|
|
142
|
-
</button>
|
|
143
|
-
</div>
|
|
98
|
+
<>
|
|
99
|
+
<button onClick={() => navigate('/dashboard')}>Dashboard</button>
|
|
100
|
+
<button onClick={() => navigate('/settings')}>Settings</button>
|
|
101
|
+
</>
|
|
144
102
|
);
|
|
145
103
|
}
|
|
146
104
|
```
|
|
147
105
|
|
|
148
|
-
### useToast
|
|
106
|
+
### `useToast`
|
|
149
107
|
|
|
150
|
-
|
|
108
|
+
Display toast notifications in the Qumra Admin UI.
|
|
151
109
|
|
|
152
|
-
```
|
|
110
|
+
```jsx
|
|
153
111
|
import { useToast } from '@qumra/jisr';
|
|
154
112
|
|
|
155
|
-
|
|
156
|
-
const
|
|
113
|
+
function ToastComponent() {
|
|
114
|
+
const { showToast, hideToast } = useToast();
|
|
115
|
+
|
|
116
|
+
const handleSuccess = () => {
|
|
117
|
+
showToast('Operation successful!', 'success');
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const handleError = () => {
|
|
121
|
+
showToast('Something went wrong.', 'error');
|
|
122
|
+
};
|
|
157
123
|
|
|
158
124
|
return (
|
|
159
|
-
|
|
160
|
-
<button
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
message: 'Operation completed successfully!',
|
|
164
|
-
duration: 3000,
|
|
165
|
-
})
|
|
166
|
-
}
|
|
167
|
-
>
|
|
168
|
-
Show Success Toast
|
|
169
|
-
</button>
|
|
170
|
-
<button
|
|
171
|
-
onClick={() =>
|
|
172
|
-
toast.show({
|
|
173
|
-
message: 'An error occurred',
|
|
174
|
-
isError: true,
|
|
175
|
-
duration: 5000,
|
|
176
|
-
})
|
|
177
|
-
}
|
|
178
|
-
>
|
|
179
|
-
Show Error Toast
|
|
180
|
-
</button>
|
|
181
|
-
<button onClick={() => toast.hide()}>
|
|
182
|
-
Hide Toast
|
|
183
|
-
</button>
|
|
184
|
-
</div>
|
|
125
|
+
<>
|
|
126
|
+
<button onClick={handleSuccess}>Show Success</button>
|
|
127
|
+
<button onClick={handleError}>Show Error</button>
|
|
128
|
+
</>
|
|
185
129
|
);
|
|
186
130
|
}
|
|
187
131
|
```
|
|
188
132
|
|
|
189
|
-
### useModal
|
|
133
|
+
### `useModal`
|
|
190
134
|
|
|
191
|
-
Open and
|
|
135
|
+
Open and manage modal dialogs.
|
|
192
136
|
|
|
193
|
-
```
|
|
137
|
+
```jsx
|
|
194
138
|
import { useModal } from '@qumra/jisr';
|
|
195
139
|
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
title: '
|
|
202
|
-
|
|
203
|
-
size: 'large',
|
|
204
|
-
primaryAction: {
|
|
205
|
-
content: 'Save',
|
|
206
|
-
onAction: () => {
|
|
207
|
-
console.log('Save clicked');
|
|
208
|
-
modal.close();
|
|
209
|
-
},
|
|
210
|
-
},
|
|
211
|
-
secondaryActions: [
|
|
212
|
-
{
|
|
213
|
-
content: 'Cancel',
|
|
214
|
-
onAction: () => {
|
|
215
|
-
modal.close();
|
|
216
|
-
},
|
|
217
|
-
},
|
|
218
|
-
],
|
|
140
|
+
function ModalComponent() {
|
|
141
|
+
const { openModal, closeModal } = useModal();
|
|
142
|
+
|
|
143
|
+
const handleOpenModal = () => {
|
|
144
|
+
openModal({
|
|
145
|
+
title: 'Confirm Action',
|
|
146
|
+
content: 'Are you sure you want to proceed?',
|
|
219
147
|
});
|
|
220
148
|
};
|
|
221
149
|
|
|
222
|
-
return
|
|
150
|
+
return (
|
|
151
|
+
<>
|
|
152
|
+
<button onClick={handleOpenModal}>Open Modal</button>
|
|
153
|
+
<button onClick={closeModal}>Close Modal</button>
|
|
154
|
+
</>
|
|
155
|
+
);
|
|
223
156
|
}
|
|
224
157
|
```
|
|
225
158
|
|
|
226
|
-
### useSaveBar
|
|
159
|
+
### `useSaveBar`
|
|
227
160
|
|
|
228
|
-
Show
|
|
161
|
+
Show/hide the save bar for form changes.
|
|
229
162
|
|
|
230
|
-
```
|
|
163
|
+
```jsx
|
|
231
164
|
import { useSaveBar } from '@qumra/jisr';
|
|
165
|
+
import { useState } from 'react';
|
|
232
166
|
|
|
233
|
-
|
|
234
|
-
const
|
|
235
|
-
const [isDirty, setIsDirty] =
|
|
167
|
+
function FormComponent() {
|
|
168
|
+
const { showSaveBar, hideSaveBar } = useSaveBar();
|
|
169
|
+
const [isDirty, setIsDirty] = useState(false);
|
|
236
170
|
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
saveBar.show();
|
|
241
|
-
}
|
|
171
|
+
const handleFieldChange = (e) => {
|
|
172
|
+
setIsDirty(true);
|
|
173
|
+
showSaveBar();
|
|
242
174
|
};
|
|
243
175
|
|
|
244
176
|
const handleSave = async () => {
|
|
245
|
-
|
|
177
|
+
// Save logic
|
|
178
|
+
hideSaveBar();
|
|
246
179
|
setIsDirty(false);
|
|
247
|
-
saveBar.hide();
|
|
248
180
|
};
|
|
249
181
|
|
|
250
182
|
return (
|
|
251
183
|
<form>
|
|
252
|
-
<input onChange={
|
|
253
|
-
<button onClick={handleSave}>Save</button>
|
|
184
|
+
<input onChange={handleFieldChange} />
|
|
185
|
+
{isDirty && <button onClick={handleSave}>Save</button>}
|
|
254
186
|
</form>
|
|
255
187
|
);
|
|
256
188
|
}
|
|
257
189
|
```
|
|
258
190
|
|
|
259
|
-
### useTitleBar
|
|
191
|
+
### `useTitleBar`
|
|
260
192
|
|
|
261
|
-
Update the title
|
|
193
|
+
Update the page title in the Qumra Admin.
|
|
262
194
|
|
|
263
|
-
```
|
|
195
|
+
```jsx
|
|
264
196
|
import { useTitleBar } from '@qumra/jisr';
|
|
197
|
+
import { useEffect } from 'react';
|
|
265
198
|
|
|
266
|
-
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
React.useEffect(() => {
|
|
270
|
-
titleBar.update({
|
|
271
|
-
title: 'Products',
|
|
272
|
-
subtitle: 'Manage your store products',
|
|
273
|
-
breadcrumbs: [
|
|
274
|
-
{ content: 'Admin', url: '/' },
|
|
275
|
-
{ content: 'Products' },
|
|
276
|
-
],
|
|
277
|
-
});
|
|
278
|
-
}, [titleBar]);
|
|
199
|
+
function PageComponent() {
|
|
200
|
+
const { updateTitleBar } = useTitleBar();
|
|
279
201
|
|
|
280
|
-
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
updateTitleBar('My Page Title');
|
|
204
|
+
}, [updateTitleBar]);
|
|
205
|
+
|
|
206
|
+
return <div>Page content</div>;
|
|
281
207
|
}
|
|
282
208
|
```
|
|
283
209
|
|
|
284
|
-
### useFullscreen
|
|
210
|
+
### `useFullscreen`
|
|
285
211
|
|
|
286
|
-
Enter and exit fullscreen mode
|
|
212
|
+
Enter and exit fullscreen mode.
|
|
287
213
|
|
|
288
|
-
```
|
|
214
|
+
```jsx
|
|
289
215
|
import { useFullscreen } from '@qumra/jisr';
|
|
290
216
|
|
|
291
|
-
|
|
292
|
-
const
|
|
217
|
+
function FullscreenComponent() {
|
|
218
|
+
const { enterFullscreen, exitFullscreen } = useFullscreen();
|
|
293
219
|
|
|
294
220
|
return (
|
|
295
|
-
|
|
296
|
-
<button onClick={
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
<button onClick={() => fullscreen.exit()}>
|
|
300
|
-
Exit Fullscreen
|
|
301
|
-
</button>
|
|
302
|
-
</div>
|
|
221
|
+
<>
|
|
222
|
+
<button onClick={enterFullscreen}>Go Fullscreen</button>
|
|
223
|
+
<button onClick={exitFullscreen}>Exit Fullscreen</button>
|
|
224
|
+
</>
|
|
303
225
|
);
|
|
304
226
|
}
|
|
305
227
|
```
|
|
306
228
|
|
|
307
|
-
### useAuthenticatedFetch
|
|
229
|
+
### `useAuthenticatedFetch`
|
|
308
230
|
|
|
309
|
-
Make authenticated API
|
|
231
|
+
Make authenticated requests to the Qumra API with automatic auth headers.
|
|
310
232
|
|
|
311
|
-
```
|
|
233
|
+
```jsx
|
|
312
234
|
import { useAuthenticatedFetch } from '@qumra/jisr';
|
|
235
|
+
import { useEffect, useState } from 'react';
|
|
236
|
+
|
|
237
|
+
function DataComponent() {
|
|
238
|
+
const { fetch: authenticatedFetch } = useAuthenticatedFetch();
|
|
239
|
+
const [data, setData] = useState(null);
|
|
240
|
+
const [loading, setLoading] = useState(false);
|
|
241
|
+
|
|
242
|
+
useEffect(() => {
|
|
243
|
+
const loadData = async () => {
|
|
244
|
+
setLoading(true);
|
|
245
|
+
try {
|
|
246
|
+
const response = await authenticatedFetch('/api/data');
|
|
247
|
+
const json = await response.json();
|
|
248
|
+
setData(json);
|
|
249
|
+
} catch (error) {
|
|
250
|
+
console.error('Fetch failed:', error);
|
|
251
|
+
} finally {
|
|
252
|
+
setLoading(false);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
313
255
|
|
|
314
|
-
export function DataFetcher() {
|
|
315
|
-
const authenticatedFetch = useAuthenticatedFetch();
|
|
316
|
-
const [data, setData] = React.useState(null);
|
|
317
|
-
|
|
318
|
-
const loadData = async () => {
|
|
319
|
-
try {
|
|
320
|
-
const response = await authenticatedFetch('/api/products');
|
|
321
|
-
const result = await response.json();
|
|
322
|
-
setData(result);
|
|
323
|
-
} catch (error) {
|
|
324
|
-
console.error('Error fetching data:', error);
|
|
325
|
-
}
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
React.useEffect(() => {
|
|
329
256
|
loadData();
|
|
330
|
-
}, []);
|
|
257
|
+
}, [authenticatedFetch]);
|
|
331
258
|
|
|
332
|
-
return <div>
|
|
259
|
+
if (loading) return <div>Loading...</div>;
|
|
260
|
+
return <pre>{JSON.stringify(data, null, 2)}</pre>;
|
|
333
261
|
}
|
|
334
262
|
```
|
|
335
263
|
|
|
336
|
-
##
|
|
337
|
-
|
|
338
|
-
### ActionType
|
|
339
|
-
|
|
340
|
-
Constants for all available action types:
|
|
341
|
-
|
|
342
|
-
```typescript
|
|
343
|
-
import { ActionType } from '@qumra/jisr';
|
|
344
|
-
|
|
345
|
-
const actions = {
|
|
346
|
-
NAVIGATE: ActionType.NAVIGATE,
|
|
347
|
-
TOAST_SHOW: ActionType.TOAST_SHOW,
|
|
348
|
-
TOAST_HIDE: ActionType.TOAST_HIDE,
|
|
349
|
-
MODAL_OPEN: ActionType.MODAL_OPEN,
|
|
350
|
-
MODAL_CLOSE: ActionType.MODAL_CLOSE,
|
|
351
|
-
SAVE_BAR_SHOW: ActionType.SAVE_BAR_SHOW,
|
|
352
|
-
SAVE_BAR_HIDE: ActionType.SAVE_BAR_HIDE,
|
|
353
|
-
TITLE_BAR_UPDATE: ActionType.TITLE_BAR_UPDATE,
|
|
354
|
-
LOADING_START: ActionType.LOADING_START,
|
|
355
|
-
LOADING_STOP: ActionType.LOADING_STOP,
|
|
356
|
-
FULLSCREEN_ENTER: ActionType.FULLSCREEN_ENTER,
|
|
357
|
-
FULLSCREEN_EXIT: ActionType.FULLSCREEN_EXIT,
|
|
358
|
-
};
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
### Action Creator Functions
|
|
264
|
+
## Action Creators
|
|
362
265
|
|
|
363
|
-
|
|
266
|
+
For advanced usage, dispatch actions directly via the `AppBridge`:
|
|
364
267
|
|
|
365
|
-
```
|
|
268
|
+
```jsx
|
|
366
269
|
import {
|
|
367
270
|
navigate,
|
|
368
271
|
showToast,
|
|
@@ -378,53 +281,84 @@ import {
|
|
|
378
281
|
exitFullscreen,
|
|
379
282
|
} from '@qumra/jisr';
|
|
380
283
|
|
|
381
|
-
// Use with useAppBridge()
|
|
382
284
|
const bridge = useAppBridge();
|
|
383
|
-
|
|
384
|
-
|
|
285
|
+
|
|
286
|
+
// Navigate
|
|
287
|
+
bridge.dispatch(navigate('/path'));
|
|
288
|
+
|
|
289
|
+
// Toast notifications
|
|
290
|
+
bridge.dispatch(showToast('Message', 'success'));
|
|
291
|
+
bridge.dispatch(hideToast());
|
|
292
|
+
|
|
293
|
+
// Modals
|
|
294
|
+
bridge.dispatch(openModal({ title: 'Title', content: 'Content' }));
|
|
295
|
+
bridge.dispatch(closeModal());
|
|
296
|
+
|
|
297
|
+
// Save bar
|
|
298
|
+
bridge.dispatch(showSaveBar());
|
|
299
|
+
bridge.dispatch(hideSaveBar());
|
|
300
|
+
|
|
301
|
+
// Title bar
|
|
302
|
+
bridge.dispatch(updateTitleBar('New Title'));
|
|
303
|
+
|
|
304
|
+
// Loading state
|
|
305
|
+
bridge.dispatch(startLoading());
|
|
306
|
+
bridge.dispatch(stopLoading());
|
|
307
|
+
|
|
308
|
+
// Fullscreen
|
|
309
|
+
bridge.dispatch(enterFullscreen());
|
|
310
|
+
bridge.dispatch(exitFullscreen());
|
|
385
311
|
```
|
|
386
312
|
|
|
387
|
-
##
|
|
313
|
+
## TypeScript
|
|
388
314
|
|
|
389
|
-
All types are exported
|
|
315
|
+
All types are exported from the main package:
|
|
390
316
|
|
|
391
317
|
```typescript
|
|
392
|
-
import
|
|
318
|
+
import {
|
|
319
|
+
AppBridge,
|
|
393
320
|
AppBridgeConfig,
|
|
394
321
|
AppBridgeAction,
|
|
395
322
|
AppBridgeState,
|
|
396
323
|
AppContext,
|
|
397
|
-
|
|
398
|
-
ToastOptions,
|
|
399
|
-
ModalOptions,
|
|
400
|
-
SaveBarOptions,
|
|
401
|
-
TitleBarOptions,
|
|
324
|
+
ActionType,
|
|
402
325
|
UseToastResult,
|
|
403
326
|
UseModalResult,
|
|
327
|
+
UseNavigateResult,
|
|
404
328
|
UseSaveBarResult,
|
|
405
|
-
UseFullscreenResult,
|
|
406
329
|
UseTitleBarResult,
|
|
330
|
+
UseFullscreenResult,
|
|
331
|
+
UseAuthenticatedFetchResult,
|
|
407
332
|
} from '@qumra/jisr';
|
|
408
333
|
```
|
|
409
334
|
|
|
410
|
-
|
|
335
|
+
### Example Type Usage
|
|
411
336
|
|
|
412
|
-
|
|
337
|
+
```typescript
|
|
338
|
+
import { AppBridgeAction, ActionType } from '@qumra/jisr';
|
|
413
339
|
|
|
414
|
-
|
|
415
|
-
|
|
340
|
+
const myAction: AppBridgeAction = {
|
|
341
|
+
type: ActionType.NAVIGATE,
|
|
342
|
+
payload: { path: '/dashboard' },
|
|
343
|
+
};
|
|
416
344
|
```
|
|
417
345
|
|
|
418
|
-
|
|
346
|
+
## Qumra Ecosystem
|
|
419
347
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
348
|
+
| Package | Description |
|
|
349
|
+
|---------|-------------|
|
|
350
|
+
| [@qumra/jisr](https://www.npmjs.com/package/@qumra/jisr) | React hooks for app bridge communication |
|
|
351
|
+
| [@qumra/config](https://www.npmjs.com/package/@qumra/config) | Centralized config management for Qumra apps |
|
|
352
|
+
| [@qumra/logger](https://www.npmjs.com/package/@qumra/logger) | Structured logging utility |
|
|
353
|
+
| [@qumra/ui](https://www.npmjs.com/package/@qumra/ui) | Reusable React component library |
|
|
354
|
+
| [@qumra/api-client](https://www.npmjs.com/package/@qumra/api-client) | API client for Qumra services |
|
|
355
|
+
| [@qumra/types](https://www.npmjs.com/package/@qumra/types) | Shared TypeScript type definitions |
|
|
356
|
+
| [@qumra/utils](https://www.npmjs.com/package/@qumra/utils) | Common utility functions |
|
|
427
357
|
|
|
428
358
|
## License
|
|
429
359
|
|
|
430
|
-
ISC
|
|
360
|
+
ISC © [Nicetag](https://github.com/nicetag)
|
|
361
|
+
|
|
362
|
+
## Repository
|
|
363
|
+
|
|
364
|
+
[github.com/nicetag/qumra-apps-sdk](https://github.com/nicetag/qumra-apps-sdk)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qumra/jisr",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "React hooks and utilities for communicating with the Qumra Admin from embedded apps — navigation, toasts, modals, and more",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|