@numerum-tech/yeriasdk 1.0.0
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 +864 -0
- package/dist/core/action-grid-view.d.ts +57 -0
- package/dist/core/action-grid-view.d.ts.map +1 -0
- package/dist/core/action-grid-view.js +112 -0
- package/dist/core/action-grid-view.js.map +1 -0
- package/dist/core/action-list-view.d.ts +39 -0
- package/dist/core/action-list-view.d.ts.map +1 -0
- package/dist/core/action-list-view.js +77 -0
- package/dist/core/action-list-view.js.map +1 -0
- package/dist/core/base/base-action-view.d.ts +82 -0
- package/dist/core/base/base-action-view.d.ts.map +1 -0
- package/dist/core/base/base-action-view.js +143 -0
- package/dist/core/base/base-action-view.js.map +1 -0
- package/dist/core/base-view.d.ts +105 -0
- package/dist/core/base-view.d.ts.map +1 -0
- package/dist/core/base-view.js +426 -0
- package/dist/core/base-view.js.map +1 -0
- package/dist/core/card-view.d.ts +24 -0
- package/dist/core/card-view.d.ts.map +1 -0
- package/dist/core/card-view.js +127 -0
- package/dist/core/card-view.js.map +1 -0
- package/dist/core/carousel-view.d.ts +22 -0
- package/dist/core/carousel-view.d.ts.map +1 -0
- package/dist/core/carousel-view.js +99 -0
- package/dist/core/carousel-view.js.map +1 -0
- package/dist/core/form-view.d.ts +165 -0
- package/dist/core/form-view.d.ts.map +1 -0
- package/dist/core/form-view.js +365 -0
- package/dist/core/form-view.js.map +1 -0
- package/dist/core/jsonapp.d.ts +263 -0
- package/dist/core/jsonapp.d.ts.map +1 -0
- package/dist/core/jsonapp.js +528 -0
- package/dist/core/jsonapp.js.map +1 -0
- package/dist/core/key-store.d.ts +51 -0
- package/dist/core/key-store.d.ts.map +1 -0
- package/dist/core/key-store.js +138 -0
- package/dist/core/key-store.js.map +1 -0
- package/dist/core/map-view.d.ts +45 -0
- package/dist/core/map-view.d.ts.map +1 -0
- package/dist/core/map-view.js +318 -0
- package/dist/core/map-view.js.map +1 -0
- package/dist/core/media-view.d.ts +20 -0
- package/dist/core/media-view.d.ts.map +1 -0
- package/dist/core/media-view.js +75 -0
- package/dist/core/media-view.js.map +1 -0
- package/dist/core/message-view.d.ts +53 -0
- package/dist/core/message-view.d.ts.map +1 -0
- package/dist/core/message-view.js +109 -0
- package/dist/core/message-view.js.map +1 -0
- package/dist/core/notification.d.ts +17 -0
- package/dist/core/notification.d.ts.map +1 -0
- package/dist/core/notification.js +33 -0
- package/dist/core/notification.js.map +1 -0
- package/dist/core/qr-display-view.d.ts +32 -0
- package/dist/core/qr-display-view.d.ts.map +1 -0
- package/dist/core/qr-display-view.js +66 -0
- package/dist/core/qr-display-view.js.map +1 -0
- package/dist/core/qr-scan-view.d.ts +148 -0
- package/dist/core/qr-scan-view.d.ts.map +1 -0
- package/dist/core/qr-scan-view.js +259 -0
- package/dist/core/qr-scan-view.js.map +1 -0
- package/dist/core/reader-view.d.ts +73 -0
- package/dist/core/reader-view.d.ts.map +1 -0
- package/dist/core/reader-view.js +285 -0
- package/dist/core/reader-view.js.map +1 -0
- package/dist/core/timeline-view.d.ts +16 -0
- package/dist/core/timeline-view.d.ts.map +1 -0
- package/dist/core/timeline-view.js +68 -0
- package/dist/core/timeline-view.js.map +1 -0
- package/dist/errors/index.d.ts +276 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +431 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +103 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +576 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +48 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/fileFormats.d.ts +52 -0
- package/dist/utils/fileFormats.d.ts.map +1 -0
- package/dist/utils/fileFormats.js +198 -0
- package/dist/utils/fileFormats.js.map +1 -0
- package/dist/utils/logger.d.ts +38 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +109 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/validators.d.ts +48 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +445 -0
- package/dist/utils/validators.js.map +1 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,864 @@
|
|
|
1
|
+
> **Note**: This is the JavaScript/TypeScript port of the JSONApp SDK. This repository is a monorepo containing multiple language implementations. See the [root README](../README.md) for an overview.
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
Un SDK TypeScript moderne et optimisé pour générer des interfaces JSON dynamiques, avec support avancé pour les formulaires, la lecture de données, les actions, les QR codes, les messages et l'affichage de données.
|
|
5
|
+
|
|
6
|
+
## 🚀 Fonctionnalités
|
|
7
|
+
|
|
8
|
+
- **Formulaires dynamiques** avec validation avancée
|
|
9
|
+
- **Lecteurs de données** pour afficher des informations
|
|
10
|
+
- **Listes d'actions** pour les menus et navigation
|
|
11
|
+
- **Grilles d'actions** pour les tableaux de bord
|
|
12
|
+
- **Scanner de QR codes** avec configuration flexible
|
|
13
|
+
- **Affichage de QR codes** avec validation d'images
|
|
14
|
+
- **Messages** pour les notifications et guides
|
|
15
|
+
- **Vues de données** pour l'affichage de contenu structuré
|
|
16
|
+
- **Cartes détaillées** pour présenter des fiches produit
|
|
17
|
+
- **Carrousels** pour mettre en avant plusieurs contenus
|
|
18
|
+
- **Timelines** pour les historiques ou étapes
|
|
19
|
+
- **Médias** audio/vidéo intégrés
|
|
20
|
+
- **Cartes interactives** pour localiser des points clés
|
|
21
|
+
- **Notifications** pour envoyer des messages signés aux utilisateurs via la plateforme City-Mate
|
|
22
|
+
- **API fluide** grâce au chaînage des méthodes
|
|
23
|
+
- **Validation robuste** avec règles personnalisables
|
|
24
|
+
- **Logging structuré** pour le débogage
|
|
25
|
+
- **TypeScript strict** pour la sécurité des types
|
|
26
|
+
- **Tests complets** avec Jest
|
|
27
|
+
|
|
28
|
+
## 📦 Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @numerum-tech/yeriasdk
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 🎯 Utilisation Rapide
|
|
35
|
+
|
|
36
|
+
> **⚠️ Note Importante** :
|
|
37
|
+
> - **FormView** : Pour créer des formulaires interactifs avec collecte de données
|
|
38
|
+
> - **ReaderView** : Pour afficher du contenu riche en lecture seule (articles, guides, etc.)
|
|
39
|
+
> - Ces deux types de vues ont des API complètement différentes !
|
|
40
|
+
|
|
41
|
+
### Formulaires
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { FormView } from '@yeria/jsonapp-sdk';
|
|
45
|
+
|
|
46
|
+
// Le titre est passé au constructeur (id, title)
|
|
47
|
+
const form = new FormView('user-registration', 'User Registration')
|
|
48
|
+
.setIntro('Please fill in your information')
|
|
49
|
+
// addField() utilise l'ordre: fieldType, fieldId, fieldLabel, params
|
|
50
|
+
.addField('text', 'name', 'Full Name', { required: true })
|
|
51
|
+
.addField('email', 'email', 'Email Address', { required: true })
|
|
52
|
+
.addField('tel', 'phone', 'Phone Number', { required: false })
|
|
53
|
+
.submitButton('Register', 'POST'); // Convention: POST /api/forms/{formId}
|
|
54
|
+
|
|
55
|
+
console.log(form.toJSON());
|
|
56
|
+
|
|
57
|
+
// Formulaire avec navigation (ex: multi-étapes)
|
|
58
|
+
const step1 = new FormView('registration-step-1', 'Personal Information')
|
|
59
|
+
.setIntro('Step 1 of 3')
|
|
60
|
+
.addTextField('firstName', 'First Name', true)
|
|
61
|
+
.addTextField('lastName', 'Last Name', true)
|
|
62
|
+
.setNext('/api/forms/registration-step-2') // Vue suivante
|
|
63
|
+
.submitButton('Continue', 'POST');
|
|
64
|
+
|
|
65
|
+
// Méthodes helper recommandées (plus simples et plus claires)
|
|
66
|
+
const formSimple = new FormView('user-registration', 'User Registration')
|
|
67
|
+
.setIntro('Please fill in your information')
|
|
68
|
+
.addTextField('name', 'Full Name', true)
|
|
69
|
+
.addEmailField('email', 'Email Address', true)
|
|
70
|
+
.addPhoneField('phone', 'Phone Number', false)
|
|
71
|
+
.submitButton('Register', 'POST');
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Injection de Données (Formulaires d'Édition)
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { FormView } from '@yeria/jsonapp-sdk';
|
|
78
|
+
|
|
79
|
+
// Méthode 1: injectData() - Injection Globale (RECOMMANDÉ)
|
|
80
|
+
// Parfait pour formulaires d'édition avec données depuis API/DB
|
|
81
|
+
const userData = {
|
|
82
|
+
firstName: 'John',
|
|
83
|
+
lastName: 'Doe',
|
|
84
|
+
email: 'john@example.com',
|
|
85
|
+
age: 30,
|
|
86
|
+
country: 'FR' // Pour select: met selected: true sur l'option 'FR'
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const editForm = new FormView('edit-user', 'Edit User Profile')
|
|
90
|
+
.addTextField('firstName', 'First Name', true)
|
|
91
|
+
.addTextField('lastName', 'Last Name', true)
|
|
92
|
+
.addEmailField('email', 'Email', true)
|
|
93
|
+
.addNumberField('age', 'Age', false, 18, 120)
|
|
94
|
+
.addSelectField('country', 'Country', false, [
|
|
95
|
+
{ label: 'France', value: 'FR' },
|
|
96
|
+
{ label: 'USA', value: 'US' },
|
|
97
|
+
{ label: 'Canada', value: 'CA' }
|
|
98
|
+
])
|
|
99
|
+
.injectData(userData) // ✅ Injecte toutes les valeurs en une fois
|
|
100
|
+
.submitButton('Update Profile', 'PUT');
|
|
101
|
+
|
|
102
|
+
// JSON généré pour le select:
|
|
103
|
+
// {
|
|
104
|
+
// "fieldType": "select",
|
|
105
|
+
// "options": [
|
|
106
|
+
// { "label": "France", "value": "FR", "selected": true }, // ✅ Automatique!
|
|
107
|
+
// { "label": "USA", "value": "US", "selected": false },
|
|
108
|
+
// { "label": "Canada", "value": "CA", "selected": false }
|
|
109
|
+
// ]
|
|
110
|
+
// }
|
|
111
|
+
|
|
112
|
+
// Checkbox avec multi-sélection (value = array)
|
|
113
|
+
const preferencesData = {
|
|
114
|
+
interests: ['sports', 'music'] // Array pour checkbox multi-sélection
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const preferencesForm = new FormView('preferences', 'Preferences')
|
|
118
|
+
.addCheckboxField('interests', 'Interests') // Checkbox avec options
|
|
119
|
+
.injectData(preferencesData);
|
|
120
|
+
|
|
121
|
+
// JSON généré pour checkbox:
|
|
122
|
+
// {
|
|
123
|
+
// "fieldType": "checkbox",
|
|
124
|
+
// "options": [
|
|
125
|
+
// { "label": "Sports", "value": "sports", "selected": true }, // ✅ Dans l'array
|
|
126
|
+
// { "label": "Music", "value": "music", "selected": true }, // ✅ Dans l'array
|
|
127
|
+
// { "label": "Reading", "value": "reading", "selected": false }
|
|
128
|
+
// ]
|
|
129
|
+
// }
|
|
130
|
+
|
|
131
|
+
// Méthode 2: setFieldValue() - Injection Individuelle
|
|
132
|
+
const form = new FormView('form', 'Form')
|
|
133
|
+
.addTextField('name', 'Name', true)
|
|
134
|
+
.setFieldValue('name', 'John Doe'); // ✅ Définit une valeur spécifique
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Lecteurs de Données (Contenu Riche)
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { ReaderView } from '@yeria/jsonapp-sdk';
|
|
141
|
+
|
|
142
|
+
// ReaderView affiche du contenu riche (pas des formulaires)
|
|
143
|
+
// Le titre est passé au constructeur (id, title)
|
|
144
|
+
const reader = new ReaderView('user-profile', 'User Profile')
|
|
145
|
+
.setIntro('Your profile information')
|
|
146
|
+
.addParagraph('Welcome to your user profile. Here you can view your personal information.')
|
|
147
|
+
.addSubTitle('Personal Information')
|
|
148
|
+
.addListField([
|
|
149
|
+
'Name: John Doe',
|
|
150
|
+
'Email: john@example.com',
|
|
151
|
+
'Phone: +1234567890'
|
|
152
|
+
])
|
|
153
|
+
.addSeparator()
|
|
154
|
+
.addSubTitle('Account Status')
|
|
155
|
+
.addParagraph('Your account is active and in good standing.')
|
|
156
|
+
.addImage('https://example.com/profile-picture.jpg', 'Profile Picture', 'Your profile photo');
|
|
157
|
+
|
|
158
|
+
console.log(reader.toJSON());
|
|
159
|
+
|
|
160
|
+
// Exemple avec Markdown
|
|
161
|
+
const readerMarkdown = new ReaderView('help-guide', 'Help Guide')
|
|
162
|
+
.setIntro('Learn how to use our platform')
|
|
163
|
+
.addMarkdown(`
|
|
164
|
+
## Getting Started
|
|
165
|
+
|
|
166
|
+
Welcome to our platform! Here's how to get started:
|
|
167
|
+
|
|
168
|
+
1. **Create an account** - Sign up with your email
|
|
169
|
+
2. **Complete your profile** - Add your information
|
|
170
|
+
3. **Explore features** - Discover what we offer
|
|
171
|
+
|
|
172
|
+
### Need Help?
|
|
173
|
+
Contact our support team at support@example.com
|
|
174
|
+
`);
|
|
175
|
+
|
|
176
|
+
// ReaderView avec navigation (ex: tutoriel multi-pages)
|
|
177
|
+
const tutorial1 = new ReaderView('tutorial-1', 'Tutorial - Getting Started')
|
|
178
|
+
.setIntro('Welcome to the tutorial!')
|
|
179
|
+
.addParagraph('This tutorial will guide you through the basics.')
|
|
180
|
+
.setNext('/api/readers/tutorial-2') // Page suivante
|
|
181
|
+
.setPrev('/api/readers/welcome'); // Page précédente
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Listes d'Actions
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import { ActionListView } from '@yeria/jsonapp-sdk';
|
|
188
|
+
|
|
189
|
+
// Le titre est passé au constructeur (viewId, viewTitle)
|
|
190
|
+
const actionList = new ActionListView('main-menu', 'Main Menu')
|
|
191
|
+
.addAction('profile', 'View Profile', 'Access your profile information', 'profile-icon.png')
|
|
192
|
+
.addAction('settings', 'Settings', 'Configure your preferences', 'settings-icon.png')
|
|
193
|
+
.addAction('help', 'Help & Support', 'Get help and contact support', 'help-icon.png');
|
|
194
|
+
|
|
195
|
+
console.log(actionList.toJSON());
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Grilles d'Actions
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import { ActionGridView } from '@yeria/jsonapp-sdk';
|
|
202
|
+
|
|
203
|
+
// Le titre est passé au constructeur (viewId, viewTitle)
|
|
204
|
+
const actionGrid = new ActionGridView('dashboard', 'Dashboard')
|
|
205
|
+
.setColumns(3)
|
|
206
|
+
.setSpacing(20)
|
|
207
|
+
.addAction('analytics', 'Analytics', 'View your analytics', 'analytics-icon.png')
|
|
208
|
+
.addAction('reports', 'Reports', 'Generate reports', 'reports-icon.png')
|
|
209
|
+
.addAction('users', 'Users', 'Manage users', 'users-icon.png');
|
|
210
|
+
|
|
211
|
+
console.log(actionGrid.toJSON());
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Scanner de QR Codes
|
|
215
|
+
|
|
216
|
+
**Note** : Version 2.0 - API simplifiée. Le rendu mobile gère toute l'implémentation du scanner (caméra, torche, mise au point, formats).
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
import { QRScanView } from '@yeria/jsonapp-sdk';
|
|
220
|
+
|
|
221
|
+
// Auto-soumission simple (scan → POST immédiat)
|
|
222
|
+
const quickScan = new QRScanView('scan-ticket', 'Scan Your Ticket')
|
|
223
|
+
.setIntro('Point your camera at the QR code on your ticket');
|
|
224
|
+
// → L'utilisateur scanne "ABC123" → POST immédiat { qrData: "ABC123" }
|
|
225
|
+
|
|
226
|
+
// Avec bouton de confirmation (désactive auto-soumission)
|
|
227
|
+
const confirmScan = new QRScanView('verify-product', 'Verify Product')
|
|
228
|
+
.setIntro('Scan the product barcode')
|
|
229
|
+
.enablePreview(false, 'Product Code')
|
|
230
|
+
.submitButton('Verify Product');
|
|
231
|
+
// → Scanne → Affiche aperçu → Utilisateur clique "Verify Product" → POST
|
|
232
|
+
|
|
233
|
+
// Avec validation : préfixe + format numérique + longueur
|
|
234
|
+
const invoiceScan = new QRScanView('scan-invoice', 'Scan Invoice')
|
|
235
|
+
.setIntro('Scan the invoice QR code')
|
|
236
|
+
.setValidation('Invalid invoice format', 'number', 10, 10, 'INV-')
|
|
237
|
+
.submitButton('Process Invoice', 'Confirm processing?');
|
|
238
|
+
// → Scanne → Valide (préfixe INV-, chiffres, longueur 10) → Confirmation → POST
|
|
239
|
+
// Accepte : "INV-123456" (10 caractères total)
|
|
240
|
+
|
|
241
|
+
// Exemple 4 : Code PIN numérique exact
|
|
242
|
+
const pinScan = new QRScanView('scan-pin', 'Scan PIN')
|
|
243
|
+
.setIntro('Scan 6-digit PIN code')
|
|
244
|
+
.setValidation('PIN must be 6 digits', 'number', 6, 6);
|
|
245
|
+
// → Auto-submit si valide (6 chiffres)
|
|
246
|
+
|
|
247
|
+
// Exemple 5 : Email
|
|
248
|
+
const emailScan = new QRScanView('scan-email', 'Scan Email QR')
|
|
249
|
+
.setIntro('Scan email QR code')
|
|
250
|
+
.setValidation('Invalid email format', 'email');
|
|
251
|
+
// → Validation simple (contient @ et .)
|
|
252
|
+
|
|
253
|
+
// Exemple 6 : URL
|
|
254
|
+
const urlScan = new QRScanView('scan-url', 'Scan URL')
|
|
255
|
+
.setIntro('Scan URL QR code')
|
|
256
|
+
.setValidation('Invalid URL', 'url');
|
|
257
|
+
// → Validation simple (commence par http:// ou https://)
|
|
258
|
+
|
|
259
|
+
console.log(quickScan.toJSON());
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Convention** : Le nom de champ est toujours `qrData` (non configurable). Données soumises : `{ qrData: "scanned-value" }`
|
|
263
|
+
|
|
264
|
+
**Formats de validation** :
|
|
265
|
+
- `'text'` : Aucune restriction
|
|
266
|
+
- `'number'` : Seulement chiffres (0-9)
|
|
267
|
+
- `'email'` : Validation simple (contient @ et .)
|
|
268
|
+
- `'url'` : Validation simple (http:// ou https://)
|
|
269
|
+
|
|
270
|
+
**IMPORTANT** : La validation mobile est **simple et permissive**. Le serveur **DOIT toujours re-valider** pour la sécurité.
|
|
271
|
+
|
|
272
|
+
### Affichage de QR Codes
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import { QRDisplayView } from '@yeria/jsonapp-sdk';
|
|
276
|
+
|
|
277
|
+
const qrDisplay = new QRDisplayView('qr-display', 'QR Code Display')
|
|
278
|
+
.setIntro('Your QR codes are ready to scan')
|
|
279
|
+
.addQRCodeReader(
|
|
280
|
+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
|
|
281
|
+
'Product QR Code',
|
|
282
|
+
'Scan this QR code to view product details',
|
|
283
|
+
{ size: 200, errorCorrection: 'M' }
|
|
284
|
+
)
|
|
285
|
+
.submitButton('Share QR Codes', 'POST');
|
|
286
|
+
|
|
287
|
+
console.log(qrDisplay.toJSON());
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Messages
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
import { MessageView } from '@yeria/jsonapp-sdk';
|
|
294
|
+
|
|
295
|
+
const message = new MessageView('maintenance-alert', 'Scheduled maintenance')
|
|
296
|
+
.setIntro('Heads up!')
|
|
297
|
+
.setBody('The platform will be unavailable tonight from 1:00 to 2:00 UTC while we apply upgrades.')
|
|
298
|
+
.setSeverity('warning')
|
|
299
|
+
.setPrimaryAction('OK, thanks', 'POST')
|
|
300
|
+
.setSecondaryAction('Remind me later', 'POST')
|
|
301
|
+
.setDismissible(true);
|
|
302
|
+
|
|
303
|
+
console.log(message.toJSON());
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Cartes Produit (CardView)
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
import { CardView } from '@yeria/jsonapp-sdk';
|
|
310
|
+
|
|
311
|
+
const productCard = new CardView('product-card', 'Super Gadget')
|
|
312
|
+
.setSubtitle('Boostez votre journée')
|
|
313
|
+
.setDescription('Un compagnon compact pour organiser vos tâches et automatiser vos routines quotidiennes.')
|
|
314
|
+
.setImage('https://cdn.example.com/gadget.jpg', 'Super Gadget')
|
|
315
|
+
.addStat('Prix', '49 €')
|
|
316
|
+
.addStat('Stock', 'Disponible')
|
|
317
|
+
.addSection('Points clés', 'Assistant vocal intégré, autonomie 48h, synchronisation multi-appareils.')
|
|
318
|
+
.addAction('Acheter maintenant', 'POST', { confirmMessage: 'Confirmez-vous votre achat ?' })
|
|
319
|
+
.addAction('Voir les détails', 'GET', { href: '/produits/super-gadget', variant: 'link' });
|
|
320
|
+
|
|
321
|
+
console.log(productCard.toJSON());
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Carrousels (CarouselView)
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
import { CarouselView } from '@yeria/jsonapp-sdk';
|
|
328
|
+
|
|
329
|
+
const highlights = new CarouselView('home-carousel', 'Mises en avant')
|
|
330
|
+
.addSlide(
|
|
331
|
+
highlights.createSlide('release-2-0', 'Version 2.0', 'Découvrez les nouveautés', {
|
|
332
|
+
imageUrl: 'https://cdn.example.com/banners/release.jpg',
|
|
333
|
+
badge: 'Nouveau'
|
|
334
|
+
})
|
|
335
|
+
)
|
|
336
|
+
.addSlide(
|
|
337
|
+
highlights.createSlide('case-study', 'Étude client', 'Comment ACME a doublé sa productivité', {
|
|
338
|
+
imageUrl: 'https://cdn.example.com/banners/case-study.jpg'
|
|
339
|
+
})
|
|
340
|
+
)
|
|
341
|
+
.addSlideAction('release-2-0', 'Lire l’article', 'GET', { href: '/blog/version-2-0', variant: 'link' })
|
|
342
|
+
.setSettings({ autoplay: true, intervalMs: 5000, loop: true });
|
|
343
|
+
|
|
344
|
+
console.log(highlights.toJSON());
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Timelines (TimelineView)
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
import { TimelineView } from '@yeria/jsonapp-sdk';
|
|
351
|
+
|
|
352
|
+
const onboarding = new TimelineView('onboarding-flow', 'Votre progression')
|
|
353
|
+
.setIntro('Suivez vos étapes de mise en service')
|
|
354
|
+
.addEvent('step-1', 'Compte créé', new Date().toISOString(), { status: 'completed' })
|
|
355
|
+
.addEvent('step-2', 'Télécharger vos documents', '2025-01-15T12:00:00Z', { status: 'active' })
|
|
356
|
+
.addEvent('step-3', 'Validation', '2025-01-20T09:00:00Z', { status: 'pending' });
|
|
357
|
+
|
|
358
|
+
console.log(onboarding.toJSON());
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Médias (MediaView)
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
import { MediaView } from '@yeria/jsonapp-sdk';
|
|
365
|
+
|
|
366
|
+
const tutorials = new MediaView('media-library', 'Tutoriels express')
|
|
367
|
+
.setIntro('Apprenez en quelques minutes')
|
|
368
|
+
.addMediaItem(
|
|
369
|
+
tutorials.createMedia('video-intro', 'video', 'https://cdn.example.com/videos/intro.mp4', {
|
|
370
|
+
type: 'video/mp4',
|
|
371
|
+
poster: 'https://cdn.example.com/posters/intro.jpg'
|
|
372
|
+
})
|
|
373
|
+
)
|
|
374
|
+
.addMediaItem({
|
|
375
|
+
id: 'audio-guide',
|
|
376
|
+
kind: 'audio',
|
|
377
|
+
title: 'Guide audio',
|
|
378
|
+
sources: [{ src: 'https://cdn.example.com/audio/guide.mp3', type: 'audio/mpeg' }]
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
console.log(tutorials.toJSON());
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Cartes interactives (MapView)
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
import { MapView } from '@yeria/jsonapp-sdk';
|
|
388
|
+
|
|
389
|
+
const storeMap = new MapView('stores-map', 'Boutiques partenaires')
|
|
390
|
+
.setViewport({ lat: 48.8566, lon: 2.3522 }, { zoom: 12 })
|
|
391
|
+
.addMarker({
|
|
392
|
+
id: 'store-paris',
|
|
393
|
+
title: 'Paris Centre',
|
|
394
|
+
description: 'Ouvert de 9h à 19h',
|
|
395
|
+
location: { lat: 48.8566, lon: 2.3522 }
|
|
396
|
+
})
|
|
397
|
+
.addMarker({
|
|
398
|
+
id: 'store-lyon',
|
|
399
|
+
title: 'Lyon République',
|
|
400
|
+
location: { lat: 45.7640, lon: 4.8357 }
|
|
401
|
+
})
|
|
402
|
+
.setControls({ zoom: true, userLocation: true });
|
|
403
|
+
|
|
404
|
+
console.log(storeMap.toJSON());
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Notifications
|
|
408
|
+
|
|
409
|
+
Envoyer des notifications signées aux utilisateurs via la plateforme City-Mate :
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
import { JsonApp } from 'jsonapp-js';
|
|
413
|
+
|
|
414
|
+
const jsonApp = new JsonApp({
|
|
415
|
+
appId: 'my-backend-service',
|
|
416
|
+
platformUrl: 'https://platform.yeria.com/api/notifications' // Optionnel: peut aussi être passé par appel
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// Créer et envoyer une notification
|
|
420
|
+
const notification = jsonApp
|
|
421
|
+
.createNotification('user-123', 'Bienvenue !', 'Merci d\'avoir rejoint City-Mate')
|
|
422
|
+
.setLink('/welcome');
|
|
423
|
+
|
|
424
|
+
await jsonApp.sendNotification(notification);
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### JsonApp sécurisé
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
import { JsonApp } from '@yeria/jsonapp-sdk';
|
|
431
|
+
|
|
432
|
+
const jsonApp = new JsonApp({
|
|
433
|
+
appId: 'my-backend-service',
|
|
434
|
+
viewExpirationMinutes: 30
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
const form = jsonApp
|
|
438
|
+
.createFormView('user-registration', 'User Registration')
|
|
439
|
+
.addTextField('email', 'Email', true)
|
|
440
|
+
.addPasswordField('password', 'Password', 8)
|
|
441
|
+
.submitButton('Register', 'POST');
|
|
442
|
+
|
|
443
|
+
const secureResponse = jsonApp.serve(form);
|
|
444
|
+
console.log('Signature:', secureResponse.signature);
|
|
445
|
+
console.log('Integrity check:', jsonApp.verifyIntegrity(secureResponse));
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
> ℹ️ **JsonApp est stateless** : il ne conserve plus les vues créées. Gardez vos instances (ex: dans un tableau) si vous devez les servir plus tard.
|
|
449
|
+
|
|
450
|
+
Vous pouvez également signer une vue sans instancier JsonApp grâce au helper statique :
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
import { JsonApp, FormView } from '@yeria/jsonapp-sdk';
|
|
454
|
+
|
|
455
|
+
const privateKey = process.env.PRIVATE_KEY!; // clé PEM Ed25519
|
|
456
|
+
const publicKey = process.env.PUBLIC_KEY!;
|
|
457
|
+
|
|
458
|
+
const manualForm = new FormView('manual', 'Manual Form')
|
|
459
|
+
.addTextField('name', 'Name', true)
|
|
460
|
+
.submitButton('Save', 'POST');
|
|
461
|
+
|
|
462
|
+
const payload = manualForm.toJSON();
|
|
463
|
+
const signed = JsonApp.signView(payload, 'my-backend-service', privateKey);
|
|
464
|
+
|
|
465
|
+
console.log('Signature valide ?', JsonApp.verifySignature(publicKey, signed));
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
## 🧭 Workflows Multi-Étapes (Process Context)
|
|
469
|
+
|
|
470
|
+
Le SDK supporte les processus multi-étapes avec suivi de progression via `belongsToProcess()`.
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
import { FormView } from '@yeria/jsonapp-sdk';
|
|
474
|
+
|
|
475
|
+
// Étape 1 : Bienvenue
|
|
476
|
+
const step1 = new FormView('welcome', 'Welcome!', 'user-onboarding')
|
|
477
|
+
.belongsToProcess('user-onboarding', {
|
|
478
|
+
processName: 'User Onboarding',
|
|
479
|
+
currentStep: 1,
|
|
480
|
+
totalSteps: 4,
|
|
481
|
+
stepName: 'Welcome',
|
|
482
|
+
canGoBack: false,
|
|
483
|
+
canSkip: false
|
|
484
|
+
})
|
|
485
|
+
.setIntro('Let\'s get you started')
|
|
486
|
+
.addTextField('firstName', 'First Name', true, 50)
|
|
487
|
+
.addTextField('lastName', 'Last Name', true, 50)
|
|
488
|
+
.setNext('personal-info') // Relative viewId (même processus)
|
|
489
|
+
.submitButton('Continue');
|
|
490
|
+
|
|
491
|
+
// Étape 2 : Informations personnelles
|
|
492
|
+
const step2 = new FormView('personal-info', 'Personal Information', 'user-onboarding')
|
|
493
|
+
.belongsToProcess('user-onboarding', {
|
|
494
|
+
processName: 'User Onboarding',
|
|
495
|
+
currentStep: 2,
|
|
496
|
+
totalSteps: 4,
|
|
497
|
+
stepName: 'Personal Info',
|
|
498
|
+
canGoBack: true,
|
|
499
|
+
canSkip: false
|
|
500
|
+
})
|
|
501
|
+
.setIntro('Tell us about yourself')
|
|
502
|
+
.addEmailField('email', 'Email Address', true)
|
|
503
|
+
.addPhoneField('phone', 'Phone Number', true)
|
|
504
|
+
.setPrev('welcome')
|
|
505
|
+
.setNext('address')
|
|
506
|
+
.submitButton('Continue');
|
|
507
|
+
|
|
508
|
+
// Pattern d'URL : /api/processes/user-onboarding/views/welcome
|
|
509
|
+
// Soumission : POST /api/processes/user-onboarding/views/welcome
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
## 🔧 Configuration
|
|
513
|
+
|
|
514
|
+
### Logging
|
|
515
|
+
|
|
516
|
+
The SDK provides a **flexible, pluggable logging system** that is **silent by default** in production.
|
|
517
|
+
|
|
518
|
+
#### **Silent Mode (Default - Production)**
|
|
519
|
+
|
|
520
|
+
```typescript
|
|
521
|
+
import { JsonApp } from '@yeria/jsonapp-sdk';
|
|
522
|
+
|
|
523
|
+
// No logger = SilentLogger (no logs in production)
|
|
524
|
+
const app = new JsonApp({ appId: 'my-app' });
|
|
525
|
+
// Clean, professional - no console pollution
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
#### **Console Logger (Development)**
|
|
529
|
+
|
|
530
|
+
```typescript
|
|
531
|
+
import { JsonApp, ConsoleLogger } from '@yeria/jsonapp-sdk';
|
|
532
|
+
|
|
533
|
+
// Opt-in to console logging for debugging
|
|
534
|
+
const app = new JsonApp({
|
|
535
|
+
appId: 'my-app',
|
|
536
|
+
logger: new ConsoleLogger('info') // 'debug' | 'info' | 'warn' | 'error'
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// Logs appear for important operations:
|
|
540
|
+
// [2025-10-25T10:30:00.000Z] [JsonApp INFO] JsonApp initialized
|
|
541
|
+
// [2025-10-25T10:30:00.001Z] [JsonApp INFO] View served securely
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
#### **Custom Logger (Integration with Existing Systems)**
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
import { JsonApp, ILogger } from '@yeria/jsonapp-sdk';
|
|
548
|
+
|
|
549
|
+
// Integrate with Sentry, Winston, Datadog, etc.
|
|
550
|
+
const customLogger: ILogger = {
|
|
551
|
+
debug: (msg, ctx) => winston.debug(msg, ctx),
|
|
552
|
+
info: (msg, ctx) => winston.info(msg, ctx),
|
|
553
|
+
warn: (msg, ctx) => winston.warn(msg, ctx),
|
|
554
|
+
error: (msg, ctx) => winston.error(msg, ctx)
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
const app = new JsonApp({
|
|
558
|
+
appId: 'my-app',
|
|
559
|
+
logger: customLogger // All SDK logs use your logger
|
|
560
|
+
});
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
#### **Environment-Based Logging**
|
|
564
|
+
|
|
565
|
+
```typescript
|
|
566
|
+
import { JsonApp, ConsoleLogger, SilentLogger } from '@yeria/jsonapp-sdk';
|
|
567
|
+
|
|
568
|
+
const logger = process.env['NODE_ENV'] === 'development'
|
|
569
|
+
? new ConsoleLogger('debug')
|
|
570
|
+
: new SilentLogger();
|
|
571
|
+
|
|
572
|
+
const app = new JsonApp({ appId: 'my-app', logger });
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
#### **Legacy Logger (Backward Compatibility)**
|
|
576
|
+
|
|
577
|
+
```typescript
|
|
578
|
+
import { Logger } from '@yeria/jsonapp-sdk';
|
|
579
|
+
|
|
580
|
+
// Old API still works (deprecated)
|
|
581
|
+
Logger.getInstance().setLogLevel('info');
|
|
582
|
+
Logger.info('JsonApp ready');
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
See [LOGGER_ARCHITECTURE.md](./LOGGER_ARCHITECTURE.md) for complete documentation.
|
|
586
|
+
|
|
587
|
+
### Validation
|
|
588
|
+
|
|
589
|
+
```typescript
|
|
590
|
+
import { FieldValidator, DataSanitizer } from '@yeria/jsonapp-sdk';
|
|
591
|
+
|
|
592
|
+
// Validation de configuration de champ
|
|
593
|
+
const fieldCheck = FieldValidator.validateField('email', 'email', 'Email', {
|
|
594
|
+
required: true,
|
|
595
|
+
value: 'test@example.com'
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
// Nettoyage d'entrée utilisateur
|
|
599
|
+
const safeValue = DataSanitizer.sanitizeInput('<script>alert(1)</script>');
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
## 📋 Types Supportés
|
|
603
|
+
|
|
604
|
+
### Champs de Formulaire
|
|
605
|
+
- `text` - Texte simple
|
|
606
|
+
- `email` - Adresse email
|
|
607
|
+
- `tel` - Numéro de téléphone
|
|
608
|
+
- `password` - Mot de passe
|
|
609
|
+
- `date` - Date
|
|
610
|
+
- `file` - Fichier
|
|
611
|
+
- `gps` - Coordonnées GPS
|
|
612
|
+
- `select` - Sélection
|
|
613
|
+
- `pluscode` - Code Plus
|
|
614
|
+
|
|
615
|
+
### Types de Vue
|
|
616
|
+
- `Form` - Formulaires
|
|
617
|
+
- `Reader` - Lecteurs de données
|
|
618
|
+
- `ActionList` - Listes d'actions
|
|
619
|
+
- `ActionGrid` - Grilles d'actions
|
|
620
|
+
- `QRScan` - Scanner de QR codes
|
|
621
|
+
- `QRDisplay` - Affichage de QR codes
|
|
622
|
+
- `Message` - Messages
|
|
623
|
+
- `Card` - Cartes produit/profil
|
|
624
|
+
- `Carousel` - Carrousels d'images
|
|
625
|
+
- `Timeline` - Lignes temporelles
|
|
626
|
+
- `Media` - Lecteurs audio/vidéo
|
|
627
|
+
- `Map` - Cartes interactives
|
|
628
|
+
|
|
629
|
+
## 🧪 Tests
|
|
630
|
+
|
|
631
|
+
```bash
|
|
632
|
+
# Exécuter tous les tests
|
|
633
|
+
npm test
|
|
634
|
+
|
|
635
|
+
# Tests en mode watch
|
|
636
|
+
npm run test:watch
|
|
637
|
+
|
|
638
|
+
# Tests avec couverture
|
|
639
|
+
npm run test:coverage
|
|
640
|
+
|
|
641
|
+
# Test du SDK complet
|
|
642
|
+
npm run test:sdk
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
## 📚 API Référence
|
|
646
|
+
|
|
647
|
+
### BaseView
|
|
648
|
+
Classe de base pour toutes les vues avec méthodes communes :
|
|
649
|
+
- `toJSON()` - Sérialisation en JSON
|
|
650
|
+
- `clone()` - Clonage de la vue
|
|
651
|
+
- `validate()` - Validation des données
|
|
652
|
+
|
|
653
|
+
### FormView
|
|
654
|
+
Gestion des formulaires avec validation avancée :
|
|
655
|
+
- `setIntro()` - Texte d'introduction du formulaire (recommandé)
|
|
656
|
+
- `setNote()` - Note introductive (déprécié, utilisez `setIntro()`)
|
|
657
|
+
- `addField()` - Ajout de champ générique
|
|
658
|
+
- `addTextField()`, `addEmailField()`, `addPhoneField()`, `addPasswordField()` - Champs texte
|
|
659
|
+
- `addNumberField()`, `addDateField()` - Champs numériques et date
|
|
660
|
+
- `addSelectField()`, `addCheckboxField()` - Sélections
|
|
661
|
+
- `addPhotoField()`, `addFileField()` - Upload de fichiers
|
|
662
|
+
- `addGPSField()`, `addPlusCodeField()` - Localisation
|
|
663
|
+
- `injectData()` - Injection de données pour formulaires d'édition
|
|
664
|
+
- `setFieldValue()` - Définir la valeur d'un champ
|
|
665
|
+
- `submitButton()`, `updateButton()`, `deleteButton()` - Boutons d'action
|
|
666
|
+
- `setNext()`, `setPrev()` - Navigation multi-étapes
|
|
667
|
+
- `belongsToProcess()` - Associer à un processus
|
|
668
|
+
|
|
669
|
+
### ReaderView
|
|
670
|
+
Affichage de contenu riche en lecture seule :
|
|
671
|
+
- `setIntro()` - Texte d'introduction
|
|
672
|
+
- `addParagraph()` - Ajout de paragraphes
|
|
673
|
+
- `addImage()` - Ajout d'images
|
|
674
|
+
- `addSubTitle()` - Ajout de sous-titres
|
|
675
|
+
- `addMarkdown()` - Ajout de contenu Markdown
|
|
676
|
+
- `addListField()` - Ajout de listes
|
|
677
|
+
- `addLink()` - Ajout de liens
|
|
678
|
+
- `addTable()` - Ajout de tableaux
|
|
679
|
+
- `addCodeBlock()` - Ajout de blocs de code
|
|
680
|
+
- `addQuote()` - Ajout de citations
|
|
681
|
+
- `addSeparator()` - Ajout de séparateurs
|
|
682
|
+
- `setNext()`, `setPrev()` - Navigation
|
|
683
|
+
|
|
684
|
+
### ActionListView/ActionGridView
|
|
685
|
+
Gestion des actions et navigation :
|
|
686
|
+
- `addAction()` - Ajout d'actions
|
|
687
|
+
- `removeAction()` - Suppression d'actions
|
|
688
|
+
- `getActiveActions()` - Actions actives
|
|
689
|
+
|
|
690
|
+
### QRScanView
|
|
691
|
+
Scanner de QR codes (v2.0 - API simplifiée) :
|
|
692
|
+
- `setIntro()` - Instructions pour l'utilisateur
|
|
693
|
+
- `submitButton()` - Bouton de confirmation (désactive auto-soumission)
|
|
694
|
+
- `setValidation(errorMessage, format?, minLength?, maxLength?, startsWith?)` - Règles de validation
|
|
695
|
+
- Formats : `'text'`, `'number'`, `'url'`, `'email'`
|
|
696
|
+
- `enablePreview()` / `disablePreview()` - Aperçu avant soumission
|
|
697
|
+
- `setAutoSubmit()` - Activer/désactiver soumission automatique
|
|
698
|
+
- **Convention** : Nom de champ toujours `qrData`
|
|
699
|
+
|
|
700
|
+
### QRDisplayView
|
|
701
|
+
Affichage de QR codes :
|
|
702
|
+
- `setIntro()` - Texte d'introduction
|
|
703
|
+
- `addQRCodeReader(imageUrl, title, description?, options?)` - Affichage d'un QR code
|
|
704
|
+
- `submitButton()` - Bouton d'action (partage, etc.)
|
|
705
|
+
|
|
706
|
+
### MessageView
|
|
707
|
+
Gestion des messages et notifications :
|
|
708
|
+
- `setIntro()` - Texte d'introduction
|
|
709
|
+
- `setBody()` - Définition du message principal
|
|
710
|
+
- `setSeverity()` - Niveau d'alerte (`'info'`, `'success'`, `'warning'`, `'error'`)
|
|
711
|
+
- `setPrimaryAction()` - Bouton principal (OK, Valider…)
|
|
712
|
+
- `setSecondaryAction()` - Bouton secondaire (Annuler, Plus tard…)
|
|
713
|
+
- `setDismissible()` - Autoriser la fermeture sans action
|
|
714
|
+
- `submitButton()` - Alias de `setPrimaryAction()`
|
|
715
|
+
|
|
716
|
+
### CardView
|
|
717
|
+
Présenter des fiches riches :
|
|
718
|
+
- `setSubtitle()` - Sous-titre court
|
|
719
|
+
- `setDescription()` - Texte détaillé
|
|
720
|
+
- `addStat()` - Statistiques clés (prix, stock…)
|
|
721
|
+
- `addSection()` - Contenu structuré (atouts, détails)
|
|
722
|
+
- `addAction()` - Boutons d'action
|
|
723
|
+
|
|
724
|
+
### CarouselView
|
|
725
|
+
Mettre en avant plusieurs contenus :
|
|
726
|
+
- `createSlide()` / `addSlide()` - Gestion des slides
|
|
727
|
+
- `addSlideAction()` - Actions par slide
|
|
728
|
+
- `setSettings()` - Autoplay, boucle, indicateurs
|
|
729
|
+
|
|
730
|
+
### TimelineView
|
|
731
|
+
Suivre une progression :
|
|
732
|
+
- `setIntro()` - Contexte
|
|
733
|
+
- `addEvent()` / `addItem()` - Ajout d'étapes
|
|
734
|
+
- `setItems()` - Définir la timeline complète
|
|
735
|
+
|
|
736
|
+
### MediaView
|
|
737
|
+
Lecteurs audio/vidéo :
|
|
738
|
+
- `setIntro()` - Présentation
|
|
739
|
+
- `createMedia()` - Helper pour créer une ressource
|
|
740
|
+
- `addMediaItem()` - Ajouter vidéos ou podcasts
|
|
741
|
+
- `clearItems()` - Réinitialiser la playlist
|
|
742
|
+
|
|
743
|
+
### MapView
|
|
744
|
+
Afficher des emplacements :
|
|
745
|
+
- `setViewport()` - Définir centre et zoom
|
|
746
|
+
- `addMarker()` / `addMarkers()` - Ajouter des points d'intérêt
|
|
747
|
+
- `setControls()` - Activer zoom, boussole, localisation
|
|
748
|
+
- `addOverlay()` - Ajouter des zones personnalisées
|
|
749
|
+
|
|
750
|
+
## 🎨 Guide de Sélection de Vue
|
|
751
|
+
|
|
752
|
+
### Quand utiliser chaque type de vue ?
|
|
753
|
+
|
|
754
|
+
#### FormView
|
|
755
|
+
- ✅ **Collecte de données utilisateur** (inscription, connexion, profil)
|
|
756
|
+
- ✅ **Formulaires interactifs** avec validation
|
|
757
|
+
- ✅ **Soumission de données** vers un serveur
|
|
758
|
+
- **Méthodes** : `addTextField()`, `addEmailField()`, `addPasswordField()`, etc.
|
|
759
|
+
|
|
760
|
+
#### ReaderView
|
|
761
|
+
- ✅ **Affichage de contenu** (articles, guides, documentation)
|
|
762
|
+
- ✅ **Présentations riches** avec images, markdown, tableaux
|
|
763
|
+
- ✅ **Pages informatives** sans interaction
|
|
764
|
+
- **Méthodes** : `addParagraph()`, `addImage()`, `addMarkdown()`, `addTable()`, etc.
|
|
765
|
+
|
|
766
|
+
#### ActionListView / ActionGridView
|
|
767
|
+
- ✅ **Menus de navigation**
|
|
768
|
+
- ✅ **Listes d'options** cliquables
|
|
769
|
+
- ✅ **Dashboards** avec actions rapides
|
|
770
|
+
|
|
771
|
+
#### QRScanView
|
|
772
|
+
- ✅ **Scanner** des QR codes avec auto-soumission
|
|
773
|
+
- ✅ **Validation** des codes scannés (format, longueur)
|
|
774
|
+
- ✅ **Aperçu** et édition manuelle avant soumission
|
|
775
|
+
- ✅ **Workflows de confirmation** avec boutons
|
|
776
|
+
- **Méthodes** : `setIntro()`, `submitButton()`, `setValidation()`, `enablePreview()`
|
|
777
|
+
|
|
778
|
+
#### QRDisplayView
|
|
779
|
+
- ✅ **Afficher** des QR codes
|
|
780
|
+
- ✅ **Partage** d'informations via QR
|
|
781
|
+
|
|
782
|
+
#### MessageView
|
|
783
|
+
- ✅ **Boîtes de dialogue** de confirmation
|
|
784
|
+
- ✅ **Messages informatifs** avec bouton OK et option Annuler
|
|
785
|
+
- ✅ **Alertes** (succès, avertissement, erreur) nécessitant une confirmation
|
|
786
|
+
|
|
787
|
+
#### CardView
|
|
788
|
+
- ✅ **Fiches produit** ou profils détaillés
|
|
789
|
+
- ✅ **Encarts de recommandations**
|
|
790
|
+
- ✅ **Résumé de compte** avec statistiques
|
|
791
|
+
|
|
792
|
+
#### CarouselView
|
|
793
|
+
- ✅ **Page d’accueil** avec bannières
|
|
794
|
+
- ✅ **Promotions** ou actualités multiples
|
|
795
|
+
- ✅ **Guides miniatures** à feuilleter
|
|
796
|
+
|
|
797
|
+
#### TimelineView
|
|
798
|
+
- ✅ **Suivi de dossier** étape par étape
|
|
799
|
+
- ✅ **Historique d’activités**
|
|
800
|
+
- ✅ **Roadmaps produit**
|
|
801
|
+
|
|
802
|
+
#### MediaView
|
|
803
|
+
- ✅ **Tutoriels vidéo**
|
|
804
|
+
- ✅ **Podcasts ou messages audio**
|
|
805
|
+
- ✅ **Playlists courtes** au sein de l’app
|
|
806
|
+
|
|
807
|
+
#### MapView
|
|
808
|
+
- ✅ **Points de vente** ou agences à proximité
|
|
809
|
+
- ✅ **Itinéraires** et zones de livraison
|
|
810
|
+
- ✅ **Visualisation de capteurs** (IoT, suivi terrain)
|
|
811
|
+
|
|
812
|
+
### Erreurs Courantes à Éviter
|
|
813
|
+
|
|
814
|
+
❌ **Erreur** : Utiliser `addField()` sur ReaderView
|
|
815
|
+
```typescript
|
|
816
|
+
// FAUX - addField() n'existe pas sur ReaderView
|
|
817
|
+
const reader = new ReaderView('profile', 'Profile')
|
|
818
|
+
.addField('name', 'text', 'Name', 'John'); // ❌ ERREUR
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
✅ **Correct** : Utiliser `addParagraph()` ou `addListField()`
|
|
822
|
+
```typescript
|
|
823
|
+
// CORRECT
|
|
824
|
+
const reader = new ReaderView('profile', 'Profile')
|
|
825
|
+
.addParagraph('Name: John Doe') // ✅
|
|
826
|
+
.addListField(['Email: john@example.com', 'Phone: +123']); // ✅
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
❌ **Erreur** : Mauvais ordre des paramètres dans `addField()`
|
|
830
|
+
```typescript
|
|
831
|
+
// FAUX - ordre inversé
|
|
832
|
+
form.addField('name', 'text', 'Full Name', true); // ❌
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
✅ **Correct** : fieldType en premier
|
|
836
|
+
```typescript
|
|
837
|
+
// CORRECT
|
|
838
|
+
form.addField('text', 'name', 'Full Name', { required: true }); // ✅
|
|
839
|
+
// OU mieux : utiliser les méthodes helper
|
|
840
|
+
form.addTextField('name', 'Full Name', true); // ✅ Recommandé
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
## 🤝 Contribution
|
|
844
|
+
|
|
845
|
+
1. Fork le projet
|
|
846
|
+
2. Créez une branche feature (`git checkout -b feature/AmazingFeature`)
|
|
847
|
+
3. Commit vos changements (`git commit -m 'Add some AmazingFeature'`)
|
|
848
|
+
4. Push vers la branche (`git push origin feature/AmazingFeature`)
|
|
849
|
+
5. Ouvrez une Pull Request
|
|
850
|
+
|
|
851
|
+
## 📄 Licence
|
|
852
|
+
|
|
853
|
+
Ce projet est sous licence MIT. Voir le fichier `LICENSE` pour plus de détails.
|
|
854
|
+
|
|
855
|
+
## 🆘 Support
|
|
856
|
+
|
|
857
|
+
Pour toute question ou problème :
|
|
858
|
+
- Ouvrez une issue sur GitHub
|
|
859
|
+
- Consultez la documentation
|
|
860
|
+
- Contactez l'équipe de développement
|
|
861
|
+
|
|
862
|
+
---
|
|
863
|
+
|
|
864
|
+
**JSONApp SDK** - Génération d'interfaces JSON dynamiques simplifiée 🚀
|