final fe part 1

This commit is contained in:
Edd
2026-01-23 03:01:13 +00:00
parent 3570527bbf
commit b9ad7879a6
5 changed files with 909 additions and 892 deletions
+54 -25
View File
@@ -5,12 +5,14 @@ const props = defineProps<{
isOpen: boolean;
api: string;
token: string | null;
postToEdit?: any;
}>();
const emit = defineEmits(['close', 'refresh']);
interface Tag { id: number; name: string; }
const notifications = useNotificationStore();
const isSubmitting = ref(false);
const availableTags = ref<Tag[]>([]);
const errors = reactive({
@@ -73,26 +75,41 @@ async function submitPublication() {
authors: uploadForm.authors,
type: uploadForm.type,
abstract: uploadForm.abstract,
tags: uploadForm.selectedTagIds,
// Sending fixed defaults for removed fields to maintain API compatibility if needed
publication_date: new Date().toISOString().split('T')[0],
is_confidential: false
tags: uploadForm.selectedTagIds
};
const formData = new FormData();
if (uploadForm.file) formData.append('file', uploadForm.file);
formData.append('data', JSON.stringify(metadata));
const isEditing = !!props.postToEdit;
const url = isEditing
? `${props.api}/publications/${props.postToEdit.id}`
: `${props.api}/publications`;
await $fetch(`${props.api}/publications`, {
method: 'POST',
headers: { Authorization: `Bearer ${props.token}` },
body: formData
let requestBody: any;
let headers: Record<string, string> = {
Authorization: `Bearer ${props.token}`
};
if (!isEditing || uploadForm.file) {
const formData = new FormData();
if (uploadForm.file) formData.append('file', uploadForm.file);
formData.append('data', JSON.stringify(metadata));
requestBody = formData;
}
else {
requestBody = metadata;
}
await $fetch(url, {
method: isEditing ? 'PATCH' : 'POST',
headers,
body: requestBody
});
notifications.success(`Publication ${isEditing ? "updated" : "created"}`);
emit('refresh');
closeModal();
} catch (error) {
alert("Upload failed.");
console.error("Submission error:", error);
notifications.error("Operation failed");
} finally {
isSubmitting.value = false;
}
@@ -113,19 +130,34 @@ function handleFileChange(event: Event) {
}
function closeModal() {
uploadForm.title = '';
uploadForm.abstract = '';
uploadForm.type = 'CONFERENCE_PAPER';
uploadForm.newAuthorName = '';
uploadForm.authors = [];
uploadForm.selectedTagIds = [];
uploadForm.file = null;
emit('close');
}
watch(() => props.isOpen, (newVal) => {
if (newVal && availableTags.value.length === 0) fetchTags();
if (!newVal) {
// Reset errors on close
errors.title = '';
errors.abstract = '';
}
});
// Helper for colorful tags
watch(() => props.postToEdit, (newPost) => {
if (newPost) {
uploadForm.title = newPost.title;
uploadForm.abstract = newPost.abstractText || newPost.abstract;
uploadForm.type = newPost.type;
uploadForm.authors = [...newPost?.authors];
uploadForm.selectedTagIds = newPost?.tags.map((t: any) => t.id);
}
}, { immediate: true });
const getTagClass = (id: number) => {
const colors = [
'bg-pink-100 text-pink-700 border-pink-200 dark:bg-pink-900/30 dark:text-pink-300',
@@ -204,9 +236,6 @@ const getTagClass = (id: number) => {
<select v-model="uploadForm.type"
class="w-full rounded-lg border-slate-300 dark:border-slate-700 bg-white dark:bg-slate-800 text-slate-900 dark:text-white shadow-sm focus:ring-blue-500 sm:text-sm py-2.5 px-3 border">
<option value="CONFERENCE_PAPER">Conference Paper</option>
<option value="ARTICLE">Article</option>
<option value="THESIS">Thesis</option>
<option value="REPORT">Report</option>
</select>
</div>
</div>
@@ -224,7 +253,7 @@ const getTagClass = (id: number) => {
<div class="flex flex-col md:flex-row gap-8">
<div class="flex-1">
<div class="w-full">
<label
class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Authors</label>
<div class="relative flex items-center">
@@ -241,7 +270,7 @@ const getTagClass = (id: number) => {
</svg>
</button>
</div>
<div class="flex flex-wrap gap-2 mt-3">
<div :class="['flex flex-wrap gap-2', uploadForm.authors.length != 0 ? 'mt-3' : '']">
<span v-for="(author, index) in uploadForm.authors" :key="index"
class="inline-flex items-center gap-1 px-2.5 py-1 rounded-md bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300 text-xs font-medium border border-slate-200 dark:border-slate-700">
{{ author }}
@@ -255,7 +284,7 @@ const getTagClass = (id: number) => {
</div>
</div>
<div class="w-full md:w-auto min-w-[200px]">
<div class="flex-1 md:w-auto min-w-[300px]">
<label
class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Tags</label>
<div
@@ -269,10 +298,10 @@ const getTagClass = (id: number) => {
if (idx > -1) uploadForm.selectedTagIds.splice(idx, 1);
else uploadForm.selectedTagIds.push(tag.id);
}" :class="[
uploadForm.selectedTagIds.includes(tag.id)
? getTagClass(tag.id) + ' border-transparent'
: 'bg-white dark:bg-slate-800 border-slate-200 dark:border-slate-700 text-slate-600 dark:text-slate-400'
]"
uploadForm.selectedTagIds.includes(tag.id)
? getTagClass(tag.id) + ' border-transparent'
: 'bg-white dark:bg-slate-800 border-slate-200 dark:border-slate-700 text-slate-600 dark:text-slate-400'
]"
class="px-3 py-1.5 rounded-full border text-xs font-bold uppercase tracking-tight transition-all shadow-sm whitespace-nowrap">
{{ tag.name }}
</button>
@@ -286,7 +315,7 @@ const getTagClass = (id: number) => {
<button :disabled="isSubmitting"
class="inline-flex w-full justify-center rounded-lg bg-blue-600 px-6 py-2.5 text-sm font-bold text-white shadow-sm hover:bg-blue-500 disabled:opacity-50 sm:w-auto transition-all"
@click="submitPublication">
{{ isSubmitting ? 'Uploading...' : 'Submit Publication' }}
{{ isSubmitting ? 'Uploading...' : 'Submit' }}
</button>
<button
class="inline-flex w-full justify-center rounded-lg bg-white dark:bg-slate-800 px-6 py-2.5 text-sm font-bold text-slate-700 dark:text-slate-300 shadow-sm ring-1 ring-inset ring-slate-300 dark:ring-slate-700 hover:bg-slate-50 sm:w-auto transition-all"