|
|
@@ -2,22 +2,18 @@ import React, {
|
|
|
useState, useCallback, useEffect, useMemo,
|
|
|
} from 'react';
|
|
|
|
|
|
-// Use the refactored hook and its exported type
|
|
|
import { useContentDisposition, type ContentDispositionSettings } from '../../../services/AdminContentDispositionSettings';
|
|
|
+import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
|
|
|
+
|
|
|
|
|
|
-/**
|
|
|
- * Helper function to ensure the mime type is normalized / clean before use.
|
|
|
- */
|
|
|
const normalizeMimeType = (mimeType: string): string => mimeType.trim().toLowerCase();
|
|
|
|
|
|
-// Helper to remove a mimeType from an array
|
|
|
const removeMimeTypeFromArray = (array: string[], mimeType: string): string[] => (
|
|
|
array.filter(m => m !== mimeType)
|
|
|
);
|
|
|
|
|
|
const ContentDispositionSettings: React.FC = () => {
|
|
|
|
|
|
- // 1. Updated destructuring from the refactored hook
|
|
|
const {
|
|
|
currentSettings,
|
|
|
isLoading,
|
|
|
@@ -25,14 +21,12 @@ const ContentDispositionSettings: React.FC = () => {
|
|
|
updateSettings,
|
|
|
} = useContentDisposition();
|
|
|
|
|
|
- // 2. State for pending changes and input
|
|
|
const [pendingSettings, setPendingSettings] = useState<ContentDispositionSettings | null>(null);
|
|
|
const [currentInput, setCurrentInput] = useState<string>('');
|
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
|
|
useEffect(() => {
|
|
|
if (currentSettings) {
|
|
|
- // Deep copy to prevent mutating the original settings object
|
|
|
setPendingSettings({
|
|
|
inlineMimeTypes: [...currentSettings.inlineMimeTypes],
|
|
|
attachmentMimeTypes: [...currentSettings.attachmentMimeTypes],
|
|
|
@@ -53,7 +47,6 @@ const ContentDispositionSettings: React.FC = () => {
|
|
|
}, [currentSettings, pendingSettings]);
|
|
|
|
|
|
|
|
|
- // 3. Handlers for setting (adding to pending state)
|
|
|
const handleSetMimeType = useCallback((disposition: 'inline' | 'attachment') => {
|
|
|
const mimeType = normalizeMimeType(currentInput);
|
|
|
if (!mimeType) return;
|
|
|
@@ -65,13 +58,13 @@ const ContentDispositionSettings: React.FC = () => {
|
|
|
const newSettings = { ...prev };
|
|
|
const otherDisposition = disposition === 'inline' ? 'attachment' : 'inline';
|
|
|
|
|
|
- // 1. Add to the target list (if not already present)
|
|
|
+ // Add to the target list (if not already present)
|
|
|
const targetKey = `${disposition}MimeTypes` as keyof ContentDispositionSettings;
|
|
|
if (!newSettings[targetKey].includes(mimeType)) {
|
|
|
newSettings[targetKey] = [...newSettings[targetKey], mimeType];
|
|
|
}
|
|
|
|
|
|
- // 2. Remove from the other list
|
|
|
+ // Remove from the other list
|
|
|
const otherKey = `${otherDisposition}MimeTypes` as keyof ContentDispositionSettings;
|
|
|
newSettings[otherKey] = removeMimeTypeFromArray(newSettings[otherKey], mimeType);
|
|
|
|
|
|
@@ -96,20 +89,7 @@ const ContentDispositionSettings: React.FC = () => {
|
|
|
});
|
|
|
}, []);
|
|
|
|
|
|
- // Handler for resetting to the last saved settings
|
|
|
- const handleReset = useCallback(() => {
|
|
|
- setError(null);
|
|
|
- if (currentSettings) {
|
|
|
- // Revert pending changes to the last fetched/saved state
|
|
|
- setPendingSettings({
|
|
|
- inlineMimeTypes: [...currentSettings.inlineMimeTypes],
|
|
|
- attachmentMimeTypes: [...currentSettings.attachmentMimeTypes],
|
|
|
- });
|
|
|
- }
|
|
|
- }, [currentSettings]);
|
|
|
-
|
|
|
-
|
|
|
- // 4. Handler for updating (saving to server)
|
|
|
+ // Handler for updating pending change
|
|
|
const handleUpdate = useCallback(async(): Promise<void> => {
|
|
|
if (!pendingSettings || !hasPendingChanges || isUpdating) return;
|
|
|
|
|
|
@@ -120,7 +100,6 @@ const ContentDispositionSettings: React.FC = () => {
|
|
|
catch (err) {
|
|
|
const errorMessage = (err instanceof Error) ? err.message : 'An unknown error occurred during update.';
|
|
|
setError(`Failed to update settings: ${errorMessage}`);
|
|
|
- console.error('Failed to update settings:', err);
|
|
|
}
|
|
|
}, [pendingSettings, hasPendingChanges, isUpdating, updateSettings]);
|
|
|
|
|
|
@@ -131,112 +110,109 @@ const ContentDispositionSettings: React.FC = () => {
|
|
|
const renderInlineMimeTypes = displaySettings.inlineMimeTypes;
|
|
|
const renderAttachmentMimeTypes = displaySettings.attachmentMimeTypes;
|
|
|
|
|
|
- // 5. Render logic
|
|
|
return (
|
|
|
- <div>
|
|
|
- <h2>Content-Disposition Mime Type Settings ⚙️</h2>
|
|
|
-
|
|
|
- {/* Input and Add Buttons */}
|
|
|
- <div>
|
|
|
- <input
|
|
|
- type="text"
|
|
|
- value={currentInput}
|
|
|
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => setCurrentInput(e.target.value)}
|
|
|
- placeholder="e.g., image/png"
|
|
|
- />
|
|
|
- <button
|
|
|
- type="button"
|
|
|
- onClick={handleSetInline}
|
|
|
- disabled={!currentInput.trim() || isUpdating}
|
|
|
- >
|
|
|
- Add Inline
|
|
|
- </button>
|
|
|
- <button
|
|
|
- type="button"
|
|
|
- onClick={handleSetAttachment}
|
|
|
- disabled={!currentInput.trim() || isUpdating}
|
|
|
- >
|
|
|
- Add Attachment
|
|
|
- </button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <p style={{ fontSize: '12px', color: '#666' }}>
|
|
|
- Note: Adding a mime type will **automatically remove it** from the other list if it exists there.
|
|
|
- </p>
|
|
|
-
|
|
|
- {/* Error Display */}
|
|
|
- {error && (
|
|
|
- <div>
|
|
|
- **Error:** {error}
|
|
|
- </div>
|
|
|
- )}
|
|
|
-
|
|
|
- {/* Update and Reset Buttons */}
|
|
|
- <div style={{ marginBottom: '20px', display: 'flex', gap: '10px' }}>
|
|
|
- <button
|
|
|
- type="button"
|
|
|
- onClick={handleUpdate}
|
|
|
- disabled={!hasPendingChanges || isUpdating}
|
|
|
- >
|
|
|
- {isUpdating ? 'Updating...' : 'Update Settings'}
|
|
|
- </button>
|
|
|
- <button
|
|
|
- type="button"
|
|
|
- onClick={handleReset}
|
|
|
- disabled={!hasPendingChanges || isUpdating}
|
|
|
- >
|
|
|
- Reset Changes
|
|
|
- </button>
|
|
|
- </div>
|
|
|
-
|
|
|
-
|
|
|
- <hr />
|
|
|
-
|
|
|
- <div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
|
|
-
|
|
|
- {/* INLINE List */}
|
|
|
- <div>
|
|
|
- <h3>Inline Mime Types (Viewable)</h3>
|
|
|
- <ul>
|
|
|
- {renderInlineMimeTypes.length === 0 && <li>No inline mime types set.</li>}
|
|
|
- {renderInlineMimeTypes.map((mimeType: string) => (
|
|
|
- <li
|
|
|
- key={mimeType}
|
|
|
- >
|
|
|
- {mimeType}
|
|
|
+ <div className="row">
|
|
|
+ <div className="col-12">
|
|
|
+ <h2 className="pb-2">Content-Disposition Mime Type Settings</h2>
|
|
|
+
|
|
|
+ {/* INPUT SECTION */}
|
|
|
+ <div className="card shadow-sm mb-4">
|
|
|
+ <div className="card-body">
|
|
|
+ <div className="form-group">
|
|
|
+ <label className="form-label fw-bold">Add New Mime Type</label>
|
|
|
+ <div className="d-flex align-items-center gap-2">
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ className="form-control"
|
|
|
+ value={currentInput}
|
|
|
+ onChange={e => setCurrentInput(e.target.value)}
|
|
|
+ placeholder="e.g., image/png"
|
|
|
+ />
|
|
|
<button
|
|
|
+ className="btn btn-primary px-3"
|
|
|
type="button"
|
|
|
- onClick={() => handleRemove(mimeType, 'inline')}
|
|
|
- disabled={isUpdating}
|
|
|
+ onClick={handleSetInline}
|
|
|
+ disabled={!currentInput.trim() || isUpdating}
|
|
|
>
|
|
|
- Remove
|
|
|
+ Inline
|
|
|
</button>
|
|
|
- </li>
|
|
|
- ))}
|
|
|
- </ul>
|
|
|
- </div>
|
|
|
-
|
|
|
- {/* ATTACHMENT List */}
|
|
|
- <div>
|
|
|
- <h3>Attachment Mime Types (Forces Download)</h3>
|
|
|
- <ul>
|
|
|
- {renderAttachmentMimeTypes.length === 0 && <li>No attachment mime types set.</li>}
|
|
|
- {renderAttachmentMimeTypes.map((mimeType: string) => (
|
|
|
- <li
|
|
|
- key={mimeType}
|
|
|
- >
|
|
|
- {mimeType}
|
|
|
<button
|
|
|
+ className="btn btn-primary text-white px-3"
|
|
|
type="button"
|
|
|
- onClick={() => handleRemove(mimeType, 'attachment')}
|
|
|
- disabled={isUpdating}
|
|
|
+ onClick={handleSetAttachment}
|
|
|
+ disabled={!currentInput.trim() || isUpdating}
|
|
|
>
|
|
|
- Remove
|
|
|
+ Attachment
|
|
|
</button>
|
|
|
- </li>
|
|
|
- ))}
|
|
|
- </ul>
|
|
|
+ </div>
|
|
|
+ <small className="form-text text-muted mt-2 d-block">
|
|
|
+ Note: Adding a mime type will <strong>automatically remove it</strong> from the other list.
|
|
|
+ </small>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {error && (
|
|
|
+ <div className="alert alert-danger">{error}</div>
|
|
|
+ )}
|
|
|
+
|
|
|
+ <div className="row">
|
|
|
+ {/* INLINE LIST COLUMN */}
|
|
|
+ <div className="col-md-6 col-sm-12 align-self-start">
|
|
|
+ <div className="card">
|
|
|
+ <div className="card-header"><span className="fw-bold">Inline Mime Types</span></div>
|
|
|
+ <div className="card-body">
|
|
|
+ <ul className="list-group list-group-flush">
|
|
|
+ {renderInlineMimeTypes.length === 0 && <li className="list-group-item text-muted">No inline types set.</li>}
|
|
|
+ {renderInlineMimeTypes.map((mimeType: string) => (
|
|
|
+ <li key={mimeType} className="list-group-item d-flex justify-content-between align-items-center">
|
|
|
+ <code>{mimeType}</code>
|
|
|
+ <button
|
|
|
+ type="button" // Fixes the lint error
|
|
|
+ className="btn btn-sm btn-outline-danger"
|
|
|
+ onClick={() => handleRemove(mimeType, 'inline')}
|
|
|
+ disabled={isUpdating}
|
|
|
+ >
|
|
|
+ Remove
|
|
|
+ </button>
|
|
|
+ </li>
|
|
|
+ ))}
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* ATTACHMENT LIST COLUMN */}
|
|
|
+ <div className="col-md-6 col-sm-12 align-self-start">
|
|
|
+ <div className="card">
|
|
|
+ <div className="card-header"><span className="fw-bold">Attachment Mime Types</span></div>
|
|
|
+ <div className="card-body">
|
|
|
+ <ul className="list-group list-group-flush">
|
|
|
+ {renderAttachmentMimeTypes.length === 0 && <li className="list-group-item text-muted">No attachment types set.</li>}
|
|
|
+ {renderAttachmentMimeTypes.map((mimeType: string) => (
|
|
|
+ <li key={mimeType} className="list-group-item d-flex justify-content-between align-items-center">
|
|
|
+ <code>{mimeType}</code>
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ className="btn btn-sm btn-outline-danger"
|
|
|
+ onClick={() => handleRemove(mimeType, 'attachment')}
|
|
|
+ disabled={isUpdating}
|
|
|
+ >
|
|
|
+ Remove
|
|
|
+ </button>
|
|
|
+ </li>
|
|
|
+ ))}
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
</div>
|
|
|
+
|
|
|
+ <AdminUpdateButtonRow
|
|
|
+ onClick={handleUpdate}
|
|
|
+ disabled={!hasPendingChanges || isUpdating}
|
|
|
+ />
|
|
|
</div>
|
|
|
</div>
|
|
|
);
|