@tradly/asset 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Example usage of @tradly/media-gallery package
3
+ *
4
+ * This shows how to integrate the media gallery package into your existing project
5
+ */
6
+
7
+ import React, { useState } from 'react'
8
+ import { MediaPopup, MediaApiService } from '@tradly/media-gallery'
9
+ import { getAuthKey } from 'constant/functions'
10
+
11
+ function ExampleMediaGalleryUsage() {
12
+ const [isOpen, setIsOpen] = useState(false)
13
+ const [selectedMedia, setSelectedMedia] = useState(null)
14
+
15
+ // Initialize API service with auth key
16
+ // API base URL is automatically detected from ENVIRONMENT:
17
+ // - Dev: https://api.dev.tradly.app
18
+ // - Prod: https://api.tradly.app
19
+ // All API calls go directly to Tradly API (no proxy needed)
20
+ const apiService = new MediaApiService({
21
+ authKey: getAuthKey(), // Get auth key from your existing function (X-Auth-Key header)
22
+ bearerToken: 'your-bearer-token', // Required: Bearer token for Authorization header
23
+ // environment is auto-detected from process.env.ENVIRONMENT
24
+ // apiBaseUrl is auto-set based on environment (can be overridden)
25
+ onError: (error) => {
26
+ console.error('Media API Error:', error)
27
+ // You can show a toast notification here
28
+ },
29
+ })
30
+
31
+ const handleSelect = (mediaUrl) => {
32
+ console.log('Selected media:', mediaUrl)
33
+ setSelectedMedia(mediaUrl)
34
+ setIsOpen(false)
35
+ }
36
+
37
+ const handleError = (error) => {
38
+ console.error('Media gallery error:', error)
39
+ // Handle error (show toast, etc.)
40
+ }
41
+
42
+ return (
43
+ <div className="p-4">
44
+ <h2 className="text-2xl font-bold mb-4">Media Gallery Example</h2>
45
+
46
+ <div className="mb-4">
47
+ <button
48
+ onClick={() => setIsOpen(true)}
49
+ className="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-dark"
50
+ >
51
+ Open Media Gallery
52
+ </button>
53
+ </div>
54
+
55
+ {selectedMedia && (
56
+ <div className="mt-4">
57
+ <p className="font-semibold">Selected Media:</p>
58
+ <img src={selectedMedia} alt="Selected" className="mt-2 max-w-xs rounded" />
59
+ </div>
60
+ )}
61
+
62
+ <MediaPopup
63
+ isOpen={isOpen}
64
+ onClose={() => setIsOpen(false)}
65
+ onSelect={handleSelect}
66
+ currentData={selectedMedia}
67
+ options={['image', 'video']} // Options: 'image', 'video', 'file'
68
+ apiService={apiService}
69
+ onError={handleError}
70
+ title="Select Media"
71
+ />
72
+ </div>
73
+ )
74
+ }
75
+
76
+ // Example: Using only images
77
+ function ImageOnlyExample() {
78
+ const [isOpen, setIsOpen] = useState(false)
79
+ const apiService = new MediaApiService({
80
+ authKey: getAuthKey(),
81
+ bearerToken: 'your-bearer-token', // Required
82
+ // apiBaseUrl is auto-detected from ENVIRONMENT
83
+ })
84
+
85
+ return (
86
+ <MediaPopup
87
+ isOpen={isOpen}
88
+ onClose={() => setIsOpen(false)}
89
+ onSelect={(url) => console.log('Selected:', url)}
90
+ options={['image']}
91
+ apiService={apiService}
92
+ />
93
+ )
94
+ }
95
+
96
+ // Example: Using individual components
97
+ function CustomGalleryExample() {
98
+ const apiService = new MediaApiService({
99
+ authKey: getAuthKey(),
100
+ bearerToken: 'your-bearer-token', // Required
101
+ // apiBaseUrl is auto-detected from ENVIRONMENT
102
+ })
103
+
104
+ return (
105
+ <div className="p-4">
106
+ <ImagesGallery
107
+ update_data={(url) => {
108
+ console.log('Image selected:', url)
109
+ }}
110
+ closePopup={() => {
111
+ console.log('Gallery closed')
112
+ }}
113
+ apiService={apiService}
114
+ />
115
+ </div>
116
+ )
117
+ }
118
+
119
+ export default ExampleMediaGalleryUsage
@@ -0,0 +1,236 @@
1
+ # Migration Guide: From Existing Media Components to @tradly/media-gallery Package
2
+
3
+ ## Overview
4
+
5
+ This guide helps you migrate from the existing media components in `src/Shared/fields/MediaSections/` to the new reusable `@tradly/media-gallery` package.
6
+
7
+ ## Benefits of Using the Package
8
+
9
+ 1. **Reusability**: Use the same media gallery across multiple projects
10
+ 2. **Maintainability**: Single source of truth for media gallery functionality
11
+ 3. **Flexibility**: Easy to configure with different auth keys and API endpoints
12
+ 4. **Separation of Concerns**: Media gallery logic is isolated from your main app
13
+
14
+ ## Package Structure
15
+
16
+ ```
17
+ packages/media-gallery/
18
+ ├── src/
19
+ │ ├── components/
20
+ │ │ ├── MediaPopup.jsx # Main popup component
21
+ │ │ ├── MediaTab.jsx # Tab navigation
22
+ │ │ ├── MediaGallery.jsx # Images gallery
23
+ │ │ ├── VideosGallery.jsx # Videos gallery
24
+ │ │ ├── FileUpload.jsx # File upload component
25
+ │ │ ├── Pagination.jsx # Pagination component
26
+ │ │ ├── ImagesSkeleton.jsx # Loading skeleton
27
+ │ │ └── Icons.jsx # Icon components
28
+ │ ├── services/
29
+ │ │ └── apiService.js # API service layer
30
+ │ └── index.js # Main export
31
+ ├── package.json
32
+ ├── README.md
33
+ └── EXAMPLE_USAGE.jsx
34
+ ```
35
+
36
+ ## Migration Steps
37
+
38
+ ### Step 1: Install/Setup the Package
39
+
40
+ Since this is a local package, you can either:
41
+
42
+ **Option A: Use as local package (for now)**
43
+
44
+ ```json
45
+ // In your main package.json, add:
46
+ {
47
+ "dependencies": {
48
+ "@tradly/media-gallery": "file:./packages/media-gallery"
49
+ }
50
+ }
51
+ ```
52
+
53
+ **Option B: Publish to npm (later)**
54
+
55
+ ```bash
56
+ cd packages/media-gallery
57
+ npm publish
58
+ ```
59
+
60
+ ### Step 2: Update Your Component
61
+
62
+ **Before (Old way):**
63
+
64
+ ```jsx
65
+ import MediaGallery from '@/Shared/fields/MediaSections/MediaPopup'
66
+
67
+ function MyComponent() {
68
+ const [isOpen, setIsOpen] = useState(false)
69
+
70
+ return (
71
+ <MediaGallery
72
+ isOpenPopup={isOpen}
73
+ setIsOpenPopup={setIsOpen}
74
+ current_data={selectedMedia}
75
+ update_data={setSelectedMedia}
76
+ options={['image']}
77
+ />
78
+ )
79
+ }
80
+ ```
81
+
82
+ **After (New way):**
83
+
84
+ ```jsx
85
+ import { MediaPopup, MediaApiService } from '@tradly/media-gallery'
86
+ import { getAuthKey } from 'constant/functions'
87
+
88
+ function MyComponent() {
89
+ const [isOpen, setIsOpen] = useState(false)
90
+ const [selectedMedia, setSelectedMedia] = useState(null)
91
+
92
+ // Initialize API service with Tradly SDK
93
+ const apiService = new MediaApiService({
94
+ authKey: getAuthKey(),
95
+ baseUrl: '/api',
96
+ tradly: tradly, // Pass Tradly SDK instance (required for uploads)
97
+ })
98
+
99
+ return (
100
+ <MediaPopup
101
+ isOpen={isOpen}
102
+ onClose={() => setIsOpen(false)}
103
+ onSelect={setSelectedMedia}
104
+ currentData={selectedMedia}
105
+ options={['image']}
106
+ apiService={apiService}
107
+ />
108
+ )
109
+ }
110
+ ```
111
+
112
+ ### Step 3: Configure API Service
113
+
114
+ The package handles all upload logic internally using direct API calls. The API base URL is automatically detected from your environment:
115
+
116
+ ```jsx
117
+ const apiService = new MediaApiService({
118
+ authKey: getAuthKey(), // X-Auth-Key header
119
+ bearerToken: 'your-bearer-token', // Required: Bearer token
120
+ // environment is auto-detected from process.env.ENVIRONMENT
121
+ // apiBaseUrl is auto-set based on environment:
122
+ // - Dev: https://api.dev.tradly.app
123
+ // - Prod: https://api.tradly.app
124
+ })
125
+ ```
126
+
127
+ The package will automatically:
128
+
129
+ 1. Detect environment from `process.env.ENVIRONMENT` (or you can pass `environment: 'dev'` or `'production'`)
130
+ 2. Set the correct API base URL (`https://api.dev.tradly.app` for dev, `https://api.tradly.app` for prod)
131
+ 3. Get S3 signed URLs via API call to `POST /v1/utils/S3signedUploadURL`
132
+ 4. Upload files to S3 using the signed URLs
133
+ 5. Save media metadata via `POST /v1/media` with `{ media: [...] }` format
134
+ 6. Fetch media list via `GET /v1/media?page=1&parent=0&mime_type=...`
135
+
136
+ ## Key Differences
137
+
138
+ | Old Component | New Package |
139
+ | --------------------------------------- | -------------------------------- |
140
+ | `isOpenPopup` prop | `isOpen` prop |
141
+ | `setIsOpenPopup` prop | `onClose` callback |
142
+ | `update_data` prop | `onSelect` callback |
143
+ | `current_data` prop | `currentData` prop |
144
+ | Uses `proxy_api_call` directly | Uses `MediaApiService` |
145
+ | Auth key from `getAuthKey()` internally | Auth key passed via `apiService` |
146
+ | Hardcoded API paths | Configurable via `apiService` |
147
+
148
+ ## Complete Example
149
+
150
+ Here's a complete example showing how to replace the old component:
151
+
152
+ ```jsx
153
+ import React, { useState } from 'react'
154
+ import { MediaPopup, MediaApiService } from '@tradly/media-gallery'
155
+ import { getAuthKey } from 'constant/functions'
156
+
157
+ function MyMediaSelector() {
158
+ const [isOpen, setIsOpen] = useState(false)
159
+ const [selectedImage, setSelectedImage] = useState(null)
160
+
161
+ // Create API service instance
162
+ // API base URL is automatically detected from ENVIRONMENT
163
+ // All API calls go directly to Tradly API (no proxy needed)
164
+ const apiService = React.useMemo(() => {
165
+ return new MediaApiService({
166
+ authKey: getAuthKey(),
167
+ bearerToken: 'your-bearer-token', // Required: Bearer token
168
+ // apiBaseUrl is auto-detected from process.env.ENVIRONMENT
169
+ onError: (error) => {
170
+ console.error('Media API Error:', error)
171
+ // Show error toast, etc.
172
+ },
173
+ })
174
+ }, [])
175
+
176
+ return (
177
+ <div>
178
+ <button onClick={() => setIsOpen(true)}>Select Media</button>
179
+
180
+ {selectedImage && <img src={selectedImage} alt="Selected" />}
181
+
182
+ <MediaPopup
183
+ isOpen={isOpen}
184
+ onClose={() => setIsOpen(false)}
185
+ onSelect={(url) => {
186
+ setSelectedImage(url)
187
+ setIsOpen(false)
188
+ }}
189
+ currentData={selectedImage}
190
+ options={['image', 'video']}
191
+ apiService={apiService}
192
+ onError={(error) => {
193
+ console.error('Gallery error:', error)
194
+ }}
195
+ />
196
+ </div>
197
+ )
198
+ }
199
+
200
+ export default MyMediaSelector
201
+ ```
202
+
203
+ ## Testing
204
+
205
+ After migration, test the following:
206
+
207
+ 1. ✅ Opening/closing the media gallery
208
+ 2. ✅ Uploading new images/videos
209
+ 3. ✅ Selecting existing media
210
+ 4. ✅ Pagination works correctly
211
+ 5. ✅ Error handling works
212
+ 6. ✅ Authentication is working
213
+
214
+ ## Rollback Plan
215
+
216
+ If you need to rollback:
217
+
218
+ 1. Keep the old components in `src/Shared/fields/MediaSections/`
219
+ 2. Import from the old location instead of the package
220
+ 3. The old components will continue to work as before
221
+
222
+ ## Next Steps
223
+
224
+ 1. Test the package in a development environment
225
+ 2. Gradually migrate components one by one
226
+ 3. Once stable, consider removing old components
227
+ 4. Optionally publish to npm for use in other projects
228
+
229
+ ## Support
230
+
231
+ If you encounter issues during migration:
232
+
233
+ 1. Check the `EXAMPLE_USAGE.jsx` file
234
+ 2. Review the `README.md` for API documentation
235
+ 3. Ensure all peer dependencies are installed
236
+ 4. Verify your auth key and API base URL are correct
package/README.md ADDED
@@ -0,0 +1,292 @@
1
+ # @tradly/media-gallery
2
+
3
+ A reusable React component package for uploading and selecting media (images, videos, files) with Tradly authentication support.
4
+
5
+ ## Features
6
+
7
+ - 📸 Upload and browse images
8
+ - 🎥 Upload and browse videos
9
+ - 📁 Upload and browse files
10
+ - 🔐 Tradly authentication support
11
+ - 🎨 Customizable UI
12
+ - 📱 Responsive design
13
+ - 🔄 Pagination support
14
+ - ⚡ Lightweight and performant
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @tradly/media-gallery
20
+ # or
21
+ yarn add @tradly/media-gallery
22
+ ```
23
+
24
+ ## Peer Dependencies
25
+
26
+ This package requires the following peer dependencies:
27
+
28
+ - `react` (>=16.8.0)
29
+ - `react-dom` (>=16.8.0)
30
+ - `@headlessui/react` (^1.7.0) - for Tab components
31
+ - `axios` (^0.24.0) - for API calls
32
+
33
+ **Note:**
34
+
35
+ - All pagination logic is built-in, no external pagination library needed!
36
+ - No Tradly SDK dependency - uses direct API calls
37
+
38
+ ## Basic Usage
39
+
40
+ ```jsx
41
+ import React, { useState } from 'react'
42
+ import { MediaPopup, MediaApiService } from '@tradly/media-gallery'
43
+
44
+ function MyComponent() {
45
+ const [isOpen, setIsOpen] = useState(false)
46
+ const [selectedMedia, setSelectedMedia] = useState(null)
47
+
48
+ // Initialize API service with your auth key
49
+ // API base URL is automatically detected from ENVIRONMENT:
50
+ // - Dev: https://api.dev.tradly.app
51
+ // - Prod: https://api.tradly.app
52
+ const apiService = new MediaApiService({
53
+ authKey: 'your-tradly-auth-key', // Required: X-Auth-Key header
54
+ bearerToken: 'your-bearer-token', // Required: Bearer token for Authorization header
55
+ // environment is auto-detected from process.env.ENVIRONMENT
56
+ // apiBaseUrl is auto-set based on environment (can be overridden)
57
+ })
58
+
59
+ const handleSelect = (mediaUrl) => {
60
+ setSelectedMedia(mediaUrl)
61
+ setIsOpen(false)
62
+ }
63
+
64
+ return (
65
+ <>
66
+ <button onClick={() => setIsOpen(true)}>Open Media Gallery</button>
67
+
68
+ <MediaPopup
69
+ isOpen={isOpen}
70
+ onClose={() => setIsOpen(false)}
71
+ onSelect={handleSelect}
72
+ options={['image', 'video']} // Options: 'image', 'video', 'file'
73
+ apiService={apiService}
74
+ />
75
+ </>
76
+ )
77
+ }
78
+ ```
79
+
80
+ ## Advanced Usage
81
+
82
+ ### Upload Functionality
83
+
84
+ The package includes complete upload functionality using direct API calls. All upload logic is handled internally:
85
+
86
+ 1. **Get S3 signed URLs** via API call to `/v1/utils/S3signedUploadURL`
87
+ 2. **Upload files to S3** using the signed URLs
88
+ 3. **Save media metadata** to your API
89
+
90
+ Configuration:
91
+
92
+ ```jsx
93
+ import { MediaApiService } from '@tradly/media-gallery'
94
+
95
+ const apiService = new MediaApiService({
96
+ authKey: 'your-auth-key', // Required: X-Auth-Key header
97
+ bearerToken: 'your-bearer-token', // Required: Bearer token for Authorization header
98
+ environment: 'dev', // Optional: 'dev' or 'production' (auto-detected from process.env.ENVIRONMENT)
99
+ apiBaseUrl: 'https://api.tradly.app', // Optional: Override auto-detected base URL
100
+ })
101
+ ```
102
+
103
+ **API Base URL Auto-Detection:**
104
+
105
+ - If `environment` includes 'dev' → `https://api.dev.tradly.app`
106
+ - Otherwise → `https://api.tradly.app`
107
+ - You can override by providing `apiBaseUrl` explicitly
108
+
109
+ ### Using Individual Components
110
+
111
+ You can also use the components individually:
112
+
113
+ ```jsx
114
+ import { ImagesGallery, MediaApiService } from '@tradly/media-gallery'
115
+
116
+ function CustomGallery() {
117
+ const apiService = new MediaApiService({
118
+ authKey: 'your-auth-key',
119
+ baseUrl: '/api',
120
+ })
121
+
122
+ return (
123
+ <ImagesGallery
124
+ update_data={(url) => console.log('Selected:', url)}
125
+ closePopup={() => console.log('Closed')}
126
+ apiService={apiService}
127
+ />
128
+ )
129
+ }
130
+ ```
131
+
132
+ ### Error Handling
133
+
134
+ ```jsx
135
+ <MediaPopup
136
+ isOpen={isOpen}
137
+ onClose={() => setIsOpen(false)}
138
+ onSelect={handleSelect}
139
+ apiService={apiService}
140
+ onError={(error) => {
141
+ console.error('Media gallery error:', error)
142
+ // Handle error (show toast, etc.)
143
+ }}
144
+ />
145
+ ```
146
+
147
+ ## API Service Configuration
148
+
149
+ ### MediaApiService Options
150
+
151
+ ```jsx
152
+ const apiService = new MediaApiService({
153
+ authKey: 'string', // Required: Authentication key for X-Auth-Key header
154
+ bearerToken: 'string', // Required: Bearer token for Authorization header
155
+ environment: 'string', // Optional: 'dev' or 'production' (auto-detected from process.env.ENVIRONMENT)
156
+ apiBaseUrl: 'string', // Optional: Override auto-detected base URL (defaults: https://api.dev.tradly.app for dev, https://api.tradly.app for prod)
157
+ onError: (error) => {}, // Optional: Global error handler
158
+ })
159
+ ```
160
+
161
+ ### Methods
162
+
163
+ ```jsx
164
+ // Update auth key
165
+ apiService.setAuthKey('new-auth-key')
166
+
167
+ // Update API base URL (used for all API calls)
168
+ apiService.setApiBaseUrl('https://api.tradly.app')
169
+
170
+ // Set Bearer token
171
+ apiService.setBearerToken('new-bearer-token')
172
+ ```
173
+
174
+ ## Props
175
+
176
+ ### MediaPopup Props
177
+
178
+ | Prop | Type | Default | Description |
179
+ | ------------- | ----------------- | ----------------- | --------------------------------------------------- |
180
+ | `isOpen` | `boolean` | `false` | Controls popup visibility |
181
+ | `onClose` | `function` | - | Callback when popup closes |
182
+ | `onSelect` | `function` | - | Callback when media is selected |
183
+ | `currentData` | `any` | - | Currently selected media data |
184
+ | `options` | `array` | `['image']` | Media types to show: `'image'`, `'video'`, `'file'` |
185
+ | `apiService` | `MediaApiService` | - | **Required**: API service instance |
186
+ | `onError` | `function` | - | Error handler callback |
187
+ | `title` | `string` | `'Media Gallery'` | Popup title |
188
+
189
+ ## Styling
190
+
191
+ This package uses Tailwind CSS classes and supports full customization at every component level. All components accept `className` props that allow you to override default styles.
192
+
193
+ ### Quick Customization Example
194
+
195
+ ```jsx
196
+ <MediaPopup
197
+ isOpen={isOpen}
198
+ onClose={() => setIsOpen(false)}
199
+ onSelect={handleSelect}
200
+ apiService={apiService}
201
+ // Customize popup
202
+ overlayClassName="bg-black/60 backdrop-blur-sm"
203
+ containerClassName="max-w-4xl bg-gray-900 rounded-xl"
204
+ titleClassName="text-2xl font-bold text-white"
205
+ // Customize tabs
206
+ tabButtonActiveClassName="text-blue-400 border-b-2 border-blue-400"
207
+ // Customize gallery
208
+ gridClassName="grid grid-cols-4 gap-4"
209
+ imageItemClassName="rounded-lg border-2 hover:border-blue-500"
210
+ />
211
+ ```
212
+
213
+ ### Available Styling Props
214
+
215
+ **MediaPopup:**
216
+
217
+ - `overlayClassName` - Overlay/backdrop
218
+ - `containerClassName` - Main popup container
219
+ - `headerClassName` - Header container
220
+ - `titleClassName` - Title text
221
+ - `closeButtonClassName` - Close button
222
+ - `tabListClassName` - Tab list (passed to MediaTab)
223
+ - `tabButtonClassName` - Base tab button
224
+ - `tabButtonActiveClassName` - Active tab button
225
+ - `tabButtonInactiveClassName` - Inactive tab button
226
+ - `gridClassName` - Media grid layout
227
+ - `imageItemClassName` - Image item styles
228
+ - `videoItemClassName` - Video item styles
229
+ - `paginationContainerClassName` - Pagination container
230
+
231
+ **Individual Components:**
232
+ You can also style individual components when using them separately. See `STYLING_GUIDE.md` for complete documentation.
233
+
234
+ ### Full Styling Guide
235
+
236
+ For detailed styling documentation with examples, see [STYLING_GUIDE.md](./STYLING_GUIDE.md).
237
+
238
+ ## Examples
239
+
240
+ ### Image Only Gallery
241
+
242
+ ```jsx
243
+ <MediaPopup
244
+ isOpen={isOpen}
245
+ onClose={() => setIsOpen(false)}
246
+ onSelect={handleSelect}
247
+ options={['image']}
248
+ apiService={apiService}
249
+ />
250
+ ```
251
+
252
+ ### Video Only Gallery
253
+
254
+ ```jsx
255
+ <MediaPopup
256
+ isOpen={isOpen}
257
+ onClose={() => setIsOpen(false)}
258
+ onSelect={handleSelect}
259
+ options={['video']}
260
+ apiService={apiService}
261
+ />
262
+ ```
263
+
264
+ ### All Media Types
265
+
266
+ ```jsx
267
+ <MediaPopup
268
+ isOpen={isOpen}
269
+ onClose={() => setIsOpen(false)}
270
+ onSelect={handleSelect}
271
+ options={['image', 'video', 'file']}
272
+ apiService={apiService}
273
+ />
274
+ ```
275
+
276
+ ## Development
277
+
278
+ To develop or modify this package:
279
+
280
+ ```bash
281
+ cd packages/media-gallery
282
+ npm install
283
+ npm run dev
284
+ ```
285
+
286
+ ## License
287
+
288
+ MIT
289
+
290
+ ## Support
291
+
292
+ For issues and questions, please open an issue on the repository.