Files
lucent-laravel/front/js/entry/RecordEditEntry/fields/FileField.svelte
T
2026-01-13 18:20:01 +02:00

223 lines
7.0 KiB
Svelte

<script>
import { get, post } from "../../../modules/remote";
import { uploadFile } from "../../../modules/upload";
import { getApp } from "../../../app";
import FieldLabel from "./FieldLabel.svelte";
import FieldError from "./FieldError.svelte";
import Sortable from "../../../common/Sortable.svelte";
let {
channel,
record,
schemaField,
dataField,
locale,
validationError,
edgeRecordPreviews,
filesPreviews,
} = $props();
let originalValue = dataField?.value ?? schemaField.props.default;
let newValue = $state(originalValue);
let valuesChanged = $derived(newValue !== originalValue);
let errorMessage = $state("");
let filesInProgress = $state([]);
let uploadInProgress = $derived(filesInProgress.length > 0);
// let validationErrorState = $state(validationError);
const app = getApp();
let suggestionsLoaded = $state(false);
let suggestions = $state([]);
let selectedFilesIds = $state([]);
let dialog = $state();
function handleModalOpen(e) {
// Add logic to handle adding a record
dialog.showModal();
if (suggestionsLoaded) {
return;
}
get(app.url("records/files"), { recordId: record.id }, (data, err) => {
suggestionsLoaded = true;
suggestions = data;
});
}
function handleModalClose(e) {
dialog.close();
}
function handleInsertSelected() {
suggestionsLoaded = false;
post(
app.url("records/files"),
{
toIds: selectedFilesIds,
from: record.id,
fieldId: schemaField.id,
locale: locale,
},
(data, err) => {
suggestionsLoaded = true;
dialog.close();
edgeRecordPreviews = data.edgeRecordPreviews;
validationError = data.validationError;
},
);
}
function handleSortUpdate(updatedEdges) {
// let updatedFieldIds = updatedFields.map((f) => f.id);
// fields = fields.filter((f) => !updatedFieldIds.includes(f.id));
// fields = [...fields, ...updatedFields];
post(
app.url("records/sort-edges"),
{
ids: updatedEdges.map((e) => e.edge.id),
},
(data, err) => {
edgeRecordPreviews = updatedEdges;
},
);
}
function handleRemoveEdge(edgeId) {
post(
app.url("edges/delete"),
{
id: edgeId,
from: record.id,
fieldId: schemaField.id,
locale: locale,
},
(data, err) => {
edgeRecordPreviews = edgeRecordPreviews.filter(
(e) => e.edge.id !== edgeId,
);
validationError = data.validationError;
},
);
}
function handleFilesUpload(e) {
let files = e.target.files ? [...e.target.files] : [];
let filesUploaded = files.map((file) => {
let fileInProgress = {
pct: 0,
hasFailed: false,
name: file.name,
};
filesInProgress.push(fileInProgress);
const progress = ({ pct, isComplete }) => {
filesInProgress.find((f) => f.name === file.name).pct = pct;
if (isComplete) {
filesInProgress = filesInProgress.filter(
(f) => f.name !== file.name,
);
}
};
const error = (errorMessage) => {
filesInProgress.find((f) => f.name === file.name).hasFailed =
true;
};
uploadFile(
file,
record.id,
schemaField.id,
locale,
progress,
error,
);
});
}
</script>
<div style="min-width: 400px;">
<label>
<FieldLabel {locale} {channel} {schemaField}></FieldLabel>
</label>
<FieldError {schemaField} {validationError}></FieldError>
<button onclick={handleModalOpen}>Choose files</button>
<dialog bind:this={dialog}>
<article>
<header>
<button onclick={handleModalClose} aria-label="Close" rel="prev"
></button>
<p>
<strong>Records</strong>
</p>
</header>
{#if suggestionsLoaded}
<form>
<button onclick={handleInsertSelected}>
Insert selected
</button>
<input
oninput={handleFilesUpload}
type="file"
multiple
disabled={uploadInProgress}
/>
{#each filesInProgress as fileInProgress}
<div>
<span>{fileInProgress.name}</span>
<progress value={fileInProgress.pct} max="100" />
{#if fileInProgress.hasFailed}
<span>Error</span>
{/if}
</div>
{/each}
<table>
<tbody>
{#each suggestions as suggestion}
<tr>
<td>
<input
type="checkbox"
value={suggestion.id}
bind:group={selectedFilesIds}
/>
</td>
<td>
<a href="#">{suggestion.name}</a>
</td>
<td> </td>
</tr>
{/each}
</tbody>
</table>
</form>
{:else}
<progress />
{/if}
</article>
</dialog>
<div>
{#if filesPreviews.length == 0}
No files exist
{:else}
<Sortable
onUpdate={handleSortUpdate}
items={filesPreviews}
itemKey="recordFile.id"
>
{#snippet itemView(filesPreview)}
<div>
<a href="#">{filesPreview.file.name}</a>
<button
onclick={(e) =>
handleRemoveEdge(filesPreview.recordFile.id)}
>remove</button
>
</div>
{/snippet}
</Sortable>
{/if}
</div>
</div>