Apply prettier to files

This commit is contained in:
Julie Lenaerts 2024-12-11 10:49:11 +01:00
parent a6aa2a81c2
commit ebfd48e41f
31 changed files with 4889 additions and 3883 deletions

View File

@ -1,23 +1,58 @@
<template>
<div v-if="isButtonGroupDisplayable" class="btn-group">
<button :class="Object.assign({'btn': true, 'btn-outline-primary': true, 'dropdown-toggle': true, 'btn-sm': props.small})" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button
:class="
Object.assign({
btn: true,
'btn-outline-primary': true,
'dropdown-toggle': true,
'btn-sm': props.small,
})
"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
Actions
</button>
<ul class="dropdown-menu">
<li v-if="isEditableOnline">
<wopi-edit-button :stored-object="props.storedObject" :classes="{'dropdown-item': true}" :execute-before-leave="props.executeBeforeLeave"></wopi-edit-button>
<wopi-edit-button
:stored-object="props.storedObject"
:classes="{ 'dropdown-item': true }"
:execute-before-leave="props.executeBeforeLeave"
></wopi-edit-button>
</li>
<li v-if="isEditableOnDesktop">
<desktop-edit-button :classes="{'dropdown-item': true}" :edit-link="props.davLink" :expiration-link="props.davLinkExpiration"></desktop-edit-button>
<desktop-edit-button
:classes="{ 'dropdown-item': true }"
:edit-link="props.davLink"
:expiration-link="props.davLinkExpiration"
></desktop-edit-button>
</li>
<li v-if="isConvertibleToPdf">
<convert-button :stored-object="props.storedObject" :filename="filename" :classes="{'dropdown-item': true}"></convert-button>
<convert-button
:stored-object="props.storedObject"
:filename="filename"
:classes="{ 'dropdown-item': true }"
></convert-button>
</li>
<li v-if="isDownloadable">
<download-button :stored-object="props.storedObject" :at-version="props.storedObject.currentVersion" :filename="filename" :classes="{'dropdown-item': true}" :display-action-string-in-button="true"></download-button>
<download-button
:stored-object="props.storedObject"
:at-version="props.storedObject.currentVersion"
:filename="filename"
:classes="{ 'dropdown-item': true }"
:display-action-string-in-button="true"
></download-button>
</li>
<li v-if="isHistoryViewable">
<history-button :stored-object="props.storedObject" :can-edit="canEdit && props.storedObject._permissions.canEdit"></history-button>
<history-button
:stored-object="props.storedObject"
:can-edit="
canEdit && props.storedObject._permissions.canEdit
"
></history-button>
</li>
</ul>
</div>
@ -27,31 +62,34 @@
<div v-else-if="'failure' === props.storedObject.status">
<div class="btn btn-outline-danger">La génération a échoué</div>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted } from "vue";
import ConvertButton from "./StoredObjectButton/ConvertButton.vue";
import DownloadButton from "./StoredObjectButton/DownloadButton.vue";
import WopiEditButton from "./StoredObjectButton/WopiEditButton.vue";
import {is_extension_editable, is_extension_viewable, is_object_ready} from "./StoredObjectButton/helpers";
import {
is_extension_editable,
is_extension_viewable,
is_object_ready,
} from "./StoredObjectButton/helpers";
import {
StoredObject,
StoredObjectStatusChange, StoredObjectVersion,
WopiEditButtonExecutableBeforeLeaveFunction
StoredObjectStatusChange,
StoredObjectVersion,
WopiEditButtonExecutableBeforeLeaveFunction,
} from "../types";
import DesktopEditButton from "ChillDocStoreAssets/vuejs/StoredObjectButton/DesktopEditButton.vue";
import HistoryButton from "ChillDocStoreAssets/vuejs/StoredObjectButton/HistoryButton.vue";
interface DocumentActionButtonsGroupConfig {
storedObject: StoredObject,
small?: boolean,
canEdit?: boolean,
canDownload?: boolean,
canConvertPdf?: boolean,
returnPath?: string,
storedObject: StoredObject;
small?: boolean;
canEdit?: boolean;
canDownload?: boolean;
canConvertPdf?: boolean;
returnPath?: string;
/**
* Will be the filename displayed to the user when he·she download the document
@ -59,34 +97,41 @@ interface DocumentActionButtonsGroupConfig {
*
* If not set, 'document' will be used.
*/
filename?: string,
filename?: string;
/**
* If set, will execute this function before leaving to the editor
*/
executeBeforeLeave?: WopiEditButtonExecutableBeforeLeaveFunction,
executeBeforeLeave?: WopiEditButtonExecutableBeforeLeaveFunction;
/**
* a link to download and edit file using webdav
*/
davLink?: string,
davLink?: string;
/**
* the expiration date of the download, as a unix timestamp
*/
davLinkExpiration?: number,
davLinkExpiration?: number;
}
const emit = defineEmits<{
(e: 'onStoredObjectStatusChange', newStatus: StoredObjectStatusChange): void
}>();
const emit =
defineEmits<
(
e: "onStoredObjectStatusChange",
newStatus: StoredObjectStatusChange,
) => void
>();
const props = withDefaults(defineProps<DocumentActionButtonsGroupConfig>(), {
small: false,
canEdit: true,
canDownload: true,
canConvertPdf: true,
returnPath: window.location.pathname + window.location.search + window.location.hash
returnPath:
window.location.pathname +
window.location.search +
window.location.hash,
});
/**
@ -100,22 +145,32 @@ let tryiesForReady = 0;
const maxTryiesForReady = 120;
const isButtonGroupDisplayable = computed<boolean>(() => {
return isDownloadable.value || isEditableOnline.value || isEditableOnDesktop.value || isConvertibleToPdf.value;
return (
isDownloadable.value ||
isEditableOnline.value ||
isEditableOnDesktop.value ||
isConvertibleToPdf.value
);
});
const isDownloadable = computed<boolean>(() => {
return props.storedObject.status === 'ready'
return (
props.storedObject.status === "ready" ||
// happens when the stored object version is just added, but not persisted
|| (props.storedObject.currentVersion !== null && props.storedObject.status === 'empty')
(props.storedObject.currentVersion !== null &&
props.storedObject.status === "empty")
);
});
const isEditableOnline = computed<boolean>(() => {
return props.storedObject.status === 'ready'
&& props.storedObject._permissions.canEdit
&& props.canEdit
&& props.storedObject.currentVersion !== null
&& is_extension_editable(props.storedObject.currentVersion.type)
&& props.storedObject.currentVersion.persisted !== false;
return (
props.storedObject.status === "ready" &&
props.storedObject._permissions.canEdit &&
props.canEdit &&
props.storedObject.currentVersion !== null &&
is_extension_editable(props.storedObject.currentVersion.type) &&
props.storedObject.currentVersion.persisted !== false
);
});
const isEditableOnDesktop = computed<boolean>(() => {
@ -123,26 +178,28 @@ const isEditableOnDesktop = computed<boolean>(() => {
});
const isConvertibleToPdf = computed<boolean>(() => {
return props.storedObject.status === 'ready'
&& props.storedObject._permissions.canSee
&& props.canConvertPdf
&& props.storedObject.currentVersion !== null
&& is_extension_viewable(props.storedObject.currentVersion.type)
&& props.storedObject.currentVersion.type !== 'application/pdf'
&& props.storedObject.currentVersion.persisted !== false;
return (
props.storedObject.status === "ready" &&
props.storedObject._permissions.canSee &&
props.canConvertPdf &&
props.storedObject.currentVersion !== null &&
is_extension_viewable(props.storedObject.currentVersion.type) &&
props.storedObject.currentVersion.type !== "application/pdf" &&
props.storedObject.currentVersion.persisted !== false
);
});
const isHistoryViewable = computed<boolean>(() => {
return props.storedObject.status === 'ready';
return props.storedObject.status === "ready";
});
const checkForReady = function (): void {
if (
'ready' === props.storedObject.status
|| 'empty' === props.storedObject.status
|| 'failure' === props.storedObject.status
"ready" === props.storedObject.status ||
"empty" === props.storedObject.status ||
"failure" === props.storedObject.status ||
// stop reloading if the page stays opened for a long time
|| tryiesForReady > maxTryiesForReady
tryiesForReady > maxTryiesForReady
) {
return;
}
@ -153,20 +210,19 @@ const checkForReady = function(): void {
};
const onObjectNewStatusCallback = async function (): Promise<void> {
if (props.storedObject.status === 'stored_object_created') {
if (props.storedObject.status === "stored_object_created") {
return Promise.resolve();
}
const new_status = await is_object_ready(props.storedObject);
if (props.storedObject.status !== new_status.status) {
emit('onStoredObjectStatusChange', new_status);
emit("onStoredObjectStatusChange", new_status);
return Promise.resolve();
} else if ('failure' === new_status.status) {
} else if ("failure" === new_status.status) {
return Promise.resolve();
}
if ('ready' !== new_status.status) {
if ("ready" !== new_status.status) {
// we check for new status, unless it is ready
checkForReady();
}
@ -176,9 +232,7 @@ const onObjectNewStatusCallback = async function(): Promise<void> {
onMounted(() => {
checkForReady();
})
});
</script>
<style scoped>
</style>
<style scoped></style>

View File

@ -27,7 +27,9 @@
</modal>
</teleport>
<div class="col-12 m-auto sticky-top">
<div class="row justify-content-center border-bottom pdf-tools d-md-none">
<div
class="row justify-content-center border-bottom pdf-tools d-md-none"
>
<div class="col-5 text-center turn-page">
<select
class="form-select form-select-sm"
@ -89,7 +91,10 @@
class="col-5 p-0 text-center turnSignature"
>
<button
:disabled="userSignatureZone === null || userSignatureZone?.index < 1"
:disabled="
userSignatureZone === null ||
userSignatureZone?.index < 1
"
class="btn btn-light btn-sm"
@click="turnSignature(-1)"
>
@ -97,7 +102,9 @@
</button>
<span>|</span>
<button
:disabled="userSignatureZone?.index >= signature.zones.length - 1"
:disabled="
userSignatureZone?.index >= signature.zones.length - 1
"
class="btn btn-light btn-sm"
@click="turnSignature(1)"
>
@ -135,7 +142,10 @@
:title="$t('add_sign_zone')"
>
<template v-if="canvasEvent === 'add'">
<div class="spinner-border spinner-border-sm" role="status">
<div
class="spinner-border spinner-border-sm"
role="status"
>
<span class="visually-hidden">Loading...</span>
</div>
</template>
@ -190,7 +200,10 @@
class="col-4 d-xl-none text-center turnSignature p-0"
>
<button
:disabled="userSignatureZone === null || userSignatureZone?.index < 1"
:disabled="
userSignatureZone === null ||
userSignatureZone?.index < 1
"
class="btn btn-light btn-sm"
@click="turnSignature(-1)"
>
@ -198,7 +211,9 @@
</button>
<span>|</span>
<button
:disabled="userSignatureZone?.index >= signature.zones.length - 1"
:disabled="
userSignatureZone?.index >= signature.zones.length - 1
"
class="btn btn-light btn-sm"
@click="turnSignature(1)"
>
@ -210,7 +225,10 @@
class="col-4 d-none d-xl-flex p-0 text-center turnSignature"
>
<button
:disabled="userSignatureZone === null || userSignatureZone?.index < 1"
:disabled="
userSignatureZone === null ||
userSignatureZone?.index < 1
"
class="btn btn-light btn-sm"
@click="turnSignature(-1)"
>
@ -218,7 +236,9 @@
</button>
<span>|</span>
<button
:disabled="userSignatureZone?.index >= signature.zones.length - 1"
:disabled="
userSignatureZone?.index >= signature.zones.length - 1
"
class="btn btn-light btn-sm"
@click="turnSignature(1)"
>
@ -259,7 +279,10 @@
</template>
<template v-else>
{{ $t("click_on_document") }}
<div class="spinner-border spinner-border-sm" role="status">
<div
class="spinner-border spinner-border-sm"
role="status"
>
<span class="visually-hidden">Loading...</span>
</div>
</template>
@ -336,7 +359,10 @@ console.log(PdfWorker); // incredible but this is needed
// pdfjsLib.GlobalWorkerOptions.workerSrc = PdfWorker;
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
import {download_and_decrypt_doc, download_doc_as_pdf} from "../StoredObjectButton/helpers";
import {
download_and_decrypt_doc,
download_doc_as_pdf,
} from "../StoredObjectButton/helpers";
pdfjsLib.GlobalWorkerOptions.workerSrc = "pdfjs-dist/build/pdf.worker.mjs";
@ -479,12 +505,18 @@ const addCanvasEvents = () => {
canvas.addEventListener(
"pointerup",
(e) => canvasClick(e, canvas),
false
false,
);
});
} else {
const canvas = document.querySelectorAll("canvas")[0] as HTMLCanvasElement;
canvas.addEventListener("pointerup", (e) => canvasClick(e, canvas), false);
const canvas = document.querySelectorAll(
"canvas",
)[0] as HTMLCanvasElement;
canvas.addEventListener(
"pointerup",
(e) => canvasClick(e, canvas),
false,
);
}
};
@ -511,7 +543,7 @@ const scaleYToCanvas = (h: number, canvasHeight: number, PDFHeight: number) =>
const hitSignature = (
zone: SignatureZone,
xy: number[],
canvas: HTMLCanvasElement
canvas: HTMLCanvasElement,
) =>
scaleXToCanvas(zone.x, canvas.width, zone.PDFPage.width) < xy[0] &&
xy[0] <
@ -520,7 +552,11 @@ const hitSignature = (
scaleYToCanvas(zone.y, canvas.height, zone.PDFPage.height) <
xy[1] &&
xy[1] <
scaleYToCanvas(zone.height - zone.y, canvas.height, zone.PDFPage.height) +
scaleYToCanvas(
zone.height - zone.y,
canvas.height,
zone.PDFPage.height,
) +
zone.PDFPage.height * zoom.value;
const selectZone = async (z: SignatureZone, canvas: HTMLCanvasElement) => {
@ -536,8 +572,9 @@ const selectZoneEvent = (e: PointerEvent, canvas: HTMLCanvasElement) =>
signature.zones
.filter(
(z) =>
(z.PDFPage.index + 1 === getCanvasId(canvas) && multiPage.value) ||
(z.PDFPage.index + 1 === page.value && !multiPage.value)
(z.PDFPage.index + 1 === getCanvasId(canvas) &&
multiPage.value) ||
(z.PDFPage.index + 1 === page.value && !multiPage.value),
)
.map((z) => {
if (hitSignature(z, [e.offsetX, e.offsetY], canvas)) {
@ -590,7 +627,7 @@ const drawZone = (
zone: SignatureZone,
ctx: CanvasRenderingContext2D,
canvasWidth: number,
canvasHeight: number
canvasHeight: number,
) => {
const unselectedBlue = "#007bff";
const selectedBlue = "#034286";
@ -605,7 +642,7 @@ const drawZone = (
zone.PDFPage.height * zoom.value -
scaleYToCanvas(zone.y, canvasHeight, zone.PDFPage.height),
scaleXToCanvas(zone.width, canvasWidth, zone.PDFPage.width),
scaleYToCanvas(zone.height, canvasHeight, zone.PDFPage.height)
scaleYToCanvas(zone.height, canvasHeight, zone.PDFPage.height),
);
ctx.font = `bold ${16 * zoom.value}px serif`;
ctx.textAlign = "center";
@ -633,7 +670,7 @@ const drawAllZones = () => {
.filter(
(z) =>
multiPage.value ||
(z.PDFPage.index + 1 === page.value && !multiPage.value)
(z.PDFPage.index + 1 === page.value && !multiPage.value),
)
.map((z) => {
const canvas = getCanvas(z.PDFPage.index + 1);
@ -663,7 +700,7 @@ const checkSignature = () => {
signedState.value = "error";
console.log("Error while checking the signature", error);
$toast.error(
`Erreur lors de la vérification de la signature: ${error.txt}`
`Erreur lors de la vérification de la signature: ${error.txt}`,
);
});
};
@ -682,7 +719,7 @@ const checkForReady = () => {
tryForReady = 0;
console.log("Reached the maximum number of tentative to try signing");
$toast.error(
"Le nombre maximum de tentatives pour essayer de signer est atteint"
"Le nombre maximum de tentatives pour essayer de signer est atteint",
);
}
if (signedState.value === "rejected") {
@ -724,7 +761,7 @@ const confirmSign = () => {
console.log("Error while posting the signature", error);
stopTrySigning();
$toast.error(
`Erreur lors de la soumission de la signature: ${error.txt}`
`Erreur lors de la soumission de la signature: ${error.txt}`,
);
});
};
@ -780,8 +817,8 @@ const addZoneEvent = async (e: PointerEvent, canvas: HTMLCanvasElement) => {
const getReturnPath = () =>
window.location.search
? window.location.search.split("?returnPath=")[1] ??
window.location.pathname
? (window.location.search.split("?returnPath=")[1] ??
window.location.pathname)
: window.location.pathname;
init();
@ -842,4 +879,3 @@ div.signature-modal-body {
height: 8rem;
}
</style>

View File

@ -1,19 +1,31 @@
<script setup lang="ts">
import { StoredObject, StoredObjectVersionCreated } from "../../types";
import {encryptFile, fetchNewStoredObject, uploadVersion} from "../../js/async-upload/uploader";
import {
encryptFile,
fetchNewStoredObject,
uploadVersion,
} from "../../js/async-upload/uploader";
import { computed, ref, Ref } from "vue";
import FileIcon from "ChillDocStoreAssets/vuejs/FileIcon.vue";
interface DropFileConfig {
existingDoc?: StoredObject,
existingDoc?: StoredObject;
}
const props = withDefaults(defineProps<DropFileConfig>(), {existingDoc: null});
const props = withDefaults(defineProps<DropFileConfig>(), {
existingDoc: null,
});
const emit = defineEmits<{
(e: 'addDocument', {stored_object_version: StoredObjectVersionCreated, stored_object: StoredObject}): void,
}>();
const emit =
defineEmits<
(
e: "addDocument",
{
stored_object_version: StoredObjectVersionCreated,
stored_object: StoredObject,
},
) => void
>();
const is_dragging: Ref<boolean> = ref(false);
const uploading: Ref<boolean> = ref(false);
@ -27,13 +39,13 @@ const onDragOver = (e: Event) => {
e.preventDefault();
is_dragging.value = true;
}
};
const onDragLeave = (e: Event) => {
e.preventDefault();
is_dragging.value = false;
}
};
const onDrop = (e: DragEvent) => {
e.preventDefault();
@ -49,8 +61,8 @@ const onDrop = (e: DragEvent) => {
return;
}
handleFile(files[0])
}
handleFile(files[0]);
};
const onZoneClick = (e: Event) => {
e.stopPropagation();
@ -61,21 +73,21 @@ const onZoneClick = (e: Event) => {
input.addEventListener("change", onFileChange);
input.click();
}
};
const onFileChange = async (event: Event): Promise<void> => {
const input = event.target as HTMLInputElement;
if (input.files && input.files[0]) {
console.log('file added', input.files[0]);
console.log("file added", input.files[0]);
const file = input.files[0];
await handleFile(file);
return Promise.resolve();
}
throw 'No file given';
}
throw "No file given";
};
const handleFile = async (file: File): Promise<void> => {
uploading.value = true;
@ -100,25 +112,39 @@ const handleFile = async (file: File): Promise<void> => {
keyInfos: jsonWebKey,
type: type,
persisted: false,
}
};
emit('addDocument', {stored_object, stored_object_version});
emit("addDocument", { stored_object, stored_object_version });
uploading.value = false;
}
};
</script>
<template>
<div class="drop-file">
<div v-if="!uploading" :class="{ area: true, dragging: is_dragging}" @click="onZoneClick" @dragover="onDragOver" @dragleave="onDragLeave" @drop="onDrop">
<div
v-if="!uploading"
:class="{ area: true, dragging: is_dragging }"
@click="onZoneClick"
@dragover="onDragOver"
@dragleave="onDragLeave"
@drop="onDrop"
>
<p v-if="has_existing_doc" class="file-icon">
<file-icon :type="props.existingDoc?.type"></file-icon>
</p>
<p v-if="display_filename !== null" class="display-filename">{{ display_filename }}</p>
<p v-if="display_filename !== null" class="display-filename">
{{ display_filename }}
</p>
<!-- todo i18n -->
<p v-if="has_existing_doc">Déposez un document ou cliquez ici pour remplacer le document existant</p>
<p v-else>Déposez un document ou cliquez ici pour ouvrir le navigateur de fichier</p>
<p v-if="has_existing_doc">
Déposez un document ou cliquez ici pour remplacer le document
existant
</p>
<p v-else>
Déposez un document ou cliquez ici pour ouvrir le navigateur de
fichier
</p>
</div>
<div v-else class="waiting">
<i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
@ -140,7 +166,8 @@ const handleFile = async (file: File): Promise<void> => {
font-weight: 200;
}
& > .area, & > .waiting {
& > .area,
& > .waiting {
width: 100%;
height: 10rem;
@ -163,5 +190,4 @@ const handleFile = async (file: File): Promise<void> => {
}
}
}
</style>

View File

@ -1,14 +1,13 @@
<script setup lang="ts">
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
import { StoredObject, StoredObjectVersion } from "../../types";
import DropFileWidget from "ChillDocStoreAssets/vuejs/DropFileWidget/DropFileWidget.vue";
import { computed, reactive } from "vue";
import {useToast} from 'vue-toast-notification';
import { useToast } from "vue-toast-notification";
interface DropFileConfig {
allowRemove: boolean,
existingDoc?: StoredObject,
allowRemove: boolean;
existingDoc?: StoredObject;
}
const props = withDefaults(defineProps<DropFileConfig>(), {
@ -16,8 +15,14 @@ const props = withDefaults(defineProps<DropFileConfig>(), {
});
const emit = defineEmits<{
(e: 'addDocument', {stored_object: StoredObject, stored_object_version: StoredObjectVersion}): void,
(e: 'removeDocument'): void
(
e: "addDocument",
{
stored_object: StoredObject,
stored_object_version: StoredObjectVersion,
},
): void;
(e: "removeDocument"): void;
}>();
const $toast = useToast();
@ -26,23 +31,30 @@ const state = reactive({showModal: false});
const modalClasses = { "modal-dialog-centered": true, "modal-md": true };
const buttonState = computed<'add'|'replace'>(() => {
const buttonState = computed<"add" | "replace">(() => {
if (props.existingDoc === undefined || props.existingDoc === null) {
return 'add';
return "add";
}
return 'replace';
})
return "replace";
});
function onAddDocument({stored_object, stored_object_version}: {stored_object: StoredObject, stored_object_version: StoredObjectVersion}): void {
const message = buttonState.value === 'add' ? "Document ajouté" : "Document remplacé";
function onAddDocument({
stored_object,
stored_object_version,
}: {
stored_object: StoredObject;
stored_object_version: StoredObjectVersion;
}): void {
const message =
buttonState.value === "add" ? "Document ajouté" : "Document remplacé";
$toast.success(message);
emit('addDocument', {stored_object_version, stored_object});
emit("addDocument", { stored_object_version, stored_object });
state.showModal = false;
}
function onRemoveDocument(): void {
emit('removeDocument');
emit("removeDocument");
}
function openModal(): void {
@ -55,15 +67,30 @@ function closeModal(): void {
</script>
<template>
<button v-if="buttonState === 'add'" @click="openModal" class="btn btn-create">Ajouter un document</button>
<button v-else @click="openModal" class="btn btn-edit">Remplacer le document</button>
<modal v-if="state.showModal" :modal-dialog-class="modalClasses" @close="closeModal">
<button
v-if="buttonState === 'add'"
@click="openModal"
class="btn btn-create"
>
Ajouter un document
</button>
<button v-else @click="openModal" class="btn btn-edit">
Remplacer le document
</button>
<modal
v-if="state.showModal"
:modal-dialog-class="modalClasses"
@close="closeModal"
>
<template v-slot:body>
<drop-file-widget :existing-doc="existingDoc" :allow-remove="allowRemove" @add-document="onAddDocument" @remove-document="onRemoveDocument" ></drop-file-widget>
<drop-file-widget
:existing-doc="existingDoc"
:allow-remove="allowRemove"
@add-document="onAddDocument"
@remove-document="onRemoveDocument"
></drop-file-widget>
</template>
</modal>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,13 +1,12 @@
<script setup lang="ts">
import { StoredObject, StoredObjectVersion } from "../../types";
import { computed, ref, Ref } from "vue";
import DropFile from "ChillDocStoreAssets/vuejs/DropFileWidget/DropFile.vue";
import DocumentActionButtonsGroup from "ChillDocStoreAssets/vuejs/DocumentActionButtonsGroup.vue";
interface DropFileConfig {
allowRemove: boolean,
existingDoc?: StoredObject,
allowRemove: boolean;
existingDoc?: StoredObject;
}
const props = withDefaults(defineProps<DropFileConfig>(), {
@ -15,8 +14,14 @@ const props = withDefaults(defineProps<DropFileConfig>(), {
});
const emit = defineEmits<{
(e: 'addDocument', {stored_object: StoredObject, stored_object_version: StoredObjectVersion}): void,
(e: 'removeDocument'): void
(
e: "addDocument",
{
stored_object: StoredObject,
stored_object_version: StoredObjectVersion,
},
): void;
(e: "removeDocument"): void;
}>();
const has_existing_doc = computed<boolean>(() => {
@ -27,7 +32,7 @@ const dav_link_expiration = computed<number|undefined>(() => {
if (props.existingDoc === undefined || props.existingDoc === null) {
return undefined;
}
if (props.existingDoc.status !== 'ready') {
if (props.existingDoc.status !== "ready") {
return undefined;
}
@ -38,28 +43,36 @@ const dav_link_href = computed<string|undefined>(() => {
if (props.existingDoc === undefined || props.existingDoc === null) {
return undefined;
}
if (props.existingDoc.status !== 'ready') {
if (props.existingDoc.status !== "ready") {
return undefined;
}
return props.existingDoc._links?.dav_link?.href;
})
});
const onAddDocument = ({stored_object, stored_object_version}: {stored_object: StoredObject, stored_object_version: StoredObjectVersion}): void => {
emit('addDocument', {stored_object, stored_object_version});
}
const onAddDocument = ({
stored_object,
stored_object_version,
}: {
stored_object: StoredObject;
stored_object_version: StoredObjectVersion;
}): void => {
emit("addDocument", { stored_object, stored_object_version });
};
const onRemoveDocument = (e: Event): void => {
e.stopPropagation();
e.preventDefault();
emit('removeDocument');
}
emit("removeDocument");
};
</script>
<template>
<div>
<drop-file :existingDoc="props.existingDoc" @addDocument="onAddDocument"></drop-file>
<drop-file
:existingDoc="props.existingDoc"
@addDocument="onAddDocument"
></drop-file>
<ul class="record_actions">
<li v-if="has_existing_doc">
@ -72,12 +85,14 @@ const onRemoveDocument = (e: Event): void => {
/>
</li>
<li>
<button v-if="allowRemove" class="btn btn-delete" @click="onRemoveDocument($event)" ></button>
<button
v-if="allowRemove"
class="btn btn-delete"
@click="onRemoveDocument($event)"
></button>
</li>
</ul>
</div>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -4,22 +4,43 @@ interface FileIconConfig {
}
const props = defineProps<FileIconConfig>();
</script>
<template>
<i class="fa fa-file-pdf-o" v-if="props.type === 'application/pdf'"></i>
<i class="fa fa-file-word-o" v-else-if="props.type === 'application/vnd.oasis.opendocument.text'"></i>
<i class="fa fa-file-word-o" v-else-if="props.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'"></i>
<i class="fa fa-file-word-o" v-else-if="props.type === 'application/msword'"></i>
<i class="fa fa-file-excel-o" v-else-if="props.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'"></i>
<i class="fa fa-file-excel-o" v-else-if="props.type === 'application/vnd.ms-excel'"></i>
<i
class="fa fa-file-word-o"
v-else-if="props.type === 'application/vnd.oasis.opendocument.text'"
></i>
<i
class="fa fa-file-word-o"
v-else-if="
props.type ===
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
"
></i>
<i
class="fa fa-file-word-o"
v-else-if="props.type === 'application/msword'"
></i>
<i
class="fa fa-file-excel-o"
v-else-if="
props.type ===
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
"
></i>
<i
class="fa fa-file-excel-o"
v-else-if="props.type === 'application/vnd.ms-excel'"
></i>
<i class="fa fa-file-image-o" v-else-if="props.type === 'image/jpeg'"></i>
<i class="fa fa-file-image-o" v-else-if="props.type === 'image/png'"></i>
<i class="fa fa-file-archive-o" v-else-if="props.type === 'application/x-zip-compressed'"></i>
<i
class="fa fa-file-archive-o"
v-else-if="props.type === 'application/x-zip-compressed'"
></i>
<i class="fa fa-file-code-o" v-else></i>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -6,20 +6,23 @@
</template>
<script lang="ts" setup>
import {build_convert_link, download_and_decrypt_doc, download_doc} from "./helpers";
import {
build_convert_link,
download_and_decrypt_doc,
download_doc,
} from "./helpers";
import mime from "mime";
import { reactive, ref } from "vue";
import { StoredObject } from "../../types";
interface ConvertButtonConfig {
storedObject: StoredObject,
classes: { [key: string]: boolean},
filename?: string,
};
storedObject: StoredObject;
classes: Record<string, boolean>;
filename?: string;
}
interface DownloadButtonState {
content: null|string
content: null | string;
}
const props = defineProps<ConvertButtonConfig>();
@ -32,13 +35,15 @@ async function download_and_open(event: Event): Promise<void> {
if (null === state.content) {
event.preventDefault();
const raw = await download_doc(build_convert_link(props.storedObject.uuid));
const raw = await download_doc(
build_convert_link(props.storedObject.uuid),
);
state.content = window.URL.createObjectURL(raw);
button.href = window.URL.createObjectURL(raw);
button.type = 'application/pdf';
button.type = "application/pdf";
button.download = (props.filename + '.pdf') || 'document.pdf';
button.download = props.filename + ".pdf" || "document.pdf";
}
button.click();
@ -47,11 +52,10 @@ async function download_and_open(event: Event): Promise<void> {
function reset_state(): void {
state.content = null;
btn.value?.removeAttribute('download');
btn.value?.removeAttribute('href');
btn.value?.removeAttribute('type');
btn.value?.removeAttribute("download");
btn.value?.removeAttribute("href");
btn.value?.removeAttribute("type");
}
</script>
<style scoped lang="scss">

View File

@ -1,9 +1,23 @@
<template>
<a v-if="!state.is_ready" :class="props.classes" @click="download_and_open()" title="T&#233;l&#233;charger">
<a
v-if="!state.is_ready"
:class="props.classes"
@click="download_and_open()"
title="T&#233;l&#233;charger"
>
<i class="fa fa-download"></i>
<template v-if="displayActionStringInButton">Télécharger</template>
</a>
<a v-else :class="props.classes" target="_blank" :type="props.atVersion.type" :download="buildDocumentName()" :href="state.href_url" ref="open_button" title="Ouvrir">
<a
v-else
:class="props.classes"
target="_blank"
:type="props.atVersion.type"
:download="buildDocumentName()"
:href="state.href_url"
ref="open_button"
title="Ouvrir"
>
<i class="fa fa-external-link"></i>
<template v-if="displayActionStringInButton">Ouvrir</template>
</a>
@ -16,43 +30,50 @@ import mime from "mime";
import { StoredObject, StoredObjectVersion } from "../../types";
interface DownloadButtonConfig {
storedObject: StoredObject,
atVersion: StoredObjectVersion,
classes: { [k: string]: boolean },
filename?: string,
storedObject: StoredObject;
atVersion: StoredObjectVersion;
classes: Record<string, boolean>;
filename?: string;
/**
* if true, display the action string into the button. If false, displays only
* the icon
*/
displayActionStringInButton?: boolean,
displayActionStringInButton?: boolean;
/**
* if true, will download directly the file on load
*/
directDownload?: boolean,
directDownload?: boolean;
}
interface DownloadButtonState {
is_ready: boolean,
is_running: boolean,
href_url: string,
is_ready: boolean;
is_running: boolean;
href_url: string;
}
const props = withDefaults(defineProps<DownloadButtonConfig>(), {displayActionStringInButton: true, directDownload: false});
const state: DownloadButtonState = reactive({is_ready: false, is_running: false, href_url: "#"});
const props = withDefaults(defineProps<DownloadButtonConfig>(), {
displayActionStringInButton: true,
directDownload: false,
});
const state: DownloadButtonState = reactive({
is_ready: false,
is_running: false,
href_url: "#",
});
const open_button = ref<HTMLAnchorElement | null>(null);
function buildDocumentName(): string {
let document_name = props.filename ?? props.storedObject.title;
if ('' === document_name) {
document_name = 'document';
if ("" === document_name) {
document_name = "document";
}
const ext = mime.getExtension(props.atVersion.type);
if (null !== ext) {
return document_name + '.' + ext;
return document_name + "." + ext;
}
return document_name;
@ -60,21 +81,24 @@ function buildDocumentName(): string {
async function download_and_open(): Promise<void> {
if (state.is_running) {
console.log('state is running, aborting');
console.log("state is running, aborting");
return;
}
state.is_running = true;
if (state.is_ready) {
console.log('state is ready. This should not happens');
console.log("state is ready. This should not happens");
return;
}
let raw;
try {
raw = await download_and_decrypt_doc(props.storedObject, props.atVersion);
raw = await download_and_decrypt_doc(
props.storedObject,
props.atVersion,
);
} catch (e) {
console.error("error while downloading and decrypting document");
console.error(e);
@ -89,13 +113,13 @@ async function download_and_open(): Promise<void> {
await nextTick();
open_button.value?.click();
console.log('open button should have been clicked');
console.log("open button should have been clicked");
setTimeout(reset_state, 45000);
}
}
function reset_state(): void {
state.href_url = '#';
state.href_url = "#";
state.is_ready = false;
state.is_running = false;
}

View File

@ -1,7 +1,9 @@
<script setup lang="ts">
import HistoryButtonModal from "ChillDocStoreAssets/vuejs/StoredObjectButton/HistoryButton/HistoryButtonModal.vue";
import {StoredObject, StoredObjectVersionWithPointInTime} from "./../../types";
import {
StoredObject,
StoredObjectVersionWithPointInTime,
} from "./../../types";
import { computed, reactive, ref, useTemplateRef } from "vue";
import { get_versions } from "./HistoryButton/api";
@ -17,7 +19,7 @@ interface HistoryButtonState {
const props = defineProps<HistoryButtonConfig>();
const state = reactive<HistoryButtonState>({ versions: [], loaded: false });
const modal = useTemplateRef<typeof HistoryButtonModal>('modal');
const modal = useTemplateRef<typeof HistoryButtonModal>("modal");
const download_version_and_open_modal = async function (): Promise<void> {
if (null !== modal.value) {
@ -34,17 +36,26 @@ const download_version_and_open_modal = async function (): Promise<void> {
}
state.loaded = true;
}
}
};
const onRestoreVersion = ({newVersion}: {newVersion: StoredObjectVersionWithPointInTime}) => {
const onRestoreVersion = ({
newVersion,
}: {
newVersion: StoredObjectVersionWithPointInTime;
}) => {
state.versions.unshift(newVersion);
}
};
</script>
<template>
<a @click="download_version_and_open_modal" class="dropdown-item">
<history-button-modal ref="modal" :versions="state.versions" :stored-object="storedObject" :can-edit="canEdit" @restore-version="onRestoreVersion"></history-button-modal>
<history-button-modal
ref="modal"
:versions="state.versions"
:stored-object="storedObject"
:can-edit="canEdit"
@restore-version="onRestoreVersion"
></history-button-modal>
<i class="fa fa-history"></i>
Historique
</a>

View File

@ -1,5 +1,8 @@
<script setup lang="ts">
import {StoredObject, StoredObjectVersionWithPointInTime} from "./../../../types";
import {
StoredObject,
StoredObjectVersionWithPointInTime,
} from "./../../../types";
import HistoryButtonListItem from "ChillDocStoreAssets/vuejs/StoredObjectButton/HistoryButton/HistoryButtonListItem.vue";
import { computed, reactive } from "vue";
@ -10,8 +13,8 @@ interface HistoryButtonListConfig {
}
const emit = defineEmits<{
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime]
}>()
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime];
}>();
interface HistoryButtonListState {
/**
@ -22,12 +25,14 @@ interface HistoryButtonListState {
const props = defineProps<HistoryButtonListConfig>();
const state = reactive<HistoryButtonListState>({restored: -1})
const state = reactive<HistoryButtonListState>({ restored: -1 });
const higher_version = computed<number>(() => props.versions.reduce(
(accumulator: number, version: StoredObjectVersionWithPointInTime) => Math.max(accumulator, version.version),
-1
)
const higher_version = computed<number>(() =>
props.versions.reduce(
(accumulator: number, version: StoredObjectVersionWithPointInTime) =>
Math.max(accumulator, version.version),
-1,
),
);
/**
@ -35,11 +40,14 @@ const higher_version = computed<number>(() => props.versions.reduce(
*
* internally, keep track of the newly restored version
*/
const onRestored = ({newVersion}: {newVersion: StoredObjectVersionWithPointInTime}) => {
const onRestored = ({
newVersion,
}: {
newVersion: StoredObjectVersionWithPointInTime;
}) => {
state.restored = newVersion.version;
emit('restoreVersion', {newVersion});
}
emit("restoreVersion", { newVersion });
};
</script>
<template>
@ -59,9 +67,6 @@ const onRestored = ({newVersion}: {newVersion: StoredObjectVersionWithPointInTim
<template v-else>
<p>Chargement des versions</p>
</template>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,5 +1,9 @@
<script setup lang="ts">
import {StoredObject, StoredObjectPointInTime, StoredObjectVersionWithPointInTime} from "./../../../types";
import {
StoredObject,
StoredObjectPointInTime,
StoredObjectVersionWithPointInTime,
} from "./../../../types";
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
import { ISOToDatetime } from "./../../../../../../ChillMainBundle/Resources/public/chill/js/date";
import FileIcon from "ChillDocStoreAssets/vuejs/FileIcon.vue";
@ -15,47 +19,120 @@ interface HistoryButtonListItemConfig {
}
const emit = defineEmits<{
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime]
}>()
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime];
}>();
const props = defineProps<HistoryButtonListItemConfig>();
const onRestore = ({newVersion}: {newVersion: StoredObjectVersionWithPointInTime}) => {
emit('restoreVersion', {newVersion});
}
const onRestore = ({
newVersion,
}: {
newVersion: StoredObjectVersionWithPointInTime;
}) => {
emit("restoreVersion", { newVersion });
};
const isKeptBeforeConversion = computed<boolean>(() => props.version["point-in-times"].reduce(
(accumulator: boolean, pit: StoredObjectPointInTime) => accumulator || "keep-before-conversion" === pit.reason,
false
const isKeptBeforeConversion = computed<boolean>(() =>
props.version["point-in-times"].reduce(
(accumulator: boolean, pit: StoredObjectPointInTime) =>
accumulator || "keep-before-conversion" === pit.reason,
false,
),
);
const isRestored = computed<boolean>(() => props.version.version > 0 && null !== props.version["from-restored"]);
const isRestored = computed<boolean>(
() => props.version.version > 0 && null !== props.version["from-restored"],
);
const isDuplicated = computed<boolean>(() => props.version.version === 0 && null !== props.version["from-restored"]);
const classes = computed<{row: true, 'row-hover': true, 'blinking-1': boolean, 'blinking-2': boolean}>(() => ({row: true, 'row-hover': true, 'blinking-1': props.isRestored && 0 === props.version.version % 2, 'blinking-2': props.isRestored && 1 === props.version.version % 2}));
const isDuplicated = computed<boolean>(
() =>
props.version.version === 0 && null !== props.version["from-restored"],
);
const classes = computed<{
row: true;
"row-hover": true;
"blinking-1": boolean;
"blinking-2": boolean;
}>(() => ({
row: true,
"row-hover": true,
"blinking-1": props.isRestored && 0 === props.version.version % 2,
"blinking-2": props.isRestored && 1 === props.version.version % 2,
}));
</script>
<template>
<div :class="classes">
<div class="col-12 tags" v-if="isCurrent || isKeptBeforeConversion || isRestored || isDuplicated">
<span class="badge bg-success" v-if="isCurrent">Version actuelle</span>
<span class="badge bg-info" v-if="isKeptBeforeConversion">Conservée avant conversion dans un autre format</span>
<span class="badge bg-info" v-if="isRestored">Restaurée depuis la version {{ version["from-restored"]?.version + 1 }}</span>
<span class="badge bg-info" v-if="isDuplicated">Dupliqué depuis un autre document</span>
<div
class="col-12 tags"
v-if="
isCurrent ||
isKeptBeforeConversion ||
isRestored ||
isDuplicated
"
>
<span class="badge bg-success" v-if="isCurrent"
>Version actuelle</span
>
<span class="badge bg-info" v-if="isKeptBeforeConversion"
>Conservée avant conversion dans un autre format</span
>
<span class="badge bg-info" v-if="isRestored"
>Restaurée depuis la version
{{ version["from-restored"]?.version + 1 }}</span
>
<span class="badge bg-info" v-if="isDuplicated"
>Dupliqué depuis un autre document</span
>
</div>
<div class="col-12">
<file-icon :type="version.type"></file-icon> <span><strong>#{{ version.version + 1 }}</strong></span> <template v-if="version.createdBy !== null && version.createdAt !== null"><strong v-if="version.version == 0">Créé par</strong><strong v-else>modifié par</strong> <span class="badge-user"><UserRenderBoxBadge :user="version.createdBy"></UserRenderBoxBadge></span> <strong>à</strong> {{ $d(ISOToDatetime(version.createdAt.datetime8601), 'long') }}</template><template v-if="version.createdBy === null && version.createdAt !== null"><strong v-if="version.version == 0">Créé le</strong><strong v-else>modifié le</strong> {{ $d(ISOToDatetime(version.createdAt.datetime8601), 'long') }}</template>
<file-icon :type="version.type"></file-icon>
<span
><strong>#{{ version.version + 1 }}</strong></span
>
<template
v-if="version.createdBy !== null && version.createdAt !== null"
><strong v-if="version.version == 0">Créé par</strong
><strong v-else>modifié par</strong>
<span class="badge-user"
><UserRenderBoxBadge
:user="version.createdBy"
></UserRenderBoxBadge
></span>
<strong>à</strong>
{{
$d(ISOToDatetime(version.createdAt.datetime8601), "long")
}}</template
><template
v-if="version.createdBy === null && version.createdAt !== null"
><strong v-if="version.version == 0">Créé le</strong
><strong v-else>modifié le</strong>
{{
$d(ISOToDatetime(version.createdAt.datetime8601), "long")
}}</template
>
</div>
<div class="col-12">
<ul class="record_actions small slim on-version-actions">
<li v-if="canEdit && !isCurrent">
<restore-version-button :stored-object-version="props.version" @restore-version="onRestore"></restore-version-button>
<restore-version-button
:stored-object-version="props.version"
@restore-version="onRestore"
></restore-version-button>
</li>
<li>
<download-button :stored-object="storedObject" :at-version="version" :classes="{btn: true, 'btn-outline-primary': true, 'btn-sm': true}" :display-action-string-in-button="false"></download-button>
<download-button
:stored-object="storedObject"
:at-version="version"
:classes="{
btn: true,
'btn-outline-primary': true,
'btn-sm': true,
}"
:display-action-string-in-button="false"
></download-button>
</li>
</ul>
</div>

View File

@ -2,7 +2,10 @@
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
import { reactive } from "vue";
import HistoryButtonList from "ChillDocStoreAssets/vuejs/StoredObjectButton/HistoryButton/HistoryButtonList.vue";
import {StoredObject, StoredObjectVersionWithPointInTime} from "./../../../types";
import {
StoredObject,
StoredObjectVersionWithPointInTime,
} from "./../../../types";
interface HistoryButtonListConfig {
versions: StoredObjectVersionWithPointInTime[];
@ -11,8 +14,8 @@ interface HistoryButtonListConfig {
}
const emit = defineEmits<{
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime]
}>()
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime];
}>();
interface HistoryButtonModalState {
opened: boolean;
@ -23,10 +26,9 @@ const state = reactive<HistoryButtonModalState>({opened: false});
const open = () => {
state.opened = true;
}
};
defineExpose({ open });
</script>
<template>
<Teleport to="body">
@ -36,12 +38,17 @@ defineExpose({open});
</template>
<template v-slot:body>
<p>Les versions sont conservées pendant 90 jours.</p>
<history-button-list :versions="props.versions" :can-edit="canEdit" :stored-object="storedObject" @restore-version="(payload) => emit('restoreVersion', payload)"></history-button-list>
<history-button-list
:versions="props.versions"
:can-edit="canEdit"
:stored-object="storedObject"
@restore-version="
(payload) => emit('restoreVersion', payload)
"
></history-button-list>
</template>
</modal>
</Teleport>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,17 +1,20 @@
<script setup lang="ts">
import {StoredObjectVersionPersisted, StoredObjectVersionWithPointInTime} from "../../../types";
import {
StoredObjectVersionPersisted,
StoredObjectVersionWithPointInTime,
} from "../../../types";
import { useToast } from "vue-toast-notification";
import { restore_version } from "./api";
interface RestoreVersionButtonProps {
storedObjectVersion: StoredObjectVersionPersisted,
storedObjectVersion: StoredObjectVersionPersisted;
}
const emit = defineEmits<{
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime]
}>()
restoreVersion: [newVersion: StoredObjectVersionWithPointInTime];
}>();
const props = defineProps<RestoreVersionButtonProps>()
const props = defineProps<RestoreVersionButtonProps>();
const $toast = useToast();
@ -19,14 +22,18 @@ const restore_version_fn = async () => {
const newVersion = await restore_version(props.storedObjectVersion);
$toast.success("Version restaurée");
emit('restoreVersion', {newVersion});
}
emit("restoreVersion", { newVersion });
};
</script>
<template>
<button class="btn btn-outline-action" @click="restore_version_fn" title="Restaurer"><i class="fa fa-rotate-left"></i> Restaurer</button>
<button
class="btn btn-outline-action"
@click="restore_version_fn"
title="Restaurer"
>
<i class="fa fa-rotate-left"></i> Restaurer
</button>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,5 +1,11 @@
<template>
<a :class="Object.assign(props.classes, {'btn': true})" @click="beforeLeave($event)" :href="build_wopi_editor_link(props.storedObject.uuid, props.returnPath)">
<a
:class="Object.assign(props.classes, { btn: true })"
@click="beforeLeave($event)"
:href="
build_wopi_editor_link(props.storedObject.uuid, props.returnPath)
"
>
<i class="fa fa-paragraph"></i>
Editer en ligne
</a>
@ -8,13 +14,16 @@
<script lang="ts" setup>
import WopiEditButton from "./WopiEditButton.vue";
import { build_wopi_editor_link } from "./helpers";
import {StoredObject, WopiEditButtonExecutableBeforeLeaveFunction} from "../../types";
import {
StoredObject,
WopiEditButtonExecutableBeforeLeaveFunction,
} from "../../types";
interface WopiEditButtonConfig {
storedObject: StoredObject,
returnPath?: string,
classes: {[k: string] : boolean},
executeBeforeLeave?: WopiEditButtonExecutableBeforeLeaveFunction,
storedObject: StoredObject;
returnPath?: string;
classes: Record<string, boolean>;
executeBeforeLeave?: WopiEditButtonExecutableBeforeLeaveFunction;
}
const props = defineProps<WopiEditButtonConfig>();
@ -43,4 +52,3 @@ i.fa::before {
color: var(--bs-dropdown-link-hover-color);
}
</style>

