feat: add dataset change detection and form submission composables
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 6s
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 6s
- Implemented `useDatasetChangeDetection` for tracking unsaved changes in dataset forms, including comparisons for licenses, basic properties, files, coverage, and more. - Added `useDatasetFormSubmission` for handling dataset form submissions with validation, success/error handling, and auto-save functionality.
This commit is contained in:
parent
0680879e2f
commit
5efddc2a58
4 changed files with 1474 additions and 436 deletions
217
resources/js/composables/useDatasetFormSubmission.ts
Normal file
217
resources/js/composables/useDatasetFormSubmission.ts
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
// ====================================================================
|
||||
// FILE: composables/useDatasetFormSubmission.ts
|
||||
// ====================================================================
|
||||
|
||||
import { Ref } from 'vue';
|
||||
import type { Dataset, License } from '@/Dataset';
|
||||
import { InertiaForm } from '@inertiajs/vue3';
|
||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
import { notify } from '@/notiwind';
|
||||
|
||||
interface SubmissionOptions {
|
||||
onSuccess?: (updatedDataset: Dataset) => void;
|
||||
onError?: (errors: any) => void;
|
||||
showNotification?: boolean;
|
||||
}
|
||||
|
||||
export function useDatasetFormSubmission(
|
||||
form: InertiaForm<Dataset>,
|
||||
originalDataset: Ref<Dataset>
|
||||
) {
|
||||
/**
|
||||
* Check if object has id attribute (type guard)
|
||||
*/
|
||||
const hasIdAttribute = (obj: License | number): obj is License => {
|
||||
return typeof obj === 'object' && 'id' in obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transform licenses for submission
|
||||
*/
|
||||
const transformLicenses = (): string[] => {
|
||||
return form.licenses.map((obj) => {
|
||||
if (hasIdAttribute(obj)) {
|
||||
return obj.id.toString();
|
||||
}
|
||||
return String(obj);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate form before submission
|
||||
*/
|
||||
const validateForm = (): { valid: boolean; errors: string[] } => {
|
||||
const errors: string[] = [];
|
||||
|
||||
// Required field validations
|
||||
if (!form.language) {
|
||||
errors.push('Language is required');
|
||||
}
|
||||
if (!form.type) {
|
||||
errors.push('Dataset type is required');
|
||||
}
|
||||
if (!form.creating_corporation) {
|
||||
errors.push('Creating corporation is required');
|
||||
}
|
||||
if (!form.titles || !form.titles[0]?.value) {
|
||||
errors.push('Main title is required');
|
||||
}
|
||||
if (!form.descriptions || !form.descriptions[0]?.value) {
|
||||
errors.push('Main abstract is required');
|
||||
}
|
||||
|
||||
return {
|
||||
valid: errors.length === 0,
|
||||
errors,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle successful submission
|
||||
*/
|
||||
const handleSubmitSuccess = (
|
||||
updatedDataset: Dataset,
|
||||
showNotification: boolean = true
|
||||
) => {
|
||||
// Clear deletion arrays
|
||||
if (updatedDataset.subjectsToDelete) {
|
||||
updatedDataset.subjectsToDelete = [];
|
||||
}
|
||||
if (updatedDataset.referencesToDelete) {
|
||||
updatedDataset.referencesToDelete = [];
|
||||
}
|
||||
|
||||
// Update form with fresh data from server
|
||||
Object.keys(updatedDataset).forEach((key) => {
|
||||
if (key !== 'licenses' && key in form) {
|
||||
form[key] = updatedDataset[key];
|
||||
}
|
||||
});
|
||||
|
||||
// Clear form errors
|
||||
form.clearErrors();
|
||||
|
||||
// Update original dataset reference
|
||||
originalDataset.value = JSON.parse(JSON.stringify(updatedDataset));
|
||||
|
||||
// Show success notification
|
||||
if (showNotification) {
|
||||
notify(
|
||||
{
|
||||
type: 'success',
|
||||
title: 'Success',
|
||||
text: 'Dataset updated successfully',
|
||||
},
|
||||
4000,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle submission errors
|
||||
*/
|
||||
const handleSubmitError = (errors: any) => {
|
||||
console.error('Submission errors:', errors);
|
||||
|
||||
notify(
|
||||
{
|
||||
type: 'error',
|
||||
title: 'Error',
|
||||
text: 'Failed to update dataset. Please check the form for errors.',
|
||||
},
|
||||
5000,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Submit form with auto-save behavior
|
||||
*/
|
||||
const submitWithAutoSave = async (
|
||||
options: SubmissionOptions = {}
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const route = stardust.route('editor.dataset.update', [form.id]);
|
||||
const licenses = transformLicenses();
|
||||
|
||||
await form
|
||||
.transform((data) => ({
|
||||
...data,
|
||||
licenses,
|
||||
rights: 'true',
|
||||
}))
|
||||
.put(route, {
|
||||
onSuccess: (page) => {
|
||||
const updatedDataset = page.props.dataset || form.data();
|
||||
handleSubmitSuccess(
|
||||
updatedDataset,
|
||||
options.showNotification ?? true
|
||||
);
|
||||
|
||||
if (options.onSuccess) {
|
||||
options.onSuccess(updatedDataset);
|
||||
}
|
||||
},
|
||||
onError: (errors) => {
|
||||
handleSubmitError(errors);
|
||||
|
||||
if (options.onError) {
|
||||
options.onError(errors);
|
||||
}
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Unexpected error during submission:', error);
|
||||
notify(
|
||||
{
|
||||
type: 'error',
|
||||
title: 'Error',
|
||||
text: 'An unexpected error occurred. Please try again.',
|
||||
},
|
||||
5000,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Standard submit with validation
|
||||
*/
|
||||
const submit = async (
|
||||
options: SubmissionOptions = {}
|
||||
): Promise<void> => {
|
||||
// Validate form first
|
||||
const validation = validateForm();
|
||||
if (!validation.valid) {
|
||||
notify(
|
||||
{
|
||||
type: 'error',
|
||||
title: 'Validation Error',
|
||||
text: validation.errors.join(', '),
|
||||
},
|
||||
5000,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await submitWithAutoSave({
|
||||
...options,
|
||||
showNotification: true,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Silent submit without notification (for auto-save)
|
||||
*/
|
||||
const submitSilently = async (): Promise<void> => {
|
||||
await submitWithAutoSave({
|
||||
showNotification: false,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
submit,
|
||||
submitWithAutoSave,
|
||||
submitSilently,
|
||||
validateForm,
|
||||
transformLicenses,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue