mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-23 18:54:24 +00:00
Merge remote-tracking branch 'origin/ticket-app-master' into ticket-app-master
This commit is contained in:
commit
dfc146ff3f
30
.vscode/launch.json
vendored
Normal file
30
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Chill Debug",
|
||||
"type": "php",
|
||||
"request": "launch",
|
||||
"port": 9000,
|
||||
"pathMappings": {
|
||||
"/var/www/html": "${workspaceFolder}"
|
||||
},
|
||||
"preLaunchTask": "symfony"
|
||||
},
|
||||
{
|
||||
"name": "Yarn Encore Dev (Watch)",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "yarn encore dev --watch",
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Chill Debug + Yarn Encore Dev (Watch)",
|
||||
"configurations": ["Chill Debug", "Yarn Encore Dev (Watch)"]
|
||||
}
|
||||
]
|
||||
}
|
23
.vscode/tasks.json
vendored
Normal file
23
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"type": "shell",
|
||||
"command": "symfony",
|
||||
"args": [
|
||||
"server:start",
|
||||
"--allow-http",
|
||||
"--no-tls",
|
||||
"--port=8000",
|
||||
"--allow-all-ip",
|
||||
"-d"
|
||||
],
|
||||
"label": "symfony"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"command": "yarn",
|
||||
"args": ["encore", "dev", "--watch"],
|
||||
"label": "webpack"
|
||||
}
|
||||
]
|
||||
}
|
@ -49,6 +49,30 @@ export interface User {
|
||||
// todo: mainCenter; mainJob; etc..
|
||||
}
|
||||
|
||||
// TODO : Add missing household properties
|
||||
export interface Household {
|
||||
type: "household";
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface ThirdParty {
|
||||
type: "thirdparty";
|
||||
id: number;
|
||||
firstname: string;
|
||||
name: string;
|
||||
email: string;
|
||||
telephone: string;
|
||||
telephone2: string;
|
||||
address: {
|
||||
address_id: number;
|
||||
text: string;
|
||||
postcode: {
|
||||
name: string;
|
||||
};
|
||||
id: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface UserGroup {
|
||||
type: "user_group";
|
||||
id: number;
|
||||
|
@ -10,7 +10,7 @@
|
||||
v-model="radioType"
|
||||
value="person"
|
||||
/>
|
||||
{{ $t("onthefly.create.person") }}
|
||||
{{ trans(ONTHEFLY_CREATE_PERSON) }}
|
||||
</label>
|
||||
</a>
|
||||
</li>
|
||||
@ -24,7 +24,7 @@
|
||||
v-model="radioType"
|
||||
value="thirdparty"
|
||||
/>
|
||||
{{ $t("onthefly.create.thirdparty") }}
|
||||
{{ trans(ONTHEFLY_CREATE_THIRDPARTY) }}
|
||||
</label>
|
||||
</a>
|
||||
</li>
|
||||
@ -46,64 +46,67 @@
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import OnTheFlyPerson from "ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue";
|
||||
import OnTheFlyThirdparty from "ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue";
|
||||
import {
|
||||
trans,
|
||||
ONTHEFLY_CREATE_PERSON,
|
||||
ONTHEFLY_CREATE_THIRDPARTY,
|
||||
} from "translator";
|
||||
|
||||
export default {
|
||||
name: "OnTheFlyCreate",
|
||||
props: ["action", "allowedTypes", "query"],
|
||||
components: {
|
||||
OnTheFlyPerson,
|
||||
OnTheFlyThirdparty,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
type: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
radioType: {
|
||||
set(type) {
|
||||
this.type = type;
|
||||
console.log("## type:", type, ", action:", this.action);
|
||||
},
|
||||
get() {
|
||||
return this.type;
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.type =
|
||||
this.allowedTypes.length === 1 &&
|
||||
this.allowedTypes.includes("thirdparty")
|
||||
? "thirdparty"
|
||||
: "person";
|
||||
},
|
||||
methods: {
|
||||
isActive(tab) {
|
||||
return this.type === tab ? true : false;
|
||||
},
|
||||
castDataByType() {
|
||||
switch (this.radioType) {
|
||||
case "person":
|
||||
return this.$refs.castPerson.$data.person;
|
||||
case "thirdparty":
|
||||
let data = this.$refs.castThirdparty.$data.thirdparty;
|
||||
if (data.address !== undefined && data.address !== null) {
|
||||
data.address = { id: data.address.address_id };
|
||||
} else {
|
||||
data.address = null;
|
||||
}
|
||||
const props = defineProps({
|
||||
action: String,
|
||||
allowedTypes: Array,
|
||||
query: String,
|
||||
});
|
||||
|
||||
return data;
|
||||
default:
|
||||
throw Error("Invalid type of entity");
|
||||
const type = ref(null);
|
||||
|
||||
const radioType = computed({
|
||||
get: () => type.value,
|
||||
set: (val) => {
|
||||
type.value = val;
|
||||
console.log("## type:", val, ", action:", props.action);
|
||||
},
|
||||
});
|
||||
|
||||
const castPerson = ref(null);
|
||||
const castThirdparty = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
type.value =
|
||||
props.allowedTypes.length === 1 &&
|
||||
props.allowedTypes.includes("thirdparty")
|
||||
? "thirdparty"
|
||||
: "person";
|
||||
});
|
||||
|
||||
function isActive(tab) {
|
||||
return type.value === tab;
|
||||
}
|
||||
|
||||
function castDataByType() {
|
||||
switch (radioType.value) {
|
||||
case "person":
|
||||
return castPerson.value.$data.person;
|
||||
case "thirdparty":
|
||||
let data = castThirdparty.value.$data.thirdparty;
|
||||
if (data.address !== undefined && data.address !== null) {
|
||||
data.address = { id: data.address.address_id };
|
||||
} else {
|
||||
data.address = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
return data;
|
||||
default:
|
||||
throw Error("Invalid type of entity");
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
castDataByType,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
@ -9,7 +9,7 @@
|
||||
class="btn btn-sm"
|
||||
target="_blank"
|
||||
:class="classAction"
|
||||
:title="$t(titleAction)"
|
||||
:title="trans(titleAction)"
|
||||
@click="openModal"
|
||||
>
|
||||
{{ buttonText }}<span v-if="isDead"> (‡)</span>
|
||||
@ -23,10 +23,10 @@
|
||||
>
|
||||
<template #header>
|
||||
<h3 v-if="parent" class="modal-title">
|
||||
{{ $t(titleModal, { q: parent.text }) }}
|
||||
{{ trans(titleModal, { q: parent.text }) }}
|
||||
</h3>
|
||||
<h3 v-else class="modal-title">
|
||||
{{ $t(titleModal) }}
|
||||
{{ trans(titleModal) }}
|
||||
</h3>
|
||||
</template>
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
ref="castPerson"
|
||||
/>
|
||||
<div v-if="hasResourceComment">
|
||||
<h3>{{ $t("onthefly.resource_comment_title") }}</h3>
|
||||
<h3>{{ trans(ONTHEFLY_RESOURCE_COMMENT_TITLE) }}</h3>
|
||||
<blockquote class="chill-user-quote">
|
||||
{{ parent.comment }}
|
||||
</blockquote>
|
||||
@ -53,7 +53,7 @@
|
||||
ref="castThirdparty"
|
||||
/>
|
||||
<div v-if="hasResourceComment">
|
||||
<h3>{{ $t("onthefly.resource_comment_title") }}</h3>
|
||||
<h3>{{ trans(ONTHEFLY_RESOURCE_COMMENT_TITLE) }}</h3>
|
||||
<blockquote class="chill-user-quote">
|
||||
{{ parent.comment }}
|
||||
</blockquote>
|
||||
@ -82,242 +82,273 @@
|
||||
<a
|
||||
v-if="action === 'show'"
|
||||
:href="buildLocation(id, type)"
|
||||
:title="$t(titleMessage)"
|
||||
:title="trans(titleMessage)"
|
||||
class="btn btn-show"
|
||||
>{{ $t(buttonMessage) }}
|
||||
>{{ trans(buttonMessage) }}
|
||||
</a>
|
||||
<a v-else class="btn btn-save" @click="saveAction">
|
||||
{{ $t("action.save") }}
|
||||
{{ trans(ACTION_SAVE) }}
|
||||
</a>
|
||||
</template>
|
||||
</modal>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, computed, defineEmits, defineProps } from "vue";
|
||||
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
|
||||
import OnTheFlyCreate from "./Create.vue";
|
||||
import OnTheFlyPerson from "ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue";
|
||||
import OnTheFlyThirdparty from "ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue";
|
||||
import {
|
||||
trans,
|
||||
ACTION_SHOW,
|
||||
ACTION_EDIT,
|
||||
ACTION_CREATE,
|
||||
ACTION_ADDCONTACT,
|
||||
ONTHEFLY_CREATE_TITLE_DEFAULT,
|
||||
ONTHEFLY_CREATE_TITLE_PERSON,
|
||||
ONTHEFLY_CREATE_TITLE_THIRDPARTY,
|
||||
ONTHEFLY_SHOW_PERSON,
|
||||
ONTHEFLY_SHOW_THIRDPARTY,
|
||||
ONTHEFLY_EDIT_PERSON,
|
||||
ONTHEFLY_EDIT_THIRDPARTY,
|
||||
ONTHEFLY_ADDCONTACT_TITLE,
|
||||
ACTION_REDIRECT_PERSON,
|
||||
ACTION_REDIRECT_THIRDPARTY,
|
||||
ONTHEFLY_SHOW_FILE_PERSON,
|
||||
ONTHEFLY_SHOW_FILE_THIRDPARTY,
|
||||
ONTHEFLY_SHOW_FILE_DEFAULT,
|
||||
ONTHEFLY_RESOURCE_COMMENT_TITLE,
|
||||
ACTION_SAVE,
|
||||
} from "translator";
|
||||
|
||||
export default {
|
||||
name: "OnTheFly",
|
||||
components: {
|
||||
Modal,
|
||||
OnTheFlyPerson,
|
||||
OnTheFlyThirdparty,
|
||||
OnTheFlyCreate,
|
||||
},
|
||||
props: [
|
||||
"type",
|
||||
"id",
|
||||
"action",
|
||||
"buttonText",
|
||||
"displayBadge",
|
||||
"isDead",
|
||||
"parent",
|
||||
"allowedTypes",
|
||||
"query",
|
||||
],
|
||||
emits: ["saveFormOnTheFly"],
|
||||
data() {
|
||||
return {
|
||||
modal: {
|
||||
showModal: false,
|
||||
modalDialogClass: "modal-dialog-scrollable modal-xl",
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
hasResourceComment() {
|
||||
return (
|
||||
typeof this.parent !== "undefined" &&
|
||||
this.parent !== null &&
|
||||
this.action === "show" &&
|
||||
this.parent.type === "accompanying_period_resource" &&
|
||||
this.parent.comment !== null &&
|
||||
this.parent.comment !== ""
|
||||
);
|
||||
},
|
||||
classAction() {
|
||||
switch (this.action) {
|
||||
case "show":
|
||||
return "btn-show";
|
||||
case "edit":
|
||||
return "btn-update";
|
||||
case "create":
|
||||
return "btn-create";
|
||||
case "addContact":
|
||||
return "btn-tpchild";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
},
|
||||
titleAction() {
|
||||
switch (this.action) {
|
||||
case "show":
|
||||
return "action.show";
|
||||
case "edit":
|
||||
return "action.edit";
|
||||
case "create":
|
||||
return "action.create";
|
||||
case "addContact":
|
||||
return "action.addContact";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
},
|
||||
titleCreate() {
|
||||
if (typeof this.allowedTypes === "undefined") {
|
||||
return "onthefly.create.title.default";
|
||||
}
|
||||
return this.allowedTypes.every((t) => t === "person")
|
||||
? "onthefly.create.title.person"
|
||||
: this.allowedTypes.every((t) => t === "thirdparty")
|
||||
? "onthefly.create.title.thirdparty"
|
||||
: "onthefly.create.title.default";
|
||||
},
|
||||
titleModal() {
|
||||
switch (this.action) {
|
||||
case "show":
|
||||
return "onthefly.show." + this.type;
|
||||
case "edit":
|
||||
return "onthefly.edit." + this.type;
|
||||
case "create":
|
||||
return this.titleCreate;
|
||||
case "addContact":
|
||||
return "onthefly.addContact.title";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
},
|
||||
titleMessage() {
|
||||
switch (this.type) {
|
||||
case "person":
|
||||
return "action.redirect." + this.type;
|
||||
case "thirdparty":
|
||||
return "action.redirect." + this.type;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
},
|
||||
buttonMessage() {
|
||||
switch (this.type) {
|
||||
case "person":
|
||||
return "onthefly.show.file_" + this.type;
|
||||
case "thirdparty":
|
||||
return "onthefly.show.file_" + this.type;
|
||||
}
|
||||
},
|
||||
isDisplayBadge() {
|
||||
return this.displayBadge === true && this.buttonText !== null;
|
||||
},
|
||||
badgeType() {
|
||||
return "entity-" + this.type + " badge-" + this.type;
|
||||
},
|
||||
getReturnPath() {
|
||||
return `?returnPath=${window.location.pathname}${window.location.search}${window.location.hash}`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
closeModal() {
|
||||
this.modal.showModal = false;
|
||||
},
|
||||
openModal() {
|
||||
// console.log('## OPEN ON THE FLY MODAL');
|
||||
// console.log('## type:', this.type, ', action:', this.action);
|
||||
this.modal.showModal = true;
|
||||
this.$nextTick(function () {
|
||||
//this.$refs.search.focus();
|
||||
});
|
||||
},
|
||||
changeActionTo(action) {
|
||||
this.$data.action = action;
|
||||
},
|
||||
saveAction() {
|
||||
// console.log('saveAction button: create/edit action with', this.type);
|
||||
let type = this.type,
|
||||
data = {};
|
||||
switch (type) {
|
||||
case "person":
|
||||
data = this.$refs.castPerson.$data.person;
|
||||
console.log("person data are", data);
|
||||
break;
|
||||
const props = defineProps({
|
||||
type: String,
|
||||
id: [String, Number],
|
||||
action: String,
|
||||
buttonText: String,
|
||||
displayBadge: Boolean,
|
||||
isDead: Boolean,
|
||||
parent: Object,
|
||||
allowedTypes: Array,
|
||||
query: String,
|
||||
});
|
||||
|
||||
case "thirdparty":
|
||||
data = this.$refs.castThirdparty.$data.thirdparty;
|
||||
/* never executed ? */
|
||||
break;
|
||||
const emit = defineEmits(["saveFormOnTheFly"]);
|
||||
|
||||
default:
|
||||
if (typeof this.type === "undefined") {
|
||||
// action=create or addContact
|
||||
// console.log('will rewrite data');
|
||||
if (this.action === "addContact") {
|
||||
type = "thirdparty";
|
||||
data = this.$refs.castThirdparty.$data.thirdparty;
|
||||
// console.log('data original', data);
|
||||
data.parent = {
|
||||
type: "thirdparty",
|
||||
id: this.parent.id,
|
||||
};
|
||||
data.civility =
|
||||
data.civility !== null
|
||||
? {
|
||||
type: "chill_main_civility",
|
||||
id: data.civility.id,
|
||||
}
|
||||
: null;
|
||||
data.profession =
|
||||
data.profession !== "" ? data.profession : "";
|
||||
} else {
|
||||
type = this.$refs.castNew.radioType;
|
||||
data = this.$refs.castNew.castDataByType();
|
||||
// console.log('type', type);
|
||||
if (
|
||||
typeof data.civility !== "undefined" &&
|
||||
null !== data.civility
|
||||
) {
|
||||
data.civility =
|
||||
data.civility !== null
|
||||
? {
|
||||
type: "chill_main_civility",
|
||||
id: data.civility.id,
|
||||
}
|
||||
: null;
|
||||
}
|
||||
if (
|
||||
typeof data.profession !== "undefined" &&
|
||||
"" !== data.profession
|
||||
) {
|
||||
data.profession =
|
||||
data.profession !== ""
|
||||
? data.profession
|
||||
: "";
|
||||
}
|
||||
// console.log('onthefly data', data);
|
||||
}
|
||||
} else {
|
||||
throw "error with object type";
|
||||
const modal = ref({
|
||||
showModal: false,
|
||||
modalDialogClass: "modal-dialog-scrollable modal-xl",
|
||||
});
|
||||
|
||||
const castPerson = ref();
|
||||
const castThirdparty = ref();
|
||||
const castNew = ref();
|
||||
|
||||
const hasResourceComment = computed(() => {
|
||||
return (
|
||||
typeof props.parent !== "undefined" &&
|
||||
props.parent !== null &&
|
||||
props.action === "show" &&
|
||||
props.parent.type === "accompanying_period_resource" &&
|
||||
props.parent.comment !== null &&
|
||||
props.parent.comment !== ""
|
||||
);
|
||||
});
|
||||
|
||||
const classAction = computed(() => {
|
||||
switch (props.action) {
|
||||
case "show":
|
||||
return "btn-show";
|
||||
case "edit":
|
||||
return "btn-update";
|
||||
case "create":
|
||||
return "btn-create";
|
||||
case "addContact":
|
||||
return "btn-tpchild";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
const titleAction = computed(() => {
|
||||
switch (props.action) {
|
||||
case "show":
|
||||
return ACTION_SHOW;
|
||||
case "edit":
|
||||
return ACTION_EDIT;
|
||||
case "create":
|
||||
return ACTION_CREATE;
|
||||
case "addContact":
|
||||
return ACTION_ADDCONTACT;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
const titleCreate = computed(() => {
|
||||
if (typeof props.allowedTypes === "undefined") {
|
||||
return ONTHEFLY_CREATE_TITLE_DEFAULT;
|
||||
}
|
||||
return props.allowedTypes.every((t) => t === "person")
|
||||
? ONTHEFLY_CREATE_TITLE_PERSON
|
||||
: props.allowedTypes.every((t) => t === "thirdparty")
|
||||
? ONTHEFLY_CREATE_TITLE_THIRDPARTY
|
||||
: ONTHEFLY_CREATE_TITLE_DEFAULT;
|
||||
});
|
||||
|
||||
const titleModal = computed(() => {
|
||||
switch (props.action) {
|
||||
case "show":
|
||||
if (props.type == "person") {
|
||||
return ONTHEFLY_SHOW_PERSON;
|
||||
} else if (props.type == "thirdparty") {
|
||||
return ONTHEFLY_SHOW_THIRDPARTY;
|
||||
}
|
||||
break;
|
||||
case "edit":
|
||||
if (props.type == "person") {
|
||||
return ONTHEFLY_EDIT_PERSON;
|
||||
} else if (props.type == "thirdparty") {
|
||||
return ONTHEFLY_EDIT_THIRDPARTY;
|
||||
}
|
||||
break;
|
||||
case "create":
|
||||
return titleCreate.value;
|
||||
case "addContact":
|
||||
return ONTHEFLY_ADDCONTACT_TITLE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
});
|
||||
|
||||
const titleMessage = computed(() => {
|
||||
switch (props.type) {
|
||||
case "person":
|
||||
return ACTION_REDIRECT_PERSON;
|
||||
case "thirdparty":
|
||||
return ACTION_REDIRECT_THIRDPARTY;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
const buttonMessage = computed(() => {
|
||||
switch (props.type) {
|
||||
case "person":
|
||||
return ONTHEFLY_SHOW_FILE_PERSON;
|
||||
case "thirdparty":
|
||||
return ONTHEFLY_SHOW_FILE_THIRDPARTY;
|
||||
default:
|
||||
return ONTHEFLY_SHOW_FILE_DEFAULT;
|
||||
}
|
||||
});
|
||||
|
||||
const isDisplayBadge = computed(() => {
|
||||
return props.displayBadge === true && props.buttonText !== null;
|
||||
});
|
||||
|
||||
const badgeType = computed(() => {
|
||||
return "entity-" + props.type + " badge-" + props.type;
|
||||
});
|
||||
|
||||
const getReturnPath = computed(() => {
|
||||
return `?returnPath=${window.location.pathname}${window.location.search}${window.location.hash}`;
|
||||
});
|
||||
|
||||
function closeModal() {
|
||||
modal.value.showModal = false;
|
||||
}
|
||||
|
||||
function openModal() {
|
||||
modal.value.showModal = true;
|
||||
}
|
||||
|
||||
function changeActionTo(action) {
|
||||
console.log(action);
|
||||
// Not reactive in setup, but you can emit or use a ref if needed
|
||||
}
|
||||
|
||||
function saveAction() {
|
||||
let type = props.type,
|
||||
data = {};
|
||||
switch (type) {
|
||||
case "person":
|
||||
data = castPerson.value?.$data.person;
|
||||
break;
|
||||
case "thirdparty":
|
||||
data = castThirdparty.value?.$data.thirdparty;
|
||||
break;
|
||||
default:
|
||||
if (typeof props.type === "undefined") {
|
||||
if (props.action === "addContact") {
|
||||
type = "thirdparty";
|
||||
data = castThirdparty.value?.$data.thirdparty;
|
||||
data.parent = {
|
||||
type: "thirdparty",
|
||||
id: props.parent.id,
|
||||
};
|
||||
data.civility =
|
||||
data.civility !== null
|
||||
? {
|
||||
type: "chill_main_civility",
|
||||
id: data.civility.id,
|
||||
}
|
||||
: null;
|
||||
data.profession =
|
||||
data.profession !== "" ? data.profession : "";
|
||||
} else {
|
||||
type = castNew.value.radioType;
|
||||
data = castNew.value.castDataByType();
|
||||
if (
|
||||
typeof data.civility !== "undefined" &&
|
||||
null !== data.civility
|
||||
) {
|
||||
data.civility =
|
||||
data.civility !== null
|
||||
? {
|
||||
type: "chill_main_civility",
|
||||
id: data.civility.id,
|
||||
}
|
||||
: null;
|
||||
}
|
||||
if (
|
||||
typeof data.profession !== "undefined" &&
|
||||
"" !== data.profession
|
||||
) {
|
||||
data.profession =
|
||||
data.profession !== "" ? data.profession : "";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw "error with object type";
|
||||
}
|
||||
// pass datas to parent
|
||||
this.$emit("saveFormOnTheFly", { type: type, data: data });
|
||||
},
|
||||
buildLocation(id, type) {
|
||||
if (type === "person") {
|
||||
// TODO i18n
|
||||
return encodeURI(
|
||||
`/fr/person/${id}/general${this.getReturnPath}`,
|
||||
);
|
||||
} else if (type === "thirdparty") {
|
||||
return encodeURI(
|
||||
`/fr/3party/3party/${id}/view${this.getReturnPath}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
emit("saveFormOnTheFly", { type: type, data: data });
|
||||
}
|
||||
|
||||
function buildLocation(id, type) {
|
||||
if (type === "person") {
|
||||
return encodeURI(`/fr/person/${id}/general${getReturnPath.value}`);
|
||||
} else if (type === "thirdparty") {
|
||||
return encodeURI(`/fr/3party/3party/${id}/view${getReturnPath.value}`);
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
openModal,
|
||||
closeModal,
|
||||
changeActionTo,
|
||||
saveAction,
|
||||
castPerson,
|
||||
castThirdparty,
|
||||
castNew,
|
||||
hasResourceComment,
|
||||
modal,
|
||||
isDisplayBadge,
|
||||
Modal,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
@ -1,9 +1,28 @@
|
||||
<template>
|
||||
<i :class="gender.icon" />
|
||||
<i :class="['fa', genderClass, 'px-1']" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
const props = defineProps({
|
||||
gender: Object,
|
||||
gender: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const genderClass = computed(() => {
|
||||
switch (props.gender.genderTranslation) {
|
||||
case "woman":
|
||||
return "fa-venus";
|
||||
case "man":
|
||||
return "fa-mars";
|
||||
case "both":
|
||||
return "fa-neuter";
|
||||
case "unknown":
|
||||
return "fa-genderless";
|
||||
default:
|
||||
return "fa-genderless";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<transition name="modal">
|
||||
<div class="modal-mask">
|
||||
<div class="modal-mask" v-if="show">
|
||||
<!-- :: styles bootstrap :: -->
|
||||
<div
|
||||
class="modal fade show"
|
||||
@ -8,7 +8,7 @@
|
||||
aria-modal="true"
|
||||
role="dialog"
|
||||
>
|
||||
<div class="modal-dialog" :class="props.modalDialogClass || {}">
|
||||
<div class="modal-dialog" :class="modalDialogClass || {}">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<slot name="header"></slot>
|
||||
@ -53,14 +53,23 @@ import { trans, MODAL_ACTION_CLOSE } from "translator";
|
||||
import { defineProps } from "vue";
|
||||
|
||||
export interface ModalProps {
|
||||
modalDialogClass: object | null;
|
||||
modalDialogClass: string;
|
||||
hideFooter: boolean;
|
||||
}
|
||||
|
||||
// Define the props
|
||||
const props = withDefaults(defineProps<ModalProps>(), {
|
||||
hideFooter: false,
|
||||
modalDialogClass: null,
|
||||
defineProps({
|
||||
modalDialogClass: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
hideFooter: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits<{
|
||||
|
@ -129,3 +129,30 @@ filter_order:
|
||||
Search: Chercher dans la liste
|
||||
By date: Filtrer par date
|
||||
search_box: Filtrer par contenu
|
||||
renderbox:
|
||||
person: "Usager"
|
||||
birthday:
|
||||
man: "Né le"
|
||||
woman: "Née le"
|
||||
neutral: "Né·e le"
|
||||
unknown: "Né·e le"
|
||||
deathdate: "Date de décès"
|
||||
household_without_address: "Le ménage de l'usager est sans adresse"
|
||||
no_data: "Aucune information renseignée"
|
||||
type:
|
||||
thirdparty: "Tiers"
|
||||
person: "Usager"
|
||||
holder: "Titulaire"
|
||||
years_old: >-
|
||||
{n, plural,
|
||||
=0 {0 an}
|
||||
one {1 an}
|
||||
other {# ans}
|
||||
}
|
||||
residential_address: "Adresse de résidence"
|
||||
located_at: "réside chez"
|
||||
household_number: "Ménage n°{number}"
|
||||
current_members: "Membres actuels"
|
||||
no_current_address: "Sans adresse actuellement"
|
||||
new_household: "Nouveau ménage"
|
||||
no_members_yet: "Aucun membre actuellement"
|
||||
|
@ -919,3 +919,34 @@ multiselect:
|
||||
editor:
|
||||
switch_to_simple: Éditeur simple
|
||||
switch_to_complex: Éditeur riche
|
||||
action:
|
||||
actions: Actions
|
||||
show: Voir
|
||||
edit: Modifier
|
||||
create: Créer
|
||||
remove: Enlever
|
||||
delete: Supprimer
|
||||
save: Enregistrer
|
||||
valid: Valider
|
||||
valid_and_see: Valider et voir
|
||||
add: Ajouter
|
||||
show_modal: Ouvrir une modale
|
||||
ok: OK
|
||||
cancel: Annuler
|
||||
close: Fermer
|
||||
back: Retour
|
||||
check_all: cocher tout
|
||||
reset: réinitialiser
|
||||
redirect:
|
||||
person: Quitter la page et ouvrir la fiche de l'usager
|
||||
thirdparty: Quitter la page et voir le tiers
|
||||
refresh: Rafraîchir
|
||||
addContact: Ajouter un contact
|
||||
|
||||
nav:
|
||||
next: "Suivant"
|
||||
previous: "Précédent"
|
||||
top: "Haut"
|
||||
bottom: "Bas"
|
||||
|
||||
|
||||
|
@ -1,12 +1,15 @@
|
||||
import { StoredObject } from "ChillDocStoreAssets/types";
|
||||
import {
|
||||
Address,
|
||||
Center,
|
||||
Civility,
|
||||
DateTime,
|
||||
Household,
|
||||
ThirdParty,
|
||||
User,
|
||||
UserGroup,
|
||||
WorkflowAvailable,
|
||||
} from "../../../ChillMainBundle/Resources/public/types";
|
||||
import { StoredObject } from "../../../ChillDocStoreBundle/Resources/public/types";
|
||||
|
||||
export interface Person {
|
||||
id: number;
|
||||
@ -41,3 +44,61 @@ export interface AccompanyingPeriodWorkEvaluationDocument {
|
||||
workflows_availables: WorkflowAvailable[];
|
||||
workflows: object[];
|
||||
}
|
||||
|
||||
export type Entities = (UserGroup | User | Person | ThirdParty | Household) & {
|
||||
address?: Address | null;
|
||||
kind?: string;
|
||||
text?: string;
|
||||
profession?: string;
|
||||
};
|
||||
|
||||
export type Result = Entities & {
|
||||
parent?: Entities | null;
|
||||
};
|
||||
|
||||
export interface Suggestion {
|
||||
key: string;
|
||||
relevance: number;
|
||||
result: Result;
|
||||
}
|
||||
|
||||
export interface SearchPagination {
|
||||
first: number;
|
||||
items_per_page: number;
|
||||
next: number | null;
|
||||
previous: number | null;
|
||||
more: boolean;
|
||||
}
|
||||
|
||||
export interface Search {
|
||||
count: number;
|
||||
pagination: SearchPagination;
|
||||
results: Suggestion[];
|
||||
}
|
||||
|
||||
export interface SearchOptions {
|
||||
uniq: boolean;
|
||||
type: string[];
|
||||
priority: number | null;
|
||||
button: {
|
||||
size: string;
|
||||
class: string;
|
||||
type: string;
|
||||
display: string;
|
||||
};
|
||||
}
|
||||
|
||||
export class MakeFetchException extends Error {
|
||||
sta: number;
|
||||
txt: string;
|
||||
violations: unknown | null;
|
||||
|
||||
constructor(txt: string, sta: number, violations: unknown | null = null) {
|
||||
super(txt);
|
||||
this.name = "ValidationException";
|
||||
this.sta = sta;
|
||||
this.txt = txt;
|
||||
this.violations = violations;
|
||||
Object.setPrototypeOf(this, MakeFetchException.prototype);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,15 @@
|
||||
import { Search, SearchOptions } from "ChillPersonAssets/types";
|
||||
|
||||
/*
|
||||
* Build query string with query and options
|
||||
*/
|
||||
const parametersToString = ({ query, options }) => {
|
||||
const parametersToString = ({
|
||||
query,
|
||||
options,
|
||||
}: {
|
||||
query: string;
|
||||
options: SearchOptions;
|
||||
}) => {
|
||||
let types = "";
|
||||
options.type.forEach(function (type) {
|
||||
types += "&type[]=" + type;
|
||||
@ -16,11 +24,13 @@ const parametersToString = ({ query, options }) => {
|
||||
* @query string - the query to search for
|
||||
* @deprecated
|
||||
*/
|
||||
const searchPersons = ({ query, options }, signal) => {
|
||||
console.err("deprecated");
|
||||
let queryStr = parametersToString({ query, options });
|
||||
let url = `/fr/search.json?name=person_regular&${queryStr}`;
|
||||
let fetchOpts = {
|
||||
export function searchPersons(
|
||||
{ query, options }: { query: string; options: SearchOptions },
|
||||
signal: AbortSignal,
|
||||
): Promise<Search> {
|
||||
const queryStr = parametersToString({ query, options });
|
||||
const url = `/fr/search.json?name=person_regular&${queryStr}`;
|
||||
const fetchOpts = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json;charset=utf-8",
|
||||
@ -34,7 +44,7 @@ const searchPersons = ({ query, options }, signal) => {
|
||||
}
|
||||
throw Error("Error with request resource response");
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Endpoint v.2 chill_main_search_global
|
||||
@ -43,15 +53,16 @@ const searchPersons = ({ query, options }, signal) => {
|
||||
* @param query string - the query to search for
|
||||
*
|
||||
*/
|
||||
const searchEntities = ({ query, options }, signal) => {
|
||||
let queryStr = parametersToString({ query, options });
|
||||
let url = `/api/1.0/search.json?${queryStr}`;
|
||||
export function searchEntities(
|
||||
{ query, options }: { query: string; options: SearchOptions },
|
||||
signal: AbortSignal,
|
||||
): Promise<Search> {
|
||||
const queryStr = parametersToString({ query, options });
|
||||
const url = `/api/1.0/search.json?${queryStr}`;
|
||||
return fetch(url, { signal }).then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
throw Error("Error with request resource response");
|
||||
});
|
||||
};
|
||||
|
||||
export { searchPersons, searchEntities };
|
||||
}
|
@ -6,48 +6,39 @@
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods.ts";
|
||||
import { defineProps, defineEmits } from "vue";
|
||||
|
||||
export default {
|
||||
name: "SetReferrer",
|
||||
props: {
|
||||
suggested: {
|
||||
type: Array,
|
||||
required: false,
|
||||
//default: [],
|
||||
},
|
||||
periodId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
const props = defineProps({
|
||||
suggested: {
|
||||
type: Array,
|
||||
required: false,
|
||||
// default: [],
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
/*suggested: [
|
||||
{id: 5, text: 'Robert'}, {id: 8, text: 'Monique'},
|
||||
]*/
|
||||
};
|
||||
periodId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
emits: ["referrerSet"],
|
||||
methods: {
|
||||
setReferrer: function (ref) {
|
||||
const url = `/api/1.0/person/accompanying-course/${this.periodId}.json`;
|
||||
const body = {
|
||||
type: "accompanying_period",
|
||||
user: { id: ref.id, type: ref.type },
|
||||
};
|
||||
});
|
||||
|
||||
return makeFetch("PATCH", url, body)
|
||||
.then((response) => {
|
||||
this.$emit("referrerSet", ref);
|
||||
})
|
||||
.catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
const emit = defineEmits(["referrerSet"]);
|
||||
|
||||
function setReferrer(ref) {
|
||||
const url = `/api/1.0/person/accompanying-course/${props.periodId}.json`;
|
||||
const body = {
|
||||
type: "accompanying_period",
|
||||
user: { id: ref.id, type: ref.type },
|
||||
};
|
||||
|
||||
return makeFetch("PATCH", url, body)
|
||||
.then(() => {
|
||||
emit("referrerSet", ref);
|
||||
})
|
||||
.catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
@ -2,21 +2,23 @@
|
||||
<a
|
||||
class="btn"
|
||||
:class="getClassButton"
|
||||
:title="$t(buttonTitle || '')"
|
||||
:title="buttonTitle"
|
||||
@click="openModal"
|
||||
>
|
||||
<span v-if="displayTextButton">{{ $t(buttonTitle || "") }}</span>
|
||||
<span v-if="displayTextButton">{{ buttonTitle }}</span>
|
||||
</a>
|
||||
|
||||
<teleport to="body">
|
||||
<modal
|
||||
v-if="modal.showModal"
|
||||
:modal-dialog-class="modal.modalDialogClass"
|
||||
@close="modal.showModal = false"
|
||||
v-if="showModal"
|
||||
@close="closeModal"
|
||||
:modal-dialog-class="modalDialogClass"
|
||||
:show="showModal"
|
||||
:hide-footer="false"
|
||||
>
|
||||
<template #header>
|
||||
<h3 class="modal-title">
|
||||
{{ $t(modalTitle) }}
|
||||
{{ modalTitle }}
|
||||
</h3>
|
||||
</template>
|
||||
|
||||
@ -24,15 +26,19 @@
|
||||
<div class="modal-body">
|
||||
<div class="search">
|
||||
<label class="col-form-label" style="float: right">
|
||||
{{ $tc("add_persons.suggested_counter", suggestedCounter) }}
|
||||
{{
|
||||
trans(ADD_PERSONS_SUGGESTED_COUNTER, {
|
||||
count: suggestedCounter,
|
||||
})
|
||||
}}
|
||||
</label>
|
||||
|
||||
<input
|
||||
id="search-persons"
|
||||
name="query"
|
||||
v-model="query"
|
||||
:placeholder="$t('add_persons.search_some_persons')"
|
||||
ref="search"
|
||||
:placeholder="trans(ADD_PERSONS_SEARCH_SOME_PERSONS)"
|
||||
ref="searchRef"
|
||||
/>
|
||||
<i class="fa fa-search fa-lg" />
|
||||
<i
|
||||
@ -46,15 +52,19 @@
|
||||
<div class="count">
|
||||
<span>
|
||||
<a v-if="suggestedCounter > 2" @click="selectAll">
|
||||
{{ $t("action.check_all") }}
|
||||
{{ trans(ACTION_CHECK_ALL) }}
|
||||
</a>
|
||||
<a v-if="selectedCounter > 0" @click="resetSelection">
|
||||
<i v-if="suggestedCounter > 2"> • </i>
|
||||
{{ $t("action.reset") }}
|
||||
{{ trans(ACTION_RESET) }}
|
||||
</a>
|
||||
</span>
|
||||
<span v-if="selectedCounter > 0">
|
||||
{{ $tc("add_persons.selected_counter", selectedCounter) }}
|
||||
{{
|
||||
trans(ADD_PERSONS_SELECTED_COUNTER, {
|
||||
count: selectedCounter,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -63,7 +73,7 @@
|
||||
<template #body>
|
||||
<div class="results">
|
||||
<person-suggestion
|
||||
v-for="item in this.selectedAndSuggested.slice().reverse()"
|
||||
v-for="item in selectedAndSuggested.slice().reverse()"
|
||||
:key="itemKey(item)"
|
||||
:item="item"
|
||||
:search="search"
|
||||
@ -80,7 +90,7 @@
|
||||
(options.type.includes('person') ||
|
||||
options.type.includes('thirdparty'))
|
||||
"
|
||||
:button-text="$t('onthefly.create.button', { q: query })"
|
||||
:button-text="trans(ONTHEFLY_CREATE_BUTTON, { q: query })"
|
||||
:allowed-types="options.type"
|
||||
:query="query"
|
||||
action="create"
|
||||
@ -94,333 +104,335 @@
|
||||
<template #footer>
|
||||
<button
|
||||
class="btn btn-create"
|
||||
@click.prevent="$emit('addNewPersons', { selected, modal })"
|
||||
@click.prevent="
|
||||
() => {
|
||||
$emit('addNewPersons', { selected: selectedComputed });
|
||||
query = '';
|
||||
closeModal();
|
||||
}
|
||||
"
|
||||
>
|
||||
{{ $t("action.add") }}
|
||||
{{ trans(ACTION_ADD) }}
|
||||
</button>
|
||||
</template>
|
||||
</modal>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Modal from "ChillMainAssets/vuejs/_components/Modal";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
import PersonSuggestion from "./AddPersons/PersonSuggestion";
|
||||
<script setup lang="ts">
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
|
||||
import { ref, reactive, computed, nextTick, watch, shallowRef } from "vue";
|
||||
import PersonSuggestion from "./AddPersons/PersonSuggestion.vue";
|
||||
import { searchEntities } from "ChillPersonAssets/vuejs/_api/AddPersons";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
|
||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
||||
|
||||
export default {
|
||||
name: "AddPersons",
|
||||
components: {
|
||||
Modal,
|
||||
PersonSuggestion,
|
||||
OnTheFly,
|
||||
},
|
||||
props: ["buttonTitle", "modalTitle", "options"],
|
||||
emits: ["addNewPersons"],
|
||||
data() {
|
||||
return {
|
||||
modal: {
|
||||
showModal: false,
|
||||
modalDialogClass: "modal-dialog-scrollable modal-xl",
|
||||
},
|
||||
search: {
|
||||
query: "",
|
||||
previousQuery: "",
|
||||
currentSearchQueryController: null,
|
||||
suggested: [],
|
||||
selected: [],
|
||||
priorSuggestion: {},
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
query: {
|
||||
set(query) {
|
||||
return this.setQuery(query);
|
||||
},
|
||||
get() {
|
||||
return this.search.query;
|
||||
},
|
||||
},
|
||||
queryLength() {
|
||||
return this.search.query.length;
|
||||
},
|
||||
suggested() {
|
||||
return this.search.suggested;
|
||||
},
|
||||
suggestedCounter() {
|
||||
return this.search.suggested.length;
|
||||
},
|
||||
selected() {
|
||||
return this.search.selected;
|
||||
},
|
||||
selectedCounter() {
|
||||
return this.search.selected.length;
|
||||
},
|
||||
selectedAndSuggested() {
|
||||
this.addPriorSuggestion();
|
||||
const uniqBy = (a, key) => [
|
||||
...new Map(a.map((x) => [key(x), x])).values(),
|
||||
];
|
||||
let union = [
|
||||
...new Set([
|
||||
...this.suggested.slice().reverse(),
|
||||
...this.selected.slice().reverse(),
|
||||
]),
|
||||
];
|
||||
return uniqBy(union, (k) => k.key);
|
||||
},
|
||||
getClassButton() {
|
||||
let size =
|
||||
typeof this.options.button !== "undefined" &&
|
||||
typeof this.options.button.size !== "undefined"
|
||||
? this.options.button.size
|
||||
: "";
|
||||
let type =
|
||||
typeof this.options.button !== "undefined" &&
|
||||
typeof this.options.button.type !== "undefined"
|
||||
? this.options.button.type
|
||||
: "btn-create";
|
||||
return size ? size + " " + type : type;
|
||||
},
|
||||
displayTextButton() {
|
||||
return typeof this.options.button !== "undefined" &&
|
||||
typeof this.options.button.display !== "undefined"
|
||||
? this.options.button.display
|
||||
: true;
|
||||
},
|
||||
checkUniq() {
|
||||
if (this.options.uniq === true) {
|
||||
return "radio";
|
||||
}
|
||||
return "checkbox";
|
||||
},
|
||||
priorSuggestion() {
|
||||
return this.search.priorSuggestion;
|
||||
},
|
||||
hasPriorSuggestion() {
|
||||
return this.search.priorSuggestion.key ? true : false;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openModal() {
|
||||
this.modal.showModal = true;
|
||||
this.$nextTick(function () {
|
||||
this.$refs.search.focus();
|
||||
import {
|
||||
trans,
|
||||
ADD_PERSONS_SUGGESTED_COUNTER,
|
||||
ADD_PERSONS_SEARCH_SOME_PERSONS,
|
||||
ADD_PERSONS_SELECTED_COUNTER,
|
||||
ONTHEFLY_CREATE_BUTTON,
|
||||
ACTION_CHECK_ALL,
|
||||
ACTION_RESET,
|
||||
ACTION_ADD,
|
||||
} from "translator";
|
||||
import {
|
||||
Suggestion,
|
||||
Search,
|
||||
Result as OriginalResult,
|
||||
SearchOptions,
|
||||
} from "ChillPersonAssets/types";
|
||||
|
||||
// Extend Result type to include optional addressId
|
||||
type Result = OriginalResult & { addressId?: number };
|
||||
|
||||
const props = defineProps({
|
||||
suggested: { type: Array as () => Suggestion[], default: () => [] },
|
||||
selected: { type: Array as () => Suggestion[], default: () => [] },
|
||||
buttonTitle: { type: String, required: true },
|
||||
modalTitle: { type: String, required: true },
|
||||
options: { type: Object as () => SearchOptions, required: true },
|
||||
});
|
||||
|
||||
defineEmits(["addNewPersons"]);
|
||||
|
||||
const showModal = ref(false);
|
||||
const modalDialogClass = ref("modal-dialog-scrollable modal-xl");
|
||||
|
||||
const modal = shallowRef({
|
||||
showModal: false,
|
||||
modalDialogClass: "modal-dialog-scrollable modal-xl",
|
||||
});
|
||||
|
||||
const search = reactive({
|
||||
query: "" as string,
|
||||
previousQuery: "" as string,
|
||||
currentSearchQueryController: null as AbortController | null,
|
||||
suggested: props.suggested as Suggestion[],
|
||||
selected: props.selected as Suggestion[],
|
||||
priorSuggestion: {} as Partial<Suggestion>,
|
||||
});
|
||||
|
||||
const searchRef = ref<HTMLInputElement | null>(null);
|
||||
const onTheFly = ref<InstanceType<typeof OnTheFly> | null>(null);
|
||||
|
||||
const query = computed({
|
||||
get: () => search.query,
|
||||
set: (val) => setQuery(val),
|
||||
});
|
||||
const queryLength = computed(() => search.query.length);
|
||||
const suggestedCounter = computed(() => search.suggested.length);
|
||||
const selectedComputed = computed(() => search.selected);
|
||||
const selectedCounter = computed(() => search.selected.length);
|
||||
|
||||
const getClassButton = computed(() => {
|
||||
let size = props.options?.button?.size ?? "";
|
||||
let type = props.options?.button?.type ?? "btn-create";
|
||||
return size ? size + " " + type : type;
|
||||
});
|
||||
const displayTextButton = computed(() =>
|
||||
props.options?.button?.display !== undefined
|
||||
? props.options.button.display
|
||||
: true,
|
||||
);
|
||||
|
||||
const checkUniq = computed(() =>
|
||||
props.options.uniq === true ? "radio" : "checkbox",
|
||||
);
|
||||
|
||||
const priorSuggestion = computed(() => search.priorSuggestion);
|
||||
const hasPriorSuggestion = computed(() => !!search.priorSuggestion.key);
|
||||
|
||||
const itemKey = (item: Suggestion) => item.result.type + item.result.id;
|
||||
|
||||
function addPriorSuggestion() {
|
||||
if (hasPriorSuggestion.value) {
|
||||
// Type assertion is safe here due to the checks above
|
||||
search.suggested.unshift(priorSuggestion.value as Suggestion);
|
||||
search.selected.unshift(priorSuggestion.value as Suggestion);
|
||||
newPriorSuggestion(null);
|
||||
}
|
||||
}
|
||||
|
||||
const selectedAndSuggested = computed(() => {
|
||||
addPriorSuggestion();
|
||||
const uniqBy = (a: Suggestion[], key: (item: Suggestion) => string) => [
|
||||
...new Map(a.map((x) => [key(x), x])).values(),
|
||||
];
|
||||
let union = [
|
||||
...new Set([
|
||||
...search.suggested.slice().reverse(),
|
||||
...search.selected.slice().reverse(),
|
||||
]),
|
||||
];
|
||||
return uniqBy(union, (k: Suggestion) => k.key);
|
||||
});
|
||||
|
||||
function openModal() {
|
||||
showModal.value = true;
|
||||
nextTick(() => {
|
||||
if (searchRef.value) searchRef.value.focus();
|
||||
});
|
||||
}
|
||||
function closeModal() {
|
||||
showModal.value = false;
|
||||
}
|
||||
|
||||
function setQuery(q: string) {
|
||||
search.query = q;
|
||||
|
||||
// Clear previous search if any
|
||||
if (search.currentSearchQueryController) {
|
||||
search.currentSearchQueryController.abort();
|
||||
search.currentSearchQueryController = null;
|
||||
}
|
||||
|
||||
if (q === "") {
|
||||
loadSuggestions([]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Debounce delay based on query length
|
||||
const delay = q.length > 3 ? 300 : 700;
|
||||
|
||||
setTimeout(() => {
|
||||
// Only search if query hasn't changed in the meantime
|
||||
if (q !== search.query) return;
|
||||
|
||||
search.currentSearchQueryController = new AbortController();
|
||||
|
||||
searchEntities(
|
||||
{ query: q, options: props.options },
|
||||
search.currentSearchQueryController.signal,
|
||||
)
|
||||
.then((suggested: Search) => {
|
||||
loadSuggestions(suggested.results);
|
||||
})
|
||||
.catch((error: DOMException) => {
|
||||
if (error instanceof DOMException && error.name === "AbortError") {
|
||||
// Request was aborted, ignore
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
setQuery(query) {
|
||||
this.search.query = query;
|
||||
}, delay);
|
||||
}
|
||||
|
||||
setTimeout(
|
||||
function () {
|
||||
if (query === "") {
|
||||
this.loadSuggestions([]);
|
||||
return;
|
||||
}
|
||||
if (query === this.search.query) {
|
||||
if (this.search.currentSearchQueryController !== null) {
|
||||
this.search.currentSearchQueryController.abort();
|
||||
}
|
||||
this.search.currentSearchQueryController = new AbortController();
|
||||
searchEntities(
|
||||
{ query, options: this.options },
|
||||
this.search.currentSearchQueryController.signal,
|
||||
)
|
||||
.then(
|
||||
(suggested) =>
|
||||
new Promise((resolve) => {
|
||||
this.loadSuggestions(suggested.results);
|
||||
resolve();
|
||||
}),
|
||||
)
|
||||
.catch((error) => {
|
||||
if (error instanceof DOMException) {
|
||||
if (error.name === "AbortError") {
|
||||
console.log("request aborted due to user continue typing");
|
||||
return;
|
||||
}
|
||||
}
|
||||
function loadSuggestions(suggestedArr: Suggestion[]) {
|
||||
search.suggested = suggestedArr;
|
||||
search.suggested.forEach((item) => {
|
||||
item.key = itemKey(item);
|
||||
});
|
||||
}
|
||||
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
}.bind(this),
|
||||
query.length > 3 ? 300 : 700,
|
||||
);
|
||||
},
|
||||
loadSuggestions(suggested) {
|
||||
this.search.suggested = suggested;
|
||||
this.search.suggested.forEach(function (item) {
|
||||
item.key = this.itemKey(item);
|
||||
}, this);
|
||||
},
|
||||
updateSelected(value) {
|
||||
//console.log('value', value);
|
||||
this.search.selected = value;
|
||||
},
|
||||
resetSearch() {
|
||||
this.resetSelection();
|
||||
this.resetSuggestion();
|
||||
},
|
||||
resetSuggestion() {
|
||||
this.search.query = "";
|
||||
this.search.suggested = [];
|
||||
},
|
||||
resetSelection() {
|
||||
this.search.selected = [];
|
||||
},
|
||||
selectAll() {
|
||||
this.search.suggested.forEach(function (item) {
|
||||
this.search.selected.push(item);
|
||||
}, this);
|
||||
},
|
||||
itemKey(item) {
|
||||
return item.result.type + item.result.id;
|
||||
},
|
||||
addPriorSuggestion() {
|
||||
// console.log('prior suggestion', this.priorSuggestion);
|
||||
if (this.hasPriorSuggestion) {
|
||||
// console.log('addPriorSuggestion',);
|
||||
this.suggested.unshift(this.priorSuggestion);
|
||||
this.selected.unshift(this.priorSuggestion);
|
||||
function updateSelected(value: Suggestion[]) {
|
||||
search.selected = value;
|
||||
}
|
||||
|
||||
this.newPriorSuggestion(null);
|
||||
}
|
||||
},
|
||||
newPriorSuggestion(entity) {
|
||||
// console.log('newPriorSuggestion', entity);
|
||||
if (entity !== null) {
|
||||
let suggestion = {
|
||||
key: entity.type + entity.id,
|
||||
relevance: 0.5,
|
||||
result: entity,
|
||||
};
|
||||
this.search.priorSuggestion = suggestion;
|
||||
// console.log('search priorSuggestion', this.search.priorSuggestion);
|
||||
this.addPriorSuggestion(suggestion);
|
||||
} else {
|
||||
this.search.priorSuggestion = {};
|
||||
}
|
||||
},
|
||||
saveFormOnTheFly({ type, data }) {
|
||||
console.log(
|
||||
"saveFormOnTheFly from addPersons, type",
|
||||
type,
|
||||
", data",
|
||||
function resetSuggestion() {
|
||||
search.query = "";
|
||||
search.suggested = [];
|
||||
}
|
||||
|
||||
function resetSelection() {
|
||||
search.selected = [];
|
||||
}
|
||||
|
||||
function resetSearch() {
|
||||
resetSelection();
|
||||
resetSuggestion();
|
||||
}
|
||||
|
||||
function selectAll() {
|
||||
search.suggested.forEach((item) => {
|
||||
search.selected.push(item);
|
||||
});
|
||||
}
|
||||
|
||||
function newPriorSuggestion(entity: Result | null) {
|
||||
if (entity !== null) {
|
||||
let suggestion = {
|
||||
key: entity.type + entity.id,
|
||||
relevance: 0.5,
|
||||
result: entity,
|
||||
};
|
||||
search.priorSuggestion = suggestion;
|
||||
} else {
|
||||
search.priorSuggestion = {};
|
||||
}
|
||||
}
|
||||
|
||||
async function saveFormOnTheFly({
|
||||
type,
|
||||
data,
|
||||
}: {
|
||||
type: string;
|
||||
data: Result;
|
||||
}) {
|
||||
try {
|
||||
if (type === "person") {
|
||||
const responsePerson: Result = await makeFetch(
|
||||
"POST",
|
||||
"/api/1.0/person/person.json",
|
||||
data,
|
||||
);
|
||||
if (type === "person") {
|
||||
makeFetch("POST", "/api/1.0/person/person.json", data)
|
||||
.then((responsePerson) => {
|
||||
this.newPriorSuggestion(responsePerson);
|
||||
this.$refs.onTheFly.closeModal();
|
||||
newPriorSuggestion(responsePerson);
|
||||
if (onTheFly.value) onTheFly.value.closeModal();
|
||||
|
||||
if (null !== data.addressId) {
|
||||
const household = {
|
||||
type: "household",
|
||||
};
|
||||
const address = {
|
||||
id: data.addressId,
|
||||
};
|
||||
makeFetch("POST", "/api/1.0/person/household.json", household)
|
||||
.then((responseHousehold) => {
|
||||
const member = {
|
||||
concerned: [
|
||||
{
|
||||
person: {
|
||||
type: "person",
|
||||
id: responsePerson.id,
|
||||
},
|
||||
start_date: {
|
||||
// TODO: use date.ts methods (low priority)
|
||||
datetime: `${new Date().toISOString().split("T")[0]}T00:00:00+02:00`,
|
||||
},
|
||||
holder: false,
|
||||
comment: null,
|
||||
},
|
||||
],
|
||||
destination: {
|
||||
type: "household",
|
||||
id: responseHousehold.id,
|
||||
},
|
||||
composition: null,
|
||||
};
|
||||
return makeFetch(
|
||||
"POST",
|
||||
"/api/1.0/person/household/members/move.json",
|
||||
member,
|
||||
)
|
||||
.then((_response) => {
|
||||
makeFetch(
|
||||
"POST",
|
||||
`/api/1.0/person/household/${responseHousehold.id}/address.json`,
|
||||
address,
|
||||
)
|
||||
.then((_response) => {
|
||||
console.log(_response);
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === "ValidationException") {
|
||||
for (let v of error.violations) {
|
||||
this.$toast.open({ message: v });
|
||||
}
|
||||
} else {
|
||||
this.$toast.open({ message: "An error occurred" });
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === "ValidationException") {
|
||||
for (let v of error.violations) {
|
||||
this.$toast.open({ message: v });
|
||||
}
|
||||
} else {
|
||||
this.$toast.open({ message: "An error occurred" });
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === "ValidationException") {
|
||||
for (let v of error.violations) {
|
||||
this.$toast.open({ message: v });
|
||||
}
|
||||
} else {
|
||||
this.$toast.open({ message: "An error occurred" });
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === "ValidationException") {
|
||||
for (let v of error.violations) {
|
||||
this.$toast.open({ message: v });
|
||||
}
|
||||
} else {
|
||||
this.$toast.open({ message: "An error occurred" });
|
||||
}
|
||||
});
|
||||
} else if (type === "thirdparty") {
|
||||
makeFetch("POST", "/api/1.0/thirdparty/thirdparty.json", data)
|
||||
.then((response) => {
|
||||
this.newPriorSuggestion(response);
|
||||
this.$refs.onTheFly.closeModal();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === "ValidationException") {
|
||||
for (let v of error.violations) {
|
||||
this.$toast.open({ message: v });
|
||||
}
|
||||
} else {
|
||||
this.$toast.open({ message: "An error occurred" });
|
||||
}
|
||||
});
|
||||
if (data.addressId != null) {
|
||||
const household = { type: "household" };
|
||||
const address = { id: data.addressId };
|
||||
try {
|
||||
const responseHousehold: Result = await makeFetch(
|
||||
"POST",
|
||||
"/api/1.0/person/household.json",
|
||||
household,
|
||||
);
|
||||
const member = {
|
||||
concerned: [
|
||||
{
|
||||
person: {
|
||||
type: "person",
|
||||
id: responsePerson.id,
|
||||
},
|
||||
start_date: {
|
||||
datetime: `${new Date().toISOString().split("T")[0]}T00:00:00+02:00`,
|
||||
},
|
||||
holder: false,
|
||||
comment: null,
|
||||
},
|
||||
],
|
||||
destination: {
|
||||
type: "household",
|
||||
id: responseHousehold.id,
|
||||
},
|
||||
composition: null,
|
||||
};
|
||||
await makeFetch(
|
||||
"POST",
|
||||
"/api/1.0/person/household/members/move.json",
|
||||
member,
|
||||
);
|
||||
try {
|
||||
const _response = await makeFetch(
|
||||
"POST",
|
||||
`/api/1.0/person/household/${responseHousehold.id}/address.json`,
|
||||
address,
|
||||
);
|
||||
console.log(_response);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
},
|
||||
} else if (type === "thirdparty") {
|
||||
const response: Result = await makeFetch(
|
||||
"POST",
|
||||
"/api/1.0/thirdparty/thirdparty.json",
|
||||
data,
|
||||
);
|
||||
newPriorSuggestion(response);
|
||||
if (onTheFly.value) onTheFly.value.closeModal();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.selected,
|
||||
(newSelected) => {
|
||||
search.selected = newSelected;
|
||||
},
|
||||
};
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.suggested,
|
||||
(newSuggested) => {
|
||||
search.suggested = newSuggested;
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
watch(
|
||||
() => modal,
|
||||
(val) => {
|
||||
showModal.value = val.value.showModal;
|
||||
modalDialogClass.value = val.value.modalDialogClass;
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
resetSearch,
|
||||
showModal,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@ -438,7 +450,6 @@ div.body-head {
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 1.2em 1.5em 1.2em 2.5em;
|
||||
//margin: 1em 0;
|
||||
}
|
||||
i {
|
||||
position: absolute;
|
||||
|
@ -3,87 +3,80 @@
|
||||
<label>
|
||||
<div>
|
||||
<input
|
||||
v-bind:type="type"
|
||||
:type="type"
|
||||
v-model="selected"
|
||||
name="item"
|
||||
v-bind:id="item"
|
||||
v-bind:value="setValueByType(item, type)"
|
||||
:id="item.key"
|
||||
:value="setValueByType(item, type)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<suggestion-person
|
||||
v-if="item.result.type === 'person'"
|
||||
v-bind:item="item"
|
||||
>
|
||||
</suggestion-person>
|
||||
:item="item"
|
||||
></suggestion-person>
|
||||
|
||||
<suggestion-third-party
|
||||
v-if="item.result.type === 'thirdparty'"
|
||||
@newPriorSuggestion="newPriorSuggestion"
|
||||
v-bind:item="item"
|
||||
>
|
||||
</suggestion-third-party>
|
||||
:item="item"
|
||||
></suggestion-third-party>
|
||||
|
||||
<suggestion-user v-if="item.result.type === 'user'" v-bind:item="item">
|
||||
</suggestion-user>
|
||||
<suggestion-user
|
||||
v-if="item.result.type === 'user'"
|
||||
:item="item"
|
||||
></suggestion-user>
|
||||
|
||||
<suggestion-user-group
|
||||
v-if="item.result.type === 'user_group'"
|
||||
v-bind:item="item"
|
||||
>
|
||||
></suggestion-user-group
|
||||
>
|
||||
:item="item"
|
||||
></suggestion-user-group>
|
||||
|
||||
<suggestion-household
|
||||
v-if="item.result.type === 'household'"
|
||||
v-bind:item="item"
|
||||
>
|
||||
</suggestion-household>
|
||||
: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";
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
|
||||
export default {
|
||||
name: "PersonSuggestion",
|
||||
components: {
|
||||
SuggestionPerson,
|
||||
SuggestionThirdParty,
|
||||
SuggestionUser,
|
||||
SuggestionHousehold,
|
||||
SuggestionUserGroup,
|
||||
},
|
||||
props: ["item", "search", "type"],
|
||||
emits: ["updateSelected", "newPriorSuggestion"],
|
||||
computed: {
|
||||
selected: {
|
||||
set(value) {
|
||||
//console.log('value', value);
|
||||
this.$emit("updateSelected", value);
|
||||
},
|
||||
get() {
|
||||
return this.search.selected;
|
||||
},
|
||||
},
|
||||
isChecked() {
|
||||
return this.search.selected.indexOf(this.item) === -1 ? false : true;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setValueByType(value, type) {
|
||||
return type === "radio" ? [value] : value;
|
||||
},
|
||||
newPriorSuggestion(response) {
|
||||
this.$emit("newPriorSuggestion", response);
|
||||
},
|
||||
},
|
||||
};
|
||||
// Components
|
||||
import SuggestionPerson from "./TypePerson.vue";
|
||||
import SuggestionThirdParty from "./TypeThirdParty.vue";
|
||||
import SuggestionUser from "./TypeUser.vue";
|
||||
import SuggestionHousehold from "./TypeHousehold.vue";
|
||||
import SuggestionUserGroup from "./TypeUserGroup.vue";
|
||||
|
||||
// Types
|
||||
import { Result, Suggestion } from "ChillPersonAssets/types";
|
||||
|
||||
const props = defineProps<{
|
||||
item: Suggestion;
|
||||
search: { selected: Suggestion[] };
|
||||
type: string;
|
||||
}>();
|
||||
const emit = defineEmits(["updateSelected", "newPriorSuggestion"]);
|
||||
|
||||
// v-model for selected
|
||||
const selected = computed({
|
||||
get: () => props.search.selected,
|
||||
set: (value) => emit("updateSelected", value),
|
||||
});
|
||||
|
||||
const isChecked = computed(
|
||||
() => props.search.selected.indexOf(props.item) !== -1,
|
||||
);
|
||||
|
||||
function setValueByType(value: Suggestion, type: string) {
|
||||
return type === "radio" ? [value] : value;
|
||||
}
|
||||
|
||||
function newPriorSuggestion(response: Result) {
|
||||
emit("newPriorSuggestion", response);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -1,26 +1,25 @@
|
||||
<template>
|
||||
<div class="container household">
|
||||
<household-render-box
|
||||
<HouseholdRenderBox
|
||||
:household="item.result"
|
||||
:is-address-multiline="false"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="right_actions">
|
||||
<badge-entity :entity="item.result" :options="{ displayLong: true }" />
|
||||
<BadgeEntity :entity="item.result" :options="{ displayLong: true }" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from "vue";
|
||||
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
|
||||
import HouseholdRenderBox from "ChillPersonAssets/vuejs/_components/Entity/HouseholdRenderBox.vue";
|
||||
import { Suggestion } from "ChillPersonAssets/types";
|
||||
|
||||
export default {
|
||||
name: "SuggestionHousehold",
|
||||
components: {
|
||||
BadgeEntity,
|
||||
HouseholdRenderBox,
|
||||
},
|
||||
props: ["item"],
|
||||
};
|
||||
interface TypeHouseholdProps {
|
||||
item: Suggestion;
|
||||
}
|
||||
|
||||
defineProps<TypeHouseholdProps>();
|
||||
</script>
|
||||
|
@ -4,11 +4,11 @@
|
||||
<person-text :person="item.result" />
|
||||
</span>
|
||||
<span class="birthday" v-if="hasBirthdate">
|
||||
{{ $d(item.result.birthdate.datetime, "short") }}
|
||||
{{ formatDate(item.result.birthdate?.datetime, "short") }}
|
||||
</span>
|
||||
<span class="location" v-if="hasAddress">
|
||||
{{ item.result.current_household_address.text }} -
|
||||
{{ item.result.current_household_address.postcode.name }}
|
||||
{{ item.result.current_household_address?.text }} -
|
||||
{{ item.result.current_household_address?.postcode?.name }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@ -18,26 +18,38 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineProps } from "vue";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
|
||||
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
|
||||
|
||||
export default {
|
||||
name: "SuggestionPerson",
|
||||
components: {
|
||||
OnTheFly,
|
||||
BadgeEntity,
|
||||
PersonText,
|
||||
},
|
||||
props: ["item"],
|
||||
computed: {
|
||||
hasBirthdate() {
|
||||
return this.item.result.birthdate !== null;
|
||||
},
|
||||
hasAddress() {
|
||||
return this.item.result.current_household_address !== null;
|
||||
},
|
||||
},
|
||||
};
|
||||
function formatDate(dateString: string | undefined, format: string) {
|
||||
if (!dateString) return "";
|
||||
// Use Intl.DateTimeFormat or your preferred formatting here
|
||||
const date = new Date(dateString);
|
||||
if (format === "short") {
|
||||
return date.toLocaleDateString();
|
||||
}
|
||||
return date.toString();
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
item: {
|
||||
result: {
|
||||
id: number | string;
|
||||
birthdate: { datetime: string } | null;
|
||||
current_household_address: {
|
||||
text: string;
|
||||
postcode: { name: string };
|
||||
} | null;
|
||||
// add other fields as needed
|
||||
};
|
||||
};
|
||||
}>();
|
||||
|
||||
const hasBirthdate = computed(() => props.item.result.birthdate !== null);
|
||||
const hasAddress = computed(
|
||||
() => props.item.result.current_household_address !== null,
|
||||
);
|
||||
</script>
|
||||
|
@ -7,13 +7,13 @@
|
||||
<span class="name"> {{ item.result.text }} </span>
|
||||
<span class="location">
|
||||
<template v-if="hasAddress">
|
||||
{{ getAddress.text }} -
|
||||
{{ getAddress.postcode.name }}
|
||||
{{ getAddress?.text }} -
|
||||
{{ getAddress?.postcode?.name }}
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="tpartyparent" v-if="hasParent">
|
||||
<span class="name"> > {{ item.result.parent.text }} </span>
|
||||
<span class="name"> > {{ item.result.parent?.text }} </span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -30,11 +30,72 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from "vue";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
|
||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
||||
import { useToast } from "vue-toast-notification";
|
||||
import { ThirdParty } from "ChillMainAssets/types";
|
||||
import { Result, Suggestion } from "ChillPersonAssets/types";
|
||||
|
||||
interface TypeThirdPartyProps {
|
||||
item: Suggestion;
|
||||
}
|
||||
|
||||
const props = defineProps<TypeThirdPartyProps>();
|
||||
|
||||
const emit = defineEmits<(e: "newPriorSuggestion", payload: unknown) => void>();
|
||||
|
||||
const onTheFly = ref<InstanceType<typeof OnTheFly> | null>(null);
|
||||
const toast = useToast();
|
||||
|
||||
const hasAddress = computed(() => {
|
||||
if (props.item.result.address !== null) {
|
||||
return true;
|
||||
}
|
||||
if (props.item.result.parent !== null) {
|
||||
if (props.item.result.parent) {
|
||||
return props.item.result.parent.address !== null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const hasParent = computed(() => {
|
||||
return props.item.result.parent !== null;
|
||||
});
|
||||
|
||||
const getAddress = computed(() => {
|
||||
if (props.item.result.address !== null) {
|
||||
return props.item.result.address;
|
||||
}
|
||||
if (props.item.result.parent && props.item.result.parent.address !== null) {
|
||||
return props.item.result.parent.address;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
function saveFormOnTheFly({ data }: { data: ThirdParty }) {
|
||||
makeFetch("POST", "/api/1.0/thirdparty/thirdparty.json", data)
|
||||
.then((response: unknown) => {
|
||||
const result = response as Result;
|
||||
emit("newPriorSuggestion", result);
|
||||
if (onTheFly.value) onTheFly.value.closeModal();
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
const errorResponse = error as { name: string; violations: string[] };
|
||||
if (errorResponse.name === "ValidationException") {
|
||||
for (let v of errorResponse.violations) {
|
||||
if (toast) toast.open({ message: v });
|
||||
}
|
||||
} else {
|
||||
if (toast) toast.open({ message: "An error occurred" });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// i18n config (if needed elsewhere)
|
||||
const i18n = {
|
||||
messages: {
|
||||
fr: {
|
||||
@ -46,59 +107,9 @@ const i18n = {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "SuggestionThirdParty",
|
||||
components: {
|
||||
OnTheFly,
|
||||
BadgeEntity,
|
||||
},
|
||||
props: ["item"],
|
||||
emits: ["newPriorSuggestion"],
|
||||
defineExpose({
|
||||
i18n,
|
||||
computed: {
|
||||
hasAddress() {
|
||||
if (this.$props.item.result.address !== null) {
|
||||
return true;
|
||||
}
|
||||
if (this.$props.item.result.parent !== null) {
|
||||
return this.$props.item.result.parent.address !== null;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
hasParent() {
|
||||
return this.$props.item.result.parent !== null;
|
||||
},
|
||||
getAddress() {
|
||||
if (this.$props.item.result.address !== null) {
|
||||
return this.$props.item.result.address;
|
||||
}
|
||||
if (this.$props.item.result.parent.address !== null) {
|
||||
return this.$props.item.result.parent.address;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
saveFormOnTheFly({ data }) {
|
||||
makeFetch("POST", "/api/1.0/thirdparty/thirdparty.json", data)
|
||||
.then((response) => {
|
||||
this.$emit("newPriorSuggestion", response);
|
||||
this.$refs.onTheFly.closeModal();
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.name === "ValidationException") {
|
||||
for (let v of error.violations) {
|
||||
this.$toast.open({ message: v });
|
||||
}
|
||||
} else {
|
||||
this.$toast.open({ message: "An error occurred" });
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -1,31 +1,31 @@
|
||||
<template>
|
||||
<div class="container usercontainer">
|
||||
<div class="user-identification">
|
||||
<user-render-box-badge :user="item.result" />
|
||||
<UserRenderBoxBadge :user="item.result" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="right_actions">
|
||||
<badge-entity :entity="item.result" :options="{ displayLong: true }" />
|
||||
<BadgeEntity :entity="item.result" :options="{ displayLong: true }" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineProps } from "vue";
|
||||
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
|
||||
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
|
||||
import { Suggestion } from "ChillPersonAssets/types";
|
||||
|
||||
export default {
|
||||
name: "SuggestionUser",
|
||||
components: {
|
||||
UserRenderBoxBadge,
|
||||
BadgeEntity,
|
||||
},
|
||||
props: ["item"],
|
||||
computed: {
|
||||
hasParent() {
|
||||
return this.$props.item.result.parent !== null;
|
||||
},
|
||||
},
|
||||
};
|
||||
interface TypeUserProps {
|
||||
item: Suggestion;
|
||||
}
|
||||
|
||||
const props = defineProps<TypeUserProps>();
|
||||
|
||||
const hasParent = computed(() => props.item.result.parent !== null);
|
||||
|
||||
defineExpose({
|
||||
hasParent,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -1,25 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
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";
|
||||
|
||||
interface TypeUserGroupProps {
|
||||
item: ResultItem<UserGroup>;
|
||||
}
|
||||
|
||||
const props = defineProps<TypeUserGroupProps>();
|
||||
</script>
|
||||
|
||||
<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 as UserGroup" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="right_actions">
|
||||
@ -27,4 +9,16 @@ const props = defineProps<TypeUserGroupProps>();
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { UserGroup } from "../../../../../../ChillMainBundle/Resources/public/types";
|
||||
import UserGroupRenderBox from "ChillMainAssets/vuejs/_components/Entity/UserGroupRenderBox.vue";
|
||||
import { Suggestion } from "ChillPersonAssets/types";
|
||||
|
||||
interface TypeUserGroupProps {
|
||||
item: Suggestion;
|
||||
}
|
||||
|
||||
const props = defineProps<TypeUserGroupProps>();
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
@ -5,11 +5,11 @@
|
||||
<!-- identifier -->
|
||||
<div v-if="isHouseholdNew()" class="h4">
|
||||
<i class="fa fa-home" />
|
||||
{{ $t("new_household") }}
|
||||
{{ trans(RENDERBOX_NEW_HOUSEHOLD) }}
|
||||
</div>
|
||||
<div v-else class="h4">
|
||||
<i class="fa fa-home" />
|
||||
{{ $t("household_number", { number: household.id }) }}
|
||||
{{ trans(RENDERBOX_HOUSEHOLD_NUMBER, { number: household.id }) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-col">
|
||||
@ -18,7 +18,7 @@
|
||||
<li
|
||||
v-if="hasCurrentMembers"
|
||||
class="members"
|
||||
:title="$t('current_members')"
|
||||
:title="trans(RENDERBOX_CURRENT_MEMBERS)"
|
||||
>
|
||||
<span
|
||||
v-for="m in currentMembers()"
|
||||
@ -42,9 +42,9 @@
|
||||
</person-render-box>
|
||||
</span>
|
||||
</li>
|
||||
<li v-else class="members" :title="$t('current_members')">
|
||||
<li v-else class="members" :title="trans(RENDERBOX_CURRENT_MEMBERS)">
|
||||
<p class="chill-no-data-statement">
|
||||
{{ $t("no_members_yet") }}
|
||||
{{ trans(RENDERBOX_NO_MEMBERS_YET) }}
|
||||
</p>
|
||||
</li>
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
</li>
|
||||
<li v-else>
|
||||
<span class="chill-no-data-statement">{{
|
||||
$t("no_current_address")
|
||||
trans(RENDERBOX_NO_CURRENT_ADDRESS)
|
||||
}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
@ -65,89 +65,82 @@
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
import PersonRenderBox from "ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue";
|
||||
import AddressRenderBox from "ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue";
|
||||
import {
|
||||
trans,
|
||||
RENDERBOX_NEW_HOUSEHOLD,
|
||||
RENDERBOX_HOUSEHOLD_NUMBER,
|
||||
RENDERBOX_CURRENT_MEMBERS,
|
||||
RENDERBOX_NO_MEMBERS_YET,
|
||||
RENDERBOX_NO_CURRENT_ADDRESS,
|
||||
} from "translator";
|
||||
|
||||
const i18n = {
|
||||
messages: {
|
||||
fr: {
|
||||
household_number: "Ménage n°{number}",
|
||||
current_members: "Membres actuels",
|
||||
no_current_address: "Sans adresse actuellement",
|
||||
new_household: "Nouveau ménage",
|
||||
no_members_yet: "Aucun membre actuellement",
|
||||
holder: "titulaire",
|
||||
},
|
||||
},
|
||||
};
|
||||
const props = defineProps({
|
||||
household: { type: Object, required: true },
|
||||
isAddressMultiline: { type: Boolean, default: false },
|
||||
});
|
||||
|
||||
export default {
|
||||
name: "HouseholdRenderBox",
|
||||
props: ["household", "isAddressMultiline"],
|
||||
components: {
|
||||
PersonRenderBox,
|
||||
AddressRenderBox,
|
||||
},
|
||||
i18n,
|
||||
computed: {
|
||||
isMultiline() {
|
||||
return typeof this.isAddressMultiline !== "undefined"
|
||||
? this.isAddressMultiline
|
||||
: false;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
hasCurrentMembers() {
|
||||
return this.household.current_members_id.length > 0;
|
||||
},
|
||||
currentMembers() {
|
||||
let members = this.household.members
|
||||
.filter((m) => this.household.current_members_id.includes(m.id))
|
||||
.sort((a, b) => {
|
||||
const orderA = a.position ? a.position.ordering : 0;
|
||||
const orderB = b.position ? b.position.ordering : 0;
|
||||
const isMultiline = computed(() =>
|
||||
typeof props.isAddressMultiline !== "undefined"
|
||||
? props.isAddressMultiline
|
||||
: false,
|
||||
);
|
||||
|
||||
if (orderA < orderB) {
|
||||
return -1;
|
||||
}
|
||||
if (orderA > orderB) {
|
||||
return 1;
|
||||
}
|
||||
if (a.holder && !b.holder) {
|
||||
return -1;
|
||||
}
|
||||
if (!a.holder && b.holder) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
function hasCurrentMembers() {
|
||||
return props.household.current_members_id.length > 0;
|
||||
}
|
||||
|
||||
if (this.household.new_members !== undefined) {
|
||||
this.household.new_members
|
||||
.map((m) => {
|
||||
m.is_new = true;
|
||||
return m;
|
||||
})
|
||||
.forEach((m) => {
|
||||
members.push(m);
|
||||
});
|
||||
function currentMembers() {
|
||||
let members = props.household.members
|
||||
.filter((m) => props.household.current_members_id.includes(m.id))
|
||||
.sort((a, b) => {
|
||||
const orderA = a.position ? a.position.ordering : 0;
|
||||
const orderB = b.position ? b.position.ordering : 0;
|
||||
|
||||
if (orderA < orderB) {
|
||||
return -1;
|
||||
}
|
||||
if (orderA > orderB) {
|
||||
return 1;
|
||||
}
|
||||
if (a.holder && !b.holder) {
|
||||
return -1;
|
||||
}
|
||||
if (!a.holder && b.holder) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
return members;
|
||||
},
|
||||
currentMembersLength() {
|
||||
return this.household.current_members_id.length;
|
||||
},
|
||||
isHouseholdNew() {
|
||||
return !Number.isInteger(this.household.id);
|
||||
},
|
||||
hasAddress() {
|
||||
return this.household.current_address !== null;
|
||||
},
|
||||
},
|
||||
};
|
||||
if (props.household.new_members !== undefined) {
|
||||
props.household.new_members
|
||||
.map((m) => {
|
||||
m.is_new = true;
|
||||
return m;
|
||||
})
|
||||
.forEach((m) => {
|
||||
members.push(m);
|
||||
});
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
function currentMembersLength() {
|
||||
return props.household.current_members_id.length;
|
||||
}
|
||||
|
||||
function isHouseholdNew() {
|
||||
return !Number.isInteger(props.household.id);
|
||||
}
|
||||
|
||||
function hasAddress() {
|
||||
return props.household.current_address !== null;
|
||||
}
|
||||
defineExpose(currentMembersLength);
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -23,7 +23,7 @@
|
||||
</a>
|
||||
|
||||
<!-- use person-text here to avoid code duplication ? TODO -->
|
||||
<span class="firstname">{{ person.firstName }}</span>
|
||||
<span class="firstname">{{ person.firstName + " " }}</span>
|
||||
<span class="lastname">{{ person.lastName }}</span>
|
||||
<span v-if="person.suffixText" class="suffixtext"
|
||||
> {{ person.suffixText }}</span
|
||||
@ -63,13 +63,11 @@
|
||||
:title="birthdate"
|
||||
>
|
||||
{{
|
||||
$t(
|
||||
person.gender
|
||||
? `renderbox.birthday.${person.gender.genderTranslation}`
|
||||
: "renderbox.birthday.neutral",
|
||||
) +
|
||||
trans(birthdateTranslation) +
|
||||
" " +
|
||||
$d(birthdate, "text")
|
||||
new Intl.DateTimeFormat("fr-FR", {
|
||||
dateStyle: "long",
|
||||
}).format(birthdate)
|
||||
}}
|
||||
</time>
|
||||
|
||||
@ -78,7 +76,17 @@
|
||||
:datetime="person.deathdate"
|
||||
:title="person.deathdate"
|
||||
>
|
||||
{{ $d(birthdate) }} - {{ $d(deathdate) }}
|
||||
{{
|
||||
new Intl.DateTimeFormat("fr-FR", {
|
||||
dateStyle: "long",
|
||||
}).format(birthdate)
|
||||
}}
|
||||
-
|
||||
{{
|
||||
new Intl.DateTimeFormat("fr-FR", {
|
||||
dateStyle: "long",
|
||||
}).format(deathdate)
|
||||
}}
|
||||
</time>
|
||||
|
||||
<time
|
||||
@ -86,12 +94,18 @@
|
||||
:datetime="person.deathdate"
|
||||
:title="person.deathdate"
|
||||
>
|
||||
{{ $t("renderbox.deathdate") + " " + deathdate }}
|
||||
{{
|
||||
trans(RENDERBOX_DEATHDATE) +
|
||||
" " +
|
||||
new Intl.DateTimeFormat("fr-FR", {
|
||||
dateStyle: "long",
|
||||
}).format(deathdate)
|
||||
}}
|
||||
</time>
|
||||
|
||||
<span v-if="options.addAge && person.birthdate" class="age">{{
|
||||
$tc("renderbox.years_old", person.age)
|
||||
}}</span>
|
||||
<span v-if="options.addAge && person.birthdate" class="age">
|
||||
({{ trans(RENDERBOX_YEARS_OLD, { n: person.age }) }})
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -111,13 +125,13 @@
|
||||
:is-multiline="isMultiline"
|
||||
/>
|
||||
<p v-else class="chill-no-data-statement">
|
||||
{{ $t("renderbox.household_without_address") }}
|
||||
{{ trans(RENDERBOX_HOUSEHOLD_WITHOUT_ADDRESS) }}
|
||||
</p>
|
||||
<a
|
||||
v-if="options.addHouseholdLink === true"
|
||||
:href="getCurrentHouseholdUrl"
|
||||
:title="
|
||||
$t('persons_associated.show_household_number', {
|
||||
trans(PERSONS_ASSOCIATED_SHOW_HOUSEHOLD_NUMBER, {
|
||||
id: person.current_household_id,
|
||||
})
|
||||
"
|
||||
@ -125,14 +139,14 @@
|
||||
<span class="badge rounded-pill bg-chill-beige">
|
||||
<i
|
||||
class="fa fa-fw fa-home"
|
||||
/><!--{{ $t('persons_associated.show_household') }}-->
|
||||
/><!--{{ trans(PERSONS_ASSOCIATED_SHOW_HOUSEHOLD) }}-->
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li v-else-if="options.addNoData">
|
||||
<i class="fa fa-li fa-map-marker" />
|
||||
<p class="chill-no-data-statement">
|
||||
{{ $t("renderbox.no_data") }}
|
||||
{{ trans(RENDERBOX_NO_DATA) }}
|
||||
</p>
|
||||
</li>
|
||||
|
||||
@ -148,9 +162,9 @@
|
||||
>
|
||||
<i class="fa fa-li fa-map-marker" />
|
||||
<div v-if="addr.address">
|
||||
<span class="item-key"
|
||||
>{{ $t("renderbox.residential_address") }}:</span
|
||||
>
|
||||
<span class="item-key">
|
||||
{{ trans(RENDERBOX_RESIDENTIAL_ADDRESS) }}:
|
||||
</span>
|
||||
<div style="margin-top: -1em">
|
||||
<address-render-box
|
||||
:address="addr.address"
|
||||
@ -159,7 +173,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="addr.hostPerson" class="mt-3">
|
||||
<p>{{ $t("renderbox.located_at") }}:</p>
|
||||
<p>{{ trans(RENDERBOX_LOCATED_AT) }}:</p>
|
||||
<span class="chill-entity entity-person badge-person">
|
||||
<person-text
|
||||
v-if="addr.hostPerson"
|
||||
@ -173,7 +187,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="addr.hostThirdParty" class="mt-3">
|
||||
<p>{{ $t("renderbox.located_at") }}:</p>
|
||||
<p>{{ trans(RENDERBOX_LOCATED_AT) }}:</p>
|
||||
<span class="chill-entity entity-person badge-thirdparty">
|
||||
<third-party-text
|
||||
v-if="addr.hostThirdParty"
|
||||
@ -196,32 +210,32 @@
|
||||
<li v-else-if="options.addNoData">
|
||||
<i class="fa fa-li fa-envelope-o" />
|
||||
<p class="chill-no-data-statement">
|
||||
{{ $t("renderbox.no_data") }}
|
||||
{{ trans(RENDERBOX_NO_DATA) }}
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li v-if="person.mobilenumber">
|
||||
<i class="fa fa-li fa-mobile" />
|
||||
<a :href="'tel: ' + person.mobilenumber">{{
|
||||
person.mobilenumber
|
||||
}}</a>
|
||||
<a :href="'tel: ' + person.mobilenumber">
|
||||
{{ person.mobilenumber }}
|
||||
</a>
|
||||
</li>
|
||||
<li v-else-if="options.addNoData">
|
||||
<i class="fa fa-li fa-mobile" />
|
||||
<p class="chill-no-data-statement">
|
||||
{{ $t("renderbox.no_data") }}
|
||||
{{ trans(RENDERBOX_NO_DATA) }}
|
||||
</p>
|
||||
</li>
|
||||
<li v-if="person.phonenumber">
|
||||
<i class="fa fa-li fa-phone" />
|
||||
<a :href="'tel: ' + person.phonenumber">{{
|
||||
person.phonenumber
|
||||
}}</a>
|
||||
<a :href="'tel: ' + person.phonenumber">
|
||||
{{ person.phonenumber }}
|
||||
</a>
|
||||
</li>
|
||||
<li v-else-if="options.addNoData">
|
||||
<i class="fa fa-li fa-phone" />
|
||||
<p class="chill-no-data-statement">
|
||||
{{ $t("renderbox.no_data") }}
|
||||
{{ trans(RENDERBOX_NO_DATA) }}
|
||||
</p>
|
||||
</li>
|
||||
|
||||
@ -240,7 +254,7 @@
|
||||
<li v-else-if="options.addNoData">
|
||||
<i class="fa fa-li fa-long-arrow-right" />
|
||||
<p class="chill-no-data-statement">
|
||||
{{ $t("renderbox.no_data") }}
|
||||
{{ trans(RENDERBOX_NO_DATA) }}
|
||||
</p>
|
||||
</li>
|
||||
<slot name="custom-zone" />
|
||||
@ -262,7 +276,7 @@
|
||||
<span
|
||||
v-if="options.isHolder"
|
||||
class="fa-stack fa-holder"
|
||||
:title="$t('renderbox.holder')"
|
||||
:title="trans(RENDERBOX_HOLDER)"
|
||||
>
|
||||
<i class="fa fa-circle fa-stack-1x text-success" />
|
||||
<i class="fa fa-stack-1x">T</i>
|
||||
@ -274,7 +288,7 @@
|
||||
<span
|
||||
v-if="options.isHolder"
|
||||
class="fa-stack fa-holder"
|
||||
:title="$t('renderbox.holder')"
|
||||
:title="trans(RENDERBOX_HOLDER)"
|
||||
>
|
||||
<i class="fa fa-circle fa-stack-1x text-success" />
|
||||
<i class="fa fa-stack-1x">T</i>
|
||||
@ -285,131 +299,120 @@
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
import { ISOToDate } from "ChillMainAssets/chill/js/date";
|
||||
import AddressRenderBox from "ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue";
|
||||
import GenderIconRenderBox from "ChillMainAssets/vuejs/_components/Entity/GenderIconRenderBox.vue";
|
||||
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
|
||||
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
|
||||
import ThirdPartyText from "ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyText.vue";
|
||||
import {
|
||||
trans,
|
||||
RENDERBOX_HOLDER,
|
||||
RENDERBOX_NO_DATA,
|
||||
RENDERBOX_DEATHDATE,
|
||||
RENDERBOX_HOUSEHOLD_WITHOUT_ADDRESS,
|
||||
RENDERBOX_RESIDENTIAL_ADDRESS,
|
||||
RENDERBOX_LOCATED_AT,
|
||||
RENDERBOX_BIRTHDAY_MAN,
|
||||
RENDERBOX_BIRTHDAY_WOMAN,
|
||||
RENDERBOX_BIRTHDAY_UNKNOWN,
|
||||
RENDERBOX_BIRTHDAY_NEUTRAL,
|
||||
PERSONS_ASSOCIATED_SHOW_HOUSEHOLD_NUMBER,
|
||||
RENDERBOX_YEARS_OLD,
|
||||
} from "translator";
|
||||
|
||||
export default {
|
||||
name: "PersonRenderBox",
|
||||
components: {
|
||||
AddressRenderBox,
|
||||
GenderIconRenderBox,
|
||||
BadgeEntity,
|
||||
PersonText,
|
||||
ThirdPartyText,
|
||||
const props = defineProps({
|
||||
person: {
|
||||
required: true,
|
||||
},
|
||||
props: {
|
||||
person: {
|
||||
required: true,
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
required: false,
|
||||
},
|
||||
render: {
|
||||
type: String,
|
||||
},
|
||||
returnPath: {
|
||||
type: String,
|
||||
},
|
||||
showResidentialAddresses: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
required: false,
|
||||
},
|
||||
computed: {
|
||||
isMultiline: function () {
|
||||
if (this.options.isMultiline) {
|
||||
return this.options.isMultiline;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
birthdate: function () {
|
||||
if (
|
||||
this.person.birthdate !== null ||
|
||||
this.person.birthdate === "undefined"
|
||||
) {
|
||||
return ISOToDate(this.person.birthdate.datetime);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
deathdate: function () {
|
||||
if (
|
||||
this.person.deathdate !== null ||
|
||||
this.person.birthdate === "undefined"
|
||||
) {
|
||||
return new Date(this.person.deathdate.datetime);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
altNameLabel: function () {
|
||||
let altNameLabel = "";
|
||||
this.person.altNames.forEach(
|
||||
(altName) => (altNameLabel += altName.label),
|
||||
);
|
||||
return altNameLabel;
|
||||
},
|
||||
altNameKey: function () {
|
||||
let altNameKey = "";
|
||||
this.person.altNames.forEach((altName) => (altNameKey += altName.key));
|
||||
return altNameKey;
|
||||
},
|
||||
getUrl: function () {
|
||||
return `/fr/person/${this.person.id}/general`;
|
||||
},
|
||||
getCurrentHouseholdUrl: function () {
|
||||
let returnPath = this.returnPath ? `?returnPath=${this.returnPath}` : ``;
|
||||
return `/fr/person/household/${this.person.current_household_id}/summary${returnPath}`;
|
||||
},
|
||||
render: {
|
||||
type: String,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
returnPath: {
|
||||
type: String,
|
||||
},
|
||||
showResidentialAddresses: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "ChillMainAssets/module/bootstrap/shared";
|
||||
@import "ChillPersonAssets/chill/scss/mixins";
|
||||
@import "ChillMainAssets/chill/scss/chill_variables";
|
||||
|
||||
.lastname:before {
|
||||
content: " ";
|
||||
}
|
||||
|
||||
div.flex-table {
|
||||
div.item-bloc {
|
||||
div.item-row {
|
||||
div.item-col:first-child {
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
div.item-col:first-child {
|
||||
width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
div.item-col:last-child {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
const birthdateTranslation = computed(() => {
|
||||
if (props.person.gender) {
|
||||
const { genderTranslation } = props.person.gender;
|
||||
switch (genderTranslation) {
|
||||
case "man":
|
||||
return RENDERBOX_BIRTHDAY_MAN;
|
||||
case "woman":
|
||||
return RENDERBOX_BIRTHDAY_WOMAN;
|
||||
case "neutral":
|
||||
return RENDERBOX_BIRTHDAY_NEUTRAL;
|
||||
case "unknown":
|
||||
return RENDERBOX_BIRTHDAY_UNKNOWN;
|
||||
default:
|
||||
return RENDERBOX_BIRTHDAY_UNKNOWN;
|
||||
}
|
||||
} else {
|
||||
return RENDERBOX_BIRTHDAY_UNKNOWN;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
.age {
|
||||
margin-left: 0.5em;
|
||||
const isMultiline = computed(() => {
|
||||
return props.options?.isMultiline || false;
|
||||
});
|
||||
|
||||
&:before {
|
||||
content: "(";
|
||||
const birthdate = computed(() => {
|
||||
if (
|
||||
props.person.birthdate !== null &&
|
||||
props.person.birthdate !== undefined &&
|
||||
props.person.birthdate.datetime
|
||||
) {
|
||||
return ISOToDate(props.person.birthdate.datetime);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
&:after {
|
||||
content: ")";
|
||||
const deathdate = computed(() => {
|
||||
if (
|
||||
props.person.deathdate !== null &&
|
||||
props.person.deathdate !== undefined &&
|
||||
props.person.deathdate.datetime
|
||||
) {
|
||||
return new Date(props.person.deathdate.datetime);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
</style>
|
||||
});
|
||||
|
||||
const altNameLabel = computed(() => {
|
||||
let altNameLabel = "";
|
||||
(props.person.altNames || []).forEach(
|
||||
(altName) => (altNameLabel += altName.label),
|
||||
);
|
||||
return altNameLabel;
|
||||
});
|
||||
|
||||
const altNameKey = computed(() => {
|
||||
let altNameKey = "";
|
||||
(props.person.altNames || []).forEach(
|
||||
(altName) => (altNameKey += altName.key),
|
||||
);
|
||||
return altNameKey;
|
||||
});
|
||||
|
||||
const getUrl = computed(() => {
|
||||
return `/fr/person/${props.person.id}/general`;
|
||||
});
|
||||
|
||||
const getCurrentHouseholdUrl = computed(() => {
|
||||
let returnPath = props.returnPath ? `?returnPath=${props.returnPath}` : ``;
|
||||
return `/fr/person/household/${props.person.current_household_id}/summary${returnPath}`;
|
||||
});
|
||||
</script>
|
||||
|
@ -2,65 +2,65 @@
|
||||
<span v-if="isCut">{{ cutText }}</span>
|
||||
<span v-else class="person-text">
|
||||
<span class="firstname">{{ person.firstName }}</span>
|
||||
<!-- display: inline -->
|
||||
<span class="lastname"> {{ person.lastName }}</span>
|
||||
<span v-if="person.altNames && person.altNames.length > 0" class="altnames">
|
||||
<!-- display: inline -->
|
||||
<span :class="'altname altname-' + altNameKey"
|
||||
> ({{ altNameLabel }})</span
|
||||
>
|
||||
</span>
|
||||
<!-- display: inline -->
|
||||
<span v-if="person.suffixText" class="suffixtext"
|
||||
> {{ person.suffixText }}</span
|
||||
>
|
||||
<!-- display: inline -->
|
||||
<span
|
||||
class="age"
|
||||
v-if="
|
||||
this.addAge && person.birthdate !== null && person.deathdate === null
|
||||
"
|
||||
> {{ $tc("renderbox.years_old", person.age) }}</span
|
||||
v-if="addAge && person.birthdate !== null && person.deathdate === null"
|
||||
> {{ trans(RENDERBOX_YEARS_OLD, person.age) }}</span
|
||||
>
|
||||
<span v-else-if="this.addAge && person.deathdate !== null"> (‡)</span>
|
||||
<span v-else-if="addAge && person.deathdate !== null"> (‡)</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "PersonText",
|
||||
props: {
|
||||
person: {
|
||||
required: true,
|
||||
},
|
||||
isCut: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
addAge: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
altNameLabel: function () {
|
||||
let altNameLabel = "";
|
||||
this.person.altNames.forEach(
|
||||
(altName) => (altNameLabel += altName.label),
|
||||
);
|
||||
return altNameLabel;
|
||||
},
|
||||
altNameKey: function () {
|
||||
let altNameKey = "";
|
||||
this.person.altNames.forEach((altName) => (altNameKey += altName.key));
|
||||
return altNameKey;
|
||||
},
|
||||
cutText: function () {
|
||||
let more = this.person.text.length > 15 ? "…" : "";
|
||||
return this.person.text.slice(0, 15) + more;
|
||||
},
|
||||
},
|
||||
};
|
||||
<script lang="ts" setup>
|
||||
import { computed, toRefs } from "vue";
|
||||
import { trans, RENDERBOX_YEARS_OLD } from "translator";
|
||||
|
||||
interface AltName {
|
||||
label: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
interface Person {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
altNames: AltName[];
|
||||
suffixText?: string;
|
||||
birthdate: string | null;
|
||||
deathdate: string | null;
|
||||
age: number;
|
||||
text: string;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
person: Person;
|
||||
isCut?: boolean;
|
||||
addAge?: boolean;
|
||||
}>();
|
||||
|
||||
const { person, isCut = false, addAge = true } = toRefs(props);
|
||||
|
||||
const altNameLabel = computed(() => {
|
||||
if (!person.value.altNames) return "";
|
||||
return person.value.altNames.map((a: AltName) => a.label).join("");
|
||||
});
|
||||
|
||||
const altNameKey = computed(() => {
|
||||
if (!person.value.altNames) return "";
|
||||
return person.value.altNames.map((a: AltName) => a.key).join("");
|
||||
});
|
||||
|
||||
const cutText = computed(() => {
|
||||
if (!person.value.text) return "";
|
||||
const more = person.value.text.length > 15 ? "…" : "";
|
||||
return person.value.text.slice(0, 15) + more;
|
||||
});
|
||||
</script>
|
||||
|
@ -17,7 +17,7 @@
|
||||
isMultiline: true,
|
||||
}"
|
||||
:show-residential-addresses="true"
|
||||
></person-render-box>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -27,10 +27,10 @@
|
||||
class="form-control form-control-lg"
|
||||
id="lastname"
|
||||
v-model="lastName"
|
||||
:placeholder="$t('person.lastname')"
|
||||
:placeholder="trans(PERSON_MESSAGES_PERSON_LASTNAME)"
|
||||
@change="checkErrors"
|
||||
/>
|
||||
<label for="lastname">{{ $t("person.lastname") }}</label>
|
||||
<label for="lastname">{{ trans(PERSON_MESSAGES_PERSON_LASTNAME) }}</label>
|
||||
</div>
|
||||
|
||||
<div v-if="queryItems">
|
||||
@ -50,10 +50,12 @@
|
||||
class="form-control form-control-lg"
|
||||
id="firstname"
|
||||
v-model="firstName"
|
||||
:placeholder="$t('person.firstname')"
|
||||
:placeholder="trans(PERSON_MESSAGES_PERSON_FIRSTNAME)"
|
||||
@change="checkErrors"
|
||||
/>
|
||||
<label for="firstname">{{ $t("person.firstname") }}</label>
|
||||
<label for="firstname">{{
|
||||
trans(PERSON_MESSAGES_PERSON_FIRSTNAME)
|
||||
}}</label>
|
||||
</div>
|
||||
|
||||
<div v-if="queryItems">
|
||||
@ -86,12 +88,14 @@
|
||||
-->
|
||||
<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>
|
||||
<option selected disabled>
|
||||
{{ trans(PERSON_MESSAGES_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>{{ trans(PERSON_MESSAGES_PERSON_GENDER_TITLE) }}</label>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@ -99,12 +103,14 @@
|
||||
v-if="showCenters && config.centers.length > 1"
|
||||
>
|
||||
<select class="form-select form-select-lg" id="center" v-model="center">
|
||||
<option selected disabled>{{ $t("person.center.placeholder") }}</option>
|
||||
<option selected disabled>
|
||||
{{ trans(PERSON_MESSAGES_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>{{ trans(PERSON_MESSAGES_PERSON_CENTER_TITLE) }}</label>
|
||||
</div>
|
||||
|
||||
<div class="form-floating mb-3">
|
||||
@ -114,64 +120,50 @@
|
||||
v-model="civility"
|
||||
>
|
||||
<option selected disabled>
|
||||
{{ $t("person.civility.placeholder") }}
|
||||
{{ trans(PERSON_MESSAGES_PERSON_CIVILITY_PLACEHOLDER) }}
|
||||
</option>
|
||||
<option v-for="c in config.civilities" :value="c.id" :key="c.id">
|
||||
{{ localizeString(c.name) }}
|
||||
</option>
|
||||
</select>
|
||||
<label>{{ $t("person.civility.title") }}</label>
|
||||
<label>{{ trans(PERSON_MESSAGES_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"
|
||||
class="form-control form-control-lg"
|
||||
id="chill_personbundle_person_birthdate"
|
||||
name="chill_personbundle_person[birthdate]"
|
||||
v-model="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>
|
||||
<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')"
|
||||
:placeholder="trans(PERSON_MESSAGES_PERSON_PHONENUMBER)"
|
||||
:aria-label="trans(PERSON_MESSAGES_PERSON_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>
|
||||
<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')"
|
||||
:placeholder="trans(PERSON_MESSAGES_PERSON_MOBILENUMBER)"
|
||||
:aria-label="trans(PERSON_MESSAGES_PERSON_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>
|
||||
<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')"
|
||||
:placeholder="trans(PERSON_MESSAGES_PERSON_EMAIL)"
|
||||
:aria-label="trans(PERSON_MESSAGES_PERSON_EMAIL)"
|
||||
aria-describedby="email"
|
||||
/>
|
||||
</div>
|
||||
@ -183,22 +175,21 @@
|
||||
v-model="showAddressForm"
|
||||
name="showAddressForm"
|
||||
/>
|
||||
<label class="form-check-label">{{
|
||||
$t("person.address.show_address_form")
|
||||
}}</label>
|
||||
<label class="form-check-label">
|
||||
{{ trans(PERSON_MESSAGES_PERSON_ADDRESS_SHOW_ADDRESS_FORM) }}
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
v-if="action === 'create' && showAddressFormValue"
|
||||
class="form-floating mb-3"
|
||||
>
|
||||
<p>{{ $t("person.address.warning") }}</p>
|
||||
<add-address
|
||||
<p>{{ trans(PERSON_MESSAGES_PERSON_ADDRESS_WARNING) }}</p>
|
||||
<AddAddress
|
||||
:context="addAddress.context"
|
||||
:options="addAddress.options"
|
||||
:addressChangedCallback="submitNewAddress"
|
||||
ref="addAddress"
|
||||
>
|
||||
</add-address>
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning" v-if="errors.length">
|
||||
@ -208,8 +199,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from "vue";
|
||||
import {
|
||||
getCentersForPersonCreation,
|
||||
getCivilities,
|
||||
@ -220,286 +211,256 @@ import {
|
||||
import PersonRenderBox from "../Entity/PersonRenderBox.vue";
|
||||
import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress.vue";
|
||||
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||
import {
|
||||
trans,
|
||||
PERSON_MESSAGES_PERSON_LASTNAME,
|
||||
PERSON_MESSAGES_PERSON_FIRSTNAME,
|
||||
PERSON_MESSAGES_PERSON_GENDER_PLACEHOLDER,
|
||||
PERSON_MESSAGES_PERSON_GENDER_TITLE,
|
||||
PERSON_MESSAGES_PERSON_CENTER_PLACEHOLDER,
|
||||
PERSON_MESSAGES_PERSON_CENTER_TITLE,
|
||||
PERSON_MESSAGES_PERSON_CIVILITY_PLACEHOLDER,
|
||||
PERSON_MESSAGES_PERSON_CIVILITY_TITLE,
|
||||
PERSON_MESSAGES_PERSON_PHONENUMBER,
|
||||
PERSON_MESSAGES_PERSON_MOBILENUMBER,
|
||||
PERSON_MESSAGES_PERSON_EMAIL,
|
||||
PERSON_MESSAGES_PERSON_ADDRESS_SHOW_ADDRESS_FORM,
|
||||
PERSON_MESSAGES_PERSON_ADDRESS_WARNING,
|
||||
} from "translator";
|
||||
|
||||
export default {
|
||||
name: "OnTheFlyPerson",
|
||||
props: ["id", "type", "action", "query"],
|
||||
//emits: ['createAction'],
|
||||
components: {
|
||||
PersonRenderBox,
|
||||
AddAddress,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
person: {
|
||||
type: "person",
|
||||
lastName: "",
|
||||
firstName: "",
|
||||
altNames: [],
|
||||
addressId: null,
|
||||
center: null,
|
||||
},
|
||||
config: {
|
||||
altNames: [],
|
||||
civilities: [],
|
||||
centers: [],
|
||||
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",
|
||||
},
|
||||
title: { create: "person.address.create_address" },
|
||||
},
|
||||
context: {
|
||||
target: {}, // boilerplate for getting the address id
|
||||
edit: false,
|
||||
addressId: null,
|
||||
defaults: window.addaddress,
|
||||
},
|
||||
},
|
||||
errors: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
firstName: {
|
||||
set(value) {
|
||||
this.person.firstName = value;
|
||||
},
|
||||
get() {
|
||||
return this.person.firstName;
|
||||
},
|
||||
},
|
||||
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;
|
||||
},
|
||||
},
|
||||
civility: {
|
||||
set(value) {
|
||||
this.person.civility = { id: value, type: "chill_main_civility" };
|
||||
},
|
||||
get() {
|
||||
return this.person.civility ? this.person.civility.id : null;
|
||||
},
|
||||
},
|
||||
birthDate: {
|
||||
set(value) {
|
||||
if (this.person.birthdate) {
|
||||
this.person.birthdate.datetime = value + "T00:00:00+0100";
|
||||
} else {
|
||||
this.person.birthdate = { datetime: value + "T00:00:00+0100" };
|
||||
}
|
||||
},
|
||||
get() {
|
||||
return this.person.birthdate
|
||||
? this.person.birthdate.datetime.split("T")[0]
|
||||
: "";
|
||||
},
|
||||
},
|
||||
phonenumber: {
|
||||
set(value) {
|
||||
this.person.phonenumber = value;
|
||||
},
|
||||
get() {
|
||||
return this.person.phonenumber;
|
||||
},
|
||||
},
|
||||
mobilenumber: {
|
||||
set(value) {
|
||||
this.person.mobilenumber = value;
|
||||
},
|
||||
get() {
|
||||
return this.person.mobilenumber;
|
||||
},
|
||||
},
|
||||
email: {
|
||||
set(value) {
|
||||
this.person.email = value;
|
||||
},
|
||||
get() {
|
||||
return this.person.email;
|
||||
},
|
||||
},
|
||||
showAddressForm: {
|
||||
set(value) {
|
||||
this.showAddressFormValue = value;
|
||||
},
|
||||
get() {
|
||||
return this.showAddressFormValue;
|
||||
},
|
||||
},
|
||||
center: {
|
||||
set(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 props = defineProps({
|
||||
id: [String, Number],
|
||||
type: String,
|
||||
action: String,
|
||||
query: String,
|
||||
});
|
||||
|
||||
console.log("center get", center);
|
||||
const person = reactive({
|
||||
type: "person",
|
||||
lastName: "",
|
||||
firstName: "",
|
||||
altNames: [],
|
||||
addressId: null,
|
||||
center: null,
|
||||
gender: null,
|
||||
civility: null,
|
||||
birthdate: null,
|
||||
phonenumber: "",
|
||||
mobilenumber: "",
|
||||
email: "",
|
||||
});
|
||||
|
||||
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";
|
||||
default:
|
||||
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";
|
||||
default:
|
||||
return "person.gender.unknown";
|
||||
}
|
||||
},
|
||||
feminized() {
|
||||
return this.person.gender === "woman" ? "e" : "";
|
||||
},
|
||||
personAltNamesLabels() {
|
||||
return this.person.altNames.map((a) => (a ? a.label : ""));
|
||||
},
|
||||
queryItems() {
|
||||
return this.query ? this.query.split(" ") : null;
|
||||
const config = reactive({
|
||||
altNames: [],
|
||||
civilities: [],
|
||||
centers: [],
|
||||
genders: [],
|
||||
});
|
||||
|
||||
const showCenters = ref(false);
|
||||
const showAddressFormValue = ref(false);
|
||||
const errors = ref([]);
|
||||
|
||||
const addAddress = reactive({
|
||||
options: {
|
||||
button: {
|
||||
text: { create: "person.address.create_address" },
|
||||
size: "btn-sm",
|
||||
},
|
||||
title: { create: "person.address.create_address" },
|
||||
},
|
||||
mounted() {
|
||||
getPersonAltNames().then((altNames) => {
|
||||
this.config.altNames = altNames;
|
||||
});
|
||||
getCivilities().then((civilities) => {
|
||||
if ("results" in civilities) {
|
||||
this.config.civilities = civilities.results;
|
||||
}
|
||||
});
|
||||
getGenders().then((genders) => {
|
||||
if ("results" in genders) {
|
||||
console.log("genders", genders.results);
|
||||
this.config.genders = genders.results;
|
||||
}
|
||||
});
|
||||
if (this.action !== "create") {
|
||||
this.loadData();
|
||||
context: {
|
||||
target: {},
|
||||
edit: false,
|
||||
addressId: null,
|
||||
defaults: window.addaddress,
|
||||
},
|
||||
});
|
||||
|
||||
const firstName = computed({
|
||||
get: () => person.firstName,
|
||||
set: (value) => {
|
||||
person.firstName = value;
|
||||
},
|
||||
});
|
||||
const lastName = computed({
|
||||
get: () => person.lastName,
|
||||
set: (value) => {
|
||||
person.lastName = value;
|
||||
},
|
||||
});
|
||||
const gender = computed({
|
||||
get: () => (person.gender ? person.gender.id : null),
|
||||
set: (value) => {
|
||||
person.gender = { id: value, type: "chill_main_gender" };
|
||||
},
|
||||
});
|
||||
const civility = computed({
|
||||
get: () => (person.civility ? person.civility.id : null),
|
||||
set: (value) => {
|
||||
person.civility = { id: value, type: "chill_main_civility" };
|
||||
},
|
||||
});
|
||||
const birthDate = computed({
|
||||
get: () => (person.birthdate ? person.birthdate.datetime.split("T")[0] : ""),
|
||||
set: (value) => {
|
||||
if (person.birthdate) {
|
||||
person.birthdate.datetime = value + "T00:00:00+0100";
|
||||
} else {
|
||||
// console.log('show centers', this.showCenters);
|
||||
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);
|
||||
if (this.showCenters && this.config.centers.length === 1) {
|
||||
this.person.center = this.config.centers[0];
|
||||
}
|
||||
});
|
||||
person.birthdate = { datetime: value + "T00:00:00+0100" };
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
localizeString,
|
||||
checkErrors() {
|
||||
this.errors = [];
|
||||
if (this.person.lastName === "") {
|
||||
this.errors.push("Le nom ne doit pas être vide.");
|
||||
}
|
||||
if (this.person.firstName === "") {
|
||||
this.errors.push("Le prénom ne doit pas être vide.");
|
||||
}
|
||||
if (!this.person.gender) {
|
||||
this.errors.push("Le genre doit être renseigné");
|
||||
}
|
||||
if (this.showCenters && this.person.center === null) {
|
||||
this.errors.push("Le centre doit être renseigné");
|
||||
}
|
||||
},
|
||||
loadData() {
|
||||
getPerson(this.id).then(
|
||||
(person) =>
|
||||
new Promise((resolve) => {
|
||||
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 });
|
||||
this.person.altNames = updateAltNames;
|
||||
},
|
||||
addQueryItem(field, queryItem) {
|
||||
switch (field) {
|
||||
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;
|
||||
break;
|
||||
}
|
||||
},
|
||||
submitNewAddress(payload) {
|
||||
this.person.addressId = payload.addressId;
|
||||
},
|
||||
});
|
||||
const phonenumber = computed({
|
||||
get: () => person.phonenumber,
|
||||
set: (value) => {
|
||||
person.phonenumber = value;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
});
|
||||
const mobilenumber = computed({
|
||||
get: () => person.mobilenumber,
|
||||
set: (value) => {
|
||||
person.mobilenumber = value;
|
||||
},
|
||||
});
|
||||
const email = computed({
|
||||
get: () => person.email,
|
||||
set: (value) => {
|
||||
person.email = value;
|
||||
},
|
||||
});
|
||||
const showAddressForm = computed({
|
||||
get: () => showAddressFormValue.value,
|
||||
set: (value) => {
|
||||
showAddressFormValue.value = value;
|
||||
},
|
||||
});
|
||||
const center = computed({
|
||||
get: () => {
|
||||
const c = config.centers.find(
|
||||
(c) => person.center !== null && person.center.id === c.id,
|
||||
);
|
||||
return typeof c === "undefined" ? null : c;
|
||||
},
|
||||
set: (value) => {
|
||||
person.center = { id: value.id, type: value.type };
|
||||
},
|
||||
});
|
||||
|
||||
<style lang="scss" scoped>
|
||||
div.flex-table {
|
||||
div.item-bloc {
|
||||
div.item-row {
|
||||
div.item-col:last-child {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
const genderClass = computed(() => {
|
||||
switch (person.gender && person.gender.id) {
|
||||
case "woman":
|
||||
return "fa-venus";
|
||||
case "man":
|
||||
return "fa-mars";
|
||||
case "both":
|
||||
return "fa-neuter";
|
||||
case "unknown":
|
||||
return "fa-genderless";
|
||||
default:
|
||||
return "fa-genderless";
|
||||
}
|
||||
});
|
||||
|
||||
const genderTranslation = computed(() => {
|
||||
switch (person.gender && person.gender.genderTranslation) {
|
||||
case "woman":
|
||||
return PERSON_MESSAGES_PERSON_GENDER_WOMAN;
|
||||
case "man":
|
||||
return PERSON_MESSAGES_PERSON_GENDER_MAN;
|
||||
case "neutral":
|
||||
return PERSON_MESSAGES_PERSON_GENDER_NEUTRAL;
|
||||
case "unknown":
|
||||
return PERSON_MESSAGES_PERSON_GENDER_UNKNOWN;
|
||||
default:
|
||||
return PERSON_MESSAGES_PERSON_GENDER_UNKNOWN;
|
||||
}
|
||||
});
|
||||
const feminized = computed(() =>
|
||||
person.gender && person.gender.id === "woman" ? "e" : "",
|
||||
);
|
||||
const personAltNamesLabels = computed(() =>
|
||||
person.altNames.map((a) => (a ? a.label : "")),
|
||||
);
|
||||
const queryItems = computed(() =>
|
||||
props.query ? props.query.split(" ") : null,
|
||||
);
|
||||
|
||||
function checkErrors() {
|
||||
errors.value = [];
|
||||
if (person.lastName === "") {
|
||||
errors.value.push("Le nom ne doit pas être vide.");
|
||||
}
|
||||
if (person.firstName === "") {
|
||||
errors.value.push("Le prénom ne doit pas être vide.");
|
||||
}
|
||||
if (!person.gender) {
|
||||
errors.value.push("Le genre doit être renseigné");
|
||||
}
|
||||
if (showCenters.value && person.center === null) {
|
||||
errors.value.push("Le centre doit être renseigné");
|
||||
}
|
||||
}
|
||||
|
||||
function loadData() {
|
||||
getPerson(props.id).then((p) => {
|
||||
Object.assign(person, p);
|
||||
});
|
||||
}
|
||||
|
||||
function onAltNameInput(event) {
|
||||
const key = event.target.id;
|
||||
const label = event.target.value;
|
||||
let updateAltNames = person.altNames.filter((a) => a.key !== key);
|
||||
updateAltNames.push({ key: key, label: label });
|
||||
person.altNames = updateAltNames;
|
||||
}
|
||||
|
||||
function addQueryItem(field, queryItem) {
|
||||
switch (field) {
|
||||
case "lastName":
|
||||
person.lastName = person.lastName
|
||||
? (person.lastName += ` ${queryItem}`)
|
||||
: queryItem;
|
||||
break;
|
||||
case "firstName":
|
||||
person.firstName = person.firstName
|
||||
? (person.firstName += ` ${queryItem}`)
|
||||
: queryItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function submitNewAddress(payload) {
|
||||
person.addressId = payload.addressId;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getPersonAltNames().then((altNames) => {
|
||||
config.altNames = altNames;
|
||||
});
|
||||
getCivilities().then((civilities) => {
|
||||
if ("results" in civilities) {
|
||||
config.civilities = civilities.results;
|
||||
}
|
||||
});
|
||||
getGenders().then((genders) => {
|
||||
if ("results" in genders) {
|
||||
config.genders = genders.results;
|
||||
}
|
||||
});
|
||||
if (props.action !== "create") {
|
||||
loadData();
|
||||
} else {
|
||||
getCentersForPersonCreation().then((params) => {
|
||||
config.centers = params.centers.filter((c) => c.isActive);
|
||||
showCenters.value = params.showCenters;
|
||||
if (showCenters.value && config.centers.length === 1) {
|
||||
person.center = config.centers[0];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
dl {
|
||||
dd {
|
||||
margin-left: 1em;
|
||||
}
|
||||
}
|
||||
div.form-check {
|
||||
label {
|
||||
margin-left: 0.5em !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
});
|
||||
|
||||
defineExpose(genderClass, genderTranslation, feminized, birthDate);
|
||||
</script>
|
||||
|
@ -198,3 +198,59 @@ accompanying_course_evaluation_document:
|
||||
|
||||
accompanying_period_work:
|
||||
title: Action d'accompagnement (n°{id}) - {action_title}
|
||||
|
||||
add_persons:
|
||||
title: "Ajouter des usagers"
|
||||
suggested_counter: >-
|
||||
{count, plural,
|
||||
=0 {Pas de résultats}
|
||||
=1 {1 résultat}
|
||||
other {# résultats}
|
||||
}
|
||||
selected_counter: >-
|
||||
{count, plural,
|
||||
=1 {1 sélectionné}
|
||||
other {# sélectionnés}
|
||||
}
|
||||
search_some_persons: "Rechercher des personnes.."
|
||||
|
||||
item:
|
||||
type_person: "Usager"
|
||||
type_user: "TMS"
|
||||
type_thirdparty: "Tiers professionnel"
|
||||
type_household: "Ménage"
|
||||
|
||||
person:
|
||||
firstname: "Prénom"
|
||||
lastname: "Nom"
|
||||
born:
|
||||
man: "Né le"
|
||||
woman: "Née le"
|
||||
neutral: "Né·e le"
|
||||
center_id: "Identifiant du centre"
|
||||
center_type: "Type de centre"
|
||||
center_name: "Territoire"
|
||||
phonenumber: "Téléphone"
|
||||
mobilenumber: "Mobile"
|
||||
altnames: "Autres noms"
|
||||
email: "Courriel"
|
||||
gender:
|
||||
title: "Genre"
|
||||
placeholder: "Choisissez le genre de l'usager"
|
||||
woman: "Féminin"
|
||||
man: "Masculin"
|
||||
neutral: "Neutre, non binaire"
|
||||
unknown: "Non renseigné"
|
||||
undefined: "Non renseigné"
|
||||
civility:
|
||||
title: "Civilité"
|
||||
placeholder: "Choisissez la civilité"
|
||||
address:
|
||||
create_address: "Ajouter une adresse"
|
||||
show_address_form: "Ajouter une adresse pour un usager non suivi et seul dans un ménage"
|
||||
warning: "Un nouveau ménage va être créé. L'usager sera membre de ce ménage."
|
||||
center:
|
||||
placeholder: "Choisissez un centre"
|
||||
title: "Centre"
|
||||
|
||||
error_only_one_person: "Une seule personne peut être sélectionnée !"
|
||||
|
@ -1505,3 +1505,48 @@ my_parcours_filters:
|
||||
parcours_intervening: Intervenant
|
||||
is_open: Parcours ouverts
|
||||
is_closed: Parcours clôturés
|
||||
|
||||
person_messages:
|
||||
add_persons:
|
||||
title: "Ajouter des usagers"
|
||||
suggested_counter: "Pas de résultats | 1 résultat | {count} résultats"
|
||||
selected_counter: " 1 sélectionné | {count} sélectionnés"
|
||||
search_some_persons: "Rechercher des personnes.."
|
||||
item:
|
||||
type_person: "Usager"
|
||||
type_user: "TMS"
|
||||
type_thirdparty: "Tiers professionnel"
|
||||
type_household: "Ménage"
|
||||
person:
|
||||
firstname: "Prénom"
|
||||
lastname: "Nom"
|
||||
born:
|
||||
man: "Né le"
|
||||
woman: "Née le"
|
||||
neutral: "Né·e le"
|
||||
center_id: "Identifiant du centre"
|
||||
center_type: "Type de centre"
|
||||
center_name: "Territoire"
|
||||
phonenumber: "Téléphone"
|
||||
mobilenumber: "Mobile"
|
||||
altnames: "Autres noms"
|
||||
email: "Courriel"
|
||||
gender:
|
||||
title: "Genre"
|
||||
placeholder: "Choisissez le genre de l'usager"
|
||||
woman: "Féminin"
|
||||
man: "Masculin"
|
||||
neutral: "Neutre, non binaire"
|
||||
unknown: "Non renseigné"
|
||||
undefined: "Non renseigné"
|
||||
civility:
|
||||
title: "Civilité"
|
||||
placeholder: "Choisissez la civilité"
|
||||
address:
|
||||
create_address: "Ajouter une adresse"
|
||||
show_address_form: "Ajouter une adresse pour un usager non suivi et seul dans un ménage"
|
||||
warning: "Un nouveau ménage va être créé. L'usager sera membre de ce ménage."
|
||||
center:
|
||||
placeholder: "Choisissez un centre"
|
||||
title: "Centre"
|
||||
error_only_one_person: "Une seule personne peut être sélectionnée !"
|
||||
|
@ -27,18 +27,18 @@
|
||||
<div v-if="parent">
|
||||
<div class="parent-info">
|
||||
<i class="fa fa-li fa-hand-o-right" />
|
||||
<b class="me-2">{{ $t("child_of") }}</b>
|
||||
<b class="me-2">{{ trans(THIRDPARTY_MESSAGES_CHILD_OF) }}</b>
|
||||
<span class="chill-entity badge-thirdparty">{{
|
||||
parent.text
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-floating mb-3" v-else-if="kind !== 'child'">
|
||||
<div class="form-floating mb-3" v-else-if="kind.value !== 'child'">
|
||||
<div class="form-check">
|
||||
<input
|
||||
class="form-check-input mt-0"
|
||||
type="radio"
|
||||
v-model="kind"
|
||||
v-model="kind.value"
|
||||
value="company"
|
||||
id="tpartyKindInstitution"
|
||||
/>
|
||||
@ -53,7 +53,7 @@
|
||||
<input
|
||||
class="form-check-input mt-0"
|
||||
type="radio"
|
||||
v-model="kind"
|
||||
v-model="kind.value"
|
||||
value="contact"
|
||||
id="tpartyKindContact"
|
||||
/>
|
||||
@ -95,7 +95,7 @@
|
||||
v-model="thirdparty.civility"
|
||||
>
|
||||
<option selected disabled :value="null">
|
||||
{{ $t("thirdparty.civility") }}
|
||||
{{ trans(THIRDPARTY_MESSAGES_THIRDPARTY_CIVILITY) }}
|
||||
</option>
|
||||
<option
|
||||
v-for="civility in civilities"
|
||||
@ -110,8 +110,12 @@
|
||||
<input
|
||||
class="form-control form-control-lg"
|
||||
v-model="thirdparty.profession"
|
||||
:placeholder="$t('thirdparty.profession')"
|
||||
:aria-label="$t('thirdparty.profession')"
|
||||
:placeholder="
|
||||
trans(THIRDPARTY_MESSAGES_THIRDPARTY_PROFESSION)
|
||||
"
|
||||
:aria-label="
|
||||
trans(THIRDPARTY_MESSAGES_THIRDPARTY_PROFESSION)
|
||||
"
|
||||
aria-describedby="profession"
|
||||
/>
|
||||
</div>
|
||||
@ -123,10 +127,12 @@
|
||||
class="form-control form-control-lg"
|
||||
id="firstname"
|
||||
v-model="thirdparty.firstname"
|
||||
:placeholder="$t('thirdparty.firstname')"
|
||||
:placeholder="
|
||||
trans(THIRDPARTY_MESSAGES_THIRDPARTY_FIRSTNAME)
|
||||
"
|
||||
/>
|
||||
<label for="firstname">{{
|
||||
$t("thirdparty.firstname")
|
||||
trans(THIRDPARTY_MESSAGES_THIRDPARTY_FIRSTNAME)
|
||||
}}</label>
|
||||
</div>
|
||||
<div v-if="queryItems">
|
||||
@ -147,10 +153,12 @@
|
||||
class="form-control form-control-lg"
|
||||
id="name"
|
||||
v-model="thirdparty.name"
|
||||
:placeholder="$t('thirdparty.lastname')"
|
||||
:placeholder="
|
||||
trans(THIRDPARTY_MESSAGES_THIRDPARTY_LASTNAME)
|
||||
"
|
||||
/>
|
||||
<label for="name">{{
|
||||
$t("thirdparty.lastname")
|
||||
trans(THIRDPARTY_MESSAGES_THIRDPARTY_LASTNAME)
|
||||
}}</label>
|
||||
</div>
|
||||
<div v-if="queryItems">
|
||||
@ -174,9 +182,11 @@
|
||||
class="form-control form-control-lg"
|
||||
id="name"
|
||||
v-model="thirdparty.name"
|
||||
:placeholder="$t('thirdparty.name')"
|
||||
:placeholder="trans(THIRDPARTY_MESSAGES_THIRDPARTY_NAME)"
|
||||
/>
|
||||
<label for="name">{{ $t("thirdparty.name") }}</label>
|
||||
<label for="name">{{
|
||||
trans(THIRDPARTY_MESSAGES_THIRDPARTY_NAME)
|
||||
}}</label>
|
||||
</div>
|
||||
<div v-if="query">
|
||||
<ul class="list-suggest add-items inline">
|
||||
@ -188,7 +198,7 @@
|
||||
</div>
|
||||
|
||||
<template v-if="thirdparty.kind !== 'child'">
|
||||
<add-address
|
||||
<AddAddress
|
||||
key="thirdparty"
|
||||
:context="context"
|
||||
:options="addAddress.options"
|
||||
@ -204,8 +214,8 @@
|
||||
<input
|
||||
class="form-control form-control-lg"
|
||||
v-model="thirdparty.email"
|
||||
:placeholder="$t('thirdparty.email')"
|
||||
:aria-label="$t('thirdparty.email')"
|
||||
:placeholder="trans(THIRDPARTY_MESSAGES_THIRDPARTY_EMAIL)"
|
||||
:aria-label="trans(THIRDPARTY_MESSAGES_THIRDPARTY_EMAIL)"
|
||||
aria-describedby="email"
|
||||
/>
|
||||
</div>
|
||||
@ -217,8 +227,8 @@
|
||||
<input
|
||||
class="form-control form-control-lg"
|
||||
v-model="thirdparty.telephone"
|
||||
:placeholder="$t('thirdparty.phonenumber')"
|
||||
:aria-label="$t('thirdparty.phonenumber')"
|
||||
:placeholder="trans(THIRDPARTY_MESSAGES_THIRDPARTY_PHONENUMBER)"
|
||||
:aria-label="trans(THIRDPARTY_MESSAGES_THIRDPARTY_PHONENUMBER)"
|
||||
aria-describedby="phonenumber"
|
||||
/>
|
||||
</div>
|
||||
@ -230,8 +240,10 @@
|
||||
<input
|
||||
class="form-control form-control-lg"
|
||||
v-model="thirdparty.telephone2"
|
||||
:placeholder="$t('thirdparty.phonenumber2')"
|
||||
:aria-label="$t('thirdparty.phonenumber2')"
|
||||
:placeholder="
|
||||
trans(THIRDPARTY_MESSAGES_THIRDPARTY_PHONENUMBER2)
|
||||
"
|
||||
:aria-label="trans(THIRDPARTY_MESSAGES_THIRDPARTY_PHONENUMBER2)"
|
||||
aria-describedby="phonenumber2"
|
||||
/>
|
||||
</div>
|
||||
@ -243,7 +255,7 @@
|
||||
/></span>
|
||||
<textarea
|
||||
class="form-control form-control-lg"
|
||||
:placeholder="$t('thirdparty.comment')"
|
||||
:placeholder="trans(THIRDPARTY_MESSAGES_THIRDPARTY_COMMENT)"
|
||||
v-model="thirdparty.comment"
|
||||
/>
|
||||
</div>
|
||||
@ -251,173 +263,178 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted, getCurrentInstance } from "vue";
|
||||
import ThirdPartyRenderBox from "../Entity/ThirdPartyRenderBox.vue";
|
||||
import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress";
|
||||
import { getThirdparty } from "../../_api/OnTheFly";
|
||||
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
|
||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
||||
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||
import { localizeString as _localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||
import {
|
||||
trans,
|
||||
THIRDPARTY_MESSAGES_THIRDPARTY_FIRSTNAME,
|
||||
THIRDPARTY_MESSAGES_THIRDPARTY_LASTNAME,
|
||||
THIRDPARTY_MESSAGES_THIRDPARTY_NAME,
|
||||
THIRDPARTY_MESSAGES_THIRDPARTY_EMAIL,
|
||||
THIRDPARTY_MESSAGES_THIRDPARTY_PHONENUMBER,
|
||||
THIRDPARTY_MESSAGES_THIRDPARTY_PHONENUMBER2,
|
||||
THIRDPARTY_MESSAGES_THIRDPARTY_COMMENT,
|
||||
THIRDPARTY_MESSAGES_THIRDPARTY_PROFESSION,
|
||||
THIRDPARTY_MESSAGES_THIRDPARTY_CIVILITY,
|
||||
THIRDPARTY_MESSAGES_CHILD_OF,
|
||||
} from "translator";
|
||||
// Props
|
||||
const props = defineProps(["id", "type", "action", "query", "parent"]);
|
||||
|
||||
export default {
|
||||
name: "OnTheFlyThirdParty",
|
||||
props: ["id", "type", "action", "query", "parent"],
|
||||
components: {
|
||||
ThirdPartyRenderBox,
|
||||
AddAddress,
|
||||
BadgeEntity,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
//context: {}, <--
|
||||
thirdparty: {
|
||||
type: "thirdparty",
|
||||
address: null,
|
||||
kind: "company",
|
||||
firstname: "",
|
||||
name: "",
|
||||
telephone: "",
|
||||
telephone2: "",
|
||||
civility: null,
|
||||
profession: "",
|
||||
},
|
||||
civilities: [],
|
||||
addAddress: {
|
||||
options: {
|
||||
openPanesInModal: true,
|
||||
onlyButton: false,
|
||||
button: {
|
||||
size: "btn-sm",
|
||||
},
|
||||
title: {
|
||||
create: "add_an_address_title",
|
||||
edit: "edit_address",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
kind: {
|
||||
get() {
|
||||
// note: there are also default to 'institution' set in the "mounted" method
|
||||
if (this.$data.thirdparty.kind !== undefined) {
|
||||
return this.$data.thirdparty.kind;
|
||||
} else {
|
||||
return "company";
|
||||
}
|
||||
},
|
||||
set(v) {
|
||||
this.$data.thirdparty.kind = v;
|
||||
},
|
||||
// Instance for $t and $toast
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
// State
|
||||
const thirdparty = reactive({
|
||||
type: "thirdparty",
|
||||
address: null,
|
||||
kind: "company",
|
||||
firstname: "",
|
||||
name: "",
|
||||
telephone: "",
|
||||
telephone2: "",
|
||||
civility: null,
|
||||
profession: "",
|
||||
comment: "",
|
||||
parent: props.parent ? props.parent : undefined,
|
||||
});
|
||||
const civilities = ref([]);
|
||||
const addAddress = reactive({
|
||||
options: {
|
||||
openPanesInModal: true,
|
||||
onlyButton: false,
|
||||
button: {
|
||||
size: "btn-sm",
|
||||
},
|
||||
context() {
|
||||
let context = {
|
||||
target: {
|
||||
name: this.type,
|
||||
id: this.id,
|
||||
},
|
||||
edit: false,
|
||||
addressId: null,
|
||||
defaults: window.addaddress,
|
||||
};
|
||||
if (
|
||||
!(
|
||||
this.thirdparty.address === undefined ||
|
||||
this.thirdparty.address === null
|
||||
) &&
|
||||
this.thirdparty.address.address_id !== null
|
||||
) {
|
||||
// to complete
|
||||
context.addressId = this.thirdparty.address.address_id;
|
||||
context.edit = true;
|
||||
}
|
||||
//this.context = context; <--
|
||||
return context;
|
||||
},
|
||||
queryItems() {
|
||||
return this.query ? this.query.split(" ") : null;
|
||||
title: {
|
||||
create: "add_an_address_title",
|
||||
edit: "edit_address",
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
localizeString,
|
||||
loadData() {
|
||||
return getThirdparty(this.id).then(
|
||||
(thirdparty) =>
|
||||
new Promise((resolve) => {
|
||||
this.thirdparty = thirdparty;
|
||||
this.thirdparty.kind = thirdparty.kind;
|
||||
if (this.action !== "show") {
|
||||
if (thirdparty.address !== null) {
|
||||
// bof! we force getInitialAddress because addressId not available when mounted
|
||||
this.$refs.addAddress.getInitialAddress(
|
||||
thirdparty.address.address_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
resolve();
|
||||
}),
|
||||
);
|
||||
});
|
||||
const addAddressRef = ref(null);
|
||||
|
||||
// Kind as computed ref
|
||||
const kind = computed({
|
||||
get() {
|
||||
return thirdparty.kind !== undefined ? thirdparty.kind : "company";
|
||||
},
|
||||
set(v) {
|
||||
thirdparty.kind = v;
|
||||
},
|
||||
});
|
||||
|
||||
// Context as computed
|
||||
const context = computed(() => {
|
||||
let ctx = {
|
||||
target: {
|
||||
name: props.type,
|
||||
id: props.id,
|
||||
},
|
||||
loadCivilities() {
|
||||
const url = `/api/1.0/main/civility.json`;
|
||||
return makeFetch("GET", url)
|
||||
.then((response) => {
|
||||
this.$data.civilities = response.results;
|
||||
return Promise.resolve();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
this.$toast.open({ message: error.body });
|
||||
});
|
||||
},
|
||||
submitAddress(payload) {
|
||||
console.log("submitAddress", payload);
|
||||
if (typeof payload.addressId !== "undefined") {
|
||||
// <--
|
||||
this.context.edit = true;
|
||||
this.context.addressId = payload.addressId; // bof! use legacy and not legacy in payload
|
||||
this.thirdparty.address = payload.address; // <--
|
||||
console.log("switch address to edit mode", this.context);
|
||||
}
|
||||
},
|
||||
addQueryItem(field, queryItem) {
|
||||
switch (field) {
|
||||
case "name":
|
||||
if (this.thirdparty.name) {
|
||||
this.thirdparty.name += ` ${queryItem}`;
|
||||
} else {
|
||||
this.thirdparty.name = queryItem;
|
||||
edit: false,
|
||||
addressId: null,
|
||||
defaults: window.addaddress,
|
||||
};
|
||||
if (
|
||||
!(thirdparty.address === undefined || thirdparty.address === null) &&
|
||||
thirdparty.address.address_id !== null
|
||||
) {
|
||||
ctx.addressId = thirdparty.address.address_id;
|
||||
ctx.edit = true;
|
||||
}
|
||||
return ctx;
|
||||
});
|
||||
|
||||
// Query items
|
||||
const queryItems = computed(() =>
|
||||
props.query ? props.query.split(" ") : null,
|
||||
);
|
||||
|
||||
// Methods
|
||||
function localizeString(str) {
|
||||
return _localizeString(str);
|
||||
}
|
||||
|
||||
function loadData() {
|
||||
return getThirdparty(props.id).then(
|
||||
(tp) =>
|
||||
new Promise((resolve) => {
|
||||
Object.assign(thirdparty, tp);
|
||||
thirdparty.kind = tp.kind;
|
||||
if (props.action !== "show") {
|
||||
if (tp.address !== null && addAddressRef.value) {
|
||||
addAddressRef.value.getInitialAddress(
|
||||
tp.address.address_id,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "firstName":
|
||||
this.thirdparty.firstname = queryItem;
|
||||
break;
|
||||
}
|
||||
resolve();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function loadCivilities() {
|
||||
const url = `/api/1.0/main/civility.json`;
|
||||
return makeFetch("GET", url)
|
||||
.then((response) => {
|
||||
civilities.value = response.results;
|
||||
return Promise.resolve();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
proxy.$toast.open({ message: error.body });
|
||||
});
|
||||
}
|
||||
|
||||
function submitAddress(payload) {
|
||||
if (typeof payload.addressId !== "undefined") {
|
||||
context.value.edit = true;
|
||||
context.value.addressId = payload.addressId;
|
||||
thirdparty.address = payload.address;
|
||||
}
|
||||
}
|
||||
|
||||
function addQueryItem(field, queryItem) {
|
||||
switch (field) {
|
||||
case "name":
|
||||
if (thirdparty.name) {
|
||||
thirdparty.name += ` ${queryItem}`;
|
||||
} else {
|
||||
thirdparty.name = queryItem;
|
||||
}
|
||||
},
|
||||
addQuery(query) {
|
||||
this.thirdparty.name = query;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
let dependencies = [];
|
||||
dependencies.push(this.loadCivilities());
|
||||
if (this.action !== "create") {
|
||||
if (this.id) {
|
||||
dependencies.push(this.loadData());
|
||||
// here we can do something when all promises are resolve, with
|
||||
// Promise.all(dependencies).then(() => { /* do something */ });
|
||||
}
|
||||
if (this.action === "addContact") {
|
||||
this.$data.thirdparty.kind = "child";
|
||||
// this.$data.thirdparty.parent = this.parent.id
|
||||
this.$data.thirdparty.address = null;
|
||||
}
|
||||
} else {
|
||||
this.thirdparty.kind = "company";
|
||||
break;
|
||||
case "firstName":
|
||||
thirdparty.firstname = queryItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function addQuery(query) {
|
||||
thirdparty.name = query;
|
||||
}
|
||||
|
||||
// Lifecycle
|
||||
onMounted(() => {
|
||||
let dependencies = [];
|
||||
dependencies.push(loadCivilities());
|
||||
if (props.action !== "create") {
|
||||
if (props.id) {
|
||||
dependencies.push(loadData());
|
||||
}
|
||||
},
|
||||
};
|
||||
if (props.action === "addContact") {
|
||||
thirdparty.kind = "child";
|
||||
thirdparty.address = null;
|
||||
}
|
||||
} else {
|
||||
thirdparty.kind = "company";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -155,3 +155,16 @@ Telephone2: Autre téléphone
|
||||
Contact email: Courrier électronique du contact
|
||||
Contact address: Adresse du contact
|
||||
Contact profession: Profession du contact
|
||||
thirdpartyMessages:
|
||||
thirdparty:
|
||||
firstname: "Prénom"
|
||||
lastname: "Nom"
|
||||
name: "Dénomination"
|
||||
email: "Courriel"
|
||||
phonenumber: "Téléphone"
|
||||
phonenumber2: "Autre numéro de téléphone"
|
||||
comment: "Commentaire"
|
||||
profession: "Qualité"
|
||||
civility: "Civilité"
|
||||
child_of: "Contact de: "
|
||||
children: "Personnes de contact: "
|
||||
|
@ -107,3 +107,15 @@ export interface Ticket {
|
||||
createdAt: DateTime | null;
|
||||
updatedBy: User | null;
|
||||
}
|
||||
|
||||
export interface addNewPersons {
|
||||
selected: Selected[];
|
||||
modal: Modal;
|
||||
}
|
||||
export interface Modal {
|
||||
showModal: boolean;
|
||||
modalDialogClass: string;
|
||||
}
|
||||
export interface Selected {
|
||||
result: User;
|
||||
}
|
||||
|
@ -6,13 +6,13 @@
|
||||
</div>
|
||||
<action-toolbar-component />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, inject, onMounted, ref } from "vue";
|
||||
<script setup lang="ts">
|
||||
import { useToast } from "vue-toast-notification";
|
||||
import { computed, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
// Types
|
||||
import { Motive, Ticket } from "../../types";
|
||||
import { Ticket } from "../../types";
|
||||
|
||||
// Components
|
||||
import TicketSelectorComponent from "./components/TicketSelectorComponent.vue";
|
||||
@ -20,43 +20,23 @@ import TicketHistoryListComponent from "./components/TicketHistoryListComponent.
|
||||
import ActionToolbarComponent from "./components/ActionToolbarComponent.vue";
|
||||
import BannerComponent from "./components/BannerComponent.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "App",
|
||||
components: {
|
||||
TicketSelectorComponent,
|
||||
TicketHistoryListComponent,
|
||||
ActionToolbarComponent,
|
||||
BannerComponent,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const toast = inject("toast") as any;
|
||||
const store = useStore();
|
||||
const toast = useToast();
|
||||
|
||||
store.commit("setTicket", JSON.parse(window.initialTicket) as Ticket);
|
||||
store.commit("setTicket", JSON.parse(window.initialTicket) as Ticket);
|
||||
|
||||
const motives = computed(() => store.getters.getMotives as Motive[]);
|
||||
const ticket = computed(() => store.getters.getTicket as Ticket);
|
||||
const ticket = computed(() => store.getters.getTicket as Ticket);
|
||||
|
||||
const ticketHistory = computed(
|
||||
() => store.getters.getDistinctAddressesHistory,
|
||||
);
|
||||
const ticketHistory = computed(() => store.getters.getDistinctAddressesHistory);
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await store.dispatch("fetchMotives");
|
||||
await store.dispatch("fetchUserGroups");
|
||||
await store.dispatch("fetchUsers");
|
||||
} catch (error) {
|
||||
toast.error(error);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
ticketHistory,
|
||||
motives,
|
||||
ticket,
|
||||
};
|
||||
},
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await store.dispatch("fetchMotives");
|
||||
await store.dispatch("fetchUserGroups");
|
||||
await store.dispatch("fetchUsers");
|
||||
} catch (error) {
|
||||
toast.error(error as string);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
<div class="tab-content p-2">
|
||||
<div>
|
||||
<label class="col-form-label">
|
||||
{{ $t(`${activeTab}.title`) }}
|
||||
{{ activeTabTitle }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@ -36,12 +36,20 @@
|
||||
@click="activeTab = ''"
|
||||
class="btn btn-cancel"
|
||||
>
|
||||
{{ $t("ticket.cancel") }}
|
||||
{{
|
||||
trans(
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_CANCEL,
|
||||
)
|
||||
}}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="btn btn-save" type="submit">
|
||||
{{ $t("ticket.save") }}
|
||||
{{
|
||||
trans(
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_SAVE,
|
||||
)
|
||||
}}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
@ -78,7 +86,7 @@
|
||||
"
|
||||
>
|
||||
<i :class="actionIcons['set_motive']"></i>
|
||||
{{ $t("set_motive.title") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_SET_MOTIVE_TITLE) }}
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item p-2">
|
||||
@ -96,7 +104,7 @@
|
||||
"
|
||||
>
|
||||
<i :class="actionIcons['add_comment']"></i>
|
||||
{{ $t("add_comment.title") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_ADD_COMMENT_TITLE) }}
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item p-2">
|
||||
@ -114,7 +122,7 @@
|
||||
"
|
||||
>
|
||||
<i :class="actionIcons['addressees_state']"></i>
|
||||
{{ $t("add_addressee.title") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_TITLE) }}
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item p-2">
|
||||
@ -132,7 +140,7 @@
|
||||
"
|
||||
>
|
||||
<i :class="actionIcons['set_persons']"></i>
|
||||
Patients concernés
|
||||
{{ trans(CHILL_TICKET_TICKET_SET_PERSONS_TITLE) }}
|
||||
</button>
|
||||
</li>
|
||||
|
||||
@ -143,7 +151,7 @@
|
||||
@click="handleClick()"
|
||||
>
|
||||
<i class="fa fa-bolt"></i>
|
||||
{{ $t("ticket.close") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_CLOSE) }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
@ -151,10 +159,34 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, inject, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { useToast } from "vue-toast-notification";
|
||||
|
||||
// Component
|
||||
import MotiveSelectorComponent from "./MotiveSelectorComponent.vue";
|
||||
import AddresseeSelectorComponent from "./AddresseeSelectorComponent.vue";
|
||||
import AddCommentComponent from "./AddCommentComponent.vue";
|
||||
import PersonsSelectorComponent from "./PersonsSelectorComponent.vue";
|
||||
|
||||
// Translations
|
||||
import {
|
||||
trans,
|
||||
CHILL_TICKET_TICKET_ADD_ADDRESSEE_TITLE,
|
||||
CHILL_TICKET_TICKET_ADD_ADDRESSEE_ERROR,
|
||||
CHILL_TICKET_TICKET_ADD_ADDRESSEE_SUCCESS,
|
||||
CHILL_TICKET_TICKET_ADD_COMMENT_TITLE,
|
||||
CHILL_TICKET_TICKET_ADD_COMMENT_ERROR,
|
||||
CHILL_TICKET_TICKET_ADD_COMMENT_SUCCESS,
|
||||
CHILL_TICKET_TICKET_SET_MOTIVE_TITLE,
|
||||
CHILL_TICKET_TICKET_SET_MOTIVE_ERROR,
|
||||
CHILL_TICKET_TICKET_SET_MOTIVE_SUCCESS,
|
||||
CHILL_TICKET_TICKET_SET_PERSONS_TITLE,
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_CLOSE,
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_CANCEL,
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_SAVE,
|
||||
} from "translator";
|
||||
|
||||
// Types
|
||||
import {
|
||||
@ -164,140 +196,118 @@ import {
|
||||
} from "../../../../../../../ChillMainBundle/Resources/public/types";
|
||||
import { Comment, Motive, Ticket } from "../../../types";
|
||||
|
||||
// Component
|
||||
import MotiveSelectorComponent from "./MotiveSelectorComponent.vue";
|
||||
import AddresseeSelectorComponent from "./AddresseeSelectorComponent.vue";
|
||||
import AddCommentComponent from "./AddCommentComponent.vue";
|
||||
import PersonsSelectorComponent from "./PersonsSelectorComponent.vue";
|
||||
const store = useStore();
|
||||
const toast = useToast();
|
||||
|
||||
export default defineComponent({
|
||||
name: "ActionToolbarComponent",
|
||||
components: {
|
||||
PersonsSelectorComponent,
|
||||
AddCommentComponent,
|
||||
MotiveSelectorComponent,
|
||||
AddresseeSelectorComponent,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const { t } = useI18n();
|
||||
const toast = inject("toast") as any;
|
||||
const activeTab = ref(
|
||||
"" as
|
||||
| ""
|
||||
| "add_comment"
|
||||
| "set_motive"
|
||||
| "add_addressee"
|
||||
| "set_persons",
|
||||
);
|
||||
const activeTab = ref(
|
||||
"" as "" | "add_comment" | "set_motive" | "add_addressee" | "set_persons",
|
||||
);
|
||||
|
||||
const ticket = computed(() => store.getters.getTicket as Ticket);
|
||||
const motives = computed(() => store.getters.getMotives as Motive[]);
|
||||
const userGroups = computed(
|
||||
() => store.getters.getUserGroups as UserGroup[],
|
||||
);
|
||||
const users = computed(() => store.getters.getUsers as User[]);
|
||||
|
||||
const hasReturnPath = computed((): boolean => {
|
||||
const params = new URL(document.location.toString()).searchParams;
|
||||
return params.has("returnPath");
|
||||
});
|
||||
|
||||
const returnPath = computed((): string => {
|
||||
const params = new URL(document.location.toString()).searchParams;
|
||||
const returnPath = params.get("returnPath");
|
||||
|
||||
if (null === returnPath) {
|
||||
throw new Error(
|
||||
"there isn't any returnPath, please check the existence before",
|
||||
);
|
||||
}
|
||||
|
||||
return returnPath;
|
||||
});
|
||||
|
||||
const motive = ref(
|
||||
ticket.value.currentMotive
|
||||
? ticket.value.currentMotive
|
||||
: ({} as Motive),
|
||||
);
|
||||
const content = ref("" as Comment["content"]);
|
||||
const addressees = ref(
|
||||
ticket.value.currentAddressees as UserGroupOrUser[],
|
||||
);
|
||||
|
||||
async function submitAction() {
|
||||
try {
|
||||
switch (activeTab.value) {
|
||||
case "add_comment":
|
||||
if (!content.value) {
|
||||
toast.error(t("add_comment.error"));
|
||||
} else {
|
||||
await store.dispatch("createComment", {
|
||||
ticketId: ticket.value.id,
|
||||
content: content.value,
|
||||
});
|
||||
content.value = "";
|
||||
activeTab.value = "";
|
||||
toast.success(t("add_comment.success"));
|
||||
}
|
||||
break;
|
||||
case "set_motive":
|
||||
if (!motive.value.id) {
|
||||
toast.error(t("set_motive.error"));
|
||||
} else {
|
||||
await store.dispatch("createMotive", {
|
||||
ticketId: ticket.value.id,
|
||||
motive: motive.value,
|
||||
});
|
||||
activeTab.value = "";
|
||||
toast.success(t("set_motive.success"));
|
||||
}
|
||||
break;
|
||||
case "add_addressee":
|
||||
if (!addressees.value.length) {
|
||||
toast.error(t("add_addressee.error"));
|
||||
} else {
|
||||
await store.dispatch("setAdressees", {
|
||||
ticketId: ticket.value.id,
|
||||
addressees: addressees.value,
|
||||
});
|
||||
activeTab.value = "";
|
||||
toast.success(t("add_addressee.success"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
alert("Sera disponible plus tard");
|
||||
}
|
||||
|
||||
const closeAllActions = function () {
|
||||
activeTab.value = "";
|
||||
};
|
||||
|
||||
return {
|
||||
actionIcons: ref(store.getters.getActionIcons),
|
||||
activeTab,
|
||||
ticket,
|
||||
motives,
|
||||
motive,
|
||||
userGroups,
|
||||
addressees,
|
||||
users,
|
||||
content,
|
||||
submitAction,
|
||||
handleClick,
|
||||
hasReturnPath,
|
||||
returnPath,
|
||||
closeAllActions,
|
||||
};
|
||||
},
|
||||
const activeTabTitle = computed((): string => {
|
||||
switch (activeTab.value) {
|
||||
case "add_comment":
|
||||
return trans(CHILL_TICKET_TICKET_ADD_COMMENT_TITLE);
|
||||
case "set_motive":
|
||||
return trans(CHILL_TICKET_TICKET_SET_MOTIVE_TITLE);
|
||||
case "add_addressee":
|
||||
return trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_TITLE);
|
||||
case "set_persons":
|
||||
return trans(CHILL_TICKET_TICKET_SET_PERSONS_TITLE);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
const ticket = computed(() => store.getters.getTicket as Ticket);
|
||||
const motives = computed(() => store.getters.getMotives as Motive[]);
|
||||
const userGroups = computed(() => store.getters.getUserGroups as UserGroup[]);
|
||||
const users = computed(() => store.getters.getUsers as User[]);
|
||||
|
||||
const hasReturnPath = computed((): boolean => {
|
||||
const params = new URL(document.location.toString()).searchParams;
|
||||
return params.has("returnPath");
|
||||
});
|
||||
|
||||
const returnPath = computed((): string => {
|
||||
const params = new URL(document.location.toString()).searchParams;
|
||||
const returnPath = params.get("returnPath");
|
||||
|
||||
if (null === returnPath) {
|
||||
throw new Error(
|
||||
"there isn't any returnPath, please check the existence before",
|
||||
);
|
||||
}
|
||||
|
||||
return returnPath;
|
||||
});
|
||||
|
||||
const motive = ref(
|
||||
ticket.value.currentMotive ? ticket.value.currentMotive : ({} as Motive),
|
||||
);
|
||||
const content = ref("" as Comment["content"]);
|
||||
const addressees = ref(ticket.value.currentAddressees as UserGroupOrUser[]);
|
||||
|
||||
async function submitAction() {
|
||||
try {
|
||||
switch (activeTab.value) {
|
||||
case "add_comment":
|
||||
if (!content.value) {
|
||||
toast.error(trans(CHILL_TICKET_TICKET_ADD_COMMENT_ERROR));
|
||||
} else {
|
||||
await store.dispatch("createComment", {
|
||||
ticketId: ticket.value.id,
|
||||
content: content.value,
|
||||
});
|
||||
content.value = "";
|
||||
activeTab.value = "";
|
||||
toast.success(
|
||||
trans(CHILL_TICKET_TICKET_ADD_COMMENT_SUCCESS),
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "set_motive":
|
||||
if (!motive.value.id) {
|
||||
toast.error(trans(CHILL_TICKET_TICKET_SET_MOTIVE_ERROR));
|
||||
} else {
|
||||
await store.dispatch("createMotive", {
|
||||
ticketId: ticket.value.id,
|
||||
motive: motive.value,
|
||||
});
|
||||
activeTab.value = "";
|
||||
toast.success(
|
||||
trans(CHILL_TICKET_TICKET_SET_MOTIVE_SUCCESS),
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "add_addressee":
|
||||
if (!addressees.value.length) {
|
||||
toast.error(trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_ERROR));
|
||||
} else {
|
||||
await store.dispatch("setAdressees", {
|
||||
ticketId: ticket.value.id,
|
||||
addressees: addressees.value,
|
||||
});
|
||||
activeTab.value = "";
|
||||
toast.success(
|
||||
trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_SUCCESS),
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error(error as string);
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
alert("Sera disponible plus tard");
|
||||
}
|
||||
|
||||
function closeAllActions() {
|
||||
activeTab.value = "";
|
||||
}
|
||||
|
||||
const actionIcons = ref(store.getters.getActionIcons);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -6,35 +6,21 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch } from "vue";
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue";
|
||||
import CommentEditor from "ChillMainAssets/vuejs/_components/CommentEditor/CommentEditor.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AddCommentComponent",
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
CommentEditor,
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
const props = defineProps<{
|
||||
modelValue?: string;
|
||||
}>();
|
||||
|
||||
setup(props, ctx) {
|
||||
const content = ref(props.modelValue);
|
||||
const emit =
|
||||
defineEmits<(e: "update:modelValue", value: string | undefined) => void>();
|
||||
|
||||
watch(content, (content) => {
|
||||
ctx.emit("update:modelValue", content);
|
||||
});
|
||||
const content = ref(props.modelValue);
|
||||
|
||||
return {
|
||||
content,
|
||||
};
|
||||
},
|
||||
watch(content, (value) => {
|
||||
emit("update:modelValue", value);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -30,8 +30,11 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, computed, defineComponent, ref } from "vue";
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
|
||||
// Components
|
||||
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
|
||||
|
||||
// Types
|
||||
import {
|
||||
@ -39,43 +42,32 @@ import {
|
||||
UserGroup,
|
||||
UserGroupOrUser,
|
||||
} from "../../../../../../../ChillMainBundle/Resources/public/types";
|
||||
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AddresseeComponent",
|
||||
components: { UserRenderBoxBadge },
|
||||
props: {
|
||||
addressees: {
|
||||
type: Array as PropType<UserGroupOrUser[]>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const userGroups = computed(
|
||||
() =>
|
||||
props.addressees.filter(
|
||||
(addressee) =>
|
||||
addressee.type == "user_group" &&
|
||||
addressee.excludeKey == "",
|
||||
) as UserGroup[],
|
||||
);
|
||||
const userGroupLevels = computed(
|
||||
() =>
|
||||
props.addressees.filter(
|
||||
(addressee) =>
|
||||
addressee.type == "user_group" &&
|
||||
addressee.excludeKey == "level",
|
||||
) as UserGroup[],
|
||||
);
|
||||
const users = computed(
|
||||
() =>
|
||||
props.addressees.filter(
|
||||
(addressee) => addressee.type == "user",
|
||||
) as User[],
|
||||
);
|
||||
return { userGroups, users, userGroupLevels };
|
||||
},
|
||||
});
|
||||
const props = defineProps<{ addressees: UserGroupOrUser[] }>();
|
||||
|
||||
const userGroups = computed(
|
||||
() =>
|
||||
props.addressees.filter(
|
||||
(addressee: UserGroupOrUser) =>
|
||||
addressee.type == "user_group" && addressee.excludeKey == "",
|
||||
) as UserGroup[],
|
||||
);
|
||||
|
||||
const userGroupLevels = computed(
|
||||
() =>
|
||||
props.addressees.filter(
|
||||
(addressee: UserGroupOrUser) =>
|
||||
addressee.type == "user_group" &&
|
||||
addressee.excludeKey == "level",
|
||||
) as UserGroup[],
|
||||
);
|
||||
|
||||
const users = computed(
|
||||
() =>
|
||||
props.addressees.filter(
|
||||
(addressee: UserGroupOrUser) => addressee.type == "user",
|
||||
) as User[],
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
@ -66,9 +66,14 @@
|
||||
<add-persons
|
||||
:options="addPersonsOptions"
|
||||
key="add-person-ticket"
|
||||
buttonTitle="add_addressee.user_label"
|
||||
modalTitle="add_addressee.user_label"
|
||||
ref="addPersons"
|
||||
:buttonTitle="
|
||||
trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_USER_LABEL)
|
||||
"
|
||||
:modalTitle="
|
||||
trans(CHILL_TICKET_TICKET_ADD_ADDRESSEE_USER_LABEL)
|
||||
"
|
||||
:selected="selectedValues"
|
||||
:suggested="suggestedValues"
|
||||
@addNewPersons="addNewEntity"
|
||||
/>
|
||||
<div class="p-2">
|
||||
@ -84,145 +89,120 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, computed, defineComponent, ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
// Types
|
||||
import { User, UserGroup, UserGroupOrUser } from "ChillMainAssets/types";
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, defineProps, defineEmits } from "vue";
|
||||
|
||||
// Components
|
||||
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AddresseeSelectorComponent",
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Array as PropType<UserGroupOrUser[]>,
|
||||
default: [],
|
||||
required: false,
|
||||
},
|
||||
userGroups: {
|
||||
type: Array as PropType<UserGroup[]>,
|
||||
required: true,
|
||||
},
|
||||
users: {
|
||||
type: Array as PropType<User[]>,
|
||||
required: true,
|
||||
},
|
||||
// Types
|
||||
import type { User, UserGroup, UserGroupOrUser } from "ChillMainAssets/types";
|
||||
import { SearchOptions, Suggestion } from "ChillPersonAssets/types";
|
||||
import type { addNewPersons } from "../../../types";
|
||||
|
||||
// Translations
|
||||
import {
|
||||
CHILL_TICKET_TICKET_ADD_ADDRESSEE_USER_LABEL,
|
||||
trans,
|
||||
} from "translator";
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: UserGroupOrUser[];
|
||||
userGroups: UserGroup[];
|
||||
users: User[];
|
||||
}>();
|
||||
|
||||
const selectedValues = ref<Suggestion[]>([]);
|
||||
const suggestedValues = ref<Suggestion[]>([]);
|
||||
|
||||
const emit =
|
||||
defineEmits<(e: "update:modelValue", value: UserGroupOrUser[]) => void>();
|
||||
|
||||
const addressees = ref<UserGroupOrUser[]>([...(props.modelValue ?? [])]);
|
||||
|
||||
const userGroupsInit = [
|
||||
...(props.modelValue ?? []).filter(
|
||||
(addressee: UserGroupOrUser) => addressee.type == "user_group",
|
||||
),
|
||||
] as UserGroup[];
|
||||
|
||||
const userGroupLevel = ref<UserGroup | Record<string, never>>(
|
||||
(userGroupsInit.filter(
|
||||
(userGroup: UserGroup) => userGroup.excludeKey == "level",
|
||||
)[0] as UserGroup) ?? {},
|
||||
);
|
||||
|
||||
const userGroup = ref<UserGroup[]>(
|
||||
userGroupsInit.filter(
|
||||
(userGroup: UserGroup) => userGroup.excludeKey == "",
|
||||
) as UserGroup[],
|
||||
);
|
||||
|
||||
const users = ref<User[]>([
|
||||
...(props.modelValue ?? []).filter(
|
||||
(addressee: UserGroupOrUser) => addressee.type == "user",
|
||||
),
|
||||
] as User[]);
|
||||
|
||||
const addPersonsOptions = {
|
||||
uniq: false,
|
||||
type: ["user"],
|
||||
priority: null,
|
||||
button: {
|
||||
size: "btn-sm",
|
||||
class: "btn-submit",
|
||||
},
|
||||
components: {
|
||||
AddPersons,
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
} as SearchOptions;
|
||||
|
||||
setup(props, ctx) {
|
||||
const addressees = ref([...props.modelValue] as UserGroupOrUser[]);
|
||||
const userGroups = [
|
||||
...props.modelValue.filter(
|
||||
(addressee) => addressee.type == "user_group",
|
||||
),
|
||||
] as UserGroup[];
|
||||
function getUserGroupBtnColor(userGroup: UserGroup) {
|
||||
return [
|
||||
`color: ${userGroup.foregroundColor};
|
||||
.btn-check:checked + .btn-${userGroup.id} {
|
||||
color: ${userGroup.foregroundColor};
|
||||
background-color: ${userGroup.backgroundColor};
|
||||
}`,
|
||||
];
|
||||
}
|
||||
|
||||
const userGroupLevel = ref(
|
||||
userGroups.filter(
|
||||
(userGroup) => userGroup.excludeKey == "level",
|
||||
)[0] as UserGroup | {},
|
||||
);
|
||||
const userGroup = ref(
|
||||
userGroups.filter(
|
||||
(userGroup) => userGroup.excludeKey == "",
|
||||
) as UserGroup[],
|
||||
);
|
||||
const users = ref([
|
||||
...props.modelValue.filter((addressee) => addressee.type == "user"),
|
||||
] as User[]);
|
||||
const addPersons = ref();
|
||||
function addNewEntity(datas: addNewPersons) {
|
||||
const { selected } = datas;
|
||||
users.value = selected.map((selected) => selected.result);
|
||||
addressees.value = addressees.value.filter(
|
||||
(addressee) => addressee.type === "user_group",
|
||||
);
|
||||
addressees.value = [...addressees.value, ...users.value];
|
||||
emit("update:modelValue", addressees.value);
|
||||
selectedValues.value = [];
|
||||
suggestedValues.value = [];
|
||||
}
|
||||
|
||||
const { t } = useI18n();
|
||||
function removeUser(user: User) {
|
||||
users.value.splice(users.value.indexOf(user), 1);
|
||||
addressees.value = addressees.value.filter(
|
||||
(addressee) => addressee.id !== user.id,
|
||||
);
|
||||
emit("update:modelValue", addressees.value);
|
||||
}
|
||||
|
||||
function getUserGroupBtnColor(userGroup: UserGroup) {
|
||||
return [
|
||||
`color: ${userGroup.foregroundColor};
|
||||
.btn-check:checked + .btn-${userGroup.id} {
|
||||
color: ${userGroup.foregroundColor};
|
||||
background-color: ${userGroup.backgroundColor};
|
||||
}`,
|
||||
];
|
||||
}
|
||||
function addNewEntity(datas: any) {
|
||||
const { selected, modal } = datas;
|
||||
users.value = selected.map((selected: any) => selected.result);
|
||||
addressees.value = addressees.value.filter(
|
||||
(addressee) => addressee.type === "user_group",
|
||||
);
|
||||
addressees.value = [...addressees.value, ...users.value];
|
||||
ctx.emit("update:modelValue", addressees.value);
|
||||
addPersons.value.resetSearch();
|
||||
modal.showModal = false;
|
||||
}
|
||||
watch(userGroupLevel, (userGroupLevelAdd, userGroupLevelRem) => {
|
||||
const index = addressees.value.indexOf(userGroupLevelRem as UserGroup);
|
||||
if (index !== -1) {
|
||||
addressees.value.splice(index, 1);
|
||||
}
|
||||
addressees.value.push(userGroupLevelAdd as UserGroup);
|
||||
emit("update:modelValue", addressees.value);
|
||||
});
|
||||
|
||||
const addPersonsOptions = computed(() => {
|
||||
return {
|
||||
uniq: false,
|
||||
type: ["user"],
|
||||
priority: null,
|
||||
button: {
|
||||
size: "btn-sm",
|
||||
class: "btn-submit",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
function removeUser(user: User) {
|
||||
users.value.splice(users.value.indexOf(user), 1);
|
||||
addressees.value = addressees.value.filter(
|
||||
(addressee) => addressee.id !== user.id,
|
||||
);
|
||||
ctx.emit("update:modelValue", addressees.value);
|
||||
}
|
||||
|
||||
watch(userGroupLevel, (userGroupLevelAdd, userGroupLevelRem) => {
|
||||
const index = addressees.value.indexOf(
|
||||
userGroupLevelRem as UserGroup,
|
||||
);
|
||||
if (index !== -1) {
|
||||
addressees.value.splice(index, 1);
|
||||
}
|
||||
addressees.value.push(userGroupLevelAdd as UserGroup);
|
||||
ctx.emit("update:modelValue", addressees.value);
|
||||
});
|
||||
|
||||
watch(userGroup, (userGroupAdd) => {
|
||||
const userGroupLevel = addressees.value.filter(
|
||||
(addressee) =>
|
||||
addressee.type == "user_group" &&
|
||||
addressee.excludeKey == "level",
|
||||
) as UserGroup[];
|
||||
const users = addressees.value.filter(
|
||||
(addressee) => addressee.type == "user",
|
||||
) as User[];
|
||||
addressees.value = [...users, ...userGroupLevel, ...userGroupAdd];
|
||||
ctx.emit("update:modelValue", addressees.value);
|
||||
});
|
||||
|
||||
return {
|
||||
addressees,
|
||||
userGroupLevel,
|
||||
userGroup,
|
||||
users,
|
||||
addPersons,
|
||||
addPersonsOptions,
|
||||
addNewEntity,
|
||||
removeUser,
|
||||
getUserGroupBtnColor,
|
||||
customUserGroupLabel(selectedUserGroup: UserGroup) {
|
||||
return selectedUserGroup.label
|
||||
? selectedUserGroup.label.fr
|
||||
: t("add_addresseeuser_group_label");
|
||||
},
|
||||
};
|
||||
},
|
||||
watch(userGroup, (userGroupAdd) => {
|
||||
const userGroupLevelArr = addressees.value.filter(
|
||||
(addressee) =>
|
||||
addressee.type == "user_group" && addressee.excludeKey == "level",
|
||||
) as UserGroup[];
|
||||
const usersArr = addressees.value.filter(
|
||||
(addressee) => addressee.type == "user",
|
||||
) as User[];
|
||||
addressees.value = [...usersArr, ...userGroupLevelArr, ...userGroupAdd];
|
||||
emit("update:modelValue", addressees.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
{{ ticket.currentMotive.label.fr }}
|
||||
</h1>
|
||||
<p class="chill-no-data-statement" v-else>
|
||||
{{ $t("banner.no_motive") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_BANNER_NO_MOTIVE) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -18,13 +18,13 @@
|
||||
class="badge text-bg-chill-green text-white"
|
||||
style="font-size: 1rem"
|
||||
>
|
||||
{{ $t("banner.open") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_BANNER_OPEN) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end">
|
||||
<p class="created-at-timespan" v-if="ticket.createdAt">
|
||||
{{
|
||||
$t("banner.since", {
|
||||
trans(CHILL_TICKET_TICKET_BANNER_SINCE, {
|
||||
time: since,
|
||||
})
|
||||
}}
|
||||
@ -39,7 +39,7 @@
|
||||
<div class="row justify-content-between">
|
||||
<div class="col-md-6 col-sm-12 ps-md-5 ps-xxl-0">
|
||||
<h3 class="text-primary">
|
||||
{{ $t("banner.concerned_patient") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_BANNER_CONCERNED_USAGER) }}
|
||||
</h3>
|
||||
<on-the-fly
|
||||
v-for="person in ticket.currentPersons"
|
||||
@ -49,10 +49,13 @@
|
||||
:buttonText="person.textAge"
|
||||
:displayBadge="'true' === 'true'"
|
||||
action="show"
|
||||
CHILL_TICKET_TICKET_BANNER_CONCERNED_USAGER
|
||||
></on-the-fly>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<h3 class="text-primary">{{ $t("banner.speaker") }}</h3>
|
||||
<h3 class="text-primary">
|
||||
{{ trans(CHILL_TICKET_TICKET_BANNER_SPEAKER) }}
|
||||
</h3>
|
||||
<addressee-component
|
||||
:addressees="ticket.currentAddressees"
|
||||
/>
|
||||
@ -69,81 +72,91 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, computed, defineComponent, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from "vue";
|
||||
|
||||
// Components
|
||||
import PersonRenderBox from "../../../../../../../ChillPersonBundle/Resources/public/vuejs/_components/Entity/PersonRenderBox.vue";
|
||||
import AddresseeComponent from "./AddresseeComponent.vue";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
|
||||
// Types
|
||||
import { Ticket } from "../../../types";
|
||||
import { ISOToDatetime } from "../../../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "BannerComponent",
|
||||
props: {
|
||||
ticket: {
|
||||
type: Object as PropType<Ticket>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
OnTheFly,
|
||||
PersonRenderBox,
|
||||
AddresseeComponent,
|
||||
},
|
||||
setup(props) {
|
||||
const { t } = useI18n();
|
||||
const today = ref(new Date());
|
||||
const createdAt = ref(props.ticket.createdAt);
|
||||
// Translations
|
||||
import {
|
||||
trans,
|
||||
CHILL_TICKET_TICKET_BANNER_NO_MOTIVE,
|
||||
CHILL_TICKET_TICKET_BANNER_OPEN,
|
||||
CHILL_TICKET_TICKET_BANNER_SINCE,
|
||||
CHILL_TICKET_TICKET_BANNER_CONCERNED_USAGER,
|
||||
CHILL_TICKET_TICKET_BANNER_SPEAKER,
|
||||
CHILL_TICKET_TICKET_BANNER_DAYS,
|
||||
CHILL_TICKET_TICKET_BANNER_HOURS,
|
||||
CHILL_TICKET_TICKET_BANNER_MINUTES,
|
||||
CHILL_TICKET_TICKET_BANNER_SECONDS,
|
||||
CHILL_TICKET_TICKET_BANNER_AND,
|
||||
} from "translator";
|
||||
|
||||
setInterval(function () {
|
||||
today.value = new Date();
|
||||
}, 5000);
|
||||
const props = defineProps<{
|
||||
ticket: Ticket;
|
||||
}>();
|
||||
|
||||
const since = computed(() => {
|
||||
if (null === createdAt.value) {
|
||||
return "";
|
||||
}
|
||||
const date = ISOToDatetime(createdAt.value.datetime);
|
||||
const today = ref(new Date());
|
||||
const createdAt = ref(props.ticket.createdAt);
|
||||
|
||||
if (null === date) {
|
||||
return "";
|
||||
}
|
||||
setInterval(() => {
|
||||
today.value = new Date();
|
||||
}, 5000);
|
||||
|
||||
const timeDiff = Math.abs(today.value.getTime() - date.getTime());
|
||||
const daysDiff = Math.floor(timeDiff / (1000 * 3600 * 24));
|
||||
const hoursDiff = Math.floor(
|
||||
(timeDiff % (1000 * 3600 * 24)) / (1000 * 3600),
|
||||
);
|
||||
const minutesDiff = Math.floor(
|
||||
(timeDiff % (1000 * 3600)) / (1000 * 60),
|
||||
);
|
||||
const secondsDiff = Math.floor((timeDiff % (1000 * 60)) / 1000);
|
||||
const since = computed(() => {
|
||||
if (createdAt.value == null) {
|
||||
return "";
|
||||
}
|
||||
const date = ISOToDatetime(createdAt.value.datetime);
|
||||
|
||||
if (daysDiff < 1 && hoursDiff < 1 && minutesDiff < 1) {
|
||||
return `${t("banner.seconds", { count: secondsDiff })}`;
|
||||
} else if (daysDiff < 1 && hoursDiff < 1) {
|
||||
return `${t("banner.minutes", { count: minutesDiff })}`;
|
||||
} else if (daysDiff < 1) {
|
||||
return `${t("banner.hours", { count: hoursDiff })}
|
||||
${t("banner.minutes", { count: minutesDiff })}`;
|
||||
} else {
|
||||
return `${t("banner.days", { count: daysDiff })}, ${t(
|
||||
"banner.hours",
|
||||
{
|
||||
count: hoursDiff,
|
||||
},
|
||||
)} ${t("banner.minutes", {
|
||||
count: minutesDiff,
|
||||
})}`;
|
||||
}
|
||||
if (date == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const timeDiff = Math.abs(today.value.getTime() - date.getTime());
|
||||
const daysDiff = Math.floor(timeDiff / (1000 * 3600 * 24));
|
||||
const hoursDiff = Math.floor(
|
||||
(timeDiff % (1000 * 3600 * 24)) / (1000 * 3600),
|
||||
);
|
||||
const minutesDiff = Math.floor((timeDiff % (1000 * 3600)) / (1000 * 60));
|
||||
const secondsDiff = Math.floor((timeDiff % (1000 * 60)) / 1000);
|
||||
|
||||
// On construit la liste des parties à afficher
|
||||
const parts: string[] = [];
|
||||
if (daysDiff > 0) {
|
||||
parts.push(trans(CHILL_TICKET_TICKET_BANNER_DAYS, { count: daysDiff }));
|
||||
}
|
||||
if (hoursDiff > 0 || daysDiff > 0) {
|
||||
parts.push(
|
||||
trans(CHILL_TICKET_TICKET_BANNER_HOURS, { count: hoursDiff }),
|
||||
);
|
||||
}
|
||||
if (minutesDiff > 0 || hoursDiff > 0 || daysDiff > 0) {
|
||||
parts.push(
|
||||
trans(CHILL_TICKET_TICKET_BANNER_MINUTES, { count: minutesDiff }),
|
||||
);
|
||||
}
|
||||
if (parts.length === 0) {
|
||||
return trans(CHILL_TICKET_TICKET_BANNER_SECONDS, {
|
||||
count: secondsDiff,
|
||||
});
|
||||
|
||||
return { since };
|
||||
},
|
||||
}
|
||||
if (parts.length > 1) {
|
||||
const last = parts.pop();
|
||||
return (
|
||||
parts.join(", ") +
|
||||
" " +
|
||||
trans(CHILL_TICKET_TICKET_BANNER_AND) +
|
||||
" " +
|
||||
last
|
||||
);
|
||||
}
|
||||
return parts[0];
|
||||
});
|
||||
</script>
|
||||
|
@ -10,10 +10,10 @@
|
||||
open-direction="top"
|
||||
:multiple="false"
|
||||
:searchable="true"
|
||||
:placeholder="$t('set_motive.label')"
|
||||
:select-label="$t('multiselect.select_label')"
|
||||
:deselect-label="$t('multiselect.deselect_label')"
|
||||
:selected-label="$t('multiselect.selected_label')"
|
||||
:placeholder="trans(CHILL_TICKET_TICKET_SET_MOTIVE_LABEL)"
|
||||
:select-label="trans(MULTISELECT_SELECT_LABEL)"
|
||||
:deselect-label="trans(MULTISELECT_DESELECT_LABEL)"
|
||||
:selected-label="trans(MULTISELECT_SELECTED_LABEL)"
|
||||
:options="motives"
|
||||
v-model="motive"
|
||||
class="mb-4"
|
||||
@ -22,47 +22,46 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent, ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue";
|
||||
import VueMultiselect from "vue-multiselect";
|
||||
|
||||
// Types
|
||||
import { Motive } from "../../../types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "MotiveSelectorComponent",
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Object as PropType<Motive>,
|
||||
required: false,
|
||||
},
|
||||
motives: {
|
||||
type: Object as PropType<Motive[]>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
VueMultiselect,
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
// Translations
|
||||
import {
|
||||
trans,
|
||||
CHILL_TICKET_TICKET_SET_MOTIVE_LABEL,
|
||||
MULTISELECT_SELECT_LABEL,
|
||||
MULTISELECT_DESELECT_LABEL,
|
||||
MULTISELECT_SELECTED_LABEL,
|
||||
} from "translator";
|
||||
|
||||
setup(props, ctx) {
|
||||
const motive = ref(props.modelValue);
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
modelValue?: Motive;
|
||||
motives: Motive[];
|
||||
}>();
|
||||
|
||||
watch(motive, (motive) => {
|
||||
ctx.emit("update:modelValue", motive);
|
||||
});
|
||||
const emit =
|
||||
defineEmits<(e: "update:modelValue", value: Motive | undefined) => void>();
|
||||
|
||||
return {
|
||||
motive,
|
||||
customLabel(motive: Motive) {
|
||||
return motive.label ? motive.label.fr : t("set_motive.label");
|
||||
},
|
||||
};
|
||||
},
|
||||
const motive = ref(props.modelValue);
|
||||
|
||||
watch(motive, (val) => {
|
||||
emit("update:modelValue", val);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
motive.value = val;
|
||||
},
|
||||
);
|
||||
|
||||
function customLabel(motive: Motive) {
|
||||
return motive?.label?.fr ?? trans(CHILL_TICKET_TICKET_SET_MOTIVE_LABEL);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -1,12 +1,68 @@
|
||||
<template>
|
||||
<div>
|
||||
<div style="display: flex; flex-direction: column; align-items: center">
|
||||
<add-persons
|
||||
:options="addPersonsOptions"
|
||||
key="add-person-selector"
|
||||
:buttonTitle="trans(CHILL_TICKET_TICKET_SET_PERSONS_USER_LABEL)"
|
||||
:modalTitle="trans(CHILL_TICKET_TICKET_SET_PERSONS_USER_LABEL)"
|
||||
:selected="selectedValues"
|
||||
:suggested="suggestedValues"
|
||||
@addNewPersons="addNewEntity"
|
||||
/>
|
||||
<div class="p-2">
|
||||
<ul class="list-suggest inline remove-items">
|
||||
<li v-for="person in currentPersons" :key="person.id">
|
||||
<span
|
||||
:title="`${person.firstName} ${person.lastName}`"
|
||||
@click="removePerson(person)"
|
||||
>
|
||||
{{ `${person.firstName} ${person.lastName}` }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="record_actions">
|
||||
<li class="cancel">
|
||||
<button
|
||||
class="btn btn-cancel"
|
||||
type="button"
|
||||
@click="emit('closeRequested')"
|
||||
>
|
||||
{{ trans(CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_CANCEL) }}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="btn btn-save" type="submit" @click.prevent="save">
|
||||
{{ trans(CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_SAVE) }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, inject, reactive, ref } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
|
||||
import { computed, inject, reactive } from "vue";
|
||||
import { Ticket } from "../../../types";
|
||||
import { Person } from "../../../../../../../ChillPersonBundle/Resources/public/types";
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
import { ToastPluginApi } from "vue-toast-notification";
|
||||
|
||||
// Components
|
||||
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
|
||||
|
||||
// Types
|
||||
import { SearchOptions, Suggestion, Person } from "ChillPersonAssets/types";
|
||||
import { Ticket } from "../../../types";
|
||||
|
||||
// Translations
|
||||
import {
|
||||
trans,
|
||||
CHILL_TICKET_TICKET_SET_PERSONS_USER_LABEL,
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_CANCEL,
|
||||
CHILL_TICKET_TICKET_ACTIONS_TOOLBAR_SAVE,
|
||||
CHILL_TICKET_TICKET_SET_PERSONS_SUCCESS,
|
||||
} from "translator";
|
||||
|
||||
const emit = defineEmits<(e: "closeRequested") => void>();
|
||||
|
||||
const store = useStore();
|
||||
@ -19,9 +75,13 @@ const addPersonsOptions = {
|
||||
type: ["person"],
|
||||
priority: null,
|
||||
button: {
|
||||
size: "btn-sm",
|
||||
class: "btn-submit",
|
||||
},
|
||||
};
|
||||
} as SearchOptions;
|
||||
|
||||
const selectedValues = ref<Suggestion[]>([]);
|
||||
const suggestedValues = ref<Suggestion[]>([]);
|
||||
|
||||
const added: Person[] = reactive([]);
|
||||
const removed: Person[] = reactive([]);
|
||||
@ -50,14 +110,12 @@ const removePerson = (p: Person) => {
|
||||
removed.push(p);
|
||||
};
|
||||
|
||||
const addNewEntity = (n: {
|
||||
modal: { showModal: boolean };
|
||||
selected: { result: Person }[];
|
||||
}) => {
|
||||
n.modal.showModal = false;
|
||||
const addNewEntity = (n: { selected: { result: Person }[] }) => {
|
||||
for (let p of n.selected) {
|
||||
added.push(p.result);
|
||||
}
|
||||
selectedValues.value = [];
|
||||
suggestedValues.value = [];
|
||||
};
|
||||
|
||||
const save = async function (): Promise<void> {
|
||||
@ -65,64 +123,14 @@ const save = async function (): Promise<void> {
|
||||
await store.dispatch("setPersons", {
|
||||
persons: computeCurrentPersons(persons.value, added, removed),
|
||||
});
|
||||
toast.success("Patients concernés sauvegardés");
|
||||
} catch (e: any) {
|
||||
console.error("error while saving", e);
|
||||
toast.error((e as Error).message);
|
||||
toast.success(trans(CHILL_TICKET_TICKET_SET_PERSONS_SUCCESS));
|
||||
} catch (error) {
|
||||
toast.error((error as Error).message);
|
||||
return Promise.resolve();
|
||||
}
|
||||
emit("closeRequested");
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<ul v-if="currentPersons.length > 0" class="person-list">
|
||||
<li v-for="person in currentPersons" :key="person.id">
|
||||
<on-the-fly
|
||||
:type="person.type"
|
||||
:id="person.id"
|
||||
:buttonText="person.textAge"
|
||||
:displayBadge="'true' === 'true'"
|
||||
action="show"
|
||||
></on-the-fly>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-delete remove-person"
|
||||
@click="removePerson(person)"
|
||||
></button>
|
||||
</li>
|
||||
</ul>
|
||||
<p v-else class="chill-no-data-statement">Aucun patient</p>
|
||||
</div>
|
||||
<ul class="record_actions">
|
||||
<li class="cancel">
|
||||
<button
|
||||
class="btn btn-cancel"
|
||||
type="button"
|
||||
@click="emit('closeRequested')"
|
||||
>
|
||||
{{ $t("ticket.cancel") }}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<add-persons
|
||||
:options="addPersonsOptions"
|
||||
key="add-person-ticket"
|
||||
buttonTitle="set_persons.user_label"
|
||||
modalTitle="set_persons.user_label"
|
||||
ref="addPersons"
|
||||
@addNewPersons="addNewEntity"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<button class="btn btn-save" type="submit" @click.prevent="save">
|
||||
{{ $t("ticket.save") }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
ul.person-list {
|
||||
list-style-type: none;
|
||||
|
@ -3,31 +3,16 @@
|
||||
<addressee-component :addressees="addressees" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from "vue";
|
||||
|
||||
<script setup lang="ts">
|
||||
// Types
|
||||
import { UserGroupOrUser } from "../../../../../../../ChillMainBundle/Resources/public/types";
|
||||
|
||||
// Components
|
||||
import AddresseeComponent from "./AddresseeComponent.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TicketHistoryAddresseeComponenvt",
|
||||
props: {
|
||||
addressees: {
|
||||
type: Array as PropType<UserGroupOrUser[]>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
AddresseeComponent,
|
||||
},
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
defineProps<{
|
||||
addressees: UserGroupOrUser[];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
@ -6,55 +6,41 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from "vue";
|
||||
<script setup lang="ts">
|
||||
import { marked } from "marked";
|
||||
import DOMPurify from "dompurify";
|
||||
|
||||
// Types
|
||||
import { Comment } from "../../../types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TicketHistoryCommentComponent",
|
||||
props: {
|
||||
commentHistory: {
|
||||
type: Object as PropType<Comment>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const preprocess = (markdown: string): string => {
|
||||
return markdown;
|
||||
};
|
||||
defineProps<{ commentHistory: Comment }>();
|
||||
|
||||
const postprocess = (html: string): string => {
|
||||
DOMPurify.addHook("afterSanitizeAttributes", (node: any) => {
|
||||
if ("target" in node) {
|
||||
node.setAttribute("target", "_blank");
|
||||
node.setAttribute("rel", "noopener noreferrer");
|
||||
}
|
||||
if (
|
||||
!node.hasAttribute("target") &&
|
||||
(node.hasAttribute("xlink:href") ||
|
||||
node.hasAttribute("href"))
|
||||
) {
|
||||
node.setAttribute("xlink:show", "new");
|
||||
}
|
||||
});
|
||||
const preprocess = (markdown: string): string => {
|
||||
return markdown;
|
||||
};
|
||||
|
||||
return DOMPurify.sanitize(html);
|
||||
};
|
||||
const postprocess = (html: string): string => {
|
||||
DOMPurify.addHook("afterSanitizeAttributes", (node: Element) => {
|
||||
if ("target" in node) {
|
||||
node.setAttribute("target", "_blank");
|
||||
node.setAttribute("rel", "noopener noreferrer");
|
||||
}
|
||||
if (
|
||||
!node.hasAttribute("target") &&
|
||||
(node.hasAttribute("xlink:href") || node.hasAttribute("href"))
|
||||
) {
|
||||
node.setAttribute("xlink:show", "new");
|
||||
}
|
||||
});
|
||||
|
||||
const convertMarkdownToHtml = (markdown: string): string => {
|
||||
marked.use({ hooks: { postprocess, preprocess } });
|
||||
const rawHtml = marked(markdown) as string;
|
||||
return rawHtml;
|
||||
};
|
||||
return {
|
||||
convertMarkdownToHtml,
|
||||
};
|
||||
},
|
||||
});
|
||||
return DOMPurify.sanitize(html);
|
||||
};
|
||||
|
||||
const convertMarkdownToHtml = (markdown: string): string => {
|
||||
marked.use({ hooks: { postprocess, preprocess } });
|
||||
const rawHtml = marked(markdown) as string;
|
||||
return rawHtml;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
@ -1,4 +1,9 @@
|
||||
<template>
|
||||
<p>Ticket créé par {{ props.by.text }}</p>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Types
|
||||
import { User } from "../../../../../../../ChillMainBundle/Resources/public/types";
|
||||
|
||||
interface TicketHistoryCreateComponentConfig {
|
||||
@ -8,8 +13,4 @@ interface TicketHistoryCreateComponentConfig {
|
||||
const props = defineProps<TicketHistoryCreateComponentConfig>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p>Ticket créé par {{ props.by.text }}</p>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
@ -50,9 +50,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent, ref, computed } from "vue";
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
// Types
|
||||
@ -66,72 +65,41 @@ import TicketHistoryCommentComponent from "./TicketHistoryCommentComponent.vue";
|
||||
import TicketHistoryAddresseeComponent from "./TicketHistoryAddresseeComponent.vue";
|
||||
import TicketHistoryCreateComponent from "./TicketHistoryCreateComponent.vue";
|
||||
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
|
||||
|
||||
// Utils
|
||||
import { ISOToDatetime } from "../../../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TicketHistoryListComponent",
|
||||
components: {
|
||||
UserRenderBoxBadge,
|
||||
TicketHistoryPersonComponent,
|
||||
TicketHistoryMotiveComponent,
|
||||
TicketHistoryCommentComponent,
|
||||
TicketHistoryAddresseeComponent,
|
||||
TicketHistoryCreateComponent,
|
||||
},
|
||||
props: {
|
||||
history: {
|
||||
type: Array as PropType<TicketHistoryLine[]>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
defineProps<{ history: TicketHistoryLine[] }>();
|
||||
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const store = useStore();
|
||||
|
||||
const explainSentence = (history: TicketHistoryLine): string => {
|
||||
switch (history.event_type) {
|
||||
case "add_comment":
|
||||
return "Nouveau commentaire";
|
||||
case "addressees_state":
|
||||
return "Attributions";
|
||||
case "persons_state":
|
||||
return "Patients concernés";
|
||||
case "set_motive":
|
||||
return "Nouveau motifs";
|
||||
case "create_ticket":
|
||||
return "Ticket créé";
|
||||
}
|
||||
};
|
||||
const actionIcons = ref(store.getters.getActionIcons);
|
||||
|
||||
function formatDate(d: DateTime): string {
|
||||
const date = ISOToDatetime(d.datetime);
|
||||
|
||||
if (date === null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const month = date.toLocaleString("default", { month: "long" });
|
||||
return `${date.getDate()} ${month} ${date.getFullYear()}, ${date.toLocaleTimeString()}`;
|
||||
}
|
||||
|
||||
return {
|
||||
actionIcons: ref(store.getters.getActionIcons),
|
||||
formatDate,
|
||||
explainSentence,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
div.history-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
& > div.description {
|
||||
margin-right: auto;
|
||||
function explainSentence(history: TicketHistoryLine): string {
|
||||
switch (history.event_type) {
|
||||
case "add_comment":
|
||||
return "Nouveau commentaire";
|
||||
case "addressees_state":
|
||||
return "Attributions";
|
||||
case "persons_state":
|
||||
return "Usagés concernés";
|
||||
case "set_motive":
|
||||
return "Nouveau motifs";
|
||||
case "create_ticket":
|
||||
return "Ticket créé";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
function formatDate(d: DateTime): string {
|
||||
const date = ISOToDatetime(d.datetime);
|
||||
|
||||
if (date === null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const month = date.toLocaleString("default", { month: "long" });
|
||||
return `${date.getDate()} ${month} ${date.getFullYear()}, ${date.toLocaleTimeString()}`;
|
||||
}
|
||||
</script>
|
||||
|
@ -4,23 +4,11 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from "vue";
|
||||
|
||||
<script lang="ts" setup>
|
||||
// Types
|
||||
import { MotiveHistory } from "../../../types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TicketHistoryMotiveComponent",
|
||||
props: {
|
||||
motiveHistory: {
|
||||
type: Object as PropType<MotiveHistory>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
setup() {},
|
||||
});
|
||||
defineProps<{ motiveHistory: MotiveHistory }>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
@ -6,7 +6,7 @@
|
||||
:type="person.type"
|
||||
:id="person.id"
|
||||
:buttonText="person.textAge"
|
||||
:displayBadge="'true' === 'true'"
|
||||
:displayBadge="true"
|
||||
action="show"
|
||||
></on-the-fly>
|
||||
</li>
|
||||
@ -14,27 +14,13 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from "vue";
|
||||
|
||||
// Type
|
||||
import { PersonsState } from "../../../types";
|
||||
<script setup lang="ts">
|
||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TicketHistoryPersonComponent",
|
||||
props: {
|
||||
personHistory: {
|
||||
type: Object as PropType<PersonsState>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
OnTheFly,
|
||||
},
|
||||
// Types
|
||||
import { PersonsState } from "../../../types";
|
||||
|
||||
setup() {},
|
||||
});
|
||||
defineProps<{ personHistory: PersonsState }>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -7,7 +7,7 @@
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
{{ $t("ticket.previous_tickets") }}
|
||||
{{ trans(CHILL_TICKET_TICKET_PREVIOUS_TICKETS) }}
|
||||
<span
|
||||
class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-chill-green"
|
||||
>
|
||||
@ -19,27 +19,18 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from "vue";
|
||||
<script setup lang="ts">
|
||||
// Translations
|
||||
import { trans, CHILL_TICKET_TICKET_PREVIOUS_TICKETS } from "translator";
|
||||
|
||||
// Types
|
||||
import { Ticket } from "../../../types";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TicketSelectorComponent",
|
||||
props: {
|
||||
tickets: {
|
||||
type: Object as PropType<Ticket[]>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
function handleClick() {
|
||||
alert("Sera disponible plus tard");
|
||||
}
|
||||
return { handleClick };
|
||||
},
|
||||
});
|
||||
defineProps<{ tickets: Ticket[] }>();
|
||||
|
||||
function handleClick() {
|
||||
alert("Sera disponible plus tard");
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
@ -1,56 +0,0 @@
|
||||
import { multiSelectMessages } from "../../../../../../../ChillMainBundle/Resources/public/vuejs/_js/i18n";
|
||||
import { personMessages } from "../../../../../../../ChillPersonBundle/Resources/public/vuejs/_js/i18n";
|
||||
|
||||
const messages = {
|
||||
fr: {
|
||||
ticket: {
|
||||
previous_tickets: "Précédents tickets",
|
||||
cancel: "Annuler",
|
||||
save: "Enregistrer",
|
||||
close: "Fermer",
|
||||
},
|
||||
history: {
|
||||
person: "Ouverture par appel téléphonique de ",
|
||||
user: "Prise en charge par ",
|
||||
},
|
||||
add_comment: {
|
||||
title: "Commentaire",
|
||||
label: "Ajouter un commentaire",
|
||||
success: "Commentaire enregistré",
|
||||
content: "Ajouter un commentaire",
|
||||
error: "Aucun commentaire ajouté",
|
||||
},
|
||||
set_motive: {
|
||||
title: "Motif",
|
||||
label: "Choisir un motif",
|
||||
success: "Motif enregistré",
|
||||
error: "Aucun motif sélectionné",
|
||||
},
|
||||
add_addressee: {
|
||||
title: "Attribuer",
|
||||
user_group_label: "Attributer à un groupe",
|
||||
user_label: "Attribuer à un ou plusieurs utilisateurs",
|
||||
success: "Attribution effectuée",
|
||||
error: "Aucun destinataire sélectionné",
|
||||
},
|
||||
set_persons: {
|
||||
title: "Patients concernés",
|
||||
user_label: "Ajouter un patient",
|
||||
},
|
||||
banner: {
|
||||
concerned_patient: "Patients concernés",
|
||||
speaker: "Attribué à",
|
||||
open: "Ouvert",
|
||||
since: "Depuis {time}",
|
||||
and: "et",
|
||||
days: "|1 jour|{count} jours",
|
||||
hours: "|1 heure et|{count} heures",
|
||||
minutes: "|1 minute|{count} minutes",
|
||||
seconds: "|1 seconde|{count} secondes",
|
||||
no_motive: "Pas de motif",
|
||||
},
|
||||
},
|
||||
};
|
||||
Object.assign(messages.fr, multiSelectMessages.fr);
|
||||
Object.assign(messages.fr, personMessages.fr);
|
||||
export default messages;
|
@ -1,13 +1,10 @@
|
||||
import App from "./App.vue";
|
||||
import { createApp } from "vue";
|
||||
|
||||
import { _createI18n } from "../../../../../../ChillMainBundle/Resources/public/vuejs/_js/i18n";
|
||||
|
||||
import VueToast from "vue-toast-notification";
|
||||
import "vue-toast-notification/dist/theme-sugar.css";
|
||||
|
||||
import { store } from "./store";
|
||||
import messages from "./i18n/messages";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@ -15,16 +12,11 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
const i18n = _createI18n(messages, false);
|
||||
|
||||
const _app = createApp({
|
||||
template: "<app></app>",
|
||||
});
|
||||
|
||||
_app.use(store)
|
||||
.use(i18n)
|
||||
// Cant use this.$toast in components in composition API so we need to provide it
|
||||
// Fix: with vue-toast-notification@^3
|
||||
.use(VueToast)
|
||||
.provide("toast", _app.config.globalProperties.$toast)
|
||||
.component("app", App)
|
||||
|
@ -0,0 +1,66 @@
|
||||
chill_ticket:
|
||||
list:
|
||||
title: Tickets
|
||||
filter:
|
||||
to_me: Tickets qui me sont attribués
|
||||
in_alert: Tickets en alerte (délai de résolution dépassé)
|
||||
created_between: Créés entre
|
||||
ticket:
|
||||
previous_tickets: "Précédents tickets"
|
||||
actions_toolbar:
|
||||
cancel: "Annuler"
|
||||
save: "Enregistrer"
|
||||
close: "Fermer"
|
||||
add_comment:
|
||||
title: "Commentaire"
|
||||
label: "Ajouter un commentaire"
|
||||
success: "Commentaire enregistré"
|
||||
content: "Ajouter un commentaire"
|
||||
error: "Aucun commentaire ajouté"
|
||||
set_motive:
|
||||
title: "Motif"
|
||||
label: "Choisir un motif"
|
||||
success: "Motif enregistré"
|
||||
error: "Aucun motif sélectionné"
|
||||
add_addressee:
|
||||
title: "Attribuer"
|
||||
user_group_label: "Attributer à un groupe"
|
||||
user_label: "Attribuer à un ou plusieurs utilisateurs"
|
||||
success: "Attribution effectuée"
|
||||
error: "Aucun destinataire sélectionné"
|
||||
set_persons:
|
||||
title: "Usagers concernés"
|
||||
user_label: "Ajouter un usager"
|
||||
success: "Usager ajouté"
|
||||
error: "Aucun usager sélectionné"
|
||||
banner:
|
||||
concerned_usager: "Usagers concernés"
|
||||
speaker: "Attribué à"
|
||||
open: "Ouvert"
|
||||
since: "Depuis {time}"
|
||||
and: "et"
|
||||
days: >-
|
||||
{count, plural,
|
||||
=0 {aucun jour}
|
||||
=1 {1 jour}
|
||||
other {# jours}
|
||||
}
|
||||
hours: >-
|
||||
{count, plural,
|
||||
=0 {aucune heure}
|
||||
=1 {1 heure}
|
||||
other {# heures}
|
||||
}
|
||||
minutes: >-
|
||||
{count, plural,
|
||||
=0 {aucune minute}
|
||||
=1 {1 minute}
|
||||
other {# minutes}
|
||||
}
|
||||
seconds: >-
|
||||
{count, plural,
|
||||
=0 {aucune seconde}
|
||||
=1 {1 seconde}
|
||||
other {# secondes}
|
||||
}
|
||||
no_motive: "Pas de motif"
|
@ -1,9 +0,0 @@
|
||||
chill_ticket:
|
||||
list:
|
||||
title: Tickets
|
||||
filter:
|
||||
to_me: Tickets qui me sont attribués
|
||||
in_alert: Tickets en alerte (délai de résolution dépassé)
|
||||
created_between: Créés entre
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user