viewlogic 1.2.3 → 1.2.5
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 +372 -450
- package/dist/viewlogic-router.js +107 -123
- package/dist/viewlogic-router.js.map +3 -3
- package/dist/viewlogic-router.min.js +3 -3
- package/dist/viewlogic-router.min.js.map +3 -3
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -12,64 +12,36 @@
|
|
|
12
12
|
</a>
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
|
-
> **Complete Vue 3 Framework**:
|
|
15
|
+
> **Complete Vue 3 Framework**: All-in-one solution for modern web development
|
|
16
16
|
|
|
17
|
-
## 🎯 Core Philosophy
|
|
17
|
+
## 🎯 Core Philosophy
|
|
18
18
|
|
|
19
|
-
ViewLogic Router revolutionizes Vue development with two fundamental
|
|
19
|
+
ViewLogic Router revolutionizes Vue development with two fundamental principles:
|
|
20
20
|
|
|
21
21
|
### 🎭 View-Logic Separation
|
|
22
|
-
**Complete separation between View (presentation) and Logic (business logic)**. Views are pure HTML templates, logic is pure JavaScript components
|
|
22
|
+
**Complete separation between View (presentation) and Logic (business logic)**. Views are pure HTML templates, logic is pure JavaScript components. This separation makes your code more maintainable, testable, and scalable.
|
|
23
23
|
|
|
24
24
|
### 🚀 Zero Build Development
|
|
25
25
|
**Zero build step required in development mode**. Work directly with source files, see changes instantly without any compilation, bundling, or build processes. True real-time development experience.
|
|
26
26
|
|
|
27
|
-
##
|
|
27
|
+
## ✨ What Makes ViewLogic Special
|
|
28
28
|
|
|
29
|
-
**All-in-One Solution** - Replace
|
|
30
|
-
- 🔀 **
|
|
31
|
-
- 📦 **
|
|
32
|
-
- 🔐 **
|
|
33
|
-
- 🌐 **
|
|
34
|
-
- 💾 **
|
|
35
|
-
- 🌐 **API
|
|
36
|
-
- 📝 **Form
|
|
29
|
+
**All-in-One Solution** - Replace multiple libraries with one unified framework:
|
|
30
|
+
- 🔀 **Routing** - File-based routing with zero configuration
|
|
31
|
+
- 📦 **State Management** - Built-in reactive state without external dependencies
|
|
32
|
+
- 🔐 **Authentication** - JWT auth with multiple storage options
|
|
33
|
+
- 🌐 **Internationalization** - Multi-language support with lazy loading
|
|
34
|
+
- 💾 **Caching** - Smart caching with TTL and LRU eviction
|
|
35
|
+
- 🌐 **API Client** - HTTP client with automatic token injection
|
|
36
|
+
- 📝 **Form Handling** - Revolutionary form processing with parameter substitution
|
|
37
37
|
|
|
38
|
-
**Tiny Bundle Size** - Complete framework in just 51KB minified / 17KB gzipped
|
|
38
|
+
**Tiny Bundle Size** - Complete framework in just **51KB minified / 17KB gzipped**!
|
|
39
39
|
|
|
40
40
|
**Easy Integration** - Drop-in UMD build available for instant usage without build tools.
|
|
41
41
|
|
|
42
|
-
## ✨ Key Features
|
|
43
|
-
|
|
44
|
-
- 🚀 **Ultra-Lightweight** - Complete routing system with zero dependencies and optimized codebase
|
|
45
|
-
- 🔄 **Multiple API Support** - Parallel data fetching from multiple APIs with named data storage
|
|
46
|
-
- 📝 **Automatic Form Handling** - Revolutionary form submission with `{paramName}` variable parameters
|
|
47
|
-
- 🛠️ **Built-in Components** - Preloaded UI components including revolutionary DynamicInclude & HtmlInclude
|
|
48
|
-
- 🔗 **Query-Based Parameter System** - Simple query-only parameters (`/users?id=123`) instead of complex path parameters
|
|
49
|
-
- ⚡ **Optimized Production** - Pre-built individual route bundles for lightning-fast production
|
|
50
|
-
- 📁 **Intuitive Structure** - Organized folder structure for views, logic, styles, layouts, and components
|
|
51
|
-
- 💾 **Smart Caching** - Intelligent route and component caching with TTL and LRU eviction
|
|
52
|
-
- 🔐 **Authentication** - Built-in JWT auth management with multiple storage options
|
|
53
|
-
- 🌐 **i18n Ready** - Built-in internationalization support with lazy loading
|
|
54
|
-
- 📊 **State Management** - Reactive state management without external dependencies
|
|
55
|
-
|
|
56
|
-
### What's Included
|
|
57
|
-
- ✅ Complete routing system with hash/history mode
|
|
58
|
-
- ✅ Advanced caching with TTL and size limits
|
|
59
|
-
- ✅ Built-in authentication with multiple storage options
|
|
60
|
-
- ✅ Internationalization system with lazy loading
|
|
61
|
-
- ✅ Form handling with automatic validation
|
|
62
|
-
- ✅ RESTful API client with parameter substitution
|
|
63
|
-
- ✅ Component loading and management
|
|
64
|
-
- ✅ Error handling and logging system
|
|
65
|
-
- ✅ Query parameter management
|
|
66
|
-
- ✅ Layout system with slot-based composition
|
|
67
|
-
- ✅ Global state management with reactivity
|
|
68
|
-
- ✅ Event system for component communication
|
|
69
|
-
|
|
70
42
|
## 🏗️ Project Structure
|
|
71
43
|
|
|
72
|
-
ViewLogic Router follows a clean, intuitive folder structure
|
|
44
|
+
ViewLogic Router follows a clean, intuitive folder structure:
|
|
73
45
|
|
|
74
46
|
```
|
|
75
47
|
project/
|
|
@@ -88,58 +60,81 @@ project/
|
|
|
88
60
|
│ ├── layouts/ # Layout templates
|
|
89
61
|
│ │ ├── default.html
|
|
90
62
|
│ │ └── admin.html
|
|
91
|
-
│
|
|
92
|
-
│
|
|
93
|
-
│
|
|
94
|
-
|
|
95
|
-
│
|
|
96
|
-
|
|
63
|
+
│ └── styles/ # Page-specific CSS files
|
|
64
|
+
│ ├── home.css
|
|
65
|
+
│ └── user-profile.css
|
|
66
|
+
├── css/ # Global CSS files
|
|
67
|
+
│ └── base.css # Base styles
|
|
68
|
+
├── js/ # JavaScript library files
|
|
69
|
+
│ ├── viewlogic-router.js # Development version
|
|
70
|
+
│ ├── viewlogic-router.min.js # Minified version
|
|
71
|
+
│ └── viewlogic-router.umd.js # UMD bundle
|
|
72
|
+
├── i18n/ # Internationalization files
|
|
73
|
+
│ ├── en.json # English translations
|
|
74
|
+
│ ├── ko.json # Korean translations
|
|
75
|
+
│ └── ja.json # Japanese translations
|
|
76
|
+
├── routes/ # Auto-generated after building
|
|
77
|
+
│ ├── home.js # Built route bundles
|
|
78
|
+
│ ├── user-profile.js
|
|
79
|
+
│ └── dashboard.js
|
|
97
80
|
├── index.html # Main entry point
|
|
98
|
-
|
|
99
|
-
└── config.json # Optional configuration
|
|
81
|
+
└── package.json
|
|
100
82
|
```
|
|
101
83
|
|
|
102
84
|
## 🚀 Quick Start
|
|
103
85
|
|
|
104
|
-
### Method 1:
|
|
86
|
+
### Method 1: Create New Project (Recommended)
|
|
105
87
|
|
|
106
88
|
```bash
|
|
107
|
-
npm
|
|
89
|
+
npm create viewlogic myapp
|
|
90
|
+
cd myapp
|
|
91
|
+
npm run dev
|
|
108
92
|
```
|
|
109
93
|
|
|
94
|
+
This creates a complete project with examples and starts the development server.
|
|
95
|
+
|
|
96
|
+
### Method 2: UMD Build (No Build Tools)
|
|
97
|
+
|
|
110
98
|
```html
|
|
111
99
|
<!DOCTYPE html>
|
|
112
100
|
<html>
|
|
113
101
|
<head>
|
|
114
102
|
<title>My ViewLogic App</title>
|
|
103
|
+
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
|
|
104
|
+
<script src="https://cdn.jsdelivr.net/npm/viewlogic/dist/viewlogic-router.umd.js"></script>
|
|
115
105
|
</head>
|
|
116
106
|
<body>
|
|
117
107
|
<div id="app"></div>
|
|
118
|
-
<script
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
authEnabled: true,
|
|
122
|
-
useI18n: true
|
|
108
|
+
<script>
|
|
109
|
+
ViewLogicRouter({
|
|
110
|
+
environment: 'development'
|
|
123
111
|
});
|
|
124
112
|
</script>
|
|
125
113
|
</body>
|
|
126
114
|
</html>
|
|
127
115
|
```
|
|
128
116
|
|
|
129
|
-
### Method
|
|
117
|
+
### Method 3: ES6 Modules
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npm install viewlogic
|
|
121
|
+
```
|
|
130
122
|
|
|
131
123
|
```html
|
|
132
124
|
<!DOCTYPE html>
|
|
133
125
|
<html>
|
|
134
126
|
<head>
|
|
135
127
|
<title>My ViewLogic App</title>
|
|
136
|
-
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
|
|
137
|
-
<script src="https://cdn.jsdelivr.net/npm/viewlogic/dist/viewlogic-router.umd.js"></script>
|
|
138
128
|
</head>
|
|
139
129
|
<body>
|
|
140
130
|
<div id="app"></div>
|
|
141
|
-
<script>
|
|
142
|
-
|
|
131
|
+
<script type="module">
|
|
132
|
+
import { ViewLogicRouter } from 'viewlogic';
|
|
133
|
+
const router = new ViewLogicRouter({
|
|
134
|
+
environment: 'production',
|
|
135
|
+
authEnabled: true,
|
|
136
|
+
useI18n: true
|
|
137
|
+
});
|
|
143
138
|
</script>
|
|
144
139
|
</body>
|
|
145
140
|
</html>
|
|
@@ -151,83 +146,194 @@ npm install viewlogic
|
|
|
151
146
|
```html
|
|
152
147
|
<div class="home">
|
|
153
148
|
<h1>{{ message }}</h1>
|
|
154
|
-
<
|
|
155
|
-
<button @click="increment">Local +1</button>
|
|
156
|
-
<button @click="incrementGlobal">Global +1</button>
|
|
157
|
-
<button @click="saveUser" :disabled="loading">
|
|
158
|
-
{{ loading ? 'Saving...' : 'Save User' }}
|
|
159
|
-
</button>
|
|
160
|
-
<div v-if="user">
|
|
161
|
-
<h3>{{ $t('welcome.message', { name: user.name }) }}</h3>
|
|
162
|
-
</div>
|
|
149
|
+
<button @click="increment">Click me: {{ count }}</button>
|
|
163
150
|
</div>
|
|
164
151
|
```
|
|
165
152
|
|
|
166
153
|
**src/logic/home.js**
|
|
167
154
|
```javascript
|
|
168
155
|
export default {
|
|
156
|
+
// Optional: specify layout (defaults to 'default')
|
|
157
|
+
layout: 'default', // Use layouts/default.html
|
|
158
|
+
// layout: 'admin', // Use layouts/admin.html
|
|
159
|
+
// layout: null, // No layout (page-only content)
|
|
160
|
+
|
|
169
161
|
data() {
|
|
170
162
|
return {
|
|
171
163
|
message: 'Welcome to ViewLogic!',
|
|
172
|
-
count: 0
|
|
173
|
-
loading: false
|
|
164
|
+
count: 0
|
|
174
165
|
};
|
|
175
166
|
},
|
|
167
|
+
methods: {
|
|
168
|
+
increment() {
|
|
169
|
+
this.count++;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**src/styles/home.css** (optional)
|
|
176
|
+
```css
|
|
177
|
+
.home {
|
|
178
|
+
padding: 2rem;
|
|
179
|
+
text-align: center;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.home h1 {
|
|
183
|
+
color: #2c3e50;
|
|
184
|
+
margin-bottom: 1rem;
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**src/layouts/default.html** (optional)
|
|
189
|
+
```html
|
|
190
|
+
<header class="navbar">
|
|
191
|
+
<h1>My App</h1>
|
|
192
|
+
<nav>
|
|
193
|
+
<a href="#/home">Home</a>
|
|
194
|
+
<a href="#/about">About</a>
|
|
195
|
+
</nav>
|
|
196
|
+
</header>
|
|
197
|
+
|
|
198
|
+
<main class="main-content">
|
|
199
|
+
<div class="container">
|
|
200
|
+
{{ content }}
|
|
201
|
+
</div>
|
|
202
|
+
</main>
|
|
203
|
+
|
|
204
|
+
<footer>
|
|
205
|
+
<p>© 2024 My ViewLogic App</p>
|
|
206
|
+
</footer>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Query Parameter Example
|
|
210
|
+
|
|
211
|
+
**src/views/user-profile.html**
|
|
212
|
+
```html
|
|
213
|
+
<div class="user-profile">
|
|
214
|
+
<h1>User Profile</h1>
|
|
215
|
+
<p>User ID: {{ userId }}</p>
|
|
216
|
+
<p>Tab: {{ activeTab }}</p>
|
|
217
|
+
<button @click="switchTab('settings')">Settings</button>
|
|
218
|
+
<button @click="switchTab('posts')">Posts</button>
|
|
219
|
+
</div>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**src/logic/user-profile.js**
|
|
223
|
+
```javascript
|
|
224
|
+
export default {
|
|
176
225
|
computed: {
|
|
177
|
-
|
|
178
|
-
return this
|
|
226
|
+
userId() {
|
|
227
|
+
return this.getParam('userId', 'No ID');
|
|
179
228
|
},
|
|
180
|
-
|
|
181
|
-
return this
|
|
229
|
+
activeTab() {
|
|
230
|
+
return this.getParam('tab', 'profile');
|
|
182
231
|
}
|
|
183
232
|
},
|
|
184
233
|
methods: {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const userData = {
|
|
196
|
-
name: 'John Doe',
|
|
197
|
-
email: 'john@example.com'
|
|
198
|
-
};
|
|
234
|
+
switchTab(tab) {
|
|
235
|
+
// Navigate with query parameters
|
|
236
|
+
this.navigateTo('user-profile', {
|
|
237
|
+
userId: this.userId,
|
|
238
|
+
tab: tab
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
```
|
|
199
244
|
|
|
200
|
-
|
|
201
|
-
this.$state.set('currentUser', savedUser);
|
|
245
|
+
**Usage:** Navigate to `/user-profile?userId=123&tab=settings` or `#/user-profile?userId=123&tab=settings` (hash mode)
|
|
202
246
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
247
|
+
**Multiple ways to access parameters:**
|
|
248
|
+
```javascript
|
|
249
|
+
// Direct parameter access
|
|
250
|
+
const userId = this.$params.userId; // Route parameter (direct access)
|
|
251
|
+
const tab = this.$query.tab; // Query parameter (direct access)
|
|
252
|
+
const search = this.getParam('search'); // Either route or query param
|
|
253
|
+
const allParams = this.getParams(); // Get all parameters
|
|
254
|
+
|
|
255
|
+
// With default values
|
|
256
|
+
const page = this.getParam('page', 1); // Default to 1 if not found
|
|
257
|
+
const sort = this.$query.sort || 'asc'; // Manual default for query params
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Reusable Components
|
|
261
|
+
|
|
262
|
+
ViewLogic automatically loads components from the `components/` folder:
|
|
263
|
+
|
|
264
|
+
**src/components/UserCard.js**
|
|
265
|
+
```javascript
|
|
266
|
+
export default {
|
|
267
|
+
name: 'UserCard',
|
|
268
|
+
template: `
|
|
269
|
+
<div class="user-card">
|
|
270
|
+
<img :src="user.avatar" :alt="user.name" class="avatar">
|
|
271
|
+
<div class="info">
|
|
272
|
+
<h3>{{ user.name }}</h3>
|
|
273
|
+
<p>{{ user.email }}</p>
|
|
274
|
+
<button @click="$emit('edit', user)" class="btn-edit">
|
|
275
|
+
Edit User
|
|
276
|
+
</button>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
`,
|
|
280
|
+
emits: ['edit'],
|
|
281
|
+
props: {
|
|
282
|
+
user: {
|
|
283
|
+
type: Object,
|
|
284
|
+
required: true
|
|
209
285
|
}
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Using components in views:**
|
|
291
|
+
|
|
292
|
+
**src/views/users.html**
|
|
293
|
+
```html
|
|
294
|
+
<div class="users-page">
|
|
295
|
+
<h1>Users</h1>
|
|
296
|
+
<UserCard
|
|
297
|
+
v-for="user in users"
|
|
298
|
+
:key="user.id"
|
|
299
|
+
:user="user"
|
|
300
|
+
@edit="editUser"
|
|
301
|
+
/>
|
|
302
|
+
</div>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**src/logic/users.js**
|
|
306
|
+
```javascript
|
|
307
|
+
export default {
|
|
308
|
+
data() {
|
|
309
|
+
return {
|
|
310
|
+
users: []
|
|
311
|
+
};
|
|
210
312
|
},
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
});
|
|
313
|
+
methods: {
|
|
314
|
+
editUser(user) {
|
|
315
|
+
this.navigateTo('user-edit', { userId: user.id });
|
|
316
|
+
}
|
|
216
317
|
}
|
|
217
318
|
};
|
|
218
319
|
```
|
|
219
320
|
|
|
321
|
+
**Dynamic Component Loading:**
|
|
322
|
+
- Just add `.js` files to `src/components/` folder
|
|
323
|
+
- Components are automatically discovered and loaded
|
|
324
|
+
- No import statements needed - ViewLogic handles everything
|
|
325
|
+
- Components are available instantly in all views
|
|
326
|
+
|
|
220
327
|
## 🎯 Core APIs
|
|
221
328
|
|
|
222
329
|
### State Management
|
|
223
330
|
|
|
224
|
-
|
|
331
|
+
Built-in reactive state management system:
|
|
225
332
|
|
|
226
333
|
```javascript
|
|
227
334
|
// Set state (any component can access)
|
|
228
335
|
this.$state.set('user', { name: 'John', age: 30 });
|
|
229
336
|
this.$state.set('theme', 'dark');
|
|
230
|
-
this.$state.set('shoppingCart', []);
|
|
231
337
|
|
|
232
338
|
// Get state with optional default
|
|
233
339
|
const user = this.$state.get('user');
|
|
@@ -241,12 +347,10 @@ if (this.$state.has('user')) {
|
|
|
241
347
|
// Watch for changes (reactive)
|
|
242
348
|
this.$state.watch('user', (newValue, oldValue) => {
|
|
243
349
|
console.log('User changed:', newValue);
|
|
244
|
-
|
|
350
|
+
// Update component data to trigger reactivity
|
|
351
|
+
this.currentUser = newValue;
|
|
245
352
|
});
|
|
246
353
|
|
|
247
|
-
// Stop watching
|
|
248
|
-
this.$state.unwatch('user', callbackFunction);
|
|
249
|
-
|
|
250
354
|
// Bulk updates
|
|
251
355
|
this.$state.update({
|
|
252
356
|
theme: 'dark',
|
|
@@ -263,42 +367,32 @@ this.$state.delete('temporaryData');
|
|
|
263
367
|
|
|
264
368
|
### Authentication System
|
|
265
369
|
|
|
266
|
-
Complete authentication management
|
|
370
|
+
Complete authentication management:
|
|
267
371
|
|
|
268
372
|
```javascript
|
|
269
373
|
// Check authentication status
|
|
270
|
-
if (this
|
|
374
|
+
if (this.isAuth()) {
|
|
271
375
|
console.log('User is logged in');
|
|
272
376
|
}
|
|
273
377
|
|
|
274
378
|
// Login with token
|
|
275
|
-
this
|
|
379
|
+
this.setToken('jwt-token-here');
|
|
276
380
|
|
|
277
381
|
// Login with options
|
|
278
|
-
this
|
|
279
|
-
storage: 'localStorage'
|
|
280
|
-
skipValidation: false // Skip JWT validation
|
|
382
|
+
this.setToken('jwt-token', {
|
|
383
|
+
storage: 'localStorage' // 'localStorage', 'sessionStorage', 'cookie'
|
|
281
384
|
});
|
|
282
385
|
|
|
283
386
|
// Get current token
|
|
284
|
-
const token = this
|
|
285
|
-
|
|
286
|
-
// Login success handling (redirects to protected route or default)
|
|
287
|
-
this.$loginSuccess('/dashboard');
|
|
387
|
+
const token = this.getToken();
|
|
288
388
|
|
|
289
389
|
// Logout (clears token and redirects to login)
|
|
290
|
-
this
|
|
291
|
-
|
|
292
|
-
// Manual auth check for specific route
|
|
293
|
-
const authResult = await this.$checkAuth('admin-panel');
|
|
294
|
-
if (authResult.allowed) {
|
|
295
|
-
// User can access admin panel
|
|
296
|
-
}
|
|
390
|
+
this.logout();
|
|
297
391
|
```
|
|
298
392
|
|
|
299
393
|
### API Management
|
|
300
394
|
|
|
301
|
-
Built-in HTTP client with automatic token injection
|
|
395
|
+
Built-in HTTP client with automatic token injection:
|
|
302
396
|
|
|
303
397
|
```javascript
|
|
304
398
|
// GET request
|
|
@@ -324,11 +418,6 @@ await this.$api.delete('/api/users/{userId}');
|
|
|
324
418
|
// If current route is /users?userId=123, this becomes /api/users/123
|
|
325
419
|
const user = await this.$api.get('/api/users/{userId}');
|
|
326
420
|
|
|
327
|
-
// Custom headers
|
|
328
|
-
const response = await this.$api.post('/api/secure-endpoint', data, {
|
|
329
|
-
headers: { 'X-Custom-Header': 'value' }
|
|
330
|
-
});
|
|
331
|
-
|
|
332
421
|
// Automatic data loading in components
|
|
333
422
|
export default {
|
|
334
423
|
// Single API endpoint
|
|
@@ -344,13 +433,48 @@ export default {
|
|
|
344
433
|
mounted() {
|
|
345
434
|
// Data automatically loaded and available as:
|
|
346
435
|
// this.profile, this.posts, this.notifications
|
|
436
|
+
},
|
|
437
|
+
|
|
438
|
+
methods: {
|
|
439
|
+
// Manual data refresh - reuses dataURL configuration
|
|
440
|
+
async refreshData() {
|
|
441
|
+
await this.fetchData();
|
|
442
|
+
// All dataURL endpoints are called again
|
|
443
|
+
},
|
|
444
|
+
|
|
445
|
+
// Refresh when filters change
|
|
446
|
+
async applyFilter(filterType) {
|
|
447
|
+
this.$query.filter = filterType;
|
|
448
|
+
await this.fetchData(); // Refetch with new filter parameter
|
|
449
|
+
},
|
|
450
|
+
|
|
451
|
+
// Refresh when user changes
|
|
452
|
+
async switchUser(newUserId) {
|
|
453
|
+
this.$params.userId = newUserId;
|
|
454
|
+
await this.fetchData(); // Refetch with new userId parameter
|
|
455
|
+
},
|
|
456
|
+
|
|
457
|
+
// Pagination
|
|
458
|
+
async changePage(page) {
|
|
459
|
+
this.$query.page = page;
|
|
460
|
+
await this.fetchData(); // Load new page data
|
|
461
|
+
},
|
|
462
|
+
|
|
463
|
+
// Custom data loading
|
|
464
|
+
async loadSpecificData() {
|
|
465
|
+
const customData = await this.fetchData({
|
|
466
|
+
profile: '/api/admin/profile',
|
|
467
|
+
stats: '/api/stats?period={period}'
|
|
468
|
+
});
|
|
469
|
+
// Override default dataURL temporarily
|
|
470
|
+
}
|
|
347
471
|
}
|
|
348
472
|
};
|
|
349
473
|
```
|
|
350
474
|
|
|
351
475
|
### Internationalization
|
|
352
476
|
|
|
353
|
-
Comprehensive i18n system
|
|
477
|
+
Comprehensive i18n system:
|
|
354
478
|
|
|
355
479
|
```javascript
|
|
356
480
|
// Simple translation
|
|
@@ -362,30 +486,57 @@ const greeting = this.$t('hello.user', { name: 'John', role: 'admin' });
|
|
|
362
486
|
// Nested keys
|
|
363
487
|
const errorMsg = this.$t('errors.validation.email.required');
|
|
364
488
|
|
|
365
|
-
// Plural forms
|
|
366
|
-
const itemCount = this.$plural('items.count', count, { count });
|
|
367
|
-
// items.count.singular: "{count} item"
|
|
368
|
-
// items.count.plural: "{count} items"
|
|
369
|
-
|
|
370
489
|
// Check current language
|
|
371
|
-
const currentLang = this
|
|
490
|
+
const currentLang = this.getLanguage();
|
|
372
491
|
|
|
373
492
|
// Change language (automatically reloads interface)
|
|
374
|
-
await this
|
|
493
|
+
await this.setLanguage('ko');
|
|
494
|
+
```
|
|
375
495
|
|
|
376
|
-
|
|
377
|
-
const date = this.$i18n.formatDate(new Date(), {
|
|
378
|
-
year: 'numeric',
|
|
379
|
-
month: 'long',
|
|
380
|
-
day: 'numeric'
|
|
381
|
-
});
|
|
496
|
+
### Logging & Error Handling
|
|
382
497
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
498
|
+
Built-in logging system for debugging and error tracking:
|
|
499
|
+
|
|
500
|
+
```javascript
|
|
501
|
+
export default {
|
|
502
|
+
async mounted() {
|
|
503
|
+
this.log('info', 'Component mounted successfully');
|
|
504
|
+
},
|
|
505
|
+
|
|
506
|
+
methods: {
|
|
507
|
+
async handleUserAction() {
|
|
508
|
+
this.log('debug', 'User action started', { action: 'submit' });
|
|
509
|
+
|
|
510
|
+
try {
|
|
511
|
+
const result = await this.$api.post('/api/users', userData);
|
|
512
|
+
this.log('info', 'User created successfully', result);
|
|
513
|
+
} catch (error) {
|
|
514
|
+
this.log('error', 'Failed to create user:', error);
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
|
|
518
|
+
async loadData() {
|
|
519
|
+
this.log('debug', 'Loading user data...');
|
|
520
|
+
|
|
521
|
+
try {
|
|
522
|
+
const data = await this.fetchData();
|
|
523
|
+
this.log('info', 'Data loaded', { count: data.length });
|
|
524
|
+
} catch (error) {
|
|
525
|
+
this.log('warn', 'Data loading failed, using cache', error);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
};
|
|
387
530
|
```
|
|
388
531
|
|
|
532
|
+
**Log Levels:**
|
|
533
|
+
- `debug` - Development debugging information
|
|
534
|
+
- `info` - General information and success messages
|
|
535
|
+
- `warn` - Warning messages for recoverable issues
|
|
536
|
+
- `error` - Error messages for failures
|
|
537
|
+
|
|
538
|
+
All logs include the component name automatically: `[routeName] Your message`
|
|
539
|
+
|
|
389
540
|
### Navigation & Routing
|
|
390
541
|
|
|
391
542
|
Simple yet powerful routing system:
|
|
@@ -403,76 +554,93 @@ this.navigateTo({
|
|
|
403
554
|
params: { query: 'vue', category: 'tutorials' }
|
|
404
555
|
});
|
|
405
556
|
|
|
406
|
-
// Get current route information
|
|
407
|
-
const currentRoute = this.$route.current;
|
|
408
|
-
const routeParams = this.$route.params;
|
|
409
|
-
const queryParams = this.$route.query;
|
|
410
|
-
|
|
411
|
-
// Access specific parameters
|
|
412
|
-
const userId = this.$params.userId; // Route parameter
|
|
413
|
-
const tab = this.$query.tab; // Query parameter
|
|
414
|
-
const searchTerm = this.$param('search'); // Either route or query param
|
|
415
|
-
|
|
416
|
-
// Check if route is protected
|
|
417
|
-
const isProtected = this.$route.isProtected('admin-dashboard');
|
|
418
|
-
|
|
419
|
-
// Navigate with state preservation
|
|
420
|
-
this.navigateTo('dashboard', {
|
|
421
|
-
preserveState: true,
|
|
422
|
-
scrollTop: false
|
|
423
|
-
});
|
|
424
557
|
```
|
|
425
558
|
|
|
559
|
+
|
|
426
560
|
### Form Handling
|
|
427
561
|
|
|
428
|
-
Revolutionary form processing with
|
|
562
|
+
Revolutionary automatic form processing with parameter substitution:
|
|
429
563
|
|
|
430
564
|
```html
|
|
431
|
-
<!-- Basic form
|
|
432
|
-
<form action="/api/users" method="POST"
|
|
565
|
+
<!-- Basic form - automatically handled on submit -->
|
|
566
|
+
<form action="/api/users" method="POST"
|
|
567
|
+
data-success="onUserCreated"
|
|
568
|
+
data-error="onUserError"
|
|
569
|
+
data-loading="setLoading">
|
|
433
570
|
<input name="name" v-model="userData.name" required>
|
|
434
571
|
<input name="email" v-model="userData.email" type="email" required>
|
|
435
572
|
<button type="submit">Create User</button>
|
|
436
573
|
</form>
|
|
437
574
|
|
|
438
575
|
<!-- Form with parameter substitution -->
|
|
439
|
-
<form action="/api/users/{userId}" method="PUT"
|
|
576
|
+
<form action="/api/users/{userId}" method="PUT"
|
|
577
|
+
data-success="onUserUpdated"
|
|
578
|
+
data-redirect="user-profile">
|
|
440
579
|
<input name="name" v-model="user.name">
|
|
441
580
|
<input name="email" v-model="user.email">
|
|
442
581
|
<button type="submit">Update User</button>
|
|
443
582
|
</form>
|
|
444
583
|
|
|
445
584
|
<!-- File upload form -->
|
|
446
|
-
<form action="/api/upload" method="POST" enctype="multipart/form-data"
|
|
585
|
+
<form action="/api/upload" method="POST" enctype="multipart/form-data"
|
|
586
|
+
data-success="onFileUploaded">
|
|
447
587
|
<input name="avatar" type="file" accept="image/*">
|
|
448
588
|
<input name="description" v-model="description">
|
|
449
589
|
<button type="submit">Upload</button>
|
|
450
590
|
</form>
|
|
591
|
+
|
|
592
|
+
<!-- Form with custom validation -->
|
|
593
|
+
<form action="/api/contact" method="POST">
|
|
594
|
+
<input name="email" type="email" data-validation="validateEmail" required>
|
|
595
|
+
<textarea name="message" data-validation="validateMessage" required></textarea>
|
|
596
|
+
<button type="submit">Send Message</button>
|
|
597
|
+
</form>
|
|
451
598
|
```
|
|
452
599
|
|
|
453
600
|
```javascript
|
|
454
|
-
//
|
|
601
|
+
// Component logic with form handlers
|
|
455
602
|
export default {
|
|
603
|
+
data() {
|
|
604
|
+
return {
|
|
605
|
+
userData: { name: '', email: '' },
|
|
606
|
+
user: { name: 'John', email: 'john@example.com' },
|
|
607
|
+
loading: false
|
|
608
|
+
};
|
|
609
|
+
},
|
|
456
610
|
methods: {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
611
|
+
// Success handlers
|
|
612
|
+
onUserCreated(response, form) {
|
|
613
|
+
this.$state.set('newUser', response);
|
|
614
|
+
this.navigateTo('user-profile', { userId: response.id });
|
|
615
|
+
},
|
|
462
616
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
617
|
+
onUserUpdated(response, form) {
|
|
618
|
+
this.$state.set('currentUser', response);
|
|
619
|
+
// Auto redirect via data-redirect="user-profile"
|
|
620
|
+
},
|
|
621
|
+
|
|
622
|
+
onFileUploaded(response, form) {
|
|
623
|
+
this.$state.set('uploadedFile', response.file);
|
|
624
|
+
},
|
|
625
|
+
|
|
626
|
+
// Error handler
|
|
627
|
+
onUserError(error, form) {
|
|
628
|
+
console.error('User operation failed:', error);
|
|
629
|
+
},
|
|
630
|
+
|
|
631
|
+
// Loading handler
|
|
632
|
+
setLoading(isLoading, form) {
|
|
633
|
+
this.loading = isLoading;
|
|
634
|
+
},
|
|
635
|
+
|
|
636
|
+
// Custom validation functions
|
|
637
|
+
validateEmail(value, input) {
|
|
638
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
639
|
+
return emailRegex.test(value);
|
|
640
|
+
},
|
|
641
|
+
|
|
642
|
+
validateMessage(value, input) {
|
|
643
|
+
return value.length >= 10;
|
|
476
644
|
}
|
|
477
645
|
}
|
|
478
646
|
};
|
|
@@ -488,9 +656,6 @@ const router = new ViewLogicRouter({
|
|
|
488
656
|
basePath: '/', // Base path for the application
|
|
489
657
|
mode: 'hash', // 'hash' or 'history'
|
|
490
658
|
|
|
491
|
-
// State management (always enabled)
|
|
492
|
-
// No configuration needed - StateHandler is always available
|
|
493
|
-
|
|
494
659
|
// Authentication settings
|
|
495
660
|
authEnabled: true, // Enable authentication system
|
|
496
661
|
loginRoute: 'login', // Route name for login page
|
|
@@ -502,16 +667,17 @@ const router = new ViewLogicRouter({
|
|
|
502
667
|
// Internationalization
|
|
503
668
|
useI18n: true, // Enable i18n system
|
|
504
669
|
defaultLanguage: 'en', // Default language
|
|
505
|
-
i18nPath: '/
|
|
670
|
+
i18nPath: '/i18n', // Path to language files
|
|
506
671
|
|
|
507
672
|
// Caching system
|
|
508
|
-
cacheMode: 'memory', //
|
|
673
|
+
cacheMode: 'memory', // Memory caching only
|
|
509
674
|
cacheTTL: 300000, // Cache TTL in milliseconds (5 minutes)
|
|
510
675
|
maxCacheSize: 100, // Maximum number of cached items
|
|
511
676
|
|
|
512
677
|
// API settings
|
|
513
|
-
apiBaseURL: '/
|
|
514
|
-
|
|
678
|
+
apiBaseURL: 'https://api.example.com/v1', // Base URL for API requests
|
|
679
|
+
requestTimeout: 30000, // Form submission timeout in milliseconds (30 seconds)
|
|
680
|
+
uploadTimeout: 300000, // File upload timeout in milliseconds (5 minutes)
|
|
515
681
|
|
|
516
682
|
// Development settings
|
|
517
683
|
environment: 'development', // 'development' or 'production'
|
|
@@ -525,163 +691,18 @@ const router = new ViewLogicRouter({
|
|
|
525
691
|
const router = new ViewLogicRouter({
|
|
526
692
|
// Custom authentication function
|
|
527
693
|
authEnabled: true,
|
|
528
|
-
checkAuthFunction: async (
|
|
529
|
-
const token = localStorage.getItem('authToken');
|
|
530
|
-
if (!token) return false;
|
|
531
|
-
|
|
694
|
+
checkAuthFunction: async (route) => {
|
|
532
695
|
try {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
'Content-Type': 'application/json'
|
|
538
|
-
}
|
|
539
|
-
});
|
|
540
|
-
|
|
541
|
-
if (response.ok) {
|
|
542
|
-
const userData = await response.json();
|
|
543
|
-
// Store user data in global state
|
|
544
|
-
router.stateHandler.set('currentUser', userData);
|
|
545
|
-
return true;
|
|
546
|
-
}
|
|
547
|
-
return false;
|
|
696
|
+
// Use ViewLogic APIs like in components
|
|
697
|
+
const userData = await route.$api.get('/api/auth/verify');
|
|
698
|
+
route.$state.set('currentUser', userData);
|
|
699
|
+
return true;
|
|
548
700
|
} catch (error) {
|
|
549
701
|
console.error('Auth verification failed:', error);
|
|
550
702
|
return false;
|
|
551
703
|
}
|
|
552
|
-
},
|
|
553
|
-
|
|
554
|
-
// Custom route loading
|
|
555
|
-
routeResolver: (routeName) => {
|
|
556
|
-
// Custom logic for resolving route files
|
|
557
|
-
if (routeName.startsWith('admin/')) {
|
|
558
|
-
return {
|
|
559
|
-
viewPath: `/admin/views/${routeName.slice(6)}.html`,
|
|
560
|
-
logicPath: `/admin/logic/${routeName.slice(6)}.js`
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
return null; // Use default resolution
|
|
564
|
-
},
|
|
565
|
-
|
|
566
|
-
// Global error handler
|
|
567
|
-
onError: (error, context) => {
|
|
568
|
-
console.error('ViewLogic Error:', error, context);
|
|
569
|
-
// Send to error tracking service
|
|
570
|
-
if (window.errorTracker) {
|
|
571
|
-
window.errorTracker.log(error, context);
|
|
572
|
-
}
|
|
573
|
-
},
|
|
574
|
-
|
|
575
|
-
// Global route change handler
|
|
576
|
-
onRouteChange: (newRoute, oldRoute) => {
|
|
577
|
-
// Analytics tracking
|
|
578
|
-
if (window.analytics) {
|
|
579
|
-
window.analytics.track('page_view', {
|
|
580
|
-
route: newRoute,
|
|
581
|
-
previous_route: oldRoute
|
|
582
|
-
});
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
});
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
## 📦 Bundle Size Comparison
|
|
589
|
-
|
|
590
|
-
| Solution | Minified | Gzipped |
|
|
591
|
-
|----------|----------|---------|
|
|
592
|
-
| **ViewLogic Router** (Complete) | **51KB** | **17KB** |
|
|
593
|
-
| Vue Router + Pinia + Vue I18n | 150KB+ | 45KB+ |
|
|
594
|
-
| React Router + Redux + i18next | 200KB+ | 60KB+ |
|
|
595
|
-
| Next.js (Runtime) | 300KB+ | 85KB+ |
|
|
596
|
-
|
|
597
|
-
*ViewLogic Router provides the functionality of 7+ libraries in a package smaller than most single-purpose libraries.*
|
|
598
|
-
|
|
599
|
-
## 🎯 Migration Guide
|
|
600
|
-
|
|
601
|
-
### From Vue Router + Pinia
|
|
602
|
-
|
|
603
|
-
**Before:**
|
|
604
|
-
```javascript
|
|
605
|
-
// main.js - Multiple library setup
|
|
606
|
-
import { createApp } from 'vue';
|
|
607
|
-
import { createRouter, createWebHistory } from 'vue-router';
|
|
608
|
-
import { createPinia } from 'pinia';
|
|
609
|
-
import { createI18n } from 'vue-i18n';
|
|
610
|
-
import App from './App.vue';
|
|
611
|
-
|
|
612
|
-
const router = createRouter({
|
|
613
|
-
history: createWebHistory(),
|
|
614
|
-
routes: [/* complex route config */]
|
|
615
|
-
});
|
|
616
|
-
|
|
617
|
-
const pinia = createPinia();
|
|
618
|
-
const i18n = createI18n({/* complex i18n config */});
|
|
619
|
-
|
|
620
|
-
const app = createApp(App);
|
|
621
|
-
app.use(router).use(pinia).use(i18n);
|
|
622
|
-
app.mount('#app');
|
|
623
|
-
```
|
|
624
|
-
|
|
625
|
-
**After:**
|
|
626
|
-
```javascript
|
|
627
|
-
// index.html - Single setup
|
|
628
|
-
import { ViewLogicRouter } from 'viewlogic';
|
|
629
|
-
|
|
630
|
-
const router = new ViewLogicRouter({
|
|
631
|
-
mode: 'history',
|
|
632
|
-
useI18n: true,
|
|
633
|
-
authEnabled: true
|
|
634
|
-
});
|
|
635
|
-
// Everything is auto-configured and ready to use!
|
|
636
|
-
```
|
|
637
|
-
|
|
638
|
-
### State Management Migration
|
|
639
|
-
|
|
640
|
-
**Before (Pinia):**
|
|
641
|
-
```javascript
|
|
642
|
-
// stores/user.js
|
|
643
|
-
import { defineStore } from 'pinia';
|
|
644
|
-
|
|
645
|
-
export const useUserStore = defineStore('user', {
|
|
646
|
-
state: () => ({
|
|
647
|
-
currentUser: null,
|
|
648
|
-
preferences: {}
|
|
649
|
-
}),
|
|
650
|
-
getters: {
|
|
651
|
-
isLoggedIn: (state) => !!state.currentUser,
|
|
652
|
-
userName: (state) => state.currentUser?.name || 'Guest'
|
|
653
|
-
},
|
|
654
|
-
actions: {
|
|
655
|
-
setUser(userData) {
|
|
656
|
-
this.currentUser = userData;
|
|
657
|
-
},
|
|
658
|
-
updatePreferences(prefs) {
|
|
659
|
-
this.preferences = { ...this.preferences, ...prefs };
|
|
660
|
-
}
|
|
661
704
|
}
|
|
662
705
|
});
|
|
663
|
-
|
|
664
|
-
// In components
|
|
665
|
-
import { useUserStore } from '@/stores/user';
|
|
666
|
-
const userStore = useUserStore();
|
|
667
|
-
userStore.setUser(userData);
|
|
668
|
-
```
|
|
669
|
-
|
|
670
|
-
**After (ViewLogic):**
|
|
671
|
-
```javascript
|
|
672
|
-
// In any component - no store files needed!
|
|
673
|
-
this.$state.set('currentUser', userData);
|
|
674
|
-
this.$state.update({ preferences: newPrefs });
|
|
675
|
-
|
|
676
|
-
// Computed properties work naturally
|
|
677
|
-
computed: {
|
|
678
|
-
isLoggedIn() {
|
|
679
|
-
return !!this.$state.get('currentUser');
|
|
680
|
-
},
|
|
681
|
-
userName() {
|
|
682
|
-
return this.$state.get('currentUser')?.name || 'Guest';
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
706
|
```
|
|
686
707
|
|
|
687
708
|
## 🔧 Production Build
|
|
@@ -695,9 +716,6 @@ npm run build
|
|
|
695
716
|
|
|
696
717
|
# Preview production build
|
|
697
718
|
npm run serve
|
|
698
|
-
|
|
699
|
-
# Build with custom config
|
|
700
|
-
npm run build -- --config custom.config.js
|
|
701
719
|
```
|
|
702
720
|
|
|
703
721
|
### Production Optimizations
|
|
@@ -710,102 +728,6 @@ ViewLogic Router automatically optimizes for production:
|
|
|
710
728
|
- **Caching**: Aggressive caching for static assets
|
|
711
729
|
- **Lazy loading**: Routes and components load on demand
|
|
712
730
|
|
|
713
|
-
## 🌟 Advanced Examples
|
|
714
|
-
|
|
715
|
-
### E-commerce Dashboard
|
|
716
|
-
|
|
717
|
-
```javascript
|
|
718
|
-
// logic/dashboard.js
|
|
719
|
-
export default {
|
|
720
|
-
dataURL: {
|
|
721
|
-
overview: '/api/dashboard/overview',
|
|
722
|
-
sales: '/api/sales/recent',
|
|
723
|
-
products: '/api/products/trending'
|
|
724
|
-
},
|
|
725
|
-
|
|
726
|
-
computed: {
|
|
727
|
-
totalRevenue() {
|
|
728
|
-
return this.sales?.reduce((sum, sale) => sum + sale.amount, 0) || 0;
|
|
729
|
-
},
|
|
730
|
-
cartItems() {
|
|
731
|
-
return this.$state.get('shoppingCart', []);
|
|
732
|
-
}
|
|
733
|
-
},
|
|
734
|
-
|
|
735
|
-
methods: {
|
|
736
|
-
async addToCart(product) {
|
|
737
|
-
const cart = this.$state.get('shoppingCart', []);
|
|
738
|
-
const existingItem = cart.find(item => item.id === product.id);
|
|
739
|
-
|
|
740
|
-
if (existingItem) {
|
|
741
|
-
existingItem.quantity += 1;
|
|
742
|
-
} else {
|
|
743
|
-
cart.push({ ...product, quantity: 1 });
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
this.$state.set('shoppingCart', cart);
|
|
747
|
-
|
|
748
|
-
// Sync with backend
|
|
749
|
-
await this.$api.post('/api/cart/sync', { items: cart });
|
|
750
|
-
},
|
|
751
|
-
|
|
752
|
-
async checkout() {
|
|
753
|
-
const items = this.$state.get('shoppingCart', []);
|
|
754
|
-
try {
|
|
755
|
-
const order = await this.$api.post('/api/orders', { items });
|
|
756
|
-
this.$state.set('shoppingCart', []);
|
|
757
|
-
this.$state.set('lastOrder', order);
|
|
758
|
-
this.navigateTo('order-confirmation', { orderId: order.id });
|
|
759
|
-
} catch (error) {
|
|
760
|
-
this.$toast?.error?.('Checkout failed. Please try again.');
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
};
|
|
765
|
-
```
|
|
766
|
-
|
|
767
|
-
### Multi-tenant Application
|
|
768
|
-
|
|
769
|
-
```javascript
|
|
770
|
-
// Handle different tenants with state management
|
|
771
|
-
export default {
|
|
772
|
-
async mounted() {
|
|
773
|
-
const tenantId = this.$params.tenantId || this.$query.tenant;
|
|
774
|
-
|
|
775
|
-
if (tenantId !== this.$state.get('currentTenant')?.id) {
|
|
776
|
-
await this.switchTenant(tenantId);
|
|
777
|
-
}
|
|
778
|
-
},
|
|
779
|
-
|
|
780
|
-
methods: {
|
|
781
|
-
async switchTenant(tenantId) {
|
|
782
|
-
try {
|
|
783
|
-
const tenant = await this.$api.get('/api/tenants/{tenantId}', {
|
|
784
|
-
params: { tenantId }
|
|
785
|
-
});
|
|
786
|
-
|
|
787
|
-
// Update global state
|
|
788
|
-
this.$state.update({
|
|
789
|
-
currentTenant: tenant,
|
|
790
|
-
userPermissions: tenant.permissions,
|
|
791
|
-
theme: tenant.branding.theme
|
|
792
|
-
});
|
|
793
|
-
|
|
794
|
-
// Update language if tenant has preference
|
|
795
|
-
if (tenant.defaultLanguage) {
|
|
796
|
-
await this.$i18n.setLanguage(tenant.defaultLanguage);
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
// Update API base URL for tenant
|
|
800
|
-
this.$api.setBaseURL(`/api/tenants/${tenantId}`);
|
|
801
|
-
|
|
802
|
-
} catch (error) {
|
|
803
|
-
this.navigateTo('tenant-not-found');
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
};
|
|
808
|
-
```
|
|
809
731
|
|
|
810
732
|
## 🤝 Contributing
|
|
811
733
|
|