Bug fixes + Save status
This commit is contained in:
58
resources/js/components/SaveStatusIcon.vue
Normal file
58
resources/js/components/SaveStatusIcon.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<script setup lang="ts">
|
||||
import { useResumesStore } from '@/stores/resume';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { CloudCheck, LoaderCircle, CircleAlert } from 'lucide-vue-next';
|
||||
|
||||
const resumeStore = useResumesStore();
|
||||
|
||||
const DISAPPEAR_DELAY = 5000;
|
||||
|
||||
const isSaving = computed(() => resumeStore.isSaving);
|
||||
|
||||
const error = ref<string | null>(null);
|
||||
watch(() => resumeStore.savingError, (newError) => {
|
||||
error.value = newError;
|
||||
if (newError) {
|
||||
showSaved.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
const showSaved = ref(false);
|
||||
let showSavedTimeout: ReturnType<typeof setTimeout>;
|
||||
watch(isSaving, (newIsSaving: boolean) => {
|
||||
if (!newIsSaving && !error.value) {
|
||||
if (showSavedTimeout) {
|
||||
clearTimeout(showSavedTimeout);
|
||||
}
|
||||
showSaved.value = true;
|
||||
showSavedTimeout = setTimeout(() => {
|
||||
showSaved.value = false;
|
||||
}, DISAPPEAR_DELAY);
|
||||
} else {
|
||||
showSaved.value = false;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex justify-between gap-2 items-center p-3 h-4">
|
||||
<p class="text-red-400">{{ error }}</p>
|
||||
<Transition mode="out-in" appear>
|
||||
<CircleAlert class="w-4 h-4 text-red-500" v-if="error"/>
|
||||
<LoaderCircle class="w-4 h-4 animate-spin" v-else-if="isSaving"/>
|
||||
<CloudCheck class="w-4 h-4" v-else-if="showSaved" title="Sauvegardé"/>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.v-enter-active,
|
||||
.v-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.v-enter-from,
|
||||
.v-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -40,7 +40,7 @@ function removeResume(deletedResume: Resume) {
|
||||
if (resumeStore.resumes.length > 0) {
|
||||
window.location.href = route("resumes.edit", resumeStore.resumes[0], false);
|
||||
} else {
|
||||
window.location.href = route("resumes.create");
|
||||
window.location.href = route("dashboard");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,20 +28,21 @@ async function sendChangedData(newData: ResumeInputData[]) {
|
||||
clearTimeout(delayedSendTimeout);
|
||||
}
|
||||
delayedSendTimeout = setTimeout(async () => {
|
||||
const { data, error } = await httpApi(route('resume-component-placements.update', newSelectedComponent), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ ...newSelectedComponent, _method: 'PUT' })
|
||||
}, {immediate: true});
|
||||
// Handle error
|
||||
if (error) {
|
||||
console.error('Failed to update component placement:', error, data);
|
||||
return;
|
||||
}
|
||||
// const { data, error } = await httpApi(route('resume-component-placements.update', newSelectedComponent), {
|
||||
// method: 'POST',
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '',
|
||||
// 'Accept': 'application/json'
|
||||
// },
|
||||
// body: JSON.stringify({ ...newSelectedComponent, _method: 'PUT' })
|
||||
// }, {immediate: true});
|
||||
// // Handle error
|
||||
// if (error) {
|
||||
// console.error('Failed to update component placement:', error, data);
|
||||
// return;
|
||||
// }
|
||||
resumeStore.modifyCurrentSelectedResumePlacementToApi(newSelectedComponent!);
|
||||
}, SEND_CHANGED_DATA_DELAY);
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import ComponentsSelectionList from './ComponentsSelectionList.vue';
|
||||
import { computed } from 'vue';
|
||||
import { useResumesStore } from '@/stores/resume';
|
||||
import { useShowComponentSelectionStore } from '@/stores/ui';
|
||||
import SaveStatusIcon from '../SaveStatusIcon.vue';
|
||||
|
||||
const resumeStore = useResumesStore();
|
||||
const selectedComponent = resumeStore.currentSelectedResumePlacement;
|
||||
@@ -14,7 +15,8 @@ const showComponentSelection = computed<boolean>(() => showComponentSelectionSto
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex h-full flex-1 gap-4 rounded-xl p-4 overflow-x-auto max-w-[25%] bg-accent relative">
|
||||
<div class="flex flex-col h-full flex-1 gap-4 rounded-xl p-4 overflow-x-auto max-w-[25%] bg-accent relative">
|
||||
<SaveStatusIcon />
|
||||
<Transition mode="out-in" appear>
|
||||
<ResumeComponentEdit v-if="selectedComponent != null" :key="selectedComponent ? selectedComponent.id : 'form'" />
|
||||
<ComponentsSelectionList v-else-if="showComponentSelection" />
|
||||
|
||||
Reference in New Issue
Block a user