@akinon/pz-similar-products 1.113.0-snapshot-ZERO-3878-20251204105428 → 1.114.0-rc.21
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/CHANGELOG.md +29 -34
- package/README.md +0 -202
- package/package.json +1 -1
- package/src/data/endpoints.ts +5 -14
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-image-search-feature.ts +32 -0
- package/src/hooks/use-similar-products.ts +23 -148
- package/src/types/index.ts +0 -51
- package/src/utils/index.ts +3 -38
- package/src/views/filters.tsx +3 -27
- package/src/views/header-image-search-feature.tsx +34 -28
- package/src/views/image-search-button.tsx +23 -19
- package/src/views/main.tsx +5 -82
- package/src/views/product-image-search-feature.tsx +22 -22
- package/src/views/search-button.tsx +2 -12
- package/src/views/search-modal.tsx +10 -169
package/CHANGELOG.md
CHANGED
|
@@ -1,67 +1,62 @@
|
|
|
1
1
|
# @akinon/pz-similar-products
|
|
2
2
|
|
|
3
|
-
## 1.
|
|
3
|
+
## 1.114.0-rc.21
|
|
4
4
|
|
|
5
|
-
## 1.
|
|
5
|
+
## 1.114.0-rc.20
|
|
6
6
|
|
|
7
7
|
### Minor Changes
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
## 1.92.0-rc.32
|
|
12
|
-
|
|
13
|
-
### Minor Changes
|
|
14
|
-
|
|
15
|
-
- 54e3179: ZERO-3532: Added customize options to icons
|
|
16
|
-
|
|
17
|
-
## 1.92.0-rc.31
|
|
18
|
-
|
|
19
|
-
## 1.92.0-rc.30
|
|
20
|
-
|
|
21
|
-
## 1.92.0-rc.29
|
|
9
|
+
- 143be2b: ZERO-3457: Crop styles are customizable and logic improved for rendering similar products modal
|
|
10
|
+
- d99a6a7: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
22
11
|
|
|
23
|
-
## 1.
|
|
12
|
+
## 1.113.0-rc.19
|
|
24
13
|
|
|
25
|
-
## 1.
|
|
14
|
+
## 1.113.0-rc.18
|
|
26
15
|
|
|
27
16
|
### Minor Changes
|
|
28
17
|
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
## 1.92.0-rc.26
|
|
18
|
+
- 143be2b: ZERO-3457: Crop styles are customizable and logic improved for rendering similar products modal
|
|
19
|
+
- d99a6a7: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
32
20
|
|
|
33
|
-
## 1.
|
|
21
|
+
## 1.112.0-rc.17
|
|
34
22
|
|
|
35
|
-
|
|
23
|
+
### Minor Changes
|
|
36
24
|
|
|
37
|
-
|
|
25
|
+
- 143be2b9: ZERO-3457: Crop styles are customizable and logic improved for rendering similar products modal
|
|
26
|
+
- d99a6a7d: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
38
27
|
|
|
39
|
-
## 1.
|
|
28
|
+
## 1.111.0-rc.16
|
|
40
29
|
|
|
41
30
|
### Minor Changes
|
|
42
31
|
|
|
43
32
|
- 143be2b: ZERO-3457: Crop styles are customizable and logic improved for rendering similar products modal
|
|
33
|
+
- d99a6a7: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
44
34
|
|
|
45
|
-
## 1.
|
|
35
|
+
## 1.110.0-rc.15
|
|
46
36
|
|
|
47
|
-
|
|
37
|
+
## 1.110.0-rc.14
|
|
48
38
|
|
|
49
|
-
|
|
39
|
+
## 1.110.0-rc.13
|
|
50
40
|
|
|
51
|
-
## 1.
|
|
41
|
+
## 1.110.0-rc.12
|
|
52
42
|
|
|
53
43
|
### Minor Changes
|
|
54
44
|
|
|
55
|
-
-
|
|
45
|
+
- 143be2b9: ZERO-3457: Crop styles are customizable and logic improved for rendering similar products modal
|
|
46
|
+
- d99a6a7d: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
56
47
|
|
|
57
|
-
## 1.
|
|
48
|
+
## 1.109.0-rc.11
|
|
58
49
|
|
|
59
50
|
### Minor Changes
|
|
60
51
|
|
|
61
|
-
-
|
|
52
|
+
- 143be2b9: ZERO-3457: Crop styles are customizable and logic improved for rendering similar products modal
|
|
53
|
+
- d99a6a7d: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
|
54
|
+
|
|
55
|
+
## 1.108.0-rc.10
|
|
62
56
|
|
|
63
|
-
## 1.
|
|
57
|
+
## 1.108.0-rc.9
|
|
64
58
|
|
|
65
|
-
|
|
59
|
+
### Minor Changes
|
|
66
60
|
|
|
67
|
-
|
|
61
|
+
- 143be2b9: ZERO-3457: Crop styles are customizable and logic improved for rendering similar products modal
|
|
62
|
+
- d99a6a7d: ZERO-3457_1: Fixed the settings prop and made sure everything is customizable.
|
package/README.md
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
|
|
11
11
|
- [Features](#markdown-header-features)
|
|
12
12
|
- [Installation](#markdown-header-installation)
|
|
13
|
-
- [Icon Customization](#markdown-header-icon-customization)
|
|
14
13
|
- [Quick Start](#markdown-header-quick-start)
|
|
15
14
|
- [Available Components](#markdown-header-available-components)
|
|
16
15
|
- [Configuration](#markdown-header-configuration)
|
|
@@ -65,7 +64,6 @@
|
|
|
65
64
|
|
|
66
65
|
- **🖼️ Visual Search**: AI-powered image-based product discovery
|
|
67
66
|
- **✂️ Image Cropping**: Built-in cropping functionality with manual confirmation for precise searches
|
|
68
|
-
- **🔤 Text Search**: Search similar products by text description with customizable input
|
|
69
67
|
- **🎛️ Advanced Filtering**: Dynamic facet-based filtering system
|
|
70
68
|
- **📄 Multiple Pagination Modes**: Traditional pagination, load more button, and infinite scroll
|
|
71
69
|
- **🎨 Granular Customization**: 50+ style targets and 30+ render points
|
|
@@ -81,92 +79,6 @@ npx @akinon/projectzero@latest --plugins
|
|
|
81
79
|
|
|
82
80
|
Select `pz-similar-products` from the plugin list during installation.
|
|
83
81
|
|
|
84
|
-
## Icon Customization
|
|
85
|
-
|
|
86
|
-
The plugin provides complete control over icon appearance and behavior through two complementary approaches:
|
|
87
|
-
|
|
88
|
-
### Icon Names (`iconNames`)
|
|
89
|
-
|
|
90
|
-
Change which icons are displayed by specifying different icon names:
|
|
91
|
-
|
|
92
|
-
```tsx
|
|
93
|
-
const iconCustomization = {
|
|
94
|
-
iconNames: {
|
|
95
|
-
searchButton: 'magnifier', // Search button (default: 'search')
|
|
96
|
-
modalClose: 'x', // Modal close buttons (default: 'close')
|
|
97
|
-
filter: 'funnel', // Filter button (default: 'filter')
|
|
98
|
-
filterRemove: 'trash', // Filter tag remove buttons (default: 'close')
|
|
99
|
-
modalSearch: 'search-outline', // Modal search button (default: 'search')
|
|
100
|
-
modalSearchClear: 'clear', // Search input clear button (default: 'close')
|
|
101
|
-
imageSearchButton: 'upload' // Image search button (default: 'search')
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Icon Styles (`customStyles`)
|
|
107
|
-
|
|
108
|
-
Customize the visual appearance of icons with CSS classes:
|
|
109
|
-
|
|
110
|
-
```tsx
|
|
111
|
-
const iconStyling = {
|
|
112
|
-
customStyles: {
|
|
113
|
-
searchButtonIcon: 'fill-blue-500 hover:fill-blue-600 transition-colors',
|
|
114
|
-
modalCloseIcon: 'text-red-500 hover:text-red-700 w-4 h-4',
|
|
115
|
-
filterIcon: 'text-purple-500 w-5 h-5',
|
|
116
|
-
filterRemoveIcon: 'text-orange-500 hover:text-orange-700 w-3 h-3',
|
|
117
|
-
imageSearchButtonIcon: 'text-blue-500 hover:text-blue-600 w-5 h-5'
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### Complete Icon Customization Example
|
|
123
|
-
|
|
124
|
-
```tsx
|
|
125
|
-
const completeIconSettings = {
|
|
126
|
-
// Change icon names
|
|
127
|
-
iconNames: {
|
|
128
|
-
searchButton: 'search-alt',
|
|
129
|
-
modalClose: 'times',
|
|
130
|
-
filter: 'filter-alt',
|
|
131
|
-
filterRemove: 'remove',
|
|
132
|
-
modalSearch: 'magnifying-glass',
|
|
133
|
-
modalSearchClear: 'clear-alt',
|
|
134
|
-
imageSearchButton: 'upload-cloud'
|
|
135
|
-
},
|
|
136
|
-
|
|
137
|
-
// Style the icons
|
|
138
|
-
customStyles: {
|
|
139
|
-
searchButtonIcon: 'fill-indigo-500 hover:fill-indigo-600 transition-all duration-200',
|
|
140
|
-
modalCloseIcon: 'text-gray-500 hover:text-gray-700 w-5 h-5',
|
|
141
|
-
filterIcon: 'text-blue-500 hover:text-blue-600 w-4 h-4',
|
|
142
|
-
filterRemoveIcon: 'text-red-400 hover:text-red-600 w-3 h-3 transition-colors',
|
|
143
|
-
modalSearchIcon: 'text-green-500 hover:text-green-600',
|
|
144
|
-
modalSearchClearIcon: 'text-gray-400 hover:text-gray-600',
|
|
145
|
-
imageSearchButtonIcon: 'text-indigo-500 hover:text-indigo-600 w-5 h-5'
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
// Usage
|
|
150
|
-
<PluginModule
|
|
151
|
-
component={Component.ProductImageSearchFeature}
|
|
152
|
-
props={{
|
|
153
|
-
product,
|
|
154
|
-
activeIndex,
|
|
155
|
-
settings: completeIconSettings
|
|
156
|
-
}}
|
|
157
|
-
/>
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### Available Icon Customization Points
|
|
161
|
-
|
|
162
|
-
- **Search Button** (`searchButton`): Main search button icon in product images
|
|
163
|
-
- **Modal Close** (`modalClose`): Close buttons in modals and filter tags
|
|
164
|
-
- **Filter** (`filter`): Filter toggle button icon
|
|
165
|
-
- **Filter Remove** (`filterRemove`): Remove icons in active filter tags
|
|
166
|
-
- **Modal Search** (`modalSearch`): Search button icon in text search input
|
|
167
|
-
- **Modal Search Clear** (`modalSearchClear`): Clear button icon in text search input
|
|
168
|
-
- **Image Search Button** (`imageSearchButton`): Camera/upload icon in header search feature
|
|
169
|
-
|
|
170
82
|
## Quick Start
|
|
171
83
|
|
|
172
84
|
### Plugin Module Integration
|
|
@@ -255,7 +167,6 @@ interface SimilarProductsSettings {
|
|
|
255
167
|
resultsPerPage?: number; // Products per page (default: 20)
|
|
256
168
|
enableCropping?: boolean; // Enable image cropping (default: true)
|
|
257
169
|
enableFileUpload?: boolean; // Enable file upload (default: true)
|
|
258
|
-
enableTextSearch?: boolean; // Enable text search input (default: false)
|
|
259
170
|
|
|
260
171
|
// Pagination settings
|
|
261
172
|
paginationType?: 'pagination' | 'load-more' | 'infinite-scroll'; // Pagination mode (default: 'pagination')
|
|
@@ -288,21 +199,6 @@ interface SimilarProductsSettings {
|
|
|
288
199
|
itemCount?: string;
|
|
289
200
|
sortDropdown?: string;
|
|
290
201
|
filterToggleButton?: string;
|
|
291
|
-
|
|
292
|
-
// Text search input
|
|
293
|
-
modalSearchInput?: string;
|
|
294
|
-
modalSearchContainer?: string;
|
|
295
|
-
modalSearchButton?: string;
|
|
296
|
-
modalSearchIcon?: string;
|
|
297
|
-
modalSearchClearButton?: string;
|
|
298
|
-
modalSearchClearIcon?: string;
|
|
299
|
-
|
|
300
|
-
// Icon customization
|
|
301
|
-
searchButtonIcon?: string; // Search button icon styling
|
|
302
|
-
modalCloseIcon?: string; // Modal close button icons styling
|
|
303
|
-
filterIcon?: string; // Filter button icon styling
|
|
304
|
-
filterRemoveIcon?: string; // Filter tag remove icons styling
|
|
305
|
-
imageSearchButtonIcon?: string; // Image search button icon styling
|
|
306
202
|
|
|
307
203
|
// Filter sidebar mobile
|
|
308
204
|
filterSidebarMobileHeader?: string;
|
|
@@ -390,17 +286,6 @@ interface SimilarProductsSettings {
|
|
|
390
286
|
cropSelectionHighlight?: string;
|
|
391
287
|
};
|
|
392
288
|
|
|
393
|
-
// Icon name customization
|
|
394
|
-
iconNames?: {
|
|
395
|
-
searchButton?: string; // Search button icon name (default: 'search')
|
|
396
|
-
modalClose?: string; // Modal close button icon name (default: 'close')
|
|
397
|
-
filter?: string; // Filter button icon name (default: 'filter')
|
|
398
|
-
filterRemove?: string; // Filter tag remove icon name (default: 'close')
|
|
399
|
-
modalSearch?: string; // Modal search button icon name (default: 'search')
|
|
400
|
-
modalSearchClear?: string; // Modal search clear button icon name (default: 'close')
|
|
401
|
-
imageSearchButton?: string; // Image search button icon name (default: 'search')
|
|
402
|
-
};
|
|
403
|
-
|
|
404
289
|
// 25+ render functions for granular control
|
|
405
290
|
customRenderers?: {
|
|
406
291
|
// Component-level renderers (full control)
|
|
@@ -419,8 +304,6 @@ interface SimilarProductsSettings {
|
|
|
419
304
|
renderItemCount?: (props) => React.ReactNode;
|
|
420
305
|
renderSortDropdown?: (props) => React.ReactNode;
|
|
421
306
|
renderFilterToggleButton?: (props) => React.ReactNode;
|
|
422
|
-
renderModalSearchInput?: (props) => React.ReactNode;
|
|
423
|
-
renderSearchIcon?: (props) => React.ReactNode;
|
|
424
307
|
// ... see examples for complete list
|
|
425
308
|
};
|
|
426
309
|
filterSidebar?: {
|
|
@@ -458,91 +341,6 @@ interface SimilarProductsSettings {
|
|
|
458
341
|
}
|
|
459
342
|
```
|
|
460
343
|
|
|
461
|
-
## Text Search Integration
|
|
462
|
-
|
|
463
|
-
The plugin features a built-in text search functionality that allows users to search for similar products using descriptive text.
|
|
464
|
-
|
|
465
|
-
### Text Search Features
|
|
466
|
-
|
|
467
|
-
1. **Search Input**: Appears only when API results are available
|
|
468
|
-
2. **Enter Key Support**: Press Enter to trigger search
|
|
469
|
-
3. **Search Icon**: Clickable icon for mobile users
|
|
470
|
-
4. **Clear Button**: X button to clear text and trigger search without text
|
|
471
|
-
5. **Custom Styling**: Fully customizable input, button, and icon
|
|
472
|
-
6. **Custom Icon**: Replaceable search icon via render functions
|
|
473
|
-
|
|
474
|
-
### Basic Text Search Configuration
|
|
475
|
-
|
|
476
|
-
```tsx
|
|
477
|
-
const textSearchSettings = {
|
|
478
|
-
enableTextSearch: true, // Enable text search input
|
|
479
|
-
|
|
480
|
-
customStyles: {
|
|
481
|
-
modalSearchContainer: 'relative flex items-center',
|
|
482
|
-
modalSearchInput: 'h-10 px-4 pr-20 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500',
|
|
483
|
-
modalSearchButton: 'absolute right-2 top-1/2 -translate-y-1/2 p-2 hover:bg-gray-100 rounded-md',
|
|
484
|
-
modalSearchIcon: 'text-gray-500',
|
|
485
|
-
modalSearchClearButton: 'absolute right-12 top-1/2 -translate-y-1/2 p-2 hover:bg-gray-100 rounded-md',
|
|
486
|
-
modalSearchClearIcon: 'text-gray-400 hover:text-gray-600'
|
|
487
|
-
}
|
|
488
|
-
};
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
### Custom Search Icon
|
|
492
|
-
|
|
493
|
-
```tsx
|
|
494
|
-
const customIconSettings = {
|
|
495
|
-
enableTextSearch: true,
|
|
496
|
-
|
|
497
|
-
customRenderers: {
|
|
498
|
-
render: {
|
|
499
|
-
modal: {
|
|
500
|
-
renderSearchIcon: ({ disabled, onClick }) => (
|
|
501
|
-
<svg
|
|
502
|
-
className="w-5 h-5 text-blue-500 cursor-pointer hover:text-blue-700"
|
|
503
|
-
onClick={onClick}
|
|
504
|
-
fill="none"
|
|
505
|
-
stroke="currentColor"
|
|
506
|
-
viewBox="0 0 24 24"
|
|
507
|
-
>
|
|
508
|
-
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
|
509
|
-
</svg>
|
|
510
|
-
),
|
|
511
|
-
renderModalSearchInput: ({ searchText, setSearchText, isLoading, placeholder, onSearch }) => (
|
|
512
|
-
<div className="relative">
|
|
513
|
-
<input
|
|
514
|
-
type="text"
|
|
515
|
-
value={searchText}
|
|
516
|
-
onChange={(e) => setSearchText(e.target.value)}
|
|
517
|
-
onKeyDown={(e) => e.key === 'Enter' && onSearch && onSearch()}
|
|
518
|
-
placeholder={placeholder}
|
|
519
|
-
className="w-full h-10 px-4 pr-20 border-2 border-blue-300 rounded-lg focus:border-blue-500"
|
|
520
|
-
disabled={isLoading}
|
|
521
|
-
/>
|
|
522
|
-
{searchText && (
|
|
523
|
-
<button
|
|
524
|
-
onClick={() => setSearchText('')}
|
|
525
|
-
disabled={isLoading}
|
|
526
|
-
className="absolute right-12 top-1/2 -translate-y-1/2 p-2 text-gray-400 hover:text-gray-600"
|
|
527
|
-
>
|
|
528
|
-
✕
|
|
529
|
-
</button>
|
|
530
|
-
)}
|
|
531
|
-
<button
|
|
532
|
-
onClick={onSearch}
|
|
533
|
-
disabled={isLoading}
|
|
534
|
-
className="absolute right-2 top-1/2 -translate-y-1/2 p-2 text-blue-500 hover:text-blue-700"
|
|
535
|
-
>
|
|
536
|
-
🔍
|
|
537
|
-
</button>
|
|
538
|
-
</div>
|
|
539
|
-
)
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
};
|
|
544
|
-
```
|
|
545
|
-
|
|
546
344
|
## Image Cropping with Manual Confirmation
|
|
547
345
|
|
|
548
346
|
The plugin features an advanced image cropping system with manual confirmation for precise control over search queries.
|
package/package.json
CHANGED
package/src/data/endpoints.ts
CHANGED
|
@@ -27,9 +27,9 @@ export const similarProductsApi = api.injectEndpoints({
|
|
|
27
27
|
endpoints: (build) => ({
|
|
28
28
|
getSimilarProductsByUrl: build.query<
|
|
29
29
|
SimilarProductsResponse,
|
|
30
|
-
{ url: string; limit?: number; excluded_product_ids?: number[]
|
|
30
|
+
{ url: string; limit?: number; excluded_product_ids?: number[] }
|
|
31
31
|
>({
|
|
32
|
-
query: ({ url, limit = 20, excluded_product_ids
|
|
32
|
+
query: ({ url, limit = 20, excluded_product_ids }) => {
|
|
33
33
|
const params = new URLSearchParams();
|
|
34
34
|
params.append('limit', String(limit));
|
|
35
35
|
params.append('url', url);
|
|
@@ -38,10 +38,6 @@ export const similarProductsApi = api.injectEndpoints({
|
|
|
38
38
|
params.append('excluded_product_ids', excluded_product_ids.join(','));
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
if (text) {
|
|
42
|
-
params.append('text', text);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
41
|
return {
|
|
46
42
|
url: `/api/similar-products?${params.toString()}`,
|
|
47
43
|
method: 'GET',
|
|
@@ -54,17 +50,12 @@ export const similarProductsApi = api.injectEndpoints({
|
|
|
54
50
|
|
|
55
51
|
getSimilarProductsByImage: build.mutation<
|
|
56
52
|
SimilarProductsResponse,
|
|
57
|
-
{ image: string; limit?: number; excluded_product_ids?: number[]
|
|
53
|
+
{ image: string; limit?: number; excluded_product_ids?: number[] }
|
|
58
54
|
>({
|
|
59
|
-
query: ({ image, limit = 20, excluded_product_ids
|
|
55
|
+
query: ({ image, limit = 20, excluded_product_ids }) => {
|
|
60
56
|
const params = new URLSearchParams();
|
|
61
57
|
params.append('limit', String(limit));
|
|
62
58
|
|
|
63
|
-
const bodyData: any = { image, excluded_product_ids };
|
|
64
|
-
if (text) {
|
|
65
|
-
bodyData.text = text;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
59
|
return {
|
|
69
60
|
url: `/api/similar-products?${params.toString()}`,
|
|
70
61
|
method: 'POST',
|
|
@@ -72,7 +63,7 @@ export const similarProductsApi = api.injectEndpoints({
|
|
|
72
63
|
'Content-Type': 'application/json',
|
|
73
64
|
Accept: 'application/json'
|
|
74
65
|
},
|
|
75
|
-
body: JSON.stringify(
|
|
66
|
+
body: JSON.stringify({ image, excluded_product_ids })
|
|
76
67
|
};
|
|
77
68
|
}
|
|
78
69
|
}),
|
package/src/hooks/index.ts
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
const IMAGE_SEARCH_STORAGE_KEY = 'enable_image_search';
|
|
4
|
+
|
|
5
|
+
export function useImageSearchFeature() {
|
|
6
|
+
const [isEnabled, setIsEnabled] = useState(false);
|
|
7
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const envEnabled = process.env.NEXT_PUBLIC_ENABLE_IMAGE_SEARCH === 'true';
|
|
11
|
+
|
|
12
|
+
if (envEnabled) {
|
|
13
|
+
setIsEnabled(true);
|
|
14
|
+
setIsLoading(false);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const localStorageValue = localStorage.getItem(IMAGE_SEARCH_STORAGE_KEY);
|
|
20
|
+
setIsEnabled(localStorageValue === 'true');
|
|
21
|
+
} catch (error) {
|
|
22
|
+
setIsEnabled(false);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setIsLoading(false);
|
|
26
|
+
}, []);
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
isEnabled,
|
|
30
|
+
isLoading
|
|
31
|
+
};
|
|
32
|
+
}
|