@owlmeans/web-wl 0.1.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/LICENSE +21 -0
- package/README.md +744 -0
- package/build/components/index.d.ts +2 -0
- package/build/components/index.d.ts.map +1 -0
- package/build/components/index.js +2 -0
- package/build/components/index.js.map +1 -0
- package/build/components/logo.d.ts +4 -0
- package/build/components/logo.d.ts.map +1 -0
- package/build/components/logo.js +17 -0
- package/build/components/logo.js.map +1 -0
- package/build/components/types.d.ts +7 -0
- package/build/components/types.d.ts.map +1 -0
- package/build/components/types.js +2 -0
- package/build/components/types.js.map +1 -0
- package/build/consts.d.ts +2 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +2 -0
- package/build/consts.js.map +1 -0
- package/build/index.d.ts +6 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/build/modules.d.ts +3 -0
- package/build/modules.d.ts.map +1 -0
- package/build/modules.js +5 -0
- package/build/modules.js.map +1 -0
- package/build/service.d.ts +3 -0
- package/build/service.d.ts.map +1 -0
- package/build/service.js +20 -0
- package/build/service.js.map +1 -0
- package/build/types.d.ts +15 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/package.json +40 -0
- package/src/components/index.ts +1 -0
- package/src/components/logo.tsx +23 -0
- package/src/components/types.ts +8 -0
- package/src/consts.ts +2 -0
- package/src/index.ts +7 -0
- package/src/modules.ts +8 -0
- package/src/service.ts +29 -0
- package/src/types.ts +19 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 OwlMeans Common — Fullstack typescript framework
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,744 @@
|
|
|
1
|
+
# @owlmeans/web-wl
|
|
2
|
+
|
|
3
|
+
Web-specific whitelabeling functionality for OwlMeans Common Libraries. This package provides React components and browser-optimized services for implementing client-side whitelabeling, enabling web applications to dynamically customize branding, theming, and content based on entity-specific configurations.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The `@owlmeans/web-wl` package serves as the web-specific implementation of the OwlMeans Whitelabeling Subsystem, designed for React-based frontend applications with focus on dynamic branding and user experience customization. It provides:
|
|
8
|
+
|
|
9
|
+
- **Web Whitelabeling Service**: Browser-optimized service for loading and caching whitelabeling data
|
|
10
|
+
- **React Components**: React components for whitelabel-aware UI elements
|
|
11
|
+
- **Caching Strategy**: Efficient client-side caching of whitelabeling configurations
|
|
12
|
+
- **API Integration**: Seamless integration with server-side whitelabeling providers
|
|
13
|
+
- **Performance Optimization**: Optimized loading and rendering of dynamic branding content
|
|
14
|
+
|
|
15
|
+
This package follows the OwlMeans "quadra" pattern as the **web** implementation, complementing:
|
|
16
|
+
- **@owlmeans/wled**: Common whitelabeling declarations and base functionality *(base package)*
|
|
17
|
+
- **@owlmeans/client-wl**: Base client whitelabeling functionality
|
|
18
|
+
- **@owlmeans/server-wl**: Server-side whitelabeling implementation
|
|
19
|
+
- **@owlmeans/web-wl**: Web browser whitelabeling implementation *(this package)*
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @owlmeans/web-wl
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Dependencies
|
|
28
|
+
|
|
29
|
+
This package requires and integrates with:
|
|
30
|
+
- `@owlmeans/wled`: Core whitelabeling types and modules
|
|
31
|
+
- `@owlmeans/client`: Base client functionality
|
|
32
|
+
- `@owlmeans/client-module`: Client module system for API calls
|
|
33
|
+
- `@owlmeans/context`: Context management and service registration
|
|
34
|
+
- React: Peer dependency for web components
|
|
35
|
+
|
|
36
|
+
## Key Concepts
|
|
37
|
+
|
|
38
|
+
### Web Whitelabeling Service
|
|
39
|
+
Browser-optimized service that:
|
|
40
|
+
- **Loads Whitelabeling Data**: Fetches entity-specific branding from server APIs
|
|
41
|
+
- **Caches Configurations**: Implements client-side caching for performance
|
|
42
|
+
- **Extracts Data**: Provides convenient access to specific whitelabeling data types
|
|
43
|
+
- **Handles Errors**: Graceful error handling for failed whitelabeling requests
|
|
44
|
+
|
|
45
|
+
### React Component Integration
|
|
46
|
+
React components that automatically adapt to whitelabeling configurations:
|
|
47
|
+
- **Dynamic Branding**: Components that change appearance based on entity branding
|
|
48
|
+
- **Conditional Rendering**: Show/hide content based on whitelabeling rules
|
|
49
|
+
- **Theme Integration**: Automatic theme switching based on entity configurations
|
|
50
|
+
- **Performance**: Optimized rendering with minimal re-renders
|
|
51
|
+
|
|
52
|
+
### Client-side Caching
|
|
53
|
+
Efficient caching strategy:
|
|
54
|
+
- **Memory Caching**: In-memory cache for frequently accessed configurations
|
|
55
|
+
- **Cache Invalidation**: Smart cache invalidation strategies
|
|
56
|
+
- **Performance**: Reduced API calls and improved user experience
|
|
57
|
+
|
|
58
|
+
## API Reference
|
|
59
|
+
|
|
60
|
+
### Factory Functions
|
|
61
|
+
|
|
62
|
+
#### `makeWlService(alias?: string): WlWebService`
|
|
63
|
+
|
|
64
|
+
Creates a web whitelabeling service instance with caching capabilities.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { makeWlService } from '@owlmeans/web-wl'
|
|
68
|
+
|
|
69
|
+
const wlService = makeWlService('main-wl')
|
|
70
|
+
context.registerService(wlService)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Parameters:**
|
|
74
|
+
- `alias`: Optional service alias (defaults to `DEFAULT_ALIAS`)
|
|
75
|
+
|
|
76
|
+
**Returns:** `WlWebService` - Web whitelabeling service instance
|
|
77
|
+
|
|
78
|
+
### Core Interfaces
|
|
79
|
+
|
|
80
|
+
#### `WlWebService`
|
|
81
|
+
|
|
82
|
+
Web-specific whitelabeling service interface.
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
interface WlWebService extends InitializedService {
|
|
86
|
+
load: (entityId: string) => Promise<ProvidedWLSet>
|
|
87
|
+
extract: <T>(key: string, set: ProvidedWLSet) => T | undefined
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Methods:**
|
|
92
|
+
|
|
93
|
+
**`load(entityId: string): Promise<ProvidedWLSet>`**
|
|
94
|
+
- **Purpose**: Load complete whitelabeling data set for an entity
|
|
95
|
+
- **Parameters**: `entityId` - Entity identifier
|
|
96
|
+
- **Returns**: Promise resolving to whitelabeling data set
|
|
97
|
+
- **Behavior**:
|
|
98
|
+
- Checks cache first for existing data
|
|
99
|
+
- Makes API call to server if not cached
|
|
100
|
+
- Caches successful responses
|
|
101
|
+
- Returns comprehensive whitelabeling data
|
|
102
|
+
|
|
103
|
+
**`extract<T>(key: string, set: ProvidedWLSet): T | undefined`**
|
|
104
|
+
- **Purpose**: Extract specific whitelabeling data type from a data set
|
|
105
|
+
- **Parameters**:
|
|
106
|
+
- `key` - Provider key (e.g., 'company-provider', 'styles-provider')
|
|
107
|
+
- `set` - Whitelabeling data set
|
|
108
|
+
- **Returns**: Extracted data of type T or undefined if not found
|
|
109
|
+
- **Usage**: Convenient access to specific provider data
|
|
110
|
+
|
|
111
|
+
#### `ProvidedWLSet`
|
|
112
|
+
|
|
113
|
+
Collection of whitelabeling data from multiple providers.
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
interface ProvidedWLSet<T extends Record<string, any> = Record<string, any>> {
|
|
117
|
+
[providerKey: string]: ProvidedWL<T>
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### `Config`
|
|
122
|
+
|
|
123
|
+
Configuration interface for web whitelabeling.
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
interface Config extends ClientConfig {
|
|
127
|
+
// Inherits client configuration
|
|
128
|
+
// Plus whitelabeling-specific web settings
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### `Context<C extends Config = Config>`
|
|
133
|
+
|
|
134
|
+
Web context interface with whitelabeling support.
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
interface Context<C extends Config = Config> extends ClientContext<C> {
|
|
138
|
+
// Inherits client context functionality
|
|
139
|
+
// With typed configuration for whitelabeling
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### React Components
|
|
144
|
+
|
|
145
|
+
#### Whitelabeling Provider Component
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
interface WlProviderProps {
|
|
149
|
+
entityId: string // Entity to load whitelabeling for
|
|
150
|
+
children: React.ReactNode // Child components
|
|
151
|
+
fallback?: React.ReactNode // Fallback content while loading
|
|
152
|
+
onError?: (error: Error) => void // Error handler
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const WlProvider: FC<WlProviderProps> = (props) => { /* ... */ }
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### Whitelabel-aware Components
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
interface WlBrandProps {
|
|
162
|
+
entityId: string
|
|
163
|
+
type: 'square' | 'wide' // Logo type
|
|
164
|
+
alt?: string // Alt text
|
|
165
|
+
fallback?: React.ReactNode // Fallback if no logo
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const WlBrand: FC<WlBrandProps> = (props) => { /* ... */ }
|
|
169
|
+
|
|
170
|
+
interface WlThemeProps {
|
|
171
|
+
entityId: string
|
|
172
|
+
children: React.ReactNode
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const WlTheme: FC<WlThemeProps> = (props) => { /* ... */ }
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Constants
|
|
179
|
+
|
|
180
|
+
#### `DEFAULT_ALIAS`
|
|
181
|
+
|
|
182
|
+
Default service alias for whitelabeling service.
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
const DEFAULT_ALIAS = 'wl-web-service'
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Usage Examples
|
|
189
|
+
|
|
190
|
+
### Basic Web Whitelabeling Setup
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
import { makeWlService } from '@owlmeans/web-wl'
|
|
194
|
+
import { makeWebContext } from '@owlmeans/web-client'
|
|
195
|
+
|
|
196
|
+
// Create web context
|
|
197
|
+
const context = makeWebContext(config)
|
|
198
|
+
|
|
199
|
+
// Create and register whitelabeling service
|
|
200
|
+
const wlService = makeWlService()
|
|
201
|
+
context.registerService(wlService)
|
|
202
|
+
|
|
203
|
+
// Initialize context
|
|
204
|
+
await context.configure().init()
|
|
205
|
+
|
|
206
|
+
// Load whitelabeling data for an entity
|
|
207
|
+
const entityId = 'company-123'
|
|
208
|
+
const whitelabelData = await wlService.load(entityId)
|
|
209
|
+
|
|
210
|
+
console.log('Whitelabeling data:', whitelabelData)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### React Component Integration
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
import React, { useEffect, useState } from 'react'
|
|
217
|
+
import { useContext } from '@owlmeans/client'
|
|
218
|
+
import type { WlWebService, ProvidedWLSet } from '@owlmeans/web-wl'
|
|
219
|
+
import type { CompanyInfo, CustomStyles, CustomMedia } from '@owlmeans/wled'
|
|
220
|
+
|
|
221
|
+
interface WhitelabeledAppProps {
|
|
222
|
+
entityId: string
|
|
223
|
+
children: React.ReactNode
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const WhitelabeledApp: React.FC<WhitelabeledAppProps> = ({ entityId, children }) => {
|
|
227
|
+
const context = useContext()
|
|
228
|
+
const [whitelabelData, setWhitelabelData] = useState<ProvidedWLSet | null>(null)
|
|
229
|
+
const [loading, setLoading] = useState(true)
|
|
230
|
+
const [error, setError] = useState<Error | null>(null)
|
|
231
|
+
|
|
232
|
+
useEffect(() => {
|
|
233
|
+
const loadWhitelabeling = async () => {
|
|
234
|
+
try {
|
|
235
|
+
setLoading(true)
|
|
236
|
+
const wlService = context.service<WlWebService>('wl-web-service')
|
|
237
|
+
const data = await wlService.load(entityId)
|
|
238
|
+
setWhitelabelData(data)
|
|
239
|
+
} catch (err) {
|
|
240
|
+
setError(err as Error)
|
|
241
|
+
} finally {
|
|
242
|
+
setLoading(false)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
loadWhitelabeling()
|
|
247
|
+
}, [entityId, context])
|
|
248
|
+
|
|
249
|
+
if (loading) {
|
|
250
|
+
return <div>Loading branding...</div>
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (error) {
|
|
254
|
+
return <div>Error loading branding: {error.message}</div>
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (!whitelabelData) {
|
|
258
|
+
return <div>No branding data available</div>
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Extract specific whitelabeling data
|
|
262
|
+
const wlService = context.service<WlWebService>('wl-web-service')
|
|
263
|
+
const companyInfo = wlService.extract<CompanyInfo>('company-provider', whitelabelData)
|
|
264
|
+
const customStyles = wlService.extract<CustomStyles>('styles-provider', whitelabelData)
|
|
265
|
+
const customMedia = wlService.extract<CustomMedia>('media-provider', whitelabelData)
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
<WhitelabelThemeProvider styles={customStyles}>
|
|
269
|
+
<div className="whitelabeled-app">
|
|
270
|
+
<header>
|
|
271
|
+
{customMedia?.brand?.wideLogo && (
|
|
272
|
+
<img
|
|
273
|
+
src={customMedia.brand.wideLogo}
|
|
274
|
+
alt={companyInfo?.fullName || 'Logo'}
|
|
275
|
+
className="company-logo"
|
|
276
|
+
/>
|
|
277
|
+
)}
|
|
278
|
+
<h1>{companyInfo?.fullName || 'Application'}</h1>
|
|
279
|
+
</header>
|
|
280
|
+
|
|
281
|
+
<main>
|
|
282
|
+
{children}
|
|
283
|
+
</main>
|
|
284
|
+
|
|
285
|
+
<footer>
|
|
286
|
+
<p>{companyInfo?.description}</p>
|
|
287
|
+
</footer>
|
|
288
|
+
</div>
|
|
289
|
+
</WhitelabelThemeProvider>
|
|
290
|
+
)
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Dynamic Theme Application
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
import React, { useMemo } from 'react'
|
|
298
|
+
import { ThemeProvider, createTheme } from '@mui/material/styles'
|
|
299
|
+
import type { CustomStyles } from '@owlmeans/wled'
|
|
300
|
+
|
|
301
|
+
interface WhitelabelThemeProviderProps {
|
|
302
|
+
styles?: CustomStyles
|
|
303
|
+
children: React.ReactNode
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const WhitelabelThemeProvider: React.FC<WhitelabelThemeProviderProps> = ({
|
|
307
|
+
styles,
|
|
308
|
+
children
|
|
309
|
+
}) => {
|
|
310
|
+
const theme = useMemo(() => {
|
|
311
|
+
const baseTheme = createTheme()
|
|
312
|
+
|
|
313
|
+
if (!styles) {
|
|
314
|
+
return baseTheme
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return createTheme({
|
|
318
|
+
...baseTheme,
|
|
319
|
+
palette: {
|
|
320
|
+
...baseTheme.palette,
|
|
321
|
+
primary: {
|
|
322
|
+
main: styles.colors.primaryColor,
|
|
323
|
+
contrastText: '#ffffff'
|
|
324
|
+
},
|
|
325
|
+
secondary: {
|
|
326
|
+
main: styles.colors.secondaryColor || baseTheme.palette.secondary.main
|
|
327
|
+
},
|
|
328
|
+
background: {
|
|
329
|
+
default: styles.colors.primaryBackground || baseTheme.palette.background.default,
|
|
330
|
+
paper: styles.colors.secondaryBackground || baseTheme.palette.background.paper
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
typography: {
|
|
334
|
+
...baseTheme.typography,
|
|
335
|
+
fontFamily: styles.font.fontFamily || baseTheme.typography.fontFamily,
|
|
336
|
+
fontSize: styles.font.basicSize || baseTheme.typography.fontSize
|
|
337
|
+
}
|
|
338
|
+
})
|
|
339
|
+
}, [styles])
|
|
340
|
+
|
|
341
|
+
return (
|
|
342
|
+
<ThemeProvider theme={theme}>
|
|
343
|
+
{children}
|
|
344
|
+
</ThemeProvider>
|
|
345
|
+
)
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Whitelabel-aware Components
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
import React from 'react'
|
|
353
|
+
import { useContext } from '@owlmeans/client'
|
|
354
|
+
import type { WlWebService } from '@owlmeans/web-wl'
|
|
355
|
+
import type { CustomMedia } from '@owlmeans/wled'
|
|
356
|
+
|
|
357
|
+
interface CompanyLogoProps {
|
|
358
|
+
entityId: string
|
|
359
|
+
type?: 'square' | 'wide'
|
|
360
|
+
className?: string
|
|
361
|
+
alt?: string
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const CompanyLogo: React.FC<CompanyLogoProps> = ({
|
|
365
|
+
entityId,
|
|
366
|
+
type = 'wide',
|
|
367
|
+
className,
|
|
368
|
+
alt = 'Company Logo'
|
|
369
|
+
}) => {
|
|
370
|
+
const context = useContext()
|
|
371
|
+
const [logoUrl, setLogoUrl] = React.useState<string | null>(null)
|
|
372
|
+
|
|
373
|
+
React.useEffect(() => {
|
|
374
|
+
const loadLogo = async () => {
|
|
375
|
+
try {
|
|
376
|
+
const wlService = context.service<WlWebService>('wl-web-service')
|
|
377
|
+
const whitelabelData = await wlService.load(entityId)
|
|
378
|
+
const mediaData = wlService.extract<CustomMedia>('media-provider', whitelabelData)
|
|
379
|
+
|
|
380
|
+
const logo = type === 'square'
|
|
381
|
+
? mediaData?.brand?.squareLogo
|
|
382
|
+
: mediaData?.brand?.wideLogo
|
|
383
|
+
|
|
384
|
+
setLogoUrl(logo || null)
|
|
385
|
+
} catch (error) {
|
|
386
|
+
console.error('Failed to load company logo:', error)
|
|
387
|
+
setLogoUrl(null)
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
loadLogo()
|
|
392
|
+
}, [entityId, type, context])
|
|
393
|
+
|
|
394
|
+
if (!logoUrl) {
|
|
395
|
+
return (
|
|
396
|
+
<div className={`company-logo-placeholder ${className || ''}`}>
|
|
397
|
+
{alt}
|
|
398
|
+
</div>
|
|
399
|
+
)
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return (
|
|
403
|
+
<img
|
|
404
|
+
src={logoUrl}
|
|
405
|
+
alt={alt}
|
|
406
|
+
className={`company-logo ${className || ''}`}
|
|
407
|
+
/>
|
|
408
|
+
)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Usage
|
|
412
|
+
<CompanyLogo
|
|
413
|
+
entityId="company-123"
|
|
414
|
+
type="wide"
|
|
415
|
+
className="header-logo"
|
|
416
|
+
alt="Acme Corporation"
|
|
417
|
+
/>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Custom Hook for Whitelabeling
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
import { useState, useEffect } from 'react'
|
|
424
|
+
import { useContext } from '@owlmeans/client'
|
|
425
|
+
import type { WlWebService, ProvidedWLSet } from '@owlmeans/web-wl'
|
|
426
|
+
|
|
427
|
+
interface UseWhitelabelResult<T = any> {
|
|
428
|
+
data: T | null
|
|
429
|
+
loading: boolean
|
|
430
|
+
error: Error | null
|
|
431
|
+
reload: () => void
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export const useWhitelabel = <T = any>(
|
|
435
|
+
entityId: string,
|
|
436
|
+
providerKey?: string
|
|
437
|
+
): UseWhitelabelResult<T> => {
|
|
438
|
+
const context = useContext()
|
|
439
|
+
const [data, setData] = useState<T | null>(null)
|
|
440
|
+
const [loading, setLoading] = useState(true)
|
|
441
|
+
const [error, setError] = useState<Error | null>(null)
|
|
442
|
+
|
|
443
|
+
const loadData = async () => {
|
|
444
|
+
try {
|
|
445
|
+
setLoading(true)
|
|
446
|
+
setError(null)
|
|
447
|
+
|
|
448
|
+
const wlService = context.service<WlWebService>('wl-web-service')
|
|
449
|
+
const whitelabelData = await wlService.load(entityId)
|
|
450
|
+
|
|
451
|
+
if (providerKey) {
|
|
452
|
+
const extracted = wlService.extract<T>(providerKey, whitelabelData)
|
|
453
|
+
setData(extracted || null)
|
|
454
|
+
} else {
|
|
455
|
+
setData(whitelabelData as T)
|
|
456
|
+
}
|
|
457
|
+
} catch (err) {
|
|
458
|
+
setError(err as Error)
|
|
459
|
+
setData(null)
|
|
460
|
+
} finally {
|
|
461
|
+
setLoading(false)
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
useEffect(() => {
|
|
466
|
+
loadData()
|
|
467
|
+
}, [entityId, providerKey])
|
|
468
|
+
|
|
469
|
+
return {
|
|
470
|
+
data,
|
|
471
|
+
loading,
|
|
472
|
+
error,
|
|
473
|
+
reload: loadData
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Usage examples
|
|
478
|
+
const CompanyInfoDisplay: React.FC<{ entityId: string }> = ({ entityId }) => {
|
|
479
|
+
const { data: companyInfo, loading, error } = useWhitelabel<CompanyInfo>(
|
|
480
|
+
entityId,
|
|
481
|
+
'company-provider'
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
if (loading) return <div>Loading company info...</div>
|
|
485
|
+
if (error) return <div>Error: {error.message}</div>
|
|
486
|
+
if (!companyInfo) return <div>No company information available</div>
|
|
487
|
+
|
|
488
|
+
return (
|
|
489
|
+
<div>
|
|
490
|
+
<h2>{companyInfo.fullName}</h2>
|
|
491
|
+
<p>{companyInfo.description}</p>
|
|
492
|
+
</div>
|
|
493
|
+
)
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const StylesDisplay: React.FC<{ entityId: string }> = ({ entityId }) => {
|
|
497
|
+
const { data: styles, loading, error } = useWhitelabel<CustomStyles>(
|
|
498
|
+
entityId,
|
|
499
|
+
'styles-provider'
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
if (loading || error || !styles) return null
|
|
503
|
+
|
|
504
|
+
return (
|
|
505
|
+
<div style={{
|
|
506
|
+
backgroundColor: styles.colors.primaryBackground,
|
|
507
|
+
color: styles.colors.primaryColor,
|
|
508
|
+
fontFamily: styles.font.fontFamily
|
|
509
|
+
}}>
|
|
510
|
+
Custom styled content
|
|
511
|
+
</div>
|
|
512
|
+
)
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### Multi-entity Whitelabeling
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
import React, { useState } from 'react'
|
|
520
|
+
import { useWhitelabel } from './useWhitelabel'
|
|
521
|
+
|
|
522
|
+
const MultiEntityDemo: React.FC = () => {
|
|
523
|
+
const [selectedEntity, setSelectedEntity] = useState('entity-1')
|
|
524
|
+
|
|
525
|
+
const entities = [
|
|
526
|
+
{ id: 'entity-1', name: 'Company A' },
|
|
527
|
+
{ id: 'entity-2', name: 'Company B' },
|
|
528
|
+
{ id: 'entity-3', name: 'Company C' }
|
|
529
|
+
]
|
|
530
|
+
|
|
531
|
+
const { data: whitelabelData, loading } = useWhitelabel(selectedEntity)
|
|
532
|
+
|
|
533
|
+
return (
|
|
534
|
+
<div>
|
|
535
|
+
<select
|
|
536
|
+
value={selectedEntity}
|
|
537
|
+
onChange={(e) => setSelectedEntity(e.target.value)}
|
|
538
|
+
>
|
|
539
|
+
{entities.map(entity => (
|
|
540
|
+
<option key={entity.id} value={entity.id}>
|
|
541
|
+
{entity.name}
|
|
542
|
+
</option>
|
|
543
|
+
))}
|
|
544
|
+
</select>
|
|
545
|
+
|
|
546
|
+
{loading ? (
|
|
547
|
+
<div>Loading whitelabel data...</div>
|
|
548
|
+
) : (
|
|
549
|
+
<WhitelabeledApp entityId={selectedEntity}>
|
|
550
|
+
<div>Content for {selectedEntity}</div>
|
|
551
|
+
</WhitelabeledApp>
|
|
552
|
+
)}
|
|
553
|
+
</div>
|
|
554
|
+
)
|
|
555
|
+
}
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
## Caching Strategy
|
|
559
|
+
|
|
560
|
+
### Memory Cache Implementation
|
|
561
|
+
|
|
562
|
+
```typescript
|
|
563
|
+
// Internal caching implementation (simplified)
|
|
564
|
+
class WhitelabelCache {
|
|
565
|
+
private cache = new Map<string, ProvidedWLSet>()
|
|
566
|
+
private ttl = 5 * 60 * 1000 // 5 minutes
|
|
567
|
+
private timestamps = new Map<string, number>()
|
|
568
|
+
|
|
569
|
+
set(entityId: string, data: ProvidedWLSet): void {
|
|
570
|
+
this.cache.set(entityId, data)
|
|
571
|
+
this.timestamps.set(entityId, Date.now())
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
get(entityId: string): ProvidedWLSet | undefined {
|
|
575
|
+
const timestamp = this.timestamps.get(entityId)
|
|
576
|
+
if (timestamp && Date.now() - timestamp > this.ttl) {
|
|
577
|
+
this.cache.delete(entityId)
|
|
578
|
+
this.timestamps.delete(entityId)
|
|
579
|
+
return undefined
|
|
580
|
+
}
|
|
581
|
+
return this.cache.get(entityId)
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
clear(): void {
|
|
585
|
+
this.cache.clear()
|
|
586
|
+
this.timestamps.clear()
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
invalidate(entityId: string): void {
|
|
590
|
+
this.cache.delete(entityId)
|
|
591
|
+
this.timestamps.delete(entityId)
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### Cache Management
|
|
597
|
+
|
|
598
|
+
```typescript
|
|
599
|
+
// Utility functions for cache management
|
|
600
|
+
export const clearWhitelabelCache = (context: Context) => {
|
|
601
|
+
const wlService = context.service<WlWebService>('wl-web-service')
|
|
602
|
+
// Cache clearing would be implemented in the service
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
export const preloadWhitelabeling = async (
|
|
606
|
+
context: Context,
|
|
607
|
+
entityIds: string[]
|
|
608
|
+
) => {
|
|
609
|
+
const wlService = context.service<WlWebService>('wl-web-service')
|
|
610
|
+
|
|
611
|
+
// Preload whitelabeling data for multiple entities
|
|
612
|
+
await Promise.all(
|
|
613
|
+
entityIds.map(entityId => wlService.load(entityId))
|
|
614
|
+
)
|
|
615
|
+
}
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
## Error Handling
|
|
619
|
+
|
|
620
|
+
### Graceful Error Handling
|
|
621
|
+
|
|
622
|
+
```typescript
|
|
623
|
+
const ErrorBoundaryWhitelabel: React.FC<{
|
|
624
|
+
children: React.ReactNode
|
|
625
|
+
fallback?: React.ReactNode
|
|
626
|
+
}> = ({ children, fallback }) => {
|
|
627
|
+
return (
|
|
628
|
+
<ErrorBoundary
|
|
629
|
+
fallback={fallback || <div>Failed to load branding</div>}
|
|
630
|
+
onError={(error) => {
|
|
631
|
+
console.error('Whitelabeling error:', error)
|
|
632
|
+
// Report to error tracking service
|
|
633
|
+
}}
|
|
634
|
+
>
|
|
635
|
+
{children}
|
|
636
|
+
</ErrorBoundary>
|
|
637
|
+
)
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Usage
|
|
641
|
+
<ErrorBoundaryWhitelabel fallback={<DefaultBranding />}>
|
|
642
|
+
<WhitelabeledApp entityId={entityId}>
|
|
643
|
+
<AppContent />
|
|
644
|
+
</WhitelabeledApp>
|
|
645
|
+
</ErrorBoundaryWhitelabel>
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
## Performance Optimization
|
|
649
|
+
|
|
650
|
+
### Lazy Loading and Code Splitting
|
|
651
|
+
|
|
652
|
+
```typescript
|
|
653
|
+
import React, { lazy, Suspense } from 'react'
|
|
654
|
+
|
|
655
|
+
// Lazy load whitelabel components
|
|
656
|
+
const WhitelabeledDashboard = lazy(() => import('./WhitelabeledDashboard'))
|
|
657
|
+
|
|
658
|
+
const App: React.FC = () => (
|
|
659
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
660
|
+
<WhitelabeledDashboard entityId="company-123" />
|
|
661
|
+
</Suspense>
|
|
662
|
+
)
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### Memoization
|
|
666
|
+
|
|
667
|
+
```typescript
|
|
668
|
+
import React, { memo, useMemo } from 'react'
|
|
669
|
+
|
|
670
|
+
const MemoizedWhitelabelComponent = memo<{ entityId: string }>(({ entityId }) => {
|
|
671
|
+
const { data } = useWhitelabel(entityId, 'company-provider')
|
|
672
|
+
|
|
673
|
+
const memoizedContent = useMemo(() => {
|
|
674
|
+
if (!data) return null
|
|
675
|
+
|
|
676
|
+
return (
|
|
677
|
+
<div>
|
|
678
|
+
<h1>{data.fullName}</h1>
|
|
679
|
+
<p>{data.description}</p>
|
|
680
|
+
</div>
|
|
681
|
+
)
|
|
682
|
+
}, [data])
|
|
683
|
+
|
|
684
|
+
return memoizedContent
|
|
685
|
+
})
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
## Integration with OwlMeans Ecosystem
|
|
689
|
+
|
|
690
|
+
### Context Integration
|
|
691
|
+
```typescript
|
|
692
|
+
import { makeWebContext } from '@owlmeans/web-client'
|
|
693
|
+
|
|
694
|
+
const context = makeWebContext(config)
|
|
695
|
+
const wlService = context.service<WlWebService>('wl-web-service')
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
### Module System Integration
|
|
699
|
+
```typescript
|
|
700
|
+
import { modules } from '@owlmeans/web-wl'
|
|
701
|
+
|
|
702
|
+
// Modules are automatically integrated via service
|
|
703
|
+
context.registerService(wlService)
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
### Client Integration
|
|
707
|
+
```typescript
|
|
708
|
+
import { useContext } from '@owlmeans/client'
|
|
709
|
+
|
|
710
|
+
const wlService = useContext().service<WlWebService>('wl-web-service')
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
## Best Practices
|
|
714
|
+
|
|
715
|
+
1. **Caching**: Implement appropriate caching strategies for performance
|
|
716
|
+
2. **Error Handling**: Provide graceful fallbacks for failed whitelabeling requests
|
|
717
|
+
3. **Performance**: Use memoization and lazy loading for large applications
|
|
718
|
+
4. **User Experience**: Show loading states during whitelabeling data fetch
|
|
719
|
+
5. **Accessibility**: Ensure dynamic content maintains accessibility standards
|
|
720
|
+
6. **Testing**: Test with different entity configurations and error scenarios
|
|
721
|
+
|
|
722
|
+
## Related Packages
|
|
723
|
+
|
|
724
|
+
- **@owlmeans/wled**: Core whitelabeling types and modules
|
|
725
|
+
- **@owlmeans/client-wl**: Base client whitelabeling functionality
|
|
726
|
+
- **@owlmeans/server-wl**: Server-side whitelabeling implementation
|
|
727
|
+
- **@owlmeans/client**: Base client functionality
|
|
728
|
+
- **@owlmeans/client-module**: Client module system for API calls
|
|
729
|
+
|
|
730
|
+
## TypeScript Support
|
|
731
|
+
|
|
732
|
+
This package is written in TypeScript and provides full type safety:
|
|
733
|
+
|
|
734
|
+
```typescript
|
|
735
|
+
import type {
|
|
736
|
+
WlWebService,
|
|
737
|
+
ProvidedWLSet,
|
|
738
|
+
Config,
|
|
739
|
+
Context
|
|
740
|
+
} from '@owlmeans/web-wl'
|
|
741
|
+
|
|
742
|
+
const wlService: WlWebService = makeWlService()
|
|
743
|
+
const context: Context = makeWebContext(config)
|
|
744
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logo.d.ts","sourceRoot":"","sources":["../../src/components/logo.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;AAI/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAG7C,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CAelC,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useContext, useValue } from '@owlmeans/client';
|
|
3
|
+
import { DEFAULT_ALIAS } from '../consts.js';
|
|
4
|
+
export const WlLogo = ({ entityId, defImg }) => {
|
|
5
|
+
const context = useContext();
|
|
6
|
+
const wl = useValue(async () => {
|
|
7
|
+
const srv = context.service(DEFAULT_ALIAS);
|
|
8
|
+
if (entityId != null) {
|
|
9
|
+
const wl = await srv.load(entityId);
|
|
10
|
+
return wl['wl-logo'];
|
|
11
|
+
}
|
|
12
|
+
return { brand: {} };
|
|
13
|
+
}, [entityId]);
|
|
14
|
+
return (wl?.brand.wideLogo ?? defImg)
|
|
15
|
+
&& _jsx("img", { src: wl?.brand.wideLogo ?? defImg, style: { maxWidth: '50%' } });
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=logo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logo.js","sourceRoot":"","sources":["../../src/components/logo.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAI5C,MAAM,CAAC,MAAM,MAAM,GAAoB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;IAC9D,MAAM,OAAO,GAAG,UAAU,EAAmB,CAAA;IAC7C,MAAM,EAAE,GAAG,QAAQ,CAAqB,KAAK,IAAI,EAAE;QACjD,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAe,aAAa,CAAC,CAAA;QACxD,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,IAAI,CAAc,QAAQ,CAAC,CAAA;YAEhD,OAAO,EAAE,CAAC,SAAS,CAAC,CAAA;QACtB,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;IACtB,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEd,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,IAAI,MAAM,CAAC;WAChC,cAAK,GAAG,EAAE,EAAE,EAAE,KAAK,CAAC,QAAQ,IAAI,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAI,CAAA;AAC7E,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/components/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,WAAY,SAAQ,gBAAgB;IACnD,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/components/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa,mBAAmB,CAAA"}
|
package/build/consts.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,aAAa,GAAG,gBAAgB,CAAA"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,uBAAuB,CAAA"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,uBAAuB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAK3D,eAAO,MAAM,OAAO,EAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,CAAA"}
|
package/build/modules.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modules.js","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAEjE,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;AAE9B,MAAM,CAAC,MAAM,OAAO,GAAG,SAAoC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkC,YAAY,EAAE,MAAM,YAAY,CAAA;AAK9E,eAAO,MAAM,aAAa,WAAW,MAAM,KAAmB,YAqB7D,CAAA"}
|
package/build/service.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DEFAULT_ALIAS } from './consts.js';
|
|
2
|
+
import { createService } from '@owlmeans/context';
|
|
3
|
+
import { WL_PROVIDE } from '@owlmeans/wled';
|
|
4
|
+
export const makeWlService = (alias = DEFAULT_ALIAS) => {
|
|
5
|
+
const cache = {};
|
|
6
|
+
const service = createService(alias, {
|
|
7
|
+
load: async (entityId) => {
|
|
8
|
+
if (cache[entityId] != null) {
|
|
9
|
+
return cache[entityId];
|
|
10
|
+
}
|
|
11
|
+
const context = service.assertCtx();
|
|
12
|
+
const module = context.module(WL_PROVIDE);
|
|
13
|
+
const [wlSet] = await module.call({ params: { entity: entityId } });
|
|
14
|
+
return cache[entityId] = wlSet;
|
|
15
|
+
},
|
|
16
|
+
extract: (key, set) => set[key]
|
|
17
|
+
});
|
|
18
|
+
return service;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAG3C,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAgB,aAAa,EAAgB,EAAE;IAC3E,MAAM,KAAK,GAA0C,EAAE,CAAA;IAEvD,MAAM,OAAO,GAAiB,aAAa,CAAe,KAAK,EAAE;QAC/D,IAAI,EAAE,KAAK,EAAC,QAAQ,EAAC,EAAE;YACrB,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC5B,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAA;YACxB,CAAC;YAED,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAmB,CAAA;YAEpD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAA8B,UAAU,CAAC,CAAA;YACtE,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAA;YAEnE,OAAO,KAAK,CAAC,QAAQ,CAAC,GAAG,KAA2B,CAAA;QACtD,CAAC;QAED,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;KAChC,CAAC,CAAA;IAEF,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { InitializedService } from '@owlmeans/context';
|
|
2
|
+
import type { ProvidedWL } from '@owlmeans/wled';
|
|
3
|
+
import type { AppConfig, AppContext } from '@owlmeans/web-client';
|
|
4
|
+
export interface WlWebService extends InitializedService {
|
|
5
|
+
load: <T extends {} = {}>(entityId: string, resource?: string) => Promise<ProvidedWLSet<T>>;
|
|
6
|
+
extract<T extends {} = {}>(key: string, set: ProvidedWLSet<any>): ProvidedWL<T>;
|
|
7
|
+
}
|
|
8
|
+
export interface ProvidedWLSet<T extends {} = {}> {
|
|
9
|
+
[key: string]: ProvidedWL<T>;
|
|
10
|
+
}
|
|
11
|
+
export interface Config extends AppConfig {
|
|
12
|
+
}
|
|
13
|
+
export interface Context<C extends Config = Config> extends AppContext<C> {
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,KAAK,EAAC,SAAS,EAAE,UAAU,EAAC,MAAM,sBAAsB,CAAA;AAE/D,MAAM,WAAW,YAAa,SAAQ,kBAAkB;IACtD,IAAI,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IAC3F,OAAO,CAAE,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA;CACjF;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE;IAC9C,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA;CAC7B;AAED,MAAM,WAAW,MAAO,SAAQ,SAAS;CACxC;AAED,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAC;CACxE"}
|
package/build/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@owlmeans/web-wl",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "tsc -b",
|
|
7
|
+
"dev": "sleep 390 && nodemon -e ts,tsx,json --watch src --exec \"tsc -p ./tsconfig.json\"",
|
|
8
|
+
"watch": "tsc -b -w --preserveWatchOutput --pretty"
|
|
9
|
+
},
|
|
10
|
+
"main": "build/index.js",
|
|
11
|
+
"module": "build/index.js",
|
|
12
|
+
"types": "build/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./build/index.js",
|
|
16
|
+
"require": "./build/index.js",
|
|
17
|
+
"default": "./build/index.js",
|
|
18
|
+
"module": "./build/index.js",
|
|
19
|
+
"types": "./build/index.d.ts"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@owlmeans/client": "^0.1.0",
|
|
24
|
+
"@owlmeans/client-module": "^0.1.0",
|
|
25
|
+
"@owlmeans/context": "^0.1.0",
|
|
26
|
+
"@owlmeans/wled": "^0.1.0"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"react": "*"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/react": "^18.3.11",
|
|
33
|
+
"nodemon": "^3.1.7",
|
|
34
|
+
"typescript": "^5.6.3"
|
|
35
|
+
},
|
|
36
|
+
"private": false,
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './logo.js'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { FC } from 'react'
|
|
2
|
+
import { useContext, useValue } from '@owlmeans/client'
|
|
3
|
+
import type { Config, Context, WlWebService } from '../types.js'
|
|
4
|
+
import { DEFAULT_ALIAS } from '../consts.js'
|
|
5
|
+
import type { WLLogoProps } from './types.js'
|
|
6
|
+
import type { CustomMedia } from '@owlmeans/wled'
|
|
7
|
+
|
|
8
|
+
export const WlLogo: FC<WLLogoProps> = ({ entityId, defImg }) => {
|
|
9
|
+
const context = useContext<Config, Context>()
|
|
10
|
+
const wl = useValue<CustomMedia | null>(async () => {
|
|
11
|
+
const srv = context.service<WlWebService>(DEFAULT_ALIAS)
|
|
12
|
+
if (entityId != null) {
|
|
13
|
+
const wl = await srv.load<CustomMedia>(entityId)
|
|
14
|
+
|
|
15
|
+
return wl['wl-logo']
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return { brand: {} }
|
|
19
|
+
}, [entityId])
|
|
20
|
+
|
|
21
|
+
return (wl?.brand.wideLogo ?? defImg)
|
|
22
|
+
&& <img src={wl?.brand.wideLogo ?? defImg} style={{ maxWidth: '50%' }} />
|
|
23
|
+
}
|
package/src/consts.ts
ADDED
package/src/index.ts
ADDED
package/src/modules.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
|
|
2
|
+
import { elevate } from '@owlmeans/client-module'
|
|
3
|
+
import type { ClientModule } from '@owlmeans/client-module'
|
|
4
|
+
import { WL_PROVIDE, modules as wlModules } from '@owlmeans/wled'
|
|
5
|
+
|
|
6
|
+
elevate(wlModules, WL_PROVIDE)
|
|
7
|
+
|
|
8
|
+
export const modules = wlModules as ClientModule<unknown>[]
|
package/src/service.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ClientModule } from '@owlmeans/client-module'
|
|
2
|
+
import { DEFAULT_ALIAS } from './consts.js'
|
|
3
|
+
import type { Config, Context, ProvidedWLSet, WlWebService } from './types.js'
|
|
4
|
+
import { createService } from '@owlmeans/context'
|
|
5
|
+
import { WL_PROVIDE } from '@owlmeans/wled'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export const makeWlService = (alias: string = DEFAULT_ALIAS): WlWebService => {
|
|
9
|
+
const cache: { [entityId: string]: ProvidedWLSet } = {}
|
|
10
|
+
|
|
11
|
+
const service: WlWebService = createService<WlWebService>(alias, {
|
|
12
|
+
load: async entityId => {
|
|
13
|
+
if (cache[entityId] != null) {
|
|
14
|
+
return cache[entityId]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const context = service.assertCtx<Config, Context>()
|
|
18
|
+
|
|
19
|
+
const module = context.module<ClientModule<ProvidedWLSet>>(WL_PROVIDE)
|
|
20
|
+
const [wlSet] = await module.call({ params: { entity: entityId } })
|
|
21
|
+
|
|
22
|
+
return cache[entityId] = wlSet as ProvidedWLSet<any>
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
extract: (key, set) => set[key]
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
return service
|
|
29
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
import type { InitializedService } from '@owlmeans/context'
|
|
3
|
+
import type { ProvidedWL } from '@owlmeans/wled'
|
|
4
|
+
import type {AppConfig, AppContext} from '@owlmeans/web-client'
|
|
5
|
+
|
|
6
|
+
export interface WlWebService extends InitializedService {
|
|
7
|
+
load: <T extends {} = {}>(entityId: string, resource?: string) => Promise<ProvidedWLSet<T>>
|
|
8
|
+
extract <T extends {} = {}>(key: string, set: ProvidedWLSet<any>): ProvidedWL<T>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ProvidedWLSet<T extends {} = {}> {
|
|
12
|
+
[key: string]: ProvidedWL<T>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface Config extends AppConfig {
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface Context<C extends Config = Config> extends AppContext<C> {
|
|
19
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": [
|
|
3
|
+
"../tsconfig.default.json",
|
|
4
|
+
"../tsconfig.react.json",
|
|
5
|
+
],
|
|
6
|
+
"compilerOptions": {
|
|
7
|
+
"rootDir": "./src/", /* Specify the root folder within your source files. */
|
|
8
|
+
"outDir": "./build/", /* Specify an output folder for all emitted files. */
|
|
9
|
+
"moduleResolution": "Bundler",
|
|
10
|
+
},
|
|
11
|
+
"exclude": [
|
|
12
|
+
"./dist/**/*",
|
|
13
|
+
"./build/**/*",
|
|
14
|
+
"./*.ts"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./src/consts.ts","./src/index.ts","./src/modules.ts","./src/service.ts","./src/types.ts","./src/components/index.ts","./src/components/logo.tsx","./src/components/types.ts"],"version":"5.6.3"}
|