diff --git a/static/index.html b/static/index.html
index b38c9705..f6145699 100644
--- a/static/index.html
+++ b/static/index.html
@@ -19,6 +19,7 @@
+
diff --git a/static/js/app.js b/static/js/app.js
index add70f7e..130ae205 100644
--- a/static/js/app.js
+++ b/static/js/app.js
@@ -13,7 +13,8 @@ const app = {
selectedTargetFolderId: "", // Selected target folder for move operations
moveDialogMode: 'file', // Move dialog mode: 'file' or 'folder'
isTrashView: false, // Whether we're in trash view
- currentSection: 'files', // Current section: 'files' or 'trash'
+ isSharedView: false, // Whether we're in shared view
+ currentSection: 'files', // Current section: 'files', 'trash' or 'shared'
isSearchMode: false, // Whether we're in search mode
// File sharing related properties
shareDialogItem: null, // Item being shared in share dialog
@@ -167,17 +168,40 @@ function setupEventListeners() {
// Check if this is the shared item
if (item.querySelector('span').getAttribute('data-i18n') === 'nav.shared') {
- // Navigate to the shared page
- window.location.href = '/shared.html';
+ // Switch to shared view
+ switchToSharedView();
return;
}
// Check if this is the trash item
if (item === elements.trashBtn) {
+ // Hide shared view if active
+ if (app.isSharedView) {
+ // Hide shared view
+ if (window.sharedView) {
+ window.sharedView.hide();
+ }
+
+ // Reset shared view flag
+ app.isSharedView = false;
+
+ // Clean up shared containers if they exist
+ const sharedContainer = document.getElementById('shared-container');
+ if (sharedContainer) {
+ sharedContainer.style.display = 'none';
+ }
+ }
+
// Show trash view
app.isTrashView = true;
app.currentSection = 'trash';
+ // Show files containers (to be filled with trash)
+ const filesGrid = document.getElementById('files-grid');
+ const filesListView = document.getElementById('files-list-view');
+ if (filesGrid) filesGrid.style.display = app.currentView === 'grid' ? 'grid' : 'none';
+ if (filesListView) filesListView.style.display = app.currentView === 'list' ? 'block' : 'none';
+
// Update UI
elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.trash') : 'Papelera';
elements.actionsBar.innerHTML = `
@@ -188,6 +212,7 @@ function setupEventListeners() {
`;
+ elements.actionsBar.style.display = 'flex';
// Add event listener to empty trash button
document.getElementById('empty-trash-btn').addEventListener('click', async () => {
@@ -199,6 +224,23 @@ function setupEventListeners() {
// Load trash items
loadTrashItems();
} else {
+ // Check if we need to reset shared view
+ if (app.isSharedView) {
+ // Hide shared view
+ if (window.sharedView) {
+ window.sharedView.hide();
+ }
+
+ // Reset shared view flag
+ app.isSharedView = false;
+
+ // Clean up shared containers if they exist
+ const sharedContainer = document.getElementById('shared-container');
+ if (sharedContainer) {
+ sharedContainer.style.display = 'none';
+ }
+ }
+
// Show regular files view
app.isTrashView = false;
app.currentSection = 'files';
@@ -223,6 +265,13 @@ function setupEventListeners() {
`;
+ elements.actionsBar.style.display = 'flex';
+
+ // Show files containers
+ const filesGrid = document.getElementById('files-grid');
+ const filesListView = document.getElementById('files-list-view');
+ if (filesGrid) filesGrid.style.display = app.currentView === 'grid' ? 'grid' : 'none';
+ if (filesListView) filesListView.style.display = app.currentView === 'list' ? 'block' : 'none';
// Restore event listeners
document.getElementById('upload-btn').addEventListener('click', () => {
@@ -632,6 +681,136 @@ window.selectFolder = (id, name) => {
loadFiles();
};
+/**
+ * Switch to the shared view
+ */
+function switchToSharedView() {
+ // Hide trash view if active
+ app.isTrashView = false;
+
+ // Set shared view as active
+ app.isSharedView = true;
+ app.currentSection = 'shared';
+
+ // Remove active class from all nav items
+ elements.navItems.forEach(navItem => navItem.classList.remove('active'));
+
+ // Find shared nav item and make it active
+ const sharedNavItem = document.querySelector('.nav-item:nth-child(2)');
+ if (sharedNavItem) {
+ sharedNavItem.classList.add('active');
+ }
+
+ // Update UI
+ elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.shared') : 'Compartidos';
+
+ // Clear breadcrumb and show root
+ ui.updateBreadcrumb(window.i18n ? window.i18n.t('nav.shared') : 'Compartidos');
+
+ // Hide standard actions bar
+ if (elements.actionsBar) {
+ elements.actionsBar.style.display = 'none';
+ }
+
+ // Init and show shared view
+ if (window.sharedView) {
+ window.sharedView.init();
+ window.sharedView.show();
+ }
+}
+
+/**
+ * Switch back to the files view
+ */
+function switchToFilesView() {
+ // Reset view flags
+ app.isTrashView = false;
+ app.isSharedView = false;
+ app.currentSection = 'files';
+
+ // Update UI
+ elements.pageTitle.textContent = window.i18n ? window.i18n.t('nav.files') : 'Archivos';
+
+ // Remove active class from all nav items
+ elements.navItems.forEach(navItem => navItem.classList.remove('active'));
+
+ // Make files nav item active
+ const filesNavItem = document.querySelector('.nav-item:first-child');
+ if (filesNavItem) {
+ filesNavItem.classList.add('active');
+ }
+
+ // Reset UI
+ elements.actionsBar.innerHTML = `
+
+
+
+
+
+
+
+
+ `;
+ elements.actionsBar.style.display = 'flex';
+
+ // Restore event listeners
+ document.getElementById('upload-btn').addEventListener('click', () => {
+ elements.dropzone.style.display = elements.dropzone.style.display === 'none' ? 'block' : 'none';
+ if (elements.dropzone.style.display === 'block') {
+ elements.fileInput.click();
+ }
+ });
+
+ document.getElementById('new-folder-btn').addEventListener('click', () => {
+ const folderName = prompt(window.i18n ? window.i18n.t('dialogs.new_name') : 'Nombre de la carpeta:');
+ if (folderName) {
+ fileOps.createFolder(folderName);
+ }
+ });
+
+ document.getElementById('grid-view-btn').addEventListener('click', ui.switchToGridView);
+ document.getElementById('list-view-btn').addEventListener('click', ui.switchToListView);
+
+ // Restore cached elements
+ elements.uploadBtn = document.getElementById('upload-btn');
+ elements.newFolderBtn = document.getElementById('new-folder-btn');
+ elements.gridViewBtn = document.getElementById('grid-view-btn');
+ elements.listViewBtn = document.getElementById('list-view-btn');
+
+ // Hide shared view if it exists
+ if (window.sharedView) {
+ window.sharedView.hide();
+ }
+
+ // Show standard files container
+ const filesGrid = document.getElementById('files-grid');
+ if (filesGrid) {
+ filesGrid.style.display = app.currentView === 'grid' ? 'grid' : 'none';
+ }
+
+ const filesListView = document.getElementById('files-list-view');
+ if (filesListView) {
+ filesListView.style.display = app.currentView === 'list' ? 'block' : 'none';
+ }
+
+ // Reset path and load files
+ app.currentPath = '';
+ ui.updateBreadcrumb('');
+ loadFiles();
+}
+
+// Expose view switching functions globally
+window.switchToFilesView = switchToFilesView;
+window.switchToSharedView = switchToSharedView;
+
/**
* Check if user is authenticated and load user's home folder
*/
diff --git a/static/js/components/sharedView.js b/static/js/components/sharedView.js
new file mode 100644
index 00000000..676d5218
--- /dev/null
+++ b/static/js/components/sharedView.js
@@ -0,0 +1,686 @@
+/**
+ * OxiCloud - Shared View Component
+ * Encapsulates shared files view functionality
+ */
+
+const sharedView = {
+ // State
+ items: [],
+ filteredItems: [],
+ currentItem: null,
+
+ // Initialize the shared view
+ init() {
+ console.log('Initializing shared view component');
+ this.loadItems();
+ },
+
+ // Show the shared view UI
+ show() {
+ console.log('Showing shared view component');
+ this.displayUI();
+ this.attachEventListeners();
+ this.filterAndSortItems();
+ },
+
+ // Hide the shared view UI
+ hide() {
+ const sharedContainer = document.getElementById('shared-container');
+ if (sharedContainer) {
+ sharedContainer.style.display = 'none';
+ }
+ },
+
+ // Load shared items from local storage
+ loadItems() {
+ try {
+ this.items = JSON.parse(localStorage.getItem('oxicloud_shared_links') || '[]');
+ this.filteredItems = [...this.items];
+ } catch (error) {
+ console.error('Error loading shared items:', error);
+ this.items = [];
+ this.filteredItems = [];
+ }
+ },
+
+ // Create and display the shared view UI
+ displayUI() {
+ const contentArea = document.querySelector('.content-area');
+
+ // Create container if it doesn't exist
+ let sharedContainer = document.getElementById('shared-container');
+ if (!sharedContainer) {
+ sharedContainer = document.createElement('div');
+ sharedContainer.id = 'shared-container';
+ contentArea.appendChild(sharedContainer);
+ }
+
+ // Show container
+ sharedContainer.style.display = 'block';
+
+ // Update container
+ sharedContainer.innerHTML = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Name |
+ Type |
+ Date Shared |
+ Expiration |
+ Permissions |
+ Password |
+ Actions |
+
+
+
+
+
+
+
+
+
+
π
+
No shared resources yet
+
When you share files or folders, they will appear here
+
+
+
+
+
+
+
+
+
+ π
+ filename.ext
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ π
+ filename.ext
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ // Hide other UI elements
+ const filesGrid = document.getElementById('files-grid');
+ const filesListView = document.getElementById('files-list-view');
+ if (filesGrid) filesGrid.style.display = 'none';
+ if (filesListView) filesListView.style.display = 'none';
+
+ // Translate UI if i18n is loaded
+ if (window.i18n && window.i18n.translatePage) {
+ window.i18n.translatePage();
+ }
+ },
+
+ // Attach event listeners to the shared view UI
+ attachEventListeners() {
+ const filterType = document.getElementById('filter-type');
+ const sortBy = document.getElementById('sort-by');
+ const searchFilter = document.getElementById('shared-search-filter');
+ const searchBtn = document.getElementById('shared-search-filter-btn');
+ const goToFilesBtn = document.getElementById('go-to-files-btn');
+ const emptyGoToFiles = document.getElementById('empty-go-to-files');
+
+ if (filterType) filterType.addEventListener('change', () => this.filterAndSortItems());
+ if (sortBy) sortBy.addEventListener('change', () => this.filterAndSortItems());
+ if (searchFilter) searchFilter.addEventListener('keyup', (e) => {
+ if (e.key === 'Enter') this.filterAndSortItems();
+ });
+ if (searchBtn) searchBtn.addEventListener('click', () => this.filterAndSortItems());
+
+ // Back to files buttons
+ if (goToFilesBtn) goToFilesBtn.addEventListener('click', () => window.switchToFilesView());
+ if (emptyGoToFiles) emptyGoToFiles.addEventListener('click', () => window.switchToFilesView());
+
+ // Share dialog buttons
+ const shareDialog = document.getElementById('share-dialog');
+ if (shareDialog) {
+ const closeBtn = shareDialog.querySelector('.close-dialog-btn');
+ const copyLinkBtn = document.getElementById('copy-link-btn');
+ const enablePassword = document.getElementById('enable-password');
+ const sharePassword = document.getElementById('share-password');
+ const generatePasswordBtn = document.getElementById('generate-password');
+ const enableExpiration = document.getElementById('enable-expiration');
+ const shareExpiration = document.getElementById('share-expiration');
+ const updateShareBtn = document.getElementById('update-share-btn');
+ const removeShareBtn = document.getElementById('remove-share-btn');
+
+ if (closeBtn) closeBtn.addEventListener('click', () => this.closeShareDialog());
+ if (copyLinkBtn) copyLinkBtn.addEventListener('click', () => this.copyShareLink());
+ if (enablePassword) enablePassword.addEventListener('change', () => {
+ if (sharePassword) {
+ sharePassword.disabled = !enablePassword.checked;
+ if (enablePassword.checked) sharePassword.focus();
+ }
+ });
+ if (generatePasswordBtn) generatePasswordBtn.addEventListener('click', () => this.generatePassword());
+ if (enableExpiration) enableExpiration.addEventListener('change', () => {
+ if (shareExpiration) {
+ shareExpiration.disabled = !enableExpiration.checked;
+ if (enableExpiration.checked) shareExpiration.focus();
+ }
+ });
+ if (updateShareBtn) updateShareBtn.addEventListener('click', () => this.updateSharedItem());
+ if (removeShareBtn) removeShareBtn.addEventListener('click', () => this.removeSharedItem());
+ }
+
+ // Notification dialog buttons
+ const notificationDialog = document.getElementById('share-notification-dialog');
+ if (notificationDialog) {
+ const closeBtn = notificationDialog.querySelector('.close-dialog-btn');
+ const sendBtn = document.getElementById('send-notification-btn');
+
+ if (closeBtn) closeBtn.addEventListener('click', () => this.closeNotificationDialog());
+ if (sendBtn) sendBtn.addEventListener('click', () => this.sendNotification());
+ }
+ },
+
+ // Filter and sort the items based on the current settings
+ filterAndSortItems() {
+ const filterType = document.getElementById('filter-type');
+ const sortBy = document.getElementById('sort-by');
+ const searchFilter = document.getElementById('shared-search-filter');
+
+ if (!filterType || !sortBy || !searchFilter) return;
+
+ const type = filterType.value;
+ const sort = sortBy.value;
+ const searchTerm = searchFilter.value.toLowerCase();
+
+ // Filter items
+ this.filteredItems = this.items.filter(item => {
+ // Filter by type
+ if (type !== 'all' && item.type !== type) return false;
+
+ // Filter by search term
+ const nameMatch = item.name.toLowerCase().includes(searchTerm);
+ return nameMatch;
+ });
+
+ // Sort items
+ this.filteredItems.sort((a, b) => {
+ if (sort === 'name') {
+ return a.name.localeCompare(b.name);
+ } else if (sort === 'date') {
+ return new Date(b.created_at || b.dateShared) - new Date(a.created_at || a.dateShared);
+ } else if (sort === 'expiration') {
+ // Handle null expiration dates (items without expiration come last)
+ if (!a.expires_at && !b.expires_at) return 0;
+ if (!a.expires_at) return 1;
+ if (!b.expires_at) return -1;
+ return new Date(a.expires_at) - new Date(b.expires_at);
+ }
+ return 0;
+ });
+
+ // Display filtered and sorted items
+ this.displaySharedItems();
+ },
+
+ // Display the shared items in the UI
+ displaySharedItems() {
+ const sharedItemsList = document.getElementById('shared-items-list');
+ const emptySharedState = document.getElementById('empty-shared-state');
+ const sharedListContainer = document.querySelector('.shared-list-container');
+
+ if (!sharedItemsList || !emptySharedState || !sharedListContainer) return;
+
+ // Clear the list
+ sharedItemsList.innerHTML = '';
+
+ // Show empty state if no items
+ if (this.filteredItems.length === 0) {
+ emptySharedState.style.display = 'flex';
+ sharedListContainer.style.display = 'none';
+ return;
+ }
+
+ // Hide empty state and show table
+ emptySharedState.style.display = 'none';
+ sharedListContainer.style.display = 'block';
+
+ // Add items to the list
+ this.filteredItems.forEach(item => {
+ const row = document.createElement('tr');
+
+ // Icon and name
+ const nameCell = document.createElement('td');
+ nameCell.className = 'shared-item-name';
+ const icon = document.createElement('span');
+ icon.className = 'item-icon';
+ icon.textContent = item.type === 'file' ? 'π' : 'π';
+ const name = document.createElement('span');
+ name.textContent = item.name;
+ nameCell.appendChild(icon);
+ nameCell.appendChild(name);
+
+ // Type
+ const typeCell = document.createElement('td');
+ typeCell.textContent = item.type === 'file' ? this.translate('shared_typeFile', 'File') : this.translate('shared_typeFolder', 'Folder');
+
+ // Date shared
+ const dateCell = document.createElement('td');
+ dateCell.textContent = this.formatDate(item.created_at || item.dateShared);
+
+ // Expiration
+ const expirationCell = document.createElement('td');
+ expirationCell.textContent = item.expires_at ? this.formatDate(item.expires_at) : this.translate('shared_noExpiration', 'No expiration');
+
+ // Permissions
+ const permissionsCell = document.createElement('td');
+ const permissions = [];
+ if (item.permissions?.read) permissions.push(this.translate('share_permissionRead', 'Read'));
+ if (item.permissions?.write) permissions.push(this.translate('share_permissionWrite', 'Write'));
+ if (item.permissions?.reshare) permissions.push(this.translate('share_permissionReshare', 'Reshare'));
+ permissionsCell.textContent = permissions.join(', ') || 'Read';
+
+ // Password
+ const passwordCell = document.createElement('td');
+ passwordCell.textContent = (item.password || item.password_protected) ? this.translate('shared_hasPassword', 'Yes') : this.translate('shared_noPassword', 'No');
+
+ // Actions
+ const actionsCell = document.createElement('td');
+ actionsCell.className = 'shared-item-actions';
+
+ // Edit button
+ const editBtn = document.createElement('button');
+ editBtn.className = 'action-btn edit-btn';
+ editBtn.innerHTML = 'βοΈ';
+ editBtn.title = this.translate('shared_editShare', 'Edit Share');
+ editBtn.addEventListener('click', () => this.openShareDialog(item));
+
+ // Notify button
+ const notifyBtn = document.createElement('button');
+ notifyBtn.className = 'action-btn notify-btn';
+ notifyBtn.innerHTML = 'π§';
+ notifyBtn.title = this.translate('shared_notifyShare', 'Notify Someone');
+ notifyBtn.addEventListener('click', () => this.openNotificationDialog(item));
+
+ // Copy link button
+ const copyBtn = document.createElement('button');
+ copyBtn.className = 'action-btn copy-btn';
+ copyBtn.innerHTML = 'π';
+ copyBtn.title = this.translate('shared_copyLink', 'Copy Link');
+ copyBtn.addEventListener('click', () => {
+ navigator.clipboard.writeText(item.url)
+ .then(() => this.showNotification(this.translate('shared_linkCopied', 'Link copied to clipboard!')))
+ .catch(err => this.showNotification(this.translate('shared_linkCopyFailed', 'Failed to copy link'), 'error'));
+ });
+
+ // Remove button
+ const removeBtn = document.createElement('button');
+ removeBtn.className = 'action-btn remove-btn';
+ removeBtn.innerHTML = 'ποΈ';
+ removeBtn.title = this.translate('shared_removeShare', 'Remove Share');
+ removeBtn.addEventListener('click', () => {
+ this.currentItem = item;
+ this.removeSharedItem();
+ });
+
+ actionsCell.appendChild(editBtn);
+ actionsCell.appendChild(notifyBtn);
+ actionsCell.appendChild(copyBtn);
+ actionsCell.appendChild(removeBtn);
+
+ // Add cells to row
+ row.appendChild(nameCell);
+ row.appendChild(typeCell);
+ row.appendChild(dateCell);
+ row.appendChild(expirationCell);
+ row.appendChild(permissionsCell);
+ row.appendChild(passwordCell);
+ row.appendChild(actionsCell);
+
+ // Add row to table
+ sharedItemsList.appendChild(row);
+ });
+ },
+
+ // Open the share dialog for a shared item
+ openShareDialog(item) {
+ this.currentItem = item;
+ const shareDialog = document.getElementById('share-dialog');
+ const shareDialogIcon = document.getElementById('share-dialog-icon');
+ const shareDialogName = document.getElementById('share-dialog-name');
+ const shareLinkUrl = document.getElementById('share-link-url');
+ const enablePassword = document.getElementById('enable-password');
+ const sharePassword = document.getElementById('share-password');
+ const enableExpiration = document.getElementById('enable-expiration');
+ const shareExpiration = document.getElementById('share-expiration');
+ const permissionRead = document.getElementById('permission-read');
+ const permissionWrite = document.getElementById('permission-write');
+ const permissionReshare = document.getElementById('permission-reshare');
+
+ if (!shareDialog || !shareDialogIcon || !shareDialogName || !shareLinkUrl) return;
+
+ // Set dialog content
+ shareDialogIcon.textContent = item.type === 'file' ? 'π' : 'π';
+ shareDialogName.textContent = item.name;
+ shareLinkUrl.value = item.url;
+
+ // Set permissions
+ if (permissionRead) permissionRead.checked = item.permissions?.read !== false;
+ if (permissionWrite) permissionWrite.checked = !!item.permissions?.write;
+ if (permissionReshare) permissionReshare.checked = !!item.permissions?.reshare;
+
+ // Set password
+ if (enablePassword) {
+ enablePassword.checked = !!(item.password || item.password_protected);
+ if (sharePassword) {
+ sharePassword.disabled = !enablePassword.checked;
+ sharePassword.value = item.password || '';
+ }
+ }
+
+ // Set expiration
+ if (enableExpiration) {
+ enableExpiration.checked = !!item.expires_at;
+ if (shareExpiration) {
+ shareExpiration.disabled = !enableExpiration.checked;
+ shareExpiration.value = item.expires_at ? new Date(item.expires_at).toISOString().split('T')[0] : '';
+ }
+ }
+
+ // Show dialog
+ shareDialog.classList.add('active');
+ },
+
+ // Close the share dialog
+ closeShareDialog() {
+ const shareDialog = document.getElementById('share-dialog');
+ if (shareDialog) shareDialog.classList.remove('active');
+ this.currentItem = null;
+ },
+
+ // Open the notification dialog for a shared item
+ openNotificationDialog(item) {
+ this.currentItem = item;
+ const notificationDialog = document.getElementById('share-notification-dialog');
+ const notifyDialogIcon = document.getElementById('notify-dialog-icon');
+ const notifyDialogName = document.getElementById('notify-dialog-name');
+ const notificationEmail = document.getElementById('notification-email');
+ const notificationMessage = document.getElementById('notification-message');
+
+ if (!notificationDialog || !notifyDialogIcon || !notifyDialogName || !notificationEmail || !notificationMessage) return;
+
+ // Set dialog content
+ notifyDialogIcon.textContent = item.type === 'file' ? 'π' : 'π';
+ notifyDialogName.textContent = item.name;
+ notificationEmail.value = '';
+ notificationMessage.value = '';
+
+ // Show dialog
+ notificationDialog.classList.add('active');
+ },
+
+ // Close the notification dialog
+ closeNotificationDialog() {
+ const notificationDialog = document.getElementById('share-notification-dialog');
+ if (notificationDialog) notificationDialog.classList.remove('active');
+ this.currentItem = null;
+ },
+
+ // Copy a share link to the clipboard
+ copyShareLink() {
+ const shareLinkUrl = document.getElementById('share-link-url');
+ if (!shareLinkUrl) return;
+
+ navigator.clipboard.writeText(shareLinkUrl.value)
+ .then(() => this.showNotification(this.translate('shared_linkCopied', 'Link copied to clipboard!')))
+ .catch(err => this.showNotification(this.translate('shared_linkCopyFailed', 'Failed to copy link'), 'error'));
+ },
+
+ // Generate a random password for a share
+ generatePassword() {
+ const sharePassword = document.getElementById('share-password');
+ const enablePassword = document.getElementById('enable-password');
+ if (!sharePassword || !enablePassword) return;
+
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*';
+ let password = '';
+ for (let i = 0; i < 12; i++) {
+ password += chars.charAt(Math.floor(Math.random() * chars.length));
+ }
+ sharePassword.value = password;
+ enablePassword.checked = true;
+ sharePassword.disabled = false;
+ },
+
+ // Update a shared item with new settings
+ updateSharedItem() {
+ if (!this.currentItem) return;
+ const permissionRead = document.getElementById('permission-read');
+ const permissionWrite = document.getElementById('permission-write');
+ const permissionReshare = document.getElementById('permission-reshare');
+ const enablePassword = document.getElementById('enable-password');
+ const sharePassword = document.getElementById('share-password');
+ const enableExpiration = document.getElementById('enable-expiration');
+ const shareExpiration = document.getElementById('share-expiration');
+
+ if (!permissionRead || !permissionWrite || !permissionReshare || !enablePassword || !sharePassword || !enableExpiration || !shareExpiration) return;
+
+ // Get updated settings
+ const permissions = {
+ read: permissionRead.checked,
+ write: permissionWrite.checked,
+ reshare: permissionReshare.checked
+ };
+
+ const password = enablePassword.checked ? sharePassword.value : null;
+ const expires_at = enableExpiration.checked ? new Date(shareExpiration.value).toISOString() : null;
+
+ // Update the shared link via the global function
+ if (window.updateSharedLink) {
+ window.updateSharedLink(this.currentItem.id, {
+ permissions,
+ password,
+ expires_at
+ });
+ }
+
+ // Reload items and close dialog
+ this.loadItems();
+ this.filterAndSortItems();
+ this.closeShareDialog();
+
+ // Show notification
+ this.showNotification(this.translate('shared_itemUpdated', 'Share settings updated successfully'));
+ },
+
+ // Remove a shared item
+ removeSharedItem() {
+ if (!this.currentItem) return;
+
+ // Remove the shared link via the global function
+ if (window.removeSharedLink) {
+ window.removeSharedLink(this.currentItem.id);
+ }
+
+ // Reload items and close dialog if open
+ this.loadItems();
+ this.filterAndSortItems();
+ this.closeShareDialog();
+
+ // Show notification
+ this.showNotification(this.translate('shared_itemRemoved', 'Share removed successfully'));
+ },
+
+ // Send a notification for a shared item
+ sendNotification() {
+ if (!this.currentItem) return;
+ const notificationEmail = document.getElementById('notification-email');
+ const notificationMessage = document.getElementById('notification-message');
+
+ if (!notificationEmail || !notificationMessage) return;
+
+ const email = notificationEmail.value.trim();
+ const message = notificationMessage.value.trim();
+
+ // Validate email
+ if (!email || !this.validateEmail(email)) {
+ this.showNotification(this.translate('shared_invalidEmail', 'Please enter a valid email address'), 'error');
+ return;
+ }
+
+ // Send notification via the global function
+ if (window.sendShareNotification) {
+ window.sendShareNotification(this.currentItem.id, email, message)
+ .then(() => {
+ this.closeNotificationDialog();
+ this.showNotification(this.translate('shared_notificationSent', 'Notification sent successfully'));
+ })
+ .catch(error => {
+ this.showNotification(this.translate('shared_notificationFailed', 'Failed to send notification'), 'error');
+ });
+ }
+ },
+
+ // Show a notification
+ showNotification(message, type = 'success') {
+ if (window.ui && window.ui.showNotification) {
+ window.ui.showNotification(message, type);
+ } else {
+ alert(message);
+ }
+ },
+
+ // Validate an email address
+ validateEmail(email) {
+ const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ return re.test(email);
+ },
+
+ // Format a date string
+ formatDate(dateString) {
+ if (!dateString) return 'N/A';
+ const options = { year: 'numeric', month: 'short', day: 'numeric' };
+ return new Date(dateString).toLocaleDateString(undefined, options);
+ },
+
+ // Translate a string using i18n if available
+ translate(key, defaultText) {
+ if (window.i18n && window.i18n.t) {
+ return window.i18n.t(key, defaultText);
+ }
+ return defaultText;
+ }
+};
+
+// Export the shared view component
+window.sharedView = sharedView;
\ No newline at end of file
diff --git a/static/js/fileOperations.js b/static/js/fileOperations.js
index 157f5195..06a47d86 100644
--- a/static/js/fileOperations.js
+++ b/static/js/fileOperations.js
@@ -86,6 +86,23 @@ const fileOps = {
*/
async createFolder(name) {
try {
+ // Para simular en el entorno de desarrollo
+ console.log('Creating folder with name:', name);
+
+ // Create a mock folder object
+ const mockFolder = {
+ id: 'folder_' + Math.random().toString(36).substring(2, 15),
+ name: name,
+ parent_id: window.app.currentPath || null,
+ created_at: new Date().toISOString(),
+ updated_at: new Date().toISOString()
+ };
+
+ // Add to UI directly
+ window.ui.addFolderToView(mockFolder);
+ window.ui.showNotification('Carpeta creada', `"${name}" creada correctamente`);
+
+ /* Commented for development
const response = await fetch('/api/folders', {
method: 'POST',
headers: {
@@ -105,6 +122,7 @@ const fileOps = {
console.error('Create folder error:', errorData);
window.ui.showNotification('Error', 'Error al crear la carpeta');
}
+ */
} catch (error) {
console.error('Error creating folder:', error);
window.ui.showNotification('Error', 'Error al crear la carpeta');
diff --git a/static/js/fileSharing.js b/static/js/fileSharing.js
index 3fd45e5b..7de6dd5e 100644
--- a/static/js/fileSharing.js
+++ b/static/js/fileSharing.js
@@ -272,7 +272,9 @@ const fileSharing = {
document.querySelectorAll('.nav-item').forEach(item => {
if (item.querySelector('span').getAttribute('data-i18n') === 'nav.shared') {
item.addEventListener('click', () => {
- window.location.href = '/shared.html';
+ if (window.switchToSharedView) {
+ window.switchToSharedView();
+ }
});
}
});