@mgonza02/goal-image-gallery 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/IMPLEMENTATION_SUMMARY.md +259 -0
- package/LICENSE +21 -0
- package/MIGRATION.md +428 -0
- package/QUICK_REFERENCE.md +235 -0
- package/README.md +479 -0
- package/lib/GoalImageGallery.js +244 -0
- package/lib/components/ImageGalleryEmptyState.js +87 -0
- package/lib/components/ImageGalleryGrid.js +108 -0
- package/lib/components/ImageGalleryItem.js +175 -0
- package/lib/components/ImageGalleryModal.js +149 -0
- package/lib/components/index.js +5 -0
- package/lib/examples.js +503 -0
- package/lib/hooks/use-image-gallery.js +252 -0
- package/lib/index.d.ts +187 -0
- package/lib/index.js +148 -0
- package/lib/styles/styled-components.js +173 -0
- package/lib/utils/image-utils.js +129 -0
- package/package.json +93 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Modal, Zoom, Backdrop, Typography, IconButton, Stack, Chip, Tooltip, Box, useMediaQuery, useTheme } from '@mui/material';
|
|
4
|
+
import { Close as CloseIcon, ZoomIn as ZoomInIcon, ZoomOut as ZoomOutIcon, ChevronLeft as ChevronLeftIcon, ChevronRight as ChevronRightIcon } from '@mui/icons-material';
|
|
5
|
+
import { StyledModalContainer, StyledModalHeader, StyledModalBody, StyledModalFooter } from '../styles/styled-components';
|
|
6
|
+
import { handleImageError } from '../utils/image-utils';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Image modal component for full-screen image viewing
|
|
10
|
+
*/
|
|
11
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
const ImageGalleryModal = _ref => {
|
|
13
|
+
let {
|
|
14
|
+
open,
|
|
15
|
+
imageUrl,
|
|
16
|
+
imageList,
|
|
17
|
+
selectedImageIndex,
|
|
18
|
+
zoomLevel,
|
|
19
|
+
noImageUrl,
|
|
20
|
+
onClose,
|
|
21
|
+
onZoomIn,
|
|
22
|
+
onZoomOut,
|
|
23
|
+
onPreviousImage,
|
|
24
|
+
onNextImage
|
|
25
|
+
} = _ref;
|
|
26
|
+
const theme = useTheme();
|
|
27
|
+
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
|
28
|
+
return /*#__PURE__*/_jsx(Modal, {
|
|
29
|
+
open: open,
|
|
30
|
+
onClose: onClose,
|
|
31
|
+
closeAfterTransition: true,
|
|
32
|
+
slots: {
|
|
33
|
+
backdrop: Backdrop
|
|
34
|
+
},
|
|
35
|
+
slotProps: {
|
|
36
|
+
backdrop: {
|
|
37
|
+
timeout: 500,
|
|
38
|
+
sx: {
|
|
39
|
+
backgroundColor: 'rgba(0, 0, 0, 0.9)'
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
children: /*#__PURE__*/_jsx(Zoom, {
|
|
44
|
+
in: open,
|
|
45
|
+
children: /*#__PURE__*/_jsxs(StyledModalContainer, {
|
|
46
|
+
isMobile: isMobile,
|
|
47
|
+
children: [/*#__PURE__*/_jsxs(StyledModalHeader, {
|
|
48
|
+
children: [/*#__PURE__*/_jsxs(Typography, {
|
|
49
|
+
variant: "h6",
|
|
50
|
+
children: ["Imagen ", selectedImageIndex + 1, " de ", imageList.length]
|
|
51
|
+
}), /*#__PURE__*/_jsxs(Stack, {
|
|
52
|
+
direction: "row",
|
|
53
|
+
spacing: 1,
|
|
54
|
+
children: [/*#__PURE__*/_jsx(Tooltip, {
|
|
55
|
+
title: "Alejar",
|
|
56
|
+
children: /*#__PURE__*/_jsx(IconButton, {
|
|
57
|
+
onClick: onZoomOut,
|
|
58
|
+
disabled: zoomLevel <= 0.5,
|
|
59
|
+
children: /*#__PURE__*/_jsx(ZoomOutIcon, {})
|
|
60
|
+
})
|
|
61
|
+
}), /*#__PURE__*/_jsx(Chip, {
|
|
62
|
+
label: `${Math.round(zoomLevel * 100)}%`,
|
|
63
|
+
variant: "outlined",
|
|
64
|
+
size: "small"
|
|
65
|
+
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
66
|
+
title: "Acercar",
|
|
67
|
+
children: /*#__PURE__*/_jsx(IconButton, {
|
|
68
|
+
onClick: onZoomIn,
|
|
69
|
+
disabled: zoomLevel >= 3,
|
|
70
|
+
children: /*#__PURE__*/_jsx(ZoomInIcon, {})
|
|
71
|
+
})
|
|
72
|
+
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
73
|
+
title: "Cerrar",
|
|
74
|
+
children: /*#__PURE__*/_jsx(IconButton, {
|
|
75
|
+
onClick: onClose,
|
|
76
|
+
children: /*#__PURE__*/_jsx(CloseIcon, {})
|
|
77
|
+
})
|
|
78
|
+
})]
|
|
79
|
+
})]
|
|
80
|
+
}), /*#__PURE__*/_jsx(StyledModalBody, {
|
|
81
|
+
children: /*#__PURE__*/_jsx(Box, {
|
|
82
|
+
sx: {
|
|
83
|
+
width: '100%',
|
|
84
|
+
height: '100%',
|
|
85
|
+
display: 'flex',
|
|
86
|
+
alignItems: 'center',
|
|
87
|
+
justifyContent: 'center',
|
|
88
|
+
overflow: zoomLevel > 1 ? 'auto' : 'hidden',
|
|
89
|
+
p: 2
|
|
90
|
+
},
|
|
91
|
+
children: /*#__PURE__*/_jsx("img", {
|
|
92
|
+
src: imageUrl,
|
|
93
|
+
alt: "Imagen completa",
|
|
94
|
+
style: {
|
|
95
|
+
maxWidth: '100%',
|
|
96
|
+
maxHeight: '100%',
|
|
97
|
+
width: 'auto',
|
|
98
|
+
height: 'auto',
|
|
99
|
+
objectFit: 'contain',
|
|
100
|
+
transform: `scale(${zoomLevel})`,
|
|
101
|
+
transition: 'transform 0.2s ease-in-out',
|
|
102
|
+
borderRadius: 8,
|
|
103
|
+
display: 'block'
|
|
104
|
+
},
|
|
105
|
+
onError: e => handleImageError(e, noImageUrl)
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
}), imageList.length > 1 && /*#__PURE__*/_jsxs(StyledModalFooter, {
|
|
109
|
+
children: [/*#__PURE__*/_jsx(Tooltip, {
|
|
110
|
+
title: "Imagen anterior",
|
|
111
|
+
children: /*#__PURE__*/_jsx(IconButton, {
|
|
112
|
+
onClick: onPreviousImage,
|
|
113
|
+
disabled: imageList.length <= 1,
|
|
114
|
+
children: /*#__PURE__*/_jsx(ChevronLeftIcon, {})
|
|
115
|
+
})
|
|
116
|
+
}), /*#__PURE__*/_jsx(Typography, {
|
|
117
|
+
variant: "body2",
|
|
118
|
+
color: "text.secondary",
|
|
119
|
+
children: "Use las flechas del teclado para navegar"
|
|
120
|
+
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
121
|
+
title: "Imagen siguiente",
|
|
122
|
+
children: /*#__PURE__*/_jsx(IconButton, {
|
|
123
|
+
onClick: onNextImage,
|
|
124
|
+
disabled: imageList.length <= 1,
|
|
125
|
+
children: /*#__PURE__*/_jsx(ChevronRightIcon, {})
|
|
126
|
+
})
|
|
127
|
+
})]
|
|
128
|
+
})]
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
ImageGalleryModal.propTypes = {
|
|
134
|
+
open: PropTypes.bool.isRequired,
|
|
135
|
+
imageUrl: PropTypes.string,
|
|
136
|
+
imageList: PropTypes.array.isRequired,
|
|
137
|
+
selectedImageIndex: PropTypes.number.isRequired,
|
|
138
|
+
zoomLevel: PropTypes.number.isRequired,
|
|
139
|
+
noImageUrl: PropTypes.string.isRequired,
|
|
140
|
+
onClose: PropTypes.func.isRequired,
|
|
141
|
+
onZoomIn: PropTypes.func.isRequired,
|
|
142
|
+
onZoomOut: PropTypes.func.isRequired,
|
|
143
|
+
onPreviousImage: PropTypes.func.isRequired,
|
|
144
|
+
onNextImage: PropTypes.func.isRequired
|
|
145
|
+
};
|
|
146
|
+
ImageGalleryModal.defaultProps = {
|
|
147
|
+
imageUrl: null
|
|
148
|
+
};
|
|
149
|
+
export default ImageGalleryModal;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Components index for easy importing
|
|
2
|
+
export { default as ImageGalleryGrid } from './ImageGalleryGrid';
|
|
3
|
+
export { default as ImageGalleryModal } from './ImageGalleryModal';
|
|
4
|
+
export { default as ImageGalleryItem } from './ImageGalleryItem';
|
|
5
|
+
export { default as ImageGalleryEmptyState } from './ImageGalleryEmptyState';
|
package/lib/examples.js
ADDED
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
// GoalImageGallery Usage Examples
|
|
2
|
+
// This file demonstrates various ways to use the GoalImageGallery component
|
|
3
|
+
|
|
4
|
+
import React, { useState, useCallback } from 'react';
|
|
5
|
+
import { Box, Typography, Button, Divider } from '@mui/material';
|
|
6
|
+
import GoalImageGallery from './GoalImageGallery';
|
|
7
|
+
|
|
8
|
+
// Example 1: Basic Read-Only Gallery
|
|
9
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
|
+
export const BasicGalleryExample = () => {
|
|
11
|
+
const imageCodes = ['img1', 'img2', 'img3', 'img4'];
|
|
12
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
13
|
+
sx: {
|
|
14
|
+
p: 2
|
|
15
|
+
},
|
|
16
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
17
|
+
variant: "h6",
|
|
18
|
+
gutterBottom: true,
|
|
19
|
+
children: "Basic Read-Only Gallery"
|
|
20
|
+
}), /*#__PURE__*/_jsx(GoalImageGallery, {
|
|
21
|
+
imageCodes: imageCodes,
|
|
22
|
+
canEdit: false,
|
|
23
|
+
emptyMessage: "No images to display"
|
|
24
|
+
})]
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Example 2: Editable Product Gallery
|
|
29
|
+
export const ProductGalleryExample = () => {
|
|
30
|
+
const [productImages, setProductImages] = useState(['prod1', 'prod2']);
|
|
31
|
+
const currentCompany = 'default-company';
|
|
32
|
+
const hasPermission = perm => true; // Mock permission check
|
|
33
|
+
|
|
34
|
+
const handleImageUpload = useCallback(async imageData => {
|
|
35
|
+
try {
|
|
36
|
+
// Mock API call
|
|
37
|
+
const response = await new Promise(resolve => {
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
resolve({
|
|
40
|
+
success: true,
|
|
41
|
+
data: {
|
|
42
|
+
code: `img-${Date.now()}`
|
|
43
|
+
},
|
|
44
|
+
message: 'Product images uploaded successfully'
|
|
45
|
+
});
|
|
46
|
+
}, 1000);
|
|
47
|
+
});
|
|
48
|
+
return response;
|
|
49
|
+
} catch (error) {
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
message: error.message
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}, [currentCompany]);
|
|
56
|
+
const refreshProduct = useCallback(result => {
|
|
57
|
+
// Refresh product data after upload
|
|
58
|
+
console.log('Product updated:', result);
|
|
59
|
+
}, []);
|
|
60
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
61
|
+
sx: {
|
|
62
|
+
p: 2
|
|
63
|
+
},
|
|
64
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
65
|
+
variant: "h6",
|
|
66
|
+
gutterBottom: true,
|
|
67
|
+
children: "Product Gallery (Editable)"
|
|
68
|
+
}), /*#__PURE__*/_jsx(GoalImageGallery, {
|
|
69
|
+
imageCodes: productImages,
|
|
70
|
+
canEdit: hasPermission('EDIT_PRODUCTS'),
|
|
71
|
+
ownerEntity: {
|
|
72
|
+
id: 'product-123',
|
|
73
|
+
type: 'product'
|
|
74
|
+
},
|
|
75
|
+
imageHandlerApi: handleImageUpload,
|
|
76
|
+
afterUpload: refreshProduct,
|
|
77
|
+
multiple: true,
|
|
78
|
+
emptyMessage: "No product images available",
|
|
79
|
+
showImageInfo: true,
|
|
80
|
+
allowDownload: true,
|
|
81
|
+
hasPermission: hasPermission,
|
|
82
|
+
currentCompany: currentCompany
|
|
83
|
+
})]
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Example 3: User Avatar Gallery
|
|
88
|
+
export const UserAvatarExample = () => {
|
|
89
|
+
const [userAvatar, setUserAvatar] = useState('avatar-001');
|
|
90
|
+
const {
|
|
91
|
+
account
|
|
92
|
+
} = useAuth();
|
|
93
|
+
const handleAvatarUpload = useCallback(async imageData => {
|
|
94
|
+
try {
|
|
95
|
+
const response = await goalMediaApi.submitImage({
|
|
96
|
+
values: {
|
|
97
|
+
...imageData,
|
|
98
|
+
application: 'USER_AVATAR',
|
|
99
|
+
folder: 'avatars',
|
|
100
|
+
owner: account.userName
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
return {
|
|
104
|
+
success: true,
|
|
105
|
+
data: response.data,
|
|
106
|
+
message: 'Avatar updated successfully'
|
|
107
|
+
};
|
|
108
|
+
} catch (error) {
|
|
109
|
+
return {
|
|
110
|
+
success: false,
|
|
111
|
+
message: error.message
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}, [account]);
|
|
115
|
+
const refreshUser = useCallback(result => {
|
|
116
|
+
setUserAvatar(result.data.code);
|
|
117
|
+
}, []);
|
|
118
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
119
|
+
sx: {
|
|
120
|
+
p: 2
|
|
121
|
+
},
|
|
122
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
123
|
+
variant: "h6",
|
|
124
|
+
gutterBottom: true,
|
|
125
|
+
children: "User Avatar (Single Image)"
|
|
126
|
+
}), /*#__PURE__*/_jsx(GoalImageGallery, {
|
|
127
|
+
imageCodes: [userAvatar],
|
|
128
|
+
canEdit: true,
|
|
129
|
+
ownerEntity: {
|
|
130
|
+
id: account.id,
|
|
131
|
+
type: 'user'
|
|
132
|
+
},
|
|
133
|
+
imageHandlerApi: handleAvatarUpload,
|
|
134
|
+
afterUpload: refreshUser,
|
|
135
|
+
multiple: false,
|
|
136
|
+
emptyMessage: "No avatar set",
|
|
137
|
+
showImageInfo: false
|
|
138
|
+
})]
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// Example 4: Document Attachments Gallery
|
|
143
|
+
export const DocumentGalleryExample = () => {
|
|
144
|
+
const [documentImages, setDocumentImages] = useState([]);
|
|
145
|
+
const {
|
|
146
|
+
currentCompany
|
|
147
|
+
} = useApp();
|
|
148
|
+
const {
|
|
149
|
+
hasPermission
|
|
150
|
+
} = useAuth();
|
|
151
|
+
const handleDocumentImageUpload = useCallback(async imageData => {
|
|
152
|
+
try {
|
|
153
|
+
const response = await goalMediaApi.submitImage({
|
|
154
|
+
values: {
|
|
155
|
+
...imageData,
|
|
156
|
+
application: 'DOCUMENT_ATTACHMENTS',
|
|
157
|
+
folder: 'documents',
|
|
158
|
+
companyId: currentCompany
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
return {
|
|
162
|
+
success: true,
|
|
163
|
+
data: response.data,
|
|
164
|
+
message: 'Document images uploaded successfully'
|
|
165
|
+
};
|
|
166
|
+
} catch (error) {
|
|
167
|
+
return {
|
|
168
|
+
success: false,
|
|
169
|
+
message: error.message
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}, [currentCompany]);
|
|
173
|
+
const refreshDocument = useCallback(result => {
|
|
174
|
+
// Update document with new images
|
|
175
|
+
console.log('Document updated:', result);
|
|
176
|
+
}, []);
|
|
177
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
178
|
+
sx: {
|
|
179
|
+
p: 2
|
|
180
|
+
},
|
|
181
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
182
|
+
variant: "h6",
|
|
183
|
+
gutterBottom: true,
|
|
184
|
+
children: "Document Attachments Gallery"
|
|
185
|
+
}), /*#__PURE__*/_jsx(GoalImageGallery, {
|
|
186
|
+
imageCodes: documentImages,
|
|
187
|
+
canEdit: hasPermission('EDIT_DOCUMENTS'),
|
|
188
|
+
ownerEntity: {
|
|
189
|
+
id: 'doc-456',
|
|
190
|
+
type: 'document'
|
|
191
|
+
},
|
|
192
|
+
imageHandlerApi: handleDocumentImageUpload,
|
|
193
|
+
afterUpload: refreshDocument,
|
|
194
|
+
multiple: true,
|
|
195
|
+
permission: "EDIT_DOCUMENTS",
|
|
196
|
+
emptyMessage: "No document attachments",
|
|
197
|
+
showImageInfo: true,
|
|
198
|
+
allowDownload: true
|
|
199
|
+
})]
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// Example 5: Gallery with Custom Empty State
|
|
204
|
+
export const CustomEmptyStateExample = () => {
|
|
205
|
+
const [images, setImages] = useState([]);
|
|
206
|
+
const handleUpload = useCallback(async imageData => {
|
|
207
|
+
// Simulate API call
|
|
208
|
+
return new Promise(resolve => {
|
|
209
|
+
setTimeout(() => {
|
|
210
|
+
resolve({
|
|
211
|
+
success: true,
|
|
212
|
+
data: {
|
|
213
|
+
code: `img-${Date.now()}`
|
|
214
|
+
},
|
|
215
|
+
message: 'Image uploaded successfully'
|
|
216
|
+
});
|
|
217
|
+
}, 1000);
|
|
218
|
+
});
|
|
219
|
+
}, []);
|
|
220
|
+
const refreshImages = useCallback(result => {
|
|
221
|
+
setImages(prev => [...prev, result.data.code]);
|
|
222
|
+
}, []);
|
|
223
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
224
|
+
sx: {
|
|
225
|
+
p: 2
|
|
226
|
+
},
|
|
227
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
228
|
+
variant: "h6",
|
|
229
|
+
gutterBottom: true,
|
|
230
|
+
children: "Custom Empty State Gallery"
|
|
231
|
+
}), /*#__PURE__*/_jsx(GoalImageGallery, {
|
|
232
|
+
imageCodes: images,
|
|
233
|
+
canEdit: true,
|
|
234
|
+
ownerEntity: {
|
|
235
|
+
id: 'custom-gallery',
|
|
236
|
+
type: 'gallery'
|
|
237
|
+
},
|
|
238
|
+
imageHandlerApi: handleUpload,
|
|
239
|
+
afterUpload: refreshImages,
|
|
240
|
+
multiple: true,
|
|
241
|
+
emptyMessage: "Start building your gallery by adding images",
|
|
242
|
+
showImageInfo: true
|
|
243
|
+
})]
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// Example 6: Gallery with URL and Clipboard Support Demo
|
|
248
|
+
export const AdvancedUploadExample = () => {
|
|
249
|
+
const [images, setImages] = useState(['demo1', 'demo2']);
|
|
250
|
+
const handleAdvancedUpload = useCallback(async imageData => {
|
|
251
|
+
// Handle different upload methods
|
|
252
|
+
const uploadMethod = imageData.method || 'file';
|
|
253
|
+
console.log(`Uploading via ${uploadMethod}:`, imageData);
|
|
254
|
+
try {
|
|
255
|
+
const response = await goalMediaApi.submitImage({
|
|
256
|
+
values: {
|
|
257
|
+
...imageData,
|
|
258
|
+
application: 'ADVANCED_GALLERY',
|
|
259
|
+
folder: 'advanced',
|
|
260
|
+
uploadMethod
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
return {
|
|
264
|
+
success: true,
|
|
265
|
+
data: response.data,
|
|
266
|
+
message: `Image uploaded successfully via ${uploadMethod}`
|
|
267
|
+
};
|
|
268
|
+
} catch (error) {
|
|
269
|
+
return {
|
|
270
|
+
success: false,
|
|
271
|
+
message: error.message
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
}, []);
|
|
275
|
+
const refreshGallery = useCallback(result => {
|
|
276
|
+
setImages(prev => [...prev, result.data.code]);
|
|
277
|
+
}, []);
|
|
278
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
279
|
+
sx: {
|
|
280
|
+
p: 2
|
|
281
|
+
},
|
|
282
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
283
|
+
variant: "h6",
|
|
284
|
+
gutterBottom: true,
|
|
285
|
+
children: "Advanced Upload Methods Demo"
|
|
286
|
+
}), /*#__PURE__*/_jsx(Typography, {
|
|
287
|
+
variant: "body2",
|
|
288
|
+
color: "text.secondary",
|
|
289
|
+
paragraph: true,
|
|
290
|
+
children: "This gallery supports multiple upload methods:"
|
|
291
|
+
}), /*#__PURE__*/_jsxs("ul", {
|
|
292
|
+
children: [/*#__PURE__*/_jsx("li", {
|
|
293
|
+
children: "File upload: Click \"Add Image\" or drag & drop"
|
|
294
|
+
}), /*#__PURE__*/_jsx("li", {
|
|
295
|
+
children: "Clipboard paste: Copy an image and press Ctrl+V"
|
|
296
|
+
}), /*#__PURE__*/_jsx("li", {
|
|
297
|
+
children: "URL loading: Enter image URLs directly"
|
|
298
|
+
})]
|
|
299
|
+
}), /*#__PURE__*/_jsx(GoalImageGallery, {
|
|
300
|
+
imageCodes: images,
|
|
301
|
+
canEdit: true,
|
|
302
|
+
ownerEntity: {
|
|
303
|
+
id: 'advanced-gallery',
|
|
304
|
+
type: 'gallery'
|
|
305
|
+
},
|
|
306
|
+
imageHandlerApi: handleAdvancedUpload,
|
|
307
|
+
afterUpload: refreshGallery,
|
|
308
|
+
multiple: true,
|
|
309
|
+
emptyMessage: "Try all upload methods: file, clipboard, and URL",
|
|
310
|
+
showImageInfo: true,
|
|
311
|
+
allowDownload: true
|
|
312
|
+
})]
|
|
313
|
+
});
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
// Example 7: Mobile-Optimized Gallery
|
|
317
|
+
export const MobileGalleryExample = () => {
|
|
318
|
+
const [mobileImages, setMobileImages] = useState(['mobile1', 'mobile2', 'mobile3']);
|
|
319
|
+
const handleMobileUpload = useCallback(async imageData => {
|
|
320
|
+
// Optimize for mobile upload
|
|
321
|
+
const compressedData = {
|
|
322
|
+
...imageData,
|
|
323
|
+
quality: 0.8,
|
|
324
|
+
// Compress for mobile
|
|
325
|
+
maxWidth: 1200,
|
|
326
|
+
maxHeight: 1200
|
|
327
|
+
};
|
|
328
|
+
try {
|
|
329
|
+
const response = await goalMediaApi.submitImage({
|
|
330
|
+
values: {
|
|
331
|
+
...compressedData,
|
|
332
|
+
application: 'MOBILE_GALLERY',
|
|
333
|
+
folder: 'mobile'
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
return {
|
|
337
|
+
success: true,
|
|
338
|
+
data: response.data,
|
|
339
|
+
message: 'Mobile image uploaded successfully'
|
|
340
|
+
};
|
|
341
|
+
} catch (error) {
|
|
342
|
+
return {
|
|
343
|
+
success: false,
|
|
344
|
+
message: error.message
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
}, []);
|
|
348
|
+
const refreshMobileGallery = useCallback(result => {
|
|
349
|
+
setMobileImages(prev => [...prev, result.data.code]);
|
|
350
|
+
}, []);
|
|
351
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
352
|
+
sx: {
|
|
353
|
+
p: 2
|
|
354
|
+
},
|
|
355
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
356
|
+
variant: "h6",
|
|
357
|
+
gutterBottom: true,
|
|
358
|
+
children: "Mobile-Optimized Gallery"
|
|
359
|
+
}), /*#__PURE__*/_jsx(Typography, {
|
|
360
|
+
variant: "body2",
|
|
361
|
+
color: "text.secondary",
|
|
362
|
+
paragraph: true,
|
|
363
|
+
children: "Optimized for mobile devices with touch-friendly interface"
|
|
364
|
+
}), /*#__PURE__*/_jsx(GoalImageGallery, {
|
|
365
|
+
imageCodes: mobileImages,
|
|
366
|
+
canEdit: true,
|
|
367
|
+
ownerEntity: {
|
|
368
|
+
id: 'mobile-gallery',
|
|
369
|
+
type: 'gallery'
|
|
370
|
+
},
|
|
371
|
+
imageHandlerApi: handleMobileUpload,
|
|
372
|
+
afterUpload: refreshMobileGallery,
|
|
373
|
+
multiple: true,
|
|
374
|
+
emptyMessage: "Mobile gallery - tap to add images",
|
|
375
|
+
showImageInfo: false,
|
|
376
|
+
allowDownload: false
|
|
377
|
+
})]
|
|
378
|
+
});
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// Example 8: Full Example with State Management
|
|
382
|
+
export const FullExampleWithStateManagement = () => {
|
|
383
|
+
const [galleryState, setGalleryState] = useState({
|
|
384
|
+
images: ['state1', 'state2'],
|
|
385
|
+
loading: false,
|
|
386
|
+
error: null
|
|
387
|
+
});
|
|
388
|
+
const handleStateUpload = useCallback(async imageData => {
|
|
389
|
+
setGalleryState(prev => ({
|
|
390
|
+
...prev,
|
|
391
|
+
loading: true,
|
|
392
|
+
error: null
|
|
393
|
+
}));
|
|
394
|
+
try {
|
|
395
|
+
const response = await goalMediaApi.submitImage({
|
|
396
|
+
values: {
|
|
397
|
+
...imageData,
|
|
398
|
+
application: 'STATE_GALLERY',
|
|
399
|
+
folder: 'state-managed'
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
if (response.success) {
|
|
403
|
+
setGalleryState(prev => ({
|
|
404
|
+
...prev,
|
|
405
|
+
images: [...prev.images, response.data.code],
|
|
406
|
+
loading: false
|
|
407
|
+
}));
|
|
408
|
+
return {
|
|
409
|
+
success: true,
|
|
410
|
+
data: response.data,
|
|
411
|
+
message: 'Image uploaded and state updated'
|
|
412
|
+
};
|
|
413
|
+
} else {
|
|
414
|
+
throw new Error(response.message);
|
|
415
|
+
}
|
|
416
|
+
} catch (error) {
|
|
417
|
+
setGalleryState(prev => ({
|
|
418
|
+
...prev,
|
|
419
|
+
loading: false,
|
|
420
|
+
error: error.message
|
|
421
|
+
}));
|
|
422
|
+
return {
|
|
423
|
+
success: false,
|
|
424
|
+
message: error.message
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
}, []);
|
|
428
|
+
const refreshWithState = useCallback(result => {
|
|
429
|
+
// State is managed in the upload handler
|
|
430
|
+
console.log('Gallery state updated:', result);
|
|
431
|
+
}, []);
|
|
432
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
433
|
+
sx: {
|
|
434
|
+
p: 2
|
|
435
|
+
},
|
|
436
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
437
|
+
variant: "h6",
|
|
438
|
+
gutterBottom: true,
|
|
439
|
+
children: "Full Example with State Management"
|
|
440
|
+
}), galleryState.error && /*#__PURE__*/_jsxs(Typography, {
|
|
441
|
+
color: "error",
|
|
442
|
+
variant: "body2",
|
|
443
|
+
paragraph: true,
|
|
444
|
+
children: ["Error: ", galleryState.error]
|
|
445
|
+
}), /*#__PURE__*/_jsx(GoalImageGallery, {
|
|
446
|
+
imageCodes: galleryState.images,
|
|
447
|
+
canEdit: true,
|
|
448
|
+
ownerEntity: {
|
|
449
|
+
id: 'state-gallery',
|
|
450
|
+
type: 'gallery'
|
|
451
|
+
},
|
|
452
|
+
imageHandlerApi: handleStateUpload,
|
|
453
|
+
afterUpload: refreshWithState,
|
|
454
|
+
multiple: true,
|
|
455
|
+
emptyMessage: "State-managed gallery - add images to see state updates",
|
|
456
|
+
showImageInfo: true,
|
|
457
|
+
allowDownload: true
|
|
458
|
+
})]
|
|
459
|
+
});
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
// Complete Demo Component
|
|
463
|
+
export const GoalImageGalleryExamples = () => {
|
|
464
|
+
return /*#__PURE__*/_jsxs(Box, {
|
|
465
|
+
sx: {
|
|
466
|
+
p: 3
|
|
467
|
+
},
|
|
468
|
+
children: [/*#__PURE__*/_jsx(Typography, {
|
|
469
|
+
variant: "h4",
|
|
470
|
+
gutterBottom: true,
|
|
471
|
+
children: "GoalImageGallery Examples"
|
|
472
|
+
}), /*#__PURE__*/_jsx(BasicGalleryExample, {}), /*#__PURE__*/_jsx(Divider, {
|
|
473
|
+
sx: {
|
|
474
|
+
my: 3
|
|
475
|
+
}
|
|
476
|
+
}), /*#__PURE__*/_jsx(ProductGalleryExample, {}), /*#__PURE__*/_jsx(Divider, {
|
|
477
|
+
sx: {
|
|
478
|
+
my: 3
|
|
479
|
+
}
|
|
480
|
+
}), /*#__PURE__*/_jsx(UserAvatarExample, {}), /*#__PURE__*/_jsx(Divider, {
|
|
481
|
+
sx: {
|
|
482
|
+
my: 3
|
|
483
|
+
}
|
|
484
|
+
}), /*#__PURE__*/_jsx(DocumentGalleryExample, {}), /*#__PURE__*/_jsx(Divider, {
|
|
485
|
+
sx: {
|
|
486
|
+
my: 3
|
|
487
|
+
}
|
|
488
|
+
}), /*#__PURE__*/_jsx(CustomEmptyStateExample, {}), /*#__PURE__*/_jsx(Divider, {
|
|
489
|
+
sx: {
|
|
490
|
+
my: 3
|
|
491
|
+
}
|
|
492
|
+
}), /*#__PURE__*/_jsx(AdvancedUploadExample, {}), /*#__PURE__*/_jsx(Divider, {
|
|
493
|
+
sx: {
|
|
494
|
+
my: 3
|
|
495
|
+
}
|
|
496
|
+
}), /*#__PURE__*/_jsx(MobileGalleryExample, {}), /*#__PURE__*/_jsx(Divider, {
|
|
497
|
+
sx: {
|
|
498
|
+
my: 3
|
|
499
|
+
}
|
|
500
|
+
}), /*#__PURE__*/_jsx(FullExampleWithStateManagement, {})]
|
|
501
|
+
});
|
|
502
|
+
};
|
|
503
|
+
export default GoalImageGalleryExamples;
|