View File

@ -1,7 +1,7 @@
import { createApp } from 'vue';
import PickEntity from 'ChillMainAssets/vuejs/PickEntity/PickEntity.vue';
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n';
import { appMessages } from 'ChillMainAssets/vuejs/PickEntity/i18n';
import { createApp } from "vue";
import PickEntity from "ChillMainAssets/vuejs/PickEntity/PickEntity.vue";
import { _createI18n } from "ChillMainAssets/vuejs/_js/i18n";
import { appMessages } from "ChillMainAssets/vuejs/PickEntity/i18n";
const i18n = _createI18n(appMessages);
@ -9,34 +9,35 @@ let appsOnPage = new Map();
let appsPerInput = new Map();
function loadDynamicPicker(element) {
let apps = element.querySelectorAll('[data-module="pick-dynamic"]');
apps.forEach(function (el) {
const
isMultiple = parseInt(el.dataset.multiple) === 1,
const isMultiple = parseInt(el.dataset.multiple) === 1,
uniqId = el.dataset.uniqid,
input = element.querySelector('[data-input-uniqid="'+ el.dataset.uniqid +'"]'),
input = element.querySelector(
'[data-input-uniqid="' + el.dataset.uniqid + '"]',
),
// the "picked" will always be an array, even if multiple is false
picked = isMultiple ?
JSON.parse(input.value) : (
(input.value === '[]' || input.value === '') ?
null : [ JSON.parse(input.value) ]
)
suggested = JSON.parse(el.dataset.suggested),
as_id = parseInt(el.dataset.asId) === 1,
submit_on_adding_new_entity = parseInt(el.dataset.submitOnAddingNewEntity) === 1
picked = isMultiple
? JSON.parse(input.value)
: input.value === "[]" || input.value === ""
? null
: [JSON.parse(input.value)];
(suggested = JSON.parse(el.dataset.suggested)),
(as_id = parseInt(el.dataset.asId) === 1),
(submit_on_adding_new_entity =
parseInt(el.dataset.submitOnAddingNewEntity) === 1);
label = el.dataset.label;
if (!isMultiple) {
if (input.value === '[]'){
if (input.value === "[]") {
input.value = null;
}
}
const app = createApp({
template: '<pick-entity ' +
template:
"<pick-entity " +
':multiple="multiple" ' +
':types="types" ' +
':picked="picked" ' +
@ -46,7 +47,7 @@ function loadDynamicPicker(element) {
'@addNewEntity="addNewEntity" ' +
'@removeEntity="removeEntity" ' +
'@addNewEntityProcessEnded="addNewEntityProcessEnded"' +
'></pick-entity>',
"></pick-entity>",
components: {
PickEntity,
},
@ -60,7 +61,7 @@ function loadDynamicPicker(element) {
as_id,
submit_on_adding_new_entity,
label,
}
};
},
computed: {
notPickedSuggested() {
@ -68,34 +69,40 @@ function loadDynamicPicker(element) {
for (const p of this.picked) {
pickedIds.add(`${p.type}${p.id}`);
}
return this.suggested.filter(e => !pickedIds.has(`${e.type}${e.id}`))
}
return this.suggested.filter(
(e) => !pickedIds.has(`${e.type}${e.id}`),
);
},
},
methods: {
addNewEntity({ entity }) {
if (this.multiple) {
if (!this.picked.some(el => {
if (
!this.picked.some((el) => {
return el.type === entity.type && el.id === entity.id;
})) {
})
) {
this.picked.push(entity);
if (!as_id) {
input.value = JSON.stringify(this.picked);
} else {
const ids = this.picked.map(el => el.id);
input.value = ids.join(',');
const ids = this.picked.map((el) => el.id);
input.value = ids.join(",");
}
console.log(entity)
console.log(entity);
}
} else {
if (!this.picked.some(el => {
if (
!this.picked.some((el) => {
return el.type === entity.type && el.id === entity.id;
})) {
})
) {
this.picked.splice(0, this.picked.length);
this.picked.push(entity);
if (!as_id) {
input.value = JSON.stringify(this.picked[0]);
} else {
input.value = this.picked.map(el => el.id);
input.value = this.picked.map((el) => el.id);
}
}
}
@ -106,17 +113,24 @@ function loadDynamicPicker(element) {
}
},
removeEntity({ entity }) {
if (-1 === this.suggested.findIndex(e => e.type === entity.type && e.id === entity.id)) {
if (
-1 ===
this.suggested.findIndex(
(e) => e.type === entity.type && e.id === entity.id,
)
) {
this.suggested.push(entity);
}
this.picked = this.picked.filter(e => !(e.type === entity.type && e.id === entity.id));
this.picked = this.picked.filter(
(e) => !(e.type === entity.type && e.id === entity.id),
);
if (this.multiple) {
input.value = JSON.stringify(this.picked);
} else {
input.value = "";
}
},
}
},
})
.use(i18n)
.mount(el);
@ -126,41 +140,41 @@ function loadDynamicPicker(element) {
});
}
document.addEventListener('show-hide-show', function(e) {
loadDynamicPicker(e.detail.container)
document.addEventListener("show-hide-show", function (e) {
loadDynamicPicker(e.detail.container);
});
document.addEventListener('show-hide-hide', function(e) {
console.log('hiding event caught')
e.detail.container.querySelectorAll('[data-module="pick-dynamic"]').forEach((el) => {
document.addEventListener("show-hide-hide", function (e) {
console.log("hiding event caught");
e.detail.container
.querySelectorAll('[data-module="pick-dynamic"]')
.forEach((el) => {
let uniqId = el.dataset.uniqid;
if (appsOnPage.has(uniqId)) {
appsOnPage.get(uniqId).unmount();
appsOnPage.delete(uniqId);
}
})
});
});
document.addEventListener('pick-entity-type-action', function (e) {
console.log('pick entity event', e);
document.addEventListener("pick-entity-type-action", function (e) {
console.log("pick entity event", e);
if (!appsPerInput.has(e.detail.name)) {
console.error('no app with this name');
console.error("no app with this name");
return;
}
const app = appsPerInput.get(e.detail.name);
if (e.detail.action === 'add') {
if (e.detail.action === "add") {
app.addNewEntity(e.detail.entity);
} else if (e.detail.action === 'remove') {
} else if (e.detail.action === "remove") {
app.removeEntity(e.detail.entity);
} else {
console.error('action not supported: '+e.detail.action);
console.error("action not supported: " + e.detail.action);
}
});
document.addEventListener('DOMContentLoaded', function(e) {
loadDynamicPicker(document)
})
document.addEventListener("DOMContentLoaded", function (e) {
loadDynamicPicker(document);
});
window.loadDynamicPicker = loadDynamicPicker;

View File

@ -1,20 +1,21 @@
import {ShowHide} from 'ChillMainAssets/lib/show_hide/show_hide.js';
window.addEventListener('DOMContentLoaded', function() {
const
divTransitions = document.querySelector('#transitions'),
futureDestUsersContainer = document.querySelector('#futureDests'),
personSignatureField = document.querySelector('#person-signature-field'),
userSignatureField = document.querySelector('#user-signature-field'),
signatureTypeChoices = document.querySelector('#signature-type-choice'),
personChoice = document.querySelector('#workflow_step_isPersonOrUserSignature_0'),
userChoice = document.querySelector('#workflow_step_isPersonOrUserSignature_1'),
signatureZone = document.querySelector('#signature-zone'),
transitionFilterContainer = document.querySelector('#transitionFilter'),
transitionsContainer = document.querySelector('#transitions'),
sendExternalContainer = document.querySelector('#sendExternalContainer')
;
import { ShowHide } from "ChillMainAssets/lib/show_hide/show_hide.js";
window.addEventListener("DOMContentLoaded", function () {
const divTransitions = document.querySelector("#transitions"),
futureDestUsersContainer = document.querySelector("#futureDests"),
personSignatureField = document.querySelector("#person-signature-field"),
userSignatureField = document.querySelector("#user-signature-field"),
signatureTypeChoices = document.querySelector("#signature-type-choice"),
personChoice = document.querySelector(
"#workflow_step_isPersonOrUserSignature_0",
),
userChoice = document.querySelector(
"#workflow_step_isPersonOrUserSignature_1",
),
signatureZone = document.querySelector("#signature-zone"),
transitionFilterContainer = document.querySelector("#transitionFilter"),
transitionsContainer = document.querySelector("#transitions"),
sendExternalContainer = document.querySelector("#sendExternalContainer");
// ShowHide instance for future dest users
new ShowHide({
debug: false,
@ -23,22 +24,24 @@ window.addEventListener('DOMContentLoaded', function() {
container: [futureDestUsersContainer],
test: function (froms, event) {
for (let transition of froms) {
for (let input of transition.querySelectorAll('input')) {
for (let input of transition.querySelectorAll("input")) {
if (input.checked) {
if ('1' === input.dataset.toFinal) {
if ("1" === input.dataset.toFinal) {
return false;
}
if ('1' === input.dataset.isSentExternal) {
if ("1" === input.dataset.isSentExternal) {
return false;
}
const inputData = JSON.parse(input.getAttribute('data-is-signature'))
if (inputData.includes('person') || inputData.includes('user')) {
const inputData = JSON.parse(
input.getAttribute("data-is-signature"),
);
if (inputData.includes("person") || inputData.includes("user")) {
return false;
} else {
personChoice.checked = false
userChoice.checked = false
personChoice.checked = false;
userChoice.checked = false;
return true;
}
@ -46,7 +49,7 @@ window.addEventListener('DOMContentLoaded', function() {
}
}
return false;
}
},
});
// ShowHide instance for send external
@ -57,17 +60,17 @@ window.addEventListener('DOMContentLoaded', function() {
container: [sendExternalContainer],
test: function (froms, event) {
for (let transition of froms) {
for (let input of transition.querySelectorAll('input')) {
for (let input of transition.querySelectorAll("input")) {
if (input.checked) {
if ('1' === input.dataset.isSentExternal) {
if ("1" === input.dataset.isSentExternal) {
return true;
}
}
}
}
return false;
}
})
},
});
// ShowHide signature zone
new ShowHide({
@ -77,17 +80,19 @@ window.addEventListener('DOMContentLoaded', function() {
container: [signatureZone],
test: function (froms, event) {
for (let transition of froms) {
for (let input of transition.querySelectorAll('input')) {
for (let input of transition.querySelectorAll("input")) {
if (input.checked) {
const inputData = JSON.parse(input.getAttribute('data-is-signature'))
if (inputData.includes('person') || inputData.includes('user')) {
const inputData = JSON.parse(
input.getAttribute("data-is-signature"),
);
if (inputData.includes("person") || inputData.includes("user")) {
return true;
}
}
}
}
return false;
}
},
});
// ShowHides for personSignatureField or userSignatureField within signature zone
@ -122,7 +127,7 @@ window.addEventListener('DOMContentLoaded', function() {
container: [futureDestUsersContainer],
test: function (divs, arg2, arg3) {
for (let div of divs) {
for (let input of div.querySelectorAll('input')) {
for (let input of div.querySelectorAll("input")) {
if (input.checked) {
if (input.dataset.toFinal === "1") {
return false;
@ -139,9 +144,10 @@ window.addEventListener('DOMContentLoaded', function() {
}
if (null !== transitionFilterContainer) {
transitionsContainer.querySelectorAll('.form-check').forEach(function(row) {
const isForward = row.querySelector('input').dataset.isForward;
transitionsContainer
.querySelectorAll(".form-check")
.forEach(function (row) {
const isForward = row.querySelector("input").dataset.isForward;
new ShowHide({
load_event: null,
@ -149,7 +155,7 @@ window.addEventListener('DOMContentLoaded', function() {
container: row,
test: function (containers) {
for (let container of containers) {
for (let input of container.querySelectorAll('input')) {
for (let input of container.querySelectorAll("input")) {
if (input.checked) {
return isForward === input.value;
}
@ -159,8 +165,8 @@ window.addEventListener('DOMContentLoaded', function() {
},
toggle_callback: function (c, dir) {
for (let div of c) {
let input = div.querySelector('input');
if ('hide' === dir) {
let input = div.querySelector("input");
if ("hide" === dir) {
input.checked = false;
input.disabled = true;
} else {

View File

@ -28,7 +28,11 @@
/>
<span class="mx-2">{{ getStep(w) }}</span>
</div>
<span v-if="w.isOnHoldAtCurrentStep" class="badge bg-success rounded-pill">{{ $t('on_hold') }}</span>
<span
v-if="w.isOnHoldAtCurrentStep"
class="badge bg-success rounded-pill"
>{{ $t("on_hold") }}</span
>
</div>
</td>
<td v-if="w.datas.persons !== null">

View File

@ -3,20 +3,25 @@ const appMessages = {
main_title: "Vue d'ensemble",
my_works: {
tab: "Mes actions",
description: "Liste des actions d'accompagnement dont je suis référent et qui arrivent à échéance.",
description:
"Liste des actions d'accompagnement dont je suis référent et qui arrivent à échéance.",
},
my_evaluations: {
tab: "Mes évaluations",
description: "Liste des évaluations dont je suis référent et qui arrivent à échéance.",
description:
"Liste des évaluations dont je suis référent et qui arrivent à échéance.",
},
my_tasks: {
tab: "Mes tâches",
description_alert: "Liste des tâches auxquelles je suis assigné et dont la date de rappel est dépassée.",
description_warning: "Liste des tâches auxquelles je suis assigné et dont la date d'échéance est dépassée.",
description_alert:
"Liste des tâches auxquelles je suis assigné et dont la date de rappel est dépassée.",
description_warning:
"Liste des tâches auxquelles je suis assigné et dont la date d'échéance est dépassée.",
},
my_accompanying_courses: {
tab: "Mes nouveaux parcours",
description: "Liste des parcours d'accompagnement que l'on vient de m'attribuer depuis moins de 15 jours.",
description:
"Liste des parcours d'accompagnement que l'on vient de m'attribuer depuis moins de 15 jours.",
},
my_notifications: {
tab: "Mes nouvelles notifications",
@ -25,7 +30,7 @@ const appMessages = {
my_workflows: {
tab: "Mes workflows",
description: "Liste des workflows en attente d'une action.",
description_cc: "Liste des workflows dont je suis en copie."
description_cc: "Liste des workflows dont je suis en copie.",
},
opening_date: "Date d'ouverture",
social_issues: "Problématiques sociales",
@ -55,10 +60,13 @@ const appMessages = {
no_data: "Aucun résultats",
no_dashboard: "Pas de tableaux de bord",
counter: {
unread_notifications: "{n} notification non lue | {n} notifications non lues",
assignated_courses: "{n} parcours récent assigné | {n} parcours récents assignés",
unread_notifications:
"{n} notification non lue | {n} notifications non lues",
assignated_courses:
"{n} parcours récent assigné | {n} parcours récents assignés",
assignated_actions: "{n} action assignée | {n} actions assignées",
assignated_evaluations: "{n} évaluation assignée | {n} évaluations assignées",
assignated_evaluations:
"{n} évaluation assignée | {n} évaluations assignées",
alert_tasks: "{n} tâche en rappel | {n} tâches en rappel",
warning_tasks: "{n} tâche à échéance | {n} tâches à échéance",
},
@ -70,14 +78,12 @@ const appMessages = {
title: "Actualités",
readMore: "Lire la suite",
date: "Date",
none: "Aucune actualité"
}
}
}
none: "Aucune actualité",
},
},
},
};
Object.assign(appMessages.fr);
export {
appMessages
};
export { appMessages };

View File

@ -18,7 +18,9 @@
</li>
</ul>
<ul class="list-suggest add-items inline">
<li v-for="s in suggested" :key="s.id" @click="addNewSuggested(s)"><span>{{ s.text }}</span></li>
<li v-for="s in suggested" :key="s.id" @click="addNewSuggested(s)">
<span>{{ s.text }}</span>
</li>
</ul>
</template>
@ -55,20 +57,20 @@ export default {
},
suggested: {
type: Array,
default: []
default: [],
},
label: {
type: String,
required: false,
}
},
emits: ['addNewEntity', 'removeEntity', 'addNewEntityProcessEnded'],
},
emits: ["addNewEntity", "removeEntity", "addNewEntityProcessEnded"],
components: {
AddPersons,
},
data() {
return {
key: ''
key: "",
};
},
computed: {
@ -78,57 +80,63 @@ export default {
type: this.types,
priority: null,
button: {
size: 'btn-sm',
class: 'btn-submit',
size: "btn-sm",
class: "btn-submit",
},
};
},
translatedListOfTypes() {
if (this.label !== '') {
if (this.label !== "") {
return this.label;
}
let trans = [];
this.types.forEach(t => {
this.types.forEach((t) => {
if (this.$props.multiple) {
trans.push(appMessages.fr.pick_entity[t].toLowerCase());
} else {
trans.push(appMessages.fr.pick_entity[t + '_one'].toLowerCase());
trans.push(
appMessages.fr.pick_entity[t + "_one"].toLowerCase(),
);
}
})
});
if (this.$props.multiple) {
return appMessages.fr.pick_entity.modal_title + trans.join(', ');
return (
appMessages.fr.pick_entity.modal_title + trans.join(", ")
);
} else {
return appMessages.fr.pick_entity.modal_title_one + trans.join(', ');
return (
appMessages.fr.pick_entity.modal_title_one +
trans.join(", ")
);
}
},
listClasses() {
return {
'list-suggest': true,
'remove-items': this.$props.removableIfSet,
"list-suggest": true,
"remove-items": this.$props.removableIfSet,
};
},
},
methods: {
addNewSuggested(entity) {
this.$emit('addNewEntity', {entity: entity});
this.$emit("addNewEntity", { entity: entity });
},
addNewEntity({ selected, modal }) {
selected.forEach((item) => {
this.$emit('addNewEntity', { entity: item.result});
}, this
);
this.$emit("addNewEntity", { entity: item.result });
}, this);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
this.$emit('addNewEntityProcessEnded');
this.$emit("addNewEntityProcessEnded");
},
removeEntity(entity) {
if (!this.$props.removableIfSet) {
return;
}
this.$emit('removeEntity',{ entity: entity });
}
this.$emit("removeEntity", { entity: entity });
},
}
},
};
</script>

View File

@ -8,19 +8,18 @@ interface UserGroupRenderBoxProps {
const props = defineProps<UserGroupRenderBoxProps>();
const styles = computed<{color: string, "background-color": string}>(() => {
const styles = computed<{ color: string; "background-color": string }>(() => {
return {
color: props.userGroup.foregroundColor,
"background-color": props.userGroup.backgroundColor,
}
};
});
</script>
<template>
<span class="badge-user-group" :style="styles">{{ userGroup.label.fr }}</span>
<span class="badge-user-group" :style="styles">{{
userGroup.label.fr
}}</span>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,8 +1,10 @@
<template>
<div class="flex-table workflow" id="workflow-list">
<div v-for="(w, i) in workflows" :key="`workflow-${i}`"
class="item-bloc">
<div
v-for="(w, i) in workflows"
:key="`workflow-${i}`"
class="item-bloc"
>
<div>
<div class="item-row col">
<h2>{{ w.title }}</h2>
@ -16,20 +18,25 @@
<div class="breadcrumb">
<template v-for="(step, j) in w.steps" :key="`step-${j}`">
<span class="mx-2"
<span
class="mx-2"
tabindex="0"
data-bs-trigger="focus hover"
data-bs-toggle="popover"
data-bs-placement="bottom"
data-bs-custom-class="workflow-transition"
:title="getPopTitle(step)"
:data-bs-content="getPopContent(step)">
<i v-if="step.currentStep.name === 'initial'"
class="fa fa-circle me-1 text-chill-yellow">
:data-bs-content="getPopContent(step)"
>
<i
v-if="step.currentStep.name === 'initial'"
class="fa fa-circle me-1 text-chill-yellow"
>
</i>
<i v-if="step.isFreezed"
class="fa fa-snowflake-o fa-sm me-1">
<i
v-if="step.isFreezed"
class="fa fa-snowflake-o fa-sm me-1"
>
</i>
{{ step.currentStep.text }}
</span>
@ -38,47 +45,56 @@
</span>
</template>
</div>
<span v-if="w.isOnHoldAtCurrentStep" class="badge bg-success rounded-pill">{{ $t('on_hold') }}</span>
<span
v-if="w.isOnHoldAtCurrentStep"
class="badge bg-success rounded-pill"
>{{ $t("on_hold") }}</span
>
</div>
<div class="item-row">
<div class="item-col flex-grow-1">
<p v-if="isUserSubscribedToStep(w)">
<i class="fa fa-check fa-fw"></i>
{{ $t('you_subscribed_to_all_steps') }}
{{ $t("you_subscribed_to_all_steps") }}
</p>
<p v-if="isUserSubscribedToFinal(w)">
<i class="fa fa-check fa-fw"></i>
{{ $t('you_subscribed_to_final_step') }}
{{ $t("you_subscribed_to_final_step") }}
</p>
</div>
<div class="item-col">
<ul class="record_actions">
<li>
<a :href="goToUrl(w)" class="btn btn-sm btn-show" :title="$t('action.show')"></a>
<a
:href="goToUrl(w)"
class="btn btn-sm btn-show"
:title="$t('action.show')"
></a>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
import Popover from 'bootstrap/js/src/popover';
import Popover from "bootstrap/js/src/popover";
const i18n = {
messages: {
fr: {
you_subscribed_to_all_steps: "Vous recevrez une notification à chaque étape",
you_subscribed_to_final_step: "Vous recevrez une notification à l'étape finale",
you_subscribed_to_all_steps:
"Vous recevrez une notification à chaque étape",
you_subscribed_to_final_step:
"Vous recevrez une notification à l'étape finale",
by: "Par",
at: "Le",
on_hold: "En attente"
}
}
}
on_hold: "En attente",
},
},
};
export default {
name: "ListWorkflow",
@ -87,7 +103,7 @@ export default {
workflows: {
type: Array,
required: true,
}
},
},
methods: {
goToUrl(w) {
@ -96,7 +112,9 @@ export default {
getPopTitle(step) {
if (step.transitionPrevious != null) {
//console.log(step.transitionPrevious.text);
let freezed = step.isFreezed ? `<i class="fa fa-snowflake-o fa-sm me-1"></i>` : ``;
let freezed = step.isFreezed
? `<i class="fa fa-snowflake-o fa-sm me-1"></i>`
: ``;
return `${freezed}${step.transitionPrevious.text}`;
}
},
@ -106,17 +124,20 @@ export default {
return `<ul class="small_in_title">
<li><span class="item-key">${i18n.messages.fr.by} : </span><b>${step.transitionPreviousBy.text}</b></li>
<li><span class="item-key">${i18n.messages.fr.at} : </span><b>${this.formatDate(step.transitionPreviousAt.datetime)}</b></li>
</ul>`
;
</ul>`;
} else {
return `<ul class="small_in_title">
<li><span class="item-key">${i18n.messages.fr.at} : </span><b>${this.formatDate(step.transitionPreviousAt.datetime)}</b></li>
</ul>`
</ul>`;
}
}
},
formatDate(datetime) {
return datetime.split('T')[0] +' '+ datetime.split('T')[1].substring(0,5)
return (
datetime.split("T")[0] +
" " +
datetime.split("T")[1].substring(0, 5)
);
},
isUserSubscribedToStep(w) {
// todo
@ -128,13 +149,15 @@ export default {
},
},
mounted() {
const triggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
const triggerList = [].slice.call(
document.querySelectorAll('[data-bs-toggle="popover"]'),
);
const popoverList = triggerList.map(function (el) {
//console.log('popover', el)
return new Popover(el, {
html: true,
});
});
}
}
},
};
</script>

View File

@ -11,50 +11,53 @@
></pick-workflow>
<teleport to="body">
<modal v-if="modal.showModal"
<modal
v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
@close="modal.showModal = false">
@close="modal.showModal = false"
>
<template v-slot:header>
<h2 class="modal-title">{{ $t('workflow_list') }}</h2>
<h2 class="modal-title">{{ $t("workflow_list") }}</h2>
</template>
<template v-slot:body>
<list-workflow-vue
:workflows="workflows"
></list-workflow-vue>
<list-workflow-vue :workflows="workflows"></list-workflow-vue>
</template>
<template v-slot:footer>
<pick-workflow v-if="allowCreate"
<pick-workflow
v-if="allowCreate"
:relatedEntityClass="this.relatedEntityClass"
:relatedEntityId="this.relatedEntityId"
:workflowsAvailables="workflowsAvailables"
:preventDefaultMoveToGenerate="this.$props.preventDefaultMoveToGenerate"
:goToGenerateWorkflowPayload="this.goToGenerateWorkflowPayload"
:preventDefaultMoveToGenerate="
this.$props.preventDefaultMoveToGenerate
"
:goToGenerateWorkflowPayload="
this.goToGenerateWorkflowPayload
"
:countExistingWorkflows="countWorkflows"
:embedded-within-list-modal="true"
@go-to-generate-workflow="this.goToGenerateWorkflow"
></pick-workflow>
</template>
</modal>
</teleport>
</template>
<script>
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import PickWorkflow from 'ChillMainAssets/vuejs/_components/EntityWorkflow/PickWorkflow.vue';
import ListWorkflowVue from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflow.vue';
import Modal from "ChillMainAssets/vuejs/_components/Modal";
import PickWorkflow from "ChillMainAssets/vuejs/_components/EntityWorkflow/PickWorkflow.vue";
import ListWorkflowVue from "ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflow.vue";
export default {
name: "ListWorkflowModal",
components: {
Modal,
PickWorkflow,
ListWorkflowVue
ListWorkflowVue,
},
emits: ['goToGenerateWorkflow'],
emits: ["goToGenerateWorkflow"],
props: {
workflows: {
type: Array,
@ -83,16 +86,16 @@ export default {
},
goToGenerateWorkflowPayload: {
required: false,
default: {}
default: {},
},
},
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl"
modalDialogClass: "modal-dialog-scrollable modal-xl",
},
}
};
},
computed: {
countWorkflows() {
@ -100,16 +103,16 @@ export default {
},
hasWorkflow() {
return this.countWorkflows > 0;
}
},
},
methods: {
openModal() {
this.modal.showModal = true;
},
goToGenerateWorkflow(data) {
console.log('go to generate workflow intercepted', data);
this.$emit('goToGenerateWorkflow', data);
}
console.log("go to generate workflow intercepted", data);
this.$emit("goToGenerateWorkflow", data);
},
},
i18n: {
messages: {
@ -117,10 +120,10 @@ export default {
workflow_list: "Liste des workflows associés",
workflow: " workflow associé",
workflows: " workflows associés",
}
}
}
}
},
},
},
};
</script>
<style scoped></style>

View File

@ -1,12 +1,27 @@
<template>
<template v-if="props.workflowsAvailables.length >= 1">
<div v-if="countExistingWorkflows == 0 || embeddedWithinListModal" class="dropdown d-grid gap-2">
<button class="btn btn-primary dropdown-toggle" type="button" id="createWorkflowButton" data-bs-toggle="dropdown" aria-expanded="false">
<div
v-if="countExistingWorkflows == 0 || embeddedWithinListModal"
class="dropdown d-grid gap-2"
>
<button
class="btn btn-primary dropdown-toggle"
type="button"
id="createWorkflowButton"
data-bs-toggle="dropdown"
aria-expanded="false"
>
Créer un workflow
</button>
<ul class="dropdown-menu" aria-labelledby="createWorkflowButton">
<li v-for="w in props.workflowsAvailables" :key="w.name">
<button class="dropdown-item" type="button" @click.prevent="goToGenerateWorkflow($event, w.name)">{{ w.text }}</button>
<button
class="dropdown-item"
type="button"
@click.prevent="goToGenerateWorkflow($event, w.name)"
>
{{ w.text }}
</button>
</li>
</ul>
</div>
@ -20,12 +35,31 @@
{{ countExistingWorkflows }} workflows associés
</template>
</button>
<button class="btn btn-primary dropdown-toggle dropdown-toggle-split" type="button" id="createWorkflowButton" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">Liste des workflows disponibles</span>
<button
class="btn btn-primary dropdown-toggle dropdown-toggle-split"
type="button"
id="createWorkflowButton"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<span class="visually-hidden"
>Liste des workflows disponibles</span
>
</button>
<ul class="dropdown-menu" aria-labelledby="createWorkflowButton">
<ul
class="dropdown-menu"
aria-labelledby="createWorkflowButton"
>
<li v-for="w in props.workflowsAvailables" :key="w.name">
<button class="dropdown-item" type="button" @click.prevent="goToGenerateWorkflow($event, w.name)">{{ w.text }}</button>
<button
class="dropdown-item"
type="button"
@click.prevent="
goToGenerateWorkflow($event, w.name)
"
>
{{ w.text }}
</button>
</li>
</ul>
</div>
@ -33,7 +67,14 @@
</template>
<template v-else>
<div v-if="countExistingWorkflows > 0" class="dropdown d-grid gap-2">
<button @click="emit('clickOpenList')" class="btn btn-primary" type="button" id="createWorkflowButton" data-bs-toggle="dropdown" aria-expanded="false">
<button
@click="emit('clickOpenList')"
class="btn btn-primary"
type="button"
id="createWorkflowButton"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<template v-if="countExistingWorkflows === 1">
1 workflow associé
</template>
@ -46,8 +87,7 @@
</template>
<script setup lang="ts">
import {buildLinkCreate} from '../../../lib/entity-workflow/api';
import { buildLinkCreate } from "../../../lib/entity-workflow/api";
import { WorkflowAvailable } from "../../../types";
interface PickWorkflowConfig {
@ -69,39 +109,68 @@ interface PickWorkflowConfig {
embeddedWithinListModal: boolean;
}
const props = withDefaults(defineProps<PickWorkflowConfig>(), {preventDefaultMoveToGenerate: false, goToGenerateWorkflowPayload: {}, allowCreateWorkflow: false});
const props = withDefaults(defineProps<PickWorkflowConfig>(), {
preventDefaultMoveToGenerate: false,
goToGenerateWorkflowPayload: {},
allowCreateWorkflow: false,
});
const emit = defineEmits<{
(e: 'goToGenerateWorkflow', {event: MouseEvent, workflowName: string, isLinkValid: boolean, link: string, payload: object}): void;
(e: 'clickOpenList'): void;
(
e: "goToGenerateWorkflow",
{
event: MouseEvent,
workflowName: string,
isLinkValid: boolean,
link: string,
payload: object,
},
): void;
(e: "clickOpenList"): void;
}>();
const makeLink = (workflowName: string): string => buildLinkCreate(workflowName, props.relatedEntityClass, props.relatedEntityId);
const makeLink = (workflowName: string): string =>
buildLinkCreate(
workflowName,
props.relatedEntityClass,
props.relatedEntityId,
);
const goToGenerateWorkflow = (event: MouseEvent, workflowName: string): void => {
console.log('goToGenerateWorkflow', event, workflowName);
let link = '';
const goToGenerateWorkflow = (
event: MouseEvent,
workflowName: string,
): void => {
console.log("goToGenerateWorkflow", event, workflowName);
let link = "";
let isLinkValid = false;
try {
link = makeLink(workflowName);
isLinkValid = true;
} catch (e) {
console.info("could not generate link to create workflow, maybe the relatedEntityId is not yet known", e);
console.info(
"could not generate link to create workflow, maybe the relatedEntityId is not yet known",
e,
);
}
if (!props.preventDefaultMoveToGenerate) {
window.location.assign(link);
}
emit('goToGenerateWorkflow', {event, workflowName, link, isLinkValid, payload: props.goToGenerateWorkflowPayload});
}
emit("goToGenerateWorkflow", {
event,
workflowName,
link,
isLinkValid,
payload: props.goToGenerateWorkflowPayload,
});
};
const goToDuplicateRelatedEntity = (event: MouseEvent, workflowName: string): void => {
}
const goToDuplicateRelatedEntity = (
event: MouseEvent,
workflowName: string,
): void => {};
</script>
<style scoped>
</style>
<style scoped></style>

View File

@ -4,7 +4,9 @@
<div>
<p class="wl-item social-issues">
<span class="chill-entity entity-social-issue">
<span class="badge bg-chill-l-gray text-dark">{{ work.socialAction.issue.text }}</span>
<span class="badge bg-chill-l-gray text-dark">{{
work.socialAction.issue.text
}}</span>
</span>
</p>
</div>
@ -15,17 +17,23 @@
</div>
<div id="startDate" class="action-row">
<label class="col-form-label">{{ $t('startDate') }}</label>
<input v-model="startDate" type="date" required="true" class="form-control" v-once/>
<label class="col-form-label">{{ $t("startDate") }}</label>
<input
v-model="startDate"
type="date"
required="true"
class="form-control"
v-once
/>
</div>
<div id="endDate" class="action-row">
<label class="col-form-label">{{ $t('endDate') }}</label>
<label class="col-form-label">{{ $t("endDate") }}</label>
<input v-model="endDate" type="date" class="form-control" />
</div>
<div id="privateComment" class="action-row">
<label class="col-form-label">{{ $t('private_comment') }}</label>
<label class="col-form-label">{{ $t("private_comment") }}</label>
<ckeditor
v-model="privateComment"
:editor="editor"
@ -34,28 +42,30 @@
</div>
<div id="comment" class="action-row">
<label class="col-form-label">{{ $t('comments') }}</label>
<ckeditor
v-model="note"
:editor="editor"
tag-name="textarea"
></ckeditor>
<label class="col-form-label">{{ $t("comments") }}</label>
<ckeditor v-model="note" :editor="editor" tag-name="textarea"></ckeditor>
</div>
<div id="objectives" class="action-row">
<div aria="hidden" class="title">
<div><h3>{{ $t('goals_title') }}</h3></div>
<div><h3>{{ $t('results_title') }}</h3></div>
<div>
<h3>{{ $t("goals_title") }}</h3>
</div>
<div>
<h3>{{ $t("results_title") }}</h3>
</div>
</div>
<!-- results which are not attached to an objective -->
<div v-if="hasResultsForAction">
<div class="results_without_objective">
{{ $t('results_without_objective') }}
{{ $t("results_without_objective") }}
</div>
<div>
<add-result :availableResults="resultsForAction" destination="action"></add-result>
<add-result
:availableResults="resultsForAction"
destination="action"
></add-result>
</div>
</div>
@ -71,51 +81,65 @@
<div class="accordion" id="expandedSuggestions">
<div v-if="availableForCheckGoal.length > 0" class="accordion-item">
<h2 class="accordion-header" id="heading_expanded_suggestions">
<button v-if="isExpanded"
<button
v-if="isExpanded"
class="accordion-button"
type="button"
data-bs-toggle="collapse"
aria-expanded="true"
@click="toggleSelect">
@click="toggleSelect"
>
Masquer
</button>
<button v-else
<button
v-else
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
aria-expanded="false"
@click="toggleSelect">
@click="toggleSelect"
>
Motifs, objectifs et dispositfs disponibles
</button>
</h2>
<div class="accordion-collapse" id="collapse_expanded_suggestions"
aria-labelledby="heading_expanded_suggestions" data-bs-parent="#expandedSuggestions">
<div
class="accordion-collapse"
id="collapse_expanded_suggestions"
aria-labelledby="heading_expanded_suggestions"
data-bs-parent="#expandedSuggestions"
>
<template v-if="isExpanded">
<ul class="list-suggest add-items">
<li v-for="g in availableForCheckGoal" @click="addGoal(g)" :key="g.id">
<li
v-for="g in availableForCheckGoal"
@click="addGoal(g)"
:key="g.id"
>
<span>{{ g.title.fr }}</span>
</li>
</ul>
</template>
</div>
<p v-if="goalsPicked.length === 0" class="chill-no-data-statement">
Aucun objectif associé
</p>
</div>
<div v-else>
<span class="chill-no-data-statement">{{ $t('no_goals_available') }}</span>
<span class="chill-no-data-statement">{{
$t("no_goals_available")
}}</span>
</div>
</div>
</div>
<div id="evaluations" class="action-row">
<div aria="hidden" class="title">
<div><h3>{{ $t('Evaluations') }} - {{ $t('Forms') }} - {{ $t('Post') }}</h3></div>
<div>
<h3>
{{ $t("Evaluations") }} - {{ $t("Forms") }} - {{ $t("Post") }}
</h3>
</div>
</div>
<!-- list evaluations -->
@ -123,37 +147,56 @@
v-for="e in pickedEvaluations"
v-bind:key="e.key"
v-bind:evaluation="e"
v-bind:docAnchorId="this.docAnchorId">
v-bind:docAnchorId="this.docAnchorId"
>
</add-evaluation>
<!-- box to add new evaluation -->
<div class="add_evaluation">
<div v-if="showAddEvaluation">
<p>{{ $t('available_evaluations_text') }}</p>
<p>{{ $t("available_evaluations_text") }}</p>
<ul class="list-suggest add-items">
<li v-for="e in evaluationsForAction" @click="addEvaluation(e)" :key="e.id">
<li
v-for="e in evaluationsForAction"
@click="addEvaluation(e)"
:key="e.id"
>
<span>{{ e.title.fr }}</span>
</li>
</ul>
</div>
<ul class="record_actions" v-if="evaluationsForAction.length > 0">
<li>
<button :title="$t('add_an_evaluation')" class="btn btn-create" @click="toggleAddEvaluation">{{ $t('add_an_evaluation') }}</button>
<button
:title="$t('add_an_evaluation')"
class="btn btn-create"
@click="toggleAddEvaluation"
>
{{ $t("add_an_evaluation") }}
</button>
</li>
</ul>
<div v-else>
<span class="chill-no-data-statement">{{ $t('no_evaluations_available') }}</span>
<span class="chill-no-data-statement">{{
$t("no_evaluations_available")
}}</span>
</div>
</div>
</div>
<div id="persons" class="action-row">
<h3 class="mb-3">{{ $t('persons_involved') }}</h3>
<h3 class="mb-3">{{ $t("persons_involved") }}</h3>
<ul class="list-unstyled">
<li v-for="p in personsReachables" :key="p.id">
<div class="form-check">
<input v-model="personsPicked" :value="p.id" type="checkbox" class="me-2 form-check-input" :id="'person_check'+p.id">
<input
v-model="personsPicked"
:value="p.id"
type="checkbox"
class="me-2 form-check-input"
:id="'person_check' + p.id"
/>
<label :for="'person_check' + p.id" class="form-check-label">
<person-text :person="p"></person-text>
</label>
@ -163,15 +206,20 @@
</div>
<div id="referrers" class="action-row">
<h3>{{ $t('referrers') }}</h3>
<h3>{{ $t("referrers") }}</h3>
<div v-if="!hasReferrers">
<p class="chill-no-data-statement">{{ $t('no_referrers') }}</p>
<p class="chill-no-data-statement">{{ $t("no_referrers") }}</p>
</div>
<div v-else>
<ul class="list-suggest remove-items inline">
<li v-for="u in referrers" :key="u.id" :title="$t('remove_referrer')" @click="removeReferrer(u)">
<li
v-for="u in referrers"
:key="u.id"
:title="$t('remove_referrer')"
@click="removeReferrer(u)"
>
<span>
{{ u.text }}
</span>
@ -187,18 +235,19 @@
:buttonTitle="$t('add_referrers')"
:modalTitle="$t('choose_referrers')"
:options="referrerPicker.options"
@addNewPersons="addReferrers">
@addNewPersons="addReferrers"
>
</add-persons>
</li>
</ul>
</div>
<div id="handlingThirdParty" class="action-row">
<h3>{{ $t('handling_thirdparty') }}</h3>
<h3>{{ $t("handling_thirdparty") }}</h3>
<div v-if="!hasHandlingThirdParty">
<p class="chill-no-data-statement">
{{ $t('no_handling_thirdparty') }}
{{ $t("no_handling_thirdparty") }}
</p>
<ul class="record_actions">
@ -209,7 +258,9 @@
v-bind:buttonTitle="$t('precise_handling_thirdparty')"
v-bind:modalTitle="$t('choose_a_thirdparty')"
v-bind:options="handlingThirdPartyPicker.options"
@addNewPersons="setHandlingThirdParty"> <!-- to cast child method -->
@addNewPersons="setHandlingThirdParty"
>
<!-- to cast child method -->
</add-persons>
</li>
</ul>
@ -224,22 +275,28 @@
addInfo: false,
hLevel: 3,
isMultiline: true,
isConfidential: false
}"></third-party-render-box>
isConfidential: false,
}"
></third-party-render-box>
<ul class="record_actions">
<li>
<button :title="$t('remove_handling_thirdparty')" class="btn btn-remove" @click="removeHandlingThirdParty"/>
<button
:title="$t('remove_handling_thirdparty')"
class="btn btn-remove"
@click="removeHandlingThirdParty"
/>
</li>
</ul>
</div>
</div>
<div id="thirdParties" class="action-row">
<h3>{{ $t('thirdparty_intervener') }}</h3>
<h3>{{ $t("thirdparty_intervener") }}</h3>
<div v-if="!hasThirdParties">
<p class="chill-no-data-statement">{{ $t('no_thirdparty_intervener') }}</p>
<p class="chill-no-data-statement">
{{ $t("no_thirdparty_intervener") }}
</p>
</div>
<div v-else>
@ -248,14 +305,38 @@
v-for="thirdparty in thirdParties"
:key="thirdparty.id"
:thirdparty="thirdparty"
:options="{ addLink : false, addId : false, addEntity: true, addInfo: false, hLevel: 3 }"
:options="{
addLink: false,
addId: false,
addEntity: true,
addInfo: false,
hLevel: 3,
}"
>
<template v-slot:record-actions>
<ul class="record_actions">
<li><on-the-fly :type="thirdparty.type" :id="thirdparty.id" action="show"></on-the-fly></li>
<li><on-the-fly :type="thirdparty.type" :id="thirdparty.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly" ref="onTheFly"></on-the-fly></li>
<li>
<button :title="$t('remove_thirdparty')" class="btn btn-sm btn-remove" @click="removeThirdParty(thirdparty)" />
<on-the-fly
:type="thirdparty.type"
:id="thirdparty.id"
action="show"
></on-the-fly>
</li>
<li>
<on-the-fly
:type="thirdparty.type"
:id="thirdparty.id"
action="edit"
@saveFormOnTheFly="saveFormOnTheFly"
ref="onTheFly"
></on-the-fly>
</li>
<li>
<button
:title="$t('remove_thirdparty')"
class="btn btn-sm btn-remove"
@click="removeThirdParty(thirdparty)"
/>
</li>
</ul>
</template>
@ -271,19 +352,24 @@
v-bind:buttonTitle="$t('add_thirdparties')"
v-bind:modalTitle="$t('choose_thirdparties')"
v-bind:options="thirdPartyPicker.options"
@addNewPersons="addThirdParties"> <!-- to cast child method -->
@addNewPersons="addThirdParties"
>
<!-- to cast child method -->
</add-persons>
</li>
</ul>
</div>
<div v-if="errors.length > 0" id="errors" class="alert alert-danger flashbag">
<p>{{ $t('fix_these_errors') }}</p>
<div
v-if="errors.length > 0"
id="errors"
class="alert alert-danger flashbag"
>
<p>{{ $t("fix_these_errors") }}</p>
<ul>
<li v-for="e in errors" :key="e.id">{{ e }}</li>
</ul>
</div>
</div>
<ul class="record_actions sticky-form-buttons">
<li>
@ -299,64 +385,87 @@
</li>
<li>
<button v-if="AmIRefferer"
<button
v-if="AmIRefferer"
class="btn btn-notify"
@click="goToGenerateNotification(false)"
></button>
<template v-else>
<button id="btnGroupNotifyButtons" type="button" class="btn btn-notify dropdown-toggle" :title="$t('notification_send')" data-bs-toggle="dropdown" aria-expanded="false">&nbsp;</button>
<button
id="btnGroupNotifyButtons"
type="button"
class="btn btn-notify dropdown-toggle"
:title="$t('notification_send')"
data-bs-toggle="dropdown"
aria-expanded="false"
>
&nbsp;
</button>
<ul class="dropdown-menu" aria-labelledby="btnGroupNotifyButtons">
<li><a class="dropdown-item" @click="goToGenerateNotification(true)">{{ $t('notification_notify_referrer') }}</a></li>
<li><a class="dropdown-item" @click="goToGenerateNotification(false)">{{ $t('notification_notify_any') }}</a></li>
<li>
<a class="dropdown-item" @click="goToGenerateNotification(true)">{{
$t("notification_notify_referrer")
}}</a>
</li>
<li>
<a class="dropdown-item" @click="goToGenerateNotification(false)">{{
$t("notification_notify_any")
}}</a>
</li>
</ul>
</template>
</li>
<li v-if="!isPosting">
<button class="btn btn-save" @click="submit">
{{ $t('action.save') }}
{{ $t("action.save") }}
</button>
</li>
<li v-if="isPosting">
<button class="btn btn-save" disabled>
{{ $t('action.save') }}
{{ $t("action.save") }}
</button>
</li>
</ul>
</template>
<script>
import {mapState, mapGetters,} from 'vuex';
import {dateToISO, ISOToDate, ISOToDatetime} from 'ChillMainAssets/chill/js/date';
import CKEditor from '@ckeditor/ckeditor5-vue';
import ClassicEditor from 'ChillMainAssets/module/ckeditor5/editor_config';
import AddResult from './components/AddResult.vue';
import AddEvaluation from './components/AddEvaluation.vue';
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue';
import PickTemplate from 'ChillDocGeneratorAssets/vuejs/_components/PickTemplate.vue';
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
import ListWorkflowModal from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue';
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api';
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
import { mapState, mapGetters } from "vuex";
import {
dateToISO,
ISOToDate,
ISOToDatetime,
} from "ChillMainAssets/chill/js/date";
import CKEditor from "@ckeditor/ckeditor5-vue";
import ClassicEditor from "ChillMainAssets/module/ckeditor5/editor_config";
import AddResult from "./components/AddResult.vue";
import AddEvaluation from "./components/AddEvaluation.vue";
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
import AddressRenderBox from "ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue";
import ThirdPartyRenderBox from "ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue";
import PickTemplate from "ChillDocGeneratorAssets/vuejs/_components/PickTemplate.vue";
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
import ListWorkflowModal from "ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue";
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
import { buildLinkCreate } from "ChillMainAssets/lib/entity-workflow/api";
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
const i18n = {
messages: {
fr: {
action: {
save: "Enregistrer"
save: "Enregistrer",
},
conflict_on_save: "Désolé, cette action d'accompagnement a été modifiée dans une autre fenêtre ou par un autre utilisateur. Rechargez la page pour voir ses changements.",
conflict_on_save:
"Désolé, cette action d'accompagnement a été modifiée dans une autre fenêtre ou par un autre utilisateur. Rechargez la page pour voir ses changements.",
action_title: "Action d'accompagnement",
comments: "Commentaire",
startDate: "Date de début",
endDate: "Date de fin",
goals_title: "Motifs - objectifs - dispositifs",
available_goals_text: "Motifs, objectifs et dispositifs disponibles pour ajout :",
available_goals_text:
"Motifs, objectifs et dispositifs disponibles pour ajout :",
results_title: "Orientations - résultats",
results_without_objective: "Résultats - orientations sans objectifs",
add_objectif: "Ajouter un motif - objectif - dispositif",
@ -389,12 +498,12 @@ const i18n = {
notification_notify_referrer: "Notifier le référent",
notification_notify_any: "Notifier d'autres utilisateurs",
notification_send: "Envoyer une notification",
}
}
},
},
};
export default {
name: 'App',
name: "App",
components: {
ckeditor: CKEditor.component,
AddResult,
@ -416,163 +525,174 @@ export default {
showAddObjective: false,
showAddEvaluation: false,
handlingThirdPartyPicker: {
key: 'handling-third-party',
key: "handling-third-party",
options: {
type: ['thirdparty'],
type: ["thirdparty"],
priority: null,
uniq: true,
button: {
display: false
}
display: false,
},
},
},
thirdPartyPicker: {
key: 'third-party',
key: "third-party",
options: {
type: ['thirdparty'],
type: ["thirdparty"],
priority: null,
uniq: false,
button: {
display: false
}
display: false,
},
},
},
referrerPicker: {
key: 'referrer',
key: "referrer",
options: {
type: ['user'],
type: ["user"],
priority: null,
uniq: false,
button: {
display: false
}
display: false,
},
},
},
};
},
beforeMount() {
const urlParams = new URLSearchParams(window.location.search);
this.docAnchorId = urlParams.get('doc_id');
this.docAnchorId = urlParams.get("doc_id");
},
mounted() {
this.scrollToElement(this.docAnchorId);
},
computed: {
...mapState([
'work',
'resultsForAction',
'evaluationsForAction',
'goalsPicked',
'personsReachables',
'handlingThirdParty',
'thirdParties',
'referrers',
'isPosting',
'errors',
'templatesAvailablesForAction',
'me',
'version'
"work",
"resultsForAction",
"evaluationsForAction",
"goalsPicked",
"personsReachables",
"handlingThirdParty",
"thirdParties",
"referrers",
"isPosting",
"errors",
"templatesAvailablesForAction",
"me",
"version",
]),
...mapGetters([
'hasResultsForAction',
'hasHandlingThirdParty',
'hasThirdParties',
'hasReferrers'
"hasResultsForAction",
"hasHandlingThirdParty",
"hasThirdParties",
"hasReferrers",
]),
startDate: {
get() {
return this.$store.state.startDate;
},
set(v) {
this.$store.commit('setStartDate', v);
}
this.$store.commit("setStartDate", v);
},
},
endDate: {
get() {
return this.$store.state.endDate;
},
set(v) {
this.$store.commit('setEndDate', v);
}
this.$store.commit("setEndDate", v);
},
},
note: {
get() {
return this.$store.state.note;
},
set(v) {
this.$store.commit('setNote', v);
}
this.$store.commit("setNote", v);
},
},
privateComment: {
get() {
return this.$store.state.privateComment;
},
set(v) {
this.$store.commit('setPrivateComment', v);
}
this.$store.commit("setPrivateComment", v);
},
},
availableForCheckGoal() {
let pickedIds = this.$store.state.goalsPicked.map(g => g.goal.id);
let pickedIds = this.$store.state.goalsPicked.map((g) => g.goal.id);
return this.$store.state.goalsForAction.filter(g => !pickedIds.includes(g.id));
return this.$store.state.goalsForAction.filter(
(g) => !pickedIds.includes(g.id),
);
},
pickedEvaluations() {
return this.$store.state.evaluationsPicked;
},
personsPicked: {
get() {
let s = this.$store.state.personsPicked.map(p => p.id);
let s = this.$store.state.personsPicked.map((p) => p.id);
return s;
},
set(v) {
this.$store.commit('setPersonsPickedIds', v);
}
this.$store.commit("setPersonsPickedIds", v);
},
},
AmIRefferer() {
return (!(this.work.accompanyingPeriod.user && this.me
&& (this.work.accompanyingPeriod.user.id !== this.me.id)));
}
return !(
this.work.accompanyingPeriod.user &&
this.me &&
this.work.accompanyingPeriod.user.id !== this.me.id
);
},
},
methods: {
toggleSelect() {
this.isExpanded = !this.isExpanded;
},
addGoal(g) {
this.$store.commit('addGoal', g);
this.$store.commit("addGoal", g);
},
removeGoal(g) {
this.$store.commit('removeGoal', g);
this.$store.commit("removeGoal", g);
},
addEvaluation(e) {
this.$store.dispatch('addEvaluation', e);
this.$store.dispatch("addEvaluation", e);
},
toggleAddEvaluation() {
this.showAddEvaluation = !this.showAddEvaluation;
},
setHandlingThirdParty({ selected, modal }) {
this.$store.commit('setHandlingThirdParty', selected.shift().result);
this.$store.commit("setHandlingThirdParty", selected.shift().result);
this.$refs.handlingThirdPartyPicker.resetSearch();
modal.showModal = false;
},
removeHandlingThirdParty() {
this.$store.commit('setHandlingThirdParty', null);
this.$store.commit("setHandlingThirdParty", null);
},
addThirdParties({ selected, modal }) {
this.$store.commit('addThirdParties', selected.map(r => r.result));
this.$store.commit(
"addThirdParties",
selected.map((r) => r.result),
);
this.$refs.thirdPartyPicker.resetSearch();
modal.showModal = false;
},
removeThirdParty(t) {
this.$store.commit('removeThirdParty', t);
this.$store.commit("removeThirdParty", t);
},
addReferrers({ selected, modal }) {
this.$store.commit('addReferrers', selected.map(r => r.result));
this.$store.commit(
"addReferrers",
selected.map((r) => r.result),
);
this.$refs.referrerPicker.resetSearch();
modal.showModal = false;
},
removeReferrer(u) {
this.$store.commit('removeReferrer', u);
this.$store.commit("removeReferrer", u);
},
goToGenerateWorkflow({ link }) {
// console.log('save before leave to generate workflow')
@ -580,30 +700,43 @@ export default {
window.location.assign(link);
};
return this.$store.dispatch('submit', callback)
.catch(e => { console.log(e); throw e; });
return this.$store.dispatch("submit", callback).catch((e) => {
console.log(e);
throw e;
});
},
goToGenerateNotification(tos) {
console.log('save before leave to notification');
console.log("save before leave to notification");
const callback = (data) => {
if (tos === true) {
window.location.assign(`/fr/notification/create?entityClass=Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork&entityId=${this.work.id}&tos[0]=${this.work.accompanyingPeriod.user.id}&returnPath=/fr/person/accompanying-period/${this.work.accompanyingPeriod.id}/work`);
window.location.assign(
`/fr/notification/create?entityClass=Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork&entityId=${this.work.id}&tos[0]=${this.work.accompanyingPeriod.user.id}&returnPath=/fr/person/accompanying-period/${this.work.accompanyingPeriod.id}/work`,
);
} else {
window.location.assign(`/fr/notification/create?entityClass=Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork&entityId=${this.work.id}&returnPath=/fr/person/accompanying-period/${this.work.accompanyingPeriod.id}/work`);
}
window.location.assign(
`/fr/notification/create?entityClass=Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork&entityId=${this.work.id}&returnPath=/fr/person/accompanying-period/${this.work.accompanyingPeriod.id}/work`,
);
}
};
return this.$store.dispatch('submit', callback)
.catch(e => {console.log(e); throw e});
return this.$store.dispatch("submit", callback).catch((e) => {
console.log(e);
throw e;
});
},
submit() {
this.$store.dispatch('submit').catch((error) => {
if (error.name === 'ValidationException' || error.name === 'AccessException') {
error.violations.forEach((violation) => this.$toast.open({message: violation}));
} else if (error.name === 'ConflictHttpException') {
this.$toast.open({message: this.$t('conflict_on_save')});
this.$store.dispatch("submit").catch((error) => {
if (
error.name === "ValidationException" ||
error.name === "AccessException"
) {
error.violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else if (error.name === "ConflictHttpException") {
this.$toast.open({ message: this.$t("conflict_on_save") });
} else {
this.$toast.open({message: 'An error occurred'});
this.$toast.open({ message: "An error occurred" });
throw error;
}
});
@ -617,37 +750,40 @@ export default {
body.telephone = payload.data.phonenumber;
body.address = { id: payload.data.address.address_id };
makeFetch('PATCH', `/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`, body)
.then(response => {
this.$store.dispatch('updateThirdParty', response)
makeFetch(
"PATCH",
`/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("updateThirdParty", response);
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === 'ValidationException') {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else if (error.name === 'ConflictHttpException') {
this.$toast.open({message: this.$t('conflict_on_save')});
} else if (error.name === "ConflictHttpException") {
this.$toast.open({ message: this.$t("conflict_on_save") });
} else {
this.$toast.open({message: 'An error occurred'});
this.$toast.open({ message: "An error occurred" });
}
})
});
},
scrollToElement(docAnchorId) {
const documentEl = document.getElementById(`document_${docAnchorId}`);
if (documentEl) {
documentEl.scrollIntoView({behavior: 'smooth'});
}
}
documentEl.scrollIntoView({ behavior: "smooth" });
}
},
},
};
</script>
<style lang="scss">
@import '~ChillMainAssets/module/bootstrap/shared';
@import '~ChillMainAssets/chill/scss/mixins';
@import "~ChillMainAssets/module/bootstrap/shared";
@import "~ChillMainAssets/chill/scss/mixins";
div#workEditor {
display: grid;
@ -667,29 +803,41 @@ div#workEditor {
"errors errors";
#title {
grid-area: title; }
grid-area: title;
}
#startDate {
grid-area: startDate; }
grid-area: startDate;
}
#endDate {
grid-area: endDate; }
grid-area: endDate;
}
#comment {
grid-area: comment; }
grid-area: comment;
}
#privateComment {
grid-area: privateComment; }
grid-area: privateComment;
}
#objectives {
grid-area: objectives; }
grid-area: objectives;
}
#evaluations {
grid-area: evaluations; }
grid-area: evaluations;
}
#persons {
grid-area: persons; }
grid-area: persons;
}
#handlingThirdParty {
grid-area: handling; }
grid-area: handling;
}
#thirdParties {
grid-area: tparties; }
grid-area: tparties;
}
#referrers {
grid-area: referrers; }
grid-area: referrers;
}
#errors {
grid-area: errors; }
grid-area: errors;
}
div.action-row {
@include border-collapse;
@ -718,10 +866,12 @@ div#workEditor {
padding: 1em;
&:nth-child(1) {
grid-area: obj; }
grid-area: obj;
}
&:nth-child(2) {
grid-area: res; }
grid-area: res;
}
}
& > div.results_without_objective {
@ -771,7 +921,9 @@ div#workEditor {
padding: 0.25rem;
color: $white;
&.fa-times { color: $red; }
&.fa-times {
color: $red;
}
}
}
@ -791,15 +943,15 @@ div#workEditor {
}
}
.accordion-item:first-of-type, .accordion-item:last-of-type {
.accordion-item:first-of-type,
.accordion-item:last-of-type {
border-radius: 0rem;
border: 0px;
.accordion-button {
padding: .25rem;
padding: 0.25rem;
border: 1px solid rgba(17, 17, 17, 0.125);
margin-top: 20px;
margin-bottom: 20px;
}
}
</style>

View File

@ -7,15 +7,21 @@
<div class="item-url mt-3 mb-4" v-if="evaluation.evaluation.url">
<i class="fa fa-link fa-lg"></i>
<a :href="evaluation.evaluation.url" target="_blank">{{ evaluation.evaluation.url }}</a>
<a :href="evaluation.evaluation.url" target="_blank">{{
evaluation.evaluation.url
}}</a>
</div>
<div>
<form-evaluation ref="FormEvaluation" :key="evaluation.key" :evaluation="evaluation" :docAnchorId="docAnchorId"></form-evaluation>
<form-evaluation
ref="FormEvaluation"
:key="evaluation.key"
:evaluation="evaluation"
:docAnchorId="docAnchorId"
></form-evaluation>
<ul class="record_actions">
<li v-if="evaluation.workflows_availables.length > 0">
<list-workflow-modal
:workflows="evaluation.workflows"
:allowCreate="true"
@ -24,25 +30,33 @@
:workflowsAvailables="evaluation.workflows_availables"
@go-to-generate-workflow="goToGenerateWorkflow"
></list-workflow-modal>
</li>
<li v-if="canDelete">
<a class="btn btn-delete" @click="modal.showModal = true" :title="$t('action.delete')">{{ $t('delete_evaluation')}}</a>
<a
class="btn btn-delete"
@click="modal.showModal = true"
:title="$t('action.delete')"
>{{ $t("delete_evaluation") }}</a
>
</li>
</ul>
</div>
<teleport to="body">
<modal v-if="modal.showModal" :modalDialogClass="modal.modalDialogClass" @close="modal.showModal = false">
<modal
v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
@close="modal.showModal = false"
>
<template v-slot:header>
<h2 class="modal-title">{{ $t('delete.sure') }}</h2>
<h2 class="modal-title">{{ $t("delete.sure") }}</h2>
</template>
<template v-slot:body>
<p>{{ $t('delete.sure_description') }}</p>
<p>{{ $t("delete.sure_description") }}</p>
</template>
<template v-slot:footer>
<button class="btn btn-danger" @click="removeEvaluation(evaluation)">
{{ $t('delete.ok') }}
{{ $t("delete.ok") }}
</button>
</template>
</modal>
@ -51,10 +65,10 @@
</template>
<script>
import FormEvaluation from './FormEvaluation.vue';
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import ListWorkflowModal from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue';
import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api';
import FormEvaluation from "./FormEvaluation.vue";
import Modal from "ChillMainAssets/vuejs/_components/Modal";
import ListWorkflowModal from "ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue";
import { buildLinkCreate } from "ChillMainAssets/lib/entity-workflow/api";
const i18n = {
messages: {
@ -70,12 +84,13 @@ const i18n = {
documents: "Documents",
delete: {
sure: "Êtes-vous sûr?",
sure_description: "Cette évaluation sera supprimée de cette action d'accompagnement",
ok: "Supprimer"
sure_description:
"Cette évaluation sera supprimée de cette action d'accompagnement",
ok: "Supprimer",
},
delete_evaluation: "Supprimer l'évaluation",
}
}
},
},
};
export default {
@ -85,14 +100,14 @@ export default {
Modal,
ListWorkflowModal,
},
props: ['evaluation', 'docAnchorId'],
props: ["evaluation", "docAnchorId"],
i18n,
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md"
}
modalDialogClass: "modal-dialog-centered modal-md",
},
};
},
computed: {
@ -115,27 +130,36 @@ export default {
},
methods: {
removeEvaluation(e) {
this.$store.commit('removeEvaluation', e);
this.$store.commit("removeEvaluation", e);
return;
},
toggleEditEvaluation(e) {
this.$store.commit('toggleEvaluationEdit', { key: this.evaluation.key });
this.$store.commit("toggleEvaluationEdit", { key: this.evaluation.key });
},
submitForm() {
this.toggleEditEvaluation();
},
goToGenerateWorkflow({ event, link, workflowName }) {
const callback = (data) => {
let evaluationId = data.accompanyingPeriodWorkEvaluations.find(e => e.key === this.evaluation.key).id;
window.location.assign(buildLinkCreate(workflowName,
'Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation', evaluationId));
let evaluationId = data.accompanyingPeriodWorkEvaluations.find(
(e) => e.key === this.evaluation.key,
).id;
window.location.assign(
buildLinkCreate(
workflowName,
"Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation",
evaluationId,
),
);
};
return this.$store.dispatch('submit', callback)
.catch(e => { console.log(e); throw e; });
}
}
}
return this.$store.dispatch("submit", callback).catch((e) => {
console.log(e);
throw e;
});
},
},
};
</script>
<style lang="scss" scoped>

View File

@ -19,43 +19,63 @@
<div class="row mb-3">
<label class="col-4 col-sm-2 col-md-4 col-lg-2 col-form-label">
{{ $t('evaluation_startdate') }}
{{ $t("evaluation_startdate") }}
</label>
<div class="col-8 col-sm-4 col-md-8 col-lg-4">
<input class="form-control form-control-sm" type="date" v-model="startDate"/>
<input
class="form-control form-control-sm"
type="date"
v-model="startDate"
/>
</div>
<label class="col-4 col-sm-2 col-md-4 col-lg-2 col-form-label">
{{ $t('evaluation_enddate') }}
{{ $t("evaluation_enddate") }}
</label>
<div class="col-8 col-sm-4 col-md-8 col-lg-4">
<input class="form-control form-control-sm" type="date" v-model="endDate"/>
<input
class="form-control form-control-sm"
type="date"
v-model="endDate"
/>
</div>
</div>
<div class="row mb-3">
<label class="col-4 col-sm-2 col-md-4 col-lg-2 col-form-label">
{{ $t('evaluation_maxdate') }}
{{ $t("evaluation_maxdate") }}
</label>
<div class="col-8 col-sm-4 col-md-8 col-lg-4">
<input class="form-control form-control-sm" type="date" v-model="maxDate"/>
<input
class="form-control form-control-sm"
type="date"
v-model="maxDate"
/>
</div>
<label class="col-4 col-sm-2 col-md-4 col-lg-2 col-form-label">
{{ $t('evaluation_warning_interval') }}
{{ $t("evaluation_warning_interval") }}
</label>
<div class="col-8 col-sm-4 col-md-8 col-lg-4">
<input class="form-control form-control-sm" type="number" v-model.number="warningInterval"/>
<input
class="form-control form-control-sm"
type="number"
v-model.number="warningInterval"
/>
</div>
</div>
<div class="row mb-3">
<label class="col-4 col-sm-2 col-md-4 col-lg-2 col-form-label">
{{ $t('evaluation_time_spent') }}
{{ $t("evaluation_time_spent") }}
</label>
<div class="col-8 col-sm-4 col-md-8 col-lg-4">
<select class="form-control form-control-sm" type="time" v-model="timeSpent">
<option disabled value="">{{ $t('select_time_spent') }}</option>
<select
class="form-control form-control-sm"
type="time"
v-model="timeSpent"
>
<option disabled value="">{{ $t("select_time_spent") }}</option>
<option v-for="time in timeSpentChoices" :value="time.value">
{{ time.text }}
</option>
@ -64,7 +84,9 @@
</div>
<div class="row mb-3">
<label class="col-sm-4 col-form-label visually-hidden">{{ $t('evaluation_public_comment') }}</label>
<label class="col-sm-4 col-form-label visually-hidden">{{
$t("evaluation_public_comment")
}}</label>
<div class="col-sm-12">
<ckeditor
:editor="editor"
@ -76,13 +98,22 @@
</div>
<div v-if="evaluation.documents.length > 0" class="row mb-3">
<h5>{{ $t('Documents') }} :</h5>
<h5>{{ $t("Documents") }} :</h5>
<div class="flex-table">
<div class="item-bloc" v-for="(d, i) in evaluation.documents" :key="d.id" :class="[parseInt(this.docAnchorId) === d.id ? 'bg-blink' : 'nothing']">
<div
class="item-bloc"
v-for="(d, i) in evaluation.documents"
:key="d.id"
:class="[
parseInt(this.docAnchorId) === d.id ? 'bg-blink' : 'nothing',
]"
>
<div :id="`document_${d.id}`" class="item-row">
<div class="input-group input-group-lg mb-3 row">
<label class="col-sm-3 col-form-label">Titre du document:</label>
<label class="col-sm-3 col-form-label"
>Titre du document:</label
>
<div class="col-sm-9">
<input
class="form-control document-title"
@ -90,20 +121,28 @@
:value="d.title"
:id="d.id"
:data-key="i"
@input="onInputDocumentTitle"/>
@input="onInputDocumentTitle"
/>
</div>
</div>
</div>
<div class="item-row">
<div class="item-col item-meta">
<p v-if="d.createdBy" class="createdBy">Créé par {{ d.createdBy.text }}<br/>
Le {{ $d(ISOToDatetime(d.createdAt.datetime), 'long') }}</p>
<p v-if="d.createdBy" class="createdBy">
Créé par {{ d.createdBy.text }}<br />
Le {{ $d(ISOToDatetime(d.createdAt.datetime), "long") }}
</p>
</div>
</div>
<div class="item-row">
<div class="item-col">
<ul class="record_actions">
<li v-if="d.workflows_availables.length > 0 || d.workflows.length > 0">
<li
v-if="
d.workflows_availables.length > 0 ||
d.workflows.length > 0
"
>
<list-workflow-modal
:workflows="d.workflows"
:allowCreate="true"
@ -112,20 +151,46 @@
:workflowsAvailables="d.workflows_availables"
:preventDefaultMoveToGenerate="true"
:goToGenerateWorkflowPayload="{ doc: d }"
@go-to-generate-workflow="goToGenerateWorkflowEvaluationDocument"
@go-to-generate-workflow="
goToGenerateWorkflowEvaluationDocument
"
></list-workflow-modal>
</li>
<li>
<button
v-if="AmIRefferer"
class="btn btn-notify"
@click="goToGenerateDocumentNotification(d, false)">
</button>
@click="goToGenerateDocumentNotification(d, false)"
></button>
<template v-else>
<button id="btnGroupNotifyButtons" type="button" class="btn btn-notify dropdown-toggle" :title="$t('notification_send')" data-bs-toggle="dropdown" aria-expanded="false">&nbsp;</button>
<ul class="dropdown-menu" aria-labelledby="btnGroupNotifyButtons">
<li><a class="dropdown-item" @click="goToGenerateDocumentNotification(d, true)">{{ $t('notification_notify_referrer') }}</a></li>
<li><a class="dropdown-item" @click="goToGenerateDocumentNotification(d, false)">{{ $t('notification_notify_any') }}</a></li>
<button
id="btnGroupNotifyButtons"
type="button"
class="btn btn-notify dropdown-toggle"
:title="$t('notification_send')"
data-bs-toggle="dropdown"
aria-expanded="false"
>
&nbsp;
</button>
<ul
class="dropdown-menu"
aria-labelledby="btnGroupNotifyButtons"
>
<li>
<a
class="dropdown-item"
@click="goToGenerateDocumentNotification(d, true)"
>{{ $t("notification_notify_referrer") }}</a
>
</li>
<li>
<a
class="dropdown-item"
@click="goToGenerateDocumentNotification(d, false)"
>{{ $t("notification_notify_any") }}</a
>
</li>
</ul>
</template>
</li>
@ -136,19 +201,36 @@
:can-edit="true"
:execute-before-leave="submitBeforeLeaveToEditor"
:davLink="d.storedObject._links?.dav_link.href"
:davLinkExpiration="d.storedObject._links?.dav_link.expiration"
:davLinkExpiration="
d.storedObject._links?.dav_link.expiration
"
@on-stored-object-status-change="onStatusDocumentChanged"
></document-action-buttons-group>
</li>
<li v-if="d.storedObject._permissions.canEdit">
<drop-file-modal :existing-doc="d.storedObject" :allow-remove="false" @add-document="(arg) => replaceDocument(d, arg.stored_object, arg.stored_object_version)"></drop-file-modal>
<drop-file-modal
:existing-doc="d.storedObject"
:allow-remove="false"
@add-document="
(arg) =>
replaceDocument(
d,
arg.stored_object,
arg.stored_object_version,
)
"
></drop-file-modal>
</li>
<li v-if="d.workflows.length === 0">
<a class="btn btn-delete" @click="removeDocument(d)">
</a>
<a class="btn btn-delete" @click="removeDocument(d)"> </a>
</li>
<li v-if="Number.isInteger(d.id)">
<button type="button" @click="duplicateDocument(d)" class="btn btn-duplicate" title="Dupliquer"></button>
<button
type="button"
@click="duplicateDocument(d)"
class="btn btn-duplicate"
title="Dupliquer"
></button>
</li>
</ul>
</div>
@ -158,7 +240,7 @@
</div>
<div class="row mb-3">
<h6>{{ $t('document_add') }} :</h6>
<h6>{{ $t("document_add") }} :</h6>
<pick-template
entityClass="Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation"
:id="evaluation.id"
@ -167,33 +249,41 @@
@go-to-generate-document="submitBeforeGenerate"
>
<template v-slot:title>
<label class="col-form-label">{{ $t('evaluation_generate_a_document') }}</label>
<label class="col-form-label">{{
$t("evaluation_generate_a_document")
}}</label>
</template>
</pick-template>
<div>
<label class="col-form-label">{{ $t('document_upload') }}</label>
<label class="col-form-label">{{ $t("document_upload") }}</label>
<ul class="record_actions document-upload">
<li>
<drop-file-modal :allow-remove="false" @add-document="addDocument"></drop-file-modal>
<drop-file-modal
:allow-remove="false"
@add-document="addDocument"
></drop-file-modal>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
import {dateToISO, ISOToDate, ISOToDatetime} from 'ChillMainAssets/chill/js/date';
import CKEditor from '@ckeditor/ckeditor5-vue';
import ClassicEditor from 'ChillMainAssets/module/ckeditor5/editor_config';
import { mapGetters, mapState } from 'vuex';
import PickTemplate from 'ChillDocGeneratorAssets/vuejs/_components/PickTemplate.vue';
import {buildLink} from 'ChillDocGeneratorAssets/lib/document-generator';
import ListWorkflowModal from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue';
import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api';
import {buildLinkCreate as buildLinkCreateNotification} from 'ChillMainAssets/lib/entity-notification/api';
import {
dateToISO,
ISOToDate,
ISOToDatetime,
} from "ChillMainAssets/chill/js/date";
import CKEditor from "@ckeditor/ckeditor5-vue";
import ClassicEditor from "ChillMainAssets/module/ckeditor5/editor_config";
import { mapGetters, mapState } from "vuex";
import PickTemplate from "ChillDocGeneratorAssets/vuejs/_components/PickTemplate.vue";
import { buildLink } from "ChillDocGeneratorAssets/lib/document-generator";
import ListWorkflowModal from "ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue";
import { buildLinkCreate } from "ChillMainAssets/lib/entity-workflow/api";
import { buildLinkCreate as buildLinkCreateNotification } from "ChillMainAssets/lib/entity-notification/api";
import DocumentActionButtonsGroup from "ChillDocStoreAssets/vuejs/DocumentActionButtonsGroup.vue";
import DropFileModal from "ChillDocStoreAssets/vuejs/DropFileWidget/DropFileModal.vue";
@ -226,13 +316,13 @@ const i18n = {
notification_notify_referrer: "Notifier le référent",
notification_notify_any: "Notifier d'autres utilisateurs",
notification_send: "Envoyer une notification",
}
}
},
},
};
export default {
name: "FormEvaluation",
props: ['evaluation', 'docAnchorId'],
props: ["evaluation", "docAnchorId"],
components: {
DropFileModal,
ckeditor: CKEditor.component,
@ -251,132 +341,212 @@ export default {
required: false,
},
timeSpentChoices: [
{ text: '1 minute', value: 60 }, { text: '2 minutes', value: 120 },
{ text: '3 minutes', value: 180 }, { text: '4 minutes', value: 240 },
{ text: '5 minutes', value: 300 }, { text: '10 minutes', value: 600 },
{ text: '15 minutes', value: 900 },{ text: '20 minutes', value: 1200 },
{ text: '25 minutes', value: 1500 }, { text: '30 minutes', value: 1800 },
{ text: '45 minutes', value: 2700 },{ text: '1 hour', value: 3600 },
{ text: '1 hour 15 minutes', value: 4500 }, { text: '1 hour 30 minutes', value: 5400 },
{ text: '1 hour 45 minutes', value: 6300 }, { text: '2 hours', value: 7200 },
{ text: '2 hours 30 minutes', value: 9000 }, { text: '3 hours', value: 10800 },
{ text: '3 hours 30 minutes', value: 12600 },{ text: '4 hours', value: 14400 },
{ text: '4 hours 30 minutes', value: 16200 },{ text: '5 hours', value: 18000 },
{ text: '5 hours 30 minutes', value: 19800 },{ text: '6 hours', value: 21600 },
{ text: '6 hours 30 minutes', value: 23400 },{ text: '7 hours', value: 25200 },
{ text: '7 hours 30 minutes', value: 27000 },{ text: '8 hours', value: 28800 },
]
}
{ text: "1 minute", value: 60 },
{ text: "2 minutes", value: 120 },
{ text: "3 minutes", value: 180 },
{ text: "4 minutes", value: 240 },
{ text: "5 minutes", value: 300 },
{ text: "10 minutes", value: 600 },
{ text: "15 minutes", value: 900 },
{ text: "20 minutes", value: 1200 },
{ text: "25 minutes", value: 1500 },
{ text: "30 minutes", value: 1800 },
{ text: "45 minutes", value: 2700 },
{ text: "1 hour", value: 3600 },
{ text: "1 hour 15 minutes", value: 4500 },
{ text: "1 hour 30 minutes", value: 5400 },
{ text: "1 hour 45 minutes", value: 6300 },
{ text: "2 hours", value: 7200 },
{ text: "2 hours 30 minutes", value: 9000 },
{ text: "3 hours", value: 10800 },
{ text: "3 hours 30 minutes", value: 12600 },
{ text: "4 hours", value: 14400 },
{ text: "4 hours 30 minutes", value: 16200 },
{ text: "5 hours", value: 18000 },
{ text: "5 hours 30 minutes", value: 19800 },
{ text: "6 hours", value: 21600 },
{ text: "6 hours 30 minutes", value: 23400 },
{ text: "7 hours", value: 25200 },
{ text: "7 hours 30 minutes", value: 27000 },
{ text: "8 hours", value: 28800 },
],
};
},
computed: {
...mapState([
'isPosting',
'work',
'me',
]),
...mapState(["isPosting", "work", "me"]),
AmIRefferer() {
return (!(this.$store.state.work.accompanyingPeriod.user && this.$store.state.me
&& (this.$store.state.work.accompanyingPeriod.user.id !== this.$store.state.me.id)));
return !(
this.$store.state.work.accompanyingPeriod.user &&
this.$store.state.me &&
this.$store.state.work.accompanyingPeriod.user.id !==
this.$store.state.me.id
);
},
getTemplatesAvailables() {
return this.$store.getters.getTemplatesAvailablesForEvaluation(this.evaluation.evaluation);
return this.$store.getters.getTemplatesAvailablesForEvaluation(
this.evaluation.evaluation,
);
},
canGenerate() {
return !this.$store.state.isPosting && this.template !== null;
},
startDate: {
get() {
console.log('evaluation', this.evaluation);
console.log("evaluation", this.evaluation);
return this.evaluation.startDate;
},
set(v) {
this.$store.commit('setEvaluationStartDate', { key: this.evaluation.key, date: v });
}
this.$store.commit("setEvaluationStartDate", {
key: this.evaluation.key,
date: v,
});
},
},
endDate: {
get() {
return this.evaluation.endDate;
},
set(v) {
this.$store.commit('setEvaluationEndDate', { key: this.evaluation.key, date: v });
}
this.$store.commit("setEvaluationEndDate", {
key: this.evaluation.key,
date: v,
});
},
},
maxDate: {
get() {
return this.evaluation.maxDate;
},
set(v) {
this.$store.commit('setEvaluationMaxDate', { key: this.evaluation.key, date: v });
}
this.$store.commit("setEvaluationMaxDate", {
key: this.evaluation.key,
date: v,
});
},
},
warningInterval: {
get() { return this.evaluation.warningInterval; },
set(v) { this.$store.commit('setEvaluationWarningInterval', { key: this.evaluation.key, days: v }); }
get() {
return this.evaluation.warningInterval;
},
set(v) {
this.$store.commit("setEvaluationWarningInterval", {
key: this.evaluation.key,
days: v,
});
},
},
timeSpent: {
get() { return this.evaluation.timeSpent },
set(v) { this.$store.commit('setEvaluationTimeSpent', { key: this.evaluation.key, time: v}) }
get() {
return this.evaluation.timeSpent;
},
set(v) {
this.$store.commit("setEvaluationTimeSpent", {
key: this.evaluation.key,
time: v,
});
},
},
comment: {
get() { return this.evaluation.comment; },
set(v) { this.$store.commit('setEvaluationComment', { key: this.evaluation.key, comment: v }); }
get() {
return this.evaluation.comment;
},
set(v) {
this.$store.commit("setEvaluationComment", {
key: this.evaluation.key,
comment: v,
});
},
},
},
methods: {
ISOToDatetime,
listAllStatus() {
console.log('load all status');
console.log("load all status");
let url = `/api/`;
fetch(url)
.then(response => {
fetch(url).then((response) => {
if (response.ok) {
return response.json();
}
throw { m: 'yeeah', s: response.status, b: response.body };
})
;
throw { m: "yeeah", s: response.status, b: response.body };
});
},
buildEditLink(document) {
return `/chill/wopi/edit/${document.storedObject.uuid}?returnPath=` + encodeURIComponent(
window.location.pathname + window.location.search + window.location.hash);
return (
`/chill/wopi/edit/${document.storedObject.uuid}?returnPath=` +
encodeURIComponent(
window.location.pathname +
window.location.search +
window.location.hash,
)
);
},
submitBeforeLeaveToEditor() {
console.log('submit beore edit 2');
console.log("submit beore edit 2");
// empty callback
const callback = () => null;
return this.$store.dispatch('submit', callback).catch(e => { console.log(e); throw e; });
return this.$store.dispatch("submit", callback).catch((e) => {
console.log(e);
throw e;
});
},
submitBeforeEdit(storedObject) {
const callback = (data) => {
let evaluation = data.accompanyingPeriodWorkEvaluations.find(e => e.key === this.evaluation.key);
let document = evaluation.documents.find(d => d.storedObject.id === storedObject.id);
let evaluation = data.accompanyingPeriodWorkEvaluations.find(
(e) => e.key === this.evaluation.key,
);
let document = evaluation.documents.find(
(d) => d.storedObject.id === storedObject.id,
);
//console.log('=> document', document);
window.location.assign(this.buildEditLink(document));
};
return this.$store.dispatch('submit', callback).catch(e => { console.log(e); throw e; });
return this.$store.dispatch("submit", callback).catch((e) => {
console.log(e);
throw e;
});
},
submitBeforeGenerate({ template }) {
const callback = (data) => {
let evaluationId = data.accompanyingPeriodWorkEvaluations.find(e => e.key === this.evaluation.key).id;
let evaluationId = data.accompanyingPeriodWorkEvaluations.find(
(e) => e.key === this.evaluation.key,
).id;
window.location.assign(buildLink(template, evaluationId, 'Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation'));
window.location.assign(
buildLink(
template,
evaluationId,
"Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation",
),
);
};
return this.$store.dispatch('submit', callback).catch(e => { console.log(e); throw e; });
return this.$store.dispatch("submit", callback).catch((e) => {
console.log(e);
throw e;
});
},
onInputDocumentTitle(event) {
const id = Number(event.target.id);
const key = Number(event.target.dataset.key) + 1;
const title = event.target.value;
this.$store.commit('updateDocumentTitle', {id: id, key: key, evaluationKey: this.evaluation.key, title: title});
this.$store.commit("updateDocumentTitle", {
id: id,
key: key,
evaluationKey: this.evaluation.key,
title: title,
});
},
addDocument({ stored_object, stored_object_version }) {
let document = {
type: 'accompanying_period_work_evaluation_document',
type: "accompanying_period_work_evaluation_document",
storedObject: stored_object,
title: 'Nouveau document',
title: "Nouveau document",
};
this.$store.commit('addDocument', {key: this.evaluation.key, document, stored_object_version});
this.$store.commit("addDocument", {
key: this.evaluation.key,
document,
stored_object_version,
});
},
/**
* Replaces a document in the store with a new document.
@ -388,51 +558,99 @@ export default {
*/
replaceDocument(oldDocument, storedObject, storedObjectVersion) {
let document = {
type: 'accompanying_period_work_evaluation_document',
type: "accompanying_period_work_evaluation_document",
storedObject: storedObject,
title: oldDocument.title
title: oldDocument.title,
};
this.$store.commit('replaceDocument', {key: this.evaluation.key, document, oldDocument: oldDocument, stored_object_version: storedObjectVersion});
this.$store.commit("replaceDocument", {
key: this.evaluation.key,
document,
oldDocument: oldDocument,
stored_object_version: storedObjectVersion,
});
},
removeDocument(document) {
if (window.confirm("Êtes-vous sûr·e de vouloir supprimer le document qui a pour titre \"" + document.title +"\" ?")) {
this.$store.commit('removeDocument', {key: this.evaluation.key, document: document});
if (
window.confirm(
'Êtes-vous sûr·e de vouloir supprimer le document qui a pour titre "' +
document.title +
'" ?',
)
) {
this.$store.commit("removeDocument", {
key: this.evaluation.key,
document: document,
});
}
},
duplicateDocument(document) {
this.$store.dispatch('duplicateDocument', {evaluation_key: this.evaluation.key, document: document});
this.$store.dispatch("duplicateDocument", {
evaluation_key: this.evaluation.key,
document: document,
});
},
onStatusDocumentChanged(newStatus) {
console.log('onStatusDocumentChanged', newStatus);
this.$store.commit('statusDocumentChanged', {key: this.evaluation.key, newStatus: newStatus});
console.log("onStatusDocumentChanged", newStatus);
this.$store.commit("statusDocumentChanged", {
key: this.evaluation.key,
newStatus: newStatus,
});
},
goToGenerateWorkflowEvaluationDocument({event, link, workflowName, payload}) {
goToGenerateWorkflowEvaluationDocument({
event,
link,
workflowName,
payload,
}) {
const callback = (data) => {
let evaluation = data.accompanyingPeriodWorkEvaluations.find(e => e.key === this.evaluation.key);
let updatedDocument = evaluation.documents.find(d => d.key === payload.doc.key);
window.location.assign(buildLinkCreate(workflowName,
'Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument', updatedDocument.id));
let evaluation = data.accompanyingPeriodWorkEvaluations.find(
(e) => e.key === this.evaluation.key,
);
let updatedDocument = evaluation.documents.find(
(d) => d.key === payload.doc.key,
);
window.location.assign(
buildLinkCreate(
workflowName,
"Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument",
updatedDocument.id,
),
);
};
return this.$store.dispatch('submit', callback)
.catch(e => { console.log(e); throw e; });
return this.$store.dispatch("submit", callback).catch((e) => {
console.log(e);
throw e;
});
},
goToGenerateDocumentNotification(document, tos) {
const callback = (data) => {
let evaluation = data.accompanyingPeriodWorkEvaluations.find(e => e.key === this.evaluation.key);
let updatedDocument = evaluation.documents.find(d => d.key === document.key);
window.location.assign(buildLinkCreateNotification(
'Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument',
let evaluation = data.accompanyingPeriodWorkEvaluations.find(
(e) => e.key === this.evaluation.key,
);
let updatedDocument = evaluation.documents.find(
(d) => d.key === document.key,
);
window.location.assign(
buildLinkCreateNotification(
"Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument",
updatedDocument.id,
tos === true ? this.$store.state.work.accompanyingPeriod.user.id : null,
window.location.pathname + window.location.search + window.location.hash
));
tos === true
? this.$store.state.work.accompanyingPeriod.user.id
: null,
window.location.pathname +
window.location.search +
window.location.hash,
),
);
};
return this.$store.dispatch('submit', callback)
.catch(e => {console.log(e); throw e});
}
return this.$store.dispatch("submit", callback).catch((e) => {
console.log(e);
throw e;
});
},
}
},
};
</script>
<style lang="scss" scoped>
@ -454,8 +672,14 @@ export default {
}
@keyframes blinkingBackground {
0% { background-color: #ed776d;}
50% { background-color: #ffffff;}
100% { background-color: #ed776d;}
0% {
background-color: #ed776d;
}
50% {
background-color: #ffffff;
}
100% {
background-color: #ed776d;
}
}
</style>

View File

@ -1,22 +1,35 @@
import { createStore } from 'vuex';
import { dateToISO, ISOToDate, datetimeToISO, ISOToDatetime, intervalDaysToISO, intervalISOToDays } from 'ChillMainAssets/chill/js/date';
import { findSocialActionsBySocialIssue } from 'ChillPersonAssets/vuejs/_api/SocialWorkSocialAction.js';
import { create } from 'ChillPersonAssets/vuejs/_api/AccompanyingCourseWork.js';
import { fetchResults, makeFetch } from 'ChillMainAssets/lib/api/apiMethods.ts';
import { fetchTemplates } from 'ChillDocGeneratorAssets/api/pickTemplate.js';
import { duplicate } from '../_api/accompanyingCourseWorkEvaluationDocument';
import { createStore } from "vuex";
import {
dateToISO,
ISOToDate,
datetimeToISO,
ISOToDatetime,
intervalDaysToISO,
intervalISOToDays,
} from "ChillMainAssets/chill/js/date";
import { findSocialActionsBySocialIssue } from "ChillPersonAssets/vuejs/_api/SocialWorkSocialAction.js";
import { create } from "ChillPersonAssets/vuejs/_api/AccompanyingCourseWork.js";
import { fetchResults, makeFetch } from "ChillMainAssets/lib/api/apiMethods.ts";
import { fetchTemplates } from "ChillDocGeneratorAssets/api/pickTemplate.js";
import { duplicate } from "../_api/accompanyingCourseWorkEvaluationDocument";
const debug = process.env.NODE_ENV !== 'production';
const evalFQDN = encodeURIComponent("Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation");
const debug = process.env.NODE_ENV !== "production";
const evalFQDN = encodeURIComponent(
"Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation",
);
const store = createStore({
strict: debug,
state: {
work: window.accompanyingCourseWork,
startDate: window.accompanyingCourseWork.startDate !== null ?
dateToISO(new Date(window.accompanyingCourseWork.startDate.datetime)) : null,
endDate: window.accompanyingCourseWork.endDate !== null ?
dateToISO(new Date(window.accompanyingCourseWork.endDate.datetime)) : null,
startDate:
window.accompanyingCourseWork.startDate !== null
? dateToISO(new Date(window.accompanyingCourseWork.startDate.datetime))
: null,
endDate:
window.accompanyingCourseWork.endDate !== null
? dateToISO(new Date(window.accompanyingCourseWork.endDate.datetime))
: null,
note: window.accompanyingCourseWork.note,
privateComment: window.accompanyingCourseWork.privateComment,
goalsPicked: window.accompanyingCourseWork.goals,
@ -29,15 +42,17 @@ const store = createStore({
templatesAvailablesForAction: [],
templatesAvailablesForEvaluation: new Map([]),
personsPicked: window.accompanyingCourseWork.persons,
personsReachables: window.accompanyingCourseWork.accompanyingPeriod.participations.filter(p => p.endDate == null)
.map(p => p.person),
personsReachables:
window.accompanyingCourseWork.accompanyingPeriod.participations
.filter((p) => p.endDate == null)
.map((p) => p.person),
handlingThirdParty: window.accompanyingCourseWork.handlingThierParty,
thirdParties: window.accompanyingCourseWork.thirdParties,
referrers: window.accompanyingCourseWork.referrers,
isPosting: false,
errors: [],
me: null,
version: window.accompanyingCourseWork.version
version: window.accompanyingCourseWork.version,
},
getters: {
socialAction(state) {
@ -47,12 +62,12 @@ const store = createStore({
return state.resultsForAction.length > 0;
},
resultsForGoal: (state) => (goal) => {
let founds = state.resultsForGoal.filter(r => r.goalId === goal.id);
let founds = state.resultsForGoal.filter((r) => r.goalId === goal.id);
return founds === undefined ? [] : founds;
},
resultsPickedForGoal: (state) => (goal) => {
let found = state.goalsPicked.find(g => g.goal.id === goal.id);
let found = state.goalsPicked.find((g) => g.goal.id === goal.id);
return found === undefined ? [] : found.results;
},
@ -74,26 +89,38 @@ const store = createStore({
},
buildPayload(state) {
return {
type: 'accompanying_period_work',
type: "accompanying_period_work",
id: state.work.id,
version: state.version,
startDate: state.startDate === null || state.startDate === '' ? null : {
datetime: datetimeToISO(ISOToDate(state.startDate))
startDate:
state.startDate === null || state.startDate === ""
? null
: {
datetime: datetimeToISO(ISOToDate(state.startDate)),
},
endDate: state.endDate === null || state.endDate === '' ? null : {
datetime: datetimeToISO(ISOToDate(state.endDate))
endDate:
state.endDate === null || state.endDate === ""
? null
: {
datetime: datetimeToISO(ISOToDate(state.endDate)),
},
note: state.note,
privateComment: state.privateComment,
persons: state.personsPicked.map(p => ({id: p.id, type: p.type})),
handlingThierParty: state.handlingThirdParty === null ? null : {
persons: state.personsPicked.map((p) => ({ id: p.id, type: p.type })),
handlingThierParty:
state.handlingThirdParty === null
? null
: {
id: state.handlingThirdParty.id,
type: state.handlingThirdParty.type
type: state.handlingThirdParty.type,
},
results: state.resultsPicked.map(r => ({id: r.id, type: r.type})),
thirdParties: state.thirdParties.map(t => ({id: t.id, type: t.type})),
referrers: state.referrers.map(t => ({id: t.id, type: t.type})),
goals: state.goalsPicked.map(g => {
results: state.resultsPicked.map((r) => ({ id: r.id, type: r.type })),
thirdParties: state.thirdParties.map((t) => ({
id: t.id,
type: t.type,
})),
referrers: state.referrers.map((t) => ({ id: t.id, type: t.type })),
goals: state.goalsPicked.map((g) => {
let o = {
type: g.type,
note: g.note,
@ -101,37 +128,46 @@ const store = createStore({
type: g.goal.type,
id: g.goal.id,
},
results: g.results.map(r => ({id: r.id, type: r.type})),
results: g.results.map((r) => ({ id: r.id, type: r.type })),
};
if (g.id !== undefined) {
o.id = g.id;
}
return o;
}),
accompanyingPeriodWorkEvaluations: state.evaluationsPicked.map(e => {
accompanyingPeriodWorkEvaluations: state.evaluationsPicked.map((e) => {
let o = {
type: e.type,
key: e.key,
evaluation: {
id: e.evaluation.id,
type: e.evaluation.type
type: e.evaluation.type,
},
startDate: e.startDate === null || e.startDate === '' ? null : { datetime: datetimeToISO(ISOToDate(e.startDate)) },
endDate: e.endDate === null || e.endDate === '' ? null : { datetime: datetimeToISO(ISOToDate(e.endDate)) },
maxDate: e.maxDate === null || e.maxDate === '' ? null : { datetime: datetimeToISO(ISOToDate(e.maxDate)) },
startDate:
e.startDate === null || e.startDate === ""
? null
: { datetime: datetimeToISO(ISOToDate(e.startDate)) },
endDate:
e.endDate === null || e.endDate === ""
? null
: { datetime: datetimeToISO(ISOToDate(e.endDate)) },
maxDate:
e.maxDate === null || e.maxDate === ""
? null
: { datetime: datetimeToISO(ISOToDate(e.maxDate)) },
warningInterval: intervalDaysToISO(e.warningInterval),
timeSpent: e.timeSpent,
comment: e.comment,
documents: e.documents
documents: e.documents,
};
if (e.id !== undefined) {
o.id = e.id;
}
return o;
})
}),
};
}
},
},
mutations: {
setWhoAmiI(state, me) {
@ -142,14 +178,22 @@ const store = createStore({
var k = Object.assign(e, {
key: index,
editEvaluation: false,
startDate: e.startDate !== null ? dateToISO(new Date(e.startDate.datetime)) : null,
endDate: e.endDate !== null ? dateToISO(new Date(e.endDate.datetime)) : null,
maxDate: e.maxDate !== null ? dateToISO(new Date(e.maxDate.datetime)) : null,
warningInterval: e.warningInterval !== null ? intervalISOToDays(e.warningInterval) : null,
startDate:
e.startDate !== null
? dateToISO(new Date(e.startDate.datetime))
: null,
endDate:
e.endDate !== null ? dateToISO(new Date(e.endDate.datetime)) : null,
maxDate:
e.maxDate !== null ? dateToISO(new Date(e.maxDate.datetime)) : null,
warningInterval:
e.warningInterval !== null
? intervalISOToDays(e.warningInterval)
: null,
timeSpent: e.timeSpent !== null ? e.timeSpent : null,
documents: e.documents.map((d, docIndex) => {
return Object.assign(d, {
key: docIndex
key: docIndex,
});
}),
});
@ -181,28 +225,30 @@ const store = createStore({
state.resultsPicked.push(result);
},
removeResultPicked(state, result) {
state.resultsPicked = state.resultsPicked.filter(r => r.id !== result.id);
state.resultsPicked = state.resultsPicked.filter(
(r) => r.id !== result.id,
);
},
addGoal(state, goal) {
let g = {
type: "accompanying_period_work_goal",
goal: goal,
note: '',
results: []
}
const tmpIndex = () => {
let ar = state.goalsPicked.map(g => g.id),
s = Math.min(...ar);
return (s < 0) ? s : 0
note: "",
results: [],
};
g.id = tmpIndex() -1
const tmpIndex = () => {
let ar = state.goalsPicked.map((g) => g.id),
s = Math.min(...ar);
return s < 0 ? s : 0;
};
g.id = tmpIndex() - 1;
state.goalsPicked.push(g);
},
removeGoal(state, goal) {
state.goalsPicked = state.goalsPicked.filter(g => g.id !== goal.id);
state.goalsPicked = state.goalsPicked.filter((g) => g.id !== goal.id);
},
addResultForGoalPicked(state, { goal, result }) {
let found = state.goalsPicked.find(g => g.goal.id === goal.id);
let found = state.goalsPicked.find((g) => g.goal.id === goal.id);
if (found === undefined) {
return;
@ -211,39 +257,48 @@ const store = createStore({
found.results.push(result);
},
removeResultForGoalPicked(state, { goal, result }) {
let found = state.goalsPicked.find(g => g.goal.id === goal.id);
let found = state.goalsPicked.find((g) => g.goal.id === goal.id);
if (found === undefined) {
return;
}
found.results = found.results.filter(r => r.id !== result.id);
found.results = found.results.filter((r) => r.id !== result.id);
},
addDocument(state, payload) {
// associate version to stored object
payload.document.storedObject.currentVersion = payload.stored_object_version;
payload.document.storedObject.currentVersion =
payload.stored_object_version;
let evaluation = state.evaluationsPicked.find(e => e.key === payload.key);
let evaluation = state.evaluationsPicked.find(
(e) => e.key === payload.key,
);
evaluation.documents.push(Object.assign(
payload.document, {
evaluation.documents.push(
Object.assign(payload.document, {
key: evaluation.documents.length + 1,
workflows_availables: state.work.workflows_availables_evaluation_documents,
workflows_availables:
state.work.workflows_availables_evaluation_documents,
workflows: [],
}));
}),
);
},
removeDocument(state, { key, document }) {
let evaluation = state.evaluationsPicked.find(e => e.key === key);
let evaluation = state.evaluationsPicked.find((e) => e.key === key);
if (evaluation === undefined) {
return;
}
evaluation.documents = evaluation.documents.filter(d => d.key !== document.key);
evaluation.documents = evaluation.documents.filter(
(d) => d.key !== document.key,
);
},
addDuplicatedDocument(state, { document, evaluation_key }) {
console.log('add duplicated document', document);
console.log('add duplicated dcuemnt - evaluation key', evaluation_key);
console.log("add duplicated document", document);
console.log("add duplicated dcuemnt - evaluation key", evaluation_key);
let evaluation = state.evaluationsPicked.find(e => e.key === evaluation_key);
let evaluation = state.evaluationsPicked.find(
(e) => e.key === evaluation_key,
);
document.key = evaluation.documents.length + 1;
evaluation.documents.splice(0, 0, document);
},
@ -255,28 +310,33 @@ const store = createStore({
* @return {void} - returns nothing.
*/
replaceDocument(state, payload) {
let evaluation = state.evaluationsPicked.find(e => e.key === payload.key);
let evaluation = state.evaluationsPicked.find(
(e) => e.key === payload.key,
);
if (evaluation === undefined) {
return;
}
let doc = evaluation.documents.find(d => d.key === payload.oldDocument.key);
let doc = evaluation.documents.find(
(d) => d.key === payload.oldDocument.key,
);
if (typeof doc === 'undefined') {
console.error('doc not found');
if (typeof doc === "undefined") {
console.error("doc not found");
return;
}
doc.storedObject.currentVersion = payload.stored_object_version;
return;
let newDocument = Object.assign(
payload.document, {
let newDocument = Object.assign(payload.document, {
key: evaluation.documents.length + 1,
workflows_availables: state.work.workflows_availables_evaluation_documents,
workflows_availables:
state.work.workflows_availables_evaluation_documents,
workflows: [],
}
});
evaluation.documents = evaluation.documents.map((d) =>
d.id === payload.oldDocument.id ? newDocument : d,
);
evaluation.documents = evaluation.documents.map(d => d.id === payload.oldDocument.id ? newDocument : d);
},
addEvaluation(state, evaluation) {
let e = {
@ -297,35 +357,31 @@ const store = createStore({
state.evaluationsPicked.push(e);
},
removeEvaluation(state, evaluation) {
state.evaluationsPicked = state.evaluationsPicked.filter(e => e.key !== evaluation.key);
state.evaluationsPicked = state.evaluationsPicked.filter(
(e) => e.key !== evaluation.key,
);
},
setEvaluationStartDate(state, { key, date }) {
state.evaluationsPicked.find(e => e.key === key)
.startDate = date;
state.evaluationsPicked.find((e) => e.key === key).startDate = date;
},
setEvaluationEndDate(state, { key, date }) {
console.log('commit date', date)
state.evaluationsPicked.find(e => e.key === key)
.endDate = date;
console.log("commit date", date);
state.evaluationsPicked.find((e) => e.key === key).endDate = date;
},
setEvaluationMaxDate(state, { key, date }) {
state.evaluationsPicked.find(e => e.key === key)
.maxDate = date;
state.evaluationsPicked.find((e) => e.key === key).maxDate = date;
},
setEvaluationWarningInterval(state, { key, days }) {
state.evaluationsPicked.find(e => e.key === key)
.warningInterval = days;
state.evaluationsPicked.find((e) => e.key === key).warningInterval = days;
},
setEvaluationTimeSpent(state, { key, time }) {
state.evaluationsPicked.find(e => e.key === key)
.timeSpent = time;
state.evaluationsPicked.find((e) => e.key === key).timeSpent = time;
},
setEvaluationComment(state, { key, comment }) {
state.evaluationsPicked.find(e => e.key === key)
.comment = comment;
state.evaluationsPicked.find((e) => e.key === key).comment = comment;
},
toggleEvaluationEdit(state, { key }) {
let evaluation = state.evaluationsPicked.find(e => e.key === key);
let evaluation = state.evaluationsPicked.find((e) => e.key === key);
evaluation.editEvaluation = !evaluation.editEvaluation;
},
setTemplatesForEvaluation(state, { templates, evaluation }) {
@ -335,8 +391,9 @@ const store = createStore({
state.templatesAvailablesForAction = templates;
},
setPersonsPickedIds(state, ids) {
state.personsPicked = state.personsReachables
.filter(p => ids.includes(p.id))
state.personsPicked = state.personsReachables.filter((p) =>
ids.includes(p.id),
);
},
setNote(state, note) {
state.note = note;
@ -349,8 +406,8 @@ const store = createStore({
},
addThirdParties(state, thirdParties) {
// filter to remove existing thirdparties
let ids = state.thirdParties.map(t => t.id);
let unexistings = thirdParties.filter(t => !ids.includes(t.id));
let ids = state.thirdParties.map((t) => t.id);
let unexistings = thirdParties.filter((t) => !ids.includes(t.id));
for (let i in unexistings) {
state.thirdParties.push(unexistings[i]);
@ -359,26 +416,28 @@ const store = createStore({
updateThirdParty(state, thirdParty) {
for (let t of state.thirdParties) {
if (t.id === thirdParty.id) {
state.thirdParties = state.thirdParties.filter(t => t.id !== thirdParty.id);
state.thirdParties = state.thirdParties.filter(
(t) => t.id !== thirdParty.id,
);
state.thirdParties.push(thirdParty);
}
}
},
removeThirdParty(state, thirdParty) {
state.thirdParties = state.thirdParties
.filter(t => t.id !== thirdParty.id);
state.thirdParties = state.thirdParties.filter(
(t) => t.id !== thirdParty.id,
);
},
addReferrers(state, referrers) {
let ids = state.referrers.map(t => t.id);
let unexistings = referrers.filter(t => !ids.includes(t.id));
let ids = state.referrers.map((t) => t.id);
let unexistings = referrers.filter((t) => !ids.includes(t.id));
for (let i in unexistings) {
state.referrers.push(unexistings[i]);
}
},
removeReferrer(state, user) {
state.referrers = state.referrers
.filter(u => u.id !== user.id);
state.referrers = state.referrers.filter((u) => u.id !== user.id);
},
setErrors(state, errors) {
state.errors = errors;
@ -388,22 +447,24 @@ const store = createStore({
},
updateDocumentTitle(state, payload) {
if (payload.id === 0) {
state.evaluationsPicked.find(e => e.key === payload.evaluationKey)
.documents.find(d => d.key === payload.key).title = payload.title;
state.evaluationsPicked
.find((e) => e.key === payload.evaluationKey)
.documents.find((d) => d.key === payload.key).title = payload.title;
} else {
state.evaluationsPicked.find(e => e.key === payload.evaluationKey)
.documents.find(d => d.id === payload.id).title = payload.title;
state.evaluationsPicked
.find((e) => e.key === payload.evaluationKey)
.documents.find((d) => d.id === payload.id).title = payload.title;
}
},
statusDocumentChanged(state, { newStatus, key }) {
const e = state.evaluationsPicked.find(e => e.key === key);
if (typeof e === 'undefined') {
console.error('evaluation not found for given key', {key});
const e = state.evaluationsPicked.find((e) => e.key === key);
if (typeof e === "undefined") {
console.error("evaluation not found for given key", { key });
}
const doc = e.documents.find(d => d.storedObject?.id === newStatus.id);
if (typeof doc === 'undefined') {
console.error('document not found', {newStatus});
const doc = e.documents.find((d) => d.storedObject?.id === newStatus.id);
if (typeof doc === "undefined") {
console.error("document not found", { newStatus });
}
doc.storedObject.status = newStatus.status;
@ -414,164 +475,188 @@ const store = createStore({
actions: {
getWhoAmI({ commit }) {
let url = `/api/1.0/main/whoami.json`;
window.fetch(url)
.then(response => {
window
.fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
}
throw { m: 'Error while retriving results for goal', s: response.status, b: response.body };
throw {
m: "Error while retriving results for goal",
s: response.status,
b: response.body,
};
})
.then(data => {
commit('setWhoAmiI', data);
.then((data) => {
commit("setWhoAmiI", data);
});
},
updateThirdParty({ commit }, payload) {
commit('updateThirdParty', payload);
commit("updateThirdParty", payload);
},
getReachablesGoalsForAction({ getters, commit, dispatch }) {
let
socialActionId = getters.socialAction.id,
url = `/api/1.0/person/social-work/goal/by-social-action/${socialActionId}.json`
;
let socialActionId = getters.socialAction.id,
url = `/api/1.0/person/social-work/goal/by-social-action/${socialActionId}.json`;
window
.fetch(
url
).then( response => {
.fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
}
throw { m: 'Error while retriving goal for social action', s: response.status, b: response.body };
}).then( data => {
throw {
m: "Error while retriving goal for social action",
s: response.status,
b: response.body,
};
})
.then((data) => {
for (let i in data.results) {
dispatch('getReachablesResultsForGoal', data.results[i]);
dispatch("getReachablesResultsForGoal", data.results[i]);
}
}).catch( errors => {
commit('addErrors', errors);
})
.catch((errors) => {
commit("addErrors", errors);
});
},
getReachablesResultsForGoal({ commit }, goal) {
let
url = `/api/1.0/person/social-work/result/by-goal/${goal.id}.json`
;
window.fetch(url)
.then(response => {
let url = `/api/1.0/person/social-work/result/by-goal/${goal.id}.json`;
window
.fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
}
throw { m: 'Error while retriving results for goal', s: response.status, b: response.body };
throw {
m: "Error while retriving results for goal",
s: response.status,
b: response.body,
};
})
.then(data => {
commit('setResultsForGoal', { goal, results: data.results });
.then((data) => {
commit("setResultsForGoal", { goal, results: data.results });
});
},
getReachablesResultsForAction({ getters, commit }) {
let
socialActionId = getters.socialAction.id,
url = `/api/1.0/person/social-work/result/by-social-action/${socialActionId}.json`
;
window.fetch(url)
.then(response => {
let socialActionId = getters.socialAction.id,
url = `/api/1.0/person/social-work/result/by-social-action/${socialActionId}.json`;
window
.fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
}
throw { m: 'Error while retriving results for social action', s: response.status, b: response.body };
throw {
m: "Error while retriving results for social action",
s: response.status,
b: response.body,
};
})
.then(data => {
commit('setResultsForAction', data.results);
.then((data) => {
commit("setResultsForAction", data.results);
});
},
getReachablesEvaluationsForAction({ getters, commit }) {
let
socialActionId = getters.socialAction.id,
url = `/api/1.0/person/social-work/evaluation/by-social-action/${socialActionId}.json`
;
window.fetch(url)
.then(response => {
let socialActionId = getters.socialAction.id,
url = `/api/1.0/person/social-work/evaluation/by-social-action/${socialActionId}.json`;
window
.fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
}
throw { m: 'Error while retriving evaluations for social action', s: response.status, b: response.body };
throw {
m: "Error while retriving evaluations for social action",
s: response.status,
b: response.body,
};
})
.then(data => {
commit('setEvaluationsForAction', data.results);
.then((data) => {
commit("setEvaluationsForAction", data.results);
});
},
addEvaluation({ commit, dispatch }, evaluation) {
commit('addEvaluation', evaluation);
dispatch('fetchTemplatesAvailablesForEvaluation', evaluation);
commit("addEvaluation", evaluation);
dispatch("fetchTemplatesAvailablesForEvaluation", evaluation);
},
fetchTemplatesAvailablesForEvaluation({ commit, state }, evaluation) {
if (!state.templatesAvailablesForEvaluation.has(evaluation.id)) {
// commit an empty array to avoid parallel fetching for same evaluation id
commit('setTemplatesForEvaluation', {templates: [], evaluation});
fetchResults(`/api/1.0/person/docgen/template/by-evaluation/${evaluation.id}.json`)
.then(templates => {
commit('setTemplatesForEvaluation', {templates, evaluation});
commit("setTemplatesForEvaluation", { templates: [], evaluation });
fetchResults(
`/api/1.0/person/docgen/template/by-evaluation/${evaluation.id}.json`,
).then((templates) => {
commit("setTemplatesForEvaluation", { templates, evaluation });
});
}
},
addDocument({ commit }, payload) {
commit('addDocument', payload);
commit("addDocument", payload);
},
async duplicateDocument({ commit }, { document, evaluation_key }) {
const newDoc = await duplicate(document.id);
commit('addDuplicatedDocument', {document: newDoc, evaluation_key});
commit("addDuplicatedDocument", { document: newDoc, evaluation_key });
},
removeDocument({ commit }, payload) {
commit('removeDocument', payload);
commit("removeDocument", payload);
},
replaceDocument({ commit }, payload) {
commit('replaceDocument', payload);
commit("replaceDocument", payload);
},
submit({ getters, state, commit }, callback) {
let
payload = getters.buildPayload,
params = new URLSearchParams({'entity_version': state.version}),
let payload = getters.buildPayload,
params = new URLSearchParams({ entity_version: state.version }),
url = `/api/1.0/person/accompanying-course/work/${state.work.id}.json?${params}`,
errors = []
;
commit('setIsPosting', true);
errors = [];
commit("setIsPosting", true);
// console.log('the social action', payload);
return makeFetch('PUT', url, payload)
.then(data => {
if (typeof(callback) !== 'undefined') {
return makeFetch("PUT", url, payload)
.then((data) => {
if (typeof callback !== "undefined") {
return callback(data);
} else {
// console.log('payload', payload.privateComment)
// console.info('nothing to do here, bye bye');
window.location.assign(`/fr/person/accompanying-period/${state.work.accompanyingPeriod.id}/work`);
window.location.assign(
`/fr/person/accompanying-period/${state.work.accompanyingPeriod.id}/work`,
);
}
}).catch(error => {
console.log('error', error)
commit('setIsPosting', false);
})
.catch((error) => {
console.log("error", error);
commit("setIsPosting", false);
throw error;
});
},
updateDocumentTitle({ commit }, payload) {
commit('updateDocumentTitle', payload)
}
}
commit("updateDocumentTitle", payload);
},
},
});
store.commit('setEvaluationsPicked', window.accompanyingCourseWork.accompanyingPeriodWorkEvaluations);
store.dispatch('getReachablesResultsForAction');
store.dispatch('getReachablesGoalsForAction');
store.dispatch('getReachablesEvaluationsForAction');
store.dispatch('getWhoAmI');
store.commit(
"setEvaluationsPicked",
window.accompanyingCourseWork.accompanyingPeriodWorkEvaluations,
);
store.dispatch("getReachablesResultsForAction");
store.dispatch("getReachablesGoalsForAction");
store.dispatch("getReachablesEvaluationsForAction");
store.dispatch("getWhoAmI");
store.state.evaluationsPicked.forEach(evaluation => {
store.dispatch('fetchTemplatesAvailablesForEvaluation', evaluation.evaluation)
store.state.evaluationsPicked.forEach((evaluation) => {
store.dispatch(
"fetchTemplatesAvailablesForEvaluation",
evaluation.evaluation,
);
});
fetchTemplates('Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork')
.then(templates => {
store.commit('setTemplatesAvailablesForAction', templates);
}
)
fetchTemplates(
"Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork",
).then((templates) => {
store.commit("setTemplatesAvailablesForAction", templates);
});
export { store };

View File

@ -1,6 +1,5 @@
<template>
<div class="list-item" :class="{ checked: isChecked }">
<label>
<div>
<input
@ -8,48 +7,51 @@
v-model="selected"
name="item"
v-bind:id="item"
v-bind:value="setValueByType(item, type)" />
v-bind:value="setValueByType(item, type)"
/>
</div>
<suggestion-person
v-if="item.result.type === 'person'"
v-bind:item="item">
v-bind:item="item"
>
</suggestion-person>
<suggestion-third-party
v-if="item.result.type === 'thirdparty'"
@newPriorSuggestion="newPriorSuggestion"
v-bind:item="item">
v-bind:item="item"
>
</suggestion-third-party>
<suggestion-user
v-if="item.result.type === 'user'"
v-bind:item="item">
<suggestion-user v-if="item.result.type === 'user'" v-bind:item="item">
</suggestion-user>
<suggestion-user-group
v-if="item.result.type === 'user_group'"
v-bind:item="item">
></suggestion-user-group>
v-bind:item="item"
>
></suggestion-user-group
>
<suggestion-household
v-if="item.result.type === 'household'"
v-bind:item="item">
v-bind:item="item"
>
</suggestion-household>
</label>
</div>
</template>
<script>
import SuggestionPerson from './TypePerson';
import SuggestionThirdParty from './TypeThirdParty';
import SuggestionUser from './TypeUser';
import SuggestionHousehold from './TypeHousehold';
import SuggestionUserGroup from './TypeUserGroup';
import SuggestionPerson from "./TypePerson";
import SuggestionThirdParty from "./TypeThirdParty";
import SuggestionUser from "./TypeUser";
import SuggestionHousehold from "./TypeHousehold";
import SuggestionUserGroup from "./TypeUserGroup";
export default {
name: 'PersonSuggestion',
name: "PersonSuggestion",
components: {
SuggestionPerson,
SuggestionThirdParty,
@ -57,34 +59,30 @@ export default {
SuggestionHousehold,
SuggestionUserGroup,
},
props: [
'item',
'search',
'type'
],
emits: ['updateSelected', 'newPriorSuggestion'],
props: ["item", "search", "type"],
emits: ["updateSelected", "newPriorSuggestion"],
computed: {
selected: {
set(value) {
//console.log('value', value);
this.$emit('updateSelected', value);
this.$emit("updateSelected", value);
},
get() {
return this.search.selected;
}
},
},
isChecked() {
return (this.search.selected.indexOf(this.item) === -1) ? false : true;
return this.search.selected.indexOf(this.item) === -1 ? false : true;
},
},
methods: {
setValueByType(value, type) {
return (type === 'radio')? [value] : value;
return type === "radio" ? [value] : value;
},
newPriorSuggestion(response) {
this.$emit('newPriorSuggestion', response)
}
}
this.$emit("newPriorSuggestion", response);
},
},
};
</script>

View File

@ -1,6 +1,8 @@
<script setup lang="ts">
import {ResultItem, UserGroup} from "../../../../../../ChillMainBundle/Resources/public/types";
import {
ResultItem,
UserGroup,
} from "../../../../../../ChillMainBundle/Resources/public/types";
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
import UserGroupRenderBox from "ChillMainAssets/vuejs/_components/Entity/UserGroupRenderBox.vue";
@ -15,16 +17,14 @@ const props = defineProps<TypeUserGroupProps>();
<template>
<div class="container user-group-container">
<div class="user-group-identification">
<user-group-render-box :user-group="props.item.result"></user-group-render-box>
<user-group-render-box
:user-group="props.item.result"
></user-group-render-box>
</div>
</div>
<div class="right_actions">
<span class="badge rounded-pill bg-user-group">
Groupe d'utilisateur
</span>
<span class="badge rounded-pill bg-user-group"> Groupe d'utilisateur </span>
</div>
</template>
<style scoped lang="scss">
</style>
<style scoped lang="scss"></style>

View File

@ -1,7 +1,8 @@
<template>
<div v-if="action === 'show'">
<div class="flex-table">
<person-render-box render="bloc"
<person-render-box
render="bloc"
:person="person"
:options="{
addInfo: true,
@ -13,7 +14,7 @@
hLevel: 3,
addCenter: true,
addNoData: true,
isMultiline: true
isMultiline: true,
}"
:show-residential-addresses="true"
></person-render-box>
@ -21,7 +22,6 @@
</div>
<div v-else-if="action === 'edit' || action === 'create'">
<div class="form-floating mb-3">
<input
class="form-control form-control-lg"
@ -30,12 +30,16 @@
:placeholder="$t('person.lastname')"
@change="checkErrors"
/>
<label for="lastname">{{ $t('person.lastname') }}</label>
<label for="lastname">{{ $t("person.lastname") }}</label>
</div>
<div v-if="queryItems">
<ul class="list-suggest add-items inline">
<li v-for="(qi, i) in queryItems" :key="i" @click="addQueryItem('lastName', qi)">
<li
v-for="(qi, i) in queryItems"
:key="i"
@click="addQueryItem('lastName', qi)"
>
<span class="person-text">{{ qi }}</span>
</li>
</ul>
@ -49,18 +53,26 @@
:placeholder="$t('person.firstname')"
@change="checkErrors"
/>
<label for="firstname">{{ $t('person.firstname') }}</label>
<label for="firstname">{{ $t("person.firstname") }}</label>
</div>
<div v-if="queryItems">
<ul class="list-suggest add-items inline">
<li v-for="(qi, i) in queryItems" :key="i" @click="addQueryItem('firstName', qi)">
<li
v-for="(qi, i) in queryItems"
:key="i"
@click="addQueryItem('firstName', qi)"
>
<span class="person-text">{{ qi }}</span>
</li>
</ul>
</div>
<div v-for="(a, i) in config.altNames" :key="a.key" class="form-floating mb-3">
<div
v-for="(a, i) in config.altNames"
:key="a.key"
class="form-floating mb-3"
>
<input
class="form-control form-control-lg"
:id="a.key"
@ -73,29 +85,26 @@
<!-- TODO fix placeholder if undefined
-->
<div class="form-floating mb-3">
<select
class="form-select form-select-lg"
id="gender"
v-model="gender"
>
<option selected disabled >{{ $t('person.gender.placeholder') }}</option>
<select class="form-select form-select-lg" id="gender" v-model="gender">
<option selected disabled>{{ $t("person.gender.placeholder") }}</option>
<option v-for="g in config.genders" :value="g.id" :key="g.id">
{{ g.label }}
</option>
</select>
<label>{{ $t('person.gender.title') }}</label>
<label>{{ $t("person.gender.title") }}</label>
</div>
<div class="form-floating mb-3" v-if="showCenters && config.centers.length > 1">
<select
class="form-select form-select-lg"
id="center"
v-model="center"
<div
class="form-floating mb-3"
v-if="showCenters && config.centers.length > 1"
>
<option selected disabled>{{ $t('person.center.placeholder') }}</option>
<option v-for="c in config.centers" :value="c" :key="c.id" >{{ c.name }}</option>
<select class="form-select form-select-lg" id="center" v-model="center">
<option selected disabled>{{ $t("person.center.placeholder") }}</option>
<option v-for="c in config.centers" :value="c" :key="c.id">
{{ c.name }}
</option>
</select>
<label>{{ $t('person.center.title') }}</label>
<label>{{ $t("person.center.title") }}</label>
</div>
<div class="form-floating mb-3">
@ -104,97 +113,127 @@
id="civility"
v-model="civility"
>
<option selected disabled >{{ $t('person.civility.placeholder') }}</option>
<option selected disabled>
{{ $t("person.civility.placeholder") }}
</option>
<option v-for="c in config.civilities" :value="c.id" :key="c.id">
{{ c.name.fr }}
</option>
</select>
<label>{{ $t('person.civility.title') }}</label>
<label>{{ $t("person.civility.title") }}</label>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="birthdate"><i class="fa fa-fw fa-birthday-cake"></i></span>
<input type="date"
<span class="input-group-text" id="birthdate"
><i class="fa fa-fw fa-birthday-cake"></i
></span>
<input
type="date"
class="form-control form-control-lg"
id="chill_personbundle_person_birthdate"
name="chill_personbundle_person[birthdate]"
v-model="birthDate"
aria-describedby="birthdate" />
aria-describedby="birthdate"
/>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="phonenumber"><i class="fa fa-fw fa-phone"></i></span>
<input class="form-control form-control-lg"
<span class="input-group-text" id="phonenumber"
><i class="fa fa-fw fa-phone"></i
></span>
<input
class="form-control form-control-lg"
v-model="phonenumber"
:placeholder="$t('person.phonenumber')"
:aria-label="$t('person.phonenumber')"
aria-describedby="phonenumber" />
aria-describedby="phonenumber"
/>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="mobilenumber"><i class="fa fa-fw fa-mobile"></i></span>
<input class="form-control form-control-lg"
<span class="input-group-text" id="mobilenumber"
><i class="fa fa-fw fa-mobile"></i
></span>
<input
class="form-control form-control-lg"
v-model="mobilenumber"
:placeholder="$t('person.mobilenumber')"
:aria-label="$t('person.mobilenumber')"
aria-describedby="mobilenumber" />
aria-describedby="mobilenumber"
/>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="email"><i class="fa fa-fw fa-at"></i></span>
<input class="form-control form-control-lg"
<span class="input-group-text" id="email"
><i class="fa fa-fw fa-at"></i
></span>
<input
class="form-control form-control-lg"
v-model="email"
:placeholder="$t('person.email')"
:aria-label="$t('person.email')"
aria-describedby="email" />
aria-describedby="email"
/>
</div>
<div v-if="action === 'create'" class="input-group mb-3 form-check">
<input class="form-check-input"
type='checkbox'
<input
class="form-check-input"
type="checkbox"
v-model="showAddressForm"
name='showAddressForm'/>
<label class="form-check-label">{{ $t('person.address.show_address_form') }}</label>
name="showAddressForm"
/>
<label class="form-check-label">{{
$t("person.address.show_address_form")
}}</label>
</div>
<div v-if="action === 'create' && showAddressFormValue" class="form-floating mb-3">
<p>{{ $t('person.address.warning') }}</p>
<div
v-if="action === 'create' && showAddressFormValue"
class="form-floating mb-3"
>
<p>{{ $t("person.address.warning") }}</p>
<add-address
:context="addAddress.context"
:options="addAddress.options"
:addressChangedCallback="submitNewAddress"
ref="addAddress">
ref="addAddress"
>
</add-address>
</div>
<div class="alert alert-warning" v-if="errors.length">
<ul>
<li v-for="(e, i) in errors" :key="i">{{ e }}</li>
</ul>
</div>
</div>
</template>
<script>
import { getCentersForPersonCreation, getCivilities, getGenders, getPerson, getPersonAltNames } from '../../_api/OnTheFly';
import PersonRenderBox from '../Entity/PersonRenderBox.vue';
import {
getCentersForPersonCreation,
getCivilities,
getGenders,
getPerson,
getPersonAltNames,
} from "../../_api/OnTheFly";
import PersonRenderBox from "../Entity/PersonRenderBox.vue";
import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress.vue";
export default {
name: "OnTheFlyPerson",
props: ['id', 'type', 'action', 'query'],
props: ["id", "type", "action", "query"],
//emits: ['createAction'],
components: {
PersonRenderBox,
AddAddress
AddAddress,
},
data() {
return {
person: {
type: 'person',
lastName: '',
firstName: '',
type: "person",
lastName: "",
firstName: "",
altNames: [],
addressId: null,
center: null,
@ -203,46 +242,60 @@ export default {
altNames: [],
civilities: [],
centers: [],
genders: []
genders: [],
},
showCenters: false, // NOTE: must remains false if the form is not in create mode
showAddressFormValue: false,
addAddress: {
options: {
button: {
text: { create: 'person.address.create_address' },
size: 'btn-sm'
text: { create: "person.address.create_address" },
size: "btn-sm",
},
title: { create: 'person.address.create_address' },
title: { create: "person.address.create_address" },
},
context: {
target: {}, // boilerplate for getting the address id
edit: false,
addressId: null,
defaults: window.addaddress
}
defaults: window.addaddress,
},
errors: []
}
},
errors: [],
};
},
computed: {
firstName: {
set(value) {
this.person.firstName = value;
},
get() { return this.person.firstName; }
get() {
return this.person.firstName;
},
},
lastName: {
set(value) { this.person.lastName = value; },
get() { return this.person.lastName; }
set(value) {
this.person.lastName = value;
},
get() {
return this.person.lastName;
},
},
gender: {
set(value) { this.person.gender = {id: value, type: 'chill_main_gender'}; },
get() { return this.person.gender ? this.person.gender.id : null; }
set(value) {
this.person.gender = { id: value, type: "chill_main_gender" };
},
get() {
return this.person.gender ? this.person.gender.id : null;
},
},
civility: {
set(value) { this.person.civility = {id: value, type: 'chill_main_civility'}; },
get() { return this.person.civility ? this.person.civility.id : null; }
set(value) {
this.person.civility = { id: value, type: "chill_main_civility" };
},
get() {
return this.person.civility ? this.person.civility.id : null;
},
},
birthDate: {
set(value) {
@ -253,101 +306,117 @@ export default {
}
},
get() {
return (this.person.birthdate) ? this.person.birthdate.datetime.split('T')[0] : '';
}
return this.person.birthdate
? this.person.birthdate.datetime.split("T")[0]
: "";
},
},
phonenumber: {
set(value) { this.person.phonenumber = value; },
get() { return this.person.phonenumber; }
set(value) {
this.person.phonenumber = value;
},
get() {
return this.person.phonenumber;
},
},
mobilenumber: {
set(value) { this.person.mobilenumber = value; },
get() { return this.person.mobilenumber; }
set(value) {
this.person.mobilenumber = value;
},
get() {
return this.person.mobilenumber;
},
},
email: {
set(value) { this.person.email = value; },
get() { return this.person.email; }
set(value) {
this.person.email = value;
},
get() {
return this.person.email;
},
},
showAddressForm: {
set(value) { this.showAddressFormValue = value; },
get() { return this.showAddressFormValue; }
set(value) {
this.showAddressFormValue = value;
},
get() {
return this.showAddressFormValue;
},
},
center: {
set(value) {
console.log('will set center', value);
console.log("will set center", value);
this.person.center = { id: value.id, type: value.type };
},
get() {
const center = this.config.centers.find(c => this.person.center !== null && this.person.center.id === c.id);
const center = this.config.centers.find(
(c) => this.person.center !== null && this.person.center.id === c.id,
);
console.log('center get', center);
console.log("center get", center);
return typeof center === 'undefined' ? null : center;
return typeof center === "undefined" ? null : center;
},
},
genderClass() {
switch (this.person.gender) {
case 'woman':
return 'fa-venus';
case 'man':
return 'fa-mars';
case 'both':
return 'fa-neuter';
case 'unknown':
return 'fa-genderless';
case "woman":
return "fa-venus";
case "man":
return "fa-mars";
case "both":
return "fa-neuter";
case "unknown":
return "fa-genderless";
default:
return 'fa-genderless';
return "fa-genderless";
}
},
genderTranslation() {
switch (this.person.gender.genderTranslation) {
case 'woman':
return 'person.gender.woman';
case 'man':
return 'person.gender.man';
case 'neutral':
return 'person.gender.neutral';
case 'unknown':
return 'person.gender.unknown';
case "woman":
return "person.gender.woman";
case "man":
return "person.gender.man";
case "neutral":
return "person.gender.neutral";
case "unknown":
return "person.gender.unknown";
default:
return 'person.gender.unknown';
return "person.gender.unknown";
}
},
feminized() {
return (this.person.gender === 'woman')? 'e' : '';
return this.person.gender === "woman" ? "e" : "";
},
personAltNamesLabels() {
return this.person.altNames.map(a => a ? a.label : '');
return this.person.altNames.map((a) => (a ? a.label : ""));
},
queryItems() {
return this.query ? this.query.split(' ') : null;
}
return this.query ? this.query.split(" ") : null;
},
},
mounted() {
getPersonAltNames()
.then(altNames => {
getPersonAltNames().then((altNames) => {
this.config.altNames = altNames;
});
getCivilities()
.then(civilities => {
if ('results' in civilities) {
getCivilities().then((civilities) => {
if ("results" in civilities) {
this.config.civilities = civilities.results;
}
});
getGenders()
.then(genders => {
if ('results' in genders) {
console.log('genders', genders.results)
getGenders().then((genders) => {
if ("results" in genders) {
console.log("genders", genders.results);
this.config.genders = genders.results;
}
});
if (this.action !== 'create') {
if (this.action !== "create") {
this.loadData();
} else {
// console.log('show centers', this.showCenters);
getCentersForPersonCreation()
.then(params => {
this.config.centers = params.centers.filter(c => c.isActive);
getCentersForPersonCreation().then((params) => {
this.config.centers = params.centers.filter((c) => c.isActive);
this.showCenters = params.showCenters;
// console.log('centers', this.config.centers)
// console.log('show centers inside', this.showCenters);
@ -374,37 +443,41 @@ export default {
}
},
loadData() {
getPerson(this.id)
.then(person => new Promise((resolve, reject) => {
getPerson(this.id).then(
(person) =>
new Promise((resolve, reject) => {
this.person = person;
//console.log('get person', this.person);
resolve();
}));
}),
);
},
onAltNameInput(event) {
const key = event.target.id;
const label = event.target.value;
let updateAltNames = this.person.altNames.filter((a) => a.key !== key);
updateAltNames.push(
{'key': key, 'label': label}
)
updateAltNames.push({ key: key, label: label });
this.person.altNames = updateAltNames;
},
addQueryItem(field, queryItem) {
switch (field) {
case 'lastName':
this.person.lastName = this.person.lastName ? this.person.lastName += ` ${queryItem}` : queryItem;
case "lastName":
this.person.lastName = this.person.lastName
? (this.person.lastName += ` ${queryItem}`)
: queryItem;
break;
case 'firstName':
this.person.firstName = this.person.firstName ? this.person.firstName += ` ${queryItem}` : queryItem;
case "firstName":
this.person.firstName = this.person.firstName
? (this.person.firstName += ` ${queryItem}`)
: queryItem;
break;
}
},
submitNewAddress(payload) {
this.person.addressId = payload.addressId;
}
}
}
},
},
};
</script>
<style lang="scss" scoped>

View File

@ -1,6 +1,6 @@
const Encore = require('@symfony/webpack-encore');
const { resolve, parse } = require('path');
const { readdir } = require('fs').promises;
const Encore = require("@symfony/webpack-encore");
const { resolve, parse } = require("path");
const { readdir } = require("fs").promises;
/**
* get the file names inside given directory recursively, limiting to
@ -23,7 +23,7 @@ async function* getFiles(dir, depth, ignored) {
yield res;
}
}
};
}
/**
* populate the config of encore in directories inside `'./src'` and
@ -41,13 +41,12 @@ async function populateConfig(Encore, chillEntries) {
// chill-main contains some bootstrap that must be loaded first.
// we register them first and, then, store this chill.webpack.config.js file
// into `toIgnore`, ignoring it when we loop on other folders.
let
toIgnore = [];
let toIgnore = [];
// loop into chill main
for await (const f of getFiles('./src/Bundle/ChillMainBundle/', 1, [])) {
for await (const f of getFiles("./src/Bundle/ChillMainBundle/", 1, [])) {
let filename = parse(f).base;
if (filename === 'chill.webpack.config.js') {
if (filename === "chill.webpack.config.js") {
configure = require(f);
configure(Encore, chillEntries);
toIgnore.push(f);
@ -55,30 +54,28 @@ async function populateConfig(Encore, chillEntries) {
}
// loop into other chill bundles
for await (const f of getFiles('./src/Bundle', 2, toIgnore)) {
for await (const f of getFiles("./src/Bundle", 2, toIgnore)) {
let filename = parse(f).base;
if (filename === 'chill.webpack.config.js') {
if (filename === "chill.webpack.config.js") {
configure = require(f);
configure(Encore, chillEntries);
}
}
};
}
// export the final configuration
module.exports = (async () => {
// Manually configure the runtime environment if not already configured yet by the "encore" command.
// It's useful when you use tools that rely on webpack.config.js file.
if (!Encore.isRuntimeEnvironmentConfigured()) {
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || "dev");
}
// basic encore configuration
Encore
.setOutputPath('public/build/')
.setPublicPath('/build')
Encore.setOutputPath("public/build/")
.setPublicPath("/build")
.enableSassLoader()
.enableVueLoader(() => {}, {
version: 3
version: 3,
})
.enableTypeScriptLoader(function (tsConfig) {
tsConfig.appendTsSuffixTo = [/\.vue$/];
@ -94,7 +91,7 @@ module.exports = (async () => {
//.enableBuildNotifications()
.enableVersioning()
.enableSingleRuntimeChunk()
.splitEntryChunks()
.splitEntryChunks();
// added when upgrading to symfony 5.4
// enables and configure @babel/preset-env polyfills
//.configureBabelPresetEnv((config) => {
@ -102,7 +99,6 @@ module.exports = (async () => {
// config.corejs = '3.23';
//})
//.addLoader({ test: /\.pdf$/, loader: 'file-loader', options: { name: '[name]_[hash].[ext]', outputPath: 'pdf/' } })
;
// populate config with chill entries
let chillEntries = [];
@ -118,7 +114,7 @@ module.exports = (async () => {
if (!Encore.isProduction()) {
console.log(config);
config.devtool = 'eval-source-map';
config.devtool = "eval-source-map";
}
return config;