@udhuong/admin-core 0.1.8 → 0.2.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/dist/client/components/media/FolderTree.d.ts +13 -0
- package/dist/client/components/media/FolderTree.d.ts.map +1 -0
- package/dist/client/components/media/FolderTree.js +50 -0
- package/dist/client/components/media/FolderTree.js.map +1 -0
- package/dist/client/components/media/MediaBrowser.d.ts +8 -0
- package/dist/client/components/media/MediaBrowser.d.ts.map +1 -0
- package/dist/client/components/media/MediaBrowser.js +210 -0
- package/dist/client/components/media/MediaBrowser.js.map +1 -0
- package/dist/client/components/media/MediaGrid.d.ts +11 -0
- package/dist/client/components/media/MediaGrid.d.ts.map +1 -0
- package/dist/client/components/media/MediaGrid.js +67 -0
- package/dist/client/components/media/MediaGrid.js.map +1 -0
- package/dist/client/components/media/MediaPicker.d.ts +12 -0
- package/dist/client/components/media/MediaPicker.d.ts.map +1 -0
- package/dist/client/components/media/MediaPicker.js +154 -0
- package/dist/client/components/media/MediaPicker.js.map +1 -0
- package/dist/client/components/media/MediaUpload.d.ts +9 -0
- package/dist/client/components/media/MediaUpload.d.ts.map +1 -0
- package/dist/client/components/media/MediaUpload.js +98 -0
- package/dist/client/components/media/MediaUpload.js.map +1 -0
- package/dist/client/components/media/index.d.ts +6 -0
- package/dist/client/components/media/index.d.ts.map +1 -0
- package/dist/client/components/media/index.js +6 -0
- package/dist/client/components/media/index.js.map +1 -0
- package/dist/client/constants/api-routes.d.ts +9 -0
- package/dist/client/constants/api-routes.d.ts.map +1 -1
- package/dist/client/constants/api-routes.js +10 -0
- package/dist/client/constants/api-routes.js.map +1 -1
- package/dist/client/index.d.ts +5 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +6 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/lib/ckeditor-upload-adapter.d.ts +8 -0
- package/dist/client/lib/ckeditor-upload-adapter.d.ts.map +1 -0
- package/dist/client/lib/ckeditor-upload-adapter.js +75 -0
- package/dist/client/lib/ckeditor-upload-adapter.js.map +1 -0
- package/dist/client/pages/MediaPage.d.ts +2 -0
- package/dist/client/pages/MediaPage.d.ts.map +1 -0
- package/dist/client/pages/MediaPage.js +303 -0
- package/dist/client/pages/MediaPage.js.map +1 -0
- package/dist/client/pages/index.d.ts +1 -0
- package/dist/client/pages/index.d.ts.map +1 -1
- package/dist/client/pages/index.js +1 -0
- package/dist/client/pages/index.js.map +1 -1
- package/dist/client/types/media.d.ts +57 -0
- package/dist/client/types/media.d.ts.map +1 -0
- package/dist/client/types/media.js +10 -0
- package/dist/client/types/media.js.map +1 -0
- package/dist/server/admin-core-options.interface.d.ts +13 -0
- package/dist/server/admin-core-options.interface.d.ts.map +1 -1
- package/dist/server/admin-core-options.interface.js.map +1 -1
- package/dist/server/admin-core.module.d.ts.map +1 -1
- package/dist/server/admin-core.module.js +9 -1
- package/dist/server/admin-core.module.js.map +1 -1
- package/dist/server/index.d.ts +7 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +19 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/media/application/services/media.service.d.ts +134 -0
- package/dist/server/media/application/services/media.service.d.ts.map +1 -0
- package/dist/server/media/application/services/media.service.js +357 -0
- package/dist/server/media/application/services/media.service.js.map +1 -0
- package/dist/server/media/application/services/minio.service.d.ts +24 -0
- package/dist/server/media/application/services/minio.service.d.ts.map +1 -0
- package/dist/server/media/application/services/minio.service.js +175 -0
- package/dist/server/media/application/services/minio.service.js.map +1 -0
- package/dist/server/media/domain/enums/media-type.enum.d.ts +15 -0
- package/dist/server/media/domain/enums/media-type.enum.d.ts.map +1 -0
- package/dist/server/media/domain/enums/media-type.enum.js +19 -0
- package/dist/server/media/domain/enums/media-type.enum.js.map +1 -0
- package/dist/server/media/infrastructure/persistence/entities/media.entity.d.ts +30 -0
- package/dist/server/media/infrastructure/persistence/entities/media.entity.d.ts.map +1 -0
- package/dist/server/media/infrastructure/persistence/entities/media.entity.js +149 -0
- package/dist/server/media/infrastructure/persistence/entities/media.entity.js.map +1 -0
- package/dist/server/media/media.module.d.ts +3 -0
- package/dist/server/media/media.module.d.ts.map +1 -0
- package/dist/server/media/media.module.js +27 -0
- package/dist/server/media/media.module.js.map +1 -0
- package/dist/server/media/presentation/controllers/media.controller.d.ts +62 -0
- package/dist/server/media/presentation/controllers/media.controller.d.ts.map +1 -0
- package/dist/server/media/presentation/controllers/media.controller.js +185 -0
- package/dist/server/media/presentation/controllers/media.controller.js.map +1 -0
- package/dist/server/media/presentation/dto/media.dto.d.ts +38 -0
- package/dist/server/media/presentation/dto/media.dto.d.ts.map +1 -0
- package/dist/server/media/presentation/dto/media.dto.js +184 -0
- package/dist/server/media/presentation/dto/media.dto.js.map +1 -0
- package/dist/server/shared/permissions.d.ts +24 -0
- package/dist/server/shared/permissions.d.ts.map +1 -1
- package/dist/server/shared/permissions.js +24 -0
- package/dist/server/shared/permissions.js.map +1 -1
- package/package.json +11 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { MediaFolder } from '../../types/media';
|
|
2
|
+
interface FolderTreeProps {
|
|
3
|
+
folders: MediaFolder[];
|
|
4
|
+
selectedFolderId?: number;
|
|
5
|
+
showAllMedia?: boolean;
|
|
6
|
+
onSelectFolder: (folderId: number | undefined) => void;
|
|
7
|
+
onShowAllMedia?: () => void;
|
|
8
|
+
onCreateFolder?: (name: string, parentId?: number) => void;
|
|
9
|
+
onDeleteFolder?: (id: number) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function FolderTree({ folders, selectedFolderId, showAllMedia, onSelectFolder, onShowAllMedia, onCreateFolder, onDeleteFolder, }: FolderTreeProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=FolderTree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FolderTree.d.ts","sourceRoot":"","sources":["../../../../src/client/components/media/FolderTree.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,UAAU,eAAe;IACvB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACvD,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,gBAAgB,EAChB,YAAoB,EACpB,cAAc,EACd,cAAc,EACd,cAAc,EACd,cAAc,GACf,EAAE,eAAe,2CA+KjB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Folder, FolderPlus, Trash2, Images } from 'lucide-react';
|
|
5
|
+
export function FolderTree({ folders, selectedFolderId, showAllMedia = false, onSelectFolder, onShowAllMedia, onCreateFolder, onDeleteFolder, }) {
|
|
6
|
+
const [expandedFolders, setExpandedFolders] = useState([]);
|
|
7
|
+
const [showNewFolder, setShowNewFolder] = useState(false);
|
|
8
|
+
const [newFolderName, setNewFolderName] = useState('');
|
|
9
|
+
const [newFolderParent, setNewFolderParent] = useState();
|
|
10
|
+
const toggleFolder = (folderId) => {
|
|
11
|
+
setExpandedFolders((prev) => prev.includes(folderId)
|
|
12
|
+
? prev.filter((id) => id !== folderId)
|
|
13
|
+
: [...prev, folderId]);
|
|
14
|
+
};
|
|
15
|
+
const handleCreateFolder = () => {
|
|
16
|
+
if (newFolderName.trim()) {
|
|
17
|
+
onCreateFolder?.(newFolderName, newFolderParent);
|
|
18
|
+
setNewFolderName('');
|
|
19
|
+
setShowNewFolder(false);
|
|
20
|
+
setNewFolderParent(undefined);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const rootFolders = folders.filter((f) => !f.parentId);
|
|
24
|
+
const renderFolder = (folder, level = 0) => {
|
|
25
|
+
const hasChildren = folders.some((f) => f.parentId === folder.id);
|
|
26
|
+
const isExpanded = expandedFolders.includes(folder.id);
|
|
27
|
+
const isSelected = selectedFolderId === folder.id;
|
|
28
|
+
return (_jsxs("div", { children: [_jsxs("div", { className: `flex items-center gap-2 px-3 py-2 hover:bg-base-200 cursor-pointer rounded-lg transition-colors ${isSelected ? 'bg-primary/10' : ''}`, style: { paddingLeft: `${level * 1.5 + 0.75}rem` }, children: [hasChildren && (_jsx("button", { onClick: () => toggleFolder(folder.id), className: "w-4 h-4 flex items-center justify-center", children: isExpanded ? '▼' : '▶' })), !hasChildren && _jsx("div", { className: "w-4" }), _jsx(Folder, { className: "w-4 h-4 text-blue-500" }), _jsx("span", { className: "flex-1 text-sm", onClick: () => onSelectFolder(folder.id), children: folder.name }), _jsx("button", { onClick: () => {
|
|
29
|
+
setNewFolderParent(folder.id);
|
|
30
|
+
setShowNewFolder(true);
|
|
31
|
+
}, className: "opacity-0 group-hover:opacity-100 p-1 hover:bg-base-300 rounded", children: _jsx(FolderPlus, { className: "w-3 h-3" }) }), _jsx("button", { onClick: () => {
|
|
32
|
+
if (confirm('Delete this folder?')) {
|
|
33
|
+
onDeleteFolder?.(folder.id);
|
|
34
|
+
}
|
|
35
|
+
}, className: "opacity-0 group-hover:opacity-100 p-1 hover:bg-error/20 rounded text-error", children: _jsx(Trash2, { className: "w-3 h-3" }) })] }), isExpanded &&
|
|
36
|
+
folders
|
|
37
|
+
.filter((f) => f.parentId === folder.id)
|
|
38
|
+
.map((child) => renderFolder(child, level + 1))] }, folder.id));
|
|
39
|
+
};
|
|
40
|
+
return (_jsxs("div", { className: "bg-base-100 rounded-lg border border-base-300 p-3", children: [_jsxs("div", { className: "flex items-center justify-between mb-3", children: [_jsx("h3", { className: "font-semibold text-sm", children: "Folders" }), _jsx("button", { onClick: () => {
|
|
41
|
+
setNewFolderParent(undefined);
|
|
42
|
+
setShowNewFolder(true);
|
|
43
|
+
}, className: "p-1 hover:bg-base-200 rounded", children: _jsx(FolderPlus, { className: "w-4 h-4" }) })] }), _jsx("div", { className: `px-3 py-2 hover:bg-base-200 cursor-pointer rounded-lg transition-colors mb-2 ${showAllMedia ? 'bg-primary/10 border border-primary/20' : ''}`, onClick: () => onShowAllMedia?.(), title: "View all media files (including organized and unorganized)", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Images, { className: "w-4 h-4 text-primary" }), _jsx("span", { className: "text-sm font-medium text-primary", children: "All Media" })] }) }), _jsx("div", { className: `px-3 py-2 hover:bg-base-200 cursor-pointer rounded-lg transition-colors mb-2 ${!selectedFolderId && !showAllMedia ? 'bg-primary/10' : ''}`, onClick: () => onSelectFolder(undefined), title: "View only unorganized media files", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Folder, { className: "w-4 h-4 text-base-content/60" }), _jsx("span", { className: "text-sm", children: "Unorganized" })] }) }), showNewFolder && (_jsxs("div", { className: "mb-2 p-2 bg-base-200 rounded-lg", children: [_jsx("input", { type: "text", value: newFolderName, onChange: (e) => setNewFolderName(e.target.value), placeholder: "Folder name", className: "w-full px-2 py-1 text-sm border border-base-300 rounded bg-base-100 mb-2", autoFocus: true, onKeyDown: (e) => {
|
|
44
|
+
if (e.key === 'Enter')
|
|
45
|
+
handleCreateFolder();
|
|
46
|
+
if (e.key === 'Escape')
|
|
47
|
+
setShowNewFolder(false);
|
|
48
|
+
} }), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { onClick: handleCreateFolder, className: "flex-1 px-2 py-1 text-xs bg-primary text-primary-content rounded hover:bg-primary/80", children: "Create" }), _jsx("button", { onClick: () => setShowNewFolder(false), className: "flex-1 px-2 py-1 text-xs bg-base-300 rounded hover:bg-base-content/20", children: "Cancel" })] })] })), folders.length > 0 && (_jsx("div", { className: "border-t border-base-300 my-3" })), folders.length > 0 && (_jsx("div", { className: "px-3 mb-2", children: _jsx("span", { className: "text-xs font-medium text-base-content/60 uppercase tracking-wider", children: "Organized Folders" }) })), _jsx("div", { className: "space-y-1", children: rootFolders.map((folder) => renderFolder(folder)) })] }));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=FolderTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FolderTree.js","sourceRoot":"","sources":["../../../../src/client/components/media/FolderTree.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAalE,MAAM,UAAU,UAAU,CAAC,EACzB,OAAO,EACP,gBAAgB,EAChB,YAAY,GAAG,KAAK,EACpB,cAAc,EACd,cAAc,EACd,cAAc,EACd,cAAc,GACE;IAChB,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAW,EAAE,CAAC,CAAC;IACrE,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1D,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,EAAsB,CAAC;IAE7E,MAAM,YAAY,GAAG,CAAC,QAAgB,EAAE,EAAE;QACxC,kBAAkB,CAAC,CAAC,IAAI,EAAE,EAAE,CAC1B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACrB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,QAAQ,CAAC;YACtC,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,QAAQ,CAAC,CACxB,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,kBAAkB,GAAG,GAAG,EAAE;QAC9B,IAAI,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC;YACzB,cAAc,EAAE,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;YACjD,gBAAgB,CAAC,EAAE,CAAC,CAAC;YACrB,gBAAgB,CAAC,KAAK,CAAC,CAAC;YACxB,kBAAkB,CAAC,SAAS,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAEvD,MAAM,YAAY,GAAG,CAAC,MAAmB,EAAE,KAAK,GAAG,CAAC,EAAE,EAAE;QACtD,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC;QAClE,MAAM,UAAU,GAAG,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACvD,MAAM,UAAU,GAAG,gBAAgB,KAAK,MAAM,CAAC,EAAE,CAAC;QAElD,OAAO,CACL,0BACE,eACE,SAAS,EAAE,mGACT,UAAU,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EACjC,EAAE,EACF,KAAK,EAAE,EAAE,WAAW,EAAE,GAAG,KAAK,GAAG,GAAG,GAAG,IAAI,KAAK,EAAE,aAEjD,WAAW,IAAI,CACd,iBACE,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,EACtC,SAAS,EAAC,0CAA0C,YAEnD,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAChB,CACV,EACA,CAAC,WAAW,IAAI,cAAK,SAAS,EAAC,KAAK,GAAG,EACxC,KAAC,MAAM,IAAC,SAAS,EAAC,uBAAuB,GAAG,EAC5C,eACE,SAAS,EAAC,gBAAgB,EAC1B,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,YAEvC,MAAM,CAAC,IAAI,GACP,EACP,iBACE,OAAO,EAAE,GAAG,EAAE;gCACZ,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gCAC9B,gBAAgB,CAAC,IAAI,CAAC,CAAC;4BACzB,CAAC,EACD,SAAS,EAAC,iEAAiE,YAE3E,KAAC,UAAU,IAAC,SAAS,EAAC,SAAS,GAAG,GAC3B,EACT,iBACE,OAAO,EAAE,GAAG,EAAE;gCACZ,IAAI,OAAO,CAAC,qBAAqB,CAAC,EAAE,CAAC;oCACnC,cAAc,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gCAC9B,CAAC;4BACH,CAAC,EACD,SAAS,EAAC,4EAA4E,YAEtF,KAAC,MAAM,IAAC,SAAS,EAAC,SAAS,GAAG,GACvB,IACL,EACL,UAAU;oBACT,OAAO;yBACJ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,CAAC;yBACvC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,KA9C3C,MAAM,CAAC,EAAE,CA+Cb,CACP,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAC,mDAAmD,aAChE,eAAK,SAAS,EAAC,wCAAwC,aACrD,aAAI,SAAS,EAAC,uBAAuB,wBAAa,EAClD,iBACE,OAAO,EAAE,GAAG,EAAE;4BACZ,kBAAkB,CAAC,SAAS,CAAC,CAAC;4BAC9B,gBAAgB,CAAC,IAAI,CAAC,CAAC;wBACzB,CAAC,EACD,SAAS,EAAC,+BAA+B,YAEzC,KAAC,UAAU,IAAC,SAAS,EAAC,SAAS,GAAG,GAC3B,IACL,EAGN,cACE,SAAS,EAAE,gFACT,YAAY,CAAC,CAAC,CAAC,wCAAwC,CAAC,CAAC,CAAC,EAC5D,EAAE,EACF,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,EAAE,EAAE,EACjC,KAAK,EAAC,4DAA4D,YAElE,eAAK,SAAS,EAAC,yBAAyB,aACtC,KAAC,MAAM,IAAC,SAAS,EAAC,sBAAsB,GAAG,EAC3C,eAAM,SAAS,EAAC,kCAAkC,0BAAiB,IAC/D,GACF,EAGN,cACE,SAAS,EAAE,gFACT,CAAC,gBAAgB,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EACzD,EAAE,EACF,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,EACxC,KAAK,EAAC,mCAAmC,YAEzC,eAAK,SAAS,EAAC,yBAAyB,aACtC,KAAC,MAAM,IAAC,SAAS,EAAC,8BAA8B,GAAG,EACnD,eAAM,SAAS,EAAC,SAAS,4BAAmB,IACxC,GACF,EAEL,aAAa,IAAI,CAChB,eAAK,SAAS,EAAC,iCAAiC,aAC9C,gBACE,IAAI,EAAC,MAAM,EACX,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACjD,WAAW,EAAC,aAAa,EACzB,SAAS,EAAC,0EAA0E,EACpF,SAAS,QACT,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;4BACf,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO;gCAAE,kBAAkB,EAAE,CAAC;4BAC5C,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ;gCAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;wBAClD,CAAC,GACD,EACF,eAAK,SAAS,EAAC,YAAY,aACzB,iBACE,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAC,sFAAsF,uBAGzF,EACT,iBACE,OAAO,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,EACtC,SAAS,EAAC,uEAAuE,uBAG1E,IACL,IACF,CACP,EAGA,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CACrB,cAAK,SAAS,EAAC,+BAA+B,GAAO,CACtD,EAGA,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CACrB,cAAK,SAAS,EAAC,WAAW,YACxB,eAAM,SAAS,EAAC,mEAAmE,kCAE5E,GACH,CACP,EAED,cAAK,SAAS,EAAC,WAAW,YACvB,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAC9C,IACF,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface MediaBrowserProps {
|
|
2
|
+
isOpen: boolean;
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
onSelect: (url: string) => void;
|
|
5
|
+
}
|
|
6
|
+
export default function MediaBrowser({ isOpen, onClose, onSelect }: MediaBrowserProps): import("react/jsx-runtime").JSX.Element | null;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=MediaBrowser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MediaBrowser.d.ts","sourceRoot":"","sources":["../../../../src/client/components/media/MediaBrowser.tsx"],"names":[],"mappings":"AAWA,UAAU,iBAAiB;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,iBAAiB,kDAuapF"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
4
|
+
import { X, Upload, Search, Grid, Image as ImageIcon } from 'lucide-react';
|
|
5
|
+
import { FolderTree } from './FolderTree';
|
|
6
|
+
import { MediaUpload } from './MediaUpload';
|
|
7
|
+
import { CORE_API_ROUTES } from '../../constants/api-routes';
|
|
8
|
+
import { getApiClient } from '../../auth/api-client';
|
|
9
|
+
import Modal from '../../ui/Modal';
|
|
10
|
+
export default function MediaBrowser({ isOpen, onClose, onSelect }) {
|
|
11
|
+
const apiClient = getApiClient();
|
|
12
|
+
const [media, setMedia] = useState([]);
|
|
13
|
+
const [folders, setFolders] = useState([]);
|
|
14
|
+
const [loading, setLoading] = useState(false);
|
|
15
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
16
|
+
const [selectedFolderId, setSelectedFolderId] = useState();
|
|
17
|
+
const [showAllMedia, setShowAllMedia] = useState(false);
|
|
18
|
+
const [viewMode, setViewMode] = useState('grid');
|
|
19
|
+
const [showUpload, setShowUpload] = useState(false);
|
|
20
|
+
const [isDragOver, setIsDragOver] = useState(false);
|
|
21
|
+
const [pagination, setPagination] = useState({
|
|
22
|
+
page: 1,
|
|
23
|
+
limit: 20,
|
|
24
|
+
total: 0,
|
|
25
|
+
totalPages: 0,
|
|
26
|
+
});
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (isOpen) {
|
|
29
|
+
setShowAllMedia(true); // Mặc định hiển thị tất cả media
|
|
30
|
+
fetchFolders();
|
|
31
|
+
fetchMedia();
|
|
32
|
+
}
|
|
33
|
+
}, [isOpen]);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (isOpen) {
|
|
36
|
+
setPagination(prev => ({ ...prev, page: 1 }));
|
|
37
|
+
fetchMedia(1);
|
|
38
|
+
}
|
|
39
|
+
}, [isOpen, selectedFolderId, searchTerm, showAllMedia]);
|
|
40
|
+
const fetchFolders = async () => {
|
|
41
|
+
try {
|
|
42
|
+
const response = await apiClient.get(CORE_API_ROUTES.MEDIA.FOLDERS);
|
|
43
|
+
setFolders(response.data);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.error('Failed to fetch folders:', error);
|
|
47
|
+
setFolders([]);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const fetchMedia = async (pageOverride) => {
|
|
51
|
+
setLoading(true);
|
|
52
|
+
try {
|
|
53
|
+
const currentPage = pageOverride ?? pagination.page;
|
|
54
|
+
const params = {
|
|
55
|
+
page: currentPage,
|
|
56
|
+
limit: pagination.limit,
|
|
57
|
+
type: 'image',
|
|
58
|
+
};
|
|
59
|
+
if (searchTerm)
|
|
60
|
+
params.search = searchTerm;
|
|
61
|
+
if (!showAllMedia) {
|
|
62
|
+
if (selectedFolderId !== undefined) {
|
|
63
|
+
params.folderId = selectedFolderId;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
params.folderId = 'null';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const response = await apiClient.get(CORE_API_ROUTES.MEDIA.BASE, { params });
|
|
70
|
+
setMedia(response.data.items);
|
|
71
|
+
setPagination({
|
|
72
|
+
page: response.data.page,
|
|
73
|
+
limit: response.data.limit,
|
|
74
|
+
total: response.data.total,
|
|
75
|
+
totalPages: response.data.totalPages,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error('Failed to fetch media:', error);
|
|
80
|
+
setMedia([]);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
setLoading(false);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const handleUpload = async (files) => {
|
|
87
|
+
const filesToUpload = files ? Array.from(files) : [];
|
|
88
|
+
if (filesToUpload.length === 0)
|
|
89
|
+
return;
|
|
90
|
+
setLoading(true);
|
|
91
|
+
try {
|
|
92
|
+
const formData = new FormData();
|
|
93
|
+
filesToUpload.forEach(file => {
|
|
94
|
+
formData.append('files', file);
|
|
95
|
+
});
|
|
96
|
+
// Thêm folderId nếu không ở mode "All Media"
|
|
97
|
+
if (!showAllMedia && selectedFolderId !== undefined) {
|
|
98
|
+
formData.append('folderId', String(selectedFolderId));
|
|
99
|
+
}
|
|
100
|
+
const response = await apiClient.post(CORE_API_ROUTES.MEDIA.UPLOAD, formData, {
|
|
101
|
+
timeout: 30000,
|
|
102
|
+
});
|
|
103
|
+
// Refresh media list
|
|
104
|
+
await fetchMedia();
|
|
105
|
+
// Auto-select first uploaded image if only one file
|
|
106
|
+
if (filesToUpload.length === 1) {
|
|
107
|
+
const uploadedMedia = Array.isArray(response.data)
|
|
108
|
+
? response.data[0]
|
|
109
|
+
: response.data;
|
|
110
|
+
if (uploadedMedia && uploadedMedia.url) {
|
|
111
|
+
onSelect(uploadedMedia.url);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
console.error('Upload failed:', error);
|
|
117
|
+
const errorMessage = error.response?.data?.message || 'Upload failed. Please try again.';
|
|
118
|
+
alert(errorMessage);
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
setLoading(false);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const handleUploadComplete = useCallback(() => {
|
|
125
|
+
setShowUpload(false);
|
|
126
|
+
fetchMedia();
|
|
127
|
+
}, []);
|
|
128
|
+
// Drag and drop handlers
|
|
129
|
+
const handleDragEnter = useCallback((e) => {
|
|
130
|
+
e.preventDefault();
|
|
131
|
+
e.stopPropagation();
|
|
132
|
+
setIsDragOver(true);
|
|
133
|
+
}, []);
|
|
134
|
+
const handleDragLeave = useCallback((e) => {
|
|
135
|
+
e.preventDefault();
|
|
136
|
+
e.stopPropagation();
|
|
137
|
+
setIsDragOver(false);
|
|
138
|
+
}, []);
|
|
139
|
+
const handleDragOver = useCallback((e) => {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
e.stopPropagation();
|
|
142
|
+
}, []);
|
|
143
|
+
const handleDrop = useCallback((e) => {
|
|
144
|
+
e.preventDefault();
|
|
145
|
+
e.stopPropagation();
|
|
146
|
+
setIsDragOver(false);
|
|
147
|
+
const files = e.dataTransfer.files;
|
|
148
|
+
if (files.length > 0) {
|
|
149
|
+
// Filter chỉ image files
|
|
150
|
+
const imageFiles = Array.from(files).filter(file => file.type.startsWith('image/'));
|
|
151
|
+
if (imageFiles.length > 0) {
|
|
152
|
+
handleUpload(imageFiles);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}, []);
|
|
156
|
+
const handleSearch = () => {
|
|
157
|
+
setPagination(prev => ({ ...prev, page: 1 }));
|
|
158
|
+
fetchMedia(1);
|
|
159
|
+
};
|
|
160
|
+
const handlePageChange = useCallback((newPage) => {
|
|
161
|
+
setPagination(prev => ({ ...prev, page: newPage }));
|
|
162
|
+
fetchMedia(newPage);
|
|
163
|
+
}, []);
|
|
164
|
+
if (!isOpen)
|
|
165
|
+
return null;
|
|
166
|
+
return (_jsx(Modal, { isOpen: isOpen, onClose: onClose, size: "custom", showCloseButton: false, className: "w-[1000px] h-[700px]", closeOnOverlayClick: false, children: _jsxs("div", { className: "w-full h-full flex flex-col relative", onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, children: [isDragOver && (_jsx("div", { className: "absolute inset-0 bg-primary/20 border-4 border-dashed border-primary rounded-lg flex items-center justify-center z-10", children: _jsxs("div", { className: "text-center", children: [_jsx(Upload, { className: "mx-auto mb-4 text-primary", size: 48 }), _jsx("p", { className: "text-xl font-semibold text-primary", children: "Drop images to upload" }), _jsx("p", { className: "text-primary/80", children: !showAllMedia && selectedFolderId !== undefined
|
|
167
|
+
? `Upload to "${folders.find(f => f.id === selectedFolderId)?.name}" folder`
|
|
168
|
+
: 'Upload to media library' })] }) })), _jsxs("div", { className: "flex items-center justify-between p-4 border-b border-base-300", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(ImageIcon, { className: "w-6 h-6 text-primary" }), _jsx("h2", { className: "text-xl font-semibold", children: "Media Library" })] }), _jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center bg-base-200 rounded-md p-1", children: [_jsx("button", { onClick: () => setViewMode('grid'), className: `p-2 rounded ${viewMode === 'grid' ? 'bg-base-100 shadow-sm' : 'hover:bg-base-300'}`, title: "Grid View", children: _jsx(Grid, { size: 16 }) }), _jsx("button", { onClick: () => setViewMode('list'), className: `p-2 rounded ${viewMode === 'list' ? 'bg-base-100 shadow-sm' : 'hover:bg-base-300'}`, title: "List View", children: _jsx(ImageIcon, { size: 16 }) })] }), _jsx("button", { onClick: onClose, className: "p-2 hover:bg-base-200 rounded-lg", children: _jsx(X, { size: 20 }) })] })] }), _jsxs("div", { className: "p-4 border-b border-base-300 flex gap-4", children: [_jsxs("div", { className: "flex-1 relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-base-content/40" }), _jsx("input", { type: "text", placeholder: "Search images...", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), className: "w-full pl-10 pr-4 py-2 border border-base-300 rounded-lg bg-base-100 focus:outline-none focus:ring-2 focus:ring-primary", onKeyPress: (e) => e.key === 'Enter' && handleSearch() })] }), _jsxs("button", { onClick: handleSearch, className: "px-4 py-2 bg-neutral text-neutral-content rounded-lg hover:bg-neutral/80 flex items-center gap-2 whitespace-nowrap", children: [_jsx(Search, { className: "w-5 h-5" }), "Search"] }), _jsxs("button", { onClick: () => setShowUpload(!showUpload), className: "px-4 py-2 bg-primary text-primary-content rounded-lg hover:bg-primary/80 flex items-center gap-2 whitespace-nowrap", children: [_jsx(Upload, { className: "w-5 h-5" }), "Upload"] })] }), showUpload && (_jsx("div", { className: "p-4 bg-base-200 border-b border-base-300", children: _jsx(MediaUpload, { folderId: showAllMedia ? undefined : selectedFolderId, folderName: showAllMedia
|
|
169
|
+
? undefined
|
|
170
|
+
: selectedFolderId !== undefined
|
|
171
|
+
? folders.find(f => f.id === selectedFolderId)?.name
|
|
172
|
+
: undefined, onUploadComplete: handleUploadComplete, maxFiles: 10 }) })), _jsxs("div", { className: "flex flex-1 overflow-hidden", children: [_jsx("div", { className: "w-64 border-r border-base-300 overflow-y-auto p-4", children: _jsx(FolderTree, { folders: folders, selectedFolderId: selectedFolderId, showAllMedia: showAllMedia, onSelectFolder: (folderId) => {
|
|
173
|
+
setSelectedFolderId(folderId);
|
|
174
|
+
setShowAllMedia(false);
|
|
175
|
+
setPagination(prev => ({ ...prev, page: 1 }));
|
|
176
|
+
fetchMedia(1);
|
|
177
|
+
}, onShowAllMedia: () => {
|
|
178
|
+
setShowAllMedia(true);
|
|
179
|
+
setSelectedFolderId(undefined);
|
|
180
|
+
setPagination(prev => ({ ...prev, page: 1 }));
|
|
181
|
+
fetchMedia(1);
|
|
182
|
+
}, onCreateFolder: async (name, parentId) => {
|
|
183
|
+
try {
|
|
184
|
+
await apiClient.post(CORE_API_ROUTES.MEDIA.CREATE_FOLDER, {
|
|
185
|
+
name,
|
|
186
|
+
parentId,
|
|
187
|
+
});
|
|
188
|
+
fetchFolders();
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
console.error('Error creating folder:', error);
|
|
192
|
+
}
|
|
193
|
+
}, onDeleteFolder: async (id) => {
|
|
194
|
+
try {
|
|
195
|
+
await apiClient.delete(CORE_API_ROUTES.MEDIA.FOLDER_BY_ID(id));
|
|
196
|
+
fetchFolders();
|
|
197
|
+
if (selectedFolderId === id) {
|
|
198
|
+
setSelectedFolderId(undefined);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
alert(error.response?.data?.message || 'Error deleting folder');
|
|
203
|
+
}
|
|
204
|
+
} }) }), _jsx("div", { className: "flex-1 flex flex-col overflow-hidden", children: _jsx("div", { className: "flex-1 p-4 overflow-y-auto bg-base-100", children: loading ? (_jsx("div", { className: "flex items-center justify-center h-full", children: _jsxs("div", { className: "text-center", children: [_jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-4 border-base-300 border-t-primary mx-auto mb-4" }), _jsx("div", { className: "text-base-content/60", children: "Loading images..." })] }) })) : Array.isArray(media) && media.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("div", { className: viewMode === 'grid'
|
|
205
|
+
? 'grid grid-cols-4 gap-4'
|
|
206
|
+
: 'space-y-3', children: media.map((item) => (_jsxs("div", { className: `group cursor-pointer rounded-lg overflow-hidden transition-all duration-200 border border-base-300 ${viewMode === 'grid'
|
|
207
|
+
? 'hover:shadow-lg hover:scale-105'
|
|
208
|
+
: 'flex items-center gap-4 p-3 hover:bg-base-200'}`, onClick: () => onSelect(item.url), children: [_jsx("div", { className: viewMode === 'grid' ? 'w-full h-40' : 'w-16 h-16 flex-shrink-0', children: _jsx("img", { src: item.url, alt: item.filename, className: "w-full h-full object-cover" }) }), _jsxs("div", { className: viewMode === 'grid' ? 'p-3' : 'flex-1 min-w-0', children: [_jsx("p", { className: `font-medium text-base-content ${viewMode === 'grid' ? 'text-sm truncate' : 'truncate'}`, children: item.filename }), _jsxs("div", { className: `text-base-content/60 ${viewMode === 'grid' ? 'text-xs mt-1' : 'text-sm flex items-center gap-4'}`, children: [_jsxs("span", { children: [Math.round(item.size / 1024), " KB"] }), viewMode === 'list' && item.createdAt && (_jsx("span", { children: new Date(item.createdAt).toLocaleDateString() }))] })] })] }, item.id))) }), pagination.totalPages > 1 && (_jsxs("div", { className: "mt-6 flex justify-center gap-2", children: [_jsx("button", { onClick: () => handlePageChange(Math.max(1, pagination.page - 1)), disabled: pagination.page === 1, className: "px-4 py-2 border border-base-300 rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-base-200", children: "Previous" }), _jsxs("span", { className: "px-4 py-2 flex items-center text-base-content", children: ["Page ", pagination.page, " of ", pagination.totalPages] }), _jsx("button", { onClick: () => handlePageChange(Math.min(pagination.totalPages, pagination.page + 1)), disabled: pagination.page === pagination.totalPages, className: "px-4 py-2 border border-base-300 rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-base-200", children: "Next" })] }))] })) : (_jsx("div", { className: "flex items-center justify-center h-full", children: _jsxs("div", { className: "text-center", children: [_jsx(ImageIcon, { className: "mx-auto mb-4 text-base-content/30", size: 48 }), _jsx("div", { className: "text-base-content/60 text-lg mb-2", children: Array.isArray(media) ? 'No images found' : 'Failed to load images' }), _jsx("p", { className: "text-base-content/40 text-sm", children: searchTerm ? 'Try adjusting your search terms' : 'Upload some images to get started' })] }) })) }) })] })] }) }));
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=MediaBrowser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MediaBrowser.js","sourceRoot":"","sources":["../../../../src/client/components/media/MediaBrowser.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Media } from '../../types/media';
|
|
2
|
+
interface MediaGridProps {
|
|
3
|
+
media: Media[];
|
|
4
|
+
onDelete?: (id: number) => void;
|
|
5
|
+
onSelect?: (media: Media) => void;
|
|
6
|
+
selectedIds?: number[];
|
|
7
|
+
selectable?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function MediaGrid({ media, onDelete, onSelect, selectedIds, selectable, }: MediaGridProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=MediaGrid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MediaGrid.d.ts","sourceRoot":"","sources":["../../../../src/client/components/media/MediaGrid.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAa,MAAM,mBAAmB,CAAC;AAYrD,UAAU,cAAc;IACtB,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAClC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,WAAgB,EAChB,UAAkB,GACnB,EAAE,cAAc,2CA8KhB"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { MediaType } from '../../types/media';
|
|
4
|
+
import { Check, Copy, MoreVertical, Trash2 } from 'lucide-react';
|
|
5
|
+
import Image from 'next/image';
|
|
6
|
+
import { useEffect, useState } from 'react';
|
|
7
|
+
import toast from 'react-hot-toast';
|
|
8
|
+
import { ConfirmModal } from '../../ui/ConfirmModal';
|
|
9
|
+
export function MediaGrid({ media, onDelete, onSelect, selectedIds = [], selectable = false, }) {
|
|
10
|
+
const [showMenu, setShowMenu] = useState(null);
|
|
11
|
+
const [deleteConfirm, setDeleteConfirm] = useState({ isOpen: false, item: null });
|
|
12
|
+
// Close menu when clicking outside
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const handleClickOutside = (event) => {
|
|
15
|
+
const target = event.target;
|
|
16
|
+
if (!target.closest('.menu-container')) {
|
|
17
|
+
setShowMenu(null);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
if (showMenu) {
|
|
21
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
22
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
23
|
+
}
|
|
24
|
+
}, [showMenu]);
|
|
25
|
+
const formatFileSize = (bytes) => {
|
|
26
|
+
if (bytes === 0)
|
|
27
|
+
return '0 Bytes';
|
|
28
|
+
const k = 1024;
|
|
29
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
30
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
31
|
+
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
|
|
32
|
+
};
|
|
33
|
+
const formatDate = (date) => {
|
|
34
|
+
return new Date(date).toLocaleDateString('en-US', {
|
|
35
|
+
year: 'numeric',
|
|
36
|
+
month: 'short',
|
|
37
|
+
day: 'numeric',
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const copyUrl = (url) => {
|
|
41
|
+
navigator.clipboard.writeText(url);
|
|
42
|
+
toast.success('URL copied to clipboard!');
|
|
43
|
+
};
|
|
44
|
+
const handleDelete = (item) => {
|
|
45
|
+
setDeleteConfirm({ isOpen: true, item });
|
|
46
|
+
};
|
|
47
|
+
const confirmDelete = () => {
|
|
48
|
+
if (deleteConfirm.item) {
|
|
49
|
+
onDelete?.(deleteConfirm.item.id);
|
|
50
|
+
toast.success('Media deleted successfully!');
|
|
51
|
+
setDeleteConfirm({ isOpen: false, item: null });
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const isSelected = (id) => selectedIds.includes(id);
|
|
55
|
+
return (_jsxs("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [media.map((item) => (_jsxs("div", { className: `relative group bg-base-100 rounded-lg overflow-hidden border-2 transition-all ${isSelected(item.id)
|
|
56
|
+
? 'border-primary ring-2 ring-primary/20'
|
|
57
|
+
: 'border-base-300 hover:border-base-content/20'}`, children: [selectable && (_jsx("div", { className: "absolute top-2 left-2 z-10", children: _jsx("button", { onClick: () => onSelect?.(item), className: `w-6 h-6 rounded border-2 flex items-center justify-center transition-all ${isSelected(item.id)
|
|
58
|
+
? 'bg-primary border-primary text-primary-content'
|
|
59
|
+
: 'bg-base-100 border-base-300 hover:border-base-content/40'}`, children: isSelected(item.id) && _jsx(Check, { className: "w-4 h-4" }) }) })), _jsx("div", { className: "aspect-square relative bg-base-200 cursor-pointer", onClick: () => onSelect?.(item), children: item.type === MediaType.IMAGE ? (_jsx(Image, { src: item.url, alt: item.alt || item.name, fill: true, className: "object-cover", sizes: "(max-width: 768px) 50vw, (max-width: 1200px) 33vw, 20vw" })) : (_jsx("div", { className: "w-full h-full flex items-center justify-center", children: _jsxs("div", { className: "text-center", children: [_jsx("div", { className: "text-4xl mb-2", children: "\uD83D\uDCC4" }), _jsx("p", { className: "text-xs text-base-content/60 px-2", children: item.ext })] }) })) }), _jsxs("div", { className: "p-3", children: [_jsx("p", { className: "text-sm font-medium text-base-content truncate mb-1", children: item.name }), _jsxs("div", { className: "flex items-center justify-between text-xs text-base-content/60", children: [_jsx("span", { children: formatFileSize(item.size) }), item.width && item.height && (_jsxs("span", { children: [item.width, "x", item.height] }))] }), _jsx("p", { className: "text-xs text-base-content/40 mt-1", children: formatDate(item.createdAt) })] }), _jsxs("div", { className: "absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-100 transition-opacity menu-container", children: [_jsx("button", { onClick: () => setShowMenu(showMenu === item.id ? null : item.id), className: "p-1 bg-base-100 rounded-full shadow-lg hover:bg-base-200", children: _jsx(MoreVertical, { className: "w-4 h-4" }) }), showMenu === item.id && (_jsxs("div", { className: "absolute right-0 mt-2 w-48 bg-base-100 rounded-lg shadow-xl border border-base-300 py-1 z-20", children: [_jsxs("button", { onClick: () => {
|
|
60
|
+
copyUrl(item.url);
|
|
61
|
+
setShowMenu(null);
|
|
62
|
+
}, className: "w-full px-4 py-2 text-left text-sm hover:bg-base-200 flex items-center gap-2", children: [_jsx(Copy, { className: "w-4 h-4" }), "Copy URL"] }), _jsxs("button", { onClick: () => {
|
|
63
|
+
handleDelete(item);
|
|
64
|
+
setShowMenu(null);
|
|
65
|
+
}, className: "w-full px-4 py-2 text-left text-sm text-error hover:bg-error/10 flex items-center gap-2", children: [_jsx(Trash2, { className: "w-4 h-4" }), "Delete"] })] }))] })] }, item.id))), _jsx(ConfirmModal, { isOpen: deleteConfirm.isOpen, onClose: () => setDeleteConfirm({ isOpen: false, item: null }), onConfirm: confirmDelete, title: "Delete MediaEntity", message: `Are you sure you want to delete "${deleteConfirm.item?.name}"? This action cannot be undone.`, confirmText: "Delete", cancelText: "Cancel", type: "danger", icon: _jsx(Trash2, { className: "w-6 h-6" }) })] }));
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=MediaGrid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MediaGrid.js","sourceRoot":"","sources":["../../../../src/client/components/media/MediaGrid.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Media } from '../../types/media';
|
|
2
|
+
interface MediaPickerProps {
|
|
3
|
+
isOpen: boolean;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
onSelect: (media: Media | Media[]) => void;
|
|
6
|
+
multiple?: boolean;
|
|
7
|
+
accept?: 'image' | 'video' | 'audio' | 'document' | 'other' | 'all';
|
|
8
|
+
selectedIds?: number[];
|
|
9
|
+
}
|
|
10
|
+
export declare function MediaPicker({ isOpen, onClose, onSelect, multiple, accept, selectedIds, }: MediaPickerProps): import("react/jsx-runtime").JSX.Element | null;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=MediaPicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MediaPicker.d.ts","sourceRoot":"","sources":["../../../../src/client/components/media/MediaPicker.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAA4C,MAAM,mBAAmB,CAAC;AAepF,UAAU,gBAAgB;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC;IACpE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,OAAO,EACP,QAAQ,EACR,QAAgB,EAChB,MAAc,EACd,WAAgB,GACjB,EAAE,gBAAgB,kDAsTlB"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
4
|
+
import { MediaType } from '../../types/media';
|
|
5
|
+
import { CORE_API_ROUTES } from '../../constants/api-routes';
|
|
6
|
+
import { getApiClient } from '../../auth/api-client';
|
|
7
|
+
import { MediaGrid } from './MediaGrid';
|
|
8
|
+
import { FolderTree } from './FolderTree';
|
|
9
|
+
import { MediaUpload } from './MediaUpload';
|
|
10
|
+
import Modal from '../../ui/Modal';
|
|
11
|
+
import { X, Search, Upload as UploadIcon, Check, Image as ImageIcon, } from 'lucide-react';
|
|
12
|
+
export function MediaPicker({ isOpen, onClose, onSelect, multiple = false, accept = 'all', selectedIds = [], }) {
|
|
13
|
+
const apiClient = getApiClient();
|
|
14
|
+
const [media, setMedia] = useState([]);
|
|
15
|
+
const [folders, setFolders] = useState([]);
|
|
16
|
+
const [loading, setLoading] = useState(false);
|
|
17
|
+
const [selectedFolderId, setSelectedFolderId] = useState();
|
|
18
|
+
const [showAllMedia, setShowAllMedia] = useState(false); // Hiển thị tất cả media
|
|
19
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
20
|
+
const [localSelectedIds, setLocalSelectedIds] = useState(() => selectedIds || []);
|
|
21
|
+
const [showUpload, setShowUpload] = useState(false);
|
|
22
|
+
const [pagination, setPagination] = useState({
|
|
23
|
+
page: 1,
|
|
24
|
+
limit: 20,
|
|
25
|
+
total: 0,
|
|
26
|
+
totalPages: 0,
|
|
27
|
+
});
|
|
28
|
+
// Use ref to avoid dependency issues
|
|
29
|
+
const paginationRef = useRef(pagination);
|
|
30
|
+
paginationRef.current = pagination;
|
|
31
|
+
const resolveTypeParam = () => {
|
|
32
|
+
if (accept === 'all')
|
|
33
|
+
return undefined;
|
|
34
|
+
const typeMap = {
|
|
35
|
+
image: MediaType.IMAGE,
|
|
36
|
+
video: MediaType.VIDEO,
|
|
37
|
+
audio: MediaType.AUDIO,
|
|
38
|
+
document: MediaType.DOCUMENT,
|
|
39
|
+
other: MediaType.OTHER,
|
|
40
|
+
};
|
|
41
|
+
return typeMap[accept];
|
|
42
|
+
};
|
|
43
|
+
const fetchMedia = useCallback(async (pageOverride) => {
|
|
44
|
+
try {
|
|
45
|
+
setLoading(true);
|
|
46
|
+
const currentPage = pageOverride ?? paginationRef.current.page;
|
|
47
|
+
const params = {
|
|
48
|
+
page: currentPage,
|
|
49
|
+
limit: paginationRef.current.limit,
|
|
50
|
+
};
|
|
51
|
+
if (searchQuery)
|
|
52
|
+
params.search = searchQuery;
|
|
53
|
+
const typeParam = resolveTypeParam();
|
|
54
|
+
if (typeParam !== undefined)
|
|
55
|
+
params.type = typeParam;
|
|
56
|
+
// Chỉ gửi folderId khi thật sự chọn thư mục; để undefined để backend trả tất cả
|
|
57
|
+
if (!showAllMedia && selectedFolderId !== undefined) {
|
|
58
|
+
params.folderId = selectedFolderId;
|
|
59
|
+
}
|
|
60
|
+
const response = await apiClient.get(CORE_API_ROUTES.MEDIA.BASE, { params });
|
|
61
|
+
setMedia(response.data.items);
|
|
62
|
+
setPagination({
|
|
63
|
+
page: response.data.page,
|
|
64
|
+
limit: response.data.limit,
|
|
65
|
+
total: response.data.total,
|
|
66
|
+
totalPages: response.data.totalPages,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error('❌ Error fetching media:', error);
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
setLoading(false);
|
|
74
|
+
}
|
|
75
|
+
}, [searchQuery, accept, selectedFolderId, showAllMedia]); // Thêm showAllMedia vào dependencies
|
|
76
|
+
const fetchFolders = useCallback(async () => {
|
|
77
|
+
try {
|
|
78
|
+
const response = await apiClient.get(CORE_API_ROUTES.MEDIA.FOLDERS);
|
|
79
|
+
setFolders(response.data);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
console.error('Error fetching folders:', error);
|
|
83
|
+
}
|
|
84
|
+
}, []);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (isOpen) {
|
|
87
|
+
// Reset pagination when opening or changing search/folder
|
|
88
|
+
setPagination(prev => ({ ...prev, page: 1 }));
|
|
89
|
+
fetchMedia(1);
|
|
90
|
+
fetchFolders();
|
|
91
|
+
}
|
|
92
|
+
}, [isOpen, selectedFolderId, searchQuery, showAllMedia]); // Thêm showAllMedia vào dependencies
|
|
93
|
+
const handleSelectMedia = useCallback((item) => {
|
|
94
|
+
if (multiple) {
|
|
95
|
+
setLocalSelectedIds((prev) => prev.includes(item.id)
|
|
96
|
+
? prev.filter((id) => id !== item.id)
|
|
97
|
+
: [...prev, item.id]);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
setLocalSelectedIds([item.id]);
|
|
101
|
+
}
|
|
102
|
+
}, [multiple]);
|
|
103
|
+
const handleConfirm = useCallback(() => {
|
|
104
|
+
const selectedMedia = media.filter((m) => localSelectedIds.includes(m.id));
|
|
105
|
+
onSelect(multiple ? selectedMedia : selectedMedia[0]);
|
|
106
|
+
onClose();
|
|
107
|
+
}, [media, localSelectedIds, multiple, onSelect, onClose]);
|
|
108
|
+
const handleUploadComplete = useCallback(() => {
|
|
109
|
+
setShowUpload(false);
|
|
110
|
+
fetchMedia();
|
|
111
|
+
}, [fetchMedia]);
|
|
112
|
+
const handlePageChange = useCallback((newPage) => {
|
|
113
|
+
setPagination(prev => ({ ...prev, page: newPage }));
|
|
114
|
+
fetchMedia(newPage);
|
|
115
|
+
}, [fetchMedia]);
|
|
116
|
+
if (!isOpen)
|
|
117
|
+
return null;
|
|
118
|
+
return (_jsx(Modal, { isOpen: isOpen, onClose: onClose, size: "custom", showCloseButton: false, className: "w-full max-w-6xl max-h-[90vh]", children: _jsxs("div", { className: "overflow-hidden flex flex-col h-full", children: [_jsxs("div", { className: "flex items-center justify-between p-4 border-b border-base-300", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(ImageIcon, { className: "w-6 h-6 text-primary" }), _jsxs("div", { children: [_jsx("h2", { className: "text-xl font-semibold text-base-content", children: multiple ? 'Select Media' : 'Select a Media' }), _jsx("p", { className: "text-sm text-base-content/70", children: localSelectedIds.length > 0
|
|
119
|
+
? `${localSelectedIds.length} selected`
|
|
120
|
+
: 'Choose from your media library' })] })] }), _jsx("button", { onClick: onClose, className: "btn btn-ghost btn-sm btn-circle", children: _jsx(X, { className: "w-5 h-5" }) })] }), _jsxs("div", { className: "p-4 border-b border-base-300 flex gap-4", children: [_jsxs("div", { className: "flex-1 relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-base-content/50" }), _jsx("input", { type: "text", placeholder: "Search media...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "input input-bordered w-full pl-10" })] }), _jsxs("button", { onClick: () => setShowUpload(!showUpload), className: "btn btn-primary flex items-center gap-2 whitespace-nowrap", children: [_jsx(UploadIcon, { className: "w-5 h-5" }), "Upload"] })] }), showUpload && (_jsx("div", { className: "p-4 bg-base-200 border-b border-base-300", children: _jsx(MediaUpload, { folderId: showAllMedia ? undefined : selectedFolderId, folderName: showAllMedia
|
|
121
|
+
? undefined
|
|
122
|
+
: selectedFolderId !== undefined
|
|
123
|
+
? folders.find(f => f.id === selectedFolderId)?.name
|
|
124
|
+
: undefined, onUploadComplete: handleUploadComplete, maxFiles: multiple ? 10 : 1 }) })), _jsxs("div", { className: "flex-1 overflow-hidden flex", children: [_jsx("div", { className: "w-64 border-r border-base-300 overflow-y-auto p-4", children: _jsx(FolderTree, { folders: folders, selectedFolderId: selectedFolderId, showAllMedia: showAllMedia, onSelectFolder: (folderId) => {
|
|
125
|
+
setSelectedFolderId(folderId);
|
|
126
|
+
setShowAllMedia(false); // Tắt showAllMedia khi chọn folder cụ thể
|
|
127
|
+
}, onShowAllMedia: () => {
|
|
128
|
+
setShowAllMedia(true);
|
|
129
|
+
setSelectedFolderId(undefined); // Reset selectedFolderId
|
|
130
|
+
}, onCreateFolder: async (name, parentId) => {
|
|
131
|
+
try {
|
|
132
|
+
await apiClient.post(CORE_API_ROUTES.MEDIA.CREATE_FOLDER, {
|
|
133
|
+
name,
|
|
134
|
+
parentId,
|
|
135
|
+
});
|
|
136
|
+
fetchFolders();
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
console.error('Error creating folder:', error);
|
|
140
|
+
}
|
|
141
|
+
}, onDeleteFolder: async (id) => {
|
|
142
|
+
try {
|
|
143
|
+
await apiClient.delete(CORE_API_ROUTES.MEDIA.FOLDER_BY_ID(id));
|
|
144
|
+
fetchFolders();
|
|
145
|
+
if (selectedFolderId === id) {
|
|
146
|
+
setSelectedFolderId(undefined);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
alert(error.response?.data?.message || 'Error deleting folder');
|
|
151
|
+
}
|
|
152
|
+
} }) }), _jsx("div", { className: "flex-1 flex flex-col overflow-hidden", children: _jsx("div", { className: "flex-1 overflow-y-auto p-4", children: loading ? (_jsx("div", { className: "flex justify-center items-center h-64", children: _jsx("span", { className: "loading loading-spinner loading-lg text-primary" }) })) : media.length === 0 ? (_jsx("div", { className: "text-center py-12 text-base-content/50", children: "No media found" })) : (_jsxs(_Fragment, { children: [_jsx(MediaGrid, { media: media, onSelect: handleSelectMedia, selectedIds: localSelectedIds, selectable: true }), pagination.totalPages > 1 && (_jsxs("div", { className: "mt-6 flex justify-center gap-2", children: [_jsx("button", { onClick: () => handlePageChange(Math.max(1, pagination.page - 1)), disabled: pagination.page === 1, className: "btn btn-outline btn-sm", children: "Previous" }), _jsxs("span", { className: "btn btn-ghost btn-sm no-animation cursor-default", children: ["Page ", pagination.page, " of ", pagination.totalPages] }), _jsx("button", { onClick: () => handlePageChange(Math.min(pagination.totalPages, pagination.page + 1)), disabled: pagination.page === pagination.totalPages, className: "btn btn-outline btn-sm", children: "Next" })] }))] })) }) })] }), _jsxs("div", { className: "p-4 border-t border-base-300 flex justify-between items-center", children: [_jsx("div", { className: "text-sm text-base-content/70", children: localSelectedIds.length > 0 ? (_jsxs("span", { children: [localSelectedIds.length, ' ', multiple ? 'items' : 'item', " selected"] })) : (_jsxs("span", { children: ["Select ", multiple ? 'one or more' : 'a', " media file"] })) }), _jsxs("div", { className: "flex gap-3", children: [_jsx("button", { onClick: onClose, className: "btn btn-outline", children: "Cancel" }), _jsxs("button", { onClick: handleConfirm, disabled: localSelectedIds.length === 0, className: "btn btn-primary", children: [_jsx(Check, { className: "w-5 h-5" }), "Confirm Selection"] })] })] })] }) }));
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=MediaPicker.js.map
|